From 3db8a7624b17e40040217bb74f592626e4e16cbf Mon Sep 17 00:00:00 2001 From: Robert Jackson Date: Wed, 5 Nov 2014 08:19:02 -0500 Subject: [PATCH] Update to Ember 1.8.1. --- assets/scripts/vendor/ember.js | 51282 ++++++++++++++------------ assets/scripts/vendor/ember.prod.js | 49584 +++++++++++++------------ 2 files changed, 52748 insertions(+), 48118 deletions(-) diff --git a/assets/scripts/vendor/ember.js b/assets/scripts/vendor/ember.js index 647ee015..54e8739e 100644 --- a/assets/scripts/vendor/ember.js +++ b/assets/scripts/vendor/ember.js @@ -5,25 +5,24 @@ * Portions Copyright 2008-2011 Apple Inc. All rights reserved. * @license Licensed under MIT license * See https://raw.github.com/emberjs/ember.js/master/LICENSE - * @version 1.6.1 + * @version 1.8.1 */ - (function() { -var define, requireModule, require, requirejs, Ember; +var enifed, requireModule, eriuqer, requirejs, Ember; (function() { Ember = this.Ember = this.Ember || {}; - if (typeof Ember === 'undefined') { Ember = {} }; + if (typeof Ember === 'undefined') { Ember = {}; }; if (typeof Ember.__loader === 'undefined') { var registry = {}, seen = {}; - define = function(name, deps, callback) { + enifed = function(name, deps, callback) { registry[name] = { deps: deps, callback: callback }; }; - requirejs = require = requireModule = function(name) { + requirejs = eriuqer = requireModule = function(name) { if (seen.hasOwnProperty(name)) { return seen[name]; } seen[name] = {}; @@ -31,11 +30,11 @@ var define, requireModule, require, requirejs, Ember; throw new Error("Could not find module " + name); } - var mod = registry[name], - deps = mod.deps, - callback = mod.callback, - reified = [], - exports; + var mod = registry[name]; + var deps = mod.deps; + var callback = mod.callback; + var reified = []; + var exports; for (var i=0, l=deps.length; i 3) { + args = new Array(length - 3); + for (var i = 3; i < length; i++) { + args[i-3] = arguments[i]; + } + } else { + args = undefined; + } + + if (!this.currentInstance) { createAutorun(this); } + return this.currentInstance.schedule(queueName, target, method, args, false, stack); + }, + + deferOnce: function(queueName, target, method /* , args */) { + if (!method) { + method = target; + target = null; + } + + if (isString(method)) { + method = target[method]; + } + + var stack = this.DEBUG ? new Error() : undefined; + var length = arguments.length; + var args; + + if (length > 3) { + args = new Array(length - 3); + for (var i = 3; i < length; i++) { + args[i-3] = arguments[i]; + } + } else { + args = undefined; + } + + if (!this.currentInstance) { + createAutorun(this); + } + return this.currentInstance.schedule(queueName, target, method, args, true, stack); + }, + + setTimeout: function() { + var l = arguments.length; + var args = new Array(l); + + for (var x = 0; x < l; x++) { + args[x] = arguments[x]; + } + + var length = args.length, + method, wait, target, + methodOrTarget, methodOrWait, methodOrArgs; + + if (length === 0) { + return; + } else if (length === 1) { + method = args.shift(); + wait = 0; + } else if (length === 2) { + methodOrTarget = args[0]; + methodOrWait = args[1]; + + if (isFunction(methodOrWait) || isFunction(methodOrTarget[methodOrWait])) { + target = args.shift(); + method = args.shift(); + wait = 0; + } else if (isCoercableNumber(methodOrWait)) { + method = args.shift(); + wait = args.shift(); + } else { + method = args.shift(); + wait = 0; + } + } else { + var last = args[args.length - 1]; + + if (isCoercableNumber(last)) { + wait = args.pop(); + } else { + wait = 0; + } + + methodOrTarget = args[0]; + methodOrArgs = args[1]; + + if (isFunction(methodOrArgs) || (isString(methodOrArgs) && + methodOrTarget !== null && + methodOrArgs in methodOrTarget)) { + target = args.shift(); + method = args.shift(); + } else { + method = args.shift(); + } + } + + var executeAt = now() + parseInt(wait, 10); + + if (isString(method)) { + method = target[method]; + } + + var onError = getOnError(this.options); + + function fn() { + if (onError) { + try { + method.apply(target, args); + } catch (e) { + onError(e); + } + } else { + method.apply(target, args); + } + } + + // find position to insert + var i = searchTimer(executeAt, this._timers); + + this._timers.splice(i, 0, executeAt, fn); + + updateLaterTimer(this, executeAt, wait); + + return fn; + }, + + throttle: function(target, method /* , args, wait, [immediate] */) { + var backburner = this; + var args = arguments; + var immediate = pop.call(args); + var wait, throttler, index, timer; + + if (isNumber(immediate) || isString(immediate)) { + wait = immediate; + immediate = true; + } else { + wait = pop.call(args); + } + + wait = parseInt(wait, 10); + + index = findThrottler(target, method, this._throttlers); + if (index > -1) { return this._throttlers[index]; } // throttled + + timer = global.setTimeout(function() { + if (!immediate) { + backburner.run.apply(backburner, args); + } + var index = findThrottler(target, method, backburner._throttlers); + if (index > -1) { + backburner._throttlers.splice(index, 1); + } + }, wait); + + if (immediate) { + this.run.apply(this, args); + } + + throttler = [target, method, timer]; + + this._throttlers.push(throttler); + + return throttler; + }, + + debounce: function(target, method /* , args, wait, [immediate] */) { + var backburner = this; + var args = arguments; + var immediate = pop.call(args); + var wait, index, debouncee, timer; + + if (isNumber(immediate) || isString(immediate)) { + wait = immediate; + immediate = false; + } else { + wait = pop.call(args); + } + + wait = parseInt(wait, 10); + // Remove debouncee + index = findDebouncee(target, method, this._debouncees); + + if (index > -1) { + debouncee = this._debouncees[index]; + this._debouncees.splice(index, 1); + clearTimeout(debouncee[2]); + } + + timer = global.setTimeout(function() { + if (!immediate) { + backburner.run.apply(backburner, args); + } + var index = findDebouncee(target, method, backburner._debouncees); + if (index > -1) { + backburner._debouncees.splice(index, 1); + } + }, wait); + + if (immediate && index === -1) { + backburner.run.apply(backburner, args); + } + + debouncee = [ + target, + method, + timer + ]; + + backburner._debouncees.push(debouncee); + + return debouncee; + }, + + cancelTimers: function() { + var clearItems = function(item) { + clearTimeout(item[2]); + }; + + each(this._throttlers, clearItems); + this._throttlers = []; + + each(this._debouncees, clearItems); + this._debouncees = []; + + if (this._laterTimer) { + clearTimeout(this._laterTimer); + this._laterTimer = null; + } + this._timers = []; + + if (this._autorun) { + clearTimeout(this._autorun); + this._autorun = null; + } + }, + + hasTimers: function() { + return !!this._timers.length || !!this._debouncees.length || !!this._throttlers.length || this._autorun; + }, + + cancel: function(timer) { + var timerType = typeof timer; + + if (timer && timerType === 'object' && timer.queue && timer.method) { // we're cancelling a deferOnce + return timer.queue.cancel(timer); + } else if (timerType === 'function') { // we're cancelling a setTimeout + for (var i = 0, l = this._timers.length; i < l; i += 2) { + if (this._timers[i + 1] === timer) { + this._timers.splice(i, 2); // remove the two elements + if (i === 0) { + if (this._laterTimer) { // Active timer? Then clear timer and reset for future timer + clearTimeout(this._laterTimer); + this._laterTimer = null; + } + if (this._timers.length > 0) { // Update to next available timer when available + updateLaterTimer(this, this._timers[0], this._timers[0] - now()); + } + } + return true; + } + } + } else if (Object.prototype.toString.call(timer) === "[object Array]"){ // we're cancelling a throttle or debounce + return this._cancelItem(findThrottler, this._throttlers, timer) || + this._cancelItem(findDebouncee, this._debouncees, timer); + } else { + return; // timer was null or not a timer + } + }, + + _cancelItem: function(findMethod, array, timer){ + var item, index; + + if (timer.length < 3) { return false; } + + index = findMethod(timer[0], timer[1], array); + + if (index > -1) { + + item = array[index]; + + if (item[2] === timer[2]) { + array.splice(index, 1); + clearTimeout(timer[2]); + return true; + } + } + + return false; + } + }; + + Backburner.prototype.schedule = Backburner.prototype.defer; + Backburner.prototype.scheduleOnce = Backburner.prototype.deferOnce; + Backburner.prototype.later = Backburner.prototype.setTimeout; + + if (needsIETryCatchFix) { + var originalRun = Backburner.prototype.run; + Backburner.prototype.run = wrapInTryCatch(originalRun); + + var originalEnd = Backburner.prototype.end; + Backburner.prototype.end = wrapInTryCatch(originalEnd); + } + + function getOnError(options) { + return options.onError || (options.onErrorTarget && options.onErrorTarget[options.onErrorMethod]); + } + + function createAutorun(backburner) { + backburner.begin(); + backburner._autorun = global.setTimeout(function() { + backburner._autorun = null; + backburner.end(); + }); + } + + function updateLaterTimer(backburner, executeAt, wait) { + var n = now(); + if (!backburner._laterTimer || executeAt < backburner._laterTimerExpiresAt || backburner._laterTimerExpiresAt < n) { + + if (backburner._laterTimer) { + // Clear when: + // - Already expired + // - New timer is earlier + clearTimeout(backburner._laterTimer); + + if (backburner._laterTimerExpiresAt < n) { // If timer was never triggered + // Calculate the left-over wait-time + wait = Math.max(0, executeAt - n); + } + } + + backburner._laterTimer = global.setTimeout(function() { + backburner._laterTimer = null; + backburner._laterTimerExpiresAt = null; + executeTimers(backburner); + }, wait); + + backburner._laterTimerExpiresAt = n + wait; + } + } + + function executeTimers(backburner) { + var n = now(); + var fns, i, l; + + backburner.run(function() { + i = searchTimer(n, backburner._timers); + + fns = backburner._timers.splice(0, i); + + for (i = 1, l = fns.length; i < l; i += 2) { + backburner.schedule(backburner.options.defaultQueue, null, fns[i]); + } + }); + + if (backburner._timers.length) { + updateLaterTimer(backburner, backburner._timers[0], backburner._timers[0] - n); + } + } + + function findDebouncee(target, method, debouncees) { + return findItem(target, method, debouncees); + } + + function findThrottler(target, method, throttlers) { + return findItem(target, method, throttlers); + } + + function findItem(target, method, collection) { + var item; + var index = -1; + + for (var i = 0, l = collection.length; i < l; i++) { + item = collection[i]; + if (item[0] === target && item[1] === method) { + index = i; + break; + } + } + + return index; + } + + __exports__["default"] = Backburner; + }); +enifed("backburner.umd", + ["./backburner"], + function(__dependency1__) { + "use strict"; + var Backburner = __dependency1__["default"]; + + /* global define:true module:true window: true */ + if (typeof enifed === 'function' && enifed.amd) { + enifed(function() { return Backburner; }); + } else if (typeof module !== 'undefined' && module.exports) { + module.exports = Backburner; + } else if (typeof this !== 'undefined') { + this['Backburner'] = Backburner; + } + }); +enifed("backburner/binary-search", + ["exports"], + function(__exports__) { + "use strict"; + __exports__["default"] = function binarySearch(time, timers) { + var start = 0; + var end = timers.length - 2; + var middle, l; + + while (start < end) { + // since timers is an array of pairs 'l' will always + // be an integer + l = (end - start) / 2; + + // compensate for the index in case even number + // of pairs inside timers + middle = start + l - (l % 2); + + if (time >= timers[middle]) { + start = middle + 2; + } else { + end = middle; + } + } + + return (time >= timers[start]) ? start + 2 : start; + } + }); +enifed("backburner/deferred-action-queues", + ["./utils","./queue","exports"], + function(__dependency1__, __dependency2__, __exports__) { + "use strict"; + var each = __dependency1__.each; + var isString = __dependency1__.isString; + var Queue = __dependency2__["default"]; + + function DeferredActionQueues(queueNames, options) { + var queues = this.queues = {}; + this.queueNames = queueNames = queueNames || []; + + this.options = options; + + each(queueNames, function(queueName) { + queues[queueName] = new Queue(queueName, options[queueName], options); + }); + } + + function noSuchQueue(name) { + throw new Error("You attempted to schedule an action in a queue (" + name + ") that doesn't exist"); + } + + DeferredActionQueues.prototype = { + schedule: function(name, target, method, args, onceFlag, stack) { + var queues = this.queues; + var queue = queues[name]; + + if (!queue) { noSuchQueue(name); } + + if (onceFlag) { + return queue.pushUnique(target, method, args, stack); + } else { + return queue.push(target, method, args, stack); + } + }, + + invoke: function(target, method, args, _, _errorRecordedForStack) { + if (args && args.length > 0) { + method.apply(target, args); + } else { + method.call(target); + } + }, + + invokeWithOnError: function(target, method, args, onError, errorRecordedForStack) { + try { + if (args && args.length > 0) { + method.apply(target, args); + } else { + method.call(target); + } + } catch(error) { + onError(error, errorRecordedForStack); + } + }, + + flush: function() { + var queues = this.queues; + var queueNames = this.queueNames; + var queueName, queue, queueItems, priorQueueNameIndex; + var queueNameIndex = 0; + var numberOfQueues = queueNames.length; + var options = this.options; + var onError = options.onError || (options.onErrorTarget && options.onErrorTarget[options.onErrorMethod]); + var invoke = onError ? this.invokeWithOnError : this.invoke; + + while (queueNameIndex < numberOfQueues) { + queueName = queueNames[queueNameIndex]; + queue = queues[queueName]; + queueItems = queue._queueBeingFlushed = queue._queue.slice(); + queue._queue = []; + queue.targetQueues = Object.create(null); + + var queueOptions = queue.options; // TODO: write a test for this + var before = queueOptions && queueOptions.before; + var after = queueOptions && queueOptions.after; + var target, method, args, errorRecordedForStack; + var queueIndex = 0; + var numberOfQueueItems = queueItems.length; + + if (numberOfQueueItems && before) { + before(); + } + + while (queueIndex < numberOfQueueItems) { + target = queueItems[queueIndex]; + method = queueItems[queueIndex+1]; + args = queueItems[queueIndex+2]; + errorRecordedForStack = queueItems[queueIndex+3]; // Debugging assistance + + // + + if (isString(method)) { + method = target[method]; + } + + // method could have been nullified / canceled during flush + if (method) { + // + // ** Attention intrepid developer ** + // + // To find out the stack of this task when it was scheduled onto + // the run loop, add the following to your app.js: + // + // Ember.run.backburner.DEBUG = true; // NOTE: This slows your app, don't leave it on in production. + // + // Once that is in place, when you are at a breakpoint and navigate + // here in the stack explorer, you can look at `errorRecordedForStack.stack`, + // which will be the captured stack when this job was scheduled. + // + invoke(target, method, args, onError, errorRecordedForStack); + } + + queueIndex += 4; + } + + queue._queueBeingFlushed = null; + if (numberOfQueueItems && after) { + after(); + } + + if ((priorQueueNameIndex = indexOfPriorQueueWithActions(this, queueNameIndex)) !== -1) { + queueNameIndex = priorQueueNameIndex; + } else { + queueNameIndex++; + } + } + } + }; + + function indexOfPriorQueueWithActions(daq, currentQueueIndex) { + var queueName, queue; + + for (var i = 0, l = currentQueueIndex; i <= l; i++) { + queueName = daq.queueNames[i]; + queue = daq.queues[queueName]; + if (queue._queue.length) { return i; } + } + + return -1; + } + + __exports__["default"] = DeferredActionQueues; + }); +enifed("backburner/platform", + ["exports"], + function(__exports__) { + "use strict"; + // In IE 6-8, try/finally doesn't work without a catch. + // Unfortunately, this is impossible to test for since wrapping it in a parent try/catch doesn't trigger the bug. + // This tests for another broken try/catch behavior that only exhibits in the same versions of IE. + var needsIETryCatchFix = (function(e,x){ + try{ x(); } + catch(e) { } // jshint ignore:line + return !!e; + })(); + __exports__.needsIETryCatchFix = needsIETryCatchFix; + }); +enifed("backburner/queue", + ["exports"], + function(__exports__) { + "use strict"; + function Queue(name, options, globalOptions) { + this.name = name; + this.globalOptions = globalOptions || {}; + this.options = options; + this._queue = []; + this.targetQueues = Object.create(null); + this._queueBeingFlushed = undefined; + } + + Queue.prototype = { + push: function(target, method, args, stack) { + var queue = this._queue; + queue.push(target, method, args, stack); + + return { + queue: this, + target: target, + method: method + }; + }, + + pushUniqueWithoutGuid: function(target, method, args, stack) { + var queue = this._queue; + + for (var i = 0, l = queue.length; i < l; i += 4) { + var currentTarget = queue[i]; + var currentMethod = queue[i+1]; + + if (currentTarget === target && currentMethod === method) { + queue[i+2] = args; // replace args + queue[i+3] = stack; // replace stack + return; + } + } + + queue.push(target, method, args, stack); + }, + + targetQueue: function(targetQueue, target, method, args, stack) { + var queue = this._queue; + + for (var i = 0, l = targetQueue.length; i < l; i += 4) { + var currentMethod = targetQueue[i]; + var currentIndex = targetQueue[i + 1]; + + if (currentMethod === method) { + queue[currentIndex + 2] = args; // replace args + queue[currentIndex + 3] = stack; // replace stack + return; + } + } + + targetQueue.push( + method, + queue.push(target, method, args, stack) - 4 + ); + }, + + pushUniqueWithGuid: function(guid, target, method, args, stack) { + var hasLocalQueue = this.targetQueues[guid]; + + if (hasLocalQueue) { + this.targetQueue(hasLocalQueue, target, method, args, stack); + } else { + this.targetQueues[guid] = [ + method, + this._queue.push(target, method, args, stack) - 4 + ]; + } + + return { + queue: this, + target: target, + method: method + }; + }, + + pushUnique: function(target, method, args, stack) { + var queue = this._queue, currentTarget, currentMethod, i, l; + var KEY = this.globalOptions.GUID_KEY; + + if (target && KEY) { + var guid = target[KEY]; + if (guid) { + return this.pushUniqueWithGuid(guid, target, method, args, stack); + } + } + + this.pushUniqueWithoutGuid(target, method, args, stack); + + return { + queue: this, + target: target, + method: method + }; + }, + + // TODO: remove me, only being used for Ember.run.sync + flush: function() { + var queue = this._queue; + var globalOptions = this.globalOptions; + var options = this.options; + var before = options && options.before; + var after = options && options.after; + var onError = globalOptions.onError || (globalOptions.onErrorTarget && globalOptions.onErrorTarget[globalOptions.onErrorMethod]); + var target, method, args, stack, i, l = queue.length; + + this.targetQueues = Object.create(null); + + if (l && before) { before(); } + for (i = 0; i < l; i += 4) { + target = queue[i]; + method = queue[i+1]; + args = queue[i+2]; + stack = queue[i+3]; // Debugging assistance + + // TODO: error handling + if (args && args.length > 0) { + if (onError) { + try { + method.apply(target, args); + } catch (e) { + onError(e); + } + } else { + method.apply(target, args); + } + } else { + if (onError) { + try { + method.call(target); + } catch(e) { + onError(e); + } + } else { + method.call(target); + } + } + } + if (l && after) { after(); } + + // check if new items have been added + if (queue.length > l) { + this._queue = queue.slice(l); + this.flush(); + } else { + this._queue.length = 0; + } + }, + + cancel: function(actionToCancel) { + var queue = this._queue, currentTarget, currentMethod, i, l; + var target = actionToCancel.target; + var method = actionToCancel.method; + var GUID_KEY = this.globalOptions.GUID_KEY; + + if (GUID_KEY && this.targetQueues && target) { + var targetQueue = this.targetQueues[target[GUID_KEY]]; + + if (targetQueue) { + for (i = 0, l = targetQueue.length; i < l; i++) { + if (targetQueue[i] === method) { + targetQueue.splice(i, 1); + } + } + } + } + + for (i = 0, l = queue.length; i < l; i += 4) { + currentTarget = queue[i]; + currentMethod = queue[i+1]; + + if (currentTarget === target && + currentMethod === method) { + queue.splice(i, 4); + return true; + } + } + + // if not found in current queue + // could be in the queue that is being flushed + queue = this._queueBeingFlushed; + if (!queue) { + return; + } + for (i = 0, l = queue.length; i < l; i += 4) { + currentTarget = queue[i]; + currentMethod = queue[i+1]; + + if (currentTarget === target && + currentMethod === method) { + // don't mess with array during flush + // just nullify the method + queue[i+1] = null; + return true; + } + } + } + }; + + __exports__["default"] = Queue; + }); +enifed("backburner/utils", + ["exports"], + function(__exports__) { + "use strict"; + var NUMBER = /\d+/; + + function each(collection, callback) { + for (var i = 0; i < collection.length; i++) { + callback(collection[i]); + } + } + + __exports__.each = each;// Date.now is not available in browsers < IE9 + // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/now#Compatibility + var now = Date.now || function() { return new Date().getTime(); }; + __exports__.now = now; + function isString(suspect) { + return typeof suspect === 'string'; + } + + __exports__.isString = isString;function isFunction(suspect) { + return typeof suspect === 'function'; + } + + __exports__.isFunction = isFunction;function isNumber(suspect) { + return typeof suspect === 'number'; + } + + __exports__.isNumber = isNumber;function isCoercableNumber(number) { + return isNumber(number) || NUMBER.test(number); + } + + __exports__.isCoercableNumber = isCoercableNumber;function wrapInTryCatch(func) { + return function () { + try { + return func.apply(this, arguments); + } catch (e) { + throw e; + } + }; + } + + __exports__.wrapInTryCatch = wrapInTryCatch; + }); +enifed("calculateVersion", + [], + function() { + "use strict"; + 'use strict'; + + var fs = eriuqer('fs'); + var path = eriuqer('path'); + + module.exports = function () { + var packageVersion = eriuqer('../package.json').version; + var output = [packageVersion]; + var gitPath = path.join(__dirname,'..','.git'); + var headFilePath = path.join(gitPath, 'HEAD'); + + if (packageVersion.indexOf('+') > -1) { + try { + if (fs.existsSync(headFilePath)) { + var headFile = fs.readFileSync(headFilePath, {encoding: 'utf8'}); + var branchName = headFile.split('/').slice(-1)[0].trim(); + var refPath = headFile.split(' ')[1]; + var branchSHA; + + if (refPath) { + var branchPath = path.join(gitPath, refPath.trim()); + branchSHA = fs.readFileSync(branchPath); + } else { + branchSHA = branchName; + } + + output.push(branchSHA.slice(0,10)); + } + } catch (err) { + console.error(err.stack); + } + return output.join('.'); + } else { + return packageVersion; + } + }; + }); +enifed("container", + ["container/container","exports"], + function(__dependency1__, __exports__) { + "use strict"; + /* + Public api for the container is still in flux. + The public api, specified on the application namespace should be considered the stable api. + // @module container + @private + */ + + /* + Flag to enable/disable model factory injections (disabled by default) + If model factory injections are enabled, models should not be + accessed globally (only through `container.lookupFactory('model:modelName'))`); + */ + Ember.MODEL_FACTORY_INJECTIONS = false; + + if (Ember.ENV && typeof Ember.ENV.MODEL_FACTORY_INJECTIONS !== 'undefined') { + Ember.MODEL_FACTORY_INJECTIONS = !!Ember.ENV.MODEL_FACTORY_INJECTIONS; + } + + + var Container = __dependency1__["default"]; + + __exports__["default"] = Container; + }); +enifed("container/container", + ["ember-metal/core","ember-metal/keys","ember-metal/dictionary","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __exports__) { + "use strict"; + var Ember = __dependency1__["default"]; + // Ember.assert + var emberKeys = __dependency2__["default"]; + var dictionary = __dependency3__["default"]; + + // A lightweight container that helps to assemble and decouple components. + // Public api for the container is still in flux. + // The public api, specified on the application namespace should be considered the stable api. + function Container(parent) { + this.parent = parent; + this.children = []; + + this.resolver = parent && parent.resolver || function() {}; + + this.registry = dictionary(parent ? parent.registry : null); + this.cache = dictionary(parent ? parent.cache : null); + this.factoryCache = dictionary(parent ? parent.factoryCache : null); + this.resolveCache = dictionary(parent ? parent.resolveCache : null); + this.typeInjections = dictionary(parent ? parent.typeInjections : null); + this.injections = dictionary(null); + this.normalizeCache = dictionary(null); + + this.factoryTypeInjections = dictionary(parent ? parent.factoryTypeInjections : null); + this.factoryInjections = dictionary(null); + + this._options = dictionary(parent ? parent._options : null); + this._typeOptions = dictionary(parent ? parent._typeOptions : null); + } + + Container.prototype = { + + /** + @property parent + @type Container + @default null + */ + parent: null, + + /** + @property children + @type Array + @default [] + */ + children: null, + + /** + @property resolver + @type function + */ + resolver: null, + + /** + @property registry + @type InheritingDict + */ + registry: null, + + /** + @property cache + @type InheritingDict + */ + cache: null, + + /** + @property typeInjections + @type InheritingDict + */ + typeInjections: null, + + /** + @property injections + @type Object + @default {} + */ + injections: null, + + /** + @private + + @property _options + @type InheritingDict + @default null + */ + _options: null, + + /** + @private + + @property _typeOptions + @type InheritingDict + */ + _typeOptions: null, + + /** + Returns a new child of the current container. These children are configured + to correctly inherit from the current container. + + @method child + @return {Container} + */ + child: function() { + var container = new Container(this); + this.children.push(container); + return container; + }, + + /** + Sets a key-value pair on the current container. If a parent container, + has the same key, once set on a child, the parent and child will diverge + as expected. + + @method set + @param {Object} object + @param {String} key + @param {any} value + */ + set: function(object, key, value) { + object[key] = value; + }, + + /** + Registers a factory for later injection. + + Example: + + ```javascript + var container = new Container(); + + container.register('model:user', Person, {singleton: false }); + container.register('fruit:favorite', Orange); + container.register('communication:main', Email, {singleton: false}); + ``` + + @method register + @param {String} fullName + @param {Function} factory + @param {Object} options + */ + register: function(fullName, factory, options) { + Ember.assert('fullName must be a proper full name', validateFullName(fullName)); + + if (factory === undefined) { + throw new TypeError('Attempting to register an unknown factory: `' + fullName + '`'); + } + + var normalizedName = this.normalize(fullName); + + if (normalizedName in this.cache) { + throw new Error('Cannot re-register: `' + fullName +'`, as it has already been looked up.'); + } + + this.registry[normalizedName] = factory; + this._options[normalizedName] = (options || {}); + }, + + /** + Unregister a fullName + + ```javascript + var container = new Container(); + container.register('model:user', User); + + container.lookup('model:user') instanceof User //=> true + + container.unregister('model:user') + container.lookup('model:user') === undefined //=> true + ``` + + @method unregister + @param {String} fullName + */ + unregister: function(fullName) { + Ember.assert('fullName must be a proper full name', validateFullName(fullName)); + + var normalizedName = this.normalize(fullName); + + delete this.registry[normalizedName]; + delete this.cache[normalizedName]; + delete this.factoryCache[normalizedName]; + delete this.resolveCache[normalizedName]; + delete this._options[normalizedName]; + }, + + /** + Given a fullName return the corresponding factory. + + By default `resolve` will retrieve the factory from + its container's registry. + + ```javascript + var container = new Container(); + container.register('api:twitter', Twitter); + + container.resolve('api:twitter') // => Twitter + ``` + + Optionally the container can be provided with a custom resolver. + If provided, `resolve` will first provide the custom resolver + the opportunity to resolve the fullName, otherwise it will fallback + to the registry. + + ```javascript + var container = new Container(); + container.resolver = function(fullName) { + // lookup via the module system of choice + }; + + // the twitter factory is added to the module system + container.resolve('api:twitter') // => Twitter + ``` + + @method resolve + @param {String} fullName + @return {Function} fullName's factory + */ + resolve: function(fullName) { + Ember.assert('fullName must be a proper full name', validateFullName(fullName)); + return resolve(this, this.normalize(fullName)); + }, + + /** + A hook that can be used to describe how the resolver will + attempt to find the factory. + + For example, the default Ember `.describe` returns the full + class name (including namespace) where Ember's resolver expects + to find the `fullName`. + + @method describe + @param {String} fullName + @return {string} described fullName + */ + describe: function(fullName) { + return fullName; + }, + + /** + A hook to enable custom fullName normalization behaviour + + @method normalizeFullName + @param {String} fullName + @return {string} normalized fullName + */ + normalizeFullName: function(fullName) { + return fullName; + }, + + /** + normalize a fullName based on the applications conventions + + @method normalize + @param {String} fullName + @return {string} normalized fullName + */ + normalize: function(fullName) { + return this.normalizeCache[fullName] || ( + this.normalizeCache[fullName] = this.normalizeFullName(fullName) + ); + }, + + /** + @method makeToString + + @param {any} factory + @param {string} fullName + @return {function} toString function + */ + makeToString: function(factory, fullName) { + return factory.toString(); + }, + + /** + Given a fullName return a corresponding instance. + + The default behaviour is for lookup to return a singleton instance. + The singleton is scoped to the container, allowing multiple containers + to all have their own locally scoped singletons. + + ```javascript + var container = new Container(); + container.register('api:twitter', Twitter); + + var twitter = container.lookup('api:twitter'); + + twitter instanceof Twitter; // => true + + // by default the container will return singletons + var twitter2 = container.lookup('api:twitter'); + twitter2 instanceof Twitter; // => true + + twitter === twitter2; //=> true + ``` + + If singletons are not wanted an optional flag can be provided at lookup. + + ```javascript + var container = new Container(); + container.register('api:twitter', Twitter); + + var twitter = container.lookup('api:twitter', { singleton: false }); + var twitter2 = container.lookup('api:twitter', { singleton: false }); + + twitter === twitter2; //=> false + ``` + + @method lookup + @param {String} fullName + @param {Object} options + @return {any} + */ + lookup: function(fullName, options) { + Ember.assert('fullName must be a proper full name', validateFullName(fullName)); + return lookup(this, this.normalize(fullName), options); + }, + + /** + Given a fullName return the corresponding factory. + + @method lookupFactory + @param {String} fullName + @return {any} + */ + lookupFactory: function(fullName) { + Ember.assert('fullName must be a proper full name', validateFullName(fullName)); + return factoryFor(this, this.normalize(fullName)); + }, + + /** + Given a fullName check if the container is aware of its factory + or singleton instance. + + @method has + @param {String} fullName + @return {Boolean} + */ + has: function(fullName) { + Ember.assert('fullName must be a proper full name', validateFullName(fullName)); + return has(this, this.normalize(fullName)); + }, + + /** + Allow registering options for all factories of a type. + + ```javascript + var container = new Container(); + + // if all of type `connection` must not be singletons + container.optionsForType('connection', { singleton: false }); + + container.register('connection:twitter', TwitterConnection); + container.register('connection:facebook', FacebookConnection); + + var twitter = container.lookup('connection:twitter'); + var twitter2 = container.lookup('connection:twitter'); + + twitter === twitter2; // => false + + var facebook = container.lookup('connection:facebook'); + var facebook2 = container.lookup('connection:facebook'); + + facebook === facebook2; // => false + ``` + + @method optionsForType + @param {String} type + @param {Object} options + */ + optionsForType: function(type, options) { + if (this.parent) { illegalChildOperation('optionsForType'); } + + this._typeOptions[type] = options; + }, + + /** + @method options + @param {String} type + @param {Object} options + */ + options: function(type, options) { + this.optionsForType(type, options); + }, + + /** + Used only via `injection`. + + Provides a specialized form of injection, specifically enabling + all objects of one type to be injected with a reference to another + object. + + For example, provided each object of type `controller` needed a `router`. + one would do the following: + + ```javascript + var container = new Container(); + + container.register('router:main', Router); + container.register('controller:user', UserController); + container.register('controller:post', PostController); + + container.typeInjection('controller', 'router', 'router:main'); + + var user = container.lookup('controller:user'); + var post = container.lookup('controller:post'); + + user.router instanceof Router; //=> true + post.router instanceof Router; //=> true + + // both controllers share the same router + user.router === post.router; //=> true + ``` + + @private + @method typeInjection + @param {String} type + @param {String} property + @param {String} fullName + */ + typeInjection: function(type, property, fullName) { + Ember.assert('fullName must be a proper full name', validateFullName(fullName)); + + if (this.parent) { illegalChildOperation('typeInjection'); } + + var fullNameType = fullName.split(':')[0]; + if (fullNameType === type) { + throw new Error('Cannot inject a `' + fullName + '` on other ' + type + '(s). Register the `' + fullName + '` as a different type and perform the typeInjection.'); + } + + addTypeInjection(this.typeInjections, type, property, fullName); + }, + + /** + Defines injection rules. + + These rules are used to inject dependencies onto objects when they + are instantiated. + + Two forms of injections are possible: + + * Injecting one fullName on another fullName + * Injecting one fullName on a type + + Example: + + ```javascript + var container = new Container(); + + container.register('source:main', Source); + container.register('model:user', User); + container.register('model:post', Post); + + // injecting one fullName on another fullName + // eg. each user model gets a post model + container.injection('model:user', 'post', 'model:post'); + + // injecting one fullName on another type + container.injection('model', 'source', 'source:main'); + + var user = container.lookup('model:user'); + var post = container.lookup('model:post'); + + user.source instanceof Source; //=> true + post.source instanceof Source; //=> true + + user.post instanceof Post; //=> true + + // and both models share the same source + user.source === post.source; //=> true + ``` + + @method injection + @param {String} factoryName + @param {String} property + @param {String} injectionName + */ + injection: function(fullName, property, injectionName) { + if (this.parent) { illegalChildOperation('injection'); } + + validateFullName(injectionName); + var normalizedInjectionName = this.normalize(injectionName); + + if (fullName.indexOf(':') === -1) { + return this.typeInjection(fullName, property, normalizedInjectionName); + } + + Ember.assert('fullName must be a proper full name', validateFullName(fullName)); + var normalizedName = this.normalize(fullName); + + if (this.cache[normalizedName]) { + throw new Error("Attempted to register an injection for a type that has already been looked up. ('" + normalizedName + "', '" + property + "', '" + injectionName + "')"); + } + addInjection(this.injections, normalizedName, property, normalizedInjectionName); + }, + + + /** + Used only via `factoryInjection`. + + Provides a specialized form of injection, specifically enabling + all factory of one type to be injected with a reference to another + object. + + For example, provided each factory of type `model` needed a `store`. + one would do the following: + + ```javascript + var container = new Container(); + + container.register('store:main', SomeStore); + + container.factoryTypeInjection('model', 'store', 'store:main'); + + var store = container.lookup('store:main'); + var UserFactory = container.lookupFactory('model:user'); + + UserFactory.store instanceof SomeStore; //=> true + ``` + + @private + @method factoryTypeInjection + @param {String} type + @param {String} property + @param {String} fullName + */ + factoryTypeInjection: function(type, property, fullName) { + if (this.parent) { illegalChildOperation('factoryTypeInjection'); } + + addTypeInjection(this.factoryTypeInjections, type, property, this.normalize(fullName)); + }, + + /** + Defines factory injection rules. + + Similar to regular injection rules, but are run against factories, via + `Container#lookupFactory`. + + These rules are used to inject objects onto factories when they + are looked up. + + Two forms of injections are possible: + + * Injecting one fullName on another fullName + * Injecting one fullName on a type + + Example: + + ```javascript + var container = new Container(); + + container.register('store:main', Store); + container.register('store:secondary', OtherStore); + container.register('model:user', User); + container.register('model:post', Post); + + // injecting one fullName on another type + container.factoryInjection('model', 'store', 'store:main'); + + // injecting one fullName on another fullName + container.factoryInjection('model:post', 'secondaryStore', 'store:secondary'); + + var UserFactory = container.lookupFactory('model:user'); + var PostFactory = container.lookupFactory('model:post'); + var store = container.lookup('store:main'); + + UserFactory.store instanceof Store; //=> true + UserFactory.secondaryStore instanceof OtherStore; //=> false + + PostFactory.store instanceof Store; //=> true + PostFactory.secondaryStore instanceof OtherStore; //=> true + + // and both models share the same source instance + UserFactory.store === PostFactory.store; //=> true + ``` + + @method factoryInjection + @param {String} factoryName + @param {String} property + @param {String} injectionName + */ + factoryInjection: function(fullName, property, injectionName) { + if (this.parent) { illegalChildOperation('injection'); } + + var normalizedName = this.normalize(fullName); + var normalizedInjectionName = this.normalize(injectionName); + + validateFullName(injectionName); + + if (fullName.indexOf(':') === -1) { + return this.factoryTypeInjection(normalizedName, property, normalizedInjectionName); + } + + Ember.assert('fullName must be a proper full name', validateFullName(fullName)); + + if (this.factoryCache[normalizedName]) { + throw new Error('Attempted to register a factoryInjection for a type that has already ' + + 'been looked up. (\'' + normalizedName + '\', \'' + property + '\', \'' + injectionName + '\')'); + } + + addInjection(this.factoryInjections, normalizedName, property, normalizedInjectionName); + }, + + /** + A depth first traversal, destroying the container, its descendant containers and all + their managed objects. + + @method destroy + */ + destroy: function() { + for (var i = 0, length = this.children.length; i < length; i++) { + this.children[i].destroy(); + } + + this.children = []; + + eachDestroyable(this, function(item) { + item.destroy(); + }); + + this.parent = undefined; + this.isDestroyed = true; + }, + + /** + @method reset + */ + reset: function() { + for (var i = 0, length = this.children.length; i < length; i++) { + resetCache(this.children[i]); + } + + resetCache(this); + } + }; + + function resolve(container, normalizedName) { + var cached = container.resolveCache[normalizedName]; + if (cached) { return cached; } + + var resolved = container.resolver(normalizedName) || container.registry[normalizedName]; + container.resolveCache[normalizedName] = resolved; + + return resolved; + } + + function has(container, fullName){ + if (container.cache[fullName]) { + return true; + } + + return !!container.resolve(fullName); + } + + function lookup(container, fullName, options) { + options = options || {}; + + if (container.cache[fullName] && options.singleton !== false) { + return container.cache[fullName]; + } + + var value = instantiate(container, fullName); + + if (value === undefined) { return; } + + if (isSingleton(container, fullName) && options.singleton !== false) { + container.cache[fullName] = value; + } + + return value; + } + + function illegalChildOperation(operation) { + throw new Error(operation + ' is not currently supported on child containers'); + } + + function isSingleton(container, fullName) { + var singleton = option(container, fullName, 'singleton'); + + return singleton !== false; + } + + function buildInjections(container, injections) { + var hash = {}; + + if (!injections) { return hash; } + + var injection, injectable; + + for (var i = 0, length = injections.length; i < length; i++) { + injection = injections[i]; + injectable = lookup(container, injection.fullName); + + if (injectable !== undefined) { + hash[injection.property] = injectable; + } else { + throw new Error('Attempting to inject an unknown injection: `' + injection.fullName + '`'); + } + } + + return hash; + } + + function option(container, fullName, optionName) { + var options = container._options[fullName]; + + if (options && options[optionName] !== undefined) { + return options[optionName]; + } + + var type = fullName.split(':')[0]; + options = container._typeOptions[type]; + + if (options) { + return options[optionName]; + } + } + + function factoryFor(container, fullName) { + var cache = container.factoryCache; + if (cache[fullName]) { + return cache[fullName]; + } + var factory = container.resolve(fullName); + if (factory === undefined) { return; } + + var type = fullName.split(':')[0]; + if (!factory || typeof factory.extend !== 'function' || (!Ember.MODEL_FACTORY_INJECTIONS && type === 'model')) { + // TODO: think about a 'safe' merge style extension + // for now just fallback to create time injection + cache[fullName] = factory; + return factory; + } else { + var injections = injectionsFor(container, fullName); + var factoryInjections = factoryInjectionsFor(container, fullName); + + factoryInjections._toString = container.makeToString(factory, fullName); + + var injectedFactory = factory.extend(injections); + injectedFactory.reopenClass(factoryInjections); + + cache[fullName] = injectedFactory; + + return injectedFactory; + } + } + + function injectionsFor(container, fullName) { + var splitName = fullName.split(':'); + var type = splitName[0]; + var injections = []; + + injections = injections.concat(container.typeInjections[type] || []); + injections = injections.concat(container.injections[fullName] || []); + + injections = buildInjections(container, injections); + injections._debugContainerKey = fullName; + injections.container = container; + + return injections; + } + + function factoryInjectionsFor(container, fullName) { + var splitName = fullName.split(':'); + var type = splitName[0]; + var factoryInjections = []; + + factoryInjections = factoryInjections.concat(container.factoryTypeInjections[type] || []); + factoryInjections = factoryInjections.concat(container.factoryInjections[fullName] || []); + + factoryInjections = buildInjections(container, factoryInjections); + factoryInjections._debugContainerKey = fullName; + + return factoryInjections; + } + + function instantiate(container, fullName) { + var factory = factoryFor(container, fullName); + + if (option(container, fullName, 'instantiate') === false) { + return factory; + } + + if (factory) { + if (typeof factory.create !== 'function') { + throw new Error('Failed to create an instance of \'' + fullName + '\'. ' + + 'Most likely an improperly defined class or an invalid module export.'); + } + + if (typeof factory.extend === 'function') { + // assume the factory was extendable and is already injected + return factory.create(); + } else { + // assume the factory was extendable + // to create time injections + // TODO: support new'ing for instantiation and merge injections for pure JS Functions + return factory.create(injectionsFor(container, fullName)); + } + } + } + + function eachDestroyable(container, callback) { + var cache = container.cache; + var keys = emberKeys(cache); + var key, value; + + for (var i = 0, l = keys.length; i < l; i++) { + key = keys[i]; + value = cache[key]; + + if (option(container, key, 'instantiate') !== false) { + callback(value); + } + } + } + + function resetCache(container) { + eachDestroyable(container, function(value) { + value.destroy(); + }); + + container.cache.dict = dictionary(null); + } + + function addTypeInjection(rules, type, property, fullName) { + var injections = rules[type]; + + if (!injections) { + injections = []; + rules[type] = injections; + } + + injections.push({ + property: property, + fullName: fullName + }); + } + + var VALID_FULL_NAME_REGEXP = /^[^:]+.+:[^:]+$/; + function validateFullName(fullName) { + if (!VALID_FULL_NAME_REGEXP.test(fullName)) { + throw new TypeError('Invalid Fullname, expected: `type:name` got: ' + fullName); + } + return true; + } + + function addInjection(rules, factoryName, property, injectionName) { + var injections = rules[factoryName] = rules[factoryName] || []; + injections.push({ + property: property, + fullName: injectionName + }); + } + + __exports__["default"] = Container; + }); +enifed("ember-application", + ["ember-metal/core","ember-runtime/system/lazy_load","ember-application/system/dag","ember-application/system/resolver","ember-application/system/application","ember-application/ext/controller"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__) { + "use strict"; + var Ember = __dependency1__["default"]; + var runLoadHooks = __dependency2__.runLoadHooks; + + /** + Ember Application + + @module ember + @submodule ember-application + @requires ember-views, ember-routing + */ + + var DAG = __dependency3__["default"]; + var Resolver = __dependency4__.Resolver; + var DefaultResolver = __dependency4__["default"]; + var Application = __dependency5__["default"]; + // side effect of extending ControllerMixin + + Ember.Application = Application; + Ember.DAG = DAG; + Ember.Resolver = Resolver; + Ember.DefaultResolver = DefaultResolver; + + runLoadHooks('Ember.Application', Application); + }); +enifed("ember-application/ext/controller", + ["ember-metal/core","ember-metal/property_get","ember-metal/property_set","ember-metal/error","ember-metal/utils","ember-metal/computed","ember-runtime/mixins/controller","ember-routing/system/controller_for","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __exports__) { + "use strict"; + /** + @module ember + @submodule ember-application + */ + + var Ember = __dependency1__["default"]; + // Ember.assert + var get = __dependency2__.get; + var set = __dependency3__.set; + var EmberError = __dependency4__["default"]; + var inspect = __dependency5__.inspect; + var computed = __dependency6__.computed; + var ControllerMixin = __dependency7__["default"]; + var meta = __dependency5__.meta; + var controllerFor = __dependency8__["default"]; + + function verifyNeedsDependencies(controller, container, needs) { + var dependency, i, l; + var missing = []; + + for (i=0, l=needs.length; i 1 ? 'they' : 'it') + " could not be found"); + } + } + + var defaultControllersComputedProperty = computed(function() { + var controller = this; + + return { + needs: get(controller, 'needs'), + container: get(controller, 'container'), + unknownProperty: function(controllerName) { + var needs = this.needs; + var dependency, i, l; + + for (i=0, l=needs.length; i 0) { + Ember.assert(' `' + inspect(this) + ' specifies `needs`, but does ' + + "not have a container. Please ensure this controller was " + + "instantiated with a container.", + this.container || meta(this, false).descs.controllers !== defaultControllersComputedProperty); + + if (this.container) { + verifyNeedsDependencies(this, this.container, needs); + } + + // if needs then initialize controllers proxy + get(this, 'controllers'); + } + + this._super.apply(this, arguments); + }, + + /** + @method controllerFor + @see {Ember.Route#controllerFor} + @deprecated Use `needs` instead + */ + controllerFor: function(controllerName) { + Ember.deprecate("Controller#controllerFor is deprecated, please use Controller#needs instead"); + return controllerFor(get(this, 'container'), controllerName); + }, + + /** + Stores the instances of other controllers available from within + this controller. Any controller listed by name in the `needs` + property will be accessible by name through this property. + + ```javascript + App.CommentsController = Ember.ArrayController.extend({ + needs: ['post'], + postTitle: function(){ + var currentPost = this.get('controllers.post'); // instance of App.PostController + return currentPost.get('title'); + }.property('controllers.post.title') + }); + ``` + + @see {Ember.ControllerMixin#needs} + @property {Object} controllers + @default null + */ + controllers: defaultControllersComputedProperty + }); + + __exports__["default"] = ControllerMixin; + }); +enifed("ember-application/system/application", + ["ember-metal","ember-metal/property_get","ember-metal/property_set","ember-runtime/system/lazy_load","ember-application/system/dag","ember-runtime/system/namespace","ember-runtime/mixins/deferred","ember-application/system/resolver","ember-metal/platform","ember-metal/run_loop","ember-metal/utils","container/container","ember-runtime/controllers/controller","ember-metal/enumerable_utils","ember-runtime/controllers/object_controller","ember-runtime/controllers/array_controller","ember-handlebars/controls/select","ember-views/system/event_dispatcher","ember-views/system/jquery","ember-routing/system/route","ember-routing/system/router","ember-routing/location/hash_location","ember-routing/location/history_location","ember-routing/location/auto_location","ember-routing/location/none_location","ember-routing/system/cache","ember-metal/core","ember-handlebars-compiler","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __dependency9__, __dependency10__, __dependency11__, __dependency12__, __dependency13__, __dependency14__, __dependency15__, __dependency16__, __dependency17__, __dependency18__, __dependency19__, __dependency20__, __dependency21__, __dependency22__, __dependency23__, __dependency24__, __dependency25__, __dependency26__, __dependency27__, __dependency28__, __exports__) { + "use strict"; + /** + @module ember + @submodule ember-application + */ + + var Ember = __dependency1__["default"]; + // Ember.FEATURES, Ember.deprecate, Ember.assert, Ember.libraries, LOG_VERSION, Namespace, BOOTED + var get = __dependency2__.get; + var set = __dependency3__.set; + var runLoadHooks = __dependency4__.runLoadHooks; + var DAG = __dependency5__["default"]; + var Namespace = __dependency6__["default"]; + var DeferredMixin = __dependency7__["default"]; + var DefaultResolver = __dependency8__["default"]; + var create = __dependency9__.create; + var run = __dependency10__["default"]; + var canInvoke = __dependency11__.canInvoke; + var Container = __dependency12__["default"]; + var Controller = __dependency13__["default"]; + var EnumerableUtils = __dependency14__["default"]; + var ObjectController = __dependency15__["default"]; + var ArrayController = __dependency16__["default"]; + var SelectView = __dependency17__["default"]; + var EventDispatcher = __dependency18__["default"]; + //import ContainerDebugAdapter from "ember-extension-support/container_debug_adapter"; + var jQuery = __dependency19__["default"]; + var Route = __dependency20__["default"]; + var Router = __dependency21__["default"]; + var HashLocation = __dependency22__["default"]; + var HistoryLocation = __dependency23__["default"]; + var AutoLocation = __dependency24__["default"]; + var NoneLocation = __dependency25__["default"]; + var BucketCache = __dependency26__["default"]; + + var K = __dependency27__.K; + var EmberHandlebars = __dependency28__["default"]; + + var ContainerDebugAdapter; + function props(obj) { + var properties = []; + + for (var key in obj) { + properties.push(key); + } + + return properties; + } + + /** + An instance of `Ember.Application` is the starting point for every Ember + application. It helps to instantiate, initialize and coordinate the many + objects that make up your app. + + Each Ember app has one and only one `Ember.Application` object. In fact, the + very first thing you should do in your application is create the instance: + + ```javascript + window.App = Ember.Application.create(); + ``` + + Typically, the application object is the only global variable. All other + classes in your app should be properties on the `Ember.Application` instance, + which highlights its first role: a global namespace. + + For example, if you define a view class, it might look like this: + + ```javascript + App.MyView = Ember.View.extend(); + ``` + + By default, calling `Ember.Application.create()` will automatically initialize + your application by calling the `Ember.Application.initialize()` method. If + you need to delay initialization, you can call your app's `deferReadiness()` + method. When you are ready for your app to be initialized, call its + `advanceReadiness()` method. + + You can define a `ready` method on the `Ember.Application` instance, which + will be run by Ember when the application is initialized. + + Because `Ember.Application` inherits from `Ember.Namespace`, any classes + you create will have useful string representations when calling `toString()`. + See the `Ember.Namespace` documentation for more information. + + While you can think of your `Ember.Application` as a container that holds the + other classes in your application, there are several other responsibilities + going on under-the-hood that you may want to understand. + + ### Event Delegation + + Ember uses a technique called _event delegation_. This allows the framework + to set up a global, shared event listener instead of requiring each view to + do it manually. For example, instead of each view registering its own + `mousedown` listener on its associated element, Ember sets up a `mousedown` + listener on the `body`. + + If a `mousedown` event occurs, Ember will look at the target of the event and + start walking up the DOM node tree, finding corresponding views and invoking + their `mouseDown` method as it goes. + + `Ember.Application` has a number of default events that it listens for, as + well as a mapping from lowercase events to camel-cased view method names. For + example, the `keypress` event causes the `keyPress` method on the view to be + called, the `dblclick` event causes `doubleClick` to be called, and so on. + + If there is a bubbling browser event that Ember does not listen for by + default, you can specify custom events and their corresponding view method + names by setting the application's `customEvents` property: + + ```javascript + App = Ember.Application.create({ + customEvents: { + // add support for the paste event + paste: "paste" + } + }); + ``` + + By default, the application sets up these event listeners on the document + body. However, in cases where you are embedding an Ember application inside + an existing page, you may want it to set up the listeners on an element + inside the body. + + For example, if only events inside a DOM element with the ID of `ember-app` + should be delegated, set your application's `rootElement` property: + + ```javascript + window.App = Ember.Application.create({ + rootElement: '#ember-app' + }); + ``` + + The `rootElement` can be either a DOM element or a jQuery-compatible selector + string. Note that *views appended to the DOM outside the root element will + not receive events.* If you specify a custom root element, make sure you only + append views inside it! + + To learn more about the advantages of event delegation and the Ember view + layer, and a list of the event listeners that are setup by default, visit the + [Ember View Layer guide](http://emberjs.com/guides/understanding-ember/the-view-layer/#toc_event-delegation). + + ### Initializers + + Libraries on top of Ember can add initializers, like so: + + ```javascript + Ember.Application.initializer({ + name: 'api-adapter', + + initialize: function(container, application) { + application.register('api-adapter:main', ApiAdapter); + } + }); + ``` + + Initializers provide an opportunity to access the container, which + organizes the different components of an Ember application. Additionally + they provide a chance to access the instantiated application. Beyond + being used for libraries, initializers are also a great way to organize + dependency injection or setup in your own application. + + ### Routing + + In addition to creating your application's router, `Ember.Application` is + also responsible for telling the router when to start routing. Transitions + between routes can be logged with the `LOG_TRANSITIONS` flag, and more + detailed intra-transition logging can be logged with + the `LOG_TRANSITIONS_INTERNAL` flag: + + ```javascript + window.App = Ember.Application.create({ + LOG_TRANSITIONS: true, // basic logging of successful transitions + LOG_TRANSITIONS_INTERNAL: true // detailed logging of all routing steps + }); + ``` + + By default, the router will begin trying to translate the current URL into + application state once the browser emits the `DOMContentReady` event. If you + need to defer routing, you can call the application's `deferReadiness()` + method. Once routing can begin, call the `advanceReadiness()` method. + + If there is any setup required before routing begins, you can implement a + `ready()` method on your app that will be invoked immediately before routing + begins. + ``` + + @class Application + @namespace Ember + @extends Ember.Namespace + */ + + var Application = Namespace.extend(DeferredMixin, { + _suppressDeferredDeprecation: true, + + /** + The root DOM element of the Application. This can be specified as an + element or a + [jQuery-compatible selector string](http://api.jquery.com/category/selectors/). + + This is the element that will be passed to the Application's, + `eventDispatcher`, which sets up the listeners for event delegation. Every + view in your application should be a child of the element you specify here. + + @property rootElement + @type DOMElement + @default 'body' + */ + rootElement: 'body', + + /** + The `Ember.EventDispatcher` responsible for delegating events to this + application's views. + + The event dispatcher is created by the application at initialization time + and sets up event listeners on the DOM element described by the + application's `rootElement` property. + + See the documentation for `Ember.EventDispatcher` for more information. + + @property eventDispatcher + @type Ember.EventDispatcher + @default null + */ + eventDispatcher: null, + + /** + The DOM events for which the event dispatcher should listen. + + By default, the application's `Ember.EventDispatcher` listens + for a set of standard DOM events, such as `mousedown` and + `keyup`, and delegates them to your application's `Ember.View` + instances. + + If you would like additional bubbling events to be delegated to your + views, set your `Ember.Application`'s `customEvents` property + to a hash containing the DOM event name as the key and the + corresponding view method name as the value. For example: + + ```javascript + App = Ember.Application.create({ + customEvents: { + // add support for the paste event + paste: "paste" + } + }); + ``` + + @property customEvents + @type Object + @default null + */ + customEvents: null, + + // Start off the number of deferrals at 1. This will be + // decremented by the Application's own `initialize` method. + _readinessDeferrals: 1, + + init: function() { + if (!this.$) { this.$ = jQuery; } + this.__container__ = this.buildContainer(); + + this.Router = this.defaultRouter(); + + this._super(); + + this.scheduleInitialize(); + + Ember.libraries.registerCoreLibrary('Handlebars' + (EmberHandlebars.compile ? '' : '-runtime'), EmberHandlebars.VERSION); + Ember.libraries.registerCoreLibrary('jQuery', jQuery().jquery); + + if ( Ember.LOG_VERSION ) { + Ember.LOG_VERSION = false; // we only need to see this once per Application#init + + var nameLengths = EnumerableUtils.map(Ember.libraries, function(item) { + return get(item, "name.length"); + }); + + var maxNameLength = Math.max.apply(this, nameLengths); + + Ember.debug('-------------------------------'); + Ember.libraries.each(function(name, version) { + var spaces = new Array(maxNameLength - name.length + 1).join(" "); + Ember.debug([name, spaces, ' : ', version].join("")); + }); + Ember.debug('-------------------------------'); + } + }, + + /** + Build the container for the current application. + + Also register a default application view in case the application + itself does not. + + @private + @method buildContainer + @return {Ember.Container} the configured container + */ + buildContainer: function() { + var container = this.__container__ = Application.buildContainer(this); + + return container; + }, + + /** + If the application has not opted out of routing and has not explicitly + defined a router, supply a default router for the application author + to configure. + + This allows application developers to do: + + ```javascript + var App = Ember.Application.create(); + + App.Router.map(function() { + this.resource('posts'); + }); + ``` + + @private + @method defaultRouter + @return {Ember.Router} the default router + */ + + defaultRouter: function() { + if (this.Router === false) { return; } + var container = this.__container__; + + if (this.Router) { + container.unregister('router:main'); + container.register('router:main', this.Router); + } + + return container.lookupFactory('router:main'); + }, + + /** + Automatically initialize the application once the DOM has + become ready. + + The initialization itself is scheduled on the actions queue + which ensures that application loading finishes before + booting. + + If you are asynchronously loading code, you should call + `deferReadiness()` to defer booting, and then call + `advanceReadiness()` once all of your code has finished + loading. + + @private + @method scheduleInitialize + */ + scheduleInitialize: function() { + var self = this; + + if (!this.$ || this.$.isReady) { + run.schedule('actions', self, '_initialize'); + } else { + this.$().ready(function runInitialize() { + run(self, '_initialize'); + }); + } + }, + + /** + Use this to defer readiness until some condition is true. + + Example: + + ```javascript + App = Ember.Application.create(); + App.deferReadiness(); + + jQuery.getJSON("/auth-token", function(token) { + App.token = token; + App.advanceReadiness(); + }); + ``` + + This allows you to perform asynchronous setup logic and defer + booting your application until the setup has finished. + + However, if the setup requires a loading UI, it might be better + to use the router for this purpose. + + @method deferReadiness + */ + deferReadiness: function() { + Ember.assert("You must call deferReadiness on an instance of Ember.Application", this instanceof Application); + Ember.assert("You cannot defer readiness since the `ready()` hook has already been called.", this._readinessDeferrals > 0); + this._readinessDeferrals++; + }, + + /** + Call `advanceReadiness` after any asynchronous setup logic has completed. + Each call to `deferReadiness` must be matched by a call to `advanceReadiness` + or the application will never become ready and routing will not begin. + + @method advanceReadiness + @see {Ember.Application#deferReadiness} + */ + advanceReadiness: function() { + Ember.assert("You must call advanceReadiness on an instance of Ember.Application", this instanceof Application); + this._readinessDeferrals--; + + if (this._readinessDeferrals === 0) { + run.once(this, this.didBecomeReady); + } + }, + + /** + Registers a factory that can be used for dependency injection (with + `App.inject`) or for service lookup. Each factory is registered with + a full name including two parts: `type:name`. + + A simple example: + + ```javascript + var App = Ember.Application.create(); + App.Orange = Ember.Object.extend(); + App.register('fruit:favorite', App.Orange); + ``` + + Ember will resolve factories from the `App` namespace automatically. + For example `App.CarsController` will be discovered and returned if + an application requests `controller:cars`. + + An example of registering a controller with a non-standard name: + + ```javascript + var App = Ember.Application.create(), + Session = Ember.Controller.extend(); + + App.register('controller:session', Session); + + // The Session controller can now be treated like a normal controller, + // despite its non-standard name. + App.ApplicationController = Ember.Controller.extend({ + needs: ['session'] + }); + ``` + + Registered factories are **instantiated** by having `create` + called on them. Additionally they are **singletons**, each time + they are looked up they return the same instance. + + Some examples modifying that default behavior: + + ```javascript + var App = Ember.Application.create(); + + App.Person = Ember.Object.extend(); + App.Orange = Ember.Object.extend(); + App.Email = Ember.Object.extend(); + App.session = Ember.Object.create(); + + App.register('model:user', App.Person, {singleton: false }); + App.register('fruit:favorite', App.Orange); + App.register('communication:main', App.Email, {singleton: false}); + App.register('session', App.session, {instantiate: false}); + ``` + + @method register + @param fullName {String} type:name (e.g., 'model:user') + @param factory {Function} (e.g., App.Person) + @param options {Object} (optional) disable instantiation or singleton usage + **/ + register: function() { + var container = this.__container__; + container.register.apply(container, arguments); + }, + + /** + Define a dependency injection onto a specific factory or all factories + of a type. + + When Ember instantiates a controller, view, or other framework component + it can attach a dependency to that component. This is often used to + provide services to a set of framework components. + + An example of providing a session object to all controllers: + + ```javascript + var App = Ember.Application.create(), + Session = Ember.Object.extend({ isAuthenticated: false }); + + // A factory must be registered before it can be injected + App.register('session:main', Session); + + // Inject 'session:main' onto all factories of the type 'controller' + // with the name 'session' + App.inject('controller', 'session', 'session:main'); + + App.IndexController = Ember.Controller.extend({ + isLoggedIn: Ember.computed.alias('session.isAuthenticated') + }); + ``` + + Injections can also be performed on specific factories. + + ```javascript + App.inject(, , ) + App.inject('route', 'source', 'source:main') + App.inject('route:application', 'email', 'model:email') + ``` + + It is important to note that injections can only be performed on + classes that are instantiated by Ember itself. Instantiating a class + directly (via `create` or `new`) bypasses the dependency injection + system. + + Ember-Data instantiates its models in a unique manner, and consequently + injections onto models (or all models) will not work as expected. Injections + on models can be enabled by setting `Ember.MODEL_FACTORY_INJECTIONS` + to `true`. + + @method inject + @param factoryNameOrType {String} + @param property {String} + @param injectionName {String} + **/ + inject: function() { + var container = this.__container__; + container.injection.apply(container, arguments); + }, + + /** + Calling initialize manually is not supported. + + Please see Ember.Application#advanceReadiness and + Ember.Application#deferReadiness. + + @private + @deprecated + @method initialize + **/ + initialize: function() { + Ember.deprecate('Calling initialize manually is not supported. Please see Ember.Application#advanceReadiness and Ember.Application#deferReadiness'); + }, + + /** + Initialize the application. This happens automatically. + + Run any initializers and run the application load hook. These hooks may + choose to defer readiness. For example, an authentication hook might want + to defer readiness until the auth token has been retrieved. + + @private + @method _initialize + */ + _initialize: function() { + if (this.isDestroyed) { return; } + + // At this point, the App.Router must already be assigned + if (this.Router) { + var container = this.__container__; + container.unregister('router:main'); + container.register('router:main', this.Router); + } + + this.runInitializers(); + runLoadHooks('application', this); + + // At this point, any initializers or load hooks that would have wanted + // to defer readiness have fired. In general, advancing readiness here + // will proceed to didBecomeReady. + this.advanceReadiness(); + + return this; + }, + + /** + Reset the application. This is typically used only in tests. It cleans up + the application in the following order: + + 1. Deactivate existing routes + 2. Destroy all objects in the container + 3. Create a new application container + 4. Re-route to the existing url + + Typical Example: + + ```javascript + + var App; + + run(function() { + App = Ember.Application.create(); + }); + + module("acceptance test", { + setup: function() { + App.reset(); + } + }); + + test("first test", function() { + // App is freshly reset + }); + + test("first test", function() { + // App is again freshly reset + }); + ``` + + Advanced Example: + + Occasionally you may want to prevent the app from initializing during + setup. This could enable extra configuration, or enable asserting prior + to the app becoming ready. + + ```javascript + + var App; + + run(function() { + App = Ember.Application.create(); + }); + + module("acceptance test", { + setup: function() { + run(function() { + App.reset(); + App.deferReadiness(); + }); + } + }); + + test("first test", function() { + ok(true, 'something before app is initialized'); + + run(function() { + App.advanceReadiness(); + }); + ok(true, 'something after app is initialized'); + }); + ``` + + @method reset + **/ + reset: function() { + this._readinessDeferrals = 1; + + function handleReset() { + var router = this.__container__.lookup('router:main'); + router.reset(); + + run(this.__container__, 'destroy'); + + this.buildContainer(); + + run.schedule('actions', this, function() { + this._initialize(); + }); + } + + run.join(this, handleReset); + }, + + /** + @private + @method runInitializers + */ + runInitializers: function() { + var initializersByName = get(this.constructor, 'initializers'); + var initializers = props(initializersByName); + var container = this.__container__; + var graph = new DAG(); + var namespace = this; + var name, initializer; + + for (var i = 0; i < initializers.length; i++) { + initializer = initializersByName[initializers[i]]; + graph.addEdges(initializer.name, initializer.initialize, initializer.before, initializer.after); + } + + graph.topsort(function (vertex) { + var initializer = vertex.value; + Ember.assert("No application initializer named '" + vertex.name + "'", initializer); + initializer(container, namespace); + }); + }, + + /** + @private + @method didBecomeReady + */ + didBecomeReady: function() { + this.setupEventDispatcher(); + this.ready(); // user hook + this.startRouting(); + + if (!Ember.testing) { + // Eagerly name all classes that are already loaded + Ember.Namespace.processAll(); + Ember.BOOTED = true; + } + + this.resolve(this); + }, + + /** + Setup up the event dispatcher to receive events on the + application's `rootElement` with any registered + `customEvents`. + + @private + @method setupEventDispatcher + */ + setupEventDispatcher: function() { + var customEvents = get(this, 'customEvents'); + var rootElement = get(this, 'rootElement'); + var dispatcher = this.__container__.lookup('event_dispatcher:main'); + + set(this, 'eventDispatcher', dispatcher); + dispatcher.setup(customEvents, rootElement); + }, + + /** + If the application has a router, use it to route to the current URL, and + trigger a new call to `route` whenever the URL changes. + + @private + @method startRouting + @property router {Ember.Router} + */ + startRouting: function() { + var router = this.__container__.lookup('router:main'); + if (!router) { return; } + + router.startRouting(); + }, + + handleURL: function(url) { + var router = this.__container__.lookup('router:main'); + + router.handleURL(url); + }, + + /** + Called when the Application has become ready. + The call will be delayed until the DOM has become ready. + + @event ready + */ + ready: K, + + /** + @deprecated Use 'Resolver' instead + Set this to provide an alternate class to `Ember.DefaultResolver` + + + @property resolver + */ + resolver: null, + + /** + Set this to provide an alternate class to `Ember.DefaultResolver` + + @property resolver + */ + Resolver: null, + + willDestroy: function() { + Ember.BOOTED = false; + // Ensure deactivation of routes before objects are destroyed + this.__container__.lookup('router:main').reset(); + + this.__container__.destroy(); + }, + + initializer: function(options) { + this.constructor.initializer(options); + }, + + /** + @method then + @private + @deprecated + */ + then: function() { + Ember.deprecate('Do not use `.then` on an instance of Ember.Application. Please use the `.ready` hook instead.'); + + this._super.apply(this, arguments); + } + }); + + Application.reopenClass({ + initializers: create(null), + + /** + Initializer receives an object which has the following attributes: + `name`, `before`, `after`, `initialize`. The only required attribute is + `initialize, all others are optional. + + * `name` allows you to specify under which name the initializer is registered. + This must be a unique name, as trying to register two initializers with the + same name will result in an error. + + ```javascript + Ember.Application.initializer({ + name: 'namedInitializer', + initialize: function(container, application) { + Ember.debug("Running namedInitializer!"); + } + }); + ``` + + * `before` and `after` are used to ensure that this initializer is ran prior + or after the one identified by the value. This value can be a single string + or an array of strings, referencing the `name` of other initializers. + + An example of ordering initializers, we create an initializer named `first`: + + ```javascript + Ember.Application.initializer({ + name: 'first', + initialize: function(container, application) { + Ember.debug("First initializer!"); + } + }); + + // DEBUG: First initializer! + ``` + + We add another initializer named `second`, specifying that it should run + after the initializer named `first`: + + ```javascript + Ember.Application.initializer({ + name: 'second', + after: 'first', + + initialize: function(container, application) { + Ember.debug("Second initializer!"); + } + }); + + // DEBUG: First initializer! + // DEBUG: Second initializer! + ``` + + Afterwards we add a further initializer named `pre`, this time specifying + that it should run before the initializer named `first`: + + ```javascript + Ember.Application.initializer({ + name: 'pre', + before: 'first', + + initialize: function(container, application) { + Ember.debug("Pre initializer!"); + } + }); + + // DEBUG: Pre initializer! + // DEBUG: First initializer! + // DEBUG: Second initializer! + ``` + + Finally we add an initializer named `post`, specifying it should run after + both the `first` and the `second` initializers: + + ```javascript + Ember.Application.initializer({ + name: 'post', + after: ['first', 'second'], + + initialize: function(container, application) { + Ember.debug("Post initializer!"); + } + }); + + // DEBUG: Pre initializer! + // DEBUG: First initializer! + // DEBUG: Second initializer! + // DEBUG: Post initializer! + ``` + + * `initialize` is a callback function that receives two arguments, `container` + and `application` on which you can operate. + + Example of using `container` to preload data into the store: + + ```javascript + Ember.Application.initializer({ + name: "preload-data", + + initialize: function(container, application) { + var store = container.lookup('store:main'); + store.pushPayload(preloadedData); + } + }); + ``` + + Example of using `application` to register an adapter: + + ```javascript + Ember.Application.initializer({ + name: 'api-adapter', + + initialize: function(container, application) { + application.register('api-adapter:main', ApiAdapter); + } + }); + ``` + + @method initializer + @param initializer {Object} + */ + initializer: function(initializer) { + // If this is the first initializer being added to a subclass, we are going to reopen the class + // to make sure we have a new `initializers` object, which extends from the parent class' using + // prototypal inheritance. Without this, attempting to add initializers to the subclass would + // pollute the parent class as well as other subclasses. + if (this.superclass.initializers !== undefined && this.superclass.initializers === this.initializers) { + this.reopenClass({ + initializers: create(this.initializers) + }); + } + + Ember.assert("The initializer '" + initializer.name + "' has already been registered", !this.initializers[initializer.name]); + Ember.assert("An initializer cannot be registered without an initialize function", canInvoke(initializer, 'initialize')); + + this.initializers[initializer.name] = initializer; + }, + + /** + This creates a container with the default Ember naming conventions. + + It also configures the container: + + * registered views are created every time they are looked up (they are + not singletons) + * registered templates are not factories; the registered value is + returned directly. + * the router receives the application as its `namespace` property + * all controllers receive the router as their `target` and `controllers` + properties + * all controllers receive the application as their `namespace` property + * the application view receives the application controller as its + `controller` property + * the application view receives the application template as its + `defaultTemplate` property + + @private + @method buildContainer + @static + @param {Ember.Application} namespace the application to build the + container for. + @return {Ember.Container} the built container + */ + buildContainer: function(namespace) { + var container = new Container(); + + container.set = set; + container.resolver = resolverFor(namespace); + container.normalizeFullName = container.resolver.normalize; + container.describe = container.resolver.describe; + container.makeToString = container.resolver.makeToString; + + container.optionsForType('component', { singleton: false }); + container.optionsForType('view', { singleton: false }); + container.optionsForType('template', { instantiate: false }); + container.optionsForType('helper', { instantiate: false }); + + container.register('application:main', namespace, { instantiate: false }); + + container.register('controller:basic', Controller, { instantiate: false }); + container.register('controller:object', ObjectController, { instantiate: false }); + container.register('controller:array', ArrayController, { instantiate: false }); + + container.register('view:select', SelectView); + + container.register('route:basic', Route, { instantiate: false }); + container.register('event_dispatcher:main', EventDispatcher); + + container.register('router:main', Router); + container.injection('router:main', 'namespace', 'application:main'); + + container.register('location:auto', AutoLocation); + container.register('location:hash', HashLocation); + container.register('location:history', HistoryLocation); + container.register('location:none', NoneLocation); + + container.injection('controller', 'target', 'router:main'); + container.injection('controller', 'namespace', 'application:main'); + + container.register('-bucket-cache:main', BucketCache); + container.injection('router', '_bucketCache', '-bucket-cache:main'); + container.injection('route', '_bucketCache', '-bucket-cache:main'); + container.injection('controller', '_bucketCache', '-bucket-cache:main'); + + container.injection('route', 'router', 'router:main'); + container.injection('location', 'rootURL', '-location-setting:root-url'); + + // DEBUGGING + container.register('resolver-for-debugging:main', container.resolver.__resolver__, { instantiate: false }); + container.injection('container-debug-adapter:main', 'resolver', 'resolver-for-debugging:main'); + container.injection('data-adapter:main', 'containerDebugAdapter', 'container-debug-adapter:main'); + // Custom resolver authors may want to register their own ContainerDebugAdapter with this key + + // ES6TODO: resolve this via import once ember-application package is ES6'ed + if (!ContainerDebugAdapter) { ContainerDebugAdapter = requireModule('ember-extension-support/container_debug_adapter')['default']; } + container.register('container-debug-adapter:main', ContainerDebugAdapter); + + return container; + } + }); + + /** + This function defines the default lookup rules for container lookups: + + * templates are looked up on `Ember.TEMPLATES` + * other names are looked up on the application after classifying the name. + For example, `controller:post` looks up `App.PostController` by default. + * if the default lookup fails, look for registered classes on the container + + This allows the application to register default injections in the container + that could be overridden by the normal naming convention. + + @private + @method resolverFor + @param {Ember.Namespace} namespace the namespace to look for classes + @return {*} the resolved value for a given lookup + */ + function resolverFor(namespace) { + if (namespace.get('resolver')) { + Ember.deprecate('Application.resolver is deprecated in favor of Application.Resolver', false); + } + + var ResolverClass = namespace.get('resolver') || namespace.get('Resolver') || DefaultResolver; + var resolver = ResolverClass.create({ + namespace: namespace + }); + + function resolve(fullName) { + return resolver.resolve(fullName); + } + + resolve.describe = function(fullName) { + return resolver.lookupDescription(fullName); + }; + + resolve.makeToString = function(factory, fullName) { + return resolver.makeToString(factory, fullName); + }; + + resolve.normalize = function(fullName) { + if (resolver.normalize) { + return resolver.normalize(fullName); + } else { + Ember.deprecate('The Resolver should now provide a \'normalize\' function', false); + return fullName; + } + }; + + resolve.__resolver__ = resolver; + + return resolve; + } + + __exports__["default"] = Application; + }); +enifed("ember-application/system/dag", + ["ember-metal/error","exports"], + function(__dependency1__, __exports__) { + "use strict"; + var EmberError = __dependency1__["default"]; + + function visit(vertex, fn, visited, path) { + var name = vertex.name; + var vertices = vertex.incoming; + var names = vertex.incomingNames; + var len = names.length; + var i; + + if (!visited) { + visited = {}; + } + if (!path) { + path = []; + } + if (visited.hasOwnProperty(name)) { + return; + } + path.push(name); + visited[name] = true; + for (i = 0; i < len; i++) { + visit(vertices[names[i]], fn, visited, path); + } + fn(vertex, path); + path.pop(); + } + + + /** + * DAG stands for Directed acyclic graph. + * + * It is used to build a graph of dependencies checking that there isn't circular + * dependencies. p.e Registering initializers with a certain precedence order. + * + * @class DAG + * @constructor + */ + function DAG() { + this.names = []; + this.vertices = Object.create(null); + } + + /** + * DAG Vertex + * + * @class Vertex + * @constructor + */ + + function Vertex(name) { + this.name = name; + this.incoming = {}; + this.incomingNames = []; + this.hasOutgoing = false; + this.value = null; + } + + /** + * Adds a vertex entry to the graph unless it is already added. + * + * @private + * @method add + * @param {String} name The name of the vertex to add + */ + DAG.prototype.add = function(name) { + if (!name) { + throw new Error("Can't add Vertex without name"); + } + if (this.vertices[name] !== undefined) { + return this.vertices[name]; + } + var vertex = new Vertex(name); + this.vertices[name] = vertex; + this.names.push(name); + return vertex; + }; + + /** + * Adds a vertex to the graph and sets its value. + * + * @private + * @method map + * @param {String} name The name of the vertex. + * @param value The value to put in the vertex. + */ + DAG.prototype.map = function(name, value) { + this.add(name).value = value; + }; + + /** + * Connects the vertices with the given names, adding them to the graph if + * necessary, only if this does not produce is any circular dependency. + * + * @private + * @method addEdge + * @param {String} fromName The name the vertex where the edge starts. + * @param {String} toName The name the vertex where the edge ends. + */ + DAG.prototype.addEdge = function(fromName, toName) { + if (!fromName || !toName || fromName === toName) { + return; + } + var from = this.add(fromName); + var to = this.add(toName); + if (to.incoming.hasOwnProperty(fromName)) { + return; + } + function checkCycle(vertex, path) { + if (vertex.name === toName) { + throw new EmberError("cycle detected: " + toName + " <- " + path.join(" <- ")); + } + } + visit(from, checkCycle); + from.hasOutgoing = true; + to.incoming[fromName] = from; + to.incomingNames.push(fromName); + }; + + /** + * Visits all the vertex of the graph calling the given function with each one, + * ensuring that the vertices are visited respecting their precedence. + * + * @method topsort + * @param {Function} fn The function to be invoked on each vertex. + */ + DAG.prototype.topsort = function(fn) { + var visited = {}; + var vertices = this.vertices; + var names = this.names; + var len = names.length; + var i, vertex; + + for (i = 0; i < len; i++) { + vertex = vertices[names[i]]; + if (!vertex.hasOutgoing) { + visit(vertex, fn, visited); + } + } + }; + + /** + * Adds a vertex with the given name and value to the graph and joins it with the + * vertices referenced in _before_ and _after_. If there isn't vertices with those + * names, they are added too. + * + * If either _before_ or _after_ are falsy/empty, the added vertex will not have + * an incoming/outgoing edge. + * + * @method addEdges + * @param {String} name The name of the vertex to be added. + * @param value The value of that vertex. + * @param before An string or array of strings with the names of the vertices before + * which this vertex must be visited. + * @param after An string or array of strings with the names of the vertex after + * which this vertex must be visited. + * + */ + DAG.prototype.addEdges = function(name, value, before, after) { + var i; + this.map(name, value); + if (before) { + if (typeof before === 'string') { + this.addEdge(name, before); + } else { + for (i = 0; i < before.length; i++) { + this.addEdge(name, before[i]); + } + } + } + if (after) { + if (typeof after === 'string') { + this.addEdge(after, name); + } else { + for (i = 0; i < after.length; i++) { + this.addEdge(after[i], name); + } + } + } + }; + + __exports__["default"] = DAG; + }); +enifed("ember-application/system/resolver", + ["ember-metal/core","ember-metal/property_get","ember-metal/logger","ember-runtime/system/string","ember-runtime/system/object","ember-runtime/system/namespace","ember-handlebars","ember-metal/dictionary","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __exports__) { + "use strict"; + /** + @module ember + @submodule ember-application + */ + + var Ember = __dependency1__["default"]; + // Ember.TEMPLATES, Ember.assert + var get = __dependency2__.get; + var Logger = __dependency3__["default"]; + var classify = __dependency4__.classify; + var capitalize = __dependency4__.capitalize; + var decamelize = __dependency4__.decamelize; + var EmberObject = __dependency5__["default"]; + var Namespace = __dependency6__["default"]; + var EmberHandlebars = __dependency7__["default"]; + + var Resolver = EmberObject.extend({ + /** + This will be set to the Application instance when it is + created. + + @property namespace + */ + namespace: null, + normalize: Ember.required(Function), + resolve: Ember.required(Function), + parseName: Ember.required(Function), + lookupDescription: Ember.required(Function), + makeToString: Ember.required(Function), + resolveOther: Ember.required(Function), + _logLookup: Ember.required(Function) + }); + __exports__.Resolver = Resolver; + /** + The DefaultResolver defines the default lookup rules to resolve + container lookups before consulting the container for registered + items: + + * templates are looked up on `Ember.TEMPLATES` + * other names are looked up on the application after converting + the name. For example, `controller:post` looks up + `App.PostController` by default. + * there are some nuances (see examples below) + + ### How Resolving Works + + The container calls this object's `resolve` method with the + `fullName` argument. + + It first parses the fullName into an object using `parseName`. + + Then it checks for the presence of a type-specific instance + method of the form `resolve[Type]` and calls it if it exists. + For example if it was resolving 'template:post', it would call + the `resolveTemplate` method. + + Its last resort is to call the `resolveOther` method. + + The methods of this object are designed to be easy to override + in a subclass. For example, you could enhance how a template + is resolved like so: + + ```javascript + App = Ember.Application.create({ + Resolver: Ember.DefaultResolver.extend({ + resolveTemplate: function(parsedName) { + var resolvedTemplate = this._super(parsedName); + if (resolvedTemplate) { return resolvedTemplate; } + return Ember.TEMPLATES['not_found']; + } + }) + }); + ``` + + Some examples of how names are resolved: + + ``` + 'template:post' //=> Ember.TEMPLATES['post'] + 'template:posts/byline' //=> Ember.TEMPLATES['posts/byline'] + 'template:posts.byline' //=> Ember.TEMPLATES['posts/byline'] + 'template:blogPost' //=> Ember.TEMPLATES['blogPost'] + // OR + // Ember.TEMPLATES['blog_post'] + 'controller:post' //=> App.PostController + 'controller:posts.index' //=> App.PostsIndexController + 'controller:blog/post' //=> Blog.PostController + 'controller:basic' //=> Ember.Controller + 'route:post' //=> App.PostRoute + 'route:posts.index' //=> App.PostsIndexRoute + 'route:blog/post' //=> Blog.PostRoute + 'route:basic' //=> Ember.Route + 'view:post' //=> App.PostView + 'view:posts.index' //=> App.PostsIndexView + 'view:blog/post' //=> Blog.PostView + 'view:basic' //=> Ember.View + 'foo:post' //=> App.PostFoo + 'model:post' //=> App.Post + ``` + + @class DefaultResolver + @namespace Ember + @extends Ember.Object + */ + var dictionary = __dependency8__["default"]; + + __exports__["default"] = EmberObject.extend({ + /** + This will be set to the Application instance when it is + created. + + @property namespace + */ + namespace: null, + + init: function() { + this._parseNameCache = dictionary(null); + }, + normalize: function(fullName) { + var split = fullName.split(':', 2); + var type = split[0]; + var name = split[1]; + + Ember.assert("Tried to normalize a container name without a colon (:) in it. You probably tried to lookup a name that did not contain a type, a colon, and a name. A proper lookup name would be `view:post`.", split.length === 2); + + if (type !== 'template') { + var result = name; + + if (result.indexOf('.') > -1) { + result = result.replace(/\.(.)/g, function(m) { + return m.charAt(1).toUpperCase(); + }); + } + + if (name.indexOf('_') > -1) { + result = result.replace(/_(.)/g, function(m) { + return m.charAt(1).toUpperCase(); + }); + } + + return type + ':' + result; + } else { + return fullName; + } + }, + + + /** + This method is called via the container's resolver method. + It parses the provided `fullName` and then looks up and + returns the appropriate template or class. + + @method resolve + @param {String} fullName the lookup string + @return {Object} the resolved factory + */ + resolve: function(fullName) { + var parsedName = this.parseName(fullName); + var resolveMethodName = parsedName.resolveMethodName; + var resolved; + + if (!(parsedName.name && parsedName.type)) { + throw new TypeError('Invalid fullName: `' + fullName + '`, must be of the form `type:name` '); + } + + if (this[resolveMethodName]) { + resolved = this[resolveMethodName](parsedName); + } + + if (!resolved) { + resolved = this.resolveOther(parsedName); + } + + if (parsedName.root && parsedName.root.LOG_RESOLVER) { + this._logLookup(resolved, parsedName); + } + + return resolved; + }, + /** + Convert the string name of the form 'type:name' to + a Javascript object with the parsed aspects of the name + broken out. + + @protected + @param {String} fullName the lookup string + @method parseName + */ + + parseName: function(fullName) { + return this._parseNameCache[fullName] || ( + this._parseNameCache[fullName] = this._parseName(fullName) + ); + }, + + _parseName: function(fullName) { + var nameParts = fullName.split(':'); + var type = nameParts[0], fullNameWithoutType = nameParts[1]; + var name = fullNameWithoutType; + var namespace = get(this, 'namespace'); + var root = namespace; + + if (type !== 'template' && name.indexOf('/') !== -1) { + var parts = name.split('/'); + name = parts[parts.length - 1]; + var namespaceName = capitalize(parts.slice(0, -1).join('.')); + root = Namespace.byName(namespaceName); + + Ember.assert('You are looking for a ' + name + ' ' + type + ' in the ' + namespaceName + ' namespace, but the namespace could not be found', root); + } + + return { + fullName: fullName, + type: type, + fullNameWithoutType: fullNameWithoutType, + name: name, + root: root, + resolveMethodName: 'resolve' + classify(type) + }; + }, + + /** + Returns a human-readable description for a fullName. Used by the + Application namespace in assertions to describe the + precise name of the class that Ember is looking for, rather than + container keys. + + @protected + @param {String} fullName the lookup string + @method lookupDescription + */ + lookupDescription: function(fullName) { + var parsedName = this.parseName(fullName); + + if (parsedName.type === 'template') { + return 'template at ' + parsedName.fullNameWithoutType.replace(/\./g, '/'); + } + + var description = parsedName.root + '.' + classify(parsedName.name); + + if (parsedName.type !== 'model') { + description += classify(parsedName.type); + } + + return description; + }, + + makeToString: function(factory, fullName) { + return factory.toString(); + }, + /** + Given a parseName object (output from `parseName`), apply + the conventions expected by `Ember.Router` + + @protected + @param {Object} parsedName a parseName object with the parsed + fullName lookup string + @method useRouterNaming + */ + useRouterNaming: function(parsedName) { + parsedName.name = parsedName.name.replace(/\./g, '_'); + if (parsedName.name === 'basic') { + parsedName.name = ''; + } + }, + /** + Look up the template in Ember.TEMPLATES + + @protected + @param {Object} parsedName a parseName object with the parsed + fullName lookup string + @method resolveTemplate + */ + resolveTemplate: function(parsedName) { + var templateName = parsedName.fullNameWithoutType.replace(/\./g, '/'); + + if (Ember.TEMPLATES[templateName]) { + return Ember.TEMPLATES[templateName]; + } + + templateName = decamelize(templateName); + if (Ember.TEMPLATES[templateName]) { + return Ember.TEMPLATES[templateName]; + } + }, + + /** + Lookup the view using `resolveOther` + + @protected + @param {Object} parsedName a parseName object with the parsed + fullName lookup string + @method resolveView + */ + resolveView: function(parsedName) { + this.useRouterNaming(parsedName); + return this.resolveOther(parsedName); + }, + + /** + Lookup the controller using `resolveOther` + + @protected + @param {Object} parsedName a parseName object with the parsed + fullName lookup string + @method resolveController + */ + resolveController: function(parsedName) { + this.useRouterNaming(parsedName); + return this.resolveOther(parsedName); + }, + /** + Lookup the route using `resolveOther` + + @protected + @param {Object} parsedName a parseName object with the parsed + fullName lookup string + @method resolveRoute + */ + resolveRoute: function(parsedName) { + this.useRouterNaming(parsedName); + return this.resolveOther(parsedName); + }, + + /** + Lookup the model on the Application namespace + + @protected + @param {Object} parsedName a parseName object with the parsed + fullName lookup string + @method resolveModel + */ + resolveModel: function(parsedName) { + var className = classify(parsedName.name); + var factory = get(parsedName.root, className); + + if (factory) { return factory; } + }, + /** + Look up the specified object (from parsedName) on the appropriate + namespace (usually on the Application) + + @protected + @param {Object} parsedName a parseName object with the parsed + fullName lookup string + @method resolveHelper + */ + resolveHelper: function(parsedName) { + return this.resolveOther(parsedName) || EmberHandlebars.helpers[parsedName.fullNameWithoutType]; + }, + /** + Look up the specified object (from parsedName) on the appropriate + namespace (usually on the Application) + + @protected + @param {Object} parsedName a parseName object with the parsed + fullName lookup string + @method resolveOther + */ + resolveOther: function(parsedName) { + var className = classify(parsedName.name) + classify(parsedName.type); + var factory = get(parsedName.root, className); + if (factory) { return factory; } + }, + + /** + @method _logLookup + @param {Boolean} found + @param {Object} parsedName + @private + */ + _logLookup: function(found, parsedName) { + var symbol, padding; + + if (found) { symbol = '[✓]'; } + else { symbol = '[ ]'; } + + if (parsedName.fullName.length > 60) { + padding = '.'; + } else { + padding = new Array(60 - parsedName.fullName.length).join('.'); + } + + Logger.info(symbol, parsedName.fullName, padding, this.lookupDescription(parsedName.fullName)); + } + }); + }); +enifed("ember-debug", ["ember-metal/core","ember-metal/error","ember-metal/logger"], function(__dependency1__, __dependency2__, __dependency3__) { "use strict"; @@ -172,7 +3919,9 @@ define("ember-debug", try { __fail__.fail(); } catch (e) { error = e; } if (Ember.LOG_STACKTRACE_ON_DEPRECATION && error.stack) { - var stack, stackStr = ''; + var stack; + var stackStr = ''; + if (error['arguments']) { // Chrome stack = error.stack.replace(/^\s+at\s+/gm, ''). @@ -239,7 +3988,7 @@ define("ember-debug", @since 1.5.0 */ Ember.runInDebug = function(func) { - func() + func(); }; // Inform the developer about the Ember Inspector if not installed. @@ -264,24 +4013,7262 @@ define("ember-debug", } } }); -})(); +enifed("ember-extension-support", + ["ember-metal/core","ember-extension-support/data_adapter","ember-extension-support/container_debug_adapter"], + function(__dependency1__, __dependency2__, __dependency3__) { + "use strict"; + /** + Ember Extension Support -(function() { -define("ember-metal/array", + @module ember + @submodule ember-extension-support + @requires ember-application + */ + + var Ember = __dependency1__["default"]; + var DataAdapter = __dependency2__["default"]; + var ContainerDebugAdapter = __dependency3__["default"]; + + Ember.DataAdapter = DataAdapter; + Ember.ContainerDebugAdapter = ContainerDebugAdapter; + }); +enifed("ember-extension-support/container_debug_adapter", + ["ember-metal/core","ember-runtime/system/native_array","ember-metal/utils","ember-runtime/system/string","ember-runtime/system/namespace","ember-runtime/system/object","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __exports__) { + "use strict"; + var Ember = __dependency1__["default"]; + var emberA = __dependency2__.A; + var typeOf = __dependency3__.typeOf; + var dasherize = __dependency4__.dasherize; + var classify = __dependency4__.classify; + var Namespace = __dependency5__["default"]; + var EmberObject = __dependency6__["default"]; + + /** + @module ember + @submodule ember-extension-support + */ + + /** + The `ContainerDebugAdapter` helps the container and resolver interface + with tools that debug Ember such as the + [Ember Extension](https://github.com/tildeio/ember-extension) + for Chrome and Firefox. + + This class can be extended by a custom resolver implementer + to override some of the methods with library-specific code. + + The methods likely to be overridden are: + + * `canCatalogEntriesByType` + * `catalogEntriesByType` + + The adapter will need to be registered + in the application's container as `container-debug-adapter:main` + + Example: + + ```javascript + Application.initializer({ + name: "containerDebugAdapter", + + initialize: function(container, application) { + application.register('container-debug-adapter:main', require('app/container-debug-adapter')); + } + }); + ``` + + @class ContainerDebugAdapter + @namespace Ember + @extends EmberObject + @since 1.5.0 + */ + __exports__["default"] = EmberObject.extend({ + /** + The container of the application being debugged. + This property will be injected + on creation. + + @property container + @default null + */ + container: null, + + /** + The resolver instance of the application + being debugged. This property will be injected + on creation. + + @property resolver + @default null + */ + resolver: null, + + /** + Returns true if it is possible to catalog a list of available + classes in the resolver for a given type. + + @method canCatalogEntriesByType + @param {String} type The type. e.g. "model", "controller", "route" + @return {boolean} whether a list is available for this type. + */ + canCatalogEntriesByType: function(type) { + if (type === 'model' || type === 'template') return false; + return true; + }, + + /** + Returns the available classes a given type. + + @method catalogEntriesByType + @param {String} type The type. e.g. "model", "controller", "route" + @return {Array} An array of strings. + */ + catalogEntriesByType: function(type) { + var namespaces = emberA(Namespace.NAMESPACES), types = emberA(), self = this; + var typeSuffixRegex = new RegExp(classify(type) + "$"); + + namespaces.forEach(function(namespace) { + if (namespace !== Ember) { + for (var key in namespace) { + if (!namespace.hasOwnProperty(key)) { continue; } + if (typeSuffixRegex.test(key)) { + var klass = namespace[key]; + if (typeOf(klass) === 'class') { + types.push(dasherize(key.replace(typeSuffixRegex, ''))); + } + } + } + } + }); + return types; + } + }); + }); +enifed("ember-extension-support/data_adapter", + ["ember-metal/core","ember-metal/property_get","ember-metal/run_loop","ember-runtime/system/string","ember-runtime/system/namespace","ember-runtime/system/object","ember-runtime/system/native_array","ember-application/system/application","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __exports__) { + "use strict"; + var Ember = __dependency1__["default"]; + var get = __dependency2__.get; + var run = __dependency3__["default"]; + var dasherize = __dependency4__.dasherize; + var Namespace = __dependency5__["default"]; + var EmberObject = __dependency6__["default"]; + var emberA = __dependency7__.A; + var Application = __dependency8__["default"]; + + /** + @module ember + @submodule ember-extension-support + */ + + /** + The `DataAdapter` helps a data persistence library + interface with tools that debug Ember such + as the [Ember Extension](https://github.com/tildeio/ember-extension) + for Chrome and Firefox. + + This class will be extended by a persistence library + which will override some of the methods with + library-specific code. + + The methods likely to be overridden are: + + * `getFilters` + * `detect` + * `columnsForType` + * `getRecords` + * `getRecordColumnValues` + * `getRecordKeywords` + * `getRecordFilterValues` + * `getRecordColor` + * `observeRecord` + + The adapter will need to be registered + in the application's container as `dataAdapter:main` + + Example: + + ```javascript + Application.initializer({ + name: "data-adapter", + + initialize: function(container, application) { + application.register('data-adapter:main', DS.DataAdapter); + } + }); + ``` + + @class DataAdapter + @namespace Ember + @extends EmberObject + */ + __exports__["default"] = EmberObject.extend({ + init: function() { + this._super(); + this.releaseMethods = emberA(); + }, + + /** + The container of the application being debugged. + This property will be injected + on creation. + + @property container + @default null + @since 1.3.0 + */ + container: null, + + + /** + The container-debug-adapter which is used + to list all models. + + @property containerDebugAdapter + @default undefined + @since 1.5.0 + **/ + containerDebugAdapter: undefined, + + /** + Number of attributes to send + as columns. (Enough to make the record + identifiable). + + @private + @property attributeLimit + @default 3 + @since 1.3.0 + */ + attributeLimit: 3, + + /** + Stores all methods that clear observers. + These methods will be called on destruction. + + @private + @property releaseMethods + @since 1.3.0 + */ + releaseMethods: emberA(), + + /** + Specifies how records can be filtered. + Records returned will need to have a `filterValues` + property with a key for every name in the returned array. + + @public + @method getFilters + @return {Array} List of objects defining filters. + The object should have a `name` and `desc` property. + */ + getFilters: function() { + return emberA(); + }, + + /** + Fetch the model types and observe them for changes. + + @public + @method watchModelTypes + + @param {Function} typesAdded Callback to call to add types. + Takes an array of objects containing wrapped types (returned from `wrapModelType`). + + @param {Function} typesUpdated Callback to call when a type has changed. + Takes an array of objects containing wrapped types. + + @return {Function} Method to call to remove all observers + */ + watchModelTypes: function(typesAdded, typesUpdated) { + var modelTypes = this.getModelTypes(); + var self = this; + var releaseMethods = emberA(); + var typesToSend; + + typesToSend = modelTypes.map(function(type) { + var klass = type.klass; + var wrapped = self.wrapModelType(klass, type.name); + releaseMethods.push(self.observeModelType(klass, typesUpdated)); + return wrapped; + }); + + typesAdded(typesToSend); + + var release = function() { + releaseMethods.forEach(function(fn) { fn(); }); + self.releaseMethods.removeObject(release); + }; + this.releaseMethods.pushObject(release); + return release; + }, + + _nameToClass: function(type) { + if (typeof type === 'string') { + type = this.container.lookupFactory('model:' + type); + } + return type; + }, + + /** + Fetch the records of a given type and observe them for changes. + + @public + @method watchRecords + + @param {Function} recordsAdded Callback to call to add records. + Takes an array of objects containing wrapped records. + The object should have the following properties: + columnValues: {Object} key and value of a table cell + object: {Object} the actual record object + + @param {Function} recordsUpdated Callback to call when a record has changed. + Takes an array of objects containing wrapped records. + + @param {Function} recordsRemoved Callback to call when a record has removed. + Takes the following parameters: + index: the array index where the records were removed + count: the number of records removed + + @return {Function} Method to call to remove all observers + */ + watchRecords: function(type, recordsAdded, recordsUpdated, recordsRemoved) { + var self = this, releaseMethods = emberA(), records = this.getRecords(type), release; + + var recordUpdated = function(updatedRecord) { + recordsUpdated([updatedRecord]); + }; + + var recordsToSend = records.map(function(record) { + releaseMethods.push(self.observeRecord(record, recordUpdated)); + return self.wrapRecord(record); + }); + + + var contentDidChange = function(array, idx, removedCount, addedCount) { + for (var i = idx; i < idx + addedCount; i++) { + var record = array.objectAt(i); + var wrapped = self.wrapRecord(record); + releaseMethods.push(self.observeRecord(record, recordUpdated)); + recordsAdded([wrapped]); + } + + if (removedCount) { + recordsRemoved(idx, removedCount); + } + }; + + var observer = { didChange: contentDidChange, willChange: Ember.K }; + records.addArrayObserver(self, observer); + + release = function() { + releaseMethods.forEach(function(fn) { fn(); }); + records.removeArrayObserver(self, observer); + self.releaseMethods.removeObject(release); + }; + + recordsAdded(recordsToSend); + + this.releaseMethods.pushObject(release); + return release; + }, + + /** + Clear all observers before destruction + @private + @method willDestroy + */ + willDestroy: function() { + this._super(); + this.releaseMethods.forEach(function(fn) { + fn(); + }); + }, + + /** + Detect whether a class is a model. + + Test that against the model class + of your persistence library + + @private + @method detect + @param {Class} klass The class to test + @return boolean Whether the class is a model class or not + */ + detect: function(klass) { + return false; + }, + + /** + Get the columns for a given model type. + + @private + @method columnsForType + @param {Class} type The model type + @return {Array} An array of columns of the following format: + name: {String} name of the column + desc: {String} Humanized description (what would show in a table column name) + */ + columnsForType: function(type) { + return emberA(); + }, + + /** + Adds observers to a model type class. + + @private + @method observeModelType + @param {Class} type The model type class + @param {Function} typesUpdated Called when a type is modified. + @return {Function} The function to call to remove observers + */ + + observeModelType: function(type, typesUpdated) { + var self = this; + var records = this.getRecords(type); + + var onChange = function() { + typesUpdated([self.wrapModelType(type)]); + }; + var observer = { + didChange: function() { + run.scheduleOnce('actions', this, onChange); + }, + willChange: Ember.K + }; + + records.addArrayObserver(this, observer); + + var release = function() { + records.removeArrayObserver(self, observer); + }; + + return release; + }, + + + /** + Wraps a given model type and observes changes to it. + + @private + @method wrapModelType + @param {Class} type A model class + @param {String} Optional name of the class + @return {Object} contains the wrapped type and the function to remove observers + Format: + type: {Object} the wrapped type + The wrapped type has the following format: + name: {String} name of the type + count: {Integer} number of records available + columns: {Columns} array of columns to describe the record + object: {Class} the actual Model type class + release: {Function} The function to remove observers + */ + wrapModelType: function(type, name) { + var records = this.getRecords(type); + var self = this; + var release, typeToSend; + + typeToSend = { + name: name || type.toString(), + count: get(records, 'length'), + columns: this.columnsForType(type), + object: type + }; + + + return typeToSend; + }, + + + /** + Fetches all models defined in the application. + + @private + @method getModelTypes + @return {Array} Array of model types + */ + getModelTypes: function() { + var self = this; + var containerDebugAdapter = this.get('containerDebugAdapter'); + var types; + + if (containerDebugAdapter.canCatalogEntriesByType('model')) { + types = containerDebugAdapter.catalogEntriesByType('model'); + } else { + types = this._getObjectsOnNamespaces(); + } + + // New adapters return strings instead of classes + types = emberA(types).map(function(name) { + return { + klass: self._nameToClass(name), + name: name + }; + }); + types = emberA(types).filter(function(type) { + return self.detect(type.klass); + }); + + return emberA(types); + }, + + /** + Loops over all namespaces and all objects + attached to them + + @private + @method _getObjectsOnNamespaces + @return {Array} Array of model type strings + */ + _getObjectsOnNamespaces: function() { + var namespaces = emberA(Namespace.NAMESPACES); + var types = emberA(); + var self = this; + + namespaces.forEach(function(namespace) { + for (var key in namespace) { + if (!namespace.hasOwnProperty(key)) { continue; } + // Even though we will filter again in `getModelTypes`, + // we should not call `lookupContainer` on non-models + // (especially when `Ember.MODEL_FACTORY_INJECTIONS` is `true`) + if (!self.detect(namespace[key])) { continue; } + var name = dasherize(key); + if (!(namespace instanceof Application) && namespace.toString()) { + name = namespace + '/' + name; + } + types.push(name); + } + }); + return types; + }, + + /** + Fetches all loaded records for a given type. + + @private + @method getRecords + @return {Array} An array of records. + This array will be observed for changes, + so it should update when new records are added/removed. + */ + getRecords: function(type) { + return emberA(); + }, + + /** + Wraps a record and observers changes to it. + + @private + @method wrapRecord + @param {Object} record The record instance. + @return {Object} The wrapped record. Format: + columnValues: {Array} + searchKeywords: {Array} + */ + wrapRecord: function(record) { + var recordToSend = { object: record }; + var columnValues = {}; + var self = this; + + recordToSend.columnValues = this.getRecordColumnValues(record); + recordToSend.searchKeywords = this.getRecordKeywords(record); + recordToSend.filterValues = this.getRecordFilterValues(record); + recordToSend.color = this.getRecordColor(record); + + return recordToSend; + }, + + /** + Gets the values for each column. + + @private + @method getRecordColumnValues + @return {Object} Keys should match column names defined + by the model type. + */ + getRecordColumnValues: function(record) { + return {}; + }, + + /** + Returns keywords to match when searching records. + + @private + @method getRecordKeywords + @return {Array} Relevant keywords for search. + */ + getRecordKeywords: function(record) { + return emberA(); + }, + + /** + Returns the values of filters defined by `getFilters`. + + @private + @method getRecordFilterValues + @param {Object} record The record instance + @return {Object} The filter values + */ + getRecordFilterValues: function(record) { + return {}; + }, + + /** + Each record can have a color that represents its state. + + @private + @method getRecordColor + @param {Object} record The record instance + @return {String} The record's color + Possible options: black, red, blue, green + */ + getRecordColor: function(record) { + return null; + }, + + /** + Observes all relevant properties and re-sends the wrapped record + when a change occurs. + + @private + @method observerRecord + @param {Object} record The record instance + @param {Function} recordUpdated The callback to call when a record is updated. + @return {Function} The function to call to remove all observers. + */ + observeRecord: function(record, recordUpdated) { + return function(){}; + } + }); + }); +enifed("ember-extension-support/initializers", + [], + function() { + "use strict"; + + }); +enifed("ember-handlebars-compiler", + ["ember-metal/core","exports"], + function(__dependency1__, __exports__) { + /* global Handlebars:true */ + + // Remove "use strict"; from transpiled module (in browser builds only) until + // https://bugs.webkit.org/show_bug.cgi?id=138038 is fixed + // + // REMOVE_USE_STRICT: true + + /** + @module ember + @submodule ember-handlebars-compiler + */ + + var Ember = __dependency1__["default"]; + + // ES6Todo: you'll need to import debugger once debugger is es6'd. + if (typeof Ember.assert === 'undefined') { Ember.assert = function(){}; } + if (typeof Ember.FEATURES === 'undefined') { Ember.FEATURES = { isEnabled: function(){} }; } + + var objectCreate = Object.create || function(parent) { + function F() {} + F.prototype = parent; + return new F(); + }; + + // set up for circular references later + var View, Component; + + // ES6Todo: when ember-debug is es6'ed import this. + // var emberAssert = Ember.assert; + var Handlebars = (Ember.imports && Ember.imports.Handlebars) || (this && this.Handlebars); + if (!Handlebars && typeof eriuqer === 'function') { + Handlebars = eriuqer('handlebars'); + } + + Ember.assert("Ember Handlebars requires Handlebars version 1.0 or 1.1. Include " + + "a SCRIPT tag in the HTML HEAD linking to the Handlebars file " + + "before you link to Ember.", Handlebars); + + Ember.assert("Ember Handlebars requires Handlebars version 1.0 or 1.1, " + + "COMPILER_REVISION expected: 4, got: " + Handlebars.COMPILER_REVISION + + " - Please note: Builds of master may have other COMPILER_REVISION values.", + Handlebars.COMPILER_REVISION === 4); + + /** + Prepares the Handlebars templating library for use inside Ember's view + system. + + The `Ember.Handlebars` object is the standard Handlebars library, extended to + use Ember's `get()` method instead of direct property access, which allows + computed properties to be used inside templates. + + To create an `Ember.Handlebars` template, call `Ember.Handlebars.compile()`. + This will return a function that can be used by `Ember.View` for rendering. + + @class Handlebars + @namespace Ember + */ + var EmberHandlebars = Ember.Handlebars = objectCreate(Handlebars); + + /** + Register a bound helper or custom view helper. + + ## Simple bound helper example + + ```javascript + Ember.Handlebars.helper('capitalize', function(value) { + return value.toUpperCase(); + }); + ``` + + The above bound helper can be used inside of templates as follows: + + ```handlebars + {{capitalize name}} + ``` + + In this case, when the `name` property of the template's context changes, + the rendered value of the helper will update to reflect this change. + + For more examples of bound helpers, see documentation for + `Ember.Handlebars.registerBoundHelper`. + + ## Custom view helper example + + Assuming a view subclass named `App.CalendarView` were defined, a helper + for rendering instances of this view could be registered as follows: + + ```javascript + Ember.Handlebars.helper('calendar', App.CalendarView): + ``` + + The above bound helper can be used inside of templates as follows: + + ```handlebars + {{calendar}} + ``` + + Which is functionally equivalent to: + + ```handlebars + {{view 'calendar'}} + ``` + + Options in the helper will be passed to the view in exactly the same + manner as with the `view` helper. + + @method helper + @for Ember.Handlebars + @param {String} name + @param {Function|Ember.View} function or view class constructor + @param {String} dependentKeys* + */ + EmberHandlebars.helper = function(name, value) { + if (!View) { View = requireModule('ember-views/views/view')['default']; } // ES6TODO: stupid circular dep + if (!Component) { Component = requireModule('ember-views/views/component')['default']; } // ES6TODO: stupid circular dep + + Ember.assert("You tried to register a component named '" + name + "', but component names must include a '-'", !Component.detect(value) || name.match(/-/)); + + if (View.detect(value)) { + EmberHandlebars.registerHelper(name, EmberHandlebars.makeViewHelper(value)); + } else { + EmberHandlebars.registerBoundHelper.apply(null, arguments); + } + }; + + /** + Returns a helper function that renders the provided ViewClass. + + Used internally by Ember.Handlebars.helper and other methods + involving helper/component registration. + + @private + @method makeViewHelper + @for Ember.Handlebars + @param {Function} ViewClass view class constructor + @since 1.2.0 + */ + EmberHandlebars.makeViewHelper = function(ViewClass) { + return function(options) { + Ember.assert("You can only pass attributes (such as name=value) not bare values to a helper for a View found in '" + ViewClass.toString() + "'", arguments.length < 2); + return EmberHandlebars.helpers.view.call(this, ViewClass, options); + }; + }; + + /** + @class helpers + @namespace Ember.Handlebars + */ + EmberHandlebars.helpers = objectCreate(Handlebars.helpers); + + /** + Override the the opcode compiler and JavaScript compiler for Handlebars. + + @class Compiler + @namespace Ember.Handlebars + @private + @constructor + */ + EmberHandlebars.Compiler = function() {}; + + // Handlebars.Compiler doesn't exist in runtime-only + if (Handlebars.Compiler) { + EmberHandlebars.Compiler.prototype = objectCreate(Handlebars.Compiler.prototype); + } + + EmberHandlebars.Compiler.prototype.compiler = EmberHandlebars.Compiler; + + /** + @class JavaScriptCompiler + @namespace Ember.Handlebars + @private + @constructor + */ + EmberHandlebars.JavaScriptCompiler = function() {}; + + // Handlebars.JavaScriptCompiler doesn't exist in runtime-only + if (Handlebars.JavaScriptCompiler) { + EmberHandlebars.JavaScriptCompiler.prototype = objectCreate(Handlebars.JavaScriptCompiler.prototype); + EmberHandlebars.JavaScriptCompiler.prototype.compiler = EmberHandlebars.JavaScriptCompiler; + } + + + EmberHandlebars.JavaScriptCompiler.prototype.namespace = "Ember.Handlebars"; + + EmberHandlebars.JavaScriptCompiler.prototype.initializeBuffer = function() { + return "''"; + }; + + /** + Override the default buffer for Ember Handlebars. By default, Handlebars + creates an empty String at the beginning of each invocation and appends to + it. Ember's Handlebars overrides this to append to a single shared buffer. + + @private + @method appendToBuffer + @param string {String} + */ + EmberHandlebars.JavaScriptCompiler.prototype.appendToBuffer = function(string) { + return "data.buffer.push("+string+");"; + }; + + // Hacks ahead: + // Handlebars presently has a bug where the `blockHelperMissing` hook + // doesn't get passed the name of the missing helper name, but rather + // gets passed the value of that missing helper evaluated on the current + // context, which is most likely `undefined` and totally useless. + // + // So we alter the compiled template function to pass the name of the helper + // instead, as expected. + // + // This can go away once the following is closed: + // https://github.com/wycats/handlebars.js/issues/634 + + var DOT_LOOKUP_REGEX = /helpers\.(.*?)\)/; + var BRACKET_STRING_LOOKUP_REGEX = /helpers\['(.*?)'/; + var INVOCATION_SPLITTING_REGEX = /(.*blockHelperMissing\.call\(.*)(stack[0-9]+)(,.*)/; + + EmberHandlebars.JavaScriptCompiler.stringifyLastBlockHelperMissingInvocation = function(source) { + var helperInvocation = source[source.length - 1]; + var helperName = (DOT_LOOKUP_REGEX.exec(helperInvocation) || BRACKET_STRING_LOOKUP_REGEX.exec(helperInvocation))[1]; + var matches = INVOCATION_SPLITTING_REGEX.exec(helperInvocation); + + source[source.length - 1] = matches[1] + "'" + helperName + "'" + matches[3]; + }; + + var stringifyBlockHelperMissing = EmberHandlebars.JavaScriptCompiler.stringifyLastBlockHelperMissingInvocation; + + var originalBlockValue = EmberHandlebars.JavaScriptCompiler.prototype.blockValue; + EmberHandlebars.JavaScriptCompiler.prototype.blockValue = function() { + originalBlockValue.apply(this, arguments); + stringifyBlockHelperMissing(this.source); + }; + + var originalAmbiguousBlockValue = EmberHandlebars.JavaScriptCompiler.prototype.ambiguousBlockValue; + EmberHandlebars.JavaScriptCompiler.prototype.ambiguousBlockValue = function() { + originalAmbiguousBlockValue.apply(this, arguments); + stringifyBlockHelperMissing(this.source); + }; + + /** + Rewrite simple mustaches from `{{foo}}` to `{{bind "foo"}}`. This means that + all simple mustaches in Ember's Handlebars will also set up an observer to + keep the DOM up to date when the underlying property changes. + + @private + @method mustache + @for Ember.Handlebars.Compiler + @param mustache + */ + EmberHandlebars.Compiler.prototype.mustache = function(mustache) { + if (!(mustache.params.length || mustache.hash)) { + var id = new Handlebars.AST.IdNode([{ part: '_triageMustache' }]); + + // Update the mustache node to include a hash value indicating whether the original node + // was escaped. This will allow us to properly escape values when the underlying value + // changes and we need to re-render the value. + if (!mustache.escaped) { + mustache.hash = mustache.hash || new Handlebars.AST.HashNode([]); + mustache.hash.pairs.push(["unescaped", new Handlebars.AST.StringNode("true")]); + } + mustache = new Handlebars.AST.MustacheNode([id].concat([mustache.id]), mustache.hash, !mustache.escaped); + } + + return Handlebars.Compiler.prototype.mustache.call(this, mustache); + }; + + /** + Used for precompilation of Ember Handlebars templates. This will not be used + during normal app execution. + + @method precompile + @for Ember.Handlebars + @static + @param {String|Object} value The template to precompile or an Handlebars AST + @param {Boolean} asObject optional parameter, defaulting to true, of whether or not the + compiled template should be returned as an Object or a String + */ + EmberHandlebars.precompile = function(value, asObject) { + var ast = Handlebars.parse(value); + + var options = { + knownHelpers: { + action: true, + unbound: true, + 'bind-attr': true, + template: true, + view: true, + _triageMustache: true + }, + data: true, + stringParams: true + }; + + asObject = asObject === undefined ? true : asObject; + + var environment = new EmberHandlebars.Compiler().compile(ast, options); + return new EmberHandlebars.JavaScriptCompiler().compile(environment, options, undefined, asObject); + }; + + // We don't support this for Handlebars runtime-only + if (Handlebars.compile) { + /** + The entry point for Ember Handlebars. This replaces the default + `Handlebars.compile` and turns on template-local data and String + parameters. + + @method compile + @for Ember.Handlebars + @static + @param {String} string The template to compile + @return {Function} + */ + EmberHandlebars.compile = function(string) { + var ast = Handlebars.parse(string); + var options = { data: true, stringParams: true }; + var environment = new EmberHandlebars.Compiler().compile(ast, options); + var templateSpec = new EmberHandlebars.JavaScriptCompiler().compile(environment, options, undefined, true); + + var template = EmberHandlebars.template(templateSpec); + template.isMethod = false; //Make sure we don't wrap templates with ._super + + return template; + }; + } + + __exports__["default"] = EmberHandlebars; + }); +enifed("ember-handlebars", + ["ember-handlebars-compiler","ember-metal/core","ember-runtime/system/lazy_load","ember-handlebars/loader","ember-handlebars/ext","ember-handlebars/string","ember-handlebars/helpers/shared","ember-handlebars/helpers/binding","ember-handlebars/helpers/collection","ember-handlebars/helpers/view","ember-handlebars/helpers/unbound","ember-handlebars/helpers/debug","ember-handlebars/helpers/each","ember-handlebars/helpers/template","ember-handlebars/helpers/partial","ember-handlebars/helpers/yield","ember-handlebars/helpers/loc","ember-handlebars/controls/checkbox","ember-handlebars/controls/select","ember-handlebars/controls/text_area","ember-handlebars/controls/text_field","ember-handlebars/controls/text_support","ember-handlebars/controls","ember-handlebars/component_lookup","ember-handlebars/views/handlebars_bound_view","ember-handlebars/views/metamorph_view","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __dependency9__, __dependency10__, __dependency11__, __dependency12__, __dependency13__, __dependency14__, __dependency15__, __dependency16__, __dependency17__, __dependency18__, __dependency19__, __dependency20__, __dependency21__, __dependency22__, __dependency23__, __dependency24__, __dependency25__, __dependency26__, __exports__) { + "use strict"; + var EmberHandlebars = __dependency1__["default"]; + var Ember = __dependency2__["default"]; + // to add to globals + + var runLoadHooks = __dependency3__.runLoadHooks; + var bootstrap = __dependency4__["default"]; + + var normalizePath = __dependency5__.normalizePath; + var template = __dependency5__.template; + var makeBoundHelper = __dependency5__.makeBoundHelper; + var registerBoundHelper = __dependency5__.registerBoundHelper; + var resolveHash = __dependency5__.resolveHash; + var resolveParams = __dependency5__.resolveParams; + var getEscaped = __dependency5__.getEscaped; + var handlebarsGet = __dependency5__.handlebarsGet; + var evaluateUnboundHelper = __dependency5__.evaluateUnboundHelper; + var helperMissingHelper = __dependency5__.helperMissingHelper; + var blockHelperMissingHelper = __dependency5__.blockHelperMissingHelper; + + + // side effect of extending StringUtils of htmlSafe + + var resolvePaths = __dependency7__["default"]; + var bind = __dependency8__.bind; + var _triageMustacheHelper = __dependency8__._triageMustacheHelper; + var resolveHelper = __dependency8__.resolveHelper; + var bindHelper = __dependency8__.bindHelper; + var boundIfHelper = __dependency8__.boundIfHelper; + var unboundIfHelper = __dependency8__.unboundIfHelper; + var withHelper = __dependency8__.withHelper; + var ifHelper = __dependency8__.ifHelper; + var unlessHelper = __dependency8__.unlessHelper; + var bindAttrHelper = __dependency8__.bindAttrHelper; + var bindAttrHelperDeprecated = __dependency8__.bindAttrHelperDeprecated; + var bindClasses = __dependency8__.bindClasses; + + var collectionHelper = __dependency9__["default"]; + var ViewHelper = __dependency10__.ViewHelper; + var viewHelper = __dependency10__.viewHelper; + var unboundHelper = __dependency11__["default"]; + var logHelper = __dependency12__.logHelper; + var debuggerHelper = __dependency12__.debuggerHelper; + var EachView = __dependency13__.EachView; + var GroupedEach = __dependency13__.GroupedEach; + var eachHelper = __dependency13__.eachHelper; + var templateHelper = __dependency14__["default"]; + var partialHelper = __dependency15__["default"]; + var yieldHelper = __dependency16__["default"]; + var locHelper = __dependency17__["default"]; + + + var Checkbox = __dependency18__["default"]; + var Select = __dependency19__.Select; + var SelectOption = __dependency19__.SelectOption; + var SelectOptgroup = __dependency19__.SelectOptgroup; + var TextArea = __dependency20__["default"]; + var TextField = __dependency21__["default"]; + var TextSupport = __dependency22__["default"]; + var inputHelper = __dependency23__.inputHelper; + var textareaHelper = __dependency23__.textareaHelper; + + + var ComponentLookup = __dependency24__["default"]; + var _HandlebarsBoundView = __dependency25__._HandlebarsBoundView; + var SimpleHandlebarsView = __dependency25__.SimpleHandlebarsView; + var _wrapMap = __dependency26__._wrapMap; + var _SimpleMetamorphView = __dependency26__._SimpleMetamorphView; + var _MetamorphView = __dependency26__._MetamorphView; + var _Metamorph = __dependency26__._Metamorph; + + + /** + Ember Handlebars + + @module ember + @submodule ember-handlebars + @requires ember-views + */ + + // Ember.Handlebars.Globals + EmberHandlebars.bootstrap = bootstrap; + EmberHandlebars.template = template; + EmberHandlebars.makeBoundHelper = makeBoundHelper; + EmberHandlebars.registerBoundHelper = registerBoundHelper; + EmberHandlebars.resolveHash = resolveHash; + EmberHandlebars.resolveParams = resolveParams; + EmberHandlebars.resolveHelper = resolveHelper; + EmberHandlebars.get = handlebarsGet; + EmberHandlebars.getEscaped = getEscaped; + EmberHandlebars.evaluateUnboundHelper = evaluateUnboundHelper; + EmberHandlebars.bind = bind; + EmberHandlebars.bindClasses = bindClasses; + EmberHandlebars.EachView = EachView; + EmberHandlebars.GroupedEach = GroupedEach; + EmberHandlebars.resolvePaths = resolvePaths; + EmberHandlebars.ViewHelper = ViewHelper; + EmberHandlebars.normalizePath = normalizePath; + + + // Ember Globals + Ember.Handlebars = EmberHandlebars; + Ember.ComponentLookup = ComponentLookup; + Ember._SimpleHandlebarsView = SimpleHandlebarsView; + Ember._HandlebarsBoundView = _HandlebarsBoundView; + Ember._SimpleMetamorphView = _SimpleMetamorphView; + Ember._MetamorphView = _MetamorphView; + Ember._Metamorph = _Metamorph; + Ember._metamorphWrapMap = _wrapMap; + Ember.TextSupport = TextSupport; + Ember.Checkbox = Checkbox; + Ember.Select = Select; + Ember.SelectOption = SelectOption; + Ember.SelectOptgroup = SelectOptgroup; + Ember.TextArea = TextArea; + Ember.TextField = TextField; + Ember.TextSupport = TextSupport; + + // register helpers + EmberHandlebars.registerHelper('helperMissing', helperMissingHelper); + EmberHandlebars.registerHelper('blockHelperMissing', blockHelperMissingHelper); + EmberHandlebars.registerHelper('bind', bindHelper); + EmberHandlebars.registerHelper('boundIf', boundIfHelper); + EmberHandlebars.registerHelper('_triageMustache', _triageMustacheHelper); + EmberHandlebars.registerHelper('unboundIf', unboundIfHelper); + EmberHandlebars.registerHelper('with', withHelper); + EmberHandlebars.registerHelper('if', ifHelper); + EmberHandlebars.registerHelper('unless', unlessHelper); + EmberHandlebars.registerHelper('bind-attr', bindAttrHelper); + EmberHandlebars.registerHelper('bindAttr', bindAttrHelperDeprecated); + EmberHandlebars.registerHelper('collection', collectionHelper); + EmberHandlebars.registerHelper("log", logHelper); + EmberHandlebars.registerHelper("debugger", debuggerHelper); + EmberHandlebars.registerHelper("each", eachHelper); + EmberHandlebars.registerHelper("loc", locHelper); + EmberHandlebars.registerHelper("partial", partialHelper); + EmberHandlebars.registerHelper("template", templateHelper); + EmberHandlebars.registerHelper("yield", yieldHelper); + EmberHandlebars.registerHelper("view", viewHelper); + EmberHandlebars.registerHelper("unbound", unboundHelper); + EmberHandlebars.registerHelper("input", inputHelper); + EmberHandlebars.registerHelper("textarea", textareaHelper); + + // run load hooks + runLoadHooks('Ember.Handlebars', EmberHandlebars); + + __exports__["default"] = EmberHandlebars; + }); +enifed("ember-handlebars/component_lookup", + ["ember-runtime/system/object","exports"], + function(__dependency1__, __exports__) { + "use strict"; + var EmberObject = __dependency1__["default"]; + + var ComponentLookup = EmberObject.extend({ + lookupFactory: function(name, container) { + + container = container || this.container; + + var fullName = 'component:' + name; + var templateFullName = 'template:components/' + name; + var templateRegistered = container && container.has(templateFullName); + + if (templateRegistered) { + container.injection(fullName, 'layout', templateFullName); + } + + var Component = container.lookupFactory(fullName); + + // Only treat as a component if either the component + // or a template has been registered. + if (templateRegistered || Component) { + if (!Component) { + container.register(fullName, Ember.Component); + Component = container.lookupFactory(fullName); + } + return Component; + } + } + }); + + __exports__["default"] = ComponentLookup; + }); +enifed("ember-handlebars/controls", + ["ember-handlebars/controls/checkbox","ember-handlebars/controls/text_field","ember-handlebars/controls/text_area","ember-metal/core","ember-handlebars-compiler","ember-handlebars/ext","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __exports__) { + "use strict"; + var Checkbox = __dependency1__["default"]; + var TextField = __dependency2__["default"]; + var TextArea = __dependency3__["default"]; + + var Ember = __dependency4__["default"]; + // Ember.assert + // var emberAssert = Ember.assert; + + var EmberHandlebars = __dependency5__["default"]; + var handlebarsGet = __dependency6__.handlebarsGet; + var helpers = EmberHandlebars.helpers; + /** + @module ember + @submodule ember-handlebars-compiler + */ + + function _resolveOption(context, options, key) { + if (options.hashTypes[key] === "ID") { + return handlebarsGet(context, options.hash[key], options); + } else { + return options.hash[key]; + } + } + + /** + + The `{{input}}` helper inserts an HTML `` tag into the template, + with a `type` value of either `text` or `checkbox`. If no `type` is provided, + `text` will be the default value applied. The attributes of `{{input}}` + match those of the native HTML tag as closely as possible for these two types. + + ## Use as text field + An `{{input}}` with no `type` or a `type` of `text` will render an HTML text input. + The following HTML attributes can be set via the helper: + + + + + + + + + + + + +
`readonly``required``autofocus`
`value``placeholder``disabled`
`size``tabindex``maxlength`
`name``min``max`
`pattern``accept``autocomplete`
`autosave``formaction``formenctype`
`formmethod``formnovalidate``formtarget`
`height``inputmode``multiple`
`step``width``form`
`selectionDirection``spellcheck` 
+ + + When set to a quoted string, these values will be directly applied to the HTML + element. When left unquoted, these values will be bound to a property on the + template's current rendering context (most typically a controller instance). + + ## Unbound: + + ```handlebars + {{input value="http://www.facebook.com"}} + ``` + + + ```html + + ``` + + ## Bound: + + ```javascript + App.ApplicationController = Ember.Controller.extend({ + firstName: "Stanley", + entryNotAllowed: true + }); + ``` + + + ```handlebars + {{input type="text" value=firstName disabled=entryNotAllowed size="50"}} + ``` + + + ```html + + ``` + + ## Actions + + The helper can send multiple actions based on user events. + + The action property defines the action which is sent when + the user presses the return key. + + ```handlebars + {{input action="submit"}} + ``` + + The helper allows some user events to send actions. + + * `enter` + * `insert-newline` + * `escape-press` + * `focus-in` + * `focus-out` + * `key-press` + + + For example, if you desire an action to be sent when the input is blurred, + you only need to setup the action name to the event name property. + + ```handlebars + {{input focus-in="alertMessage"}} + ``` + + See more about [Text Support Actions](/api/classes/Ember.TextField.html) + + ## Extension + + Internally, `{{input type="text"}}` creates an instance of `Ember.TextField`, passing + arguments from the helper to `Ember.TextField`'s `create` method. You can extend the + capabilities of text inputs in your applications by reopening this class. For example, + if you are building a Bootstrap project where `data-*` attributes are used, you + can add one to the `TextField`'s `attributeBindings` property: + + + ```javascript + Ember.TextField.reopen({ + attributeBindings: ['data-error'] + }); + ``` + + Keep in mind when writing `Ember.TextField` subclasses that `Ember.TextField` + itself extends `Ember.Component`, meaning that it does NOT inherit + the `controller` of the parent view. + + See more about [Ember components](/api/classes/Ember.Component.html) + + + ## Use as checkbox + + An `{{input}}` with a `type` of `checkbox` will render an HTML checkbox input. + The following HTML attributes can be set via the helper: + + * `checked` + * `disabled` + * `tabindex` + * `indeterminate` + * `name` + * `autofocus` + * `form` + + + When set to a quoted string, these values will be directly applied to the HTML + element. When left unquoted, these values will be bound to a property on the + template's current rendering context (most typically a controller instance). + + ## Unbound: + + ```handlebars + {{input type="checkbox" name="isAdmin"}} + ``` + + ```html + + ``` + + ## Bound: + + ```javascript + App.ApplicationController = Ember.Controller.extend({ + isAdmin: true + }); + ``` + + + ```handlebars + {{input type="checkbox" checked=isAdmin }} + ``` + + + ```html + + ``` + + ## Extension + + Internally, `{{input type="checkbox"}}` creates an instance of `Ember.Checkbox`, passing + arguments from the helper to `Ember.Checkbox`'s `create` method. You can extend the + capablilties of checkbox inputs in your applications by reopening this class. For example, + if you wanted to add a css class to all checkboxes in your application: + + + ```javascript + Ember.Checkbox.reopen({ + classNames: ['my-app-checkbox'] + }); + ``` + + + @method input + @for Ember.Handlebars.helpers + @param {Hash} options + */ + function inputHelper(options) { + Ember.assert('You can only pass attributes to the `input` helper, not arguments', arguments.length < 2); + + var hash = options.hash; + var types = options.hashTypes; + var inputType = _resolveOption(this, options, 'type'); + var onEvent = hash.on; + + if (inputType === 'checkbox') { + delete hash.type; + delete types.type; + + Ember.assert("{{input type='checkbox'}} does not support setting `value=someBooleanValue`; you must use `checked=someBooleanValue` instead.", options.hashTypes.value !== 'ID'); + + return helpers.view.call(this, Checkbox, options); + } else { + delete hash.on; + + hash.onEvent = onEvent || 'enter'; + return helpers.view.call(this, TextField, options); + } + } + + __exports__.inputHelper = inputHelper;/** + `{{textarea}}` inserts a new instance of ` + ``` + + Bound: + + In the following example, the `writtenWords` property on `App.ApplicationController` + will be updated live as the user types 'Lots of text that IS bound' into + the text area of their browser's window. + + ```javascript + App.ApplicationController = Ember.Controller.extend({ + writtenWords: "Lots of text that IS bound" + }); + ``` + + ```handlebars + {{textarea value=writtenWords}} + ``` + + Would result in the following HTML: + + ```html + + ``` + + If you wanted a one way binding between the text area and a div tag + somewhere else on your screen, you could use `Ember.computed.oneWay`: + + ```javascript + App.ApplicationController = Ember.Controller.extend({ + writtenWords: "Lots of text that IS bound", + outputWrittenWords: Ember.computed.oneWay("writtenWords") + }); + ``` + + ```handlebars + {{textarea value=writtenWords}} + +
+ {{outputWrittenWords}} +
+ ``` + + Would result in the following HTML: + + ```html + + + <-- the following div will be updated in real time as you type --> + +
+ Lots of text that IS bound +
+ ``` + + Finally, this example really shows the power and ease of Ember when two + properties are bound to eachother via `Ember.computed.alias`. Type into + either text area box and they'll both stay in sync. Note that + `Ember.computed.alias` costs more in terms of performance, so only use it when + your really binding in both directions: + + ```javascript + App.ApplicationController = Ember.Controller.extend({ + writtenWords: "Lots of text that IS bound", + twoWayWrittenWords: Ember.computed.alias("writtenWords") + }); + ``` + + ```handlebars + {{textarea value=writtenWords}} + {{textarea value=twoWayWrittenWords}} + ``` + + ```html + + + <-- both updated in real time --> + + + ``` + + ## Actions + + The helper can send multiple actions based on user events. + + The action property defines the action which is send when + the user presses the return key. + + ```handlebars + {{input action="submit"}} + ``` + + The helper allows some user events to send actions. + + * `enter` + * `insert-newline` + * `escape-press` + * `focus-in` + * `focus-out` + * `key-press` + + For example, if you desire an action to be sent when the input is blurred, + you only need to setup the action name to the event name property. + + ```handlebars + {{textarea focus-in="alertMessage"}} + ``` + + See more about [Text Support Actions](/api/classes/Ember.TextArea.html) + + ## Extension + + Internally, `{{textarea}}` creates an instance of `Ember.TextArea`, passing + arguments from the helper to `Ember.TextArea`'s `create` method. You can + extend the capabilities of text areas in your application by reopening this + class. For example, if you are building a Bootstrap project where `data-*` + attributes are used, you can globally add support for a `data-*` attribute + on all `{{textarea}}`s' in your app by reopening `Ember.TextArea` or + `Ember.TextSupport` and adding it to the `attributeBindings` concatenated + property: + + ```javascript + Ember.TextArea.reopen({ + attributeBindings: ['data-error'] + }); + ``` + + Keep in mind when writing `Ember.TextArea` subclasses that `Ember.TextArea` + itself extends `Ember.Component`, meaning that it does NOT inherit + the `controller` of the parent view. + + See more about [Ember components](/api/classes/Ember.Component.html) + + @method textarea + @for Ember.Handlebars.helpers + @param {Hash} options + */ + function textareaHelper(options) { + Ember.assert('You can only pass attributes to the `textarea` helper, not arguments', arguments.length < 2); + + var hash = options.hash; + var types = options.hashTypes; + + return helpers.view.call(this, TextArea, options); + } + + __exports__.textareaHelper = textareaHelper; + }); +enifed("ember-handlebars/controls/checkbox", + ["ember-metal/property_get","ember-metal/property_set","ember-views/views/view","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __exports__) { + "use strict"; + var get = __dependency1__.get; + var set = __dependency2__.set; + var View = __dependency3__["default"]; + + /** + @module ember + @submodule ember-handlebars + */ + + /** + The internal class used to create text inputs when the `{{input}}` + helper is used with `type` of `checkbox`. + + See [handlebars.helpers.input](/api/classes/Ember.Handlebars.helpers.html#method_input) for usage details. + + ## Direct manipulation of `checked` + + The `checked` attribute of an `Ember.Checkbox` object should always be set + through the Ember object or by interacting with its rendered element + representation via the mouse, keyboard, or touch. Updating the value of the + checkbox via jQuery will result in the checked value of the object and its + element losing synchronization. + + ## Layout and LayoutName properties + + Because HTML `input` elements are self closing `layout` and `layoutName` + properties will not be applied. See [Ember.View](/api/classes/Ember.View.html)'s + layout section for more information. + + @class Checkbox + @namespace Ember + @extends Ember.View + */ + __exports__["default"] = View.extend({ + instrumentDisplay: '{{input type="checkbox"}}', + + classNames: ['ember-checkbox'], + + tagName: 'input', + + attributeBindings: [ + 'type', + 'checked', + 'indeterminate', + 'disabled', + 'tabindex', + 'name', + 'autofocus', + 'required', + 'form' + ], + + type: 'checkbox', + checked: false, + disabled: false, + indeterminate: false, + + init: function() { + this._super(); + this.on('change', this, this._updateElementValue); + }, + + didInsertElement: function() { + this._super(); + get(this, 'element').indeterminate = !!get(this, 'indeterminate'); + }, + + _updateElementValue: function() { + set(this, 'checked', this.$().prop('checked')); + } + }); + }); +enifed("ember-handlebars/controls/select", + ["ember-handlebars-compiler","ember-metal/enumerable_utils","ember-metal/property_get","ember-metal/property_set","ember-views/views/view","ember-views/views/collection_view","ember-metal/utils","ember-metal/is_none","ember-metal/computed","ember-runtime/system/native_array","ember-metal/mixin","ember-metal/properties","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __dependency9__, __dependency10__, __dependency11__, __dependency12__, __exports__) { + "use strict"; + /** + @module ember + @submodule ember-handlebars + */ + + var EmberHandlebars = __dependency1__["default"]; + + var forEach = __dependency2__.forEach; + var indexOf = __dependency2__.indexOf; + var indexesOf = __dependency2__.indexesOf; + var replace = __dependency2__.replace; + + var get = __dependency3__.get; + var set = __dependency4__.set; + var View = __dependency5__["default"]; + var CollectionView = __dependency6__["default"]; + var isArray = __dependency7__.isArray; + var isNone = __dependency8__["default"]; + var computed = __dependency9__.computed; + var emberA = __dependency10__.A; + var observer = __dependency11__.observer; + var defineProperty = __dependency12__.defineProperty; + + var precompileTemplate = EmberHandlebars.compile; + + var SelectOption = View.extend({ + instrumentDisplay: 'Ember.SelectOption', + + tagName: 'option', + attributeBindings: ['value', 'selected'], + + defaultTemplate: function(context, options) { + options = { data: options.data, hash: {} }; + EmberHandlebars.helpers.bind.call(context, "view.label", options); + }, + + init: function() { + this.labelPathDidChange(); + this.valuePathDidChange(); + + this._super(); + }, + + selected: computed(function() { + var content = get(this, 'content'); + var selection = get(this, 'parentView.selection'); + if (get(this, 'parentView.multiple')) { + return selection && indexOf(selection, content.valueOf()) > -1; + } else { + // Primitives get passed through bindings as objects... since + // `new Number(4) !== 4`, we use `==` below + return content == selection; // jshint ignore:line + } + }).property('content', 'parentView.selection'), + + labelPathDidChange: observer('parentView.optionLabelPath', function() { + var labelPath = get(this, 'parentView.optionLabelPath'); + + if (!labelPath) { return; } + + defineProperty(this, 'label', computed(function() { + return get(this, labelPath); + }).property(labelPath)); + }), + + valuePathDidChange: observer('parentView.optionValuePath', function() { + var valuePath = get(this, 'parentView.optionValuePath'); + + if (!valuePath) { return; } + + defineProperty(this, 'value', computed(function() { + return get(this, valuePath); + }).property(valuePath)); + }) + }); + + var SelectOptgroup = CollectionView.extend({ + instrumentDisplay: 'Ember.SelectOptgroup', + + tagName: 'optgroup', + attributeBindings: ['label'], + + selectionBinding: 'parentView.selection', + multipleBinding: 'parentView.multiple', + optionLabelPathBinding: 'parentView.optionLabelPath', + optionValuePathBinding: 'parentView.optionValuePath', + + itemViewClassBinding: 'parentView.optionView' + }); + + /** + The `Ember.Select` view class renders a + [select](https://developer.mozilla.org/en/HTML/Element/select) HTML element, + allowing the user to choose from a list of options. + + The text and `value` property of each ` + + + ``` + + The `value` attribute of the selected `"); + return buffer; + } + + function program3(depth0,data) { + + var stack1; + stack1 = helpers.each.call(depth0, "view.groupedContent", {hash:{},hashTypes:{},hashContexts:{},inverse:self.noop,fn:self.program(4, program4, data),contexts:[depth0],types:["ID"],data:data}); + if(stack1 || stack1 === 0) { data.buffer.push(stack1); } + else { data.buffer.push(''); } + } + function program4(depth0,data) { + + + data.buffer.push(escapeExpression(helpers.view.call(depth0, "view.groupView", {hash:{ + 'content': ("content"), + 'label': ("label") + },hashTypes:{'content': "ID",'label': "ID"},hashContexts:{'content': depth0,'label': depth0},contexts:[depth0],types:["ID"],data:data}))); + } + + function program6(depth0,data) { + + var stack1; + stack1 = helpers.each.call(depth0, "view.content", {hash:{},hashTypes:{},hashContexts:{},inverse:self.noop,fn:self.program(7, program7, data),contexts:[depth0],types:["ID"],data:data}); + if(stack1 || stack1 === 0) { data.buffer.push(stack1); } + else { data.buffer.push(''); } + } + function program7(depth0,data) { + + + data.buffer.push(escapeExpression(helpers.view.call(depth0, "view.optionView", {hash:{ + 'content': ("") + },hashTypes:{'content': "ID"},hashContexts:{'content': depth0},contexts:[depth0],types:["ID"],data:data}))); + } + + stack1 = helpers['if'].call(depth0, "view.prompt", {hash:{},hashTypes:{},hashContexts:{},inverse:self.noop,fn:self.program(1, program1, data),contexts:[depth0],types:["ID"],data:data}); + if(stack1 || stack1 === 0) { data.buffer.push(stack1); } + stack1 = helpers['if'].call(depth0, "view.optionGroupPath", {hash:{},hashTypes:{},hashContexts:{},inverse:self.program(6, program6, data),fn:self.program(3, program3, data),contexts:[depth0],types:["ID"],data:data}); + if(stack1 || stack1 === 0) { data.buffer.push(stack1); } + return buffer; + + }), + attributeBindings: ['multiple', 'disabled', 'tabindex', 'name', 'required', 'autofocus', + 'form', 'size'], + + /** + The `multiple` attribute of the select element. Indicates whether multiple + options can be selected. + + @property multiple + @type Boolean + @default false + */ + multiple: false, + + /** + The `disabled` attribute of the select element. Indicates whether + the element is disabled from interactions. + + @property disabled + @type Boolean + @default false + */ + disabled: false, + + /** + The `required` attribute of the select element. Indicates whether + a selected option is required for form validation. + + @property required + @type Boolean + @default false + @since 1.5.0 + */ + required: false, + + /** + The list of options. + + If `optionLabelPath` and `optionValuePath` are not overridden, this should + be a list of strings, which will serve simultaneously as labels and values. + + Otherwise, this should be a list of objects. For instance: + + ```javascript + var App = Ember.Application.create(); + var App.MySelect = Ember.Select.extend({ + content: Ember.A([ + { id: 1, firstName: 'Yehuda' }, + { id: 2, firstName: 'Tom' } + ]), + optionLabelPath: 'content.firstName', + optionValuePath: 'content.id' + }); + ``` + + @property content + @type Array + @default null + */ + content: null, + + /** + When `multiple` is `false`, the element of `content` that is currently + selected, if any. + + When `multiple` is `true`, an array of such elements. + + @property selection + @type Object or Array + @default null + */ + selection: null, + + /** + In single selection mode (when `multiple` is `false`), value can be used to + get the current selection's value or set the selection by it's value. + + It is not currently supported in multiple selection mode. + + @property value + @type String + @default null + */ + value: computed(function(key, value) { + if (arguments.length === 2) { return value; } + var valuePath = get(this, 'optionValuePath').replace(/^content\.?/, ''); + return valuePath ? get(this, 'selection.' + valuePath) : get(this, 'selection'); + }).property('selection'), + + /** + If given, a top-most dummy option will be rendered to serve as a user + prompt. + + @property prompt + @type String + @default null + */ + prompt: null, + + /** + The path of the option labels. See [content](/api/classes/Ember.Select.html#property_content). + + @property optionLabelPath + @type String + @default 'content' + */ + optionLabelPath: 'content', + + /** + The path of the option values. See [content](/api/classes/Ember.Select.html#property_content). + + @property optionValuePath + @type String + @default 'content' + */ + optionValuePath: 'content', + + /** + The path of the option group. + When this property is used, `content` should be sorted by `optionGroupPath`. + + @property optionGroupPath + @type String + @default null + */ + optionGroupPath: null, + + /** + The view class for optgroup. + + @property groupView + @type Ember.View + @default Ember.SelectOptgroup + */ + groupView: SelectOptgroup, + + groupedContent: computed(function() { + var groupPath = get(this, 'optionGroupPath'); + var groupedContent = emberA(); + var content = get(this, 'content') || []; + + forEach(content, function(item) { + var label = get(item, groupPath); + + if (get(groupedContent, 'lastObject.label') !== label) { + groupedContent.pushObject({ + label: label, + content: emberA() + }); + } + + get(groupedContent, 'lastObject.content').push(item); + }); + + return groupedContent; + }).property('optionGroupPath', 'content.@each'), + + /** + The view class for option. + + @property optionView + @type Ember.View + @default Ember.SelectOption + */ + optionView: SelectOption, + + _change: function() { + if (get(this, 'multiple')) { + this._changeMultiple(); + } else { + this._changeSingle(); + } + }, + + selectionDidChange: observer('selection.@each', function() { + var selection = get(this, 'selection'); + if (get(this, 'multiple')) { + if (!isArray(selection)) { + set(this, 'selection', emberA([selection])); + return; + } + this._selectionDidChangeMultiple(); + } else { + this._selectionDidChangeSingle(); + } + }), + + valueDidChange: observer('value', function() { + var content = get(this, 'content'); + var value = get(this, 'value'); + var valuePath = get(this, 'optionValuePath').replace(/^content\.?/, ''); + var selectedValue = (valuePath ? get(this, 'selection.' + valuePath) : get(this, 'selection')); + var selection; + + if (value !== selectedValue) { + selection = content ? content.find(function(obj) { + return value === (valuePath ? get(obj, valuePath) : obj); + }) : null; + + this.set('selection', selection); + } + }), + + + _triggerChange: function() { + var selection = get(this, 'selection'); + var value = get(this, 'value'); + + if (!isNone(selection)) { this.selectionDidChange(); } + if (!isNone(value)) { this.valueDidChange(); } + + this._change(); + }, + + _changeSingle: function() { + var selectedIndex = this.$()[0].selectedIndex; + var content = get(this, 'content'); + var prompt = get(this, 'prompt'); + + if (!content || !get(content, 'length')) { return; } + if (prompt && selectedIndex === 0) { set(this, 'selection', null); return; } + + if (prompt) { selectedIndex -= 1; } + set(this, 'selection', content.objectAt(selectedIndex)); + }, + + + _changeMultiple: function() { + var options = this.$('option:selected'); + var prompt = get(this, 'prompt'); + var offset = prompt ? 1 : 0; + var content = get(this, 'content'); + var selection = get(this, 'selection'); + + if (!content) { return; } + if (options) { + var selectedIndexes = options.map(function() { + return this.index - offset; + }).toArray(); + var newSelection = content.objectsAt(selectedIndexes); + + if (isArray(selection)) { + replace(selection, 0, get(selection, 'length'), newSelection); + } else { + set(this, 'selection', newSelection); + } + } + }, + + _selectionDidChangeSingle: function() { + var el = this.get('element'); + if (!el) { return; } + + var content = get(this, 'content'); + var selection = get(this, 'selection'); + var selectionIndex = content ? indexOf(content, selection) : -1; + var prompt = get(this, 'prompt'); + + if (prompt) { selectionIndex += 1; } + if (el) { el.selectedIndex = selectionIndex; } + }, + + _selectionDidChangeMultiple: function() { + var content = get(this, 'content'); + var selection = get(this, 'selection'); + var selectedIndexes = content ? indexesOf(content, selection) : [-1]; + var prompt = get(this, 'prompt'); + var offset = prompt ? 1 : 0; + var options = this.$('option'); + var adjusted; + + if (options) { + options.each(function() { + adjusted = this.index > -1 ? this.index - offset : -1; + this.selected = indexOf(selectedIndexes, adjusted) > -1; + }); + } + }, + + init: function() { + this._super(); + this.on("didInsertElement", this, this._triggerChange); + this.on("change", this, this._change); + } + }); + + __exports__["default"] = Select; + __exports__.Select = Select; + __exports__.SelectOption = SelectOption; + __exports__.SelectOptgroup = SelectOptgroup; + }); +enifed("ember-handlebars/controls/text_area", + ["ember-metal/property_get","ember-views/views/component","ember-handlebars/controls/text_support","ember-metal/mixin","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __exports__) { + "use strict"; + + /** + @module ember + @submodule ember-handlebars + */ + var get = __dependency1__.get; + var Component = __dependency2__["default"]; + var TextSupport = __dependency3__["default"]; + var observer = __dependency4__.observer; + + /** + The internal class used to create textarea element when the `{{textarea}}` + helper is used. + + See [handlebars.helpers.textarea](/api/classes/Ember.Handlebars.helpers.html#method_textarea) for usage details. + + ## Layout and LayoutName properties + + Because HTML `textarea` elements do not contain inner HTML the `layout` and + `layoutName` properties will not be applied. See [Ember.View](/api/classes/Ember.View.html)'s + layout section for more information. + + @class TextArea + @namespace Ember + @extends Ember.Component + @uses Ember.TextSupport + */ + __exports__["default"] = Component.extend(TextSupport, { + instrumentDisplay: '{{textarea}}', + + classNames: ['ember-text-area'], + + tagName: "textarea", + attributeBindings: ['rows', 'cols', 'name', 'selectionEnd', 'selectionStart', 'wrap', 'lang', 'dir'], + rows: null, + cols: null, + + _updateElementValue: observer('value', function() { + // We do this check so cursor position doesn't get affected in IE + var value = get(this, 'value'); + var $el = this.$(); + if ($el && value !== $el.val()) { + $el.val(value); + } + }), + + init: function() { + this._super(); + this.on("didInsertElement", this, this._updateElementValue); + } + }); + }); +enifed("ember-handlebars/controls/text_field", + ["ember-metal/property_get","ember-metal/property_set","ember-views/views/component","ember-handlebars/controls/text_support","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __exports__) { + "use strict"; + /** + @module ember + @submodule ember-handlebars + */ + + var get = __dependency1__.get; + var set = __dependency2__.set; + var Component = __dependency3__["default"]; + var TextSupport = __dependency4__["default"]; + + /** + + The internal class used to create text inputs when the `{{input}}` + helper is used with `type` of `text`. + + See [Handlebars.helpers.input](/api/classes/Ember.Handlebars.helpers.html#method_input) for usage details. + + ## Layout and LayoutName properties + + Because HTML `input` elements are self closing `layout` and `layoutName` + properties will not be applied. See [Ember.View](/api/classes/Ember.View.html)'s + layout section for more information. + + @class TextField + @namespace Ember + @extends Ember.Component + @uses Ember.TextSupport + */ + __exports__["default"] = Component.extend(TextSupport, { + instrumentDisplay: '{{input type="text"}}', + + classNames: ['ember-text-field'], + tagName: "input", + attributeBindings: ['type', 'value', 'size', 'pattern', 'name', 'min', 'max', + 'accept', 'autocomplete', 'autosave', 'formaction', + 'formenctype', 'formmethod', 'formnovalidate', 'formtarget', + 'height', 'inputmode', 'list', 'multiple', 'step', 'lang', 'dir', + 'width'], + + /** + The `value` attribute of the input element. As the user inputs text, this + property is updated live. + + @property value + @type String + @default "" + */ + value: "", + + /** + The `type` attribute of the input element. + + @property type + @type String + @default "text" + */ + type: "text", + + /** + The `size` of the text field in characters. + + @property size + @type String + @default null + */ + size: null, + + /** + The `pattern` attribute of input element. + + @property pattern + @type String + @default null + */ + pattern: null, + + /** + The `min` attribute of input element used with `type="number"` or `type="range"`. + + @property min + @type String + @default null + @since 1.4.0 + */ + min: null, + + /** + The `max` attribute of input element used with `type="number"` or `type="range"`. + + @property max + @type String + @default null + @since 1.4.0 + */ + max: null + }); + }); +enifed("ember-handlebars/controls/text_support", + ["ember-metal/property_get","ember-metal/property_set","ember-metal/mixin","ember-runtime/mixins/target_action_support","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __exports__) { + "use strict"; + /** + @module ember + @submodule ember-handlebars + */ + + var get = __dependency1__.get; + var set = __dependency2__.set; + var Mixin = __dependency3__.Mixin; + var TargetActionSupport = __dependency4__["default"]; + + /** + Shared mixin used by `Ember.TextField` and `Ember.TextArea`. + + @class TextSupport + @namespace Ember + @uses Ember.TargetActionSupport + @extends Ember.Mixin + @private + */ + var TextSupport = Mixin.create(TargetActionSupport, { + value: "", + + attributeBindings: ['placeholder', 'disabled', 'maxlength', 'tabindex', 'readonly', + 'autofocus', 'form', 'selectionDirection', 'spellcheck', 'required', + 'title', 'autocapitalize', 'autocorrect'], + placeholder: null, + disabled: false, + maxlength: null, + + init: function() { + this._super(); + this.on("focusOut", this, this._elementValueDidChange); + this.on("change", this, this._elementValueDidChange); + this.on("paste", this, this._elementValueDidChange); + this.on("cut", this, this._elementValueDidChange); + this.on("input", this, this._elementValueDidChange); + this.on("keyUp", this, this.interpretKeyEvents); + }, + + /** + The action to be sent when the user presses the return key. + + This is similar to the `{{action}}` helper, but is fired when + the user presses the return key when editing a text field, and sends + the value of the field as the context. + + @property action + @type String + @default null + */ + action: null, + + /** + The event that should send the action. + + Options are: + + * `enter`: the user pressed enter + * `keyPress`: the user pressed a key + + @property onEvent + @type String + @default enter + */ + onEvent: 'enter', + + /** + Whether the `keyUp` event that triggers an `action` to be sent continues + propagating to other views. + + By default, when the user presses the return key on their keyboard and + the text field has an `action` set, the action will be sent to the view's + controller and the key event will stop propagating. + + If you would like parent views to receive the `keyUp` event even after an + action has been dispatched, set `bubbles` to true. + + @property bubbles + @type Boolean + @default false + */ + bubbles: false, + + interpretKeyEvents: function(event) { + var map = TextSupport.KEY_EVENTS; + var method = map[event.keyCode]; + + this._elementValueDidChange(); + if (method) { return this[method](event); } + }, + + _elementValueDidChange: function() { + set(this, 'value', this.$().val()); + }, + + /** + Called when the user inserts a new line. + + Called by the `Ember.TextSupport` mixin on keyUp if keycode matches 13. + Uses sendAction to send the `enter` action. + + @method insertNewline + @param {Event} event + */ + insertNewline: function(event) { + sendAction('enter', this, event); + sendAction('insert-newline', this, event); + }, + + /** + Called when the user hits escape. + + Called by the `Ember.TextSupport` mixin on keyUp if keycode matches 27. + Uses sendAction to send the `escape-press` action. + + @method cancel + @param {Event} event + */ + cancel: function(event) { + sendAction('escape-press', this, event); + }, + + /** + Called when the text area is focused. + + Uses sendAction to send the `focus-in` action. + + @method focusIn + @param {Event} event + */ + focusIn: function(event) { + sendAction('focus-in', this, event); + }, + + /** + Called when the text area is blurred. + + Uses sendAction to send the `focus-out` action. + + @method focusOut + @param {Event} event + */ + focusOut: function(event) { + sendAction('focus-out', this, event); + }, + + /** + Called when the user presses a key. Enabled by setting + the `onEvent` property to `keyPress`. + + Uses sendAction to send the `key-press` action. + + @method keyPress + @param {Event} event + */ + keyPress: function(event) { + sendAction('key-press', this, event); + } + + }); + + TextSupport.KEY_EVENTS = { + 13: 'insertNewline', + 27: 'cancel' + }; + + // In principle, this shouldn't be necessary, but the legacy + // sendAction semantics for TextField are different from + // the component semantics so this method normalizes them. + function sendAction(eventName, view, event) { + var action = get(view, eventName); + var on = get(view, 'onEvent'); + var value = get(view, 'value'); + + // back-compat support for keyPress as an event name even though + // it's also a method name that consumes the event (and therefore + // incompatible with sendAction semantics). + if (on === eventName || (on === 'keyPress' && eventName === 'key-press')) { + view.sendAction('action', value); + } + + view.sendAction(eventName, value); + + if (action || on === eventName) { + if(!get(view, 'bubbles')) { + event.stopPropagation(); + } + } + } + + __exports__["default"] = TextSupport; + }); +enifed("ember-handlebars/ext", + ["ember-metal/core","ember-runtime/system/string","ember-handlebars-compiler","ember-metal/property_get","ember-metal/error","ember-metal/mixin","ember-views/views/view","ember-handlebars/views/metamorph_view","ember-metal/path_cache","ember-metal/is_empty","ember-metal/cache","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __dependency9__, __dependency10__, __dependency11__, __exports__) { + "use strict"; + var Ember = __dependency1__["default"]; + // Ember.FEATURES, Ember.assert, Ember.Handlebars, Ember.lookup + // var emberAssert = Ember.assert; + + var fmt = __dependency2__.fmt; + + var EmberHandlebars = __dependency3__["default"]; + var helpers = EmberHandlebars.helpers; + + var get = __dependency4__.get; + var EmberError = __dependency5__["default"]; + var IS_BINDING = __dependency6__.IS_BINDING; + + var View = __dependency7__["default"]; + var _Metamorph = __dependency8__._Metamorph; + var detectIsGlobal = __dependency9__.isGlobal; + + // late bound via requireModule because of circular dependencies. + var resolveHelper, SimpleHandlebarsView; + + var isEmpty = __dependency10__["default"]; + + var slice = [].slice; + var originalTemplate = EmberHandlebars.template; + + /** + If a path starts with a reserved keyword, returns the root + that should be used. + + @private + @method normalizePath + @for Ember + @param root {Object} + @param path {String} + @param data {Hash} + */ + + var Cache = __dependency11__["default"]; + + var FIRST_SEGMENT_CACHE = new Cache(1000, function(path){ + return path.split('.', 1)[0]; + }); + + function normalizePath(root, path, data) { + var keywords = (data && data.keywords) || {}; + var keyword, isKeyword; + + // Get the first segment of the path. For example, if the + // path is "foo.bar.baz", returns "foo". + keyword = FIRST_SEGMENT_CACHE.get(path); + + // Test to see if the first path is a keyword that has been + // passed along in the view's data hash. If so, we will treat + // that object as the new root. + if (keywords.hasOwnProperty(keyword)) { + // Look up the value in the template's data hash. + root = keywords[keyword]; + isKeyword = true; + + // Handle cases where the entire path is the reserved + // word. In that case, return the object itself. + if (path === keyword) { + path = ''; + } else { + // Strip the keyword from the path and look up + // the remainder from the newly found root. + path = path.substr(keyword.length+1); + } + } + + return { + root: root, + path: path, + isKeyword: isKeyword + }; + } + + + /** + Lookup both on root and on window. If the path starts with + a keyword, the corresponding object will be looked up in the + template's data hash and used to resolve the path. + + @method get + @for Ember.Handlebars + @param {Object} root The object to look up the property on + @param {String} path The path to be lookedup + @param {Object} options The template's option hash + */ + function handlebarsGet(root, path, options) { + var data = options && options.data; + var normalizedPath = normalizePath(root, path, data); + var value; + + // In cases where the path begins with a keyword, change the + // root to the value represented by that keyword, and ensure + // the path is relative to it. + root = normalizedPath.root; + path = normalizedPath.path; + + // Ember.get with a null root and GlobalPath will fall back to + // Ember.lookup, which is no longer allowed in templates. + // + // But when outputting a primitive, root will be the primitive + // and path a blank string. These primitives should pass through + // to `get`. + if (root || path === '') { + value = get(root, path); + } + + if (detectIsGlobal(path)) { + if (value === undefined && root !== Ember.lookup) { + root = Ember.lookup; + value = get(root, path); + } + if (root === Ember.lookup || root === null) { + Ember.deprecate("Global lookup of "+path+" from a Handlebars template is deprecated."); + } + } + + return value; + } + + function lookupViewInContainer(container, path) { + Ember.assert("View requires a container to resolve views not passed in through the context", !!container); + return container.lookupFactory('view:'+path); + } + + function lookupViewByClassName(path) { + var viewClass; + if (detectIsGlobal(path)) { + viewClass = get(path); + Ember.deprecate('Resolved the view "'+path+'" on the global context. Pass a view name to be looked up on the container instead, such as {{view "select"}}. http://emberjs.com/guides/deprecations#toc_global-lookup-of-views-since-1-8', !viewClass); + return viewClass; + } + } + + /** + handlebarsGetView resolves a view based on strings passed into a template. + For example: + + ```handlebars + {{view "some-view"}} + {{view view.someView}} + {{view App.SomeView}} {{! deprecated }} + ``` + + A value is first checked to be a string- non-strings are presumed to be + an object and returned. This handles the "access a view on a context" + case (line 2 in the above examples). + + Next a string is normalized, then called on the context with `get`. If + there is still no value, a GlobalPath will be fetched from the global + context (raising a deprecation) and a localPath will be passed to the + container to be looked up. + + @private + @for Ember.Handlebars + @param {Object} context The context of the template being rendered + @param {String} path The path to be lookedup + @param {Object} container The container + @param {Object} options The options from the template + */ + function handlebarsGetView(context, path, container, options) { + var viewClass; + var data; + var pathType; + if (options) { + data = options.data; + pathType = options.types && options.types[0]; + } + + if ('string' === typeof path) { + if('STRING' === pathType && container) { + viewClass = lookupViewInContainer(container, path); + Ember.deprecate('Quoted view names must refer to a view in the container.', viewClass); + + } + + if(!viewClass) { + viewClass = lookupViewByClassName(path); + } + + if(!viewClass) { + if (data) { + var normalizedPath = normalizePath(context, path, data); + context = normalizedPath.root; + path = normalizedPath.path; + } + + // Only lookup view class on context if there is a context. If not, + // the global lookup path on get may kick in. + viewClass = context && get(context, path); + + if(!viewClass) { + // try the container once more with the normalized path + viewClass = lookupViewInContainer(container, path); + } + } + } else { + viewClass = path; + } + + // Sometimes a view's value is yet another path + if ('string' === typeof viewClass && data && data.view) { + viewClass = handlebarsGetView(data.view, viewClass, container, { + data: data, + types: ['ID'] + }); + } + + Ember.assert( + fmt(path+" must be a subclass or an instance of Ember.View, not %@", [viewClass]), + View.detect(viewClass) || View.detectInstance(viewClass) + ); + + return viewClass; + } + + /** + This method uses `Ember.Handlebars.get` to lookup a value, then ensures + that the value is escaped properly. + + If `unescaped` is a truthy value then the escaping will not be performed. + + @method getEscaped + @for Ember.Handlebars + @param {Object} root The object to look up the property on + @param {String} path The path to be lookedup + @param {Object} options The template's option hash + @since 1.4.0 + */ + function getEscaped(root, path, options) { + var result = handlebarsGet(root, path, options); + + if (result === null || result === undefined) { + result = ""; + } else if (!(result instanceof Handlebars.SafeString)) { + result = String(result); + } + if (!options.hash.unescaped){ + result = Handlebars.Utils.escapeExpression(result); + } + + return result; + } + + __exports__.getEscaped = getEscaped;function resolveParams(context, params, options) { + var resolvedParams = [], types = options.types, param, type; + + for (var i=0, l=params.length; i{{user.name}} + +
+
{{user.role.label}}
+ {{user.role.id}} + +

{{user.role.description}}

+
+ ``` + + `{{with}}` can be our best friend in these cases, + instead of writing `user.role.*` over and over, we use `{{#with user.role}}`. + Now the context within the `{{#with}} .. {{/with}}` block is `user.role` so you can do the following: + + ```handlebars +
{{user.name}}
+ +
+ {{#with user.role}} +
{{label}}
+ {{id}} + +

{{description}}

+ {{/with}} +
+ ``` + + ### `as` operator + + This operator aliases the scope to a new name. It's helpful for semantic clarity and to retain + default scope or to reference from another `{{with}}` block. + + ```handlebars + // posts might not be + {{#with user.posts as blogPosts}} +
+ There are {{blogPosts.length}} blog posts written by {{user.name}}. +
+ + {{#each post in blogPosts}} +
  • {{post.title}}
  • + {{/each}} + {{/with}} + ``` + + Without the `as` operator, it would be impossible to reference `user.name` in the example above. + + NOTE: The alias should not reuse a name from the bound property path. + For example: `{{#with foo.bar as foo}}` is not supported because it attempts to alias using + the first part of the property path, `foo`. Instead, use `{{#with foo.bar as baz}}`. + + ### `controller` option + + Adding `controller='something'` instructs the `{{with}}` helper to create and use an instance of + the specified controller with the new context as its content. + + This is very similar to using an `itemController` option with the `{{each}}` helper. + + ```handlebars + {{#with users.posts controller='userBlogPosts'}} + {{!- The current context is wrapped in our controller instance }} + {{/with}} + ``` + + In the above example, the template provided to the `{{with}}` block is now wrapped in the + `userBlogPost` controller, which provides a very elegant way to decorate the context with custom + functions/properties. + + @method with + @for Ember.Handlebars.helpers + @param {Function} context + @param {Hash} options + @return {String} HTML string + */ + function withHelper(context, options) { + var bindContext, preserveContext, controller; + var helperName = 'with'; + + if (arguments.length === 4) { + var keywordName, path, rootPath, normalized, contextPath; + + Ember.assert("If you pass more than one argument to the with helper, it must be in the form #with foo as bar", arguments[1] === "as"); + options = arguments[3]; + keywordName = arguments[2]; + path = arguments[0]; + + if (path) { + helperName += ' ' + path + ' as ' + keywordName; + } + + Ember.assert("You must pass a block to the with helper", options.fn && options.fn !== Handlebars.VM.noop); + + var localizedOptions = o_create(options); + localizedOptions.data = o_create(options.data); + localizedOptions.data.keywords = o_create(options.data.keywords || {}); + + if (isGlobalPath(path)) { + contextPath = path; + } else { + normalized = normalizePath(this, path, options.data); + path = normalized.path; + rootPath = normalized.root; + + // This is a workaround for the fact that you cannot bind separate objects + // together. When we implement that functionality, we should use it here. + var contextKey = jQuery.expando + guidFor(rootPath); + localizedOptions.data.keywords[contextKey] = rootPath; + // if the path is '' ("this"), just bind directly to the current context + contextPath = path ? contextKey + '.' + path : contextKey; + } + + localizedOptions.hash.keywordName = keywordName; + localizedOptions.hash.keywordPath = contextPath; + + bindContext = this; + context = contextPath; + options = localizedOptions; + preserveContext = true; + } else { + Ember.assert("You must pass exactly one argument to the with helper", arguments.length === 2); + Ember.assert("You must pass a block to the with helper", options.fn && options.fn !== Handlebars.VM.noop); + + helperName += ' ' + context; + bindContext = options.contexts[0]; + preserveContext = false; + } + + options.helperName = helperName; + options.isWithHelper = true; + + return bind.call(bindContext, context, options, preserveContext, exists); + } + /** + See [boundIf](/api/classes/Ember.Handlebars.helpers.html#method_boundIf) + and [unboundIf](/api/classes/Ember.Handlebars.helpers.html#method_unboundIf) + + @method if + @for Ember.Handlebars.helpers + @param {Function} context + @param {Hash} options + @return {String} HTML string + */ + function ifHelper(context, options) { + Ember.assert("You must pass exactly one argument to the if helper", arguments.length === 2); + Ember.assert("You must pass a block to the if helper", options.fn && options.fn !== Handlebars.VM.noop); + + options.helperName = options.helperName || ('if ' + context); + + if (options.data.isUnbound) { + return helpers.unboundIf.call(options.contexts[0], context, options); + } else { + return helpers.boundIf.call(options.contexts[0], context, options); + } + } + + /** + @method unless + @for Ember.Handlebars.helpers + @param {Function} context + @param {Hash} options + @return {String} HTML string + */ + function unlessHelper(context, options) { + Ember.assert("You must pass exactly one argument to the unless helper", arguments.length === 2); + Ember.assert("You must pass a block to the unless helper", options.fn && options.fn !== Handlebars.VM.noop); + + var fn = options.fn; + var inverse = options.inverse; + var helperName = 'unless'; + + if (context) { + helperName += ' ' + context; + } + + options.fn = inverse; + options.inverse = fn; + + options.helperName = options.helperName || helperName; + + if (options.data.isUnbound) { + return helpers.unboundIf.call(options.contexts[0], context, options); + } else { + return helpers.boundIf.call(options.contexts[0], context, options); + } + } + + /** + `bind-attr` allows you to create a binding between DOM element attributes and + Ember objects. For example: + + ```handlebars + imageTitle + ``` + + The above handlebars template will fill the ``'s `src` attribute with + the value of the property referenced with `"imageUrl"` and its `alt` + attribute with the value of the property referenced with `"imageTitle"`. + + If the rendering context of this template is the following object: + + ```javascript + { + imageUrl: 'http://lolcats.info/haz-a-funny', + imageTitle: 'A humorous image of a cat' + } + ``` + + The resulting HTML output will be: + + ```html + A humorous image of a cat + ``` + + `bind-attr` cannot redeclare existing DOM element attributes. The use of `src` + in the following `bind-attr` example will be ignored and the hard coded value + of `src="/failwhale.gif"` will take precedence: + + ```handlebars + imageTitle + ``` + + ### `bind-attr` and the `class` attribute + + `bind-attr` supports a special syntax for handling a number of cases unique + to the `class` DOM element attribute. The `class` attribute combines + multiple discrete values into a single attribute as a space-delimited + list of strings. Each string can be: + + * a string return value of an object's property. + * a boolean return value of an object's property + * a hard-coded value + + A string return value works identically to other uses of `bind-attr`. The + return value of the property will become the value of the attribute. For + example, the following view and template: + + ```javascript + AView = View.extend({ + someProperty: function() { + return "aValue"; + }.property() + }) + ``` + + ```handlebars + + ``` + + A boolean return value will insert a specified class name if the property + returns `true` and remove the class name if the property returns `false`. + + A class name is provided via the syntax + `somePropertyName:class-name-if-true`. + + ```javascript + AView = View.extend({ + someBool: true + }) + ``` + + ```handlebars + + ``` + + Result in the following rendered output: + + ```html + + ``` + + An additional section of the binding can be provided if you want to + replace the existing class instead of removing it when the boolean + value changes: + + ```handlebars + + ``` + + A hard-coded value can be used by prepending `:` to the desired + class name: `:class-name-to-always-apply`. + + ```handlebars + + ``` + + Results in the following rendered output: + + ```html + + ``` + + All three strategies - string return value, boolean return value, and + hard-coded value – can be combined in a single declaration: + + ```handlebars + + ``` + + @method bind-attr + @for Ember.Handlebars.helpers + @param {Hash} options + @return {String} HTML string + */ + function bindAttrHelper(options) { + var attrs = options.hash; + + Ember.assert("You must specify at least one hash argument to bind-attr", !!keys(attrs).length); + + var view = options.data.view; + var ret = []; + + // we relied on the behavior of calling without + // context to mean this === window, but when running + // "use strict", it's possible for this to === undefined; + var ctx = this || window; + + // Generate a unique id for this element. This will be added as a + // data attribute to the element so it can be looked up when + // the bound property changes. + var dataId = uuid(); + + // Handle classes differently, as we can bind multiple classes + var classBindings = attrs['class']; + if (classBindings != null) { + var classResults = bindClasses(ctx, classBindings, view, dataId, options); + + ret.push('class="' + Handlebars.Utils.escapeExpression(classResults.join(' ')) + '"'); + delete attrs['class']; + } + + var attrKeys = keys(attrs); + + // For each attribute passed, create an observer and emit the + // current value of the property as an attribute. + forEach.call(attrKeys, function(attr) { + var path = attrs[attr]; + var normalized; + + Ember.assert(fmt("You must provide an expression as the value of bound attribute. You specified: %@=%@", [attr, path]), typeof path === 'string'); + + normalized = normalizePath(ctx, path, options.data); + + var value = (path === 'this') ? normalized.root : handlebarsGet(ctx, path, options); + var type = typeOf(value); + + Ember.assert(fmt("Attributes must be numbers, strings or booleans, not %@", [value]), value === null || value === undefined || type === 'number' || type === 'string' || type === 'boolean'); + + var observer; + + observer = function observer() { + var result = handlebarsGet(ctx, path, options); + + Ember.assert(fmt("Attributes must be numbers, strings or booleans, not %@", [result]), + result === null || result === undefined || typeof result === 'number' || + typeof result === 'string' || typeof result === 'boolean'); + + var elem = view.$("[data-bindattr-" + dataId + "='" + dataId + "']"); + + // If we aren't able to find the element, it means the element + // to which we were bound has been removed from the view. + // In that case, we can assume the template has been re-rendered + // and we need to clean up the observer. + if (!elem || elem.length === 0) { + removeObserver(normalized.root, normalized.path, observer); + return; + } + + View.applyAttributeBindings(elem, attr, result); + }; + + // Add an observer to the view for when the property changes. + // When the observer fires, find the element using the + // unique data id and update the attribute to the new value. + // Note: don't add observer when path is 'this' or path + // is whole keyword e.g. {{#each x in list}} ... {{bind-attr attr="x"}} + if (path !== 'this' && !(normalized.isKeyword && normalized.path === '' )) { + view.registerObserver(normalized.root, normalized.path, observer); + } + + // if this changes, also change the logic in ember-views/lib/views/view.js + if ((type === 'string' || (type === 'number' && !isNaN(value)))) { + ret.push(attr + '="' + Handlebars.Utils.escapeExpression(value) + '"'); + } else if (value && type === 'boolean') { + // The developer controls the attr name, so it should always be safe + ret.push(attr + '="' + attr + '"'); + } + }, this); + + // Add the unique identifier + // NOTE: We use all lower-case since Firefox has problems with mixed case in SVG + ret.push('data-bindattr-' + dataId + '="' + dataId + '"'); + return new SafeString(ret.join(' ')); + } + + /** + See `bind-attr` + + @method bindAttr + @for Ember.Handlebars.helpers + @deprecated + @param {Function} context + @param {Hash} options + @return {String} HTML string + */ + function bindAttrHelperDeprecated() { + Ember.warn("The 'bindAttr' view helper is deprecated in favor of 'bind-attr'"); + return helpers['bind-attr'].apply(this, arguments); + } + + /** + Helper that, given a space-separated string of property paths and a context, + returns an array of class names. Calling this method also has the side + effect of setting up observers at those property paths, such that if they + change, the correct class name will be reapplied to the DOM element. + + For example, if you pass the string "fooBar", it will first look up the + "fooBar" value of the context. If that value is true, it will add the + "foo-bar" class to the current element (i.e., the dasherized form of + "fooBar"). If the value is a string, it will add that string as the class. + Otherwise, it will not add any new class name. + + @private + @method bindClasses + @for Ember.Handlebars + @param {Ember.Object} context The context from which to lookup properties + @param {String} classBindings A string, space-separated, of class bindings + to use + @param {View} view The view in which observers should look for the + element to update + @param {Srting} bindAttrId Optional bindAttr id used to lookup elements + @return {Array} An array of class names to add + */ + function bindClasses(context, classBindings, view, bindAttrId, options) { + var ret = []; + var newClass, value, elem; + + // Helper method to retrieve the property from the context and + // determine which class string to return, based on whether it is + // a Boolean or not. + var classStringForPath = function(root, parsedPath, options) { + var val; + var path = parsedPath.path; + + if (path === 'this') { + val = root; + } else if (path === '') { + val = true; + } else { + val = handlebarsGet(root, path, options); + } + + return View._classStringForValue(path, val, parsedPath.className, parsedPath.falsyClassName); + }; + + // For each property passed, loop through and setup + // an observer. + forEach.call(classBindings.split(' '), function(binding) { + + // Variable in which the old class value is saved. The observer function + // closes over this variable, so it knows which string to remove when + // the property changes. + var oldClass; + var observer; + var parsedPath = View._parsePropertyPath(binding); + var path = parsedPath.path; + var pathRoot = context; + var normalized; + + if (path !== '' && path !== 'this') { + normalized = normalizePath(context, path, options.data); + + pathRoot = normalized.root; + path = normalized.path; + } + + // Set up an observer on the context. If the property changes, toggle the + // class name. + observer = function() { + // Get the current value of the property + newClass = classStringForPath(context, parsedPath, options); + elem = bindAttrId ? view.$("[data-bindattr-" + bindAttrId + "='" + bindAttrId + "']") : view.$(); + + // If we can't find the element anymore, a parent template has been + // re-rendered and we've been nuked. Remove the observer. + if (!elem || elem.length === 0) { + removeObserver(pathRoot, path, observer); + } else { + // If we had previously added a class to the element, remove it. + if (oldClass) { + elem.removeClass(oldClass); + } + + // If necessary, add a new class. Make sure we keep track of it so + // it can be removed in the future. + if (newClass) { + elem.addClass(newClass); + oldClass = newClass; + } else { + oldClass = null; + } + } + }; + + if (path !== '' && path !== 'this') { + view.registerObserver(pathRoot, path, observer); + } + + // We've already setup the observer; now we just need to figure out the + // correct behavior right now on the first pass through. + value = classStringForPath(context, parsedPath, options); + + if (value) { + ret.push(value); + + // Make sure we save the current value so that it can be removed if the + // observer fires. + oldClass = value; + } + }); + + return ret; + } + + __exports__.bind = bind; + __exports__._triageMustacheHelper = _triageMustacheHelper; + __exports__.resolveHelper = resolveHelper; + __exports__.bindHelper = bindHelper; + __exports__.boundIfHelper = boundIfHelper; + __exports__.unboundIfHelper = unboundIfHelper; + __exports__.withHelper = withHelper; + __exports__.ifHelper = ifHelper; + __exports__.unlessHelper = unlessHelper; + __exports__.bindAttrHelper = bindAttrHelper; + __exports__.bindAttrHelperDeprecated = bindAttrHelperDeprecated; + __exports__.bindClasses = bindClasses; + }); +enifed("ember-handlebars/helpers/collection", + ["ember-metal/core","ember-metal/utils","ember-handlebars-compiler","ember-runtime/system/string","ember-metal/property_get","ember-handlebars/ext","ember-handlebars/helpers/view","ember-metal/computed","ember-views/views/collection_view","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __dependency9__, __exports__) { + "use strict"; + /** + @module ember + @submodule ember-handlebars + */ + + var Ember = __dependency1__["default"]; + // Ember.assert, Ember.deprecate + var inspect = __dependency2__.inspect; + + // var emberAssert = Ember.assert; + // emberDeprecate = Ember.deprecate; + + var EmberHandlebars = __dependency3__["default"]; + var helpers = EmberHandlebars.helpers; + + var fmt = __dependency4__.fmt; + var get = __dependency5__.get; + var handlebarsGet = __dependency6__.handlebarsGet; + var handlebarsGetView = __dependency6__.handlebarsGetView; + var ViewHelper = __dependency7__.ViewHelper; + var computed = __dependency8__.computed; + var CollectionView = __dependency9__["default"]; + + var alias = computed.alias; + /** + `{{collection}}` is a `Ember.Handlebars` helper for adding instances of + `Ember.CollectionView` to a template. See [Ember.CollectionView](/api/classes/Ember.CollectionView.html) + for additional information on how a `CollectionView` functions. + + `{{collection}}`'s primary use is as a block helper with a `contentBinding` + option pointing towards an `Ember.Array`-compatible object. An `Ember.View` + instance will be created for each item in its `content` property. Each view + will have its own `content` property set to the appropriate item in the + collection. + + The provided block will be applied as the template for each item's view. + + Given an empty `` the following template: + + ```handlebars + {{! application.hbs }} + {{#collection content=model}} + Hi {{view.content.name}} + {{/collection}} + ``` + + And the following application code + + ```javascript + App = Ember.Application.create(); + App.ApplicationRoute = Ember.Route.extend({ + model: function(){ + return [{name: 'Yehuda'},{name: 'Tom'},{name: 'Peter'}]; + } + }); + ``` + + The following HTML will result: + + ```html +
    +
    Hi Yehuda
    +
    Hi Tom
    +
    Hi Peter
    +
    + ``` + + ### Non-block version of collection + + If you provide an `itemViewClass` option that has its own `template` you may + omit the block. + + The following template: + + ```handlebars + {{! application.hbs }} + {{collection content=model itemViewClass="an-item"}} + ``` + + And application code + + ```javascript + App = Ember.Application.create(); + App.ApplicationRoute = Ember.Route.extend({ + model: function(){ + return [{name: 'Yehuda'},{name: 'Tom'},{name: 'Peter'}]; + } + }); + + App.AnItemView = Ember.View.extend({ + template: Ember.Handlebars.compile("Greetings {{view.content.name}}") + }); + ``` + + Will result in the HTML structure below + + ```html +
    +
    Greetings Yehuda
    +
    Greetings Tom
    +
    Greetings Peter
    +
    + ``` + + ### Specifying a CollectionView subclass + + By default the `{{collection}}` helper will create an instance of + `Ember.CollectionView`. You can supply a `Ember.CollectionView` subclass to + the helper by passing it as the first argument: + + ```handlebars + {{#collection "my-custom-collection" content=model}} + Hi {{view.content.name}} + {{/collection}} + ``` + + This example would look for the class `App.MyCustomCollection`. + + ### Forwarded `item.*`-named Options + + As with the `{{view}}`, helper options passed to the `{{collection}}` will be + set on the resulting `Ember.CollectionView` as properties. Additionally, + options prefixed with `item` will be applied to the views rendered for each + item (note the camelcasing): + + ```handlebars + {{#collection content=model + itemTagName="p" + itemClassNames="greeting"}} + Howdy {{view.content.name}} + {{/collection}} + ``` + + Will result in the following HTML structure: + + ```html +
    +

    Howdy Yehuda

    +

    Howdy Tom

    +

    Howdy Peter

    +
    + ``` + + @method collection + @for Ember.Handlebars.helpers + @param {String} path + @param {Hash} options + @return {String} HTML string + @deprecated Use `{{each}}` helper instead. + */ + function collectionHelper(path, options) { + Ember.deprecate("Using the {{collection}} helper without specifying a class has been deprecated as the {{each}} helper now supports the same functionality.", path !== 'collection'); + + // If no path is provided, treat path param as options. + if (path && path.data && path.data.isRenderData) { + options = path; + path = undefined; + Ember.assert("You cannot pass more than one argument to the collection helper", arguments.length === 1); + } else { + Ember.assert("You cannot pass more than one argument to the collection helper", arguments.length === 2); + } + + var fn = options.fn, + data = options.data, + inverse = options.inverse, + view = options.data.view, + // This should be deterministic, and should probably come from a + // parent view and not the controller. + container = (view.controller && view.controller.container ? view.controller.container : view.container); + + // If passed a path string, convert that into an object. + // Otherwise, just default to the standard class. + var collectionClass; + if (path) { + collectionClass = handlebarsGetView(this, path, container, options); + Ember.assert(fmt("%@ #collection: Could not find collection class %@", [data.view, path]), !!collectionClass); + } + else { + collectionClass = CollectionView; + } + + var hash = options.hash; + var itemHash = {}; + var match; + + // Extract item view class if provided else default to the standard class + var collectionPrototype = collectionClass.proto(); + var itemViewClass; + + if (hash.itemView) { + itemViewClass = handlebarsGetView(this, hash.itemView, container, options); + } else if (hash.itemViewClass) { + itemViewClass = handlebarsGetView(collectionPrototype, hash.itemViewClass, container, options); + } else { + itemViewClass = handlebarsGetView(collectionPrototype, collectionPrototype.itemViewClass, container, options); + } + + Ember.assert(fmt("%@ #collection: Could not find itemViewClass %@", [data.view, itemViewClass]), !!itemViewClass); + + delete hash.itemViewClass; + delete hash.itemView; + + // Go through options passed to the {{collection}} helper and extract options + // that configure item views instead of the collection itself. + for (var prop in hash) { + if (hash.hasOwnProperty(prop)) { + match = prop.match(/^item(.)(.*)$/); + + if (match && prop !== 'itemController') { + // Convert itemShouldFoo -> shouldFoo + itemHash[match[1].toLowerCase() + match[2]] = hash[prop]; + // Delete from hash as this will end up getting passed to the + // {{view}} helper method. + delete hash[prop]; + } + } + } + + if (fn) { + itemHash.template = fn; + delete options.fn; + } + + var emptyViewClass; + if (inverse && inverse !== EmberHandlebars.VM.noop) { + emptyViewClass = get(collectionPrototype, 'emptyViewClass'); + emptyViewClass = emptyViewClass.extend({ + template: inverse, + tagName: itemHash.tagName + }); + } else if (hash.emptyViewClass) { + emptyViewClass = handlebarsGetView(this, hash.emptyViewClass, container, options); + } + if (emptyViewClass) { hash.emptyView = emptyViewClass; } + + if (hash.keyword) { + itemHash._context = this; + } else { + itemHash._context = alias('content'); + } + + var viewOptions = ViewHelper.propertiesFromHTMLOptions({ data: data, hash: itemHash }, this); + hash.itemViewClass = itemViewClass.extend(viewOptions); + + options.helperName = options.helperName || 'collection'; + + return helpers.view.call(this, collectionClass, options); + } + + __exports__["default"] = collectionHelper; + }); +enifed("ember-handlebars/helpers/debug", + ["ember-metal/core","ember-metal/utils","ember-metal/logger","ember-metal/property_get","ember-handlebars/ext","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __exports__) { + "use strict"; + /*jshint debug:true*/ + + /** + @module ember + @submodule ember-handlebars + */ + var Ember = __dependency1__["default"]; + // Ember.FEATURES, + var inspect = __dependency2__.inspect; + var Logger = __dependency3__["default"]; + + var get = __dependency4__.get; + var normalizePath = __dependency5__.normalizePath; + var handlebarsGet = __dependency5__.handlebarsGet; + + var a_slice = [].slice; + + /** + `log` allows you to output the value of variables in the current rendering + context. `log` also accepts primitive types such as strings or numbers. + + ```handlebars + {{log "myVariable:" myVariable }} + ``` + + @method log + @for Ember.Handlebars.helpers + @param {String} property + */ + function logHelper() { + var params = a_slice.call(arguments, 0, -1); + var options = arguments[arguments.length - 1]; + var logger = Logger.log; + var values = []; + var allowPrimitives = true; + + for (var i = 0; i < params.length; i++) { + var type = options.types[i]; + + if (type === 'ID' || !allowPrimitives) { + var context = (options.contexts && options.contexts[i]) || this; + var normalized = normalizePath(context, params[i], options.data); + + if (normalized.path === 'this') { + values.push(normalized.root); + } else { + values.push(handlebarsGet(normalized.root, normalized.path, options)); + } + } else { + values.push(params[i]); + } + } + + logger.apply(logger, values); + } + + /** + Execute the `debugger` statement in the current context. + + ```handlebars + {{debugger}} + ``` + + Before invoking the `debugger` statement, there + are a few helpful variables defined in the + body of this helper that you can inspect while + debugging that describe how and where this + helper was invoked: + + - templateContext: this is most likely a controller + from which this template looks up / displays properties + - typeOfTemplateContext: a string description of + what the templateContext is + + For example, if you're wondering why a value `{{foo}}` + isn't rendering as expected within a template, you + could place a `{{debugger}}` statement, and when + the `debugger;` breakpoint is hit, you can inspect + `templateContext`, determine if it's the object you + expect, and/or evaluate expressions in the console + to perform property lookups on the `templateContext`: + + ``` + > templateContext.get('foo') // -> "" + ``` + + @method debugger + @for Ember.Handlebars.helpers + @param {String} property + */ + function debuggerHelper(options) { + + // These are helpful values you can inspect while debugging. + var templateContext = this; + var typeOfTemplateContext = inspect(templateContext); + Ember.Logger.info('Use `this` to access the context of the calling template.'); + + debugger; + } + + __exports__.logHelper = logHelper; + __exports__.debuggerHelper = debuggerHelper; + }); +enifed("ember-handlebars/helpers/each", + ["ember-metal/core","ember-handlebars-compiler","ember-runtime/system/string","ember-metal/property_get","ember-metal/property_set","ember-views/views/collection_view","ember-metal/binding","ember-runtime/mixins/controller","ember-runtime/controllers/array_controller","ember-runtime/mixins/array","ember-runtime/copy","ember-metal/run_loop","ember-metal/events","ember-handlebars/ext","ember-metal/computed","ember-metal/observer","ember-handlebars/views/metamorph_view","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __dependency9__, __dependency10__, __dependency11__, __dependency12__, __dependency13__, __dependency14__, __dependency15__, __dependency16__, __dependency17__, __exports__) { + "use strict"; + + /** + @module ember + @submodule ember-handlebars + */ + var Ember = __dependency1__["default"]; + // Ember.assert;, Ember.K + var K = Ember.K; + + var EmberHandlebars = __dependency2__["default"]; + var helpers = EmberHandlebars.helpers; + + var fmt = __dependency3__.fmt; + var get = __dependency4__.get; + var set = __dependency5__.set; + var CollectionView = __dependency6__["default"]; + var Binding = __dependency7__.Binding; + var ControllerMixin = __dependency8__["default"]; + var ArrayController = __dependency9__["default"]; + var EmberArray = __dependency10__["default"]; + var copy = __dependency11__["default"]; + var run = __dependency12__["default"]; + var on = __dependency13__.on; + var handlebarsGet = __dependency14__.handlebarsGet; + var computed = __dependency15__.computed; + + var addObserver = __dependency16__.addObserver; + var removeObserver = __dependency16__.removeObserver; + var addBeforeObserver = __dependency16__.addBeforeObserver; + var removeBeforeObserver = __dependency16__.removeBeforeObserver; + + var _Metamorph = __dependency17__._Metamorph; + var _MetamorphView = __dependency17__._MetamorphView; + + var EachView = CollectionView.extend(_Metamorph, { + + init: function() { + var itemController = get(this, 'itemController'); + var binding; + + if (itemController) { + var controller = get(this, 'controller.container').lookupFactory('controller:array').create({ + _isVirtual: true, + parentController: get(this, 'controller'), + itemController: itemController, + target: get(this, 'controller'), + _eachView: this + }); + + this.disableContentObservers(function() { + set(this, 'content', controller); + binding = new Binding('content', '_eachView.dataSource').oneWay(); + binding.connect(controller); + }); + + set(this, '_arrayController', controller); + } else { + this.disableContentObservers(function() { + binding = new Binding('content', 'dataSource').oneWay(); + binding.connect(this); + }); + } + + return this._super(); + }, + + _assertArrayLike: function(content) { + Ember.assert(fmt("The value that #each loops over must be an Array. You " + + "passed %@, but it should have been an ArrayController", + [content.constructor]), + !ControllerMixin.detect(content) || + (content && content.isGenerated) || + content instanceof ArrayController); + Ember.assert(fmt("The value that #each loops over must be an Array. You passed %@", [(ControllerMixin.detect(content) && content.get('model') !== undefined) ? fmt("'%@' (wrapped in %@)", [content.get('model'), content]) : content]), EmberArray.detect(content)); + }, + + disableContentObservers: function(callback) { + removeBeforeObserver(this, 'content', null, '_contentWillChange'); + removeObserver(this, 'content', null, '_contentDidChange'); + + callback.call(this); + + addBeforeObserver(this, 'content', null, '_contentWillChange'); + addObserver(this, 'content', null, '_contentDidChange'); + }, + + itemViewClass: _MetamorphView, + emptyViewClass: _MetamorphView, + + createChildView: function(view, attrs) { + view = this._super(view, attrs); + + // At the moment, if a container view subclass wants + // to insert keywords, it is responsible for cloning + // the keywords hash. This will be fixed momentarily. + var keyword = get(this, 'keyword'); + var content = get(view, 'content'); + + if (keyword) { + var data = get(view, 'templateData'); + + data = copy(data); + data.keywords = view.cloneKeywords(); + set(view, 'templateData', data); + + // In this case, we do not bind, because the `content` of + // a #each item cannot change. + data.keywords[keyword] = content; + } + + // If {{#each}} is looping over an array of controllers, + // point each child view at their respective controller. + if (content && content.isController) { + set(view, 'controller', content); + } + + return view; + }, + + destroy: function() { + if (!this._super()) { return; } + + var arrayController = get(this, '_arrayController'); + + if (arrayController) { + arrayController.destroy(); + } + + return this; + } + }); + + var GroupedEach = EmberHandlebars.GroupedEach = function(context, path, options) { + var self = this; + var normalized = EmberHandlebars.normalizePath(context, path, options.data); + + this.context = context; + this.path = path; + this.options = options; + this.template = options.fn; + this.containingView = options.data.view; + this.normalizedRoot = normalized.root; + this.normalizedPath = normalized.path; + this.content = this.lookupContent(); + + this.addContentObservers(); + this.addArrayObservers(); + + this.containingView.on('willClearRender', function() { + self.destroy(); + }); + }; + + GroupedEach.prototype = { + contentWillChange: function() { + this.removeArrayObservers(); + }, + + contentDidChange: function() { + this.content = this.lookupContent(); + this.addArrayObservers(); + this.rerenderContainingView(); + }, + + contentArrayWillChange: K, + + contentArrayDidChange: function() { + this.rerenderContainingView(); + }, + + lookupContent: function() { + return handlebarsGet(this.normalizedRoot, this.normalizedPath, this.options); + }, + + addArrayObservers: function() { + if (!this.content) { return; } + + this.content.addArrayObserver(this, { + willChange: 'contentArrayWillChange', + didChange: 'contentArrayDidChange' + }); + }, + + removeArrayObservers: function() { + if (!this.content) { return; } + + this.content.removeArrayObserver(this, { + willChange: 'contentArrayWillChange', + didChange: 'contentArrayDidChange' + }); + }, + + addContentObservers: function() { + addBeforeObserver(this.normalizedRoot, this.normalizedPath, this, this.contentWillChange); + addObserver(this.normalizedRoot, this.normalizedPath, this, this.contentDidChange); + }, + + removeContentObservers: function() { + removeBeforeObserver(this.normalizedRoot, this.normalizedPath, this.contentWillChange); + removeObserver(this.normalizedRoot, this.normalizedPath, this.contentDidChange); + }, + + render: function() { + if (!this.content) { return; } + + var content = this.content; + var contentLength = get(content, 'length'); + var options = this.options; + var data = options.data; + var template = this.template; + + data.insideEach = true; + for (var i = 0; i < contentLength; i++) { + var context = content.objectAt(i); + options.data.keywords[options.hash.keyword] = context; + template(context, { data: data }); + } + }, + + rerenderContainingView: function() { + var self = this; + run.scheduleOnce('render', this, function() { + // It's possible it's been destroyed after we enqueued a re-render call. + if (!self.destroyed) { + self.containingView.rerender(); + } + }); + }, + + destroy: function() { + this.removeContentObservers(); + if (this.content) { + this.removeArrayObservers(); + } + this.destroyed = true; + } + }; + + /** + The `{{#each}}` helper loops over elements in a collection. It is an extension + of the base Handlebars `{{#each}}` helper. + + The default behavior of `{{#each}}` is to yield its inner block once for every + item in an array. Each yield will provide the item as the context of the block. + + ```javascript + var developers = [{name: 'Yehuda'},{name: 'Tom'}, {name: 'Paul'}]; + ``` + + ```handlebars + {{#each developers}} + {{name}} + {{! `this` is each developer }} + {{/each}} + ``` + + `{{#each}}` supports an alternative syntax with element naming. This preserves + context of the yielded block: + + ```handlebars + {{#each person in developers}} + {{person.name}} + {{! `this` is whatever it was outside the #each }} + {{/each}} + ``` + + The same rules apply to arrays of primitives, but the items may need to be + references with `{{this}}`. + + ```javascript + var developerNames = ['Yehuda', 'Tom', 'Paul'] + ``` + + ```handlebars + {{#each developerNames}} + {{this}} + {{/each}} + ``` + + ### {{else}} condition + + `{{#each}}` can have a matching `{{else}}`. The contents of this block will render + if the collection is empty. + + ``` + {{#each person in developers}} + {{person.name}} + {{else}} +

    Sorry, nobody is available for this task.

    + {{/each}} + ``` + + ### Specifying an alternative view for each item + + `itemViewClass` can control which view will be used during the render of each + item's template. + + The following template: + + ```handlebars +
      + {{#each developers itemViewClass="person"}} + {{name}} + {{/each}} +
    + ``` + + Will use the following view for each item + + ```javascript + App.PersonView = Ember.View.extend({ + tagName: 'li' + }); + ``` + + Resulting in HTML output that looks like the following: + + ```html +
      +
    • Yehuda
    • +
    • Tom
    • +
    • Paul
    • +
    + ``` + + `itemViewClass` also enables a non-block form of `{{each}}`. The view + must {{#crossLink "Ember.View/toc_templates"}}provide its own template{{/crossLink}}, + and then the block should be dropped. An example that outputs the same HTML + as the previous one: + + ```javascript + App.PersonView = Ember.View.extend({ + tagName: 'li', + template: '{{name}}' + }); + ``` + + ```handlebars +
      + {{each developers itemViewClass="person"}} +
    + ``` + + ### Specifying an alternative view for no items (else) + + The `emptyViewClass` option provides the same flexibility to the `{{else}}` + case of the each helper. + + ```javascript + App.NoPeopleView = Ember.View.extend({ + tagName: 'li', + template: 'No person is available, sorry' + }); + ``` + + ```handlebars +
      + {{#each developers emptyViewClass="no-people"}} +
    • {{name}}
    • + {{/each}} +
    + ``` + + ### Wrapping each item in a controller + + Controllers in Ember manage state and decorate data. In many cases, + providing a controller for each item in a list can be useful. + Specifically, an {{#crossLink "Ember.ObjectController"}}Ember.ObjectController{{/crossLink}} + should probably be used. Item controllers are passed the item they + will present as a `model` property, and an object controller will + proxy property lookups to `model` for us. + + This allows state and decoration to be added to the controller + while any other property lookups are delegated to the model. An example: + + ```javascript + App.RecruitController = Ember.ObjectController.extend({ + isAvailableForHire: function() { + return !this.get('isEmployed') && this.get('isSeekingWork'); + }.property('isEmployed', 'isSeekingWork') + }) + ``` + + ```handlebars + {{#each person in developers itemController="recruit"}} + {{person.name}} {{#if person.isAvailableForHire}}Hire me!{{/if}} + {{/each}} + ``` + + ### (Experimental) Grouped Each + + If a list's membership often changes, but properties of items in that + group rarely change, a significant improvement in template rendering + time can be achieved by using the experimental [group helper](https://github.com/emberjs/group-helper). + + ```handlebars + {{#group}} + {{#each people}} + {{firstName}} {{lastName}} + {{/each}} + {{/group}} + ``` + + When the membership of `people` changes, or when any property changes, the entire + `{{#group}}` block will be re-rendered. + + An `{{#each}}` inside the `{{#group}}` helper can opt-out of the special group + behavior by passing the `groupedRows` option. For example: + + ```handlebars + {{#group}} + {{#each dealers}} + {{! uses group's special behavior }} + {{firstName}} {{lastName}} + {{/each}} + + {{#each car in cars groupedRows=true}} + {{! does not use group's special behavior }} + {{car.make}} {{car.model}} {{car.color}} + {{/each}} + {{/group}} + ``` + + Any change to the `dealers` collection will cause the entire group to be re-rendered. + Changes to the `cars` collection will be re-rendered individually, as they are with + normal `{{#each}}` usage. + + `{{#group}}` is implemented with an `itemViewClass`, so specifying an `itemViewClass` + on an `{{#each}}` will also disable the special re-rendering behavior. + + @method each + @for Ember.Handlebars.helpers + @param [name] {String} name for item (used with `in`) + @param [path] {String} path + @param [options] {Object} Handlebars key/value pairs of options + @param [options.itemViewClass] {String} a path to a view class used for each item + @param [options.emptyViewClass] {String} a path to a view class used for each item + @param [options.itemController] {String} name of a controller to be created for each item + @param [options.groupedRows] {boolean} enable normal item-by-item rendering when inside a `#group` helper + */ + function eachHelper(path, options) { + var ctx; + var helperName = 'each'; + + if (arguments.length === 4) { + Ember.assert("If you pass more than one argument to the each helper, it must be in the form #each foo in bar", arguments[1] === "in"); + + var keywordName = arguments[0]; + + + options = arguments[3]; + path = arguments[2]; + + helperName += ' ' + keywordName + ' in ' + path; + + if (path === '') { path = "this"; } + + options.hash.keyword = keywordName; + + } else if (arguments.length === 1) { + options = path; + path = 'this'; + } else { + helperName += ' ' + path; + } + + options.hash.dataSourceBinding = path; + // Set up emptyView as a metamorph with no tag + //options.hash.emptyViewClass = Ember._MetamorphView; + + // can't rely on this default behavior when use strict + ctx = this || window; + + options.helperName = options.helperName || helperName; + + if (options.data.insideGroup && !options.hash.groupedRows && !options.hash.itemViewClass) { + new GroupedEach(ctx, path, options).render(); + } else { + return helpers.collection.call(ctx, EmberHandlebars.EachView, options); + } + } + + __exports__.EachView = EachView; + __exports__.GroupedEach = GroupedEach; + __exports__.eachHelper = eachHelper; + }); +enifed("ember-handlebars/helpers/loc", + ["ember-runtime/system/string","exports"], + function(__dependency1__, __exports__) { + "use strict"; + var loc = __dependency1__.loc; + + /** + @module ember + @submodule ember-handlebars + */ + + /** + Calls [Ember.String.loc](/api/classes/Ember.String.html#method_loc) with the + provided string. + + This is a convenient way to localize text within a template: + + ```javascript + Ember.STRINGS = { + '_welcome_': 'Bonjour' + }; + ``` + + ```handlebars +
    + {{loc '_welcome_'}} +
    + ``` + + ```html +
    + Bonjour +
    + ``` + + See [Ember.String.loc](/api/classes/Ember.String.html#method_loc) for how to + set up localized string references. + + @method loc + @for Ember.Handlebars.helpers + @param {String} str The string to format + @see {Ember.String#loc} + */ + __exports__["default"] = loc; + }); +enifed("ember-handlebars/helpers/partial", + ["ember-metal/core","ember-metal/is_none","ember-handlebars/ext","ember-handlebars/helpers/binding","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __exports__) { + "use strict"; + var Ember = __dependency1__["default"]; + // Ember.assert + // var emberAssert = Ember.assert; + + var isNone = __dependency2__.isNone; + var handlebarsGet = __dependency3__.handlebarsGet; + var bind = __dependency4__.bind; + + /** + @module ember + @submodule ember-handlebars + */ + + /** + The `partial` helper renders another template without + changing the template context: + + ```handlebars + {{foo}} + {{partial "nav"}} + ``` + + The above example template will render a template named + "_nav", which has the same context as the parent template + it's rendered into, so if the "_nav" template also referenced + `{{foo}}`, it would print the same thing as the `{{foo}}` + in the above example. + + If a "_nav" template isn't found, the `partial` helper will + fall back to a template named "nav". + + ## Bound template names + + The parameter supplied to `partial` can also be a path + to a property containing a template name, e.g.: + + ```handlebars + {{partial someTemplateName}} + ``` + + The above example will look up the value of `someTemplateName` + on the template context (e.g. a controller) and use that + value as the name of the template to render. If the resolved + value is falsy, nothing will be rendered. If `someTemplateName` + changes, the partial will be re-rendered using the new template + name. + + ## Setting the partial's context with `with` + + The `partial` helper can be used in conjunction with the `with` + helper to set a context that will be used by the partial: + + ```handlebars + {{#with currentUser}} + {{partial "user_info"}} + {{/with}} + ``` + + @method partial + @for Ember.Handlebars.helpers + @param {String} partialName the name of the template to render minus the leading underscore + */ + + __exports__["default"] = function partialHelper(name, options) { + + var context = (options.contexts && options.contexts.length) ? options.contexts[0] : this; + + options.helperName = options.helperName || 'partial'; + + if (options.types[0] === "ID") { + // Helper was passed a property path; we need to + // create a binding that will re-render whenever + // this property changes. + options.fn = function(context, fnOptions) { + var partialName = handlebarsGet(context, name, fnOptions); + renderPartial(context, partialName, fnOptions); + }; + + return bind.call(context, name, options, true, exists); + } else { + // Render the partial right into parent template. + renderPartial(context, name, options); + } + } + + function exists(value) { + return !isNone(value); + } + + function renderPartial(context, name, options) { + var nameParts = name.split("/"); + var lastPart = nameParts[nameParts.length - 1]; + + nameParts[nameParts.length - 1] = "_" + lastPart; + + var view = options.data.view; + var underscoredName = nameParts.join("/"); + var template = view.templateForName(underscoredName); + var deprecatedTemplate = !template && view.templateForName(name); + + Ember.assert("Unable to find partial with name '"+name+"'.", template || deprecatedTemplate); + + template = template || deprecatedTemplate; + + template(context, { data: options.data }); + } + }); +enifed("ember-handlebars/helpers/shared", + ["ember-handlebars/ext","exports"], + function(__dependency1__, __exports__) { + "use strict"; + var handlebarsGet = __dependency1__.handlebarsGet; + + __exports__["default"] = function resolvePaths(options) { + var ret = []; + var contexts = options.contexts; + var roots = options.roots; + var data = options.data; + + for (var i=0, l=contexts.length; i{{unbound somePropertyThatDoesntChange}} + ``` + + `unbound` can also be used in conjunction with a bound helper to + render it in its unbound form: + + ```handlebars +
    {{unbound helperName somePropertyThatDoesntChange}}
    + ``` + + @method unbound + @for Ember.Handlebars.helpers + @param {String} property + @return {String} HTML string + */ + __exports__["default"] = function unboundHelper(property, fn) { + var options = arguments[arguments.length - 1]; + var container = options.data.view.container; + var helper, context, out, ctx; + + ctx = this; + if (arguments.length > 2) { + // Unbound helper call. + options.data.isUnbound = true; + helper = resolveHelper(container, property) || helpers.helperMissing; + out = helper.apply(ctx, slice.call(arguments, 1)); + delete options.data.isUnbound; + return out; + } + + context = (fn.contexts && fn.contexts.length) ? fn.contexts[0] : ctx; + return handlebarsGet(context, property, fn); + } + }); +enifed("ember-handlebars/helpers/view", + ["ember-metal/core","ember-runtime/system/object","ember-metal/property_get","ember-metal/property_set","ember-metal/mixin","ember-views/system/jquery","ember-views/views/view","ember-metal/binding","ember-metal/keys","ember-handlebars/ext","ember-runtime/system/string","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __dependency9__, __dependency10__, __dependency11__, __exports__) { + "use strict"; + /*globals Handlebars */ + + /** + @module ember + @submodule ember-handlebars + */ + + var Ember = __dependency1__["default"]; + // Ember.warn, Ember.assert + // var emberWarn = Ember.warn, emberAssert = Ember.assert; + + var EmberObject = __dependency2__["default"]; + var get = __dependency3__.get; + var set = __dependency4__.set; + var IS_BINDING = __dependency5__.IS_BINDING; + var jQuery = __dependency6__["default"]; + var View = __dependency7__["default"]; + var isGlobalPath = __dependency8__.isGlobalPath; + var keys = __dependency9__["default"]; + var normalizePath = __dependency10__.normalizePath; + var handlebarsGet = __dependency10__.handlebarsGet; + var handlebarsGetView = __dependency10__.handlebarsGetView; + var EmberString = __dependency11__["default"]; + + + var LOWERCASE_A_Z = /^[a-z]/; + var VIEW_PREFIX = /^view\./; + + function makeBindings(thisContext, options) { + var hash = options.hash; + var hashType = options.hashTypes; + + for (var prop in hash) { + if (hashType[prop] === 'ID') { + + var value = hash[prop]; + + if (IS_BINDING.test(prop)) { + Ember.warn("You're attempting to render a view by passing " + prop + "=" + value + " to a view helper, but this syntax is ambiguous. You should either surround " + value + " in quotes or remove `Binding` from " + prop + "."); + } else { + hash[prop + 'Binding'] = value; + hashType[prop + 'Binding'] = 'STRING'; + delete hash[prop]; + delete hashType[prop]; + } + } + } + + if (hash.hasOwnProperty('idBinding')) { + // id can't be bound, so just perform one-time lookup. + hash.id = handlebarsGet(thisContext, hash.idBinding, options); + hashType.id = 'STRING'; + delete hash.idBinding; + delete hashType.idBinding; + } + } + + var ViewHelper = EmberObject.create({ + propertiesFromHTMLOptions: function(options) { + var hash = options.hash; + var data = options.data; + var classes = hash['class']; + + var extensions = { + helperName: options.helperName || '' + }; + + if (hash.id) { + extensions.elementId = hash.id; + } + + if (hash.tag) { + extensions.tagName = hash.tag; + } + + if (classes) { + classes = classes.split(' '); + extensions.classNames = classes; + } + + if (hash.classBinding) { + extensions.classNameBindings = hash.classBinding.split(' '); + } + + if (hash.classNameBindings) { + if (extensions.classNameBindings === undefined) { + extensions.classNameBindings = []; + } + extensions.classNameBindings = extensions.classNameBindings.concat(hash.classNameBindings.split(' ')); + } + + if (hash.attributeBindings) { + Ember.assert("Setting 'attributeBindings' via Handlebars is not allowed. Please subclass Ember.View and set it there instead."); + extensions.attributeBindings = null; + } + + // Set the proper context for all bindings passed to the helper. This applies to regular attribute bindings + // as well as class name bindings. If the bindings are local, make them relative to the current context + // instead of the view. + var path; + var hashKeys = keys(hash); + + for (var i = 0, l = hashKeys.length; i < l; i++) { + var prop = hashKeys[i]; + var isBinding = IS_BINDING.test(prop); + + if (prop !== 'classNameBindings') { + extensions[prop] = hash[prop]; + } + + // Test if the property ends in "Binding" + if (isBinding && typeof extensions[prop] === 'string') { + path = this.contextualizeBindingPath(hash[prop], data); + if (path) { + extensions[prop] = path; + } + } + } + + if (extensions.classNameBindings) { + // Evaluate the context of class name bindings: + for (var j = 0, k = extensions.classNameBindings.length; j < k; j++) { + var full = extensions.classNameBindings[j]; + + if (typeof full === 'string') { + // Contextualize the path of classNameBinding so this: + // + // classNameBinding="isGreen:green" + // + // is converted to this: + // + // classNameBinding="_parentView.context.isGreen:green" + var parsedPath = View._parsePropertyPath(full); + if (parsedPath.path !== '') { + path = this.contextualizeBindingPath(parsedPath.path, data); + if (path) { + extensions.classNameBindings[j] = path + parsedPath.classNames; + } + } + } + } + } + + return extensions; + }, + + // Transform bindings from the current context to a context that can be evaluated within the view. + // Returns null if the path shouldn't be changed. + // + // TODO: consider the addition of a prefix that would allow this method to return `path`. + contextualizeBindingPath: function(path, data) { + var normalized = normalizePath(null, path, data); + if (normalized.isKeyword) { + return 'templateData.keywords.' + path; + } else if (isGlobalPath(path)) { + return null; + } else if (path === 'this' || path === '') { + return '_parentView.context'; + } else { + return '_parentView.context.' + path; + } + }, + + helper: function(thisContext, path, options) { + var data = options.data; + var fn = options.fn; + var newView; + var newViewProto; + + makeBindings(thisContext, options); + + var container = this.container || (data && data.view && data.view.container); + newView = handlebarsGetView(thisContext, path, container, options); + + if (View.detectInstance(newView)) { + newViewProto = newView; + } else { + newViewProto = newView.proto(); + } + + var viewOptions = this.propertiesFromHTMLOptions(options, thisContext); + var currentView = data.view; + viewOptions.templateData = data; + + if (fn) { + Ember.assert("You cannot provide a template block if you also specified a templateName", !get(viewOptions, 'templateName') && !get(newViewProto, 'templateName')); + viewOptions.template = fn; + } + + // We only want to override the `_context` computed property if there is + // no specified controller. See View#_context for more information. + if (!newViewProto.controller && !newViewProto.controllerBinding && !viewOptions.controller && !viewOptions.controllerBinding) { + viewOptions._context = thisContext; + } + + currentView.appendChild(newView, viewOptions); + }, + + instanceHelper: function(thisContext, newView, options) { + var data = options.data; + var fn = options.fn; + + makeBindings(thisContext, options); + + Ember.assert( + 'Only a instance of a view may be passed to the ViewHelper.instanceHelper', + View.detectInstance(newView) + ); + + var viewOptions = this.propertiesFromHTMLOptions(options, thisContext); + var currentView = data.view; + viewOptions.templateData = data; + + if (fn) { + Ember.assert("You cannot provide a template block if you also specified a templateName", !get(viewOptions, 'templateName') && !get(newView, 'templateName')); + viewOptions.template = fn; + } + + // We only want to override the `_context` computed property if there is + // no specified controller. See View#_context for more information. + if (!newView.controller && !newView.controllerBinding && !viewOptions.controller && !viewOptions.controllerBinding) { + viewOptions._context = thisContext; + } + + currentView.appendChild(newView, viewOptions); + } + }); + __exports__.ViewHelper = ViewHelper; + /** + `{{view}}` inserts a new instance of an `Ember.View` into a template passing its + options to the `Ember.View`'s `create` method and using the supplied block as + the view's own template. + + An empty `` and the following template: + + ```handlebars + A span: + {{#view tagName="span"}} + hello. + {{/view}} + ``` + + Will result in HTML structure: + + ```html + + + +
    + A span: + + Hello. + +
    + + ``` + + ### `parentView` setting + + The `parentView` property of the new `Ember.View` instance created through + `{{view}}` will be set to the `Ember.View` instance of the template where + `{{view}}` was called. + + ```javascript + aView = Ember.View.create({ + template: Ember.Handlebars.compile("{{#view}} my parent: {{parentView.elementId}} {{/view}}") + }); + + aView.appendTo('body'); + ``` + + Will result in HTML structure: + + ```html +
    +
    + my parent: ember1 +
    +
    + ``` + + ### Setting CSS id and class attributes + + The HTML `id` attribute can be set on the `{{view}}`'s resulting element with + the `id` option. This option will _not_ be passed to `Ember.View.create`. + + ```handlebars + {{#view tagName="span" id="a-custom-id"}} + hello. + {{/view}} + ``` + + Results in the following HTML structure: + + ```html +
    + + hello. + +
    + ``` + + The HTML `class` attribute can be set on the `{{view}}`'s resulting element + with the `class` or `classNameBindings` options. The `class` option will + directly set the CSS `class` attribute and will not be passed to + `Ember.View.create`. `classNameBindings` will be passed to `create` and use + `Ember.View`'s class name binding functionality: + + ```handlebars + {{#view tagName="span" class="a-custom-class"}} + hello. + {{/view}} + ``` + + Results in the following HTML structure: + + ```html +
    + + hello. + +
    + ``` + + ### Supplying a different view class + + `{{view}}` can take an optional first argument before its supplied options to + specify a path to a custom view class. + + ```handlebars + {{#view "custom"}}{{! will look up App.CustomView }} + hello. + {{/view}} + ``` + + The first argument can also be a relative path accessible from the current + context. + + ```javascript + MyApp = Ember.Application.create({}); + MyApp.OuterView = Ember.View.extend({ + innerViewClass: Ember.View.extend({ + classNames: ['a-custom-view-class-as-property'] + }), + template: Ember.Handlebars.compile('{{#view view.innerViewClass}} hi {{/view}}') + }); + + MyApp.OuterView.create().appendTo('body'); + ``` + + Will result in the following HTML: + + ```html +
    +
    + hi +
    +
    + ``` + + ### Blockless use + + If you supply a custom `Ember.View` subclass that specifies its own template + or provide a `templateName` option to `{{view}}` it can be used without + supplying a block. Attempts to use both a `templateName` option and supply a + block will throw an error. + + ```javascript + var App = Ember.Application.create(); + App.WithTemplateDefinedView = Ember.View.extend({ + templateName: 'defined-template' + }); + ``` + + ```handlebars + {{! application.hbs }} + {{view 'with-template-defined'}} + ``` + + ```handlebars + {{! defined-template.hbs }} + Some content for the defined template view. + ``` + + ### `viewName` property + + You can supply a `viewName` option to `{{view}}`. The `Ember.View` instance + will be referenced as a property of its parent view by this name. + + ```javascript + aView = Ember.View.create({ + template: Ember.Handlebars.compile('{{#view viewName="aChildByName"}} hi {{/view}}') + }); + + aView.appendTo('body'); + aView.get('aChildByName') // the instance of Ember.View created by {{view}} helper + ``` + + @method view + @for Ember.Handlebars.helpers + @param {String} path + @param {Hash} options + @return {String} HTML string + */ + function viewHelper(path, options) { + Ember.assert("The view helper only takes a single argument", arguments.length <= 2); + + // If no path is provided, treat path param as options + // and get an instance of the registered `view:toplevel` + if (path && path.data && path.data.isRenderData) { + options = path; + if (options.data && options.data.view && options.data.view.container) { + path = options.data.view.container.lookupFactory('view:toplevel'); + } else { + path = View; + } + } + + options.helperName = options.helperName || 'view'; + + return ViewHelper.helper(this, path, options); + } + + __exports__.viewHelper = viewHelper; + }); +enifed("ember-handlebars/helpers/yield", + ["ember-metal/core","ember-metal/property_get","exports"], + function(__dependency1__, __dependency2__, __exports__) { + "use strict"; + /** + @module ember + @submodule ember-handlebars + */ + + var Ember = __dependency1__["default"]; + // var emberAssert = Ember.assert; + + var get = __dependency2__.get; + + /** + `{{yield}}` denotes an area of a template that will be rendered inside + of another template. It has two main uses: + + ### Use with `layout` + When used in a Handlebars template that is assigned to an `Ember.View` + instance's `layout` property Ember will render the layout template first, + inserting the view's own rendered output at the `{{yield}}` location. + + An empty `` and the following application code: + + ```javascript + AView = Ember.View.extend({ + classNames: ['a-view-with-layout'], + layout: Ember.Handlebars.compile('
    {{yield}}
    '), + template: Ember.Handlebars.compile('I am wrapped') + }); + + aView = AView.create(); + aView.appendTo('body'); + ``` + + Will result in the following HTML output: + + ```html + +
    +
    + I am wrapped +
    +
    + + ``` + + The `yield` helper cannot be used outside of a template assigned to an + `Ember.View`'s `layout` property and will throw an error if attempted. + + ```javascript + BView = Ember.View.extend({ + classNames: ['a-view-with-layout'], + template: Ember.Handlebars.compile('{{yield}}') + }); + + bView = BView.create(); + bView.appendTo('body'); + + // throws + // Uncaught Error: assertion failed: + // You called yield in a template that was not a layout + ``` + + ### Use with Ember.Component + When designing components `{{yield}}` is used to denote where, inside the component's + template, an optional block passed to the component should render: + + ```handlebars + + {{#labeled-textfield value=someProperty}} + First name: + {{/labeled-textfield}} + ``` + + ```handlebars + + + ``` + + Result: + + ```html + + ``` + + @method yield + @for Ember.Handlebars.helpers + @param {Hash} options + @return {String} HTML string + */ + __exports__["default"] = function yieldHelper(options) { + var view = options.data.view; + + while (view && !get(view, 'layout')) { + if (view._contextView) { + view = view._contextView; + } else { + view = get(view, '_parentView'); + } + } + + Ember.assert("You called yield in a template that was not a layout", !!view); + + view._yield(this, options); + } + }); +enifed("ember-handlebars/loader", + ["ember-handlebars/component_lookup","ember-views/system/jquery","ember-metal/error","ember-runtime/system/lazy_load","ember-handlebars-compiler","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __exports__) { + "use strict"; + /*globals Handlebars */ + + var ComponentLookup = __dependency1__["default"]; + var jQuery = __dependency2__["default"]; + var EmberError = __dependency3__["default"]; + var onLoad = __dependency4__.onLoad; + + var EmberHandlebars = __dependency5__["default"]; + + /** + @module ember + @submodule ember-handlebars + */ + + /** + Find templates stored in the head tag as script tags and make them available + to `Ember.CoreView` in the global `Ember.TEMPLATES` object. This will be run + as as jQuery DOM-ready callback. + + Script tags with `text/x-handlebars` will be compiled + with Ember's Handlebars and are suitable for use as a view's template. + Those with type `text/x-raw-handlebars` will be compiled with regular + Handlebars and are suitable for use in views' computed properties. + + @private + @method bootstrap + @for Ember.Handlebars + @static + @param ctx + */ + function bootstrap(ctx) { + var selectors = 'script[type="text/x-handlebars"], script[type="text/x-raw-handlebars"]'; + + jQuery(selectors, ctx) + .each(function() { + // Get a reference to the script tag + var script = jQuery(this); + + var compile = (script.attr('type') === 'text/x-raw-handlebars') ? + jQuery.proxy(Handlebars.compile, Handlebars) : + jQuery.proxy(EmberHandlebars.compile, EmberHandlebars); + // Get the name of the script, used by Ember.View's templateName property. + // First look for data-template-name attribute, then fall back to its + // id if no name is found. + var templateName = script.attr('data-template-name') || script.attr('id') || 'application'; + var template = compile(script.html()); + + // Check if template of same name already exists + if (Ember.TEMPLATES[templateName] !== undefined) { + throw new EmberError('Template named "' + templateName + '" already exists.'); + } + + // For templates which have a name, we save them and then remove them from the DOM + Ember.TEMPLATES[templateName] = template; + + // Remove script tag from DOM + script.remove(); + }); + } + + function _bootstrap() { + bootstrap( jQuery(document) ); + } + + function registerComponentLookup(container) { + container.register('component-lookup:main', ComponentLookup); + } + + /* + We tie this to application.load to ensure that we've at least + attempted to bootstrap at the point that the application is loaded. + + We also tie this to document ready since we're guaranteed that all + the inline templates are present at this point. + + There's no harm to running this twice, since we remove the templates + from the DOM after processing. + */ + + onLoad('Ember.Application', function(Application) { + Application.initializer({ + name: 'domTemplates', + initialize: _bootstrap + }); + + Application.initializer({ + name: 'registerComponentLookup', + after: 'domTemplates', + initialize: registerComponentLookup + }); + }); + + __exports__["default"] = bootstrap; + }); +enifed("ember-handlebars/string", + ["ember-runtime/system/string","exports"], + function(__dependency1__, __exports__) { + "use strict"; + // required so we can extend this object. + var EmberStringUtils = __dependency1__["default"]; + + /** + Mark a string as safe for unescaped output with Handlebars. If you + return HTML from a Handlebars helper, use this function to + ensure Handlebars does not escape the HTML. + + ```javascript + Ember.String.htmlSafe('
    someString
    ') + ``` + + @method htmlSafe + @for Ember.String + @static + @return {Handlebars.SafeString} a string that will not be html escaped by Handlebars + */ + function htmlSafe(str) { + if (typeof str !== 'string') { + str = ''+str; + } + return new Handlebars.SafeString(str); + } + + EmberStringUtils.htmlSafe = htmlSafe; + if (Ember.EXTEND_PROTOTYPES === true || Ember.EXTEND_PROTOTYPES.String) { + + /** + Mark a string as being safe for unescaped output with Handlebars. + + ```javascript + '
    someString
    '.htmlSafe() + ``` + + See [Ember.String.htmlSafe](/api/classes/Ember.String.html#method_htmlSafe). + + @method htmlSafe + @for String + @return {Handlebars.SafeString} a string that will not be html escaped by Handlebars + */ + String.prototype.htmlSafe = function() { + return htmlSafe(this); + }; + } + + __exports__["default"] = htmlSafe; + }); +enifed("ember-handlebars/views/handlebars_bound_view", + ["ember-handlebars-compiler","ember-metal/core","ember-metal/error","ember-metal/property_get","ember-metal/property_set","ember-metal/merge","ember-metal/run_loop","ember-views/views/view","ember-handlebars/string","ember-views/views/states","ember-handlebars/views/metamorph_view","ember-handlebars/ext","ember-metal/utils","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __dependency9__, __dependency10__, __dependency11__, __dependency12__, __dependency13__, __exports__) { + "use strict"; + /*globals Handlebars, Metamorph:true */ + /*jshint newcap:false*/ + + + /** + @module ember + @submodule ember-handlebars + */ + + var EmberHandlebars = __dependency1__["default"]; + // EmberHandlebars.SafeString; + var SafeString = EmberHandlebars.SafeString; + + var Ember = __dependency2__["default"]; + // Ember.K + var K = Ember.K; + + var EmberError = __dependency3__["default"]; + var get = __dependency4__.get; + var set = __dependency5__.set; + var merge = __dependency6__["default"]; + var run = __dependency7__["default"]; + var View = __dependency8__["default"]; + var htmlSafe = __dependency9__["default"]; + var cloneStates = __dependency10__.cloneStates; + var states = __dependency10__.states; + var viewStates = states; + + var _MetamorphView = __dependency11__["default"]; + var handlebarsGet = __dependency12__.handlebarsGet; + var uuid = __dependency13__.uuid; + + function SimpleHandlebarsView(path, pathRoot, isEscaped, templateData) { + this.path = path; + this.pathRoot = pathRoot; + this.isEscaped = isEscaped; + this.templateData = templateData; + this[Ember.GUID_KEY] = uuid(); + this._lastNormalizedValue = undefined; + this.state = 'preRender'; + this.updateId = null; + this._parentView = null; + this.buffer = null; + this._morph = null; + } + + SimpleHandlebarsView.prototype = { + isVirtual: true, + isView: true, + + destroy: function () { + if (this.updateId) { + run.cancel(this.updateId); + this.updateId = null; + } + if (this._parentView) { + this._parentView.removeChild(this); + } + this.morph = null; + this.state = 'destroyed'; + }, + + propertyWillChange: K, + + propertyDidChange: K, + + normalizedValue: function() { + var path = this.path; + var pathRoot = this.pathRoot; + var escape = this.isEscaped; + var result, templateData; + + // Use the pathRoot as the result if no path is provided. This + // happens if the path is `this`, which gets normalized into + // a `pathRoot` of the current Handlebars context and a path + // of `''`. + if (path === '') { + result = pathRoot; + } else { + templateData = this.templateData; + result = handlebarsGet(pathRoot, path, { data: templateData }); + } + + if (!escape && !(result instanceof SafeString)) { + result = htmlSafe(result); + } + + return result; + }, + + render: function(buffer) { + var value = this.normalizedValue(); + this._lastNormalizedValue = value; + buffer._element = value; + }, + + rerender: function() { + switch(this.state) { + case 'preRender': + case 'destroyed': + break; + case 'inBuffer': + throw new EmberError("Something you did tried to replace an {{expression}} before it was inserted into the DOM."); + case 'hasElement': + case 'inDOM': + this.updateId = run.scheduleOnce('render', this, 'update'); + break; + } + return this; + }, + + update: function () { + this.updateId = null; + var value = this.normalizedValue(); + // doesn't diff SafeString instances + if (value !== this._lastNormalizedValue) { + this._lastNormalizedValue = value; + this._morph.update(value); + } + }, + + _transitionTo: function(state) { + this.state = state; + } + }; + + states = cloneStates(viewStates); + + merge(states._default, { + rerenderIfNeeded: K + }); + + merge(states.inDOM, { + rerenderIfNeeded: function(view) { + if (view.normalizedValue() !== view._lastNormalizedValue) { + view.rerender(); + } + } + }); + + /** + `Ember._HandlebarsBoundView` is a private view created by the Handlebars + `{{bind}}` helpers that is used to keep track of bound properties. + + Every time a property is bound using a `{{mustache}}`, an anonymous subclass + of `Ember._HandlebarsBoundView` is created with the appropriate sub-template + and context set up. When the associated property changes, just the template + for this view will re-render. + + @class _HandlebarsBoundView + @namespace Ember + @extends Ember._MetamorphView + @private + */ + var _HandlebarsBoundView = _MetamorphView.extend({ + instrumentName: 'boundHandlebars', + + _states: states, + + /** + The function used to determine if the `displayTemplate` or + `inverseTemplate` should be rendered. This should be a function that takes + a value and returns a Boolean. + + @property shouldDisplayFunc + @type Function + @default null + */ + shouldDisplayFunc: null, + + /** + Whether the template rendered by this view gets passed the context object + of its parent template, or gets passed the value of retrieving `path` + from the `pathRoot`. + + For example, this is true when using the `{{#if}}` helper, because the + template inside the helper should look up properties relative to the same + object as outside the block. This would be `false` when used with `{{#with + foo}}` because the template should receive the object found by evaluating + `foo`. + + @property preserveContext + @type Boolean + @default false + */ + preserveContext: false, + + /** + If `preserveContext` is true, this is the object that will be used + to render the template. + + @property previousContext + @type Object + */ + previousContext: null, + + /** + The template to render when `shouldDisplayFunc` evaluates to `true`. + + @property displayTemplate + @type Function + @default null + */ + displayTemplate: null, + + /** + The template to render when `shouldDisplayFunc` evaluates to `false`. + + @property inverseTemplate + @type Function + @default null + */ + inverseTemplate: null, + + + /** + The path to look up on `pathRoot` that is passed to + `shouldDisplayFunc` to determine which template to render. + + In addition, if `preserveContext` is `false,` the object at this path will + be passed to the template when rendering. + + @property path + @type String + @default null + */ + path: null, + + /** + The object from which the `path` will be looked up. Sometimes this is the + same as the `previousContext`, but in cases where this view has been + generated for paths that start with a keyword such as `view` or + `controller`, the path root will be that resolved object. + + @property pathRoot + @type Object + */ + pathRoot: null, + + normalizedValue: function() { + var path = get(this, 'path'); + var pathRoot = get(this, 'pathRoot'); + var valueNormalizer = get(this, 'valueNormalizerFunc'); + var result, templateData; + + // Use the pathRoot as the result if no path is provided. This + // happens if the path is `this`, which gets normalized into + // a `pathRoot` of the current Handlebars context and a path + // of `''`. + if (path === '') { + result = pathRoot; + } else { + templateData = get(this, 'templateData'); + result = handlebarsGet(pathRoot, path, { data: templateData }); + } + + return valueNormalizer ? valueNormalizer(result) : result; + }, + + rerenderIfNeeded: function() { + this.currentState.rerenderIfNeeded(this); + }, + + /** + Determines which template to invoke, sets up the correct state based on + that logic, then invokes the default `Ember.View` `render` implementation. + + This method will first look up the `path` key on `pathRoot`, + then pass that value to the `shouldDisplayFunc` function. If that returns + `true,` the `displayTemplate` function will be rendered to DOM. Otherwise, + `inverseTemplate`, if specified, will be rendered. + + For example, if this `Ember._HandlebarsBoundView` represented the `{{#with + foo}}` helper, it would look up the `foo` property of its context, and + `shouldDisplayFunc` would always return true. The object found by looking + up `foo` would be passed to `displayTemplate`. + + @method render + @param {Ember.RenderBuffer} buffer + */ + render: function(buffer) { + // If not invoked via a triple-mustache ({{{foo}}}), escape + // the content of the template. + var escape = get(this, 'isEscaped'); + + var shouldDisplay = get(this, 'shouldDisplayFunc'); + var preserveContext = get(this, 'preserveContext'); + var context = get(this, 'previousContext'); + + var inverseTemplate = get(this, 'inverseTemplate'); + var displayTemplate = get(this, 'displayTemplate'); + + var result = this.normalizedValue(); + + this._lastNormalizedValue = result; + + // First, test the conditional to see if we should + // render the template or not. + if (shouldDisplay(result)) { + set(this, 'template', displayTemplate); + + // If we are preserving the context (for example, if this + // is an #if block, call the template with the same object. + if (preserveContext) { + set(this, '_context', context); + } else { + // Otherwise, determine if this is a block bind or not. + // If so, pass the specified object to the template + if (displayTemplate) { + set(this, '_context', result); + } else { + // This is not a bind block, just push the result of the + // expression to the render context and return. + if (result === null || result === undefined) { + result = ""; + } else if (!(result instanceof SafeString)) { + result = String(result); + } + + if (escape) { result = Handlebars.Utils.escapeExpression(result); } + buffer.push(result); + return; + } + } + } else if (inverseTemplate) { + set(this, 'template', inverseTemplate); + + if (preserveContext) { + set(this, '_context', context); + } else { + set(this, '_context', result); + } + } else { + set(this, 'template', function() { return ''; }); + } + + return this._super(buffer); + } + }); + + __exports__._HandlebarsBoundView = _HandlebarsBoundView; + __exports__.SimpleHandlebarsView = SimpleHandlebarsView; + }); +enifed("ember-handlebars/views/metamorph_view", + ["ember-metal/core","ember-views/views/core_view","ember-views/views/view","ember-metal/mixin","ember-metal/run_loop","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __exports__) { + "use strict"; + /* global Metamorph:true */ + + /*jshint newcap:false*/ + var Ember = __dependency1__["default"]; + // Ember.deprecate + + var CoreView = __dependency2__["default"]; + var View = __dependency3__["default"]; + var Mixin = __dependency4__.Mixin; + var run = __dependency5__["default"]; + + /** + @module ember + @submodule ember-handlebars + */ + + function notifyMutationListeners() { + run.once(View, 'notifyMutationListeners'); + } + + // The `morph` and `outerHTML` properties are internal only + // and not observable. + + /** + @class _Metamorph + @namespace Ember + @private + */ + var _Metamorph = Mixin.create({ + isVirtual: true, + tagName: '', + + instrumentName: 'metamorph', + + init: function() { + this._super(); + Ember.deprecate('Supplying a tagName to Metamorph views is unreliable and is deprecated. You may be setting the tagName on a Handlebars helper that creates a Metamorph.', !this.tagName); + } + }); + __exports__._Metamorph = _Metamorph; + /** + @class _MetamorphView + @namespace Ember + @extends Ember.View + @uses Ember._Metamorph + @private + */ + var _MetamorphView = View.extend(_Metamorph); + __exports__._MetamorphView = _MetamorphView; + /** + @class _SimpleMetamorphView + @namespace Ember + @extends Ember.CoreView + @uses Ember._Metamorph + @private + */ + var _SimpleMetamorphView = CoreView.extend(_Metamorph); + __exports__._SimpleMetamorphView = _SimpleMetamorphView;__exports__["default"] = View.extend(_Metamorph); + }); +enifed("ember-metal-views", + ["ember-metal-views/renderer","exports"], + function(__dependency1__, __exports__) { + "use strict"; + var Renderer = __dependency1__["default"]; + __exports__.Renderer = Renderer; + }); +enifed("ember-metal-views/renderer", + ["morph","exports"], + function(__dependency1__, __exports__) { + "use strict"; + var DOMHelper = __dependency1__.DOMHelper; + + function Renderer() { + this._uuid = 0; + this._views = new Array(2000); + this._queue = [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]; + this._parents = [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]; + this._elements = new Array(17); + this._inserts = {}; + this._dom = new DOMHelper(); + } + + function Renderer_renderTree(_view, _parentView, _insertAt) { + var views = this._views; + views[0] = _view; + var insertAt = _insertAt === undefined ? -1 : _insertAt; + var index = 0; + var total = 1; + var levelBase = _parentView ? _parentView._level+1 : 0; + + var root = _parentView == null ? _view : _parentView._root; + + // if root view has a _morph assigned + var willInsert = !!root._morph; + + var queue = this._queue; + queue[0] = 0; + var length = 1; + + var parentIndex = -1; + var parents = this._parents; + var parent = _parentView || null; + var elements = this._elements; + var element = null; + var contextualElement = null; + var level = 0; + + var view = _view; + var children, i, l, child; + while (length) { + elements[level] = element; + if (!view._morph) { + // ensure props we add are in same order + view._morph = null; + } + view._root = root; + this.uuid(view); + view._level = levelBase + level; + if (view._elementCreated) { + this.remove(view, false, true); + } + + this.willCreateElement(view); + + contextualElement = view._morph && view._morph.contextualElement; + if (!contextualElement && parent && parent._childViewsMorph) { + contextualElement = parent._childViewsMorph.contextualElement; + } + if (!contextualElement && view._didCreateElementWithoutMorph) { + // This code path is only used by createElement and rerender when createElement + // was previously called on a view. + contextualElement = document.body; + } + Ember.assert("Required contextualElement for view "+_view+" is missing", contextualElement); + element = this.createElement(view, contextualElement); + + parents[level++] = parentIndex; + parentIndex = index; + parent = view; + + // enqueue for end + queue[length++] = index; + // enqueue children + children = this.childViews(view); + if (children) { + for (i=children.length-1;i>=0;i--) { + child = children[i]; + index = total++; + views[index] = child; + queue[length++] = index; + view = child; + } + } + + index = queue[--length]; + view = views[index]; + + while (parentIndex === index) { + level--; + view._elementCreated = true; + this.didCreateElement(view); + if (willInsert) { + this.willInsertElement(view); + } + + if (level === 0) { + length--; + break; + } + + parentIndex = parents[level]; + parent = parentIndex === -1 ? _parentView : views[parentIndex]; + this.insertElement(view, parent, element, -1); + index = queue[--length]; + view = views[index]; + element = elements[level]; + elements[level] = null; + } + } + + this.insertElement(view, _parentView, element, insertAt); + + for (i=total-1;i>=0;i--) { + if (willInsert) { + views[i]._elementInserted = true; + this.didInsertElement(views[i]); + } + views[i] = null; + } + + return element; + } + + Renderer.prototype.uuid = function Renderer_uuid(view) { + if (view._uuid === undefined) { + view._uuid = ++this._uuid; + view._renderer = this; + } // else assert(view._renderer === this) + return view._uuid; + }; + + Renderer.prototype.scheduleInsert = + function Renderer_scheduleInsert(view, morph) { + if (view._morph || view._elementCreated) { + throw new Error("You cannot insert a View that has already been rendered"); + } + Ember.assert("You cannot insert a View without a morph", morph); + view._morph = morph; + var viewId = this.uuid(view); + this._inserts[viewId] = this.scheduleRender(this, function() { + this._inserts[viewId] = null; + this.renderTree(view); + }); + }; + + Renderer.prototype.appendTo = + function Renderer_appendTo(view, target) { + var morph = this._dom.appendMorph(target); + this.scheduleInsert(view, morph); + }; + + Renderer.prototype.replaceIn = + function Renderer_replaceIn(view, target) { + var morph = this._dom.createMorph(target, null, null); + this.scheduleInsert(view, morph); + }; + + function Renderer_remove(_view, shouldDestroy, reset) { + var viewId = this.uuid(_view); + + if (this._inserts[viewId]) { + this.cancelRender(this._inserts[viewId]); + this._inserts[viewId] = undefined; + } + + if (!_view._elementCreated) { + return; + } + + var removeQueue = []; + var destroyQueue = []; + var morph = _view._morph; + var idx, len, view, staticChildren, queue, + childViews, i, l, parentView; + + removeQueue.push(_view); + + for (idx=0; idx -1; }; + var defineNativeShim = function(nativeFunc, shim) { + if (isNativeFunc(nativeFunc)) { + return nativeFunc; + } + return shim; + }; + // From: https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/array/map - var map = isNativeFunc(ArrayPrototype.map) ? ArrayPrototype.map : function(fun /*, thisp */) { + var map = defineNativeShim(ArrayPrototype.map, function(fun /*, thisp */) { //"use strict"; - if (this === void 0 || this === null) { + if (this === void 0 || this === null || typeof fun !== "function") { throw new TypeError(); } var t = Object(this); var len = t.length >>> 0; - if (typeof fun !== "function") { - throw new TypeError(); - } - var res = new Array(len); var thisp = arguments[1]; + for (var i = 0; i < len; i++) { if (i in t) { res[i] = fun.call(thisp, t[i], i, t); @@ -312,44 +11303,61 @@ define("ember-metal/array", } return res; - }; + }); // From: https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/array/foreach - var forEach = isNativeFunc(ArrayPrototype.forEach) ? ArrayPrototype.forEach : function(fun /*, thisp */) { + var forEach = defineNativeShim(ArrayPrototype.forEach, function(fun /*, thisp */) { //"use strict"; - if (this === void 0 || this === null) { + if (this === void 0 || this === null || typeof fun !== "function") { throw new TypeError(); } var t = Object(this); var len = t.length >>> 0; - if (typeof fun !== "function") { - throw new TypeError(); - } - var thisp = arguments[1]; + for (var i = 0; i < len; i++) { if (i in t) { fun.call(thisp, t[i], i, t); } } - }; + }); + + var indexOf = defineNativeShim(ArrayPrototype.indexOf, function (obj, fromIndex) { + if (fromIndex === null || fromIndex === undefined) { + fromIndex = 0; + } + else if (fromIndex < 0) { + fromIndex = Math.max(0, this.length + fromIndex); + } - var indexOf = isNativeFunc(ArrayPrototype.indexOf) ? ArrayPrototype.indexOf : function (obj, fromIndex) { - if (fromIndex === null || fromIndex === undefined) { fromIndex = 0; } - else if (fromIndex < 0) { fromIndex = Math.max(0, this.length + fromIndex); } for (var i = fromIndex, j = this.length; i < j; i++) { - if (this[i] === obj) { return i; } + if (this[i] === obj) { + return i; + } } return -1; - }; + }); - var filter = isNativeFunc(ArrayPrototype.filter) ? ArrayPrototype.filter : function (fn, context) { - var i, - value, - result = [], - length = this.length; + var lastIndexOf = defineNativeShim(ArrayPrototype.lastIndexOf, function(obj, fromIndex) { + var len = this.length; + var idx; + + if (fromIndex === undefined) fromIndex = len-1; + else fromIndex = (fromIndex < 0) ? Math.ceil(fromIndex) : Math.floor(fromIndex); + if (fromIndex < 0) fromIndex += len; + + for(idx = fromIndex;idx>=0;idx--) { + if (this[idx] === obj) return idx ; + } + return -1; + }); + + var filter = defineNativeShim(ArrayPrototype.filter, function (fn, context) { + var i, value; + var result = []; + var length = this.length; for (i = 0; i < length; i++) { if (this.hasOwnProperty(i)) { @@ -360,25 +11368,14 @@ define("ember-metal/array", } } return result; - }; - + }); if (Ember.SHIM_ES5) { - if (!ArrayPrototype.map) { - ArrayPrototype.map = map; - } - - if (!ArrayPrototype.forEach) { - ArrayPrototype.forEach = forEach; - } - - if (!ArrayPrototype.filter) { - ArrayPrototype.filter = filter; - } - - if (!ArrayPrototype.indexOf) { - ArrayPrototype.indexOf = indexOf; - } + ArrayPrototype.map = ArrayPrototype.map || map; + ArrayPrototype.forEach = ArrayPrototype.forEach || forEach; + ArrayPrototype.filter = ArrayPrototype.filter || filter; + ArrayPrototype.indexOf = ArrayPrototype.indexOf || indexOf; + ArrayPrototype.lastIndexOf = ArrayPrototype.lastIndexOf || lastIndexOf; } /** @@ -391,9 +11388,10 @@ define("ember-metal/array", __exports__.forEach = forEach; __exports__.filter = filter; __exports__.indexOf = indexOf; + __exports__.lastIndexOf = lastIndexOf; }); -define("ember-metal/binding", - ["ember-metal/core","ember-metal/property_get","ember-metal/property_set","ember-metal/utils","ember-metal/map","ember-metal/observer","ember-metal/run_loop","exports"], +enifed("ember-metal/binding", + ["ember-metal/core","ember-metal/property_get","ember-metal/property_set","ember-metal/utils","ember-metal/observer","ember-metal/run_loop","ember-metal/path_cache","exports"], function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __exports__) { "use strict"; var Ember = __dependency1__["default"]; @@ -402,11 +11400,12 @@ define("ember-metal/binding", var set = __dependency3__.set; var trySet = __dependency3__.trySet; var guidFor = __dependency4__.guidFor; - var Map = __dependency5__.Map; - var addObserver = __dependency6__.addObserver; - var removeObserver = __dependency6__.removeObserver; - var _suspendObserver = __dependency6__._suspendObserver; - var run = __dependency7__["default"]; + var addObserver = __dependency5__.addObserver; + var removeObserver = __dependency5__.removeObserver; + var _suspendObserver = __dependency5__._suspendObserver; + var run = __dependency6__["default"]; + var isGlobalPath = __dependency7__.isGlobal; + // ES6TODO: where is Ember.lookup defined? /** @@ -429,8 +11428,6 @@ define("ember-metal/binding", */ Ember.LOG_BINDINGS = false || !!Ember.ENV.LOG_BINDINGS; - var IS_GLOBAL = /^([A-Z$]|([0-9][A-Z$]))/; - /** Returns true if the provided path is global (e.g., `MyApp.fooController.bar`) instead of local (`foo.bar.baz`). @@ -441,9 +11438,6 @@ define("ember-metal/binding", @param {String} path @return Boolean */ - function isGlobalPath(path) { - return IS_GLOBAL.test(path); - }; function getWithGlobals(obj, path) { return get(isGlobalPath(path) ? Ember.lookup : obj, path); @@ -453,12 +11447,13 @@ define("ember-metal/binding", // BINDING // - var Binding = function(toPath, fromPath) { - this._direction = 'fwd'; + function Binding(toPath, fromPath) { + this._direction = undefined; this._from = fromPath; this._to = toPath; - this._directionMap = Map.create(); - }; + this._readyToSync = undefined; + this._oneWay = undefined; + } /** @class Binding @@ -557,7 +11552,8 @@ define("ember-metal/binding", connect: function(obj) { Ember.assert('Must pass a valid object to Ember.Binding.connect()', !!obj); - var fromPath = this._from, toPath = this._to; + var fromPath = this._from; + var toPath = this._to; trySet(obj, toPath, getWithGlobals(obj, fromPath)); // add an observer on the object to be notified when the binding should be updated @@ -610,19 +11606,18 @@ define("ember-metal/binding", }, _scheduleSync: function(obj, dir) { - var directionMap = this._directionMap; - var existingDir = directionMap.get(obj); + var existingDir = this._direction; // if we haven't scheduled the binding yet, schedule it - if (!existingDir) { + if (existingDir === undefined) { run.schedule('sync', this, this._sync, obj); - directionMap.set(obj, dir); + this._direction = dir; } // If both a 'back' and 'fwd' sync have been scheduled on the same object, // default to a 'fwd' sync so that it remains deterministic. if (existingDir === 'back' && dir === 'fwd') { - directionMap.set(obj, 'fwd'); + this._direction = 'fwd'; } }, @@ -634,12 +11629,12 @@ define("ember-metal/binding", // get the direction of the binding for the object we are // synchronizing from - var directionMap = this._directionMap; - var direction = directionMap.get(obj); + var direction = this._direction; - var fromPath = this._from, toPath = this._to; + var fromPath = this._from; + var toPath = this._to; - directionMap.remove(obj); + this._direction = undefined; // if we're synchronizing from the remote object... if (direction === 'fwd') { @@ -684,9 +11679,9 @@ define("ember-metal/binding", @method from @static */ - from: function() { - var C = this, binding = new C(); - return binding.from.apply(binding, arguments); + from: function(from) { + var C = this; + return new C(undefined, from); }, /* @@ -695,9 +11690,9 @@ define("ember-metal/binding", @method to @static */ - to: function() { - var C = this, binding = new C(); - return binding.to.apply(binding, arguments); + to: function(to) { + var C = this; + return new C(to, undefined); }, /** @@ -717,12 +11712,11 @@ define("ember-metal/binding", @return {Ember.Binding} `this` */ oneWay: function(from, flag) { - var C = this, binding = new C(null, from); - return binding.oneWay(flag); + var C = this; + return new C(undefined, from).oneWay(flag); } }); - /** An `Ember.Binding` connects the properties of two objects so that whenever the value of one property changes, the other property will be changed also. @@ -735,7 +11729,7 @@ define("ember-metal/binding", Properties ending in a `Binding` suffix will be converted to `Ember.Binding` instances. The value of this property should be a string representing a path - to another object or a custom binding instanced created using Binding helpers + to another object or a custom binding instance created using Binding helpers (see "One Way Bindings"): ``` @@ -791,7 +11785,7 @@ define("ember-metal/binding", something like this on your binding: ```javascript - binding = Ember.Binding.from(this.valueBinding).to("value"); + binding = Ember.Binding.from("valueBinding").to("value"); ``` This creates a new binding instance based on the template you provide, and @@ -808,6 +11802,19 @@ define("ember-metal/binding", to side of the binding when inspecting relative paths. This allows the binding to be automatically inherited by subclassed objects as well. + This also allows you to bind between objects using the paths you declare in + `from` and `to`: + + ```javascript + // Example 1 + binding = Ember.Binding.from("App.someObject.value").to("value"); + binding.connect(this); + + // Example 2 + binding = Ember.Binding.from("parentView.value").to("App.someObject.value"); + binding.connect(this); + ``` + Now that the binding is connected, it will observe both the from and to side and relay changes. @@ -857,9 +11864,9 @@ define("ember-metal/binding", */ function bind(obj, to, from) { return new Binding(to, from).connect(obj); - }; + } - /** + __exports__.bind = bind;/** @method oneWay @for Ember @param {Object} obj The root object of the transform. @@ -871,14 +11878,72 @@ define("ember-metal/binding", */ function oneWay(obj, to, from) { return new Binding(to, from).oneWay().connect(obj); - }; + } - __exports__.Binding = Binding; - __exports__.bind = bind; - __exports__.oneWay = oneWay; + __exports__.oneWay = oneWay;__exports__.Binding = Binding; __exports__.isGlobalPath = isGlobalPath; }); -define("ember-metal/chains", +enifed("ember-metal/cache", + ["ember-metal/dictionary","exports"], + function(__dependency1__, __exports__) { + "use strict"; + var dictionary = __dependency1__["default"]; + __exports__["default"] = Cache; + + function Cache(limit, func) { + this.store = dictionary(null); + this.size = 0; + this.misses = 0; + this.hits = 0; + this.limit = limit; + this.func = func; + } + + var FALSE = function() { }; + var ZERO = function() { }; + var UNDEFINED = function() { }; + var NULL = function() { }; + + Cache.prototype = { + set: function(key, value) { + if (this.limit > this.size) { + this.size ++; + if (value === undefined) { + this.store[key] = UNDEFINED; + } else { + this.store[key] = value; + } + } + + return value; + }, + + get: function(key) { + var value = this.store[key]; + + if (value === undefined) { + this.misses ++; + value = this.set(key, this.func(key)); + } else if (value === UNDEFINED) { + this.hits ++; + value = undefined; + } else { + this.hits ++; + // nothing to translate + } + + return value; + }, + + purge: function() { + this.store = dictionary(null); + this.size = 0; + this.hits = 0; + this.misses = 0; + } + }; + }); +enifed("ember-metal/chains", ["ember-metal/core","ember-metal/property_get","ember-metal/utils","ember-metal/array","ember-metal/watch_key","exports"], function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __exports__) { "use strict"; @@ -887,14 +11952,13 @@ define("ember-metal/chains", var get = __dependency2__.get; var normalizeTuple = __dependency2__.normalizeTuple; var meta = __dependency3__.meta; - var META_KEY = __dependency3__.META_KEY; var forEach = __dependency4__.forEach; var watchKey = __dependency5__.watchKey; var unwatchKey = __dependency5__.unwatchKey; - var metaFor = meta, - warn = Ember.warn, - FIRST_KEY = /^([^\.]+)/; + var metaFor = meta; + var warn = Ember.warn; + var FIRST_KEY = /^([^\.]+)/; function firstKey(path) { return path.match(FIRST_KEY)[0]; @@ -914,13 +11978,13 @@ define("ember-metal/chains", forEach.call(queue, function(q) { q[0].add(q[1]); }); warn('Watching an undefined global, Ember expects watched globals to be setup by the time the run loop is flushed, check for typos', pendingQueue.length === 0); - }; + } - - function addChainWatcher(obj, keyName, node) { + __exports__.flushPendingChains = flushPendingChains;function addChainWatcher(obj, keyName, node) { if (!obj || ('object' !== typeof obj)) { return; } // nothing to do - var m = metaFor(obj), nodes = m.chainWatchers; + var m = metaFor(obj); + var nodes = m.chainWatchers; if (!m.hasOwnProperty('chainWatchers')) { nodes = m.chainWatchers = {}; @@ -934,7 +11998,7 @@ define("ember-metal/chains", function removeChainWatcher(obj, keyName, node) { if (!obj || 'object' !== typeof obj) { return; } // nothing to do - var m = obj[META_KEY]; + var m = obj['__ember_meta__']; if (m && !m.hasOwnProperty('chainWatchers')) { return; } // nothing to do var nodes = m && m.chainWatchers; @@ -942,11 +12006,14 @@ define("ember-metal/chains", if (nodes && nodes[keyName]) { nodes = nodes[keyName]; for (var i = 0, l = nodes.length; i < l; i++) { - if (nodes[i] === node) { nodes.splice(i, 1); } + if (nodes[i] === node) { + nodes.splice(i, 1); + break; + } } } unwatchKey(obj, keyName, m); - }; + } // A ChainNode watches a single key on an object. If you provide a starting // value for the key then the node won't actually watch it. For a root node @@ -978,14 +12045,14 @@ define("ember-metal/chains", if (this._parent && this._parent._key === '@each') { this.value(); } - }; + } var ChainNodePrototype = ChainNode.prototype; function lazyGet(obj, key) { if (!obj) return undefined; - var meta = obj[META_KEY]; + var meta = obj['__ember_meta__']; // check if object meant only to be a prototype if (meta && meta.proto === obj) return undefined; @@ -1022,8 +12089,10 @@ define("ember-metal/chains", // copies a top level object only ChainNodePrototype.copy = function(obj) { - var ret = new ChainNode(null, null, obj), - paths = this._paths, path; + var ret = new ChainNode(null, null, obj); + var paths = this._paths; + var path; + for (path in paths) { if (paths[path] <= 0) { continue; } // this check will also catch non-number vals. ret.add(path); @@ -1093,7 +12162,8 @@ define("ember-metal/chains", ChainNodePrototype.count = 0; ChainNodePrototype.chain = function(key, path, src) { - var chains = this._chains, node; + var chains = this._chains; + var node; if (!chains) { chains = this._chains = {}; } node = chains[key]; @@ -1101,7 +12171,7 @@ define("ember-metal/chains", node.count++; // count chains... // chain rest of path if there is one - if (path && path.length>0) { + if (path) { key = firstKey(path); path = path.slice(key.length+1); node.chain(key, path); // NOTE: no src means it will observe changes... @@ -1109,7 +12179,8 @@ define("ember-metal/chains", }; ChainNodePrototype.unchain = function(key, path) { - var chains = this._chains, node = chains[key]; + var chains = this._chains; + var node = chains[key]; // unchain rest of path first... if (path && path.length>1) { @@ -1205,45 +12276,50 @@ define("ember-metal/chains", function finishChains(obj) { // We only create meta if we really have to - var m = obj[META_KEY], chains = m && m.chains; - if (chains) { - if (chains.value() !== obj) { + var m = obj['__ember_meta__'], + chains, chainWatchers, chainNodes; + if (m) { + // finish any current chains node watchers that reference obj + chainWatchers = m.chainWatchers; + if (chainWatchers) { + for(var key in chainWatchers) { + if (!chainWatchers.hasOwnProperty(key)) { continue; } + chainNodes = chainWatchers[key]; + if (chainNodes) { + for (var i=0,l=chainNodes.length;i 1) { - args = a_slice.call(arguments, 0, -1); - func = a_slice.call(arguments, -1)[0]; + args = a_slice.call(arguments); + func = args.pop(); } if (typeof func !== "function") { @@ -1782,7 +12866,7 @@ define("ember-metal/computed", } return cp; - }; + } /** Returns the cached value for a property, if one exists. @@ -1798,13 +12882,13 @@ define("ember-metal/computed", @return {Object} the cached value */ function cacheFor(obj, key) { - var meta = obj[META_KEY], - cache = meta && meta.cache, - ret = cache && cache[key]; + var meta = obj['__ember_meta__']; + var cache = meta && meta.cache; + var ret = cache && cache[key]; if (ret === UNDEFINED) { return undefined; } return ret; - }; + } cacheFor.set = function(cache, key, value) { if (value === undefined) { @@ -1824,6 +12908,28 @@ define("ember-metal/computed", cache[key] = undefined; }; + __exports__.ComputedProperty = ComputedProperty; + __exports__.computed = computed; + __exports__.cacheFor = cacheFor; + }); +enifed("ember-metal/computed_macros", + ["ember-metal/core","ember-metal/property_get","ember-metal/property_set","ember-metal/computed","ember-metal/is_empty","ember-metal/is_none","ember-metal/alias"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__) { + "use strict"; + var Ember = __dependency1__["default"]; + var get = __dependency2__.get; + var set = __dependency3__.set; + var computed = __dependency4__.computed; + var isEmpty = __dependency5__["default"]; + var isNone = __dependency6__.isNone; + var alias = __dependency7__.alias; + + /** + @module ember-metal + */ + + var a_slice = [].slice; + function getProperties(self, propertyNames) { var ret = {}; for(var i = 0; i < propertyNames.length; i++) { @@ -1839,7 +12945,7 @@ define("ember-metal/computed", return macro.apply(this, args); }); }; - }; + } function registerComputedWithProperties(name, macro) { computed[name] = function() { @@ -1851,7 +12957,7 @@ define("ember-metal/computed", return computedFunc.property.apply(computedFunc, properties); }; - }; + } /** A computed property that returns true if the value of the dependent @@ -1890,15 +12996,11 @@ define("ember-metal/computed", A computed property that returns true if the value of the dependent property is NOT null, an empty string, empty array, or empty function. - Note: When using `computed.notEmpty` to watch an array make sure to - use the `array.[]` syntax so the computed can subscribe to transitions - from empty to non-empty states. - Example ```javascript var Hamster = Ember.Object.extend({ - hasStuff: Ember.computed.notEmpty('backpack.[]') + hasStuff: Ember.computed.notEmpty('backpack') }); var hamster = Hamster.create({ backpack: ['Food', 'Sleeping Bag', 'Tent'] }); @@ -1914,9 +13016,11 @@ define("ember-metal/computed", @return {Ember.ComputedProperty} computed property which returns true if original value for property is not empty. */ - registerComputed('notEmpty', function(dependentKey) { - return !isEmpty(get(this, dependentKey)); - }); + computed.notEmpty = function(dependentKey) { + return computed(dependentKey + '.length', function () { + return !isEmpty(get(this, dependentKey)); + }); + }; /** A computed property that returns true if the value of the dependent @@ -2072,7 +13176,7 @@ define("ember-metal/computed", }); /** - A computed property that returns true if the provied dependent property + A computed property that returns true if the provided dependent property is greater than the provided value. Example @@ -2096,7 +13200,7 @@ define("ember-metal/computed", @param {String} dependentKey @param {Number} value @return {Ember.ComputedProperty} computed property which returns true if - the original value for property is greater then given value. + the original value for property is greater than given value. */ registerComputed('gt', function(dependentKey, value) { return get(this, dependentKey) > value; @@ -2189,7 +13293,7 @@ define("ember-metal/computed", @param {String} dependentKey @param {Number} value @return {Ember.ComputedProperty} computed property which returns true if - the original value for property is less or equal then given value. + the original value for property is less or equal than given value. */ registerComputed('lte', function(dependentKey, value) { return get(this, dependentKey) <= value; @@ -2319,7 +13423,7 @@ define("ember-metal/computed", @for Ember @param {String} dependentKey* @return {Ember.ComputedProperty} computed property which maps - values of all passed properties in to an array. + values of all passed in properties to an array. */ registerComputedWithProperties('collect', function(properties) { var res = []; @@ -2361,16 +13465,7 @@ define("ember-metal/computed", @return {Ember.ComputedProperty} computed property which creates an alias to the original value for property. */ - computed.alias = function(dependentKey) { - return computed(dependentKey, function(key, value) { - if (arguments.length > 1) { - set(this, dependentKey, value); - return get(this, dependentKey); - } else { - return get(this, dependentKey); - } - }); - }; + computed.alias = alias; /** Where `computed.alias` aliases `get` and `set`, and allows for bidirectional @@ -2405,12 +13500,21 @@ define("ember-metal/computed", one way computed property to the original value for property. */ computed.oneWay = function(dependentKey) { - return computed(dependentKey, function() { - return get(this, dependentKey); - }); + return alias(dependentKey).oneWay(); }; - + /** + This is a more semantically meaningful alias of `computed.oneWay`, + whose name is somewhat ambiguous as to which direction the data flows. + + @method computed.reads + @for Ember + @param {String} dependentKey + @return {Ember.ComputedProperty} computed property which creates a + one way computed property to the original value for property. + */ + computed.reads = computed.oneWay; + /** Where `computed.oneWay` provides oneWay bindings, `computed.readOnly` provides a readOnly one way binding. Very often when using `computed.oneWay` one does @@ -2446,9 +13550,7 @@ define("ember-metal/computed", @since 1.5.0 */ computed.readOnly = function(dependentKey) { - return computed(dependentKey, function() { - return get(this, dependentKey); - }).readOnly(); + return alias(dependentKey).readOnly(); }; /** A computed property that acts like a standard getter and setter, @@ -2475,10 +13577,13 @@ define("ember-metal/computed", @param {String} defaultPath @return {Ember.ComputedProperty} computed property which acts like a standard getter and setter, but defaults to the value from `defaultPath`. + @deprecated Use `Ember.computed.oneWay` or custom CP with default instead. */ // ES6TODO: computed should have its own export path so you can do import {defaultTo} from computed computed.defaultTo = function(defaultPath) { return computed(function(key, newValue, cachedValue) { + Ember.deprecate('Usage of Ember.computed.defaultTo is deprecated, use `Ember.computed.oneWay` instead.'); + if (arguments.length === 1) { return get(this, defaultPath); } @@ -2486,15 +13591,37 @@ define("ember-metal/computed", }); }; - __exports__.ComputedProperty = ComputedProperty; - __exports__.computed = computed; - __exports__.cacheFor = cacheFor; + /** + Creates a new property that is an alias for another property + on an object. Calls to `get` or `set` this property behave as + though they were called on the original property, but also + print a deprecation warning. + + @method computed.deprecatingAlias + @for Ember + @param {String} dependentKey + @return {Ember.ComputedProperty} computed property which creates an + alias with a deprecation to the original value for property. + @since 1.7.0 + */ + computed.deprecatingAlias = function(dependentKey) { + return computed(dependentKey, function(key, value) { + Ember.deprecate('Usage of `' + key + '` is deprecated, use `' + dependentKey + '` instead.'); + + if (arguments.length > 1) { + set(this, dependentKey, value); + return value; + } else { + return get(this, dependentKey); + } + }); + }; }); -define("ember-metal/core", +enifed("ember-metal/core", ["exports"], function(__exports__) { "use strict"; - /*globals Em:true ENV EmberENV MetamorphENV:true */ + /*globals Ember:true,Em:true,ENV,EmberENV,MetamorphENV:true */ /** @module ember @@ -2518,7 +13645,7 @@ define("ember-metal/core", @class Ember @static - @version 1.6.1 + @version 1.8.1 */ if ('undefined' === typeof Ember) { @@ -2545,10 +13672,10 @@ define("ember-metal/core", /** @property VERSION @type String - @default '1.6.1' + @default '1.8.1' @static */ - Ember.VERSION = '1.6.1'; + Ember.VERSION = '1.8.1'; /** Standard environmental variables. You can define these in a global `EmberENV` @@ -2585,7 +13712,7 @@ define("ember-metal/core", MetamorphENV.DISABLE_RANGE_API = Ember.ENV.DISABLE_RANGE_API; /** - Hash of enabled Canary features. Add to before creating your application. + Hash of enabled Canary features. Add to this before creating your application. You can also define `ENV.FEATURES` if you need to enable features flagged at runtime. @@ -2687,8 +13814,10 @@ define("ember-metal/core", @private @return {Object} */ - Ember.K = function() { return this; }; - + var K = function() { return this; }; + var K = K; + __exports__.K = K;Ember.K = K; + //TODO: ES6 GLOBL TODO // Stub out the methods defined by the ember-debug package in case it's not loaded @@ -2701,35 +13830,169 @@ define("ember-metal/core", Ember.deprecateFunc = function(_, func) { return func; }; } - /** - Previously we used `Ember.$.uuid`, however `$.uuid` has been removed from - jQuery master. We'll just bootstrap our own uuid now. - - @property uuid - @type Number - @private - */ - Ember.uuid = 0; - __exports__["default"] = Ember; }); -define("ember-metal/enumerable_utils", +enifed("ember-metal/dependent_keys", + ["ember-metal/platform","ember-metal/watching","exports"], + function(__dependency1__, __dependency2__, __exports__) { + // Remove "use strict"; from transpiled module until + // https://bugs.webkit.org/show_bug.cgi?id=138038 is fixed + // + // REMOVE_USE_STRICT: true + + var o_create = __dependency1__.create; + var watch = __dependency2__.watch; + var unwatch = __dependency2__.unwatch; + + /** + @module ember-metal + */ + + // .......................................................... + // DEPENDENT KEYS + // + + // data structure: + // meta.deps = { + // 'depKey': { + // 'keyName': count, + // } + // } + + /* + This function returns a map of unique dependencies for a + given object and key. + */ + function keysForDep(depsMeta, depKey) { + var keys = depsMeta[depKey]; + if (!keys) { + // if there are no dependencies yet for a the given key + // create a new empty list of dependencies for the key + keys = depsMeta[depKey] = {}; + } else if (!depsMeta.hasOwnProperty(depKey)) { + // otherwise if the dependency list is inherited from + // a superclass, clone the hash + keys = depsMeta[depKey] = o_create(keys); + } + return keys; + } + + function metaForDeps(meta) { + return keysForDep(meta, 'deps'); + } + + function addDependentKeys(desc, obj, keyName, meta) { + // the descriptor has a list of dependent keys, so + // add all of its dependent keys. + var depKeys = desc._dependentKeys, depsMeta, idx, len, depKey, keys; + if (!depKeys) return; + + depsMeta = metaForDeps(meta); + + for(idx = 0, len = depKeys.length; idx < len; idx++) { + depKey = depKeys[idx]; + // Lookup keys meta for depKey + keys = keysForDep(depsMeta, depKey); + // Increment the number of times depKey depends on keyName. + keys[keyName] = (keys[keyName] || 0) + 1; + // Watch the depKey + watch(obj, depKey, meta); + } + } + + __exports__.addDependentKeys = addDependentKeys;function removeDependentKeys(desc, obj, keyName, meta) { + // the descriptor has a list of dependent keys, so + // remove all of its dependent keys. + var depKeys = desc._dependentKeys, depsMeta, idx, len, depKey, keys; + if (!depKeys) return; + + depsMeta = metaForDeps(meta); + + for(idx = 0, len = depKeys.length; idx < len; idx++) { + depKey = depKeys[idx]; + // Lookup keys meta for depKey + keys = keysForDep(depsMeta, depKey); + // Decrement the number of times depKey depends on keyName. + keys[keyName] = (keys[keyName] || 0) - 1; + // Unwatch the depKey + unwatch(obj, depKey, meta); + } + } + + __exports__.removeDependentKeys = removeDependentKeys; + }); +enifed("ember-metal/deprecate_property", + ["ember-metal/core","ember-metal/platform","ember-metal/properties","ember-metal/property_get","ember-metal/property_set","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __exports__) { + "use strict"; + /** + @module ember-metal + */ + + var Ember = __dependency1__["default"]; + var hasPropertyAccessors = __dependency2__.hasPropertyAccessors; + var defineProperty = __dependency3__.defineProperty; + var get = __dependency4__.get; + var set = __dependency5__.set; + + + /** + Used internally to allow changing properties in a backwards compatible way, and print a helpful + deprecation warning. + + @method deprecateProperty + @param {Object} object The object to add the deprecated property to. + @param {String} deprecatedKey The property to add (and print deprecation warnings upon accessing). + @param {String} newKey The property that will be aliased. + @private + @since 1.7.0 + */ + + function deprecateProperty(object, deprecatedKey, newKey) { + function deprecate() { + Ember.deprecate('Usage of `' + deprecatedKey + '` is deprecated, use `' + newKey + '` instead.'); + } + + if (hasPropertyAccessors) { + defineProperty(object, deprecatedKey, { + configurable: true, + enumerable: false, + set: function(value) { deprecate(); set(this, newKey, value); }, + get: function() { deprecate(); return get(this, newKey); } + }); + } + } + + __exports__.deprecateProperty = deprecateProperty; + }); +enifed("ember-metal/dictionary", + ["ember-metal/platform","exports"], + function(__dependency1__, __exports__) { + "use strict"; + var create = __dependency1__.create; + + // the delete is meant to hint at runtimes that this object should remain in + // dictionary mode. This is clearly a runtime specific hack, but currently it + // appears worthwile in some usecases. Please note, these deletes do increase + // the cost of creation dramatically over a plain Object.create. And as this + // only makes sense for long-lived dictionaries that aren't instantiated often. + __exports__["default"] = function makeDictionary(parent) { + var dict = create(parent); + dict['_dict'] = null; + delete dict['_dict']; + return dict; + } + }); +enifed("ember-metal/enumerable_utils", ["ember-metal/array","exports"], function(__dependency1__, __exports__) { "use strict"; - var map, forEach, indexOf, splice, filter; + var _filter = __dependency1__.filter; + var a_forEach = __dependency1__.forEach; + var _indexOf = __dependency1__.indexOf; + var _map = __dependency1__.map; - var map = __dependency1__.map; - var forEach = __dependency1__.forEach; - var indexOf = __dependency1__.indexOf; - var filter = __dependency1__.filter; - - // ES6TODO: doesn't array polyfills already do this? - map = Array.prototype.map || map; - forEach = Array.prototype.forEach || forEach; - indexOf = Array.prototype.indexOf || indexOf; - filter = Array.prototype.filter || filter; - splice = Array.prototype.splice; + var splice = Array.prototype.splice; /** * Defines some convenience methods for working with Enumerables. @@ -2739,219 +14002,242 @@ define("ember-metal/enumerable_utils", * @namespace Ember * @static * */ - var utils = { - /** - * Calls the map function on the passed object with a specified callback. This - * uses `Ember.ArrayPolyfill`'s-map method when necessary. - * - * @method map - * @param {Object} obj The object that should be mapped - * @param {Function} callback The callback to execute - * @param {Object} thisArg Value to use as this when executing *callback* - * - * @return {Array} An array of mapped values. - */ - map: function(obj, callback, thisArg) { - return obj.map ? obj.map.call(obj, callback, thisArg) : map.call(obj, callback, thisArg); - }, - /** - * Calls the forEach function on the passed object with a specified callback. This - * uses `Ember.ArrayPolyfill`'s-forEach method when necessary. - * - * @method forEach - * @param {Object} obj The object to call forEach on - * @param {Function} callback The callback to execute - * @param {Object} thisArg Value to use as this when executing *callback* - * - */ - forEach: function(obj, callback, thisArg) { - return obj.forEach ? obj.forEach.call(obj, callback, thisArg) : forEach.call(obj, callback, thisArg); - }, + /** + * Calls the map function on the passed object with a specified callback. This + * uses `Ember.ArrayPolyfill`'s-map method when necessary. + * + * @method map + * @param {Object} obj The object that should be mapped + * @param {Function} callback The callback to execute + * @param {Object} thisArg Value to use as this when executing *callback* + * + * @return {Array} An array of mapped values. + */ + function map(obj, callback, thisArg) { + return obj.map ? obj.map(callback, thisArg) : _map.call(obj, callback, thisArg); + } - /** - * Calls the filter function on the passed object with a specified callback. This - * uses `Ember.ArrayPolyfill`'s-filter method when necessary. - * - * @method filter - * @param {Object} obj The object to call filter on - * @param {Function} callback The callback to execute - * @param {Object} thisArg Value to use as this when executing *callback* - * - * @return {Array} An array containing the filtered values - * @since 1.4.0 - */ - filter: function(obj, callback, thisArg) { - return obj.filter ? obj.filter.call(obj, callback, thisArg) : filter.call(obj, callback, thisArg); - }, + __exports__.map = map;/** + * Calls the forEach function on the passed object with a specified callback. This + * uses `Ember.ArrayPolyfill`'s-forEach method when necessary. + * + * @method forEach + * @param {Object} obj The object to call forEach on + * @param {Function} callback The callback to execute + * @param {Object} thisArg Value to use as this when executing *callback* + * + */ + function forEach(obj, callback, thisArg) { + return obj.forEach ? obj.forEach(callback, thisArg) : a_forEach.call(obj, callback, thisArg); + } - /** - * Calls the indexOf function on the passed object with a specified callback. This - * uses `Ember.ArrayPolyfill`'s-indexOf method when necessary. - * - * @method indexOf - * @param {Object} obj The object to call indexOn on - * @param {Function} callback The callback to execute - * @param {Object} index The index to start searching from - * - */ - indexOf: function(obj, element, index) { - return obj.indexOf ? obj.indexOf.call(obj, element, index) : indexOf.call(obj, element, index); - }, + __exports__.forEach = forEach;/** + * Calls the filter function on the passed object with a specified callback. This + * uses `Ember.ArrayPolyfill`'s-filter method when necessary. + * + * @method filter + * @param {Object} obj The object to call filter on + * @param {Function} callback The callback to execute + * @param {Object} thisArg Value to use as this when executing *callback* + * + * @return {Array} An array containing the filtered values + * @since 1.4.0 + */ + function filter(obj, callback, thisArg) { + return obj.filter ? obj.filter(callback, thisArg) : _filter.call(obj, callback, thisArg); + } - /** - * Returns an array of indexes of the first occurrences of the passed elements - * on the passed object. - * - * ```javascript - * var array = [1, 2, 3, 4, 5]; - * Ember.EnumerableUtils.indexesOf(array, [2, 5]); // [1, 4] - * - * var fubar = "Fubarr"; - * Ember.EnumerableUtils.indexesOf(fubar, ['b', 'r']); // [2, 4] - * ``` - * - * @method indexesOf - * @param {Object} obj The object to check for element indexes - * @param {Array} elements The elements to search for on *obj* - * - * @return {Array} An array of indexes. - * - */ - indexesOf: function(obj, elements) { - return elements === undefined ? [] : utils.map(elements, function(item) { - return utils.indexOf(obj, item); - }); - }, + __exports__.filter = filter;/** + * Calls the indexOf function on the passed object with a specified callback. This + * uses `Ember.ArrayPolyfill`'s-indexOf method when necessary. + * + * @method indexOf + * @param {Object} obj The object to call indexOn on + * @param {Function} callback The callback to execute + * @param {Object} index The index to start searching from + * + */ + function indexOf(obj, element, index) { + return obj.indexOf ? obj.indexOf(element, index) : _indexOf.call(obj, element, index); + } - /** - * Adds an object to an array. If the array already includes the object this - * method has no effect. - * - * @method addObject - * @param {Array} array The array the passed item should be added to - * @param {Object} item The item to add to the passed array - * - * @return 'undefined' - */ - addObject: function(array, item) { - var index = utils.indexOf(array, item); - if (index === -1) { array.push(item); } - }, + __exports__.indexOf = indexOf;/** + * Returns an array of indexes of the first occurrences of the passed elements + * on the passed object. + * + * ```javascript + * var array = [1, 2, 3, 4, 5]; + * Ember.EnumerableUtils.indexesOf(array, [2, 5]); // [1, 4] + * + * var fubar = "Fubarr"; + * Ember.EnumerableUtils.indexesOf(fubar, ['b', 'r']); // [2, 4] + * ``` + * + * @method indexesOf + * @param {Object} obj The object to check for element indexes + * @param {Array} elements The elements to search for on *obj* + * + * @return {Array} An array of indexes. + * + */ + function indexesOf(obj, elements) { + return elements === undefined ? [] : map(elements, function(item) { + return indexOf(obj, item); + }); + } - /** - * Removes an object from an array. If the array does not contain the passed - * object this method has no effect. - * - * @method removeObject - * @param {Array} array The array to remove the item from. - * @param {Object} item The item to remove from the passed array. - * - * @return 'undefined' - */ - removeObject: function(array, item) { - var index = utils.indexOf(array, item); - if (index !== -1) { array.splice(index, 1); } - }, + __exports__.indexesOf = indexesOf;/** + * Adds an object to an array. If the array already includes the object this + * method has no effect. + * + * @method addObject + * @param {Array} array The array the passed item should be added to + * @param {Object} item The item to add to the passed array + * + * @return 'undefined' + */ + function addObject(array, item) { + var index = indexOf(array, item); + if (index === -1) { array.push(item); } + } - _replace: function(array, idx, amt, objects) { - var args = [].concat(objects), chunk, ret = [], - // https://code.google.com/p/chromium/issues/detail?id=56588 - size = 60000, start = idx, ends = amt, count; + __exports__.addObject = addObject;/** + * Removes an object from an array. If the array does not contain the passed + * object this method has no effect. + * + * @method removeObject + * @param {Array} array The array to remove the item from. + * @param {Object} item The item to remove from the passed array. + * + * @return 'undefined' + */ + function removeObject(array, item) { + var index = indexOf(array, item); + if (index !== -1) { array.splice(index, 1); } + } - while (args.length) { - count = ends > size ? size : ends; - if (count <= 0) { count = 0; } + __exports__.removeObject = removeObject;function _replace(array, idx, amt, objects) { + var args = [].concat(objects); + var ret = []; + // https://code.google.com/p/chromium/issues/detail?id=56588 + var size = 60000; + var start = idx; + var ends = amt; + var count, chunk; - chunk = args.splice(0, size); - chunk = [start, count].concat(chunk); + while (args.length) { + count = ends > size ? size : ends; + if (count <= 0) { count = 0; } - start += size; - ends -= count; + chunk = args.splice(0, size); + chunk = [start, count].concat(chunk); - ret = ret.concat(splice.apply(array, chunk)); - } - return ret; - }, + start += size; + ends -= count; - /** - * Replaces objects in an array with the passed objects. - * - * ```javascript - * var array = [1,2,3]; - * Ember.EnumerableUtils.replace(array, 1, 2, [4, 5]); // [1, 4, 5] - * - * var array = [1,2,3]; - * Ember.EnumerableUtils.replace(array, 1, 1, [4, 5]); // [1, 4, 5, 3] - * - * var array = [1,2,3]; - * Ember.EnumerableUtils.replace(array, 10, 1, [4, 5]); // [1, 2, 3, 4, 5] - * ``` - * - * @method replace - * @param {Array} array The array the objects should be inserted into. - * @param {Number} idx Starting index in the array to replace. If *idx* >= - * length, then append to the end of the array. - * @param {Number} amt Number of elements that should be removed from the array, - * starting at *idx* - * @param {Array} objects An array of zero or more objects that should be - * inserted into the array at *idx* - * - * @return {Array} The modified array. - */ - replace: function(array, idx, amt, objects) { - if (array.replace) { - return array.replace(idx, amt, objects); - } else { - return utils._replace(array, idx, amt, objects); - } - }, - - /** - * Calculates the intersection of two arrays. This method returns a new array - * filled with the records that the two passed arrays share with each other. - * If there is no intersection, an empty array will be returned. - * - * ```javascript - * var array1 = [1, 2, 3, 4, 5]; - * var array2 = [1, 3, 5, 6, 7]; - * - * Ember.EnumerableUtils.intersection(array1, array2); // [1, 3, 5] - * - * var array1 = [1, 2, 3]; - * var array2 = [4, 5, 6]; - * - * Ember.EnumerableUtils.intersection(array1, array2); // [] - * ``` - * - * @method intersection - * @param {Array} array1 The first array - * @param {Array} array2 The second array - * - * @return {Array} The intersection of the two passed arrays. - */ - intersection: function(array1, array2) { - var intersection = []; - - utils.forEach(array1, function(element) { - if (utils.indexOf(array2, element) >= 0) { - intersection.push(element); - } - }); - - return intersection; + ret = ret.concat(splice.apply(array, chunk)); } - }; + return ret; + } - __exports__["default"] = utils; + __exports__._replace = _replace;/** + * Replaces objects in an array with the passed objects. + * + * ```javascript + * var array = [1,2,3]; + * Ember.EnumerableUtils.replace(array, 1, 2, [4, 5]); // [1, 4, 5] + * + * var array = [1,2,3]; + * Ember.EnumerableUtils.replace(array, 1, 1, [4, 5]); // [1, 4, 5, 3] + * + * var array = [1,2,3]; + * Ember.EnumerableUtils.replace(array, 10, 1, [4, 5]); // [1, 2, 3, 4, 5] + * ``` + * + * @method replace + * @param {Array} array The array the objects should be inserted into. + * @param {Number} idx Starting index in the array to replace. If *idx* >= + * length, then append to the end of the array. + * @param {Number} amt Number of elements that should be removed from the array, + * starting at *idx* + * @param {Array} objects An array of zero or more objects that should be + * inserted into the array at *idx* + * + * @return {Array} The modified array. + */ + function replace(array, idx, amt, objects) { + if (array.replace) { + return array.replace(idx, amt, objects); + } else { + return _replace(array, idx, amt, objects); + } + } + + __exports__.replace = replace;/** + * Calculates the intersection of two arrays. This method returns a new array + * filled with the records that the two passed arrays share with each other. + * If there is no intersection, an empty array will be returned. + * + * ```javascript + * var array1 = [1, 2, 3, 4, 5]; + * var array2 = [1, 3, 5, 6, 7]; + * + * Ember.EnumerableUtils.intersection(array1, array2); // [1, 3, 5] + * + * var array1 = [1, 2, 3]; + * var array2 = [4, 5, 6]; + * + * Ember.EnumerableUtils.intersection(array1, array2); // [] + * ``` + * + * @method intersection + * @param {Array} array1 The first array + * @param {Array} array2 The second array + * + * @return {Array} The intersection of the two passed arrays. + */ + function intersection(array1, array2) { + var result = []; + forEach(array1, function(element) { + if (indexOf(array2, element) >= 0) { + result.push(element); + } + }); + + return result; + } + + __exports__.intersection = intersection;// TODO: this only exists to maintain the existing api, as we move forward it + // should only be part of the "global build" via some shim + __exports__["default"] = { + _replace: _replace, + addObject: addObject, + filter: filter, + forEach: forEach, + indexOf: indexOf, + indexesOf: indexesOf, + intersection: intersection, + map: map, + removeObject: removeObject, + replace: replace + }; }); -define("ember-metal/error", +enifed("ember-metal/error", ["ember-metal/platform","exports"], function(__dependency1__, __exports__) { "use strict"; var create = __dependency1__.create; - var errorProps = ['description', 'fileName', 'lineNumber', 'message', 'name', 'number', 'stack']; + var errorProps = [ + 'description', + 'fileName', + 'lineNumber', + 'message', + 'name', + 'number', + 'stack' + ]; /** A subclass of the JavaScript Error object for use in Ember. @@ -2961,7 +14247,7 @@ define("ember-metal/error", @extends Error @constructor */ - var EmberError = function() { + function EmberError() { var tmp = Error.apply(this, arguments); // Adds a `stack` property to the given error object that will yield the @@ -2978,31 +14264,36 @@ define("ember-metal/error", for (var idx = 0; idx < errorProps.length; idx++) { this[errorProps[idx]] = tmp[errorProps[idx]]; } - }; + } EmberError.prototype = create(Error.prototype); __exports__["default"] = EmberError; }); -define("ember-metal/events", +enifed("ember-metal/events", ["ember-metal/core","ember-metal/utils","ember-metal/platform","exports"], function(__dependency1__, __dependency2__, __dependency3__, __exports__) { - "use strict"; + // Remove "use strict"; from transpiled module until + // https://bugs.webkit.org/show_bug.cgi?id=138038 is fixed + // + // REMOVE_USE_STRICT: true + /** @module ember-metal */ var Ember = __dependency1__["default"]; var meta = __dependency2__.meta; - var META_KEY = __dependency2__.META_KEY; var tryFinally = __dependency2__.tryFinally; var apply = __dependency2__.apply; var applyStr = __dependency2__.applyStr; var create = __dependency3__.create; - var a_slice = [].slice, - metaFor = meta, - /* listener flags */ - ONCE = 1, SUSPENDED = 2; + var a_slice = [].slice; + var metaFor = meta; + + /* listener flags */ + var ONCE = 1; + var SUSPENDED = 2; /* @@ -3037,8 +14328,8 @@ define("ember-metal/events", } function actionsFor(obj, eventName) { - var meta = metaFor(obj, true), - actions; + var meta = metaFor(obj, true); + var actions; if (!meta.listeners) { meta.listeners = {}; } @@ -3060,15 +14351,15 @@ define("ember-metal/events", } function listenersUnion(obj, eventName, otherActions) { - var meta = obj[META_KEY], - actions = meta && meta.listeners && meta.listeners[eventName]; + var meta = obj['__ember_meta__']; + var actions = meta && meta.listeners && meta.listeners[eventName]; if (!actions) { return; } for (var i = actions.length - 3; i >= 0; i -= 3) { - var target = actions[i], - method = actions[i+1], - flags = actions[i+2], - actionIndex = indexOf(otherActions, target, method); + var target = actions[i]; + var method = actions[i+1]; + var flags = actions[i+2]; + var actionIndex = indexOf(otherActions, target, method); if (actionIndex === -1) { otherActions.push(target, method, flags); @@ -3076,17 +14367,17 @@ define("ember-metal/events", } } - function listenersDiff(obj, eventName, otherActions) { - var meta = obj[META_KEY], - actions = meta && meta.listeners && meta.listeners[eventName], - diffActions = []; + __exports__.listenersUnion = listenersUnion;function listenersDiff(obj, eventName, otherActions) { + var meta = obj['__ember_meta__']; + var actions = meta && meta.listeners && meta.listeners[eventName]; + var diffActions = []; if (!actions) { return; } for (var i = actions.length - 3; i >= 0; i -= 3) { - var target = actions[i], - method = actions[i+1], - flags = actions[i+2], - actionIndex = indexOf(otherActions, target, method); + var target = actions[i]; + var method = actions[i+1]; + var flags = actions[i+2]; + var actionIndex = indexOf(otherActions, target, method); if (actionIndex !== -1) { continue; } @@ -3097,7 +14388,7 @@ define("ember-metal/events", return diffActions; } - /** + __exports__.listenersDiff = listenersDiff;/** Add an event listener @method addListener @@ -3116,9 +14407,9 @@ define("ember-metal/events", target = null; } - var actions = actionsFor(obj, eventName), - actionIndex = indexOf(actions, target, method), - flags = 0; + var actions = actionsFor(obj, eventName); + var actionIndex = indexOf(actions, target, method); + var flags = 0; if (once) flags |= ONCE; @@ -3131,7 +14422,7 @@ define("ember-metal/events", } } - /** + __exports__.addListener = addListener;/** Remove an event listener Arguments should match those passed to `Ember.addListener`. @@ -3152,8 +14443,8 @@ define("ember-metal/events", } function _removeListener(target, method) { - var actions = actionsFor(obj, eventName), - actionIndex = indexOf(actions, target, method); + var actions = actionsFor(obj, eventName); + var actionIndex = indexOf(actions, target, method); // action doesn't exist, give up silently if (actionIndex === -1) { return; } @@ -3168,8 +14459,8 @@ define("ember-metal/events", if (method) { _removeListener(target, method); } else { - var meta = obj[META_KEY], - actions = meta && meta.listeners && meta.listeners[eventName]; + var meta = obj['__ember_meta__']; + var actions = meta && meta.listeners && meta.listeners[eventName]; if (!actions) { return; } for (var i = actions.length - 3; i >= 0; i -= 3) { @@ -3202,8 +14493,8 @@ define("ember-metal/events", target = null; } - var actions = actionsFor(obj, eventName), - actionIndex = indexOf(actions, target, method); + var actions = actionsFor(obj, eventName); + var actionIndex = indexOf(actions, target, method); if (actionIndex !== -1) { actions[actionIndex+2] |= SUSPENDED; // mark the action as suspended @@ -3215,7 +14506,7 @@ define("ember-metal/events", return tryFinally(tryable, finalizer); } - /** + __exports__.suspendListener = suspendListener;/** Suspends multiple listeners during a callback. @method suspendListeners @@ -3234,9 +14525,9 @@ define("ember-metal/events", target = null; } - var suspendedActions = [], - actionsList = [], - eventName, actions, i, l; + var suspendedActions = []; + var actionsList = []; + var eventName, actions, i, l; for (i=0, l=eventNames.length; i 'foo.bar' - Ember.expandProperties('{foo,bar}', echo); //=> 'foo', 'bar' - Ember.expandProperties('foo.{bar,baz}', echo); //=> 'foo.bar', 'foo.baz' - Ember.expandProperties('{foo,bar}.baz', echo); //=> '{foo,bar}.baz' + Ember.expandProperties('foo.bar', echo); //=> 'foo.bar' + Ember.expandProperties('{foo,bar}', echo); //=> 'foo', 'bar' + Ember.expandProperties('foo.{bar,baz}', echo); //=> 'foo.bar', 'foo.baz' + Ember.expandProperties('{foo,bar}.baz', echo); //=> '{foo,bar}.baz' + Ember.expandProperties('foo.{bar,baz}.@each', echo) //=> 'foo.bar.@each', 'foo.baz.@each' + Ember.expandProperties('{foo,bar}.{spam,eggs}', echo) //=> 'foo.spam', 'foo.eggs', 'bar.spam', 'bar.eggs' + Ember.expandProperties('{foo}.bar.{baz}') //=> 'foo.bar.baz' ``` @method @private - @param {string} pattern The property pattern to expand. - @param {function} callback The callback to invoke. It is invoked once per + @param {String} pattern The property pattern to expand. + @param {Function} callback The callback to invoke. It is invoked once per expansion, and is passed the expansion. */ - function expandProperties(pattern, callback) { - var match, prefix, list; - + __exports__["default"] = function expandProperties(pattern, callback) { if (pattern.indexOf(' ') > -1) { - throw new EmberError('Brace expanded properties cannot contain spaces, ' + + throw new EmberError('Brace expanded properties cannot contain spaces, ' + 'e.g. `user.{firstName, lastName}` should be `user.{firstName,lastName}`'); } + + return newExpandProperties(pattern, callback); + } + + function oldExpandProperties(pattern, callback) { + var match, prefix, list; + if (match = BRACE_EXPANSION.exec(pattern)) { prefix = match[1]; list = match[2]; @@ -3465,11 +14755,42 @@ define("ember-metal/expand_properties", } else { callback(pattern); } - }; + } - __exports__["default"] = expandProperties; + function newExpandProperties(pattern, callback) { + if ('string' === Ember.typeOf(pattern)) { + var parts = pattern.split(SPLIT_REGEX); + var properties = [parts]; + + forEach(parts, function(part, index) { + if (part.indexOf(',') >= 0) { + properties = duplicateAndReplace(properties, part.split(','), index); + } + }); + + forEach(properties, function(property) { + callback(property.join('')); + }); + } else { + callback(pattern); + } + } + + function duplicateAndReplace(properties, currentParts, index) { + var all = []; + + forEach(properties, function(property) { + forEach(currentParts, function(part) { + var current = property.slice(0); + current[index] = part; + all.push(current); + }); + }); + + return all; + } }); -define("ember-metal/get_properties", +enifed("ember-metal/get_properties", ["ember-metal/property_get","ember-metal/utils","exports"], function(__dependency1__, __dependency2__, __exports__) { "use strict"; @@ -3497,10 +14818,10 @@ define("ember-metal/get_properties", @param {String...|Array} list of keys to get @return {Hash} */ - function getProperties(obj) { - var ret = {}, - propertyNames = arguments, - i = 1; + __exports__["default"] = function getProperties(obj) { + var ret = {}; + var propertyNames = arguments; + var i = 1; if (arguments.length === 2 && typeOf(arguments[1]) === 'array') { i = 0; @@ -3510,11 +14831,9 @@ define("ember-metal/get_properties", ret[propertyNames[i]] = get(obj, propertyNames[i]); } return ret; - }; - - __exports__["default"] = getProperties; + } }); -define("ember-metal/instrumentation", +enifed("ember-metal/instrumentation", ["ember-metal/core","ember-metal/utils","exports"], function(__dependency1__, __dependency2__, __exports__) { "use strict"; @@ -3567,10 +14886,12 @@ define("ember-metal/instrumentation", @namespace Ember @static */ - var subscribers = [], cache = {}; + var subscribers = []; + __exports__.subscribers = subscribers;var cache = {}; var populateListeners = function(name) { - var listeners = [], subscriber; + var listeners = []; + var subscriber; for (var i=0, l=subscribers.length; i -1) { - list.splice(index, 1); + /** + @method delete + @param obj + @param _guid (optional and for internal use only) + @return {Boolean} + */ + "delete": function(obj, _guid) { + var guid = _guid || guidFor(obj); + var presenceSet = this.presenceSet; + var list = this.list; + + if (presenceSet[guid] === true) { + delete presenceSet[guid]; + var index = indexOf.call(list, obj); + if (index > -1) { + list.splice(index, 1); + } + this.size = list.length; + return true; + } else { + return false; } }, @@ -4351,7 +15664,7 @@ define("ember-metal/map", @return {Boolean} */ isEmpty: function() { - return this.list.length === 0; + return this.size === 0; }, /** @@ -4360,10 +15673,12 @@ define("ember-metal/map", @return {Boolean} */ has: function(obj) { - var guid = guidFor(obj), - presenceSet = this.presenceSet; + if (this.size === 0) { return false; } - return guid in presenceSet; + var guid = guidFor(obj); + var presenceSet = this.presenceSet; + + return presenceSet[guid] === true; }, /** @@ -4371,12 +15686,25 @@ define("ember-metal/map", @param {Function} fn @param self */ - forEach: function(fn, self) { - // allow mutation during iteration - var list = this.toArray(); + forEach: function(fn /*, thisArg*/) { + if (typeof fn !== 'function') { + missingFunction(fn); + } - for (var i = 0, j = list.length; i < j; i++) { - fn.call(self, list[i]); + if (this.size === 0) { return; } + + var list = this.list; + var length = arguments.length; + var i; + + if (length === 2) { + for (i = 0; i < list.length; i++) { + fn.call(arguments[1], list[i]); + } + } else { + for (i = 0; i < list.length; i++) { + fn(list[i]); + } } }, @@ -4393,15 +15721,20 @@ define("ember-metal/map", @return {Ember.OrderedSet} */ copy: function() { - var set = new OrderedSet(); + var Constructor = this.constructor; + var set = new Constructor(); - set.presenceSet = copy(this.presenceSet); + set._silenceRemoveDeprecation = this._silenceRemoveDeprecation; + set.presenceSet = copyNull(this.presenceSet); set.list = this.toArray(); + set.size = this.size; return set; } }; + deprecateProperty(OrderedSet.prototype, 'length', 'size'); + /** A Map stores values indexed by keys. Unlike JavaScript's default Objects, the keys of a Map can be any JavaScript @@ -4422,29 +15755,39 @@ define("ember-metal/map", @private @constructor */ - var Map = Ember.Map = function() { - this.keys = OrderedSet.create(); - this.values = {}; - }; + function Map() { + if (this instanceof this.constructor) { + this.keys = OrderedSet.create(); + this.keys._silenceRemoveDeprecation = true; + this.values = create(null); + this.size = 0; + } else { + missingNew("OrderedSet"); + } + } + + Ember.Map = Map; /** @method create @static */ Map.create = function() { - return new Map(); + var Constructor = this; + return new Constructor(); }; Map.prototype = { + constructor: Map, + /** This property will change as the number of objects in the map changes. - @property length + @property size @type number @default 0 */ - length: 0, - + size: 0, /** Retrieve the value associated with a given key. @@ -4454,8 +15797,10 @@ define("ember-metal/map", @return {*} the value associated with the key, or `undefined` */ get: function(key) { - var values = this.values, - guid = guidFor(key); + if (this.size === 0) { return; } + + var values = this.values; + var guid = guidFor(key); return values[guid]; }, @@ -4467,18 +15812,27 @@ define("ember-metal/map", @method set @param {*} key @param {*} value + @return {Ember.Map} */ set: function(key, value) { - var keys = this.keys, - values = this.values, - guid = guidFor(key); + var keys = this.keys; + var values = this.values; + var guid = guidFor(key); + + // ensure we don't store -0 + var k = key === -0 ? 0 : key; + + keys.add(k, guid); - keys.add(key); values[guid] = value; - set(this, 'length', keys.list.length); + + this.size = keys.size; + + return this; }, /** + @deprecated see delete Removes a value from the map for an associated key. @method remove @@ -4486,16 +15840,29 @@ define("ember-metal/map", @return {Boolean} true if an item was removed, false otherwise */ remove: function(key) { + Ember.deprecate('Calling `Map.prototype.remove` has been deprecated, please use `Map.prototype.delete` instead.'); + + return this["delete"](key); + }, + + /** + Removes a value from the map for an associated key. + + @method delete + @param {*} key + @return {Boolean} true if an item was removed, false otherwise + */ + "delete": function(key) { + if (this.size === 0) { return false; } // don't use ES6 "delete" because it will be annoying // to use in browsers that are not ES6 friendly; - var keys = this.keys, - values = this.values, - guid = guidFor(key); + var keys = this.keys; + var values = this.values; + var guid = guidFor(key); - if (values.hasOwnProperty(guid)) { - keys.remove(key); + if (keys["delete"](key, guid)) { delete values[guid]; - set(this, 'length', keys.list.length); + this.size = keys.size; return true; } else { return false; @@ -4510,10 +15877,7 @@ define("ember-metal/map", @return {Boolean} true if the item was present, false otherwise */ has: function(key) { - var values = this.values, - guid = guidFor(key); - - return values.hasOwnProperty(guid); + return this.keys.has(key); }, /** @@ -4527,14 +15891,38 @@ define("ember-metal/map", @param {*} self if passed, the `this` value inside the callback. By default, `this` is the map. */ - forEach: function(callback, self) { - var keys = this.keys, - values = this.values; + forEach: function(callback /*, thisArg*/) { + if (typeof callback !== 'function') { + missingFunction(callback); + } - keys.forEach(function(key) { - var guid = guidFor(key); - callback.call(self, key, values[guid]); - }); + if (this.size === 0) { return; } + + var length = arguments.length; + var map = this; + var cb, thisArg; + + if (length === 2) { + thisArg = arguments[1]; + cb = function(key) { + callback.call(thisArg, map.get(key), key); + }; + } else { + cb = function(key) { + callback(map.get(key), key); + }; + } + + this.keys.forEach(cb); + }, + + /** + @method clear + */ + clear: function() { + this.keys.clear(); + this.values = create(null); + this.size = 0; }, /** @@ -4546,6 +15934,8 @@ define("ember-metal/map", } }; + deprecateProperty(Map.prototype, 'length', 'size'); + /** @class MapWithDefault @namespace Ember @@ -4556,9 +15946,9 @@ define("ember-metal/map", @param {*} [options.defaultValue] */ function MapWithDefault(options) { - Map.call(this); + this._super$constructor(); this.defaultValue = options.defaultValue; - }; + } /** @method create @@ -4577,6 +15967,9 @@ define("ember-metal/map", }; MapWithDefault.prototype = create(Map.prototype); + MapWithDefault.prototype.constructor = MapWithDefault; + MapWithDefault.prototype._super$constructor = Map; + MapWithDefault.prototype._super$get = Map.prototype.get; /** Retrieve the value associated with a given key. @@ -4589,7 +15982,7 @@ define("ember-metal/map", var hasValue = this.has(key); if (hasValue) { - return Map.prototype.get.call(this, key); + return this._super$get(key); } else { var defaultValue = this.defaultValue(key); this.set(key, defaultValue); @@ -4602,19 +15995,24 @@ define("ember-metal/map", @return {Ember.MapWithDefault} */ MapWithDefault.prototype.copy = function() { - return copyMap(this, new MapWithDefault({ + var Constructor = this.constructor; + return copyMap(this, new Constructor({ defaultValue: this.defaultValue })); }; + __exports__["default"] = Map; + __exports__.OrderedSet = OrderedSet; __exports__.Map = Map; __exports__.MapWithDefault = MapWithDefault; }); -define("ember-metal/merge", - ["exports"], - function(__exports__) { +enifed("ember-metal/merge", + ["ember-metal/keys","exports"], + function(__dependency1__, __exports__) { "use strict"; + var keys = __dependency1__["default"]; + /** Merge the contents of two objects together into the first object. @@ -4630,20 +16028,31 @@ define("ember-metal/merge", @param {Object} updates The object to copy properties from @return {Object} */ - function merge(original, updates) { - for (var prop in updates) { - if (!updates.hasOwnProperty(prop)) { continue; } + __exports__["default"] = function merge(original, updates) { + if (!updates || typeof updates !== 'object') { + return original; + } + + var props = keys(updates); + var prop; + var length = props.length; + + for (var i = 0; i < length; i++) { + prop = props[i]; original[prop] = updates[prop]; } - return original; - }; - __exports__["default"] = merge; + return original; + } }); -define("ember-metal/mixin", +enifed("ember-metal/mixin", ["ember-metal/core","ember-metal/merge","ember-metal/array","ember-metal/platform","ember-metal/utils","ember-metal/expand_properties","ember-metal/properties","ember-metal/computed","ember-metal/binding","ember-metal/observer","ember-metal/events","exports"], function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __dependency9__, __dependency10__, __dependency11__, __exports__) { - "use strict"; + // Remove "use strict"; from transpiled module until + // https://bugs.webkit.org/show_bug.cgi?id=138038 is fixed + // + // REMOVE_USE_STRICT: true + /** @module ember @submodule ember-metal @@ -4658,10 +16067,10 @@ define("ember-metal/mixin", var create = __dependency4__.create; var guidFor = __dependency5__.guidFor; var meta = __dependency5__.meta; - var META_KEY = __dependency5__.META_KEY; var wrap = __dependency5__.wrap; var makeArray = __dependency5__.makeArray; var apply = __dependency5__.apply; + var isArray = __dependency5__.isArray; var expandProperties = __dependency6__["default"]; var Descriptor = __dependency7__.Descriptor; var defineProperty = __dependency7__.defineProperty; @@ -4674,27 +16083,32 @@ define("ember-metal/mixin", var addListener = __dependency11__.addListener; var removeListener = __dependency11__.removeListener; - var REQUIRED, Alias, - a_map = map, - a_indexOf = indexOf, - a_forEach = forEach, - a_slice = [].slice, - o_create = create, - defineProperty = defineProperty, - metaFor = meta; + var REQUIRED; + var a_map = map; + var a_indexOf = indexOf; + var a_forEach = forEach; + var a_slice = [].slice; + var o_create = create; + var metaFor = meta; function superFunction(){ - var ret, func = this.__nextSuper; + var func = this.__nextSuper; + var ret; if (func) { + var args = new Array(arguments.length); + for (var i = 0, l = args.length; i < l; i++) { + args[i] = arguments[i]; + } this.__nextSuper = null; - ret = apply(this, func, arguments); + ret = apply(this, func, args); this.__nextSuper = func; } return ret; } function mixinsMeta(obj) { - var m = metaFor(obj, true), ret = m.mixins; + var m = metaFor(obj, true); + var ret = m.mixins; if (!ret) { ret = m.mixins = {}; } else if (!m.hasOwnProperty('mixins')) { @@ -4765,7 +16179,7 @@ define("ember-metal/mixin", // it on the original object. superProperty = superProperty || meta.descs[key]; - if (!superProperty || !(superProperty instanceof ComputedProperty)) { + if (superProperty === undefined || !(superProperty instanceof ComputedProperty)) { return property; } @@ -4792,7 +16206,7 @@ define("ember-metal/mixin", superMethod = superMethod || obj[key]; // Only wrap the new method if the original method was a function - if ('function' !== typeof superMethod) { + if (superMethod === undefined || 'function' !== typeof superMethod) { return method; } @@ -4816,10 +16230,13 @@ define("ember-metal/mixin", function applyMergedProperties(obj, key, value, values) { var baseValue = values[key] || obj[key]; + Ember.assert("You passed in `" + JSON.stringify(value) + "` as the value for `" + key + + "` but `" + key + "` cannot be an Array", !isArray(value)); + if (!baseValue) { return value; } - var newBase = merge({}, baseValue), - hasFunction = false; + var newBase = merge({}, baseValue); + var hasFunction = false; for (var prop in value) { if (!value.hasOwnProperty(prop)) { continue; } @@ -4922,7 +16339,8 @@ define("ember-metal/mixin", function connectBindings(obj, m) { // TODO Mixin.apply(instance) should disconnect binding if exists - var bindings = m.bindings, key, binding, to; + var bindings = m.bindings; + var key, binding, to; if (bindings) { for (key in bindings) { binding = bindings[key]; @@ -4949,7 +16367,8 @@ define("ember-metal/mixin", } function followAlias(obj, desc, m, descs, values) { - var altKey = desc.methodName, value; + var altKey = desc.methodName; + var value; if (descs[altKey] || values[altKey]) { value = values[altKey]; desc = descs[altKey]; @@ -4991,8 +16410,11 @@ define("ember-metal/mixin", } function applyMixin(obj, mixins, partial) { - var descs = {}, values = {}, m = metaFor(obj), - key, value, desc, keys = []; + var descs = {}; + var values = {}; + var m = metaFor(obj); + var keys = []; + var key, value, desc; obj._super = superFunction; @@ -5045,9 +16467,9 @@ define("ember-metal/mixin", var args = a_slice.call(arguments, 1); applyMixin(obj, args, false); return obj; - }; + } - /** + __exports__.mixin = mixin;/** The `Ember.Mixin` class allows you to create mixins, whose properties can be added to other classes. For instance, @@ -5101,8 +16523,8 @@ define("ember-metal/mixin", @class Mixin @namespace Ember */ - function Mixin() { return initMixin(this, arguments); }; - + __exports__["default"] = Mixin; + function Mixin() { return initMixin(this, arguments); } Mixin.prototype = { properties: null, mixins: null, @@ -5151,7 +16573,9 @@ define("ember-metal/mixin", this.mixins = []; } - var len = arguments.length, mixins = this.mixins, idx; + var len = arguments.length; + var mixins = this.mixins; + var idx; for(idx=0; idx < len; idx++) { mixin = arguments[idx]; @@ -5190,7 +16614,8 @@ define("ember-metal/mixin", seen[guid] = true; if (curMixin === targetMixin) { return true; } - var mixins = curMixin.mixins, loc = mixins ? mixins.length : 0; + var mixins = curMixin.mixins; + var loc = mixins ? mixins.length : 0; while (--loc >= 0) { if (_detect(mixins[loc], targetMixin, seen)) { return true; } } @@ -5205,8 +16630,8 @@ define("ember-metal/mixin", MixinPrototype.detect = function(obj) { if (!obj) { return false; } if (obj instanceof Mixin) { return _detect(obj, this, {}); } - var m = obj[META_KEY], - mixins = m && m.mixins; + var m = obj['__ember_meta__']; + var mixins = m && m.mixins; if (mixins) { return !!mixins[guidFor(this)]; } @@ -5234,7 +16659,9 @@ define("ember-metal/mixin", } MixinPrototype.keys = function() { - var keys = {}, seen = {}, ret = []; + var keys = {}; + var seen = {}; + var ret = []; _keys(keys, this, seen); for(var key in keys) { if (keys.hasOwnProperty(key)) { ret.push(key); } @@ -5245,8 +16672,9 @@ define("ember-metal/mixin", // returns the mixins currently applied to the specified object // TODO: Make Ember.mixin Mixin.mixins = function(obj) { - var m = obj[META_KEY], - mixins = m && m.mixins, ret = []; + var m = obj['__ember_meta__']; + var mixins = m && m.mixins; + var ret = []; if (!mixins) { return ret; } @@ -5271,11 +16699,12 @@ define("ember-metal/mixin", */ function required() { return REQUIRED; - }; + } - Alias = function(methodName) { + __exports__.required = required;function Alias(methodName) { this.methodName = methodName; - }; + } + Alias.prototype = new Descriptor(); /** @@ -5290,7 +16719,7 @@ define("ember-metal/mixin", }); var goodGuy = App.Person.create(); - + goodGuy.name(); // 'Tomhuda Katzdale' goodGuy.moniker(); // 'Tomhuda Katzdale' ``` @@ -5302,9 +16731,9 @@ define("ember-metal/mixin", */ function aliasMethod(methodName) { return new Alias(methodName); - }; + } - // .......................................................... + __exports__.aliasMethod = aliasMethod;// .......................................................... // OBSERVER HELPER // @@ -5357,9 +16786,9 @@ define("ember-metal/mixin", func.__ember_observes__ = paths; return func; - }; + } - /** + __exports__.observer = observer;/** Specify a method that observes property changes. ```javascript @@ -5389,9 +16818,9 @@ define("ember-metal/mixin", } return observer.apply(this, arguments); - }; + } - /** + __exports__.immediateObserver = immediateObserver;/** When observers fire, they are called with the arguments `obj`, `keyName`. Note, `@each.property` observer is called per each add or replace of an element @@ -5460,18 +16889,12 @@ define("ember-metal/mixin", func.__ember_observesBefore__ = paths; return func; - }; + } - __exports__.IS_BINDING = IS_BINDING; - __exports__.mixin = mixin; + __exports__.beforeObserver = beforeObserver;__exports__.IS_BINDING = IS_BINDING; __exports__.Mixin = Mixin; - __exports__.required = required; - __exports__.aliasMethod = aliasMethod; - __exports__.observer = observer; - __exports__.immediateObserver = immediateObserver; - __exports__.beforeObserver = beforeObserver; }); -define("ember-metal/observer", +enifed("ember-metal/observer", ["ember-metal/watching","ember-metal/array","ember-metal/events","exports"], function(__dependency1__, __dependency2__, __dependency3__, __exports__) { "use strict"; @@ -5487,15 +16910,15 @@ define("ember-metal/observer", @module ember-metal */ - var AFTER_OBSERVERS = ':change', - BEFORE_OBSERVERS = ':before'; + var AFTER_OBSERVERS = ':change'; + var BEFORE_OBSERVERS = ':before'; function changeEvent(keyName) { - return keyName+AFTER_OBSERVERS; + return keyName + AFTER_OBSERVERS; } function beforeEvent(keyName) { - return keyName+BEFORE_OBSERVERS; + return keyName + BEFORE_OBSERVERS; } /** @@ -5511,13 +16934,13 @@ define("ember-metal/observer", watch(obj, _path); return this; - }; + } - function observersFor(obj, path) { + __exports__.addObserver = addObserver;function observersFor(obj, path) { return listenersFor(obj, changeEvent(path)); - }; + } - /** + __exports__.observersFor = observersFor;/** @method removeObserver @for Ember @param obj @@ -5530,9 +16953,9 @@ define("ember-metal/observer", removeListener(obj, changeEvent(_path), target, method); return this; - }; + } - /** + __exports__.removeObserver = removeObserver;/** @method addBeforeObserver @for Ember @param obj @@ -5545,35 +16968,35 @@ define("ember-metal/observer", watch(obj, _path); return this; - }; + } - // Suspend observer during callback. + __exports__.addBeforeObserver = addBeforeObserver;// Suspend observer during callback. // // This should only be used by the target of the observer // while it is setting the observed path. function _suspendBeforeObserver(obj, path, target, method, callback) { return suspendListener(obj, beforeEvent(path), target, method, callback); - }; + } - function _suspendObserver(obj, path, target, method, callback) { + __exports__._suspendBeforeObserver = _suspendBeforeObserver;function _suspendObserver(obj, path, target, method, callback) { return suspendListener(obj, changeEvent(path), target, method, callback); - }; + } - function _suspendBeforeObservers(obj, paths, target, method, callback) { + __exports__._suspendObserver = _suspendObserver;function _suspendBeforeObservers(obj, paths, target, method, callback) { var events = map.call(paths, beforeEvent); return suspendListeners(obj, events, target, method, callback); - }; + } - function _suspendObservers(obj, paths, target, method, callback) { + __exports__._suspendBeforeObservers = _suspendBeforeObservers;function _suspendObservers(obj, paths, target, method, callback) { var events = map.call(paths, changeEvent); return suspendListeners(obj, events, target, method, callback); - }; + } - function beforeObserversFor(obj, path) { + __exports__._suspendObservers = _suspendObservers;function beforeObserversFor(obj, path) { return listenersFor(obj, beforeEvent(path)); - }; + } - /** + __exports__.beforeObserversFor = beforeObserversFor;/** @method removeBeforeObserver @for Ember @param obj @@ -5586,20 +17009,11 @@ define("ember-metal/observer", removeListener(obj, beforeEvent(_path), target, method); return this; - }; + } - __exports__.addObserver = addObserver; - __exports__.observersFor = observersFor; - __exports__.removeObserver = removeObserver; - __exports__.addBeforeObserver = addBeforeObserver; - __exports__._suspendBeforeObserver = _suspendBeforeObserver; - __exports__._suspendObserver = _suspendObserver; - __exports__._suspendBeforeObservers = _suspendBeforeObservers; - __exports__._suspendObservers = _suspendObservers; - __exports__.beforeObserversFor = beforeObserversFor; __exports__.removeBeforeObserver = removeBeforeObserver; }); -define("ember-metal/observer_set", +enifed("ember-metal/observer_set", ["ember-metal/utils","ember-metal/events","exports"], function(__dependency1__, __dependency2__, __exports__) { "use strict"; @@ -5624,16 +17038,18 @@ define("ember-metal/observer_set", ... ] */ + __exports__["default"] = ObserverSet; function ObserverSet() { this.clear(); - }; + } + ObserverSet.prototype.add = function(sender, keyName, eventName) { - var observerSet = this.observerSet, - observers = this.observers, - senderGuid = guidFor(sender), - keySet = observerSet[senderGuid], - index; + var observerSet = this.observerSet; + var observers = this.observers; + var senderGuid = guidFor(sender); + var keySet = observerSet[senderGuid]; + var index; if (!keySet) { observerSet[senderGuid] = keySet = {}; @@ -5652,7 +17068,8 @@ define("ember-metal/observer_set", }; ObserverSet.prototype.flush = function() { - var observers = this.observers, i, len, observer, sender; + var observers = this.observers; + var i, len, observer, sender; this.clear(); for (i=0, len=observers.length; i < len; ++i) { observer = observers[i]; @@ -5666,21 +17083,63 @@ define("ember-metal/observer_set", this.observerSet = {}; this.observers = []; }; - - __exports__["default"] = ObserverSet; }); -define("ember-metal/platform", - ["ember-metal/core","exports"], +enifed("ember-metal/path_cache", + ["ember-metal/cache","exports"], function(__dependency1__, __exports__) { "use strict"; - /*globals Node */ + var Cache = __dependency1__["default"]; - var Ember = __dependency1__["default"]; + var IS_GLOBAL = /^([A-Z$]|([0-9][A-Z$]))/; + var IS_GLOBAL_PATH = /^([A-Z$]|([0-9][A-Z$])).*[\.]/; + var HAS_THIS = 'this.'; + + var isGlobalCache = new Cache(1000, function(key) { return IS_GLOBAL.test(key); }); + var isGlobalPathCache = new Cache(1000, function(key) { return IS_GLOBAL_PATH.test(key); }); + var hasThisCache = new Cache(1000, function(key) { return key.indexOf(HAS_THIS) !== -1; }); + var isPathCache = new Cache(1000, function(key) { return key.indexOf('.') !== -1; }); + + var caches = { + isGlobalCache: isGlobalCache, + isGlobalPathCache: isGlobalPathCache, + hasThisCache: hasThisCache, + isPathCache: isPathCache + }; + __exports__.caches = caches; + function isGlobal(path) { + return isGlobalCache.get(path); + } + + __exports__.isGlobal = isGlobal;function isGlobalPath(path) { + return isGlobalPathCache.get(path); + } + + __exports__.isGlobalPath = isGlobalPath;function hasThis(path) { + return hasThisCache.get(path); + } + + __exports__.hasThis = hasThis;function isPath(path) { + return isPathCache.get(path); + } + + __exports__.isPath = isPath; + }); +enifed("ember-metal/platform", + ["ember-metal/platform/define_property","ember-metal/platform/define_properties","ember-metal/platform/create","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __exports__) { + "use strict"; + var hasES5CompliantDefineProperty = __dependency1__.hasES5CompliantDefineProperty; + var defineProperty = __dependency1__.defineProperty; + var defineProperties = __dependency2__["default"]; + var create = __dependency3__["default"]; /** @module ember-metal */ + var hasPropertyAccessors = hasES5CompliantDefineProperty; + var canDefineNonEnumerableProperties = hasES5CompliantDefineProperty; + /** Platform specific methods and feature detectors needed by the framework. @@ -5688,8 +17147,26 @@ define("ember-metal/platform", @namespace Ember @static */ - // TODO remove this - var platform = {}; + + __exports__.create = create; + __exports__.defineProperty = defineProperty; + __exports__.defineProperties = defineProperties; + __exports__.hasPropertyAccessors = hasPropertyAccessors; + __exports__.canDefineNonEnumerableProperties = canDefineNonEnumerableProperties; + }); +enifed("ember-metal/platform/create", + ["exports"], + function(__exports__) { + // Remove "use strict"; from transpiled module until + // https://bugs.webkit.org/show_bug.cgi?id=138038 is fixed + // + // REMOVE_USE_STRICT: true + + /** + @class platform + @namespace Ember + @static + */ /** Identical to `Object.create()`. Implements if not available natively. @@ -5697,76 +17174,190 @@ define("ember-metal/platform", @method create @for Ember */ - var create = Object.create; + var create; + // ES5 15.2.3.5 + // http://es5.github.com/#x15.2.3.5 + if (!(Object.create && !Object.create(null).hasOwnProperty)) { + /* jshint scripturl:true, proto:true */ + // Contributed by Brandon Benvie, October, 2012 + var createEmpty; + var supportsProto = !({'__proto__':null} instanceof Object); + // the following produces false positives + // in Opera Mini => not a reliable check + // Object.prototype.__proto__ === null + if (supportsProto || typeof document === 'undefined') { + createEmpty = function () { + return { "__proto__": null }; + }; + } else { + // In old IE __proto__ can't be used to manually set `null`, nor does + // any other method exist to make an object that inherits from nothing, + // aside from Object.prototype itself. Instead, create a new global + // object and *steal* its Object.prototype and strip it bare. This is + // used as the prototype to create nullary objects. + createEmpty = function () { + var iframe = document.createElement('iframe'); + var parent = document.body || document.documentElement; + iframe.style.display = 'none'; + parent.appendChild(iframe); + iframe.src = 'javascript:'; + var empty = iframe.contentWindow.Object.prototype; + parent.removeChild(iframe); + iframe = null; + delete empty.constructor; + delete empty.hasOwnProperty; + delete empty.propertyIsEnumerable; + delete empty.isPrototypeOf; + delete empty.toLocaleString; + delete empty.toString; + delete empty.valueOf; - // IE8 has Object.create but it couldn't treat property descriptors. - if (create) { - if (create({a: 1}, {a: {value: 2}}).a !== 2) { - create = null; + function Empty() {} + Empty.prototype = empty; + // short-circuit future calls + createEmpty = function () { + return new Empty(); + }; + return new Empty(); + }; } + + create = Object.create = function create(prototype, properties) { + + var object; + function Type() {} // An empty constructor. + + if (prototype === null) { + object = createEmpty(); + } else { + if (typeof prototype !== "object" && typeof prototype !== "function") { + // In the native implementation `parent` can be `null` + // OR *any* `instanceof Object` (Object|Function|Array|RegExp|etc) + // Use `typeof` tho, b/c in old IE, DOM elements are not `instanceof Object` + // like they are in modern browsers. Using `Object.create` on DOM elements + // is...err...probably inappropriate, but the native version allows for it. + throw new TypeError("Object prototype may only be an Object or null"); // same msg as Chrome + } + + Type.prototype = prototype; + + object = new Type(); + } + + if (properties !== undefined) { + Object.defineProperties(object, properties); + } + + return object; + }; + } else { + create = Object.create; } - // STUB_OBJECT_CREATE allows us to override other libraries that stub - // Object.create different than we would prefer - if (!create || Ember.ENV.STUB_OBJECT_CREATE) { - var K = function() {}; + __exports__["default"] = create; + }); +enifed("ember-metal/platform/define_properties", + ["ember-metal/platform/define_property","exports"], + function(__dependency1__, __exports__) { + "use strict"; + var defineProperty = __dependency1__.defineProperty; - create = function(obj, props) { - K.prototype = obj; - obj = new K(); - if (props) { - K.prototype = obj; - for (var prop in props) { - K.prototype[prop] = props[prop].value; + var defineProperties = Object.defineProperties; + + // ES5 15.2.3.7 + // http://es5.github.com/#x15.2.3.7 + if (!defineProperties) { + defineProperties = function defineProperties(object, properties) { + for (var property in properties) { + if (properties.hasOwnProperty(property) && property !== "__proto__") { + defineProperty(object, property, properties[property]); } - obj = new K(); } - K.prototype = null; - - return obj; + return object; }; - create.isSimulated = true; + Object.defineProperties = defineProperties; } - var defineProperty = Object.defineProperty; - var canRedefineProperties, canDefinePropertyOnDOM; + __exports__["default"] = defineProperties; + }); +enifed("ember-metal/platform/define_property", + ["exports"], + function(__exports__) { + "use strict"; + /*globals Node */ - // Catch IE8 where Object.defineProperty exists but only works on DOM elements - if (defineProperty) { + /** + @class platform + @namespace Ember + @static + */ + + /** + Set to true if the platform supports native getters and setters. + + @property hasPropertyAccessors + @final + */ + + /** + Identical to `Object.defineProperty()`. Implements as much functionality + as possible if not available natively. + + @method defineProperty + @param {Object} obj The object to modify + @param {String} keyName property name to modify + @param {Object} desc descriptor hash + @return {void} + */ + var defineProperty = (function checkCompliance(defineProperty) { + if (!defineProperty) return; try { - defineProperty({}, 'a',{get:function() {}}); - } catch (e) { - defineProperty = null; - } - } - - if (defineProperty) { - // Detects a bug in Android <3.2 where you cannot redefine a property using - // Object.defineProperty once accessors have already been set. - canRedefineProperties = (function() { + var a = 5; var obj = {}; - defineProperty(obj, 'a', { configurable: true, enumerable: true, - get: function() { }, - set: function() { } + get: function () { + return a; + }, + set: function (v) { + a = v; + } }); + if (obj.a !== 5) return; + obj.a = 10; + if (a !== 10) return; + // check non-enumerability defineProperty(obj, 'a', { configurable: true, - enumerable: true, + enumerable: false, writable: true, value: true }); + for (var key in obj) { + if (key === 'a') return; + } - return obj.a === true; - })(); + // Detects a bug in Android <3.2 where you cannot redefine a property using + // Object.defineProperty once accessors have already been set. + if (obj.a !== true) return; + // defineProperty is compliant + return defineProperty; + } catch (e) { + // IE8 defines Object.defineProperty but calling it on an Object throws + return; + } + })(Object.defineProperty); + + var hasES5CompliantDefineProperty = !!defineProperty; + + if (hasES5CompliantDefineProperty && typeof document !== 'undefined') { // This is for Safari 5.0, which supports Object.defineProperty, but not // on DOM nodes. - canDefinePropertyOnDOM = (function() { + var canDefinePropertyOnDOM = (function() { try { defineProperty(document.createElement('div'), 'definePropertyOnDOM', {}); return true; @@ -5775,9 +17366,7 @@ define("ember-metal/platform", return false; })(); - if (!canRedefineProperties) { - defineProperty = null; - } else if (!canDefinePropertyOnDOM) { + if (!canDefinePropertyOnDOM) { defineProperty = function(obj, keyName, desc) { var isNode; @@ -5797,49 +17386,16 @@ define("ember-metal/platform", } } - /** - @class platform - @namespace Ember - */ - - /** - Identical to `Object.defineProperty()`. Implements as much functionality - as possible if not available natively. - - @method defineProperty - @param {Object} obj The object to modify - @param {String} keyName property name to modify - @param {Object} desc descriptor hash - @return {void} - */ - platform.defineProperty = defineProperty; - - /** - Set to true if the platform supports native getters and setters. - - @property hasPropertyAccessors - @final - */ - platform.hasPropertyAccessors = true; - - if (!platform.defineProperty) { - platform.hasPropertyAccessors = false; - - platform.defineProperty = function(obj, keyName, desc) { + if (!hasES5CompliantDefineProperty) { + defineProperty = function defineProperty(obj, keyName, desc) { if (!desc.get) { obj[keyName] = desc.value; } }; - - platform.defineProperty.isSimulated = true; } - if (Ember.ENV.MANDATORY_SETTER && !platform.hasPropertyAccessors) { - Ember.ENV.MANDATORY_SETTER = false; - } - - __exports__.create = create; - __exports__.platform = platform; + __exports__.hasES5CompliantDefineProperty = hasES5CompliantDefineProperty; + __exports__.defineProperty = defineProperty; }); -define("ember-metal/properties", +enifed("ember-metal/properties", ["ember-metal/core","ember-metal/utils","ember-metal/platform","ember-metal/property_events","exports"], function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __exports__) { "use strict"; @@ -5848,15 +17404,10 @@ define("ember-metal/properties", */ var Ember = __dependency1__["default"]; - var META_KEY = __dependency2__.META_KEY; - var meta = __dependency2__.meta; - var platform = __dependency3__.platform; + var metaFor = __dependency2__.meta; + var objectDefineProperty = __dependency3__.defineProperty; + var hasPropertyAccessors = __dependency3__.hasPropertyAccessors; var overrideChains = __dependency4__.overrideChains; - var metaFor = meta, - objectDefineProperty = platform.defineProperty; - - var MANDATORY_SETTER = Ember.ENV.MANDATORY_SETTER; - // .......................................................... // DESCRIPTOR // @@ -5872,24 +17423,26 @@ define("ember-metal/properties", @private @constructor */ - function Descriptor() {}; + function Descriptor() {} - // .......................................................... + __exports__.Descriptor = Descriptor;// .......................................................... // DEFINING PROPERTIES API // - var MANDATORY_SETTER_FUNCTION = Ember.MANDATORY_SETTER_FUNCTION = function(value) { - Ember.assert("You must use Ember.set() to access this property (of " + this + ")", false); - }; + function MANDATORY_SETTER_FUNCTION(name) { + return function SETTER_FUNCTION(value) { + Ember.assert("You must use Ember.set() to set the `" + name + "` property (of " + this + ") to `" + value + "`.", false); + }; + } - var DEFAULT_GETTER_FUNCTION = Ember.DEFAULT_GETTER_FUNCTION = function(name) { - return function() { - var meta = this[META_KEY]; + __exports__.MANDATORY_SETTER_FUNCTION = MANDATORY_SETTER_FUNCTION;function DEFAULT_GETTER_FUNCTION(name) { + return function GETTER_FUNCTION() { + var meta = this['__ember_meta__']; return meta && meta.values[name]; }; - }; + } - /** + __exports__.DEFAULT_GETTER_FUNCTION = DEFAULT_GETTER_FUNCTION;/** NOTE: This is a low-level method used by other parts of the API. You almost never want to call this method directly. Instead you should use `Ember.mixin()` to define new properties. @@ -5940,7 +17493,9 @@ define("ember-metal/properties", if (!meta) meta = metaFor(obj); descs = meta.descs; existingDesc = meta.descs[keyName]; - watching = meta.watching[keyName] > 0; + var watchEntry = meta.watching[keyName]; + + watching = watchEntry !== undefined && watchEntry > 0; if (existingDesc instanceof Descriptor) { existingDesc.teardown(obj, keyName); @@ -5950,33 +17505,36 @@ define("ember-metal/properties", value = desc; descs[keyName] = desc; - if (MANDATORY_SETTER && watching) { - objectDefineProperty(obj, keyName, { - configurable: true, - enumerable: true, - writable: true, - value: undefined // make enumerable - }); - } else { - obj[keyName] = undefined; // make enumerable - } + + if (watching && hasPropertyAccessors) { + objectDefineProperty(obj, keyName, { + configurable: true, + enumerable: true, + writable: true, + value: undefined // make enumerable + }); + } else { + obj[keyName] = undefined; // make enumerable + } + if (desc.setup) { desc.setup(obj, keyName); } } else { descs[keyName] = undefined; // shadow descriptor in proto if (desc == null) { value = data; - if (MANDATORY_SETTER && watching) { - meta.values[keyName] = data; - objectDefineProperty(obj, keyName, { - configurable: true, - enumerable: true, - set: MANDATORY_SETTER_FUNCTION, - get: DEFAULT_GETTER_FUNCTION(keyName) - }); - } else { - obj[keyName] = data; - } - } else { + + if (watching && hasPropertyAccessors) { + meta.values[keyName] = data; + objectDefineProperty(obj, keyName, { + configurable: true, + enumerable: true, + set: MANDATORY_SETTER_FUNCTION(keyName), + get: DEFAULT_GETTER_FUNCTION(keyName) + }); + } else { + obj[keyName] = data; + } + } else { value = desc; // compatibility with ES5 @@ -5993,16 +17551,13 @@ define("ember-metal/properties", if (obj.didDefineProperty) { obj.didDefineProperty(obj, keyName, value); } return this; - }; - - __exports__.Descriptor = Descriptor; + } __exports__.defineProperty = defineProperty; }); -define("ember-metal/property_events", +enifed("ember-metal/property_events", ["ember-metal/utils","ember-metal/events","ember-metal/observer_set","exports"], function(__dependency1__, __dependency2__, __dependency3__, __exports__) { "use strict"; - var META_KEY = __dependency1__.META_KEY; var guidFor = __dependency1__.guidFor; var tryFinally = __dependency1__.tryFinally; var sendEvent = __dependency2__.sendEvent; @@ -6010,9 +17565,9 @@ define("ember-metal/property_events", var listenersDiff = __dependency2__.listenersDiff; var ObserverSet = __dependency3__["default"]; - var beforeObserverSet = new ObserverSet(), - observerSet = new ObserverSet(), - deferred = 0; + var beforeObserverSet = new ObserverSet(); + var observerSet = new ObserverSet(); + var deferred = 0; // .......................................................... // PROPERTY CHANGES @@ -6034,10 +17589,10 @@ define("ember-metal/property_events", @return {void} */ function propertyWillChange(obj, keyName) { - var m = obj[META_KEY], - watching = (m && m.watching[keyName] > 0) || keyName === 'length', - proto = m && m.proto, - desc = m && m.descs[keyName]; + var m = obj['__ember_meta__']; + var watching = (m && m.watching[keyName] > 0) || keyName === 'length'; + var proto = m && m.proto; + var desc = m && m.descs[keyName]; if (!watching) { return; } if (proto === obj) { return; } @@ -6063,10 +17618,10 @@ define("ember-metal/property_events", @return {void} */ function propertyDidChange(obj, keyName) { - var m = obj[META_KEY], - watching = (m && m.watching[keyName] > 0) || keyName === 'length', - proto = m && m.proto, - desc = m && m.descs[keyName]; + var m = obj['__ember_meta__']; + var watching = (m && m.watching[keyName] > 0) || keyName === 'length'; + var proto = m && m.proto; + var desc = m && m.descs[keyName]; if (proto === obj) { return; } @@ -6074,44 +17629,63 @@ define("ember-metal/property_events", if (desc && desc.didChange) { desc.didChange(obj, keyName); } if (!watching && keyName !== 'length') { return; } - dependentKeysDidChange(obj, keyName, m); + if (m && m.deps && m.deps[keyName]) { + dependentKeysDidChange(obj, keyName, m); + } + chainsDidChange(obj, keyName, m, false); notifyObservers(obj, keyName); } var WILL_SEEN, DID_SEEN; - // called whenever a property is about to change to clear the cache of any dependent keys (and notify those properties of changes, etc...) function dependentKeysWillChange(obj, depKey, meta) { if (obj.isDestroying) { return; } - var seen = WILL_SEEN, top = !seen; - if (top) { seen = WILL_SEEN = {}; } - iterDeps(propertyWillChange, obj, depKey, seen, meta); - if (top) { WILL_SEEN = null; } + var deps; + if (meta && meta.deps && (deps = meta.deps[depKey])) { + var seen = WILL_SEEN; + var top = !seen; + if (top) { seen = WILL_SEEN = {}; } + iterDeps(propertyWillChange, obj, deps, depKey, seen, meta); + if (top) { WILL_SEEN = null; } + } } // called whenever a property has just changed to update dependent keys function dependentKeysDidChange(obj, depKey, meta) { if (obj.isDestroying) { return; } - var seen = DID_SEEN, top = !seen; - if (top) { seen = DID_SEEN = {}; } - iterDeps(propertyDidChange, obj, depKey, seen, meta); - if (top) { DID_SEEN = null; } + var deps; + if (meta && meta.deps && (deps = meta.deps[depKey])) { + var seen = DID_SEEN; + var top = !seen; + if (top) { seen = DID_SEEN = {}; } + iterDeps(propertyDidChange, obj, deps, depKey, seen, meta); + if (top) { DID_SEEN = null; } + } } - function iterDeps(method, obj, depKey, seen, meta) { - var guid = guidFor(obj); - if (!seen[guid]) seen[guid] = {}; - if (seen[guid][depKey]) return; - seen[guid][depKey] = true; + function keysOf(obj) { + var keys = []; + for (var key in obj) keys.push(key); + return keys; + } + + function iterDeps(method, obj, deps, depKey, seen, meta) { + var keys, key, i, desc; + var guid = guidFor(obj); + var current = seen[guid]; + if (!current) current = seen[guid] = {}; + if (current[depKey]) return; + current[depKey] = true; - var deps = meta.deps; - deps = deps && deps[depKey]; if (deps) { - for(var key in deps) { - var desc = meta.descs[key]; + keys = keysOf(deps); + var descs = meta.descs; + for (i=0; i 0) { - ret = meta.values[keyName]; - } else { - ret = obj[keyName]; - } - + + if (hasPropertyAccessors && meta && meta.watching[keyName] > 0) { + ret = meta.values[keyName]; + } else { + ret = obj[keyName]; + } + if (ret === undefined && 'object' === typeof obj && !(keyName in obj) && 'function' === typeof obj.unknownProperty) { return obj.unknownProperty(keyName); @@ -6349,13 +17932,18 @@ define("ember-metal/property_get", @return {Array} a temporary array with the normalized target/path pair. */ function normalizeTuple(target, path) { - var hasThis = path.indexOf(HAS_THIS) === 0, - isGlobal = !hasThis && IS_GLOBAL_PATH.test(path), - key; + var hasThis = pathHasThis(path); + var isGlobal = !hasThis && isGlobalPath(path); + var key; if (!target || isGlobal) target = Ember.lookup; if (hasThis) path = path.slice(5); + Ember.deprecate( + "normalizeTuple will return '"+path+"' as a non-global. This behavior will change in the future (issue #3852)", + target === Ember.lookup || !target || hasThis || isGlobal || !isGlobalPath(path+'.') + ); + if (target === Ember.lookup) { key = path.match(FIRST_KEY)[0]; target = get(target, key); @@ -6366,7 +17954,7 @@ define("ember-metal/property_get", if (!path || path.length===0) throw new EmberError('Path cannot be empty'); return [ target, path ]; - }; + } function _getPath(root, path) { var hasThis, parts, tuple, idx, len; @@ -6374,10 +17962,12 @@ define("ember-metal/property_get", // If there is no root and path is a key name, return that // property from the global object. // E.g. get('Ember') -> Ember - if (root === null && path.indexOf('.') === -1) { return get(Ember.lookup, path); } + if (root === null && !isPath(path)) { + return get(Ember.lookup, path); + } // detect complicated paths and normalize them - hasThis = path.indexOf(HAS_THIS) === 0; + hasThis = pathHasThis(path); if (!root || hasThis) { tuple = normalizeTuple(root, path); @@ -6393,35 +17983,34 @@ define("ember-metal/property_get", if (root && root.isDestroyed) { return undefined; } } return root; - }; + } function getWithDefault(root, key, defaultValue) { var value = get(root, key); if (value === undefined) { return defaultValue; } return value; - }; + } - __exports__["default"] = get; + __exports__.getWithDefault = getWithDefault;__exports__["default"] = get; __exports__.get = get; - __exports__.getWithDefault = getWithDefault; __exports__.normalizeTuple = normalizeTuple; __exports__._getPath = _getPath; }); -define("ember-metal/property_set", - ["ember-metal/core","ember-metal/property_get","ember-metal/utils","ember-metal/property_events","ember-metal/properties","ember-metal/error","exports"], - function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __exports__) { +enifed("ember-metal/property_set", + ["ember-metal/core","ember-metal/property_get","ember-metal/property_events","ember-metal/properties","ember-metal/error","ember-metal/path_cache","ember-metal/platform","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __exports__) { "use strict"; var Ember = __dependency1__["default"]; var getPath = __dependency2__._getPath; - var META_KEY = __dependency3__.META_KEY; - var propertyWillChange = __dependency4__.propertyWillChange; - var propertyDidChange = __dependency4__.propertyDidChange; - var defineProperty = __dependency5__.defineProperty; - var EmberError = __dependency6__["default"]; + var propertyWillChange = __dependency3__.propertyWillChange; + var propertyDidChange = __dependency3__.propertyDidChange; + var defineProperty = __dependency4__.defineProperty; + var EmberError = __dependency5__["default"]; + var isPath = __dependency6__.isPath; + var hasPropertyAccessors = __dependency7__.hasPropertyAccessors; - var MANDATORY_SETTER = Ember.ENV.MANDATORY_SETTER, - IS_GLOBAL = /^([A-Z$]|([0-9][A-Z$]))/; + var IS_GLOBAL = /^([A-Z$]|([0-9][A-Z$]))/; /** Sets the value of a property on an object, respecting computed properties @@ -6450,10 +18039,11 @@ define("ember-metal/property_set", return setPath(obj, keyName, value, tolerant); } - var meta = obj[META_KEY], desc = meta && meta.descs[keyName], - isUnknown, currentValue; + var meta = obj['__ember_meta__']; + var desc = meta && meta.descs[keyName]; + var isUnknown, currentValue; - if (desc === undefined && keyName.indexOf('.') !== -1) { + if (desc === undefined && isPath(keyName)) { return setPath(obj, keyName, value, tolerant); } @@ -6476,24 +18066,29 @@ define("ember-metal/property_set", if (isUnknown && 'function' === typeof obj.setUnknownProperty) { obj.setUnknownProperty(keyName, value); } else if (meta && meta.watching[keyName] > 0) { - if (MANDATORY_SETTER) { - currentValue = meta.values[keyName]; - } else { - currentValue = obj[keyName]; - } - // only trigger a change if the value has changed + + if (hasPropertyAccessors) { + currentValue = meta.values[keyName]; + } else { + currentValue = obj[keyName]; + } + // only trigger a change if the value has changed if (value !== currentValue) { propertyWillChange(obj, keyName); - if (MANDATORY_SETTER) { - if ((currentValue === undefined && !(keyName in obj)) || !obj.propertyIsEnumerable(keyName)) { - defineProperty(obj, keyName, null, value); // setup mandatory setter + + if (hasPropertyAccessors) { + if ( + (currentValue === undefined && !(keyName in obj)) || + !Object.prototype.propertyIsEnumerable.call(obj, keyName) + ) { + defineProperty(obj, keyName, null, value); // setup mandatory setter + } else { + meta.values[keyName] = value; + } } else { - meta.values[keyName] = value; + obj[keyName] = value; } - } else { - obj[keyName] = value; - } - propertyDidChange(obj, keyName); + propertyDidChange(obj, keyName); } } else { obj[keyName] = value; @@ -6552,44 +18147,45 @@ define("ember-metal/property_set", */ function trySet(root, path, value) { return set(root, path, value, true); - }; + } - __exports__.set = set; - __exports__.trySet = trySet; + __exports__.trySet = trySet;__exports__.set = set; }); -define("ember-metal/run_loop", - ["ember-metal/core","ember-metal/utils","ember-metal/array","ember-metal/property_events","exports"], - function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __exports__) { +enifed("ember-metal/run_loop", + ["ember-metal/core","ember-metal/utils","ember-metal/array","ember-metal/property_events","backburner","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __exports__) { "use strict"; var Ember = __dependency1__["default"]; var apply = __dependency2__.apply; + var GUID_KEY = __dependency2__.GUID_KEY; var indexOf = __dependency3__.indexOf; var beginPropertyChanges = __dependency4__.beginPropertyChanges; var endPropertyChanges = __dependency4__.endPropertyChanges; + var Backburner = __dependency5__["default"]; - var onBegin = function(current) { + function onBegin(current) { run.currentRunLoop = current; - }; + } - var onEnd = function(current, next) { + function onEnd(current, next) { run.currentRunLoop = next; - }; + } // ES6TODO: should Backburner become es6? - var Backburner = requireModule('backburner').Backburner, - backburner = new Backburner(['sync', 'actions', 'destroy'], { - sync: { - before: beginPropertyChanges, - after: endPropertyChanges - }, - defaultQueue: 'actions', - onBegin: onBegin, - onEnd: onEnd, - onErrorTarget: Ember, - onErrorMethod: 'onerror' - }), - slice = [].slice, - concat = [].concat; + var backburner = new Backburner(['sync', 'actions', 'destroy'], { + GUID_KEY: GUID_KEY, + sync: { + before: beginPropertyChanges, + after: endPropertyChanges + }, + defaultQueue: 'actions', + onBegin: onBegin, + onEnd: onEnd, + onErrorTarget: Ember, + onErrorMethod: 'onerror' + }); + var slice = [].slice; + var concat = [].concat; // .......................................................... // run - this is ideally the only public API the dev sees @@ -6622,9 +18218,10 @@ define("ember-metal/run_loop", @param {Object} [args*] Any additional arguments you wish to pass to the method. @return {Object} return value from invoking the passed function. */ - var run = function() { - return apply(backburner, backburner.run, arguments); - }; + __exports__["default"] = run; + function run() { + return backburner.run.apply(backburner, arguments); + } /** If no run-loop is present, it creates a new one. If a run loop is @@ -6665,12 +18262,12 @@ define("ember-metal/run_loop", */ run.join = function(target, method /* args */) { if (!run.currentRunLoop) { - return apply(Ember, run, arguments); + return Ember.run.apply(Ember, arguments); } var args = slice.call(arguments); args.unshift('actions'); - apply(run, run.schedule, args); + run.schedule.apply(run, args); }; /** @@ -6704,7 +18301,7 @@ define("ember-metal/run_loop", ``` @method bind - @namespace run + @namespace Ember @param {Object} [target] target of method to call @param {Function|String} method Method to invoke. May be a function or a string. If you pass a string @@ -6717,7 +18314,7 @@ define("ember-metal/run_loop", run.bind = function(target, method /* args*/) { var args = slice.call(arguments); return function() { - return apply(run, run.join, args.concat(slice.call(arguments))); + return run.join.apply(run, args.concat(slice.call(arguments))); }; }; @@ -6811,7 +18408,7 @@ define("ember-metal/run_loop", */ run.schedule = function(queue, target, method) { checkAutoRun(); - apply(backburner, backburner.schedule, arguments); + backburner.schedule.apply(backburner, arguments); }; // Used by global test teardown @@ -6848,7 +18445,7 @@ define("ember-metal/run_loop", /** Invokes the passed target/method and optional arguments after a specified - period if time. The last parameter of this method must always be a number + period of time. The last parameter of this method must always be a number of milliseconds. You should use this method whenever you need to run some action after a @@ -6869,11 +18466,10 @@ define("ember-metal/run_loop", target at the time the method is invoked. @param {Object} [args*] Optional arguments to pass to the timeout. @param {Number} wait Number of milliseconds to wait. - @return {String} a string you can use to cancel the timer in - `run.cancel` later. + @return {Object} Timer information for use in cancelling, see `run.cancel`. */ - run.later = function(target, method) { - return apply(backburner, backburner.later, arguments); + run.later = function(/*target, method*/) { + return backburner.later.apply(backburner, arguments); }; /** @@ -6939,9 +18535,9 @@ define("ember-metal/run_loop", @param {Object} [args*] Optional arguments to pass to the timeout. @return {Object} Timer information for use in cancelling, see `run.cancel`. */ - run.scheduleOnce = function(queue, target, method) { + run.scheduleOnce = function(/*queue, target, method*/) { checkAutoRun(); - return apply(backburner, backburner.scheduleOnce, arguments); + return backburner.scheduleOnce.apply(backburner, arguments); }; /** @@ -7120,7 +18716,7 @@ define("ember-metal/run_loop", @return {Array} Timer information for use in cancelling, see `run.cancel`. */ run.debounce = function() { - return apply(backburner, backburner.debounce, arguments); + return backburner.debounce.apply(backburner, arguments); }; /** @@ -7159,7 +18755,7 @@ define("ember-metal/run_loop", @return {Array} Timer information for use in cancelling, see `run.cancel`. */ run.throttle = function() { - return apply(backburner, backburner.throttle, arguments); + return backburner.throttle.apply(backburner, arguments); }; // Make sure it's not an autorun during testing @@ -7183,16 +18779,15 @@ define("ember-metal/run_loop", if (indexOf.call(run.queues, name) === -1) { run.queues.splice(indexOf.call(run.queues, after)+1, 0, name); } - } - - __exports__["default"] = run + }; }); -define("ember-metal/set_properties", - ["ember-metal/property_events","ember-metal/property_set","exports"], - function(__dependency1__, __dependency2__, __exports__) { +enifed("ember-metal/set_properties", + ["ember-metal/property_events","ember-metal/property_set","ember-metal/keys","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __exports__) { "use strict"; var changeProperties = __dependency1__.changeProperties; var set = __dependency2__.set; + var keys = __dependency3__["default"]; /** Set a list of properties on an object. These properties are set inside @@ -7210,28 +18805,39 @@ define("ember-metal/set_properties", ``` @method setProperties - @param self - @param {Object} hash - @return self + @param obj + @param {Object} properties + @return obj */ - function setProperties(self, hash) { + __exports__["default"] = function setProperties(obj, properties) { + if (!properties || typeof properties !== "object") { return obj; } changeProperties(function() { - for(var prop in hash) { - if (hash.hasOwnProperty(prop)) { set(self, prop, hash[prop]); } + var props = keys(properties); + var propertyName; + + for (var i = 0, l = props.length; i < l; i++) { + propertyName = props[i]; + + set(obj, propertyName, properties[propertyName]); } }); - return self; - }; - - __exports__["default"] = setProperties; + return obj; + } }); -define("ember-metal/utils", +enifed("ember-metal/utils", ["ember-metal/core","ember-metal/platform","ember-metal/array","exports"], function(__dependency1__, __dependency2__, __dependency3__, __exports__) { - "use strict"; + // Remove "use strict"; from transpiled module until + // https://bugs.webkit.org/show_bug.cgi?id=138038 is fixed + // + // REMOVE_USE_STRICT: true + var Ember = __dependency1__["default"]; - var platform = __dependency2__.platform; + var o_defineProperty = __dependency2__.defineProperty; + var canDefineNonEnumerableProperties = __dependency2__.canDefineNonEnumerableProperties; + var hasPropertyAccessors = __dependency2__.hasPropertyAccessors; var create = __dependency2__.create; + var forEach = __dependency3__.forEach; /** @@ -7239,6 +18845,28 @@ define("ember-metal/utils", */ /** + Previously we used `Ember.$.uuid`, however `$.uuid` has been removed from + jQuery master. We'll just bootstrap our own uuid now. + + @private + @return {Number} the uuid + */ + var _uuid = 0; + + /** + Generates a universally unique identifier. This method + is used internally by Ember for assisting with + the generation of GUID's and other unique identifiers + such as `bind-attr` data attributes. + + @public + @return {Number} [description] + */ + function uuid() { + return ++_uuid; + } + + __exports__.uuid = uuid;/** Prefix used for guids through out Ember. @private @property GUID_PREFIX @@ -7248,15 +18876,58 @@ define("ember-metal/utils", */ var GUID_PREFIX = 'ember'; + var o_create = create; + // Used for guid generation... + var numberCache = []; + var stringCache = {}; - var o_defineProperty = platform.defineProperty, - o_create = create, - // Used for guid generation... - numberCache = [], - stringCache = {}, - uuid = 0; + /** + Strongly hint runtimes to intern the provided string. - var MANDATORY_SETTER = Ember.ENV.MANDATORY_SETTER; + When do I need to use this function? + + For the most part, never. Pre-mature optimization is bad, and often the + runtime does exactly what you need it to, and more often the trade-off isn't + worth it. + + Why? + + Runtimes store strings in at least 2 different representations: + Ropes and Symbols (interned strings). The Rope provides a memory efficient + data-structure for strings created from concatenation or some other string + manipulation like splitting. + + Unfortunately checking equality of different ropes can be quite costly as + runtimes must resort to clever string comparison algorithims. These + algorithims typically cost in proportion to the length of the string. + Luckily, this is where the Symbols (interned strings) shine. As Symbols are + unique by their string content, equality checks can be done by pointer + comparision. + + How do I know if my string is a rope or symbol? + + Typically (warning general sweeping statement, but truthy in runtimes at + present) static strings created as part of the JS source are interned. + Strings often used for comparisions can be interned at runtime if some + criteria are met. One of these criteria can be the size of the entire rope. + For example, in chrome 38 a rope longer then 12 characters will not + intern, nor will segments of that rope. + + Some numbers: http://jsperf.com/eval-vs-keys/8 + + Known Trick™ + + @private + @return {String} interned version of the provided string + */ + function intern(str) { + var obj = {}; + obj[str] = 1; + for (var key in obj) { + if (key === str) return key; + } + return str; + } /** A unique key used to assign guids and other private metadata to objects. @@ -7272,7 +18943,7 @@ define("ember-metal/utils", @type String @final */ - var GUID_KEY = '__ember' + (+ new Date()); + var GUID_KEY = intern('__ember' + (+ new Date())); var GUID_DESC = { writable: false, @@ -7300,7 +18971,7 @@ define("ember-metal/utils", */ function generateGuid(obj, prefix) { if (!prefix) prefix = GUID_PREFIX; - var ret = (prefix + (uuid++)); + var ret = (prefix + uuid()); if (obj) { if (obj[GUID_KEY] === null) { obj[GUID_KEY] = ret; @@ -7312,7 +18983,7 @@ define("ember-metal/utils", return ret; } - /** + __exports__.generateGuid = generateGuid;/** Returns a unique id for the object. If the object does not yet have a guid, one will be assigned to it. You can call this on any object, `Ember.Object`-based or not, but be aware that it will add a `_guid` @@ -7344,7 +19015,7 @@ define("ember-metal/utils", case 'string': ret = stringCache[obj]; - if (!ret) ret = stringCache[obj] = 'st'+(uuid++); + if (!ret) ret = stringCache[obj] = 'st' + uuid(); return ret; case 'boolean': @@ -7354,7 +19025,7 @@ define("ember-metal/utils", if (obj[GUID_KEY]) return obj[GUID_KEY]; if (obj === Object) return '(Object)'; if (obj === Array) return '(Array)'; - ret = 'ember' + (uuid++); + ret = GUID_PREFIX + uuid(); if (obj[GUID_KEY] === null) { obj[GUID_KEY] = ret; @@ -7364,33 +19035,19 @@ define("ember-metal/utils", } return ret; } - }; + } - // .......................................................... + __exports__.guidFor = guidFor;// .......................................................... // META // var META_DESC = { - writable: true, + writable: true, configurable: false, - enumerable: false, + enumerable: false, value: null }; - - /** - The key used to store meta information on object for property observing. - - @property META_KEY - @for Ember - @private - @final - @type String - */ - var META_KEY = '__ember_meta__'; - - var isDefinePropertySimulated = platform.defineProperty.isSimulated; - function Meta(obj) { this.descs = {}; this.watching = {}; @@ -7415,7 +19072,7 @@ define("ember-metal/utils", proto: null }; - if (isDefinePropertySimulated) { + if (!canDefineNonEnumerableProperties) { // on platforms that don't support enumerable false // make meta fail jQuery.isPlainObject() to hide from // jQuery.extend() by having a property that fails @@ -7430,7 +19087,11 @@ define("ember-metal/utils", // Placeholder for non-writable metas. var EMPTY_META = new Meta(null); - if (MANDATORY_SETTER) { EMPTY_META.values = {}; } + + if (hasPropertyAccessors) { + EMPTY_META.values = {}; + } + /** Retrieves the meta hash for an object. If `writable` is true ensures the @@ -7452,23 +19113,27 @@ define("ember-metal/utils", */ function meta(obj, writable) { - var ret = obj[META_KEY]; + var ret = obj['__ember_meta__']; if (writable===false) return ret || EMPTY_META; if (!ret) { - if (!isDefinePropertySimulated) o_defineProperty(obj, META_KEY, META_DESC); + if (canDefineNonEnumerableProperties) o_defineProperty(obj, '__ember_meta__', META_DESC); ret = new Meta(obj); - if (MANDATORY_SETTER) { ret.values = {}; } + + if (hasPropertyAccessors) { + ret.values = {}; + } + - obj[META_KEY] = ret; + obj['__ember_meta__'] = ret; // make sure we don't accidentally try to create constructor like desc ret.descs.constructor = null; } else if (ret.source !== obj) { - if (!isDefinePropertySimulated) o_defineProperty(obj, META_KEY, META_DESC); + if (canDefineNonEnumerableProperties) o_defineProperty(obj, '__ember_meta__', META_DESC); ret = o_create(ret); ret.descs = o_create(ret.descs); @@ -7477,25 +19142,29 @@ define("ember-metal/utils", ret.cacheMeta = {}; ret.source = obj; - if (MANDATORY_SETTER) { ret.values = o_create(ret.values); } + + if (hasPropertyAccessors) { + ret.values = o_create(ret.values); + } + - obj[META_KEY] = ret; + obj['__ember_meta__'] = ret; } return ret; - }; + } function getMeta(obj, property) { var _meta = meta(obj, false); return _meta[property]; - }; + } - function setMeta(obj, property, value) { + __exports__.getMeta = getMeta;function setMeta(obj, property, value) { var _meta = meta(obj, true); _meta[property] = value; return value; - }; + } - /** + __exports__.setMeta = setMeta;/** @deprecated @private @@ -7530,7 +19199,8 @@ define("ember-metal/utils", */ function metaPath(obj, path, writable) { Ember.deprecate("Ember.metaPath is deprecated and will be removed from future releases."); - var _meta = meta(obj, writable), keyName, value; + var _meta = meta(obj, writable); + var keyName, value; for (var i=0, l=path.length; i 3 ? slice.call(arguments, 3) : undefined; - if (!this.currentInstance) { createAutorun(this); } - return this.currentInstance.schedule(queueName, target, method, args, false, stack); - }, - - deferOnce: function(queueName, target, method /* , args */) { - if (!method) { - method = target; - target = null; - } - - if (isString(method)) { - method = target[method]; - } - - var stack = this.DEBUG ? new Error() : undefined, - args = arguments.length > 3 ? slice.call(arguments, 3) : undefined; - if (!this.currentInstance) { createAutorun(this); } - return this.currentInstance.schedule(queueName, target, method, args, true, stack); - }, - - setTimeout: function() { - var args = slice.call(arguments), - length = args.length, - method, wait, target, - methodOrTarget, methodOrWait, methodOrArgs; - - if (length === 0) { - return; - } else if (length === 1) { - method = args.shift(); - wait = 0; - } else if (length === 2) { - methodOrTarget = args[0]; - methodOrWait = args[1]; - - if (isFunction(methodOrWait) || isFunction(methodOrTarget[methodOrWait])) { - target = args.shift(); - method = args.shift(); - wait = 0; - } else if (isCoercableNumber(methodOrWait)) { - method = args.shift(); - wait = args.shift(); - } else { - method = args.shift(); - wait = 0; - } - } else { - var last = args[args.length - 1]; - - if (isCoercableNumber(last)) { - wait = args.pop(); - } else { - wait = 0; - } - - methodOrTarget = args[0]; - methodOrArgs = args[1]; - - if (isFunction(methodOrArgs) || (isString(methodOrArgs) && - methodOrTarget !== null && - methodOrArgs in methodOrTarget)) { - target = args.shift(); - method = args.shift(); - } else { - method = args.shift(); - } - } - - var executeAt = (+new Date()) + parseInt(wait, 10); - - if (isString(method)) { - method = target[method]; - } - - var onError = getOnError(this.options); - - function fn() { - if (onError) { - try { - method.apply(target, args); - } catch (e) { - onError(e); - } - } else { - method.apply(target, args); - } - } - - // find position to insert - var i = searchTimer(executeAt, timers); - - timers.splice(i, 0, executeAt, fn); - - updateLaterTimer(this, executeAt, wait); - - return fn; - }, - - throttle: function(target, method /* , args, wait, [immediate] */) { - var self = this, - args = arguments, - immediate = pop.call(args), - wait, - throttler, - index, - timer; - - if (isNumber(immediate) || isString(immediate)) { - wait = immediate; - immediate = true; - } else { - wait = pop.call(args); - } - - wait = parseInt(wait, 10); - - index = findThrottler(target, method, this._throttlers); - if (index > -1) { return this._throttlers[index]; } // throttled - - timer = global.setTimeout(function() { - if (!immediate) { - self.run.apply(self, args); - } - var index = findThrottler(target, method, self._throttlers); - if (index > -1) { - self._throttlers.splice(index, 1); - } - }, wait); - - if (immediate) { - self.run.apply(self, args); - } - - throttler = [target, method, timer]; - - this._throttlers.push(throttler); - - return throttler; - }, - - debounce: function(target, method /* , args, wait, [immediate] */) { - var self = this, - args = arguments, - immediate = pop.call(args), - wait, - index, - debouncee, - timer; - - if (isNumber(immediate) || isString(immediate)) { - wait = immediate; - immediate = false; - } else { - wait = pop.call(args); - } - - wait = parseInt(wait, 10); - // Remove debouncee - index = findDebouncee(target, method, this._debouncees); - - if (index > -1) { - debouncee = this._debouncees[index]; - this._debouncees.splice(index, 1); - clearTimeout(debouncee[2]); - } - - timer = global.setTimeout(function() { - if (!immediate) { - self.run.apply(self, args); - } - var index = findDebouncee(target, method, self._debouncees); - if (index > -1) { - self._debouncees.splice(index, 1); - } - }, wait); - - if (immediate && index === -1) { - self.run.apply(self, args); - } - - debouncee = [target, method, timer]; - - self._debouncees.push(debouncee); - - return debouncee; - }, - - cancelTimers: function() { - var clearItems = function(item) { - clearTimeout(item[2]); - }; - - each(this._throttlers, clearItems); - this._throttlers = []; - - each(this._debouncees, clearItems); - this._debouncees = []; - - if (this._laterTimer) { - clearTimeout(this._laterTimer); - this._laterTimer = null; - } - timers = []; - - if (this._autorun) { - clearTimeout(this._autorun); - this._autorun = null; - } - }, - - hasTimers: function() { - return !!timers.length || !!this._debouncees.length || !!this._throttlers.length || this._autorun; - }, - - cancel: function(timer) { - var timerType = typeof timer; - - if (timer && timerType === 'object' && timer.queue && timer.method) { // we're cancelling a deferOnce - return timer.queue.cancel(timer); - } else if (timerType === 'function') { // we're cancelling a setTimeout - for (var i = 0, l = timers.length; i < l; i += 2) { - if (timers[i + 1] === timer) { - timers.splice(i, 2); // remove the two elements - return true; - } - } - } else if (Object.prototype.toString.call(timer) === "[object Array]"){ // we're cancelling a throttle or debounce - return this._cancelItem(findThrottler, this._throttlers, timer) || - this._cancelItem(findDebouncee, this._debouncees, timer); - } else { - return; // timer was null or not a timer - } - }, - - _cancelItem: function(findMethod, array, timer){ - var item, - index; - - if (timer.length < 3) { return false; } - - index = findMethod(timer[0], timer[1], array); - - if(index > -1) { - - item = array[index]; - - if(item[2] === timer[2]){ - array.splice(index, 1); - clearTimeout(timer[2]); - return true; - } - } - - return false; - } - }; - - Backburner.prototype.schedule = Backburner.prototype.defer; - Backburner.prototype.scheduleOnce = Backburner.prototype.deferOnce; - Backburner.prototype.later = Backburner.prototype.setTimeout; - - if (needsIETryCatchFix) { - var originalRun = Backburner.prototype.run; - Backburner.prototype.run = wrapInTryCatch(originalRun); - - var originalEnd = Backburner.prototype.end; - Backburner.prototype.end = wrapInTryCatch(originalEnd); - } - - function wrapInTryCatch(func) { - return function () { - try { - return func.apply(this, arguments); - } catch (e) { - throw e; - } - }; - } - - function getOnError(options) { - return options.onError || (options.onErrorTarget && options.onErrorTarget[options.onErrorMethod]); - } - - - function createAutorun(backburner) { - backburner.begin(); - backburner._autorun = global.setTimeout(function() { - backburner._autorun = null; - backburner.end(); - }); - } - - function updateLaterTimer(self, executeAt, wait) { - if (!self._laterTimer || executeAt < self._laterTimerExpiresAt) { - self._laterTimer = global.setTimeout(function() { - self._laterTimer = null; - self._laterTimerExpiresAt = null; - executeTimers(self); - }, wait); - self._laterTimerExpiresAt = executeAt; - } - } - - function executeTimers(self) { - var now = +new Date(), - time, fns, i, l; - - self.run(function() { - i = searchTimer(now, timers); - - fns = timers.splice(0, i); - - for (i = 1, l = fns.length; i < l; i += 2) { - self.schedule(self.options.defaultQueue, null, fns[i]); - } - }); - - if (timers.length) { - updateLaterTimer(self, timers[0], timers[0] - now); - } - } - - function findDebouncee(target, method, debouncees) { - return findItem(target, method, debouncees); - } - - function findThrottler(target, method, throttlers) { - return findItem(target, method, throttlers); - } - - function findItem(target, method, collection) { - var item, - index = -1; - - for (var i = 0, l = collection.length; i < l; i++) { - item = collection[i]; - if (item[0] === target && item[1] === method) { - index = i; - break; - } - } - - return index; - } - - function searchTimer(time, timers) { - var start = 0, - end = timers.length - 2, - middle, l; - - while (start < end) { - // since timers is an array of pairs 'l' will always - // be an integer - l = (end - start) / 2; - - // compensate for the index in case even number - // of pairs inside timers - middle = start + l - (l % 2); - - if (time >= timers[middle]) { - start = middle + 2; - } else { - end = middle; - } - } - - return (time >= timers[start]) ? start + 2 : start; - } - - __exports__.Backburner = Backburner; - }); -define("backburner/deferred_action_queues", - ["backburner/utils","backburner/queue","exports"], - function(__dependency1__, __dependency2__, __exports__) { - "use strict"; - var Utils = __dependency1__["default"]; - var Queue = __dependency2__.Queue; - - var each = Utils.each, - isString = Utils.isString; - - function DeferredActionQueues(queueNames, options) { - var queues = this.queues = {}; - this.queueNames = queueNames = queueNames || []; - - this.options = options; - - each(queueNames, function(queueName) { - queues[queueName] = new Queue(this, queueName, options); - }); - } - - DeferredActionQueues.prototype = { - queueNames: null, - queues: null, - options: null, - - schedule: function(queueName, target, method, args, onceFlag, stack) { - var queues = this.queues, - queue = queues[queueName]; - - if (!queue) { throw new Error("You attempted to schedule an action in a queue (" + queueName + ") that doesn't exist"); } - - if (onceFlag) { - return queue.pushUnique(target, method, args, stack); - } else { - return queue.push(target, method, args, stack); - } - }, - - invoke: function(target, method, args, _) { - if (args && args.length > 0) { - method.apply(target, args); - } else { - method.call(target); - } - }, - - invokeWithOnError: function(target, method, args, onError) { - try { - if (args && args.length > 0) { - method.apply(target, args); - } else { - method.call(target); - } - } catch(error) { - onError(error); - } - }, - - flush: function() { - var queues = this.queues, - queueNames = this.queueNames, - queueName, queue, queueItems, priorQueueNameIndex, - queueNameIndex = 0, numberOfQueues = queueNames.length, - options = this.options, - onError = options.onError || (options.onErrorTarget && options.onErrorTarget[options.onErrorMethod]), - invoke = onError ? this.invokeWithOnError : this.invoke; - - outerloop: - while (queueNameIndex < numberOfQueues) { - queueName = queueNames[queueNameIndex]; - queue = queues[queueName]; - queueItems = queue._queueBeingFlushed = queue._queue.slice(); - queue._queue = []; - - var queueOptions = queue.options, // TODO: write a test for this - before = queueOptions && queueOptions.before, - after = queueOptions && queueOptions.after, - target, method, args, stack, - queueIndex = 0, numberOfQueueItems = queueItems.length; - - if (numberOfQueueItems && before) { before(); } - - while (queueIndex < numberOfQueueItems) { - target = queueItems[queueIndex]; - method = queueItems[queueIndex+1]; - args = queueItems[queueIndex+2]; - stack = queueItems[queueIndex+3]; // Debugging assistance - - if (isString(method)) { method = target[method]; } - - // method could have been nullified / canceled during flush - if (method) { - invoke(target, method, args, onError); - } - - queueIndex += 4; - } - - queue._queueBeingFlushed = null; - if (numberOfQueueItems && after) { after(); } - - if ((priorQueueNameIndex = indexOfPriorQueueWithActions(this, queueNameIndex)) !== -1) { - queueNameIndex = priorQueueNameIndex; - continue outerloop; - } - - queueNameIndex++; - } - } - }; - - function indexOfPriorQueueWithActions(daq, currentQueueIndex) { - var queueName, queue; - - for (var i = 0, l = currentQueueIndex; i <= l; i++) { - queueName = daq.queueNames[i]; - queue = daq.queues[queueName]; - if (queue._queue.length) { return i; } - } - - return -1; - } - - __exports__.DeferredActionQueues = DeferredActionQueues; - }); -define("backburner/queue", - ["exports"], - function(__exports__) { - "use strict"; - function Queue(daq, name, options) { - this.daq = daq; - this.name = name; - this.globalOptions = options; - this.options = options[name]; - this._queue = []; - } - - Queue.prototype = { - daq: null, - name: null, - options: null, - onError: null, - _queue: null, - - push: function(target, method, args, stack) { - var queue = this._queue; - queue.push(target, method, args, stack); - return {queue: this, target: target, method: method}; - }, - - pushUnique: function(target, method, args, stack) { - var queue = this._queue, currentTarget, currentMethod, i, l; - - for (i = 0, l = queue.length; i < l; i += 4) { - currentTarget = queue[i]; - currentMethod = queue[i+1]; - - if (currentTarget === target && currentMethod === method) { - queue[i+2] = args; // replace args - queue[i+3] = stack; // replace stack - return {queue: this, target: target, method: method}; - } - } - - queue.push(target, method, args, stack); - return {queue: this, target: target, method: method}; - }, - - // TODO: remove me, only being used for Ember.run.sync - flush: function() { - var queue = this._queue, - globalOptions = this.globalOptions, - options = this.options, - before = options && options.before, - after = options && options.after, - onError = globalOptions.onError || (globalOptions.onErrorTarget && globalOptions.onErrorTarget[globalOptions.onErrorMethod]), - target, method, args, stack, i, l = queue.length; - - if (l && before) { before(); } - for (i = 0; i < l; i += 4) { - target = queue[i]; - method = queue[i+1]; - args = queue[i+2]; - stack = queue[i+3]; // Debugging assistance - - // TODO: error handling - if (args && args.length > 0) { - if (onError) { - try { - method.apply(target, args); - } catch (e) { - onError(e); - } - } else { - method.apply(target, args); - } - } else { - if (onError) { - try { - method.call(target); - } catch(e) { - onError(e); - } - } else { - method.call(target); - } - } - } - if (l && after) { after(); } - - // check if new items have been added - if (queue.length > l) { - this._queue = queue.slice(l); - this.flush(); - } else { - this._queue.length = 0; - } - }, - - cancel: function(actionToCancel) { - var queue = this._queue, currentTarget, currentMethod, i, l; - - for (i = 0, l = queue.length; i < l; i += 4) { - currentTarget = queue[i]; - currentMethod = queue[i+1]; - - if (currentTarget === actionToCancel.target && currentMethod === actionToCancel.method) { - queue.splice(i, 4); - return true; - } - } - - // if not found in current queue - // could be in the queue that is being flushed - queue = this._queueBeingFlushed; - if (!queue) { - return; - } - for (i = 0, l = queue.length; i < l; i += 4) { - currentTarget = queue[i]; - currentMethod = queue[i+1]; - - if (currentTarget === actionToCancel.target && currentMethod === actionToCancel.method) { - // don't mess with array during flush - // just nullify the method - queue[i+1] = null; - return true; - } - } - } - }; - - __exports__.Queue = Queue; - }); -define("backburner/utils", - ["exports"], - function(__exports__) { - "use strict"; - __exports__["default"] = { - each: function(collection, callback) { - for (var i = 0; i < collection.length; i++) { - callback(collection[i]); - } - }, - - isString: function(suspect) { - return typeof suspect === 'string'; - }, - - isFunction: function(suspect) { - return typeof suspect === 'function'; - }, - - isNumber: function(suspect) { - return typeof suspect === 'number'; - } - }; - }); - -define("ember-metal/watch_key", - ["ember-metal/core","ember-metal/utils","ember-metal/platform","exports"], - function(__dependency1__, __dependency2__, __dependency3__, __exports__) { +enifed("ember-metal/watch_key", + ["ember-metal/core","ember-metal/utils","ember-metal/platform","ember-metal/properties","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __exports__) { "use strict"; var Ember = __dependency1__["default"]; var meta = __dependency2__.meta; var typeOf = __dependency2__.typeOf; - var platform = __dependency3__.platform; + var o_defineProperty = __dependency3__.defineProperty; + var hasPropertyAccessors = __dependency3__.hasPropertyAccessors; + var MANDATORY_SETTER_FUNCTION = __dependency4__.MANDATORY_SETTER_FUNCTION; + var DEFAULT_GETTER_FUNCTION = __dependency4__.DEFAULT_GETTER_FUNCTION; + + var metaFor = meta; // utils.js - var metaFor = meta, // utils.js - MANDATORY_SETTER = Ember.ENV.MANDATORY_SETTER, - o_defineProperty = platform.defineProperty; function watchKey(obj, keyName, meta) { // can't watch length on Array - it is special... @@ -8853,23 +19727,38 @@ define("ember-metal/watch_key", if (!watching[keyName]) { watching[keyName] = 1; + var desc = m.descs[keyName]; + if (desc && desc.willWatch) { desc.willWatch(obj, keyName); } + if ('function' === typeof obj.willWatchProperty) { obj.willWatchProperty(keyName); } - if (MANDATORY_SETTER && keyName in obj) { - m.values[keyName] = obj[keyName]; - o_defineProperty(obj, keyName, { - configurable: true, - enumerable: obj.propertyIsEnumerable(keyName), - set: Ember.MANDATORY_SETTER_FUNCTION, - get: Ember.DEFAULT_GETTER_FUNCTION(keyName) - }); - } + + if (hasPropertyAccessors) { + handleMandatorySetter(m, obj, keyName); + } + } else { watching[keyName] = (watching[keyName] || 0) + 1; } - }; + } + + __exports__.watchKey = watchKey; + + var handleMandatorySetter = function handleMandatorySetter(m, obj, keyName) { + // this x in Y deopts, so keeping it in this function is better; + if (keyName in obj) { + m.values[keyName] = obj[keyName]; + o_defineProperty(obj, keyName, { + configurable: true, + enumerable: Object.prototype.propertyIsEnumerable.call(obj, keyName), + set: MANDATORY_SETTER_FUNCTION(keyName), + get: DEFAULT_GETTER_FUNCTION(keyName) + }); + } + }; + function unwatchKey(obj, keyName, meta) { var m = meta || metaFor(obj), watching = m.watching; @@ -8877,36 +19766,40 @@ define("ember-metal/watch_key", if (watching[keyName] === 1) { watching[keyName] = 0; + var desc = m.descs[keyName]; + if (desc && desc.didUnwatch) { desc.didUnwatch(obj, keyName); } + if ('function' === typeof obj.didUnwatchProperty) { obj.didUnwatchProperty(keyName); } - if (MANDATORY_SETTER && keyName in obj) { - o_defineProperty(obj, keyName, { - configurable: true, - enumerable: obj.propertyIsEnumerable(keyName), - set: function(val) { - // redefine to set as enumerable - o_defineProperty(obj, keyName, { - configurable: true, - writable: true, - enumerable: true, - value: val - }); - delete m.values[keyName]; - }, - get: Ember.DEFAULT_GETTER_FUNCTION(keyName) - }); - } + + if (hasPropertyAccessors && keyName in obj) { + o_defineProperty(obj, keyName, { + configurable: true, + enumerable: Object.prototype.propertyIsEnumerable.call(obj, keyName), + set: function(val) { + // redefine to set as enumerable + o_defineProperty(obj, keyName, { + configurable: true, + writable: true, + enumerable: true, + value: val + }); + delete m.values[keyName]; + }, + get: DEFAULT_GETTER_FUNCTION(keyName) + }); + } + } else if (watching[keyName] > 1) { watching[keyName]--; } - }; + } - __exports__.watchKey = watchKey; __exports__.unwatchKey = unwatchKey; }); -define("ember-metal/watch_path", +enifed("ember-metal/watch_path", ["ember-metal/utils","ember-metal/chains","exports"], function(__dependency1__, __dependency2__, __exports__) { "use strict"; @@ -8920,7 +19813,8 @@ define("ember-metal/watch_path", // chains inherited from the proto they will be cloned and reconfigured for // the current object. function chainsFor(obj, meta) { - var m = meta || metaFor(obj), ret = m.chains; + var m = meta || metaFor(obj); + var ret = m.chains; if (!ret) { ret = m.chains = new ChainNode(null, null, obj); } else if (ret.value() !== obj) { @@ -8933,7 +19827,8 @@ define("ember-metal/watch_path", // can't watch length on Array - it is special... if (keyPath === 'length' && typeOf(obj) === 'array') { return; } - var m = meta || metaFor(obj), watching = m.watching; + var m = meta || metaFor(obj); + var watching = m.watching; if (!watching[keyPath]) { // activate watching first time watching[keyPath] = 1; @@ -8941,10 +19836,11 @@ define("ember-metal/watch_path", } else { watching[keyPath] = (watching[keyPath] || 0) + 1; } - }; + } - function unwatchPath(obj, keyPath, meta) { - var m = meta || metaFor(obj), watching = m.watching; + __exports__.watchPath = watchPath;function unwatchPath(obj, keyPath, meta) { + var m = meta || metaFor(obj); + var watching = m.watching; if (watching[keyPath] === 1) { watching[keyPath] = 0; @@ -8952,21 +19848,19 @@ define("ember-metal/watch_path", } else if (watching[keyPath] > 1) { watching[keyPath]--; } - }; + } - __exports__.watchPath = watchPath; __exports__.unwatchPath = unwatchPath; }); -define("ember-metal/watching", - ["ember-metal/utils","ember-metal/chains","ember-metal/watch_key","ember-metal/watch_path","exports"], - function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __exports__) { +enifed("ember-metal/watching", + ["ember-metal/utils","ember-metal/chains","ember-metal/watch_key","ember-metal/watch_path","ember-metal/path_cache","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __exports__) { "use strict"; /** @module ember-metal */ var meta = __dependency1__.meta; - var META_KEY = __dependency1__.META_KEY; var GUID_KEY = __dependency1__.GUID_KEY; var typeOf = __dependency1__.typeOf; var generateGuid = __dependency1__.generateGuid; @@ -8978,11 +19872,7 @@ define("ember-metal/watching", var unwatchPath = __dependency4__.unwatchPath; var metaFor = meta; // utils.js - - // returns true if the passed path is just a keyName - function isKeyName(path) { - return path.indexOf('.') === -1; - } + var isPath = __dependency5__.isPath; /** Starts watching a property on an object. Whenever the property changes, @@ -9001,32 +19891,34 @@ define("ember-metal/watching", // can't watch length on Array - it is special... if (_keyPath === 'length' && typeOf(obj) === 'array') { return; } - if (isKeyName(_keyPath)) { + if (!isPath(_keyPath)) { watchKey(obj, _keyPath, m); } else { watchPath(obj, _keyPath, m); } - }; + } + + __exports__.watch = watch; function isWatching(obj, key) { - var meta = obj[META_KEY]; + var meta = obj['__ember_meta__']; return (meta && meta.watching[key]) > 0; - }; + } - watch.flushPending = flushPendingChains; + __exports__.isWatching = isWatching;watch.flushPending = flushPendingChains; function unwatch(obj, _keyPath, m) { // can't watch length on Array - it is special... if (_keyPath === 'length' && typeOf(obj) === 'array') { return; } - if (isKeyName(_keyPath)) { + if (!isPath(_keyPath)) { unwatchKey(obj, _keyPath, m); } else { unwatchPath(obj, _keyPath, m); } - }; + } - /** + __exports__.unwatch = unwatch;/** Call on an object when you first beget it from another object. This will setup any chained watchers on the object instance as needed. This method is safe to call multiple times. @@ -9037,7 +19929,7 @@ define("ember-metal/watching", @param obj */ function rewatch(obj) { - var m = obj[META_KEY], chains = m && m.chains; + var m = obj['__ember_meta__'], chains = m && m.chains; // make sure the object has its own guid. if (GUID_KEY in obj && !obj.hasOwnProperty(GUID_KEY)) { @@ -9048,9 +19940,9 @@ define("ember-metal/watching", if (chains && chains.value() !== obj) { m.chains = chains.copy(obj); } - }; + } - var NODE_STACK = []; + __exports__.rewatch = rewatch;var NODE_STACK = []; /** Tears down the meta on an object so that it can be garbage collected. @@ -9062,9 +19954,9 @@ define("ember-metal/watching", @return {void} */ function destroy(obj) { - var meta = obj[META_KEY], node, nodes, key, nodeObject; + var meta = obj['__ember_meta__'], node, nodes, key, nodeObject; if (meta) { - obj[META_KEY] = null; + obj['__ember_meta__'] = null; // remove chainWatchers to remove circular references that would prevent GC node = meta.chains; if (node) { @@ -9091,3147 +19983,6746 @@ define("ember-metal/watching", } } } - }; + } - __exports__.watch = watch; - __exports__.isWatching = isWatching; - __exports__.unwatch = unwatch; - __exports__.rewatch = rewatch; __exports__.destroy = destroy; }); -})(); - -(function() { -/** - @class RSVP - @module RSVP - */ -define("rsvp/all", - ["./promise","exports"], - function(__dependency1__, __exports__) { +enifed("ember-routing-handlebars", + ["ember-metal/core","ember-handlebars","ember-routing/system/router","ember-routing-handlebars/helpers/shared","ember-routing-handlebars/helpers/link_to","ember-routing-handlebars/helpers/outlet","ember-routing-handlebars/helpers/render","ember-routing-handlebars/helpers/action","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __exports__) { "use strict"; - var Promise = __dependency1__["default"]; - /** - This is a convenient alias for `RSVP.Promise.all`. + Ember Routing Handlebars - @method all - @for RSVP - @param {Array} array Array of promises. - @param {String} label An optional label. This is useful - for tooling. - @static + @module ember + @submodule ember-routing-handlebars + @requires ember-views */ - __exports__["default"] = function all(array, label) { - return Promise.all(array, label); - }; + + var Ember = __dependency1__["default"]; + var EmberHandlebars = __dependency2__["default"]; + var Router = __dependency3__["default"]; + + var resolvePaths = __dependency4__.resolvePaths; + var resolveParams = __dependency4__.resolveParams; + + var deprecatedLinkToHelper = __dependency5__.deprecatedLinkToHelper; + var linkToHelper = __dependency5__.linkToHelper; + var LinkView = __dependency5__.LinkView; + var queryParamsHelper = __dependency5__.queryParamsHelper; + + var outletHelper = __dependency6__.outletHelper; + var OutletView = __dependency6__.OutletView; + + var renderHelper = __dependency7__["default"]; + + var ActionHelper = __dependency8__.ActionHelper; + var actionHelper = __dependency8__.actionHelper; + + Router.resolveParams = resolveParams; + Router.resolvePaths = resolvePaths; + + Ember.LinkView = LinkView; + EmberHandlebars.ActionHelper = ActionHelper; + EmberHandlebars.OutletView = OutletView; + + EmberHandlebars.registerHelper('render', renderHelper); + EmberHandlebars.registerHelper('action', actionHelper); + EmberHandlebars.registerHelper('outlet', outletHelper); + EmberHandlebars.registerHelper('link-to', linkToHelper); + EmberHandlebars.registerHelper('linkTo', deprecatedLinkToHelper); + EmberHandlebars.registerHelper('query-params', queryParamsHelper); + + __exports__["default"] = Ember; }); -define("rsvp/all_settled", - ["./promise","./utils","exports"], - function(__dependency1__, __dependency2__, __exports__) { +enifed("ember-routing-handlebars/helpers/action", + ["ember-metal/core","ember-metal/property_get","ember-metal/array","ember-metal/utils","ember-metal/run_loop","ember-views/system/utils","ember-views/system/action_manager","ember-routing/system/router","ember-handlebars","ember-handlebars/ext","ember-handlebars/helpers/view","ember-routing-handlebars/helpers/shared","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __dependency9__, __dependency10__, __dependency11__, __dependency12__, __exports__) { "use strict"; - var Promise = __dependency1__["default"]; - var isArray = __dependency2__.isArray; - var isNonThenable = __dependency2__.isNonThenable; + var Ember = __dependency1__["default"]; + // Handlebars, uuid, FEATURES, assert, deprecate + var get = __dependency2__.get; + var forEach = __dependency3__.forEach; + var uuid = __dependency4__.uuid; + var run = __dependency5__["default"]; + + var isSimpleClick = __dependency6__.isSimpleClick; + var ActionManager = __dependency7__["default"]; + var EmberRouter = __dependency8__["default"]; + + var EmberHandlebars = __dependency9__["default"]; + var handlebarsGet = __dependency10__.handlebarsGet; + var viewHelper = __dependency11__.viewHelper; + var resolveParams = __dependency12__.resolveParams; + var resolvePath = __dependency12__.resolvePath; /** - `RSVP.allSettled` is similar to `RSVP.all`, but instead of implementing - a fail-fast method, it waits until all the promises have returned and - shows you all the results. This is useful if you want to handle multiple - promises' failure states together as a set. + @module ember + @submodule ember-routing + */ - Returns a promise that is fulfilled when all the given promises have been - settled. The return promise is fulfilled with an array of the states of - the promises passed into the `promises` array argument. + var SafeString = EmberHandlebars.SafeString; + var a_slice = Array.prototype.slice; - Each state object will either indicate fulfillment or rejection, and - provide the corresponding value or reason. The states will take one of - the following formats: + function args(options, actionName) { + var ret = []; + if (actionName) { ret.push(actionName); } - ```javascript - { state: 'fulfilled', value: value } - or - { state: 'rejected', reason: reason } + var types = options.options.types.slice(1); + var data = options.options.data; + + return ret.concat(resolveParams(options.context, options.params, { types: types, data: data })); + } + + var ActionHelper = {}; + + // registeredActions is re-exported for compatibility with older plugins + // that were using this undocumented API. + ActionHelper.registeredActions = ActionManager.registeredActions; + + __exports__.ActionHelper = ActionHelper; + + var keys = ["alt", "shift", "meta", "ctrl"]; + + var POINTER_EVENT_TYPE_REGEX = /^click|mouse|touch/; + + var isAllowedEvent = function(event, allowedKeys) { + if (typeof allowedKeys === "undefined") { + if (POINTER_EVENT_TYPE_REGEX.test(event.type)) { + return isSimpleClick(event); + } else { + allowedKeys = ''; + } + } + + if (allowedKeys.indexOf("any") >= 0) { + return true; + } + + var allowed = true; + + forEach.call(keys, function(key) { + if (event[key + "Key"] && allowedKeys.indexOf(key) === -1) { + allowed = false; + } + }); + + return allowed; + }; + + function isKeyEvent(eventName) { + return ['keyUp', 'keyPress', 'keyDown'].indexOf(eventName) !== -1; + } + + function ignoreKeyEvent(eventName, event, keyCode) { + var any = 'any'; + keyCode = keyCode || any; + return isKeyEvent(eventName) && keyCode !== any && keyCode !== event.which.toString(); + } + + ActionHelper.registerAction = function(actionNameOrPath, options, allowedKeys) { + var actionId = uuid(); + + ActionManager.registeredActions[actionId] = { + eventName: options.eventName, + handler: function handleRegisteredAction(event) { + if (!isAllowedEvent(event, allowedKeys)) { return true; } + + if (options.preventDefault !== false) { + event.preventDefault(); + } + + if (options.bubbles === false) { + event.stopPropagation(); + } + + var target = options.target; + var parameters = options.parameters; + var eventName = options.eventName; + var actionName; + + + if (target.target) { + target = handlebarsGet(target.root, target.target, target.options); + } else { + target = target.root; + } + + if (options.boundProperty) { + actionName = resolveParams(parameters.context, [actionNameOrPath], { types: ['ID'], data: parameters.options.data })[0]; + + if (typeof actionName === 'undefined' || typeof actionName === 'function') { + Ember.deprecate("You specified a quoteless path to the {{action}} helper '" + actionNameOrPath + "' which did not resolve to an actionName. Perhaps you meant to use a quoted actionName? (e.g. {{action '" + actionNameOrPath + "'}})."); + actionName = actionNameOrPath; + } + } + + if (!actionName) { + actionName = actionNameOrPath; + } + + run(function runRegisteredAction() { + if (target.send) { + target.send.apply(target, args(parameters, actionName)); + } else { + Ember.assert("The action '" + actionName + "' did not exist on " + target, typeof target[actionName] === 'function'); + target[actionName].apply(target, args(parameters)); + } + }); + } + }; + + options.view.on('willClearRender', function() { + delete ActionManager.registeredActions[actionId]; + }); + + return actionId; + }; + + /** + + The `{{action}}` helper provides a useful shortcut for registering an HTML + element within a template for a single DOM event and forwarding that + interaction to the template's controller or specified `target` option. + + If the controller does not implement the specified action, the event is sent + to the current route, and it bubbles up the route hierarchy from there. + + For more advanced event handling see [Ember.Component](/api/classes/Ember.Component.html) + + + ### Use + Given the following application Handlebars template on the page + + ```handlebars +
    + click me +
    ``` - Example: + And application code ```javascript - var promise1 = RSVP.Promise.resolve(1); - var promise2 = RSVP.Promise.reject(new Error('2')); - var promise3 = RSVP.Promise.reject(new Error('3')); - var promises = [ promise1, promise2, promise3 ]; - - RSVP.allSettled(promises).then(function(array){ - // array == [ - // { state: 'fulfilled', value: 1 }, - // { state: 'rejected', reason: Error }, - // { state: 'rejected', reason: Error } - // ] - // Note that for the second item, reason.message will be "2", and for the - // third item, reason.message will be "3". - }, function(error) { - // Not run. (This block would only be called if allSettled had failed, - // for instance if passed an incorrect argument type.) + App.ApplicationController = Ember.Controller.extend({ + actions: { + anActionName: function() { + } + } }); ``` - @method allSettled - @for RSVP - @param {Array} promises - @param {String} label - optional string that describes the promise. - Useful for tooling. - @return {Promise} promise that is fulfilled with an array of the settled - states of the constituent promises. - @static + Will result in the following rendered HTML + + ```html +
    +
    + click me +
    +
    + ``` + + Clicking "click me" will trigger the `anActionName` action of the + `App.ApplicationController`. In this case, no additional parameters will be passed. + + If you provide additional parameters to the helper: + + ```handlebars + + ``` + + Those parameters will be passed along as arguments to the JavaScript + function implementing the action. + + ### Event Propagation + + Events triggered through the action helper will automatically have + `.preventDefault()` called on them. You do not need to do so in your event + handlers. If you need to allow event propagation (to handle file inputs for + example) you can supply the `preventDefault=false` option to the `{{action}}` helper: + + ```handlebars +
    + + +
    + ``` + + To disable bubbling, pass `bubbles=false` to the helper: + + ```handlebars + + ``` + + If you need the default handler to trigger you should either register your + own event handler, or use event methods on your view class. See [Ember.View](/api/classes/Ember.View.html) + 'Responding to Browser Events' for more information. + + ### Specifying DOM event type + + By default the `{{action}}` helper registers for DOM `click` events. You can + supply an `on` option to the helper to specify a different DOM event name: + + ```handlebars +
    + click me +
    + ``` + + See `Ember.View` 'Responding to Browser Events' for a list of + acceptable DOM event names. + + ### Specifying whitelisted modifier keys + + By default the `{{action}}` helper will ignore click event with pressed modifier + keys. You can supply an `allowedKeys` option to specify which keys should not be ignored. + + ```handlebars +
    + click me +
    + ``` + + This way the `{{action}}` will fire when clicking with the alt key pressed down. + + Alternatively, supply "any" to the `allowedKeys` option to accept any combination of modifier keys. + + ```handlebars +
    + click me with any key pressed +
    + ``` + + ### Specifying a Target + + There are several possible target objects for `{{action}}` helpers: + + In a typical Ember application, where templates are managed through use of the + `{{outlet}}` helper, actions will bubble to the current controller, then + to the current route, and then up the route hierarchy. + + Alternatively, a `target` option can be provided to the helper to change + which object will receive the method call. This option must be a path + to an object, accessible in the current context: + + ```handlebars + {{! the application template }} +
    + click me +
    + ``` + + ```javascript + App.ApplicationView = Ember.View.extend({ + actions: { + anActionName: function(){} + } + }); + + ``` + + ### Additional Parameters + + You may specify additional parameters to the `{{action}}` helper. These + parameters are passed along as the arguments to the JavaScript function + implementing the action. + + ```handlebars + {{#each person in people}} +
    + click me +
    + {{/each}} + ``` + + Clicking "click me" will trigger the `edit` method on the current controller + with the value of `person` as a parameter. + + @method action + @for Ember.Handlebars.helpers + @param {String} actionName + @param {Object} [context]* + @param {Hash} options + */ + function actionHelper(actionName) { + var options = arguments[arguments.length - 1]; + var contexts = a_slice.call(arguments, 1, -1); + var hash = options.hash; + var controller = options.data.keywords.controller; + + // create a hash to pass along to registerAction + var action = { + eventName: hash.on || "click", + parameters: { + context: this, + options: options, + params: contexts + }, + view: options.data.view, + bubbles: hash.bubbles, + preventDefault: hash.preventDefault, + target: { options: options }, + withKeyCode: hash.withKeyCode, + boundProperty: options.types[0] === "ID" + }; + + if (hash.target) { + action.target.root = this; + action.target.target = hash.target; + } else if (controller) { + action.target.root = controller; + } + + var actionId = ActionHelper.registerAction(actionName, action, hash.allowedKeys); + return new SafeString('data-ember-action="' + actionId + '"'); + } + + __exports__.actionHelper = actionHelper; + }); +enifed("ember-routing-handlebars/helpers/link_to", + ["ember-metal/core","ember-metal/property_get","ember-metal/property_set","ember-metal/merge","ember-metal/run_loop","ember-metal/computed","ember-runtime/system/lazy_load","ember-runtime/system/string","ember-runtime/system/object","ember-metal/keys","ember-views/system/utils","ember-views/views/component","ember-handlebars","ember-handlebars/helpers/view","ember-routing/system/router","ember-routing-handlebars/helpers/shared","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __dependency9__, __dependency10__, __dependency11__, __dependency12__, __dependency13__, __dependency14__, __dependency15__, __dependency16__, __exports__) { + "use strict"; + var Ember = __dependency1__["default"]; + // FEATURES, Logger, Handlebars, warn, assert + var get = __dependency2__.get; + var set = __dependency3__.set; + var merge = __dependency4__["default"]; + var run = __dependency5__["default"]; + var computed = __dependency6__.computed; + + var onLoad = __dependency7__.onLoad; + var fmt = __dependency8__.fmt; + var EmberObject = __dependency9__["default"]; + var keys = __dependency10__["default"]; + var isSimpleClick = __dependency11__.isSimpleClick; + var EmberComponent = __dependency12__["default"]; + var EmberHandlebars = __dependency13__["default"]; + var viewHelper = __dependency14__.viewHelper; + var EmberRouter = __dependency15__["default"]; + var resolveParams = __dependency16__.resolveParams; + var resolvePaths = __dependency16__.resolvePaths; + var routeArgs = __dependency16__.routeArgs; + + /** + @module ember + @submodule ember-routing */ - __exports__["default"] = function allSettled(entries, label) { - return new Promise(function(resolve, reject) { - if (!isArray(entries)) { - throw new TypeError('You must pass an array to allSettled.'); + var slice = [].slice; + + requireModule('ember-handlebars'); + + var numberOfContextsAcceptedByHandler = function(handler, handlerInfos) { + var req = 0; + for (var i = 0, l = handlerInfos.length; i < l; i++) { + req = req + handlerInfos[i].names.length; + if (handlerInfos[i].handler === handler) + break; + } + + return req; + }; + + var QueryParams = EmberObject.extend({ + values: null + }); + + function getResolvedPaths(options) { + + var types = options.options.types; + var data = options.options.data; + + return resolvePaths(options.context, options.params, { types: types, data: data }); + } + + /** + `Ember.LinkView` renders an element whose `click` event triggers a + transition of the application's instance of `Ember.Router` to + a supplied route by name. + + Instances of `LinkView` will most likely be created through + the `link-to` Handlebars helper, but properties of this class + can be overridden to customize application-wide behavior. + + @class LinkView + @namespace Ember + @extends Ember.View + @see {Handlebars.helpers.link-to} + **/ + var LinkView = Ember.LinkView = EmberComponent.extend({ + tagName: 'a', + + /** + @deprecated Use current-when instead. + @property currentWhen + */ + currentWhen: null, + + /** + Used to determine when this LinkView is active. + + @property currentWhen + */ + 'current-when': null, + + /** + Sets the `title` attribute of the `LinkView`'s HTML element. + + @property title + @default null + **/ + title: null, + + /** + Sets the `rel` attribute of the `LinkView`'s HTML element. + + @property rel + @default null + **/ + rel: null, + + /** + The CSS class to apply to `LinkView`'s element when its `active` + property is `true`. + + @property activeClass + @type String + @default active + **/ + activeClass: 'active', + + /** + The CSS class to apply to `LinkView`'s element when its `loading` + property is `true`. + + @property loadingClass + @type String + @default loading + **/ + loadingClass: 'loading', + + /** + The CSS class to apply to a `LinkView`'s element when its `disabled` + property is `true`. + + @property disabledClass + @type String + @default disabled + **/ + disabledClass: 'disabled', + _isDisabled: false, + + /** + Determines whether the `LinkView` will trigger routing via + the `replaceWith` routing strategy. + + @property replace + @type Boolean + @default false + **/ + replace: false, + + /** + By default the `{{link-to}}` helper will bind to the `href` and + `title` attributes. It's discourage that you override these defaults, + however you can push onto the array if needed. + + @property attributeBindings + @type Array | String + @default ['href', 'title', 'rel'] + **/ + attributeBindings: ['href', 'title', 'rel', 'tabindex'], + + /** + By default the `{{link-to}}` helper will bind to the `active`, `loading`, and + `disabled` classes. It is discouraged to override these directly. + + @property classNameBindings + @type Array + @default ['active', 'loading', 'disabled'] + **/ + classNameBindings: ['active', 'loading', 'disabled'], + + /** + By default the `{{link-to}}` helper responds to the `click` event. You + can override this globally by setting this property to your custom + event name. + + This is particularly useful on mobile when one wants to avoid the 300ms + click delay using some sort of custom `tap` event. + + @property eventName + @type String + @default click + */ + eventName: 'click', + + // this is doc'ed here so it shows up in the events + // section of the API documentation, which is where + // people will likely go looking for it. + /** + Triggers the `LinkView`'s routing behavior. If + `eventName` is changed to a value other than `click` + the routing behavior will trigger on that custom event + instead. + + @event click + **/ + + /** + An overridable method called when LinkView objects are instantiated. + + Example: + + ```javascript + App.MyLinkView = Ember.LinkView.extend({ + init: function() { + this._super(); + Ember.Logger.log('Event is ' + this.get('eventName')); + } + }); + ``` + + NOTE: If you do override `init` for a framework class like `Ember.View` or + `Ember.ArrayController`, be sure to call `this._super()` in your + `init` declaration! If you don't, Ember may not have an opportunity to + do important setup work, and you'll see strange behavior in your + application. + + @method init + */ + init: function() { + this._super.apply(this, arguments); + + Ember.deprecate('Using currentWhen with {{link-to}} is deprecated in favor of `current-when`.', !this.currentWhen); + + // Map desired event name to invoke function + var eventName = get(this, 'eventName'); + this.on(eventName, this, this._invoke); + }, + + /** + This method is invoked by observers installed during `init` that fire + whenever the params change + + @private + @method _paramsChanged + @since 1.3.0 + */ + _paramsChanged: function() { + this.notifyPropertyChange('resolvedParams'); + }, + + /** + This is called to setup observers that will trigger a rerender. + + @private + @method _setupPathObservers + @since 1.3.0 + **/ + _setupPathObservers: function(){ + var helperParameters = this.parameters; + var linkTextPath = helperParameters.options.linkTextPath; + var paths = getResolvedPaths(helperParameters); + var length = paths.length; + var path, i, normalizedPath; + + if (linkTextPath) { + normalizedPath = getNormalizedPath(linkTextPath, helperParameters); + this.registerObserver(normalizedPath.root, normalizedPath.path, this, this.rerender); } - var remaining = entries.length; - var entry; + for(i=0; i < length; i++) { + path = paths[i]; + if (null === path) { + // A literal value was provided, not a path, so nothing to observe. + continue; + } - if (remaining === 0) { - resolve([]); + normalizedPath = getNormalizedPath(path, helperParameters); + this.registerObserver(normalizedPath.root, normalizedPath.path, this, this._paramsChanged); + } + + var queryParamsObject = this.queryParamsObject; + if (queryParamsObject) { + var values = queryParamsObject.values; + + // Install observers for all of the hash options + // provided in the (query-params) subexpression. + for (var k in values) { + if (!values.hasOwnProperty(k)) { continue; } + + if (queryParamsObject.types[k] === 'ID') { + normalizedPath = getNormalizedPath(values[k], helperParameters); + this.registerObserver(normalizedPath.root, normalizedPath.path, this, this._paramsChanged); + } + } + } + }, + + afterRender: function(){ + this._super.apply(this, arguments); + this._setupPathObservers(); + }, + + /** + + Accessed as a classname binding to apply the `LinkView`'s `disabledClass` + CSS `class` to the element when the link is disabled. + + When `true` interactions with the element will not trigger route changes. + @property disabled + */ + disabled: computed(function computeLinkViewDisabled(key, value) { + if (value !== undefined) { this.set('_isDisabled', value); } + + return value ? get(this, 'disabledClass') : false; + }), + + /** + Accessed as a classname binding to apply the `LinkView`'s `activeClass` + CSS `class` to the element when the link is active. + + A `LinkView` is considered active when its `currentWhen` property is `true` + or the application's current route is the route the `LinkView` would trigger + transitions into. + + The `currentWhen` property can match against multiple routes by separating + route names using the ` ` (space) character. + + @property active + **/ + active: computed('loadedParams', function computeLinkViewActive() { + if (get(this, 'loading')) { return false; } + + var router = get(this, 'router'); + var loadedParams = get(this, 'loadedParams'); + var contexts = loadedParams.models; + var currentWhen = this['current-when'] || this.currentWhen; + var isCurrentWhenSpecified = Boolean(currentWhen); + currentWhen = currentWhen || loadedParams.targetRouteName; + + function isActiveForRoute(routeName) { + var handlers = router.router.recognizer.handlersFor(routeName); + var leafName = handlers[handlers.length-1].handler; + var maximumContexts = numberOfContextsAcceptedByHandler(routeName, handlers); + + // NOTE: any ugliness in the calculation of activeness is largely + // due to the fact that we support automatic normalizing of + // `resource` -> `resource.index`, even though there might be + // dynamic segments / query params defined on `resource.index` + // which complicates (and makes somewhat ambiguous) the calculation + // of activeness for links that link to `resource` instead of + // directly to `resource.index`. + + // if we don't have enough contexts revert back to full route name + // this is because the leaf route will use one of the contexts + if (contexts.length > maximumContexts) { + routeName = leafName; + } + + var args = routeArgs(routeName, contexts, null); + var isActive = router.isActive.apply(router, args); + if (!isActive) { return false; } + + var emptyQueryParams = Ember.isEmpty(Ember.keys(loadedParams.queryParams)); + + if (!isCurrentWhenSpecified && !emptyQueryParams && isActive) { + var visibleQueryParams = {}; + merge(visibleQueryParams, loadedParams.queryParams); + router._prepareQueryParams(loadedParams.targetRouteName, loadedParams.models, visibleQueryParams); + isActive = shallowEqual(visibleQueryParams, router.router.state.queryParams); + } + + return isActive; + } + + + currentWhen = currentWhen.split(' '); + for (var i = 0, len = currentWhen.length; i < len; i++) { + if (isActiveForRoute(currentWhen[i])) { + return get(this, 'activeClass'); + } + } + }), + + /** + Accessed as a classname binding to apply the `LinkView`'s `loadingClass` + CSS `class` to the element when the link is loading. + + A `LinkView` is considered loading when it has at least one + parameter whose value is currently null or undefined. During + this time, clicking the link will perform no transition and + emit a warning that the link is still in a loading state. + + @property loading + **/ + loading: computed('loadedParams', function computeLinkViewLoading() { + if (!get(this, 'loadedParams')) { return get(this, 'loadingClass'); } + }), + + /** + Returns the application's main router from the container. + + @private + @property router + **/ + router: computed(function() { + var controller = get(this, 'controller'); + if (controller && controller.container) { + return controller.container.lookup('router:main'); + } + }), + + /** + Event handler that invokes the link, activating the associated route. + + @private + @method _invoke + @param {Event} event + */ + _invoke: function(event) { + if (!isSimpleClick(event)) { return true; } + + if (this.preventDefault !== false) { + + var targetAttribute = get(this, 'target'); + if (!targetAttribute || targetAttribute === '_self') { + event.preventDefault(); + } + } + + if (this.bubbles === false) { event.stopPropagation(); } + + if (get(this, '_isDisabled')) { return false; } + + if (get(this, 'loading')) { + Ember.Logger.warn("This link-to is in an inactive loading state because at least one of its parameters presently has a null/undefined value, or the provided route name is invalid."); + return false; + } + + + var targetAttribute2 = get(this, 'target'); + if (targetAttribute2 && targetAttribute2 !== '_self') { + return false; + } + + + var router = get(this, 'router'); + var loadedParams = get(this, 'loadedParams'); + + var transition = router._doTransition(loadedParams.targetRouteName, loadedParams.models, loadedParams.queryParams); + if (get(this, 'replace')) { + transition.method('replace'); + } + + // Schedule eager URL update, but after we've given the transition + // a chance to synchronously redirect. + // We need to always generate the URL instead of using the href because + // the href will include any rootURL set, but the router expects a URL + // without it! Note that we don't use the first level router because it + // calls location.formatURL(), which also would add the rootURL! + var args = routeArgs(loadedParams.targetRouteName, loadedParams.models, transition.state.queryParams); + var url = router.router.generate.apply(router.router, args); + + run.scheduleOnce('routerTransitions', this, this._eagerUpdateUrl, transition, url); + }, + + /** + @private + @method _eagerUpdateUrl + @param transition + @param href + */ + _eagerUpdateUrl: function(transition, href) { + if (!transition.isActive || !transition.urlMethod) { + // transition was aborted, already ran to completion, + // or it has a null url-updated method. return; } - var results = new Array(remaining); - - function fulfilledResolver(index) { - return function(value) { - resolveAll(index, fulfilled(value)); - }; + if (href.indexOf('#') === 0) { + href = href.slice(1); } - function rejectedResolver(index) { - return function(reason) { - resolveAll(index, rejected(reason)); - }; + // Re-use the routerjs hooks set up by the Ember router. + var routerjs = get(this, 'router.router'); + if (transition.urlMethod === 'update') { + routerjs.updateURL(href); + } else if (transition.urlMethod === 'replace') { + routerjs.replaceURL(href); } - function resolveAll(index, value) { - results[index] = value; - if (--remaining === 0) { - resolve(results); - } + // Prevent later update url refire. + transition.method(null); + }, + + /** + Computed property that returns an array of the + resolved parameters passed to the `link-to` helper, + e.g.: + + ```hbs + {{link-to a b '123' c}} + ``` + + will generate a `resolvedParams` of: + + ```js + [aObject, bObject, '123', cObject] + ``` + + @private + @property + @return {Array} + */ + resolvedParams: computed('router.url', function() { + var parameters = this.parameters; + var options = parameters.options; + var types = options.types; + var data = options.data; + var targetRouteName, models; + var onlyQueryParamsSupplied = (parameters.params.length === 0); + + if (onlyQueryParamsSupplied) { + var appController = this.container.lookup('controller:application'); + targetRouteName = get(appController, 'currentRouteName'); + models = []; + } else { + models = resolveParams(parameters.context, parameters.params, { types: types, data: data }); + targetRouteName = models.shift(); } - for (var index = 0; index < entries.length; index++) { - entry = entries[index]; + var suppliedQueryParams = getResolvedQueryParams(this, targetRouteName); - if (isNonThenable(entry)) { - resolveAll(index, fulfilled(entry)); - } else { - Promise.cast(entry).then(fulfilledResolver(index), rejectedResolver(index)); - } + return { + targetRouteName: targetRouteName, + models: models, + queryParams: suppliedQueryParams + }; + }), + + /** + Computed property that returns the current route name, + dynamic segments, and query params. Returns falsy if + for null/undefined params to indicate that the link view + is still in a loading state. + + @private + @property + @return {Array} An array with the route name and any dynamic segments + **/ + loadedParams: computed('resolvedParams', function computeLinkViewRouteArgs() { + var router = get(this, 'router'); + if (!router) { return; } + + var resolvedParams = get(this, 'resolvedParams'); + var namedRoute = resolvedParams.targetRouteName; + + if (!namedRoute) { return; } + + Ember.assert(fmt("The attempt to link-to route '%@' failed. " + + "The router did not find '%@' in its possible routes: '%@'", + [namedRoute, namedRoute, keys(router.router.recognizer.names).join("', '")]), + router.hasRoute(namedRoute)); + + if (!paramsAreLoaded(resolvedParams.models)) { return; } + + return resolvedParams; + }), + + queryParamsObject: null, + + /** + Sets the element's `href` attribute to the url for + the `LinkView`'s targeted route. + + If the `LinkView`'s `tagName` is changed to a value other + than `a`, this property will be ignored. + + @property href + **/ + href: computed('loadedParams', function computeLinkViewHref() { + if (get(this, 'tagName') !== 'a') { return; } + + var router = get(this, 'router'); + var loadedParams = get(this, 'loadedParams'); + + if (!loadedParams) { + return get(this, 'loadingHref'); } - }, label); - }; - function fulfilled(value) { - return { state: 'fulfilled', value: value }; - } + var visibleQueryParams = {}; + merge(visibleQueryParams, loadedParams.queryParams); + router._prepareQueryParams(loadedParams.targetRouteName, loadedParams.models, visibleQueryParams); - function rejected(reason) { - return { state: 'rejected', reason: reason }; - } - }); -define("rsvp/config", - ["./events","exports"], - function(__dependency1__, __exports__) { - "use strict"; - var EventTarget = __dependency1__["default"]; + var args = routeArgs(loadedParams.targetRouteName, loadedParams.models, visibleQueryParams); + var result = router.generate.apply(router, args); + return result; + }), - var config = { - instrument: false - }; + /** + The default href value to use while a link-to is loading. + Only applies when tagName is 'a' - EventTarget.mixin(config); + @property loadingHref + @type String + @default # + */ + loadingHref: '#' + }); - function configure(name, value) { - if (name === 'onerror') { - // handle for legacy users that expect the actual - // error to be passed to their function added via - // `RSVP.configure('onerror', someFunctionHere);` - config.on('error', value); - return; - } + LinkView.toString = function() { return "LinkView"; }; - if (arguments.length === 2) { - config[name] = value; - } else { - return config[name]; - } - } + + LinkView.reopen({ + attributeBindings: ['target'], - __exports__.config = config; - __exports__.configure = configure; - }); -define("rsvp/defer", - ["./promise","exports"], - function(__dependency1__, __exports__) { - "use strict"; - var Promise = __dependency1__["default"]; + /** + Sets the `target` attribute of the `LinkView`'s anchor element. + + @property target + @default null + **/ + target: null + }); + /** - `RSVP.defer` returns an object similar to jQuery's `$.Deferred`. - `RSVP.defer` should be used when porting over code reliant on `$.Deferred`'s - interface. New code should use the `RSVP.Promise` constructor instead. + The `{{link-to}}` helper renders a link to the supplied + `routeName` passing an optionally supplied model to the + route as its `model` context of the route. The block + for `{{link-to}}` becomes the innerHTML of the rendered + element: - The object returned from `RSVP.defer` is a plain object with three properties: + ```handlebars + {{#link-to 'photoGallery'}} + Great Hamster Photos + {{/link-to}} + ``` - * promise - an `RSVP.Promise`. - * reject - a function that causes the `promise` property on this object to - become rejected - * resolve - a function that causes the `promise` property on this object to - become fulfilled. + ```html + + Great Hamster Photos + + ``` + + ### Supplying a tagName + By default `{{link-to}}` renders an `` element. This can + be overridden for a single use of `{{link-to}}` by supplying + a `tagName` option: + + ```handlebars + {{#link-to 'photoGallery' tagName="li"}} + Great Hamster Photos + {{/link-to}} + ``` + + ```html +
  • + Great Hamster Photos +
  • + ``` + + To override this option for your entire application, see + "Overriding Application-wide Defaults". + + ### Disabling the `link-to` helper + By default `{{link-to}}` is enabled. + any passed value to `disabled` helper property will disable the `link-to` helper. + + static use: the `disabled` option: + + ```handlebars + {{#link-to 'photoGallery' disabled=true}} + Great Hamster Photos + {{/link-to}} + ``` + + dynamic use: the `disabledWhen` option: + + ```handlebars + {{#link-to 'photoGallery' disabledWhen=controller.someProperty}} + Great Hamster Photos + {{/link-to}} + ``` + + any passed value to `disabled` will disable it except `undefined`. + to ensure that only `true` disable the `link-to` helper you can + override the global behaviour of `Ember.LinkView`. + + ```javascript + Ember.LinkView.reopen({ + disabled: Ember.computed(function(key, value) { + if (value !== undefined) { + this.set('_isDisabled', value === true); + } + return value === true ? get(this, 'disabledClass') : false; + }) + }); + ``` + + see "Overriding Application-wide Defaults" for more. + + ### Handling `href` + `{{link-to}}` will use your application's Router to + fill the element's `href` property with a url that + matches the path to the supplied `routeName` for your + routers's configured `Location` scheme, which defaults + to Ember.HashLocation. + + ### Handling current route + `{{link-to}}` will apply a CSS class name of 'active' + when the application's current route matches + the supplied routeName. For example, if the application's + current route is 'photoGallery.recent' the following + use of `{{link-to}}`: + + ```handlebars + {{#link-to 'photoGallery.recent'}} + Great Hamster Photos from the last week + {{/link-to}} + ``` + + will result in + + ```html +
    + Great Hamster Photos + + ``` + + The CSS class name used for active classes can be customized + for a single use of `{{link-to}}` by passing an `activeClass` + option: + + ```handlebars + {{#link-to 'photoGallery.recent' activeClass="current-url"}} + Great Hamster Photos from the last week + {{/link-to}} + ``` + + ```html + + Great Hamster Photos + + ``` + + To override this option for your entire application, see + "Overriding Application-wide Defaults". + + ### Supplying a model + An optional model argument can be used for routes whose + paths contain dynamic segments. This argument will become + the model context of the linked route: + + ```javascript + App.Router.map(function() { + this.resource("photoGallery", {path: "hamster-photos/:photo_id"}); + }); + ``` + + ```handlebars + {{#link-to 'photoGallery' aPhoto}} + {{aPhoto.title}} + {{/link-to}} + ``` + + ```html + + Tomster + + ``` + + ### Supplying multiple models + For deep-linking to route paths that contain multiple + dynamic segments, multiple model arguments can be used. + As the router transitions through the route path, each + supplied model argument will become the context for the + route with the dynamic segments: + + ```javascript + App.Router.map(function() { + this.resource("photoGallery", {path: "hamster-photos/:photo_id"}, function() { + this.route("comment", {path: "comments/:comment_id"}); + }); + }); + ``` + This argument will become the model context of the linked route: + + ```handlebars + {{#link-to 'photoGallery.comment' aPhoto comment}} + {{comment.body}} + {{/link-to}} + ``` + + ```html + + A+++ would snuggle again. + + ``` + + ### Supplying an explicit dynamic segment value + If you don't have a model object available to pass to `{{link-to}}`, + an optional string or integer argument can be passed for routes whose + paths contain dynamic segments. This argument will become the value + of the dynamic segment: + + ```javascript + App.Router.map(function() { + this.resource("photoGallery", {path: "hamster-photos/:photo_id"}); + }); + ``` + + ```handlebars + {{#link-to 'photoGallery' aPhotoId}} + {{aPhoto.title}} + {{/link-to}} + ``` + + ```html + + Tomster + + ``` + + When transitioning into the linked route, the `model` hook will + be triggered with parameters including this passed identifier. + + ### Allowing Default Action + + By default the `{{link-to}}` helper prevents the default browser action + by calling `preventDefault()` as this sort of action bubbling is normally + handled internally and we do not want to take the browser to a new URL (for + example). + + If you need to override this behavior specify `preventDefault=false` in + your template: + + ```handlebars + {{#link-to 'photoGallery' aPhotoId preventDefault=false}} + {{aPhotoId.title}} + {{/link-to}} + ``` + + ### Overriding attributes + You can override any given property of the Ember.LinkView + that is generated by the `{{link-to}}` helper by passing + key/value pairs, like so: + + ```handlebars + {{#link-to aPhoto tagName='li' title='Following this link will change your life' classNames='pic sweet'}} + Uh-mazing! + {{/link-to}} + ``` + + See [Ember.LinkView](/api/classes/Ember.LinkView.html) for a + complete list of overrideable properties. Be sure to also + check out inherited properties of `LinkView`. + + ### Overriding Application-wide Defaults + ``{{link-to}}`` creates an instance of Ember.LinkView + for rendering. To override options for your entire + application, reopen Ember.LinkView and supply the + desired values: + + ``` javascript + Ember.LinkView.reopen({ + activeClass: "is-active", + tagName: 'li' + }) + ``` + + It is also possible to override the default event in + this manner: + + ``` javascript + Ember.LinkView.reopen({ + eventName: 'customEventName' + }); + ``` + + @method link-to + @for Ember.Handlebars.helpers + @param {String} routeName + @param {Object} [context]* + @param [options] {Object} Handlebars key/value pairs of options, you can override any property of Ember.LinkView + @return {String} HTML string + @see {Ember.LinkView} + */ + function linkToHelper(name) { + var options = slice.call(arguments, -1)[0]; + var params = slice.call(arguments, 0, -1); + var hash = options.hash; + + Ember.assert("You must provide one or more parameters to the link-to helper.", params.length); + + if (params[params.length - 1] instanceof QueryParams) { + hash.queryParamsObject = params.pop(); + } + + hash.disabledBinding = hash.disabledWhen; + + if (!options.fn) { + var linkTitle = params.shift(); + var linkType = options.types.shift(); + var context = this; + if (linkType === 'ID') { + options.linkTextPath = linkTitle; + options.fn = function() { + return EmberHandlebars.getEscaped(context, linkTitle, options); + }; + } else { + options.fn = function() { + return linkTitle; + }; + } + } + + hash.parameters = { + context: this, + options: options, + params: params + }; + + options.helperName = options.helperName || 'link-to'; + + return viewHelper.call(this, LinkView, options); + } + + /** + @method query-params + @for Ember.Handlebars.helpers + @param {Object} hash takes a hash of query parameters + @return {String} HTML string + */ + function queryParamsHelper(options) { + Ember.assert(fmt("The `query-params` helper only accepts hash parameters, e.g. (query-params queryParamPropertyName='%@') as opposed to just (query-params '%@')", [options, options]), arguments.length === 1); + + return QueryParams.create({ + values: options.hash, + types: options.hashTypes + }); + } + + __exports__.queryParamsHelper = queryParamsHelper;/** + See [link-to](/api/classes/Ember.Handlebars.helpers.html#method_link-to) + + @method linkTo + @for Ember.Handlebars.helpers + @deprecated + @param {String} routeName + @param {Object} [context]* + @return {String} HTML string + */ + function deprecatedLinkToHelper() { + Ember.warn("The 'linkTo' view helper is deprecated in favor of 'link-to'"); + return linkToHelper.apply(this, arguments); + } + + function getResolvedQueryParams(linkView, targetRouteName) { + var helperParameters = linkView.parameters; + var queryParamsObject = linkView.queryParamsObject; + var resolvedQueryParams = {}; + + if (!queryParamsObject) { return resolvedQueryParams; } + var rawParams = queryParamsObject.values; + + for (var key in rawParams) { + if (!rawParams.hasOwnProperty(key)) { continue; } + + var value = rawParams[key]; + var type = queryParamsObject.types[key]; + + if (type === 'ID') { + var normalizedPath = getNormalizedPath(value, helperParameters); + value = EmberHandlebars.get(normalizedPath.root, normalizedPath.path, helperParameters.options); + } + resolvedQueryParams[key] = value; + } + return resolvedQueryParams; + } + + function getNormalizedPath(path, helperParameters) { + return EmberHandlebars.normalizePath(helperParameters.context, path, helperParameters.options.data); + } + + function paramsAreLoaded(params) { + for (var i = 0, len = params.length; i < len; ++i) { + var param = params[i]; + if (param === null || typeof param === 'undefined') { + return false; + } + } + return true; + } + + function shallowEqual(a, b) { + var k; + for (k in a) { + if (a.hasOwnProperty(k) && a[k] !== b[k]) { return false; } + } + for (k in b) { + if (b.hasOwnProperty(k) && a[k] !== b[k]) { return false; } + } + return true; + } + + __exports__.LinkView = LinkView; + __exports__.deprecatedLinkToHelper = deprecatedLinkToHelper; + __exports__.linkToHelper = linkToHelper; + }); +enifed("ember-routing-handlebars/helpers/outlet", + ["ember-metal/core","ember-metal/property_get","ember-metal/property_set","ember-runtime/system/lazy_load","ember-views/views/container_view","ember-handlebars/views/metamorph_view","ember-handlebars/helpers/view","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __exports__) { + "use strict"; + var Ember = __dependency1__["default"]; + // assert + var get = __dependency2__.get; + var set = __dependency3__.set; + var onLoad = __dependency4__.onLoad; + var ContainerView = __dependency5__["default"]; + var _Metamorph = __dependency6__._Metamorph; + var viewHelper = __dependency7__.viewHelper; + + /** + @module ember + @submodule ember-routing + */ + + /** + @module ember + @submodule ember-routing + */ + + var OutletView = ContainerView.extend(_Metamorph); + __exports__.OutletView = OutletView; + /** + The `outlet` helper is a placeholder that the router will fill in with + the appropriate template based on the current state of the application. + + ``` handlebars + {{outlet}} + ``` + + By default, a template based on Ember's naming conventions will be rendered + into the `outlet` (e.g. `App.PostsRoute` will render the `posts` template). + + You can render a different template by using the `render()` method in the + route's `renderTemplate` hook. The following will render the `favoritePost` + template into the `outlet`. + + ``` javascript + App.PostsRoute = Ember.Route.extend({ + renderTemplate: function() { + this.render('favoritePost'); + } + }); + ``` + + You can create custom named outlets for more control. + + ``` handlebars + {{outlet 'favoritePost'}} + {{outlet 'posts'}} + ``` + + Then you can define what template is rendered into each outlet in your + route. + + + ``` javascript + App.PostsRoute = Ember.Route.extend({ + renderTemplate: function() { + this.render('favoritePost', { outlet: 'favoritePost' }); + this.render('posts', { outlet: 'posts' }); + } + }); + ``` + + You can specify the view that the outlet uses to contain and manage the + templates rendered into it. + + ``` handlebars + {{outlet view='sectionContainer'}} + ``` + + ``` javascript + App.SectionContainer = Ember.ContainerView.extend({ + tagName: 'section', + classNames: ['special'] + }); + ``` + + @method outlet + @for Ember.Handlebars.helpers + @param {String} property the property on the controller + that holds the view for this outlet + @return {String} HTML string + */ + function outletHelper(property, options) { + var outletSource; + var container; + var viewName; + var viewClass; + var viewFullName; + + if (property && property.data && property.data.isRenderData) { + options = property; + property = 'main'; + } + + container = options.data.view.container; + + outletSource = options.data.view; + while (!outletSource.get('template.isTop')) { + outletSource = outletSource.get('_parentView'); + } + + // provide controller override + viewName = options.hash.view; + + if (viewName) { + viewFullName = 'view:' + viewName; + Ember.assert("Using a quoteless view parameter with {{outlet}} is not supported. Please update to quoted usage '{{outlet \"" + viewName + "\"}}.", options.hashTypes.view !== 'ID'); + Ember.assert("The view name you supplied '" + viewName + "' did not resolve to a view.", container.has(viewFullName)); + } + + viewClass = viewName ? container.lookupFactory(viewFullName) : options.hash.viewClass || OutletView; + + options.data.view.set('outletSource', outletSource); + options.hash.currentViewBinding = '_view.outletSource._outlets.' + property; + + options.helperName = options.helperName || 'outlet'; + + return viewHelper.call(this, viewClass, options); + } + + __exports__.outletHelper = outletHelper; + }); +enifed("ember-routing-handlebars/helpers/render", + ["ember-metal/core","ember-metal/error","ember-metal/property_get","ember-metal/property_set","ember-runtime/system/string","ember-routing/system/generate_controller","ember-handlebars/ext","ember-handlebars/helpers/view","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __exports__) { + "use strict"; + var Ember = __dependency1__["default"]; + // assert, deprecate + var EmberError = __dependency2__["default"]; + var get = __dependency3__.get; + var set = __dependency4__.set; + var camelize = __dependency5__.camelize; + var generateControllerFactory = __dependency6__.generateControllerFactory; + var generateController = __dependency6__["default"]; + var handlebarsGet = __dependency7__.handlebarsGet; + var ViewHelper = __dependency8__.ViewHelper; + + + /** + @module ember + @submodule ember-routing + */ + + /** + Calling ``{{render}}`` from within a template will insert another + template that matches the provided name. The inserted template will + access its properties on its own controller (rather than the controller + of the parent template). + + If a view class with the same name exists, the view class also will be used. + + Note: A given controller may only be used *once* in your app in this manner. + A singleton instance of the controller will be created for you. Example: + ```javascript + App.NavigationController = Ember.Controller.extend({ + who: "world" + }); + ``` + + ```handlebars + + Hello, {{who}}. + ``` + + ```handelbars + +

    My great app

    + {{render "navigation"}} + ``` + + ```html +

    My great app

    +
    + Hello, world. +
    + ``` + + Optionally you may provide a second argument: a property path + that will be bound to the `model` property of the controller. + + If a `model` property path is specified, then a new instance of the + controller will be created and `{{render}}` can be used multiple times + with the same name. + + For example if you had this `author` template. + + ```handlebars +
    + Written by {{firstName}} {{lastName}}. + Total Posts: {{postCount}} +
    + ``` + + You could render it inside the `post` template using the `render` helper. + + ```handlebars +
    +

    {{title}}

    +
    {{body}}
    + {{render "author" author}} +
    + ``` + + @method render + @for Ember.Handlebars.helpers + @param {String} name + @param {Object?} contextString + @param {Hash} options + @return {String} HTML string + */ + __exports__["default"] = function renderHelper(name, contextString, options) { + var length = arguments.length; + var contextProvided = length === 3; + var container, router, controller, view, context, lookupOptions; + + container = (options || contextString).data.keywords.controller.container; + router = container.lookup('router:main'); + + if (length === 2) { + // use the singleton controller + options = contextString; + contextString = undefined; + Ember.assert("You can only use the {{render}} helper once without a model object as its second argument, as in {{render \"post\" post}}.", !router || !router._lookupActiveView(name)); + } else if (length === 3) { + // create a new controller + context = handlebarsGet(options.contexts[1], contextString, options); + } else { + throw new EmberError("You must pass a templateName to render"); + } + + Ember.deprecate("Using a quoteless parameter with {{render}} is deprecated. Please update to quoted usage '{{render \"" + name + "\"}}.", options.types[0] !== 'ID'); + + // # legacy namespace + name = name.replace(/\//g, '.'); + // \ legacy slash as namespace support + + + view = container.lookup('view:' + name) || container.lookup('view:default'); + + // provide controller override + var controllerName = options.hash.controller || name; + var controllerFullName = 'controller:' + controllerName; + + if (options.hash.controller) { + Ember.assert("The controller name you supplied '" + controllerName + "' did not resolve to a controller.", container.has(controllerFullName)); + } + + var parentController = options.data.keywords.controller; + + // choose name + if (length > 2) { + var factory = container.lookupFactory(controllerFullName) || + generateControllerFactory(container, controllerName, context); + + controller = factory.create({ + model: context, + parentController: parentController, + target: parentController + }); + + view.one('willDestroyElement', function() { + controller.destroy(); + }); + } else { + controller = container.lookup(controllerFullName) || + generateController(container, controllerName); + + controller.setProperties({ + target: parentController, + parentController: parentController + }); + } + + var root = options.contexts[1]; + + if (root) { + view.registerObserver(root, contextString, function() { + controller.set('model', handlebarsGet(root, contextString, options)); + }); + } + + options.hash.viewName = camelize(name); + + var templateName = 'template:' + name; + Ember.assert("You used `{{render '" + name + "'}}`, but '" + name + "' can not be found as either a template or a view.", container.has("view:" + name) || container.has(templateName) || options.fn); + options.hash.template = container.lookup(templateName); + + options.hash.controller = controller; + + if (router && !context) { + router._connectActiveView(name, view); + } + + options.helperName = options.helperName || ('render "' + name + '"'); + + ViewHelper.instanceHelper(this, view, options); + } + }); +enifed("ember-routing-handlebars/helpers/shared", + ["ember-metal/property_get","ember-metal/array","ember-runtime/mixins/controller","ember-handlebars/ext","ember-metal/utils","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __exports__) { + "use strict"; + var get = __dependency1__.get; + var map = __dependency2__.map; + var ControllerMixin = __dependency3__["default"]; + var handlebarsResolve = __dependency4__.resolveParams; + var handlebarsGet = __dependency4__.handlebarsGet; + var typeOf = __dependency5__.typeOf; + var get = __dependency1__.get; + + function routeArgs(targetRouteName, models, queryParams) { + var args = []; + if (typeOf(targetRouteName) === 'string') { + args.push('' + targetRouteName); + } + args.push.apply(args, models); + args.push({ queryParams: queryParams }); + return args; + } + + __exports__.routeArgs = routeArgs;function getActiveTargetName(router) { + var handlerInfos = router.activeTransition ? + router.activeTransition.state.handlerInfos : + router.state.handlerInfos; + return handlerInfos[handlerInfos.length - 1].name; + } + + __exports__.getActiveTargetName = getActiveTargetName;function resolveParams(context, params, options) { + return map.call(resolvePaths(context, params, options), function(path, i) { + if (null === path) { + // Param was string/number, not a path, so just return raw string/number. + return params[i]; + } else { + return handlebarsGet(context, path, options); + } + }); + } + + __exports__.resolveParams = resolveParams;function stashParamNames(router, handlerInfos) { + if (handlerInfos._namesStashed) { return; } + + // This helper exists because router.js/route-recognizer.js awkwardly + // keeps separate a handlerInfo's list of parameter names depending + // on whether a URL transition or named transition is happening. + // Hopefully we can remove this in the future. + var targetRouteName = handlerInfos[handlerInfos.length-1].name; + var recogHandlers = router.router.recognizer.handlersFor(targetRouteName); + var dynamicParent = null; + + for (var i = 0, len = handlerInfos.length; i < len; ++i) { + var handlerInfo = handlerInfos[i]; + var names = recogHandlers[i].names; + + if (names.length) { + dynamicParent = handlerInfo; + } + + handlerInfo._names = names; + + var route = handlerInfo.handler; + route._stashNames(handlerInfo, dynamicParent); + } + + handlerInfos._namesStashed = true; + } + + __exports__.stashParamNames = stashParamNames;function resolvePaths(context, params, options) { + var resolved = handlebarsResolve(context, params, options); + var types = options.types; + + return map.call(resolved, function(object, i) { + if (types[i] === 'ID') { + return unwrap(object, params[i]); + } else { + return null; + } + }); + + function unwrap(object, path) { + if (path === 'controller') { return path; } + + if (ControllerMixin.detect(object)) { + return unwrap(get(object, 'model'), path ? path + '.model' : 'model'); + } else { + return path; + } + } + } + + __exports__.resolvePaths = resolvePaths; + }); +enifed("ember-routing", + ["ember-handlebars","ember-metal/core","ember-routing/ext/run_loop","ember-routing/ext/controller","ember-routing/ext/view","ember-routing/location/api","ember-routing/location/none_location","ember-routing/location/hash_location","ember-routing/location/history_location","ember-routing/location/auto_location","ember-routing/system/generate_controller","ember-routing/system/controller_for","ember-routing/system/dsl","ember-routing/system/router","ember-routing/system/route","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __dependency9__, __dependency10__, __dependency11__, __dependency12__, __dependency13__, __dependency14__, __dependency15__, __exports__) { + "use strict"; + /** + Ember Routing + + @module ember + @submodule ember-routing + @requires ember-views + */ + + var EmberHandlebars = __dependency1__["default"]; + var Ember = __dependency2__["default"]; + + // ES6TODO: Cleanup modules with side-effects below + + var EmberLocation = __dependency6__["default"]; + var NoneLocation = __dependency7__["default"]; + var HashLocation = __dependency8__["default"]; + var HistoryLocation = __dependency9__["default"]; + var AutoLocation = __dependency10__["default"]; + + var generateControllerFactory = __dependency11__.generateControllerFactory; + var generateController = __dependency11__["default"]; + var controllerFor = __dependency12__["default"]; + var RouterDSL = __dependency13__["default"]; + var Router = __dependency14__["default"]; + var Route = __dependency15__["default"]; + + Ember.Location = EmberLocation; + Ember.AutoLocation = AutoLocation; + Ember.HashLocation = HashLocation; + Ember.HistoryLocation = HistoryLocation; + Ember.NoneLocation = NoneLocation; + + Ember.controllerFor = controllerFor; + Ember.generateControllerFactory = generateControllerFactory; + Ember.generateController = generateController; + Ember.RouterDSL = RouterDSL; + Ember.Router = Router; + Ember.Route = Route; + + __exports__["default"] = Ember; + }); +enifed("ember-routing/ext/controller", + ["ember-metal/core","ember-metal/property_get","ember-metal/property_set","ember-metal/computed","ember-metal/utils","ember-metal/merge","ember-metal/enumerable_utils","ember-runtime/mixins/controller","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __exports__) { + "use strict"; + var Ember = __dependency1__["default"]; + // FEATURES, deprecate + var get = __dependency2__.get; + var set = __dependency3__.set; + var computed = __dependency4__.computed; + var typeOf = __dependency5__.typeOf; + var meta = __dependency5__.meta; + var merge = __dependency6__["default"]; + var map = __dependency7__.map; + + var ControllerMixin = __dependency8__["default"]; + + /** + @module ember + @submodule ember-routing + */ + + ControllerMixin.reopen({ + concatenatedProperties: ['queryParams', '_pCacheMeta'], + + init: function() { + this._super.apply(this, arguments); + listenForQueryParamChanges(this); + }, + + /** + @property queryParams + @public + */ + queryParams: null, + + /** + @property _qpDelegate + @private + */ + _qpDelegate: null, + + /** + @property _normalizedQueryParams + @private + */ + _normalizedQueryParams: computed(function() { + var m = meta(this); + if (m.proto !== this) { + return get(m.proto, '_normalizedQueryParams'); + } + + var queryParams = get(this, 'queryParams'); + if (queryParams._qpMap) { + return queryParams._qpMap; + } + + var qpMap = queryParams._qpMap = {}; + + for (var i = 0, len = queryParams.length; i < len; ++i) { + accumulateQueryParamDescriptors(queryParams[i], qpMap); + } + + return qpMap; + }), + + /** + @property _cacheMeta + @private + */ + _cacheMeta: computed(function() { + var m = meta(this); + if (m.proto !== this) { + return get(m.proto, '_cacheMeta'); + } + + var cacheMeta = {}; + var qpMap = get(this, '_normalizedQueryParams'); + for (var prop in qpMap) { + if (!qpMap.hasOwnProperty(prop)) { continue; } + + var qp = qpMap[prop]; + var scope = qp.scope; + var parts; + + if (scope === 'controller') { + parts = []; + } + + cacheMeta[prop] = { + parts: parts, // provided by route if 'model' scope + values: null, // provided by route + scope: scope, + prefix: "", + def: get(this, prop) + }; + } + + return cacheMeta; + }), + + /** + @method _updateCacheParams + @private + */ + _updateCacheParams: function(params) { + var cacheMeta = get(this, '_cacheMeta'); + for (var prop in cacheMeta) { + if (!cacheMeta.hasOwnProperty(prop)) { continue; } + var propMeta = cacheMeta[prop]; + propMeta.values = params; + + var cacheKey = this._calculateCacheKey(propMeta.prefix, propMeta.parts, propMeta.values); + var cache = this._bucketCache; + + if (cache) { + var value = cache.lookup(cacheKey, prop, propMeta.def); + set(this, prop, value); + } + } + }, + + /** + @method _qpChanged + @private + */ + _qpChanged: function(controller, _prop) { + var prop = _prop.substr(0, _prop.length-3); + var cacheMeta = get(controller, '_cacheMeta'); + var propCache = cacheMeta[prop]; + var cacheKey = controller._calculateCacheKey(propCache.prefix || "", propCache.parts, propCache.values); + var value = get(controller, prop); + + // 1. Update model-dep cache + var cache = this._bucketCache; + if (cache) { + controller._bucketCache.stash(cacheKey, prop, value); + } + + // 2. Notify a delegate (e.g. to fire a qp transition) + var delegate = controller._qpDelegate; + if (delegate) { + delegate(controller, prop); + } + }, + + /** + @method _calculateCacheKey + @private + */ + _calculateCacheKey: function(prefix, _parts, values) { + var parts = _parts || [], suffixes = ""; + for (var i = 0, len = parts.length; i < len; ++i) { + var part = parts[i]; + var value = get(values, part); + suffixes += "::" + part + ":" + value; + } + return prefix + suffixes.replace(ALL_PERIODS_REGEX, '-'); + }, + + /** + Transition the application into another route. The route may + be either a single route or route path: + + ```javascript + aController.transitionToRoute('blogPosts'); + aController.transitionToRoute('blogPosts.recentEntries'); + ``` + + Optionally supply a model for the route in question. The model + will be serialized into the URL using the `serialize` hook of + the route: + + ```javascript + aController.transitionToRoute('blogPost', aPost); + ``` + + If a literal is passed (such as a number or a string), it will + be treated as an identifier instead. In this case, the `model` + hook of the route will be triggered: + + ```javascript + aController.transitionToRoute('blogPost', 1); + ``` + + Multiple models will be applied last to first recursively up the + resource tree. + + ```javascript + App.Router.map(function() { + this.resource('blogPost', {path:':blogPostId'}, function(){ + this.resource('blogComment', {path: ':blogCommentId'}); + }); + }); + + aController.transitionToRoute('blogComment', aPost, aComment); + aController.transitionToRoute('blogComment', 1, 13); + ``` + + It is also possible to pass a URL (a string that starts with a + `/`). This is intended for testing and debugging purposes and + should rarely be used in production code. + + ```javascript + aController.transitionToRoute('/'); + aController.transitionToRoute('/blog/post/1/comment/13'); + ``` + + See also [replaceRoute](/api/classes/Ember.ControllerMixin.html#method_replaceRoute). + + @param {String} name the name of the route or a URL + @param {...Object} models the model(s) or identifier(s) to be used + while transitioning to the route. + @for Ember.ControllerMixin + @method transitionToRoute + */ + transitionToRoute: function() { + // target may be either another controller or a router + var target = get(this, 'target'); + var method = target.transitionToRoute || target.transitionTo; + return method.apply(target, arguments); + }, + + /** + @deprecated + @for Ember.ControllerMixin + @method transitionTo + */ + transitionTo: function() { + Ember.deprecate("transitionTo is deprecated. Please use transitionToRoute."); + return this.transitionToRoute.apply(this, arguments); + }, + + /** + Transition into another route while replacing the current URL, if possible. + This will replace the current history entry instead of adding a new one. + Beside that, it is identical to `transitionToRoute` in all other respects. + + ```javascript + aController.replaceRoute('blogPosts'); + aController.replaceRoute('blogPosts.recentEntries'); + ``` + + Optionally supply a model for the route in question. The model + will be serialized into the URL using the `serialize` hook of + the route: + + ```javascript + aController.replaceRoute('blogPost', aPost); + ``` + + If a literal is passed (such as a number or a string), it will + be treated as an identifier instead. In this case, the `model` + hook of the route will be triggered: + + ```javascript + aController.replaceRoute('blogPost', 1); + ``` + + Multiple models will be applied last to first recursively up the + resource tree. + + ```javascript + App.Router.map(function() { + this.resource('blogPost', {path:':blogPostId'}, function(){ + this.resource('blogComment', {path: ':blogCommentId'}); + }); + }); + + aController.replaceRoute('blogComment', aPost, aComment); + aController.replaceRoute('blogComment', 1, 13); + ``` + + It is also possible to pass a URL (a string that starts with a + `/`). This is intended for testing and debugging purposes and + should rarely be used in production code. + + ```javascript + aController.replaceRoute('/'); + aController.replaceRoute('/blog/post/1/comment/13'); + ``` + + @param {String} name the name of the route or a URL + @param {...Object} models the model(s) or identifier(s) to be used + while transitioning to the route. + @for Ember.ControllerMixin + @method replaceRoute + */ + replaceRoute: function() { + // target may be either another controller or a router + var target = get(this, 'target'); + var method = target.replaceRoute || target.replaceWith; + return method.apply(target, arguments); + }, + + /** + @deprecated + @for Ember.ControllerMixin + @method replaceWith + */ + replaceWith: function() { + Ember.deprecate("replaceWith is deprecated. Please use replaceRoute."); + return this.replaceRoute.apply(this, arguments); + } + }); + + var ALL_PERIODS_REGEX = /\./g; + + function accumulateQueryParamDescriptors(_desc, accum) { + var desc = _desc, tmp; + if (typeOf(desc) === 'string') { + tmp = {}; + tmp[desc] = { as: null }; + desc = tmp; + } + + for (var key in desc) { + if (!desc.hasOwnProperty(key)) { return; } + + var singleDesc = desc[key]; + if (typeOf(singleDesc) === 'string') { + singleDesc = { as: singleDesc }; + } + + tmp = accum[key] || { as: null, scope: 'model' }; + merge(tmp, singleDesc); + + accum[key] = tmp; + } + } + + function listenForQueryParamChanges(controller) { + var qpMap = get(controller, '_normalizedQueryParams'); + for (var prop in qpMap) { + if (!qpMap.hasOwnProperty(prop)) { continue; } + controller.addObserver(prop + '.[]', controller, controller._qpChanged); + } + } + + + __exports__["default"] = ControllerMixin; + }); +enifed("ember-routing/ext/run_loop", + ["ember-metal/run_loop"], + function(__dependency1__) { + "use strict"; + var run = __dependency1__["default"]; + + /** + @module ember + @submodule ember-views + */ + + // Add a new named queue after the 'actions' queue (where RSVP promises + // resolve), which is used in router transitions to prevent unnecessary + // loading state entry if all context promises resolve on the + // 'actions' queue first. + + var queues = run.queues; + run._addQueue('routerTransitions', 'actions'); + }); +enifed("ember-routing/ext/view", + ["ember-metal/property_get","ember-metal/property_set","ember-metal/run_loop","ember-views/views/view","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __exports__) { + "use strict"; + var get = __dependency1__.get; + var set = __dependency2__.set; + var run = __dependency3__["default"]; + var EmberView = __dependency4__["default"]; + + /** + @module ember + @submodule ember-routing + */ + + EmberView.reopen({ + + /** + Sets the private `_outlets` object on the view. + + @method init + */ + init: function() { + set(this, '_outlets', {}); + this._super(); + }, + + /** + Manually fill any of a view's `{{outlet}}` areas with the + supplied view. + + Example + + ```javascript + var MyView = Ember.View.extend({ + template: Ember.Handlebars.compile('Child view: {{outlet "main"}} ') + }); + var myView = MyView.create(); + myView.appendTo('body'); + // The html for myView now looks like: + //
    Child view:
    + + var FooView = Ember.View.extend({ + template: Ember.Handlebars.compile('

    Foo

    ') + }); + var fooView = FooView.create(); + myView.connectOutlet('main', fooView); + // The html for myView now looks like: + //
    Child view: + //

    Foo

    + //
    + ``` + @method connectOutlet + @param {String} outletName A unique name for the outlet + @param {Object} view An Ember.View + */ + connectOutlet: function(outletName, view) { + if (this._pendingDisconnections) { + delete this._pendingDisconnections[outletName]; + } + + if (this._hasEquivalentView(outletName, view)) { + view.destroy(); + return; + } + + var outlets = get(this, '_outlets'); + var container = get(this, 'container'); + var router = container && container.lookup('router:main'); + var renderedName = get(view, 'renderedName'); + + set(outlets, outletName, view); + + if (router && renderedName) { + router._connectActiveView(renderedName, view); + } + }, + + /** + Determines if the view has already been created by checking if + the view has the same constructor, template, and context as the + view in the `_outlets` object. + + @private + @method _hasEquivalentView + @param {String} outletName The name of the outlet we are checking + @param {Object} view An Ember.View + @return {Boolean} + */ + _hasEquivalentView: function(outletName, view) { + var existingView = get(this, '_outlets.'+outletName); + return existingView && + existingView.constructor === view.constructor && + existingView.get('template') === view.get('template') && + existingView.get('context') === view.get('context'); + }, + + /** + Removes an outlet from the view. + + Example + + ```javascript + var MyView = Ember.View.extend({ + template: Ember.Handlebars.compile('Child view: {{outlet "main"}} ') + }); + var myView = MyView.create(); + myView.appendTo('body'); + // myView's html: + //
    Child view:
    + + var FooView = Ember.View.extend({ + template: Ember.Handlebars.compile('

    Foo

    ') + }); + var fooView = FooView.create(); + myView.connectOutlet('main', fooView); + // myView's html: + //
    Child view: + //

    Foo

    + //
    + + myView.disconnectOutlet('main'); + // myView's html: + //
    Child view:
    + ``` + + @method disconnectOutlet + @param {String} outletName The name of the outlet to be removed + */ + disconnectOutlet: function(outletName) { + if (!this._pendingDisconnections) { + this._pendingDisconnections = {}; + } + this._pendingDisconnections[outletName] = true; + run.once(this, '_finishDisconnections'); + }, + + /** + Gets an outlet that is pending disconnection and then + nullifys the object on the `_outlet` object. + + @private + @method _finishDisconnections + */ + _finishDisconnections: function() { + if (this.isDestroyed) return; // _outlets will be gone anyway + var outlets = get(this, '_outlets'); + var pendingDisconnections = this._pendingDisconnections; + this._pendingDisconnections = null; + + for (var outletName in pendingDisconnections) { + set(outlets, outletName, null); + } + } + }); + + __exports__["default"] = EmberView; + }); +enifed("ember-routing/location/api", + ["ember-metal/core","ember-metal/property_get","ember-metal/property_set","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __exports__) { + "use strict"; + var Ember = __dependency1__["default"]; + // deprecate, assert + var get = __dependency2__.get; + var set = __dependency3__.set; + + /** + @module ember + @submodule ember-routing + */ + + /** + Ember.Location returns an instance of the correct implementation of + the `location` API. + + ## Implementations + + You can pass an implementation name (`hash`, `history`, `none`) to force a + particular implementation to be used in your application. + + ### HashLocation + + Using `HashLocation` results in URLs with a `#` (hash sign) separating the + server side URL portion of the URL from the portion that is used by Ember. + This relies upon the `hashchange` event existing in the browser. + + Example: + + ```javascript + App.Router.map(function() { + this.resource('posts', function() { + this.route('new'); + }); + }); + + App.Router.reopen({ + location: 'hash' + }); + ``` + + This will result in a posts.new url of `/#/posts/new`. + + ### HistoryLocation + + Using `HistoryLocation` results in URLs that are indistinguishable from a + standard URL. This relies upon the browser's `history` API. + + Example: + + ```javascript + App.Router.map(function() { + this.resource('posts', function() { + this.route('new'); + }); + }); + + App.Router.reopen({ + location: 'history' + }); + ``` + + This will result in a posts.new url of `/posts/new`. + + Keep in mind that your server must serve the Ember app at all the routes you + define. + + ### AutoLocation + + Using `AutoLocation`, the router will use the best Location class supported by + the browser it is running in. + + Browsers that support the `history` API will use `HistoryLocation`, those that + do not, but still support the `hashchange` event will use `HashLocation`, and + in the rare case neither is supported will use `NoneLocation`. + + Example: + + ```javascript + App.Router.map(function() { + this.resource('posts', function() { + this.route('new'); + }); + }); + + App.Router.reopen({ + location: 'auto' + }); + ``` + + This will result in a posts.new url of `/posts/new` for modern browsers that + support the `history` api or `/#/posts/new` for older ones, like Internet + Explorer 9 and below. + + When a user visits a link to your application, they will be automatically + upgraded or downgraded to the appropriate `Location` class, with the URL + transformed accordingly, if needed. + + Keep in mind that since some of your users will use `HistoryLocation`, your + server must serve the Ember app at all the routes you define. + + ### NoneLocation + + Using `NoneLocation` causes Ember to not store the applications URL state + in the actual URL. This is generally used for testing purposes, and is one + of the changes made when calling `App.setupForTesting()`. + + ## Location API + + Each location implementation must provide the following methods: + + * implementation: returns the string name used to reference the implementation. + * getURL: returns the current URL. + * setURL(path): sets the current URL. + * replaceURL(path): replace the current URL (optional). + * onUpdateURL(callback): triggers the callback when the URL changes. + * formatURL(url): formats `url` to be placed into `href` attribute. + + Calling setURL or replaceURL will not trigger onUpdateURL callbacks. + + @class Location + @namespace Ember + @static + */ + __exports__["default"] = { + /** + This is deprecated in favor of using the container to lookup the location + implementation as desired. + + For example: + ```javascript - var deferred = RSVP.defer(); + // Given a location registered as follows: + container.register('location:history-test', HistoryTestLocation); - deferred.resolve("Success!"); + // You could create a new instance via: + container.lookup('location:history-test'); + ``` - deferred.promise.then(function(value){ - // value here is "Success!" + @method create + @param {Object} options + @return {Object} an instance of an implementation of the `location` API + @deprecated Use the container to lookup the location implementation that you + need. + */ + create: function(options) { + var implementation = options && options.implementation; + Ember.assert("Ember.Location.create: you must specify a 'implementation' option", !!implementation); + + var implementationClass = this.implementations[implementation]; + Ember.assert("Ember.Location.create: " + implementation + " is not a valid implementation", !!implementationClass); + + return implementationClass.create.apply(implementationClass, arguments); + }, + + /** + This is deprecated in favor of using the container to register the + location implementation as desired. + + Example: + + ```javascript + Application.initializer({ + name: "history-test-location", + + initialize: function(container, application) { + application.register('location:history-test', HistoryTestLocation); + } }); ``` - @method defer - @for RSVP - @param {String} label optional string for labeling the promise. - Useful for tooling. - @return {Object} - */ + @method registerImplementation + @param {String} name + @param {Object} implementation of the `location` API + @deprecated Register your custom location implementation with the + container directly. + */ + registerImplementation: function(name, implementation) { + Ember.deprecate('Using the Ember.Location.registerImplementation is no longer supported. Register your custom location implementation with the container instead.', false); - __exports__["default"] = function defer(label) { - var deferred = { }; + this.implementations[name] = implementation; + }, - deferred.promise = new Promise(function(resolve, reject) { - deferred.resolve = resolve; - deferred.reject = reject; - }, label); + implementations: {}, + _location: window.location, - return deferred; + /** + Returns the current `location.hash` by parsing location.href since browsers + inconsistently URL-decode `location.hash`. + + https://bugzilla.mozilla.org/show_bug.cgi?id=483304 + + @private + @method getHash + @since 1.4.0 + */ + _getHash: function () { + // AutoLocation has it at _location, HashLocation at .location. + // Being nice and not changing + var href = (this._location || this.location).href; + var hashIndex = href.indexOf('#'); + + if (hashIndex === -1) { + return ''; + } else { + return href.substr(hashIndex); + } + } }; }); -define("rsvp/events", - ["exports"], - function(__exports__) { +enifed("ember-routing/location/auto_location", + ["ember-metal/core","ember-metal/property_get","ember-metal/property_set","ember-routing/location/api","ember-routing/location/history_location","ember-routing/location/hash_location","ember-routing/location/none_location","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __exports__) { "use strict"; - var indexOf = function(callbacks, callback) { - for (var i=0, l=callbacks.length; i 7 )); + }, + + /** + @private + + Redirects the browser using location.replace, prepending the locatin.origin + to prevent phishing attempts + + @method _replacePath + */ + _replacePath: function (path) { + this._location.replace(this._getOrigin() + path); + }, + + /** + @since 1.5.1 + @private + @method _getRootURL + */ + _getRootURL: function () { + return this.rootURL; + }, + + /** + @private + + Returns the current `location.pathname`, normalized for IE inconsistencies. + + @method _getPath + */ + _getPath: function () { + var pathname = this._location.pathname; + // Various versions of IE/Opera don't always return a leading slash + if (pathname.charAt(0) !== '/') { + pathname = '/' + pathname; + } + + return pathname; + }, + + /** + @private + + Returns normalized location.hash as an alias to Ember.Location._getHash + + @since 1.5.1 + @method _getHash + */ + _getHash: EmberLocation._getHash, + + /** + @private + + Returns location.search + + @since 1.5.1 + @method _getQuery + */ + _getQuery: function () { + return this._location.search; + }, + + /** + @private + + Returns the full pathname including query and hash + + @method _getFullPath + */ + _getFullPath: function () { + return this._getPath() + this._getQuery() + this._getHash(); + }, + + /** + @private + + Returns the current path as it should appear for HistoryLocation supported + browsers. This may very well differ from the real current path (e.g. if it + starts off as a hashed URL) + + @method _getHistoryPath + */ + _getHistoryPath: function () { + var rootURL = this._getRootURL(); + var path = this._getPath(); + var hash = this._getHash(); + var query = this._getQuery(); + var rootURLIndex = path.indexOf(rootURL); + var routeHash, hashParts; + + Ember.assert('Path ' + path + ' does not start with the provided rootURL ' + rootURL, rootURLIndex === 0); + + // By convention, Ember.js routes using HashLocation are required to start + // with `#/`. Anything else should NOT be considered a route and should + // be passed straight through, without transformation. + if (hash.substr(0, 2) === '#/') { + // There could be extra hash segments after the route + hashParts = hash.substr(1).split('#'); + // The first one is always the route url + routeHash = hashParts.shift(); + + // If the path already has a trailing slash, remove the one + // from the hashed route so we don't double up. + if (path.slice(-1) === '/') { + routeHash = routeHash.substr(1); + } + + // This is the "expected" final order + path += routeHash; + path += query; + + if (hashParts.length) { + path += '#' + hashParts.join('#'); + } + } else { + path += query; + path += hash; + } + + return path; + }, + + /** + @private + + Returns the current path as it should appear for HashLocation supported + browsers. This may very well differ from the real current path. + + @method _getHashPath + */ + _getHashPath: function () { + var rootURL = this._getRootURL(); + var path = rootURL; + var historyPath = this._getHistoryPath(); + var routePath = historyPath.substr(rootURL.length); + + if (routePath !== '') { + if (routePath.charAt(0) !== '/') { + routePath = '/' + routePath; + } + + path += '#' + routePath; + } + + return path; + }, + + /** + Selects the best location option based off browser support and returns an + instance of that Location class. + + @see Ember.AutoLocation + @method create + */ + create: function (options) { + if (options && options.rootURL) { + Ember.assert('rootURL must end with a trailing forward slash e.g. "/app/"', options.rootURL.charAt(options.rootURL.length-1) === '/'); + this.rootURL = options.rootURL; + } + + var historyPath, hashPath; + var cancelRouterSetup = false; + var implementationClass = this._NoneLocation; + var currentPath = this._getFullPath(); + + if (this._getSupportsHistory()) { + historyPath = this._getHistoryPath(); + + // Since we support history paths, let's be sure we're using them else + // switch the location over to it. + if (currentPath === historyPath) { + implementationClass = this._HistoryLocation; + } else { + + if (currentPath.substr(0, 2) === '/#') { + this._history.replaceState({ path: historyPath }, null, historyPath); + implementationClass = this._HistoryLocation; + } else { + cancelRouterSetup = true; + this._replacePath(historyPath); + } + } + + } else if (this._getSupportsHashChange()) { + hashPath = this._getHashPath(); + + // Be sure we're using a hashed path, otherwise let's switch over it to so + // we start off clean and consistent. We'll count an index path with no + // hash as "good enough" as well. + if (currentPath === hashPath || (currentPath === '/' && hashPath === '/#/')) { + implementationClass = this._HashLocation; + } else { + // Our URL isn't in the expected hash-supported format, so we want to + // cancel the router setup and replace the URL to start off clean + cancelRouterSetup = true; + this._replacePath(hashPath); + } + } + + var implementation = implementationClass.create.apply(implementationClass, arguments); + + if (cancelRouterSetup) { + set(implementation, 'cancelRouterSetup', true); + } + + return implementation; } }; }); -define("rsvp/filter", - ["./all","./map","./utils","exports"], +enifed("ember-routing/location/hash_location", + ["ember-metal/core","ember-metal/property_get","ember-metal/property_set","ember-metal/run_loop","ember-metal/utils","ember-runtime/system/object","ember-routing/location/api","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __exports__) { + "use strict"; + var Ember = __dependency1__["default"]; + var get = __dependency2__.get; + var set = __dependency3__.set; + var run = __dependency4__["default"]; + var guidFor = __dependency5__.guidFor; + + var EmberObject = __dependency6__["default"]; + var EmberLocation = __dependency7__["default"]; + + /** + @module ember + @submodule ember-routing + */ + + /** + `Ember.HashLocation` implements the location API using the browser's + hash. At present, it relies on a `hashchange` event existing in the + browser. + + @class HashLocation + @namespace Ember + @extends Ember.Object + */ + __exports__["default"] = EmberObject.extend({ + implementation: 'hash', + + init: function() { + set(this, 'location', get(this, '_location') || window.location); + }, + + /** + @private + + Returns normalized location.hash + + @since 1.5.1 + @method getHash + */ + getHash: EmberLocation._getHash, + + /** + Returns the current `location.hash`, minus the '#' at the front. + + @private + @method getURL + */ + getURL: function() { + var path = this.getHash().substr(1); + Ember.deprecate('location.hash value is ambiguous. Support for this will be removed soon. When using location: "hash|auto" your hash paths MUST begin with a forward slash. e.g. #/' + path + ' NOT #' + path + '. See http://emberjs.com/guides/deprecations/#toc_location-hash-paths-must-now-include-a-forward-slash-e-g-foo-not-foo', path.length === 0 || path.charAt(0) === '/'); + return path; + }, + + /** + Set the `location.hash` and remembers what was set. This prevents + `onUpdateURL` callbacks from triggering when the hash was set by + `HashLocation`. + + @private + @method setURL + @param path {String} + */ + setURL: function(path) { + get(this, 'location').hash = path; + set(this, 'lastSetURL', path); + }, + + /** + Uses location.replace to update the url without a page reload + or history modification. + + @private + @method replaceURL + @param path {String} + */ + replaceURL: function(path) { + get(this, 'location').replace('#' + path); + set(this, 'lastSetURL', path); + }, + + /** + Register a callback to be invoked when the hash changes. These + callbacks will execute when the user presses the back or forward + button, but not after `setURL` is invoked. + + @private + @method onUpdateURL + @param callback {Function} + */ + onUpdateURL: function(callback) { + var self = this; + var guid = guidFor(this); + + Ember.$(window).on('hashchange.ember-location-'+guid, function() { + run(function() { + var path = self.getURL(); + if (get(self, 'lastSetURL') === path) { return; } + + set(self, 'lastSetURL', null); + + callback(path); + }); + }); + }, + + /** + Given a URL, formats it to be placed into the page as part + of an element's `href` attribute. + + This is used, for example, when using the {{action}} helper + to generate a URL based on an event. + + @private + @method formatURL + @param url {String} + */ + formatURL: function(url) { + return '#' + url; + }, + + /** + Cleans up the HashLocation event listener. + + @private + @method willDestroy + */ + willDestroy: function() { + var guid = guidFor(this); + + Ember.$(window).off('hashchange.ember-location-'+guid); + } + }); + }); +enifed("ember-routing/location/history_location", + ["ember-metal/core","ember-metal/property_get","ember-metal/property_set","ember-metal/utils","ember-runtime/system/object","ember-views/system/jquery","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __exports__) { + "use strict"; + var Ember = __dependency1__["default"]; + // FEATURES + var get = __dependency2__.get; + var set = __dependency3__.set; + var guidFor = __dependency4__.guidFor; + + var EmberObject = __dependency5__["default"]; + var jQuery = __dependency6__["default"]; + + /** + @module ember + @submodule ember-routing + */ + + var popstateFired = false; + var supportsHistoryState = window.history && 'state' in window.history; + + /** + Ember.HistoryLocation implements the location API using the browser's + history.pushState API. + + @class HistoryLocation + @namespace Ember + @extends Ember.Object + */ + __exports__["default"] = EmberObject.extend({ + implementation: 'history', + + init: function() { + set(this, 'location', get(this, 'location') || window.location); + set(this, 'baseURL', jQuery('base').attr('href') || ''); + }, + + /** + Used to set state on first call to setURL + + @private + @method initState + */ + initState: function() { + set(this, 'history', get(this, 'history') || window.history); + this.replaceState(this.formatURL(this.getURL())); + }, + + /** + Will be pre-pended to path upon state change + + @property rootURL + @default '/' + */ + rootURL: '/', + + /** + Returns the current `location.pathname` without `rootURL` or `baseURL` + + @private + @method getURL + @return url {String} + */ + getURL: function() { + var rootURL = get(this, 'rootURL'); + var location = get(this, 'location'); + var path = location.pathname; + var baseURL = get(this, 'baseURL'); + + rootURL = rootURL.replace(/\/$/, ''); + baseURL = baseURL.replace(/\/$/, ''); + + var url = path.replace(baseURL, '').replace(rootURL, ''); + var search = location.search || ''; + + url += search; + + return url; + }, + + /** + Uses `history.pushState` to update the url without a page reload. + + @private + @method setURL + @param path {String} + */ + setURL: function(path) { + var state = this.getState(); + path = this.formatURL(path); + + if (!state || state.path !== path) { + this.pushState(path); + } + }, + + /** + Uses `history.replaceState` to update the url without a page reload + or history modification. + + @private + @method replaceURL + @param path {String} + */ + replaceURL: function(path) { + var state = this.getState(); + path = this.formatURL(path); + + if (!state || state.path !== path) { + this.replaceState(path); + } + }, + + /** + Get the current `history.state`. Checks for if a polyfill is + required and if so fetches this._historyState. The state returned + from getState may be null if an iframe has changed a window's + history. + + @private + @method getState + @return state {Object} + */ + getState: function() { + return supportsHistoryState ? get(this, 'history').state : this._historyState; + }, + + /** + Pushes a new state. + + @private + @method pushState + @param path {String} + */ + pushState: function(path) { + var state = { path: path }; + + get(this, 'history').pushState(state, null, path); + + // store state if browser doesn't support `history.state` + if (!supportsHistoryState) { + this._historyState = state; + } + + // used for webkit workaround + this._previousURL = this.getURL(); + }, + + /** + Replaces the current state. + + @private + @method replaceState + @param path {String} + */ + replaceState: function(path) { + var state = { path: path }; + + get(this, 'history').replaceState(state, null, path); + + // store state if browser doesn't support `history.state` + if (!supportsHistoryState) { + this._historyState = state; + } + + // used for webkit workaround + this._previousURL = this.getURL(); + }, + + /** + Register a callback to be invoked whenever the browser + history changes, including using forward and back buttons. + + @private + @method onUpdateURL + @param callback {Function} + */ + onUpdateURL: function(callback) { + var guid = guidFor(this); + var self = this; + + jQuery(window).on('popstate.ember-location-'+guid, function(e) { + // Ignore initial page load popstate event in Chrome + if (!popstateFired) { + popstateFired = true; + if (self.getURL() === self._previousURL) { return; } + } + callback(self.getURL()); + }); + }, + + /** + Used when using `{{action}}` helper. The url is always appended to the rootURL. + + @private + @method formatURL + @param url {String} + @return formatted url {String} + */ + formatURL: function(url) { + var rootURL = get(this, 'rootURL'); + var baseURL = get(this, 'baseURL'); + + if (url !== '') { + rootURL = rootURL.replace(/\/$/, ''); + baseURL = baseURL.replace(/\/$/, ''); + } else if(baseURL.match(/^\//) && rootURL.match(/^\//)) { + baseURL = baseURL.replace(/\/$/, ''); + } + + return baseURL + rootURL + url; + }, + + /** + Cleans up the HistoryLocation event listener. + + @private + @method willDestroy + */ + willDestroy: function() { + var guid = guidFor(this); + + jQuery(window).off('popstate.ember-location-'+guid); + } + }); + }); +enifed("ember-routing/location/none_location", + ["ember-metal/property_get","ember-metal/property_set","ember-runtime/system/object","exports"], function(__dependency1__, __dependency2__, __dependency3__, __exports__) { "use strict"; - var all = __dependency1__["default"]; - var map = __dependency2__["default"]; - var isFunction = __dependency3__.isFunction; - var isArray = __dependency3__.isArray; + var get = __dependency1__.get; + var set = __dependency2__.set; + var EmberObject = __dependency3__["default"]; /** - `RSVP.filter` is similar to JavaScript's native `filter` method, except that it - waits for all promises to become fulfilled before running the `filterFn` on - each item in given to `promises`. `RSVP.filter` returns a promise that will - become fulfilled with the result of running `filterFn` on the values the - promises become fulfilled with. - - For example: - - ```javascript - - var promise1 = RSVP.resolve(1); - var promise2 = RSVP.resolve(2); - var promise3 = RSVP.resolve(3); - - var filterFn = function(item){ - return item > 1; - }; - - RSVP.filter(promises, filterFn).then(function(result){ - // result is [ 2, 3 ] - }); - ``` - - If any of the `promises` given to `RSVP.filter` are rejected, the first promise - that is rejected will be given as an argument to the returned promise's - rejection handler. For example: - - ```javascript - var promise1 = RSVP.resolve(1); - var promise2 = RSVP.reject(new Error("2")); - var promise3 = RSVP.reject(new Error("3")); - var promises = [ promise1, promise2, promise3 ]; - - var filterFn = function(item){ - return item > 1; - }; - - RSVP.filter(promises, filterFn).then(function(array){ - // Code here never runs because there are rejected promises! - }, function(reason) { - // reason.message === "2" - }); - ``` - - `RSVP.filter` will also wait for any promises returned from `filterFn`. - For instance, you may want to fetch a list of users then return a subset - of those users based on some asynchronous operation: - - ```javascript - - var alice = { name: 'alice' }; - var bob = { name: 'bob' }; - var users = [ alice, bob ]; - - var promises = users.map(function(user){ - return RSVP.resolve(user); - }); - - var filterFn = function(user){ - // Here, Alice has permissions to create a blog post, but Bob does not. - return getPrivilegesForUser(user).then(function(privs){ - return privs.can_create_blog_post === true; - }); - }; - RSVP.filter(promises, filterFn).then(function(users){ - // true, because the server told us only Alice can create a blog post. - users.length === 1; - // false, because Alice is the only user present in `users` - users[0] === bob; - }); - ``` - - @method filter - @for RSVP - @param {Array} promises - @param {Function} filterFn - function to be called on each resolved value to - filter the final results. - @param {String} label optional string describing the promise. Useful for - tooling. - @return {Promise} + @module ember + @submodule ember-routing */ - function filter(promises, filterFn, label) { - return all(promises, label).then(function(values){ - if (!isArray(promises)) { - throw new TypeError('You must pass an array to filter.'); - } - - if (!isFunction(filterFn)){ - throw new TypeError("You must pass a function to filter's second argument."); - } - - return map(promises, filterFn, label).then(function(filterResults){ - var i, - valuesLen = values.length, - filtered = []; - - for (i = 0; i < valuesLen; i++){ - if(filterResults[i]) filtered.push(values[i]); - } - return filtered; - }); - }); - } - - __exports__["default"] = filter; - }); -define("rsvp/hash", - ["./promise","./utils","exports"], - function(__dependency1__, __dependency2__, __exports__) { - "use strict"; - var Promise = __dependency1__["default"]; - var isNonThenable = __dependency2__.isNonThenable; - var keysOf = __dependency2__.keysOf; /** - `RSVP.hash` is similar to `RSVP.all`, but takes an object instead of an array - for its `promises` argument. + Ember.NoneLocation does not interact with the browser. It is useful for + testing, or when you need to manage state with your Router, but temporarily + don't want it to muck with the URL (for example when you embed your + application in a larger page). - Returns a promise that is fulfilled when all the given promises have been - fulfilled, or rejected if any of them become rejected. The returned promise - is fulfilled with a hash that has the same key names as the `promises` object - argument. If any of the values in the object are not promises, they will - simply be copied over to the fulfilled object. - - Example: - - ```javascript - var promises = { - myPromise: RSVP.resolve(1), - yourPromise: RSVP.resolve(2), - theirPromise: RSVP.resolve(3), - notAPromise: 4 - }; - - RSVP.hash(promises).then(function(hash){ - // hash here is an object that looks like: - // { - // myPromise: 1, - // yourPromise: 2, - // theirPromise: 3, - // notAPromise: 4 - // } - }); - ```` - - If any of the `promises` given to `RSVP.hash` are rejected, the first promise - that is rejected will be given as the reason to the rejection handler. - - Example: - - ```javascript - var promises = { - myPromise: RSVP.resolve(1), - rejectedPromise: RSVP.reject(new Error("rejectedPromise")), - anotherRejectedPromise: RSVP.reject(new Error("anotherRejectedPromise")), - }; - - RSVP.hash(promises).then(function(hash){ - // Code here never runs because there are rejected promises! - }, function(reason) { - // reason.message === "rejectedPromise" - }); - ``` - - An important note: `RSVP.hash` is intended for plain JavaScript objects that - are just a set of keys and values. `RSVP.hash` will NOT preserve prototype - chains. - - Example: - - ```javascript - function MyConstructor(){ - this.example = RSVP.resolve("Example"); - } - - MyConstructor.prototype = { - protoProperty: RSVP.resolve("Proto Property") - }; - - var myObject = new MyConstructor(); - - RSVP.hash(myObject).then(function(hash){ - // protoProperty will not be present, instead you will just have an - // object that looks like: - // { - // example: "Example" - // } - // - // hash.hasOwnProperty('protoProperty'); // false - // 'undefined' === typeof hash.protoProperty - }); - ``` - - @method hash - @for RSVP - @param {Object} promises - @param {String} label optional string that describes the promise. - Useful for tooling. - @return {Promise} promise that is fulfilled when all properties of `promises` - have been fulfilled, or rejected if any of them become rejected. - @static + @class NoneLocation + @namespace Ember + @extends Ember.Object */ - __exports__["default"] = function hash(object, label) { - return new Promise(function(resolve, reject){ - var results = {}; - var keys = keysOf(object); - var remaining = keys.length; - var entry, property; - - if (remaining === 0) { - resolve(results); - return; - } - - function fulfilledTo(property) { - return function(value) { - results[property] = value; - if (--remaining === 0) { - resolve(results); - } - }; - } - - function onRejection(reason) { - remaining = 0; - reject(reason); - } - - for (var i = 0; i < keys.length; i++) { - property = keys[i]; - entry = object[property]; - - if (isNonThenable(entry)) { - results[property] = entry; - if (--remaining === 0) { - resolve(results); - } - } else { - Promise.cast(entry).then(fulfilledTo(property), onRejection); - } - } - }); - }; - }); -define("rsvp/instrument", - ["./config","./utils","exports"], - function(__dependency1__, __dependency2__, __exports__) { - "use strict"; - var config = __dependency1__.config; - var now = __dependency2__.now; - - __exports__["default"] = function instrument(eventName, promise, child) { - // instrumentation should not disrupt normal usage. - try { - config.trigger(eventName, { - guid: promise._guidKey + promise._id, - eventName: eventName, - detail: promise._detail, - childGuid: child && promise._guidKey + child._id, - label: promise._label, - timeStamp: now(), - stack: new Error(promise._label).stack - }); - } catch(error) { - setTimeout(function(){ - throw error; - }, 0); - } - }; - }); -define("rsvp/map", - ["./promise","./all","./utils","exports"], - function(__dependency1__, __dependency2__, __dependency3__, __exports__) { - "use strict"; - var Promise = __dependency1__["default"]; - var all = __dependency2__["default"]; - var isArray = __dependency3__.isArray; - var isFunction = __dependency3__.isFunction; - - /** - `RSVP.map` is similar to JavaScript's native `map` method, except that it - waits for all promises to become fulfilled before running the `mapFn` on - each item in given to `promises`. `RSVP.map` returns a promise that will - become fulfilled with the result of running `mapFn` on the values the promises - become fulfilled with. - - For example: - - ```javascript - - var promise1 = RSVP.resolve(1); - var promise2 = RSVP.resolve(2); - var promise3 = RSVP.resolve(3); - var promises = [ promise1, promise2, promise3 ]; - - var mapFn = function(item){ - return item + 1; - }; - - RSVP.map(promises, mapFn).then(function(result){ - // result is [ 2, 3, 4 ] - }); - ``` - - If any of the `promises` given to `RSVP.map` are rejected, the first promise - that is rejected will be given as an argument to the returned promise's - rejection handler. For example: - - ```javascript - var promise1 = RSVP.resolve(1); - var promise2 = RSVP.reject(new Error("2")); - var promise3 = RSVP.reject(new Error("3")); - var promises = [ promise1, promise2, promise3 ]; - - var mapFn = function(item){ - return item + 1; - }; - - RSVP.map(promises, mapFn).then(function(array){ - // Code here never runs because there are rejected promises! - }, function(reason) { - // reason.message === "2" - }); - ``` - - `RSVP.map` will also wait if a promise is returned from `mapFn`. For example, - say you want to get all comments from a set of blog posts, but you need - the blog posts first becuase they contain a url to those comments. - - ```javscript - - var mapFn = function(blogPost){ - // getComments does some ajax and returns an RSVP.Promise that is fulfilled - // with some comments data - return getComments(blogPost.comments_url); - }; - - // getBlogPosts does some ajax and returns an RSVP.Promise that is fulfilled - // with some blog post data - RSVP.map(getBlogPosts(), mapFn).then(function(comments){ - // comments is the result of asking the server for the comments - // of all blog posts returned from getBlogPosts() - }); - ``` - - @method map - @for RSVP - @param {Array} promises - @param {Function} mapFn function to be called on each fulfilled promise. - @param {String} label optional string for labeling the promise. - Useful for tooling. - @return {Promise} promise that is fulfilled with the result of calling - `mapFn` on each fulfilled promise or value when they become fulfilled. - The promise will be rejected if any of the given `promises` become rejected. - @static - */ - __exports__["default"] = function map(promises, mapFn, label) { - return all(promises, label).then(function(results){ - if (!isArray(promises)) { - throw new TypeError('You must pass an array to map.'); - } - - if (!isFunction(mapFn)){ - throw new TypeError("You must pass a function to map's second argument."); - } - - - var resultLen = results.length, - mappedResults = [], - i; - - for (i = 0; i < resultLen; i++){ - mappedResults.push(mapFn(results[i])); - } - - return all(mappedResults, label); - }); - }; - }); -define("rsvp/node", - ["./promise","exports"], - function(__dependency1__, __exports__) { - "use strict"; - var Promise = __dependency1__["default"]; - - var slice = Array.prototype.slice; - - function makeNodeCallbackFor(resolve, reject) { - return function (error, value) { - if (error) { - reject(error); - } else if (arguments.length > 2) { - resolve(slice.call(arguments, 1)); - } else { - resolve(value); - } - }; - } - - /** - `RSVP.denodeify` takes a "node-style" function and returns a function that - will return an `RSVP.Promise`. You can use `denodeify` in Node.js or the - browser when you'd prefer to use promises over using callbacks. For example, - `denodeify` transforms the following: - - ```javascript - var fs = require('fs'); - - fs.readFile('myfile.txt', function(err, data){ - if (err) return handleError(err); - handleData(data); - }); - ``` - - into: - - ```javascript - var fs = require('fs'); - - var readFile = RSVP.denodeify(fs.readFile); - - readFile('myfile.txt').then(handleData, handleError); - ``` - - Using `denodeify` makes it easier to compose asynchronous operations instead - of using callbacks. For example, instead of: - - ```javascript - var fs = require('fs'); - var log = require('some-async-logger'); - - fs.readFile('myfile.txt', function(err, data){ - if (err) return handleError(err); - fs.writeFile('myfile2.txt', data, function(err){ - if (err) throw err; - log('success', function(err) { - if (err) throw err; - }); - }); - }); - ``` - - You can chain the operations together using `then` from the returned promise: - - ```javascript - var fs = require('fs'); - var denodeify = RSVP.denodeify; - var readFile = denodeify(fs.readFile); - var writeFile = denodeify(fs.writeFile); - var log = denodeify(require('some-async-logger')); - - readFile('myfile.txt').then(function(data){ - return writeFile('myfile2.txt', data); - }).then(function(){ - return log('SUCCESS'); - }).then(function(){ - // success handler - }, function(reason){ - // rejection handler - }); - ``` - - @method denodeify - @for RSVP - @param {Function} nodeFunc a "node-style" function that takes a callback as - its last argument. The callback expects an error to be passed as its first - argument (if an error occurred, otherwise null), and the value from the - operation as its second argument ("function(err, value){ }"). - @param {Any} binding optional argument for binding the "this" value when - calling the `nodeFunc` function. - @return {Function} a function that wraps `nodeFunc` to return an - `RSVP.Promise` - @static - */ - __exports__["default"] = function denodeify(nodeFunc, binding) { - return function() { - var nodeArgs = slice.call(arguments), resolve, reject; - var thisArg = this || binding; - - return new Promise(function(resolve, reject) { - Promise.all(nodeArgs).then(function(nodeArgs) { - try { - nodeArgs.push(makeNodeCallbackFor(resolve, reject)); - nodeFunc.apply(thisArg, nodeArgs); - } catch(e) { - reject(e); - } - }); - }); - }; - }; - }); -define("rsvp/promise", - ["./config","./events","./instrument","./utils","./promise/cast","./promise/all","./promise/race","./promise/resolve","./promise/reject","exports"], - function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __dependency9__, __exports__) { - "use strict"; - var config = __dependency1__.config; - var EventTarget = __dependency2__["default"]; - var instrument = __dependency3__["default"]; - var objectOrFunction = __dependency4__.objectOrFunction; - var isFunction = __dependency4__.isFunction; - var now = __dependency4__.now; - var cast = __dependency5__["default"]; - var all = __dependency6__["default"]; - var race = __dependency7__["default"]; - var Resolve = __dependency8__["default"]; - var Reject = __dependency9__["default"]; - - var guidKey = 'rsvp_' + now() + '-'; - var counter = 0; - - function noop() {} - - __exports__["default"] = Promise; - - - /** - Promise objects represent the eventual result of an asynchronous operation. The - primary way of interacting with a promise is through its `then` method, which - registers callbacks to receive either a promise’s eventual value or the reason - why the promise cannot be fulfilled. - - Terminology - ----------- - - - `promise` is an object or function with a `then` method whose behavior conforms to this specification. - - `thenable` is an object or function that defines a `then` method. - - `value` is any legal JavaScript value (including undefined, a thenable, or a promise). - - `exception` is a value that is thrown using the throw statement. - - `reason` is a value that indicates why a promise was rejected. - - `settled` the final resting state of a promise, fulfilled or rejected. - - A promise can be in one of three states: pending, fulfilled, or rejected. - - Promises that are fulfilled have a fulfillment value and are in the fulfilled - state. Promises that are rejected have a rejection reason and are in the - rejected state. A fulfillment value is never a thenable. Similarly, a - rejection reason is never a thenable. - - Promises can also be said to *resolve* a value. If this value is also a - promise, then the original promise's settled state will match the value's - settled state. So a promise that *resolves* a promise that rejects will - itself reject, and a promise that *resolves* a promise that fulfills will - itself fulfill. - - - Basic Usage: - ------------ - - ```js - var promise = new Promise(function(resolve, reject) { - // on success - resolve(value); - - // on failure - reject(reason); - }); - - promise.then(function(value) { - // on fulfillment - }, function(reason) { - // on rejection - }); - ``` - - Advanced Usage: - --------------- - - Promises shine when abstracting away asynchronous interactions such as - `XMLHttpRequest`s. - - ```js - function getJSON(url) { - return new Promise(function(resolve, reject){ - var xhr = new XMLHttpRequest(); - - xhr.open('GET', url); - xhr.onreadystatechange = handler; - xhr.responseType = 'json'; - xhr.setRequestHeader('Accept', 'application/json'); - xhr.send(); - - function handler() { - if (this.readyState === this.DONE) { - if (this.status === 200) { - resolve(this.response); - } else { - reject(new Error("getJSON: `" + url + "` failed with status: [" + this.status + "]"); - } - } - }; - }); - } - - getJSON('/posts.json').then(function(json) { - // on fulfillment - }, function(reason) { - // on rejection - }); - ``` - - Unlike callbacks, promises are great composable primitives. - - ```js - Promise.all([ - getJSON('/posts'), - getJSON('/comments') - ]).then(function(values){ - values[0] // => postsJSON - values[1] // => commentsJSON - - return values; - }); - ``` - - @class RSVP.Promise - @param {function} - @param {String} label optional string for labeling the promise. - Useful for tooling. - @constructor - */ - function Promise(resolver, label) { - if (!isFunction(resolver)) { - throw new TypeError('You must pass a resolver function as the first argument to the promise constructor'); - } - - if (!(this instanceof Promise)) { - throw new TypeError("Failed to construct 'Promise': Please use the 'new' operator, this object constructor cannot be called as a function."); - } - - this._id = counter++; - this._label = label; - this._subscribers = []; - - if (config.instrument) { - instrument('created', this); - } - - if (noop !== resolver) { - invokeResolver(resolver, this); - } - } - - function invokeResolver(resolver, promise) { - function resolvePromise(value) { - resolve(promise, value); - } - - function rejectPromise(reason) { - reject(promise, reason); - } - - try { - resolver(resolvePromise, rejectPromise); - } catch(e) { - rejectPromise(e); - } - } - - Promise.cast = cast; - Promise.all = all; - Promise.race = race; - Promise.resolve = Resolve; - Promise.reject = Reject; - - var PENDING = void 0; - var SEALED = 0; - var FULFILLED = 1; - var REJECTED = 2; - - function subscribe(parent, child, onFulfillment, onRejection) { - var subscribers = parent._subscribers; - var length = subscribers.length; - - subscribers[length] = child; - subscribers[length + FULFILLED] = onFulfillment; - subscribers[length + REJECTED] = onRejection; - } - - function publish(promise, settled) { - var child, callback, subscribers = promise._subscribers, detail = promise._detail; - - if (config.instrument) { - instrument(settled === FULFILLED ? 'fulfilled' : 'rejected', promise); - } - - for (var i = 0; i < subscribers.length; i += 3) { - child = subscribers[i]; - callback = subscribers[i + settled]; - - invokeCallback(settled, child, callback, detail); - } - - promise._subscribers = null; - } - - Promise.prototype = { - constructor: Promise, - - _id: undefined, - _guidKey: guidKey, - _label: undefined, - - _state: undefined, - _detail: undefined, - _subscribers: undefined, - - _onerror: function (reason) { - config.trigger('error', reason); - }, - - /** - The primary way of interacting with a promise is through its `then` method, - which registers callbacks to receive either a promise's eventual value or the - reason why the promise cannot be fulfilled. - - ```js - findUser().then(function(user){ - // user is available - }, function(reason){ - // user is unavailable, and you are given the reason why - }); - ``` - - Chaining - -------- - - The return value of `then` is itself a promise. This second, "downstream" - promise is resolved with the return value of the first promise's fulfillment - or rejection handler, or rejected if the handler throws an exception. - - ```js - findUser().then(function (user) { - return user.name; - }, function (reason) { - return "default name"; - }).then(function (userName) { - // If `findUser` fulfilled, `userName` will be the user's name, otherwise it - // will be `"default name"` - }); - - findUser().then(function (user) { - throw new Error("Found user, but still unhappy"); - }, function (reason) { - throw new Error("`findUser` rejected and we're unhappy"); - }).then(function (value) { - // never reached - }, function (reason) { - // if `findUser` fulfilled, `reason` will be "Found user, but still unhappy". - // If `findUser` rejected, `reason` will be "`findUser` rejected and we're unhappy". - }); - ``` - If the downstream promise does not specify a rejection handler, rejection reasons will be propagated further downstream. - - ```js - findUser().then(function (user) { - throw new PedagogicalException("Upstream error"); - }).then(function (value) { - // never reached - }).then(function (value) { - // never reached - }, function (reason) { - // The `PedgagocialException` is propagated all the way down to here - }); - ``` - - Assimilation - ------------ - - Sometimes the value you want to propagate to a downstream promise can only be - retrieved asynchronously. This can be achieved by returning a promise in the - fulfillment or rejection handler. The downstream promise will then be pending - until the returned promise is settled. This is called *assimilation*. - - ```js - findUser().then(function (user) { - return findCommentsByAuthor(user); - }).then(function (comments) { - // The user's comments are now available - }); - ``` - - If the assimliated promise rejects, then the downstream promise will also reject. - - ```js - findUser().then(function (user) { - return findCommentsByAuthor(user); - }).then(function (comments) { - // If `findCommentsByAuthor` fulfills, we'll have the value here - }, function (reason) { - // If `findCommentsByAuthor` rejects, we'll have the reason here - }); - ``` - - Simple Example - -------------- - - Synchronous Example - - ```javascript - var result; - - try { - result = findResult(); - // success - } catch(reason) { - // failure - } - ``` - - Errback Example - - ```js - findResult(function(result, err){ - if (err) { - // failure - } else { - // success - } - }); - ``` - - Promise Example; - - ```javascript - findResult().then(function(result){ - // success - }, function(reason){ - // failure - }); - ``` - - Advanced Example - -------------- - - Synchronous Example - - ```javascript - var author, books; - - try { - author = findAuthor(); - books = findBooksByAuthor(author); - // success - } catch(reason) { - // failure - } - ``` - - Errback Example - - ```js - - function foundBooks(books) { - - } - - function failure(reason) { - - } - - findAuthor(function(author, err){ - if (err) { - failure(err); - // failure - } else { - try { - findBoooksByAuthor(author, function(books, err) { - if (err) { - failure(err); - } else { - try { - foundBooks(books); - } catch(reason) { - failure(reason); - } - } - }); - } catch(error) { - failure(err); - } - // success - } - }); - ``` - - Promise Example; - - ```javascript - findAuthor(). - then(findBooksByAuthor). - then(function(books){ - // found books - }).catch(function(reason){ - // something went wrong - }); - ``` - - @method then - @param {Function} onFulfilled - @param {Function} onRejected - @param {String} label optional string for labeling the promise. - Useful for tooling. - @return {Promise} - */ - then: function(onFulfillment, onRejection, label) { - var promise = this; - this._onerror = null; - - var thenPromise = new this.constructor(noop, label); - - if (this._state) { - var callbacks = arguments; - config.async(function invokePromiseCallback() { - invokeCallback(promise._state, thenPromise, callbacks[promise._state - 1], promise._detail); - }); - } else { - subscribe(this, thenPromise, onFulfillment, onRejection); - } - - if (config.instrument) { - instrument('chained', promise, thenPromise); - } - - return thenPromise; - }, - - /** - `catch` is simply sugar for `then(undefined, onRejection)` which makes it the same - as the catch block of a try/catch statement. - - ```js - function findAuthor(){ - throw new Error("couldn't find that author"); - } - - // synchronous - try { - findAuthor(); - } catch(reason) { - // something went wrong - } - - // async with promises - findAuthor().catch(function(reason){ - // something went wrong - }); - ``` - - @method catch - @param {Function} onRejection - @param {String} label optional string for labeling the promise. - Useful for tooling. - @return {Promise} - */ - 'catch': function(onRejection, label) { - return this.then(null, onRejection, label); - }, - - /** - `finally` will be invoked regardless of the promise's fate just as native - try/catch/finally behaves - - Synchronous example: - - ```js - findAuthor() { - if (Math.random() > 0.5) { - throw new Error(); - } - return new Author(); - } - - try { - return findAuthor(); // succeed or fail - } catch(error) { - return findOtherAuther(); - } finally { - // always runs - // doesn't affect the return value - } - ``` - - Asynchronous example: - - ```js - findAuthor().catch(function(reason){ - return findOtherAuther(); - }).finally(function(){ - // author was either found, or not - }); - ``` - - @method finally - @param {Function} callback - @param {String} label optional string for labeling the promise. - Useful for tooling. - @return {Promise} - */ - 'finally': function(callback, label) { - var constructor = this.constructor; - - return this.then(function(value) { - return constructor.cast(callback()).then(function(){ - return value; - }); - }, function(reason) { - return constructor.cast(callback()).then(function(){ - throw reason; - }); - }, label); - } - }; - - function invokeCallback(settled, promise, callback, detail) { - var hasCallback = isFunction(callback), - value, error, succeeded, failed; - - if (hasCallback) { - try { - value = callback(detail); - succeeded = true; - } catch(e) { - failed = true; - error = e; - } - } else { - value = detail; - succeeded = true; - } - - if (handleThenable(promise, value)) { - return; - } else if (hasCallback && succeeded) { - resolve(promise, value); - } else if (failed) { - reject(promise, error); - } else if (settled === FULFILLED) { - resolve(promise, value); - } else if (settled === REJECTED) { - reject(promise, value); - } - } - - function handleThenable(promise, value) { - var then = null, - resolved; - - try { - if (promise === value) { - throw new TypeError("A promises callback cannot return that same promise."); - } - - if (objectOrFunction(value)) { - then = value.then; - - if (isFunction(then)) { - then.call(value, function(val) { - if (resolved) { return true; } - resolved = true; - - if (value !== val) { - resolve(promise, val); - } else { - fulfill(promise, val); - } - }, function(val) { - if (resolved) { return true; } - resolved = true; - - reject(promise, val); - }, 'derived from: ' + (promise._label || ' unknown promise')); - - return true; - } - } - } catch (error) { - if (resolved) { return true; } - reject(promise, error); - return true; - } - - return false; - } - - function resolve(promise, value) { - if (promise === value) { - fulfill(promise, value); - } else if (!handleThenable(promise, value)) { - fulfill(promise, value); - } - } - - function fulfill(promise, value) { - if (promise._state !== PENDING) { return; } - promise._state = SEALED; - promise._detail = value; - - config.async(publishFulfillment, promise); - } - - function reject(promise, reason) { - if (promise._state !== PENDING) { return; } - promise._state = SEALED; - promise._detail = reason; - - config.async(publishRejection, promise); - } - - function publishFulfillment(promise) { - publish(promise, promise._state = FULFILLED); - } - - function publishRejection(promise) { - if (promise._onerror) { - promise._onerror(promise._detail); - } - - publish(promise, promise._state = REJECTED); - } - }); -define("rsvp/promise/all", - ["../utils","exports"], - function(__dependency1__, __exports__) { - "use strict"; - var isArray = __dependency1__.isArray; - var isNonThenable = __dependency1__.isNonThenable; - - /** - `RSVP.Promise.all` accepts an array of promises, and returns a new promise which - is fulfilled with an array of fulfillment values for the passed promises, or - rejected with the reason of the first passed promise to be rejected. It casts all - elements of the passed iterable to promises as it runs this algorithm. - - Example: - - ```javascript - var promise1 = RSVP.resolve(1); - var promise2 = RSVP.resolve(2); - var promise3 = RSVP.resolve(3); - var promises = [ promise1, promise2, promise3 ]; - - RSVP.Promise.all(promises).then(function(array){ - // The array here would be [ 1, 2, 3 ]; - }); - ``` - - If any of the `promises` given to `RSVP.all` are rejected, the first promise - that is rejected will be given as an argument to the returned promises's - rejection handler. For example: - - Example: - - ```javascript - var promise1 = RSVP.resolve(1); - var promise2 = RSVP.reject(new Error("2")); - var promise3 = RSVP.reject(new Error("3")); - var promises = [ promise1, promise2, promise3 ]; - - RSVP.Promise.all(promises).then(function(array){ - // Code here never runs because there are rejected promises! - }, function(error) { - // error.message === "2" - }); - ``` - - @method all - @for Ember.RSVP.Promise - @param {Array} entries array of promises - @param {String} label optional string for labeling the promise. - Useful for tooling. - @return {Promise} promise that is fulfilled when all `promises` have been - fulfilled, or rejected if any of them become rejected. - @static - */ - __exports__["default"] = function all(entries, label) { - - /*jshint validthis:true */ - var Constructor = this; - - return new Constructor(function(resolve, reject) { - if (!isArray(entries)) { - throw new TypeError('You must pass an array to all.'); - } - - var remaining = entries.length; - var results = new Array(remaining); - var entry, pending = true; - - if (remaining === 0) { - resolve(results); - return; - } - - function fulfillmentAt(index) { - return function(value) { - results[index] = value; - if (--remaining === 0) { - resolve(results); - } - }; - } - - function onRejection(reason) { - remaining = 0; - reject(reason); - } - - for (var index = 0; index < entries.length; index++) { - entry = entries[index]; - if (isNonThenable(entry)) { - results[index] = entry; - if (--remaining === 0) { - resolve(results); - } - } else { - Constructor.cast(entry).then(fulfillmentAt(index), onRejection); - } - } - }, label); - }; - }); -define("rsvp/promise/cast", - ["exports"], - function(__exports__) { - "use strict"; - /** - `RSVP.Promise.cast` coerces its argument to a promise, or returns the - argument if it is already a promise which shares a constructor with the caster. - - Example: - - ```javascript - var promise = RSVP.Promise.resolve(1); - var casted = RSVP.Promise.cast(promise); - - console.log(promise === casted); // true - ``` - - In the case of a promise whose constructor does not match, it is assimilated. - The resulting promise will fulfill or reject based on the outcome of the - promise being casted. - - Example: - - ```javascript - var thennable = $.getJSON('/api/foo'); - var casted = RSVP.Promise.cast(thennable); - - console.log(thennable === casted); // false - console.log(casted instanceof RSVP.Promise) // true - - casted.then(function(data) { - // data is the value getJSON fulfills with - }); - ``` - - In the case of a non-promise, a promise which will fulfill with that value is - returned. - - Example: - - ```javascript - var value = 1; // could be a number, boolean, string, undefined... - var casted = RSVP.Promise.cast(value); - - console.log(value === casted); // false - console.log(casted instanceof RSVP.Promise) // true - - casted.then(function(val) { - val === value // => true - }); - ``` - - `RSVP.Promise.cast` is similar to `RSVP.Promise.resolve`, but `RSVP.Promise.cast` differs in the - following ways: - - * `RSVP.Promise.cast` serves as a memory-efficient way of getting a promise, when you - have something that could either be a promise or a value. RSVP.resolve - will have the same effect but will create a new promise wrapper if the - argument is a promise. - * `RSVP.Promise.cast` is a way of casting incoming thenables or promise subclasses to - promises of the exact class specified, so that the resulting object's `then` is - ensured to have the behavior of the constructor you are calling cast on (i.e., RSVP.Promise). - - @method cast - @param {Object} object to be casted - @param {String} label optional string for labeling the promise. - Useful for tooling. - @return {Promise} promise - @static - */ - - __exports__["default"] = function cast(object, label) { - /*jshint validthis:true */ - var Constructor = this; - - if (object && typeof object === 'object' && object.constructor === Constructor) { - return object; - } - - return new Constructor(function(resolve) { - resolve(object); - }, label); - }; - }); -define("rsvp/promise/race", - ["../utils","exports"], - function(__dependency1__, __exports__) { - "use strict"; - /* global toString */ - - var isArray = __dependency1__.isArray; - var isFunction = __dependency1__.isFunction; - var isNonThenable = __dependency1__.isNonThenable; - - /** - `RSVP.Promise.race` returns a new promise which is settled in the same way as the - first passed promise to settle. - - Example: - - ```javascript - var promise1 = new RSVP.Promise(function(resolve, reject){ - setTimeout(function(){ - resolve("promise 1"); - }, 200); - }); - - var promise2 = new RSVP.Promise(function(resolve, reject){ - setTimeout(function(){ - resolve("promise 2"); - }, 100); - }); - - RSVP.Promise.race([promise1, promise2]).then(function(result){ - // result === "promise 2" because it was resolved before promise1 - // was resolved. - }); - ``` - - `RSVP.Promise.race` is deterministic in that only the state of the first - settled promise matters. For example, even if other promises given to the - `promises` array argument are resolved, but the first settled promise has - become rejected before the other promises became fulfilled, the returned - promise will become rejected: - - ```javascript - var promise1 = new RSVP.Promise(function(resolve, reject){ - setTimeout(function(){ - resolve("promise 1"); - }, 200); - }); - - var promise2 = new RSVP.Promise(function(resolve, reject){ - setTimeout(function(){ - reject(new Error("promise 2")); - }, 100); - }); - - RSVP.Promise.race([promise1, promise2]).then(function(result){ - // Code here never runs - }, function(reason){ - // reason.message === "promise2" because promise 2 became rejected before - // promise 1 became fulfilled - }); - ``` - - An example real-world use case is implementing timeouts: - - ```javascript - RSVP.Promise.race([ajax('foo.json'), timeout(5000)]) - ``` - - @method race - @param {Array} promises array of promises to observe - @param {String} label optional string for describing the promise returned. - Useful for tooling. - @return {Promise} a promise which settles in the same way as the first passed - promise to settle. - @static - */ - __exports__["default"] = function race(entries, label) { - /*jshint validthis:true */ - var Constructor = this, entry; - - return new Constructor(function(resolve, reject) { - if (!isArray(entries)) { - throw new TypeError('You must pass an array to race.'); - } - - var pending = true; - - function onFulfillment(value) { if (pending) { pending = false; resolve(value); } } - function onRejection(reason) { if (pending) { pending = false; reject(reason); } } - - for (var i = 0; i < entries.length; i++) { - entry = entries[i]; - if (isNonThenable(entry)) { - pending = false; - resolve(entry); - return; - } else { - Constructor.cast(entry).then(onFulfillment, onRejection); - } - } - }, label); - }; - }); -define("rsvp/promise/reject", - ["exports"], - function(__exports__) { - "use strict"; - /** - `RSVP.Promise.reject` returns a promise rejected with the passed `reason`. - It is shorthand for the following: - - ```javascript - var promise = new RSVP.Promise(function(resolve, reject){ - reject(new Error('WHOOPS')); - }); - - promise.then(function(value){ - // Code here doesn't run because the promise is rejected! - }, function(reason){ - // reason.message === 'WHOOPS' - }); - ``` - - Instead of writing the above, your code now simply becomes the following: - - ```javascript - var promise = RSVP.Promise.reject(new Error('WHOOPS')); - - promise.then(function(value){ - // Code here doesn't run because the promise is rejected! - }, function(reason){ - // reason.message === 'WHOOPS' - }); - ``` - - @method reject - @param {Any} reason value that the returned promise will be rejected with. - @param {String} label optional string for identifying the returned promise. - Useful for tooling. - @return {Promise} a promise rejected with the given `reason`. - @static - */ - __exports__["default"] = function reject(reason, label) { - /*jshint validthis:true */ - var Constructor = this; - - return new Constructor(function (resolve, reject) { - reject(reason); - }, label); - }; - }); -define("rsvp/promise/resolve", - ["exports"], - function(__exports__) { - "use strict"; - /** - `RSVP.Promise.resolve` returns a promise that will become resolved with the - passed `value`. It is shorthand for the following: - - ```javascript - var promise = new RSVP.Promise(function(resolve, reject){ - resolve(1); - }); - - promise.then(function(value){ - // value === 1 - }); - ``` - - Instead of writing the above, your code now simply becomes the following: - - ```javascript - var promise = RSVP.Promise.resolve(1); - - promise.then(function(value){ - // value === 1 - }); - ``` - - @method resolve - @param {Any} value value that the returned promise will be resolved with - @param {String} label optional string for identifying the returned promise. - Useful for tooling. - @return {Promise} a promise that will become fulfilled with the given - `value` - @static - */ - __exports__["default"] = function resolve(value, label) { - /*jshint validthis:true */ - var Constructor = this; - - return new Constructor(function(resolve, reject) { - resolve(value); - }, label); - }; - }); -define("rsvp/race", - ["./promise","exports"], - function(__dependency1__, __exports__) { - "use strict"; - var Promise = __dependency1__["default"]; - - /** - This is a convenient alias for `RSVP.Promise.race`. - - @method race - @param {Array} array Array of promises. - @param {String} label An optional label. This is useful - for tooling. - @static - */ - __exports__["default"] = function race(array, label) { - return Promise.race(array, label); - }; - }); -define("rsvp/reject", - ["./promise","exports"], - function(__dependency1__, __exports__) { - "use strict"; - var Promise = __dependency1__["default"]; - - /** - This is a convenient alias for `RSVP.Promise.reject`. - - @method reject - @for RSVP - @param {Any} reason value that the returned promise will be rejected with. - @param {String} label optional string for identifying the returned promise. - Useful for tooling. - @return {Promise} a promise rejected with the given `reason`. - @static - */ - __exports__["default"] = function reject(reason, label) { - return Promise.reject(reason, label); - }; - }); -define("rsvp/resolve", - ["./promise","exports"], - function(__dependency1__, __exports__) { - "use strict"; - var Promise = __dependency1__["default"]; - - /** - This is a convenient alias for `RSVP.Promise.resolve`. - - @method resolve - @for RSVP - @param {Any} value value that the returned promise will be resolved with - @param {String} label optional string for identifying the returned promise. - Useful for tooling. - @return {Promise} a promise that will become fulfilled with the given - `value` - @static - */ - __exports__["default"] = function resolve(value, label) { - return Promise.resolve(value, label); - }; - }); -define("rsvp/rethrow", - ["exports"], - function(__exports__) { - "use strict"; - /** - `RSVP.rethrow` will rethrow an error on the next turn of the JavaScript event - loop in order to aid debugging. - - Promises A+ specifies that any exceptions that occur with a promise must be - caught by the promises implementation and bubbled to the last handler. For - this reason, it is recommended that you always specify a second rejection - handler function to `then`. However, `RSVP.rethrow` will throw the exception - outside of the promise, so it bubbles up to your console if in the browser, - or domain/cause uncaught exception in Node. `rethrow` will also throw the - error again so the error can be handled by the promise per the spec. - - ```javascript - function throws(){ - throw new Error('Whoops!'); - } - - var promise = new RSVP.Promise(function(resolve, reject){ - throws(); - }); - - promise.catch(RSVP.rethrow).then(function(){ - // Code here doesn't run because the promise became rejected due to an - // error! - }, function (err){ - // handle the error here - }); - ``` - - The 'Whoops' error will be thrown on the next turn of the event loop - and you can watch for it in your console. You can also handle it using a - rejection handler given to `.then` or `.catch` on the returned promise. - - @method rethrow - @for RSVP - @param {Error} reason reason the promise became rejected. - @throws Error - @static - */ - __exports__["default"] = function rethrow(reason) { - setTimeout(function() { - throw reason; - }); - throw reason; - }; - }); -define("rsvp/utils", - ["exports"], - function(__exports__) { - "use strict"; - function objectOrFunction(x) { - return typeof x === "function" || (typeof x === "object" && x !== null); - } - - __exports__.objectOrFunction = objectOrFunction;function isFunction(x) { - return typeof x === "function"; - } - - __exports__.isFunction = isFunction;function isNonThenable(x) { - return !objectOrFunction(x); - } - - __exports__.isNonThenable = isNonThenable;function isArray(x) { - return Object.prototype.toString.call(x) === "[object Array]"; - } - - __exports__.isArray = isArray;// Date.now is not available in browsers < IE9 - // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/now#Compatibility - var now = Date.now || function() { return new Date().getTime(); }; - __exports__.now = now; - var keysOf = Object.keys || function(object) { - var result = []; - - for (var prop in object) { - result.push(prop); - } - - return result; - }; - __exports__.keysOf = keysOf; - }); -define("rsvp", - ["./rsvp/promise","./rsvp/events","./rsvp/node","./rsvp/all","./rsvp/all_settled","./rsvp/race","./rsvp/hash","./rsvp/rethrow","./rsvp/defer","./rsvp/config","./rsvp/map","./rsvp/resolve","./rsvp/reject","./rsvp/filter","exports"], - function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __dependency9__, __dependency10__, __dependency11__, __dependency12__, __dependency13__, __dependency14__, __exports__) { - "use strict"; - var Promise = __dependency1__["default"]; - var EventTarget = __dependency2__["default"]; - var denodeify = __dependency3__["default"]; - var all = __dependency4__["default"]; - var allSettled = __dependency5__["default"]; - var race = __dependency6__["default"]; - var hash = __dependency7__["default"]; - var rethrow = __dependency8__["default"]; - var defer = __dependency9__["default"]; - var config = __dependency10__.config; - var configure = __dependency10__.configure; - var map = __dependency11__["default"]; - var resolve = __dependency12__["default"]; - var reject = __dependency13__["default"]; - var filter = __dependency14__["default"]; - - function async(callback, arg) { - config.async(callback, arg); - } - - function on() { - config.on.apply(config, arguments); - } - - function off() { - config.off.apply(config, arguments); - } - - // Set up instrumentation through `window.__PROMISE_INTRUMENTATION__` - if (typeof window !== 'undefined' && typeof window.__PROMISE_INSTRUMENTATION__ === 'object') { - var callbacks = window.__PROMISE_INSTRUMENTATION__; - configure('instrument', true); - for (var eventName in callbacks) { - if (callbacks.hasOwnProperty(eventName)) { - on(eventName, callbacks[eventName]); - } - } - } - - __exports__.Promise = Promise; - __exports__.EventTarget = EventTarget; - __exports__.all = all; - __exports__.allSettled = allSettled; - __exports__.race = race; - __exports__.hash = hash; - __exports__.rethrow = rethrow; - __exports__.defer = defer; - __exports__.denodeify = denodeify; - __exports__.configure = configure; - __exports__.on = on; - __exports__.off = off; - __exports__.resolve = resolve; - __exports__.reject = reject; - __exports__.async = async; - __exports__.map = map; - __exports__.filter = filter; - }); - -})(); - -(function() { -define("container/container", - ["container/inheriting_dict","exports"], - function(__dependency1__, __exports__) { - "use strict"; - var InheritingDict = __dependency1__["default"]; - - // A lightweight container that helps to assemble and decouple components. - // Public api for the container is still in flux. - // The public api, specified on the application namespace should be considered the stable api. - function Container(parent) { - this.parent = parent; - this.children = []; - - this.resolver = parent && parent.resolver || function() {}; - - this.registry = new InheritingDict(parent && parent.registry); - this.cache = new InheritingDict(parent && parent.cache); - this.factoryCache = new InheritingDict(parent && parent.factoryCache); - this.resolveCache = new InheritingDict(parent && parent.resolveCache); - this.typeInjections = new InheritingDict(parent && parent.typeInjections); - this.injections = {}; - - this.factoryTypeInjections = new InheritingDict(parent && parent.factoryTypeInjections); - this.factoryInjections = {}; - - this._options = new InheritingDict(parent && parent._options); - this._typeOptions = new InheritingDict(parent && parent._typeOptions); - } - - Container.prototype = { + __exports__["default"] = EmberObject.extend({ + implementation: 'none', + path: '', /** - @property parent - @type Container - @default null - */ - parent: null, - - /** - @property children - @type Array - @default [] - */ - children: null, - - /** - @property resolver - @type function - */ - resolver: null, - - /** - @property registry - @type InheritingDict - */ - registry: null, - - /** - @property cache - @type InheritingDict - */ - cache: null, - - /** - @property typeInjections - @type InheritingDict - */ - typeInjections: null, - - /** - @property injections - @type Object - @default {} - */ - injections: null, - - /** - @private - - @property _options - @type InheritingDict - @default null - */ - _options: null, - - /** - @private - - @property _typeOptions - @type InheritingDict - */ - _typeOptions: null, - - /** - Returns a new child of the current container. These children are configured - to correctly inherit from the current container. - - @method child - @return {Container} - */ - child: function() { - var container = new Container(this); - this.children.push(container); - return container; - }, - - /** - Sets a key-value pair on the current container. If a parent container, - has the same key, once set on a child, the parent and child will diverge - as expected. - - @method set - @param {Object} object - @param {String} key - @param {any} value - */ - set: function(object, key, value) { - object[key] = value; - }, - - /** - Registers a factory for later injection. - - Example: - - ```javascript - var container = new Container(); - - container.register('model:user', Person, {singleton: false }); - container.register('fruit:favorite', Orange); - container.register('communication:main', Email, {singleton: false}); - ``` - - @method register - @param {String} fullName - @param {Function} factory - @param {Object} options - */ - register: function(fullName, factory, options) { - validateFullName(fullName); - - if (factory === undefined) { - throw new TypeError('Attempting to register an unknown factory: `' + fullName + '`'); - } - - var normalizedName = this.normalize(fullName); - - if (this.cache.has(normalizedName)) { - throw new Error('Cannot re-register: `' + fullName +'`, as it has already been looked up.'); - } - - this.registry.set(normalizedName, factory); - this._options.set(normalizedName, options || {}); - }, - - /** - Unregister a fullName - - ```javascript - var container = new Container(); - container.register('model:user', User); - - container.lookup('model:user') instanceof User //=> true - - container.unregister('model:user') - container.lookup('model:user') === undefined //=> true - ``` - - @method unregister - @param {String} fullName - */ - unregister: function(fullName) { - validateFullName(fullName); - - var normalizedName = this.normalize(fullName); - - this.registry.remove(normalizedName); - this.cache.remove(normalizedName); - this.factoryCache.remove(normalizedName); - this.resolveCache.remove(normalizedName); - this._options.remove(normalizedName); - }, - - /** - Given a fullName return the corresponding factory. - - By default `resolve` will retrieve the factory from - its container's registry. - - ```javascript - var container = new Container(); - container.register('api:twitter', Twitter); - - container.resolve('api:twitter') // => Twitter - ``` - - Optionally the container can be provided with a custom resolver. - If provided, `resolve` will first provide the custom resolver - the opportunity to resolve the fullName, otherwise it will fallback - to the registry. - - ```javascript - var container = new Container(); - container.resolver = function(fullName) { - // lookup via the module system of choice - }; - - // the twitter factory is added to the module system - container.resolve('api:twitter') // => Twitter - ``` - - @method resolve - @param {String} fullName - @return {Function} fullName's factory - */ - resolve: function(fullName) { - validateFullName(fullName); - - var normalizedName = this.normalize(fullName); - var cached = this.resolveCache.get(normalizedName); - - if (cached) { return cached; } - - var resolved = this.resolver(normalizedName) || this.registry.get(normalizedName); - - this.resolveCache.set(normalizedName, resolved); - - return resolved; - }, - - /** - A hook that can be used to describe how the resolver will - attempt to find the factory. - - For example, the default Ember `.describe` returns the full - class name (including namespace) where Ember's resolver expects - to find the `fullName`. - - @method describe - @param {String} fullName - @return {string} described fullName - */ - describe: function(fullName) { - return fullName; - }, - - /** - A hook to enable custom fullName normalization behaviour - - @method normalize - @param {String} fullName - @return {string} normalized fullName - */ - normalize: function(fullName) { - return fullName; - }, - - /** - @method makeToString - - @param {any} factory - @param {string} fullName - @return {function} toString function - */ - makeToString: function(factory, fullName) { - return factory.toString(); - }, - - /** - Given a fullName return a corresponding instance. - - The default behaviour is for lookup to return a singleton instance. - The singleton is scoped to the container, allowing multiple containers - to all have their own locally scoped singletons. - - ```javascript - var container = new Container(); - container.register('api:twitter', Twitter); - - var twitter = container.lookup('api:twitter'); - - twitter instanceof Twitter; // => true - - // by default the container will return singletons - var twitter2 = container.lookup('api:twitter'); - twitter2 instanceof Twitter; // => true - - twitter === twitter2; //=> true - ``` - - If singletons are not wanted an optional flag can be provided at lookup. - - ```javascript - var container = new Container(); - container.register('api:twitter', Twitter); - - var twitter = container.lookup('api:twitter', { singleton: false }); - var twitter2 = container.lookup('api:twitter', { singleton: false }); - - twitter === twitter2; //=> false - ``` - - @method lookup - @param {String} fullName - @param {Object} options - @return {any} - */ - lookup: function(fullName, options) { - validateFullName(fullName); - return lookup(this, this.normalize(fullName), options); - }, - - /** - Given a fullName return the corresponding factory. - - @method lookupFactory - @param {String} fullName - @return {any} - */ - lookupFactory: function(fullName) { - validateFullName(fullName); - return factoryFor(this, this.normalize(fullName)); - }, - - /** - Given a fullName check if the container is aware of its factory - or singleton instance. - - @method has - @param {String} fullName - @return {Boolean} - */ - has: function(fullName) { - validateFullName(fullName); - return has(this, this.normalize(fullName)); - }, - - /** - Allow registering options for all factories of a type. - - ```javascript - var container = new Container(); - - // if all of type `connection` must not be singletons - container.optionsForType('connection', { singleton: false }); - - container.register('connection:twitter', TwitterConnection); - container.register('connection:facebook', FacebookConnection); - - var twitter = container.lookup('connection:twitter'); - var twitter2 = container.lookup('connection:twitter'); - - twitter === twitter2; // => false - - var facebook = container.lookup('connection:facebook'); - var facebook2 = container.lookup('connection:facebook'); - - facebook === facebook2; // => false - ``` - - @method optionsForType - @param {String} type - @param {Object} options - */ - optionsForType: function(type, options) { - if (this.parent) { illegalChildOperation('optionsForType'); } - - this._typeOptions.set(type, options); - }, - - /** - @method options - @param {String} type - @param {Object} options - */ - options: function(type, options) { - this.optionsForType(type, options); - }, - - /** - Used only via `injection`. - - Provides a specialized form of injection, specifically enabling - all objects of one type to be injected with a reference to another - object. - - For example, provided each object of type `controller` needed a `router`. - one would do the following: - - ```javascript - var container = new Container(); - - container.register('router:main', Router); - container.register('controller:user', UserController); - container.register('controller:post', PostController); - - container.typeInjection('controller', 'router', 'router:main'); - - var user = container.lookup('controller:user'); - var post = container.lookup('controller:post'); - - user.router instanceof Router; //=> true - post.router instanceof Router; //=> true - - // both controllers share the same router - user.router === post.router; //=> true - ``` + Returns the current path. @private - @method typeInjection - @param {String} type - @param {String} property - @param {String} fullName + @method getURL + @return {String} path */ - typeInjection: function(type, property, fullName) { - validateFullName(fullName); - if (this.parent) { illegalChildOperation('typeInjection'); } - - var fullNameType = fullName.split(':')[0]; - if(fullNameType === type) { - throw new Error('Cannot inject a `' + fullName + '` on other ' + type + '(s). Register the `' + fullName + '` as a different type and perform the typeInjection.'); - } - addTypeInjection(this.typeInjections, type, property, fullName); + getURL: function() { + return get(this, 'path'); }, /** - Defines injection rules. - - These rules are used to inject dependencies onto objects when they - are instantiated. - - Two forms of injections are possible: - - * Injecting one fullName on another fullName - * Injecting one fullName on a type - - Example: - - ```javascript - var container = new Container(); - - container.register('source:main', Source); - container.register('model:user', User); - container.register('model:post', Post); - - // injecting one fullName on another fullName - // eg. each user model gets a post model - container.injection('model:user', 'post', 'model:post'); - - // injecting one fullName on another type - container.injection('model', 'source', 'source:main'); - - var user = container.lookup('model:user'); - var post = container.lookup('model:post'); - - user.source instanceof Source; //=> true - post.source instanceof Source; //=> true - - user.post instanceof Post; //=> true - - // and both models share the same source - user.source === post.source; //=> true - ``` - - @method injection - @param {String} factoryName - @param {String} property - @param {String} injectionName - */ - injection: function(fullName, property, injectionName) { - if (this.parent) { illegalChildOperation('injection'); } - - validateFullName(injectionName); - var normalizedInjectionName = this.normalize(injectionName); - - if (fullName.indexOf(':') === -1) { - return this.typeInjection(fullName, property, normalizedInjectionName); - } - - validateFullName(fullName); - var normalizedName = this.normalize(fullName); - - addInjection(this.injections, normalizedName, property, normalizedInjectionName); - }, - - - /** - Used only via `factoryInjection`. - - Provides a specialized form of injection, specifically enabling - all factory of one type to be injected with a reference to another - object. - - For example, provided each factory of type `model` needed a `store`. - one would do the following: - - ```javascript - var container = new Container(); - - container.register('store:main', SomeStore); - - container.factoryTypeInjection('model', 'store', 'store:main'); - - var store = container.lookup('store:main'); - var UserFactory = container.lookupFactory('model:user'); - - UserFactory.store instanceof SomeStore; //=> true - ``` + Set the path and remembers what was set. Using this method + to change the path will not invoke the `updateURL` callback. @private - @method factoryTypeInjection - @param {String} type - @param {String} property - @param {String} fullName + @method setURL + @param path {String} */ - factoryTypeInjection: function(type, property, fullName) { - if (this.parent) { illegalChildOperation('factoryTypeInjection'); } - - addTypeInjection(this.factoryTypeInjections, type, property, this.normalize(fullName)); + setURL: function(path) { + set(this, 'path', path); }, /** - Defines factory injection rules. + Register a callback to be invoked when the path changes. These + callbacks will execute when the user presses the back or forward + button, but not after `setURL` is invoked. - Similar to regular injection rules, but are run against factories, via - `Container#lookupFactory`. - - These rules are used to inject objects onto factories when they - are looked up. - - Two forms of injections are possible: - - * Injecting one fullName on another fullName - * Injecting one fullName on a type - - Example: - - ```javascript - var container = new Container(); - - container.register('store:main', Store); - container.register('store:secondary', OtherStore); - container.register('model:user', User); - container.register('model:post', Post); - - // injecting one fullName on another type - container.factoryInjection('model', 'store', 'store:main'); - - // injecting one fullName on another fullName - container.factoryInjection('model:post', 'secondaryStore', 'store:secondary'); - - var UserFactory = container.lookupFactory('model:user'); - var PostFactory = container.lookupFactory('model:post'); - var store = container.lookup('store:main'); - - UserFactory.store instanceof Store; //=> true - UserFactory.secondaryStore instanceof OtherStore; //=> false - - PostFactory.store instanceof Store; //=> true - PostFactory.secondaryStore instanceof OtherStore; //=> true - - // and both models share the same source instance - UserFactory.store === PostFactory.store; //=> true - ``` - - @method factoryInjection - @param {String} factoryName - @param {String} property - @param {String} injectionName + @private + @method onUpdateURL + @param callback {Function} */ - factoryInjection: function(fullName, property, injectionName) { - if (this.parent) { illegalChildOperation('injection'); } - - var normalizedName = this.normalize(fullName); - var normalizedInjectionName = this.normalize(injectionName); - - validateFullName(injectionName); - - if (fullName.indexOf(':') === -1) { - return this.factoryTypeInjection(normalizedName, property, normalizedInjectionName); - } - - validateFullName(fullName); - - addInjection(this.factoryInjections, normalizedName, property, normalizedInjectionName); + onUpdateURL: function(callback) { + this.updateCallback = callback; }, /** - A depth first traversal, destroying the container, its descendant containers and all - their managed objects. + Sets the path and calls the `updateURL` callback. - @method destroy + @private + @method handleURL + @param callback {Function} */ - destroy: function() { - for (var i=0, l=this.children.length; i " + fullName, { fullName: fullName }); + } + + return instance; + } + }); +enifed("ember-routing/system/route", + ["ember-metal/core","ember-metal/error","ember-metal/property_get","ember-metal/property_set","ember-metal/get_properties","ember-metal/enumerable_utils","ember-metal/is_none","ember-metal/computed","ember-metal/merge","ember-metal/utils","ember-metal/run_loop","ember-metal/keys","ember-runtime/copy","ember-runtime/system/string","ember-runtime/system/object","ember-runtime/mixins/action_handler","ember-routing/system/generate_controller","ember-routing-handlebars/helpers/shared","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __dependency9__, __dependency10__, __dependency11__, __dependency12__, __dependency13__, __dependency14__, __dependency15__, __dependency16__, __dependency17__, __dependency18__, __exports__) { + "use strict"; + var Ember = __dependency1__["default"]; + // FEATURES, K, A, deprecate, assert, Logger + var EmberError = __dependency2__["default"]; + var get = __dependency3__.get; + var set = __dependency4__.set; + var getProperties = __dependency5__["default"]; + var forEach = __dependency6__.forEach; + var replace = __dependency6__.replace; + var isNone = __dependency7__.isNone; + var computed = __dependency8__.computed; + var merge = __dependency9__["default"]; + var isArray = __dependency10__.isArray; + var typeOf = __dependency10__.typeOf; + var run = __dependency11__["default"]; + var keys = __dependency12__["default"]; + var copy = __dependency13__["default"]; + var classify = __dependency14__.classify; + var fmt = __dependency14__.fmt; + var EmberObject = __dependency15__["default"]; + var ActionHandler = __dependency16__["default"]; + var generateController = __dependency17__["default"]; + var stashParamNames = __dependency18__.stashParamNames; + + /** + @module ember + @submodule ember-routing + */ + + /** + The `Ember.Route` class is used to define individual routes. Refer to + the [routing guide](http://emberjs.com/guides/routing/) for documentation. + + @class Route + @namespace Ember + @extends Ember.Object + @uses Ember.ActionHandler + */ + var Route = EmberObject.extend(ActionHandler, { + /** + Configuration hash for this route's queryParams. The possible + configuration options and their defaults are as follows + (assuming a query param whose URL key is `page`): + + ```js + queryParams: { + page: { + // By default, controller query param properties don't + // cause a full transition when they are changed, but + // rather only cause the URL to update. Setting + // `refreshModel` to true will cause an "in-place" + // transition to occur, whereby the model hooks for + // this route (and any child routes) will re-fire, allowing + // you to reload models (e.g., from the server) using the + // updated query param values. + refreshModel: false, + + // By default, changes to controller query param properties + // cause the URL to update via `pushState`, which means an + // item will be added to the browser's history, allowing + // you to use the back button to restore the app to the + // previous state before the query param property was changed. + // Setting `replace` to true will use `replaceState` (or its + // hash location equivalent), which causes no browser history + // item to be added. This options name and default value are + // the same as the `link-to` helper's `replace` option. + replace: false + } + } + ``` + + @property queryParams + @for Ember.Route + @type Hash + */ + queryParams: {}, + + /** + @private + + @property _qp + */ + _qp: computed(function() { + var controllerName = this.controllerName || this.routeName; + var controllerClass = this.container.lookupFactory('controller:' + controllerName); + + if (!controllerClass) { + return defaultQPMeta; + } + + var controllerProto = controllerClass.proto(); + var qpProps = get(controllerProto, '_normalizedQueryParams'); + var cacheMeta = get(controllerProto, '_cacheMeta'); + + var qps = [], map = {}, self = this; + for (var propName in qpProps) { + if (!qpProps.hasOwnProperty(propName)) { continue; } + + var desc = qpProps[propName]; + var urlKey = desc.as || this.serializeQueryParamKey(propName); + var defaultValue = get(controllerProto, propName); + + if (isArray(defaultValue)) { + defaultValue = Ember.A(defaultValue.slice()); + } + + var type = typeOf(defaultValue); + var defaultValueSerialized = this.serializeQueryParam(defaultValue, urlKey, type); + var fprop = controllerName + ':' + propName; + var qp = { + def: defaultValue, + sdef: defaultValueSerialized, + type: type, + urlKey: urlKey, + prop: propName, + fprop: fprop, + ctrl: controllerName, + cProto: controllerProto, + svalue: defaultValueSerialized, + cacheType: desc.scope, + route: this, + cacheMeta: cacheMeta[propName] + }; + + map[propName] = map[urlKey] = map[fprop] = qp; + qps.push(qp); + } + + return { + qps: qps, + map: map, + states: { + active: function(controller, prop) { + return self._activeQPChanged(controller, map[prop]); + }, + allowOverrides: function(controller, prop) { + return self._updatingQPChanged(controller, map[prop]); + }, + changingKeys: function(controller, prop) { + return self._updateSerializedQPValue(controller, map[prop]); + } + } + }; + }), + + /** + @private + + @property _names + */ + _names: null, + + /** + @private + + @method _stashNames + */ + _stashNames: function(_handlerInfo, dynamicParent) { + var handlerInfo = _handlerInfo; + if (this._names) { return; } + var names = this._names = handlerInfo._names; + + if (!names.length) { + handlerInfo = dynamicParent; + names = handlerInfo && handlerInfo._names || []; + } + + var qps = get(this, '_qp.qps'); + var len = qps.length; + + var namePaths = new Array(names.length); + for (var a = 0, nlen = names.length; a < nlen; ++a) { + namePaths[a] = handlerInfo.name + '.' + names[a]; + } + + for (var i = 0; i < len; ++i) { + var qp = qps[i]; + var cacheMeta = qp.cacheMeta; + if (cacheMeta.scope === 'model') { + cacheMeta.parts = namePaths; + } + cacheMeta.prefix = qp.ctrl; + } + }, + + /** + @private + + @property _updateSerializedQPValue + */ + _updateSerializedQPValue: function(controller, qp) { + var value = get(controller, qp.prop); + qp.svalue = this.serializeQueryParam(value, qp.urlKey, qp.type); + }, + + /** + @private + + @property _activeQPChanged + */ + _activeQPChanged: function(controller, qp) { + var value = get(controller, qp.prop); + this.router._queuedQPChanges[qp.fprop] = value; + run.once(this, this._fireQueryParamTransition); + }, + + /** + @private + @method _updatingQPChanged + */ + _updatingQPChanged: function(controller, qp) { + var router = this.router; + if (!router._qpUpdates) { + router._qpUpdates = {}; + } + router._qpUpdates[qp.urlKey] = true; + }, + + mergedProperties: ['events', 'queryParams'], + + /** + @method paramsFor + */ + paramsFor: function(name) { + var route = this.container.lookup('route:' + name); + + if (!route) { + return {}; + } + + var transition = this.router.router.activeTransition; + var state = transition ? transition.state : this.router.router.state; + + var params = {}; + merge(params, state.params[name]); + merge(params, getQueryParamsFor(route, state)); + + return params; + }, + + /** + @method serializeQueryParamKey + */ + serializeQueryParamKey: function(controllerPropertyName) { + return controllerPropertyName; + }, + + /** + @method serializeQueryParam + */ + serializeQueryParam: function(value, urlKey, defaultValueType) { + // urlKey isn't used here, but anyone overriding + // can use it to provide serialization specific + // to a certain query param. + if (defaultValueType === 'array') { + return JSON.stringify(value); + } + return '' + value; + }, + + /** + @method deserializeQueryParam + */ + deserializeQueryParam: function(value, urlKey, defaultValueType) { + // urlKey isn't used here, but anyone overriding + // can use it to provide deserialization specific + // to a certain query param. + + // Use the defaultValueType of the default value (the initial value assigned to a + // controller query param property), to intelligently deserialize and cast. + if (defaultValueType === 'boolean') { + return (value === 'true') ? true : false; + } else if (defaultValueType === 'number') { + return (Number(value)).valueOf(); + } else if (defaultValueType === 'array') { + return Ember.A(JSON.parse(value)); + } + return value; + }, + + + /** + @private + @property _fireQueryParamTransition + */ + _fireQueryParamTransition: function() { + this.transitionTo({ queryParams: this.router._queuedQPChanges }); + this.router._queuedQPChanges = {}; + }, + + /** + A hook you can use to reset controller values either when the model + changes or the route is exiting. + + ```js + App.ArticlesRoute = Ember.Route.extend({ + // ... + + resetController: function (controller, isExiting, transition) { + if (isExiting) { + controller.set('page', 1); + } + } + }); + ``` + + @method resetController + @param {Controller} controller instance + @param {Boolean} isExiting + @param {Object} transition + @since 1.7.0 + */ + resetController: Ember.K, + + /** + @private + + @method exit + */ + exit: function() { + this.deactivate(); + this.teardownViews(); + }, + + /** + @private + + @method _reset + @since 1.7.0 + */ + _reset: function(isExiting, transition) { + var controller = this.controller; + + controller._qpDelegate = get(this, '_qp.states.inactive'); + + this.resetController(controller, isExiting, transition); + }, + + /** + @private + + @method enter + */ + enter: function() { + this.activate(); + }, + + /** + The name of the view to use by default when rendering this routes template. + + When rendering a template, the route will, by default, determine the + template and view to use from the name of the route itself. If you need to + define a specific view, set this property. + + This is useful when multiple routes would benefit from using the same view + because it doesn't require a custom `renderTemplate` method. For example, + the following routes will all render using the `App.PostsListView` view: + + ```js + var PostsList = Ember.Route.extend({ + viewName: 'postsList' + }); + + App.PostsIndexRoute = PostsList.extend(); + App.PostsArchivedRoute = PostsList.extend(); + ``` + + @property viewName + @type String + @default null + @since 1.4.0 + */ + viewName: null, + + /** + The name of the template to use by default when rendering this routes + template. + + This is similar with `viewName`, but is useful when you just want a custom + template without a view. + + ```js + var PostsList = Ember.Route.extend({ + templateName: 'posts/list' + }); + + App.PostsIndexRoute = PostsList.extend(); + App.PostsArchivedRoute = PostsList.extend(); + ``` + + @property templateName + @type String + @default null + @since 1.4.0 + */ + templateName: null, + + /** + The name of the controller to associate with this route. + + By default, Ember will lookup a route's controller that matches the name + of the route (i.e. `App.PostController` for `App.PostRoute`). However, + if you would like to define a specific controller to use, you can do so + using this property. + + This is useful in many ways, as the controller specified will be: + + * passed to the `setupController` method. + * used as the controller for the view being rendered by the route. + * returned from a call to `controllerFor` for the route. + + @property controllerName + @type String + @default null + @since 1.4.0 + */ + controllerName: null, + + /** + The `willTransition` action is fired at the beginning of any + attempted transition with a `Transition` object as the sole + argument. This action can be used for aborting, redirecting, + or decorating the transition from the currently active routes. + + A good example is preventing navigation when a form is + half-filled out: + + ```js + App.ContactFormRoute = Ember.Route.extend({ + actions: { + willTransition: function(transition) { + if (this.controller.get('userHasEnteredData')) { + this.controller.displayNavigationConfirm(); + transition.abort(); + } + } + } + }); + ``` + + You can also redirect elsewhere by calling + `this.transitionTo('elsewhere')` from within `willTransition`. + Note that `willTransition` will not be fired for the + redirecting `transitionTo`, since `willTransition` doesn't + fire when there is already a transition underway. If you want + subsequent `willTransition` actions to fire for the redirecting + transition, you must first explicitly call + `transition.abort()`. + + @event willTransition + @param {Transition} transition + */ + + /** + The `didTransition` action is fired after a transition has + successfully been completed. This occurs after the normal model + hooks (`beforeModel`, `model`, `afterModel`, `setupController`) + have resolved. The `didTransition` action has no arguments, + however, it can be useful for tracking page views or resetting + state on the controller. + + ```js + App.LoginRoute = Ember.Route.extend({ + actions: { + didTransition: function() { + this.controller.get('errors.base').clear(); + return true; // Bubble the didTransition event + } + } + }); + ``` + + @event didTransition + @since 1.2.0 + */ + + /** + The `loading` action is fired on the route when a route's `model` + hook returns a promise that is not already resolved. The current + `Transition` object is the first parameter and the route that + triggered the loading event is the second parameter. + + ```js + App.ApplicationRoute = Ember.Route.extend({ + actions: { + loading: function(transition, route) { + var view = Ember.View.create({ + classNames: ['app-loading'] + }) + .append(); + + this.router.one('didTransition', function () { + view.destroy(); + }); + return true; // Bubble the loading event + } + } + }); + ``` + + @event loading + @param {Transition} transition + @param {Ember.Route} route The route that triggered the loading event + @since 1.2.0 + */ + + /** + When attempting to transition into a route, any of the hooks + may return a promise that rejects, at which point an `error` + action will be fired on the partially-entered routes, allowing + for per-route error handling logic, or shared error handling + logic defined on a parent route. + + Here is an example of an error handler that will be invoked + for rejected promises from the various hooks on the route, + as well as any unhandled errors from child routes: + + ```js + App.AdminRoute = Ember.Route.extend({ + beforeModel: function() { + return Ember.RSVP.reject("bad things!"); + }, + + actions: { + error: function(error, transition) { + // Assuming we got here due to the error in `beforeModel`, + // we can expect that error === "bad things!", + // but a promise model rejecting would also + // call this hook, as would any errors encountered + // in `afterModel`. + + // The `error` hook is also provided the failed + // `transition`, which can be stored and later + // `.retry()`d if desired. + + this.transitionTo('login'); + } + } + }); + ``` + + `error` actions that bubble up all the way to `ApplicationRoute` + will fire a default error handler that logs the error. You can + specify your own global default error handler by overriding the + `error` handler on `ApplicationRoute`: + + ```js + App.ApplicationRoute = Ember.Route.extend({ + actions: { + error: function(error, transition) { + this.controllerFor('banner').displayError(error.message); + } + } + }); + ``` + @event error + @param {Error} error + @param {Transition} transition + */ + + /** + The controller associated with this route. + + Example + + ```javascript + App.FormRoute = Ember.Route.extend({ + actions: { + willTransition: function(transition) { + if (this.controller.get('userHasEnteredData') && + !confirm("Are you sure you want to abandon progress?")) { + transition.abort(); + } else { + // Bubble the `willTransition` action so that + // parent routes can decide whether or not to abort. + return true; + } + } + } + }); + ``` + + @property controller + @type Ember.Controller + @since 1.6.0 + */ + + _actions: { + + queryParamsDidChange: function(changed, totalPresent, removed) { + var totalChanged = keys(changed).concat(keys(removed)); + for (var i = 0, len = totalChanged.length; i < len; ++i) { + var urlKey = totalChanged[i]; + var options = get(this.queryParams, urlKey) || {}; + if (get(options, 'refreshModel')) { + this.refresh(); + } + } + + return true; + }, + + finalizeQueryParamChange: function(params, finalParams, transition) { + if (this.routeName !== 'application') { return true; } + + // Transition object is absent for intermediate transitions. + if (!transition) { return; } + + var handlerInfos = transition.state.handlerInfos; + var router = this.router; + var qpMeta = router._queryParamsFor(handlerInfos[handlerInfos.length-1].name); + var changes = router._qpUpdates; + var replaceUrl; + + stashParamNames(router, handlerInfos); + + for (var i = 0, len = qpMeta.qps.length; i < len; ++i) { + var qp = qpMeta.qps[i]; + var route = qp.route; + var controller = route.controller; + var presentKey = qp.urlKey in params && qp.urlKey; + + // Do a reverse lookup to see if the changed query + // param URL key corresponds to a QP property on + // this controller. + var value, svalue; + if (changes && qp.urlKey in changes) { + // Value updated in/before setupController + value = get(controller, qp.prop); + svalue = route.serializeQueryParam(value, qp.urlKey, qp.type); + } else { + if (presentKey) { + svalue = params[presentKey]; + value = route.deserializeQueryParam(svalue, qp.urlKey, qp.type); + } else { + // No QP provided; use default value. + svalue = qp.sdef; + value = copyDefaultValue(qp.def); + } + } + + controller._qpDelegate = get(this, '_qp.states.inactive'); + + var thisQueryParamChanged = (svalue !== qp.svalue); + if (thisQueryParamChanged) { + var options = get(route, 'queryParams.' + qp.urlKey) || {}; + + if (transition.queryParamsOnly && replaceUrl !== false) { + var replaceConfigValue = get(options, 'replace'); + if (replaceConfigValue) { + replaceUrl = true; + } else if (replaceConfigValue === false) { + // Explicit pushState wins over any other replaceStates. + replaceUrl = false; + } + } + + set(controller, qp.prop, value); + } + + // Stash current serialized value of controller. + qp.svalue = svalue; + + var thisQueryParamHasDefaultValue = (qp.sdef === svalue); + if (!thisQueryParamHasDefaultValue) { + finalParams.push({ + value: svalue, + visible: true, + key: presentKey || qp.urlKey + }); + } + } + + if (replaceUrl) { + transition.method('replace'); + } + + forEach(qpMeta.qps, function(qp) { + var routeQpMeta = get(qp.route, '_qp'); + var finalizedController = qp.route.controller; + finalizedController._qpDelegate = get(routeQpMeta, 'states.active'); + }); + + router._qpUpdates = null; + } + }, + + /** + @deprecated + + Please use `actions` instead. + @method events + */ + events: null, + + /** + This hook is executed when the router completely exits this route. It is + not executed when the model for the route changes. + + @method deactivate + */ + deactivate: Ember.K, + + /** + This hook is executed when the router enters the route. It is not executed + when the model for the route changes. + + @method activate + */ + activate: Ember.K, + + /** + Transition the application into another route. The route may + be either a single route or route path: + + ```javascript + this.transitionTo('blogPosts'); + this.transitionTo('blogPosts.recentEntries'); + ``` + + Optionally supply a model for the route in question. The model + will be serialized into the URL using the `serialize` hook of + the route: + + ```javascript + this.transitionTo('blogPost', aPost); + ``` + + If a literal is passed (such as a number or a string), it will + be treated as an identifier instead. In this case, the `model` + hook of the route will be triggered: + + ```javascript + this.transitionTo('blogPost', 1); + ``` + + Multiple models will be applied last to first recursively up the + resource tree. + + ```javascript + App.Router.map(function() { + this.resource('blogPost', {path:':blogPostId'}, function(){ + this.resource('blogComment', {path: ':blogCommentId'}); + }); + }); + + this.transitionTo('blogComment', aPost, aComment); + this.transitionTo('blogComment', 1, 13); + ``` + + It is also possible to pass a URL (a string that starts with a + `/`). This is intended for testing and debugging purposes and + should rarely be used in production code. + + ```javascript + this.transitionTo('/'); + this.transitionTo('/blog/post/1/comment/13'); + ``` + + See also 'replaceWith'. + + Simple Transition Example + + ```javascript + App.Router.map(function() { + this.route("index"); + this.route("secret"); + this.route("fourOhFour", { path: "*:"}); + }); + + App.IndexRoute = Ember.Route.extend({ + actions: { + moveToSecret: function(context){ + if (authorized()){ + this.transitionTo('secret', context); + } + this.transitionTo('fourOhFour'); + } + } + }); + ``` + + Transition to a nested route + + ```javascript + App.Router.map(function() { + this.resource('articles', { path: '/articles' }, function() { + this.route('new'); + }); + }); + + App.IndexRoute = Ember.Route.extend({ + actions: { + transitionToNewArticle: function() { + this.transitionTo('articles.new'); + } + } + }); + ``` + + Multiple Models Example + + ```javascript + App.Router.map(function() { + this.route("index"); + this.resource('breakfast', {path:':breakfastId'}, function(){ + this.resource('cereal', {path: ':cerealId'}); + }); + }); + + App.IndexRoute = Ember.Route.extend({ + actions: { + moveToChocolateCereal: function(){ + var cereal = { cerealId: "ChocolateYumminess"}, + breakfast = {breakfastId: "CerealAndMilk"}; + + this.transitionTo('cereal', breakfast, cereal); + } + } + }); + ``` + + @method transitionTo + @param {String} name the name of the route or a URL + @param {...Object} models the model(s) or identifier(s) to be used while + transitioning to the route. + @return {Transition} the transition object associated with this + attempted transition + */ + transitionTo: function(name, context) { + var router = this.router; + return router.transitionTo.apply(router, arguments); + }, + + /** + Perform a synchronous transition into another route without attempting + to resolve promises, update the URL, or abort any currently active + asynchronous transitions (i.e. regular transitions caused by + `transitionTo` or URL changes). + + This method is handy for performing intermediate transitions on the + way to a final destination route, and is called internally by the + default implementations of the `error` and `loading` handlers. + + @method intermediateTransitionTo + @param {String} name the name of the route + @param {...Object} models the model(s) to be used while transitioning + to the route. + @since 1.2.0 + */ + intermediateTransitionTo: function() { + var router = this.router; + router.intermediateTransitionTo.apply(router, arguments); + }, + + /** + Refresh the model on this route and any child routes, firing the + `beforeModel`, `model`, and `afterModel` hooks in a similar fashion + to how routes are entered when transitioning in from other route. + The current route params (e.g. `article_id`) will be passed in + to the respective model hooks, and if a different model is returned, + `setupController` and associated route hooks will re-fire as well. + + An example usage of this method is re-querying the server for the + latest information using the same parameters as when the route + was first entered. + + Note that this will cause `model` hooks to fire even on routes + that were provided a model object when the route was initially + entered. + + @method refresh + @return {Transition} the transition object associated with this + attempted transition + @since 1.4.0 + */ + refresh: function() { + return this.router.router.refresh(this); + }, + + /** + Transition into another route while replacing the current URL, if possible. + This will replace the current history entry instead of adding a new one. + Beside that, it is identical to `transitionTo` in all other respects. See + 'transitionTo' for additional information regarding multiple models. + + Example + + ```javascript + App.Router.map(function() { + this.route("index"); + this.route("secret"); + }); + + App.SecretRoute = Ember.Route.extend({ + afterModel: function() { + if (!authorized()){ + this.replaceWith('index'); + } + } + }); + ``` + + @method replaceWith + @param {String} name the name of the route or a URL + @param {...Object} models the model(s) or identifier(s) to be used while + transitioning to the route. + @return {Transition} the transition object associated with this + attempted transition + */ + replaceWith: function() { + var router = this.router; + return router.replaceWith.apply(router, arguments); + }, + + /** + Sends an action to the router, which will delegate it to the currently + active route hierarchy per the bubbling rules explained under `actions`. + + Example + + ```javascript + App.Router.map(function() { + this.route("index"); + }); + + App.ApplicationRoute = Ember.Route.extend({ + actions: { + track: function(arg) { + console.log(arg, 'was clicked'); + } + } + }); + + App.IndexRoute = Ember.Route.extend({ + actions: { + trackIfDebug: function(arg) { + if (debug) { + this.send('track', arg); + } + } + } + }); + ``` + + @method send + @param {String} name the name of the action to trigger + @param {...*} args + */ + send: function() { + return this.router.send.apply(this.router, arguments); + }, + + /** + This hook is the entry point for router.js + + @private + @method setup + */ + setup: function(context, transition) { + var controllerName = this.controllerName || this.routeName; + var controller = this.controllerFor(controllerName, true); + + if (!controller) { + controller = this.generateController(controllerName, context); + } + + // Assign the route's controller so that it can more easily be + // referenced in action handlers + this.controller = controller; + + if (this.setupControllers) { + Ember.deprecate("Ember.Route.setupControllers is deprecated. Please use Ember.Route.setupController(controller, model) instead."); + this.setupControllers(controller, context); + } else { + var states = get(this, '_qp.states'); + if (transition) { + // Update the model dep values used to calculate cache keys. + stashParamNames(this.router, transition.state.handlerInfos); + controller._qpDelegate = states.changingKeys; + controller._updateCacheParams(transition.params); + } + controller._qpDelegate = states.allowOverrides; + + if (transition) { + var qpValues = getQueryParamsFor(this, transition.state); + controller.setProperties(qpValues); + } + + this.setupController(controller, context, transition); + } + + if (this.renderTemplates) { + Ember.deprecate("Ember.Route.renderTemplates is deprecated. Please use Ember.Route.renderTemplate(controller, model) instead."); + this.renderTemplates(context); + } else { + this.renderTemplate(controller, context); + } + }, + + /** + This hook is the first of the route entry validation hooks + called when an attempt is made to transition into a route + or one of its children. It is called before `model` and + `afterModel`, and is appropriate for cases when: + + 1) A decision can be made to redirect elsewhere without + needing to resolve the model first. + 2) Any async operations need to occur first before the + model is attempted to be resolved. + + This hook is provided the current `transition` attempt + as a parameter, which can be used to `.abort()` the transition, + save it for a later `.retry()`, or retrieve values set + on it from a previous hook. You can also just call + `this.transitionTo` to another route to implicitly + abort the `transition`. + + You can return a promise from this hook to pause the + transition until the promise resolves (or rejects). This could + be useful, for instance, for retrieving async code from + the server that is required to enter a route. + + ```js + App.PostRoute = Ember.Route.extend({ + beforeModel: function(transition) { + if (!App.Post) { + return Ember.$.getScript('/models/post.js'); + } + } + }); + ``` + + If `App.Post` doesn't exist in the above example, + `beforeModel` will use jQuery's `getScript`, which + returns a promise that resolves after the server has + successfully retrieved and executed the code from the + server. Note that if an error were to occur, it would + be passed to the `error` hook on `Ember.Route`, but + it's also possible to handle errors specific to + `beforeModel` right from within the hook (to distinguish + from the shared error handling behavior of the `error` + hook): + + ```js + App.PostRoute = Ember.Route.extend({ + beforeModel: function(transition) { + if (!App.Post) { + var self = this; + return Ember.$.getScript('post.js').then(null, function(e) { + self.transitionTo('help'); + + // Note that the above transitionTo will implicitly + // halt the transition. If you were to return + // nothing from this promise reject handler, + // according to promise semantics, that would + // convert the reject into a resolve and the + // transition would continue. To propagate the + // error so that it'd be handled by the `error` + // hook, you would have to either + return Ember.RSVP.reject(e); + }); + } + } + }); + ``` + + @method beforeModel + @param {Transition} transition + @param {Object} queryParams the active query params for this route + @return {Promise} if the value returned from this hook is + a promise, the transition will pause until the transition + resolves. Otherwise, non-promise return values are not + utilized in any way. + */ + beforeModel: Ember.K, + + /** + This hook is called after this route's model has resolved. + It follows identical async/promise semantics to `beforeModel` + but is provided the route's resolved model in addition to + the `transition`, and is therefore suited to performing + logic that can only take place after the model has already + resolved. + + ```js + App.PostsRoute = Ember.Route.extend({ + afterModel: function(posts, transition) { + if (posts.get('length') === 1) { + this.transitionTo('post.show', posts.get('firstObject')); + } + } + }); + ``` + + Refer to documentation for `beforeModel` for a description + of transition-pausing semantics when a promise is returned + from this hook. + + @method afterModel + @param {Object} resolvedModel the value returned from `model`, + or its resolved value if it was a promise + @param {Transition} transition + @param {Object} queryParams the active query params for this handler + @return {Promise} if the value returned from this hook is + a promise, the transition will pause until the transition + resolves. Otherwise, non-promise return values are not + utilized in any way. + */ + afterModel: Ember.K, + + /** + A hook you can implement to optionally redirect to another route. + + If you call `this.transitionTo` from inside of this hook, this route + will not be entered in favor of the other hook. + + `redirect` and `afterModel` behave very similarly and are + called almost at the same time, but they have an important + distinction in the case that, from one of these hooks, a + redirect into a child route of this route occurs: redirects + from `afterModel` essentially invalidate the current attempt + to enter this route, and will result in this route's `beforeModel`, + `model`, and `afterModel` hooks being fired again within + the new, redirecting transition. Redirects that occur within + the `redirect` hook, on the other hand, will _not_ cause + these hooks to be fired again the second time around; in + other words, by the time the `redirect` hook has been called, + both the resolved model and attempted entry into this route + are considered to be fully validated. + + @method redirect + @param {Object} model the model for this route + @param {Transition} transition the transition object associated with the current transition + */ + redirect: Ember.K, + + /** + Called when the context is changed by router.js. + + @private + @method contextDidChange + */ + contextDidChange: function() { + this.currentModel = this.context; + }, + + /** + A hook you can implement to convert the URL into the model for + this route. + + ```js + App.Router.map(function() { + this.resource('post', {path: '/posts/:post_id'}); + }); + ``` + + The model for the `post` route is `store.find('post', params.post_id)`. + + By default, if your route has a dynamic segment ending in `_id`: + + * The model class is determined from the segment (`post_id`'s + class is `App.Post`) + * The find method is called on the model class with the value of + the dynamic segment. + + Note that for routes with dynamic segments, this hook is not always + executed. If the route is entered through a transition (e.g. when + using the `link-to` Handlebars helper or the `transitionTo` method + of routes), and a model context is already provided this hook + is not called. + + A model context does not include a primitive string or number, + which does cause the model hook to be called. + + Routes without dynamic segments will always execute the model hook. + + ```js + // no dynamic segment, model hook always called + this.transitionTo('posts'); + + // model passed in, so model hook not called + thePost = store.find('post', 1); + this.transitionTo('post', thePost); + + // integer passed in, model hook is called + this.transitionTo('post', 1); + ``` + + + This hook follows the asynchronous/promise semantics + described in the documentation for `beforeModel`. In particular, + if a promise returned from `model` fails, the error will be + handled by the `error` hook on `Ember.Route`. + + Example + + ```js + App.PostRoute = Ember.Route.extend({ + model: function(params) { + return this.store.find('post', params.post_id); + } + }); + ``` + + @method model + @param {Object} params the parameters extracted from the URL + @param {Transition} transition + @param {Object} queryParams the query params for this route + @return {Object|Promise} the model for this route. If + a promise is returned, the transition will pause until + the promise resolves, and the resolved value of the promise + will be used as the model for this route. + */ + model: function(params, transition) { + var match, name, sawParams, value; + + var queryParams = get(this, '_qp.map'); + + for (var prop in params) { + if (prop === 'queryParams' || (queryParams && prop in queryParams)) { + continue; + } + + if (match = prop.match(/^(.*)_id$/)) { + name = match[1]; + value = params[prop]; + } + sawParams = true; + } + + if (!name && sawParams) { return copy(params); } + else if (!name) { + if (transition.resolveIndex < 1) { return; } + + var parentModel = transition.state.handlerInfos[transition.resolveIndex-1].context; + + return parentModel; + } + + return this.findModel(name, value); + }, + + /** + @private + @method deserialize + @param {Object} params the parameters extracted from the URL + @param {Transition} transition + @return {Object|Promise} the model for this route. + + Router.js hook. + */ + deserialize: function(params, transition) { + return this.model(this.paramsFor(this.routeName), transition); + }, + + /** + + @method findModel + @param {String} type the model type + @param {Object} value the value passed to find + */ + findModel: function(){ + var store = get(this, 'store'); + return store.find.apply(store, arguments); + }, + + /** + Store property provides a hook for data persistence libraries to inject themselves. + + By default, this store property provides the exact same functionality previously + in the model hook. + + Currently, the required interface is: + + `store.find(modelName, findArguments)` + + @method store + @param {Object} store + */ + store: computed(function(){ + var container = this.container; + var routeName = this.routeName; + var namespace = get(this, 'router.namespace'); + + return { + find: function(name, value) { + var modelClass = container.lookupFactory('model:' + name); + + Ember.assert("You used the dynamic segment " + name + "_id in your route " + + routeName + ", but " + namespace + "." + classify(name) + + " did not exist and you did not override your route's `model` " + + "hook.", modelClass); + + if (!modelClass) { return; } + + Ember.assert(classify(name) + ' has no method `find`.', typeof modelClass.find === 'function'); + + return modelClass.find(value); + } + }; + }), + + /** + A hook you can implement to convert the route's model into parameters + for the URL. + + ```js + App.Router.map(function() { + this.resource('post', {path: '/posts/:post_id'}); + }); + + App.PostRoute = Ember.Route.extend({ + model: function(params) { + // the server returns `{ id: 12 }` + return jQuery.getJSON("/posts/" + params.post_id); + }, + + serialize: function(model) { + // this will make the URL `/posts/12` + return { post_id: model.id }; + } + }); + ``` + + The default `serialize` method will insert the model's `id` into the + route's dynamic segment (in this case, `:post_id`) if the segment contains '_id'. + If the route has multiple dynamic segments or does not contain '_id', `serialize` + will return `Ember.getProperties(model, params)` + + This method is called when `transitionTo` is called with a context + in order to populate the URL. + + @method serialize + @param {Object} model the route's model + @param {Array} params an Array of parameter names for the current + route (in the example, `['post_id']`. + @return {Object} the serialized parameters + */ + serialize: function(model, params) { + if (params.length < 1) { return; } + if (!model) { return; } + + var name = params[0], object = {}; + + if (/_id$/.test(name) && params.length === 1) { + object[name] = get(model, "id"); + } else { + object = getProperties(model, params); + } + + return object; + }, + + /** + A hook you can use to setup the controller for the current route. + + This method is called with the controller for the current route and the + model supplied by the `model` hook. + + By default, the `setupController` hook sets the `model` property of + the controller to the `model`. + + If you implement the `setupController` hook in your Route, it will + prevent this default behavior. If you want to preserve that behavior + when implementing your `setupController` function, make sure to call + `_super`: + + ```js + App.PhotosRoute = Ember.Route.extend({ + model: function() { + return this.store.find('photo'); + }, + + setupController: function (controller, model) { + // Call _super for default behavior + this._super(controller, model); + // Implement your custom setup after + this.controllerFor('application').set('showingPhotos', true); + } + }); + ``` + + This means that your template will get a proxy for the model as its + context, and you can act as though the model itself was the context. + + The provided controller will be one resolved based on the name + of this route. + + If no explicit controller is defined, Ember will automatically create + an appropriate controller for the model. + + * if the model is an `Ember.Array` (including record arrays from Ember + Data), the controller is an `Ember.ArrayController`. + * otherwise, the controller is an `Ember.ObjectController`. + + As an example, consider the router: + + ```js + App.Router.map(function() { + this.resource('post', {path: '/posts/:post_id'}); + }); + ``` + + For the `post` route, a controller named `App.PostController` would + be used if it is defined. If it is not defined, an `Ember.ObjectController` + instance would be used. + + Example + + ```js + App.PostRoute = Ember.Route.extend({ + setupController: function(controller, model) { + controller.set('model', model); + } + }); + ``` + + @method setupController + @param {Controller} controller instance + @param {Object} model + */ + setupController: function(controller, context, transition) { + if (controller && (context !== undefined)) { + set(controller, 'model', context); + } + }, + + /** + Returns the controller for a particular route or name. + + The controller instance must already have been created, either through entering the + associated route or using `generateController`. + + ```js + App.PostRoute = Ember.Route.extend({ + setupController: function(controller, post) { + this._super(controller, post); + this.controllerFor('posts').set('currentPost', post); + } + }); + ``` + + @method controllerFor + @param {String} name the name of the route or controller + @return {Ember.Controller} + */ + controllerFor: function(name, _skipAssert) { + var container = this.container; + var route = container.lookup('route:'+name); + var controller; + + if (route && route.controllerName) { + name = route.controllerName; + } + + controller = container.lookup('controller:' + name); + + // NOTE: We're specifically checking that skipAssert is true, because according + // to the old API the second parameter was model. We do not want people who + // passed a model to skip the assertion. + Ember.assert("The controller named '"+name+"' could not be found. Make sure " + + "that this route exists and has already been entered at least " + + "once. If you are accessing a controller not associated with a " + + "route, make sure the controller class is explicitly defined.", + controller || _skipAssert === true); + + return controller; + }, + + /** + Generates a controller for a route. + + If the optional model is passed then the controller type is determined automatically, + e.g., an ArrayController for arrays. + + Example + + ```js + App.PostRoute = Ember.Route.extend({ + setupController: function(controller, post) { + this._super(controller, post); + this.generateController('posts', post); + } + }); + ``` + + @method generateController + @param {String} name the name of the controller + @param {Object} model the model to infer the type of the controller (optional) + */ + generateController: function(name, model) { + var container = this.container; + + model = model || this.modelFor(name); + + return generateController(container, name, model); + }, + + /** + Returns the model of a parent (or any ancestor) route + in a route hierarchy. During a transition, all routes + must resolve a model object, and if a route + needs access to a parent route's model in order to + resolve a model (or just reuse the model from a parent), + it can call `this.modelFor(theNameOfParentRoute)` to + retrieve it. + + Example + + ```js + App.Router.map(function() { + this.resource('post', { path: '/post/:post_id' }, function() { + this.resource('comments'); + }); + }); + + App.CommentsRoute = Ember.Route.extend({ + afterModel: function() { + this.set('post', this.modelFor('post')); + } + }); + ``` + + @method modelFor + @param {String} name the name of the route + @return {Object} the model object + */ + modelFor: function(name) { + var route = this.container.lookup('route:' + name); + var transition = this.router ? this.router.router.activeTransition : null; + + // If we are mid-transition, we want to try and look up + // resolved parent contexts on the current transitionEvent. + if (transition) { + var modelLookupName = (route && route.routeName) || name; + if (transition.resolvedModels.hasOwnProperty(modelLookupName)) { + return transition.resolvedModels[modelLookupName]; + } + } + + return route && route.currentModel; + }, + + /** + A hook you can use to render the template for the current route. + + This method is called with the controller for the current route and the + model supplied by the `model` hook. By default, it renders the route's + template, configured with the controller for the route. + + This method can be overridden to set up and render additional or + alternative templates. + + ```js + App.PostsRoute = Ember.Route.extend({ + renderTemplate: function(controller, model) { + var favController = this.controllerFor('favoritePost'); + + // Render the `favoritePost` template into + // the outlet `posts`, and display the `favoritePost` + // controller. + this.render('favoritePost', { + outlet: 'posts', + controller: favController + }); + } + }); + ``` + + @method renderTemplate + @param {Object} controller the route's controller + @param {Object} model the route's model + */ + renderTemplate: function(controller, model) { + this.render(); + }, + + /** + `render` is used to render a template into a region of another template + (indicated by an `{{outlet}}`). `render` is used both during the entry + phase of routing (via the `renderTemplate` hook) and later in response to + user interaction. + + For example, given the following minimal router and templates: + + ```js + Router.map(function() { + this.resource('photos'); + }); + ``` + + ```handlebars + +
    + {{outlet "anOutletName"}} +
    + ``` + + ```handlebars + +

    Photos

    + ``` + + You can render `photos.hbs` into the `"anOutletName"` outlet of + `application.hbs` by calling `render`: + + ```js + // posts route + Ember.Route.extend({ + renderTemplate: function(){ + this.render('photos', { + into: 'application', + outlet: 'anOutletName' + }) + } + }); + ``` + + `render` additionally allows you to supply which `view`, `controller`, and + `model` objects should be loaded and associated with the rendered template. + + + ```js + // posts route + Ember.Route.extend({ + renderTemplate: function(controller, model){ + this.render('posts', { // the template to render, referenced by name + into: 'application', // the template to render into, referenced by name + outlet: 'anOutletName', // the outlet inside `options.template` to render into. + view: 'aViewName', // the view to use for this template, referenced by name + controller: 'someControllerName', // the controller to use for this template, referenced by name + model: model // the model to set on `options.controller`. + }) + } + }); + ``` + + The string values provided for the template name, view, and controller + will eventually pass through to the resolver for lookup. See + Ember.Resolver for how these are mapped to JavaScript objects in your + application. + + Not all options need to be passed to `render`. Default values will be used + based on the name of the route specified in the router or the Route's + `controllerName`, `viewName` and and `templateName` properties. + + For example: + + ```js + // router + Router.map(function() { + this.route('index'); + this.resource('post', {path: '/posts/:post_id'}); + }); + ``` + + ```js + // post route + PostRoute = App.Route.extend({ + renderTemplate: function() { + this.render(); // all defaults apply + } + }); + ``` + + The name of the `PostRoute`, defined by the router, is `post`. + + The following equivalent default options will be applied when + the Route calls `render`: + + ```js + // + this.render('post', { // the template name associated with 'post' Route + into: 'application', // the parent route to 'post' Route + outlet: 'main', // {{outlet}} and {{outlet 'main' are synonymous}}, + view: 'post', // the view associated with the 'post' Route + controller: 'post', // the controller associated with the 'post' Route + }) + ``` + + By default the controller's `model` will be the route's model, so it does not + need to be passed unless you wish to change which model is being used. + + @method render + @param {String} name the name of the template to render + @param {Object} [options] the options + @param {String} [options.into] the template to render into, + referenced by name. Defaults to the parent template + @param {String} [options.outlet] the outlet inside `options.template` to render into. + Defaults to 'main' + @param {String} [options.controller] the controller to use for this template, + referenced by name. Defaults to the Route's paired controller + @param {String} [options.model] the model object to set on `options.controller` + Defaults to the return value of the Route's model hook + */ + render: function(name, options) { + Ember.assert("The name in the given arguments is undefined", arguments.length > 0 ? !isNone(arguments[0]) : true); + + var namePassed = typeof name === 'string' && !!name; + + if (typeof name === 'object' && !options) { + options = name; + name = this.routeName; + } + + options = options || {}; + options.namePassed = namePassed; + + var templateName; + + if (name) { + name = name.replace(/\//g, '.'); + templateName = name; + } else { + name = this.routeName; + templateName = this.templateName || name; + } + + var viewName = options.view || namePassed && name || this.viewName || name; + + var container = this.container; + var view = container.lookup('view:' + viewName); + var template = view ? view.get('template') : null; + + if (!template) { + template = container.lookup('template:' + templateName); + } + + if (!view && !template) { + Ember.assert("Could not find \"" + name + "\" template or view.", Ember.isEmpty(arguments[0])); + if (get(this.router, 'namespace.LOG_VIEW_LOOKUPS')) { + Ember.Logger.info("Could not find \"" + name + "\" template or view. Nothing will be rendered", { fullName: 'template:' + name }); + } + return; + } + + options = normalizeOptions(this, name, template, options); + view = setupView(view, container, options); + + if (options.outlet === 'main') { this.lastRenderedTemplate = name; } + + appendView(this, view, options); + }, + + /** + Disconnects a view that has been rendered into an outlet. + + You may pass any or all of the following options to `disconnectOutlet`: + + * `outlet`: the name of the outlet to clear (default: 'main') + * `parentView`: the name of the view containing the outlet to clear + (default: the view rendered by the parent route) + + Example: + + ```js + App.ApplicationRoute = App.Route.extend({ + actions: { + showModal: function(evt) { + this.render(evt.modalName, { + outlet: 'modal', + into: 'application' + }); + }, + hideModal: function(evt) { + this.disconnectOutlet({ + outlet: 'modal', + parentView: 'application' + }); + } + } + }); + ``` + + Alternatively, you can pass the `outlet` name directly as a string. + + Example: + + ```js + hideModal: function(evt) { + this.disconnectOutlet('modal'); + } + ``` + + @method disconnectOutlet + @param {Object|String} options the options hash or outlet name + */ + disconnectOutlet: function(options) { + if (!options || typeof options === "string") { + var outletName = options; + options = {}; + options.outlet = outletName; + } + options.parentView = options.parentView ? options.parentView.replace(/\//g, '.') : parentTemplate(this); + options.outlet = options.outlet || 'main'; + + var parentView = this.router._lookupActiveView(options.parentView); + if (parentView) { parentView.disconnectOutlet(options.outlet); } + }, + + willDestroy: function() { + this.teardownViews(); + }, + + /** + @private + + @method teardownViews + */ + teardownViews: function() { + // Tear down the top level view + if (this.teardownTopLevelView) { this.teardownTopLevelView(); } + + // Tear down any outlets rendered with 'into' + var teardownOutletViews = this.teardownOutletViews || []; + forEach(teardownOutletViews, function(teardownOutletView) { + teardownOutletView(); + }); + + delete this.teardownTopLevelView; + delete this.teardownOutletViews; + delete this.lastRenderedTemplate; + } + }); + + var defaultQPMeta = { + qps: [], + map: {}, + states: {} + }; + + function parentRoute(route) { + var handlerInfo = handlerInfoFor(route, route.router.router.state.handlerInfos, -1); + return handlerInfo && handlerInfo.handler; + } + + function handlerInfoFor(route, handlerInfos, _offset) { + if (!handlerInfos) { return; } + + var offset = _offset || 0, current; + for (var i=0, l=handlerInfos.length; i " + routeName, { fullName: routeName }); + } + } + + handler.routeName = name; + return handler; + }; + }, + + _setupRouter: function(router, location) { + var lastURL, emberRouter = this; + + router.getHandler = this._getHandlerFunction(); + + var doUpdateURL = function() { + location.setURL(lastURL); + }; + + router.updateURL = function(path) { + lastURL = path; + run.once(doUpdateURL); + }; + + if (location.replaceURL) { + var doReplaceURL = function() { + location.replaceURL(lastURL); + }; + + router.replaceURL = function(path) { + lastURL = path; + run.once(doReplaceURL); + }; + } + + router.didTransition = function(infos) { + emberRouter.didTransition(infos); + }; + }, + + _serializeQueryParams: function(targetRouteName, queryParams) { + var groupedByUrlKey = {}; + + forEachQueryParam(this, targetRouteName, queryParams, function(key, value, qp) { + var urlKey = qp.urlKey; + if (!groupedByUrlKey[urlKey]) { + groupedByUrlKey[urlKey] = []; + } + groupedByUrlKey[urlKey].push({ + qp: qp, + value: value + }); + delete queryParams[key]; + }); + + for (var key in groupedByUrlKey) { + var qps = groupedByUrlKey[key]; + if (qps.length > 1) { + var qp0 = qps[0].qp, qp1=qps[1].qp; + Ember.assert(fmt("You're not allowed to have more than one controller property map to the same query param key, but both `%@` and `%@` map to `%@`. You can fix this by mapping one of the controller properties to a different query param key via the `as` config option, e.g. `%@: { as: 'other-%@' }`", [qp0.fprop, qp1.fprop, qp0.urlKey, qp0.prop, qp0.prop]), false); + } + var qp = qps[0].qp; + queryParams[qp.urlKey] = qp.route.serializeQueryParam(qps[0].value, qp.urlKey, qp.type); + } + }, + + _deserializeQueryParams: function(targetRouteName, queryParams) { + forEachQueryParam(this, targetRouteName, queryParams, function(key, value, qp) { + delete queryParams[key]; + queryParams[qp.prop] = qp.route.deserializeQueryParam(value, qp.urlKey, qp.type); + }); + }, + + _pruneDefaultQueryParamValues: function(targetRouteName, queryParams) { + var qps = this._queryParamsFor(targetRouteName); + for (var key in queryParams) { + var qp = qps.map[key]; + if (qp && qp.sdef === queryParams[key]) { + delete queryParams[key]; + } + } + }, + + _doTransition: function(_targetRouteName, models, _queryParams) { + var targetRouteName = _targetRouteName || getActiveTargetName(this.router); + Ember.assert("The route " + targetRouteName + " was not found", targetRouteName && this.router.hasRoute(targetRouteName)); + + var queryParams = {}; + merge(queryParams, _queryParams); + this._prepareQueryParams(targetRouteName, models, queryParams); + + var transitionArgs = routeArgs(targetRouteName, models, queryParams); + var transitionPromise = this.router.transitionTo.apply(this.router, transitionArgs); + + listenForTransitionErrors(transitionPromise); + + return transitionPromise; + }, + + _prepareQueryParams: function(targetRouteName, models, queryParams) { + this._hydrateUnsuppliedQueryParams(targetRouteName, models, queryParams); + this._serializeQueryParams(targetRouteName, queryParams); + this._pruneDefaultQueryParamValues(targetRouteName, queryParams); + }, + + /** + Returns a merged query params meta object for a given route. + Useful for asking a route what its known query params are. + */ + _queryParamsFor: function(leafRouteName) { + if (this._qpCache[leafRouteName]) { + return this._qpCache[leafRouteName]; + } + + var map = {}, qps = [], qpCache = this._qpCache[leafRouteName] = { + map: map, + qps: qps + }; + + var routerjs = this.router; + var recogHandlerInfos = routerjs.recognizer.handlersFor(leafRouteName); + + for (var i = 0, len = recogHandlerInfos.length; i < len; ++i) { + var recogHandler = recogHandlerInfos[i]; + var route = routerjs.getHandler(recogHandler.handler); + var qpMeta = get(route, '_qp'); + + if (!qpMeta) { continue; } + + merge(map, qpMeta.map); + qps.push.apply(qps, qpMeta.qps); + } + + return { + qps: qps, + map: map + }; + }, + + /* + becomeResolved: function(payload, resolvedContext) { + var params = this.serialize(resolvedContext); + + if (payload) { + this.stashResolvedModel(payload, resolvedContext); + payload.params = payload.params || {}; + payload.params[this.name] = params; + } + + return this.factory('resolved', { + context: resolvedContext, + name: this.name, + handler: this.handler, + params: params + }); + }, + */ + + _hydrateUnsuppliedQueryParams: function(leafRouteName, contexts, queryParams) { + var state = calculatePostTransitionState(this, leafRouteName, contexts); + var handlerInfos = state.handlerInfos; + var appCache = this._bucketCache; + + stashParamNames(this, handlerInfos); + + for (var i = 0, len = handlerInfos.length; i < len; ++i) { + var route = handlerInfos[i].handler; + var qpMeta = get(route, '_qp'); + + for (var j = 0, qpLen = qpMeta.qps.length; j < qpLen; ++j) { + var qp = qpMeta.qps[j]; + var presentProp = qp.prop in queryParams && qp.prop || + qp.fprop in queryParams && qp.fprop; + + if (presentProp) { + if (presentProp !== qp.fprop) { + queryParams[qp.fprop] = queryParams[presentProp]; + delete queryParams[presentProp]; + } + } else { + var controllerProto = qp.cProto; + var cacheMeta = get(controllerProto, '_cacheMeta'); + + var cacheKey = controllerProto._calculateCacheKey(qp.ctrl, cacheMeta[qp.prop].parts, state.params); + queryParams[qp.fprop] = appCache.lookup(cacheKey, qp.prop, qp.def); + } + } + } + }, + + _scheduleLoadingEvent: function(transition, originRoute) { + this._cancelLoadingEvent(); + this._loadingStateTimer = run.scheduleOnce('routerTransitions', this, '_fireLoadingEvent', transition, originRoute); + }, + + _fireLoadingEvent: function(transition, originRoute) { + if (!this.router.activeTransition) { + // Don't fire an event if we've since moved on from + // the transition that put us in a loading state. + return; + } + + transition.trigger(true, 'loading', transition, originRoute); + }, + + _cancelLoadingEvent: function () { + if (this._loadingStateTimer) { + run.cancel(this._loadingStateTimer); + } + this._loadingStateTimer = null; + } + }); + + /* + Helper function for iterating root-ward, starting + from (but not including) the provided `originRoute`. + + Returns true if the last callback fired requested + to bubble upward. + + @private + */ + function forEachRouteAbove(originRoute, transition, callback) { + var handlerInfos = transition.state.handlerInfos; + var originRouteFound = false; + var handlerInfo, route; + + for (var i = handlerInfos.length - 1; i >= 0; --i) { + handlerInfo = handlerInfos[i]; + route = handlerInfo.handler; + + if (!originRouteFound) { + if (originRoute === route) { + originRouteFound = true; + } + continue; + } + + if (callback(route, handlerInfos[i + 1].handler) !== true) { + return false; + } + } + return true; + } + + // These get invoked when an action bubbles above ApplicationRoute + // and are not meant to be overridable. + var defaultActionHandlers = { + + willResolveModel: function(transition, originRoute) { + originRoute.router._scheduleLoadingEvent(transition, originRoute); + }, + + error: function(error, transition, originRoute) { + // Attempt to find an appropriate error substate to enter. + var router = originRoute.router; + + var tryTopLevel = forEachRouteAbove(originRoute, transition, function(route, childRoute) { + var childErrorRouteName = findChildRouteName(route, childRoute, 'error'); + if (childErrorRouteName) { + router.intermediateTransitionTo(childErrorRouteName, error); + return; + } + return true; + }); + + if (tryTopLevel) { + // Check for top-level error state to enter. + if (routeHasBeenDefined(originRoute.router, 'application_error')) { + router.intermediateTransitionTo('application_error', error); + return; + } + } + + logError(error, 'Error while processing route: ' + transition.targetName); + }, + + loading: function(transition, originRoute) { + // Attempt to find an appropriate loading substate to enter. + var router = originRoute.router; + + var tryTopLevel = forEachRouteAbove(originRoute, transition, function(route, childRoute) { + var childLoadingRouteName = findChildRouteName(route, childRoute, 'loading'); + + if (childLoadingRouteName) { + router.intermediateTransitionTo(childLoadingRouteName); + return; + } + + // Don't bubble above pivot route. + if (transition.pivotHandler !== route) { + return true; + } + }); + + if (tryTopLevel) { + // Check for top-level loading state to enter. + if (routeHasBeenDefined(originRoute.router, 'application_loading')) { + router.intermediateTransitionTo('application_loading'); + return; + } + } + } + }; + + function logError(error, initialMessage) { + var errorArgs = []; + + if (initialMessage) { errorArgs.push(initialMessage); } + + if (error) { + if (error.message) { errorArgs.push(error.message); } + if (error.stack) { errorArgs.push(error.stack); } + + if (typeof error === "string") { errorArgs.push(error); } + } + + Ember.Logger.error.apply(this, errorArgs); + } + + function findChildRouteName(parentRoute, originatingChildRoute, name) { + var router = parentRoute.router; + var childName; + var targetChildRouteName = originatingChildRoute.routeName.split('.').pop(); + var namespace = parentRoute.routeName === 'application' ? '' : parentRoute.routeName + '.'; + + + // Second, try general loading state, e.g. 'loading' + childName = namespace + name; + if (routeHasBeenDefined(router, childName)) { + return childName; + } + } + + function routeHasBeenDefined(router, name) { + var container = router.container; + return router.hasRoute(name) && + (container.has('template:' + name) || container.has('route:' + name)); + } + + function triggerEvent(handlerInfos, ignoreFailure, args) { + var name = args.shift(); + + if (!handlerInfos) { + if (ignoreFailure) { return; } + throw new EmberError("Can't trigger action '" + name + "' because your app hasn't finished transitioning into its first route. To trigger an action on destination routes during a transition, you can call `.send()` on the `Transition` object passed to the `model/beforeModel/afterModel` hooks."); + } + + var eventWasHandled = false; + var handlerInfo, handler; + + for (var i = handlerInfos.length - 1; i >= 0; i--) { + handlerInfo = handlerInfos[i]; + handler = handlerInfo.handler; + + if (handler._actions && handler._actions[name]) { + if (handler._actions[name].apply(handler, args) === true) { + eventWasHandled = true; + } else { + return; + } + } + } + + if (defaultActionHandlers[name]) { + defaultActionHandlers[name].apply(null, args); + return; + } + + if (!eventWasHandled && !ignoreFailure) { + throw new EmberError("Nothing handled the action '" + name + "'. If you did handle the action, this error can be caused by returning true from an action handler in a controller, causing the action to bubble."); + } + } + + function calculatePostTransitionState(emberRouter, leafRouteName, contexts) { + var routerjs = emberRouter.router; + var state = routerjs.applyIntent(leafRouteName, contexts); + var handlerInfos = state.handlerInfos; + var params = state.params; + + for (var i = 0, len = handlerInfos.length; i < len; ++i) { + var handlerInfo = handlerInfos[i]; + if (!handlerInfo.isResolved) { + handlerInfo = handlerInfo.becomeResolved(null, handlerInfo.context); + } + params[handlerInfo.name] = handlerInfo.params; + } + return state; + } + + function updatePaths(router) { + var appController = router.container.lookup('controller:application'); + + if (!appController) { + // appController might not exist when top-level loading/error + // substates have been entered since ApplicationRoute hasn't + // actually been entered at that point. + return; + } + + var infos = router.router.currentHandlerInfos; + var path = EmberRouter._routePath(infos); + + if (!('currentPath' in appController)) { + defineProperty(appController, 'currentPath'); + } + + set(appController, 'currentPath', path); + + if (!('currentRouteName' in appController)) { + defineProperty(appController, 'currentRouteName'); + } + + set(appController, 'currentRouteName', infos[infos.length - 1].name); + } + + EmberRouter.reopenClass({ + router: null, + + /** + The `Router.map` function allows you to define mappings from URLs to routes + and resources in your application. These mappings are defined within the + supplied callback function using `this.resource` and `this.route`. + + ```javascript + App.Router.map(function({ + this.route('about'); + this.resource('article'); + })); + ``` + + For more detailed examples please see + [the guides](http://emberjs.com/guides/routing/defining-your-routes/). + + @method map + @param callback + */ + map: function(callback) { + var router = this.router; + if (!router) { + router = new Router(); + + + router._triggerWillChangeContext = Ember.K; + router._triggerWillLeave = Ember.K; + + + router.callbacks = []; + router.triggerEvent = triggerEvent; + this.reopenClass({ router: router }); + } + + var dsl = EmberRouterDSL.map(function() { + this.resource('application', { path: "/" }, function() { + for (var i=0; i < router.callbacks.length; i++) { + router.callbacks[i].call(this); + } + callback.call(this); + }); + }); + + router.callbacks.push(callback); + router.map(dsl.generate()); + return router; + }, + + _routePath: function(handlerInfos) { + var path = []; + + // We have to handle coalescing resource names that + // are prefixed with their parent's names, e.g. + // ['foo', 'foo.bar.baz'] => 'foo.bar.baz', not 'foo.foo.bar.baz' + + function intersectionMatches(a1, a2) { + for (var i = 0, len = a1.length; i < len; ++i) { + if (a1[i] !== a2[i]) { + return false; + } + } + return true; + } + + var name, nameParts, oldNameParts; + for (var i=1, l=handlerInfos.length; i 0) - (diff < 0); + } /** This will compare two javascript values of possibly different types. @@ -12256,75 +26747,53 @@ define("ember-runtime/compare", @param {Object} w Second value to compare @return {Number} -1 if v < w, 0 if v = w and 1 if v > w. */ - function compare(v, w) { - if (v === w) { return 0; } + __exports__["default"] = function compare(v, w) { + if (v === w) { + return 0; + } var type1 = typeOf(v); var type2 = typeOf(w); if (Comparable) { - if (type1==='instance' && Comparable.detect(v.constructor)) { + if (type1 ==='instance' && Comparable.detect(v.constructor)) { return v.constructor.compare(v, w); } if (type2 === 'instance' && Comparable.detect(w.constructor)) { - return 1-w.constructor.compare(w, v); + return 1 - w.constructor.compare(w, v); } } - // If we haven't yet generated a reverse-mapping of Ember.ORDER_DEFINITION, - // do so now. - var mapping = Ember.ORDER_DEFINITION_MAPPING; - if (!mapping) { - var order = Ember.ORDER_DEFINITION; - mapping = Ember.ORDER_DEFINITION_MAPPING = {}; - var idx, len; - for (idx = 0, len = order.length; idx < len; ++idx) { - mapping[order[idx]] = idx; - } - - // We no longer need Ember.ORDER_DEFINITION. - delete Ember.ORDER_DEFINITION; + var res = spaceship(TYPE_ORDER[type1], TYPE_ORDER[type2]); + if (res !== 0) { + return res; } - var type1Index = mapping[type1]; - var type2Index = mapping[type2]; - - if (type1Index < type2Index) { return -1; } - if (type1Index > type2Index) { return 1; } - // types are equal - so we have to check values now switch (type1) { case 'boolean': case 'number': - if (v < w) { return -1; } - if (v > w) { return 1; } - return 0; + return spaceship(v,w); case 'string': - var comp = v.localeCompare(w); - if (comp < 0) { return -1; } - if (comp > 0) { return 1; } - return 0; + return spaceship(v.localeCompare(w), 0); case 'array': var vLen = v.length; var wLen = w.length; - var l = Math.min(vLen, wLen); - var r = 0; - var i = 0; - while (r === 0 && i < l) { - r = compare(v[i],w[i]); - i++; + var len = Math.min(vLen, wLen); + + for (var i = 0; i < len; i++) { + var r = compare(v[i], w[i]); + if (r !== 0) { + return r; + } } - if (r !== 0) { return r; } // all elements are equal now // shorter array should be ordered first - if (vLen < wLen) { return -1; } - if (vLen > wLen) { return 1; } - // arrays are equal now - return 0; + return spaceship(vLen, wLen); case 'instance': if (Comparable && Comparable.detect(v)) { @@ -12333,34 +26802,26 @@ define("ember-runtime/compare", return 0; case 'date': - var vNum = v.getTime(); - var wNum = w.getTime(); - if (vNum < wNum) { return -1; } - if (vNum > wNum) { return 1; } - return 0; + return spaceship(v.getTime(), w.getTime()); default: return 0; } - }; - - __exports__["default"] = compare; + } }); -define("ember-runtime/computed/array_computed", +enifed("ember-runtime/computed/array_computed", ["ember-metal/core","ember-runtime/computed/reduce_computed","ember-metal/enumerable_utils","ember-metal/platform","ember-metal/observer","ember-metal/error","exports"], function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __exports__) { "use strict"; var Ember = __dependency1__["default"]; var reduceComputed = __dependency2__.reduceComputed; var ReduceComputedProperty = __dependency2__.ReduceComputedProperty; - var EnumerableUtils = __dependency3__["default"]; - var create = __dependency4__.create; + var forEach = __dependency3__.forEach; + var o_create = __dependency4__.create; var addObserver = __dependency5__.addObserver; var EmberError = __dependency6__["default"]; - var a_slice = [].slice, - o_create = create, - forEach = EnumerableUtils.forEach; + var a_slice = [].slice; function ArrayComputedProperty() { var cp = this; @@ -12388,9 +26849,11 @@ define("ember-runtime/computed/array_computed", } ArrayComputedProperty.prototype = o_create(ReduceComputedProperty.prototype); + ArrayComputedProperty.prototype.initialValue = function () { return Ember.A(); }; + ArrayComputedProperty.prototype.resetValue = function (array) { array.clear(); return array; @@ -12523,8 +26986,8 @@ define("ember-runtime/computed/array_computed", options = a_slice.call(arguments, -1)[0]; } - if (typeof options !== "object") { - throw new EmberError("Array Computed Property declared without an options hash"); + if (typeof options !== 'object') { + throw new EmberError('Array Computed Property declared without an options hash'); } var cp = new ArrayComputedProperty(options); @@ -12534,14 +26997,14 @@ define("ember-runtime/computed/array_computed", } return cp; - }; + } __exports__.arrayComputed = arrayComputed; __exports__.ArrayComputedProperty = ArrayComputedProperty; }); -define("ember-runtime/computed/reduce_computed", - ["ember-metal/core","ember-metal/property_get","ember-metal/property_set","ember-metal/utils","ember-metal/error","ember-metal/property_events","ember-metal/expand_properties","ember-metal/observer","ember-metal/computed","ember-metal/platform","ember-metal/enumerable_utils","ember-runtime/system/tracked_array","ember-runtime/mixins/array","ember-metal/run_loop","ember-runtime/system/set","exports"], - function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __dependency9__, __dependency10__, __dependency11__, __dependency12__, __dependency13__, __dependency14__, __dependency15__, __exports__) { +enifed("ember-runtime/computed/reduce_computed", + ["ember-metal/core","ember-metal/property_get","ember-metal/property_set","ember-metal/utils","ember-metal/error","ember-metal/property_events","ember-metal/expand_properties","ember-metal/observer","ember-metal/computed","ember-metal/platform","ember-metal/enumerable_utils","ember-runtime/system/tracked_array","ember-runtime/mixins/array","ember-metal/run_loop","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __dependency9__, __dependency10__, __dependency11__, __dependency12__, __dependency13__, __dependency14__, __exports__) { "use strict"; var Ember = __dependency1__["default"]; // Ember.assert @@ -12560,25 +27023,22 @@ define("ember-runtime/computed/reduce_computed", var removeBeforeObserver = __dependency8__.removeBeforeObserver; var ComputedProperty = __dependency9__.ComputedProperty; var cacheFor = __dependency9__.cacheFor; - var create = __dependency10__.create; - var EnumerableUtils = __dependency11__["default"]; + var o_create = __dependency10__.create; + var forEach = __dependency11__.forEach; var TrackedArray = __dependency12__["default"]; var EmberArray = __dependency13__["default"]; var run = __dependency14__["default"]; - var Set = __dependency15__["default"]; var isArray = __dependency4__.isArray; - var cacheSet = cacheFor.set, - cacheGet = cacheFor.get, - cacheRemove = cacheFor.remove, - a_slice = [].slice, - o_create = create, - forEach = EnumerableUtils.forEach, - // Here we explicitly don't allow `@each.foo`; it would require some special - // testing, but there's no particular reason why it should be disallowed. - eachPropertyPattern = /^(.*)\.@each\.(.*)/, - doubleEachPropertyPattern = /(.*\.@each){2,}/, - arrayBracketPattern = /\.\[\]$/; + var cacheSet = cacheFor.set; + var cacheGet = cacheFor.get; + var cacheRemove = cacheFor.remove; + var a_slice = [].slice; + // Here we explicitly don't allow `@each.foo`; it would require some special + // testing, but there's no particular reason why it should be disallowed. + var eachPropertyPattern = /^(.*)\.@each\.(.*)/; + var doubleEachPropertyPattern = /(.*\.@each){2,}/; + var arrayBracketPattern = /\.\[\]$/; function get(obj, key) { if (key === '@this') { @@ -12630,7 +27090,7 @@ define("ember-runtime/computed/reduce_computed", } function ItemPropertyObserverContext (dependentArray, index, trackedArray) { - Ember.assert("Internal error: trackedArray is null or undefined", trackedArray); + Ember.assert('Internal error: trackedArray is null or undefined', trackedArray); this.dependentArray = dependentArray; this.index = index; @@ -12638,7 +27098,6 @@ define("ember-runtime/computed/reduce_computed", this.trackedArray = trackedArray; this.beforeObserver = null; this.observer = null; - this.destroyed = false; } @@ -12646,6 +27105,7 @@ define("ember-runtime/computed/reduce_computed", setValue: function (newValue) { this.instanceMeta.setValue(newValue, true); }, + getValue: function () { return this.instanceMeta.getValue(); }, @@ -12684,9 +27144,9 @@ define("ember-runtime/computed/reduce_computed", }, setupPropertyObservers: function (dependentKey, itemPropertyKeys) { - var dependentArray = get(this.instanceMeta.context, dependentKey), - length = get(dependentArray, 'length'), - observerContexts = new Array(length); + var dependentArray = get(this.instanceMeta.context, dependentKey); + var length = get(dependentArray, 'length'); + var observerContexts = new Array(length); this.resetTransformations(dependentKey, observerContexts); @@ -12702,11 +27162,9 @@ define("ember-runtime/computed/reduce_computed", }, teardownPropertyObservers: function (dependentKey, itemPropertyKeys) { - var dependentArrayObserver = this, - trackedArray = this.trackedArraysByGuid[dependentKey], - beforeObserver, - observer, - item; + var dependentArrayObserver = this; + var trackedArray = this.trackedArraysByGuid[dependentKey]; + var beforeObserver, observer, item; if (!trackedArray) { return; } @@ -12741,6 +27199,7 @@ define("ember-runtime/computed/reduce_computed", observerContext.beforeObserver = function (obj, keyName) { return dependentArrayObserver.itemPropertyWillChange(obj, keyName, observerContext.dependentArray, observerContext); }; + observerContext.observer = function (obj, keyName) { return dependentArrayObserver.itemPropertyDidChange(obj, keyName, observerContext.dependentArray, observerContext); }; @@ -12752,6 +27211,7 @@ define("ember-runtime/computed/reduce_computed", trackAdd: function (dependentKey, index, newItems) { var trackedArray = this.trackedArraysByGuid[dependentKey]; + if (trackedArray) { trackedArray.addItems(index, newItems); } @@ -12790,18 +27250,15 @@ define("ember-runtime/computed/reduce_computed", dependentArrayWillChange: function (dependentArray, index, removedCount, addedCount) { if (this.suspended) { return; } - var removedItem = this.callbacks.removedItem, - changeMeta, - guid = guidFor(dependentArray), - dependentKey = this.dependentKeysByGuid[guid], - itemPropertyKeys = this.cp._itemPropertyKeys[dependentKey] || [], - length = get(dependentArray, 'length'), - normalizedIndex = normalizeIndex(index, length, 0), - normalizedRemoveCount = normalizeRemoveCount(normalizedIndex, length, removedCount), - item, - itemIndex, - sliceIndex, - observerContexts; + var removedItem = this.callbacks.removedItem; + var changeMeta; + var guid = guidFor(dependentArray); + var dependentKey = this.dependentKeysByGuid[guid]; + var itemPropertyKeys = this.cp._itemPropertyKeys[dependentKey] || []; + var length = get(dependentArray, 'length'); + var normalizedIndex = normalizeIndex(index, length, 0); + var normalizedRemoveCount = normalizeRemoveCount(normalizedIndex, length, removedCount); + var item, itemIndex, sliceIndex, observerContexts; observerContexts = this.trackRemove(dependentKey, normalizedIndex, normalizedRemoveCount); @@ -12819,41 +27276,43 @@ define("ember-runtime/computed/reduce_computed", forEach(itemPropertyKeys, removeObservers, this); - changeMeta = createChangeMeta(dependentArray, item, itemIndex, this.instanceMeta.propertyName, this.cp); - this.setValue( removedItem.call( + changeMeta = new ChangeMeta(dependentArray, item, itemIndex, this.instanceMeta.propertyName, this.cp, normalizedRemoveCount); + this.setValue(removedItem.call( this.instanceMeta.context, this.getValue(), item, changeMeta, this.instanceMeta.sugarMeta)); } + this.callbacks.flushedChanges.call(this.instanceMeta.context, this.getValue(), this.instanceMeta.sugarMeta); }, dependentArrayDidChange: function (dependentArray, index, removedCount, addedCount) { if (this.suspended) { return; } - var addedItem = this.callbacks.addedItem, - guid = guidFor(dependentArray), - dependentKey = this.dependentKeysByGuid[guid], - observerContexts = new Array(addedCount), - itemPropertyKeys = this.cp._itemPropertyKeys[dependentKey], - length = get(dependentArray, 'length'), - normalizedIndex = normalizeIndex(index, length, addedCount), - changeMeta, - observerContext; + var addedItem = this.callbacks.addedItem; + var guid = guidFor(dependentArray); + var dependentKey = this.dependentKeysByGuid[guid]; + var observerContexts = new Array(addedCount); + var itemPropertyKeys = this.cp._itemPropertyKeys[dependentKey]; + var length = get(dependentArray, 'length'); + var normalizedIndex = normalizeIndex(index, length, addedCount); + var endIndex = normalizedIndex + addedCount; + var changeMeta, observerContext; - forEach(dependentArray.slice(normalizedIndex, normalizedIndex + addedCount), function (item, sliceIndex) { + forEach(dependentArray.slice(normalizedIndex, endIndex), function (item, sliceIndex) { if (itemPropertyKeys) { - observerContext = - observerContexts[sliceIndex] = - this.createPropertyObserverContext(dependentArray, normalizedIndex + sliceIndex, this.trackedArraysByGuid[dependentKey]); + observerContext = this.createPropertyObserverContext(dependentArray, normalizedIndex + sliceIndex, + this.trackedArraysByGuid[dependentKey]); + observerContexts[sliceIndex] = observerContext; + forEach(itemPropertyKeys, function (propertyKey) { addBeforeObserver(item, propertyKey, this, observerContext.beforeObserver); addObserver(item, propertyKey, this, observerContext.observer); }, this); } - changeMeta = createChangeMeta(dependentArray, item, normalizedIndex + sliceIndex, this.instanceMeta.propertyName, this.cp); - this.setValue( addedItem.call( + changeMeta = new ChangeMeta(dependentArray, item, normalizedIndex + sliceIndex, this.instanceMeta.propertyName, this.cp, addedCount); + this.setValue(addedItem.call( this.instanceMeta.context, this.getValue(), item, changeMeta, this.instanceMeta.sugarMeta)); }, this); - + this.callbacks.flushedChanges.call(this.instanceMeta.context, this.getValue(), this.instanceMeta.sugarMeta); this.trackAdd(dependentKey, normalizedIndex, observerContexts); }, @@ -12862,25 +27321,26 @@ define("ember-runtime/computed/reduce_computed", if (!this.changedItems[guid]) { this.changedItems[guid] = { - array: array, - observerContext: observerContext, - obj: obj, - previousValues: {} + array: array, + observerContext: observerContext, + obj: obj, + previousValues: {} }; } - ++this.changedItemCount; + ++this.changedItemCount; this.changedItems[guid].previousValues[keyName] = get(obj, keyName); }, - itemPropertyDidChange: function(obj, keyName, array, observerContext) { + itemPropertyDidChange: function (obj, keyName, array, observerContext) { if (--this.changedItemCount === 0) { this.flushChanges(); } }, - flushChanges: function() { - var changedItems = this.changedItems, key, c, changeMeta; + flushChanges: function () { + var changedItems = this.changedItems; + var key, c, changeMeta; for (key in changedItems) { c = changedItems[key]; @@ -12888,13 +27348,15 @@ define("ember-runtime/computed/reduce_computed", this.updateIndexes(c.observerContext.trackedArray, c.observerContext.dependentArray); - changeMeta = createChangeMeta(c.array, c.obj, c.observerContext.index, this.instanceMeta.propertyName, this.cp, c.previousValues); + changeMeta = new ChangeMeta(c.array, c.obj, c.observerContext.index, this.instanceMeta.propertyName, this.cp, changedItems.length, c.previousValues); this.setValue( this.callbacks.removedItem.call(this.instanceMeta.context, this.getValue(), c.obj, changeMeta, this.instanceMeta.sugarMeta)); this.setValue( this.callbacks.addedItem.call(this.instanceMeta.context, this.getValue(), c.obj, changeMeta, this.instanceMeta.sugarMeta)); } + this.changedItems = {}; + this.callbacks.flushedChanges.call(this.instanceMeta.context, this.getValue(), this.instanceMeta.sugarMeta); } }; @@ -12912,43 +27374,40 @@ define("ember-runtime/computed/reduce_computed", return Math.min(removedCount, length - index); } - function createChangeMeta(dependentArray, item, index, propertyName, property, previousValues) { - var meta = { - arrayChanged: dependentArray, - index: index, - item: item, - propertyName: propertyName, - property: property - }; + function ChangeMeta(dependentArray, item, index, propertyName, property, changedCount, previousValues){ + this.arrayChanged = dependentArray; + this.index = index; + this.item = item; + this.propertyName = propertyName; + this.property = property; + this.changedCount = changedCount; if (previousValues) { // previous values only available for item property changes - meta.previousValues = previousValues; + this.previousValues = previousValues; } - - return meta; } - function addItems (dependentArray, callbacks, cp, propertyName, meta) { + function addItems(dependentArray, callbacks, cp, propertyName, meta) { forEach(dependentArray, function (item, index) { meta.setValue( callbacks.addedItem.call( - this, meta.getValue(), item, createChangeMeta(dependentArray, item, index, propertyName, cp), meta.sugarMeta)); + this, meta.getValue(), item, new ChangeMeta(dependentArray, item, index, propertyName, cp, dependentArray.length), meta.sugarMeta)); }, this); + callbacks.flushedChanges.call(this, meta.getValue(), meta.sugarMeta); } function reset(cp, propertyName) { - var callbacks = cp._callbacks(), - meta; + var callbacks = cp._callbacks(); + var hadMeta = cp._hasInstanceMeta(this, propertyName); + var meta = cp._instanceMeta(this, propertyName); - if (cp._hasInstanceMeta(this, propertyName)) { - meta = cp._instanceMeta(this, propertyName); - meta.setValue(cp.resetValue(meta.getValue())); - } else { - meta = cp._instanceMeta(this, propertyName); - } + if (hadMeta) { meta.setValue(cp.resetValue(meta.getValue())); } if (cp.options.initialize) { - cp.options.initialize.call(this, meta.getValue(), { property: cp, propertyName: propertyName }, meta.sugarMeta); + cp.options.initialize.call(this, meta.getValue(), { + property: cp, + propertyName: propertyName + }, meta.sugarMeta); } } @@ -12965,16 +27424,15 @@ define("ember-runtime/computed/reduce_computed", this.context = context; this.propertyName = propertyName; this.cache = metaFor(context).cache; - this.dependentArrays = {}; this.sugarMeta = {}; - this.initialValue = initialValue; } ReduceComputedPropertyInstanceMeta.prototype = { getValue: function () { var value = cacheGet(this.cache, this.propertyName); + if (value !== undefined) { return value; } else { @@ -13014,11 +27472,14 @@ define("ember-runtime/computed/reduce_computed", @extends Ember.ComputedProperty @constructor */ + + __exports__.ReduceComputedProperty = ReduceComputedProperty; + // TODO: default export + function ReduceComputedProperty(options) { var cp = this; this.options = options; - this._dependentKeys = null; // A map of dependentKey -> [itemProperty, ...] that tracks what properties of // items in the array we must track to update this property. @@ -13034,24 +27495,25 @@ define("ember-runtime/computed/reduce_computed", // coalesce by, in addition to the target and method. run.once(this, recompute, propertyName); }; + var recompute = function(propertyName) { - var dependentKeys = cp._dependentKeys, - meta = cp._instanceMeta(this, propertyName), - callbacks = cp._callbacks(); + var dependentKeys = cp._dependentKeys; + var meta = cp._instanceMeta(this, propertyName); + var callbacks = cp._callbacks(); reset.call(this, cp, propertyName); meta.dependentArraysObserver.suspendArrayObservers(function () { forEach(cp._dependentKeys, function (dependentKey) { Ember.assert( - "dependent array " + dependentKey + " must be an `Ember.Array`. " + - "If you are not extending arrays, you will need to wrap native arrays with `Ember.A`", + 'dependent array ' + dependentKey + ' must be an `Ember.Array`. ' + + 'If you are not extending arrays, you will need to wrap native arrays with `Ember.A`', !(isArray(get(this, dependentKey)) && !EmberArray.detect(get(this, dependentKey)))); if (!partiallyRecomputeFor(this, dependentKey)) { return; } - var dependentArray = get(this, dependentKey), - previousDependentArray = meta.dependentArrays[dependentKey]; + var dependentArray = get(this, dependentKey); + var previousDependentArray = meta.dependentArrays[dependentKey]; if (dependentArray === previousDependentArray) { // The array may be the same, but our item property keys may have @@ -13080,6 +27542,7 @@ define("ember-runtime/computed/reduce_computed", if (!partiallyRecomputeFor(this, dependentKey)) { return; } var dependentArray = get(this, dependentKey); + if (dependentArray) { addItems.call(this, dependentArray, callbacks, cp, propertyName, meta); } @@ -13088,7 +27551,7 @@ define("ember-runtime/computed/reduce_computed", this.func = function (propertyName) { - Ember.assert("Computed reduce values require at least one dependent key", cp._dependentKeys); + Ember.assert('Computed reduce values require at least one dependent key', cp._dependentKeys); recompute.call(this, propertyName); @@ -13105,11 +27568,14 @@ define("ember-runtime/computed/reduce_computed", ReduceComputedProperty.prototype._callbacks = function () { if (!this.callbacks) { var options = this.options; + this.callbacks = { removedItem: options.removedItem || defaultCallback, - addedItem: options.addedItem || defaultCallback + addedItem: options.addedItem || defaultCallback, + flushedChanges: options.flushedChanges || defaultCallback }; } + return this.callbacks; }; @@ -13118,8 +27584,8 @@ define("ember-runtime/computed/reduce_computed", }; ReduceComputedProperty.prototype._instanceMeta = function (context, propertyName) { - var cacheMeta = metaFor(context).cacheMeta, - meta = cacheMeta[propertyName]; + var cacheMeta = metaFor(context).cacheMeta; + var meta = cacheMeta[propertyName]; if (!meta) { meta = cacheMeta[propertyName] = new ReduceComputedPropertyInstanceMeta(context, propertyName, this.initialValue()); @@ -13155,33 +27621,35 @@ define("ember-runtime/computed/reduce_computed", }; ReduceComputedProperty.prototype.property = function () { - var cp = this, - args = a_slice.call(arguments), - propertyArgs = new Set(), - match, - dependentArrayKey, - itemPropertyKey; + var cp = this; + var args = a_slice.call(arguments); + var propertyArgs = {}; + var match, dependentArrayKey, itemPropertyKey; forEach(args, function (dependentKey) { if (doubleEachPropertyPattern.test(dependentKey)) { - throw new EmberError("Nested @each properties not supported: " + dependentKey); + throw new EmberError('Nested @each properties not supported: ' + dependentKey); } else if (match = eachPropertyPattern.exec(dependentKey)) { dependentArrayKey = match[1]; - var itemPropertyKeyPattern = match[2], - addItemPropertyKey = function (itemPropertyKey) { - cp.itemPropertyKey(dependentArrayKey, itemPropertyKey); - }; + var itemPropertyKeyPattern = match[2]; + var addItemPropertyKey = function (itemPropertyKey) { + cp.itemPropertyKey(dependentArrayKey, itemPropertyKey); + }; expandProperties(itemPropertyKeyPattern, addItemPropertyKey); - propertyArgs.add(dependentArrayKey); + propertyArgs[guidFor(dependentArrayKey)] = dependentArrayKey; } else { - propertyArgs.add(dependentKey); + propertyArgs[guidFor(dependentKey)] = dependentKey; } }); - return ComputedProperty.prototype.property.apply(this, propertyArgs.toArray()); + var propertyArgsToArray = []; + for (var guid in propertyArgs) { + propertyArgsToArray.push(propertyArgs[guid]); + } + return ComputedProperty.prototype.property.apply(this, propertyArgsToArray); }; /** @@ -13317,8 +27785,8 @@ define("ember-runtime/computed/reduce_computed", // `content.@each.reversedName` above, we would be getting the objects // directly and not have access to `reversedName`. // - var reversedNameA = get(personA, 'reversedName'), - reversedNameB = get(personB, 'reversedName'); + var reversedNameA = get(personA, 'reversedName'); + var reversedNameB = get(personB, 'reversedName'); return Ember.compare(reversedNameA, reversedNameB); }) @@ -13377,12 +27845,12 @@ define("ember-runtime/computed/reduce_computed", options = a_slice.call(arguments, -1)[0]; } - if (typeof options !== "object") { - throw new EmberError("Reduce Computed Property declared without an options hash"); + if (typeof options !== 'object') { + throw new EmberError('Reduce Computed Property declared without an options hash'); } if (!('initialValue' in options)) { - throw new EmberError("Reduce Computed Property declared without an initial value"); + throw new EmberError('Reduce Computed Property declared without an initial value'); } var cp = new ReduceComputedProperty(options); @@ -13395,11 +27863,10 @@ define("ember-runtime/computed/reduce_computed", } __exports__.reduceComputed = reduceComputed; - __exports__.ReduceComputedProperty = ReduceComputedProperty; }); -define("ember-runtime/computed/reduce_computed_macros", - ["ember-metal/core","ember-metal/merge","ember-metal/property_get","ember-metal/property_set","ember-metal/utils","ember-metal/error","ember-metal/enumerable_utils","ember-metal/run_loop","ember-metal/observer","ember-runtime/computed/array_computed","ember-runtime/computed/reduce_computed","ember-runtime/system/object_proxy","ember-runtime/system/subarray","ember-runtime/keys","ember-runtime/compare","exports"], - function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __dependency9__, __dependency10__, __dependency11__, __dependency12__, __dependency13__, __dependency14__, __dependency15__, __exports__) { +enifed("ember-runtime/computed/reduce_computed_macros", + ["ember-metal/core","ember-metal/property_get","ember-metal/property_set","ember-metal/utils","ember-metal/error","ember-metal/enumerable_utils","ember-metal/run_loop","ember-metal/observer","ember-runtime/computed/array_computed","ember-runtime/computed/reduce_computed","ember-runtime/system/subarray","ember-metal/keys","ember-runtime/compare","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __dependency9__, __dependency10__, __dependency11__, __dependency12__, __dependency13__, __exports__) { "use strict"; /** @module ember @@ -13408,25 +27875,21 @@ define("ember-runtime/computed/reduce_computed_macros", var Ember = __dependency1__["default"]; // Ember.assert - var merge = __dependency2__["default"]; - var get = __dependency3__.get; - var set = __dependency4__.set; - var isArray = __dependency5__.isArray; - var guidFor = __dependency5__.guidFor; - var EmberError = __dependency6__["default"]; - var EnumerableUtils = __dependency7__["default"]; - var run = __dependency8__["default"]; - var addObserver = __dependency9__.addObserver; - var arrayComputed = __dependency10__.arrayComputed; - var reduceComputed = __dependency11__.reduceComputed; - var ObjectProxy = __dependency12__["default"]; - var SubArray = __dependency13__["default"]; - var keys = __dependency14__["default"]; - var compare = __dependency15__["default"]; + var get = __dependency2__.get; + var set = __dependency3__.set; + var isArray = __dependency4__.isArray; + var guidFor = __dependency4__.guidFor; + var EmberError = __dependency5__["default"]; + var forEach = __dependency6__.forEach; + var run = __dependency7__["default"]; + var addObserver = __dependency8__.addObserver; + var arrayComputed = __dependency9__.arrayComputed; + var reduceComputed = __dependency10__.reduceComputed; + var SubArray = __dependency11__["default"]; + var keys = __dependency12__["default"]; + var compare = __dependency13__["default"]; - var a_slice = [].slice, - forEach = EnumerableUtils.forEach, - SearchProxy; + var a_slice = [].slice; /** A computed property that returns the sum of the value @@ -13451,9 +27914,9 @@ define("ember-runtime/computed/reduce_computed_macros", return accumulatedValue - item; } }); - }; + } - /** + __exports__.sum = sum;/** A computed property that calculates the maximum value in the dependent array. This will return `-Infinity` when the dependent array is empty. @@ -13486,7 +27949,7 @@ define("ember-runtime/computed/reduce_computed_macros", @param {String} dependentKey @return {Ember.ComputedProperty} computes the largest value in the dependentKey's array */ - function max (dependentKey) { + function max(dependentKey) { return reduceComputed(dependentKey, { initialValue: -Infinity, @@ -13500,9 +27963,9 @@ define("ember-runtime/computed/reduce_computed_macros", } } }); - }; + } - /** + __exports__.max = max;/** A computed property that calculates the minimum value in the dependent array. This will return `Infinity` when the dependent array is empty. @@ -13549,23 +28012,24 @@ define("ember-runtime/computed/reduce_computed_macros", } } }); - }; + } - /** + __exports__.min = min;/** Returns an array mapped via the callback The callback method you provide should have the following signature. `item` is the current item in the iteration. + `index` is the integer index of the current item in the iteration. ```javascript - function(item); + function(item, index); ``` Example ```javascript var Hamster = Ember.Object.extend({ - excitingChores: Ember.computed.map('chores', function(chore) { + excitingChores: Ember.computed.map('chores', function(chore, index) { return chore.toUpperCase() + '!'; }) }); @@ -13586,7 +28050,7 @@ define("ember-runtime/computed/reduce_computed_macros", function map(dependentKey, callback) { var options = { addedItem: function(array, item, changeMeta, instanceMeta) { - var mapped = callback.call(this, item); + var mapped = callback.call(this, item, changeMeta.index); array.insertAt(changeMeta.index, mapped); return array; }, @@ -13597,9 +28061,9 @@ define("ember-runtime/computed/reduce_computed_macros", }; return arrayComputed(dependentKey, options); - }; + } - /** + __exports__.map = map;/** Returns an array mapped to the specified key. ```javascript @@ -13631,9 +28095,9 @@ define("ember-runtime/computed/reduce_computed_macros", function mapBy (dependentKey, propertyKey) { var callback = function(item) { return get(item, propertyKey); }; return map(dependentKey + '.@each.' + propertyKey, callback); - }; + } - /** + __exports__.mapBy = mapBy;/** @method computed.mapProperty @for Ember @deprecated Use `Ember.computed.mapBy` instead @@ -13641,30 +28105,31 @@ define("ember-runtime/computed/reduce_computed_macros", @param propertyKey */ var mapProperty = mapBy; - + __exports__.mapProperty = mapProperty; /** Filters the array by the callback. The callback method you provide should have the following signature. `item` is the current item in the iteration. + `index` is the integer index of the current item in the iteration. ```javascript - function(item); + function(item, index); ``` ```javascript var Hamster = Ember.Object.extend({ - remainingChores: Ember.computed.filter('chores', function(chore) { + remainingChores: Ember.computed.filter('chores', function(chore, index) { return !chore.done; }) }); - var hamster = Hamster.create({ + var hamster = Hamster.create({ chores: [ { name: 'cook', done: true }, { name: 'clean', done: true }, { name: 'write more unit tests', done: false } - ] + ] }); hamster.get('remainingChores'); // [{name: 'write more unit tests', done: false}] @@ -13682,9 +28147,9 @@ define("ember-runtime/computed/reduce_computed_macros", instanceMeta.filteredArrayIndexes = new SubArray(); }, - addedItem: function(array, item, changeMeta, instanceMeta) { - var match = !!callback.call(this, item), - filterIndex = instanceMeta.filteredArrayIndexes.addItem(changeMeta.index, match); + addedItem: function (array, item, changeMeta, instanceMeta) { + var match = !!callback.call(this, item, changeMeta.index); + var filterIndex = instanceMeta.filteredArrayIndexes.addItem(changeMeta.index, match); if (match) { array.insertAt(filterIndex, item); @@ -13705,9 +28170,9 @@ define("ember-runtime/computed/reduce_computed_macros", }; return arrayComputed(dependentKey, options); - }; + } - /** + __exports__.filter = filter;/** Filters the array by the property and value ```javascript @@ -13747,9 +28212,9 @@ define("ember-runtime/computed/reduce_computed_macros", } return filter(dependentKey + '.@each.' + propertyKey, callback); - }; + } - /** + __exports__.filterBy = filterBy;/** @method computed.filterProperty @for Ember @param dependentKey @@ -13758,7 +28223,7 @@ define("ember-runtime/computed/reduce_computed_macros", @deprecated Use `Ember.computed.filterBy` instead */ var filterProperty = filterBy; - + __exports__.filterProperty = filterProperty; /** A computed property which returns a new array with all the unique elements from one or more dependent arrays. @@ -13790,6 +28255,7 @@ define("ember-runtime/computed/reduce_computed_macros", */ function uniq() { var args = a_slice.call(arguments); + args.push({ initialize: function(array, changeMeta, instanceMeta) { instanceMeta.itemCounts = {}; @@ -13800,26 +28266,29 @@ define("ember-runtime/computed/reduce_computed_macros", if (!instanceMeta.itemCounts[guid]) { instanceMeta.itemCounts[guid] = 1; + array.pushObject(item); } else { ++instanceMeta.itemCounts[guid]; } - array.addObject(item); return array; }, + removedItem: function(array, item, _, instanceMeta) { - var guid = guidFor(item), - itemCounts = instanceMeta.itemCounts; + var guid = guidFor(item); + var itemCounts = instanceMeta.itemCounts; if (--itemCounts[guid] === 0) { array.removeObject(item); } + return array; } }); - return arrayComputed.apply(null, args); - }; - /** + return arrayComputed.apply(null, args); + } + + __exports__.uniq = uniq;/** Alias for [Ember.computed.uniq](/api/#method_computed_uniq). @method computed.union @@ -13829,7 +28298,7 @@ define("ember-runtime/computed/reduce_computed_macros", unique elements from the dependent array */ var union = uniq; - + __exports__.union = union; /** A computed property which returns a new array with all the duplicated elements from two or more dependent arrays. @@ -13853,44 +28322,46 @@ define("ember-runtime/computed/reduce_computed_macros", duplicated elements from the dependent arrays */ function intersect() { - var getDependentKeyGuids = function (changeMeta) { - return EnumerableUtils.map(changeMeta.property._dependentKeys, function (dependentKey) { - return guidFor(dependentKey); - }); - }; - var args = a_slice.call(arguments); + args.push({ initialize: function (array, changeMeta, instanceMeta) { instanceMeta.itemCounts = {}; }, addedItem: function(array, item, changeMeta, instanceMeta) { - var itemGuid = guidFor(item), - dependentGuids = getDependentKeyGuids(changeMeta), - dependentGuid = guidFor(changeMeta.arrayChanged), - numberOfDependentArrays = changeMeta.property._dependentKeys.length, - itemCounts = instanceMeta.itemCounts; + var itemGuid = guidFor(item); + var dependentGuid = guidFor(changeMeta.arrayChanged); + var numberOfDependentArrays = changeMeta.property._dependentKeys.length; + var itemCounts = instanceMeta.itemCounts; - if (!itemCounts[itemGuid]) { itemCounts[itemGuid] = {}; } - if (itemCounts[itemGuid][dependentGuid] === undefined) { itemCounts[itemGuid][dependentGuid] = 0; } + if (!itemCounts[itemGuid]) { + itemCounts[itemGuid] = {}; + } + + if (itemCounts[itemGuid][dependentGuid] === undefined) { + itemCounts[itemGuid][dependentGuid] = 0; + } if (++itemCounts[itemGuid][dependentGuid] === 1 && numberOfDependentArrays === keys(itemCounts[itemGuid]).length) { - array.addObject(item); } + return array; }, - removedItem: function(array, item, changeMeta, instanceMeta) { - var itemGuid = guidFor(item), - dependentGuids = getDependentKeyGuids(changeMeta), - dependentGuid = guidFor(changeMeta.arrayChanged), - numberOfDependentArrays = changeMeta.property._dependentKeys.length, - numberOfArraysItemAppearsIn, - itemCounts = instanceMeta.itemCounts; - if (itemCounts[itemGuid][dependentGuid] === undefined) { itemCounts[itemGuid][dependentGuid] = 0; } + removedItem: function(array, item, changeMeta, instanceMeta) { + var itemGuid = guidFor(item); + var dependentGuid = guidFor(changeMeta.arrayChanged); + var numberOfDependentArrays = changeMeta.property._dependentKeys.length; + var numberOfArraysItemAppearsIn; + var itemCounts = instanceMeta.itemCounts; + + if (itemCounts[itemGuid][dependentGuid] === undefined) { + itemCounts[itemGuid][dependentGuid] = 0; + } + if (--itemCounts[itemGuid][dependentGuid] === 0) { delete itemCounts[itemGuid][dependentGuid]; numberOfArraysItemAppearsIn = keys(itemCounts[itemGuid]).length; @@ -13898,15 +28369,18 @@ define("ember-runtime/computed/reduce_computed_macros", if (numberOfArraysItemAppearsIn === 0) { delete itemCounts[itemGuid]; } + array.removeObject(item); } + return array; } }); - return arrayComputed.apply(null, args); - }; - /** + return arrayComputed.apply(null, args); + } + + __exports__.intersect = intersect;/** A computed property which returns a new array with all the properties from the first dependent array that are not in the second dependent array. @@ -13939,12 +28413,13 @@ define("ember-runtime/computed/reduce_computed_macros", */ function setDiff(setAProperty, setBProperty) { if (arguments.length !== 2) { - throw new EmberError("setDiff requires exactly two dependent arrays."); + throw new EmberError('setDiff requires exactly two dependent arrays.'); } + return arrayComputed(setAProperty, setBProperty, { addedItem: function (array, item, changeMeta, instanceMeta) { - var setA = get(this, setAProperty), - setB = get(this, setBProperty); + var setA = get(this, setAProperty); + var setB = get(this, setBProperty); if (changeMeta.arrayChanged === setA) { if (!setB.contains(item)) { @@ -13953,12 +28428,13 @@ define("ember-runtime/computed/reduce_computed_macros", } else { array.removeObject(item); } + return array; }, removedItem: function (array, item, changeMeta, instanceMeta) { - var setA = get(this, setAProperty), - setB = get(this, setBProperty); + var setA = get(this, setAProperty); + var setB = get(this, setBProperty); if (changeMeta.arrayChanged === setB) { if (setA.contains(item)) { @@ -13967,16 +28443,22 @@ define("ember-runtime/computed/reduce_computed_macros", } else { array.removeObject(item); } + return array; } }); - }; + } - function binarySearch(array, item, low, high) { + __exports__.setDiff = setDiff;function binarySearch(array, item, low, high) { var mid, midItem, res, guidMid, guidItem; - if (arguments.length < 4) { high = get(array, 'length'); } - if (arguments.length < 3) { low = 0; } + if (arguments.length < 4) { + high = get(array, 'length'); + } + + if (arguments.length < 3) { + low = 0; + } if (low === high) { return low; @@ -13985,14 +28467,15 @@ define("ember-runtime/computed/reduce_computed_macros", mid = low + Math.floor((high - low) / 2); midItem = array.objectAt(mid); - guidMid = _guidFor(midItem); - guidItem = _guidFor(item); + guidMid = guidFor(midItem); + guidItem = guidFor(item); if (guidMid === guidItem) { return mid; } res = this.order(midItem, item); + if (res === 0) { res = guidMid < guidItem ? -1 : 1; } @@ -14005,18 +28488,9 @@ define("ember-runtime/computed/reduce_computed_macros", } return mid; - - function _guidFor(item) { - if (SearchProxy.detectInstance(item)) { - return guidFor(get(item, 'content')); - } - return guidFor(item); - } } - var SearchProxy = ObjectProxy.extend(); - /** A computed property which returns a new array with all the properties from the first dependent array sorted based on a property @@ -14059,7 +28533,7 @@ define("ember-runtime/computed/reduce_computed_macros", } return 0; - }), + }) }); var todoList = ToDoList.create({todos: [ @@ -14082,27 +28556,64 @@ define("ember-runtime/computed/reduce_computed_macros", on the sort property array or callback function */ function sort(itemsKey, sortDefinition) { - Ember.assert("Ember.computed.sort requires two arguments: an array key to sort and either a sort properties key or sort function", arguments.length === 2); - - var initFn, sortPropertiesKey; + Ember.assert('Ember.computed.sort requires two arguments: an array key to sort and ' + + 'either a sort properties key or sort function', arguments.length === 2); if (typeof sortDefinition === 'function') { - initFn = function (array, changeMeta, instanceMeta) { - instanceMeta.order = sortDefinition; - instanceMeta.binarySearch = binarySearch; - }; + return customSort(itemsKey, sortDefinition); } else { - sortPropertiesKey = sortDefinition; - initFn = function (array, changeMeta, instanceMeta) { - function setupSortProperties() { - var sortPropertyDefinitions = get(this, sortPropertiesKey), - sortProperty, - sortProperties = instanceMeta.sortProperties = [], - sortPropertyAscending = instanceMeta.sortPropertyAscending = {}, - idx, - asc; + return propertySort(itemsKey, sortDefinition); + } + } - Ember.assert("Cannot sort: '" + sortPropertiesKey + "' is not an array.", isArray(sortPropertyDefinitions)); + __exports__.sort = sort;function customSort(itemsKey, comparator) { + return arrayComputed(itemsKey, { + initialize: function (array, changeMeta, instanceMeta) { + instanceMeta.order = comparator; + instanceMeta.binarySearch = binarySearch; + instanceMeta.waitingInsertions = []; + instanceMeta.insertWaiting = function() { + var index, item; + var waiting = instanceMeta.waitingInsertions; + instanceMeta.waitingInsertions = []; + for (var i=0; i{{post.title}} ({{post.titleLength}} characters) - {{/each}} + {{#each post in controller}} +
  • {{post.title}} ({{post.titleLength}} characters)
  • + {{/each}} ``` ```javascript @@ -14275,7 +28780,6 @@ define("ember-runtime/controllers/array_controller", App.PostController = Ember.ObjectController.extend({ // the `title` property will be proxied to the underlying post. - titleLength: function() { return this.get('title').length; }.property('title') @@ -14310,13 +28814,25 @@ define("ember-runtime/controllers/array_controller", @uses Ember.ControllerMixin */ - var ArrayController = ArrayProxy.extend(ControllerMixin, SortableMixin, { + __exports__["default"] = ArrayProxy.extend(ControllerMixin, SortableMixin, { /** - The controller used to wrap items, if any. + The controller used to wrap items, if any. If the value is a string, it will + be used to lookup the container for the controller. As an alternative, you + can also provide a controller class as the value. + + For example: + + ```javascript + App.MyArrayController = Ember.ArrayController.extend({ + itemController: Ember.ObjectController.extend({ + //Item Controller Implementation + }) + }); + ``` @property itemController - @type String + @type String | Ember.Controller @default null */ itemController: null, @@ -14350,12 +28866,14 @@ define("ember-runtime/controllers/array_controller", }, objectAtContent: function(idx) { - var length = get(this, 'length'), - arrangedContent = get(this,'arrangedContent'), - object = arrangedContent && arrangedContent.objectAt(idx); + var length = get(this, 'length'); + var arrangedContent = get(this, 'arrangedContent'); + var object = arrangedContent && arrangedContent.objectAt(idx); + var controllerClass; if (idx >= 0 && idx < length) { - var controllerClass = this.lookupItemController(object); + controllerClass = this.lookupItemController(object); + if (controllerClass) { return this.controllerAt(idx, object, controllerClass); } @@ -14376,14 +28894,19 @@ define("ember-runtime/controllers/array_controller", }, arrayContentDidChange: function(idx, removedCnt, addedCnt) { - var subControllers = get(this, '_subControllers'), - subControllersToRemove = subControllers.slice(idx, idx+removedCnt); + var subControllers = this._subControllers; - forEach(subControllersToRemove, function(subController) { - if (subController) { subController.destroy(); } - }); + if (subControllers.length) { + var subControllersToRemove = subControllers.slice(idx, idx + removedCnt); - replace(subControllers, idx, removedCnt, new Array(addedCnt)); + forEach(subControllersToRemove, function(subController) { + if (subController) { + subController.destroy(); + } + }); + + replace(subControllers, idx, removedCnt, new Array(addedCnt)); + } // The shadow array of subcontrollers must be updated before we trigger // observers, otherwise observers will get the wrong subcontainer when @@ -14393,11 +28916,10 @@ define("ember-runtime/controllers/array_controller", init: function() { this._super(); - - this.set('_subControllers', [ ]); + this._subControllers = []; }, - content: computed(function () { + model: computed(function () { return Ember.A(); }), @@ -14412,28 +28934,37 @@ define("ember-runtime/controllers/array_controller", _isVirtual: false, controllerAt: function(idx, object, controllerClass) { - var container = get(this, 'container'), - subControllers = get(this, '_subControllers'), - subController = subControllers[idx], - fullName; + var container = get(this, 'container'); + var subControllers = this._subControllers; + var fullName, subController, subControllerFactory, parentController, options; - if (subController) { return subController; } + if (subControllers.length > idx) { + subController = subControllers[idx]; - fullName = "controller:" + controllerClass; - - if (!container.has(fullName)) { - throw new EmberError('Could not resolve itemController: "' + controllerClass + '"'); + if (subController) { + return subController; + } } - var parentController; + if (this._isVirtual) { parentController = get(this, 'parentController'); + } else { + parentController = this; } - parentController = parentController || this; - subController = container.lookupFactory(fullName).create({ - target: this, - parentController: parentController, - content: object - }); + + + fullName = 'controller:' + controllerClass; + + if (!container.has(fullName)) { + throw new EmberError('Could not resolve itemController: "' + controllerClass + '"'); + } + + subController = container.lookupFactory(fullName).create({ + target: parentController, + parentController: parentController, + model: object + }); + subControllers[idx] = subController; @@ -14443,12 +28974,13 @@ define("ember-runtime/controllers/array_controller", _subControllers: null, _resetSubControllers: function() { - var subControllers = get(this, '_subControllers'); var controller; + var subControllers = this._subControllers; if (subControllers.length) { for (var i = 0, length = subControllers.length; length > i; i++) { controller = subControllers[i]; + if (controller) { controller.destroy(); } @@ -14463,96 +28995,32 @@ define("ember-runtime/controllers/array_controller", this._super(); } }); - - __exports__["default"] = ArrayController; }); -define("ember-runtime/controllers/controller", - ["ember-metal/core","ember-metal/property_get","ember-runtime/system/object","ember-metal/mixin","ember-metal/computed","ember-runtime/mixins/action_handler","exports"], - function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __exports__) { +enifed("ember-runtime/controllers/controller", + ["ember-runtime/system/object","ember-runtime/mixins/controller","exports"], + function(__dependency1__, __dependency2__, __exports__) { "use strict"; - var Ember = __dependency1__["default"]; - // Ember.assert, Ember.deprecate - var get = __dependency2__.get; - var EmberObject = __dependency3__["default"]; - var Mixin = __dependency4__.Mixin; - var computed = __dependency5__.computed; - var ActionHandler = __dependency6__["default"]; + var EmberObject = __dependency1__["default"]; + var Mixin = __dependency2__["default"]; /** @module ember @submodule ember-runtime */ - /** - `Ember.ControllerMixin` provides a standard interface for all classes that - compose Ember's controller layer: `Ember.Controller`, - `Ember.ArrayController`, and `Ember.ObjectController`. - - @class ControllerMixin - @namespace Ember - @uses Ember.ActionHandler - */ - var ControllerMixin = Mixin.create(ActionHandler, { - /* ducktype as a controller */ - isController: true, - - /** - The object to which actions from the view should be sent. - - For example, when a Handlebars template uses the `{{action}}` helper, - it will attempt to send the action to the view's controller's `target`. - - By default, the value of the target property is set to the router, and - is injected when a controller is instantiated. This injection is defined - in Ember.Application#buildContainer, and is applied as part of the - applications initialization process. It can also be set after a controller - has been instantiated, for instance when using the render helper in a - template, or when a controller is used as an `itemController`. In most - cases the `target` property will automatically be set to the logical - consumer of actions for the controller. - - @property target - @default null - */ - target: null, - - container: null, - - parentController: null, - - store: null, - - model: computed.alias('content'), - - deprecatedSendHandles: function(actionName) { - return !!this[actionName]; - }, - - deprecatedSend: function(actionName) { - var args = [].slice.call(arguments, 1); - Ember.assert('' + this + " has the action " + actionName + " but it is not a function", typeof this[actionName] === 'function'); - Ember.deprecate('Action handlers implemented directly on controllers are deprecated in favor of action handlers on an `actions` object ( action: `' + actionName + '` on ' + this + ')', false); - this[actionName].apply(this, args); - return; - } - }); - /** @class Controller @namespace Ember @extends Ember.Object @uses Ember.ControllerMixin */ - var Controller = EmberObject.extend(ControllerMixin); - - __exports__.Controller = Controller; - __exports__.ControllerMixin = ControllerMixin; + __exports__["default"] = EmberObject.extend(Mixin); }); -define("ember-runtime/controllers/object_controller", - ["ember-runtime/controllers/controller","ember-runtime/system/object_proxy","exports"], +enifed("ember-runtime/controllers/object_controller", + ["ember-runtime/mixins/controller","ember-runtime/system/object_proxy","exports"], function(__dependency1__, __dependency2__, __exports__) { "use strict"; - var ControllerMixin = __dependency1__.ControllerMixin; + var ControllerMixin = __dependency1__["default"]; var ObjectProxy = __dependency2__["default"]; /** @@ -14563,7 +29031,7 @@ define("ember-runtime/controllers/object_controller", /** `Ember.ObjectController` is part of Ember's Controller layer. It is intended to wrap a single object, proxying unhandled attempts to `get` and `set` to the underlying - content object, and to forward unhandled action attempts to its `target`. + model object, and to forward unhandled action attempts to its `target`. `Ember.ObjectController` derives this functionality from its superclass `Ember.ObjectProxy` and the `Ember.ControllerMixin` mixin. @@ -14573,39 +29041,44 @@ define("ember-runtime/controllers/object_controller", @extends Ember.ObjectProxy @uses Ember.ControllerMixin **/ - var ObjectController = ObjectProxy.extend(ControllerMixin); - __exports__["default"] = ObjectController; + __exports__["default"] = ObjectProxy.extend(ControllerMixin); }); -define("ember-runtime/copy", - ["ember-metal/enumerable_utils","ember-metal/utils","ember-runtime/system/object","ember-runtime/mixins/copyable","ember-metal/platform","exports"], - function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __exports__) { +enifed("ember-runtime/copy", + ["ember-metal/enumerable_utils","ember-metal/utils","ember-runtime/system/object","ember-runtime/mixins/copyable","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __exports__) { "use strict"; - var EnumerableUtils = __dependency1__["default"]; + var indexOf = __dependency1__.indexOf; var typeOf = __dependency2__.typeOf; var EmberObject = __dependency3__["default"]; var Copyable = __dependency4__["default"]; - var create = __dependency5__.create; - - var indexOf = EnumerableUtils.indexOf; function _copy(obj, deep, seen, copies) { var ret, loc, key; // primitive data types are immutable, just return them. - if ('object' !== typeof obj || obj===null) return obj; + if (typeof obj !== 'object' || obj === null) { + return obj; + } // avoid cyclical loops - if (deep && (loc=indexOf(seen, obj))>=0) return copies[loc]; + if (deep && (loc = indexOf(seen, obj)) >= 0) { + return copies[loc]; + } - Ember.assert('Cannot clone an Ember.Object that does not implement Ember.Copyable', !(obj instanceof EmberObject) || (Copyable && Copyable.detect(obj))); + Ember.assert('Cannot clone an Ember.Object that does not implement Ember.Copyable', + !(obj instanceof EmberObject) || (Copyable && Copyable.detect(obj))); // IMPORTANT: this specific test will detect a native array only. Any other // object will need to implement Copyable. if (typeOf(obj) === 'array') { ret = obj.slice(); + if (deep) { loc = ret.length; - while(--loc>=0) ret[loc] = _copy(ret[loc], deep, seen, copies); + + while (--loc >= 0) { + ret[loc] = _copy(ret[loc], deep, seen, copies); + } } } else if (Copyable && Copyable.detect(obj)) { ret = obj.copy(deep, seen, copies); @@ -14613,12 +29086,18 @@ define("ember-runtime/copy", ret = new Date(obj.getTime()); } else { ret = {}; - for(key in obj) { - if (!obj.hasOwnProperty(key)) continue; + + for (key in obj) { + // support Null prototype + if (!Object.prototype.hasOwnProperty.call(obj, key)) { + continue; + } // Prevents browsers that don't respect non-enumerability from // copying internal Ember properties - if (key.substring(0,2) === '__') continue; + if (key.substring(0, 2) === '__') { + continue; + } ret[key] = deep ? _copy(obj[key], deep, seen, copies) : obj[key]; } @@ -14646,16 +29125,20 @@ define("ember-runtime/copy", @param {Boolean} deep If true, a deep copy of the object is made @return {Object} The cloned object */ - function copy(obj, deep) { + __exports__["default"] = function copy(obj, deep) { // fast paths - if ('object' !== typeof obj || obj===null) return obj; // can't copy primitives - if (Copyable && Copyable.detect(obj)) return obj.copy(deep); - return _copy(obj, deep, deep ? [] : null, deep ? [] : null); - }; + if ('object' !== typeof obj || obj === null) { + return obj; // can't copy primitives + } - __exports__["default"] = copy; + if (Copyable && Copyable.detect(obj)) { + return obj.copy(deep); + } + + return _copy(obj, deep, deep ? [] : null, deep ? [] : null); + } }); -define("ember-runtime/core", +enifed("ember-runtime/core", ["exports"], function(__exports__) { "use strict"; @@ -14682,19 +29165,22 @@ define("ember-runtime/core", @param {Object} b second object to compare @return {Boolean} */ - function isEqual(a, b) { - if (a && 'function'===typeof a.isEqual) return a.isEqual(b); + var isEqual = function isEqual(a, b) { + if (a && typeof a.isEqual === 'function') { + return a.isEqual(b); + } + if (a instanceof Date && b instanceof Date) { return a.getTime() === b.getTime(); - } + } + return a === b; }; - __exports__.isEqual = isEqual; }); -define("ember-runtime/ext/function", - ["ember-metal/core","ember-metal/expand_properties","ember-metal/computed"], - function(__dependency1__, __dependency2__, __dependency3__) { +enifed("ember-runtime/ext/function", + ["ember-metal/core","ember-metal/expand_properties","ember-metal/computed","ember-metal/mixin"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__) { "use strict"; /** @module ember @@ -14705,6 +29191,7 @@ define("ember-runtime/ext/function", // Ember.EXTEND_PROTOTYPES, Ember.assert var expandProperties = __dependency2__["default"]; var computed = __dependency3__.computed; + var observer = __dependency4__.observer; var a_slice = Array.prototype.slice; var FunctionPrototype = Function.prototype; @@ -14725,17 +29212,15 @@ define("ember-runtime/ext/function", fullName: function() { return this.get('firstName') + ' ' + this.get('lastName'); - - // Call this flag to mark the function as a property - }.property() + }.property() // Call this flag to mark the function as a property }); var president = MyApp.President.create({ - firstName: "Barack", - lastName: "Obama" + firstName: 'Barack', + lastName: 'Obama' }); - president.get('fullName'); // "Barack Obama" + president.get('fullName'); // 'Barack Obama' ``` Treating a function like a property is useful because they can work with @@ -14771,7 +29256,7 @@ define("ember-runtime/ext/function", @method property @for Function */ - FunctionPrototype.property = function() { + FunctionPrototype.property = function () { var ret = computed(this); // ComputedProperty.prototype.property expands properties; no need for us to // do so here. @@ -14804,16 +29289,12 @@ define("ember-runtime/ext/function", @for Function */ FunctionPrototype.observes = function() { - var addWatchedProperty = function (obs) { watched.push(obs); }; - var watched = []; - - for (var i=0; i= 0) return; - if (typeof obj.hasOwnProperty === 'function' && !obj.hasOwnProperty(key)) return; - - array.push(key); - }; - - keys = function keys(obj) { - var ret = [], key; - for (key in obj) { - pushPropertyName(obj, ret, key); - } - - // IE8 doesn't enumerate property that named the same as prototype properties. - for (var i = 0, l = prototypeProperties.length; i < l; i++) { - key = prototypeProperties[i]; - - pushPropertyName(obj, ret, key); - } - - return ret; - }; - } - - __exports__["default"] = keys; - }); -define("ember-runtime", - ["ember-metal","ember-runtime/core","ember-runtime/keys","ember-runtime/compare","ember-runtime/copy","ember-runtime/system/namespace","ember-runtime/system/object","ember-runtime/system/tracked_array","ember-runtime/system/subarray","ember-runtime/system/container","ember-runtime/system/application","ember-runtime/system/array_proxy","ember-runtime/system/object_proxy","ember-runtime/system/core_object","ember-runtime/system/each_proxy","ember-runtime/system/native_array","ember-runtime/system/set","ember-runtime/system/string","ember-runtime/system/deferred","ember-runtime/system/lazy_load","ember-runtime/mixins/array","ember-runtime/mixins/comparable","ember-runtime/mixins/copyable","ember-runtime/mixins/enumerable","ember-runtime/mixins/freezable","ember-runtime/mixins/observable","ember-runtime/mixins/action_handler","ember-runtime/mixins/deferred","ember-runtime/mixins/mutable_enumerable","ember-runtime/mixins/mutable_array","ember-runtime/mixins/target_action_support","ember-runtime/mixins/evented","ember-runtime/mixins/promise_proxy","ember-runtime/mixins/sortable","ember-runtime/computed/array_computed","ember-runtime/computed/reduce_computed","ember-runtime/computed/reduce_computed_macros","ember-runtime/controllers/array_controller","ember-runtime/controllers/object_controller","ember-runtime/controllers/controller","ember-runtime/ext/rsvp","ember-runtime/ext/string","ember-runtime/ext/function","exports"], - function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __dependency9__, __dependency10__, __dependency11__, __dependency12__, __dependency13__, __dependency14__, __dependency15__, __dependency16__, __dependency17__, __dependency18__, __dependency19__, __dependency20__, __dependency21__, __dependency22__, __dependency23__, __dependency24__, __dependency25__, __dependency26__, __dependency27__, __dependency28__, __dependency29__, __dependency30__, __dependency31__, __dependency32__, __dependency33__, __dependency34__, __dependency35__, __dependency36__, __dependency37__, __dependency38__, __dependency39__, __dependency40__, __dependency41__, __dependency42__, __dependency43__, __exports__) { +enifed("ember-runtime/mixins/-proxy", + ["ember-metal/core","ember-metal/property_get","ember-metal/property_set","ember-metal/utils","ember-metal/observer","ember-metal/property_events","ember-metal/computed","ember-metal/properties","ember-metal/mixin","ember-runtime/system/string","ember-runtime/system/object","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __dependency9__, __dependency10__, __dependency11__, __exports__) { "use strict"; /** - Ember Runtime - @module ember @submodule ember-runtime - @requires ember-metal */ + var Ember = __dependency1__["default"]; + // Ember.assert + var get = __dependency2__.get; + var set = __dependency3__.set; + var meta = __dependency4__.meta; + var addObserver = __dependency5__.addObserver; + var removeObserver = __dependency5__.removeObserver; + var addBeforeObserver = __dependency5__.addBeforeObserver; + var removeBeforeObserver = __dependency5__.removeBeforeObserver; + var propertyWillChange = __dependency6__.propertyWillChange; + var propertyDidChange = __dependency6__.propertyDidChange; + var computed = __dependency7__.computed; + var defineProperty = __dependency8__.defineProperty; + var Mixin = __dependency9__.Mixin; + var observer = __dependency9__.observer; + var fmt = __dependency10__.fmt; + var EmberObject = __dependency11__["default"]; - // BEGIN EXPORTS - Ember.compare = __dependency4__["default"]; - Ember.copy = __dependency5__["default"]; - Ember.isEqual = __dependency2__.isEqual; - Ember.keys = __dependency3__["default"]; + function contentPropertyWillChange(content, contentKey) { + var key = contentKey.slice(8); // remove "content." + if (key in this) { return; } // if shadowed in proxy + propertyWillChange(this, key); + } - Ember.Array = __dependency21__["default"]; + function contentPropertyDidChange(content, contentKey) { + var key = contentKey.slice(8); // remove "content." + if (key in this) { return; } // if shadowed in proxy + propertyDidChange(this, key); + } - Ember.Comparable = __dependency22__["default"]; - Ember.Copyable = __dependency23__["default"]; + /** + `Ember.ProxyMixin` forwards all properties not defined by the proxy itself + to a proxied `content` object. See Ember.ObjectProxy for more details. - Ember.SortableMixin = __dependency34__["default"]; + @class ProxyMixin + @namespace Ember + */ + __exports__["default"] = Mixin.create({ + /** + The object whose properties will be forwarded. - Ember.Freezable = __dependency25__.Freezable; - Ember.FROZEN_ERROR = __dependency25__.FROZEN_ERROR; + @property content + @type Ember.Object + @default null + */ + content: null, + _contentDidChange: observer('content', function() { + Ember.assert("Can't set Proxy's content to itself", get(this, 'content') !== this); + }), - Ember.DeferredMixin = __dependency28__["default"]; + isTruthy: computed.bool('content'), - Ember.MutableEnumerable = __dependency29__["default"]; - Ember.MutableArray = __dependency30__["default"]; + _debugContainerKey: null, - Ember.TargetActionSupport = __dependency31__["default"]; - Ember.Evented = __dependency32__["default"]; + willWatchProperty: function (key) { + var contentKey = 'content.' + key; + addBeforeObserver(this, contentKey, null, contentPropertyWillChange); + addObserver(this, contentKey, null, contentPropertyDidChange); + }, - Ember.PromiseProxyMixin = __dependency33__["default"]; + didUnwatchProperty: function (key) { + var contentKey = 'content.' + key; + removeBeforeObserver(this, contentKey, null, contentPropertyWillChange); + removeObserver(this, contentKey, null, contentPropertyDidChange); + }, - Ember.Observable = __dependency26__["default"]; + unknownProperty: function (key) { + var content = get(this, 'content'); + if (content) { + return get(content, key); + } + }, - Ember.arrayComputed = __dependency35__.arrayComputed; - Ember.ArrayComputedProperty = __dependency35__.ArrayComputedProperty; - Ember.reduceComputed = __dependency36__.reduceComputed; - Ember.ReduceComputedProperty = __dependency36__.ReduceComputedProperty; + setUnknownProperty: function (key, value) { + var m = meta(this); + if (m.proto === this) { + // if marked as prototype then just defineProperty + // rather than delegate + defineProperty(this, key, null, value); + return value; + } - // ES6TODO: this seems a less than ideal way/place to add properties to Ember.computed - var EmComputed = Ember.computed; + var content = get(this, 'content'); + Ember.assert(fmt("Cannot delegate set('%@', %@) to the 'content' property of object proxy %@: its 'content' is undefined.", [key, value, this]), content); + return set(content, key, value); + } - EmComputed.sum = __dependency37__.sum; - EmComputed.min = __dependency37__.min; - EmComputed.max = __dependency37__.max; - EmComputed.map = __dependency37__.map; - EmComputed.sort = __dependency37__.sort; - EmComputed.setDiff = __dependency37__.setDiff; - EmComputed.mapBy = __dependency37__.mapBy; - EmComputed.mapProperty = __dependency37__.mapProperty; - EmComputed.filter = __dependency37__.filter; - EmComputed.filterBy = __dependency37__.filterBy; - EmComputed.filterProperty = __dependency37__.filterProperty; - EmComputed.uniq = __dependency37__.uniq; - EmComputed.union = __dependency37__.union; - EmComputed.intersect = __dependency37__.intersect; - - Ember.String = __dependency18__["default"]; - Ember.Object = __dependency7__["default"]; - Ember.TrackedArray = __dependency8__["default"]; - Ember.SubArray = __dependency9__["default"]; - Ember.Container = __dependency10__["default"]; - Ember.Namespace = __dependency6__["default"]; - Ember.Application = __dependency11__["default"]; - Ember.Enumerable = __dependency24__["default"]; - Ember.ArrayProxy = __dependency12__["default"]; - Ember.ObjectProxy = __dependency13__["default"]; - Ember.ActionHandler = __dependency27__["default"]; - Ember.CoreObject = __dependency14__["default"]; - Ember.EachArray = __dependency15__.EachArray; - Ember.EachProxy = __dependency15__.EachProxy; - Ember.NativeArray = __dependency16__["default"]; - // ES6TODO: Currently we must rely on the global from ember-metal/core to avoid circular deps - // Ember.A = A; - Ember.Set = __dependency17__["default"]; - Ember.Deferred = __dependency19__["default"]; - Ember.onLoad = __dependency20__.onLoad; - Ember.runLoadHooks = __dependency20__.runLoadHooks; - - Ember.ArrayController = __dependency38__["default"]; - Ember.ObjectController = __dependency39__["default"]; - Ember.Controller = __dependency40__.Controller; - Ember.ControllerMixin = __dependency40__.ControllerMixin; - - Ember.RSVP = __dependency41__["default"]; - // END EXPORTS - - __exports__["default"] = Ember; + }); }); -define("ember-runtime/mixins/action_handler", +enifed("ember-runtime/mixins/action_handler", ["ember-metal/merge","ember-metal/mixin","ember-metal/property_get","ember-metal/utils","exports"], function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __exports__) { "use strict"; @@ -15429,7 +29891,8 @@ define("ember-runtime/mixins/action_handler", @param {*} context a context to send with the action */ send: function(actionName) { - var args = [].slice.call(arguments, 1), target; + var args = [].slice.call(arguments, 1); + var target; if (this._actions && this._actions[actionName]) { if (this._actions[actionName].apply(this, args) === true) { @@ -15437,13 +29900,6 @@ define("ember-runtime/mixins/action_handler", } else { return; } - } else if (!Ember.FEATURES.isEnabled('ember-routing-drop-deprecated-action-style') && this.deprecatedSend && this.deprecatedSendHandles && this.deprecatedSendHandles(actionName)) { - Ember.warn("The current default is deprecated but will prefer to handle actions directly on the controller instead of a similarly named action in the actions hash. To turn off this deprecated feature set: Ember.FEATURES['ember-routing-drop-deprecated-action-style'] = true"); - if (this.deprecatedSend.apply(this, [].slice.call(arguments)) === true) { - // handler return true, so this action will bubble - } else { - return; - } } if (target = get(this, 'target')) { @@ -15455,9 +29911,9 @@ define("ember-runtime/mixins/action_handler", __exports__["default"] = ActionHandler; }); -define("ember-runtime/mixins/array", - ["ember-metal/core","ember-metal/property_get","ember-metal/property_set","ember-metal/computed","ember-metal/is_none","ember-runtime/mixins/enumerable","ember-metal/enumerable_utils","ember-metal/mixin","ember-metal/property_events","ember-metal/events","ember-metal/watching","exports"], - function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __dependency9__, __dependency10__, __dependency11__, __exports__) { +enifed("ember-runtime/mixins/array", + ["ember-metal/core","ember-metal/property_get","ember-metal/computed","ember-metal/is_none","ember-runtime/mixins/enumerable","ember-metal/enumerable_utils","ember-metal/mixin","ember-metal/property_events","ember-metal/events","ember-metal/watching","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __dependency9__, __dependency10__, __exports__) { "use strict"; /** @module ember @@ -15469,26 +29925,41 @@ define("ember-runtime/mixins/array", // var Ember = __dependency1__["default"]; // ES6TODO: Ember.A - var get = __dependency2__.get; - var set = __dependency3__.set; - var computed = __dependency4__.computed; - var cacheFor = __dependency4__.cacheFor; - var isNone = __dependency5__.isNone; - var none = __dependency5__.none; - var Enumerable = __dependency6__["default"]; - var EnumerableUtils = __dependency7__["default"]; - var Mixin = __dependency8__.Mixin; - var required = __dependency8__.required; - var propertyWillChange = __dependency9__.propertyWillChange; - var propertyDidChange = __dependency9__.propertyDidChange; - var addListener = __dependency10__.addListener; - var removeListener = __dependency10__.removeListener; - var sendEvent = __dependency10__.sendEvent; - var hasListeners = __dependency10__.hasListeners; - var isWatching = __dependency11__.isWatching; + var computed = __dependency3__.computed; + var cacheFor = __dependency3__.cacheFor; + var isNone = __dependency4__.isNone; + var none = __dependency4__.none; + var Enumerable = __dependency5__["default"]; + var map = __dependency6__.map; + var Mixin = __dependency7__.Mixin; + var required = __dependency7__.required; + var propertyWillChange = __dependency8__.propertyWillChange; + var propertyDidChange = __dependency8__.propertyDidChange; + var addListener = __dependency9__.addListener; + var removeListener = __dependency9__.removeListener; + var sendEvent = __dependency9__.sendEvent; + var hasListeners = __dependency9__.hasListeners; + var isWatching = __dependency10__.isWatching; - var map = EnumerableUtils.map; + function arrayObserversHelper(obj, target, opts, operation, notify) { + var willChange = (opts && opts.willChange) || 'arrayWillChange'; + var didChange = (opts && opts.didChange) || 'arrayDidChange'; + var hasObservers = get(obj, 'hasArrayObservers'); + + if (hasObservers === notify) { + propertyWillChange(obj, 'hasArrayObservers'); + } + + operation(obj, '@array:before', target, willChange); + operation(obj, '@array:change', target, didChange); + + if (hasObservers === notify) { + propertyDidChange(obj, 'hasArrayObservers'); + } + + return obj; + } // .......................................................... // ARRAY @@ -15529,7 +30000,7 @@ define("ember-runtime/mixins/array", @uses Ember.Enumerable @since Ember 0.9.0 */ - var EmberArray = Mixin.create(Enumerable, { + __exports__["default"] = Mixin.create(Enumerable, { /** Your array must support the `length` property. Your replace methods should @@ -15550,8 +30021,9 @@ define("ember-runtime/mixins/array", ```javascript var arr = ['a', 'b', 'c', 'd']; - arr.objectAt(0); // "a" - arr.objectAt(3); // "d" + + arr.objectAt(0); // 'a' + arr.objectAt(3); // 'd' arr.objectAt(-1); // undefined arr.objectAt(4); // undefined arr.objectAt(5); // undefined @@ -15562,7 +30034,10 @@ define("ember-runtime/mixins/array", @return {*} item at index or undefined */ objectAt: function(idx) { - if ((idx < 0) || (idx >= get(this, 'length'))) return undefined; + if (idx < 0 || idx >= get(this, 'length')) { + return undefined; + } + return get(this, idx); }, @@ -15571,8 +30046,9 @@ define("ember-runtime/mixins/array", ```javascript var arr = ['a', 'b', 'c', 'd']; - arr.objectsAt([0, 1, 2]); // ["a", "b", "c"] - arr.objectsAt([2, 3, 4]); // ["c", "d", undefined] + + arr.objectsAt([0, 1, 2]); // ['a', 'b', 'c'] + arr.objectsAt([2, 3, 4]); // ['c', 'd', undefined] ``` @method objectsAt @@ -15581,7 +30057,10 @@ define("ember-runtime/mixins/array", */ objectsAt: function(indexes) { var self = this; - return map(indexes, function(idx) { return self.objectAt(idx); }); + + return map(indexes, function(idx) { + return self.objectAt(idx); + }); }, // overrides Ember.Enumerable version @@ -15591,7 +30070,7 @@ define("ember-runtime/mixins/array", /** This is the handler for the special array content property. If you get - this property, it will return this. If you set this property it a new + this property, it will return this. If you set this property to a new array, it will replace the current content. This property overrides the default property defined in `Ember.Enumerable`. @@ -15600,8 +30079,11 @@ define("ember-runtime/mixins/array", @return this */ '[]': computed(function(key, value) { - if (value !== undefined) this.replace(0, get(this, 'length'), value) ; - return this ; + if (value !== undefined) { + this.replace(0, get(this, 'length'), value); + } + + return this; }), firstObject: computed(function() { @@ -15609,7 +30091,7 @@ define("ember-runtime/mixins/array", }), lastObject: computed(function() { - return this.objectAt(get(this, 'length')-1); + return this.objectAt(get(this, 'length') - 1); }), // optimized version from Enumerable @@ -15625,6 +30107,7 @@ define("ember-runtime/mixins/array", ```javascript var arr = ['red', 'green', 'blue']; + arr.slice(0); // ['red', 'green', 'blue'] arr.slice(0, 2); // ['red', 'green'] arr.slice(1, 100); // ['green', 'blue'] @@ -15637,17 +30120,29 @@ define("ember-runtime/mixins/array", */ slice: function(beginIndex, endIndex) { var ret = Ember.A(); - var length = get(this, 'length') ; - if (isNone(beginIndex)) beginIndex = 0 ; - if (isNone(endIndex) || (endIndex > length)) endIndex = length ; + var length = get(this, 'length'); - if (beginIndex < 0) beginIndex = length + beginIndex; - if (endIndex < 0) endIndex = length + endIndex; - - while(beginIndex < endIndex) { - ret[ret.length] = this.objectAt(beginIndex++) ; + if (isNone(beginIndex)) { + beginIndex = 0; } - return ret ; + + if (isNone(endIndex) || (endIndex > length)) { + endIndex = length; + } + + if (beginIndex < 0) { + beginIndex = length + beginIndex; + } + + if (endIndex < 0) { + endIndex = length + endIndex; + } + + while (beginIndex < endIndex) { + ret[ret.length] = this.objectAt(beginIndex++); + } + + return ret; }, /** @@ -15657,13 +30152,14 @@ define("ember-runtime/mixins/array", the end of the array. Returns -1 if no match is found. ```javascript - var arr = ["a", "b", "c", "d", "a"]; - arr.indexOf("a"); // 0 - arr.indexOf("z"); // -1 - arr.indexOf("a", 2); // 4 - arr.indexOf("a", -1); // 4 - arr.indexOf("b", 3); // -1 - arr.indexOf("a", 100); // -1 + var arr = ['a', 'b', 'c', 'd', 'a']; + + arr.indexOf('a'); // 0 + arr.indexOf('z'); // -1 + arr.indexOf('a', 2); // 4 + arr.indexOf('a', -1); // 4 + arr.indexOf('b', 3); // -1 + arr.indexOf('a', 100); // -1 ``` @method indexOf @@ -15672,14 +30168,23 @@ define("ember-runtime/mixins/array", @return {Number} index or -1 if not found */ indexOf: function(object, startAt) { - var idx, len = get(this, 'length'); + var len = get(this, 'length'); + var idx; - if (startAt === undefined) startAt = 0; - if (startAt < 0) startAt += len; - - for(idx = startAt; idx < len; idx++) { - if (this.objectAt(idx) === object) return idx; + if (startAt === undefined) { + startAt = 0; } + + if (startAt < 0) { + startAt += len; + } + + for (idx = startAt; idx < len; idx++) { + if (this.objectAt(idx) === object) { + return idx; + } + } + return -1; }, @@ -15690,13 +30195,14 @@ define("ember-runtime/mixins/array", from the end of the array. Returns -1 if no match is found. ```javascript - var arr = ["a", "b", "c", "d", "a"]; - arr.lastIndexOf("a"); // 4 - arr.lastIndexOf("z"); // -1 - arr.lastIndexOf("a", 2); // 0 - arr.lastIndexOf("a", -1); // 4 - arr.lastIndexOf("b", 3); // 1 - arr.lastIndexOf("a", 100); // 4 + var arr = ['a', 'b', 'c', 'd', 'a']; + + arr.lastIndexOf('a'); // 4 + arr.lastIndexOf('z'); // -1 + arr.lastIndexOf('a', 2); // 0 + arr.lastIndexOf('a', -1); // 4 + arr.lastIndexOf('b', 3); // 1 + arr.lastIndexOf('a', 100); // 4 ``` @method lastIndexOf @@ -15705,14 +30211,23 @@ define("ember-runtime/mixins/array", @return {Number} index or -1 if not found */ lastIndexOf: function(object, startAt) { - var idx, len = get(this, 'length'); + var len = get(this, 'length'); + var idx; - if (startAt === undefined || startAt >= len) startAt = len-1; - if (startAt < 0) startAt += len; - - for(idx = startAt; idx >= 0; idx--) { - if (this.objectAt(idx) === object) return idx; + if (startAt === undefined || startAt >= len) { + startAt = len-1; } + + if (startAt < 0) { + startAt += len; + } + + for (idx = startAt; idx >= 0; idx--) { + if (this.objectAt(idx) === object) { + return idx; + } + } + return -1; }, @@ -15744,16 +30259,9 @@ define("ember-runtime/mixins/array", `willChange` and `didChange` option. @return {Ember.Array} receiver */ - addArrayObserver: function(target, opts) { - var willChange = (opts && opts.willChange) || 'arrayWillChange', - didChange = (opts && opts.didChange) || 'arrayDidChange'; - var hasObservers = get(this, 'hasArrayObservers'); - if (!hasObservers) propertyWillChange(this, 'hasArrayObservers'); - addListener(this, '@array:before', target, willChange); - addListener(this, '@array:change', target, didChange); - if (!hasObservers) propertyDidChange(this, 'hasArrayObservers'); - return this; + addArrayObserver: function(target, opts) { + return arrayObserversHelper(this, target, opts, addListener, false); }, /** @@ -15768,15 +30276,7 @@ define("ember-runtime/mixins/array", @return {Ember.Array} receiver */ removeArrayObserver: function(target, opts) { - var willChange = (opts && opts.willChange) || 'arrayWillChange', - didChange = (opts && opts.didChange) || 'arrayDidChange'; - - var hasObservers = get(this, 'hasArrayObservers'); - if (hasObservers) propertyWillChange(this, 'hasArrayObservers'); - removeListener(this, '@array:before', target, willChange); - removeListener(this, '@array:change', target, didChange); - if (hasObservers) propertyDidChange(this, 'hasArrayObservers'); - return this; + return arrayObserversHelper(this, target, opts, removeListener, true); }, /** @@ -15804,26 +30304,36 @@ define("ember-runtime/mixins/array", @return {Ember.Array} receiver */ arrayContentWillChange: function(startIdx, removeAmt, addAmt) { + var removing, lim; // if no args are passed assume everything changes - if (startIdx===undefined) { + if (startIdx === undefined) { startIdx = 0; removeAmt = addAmt = -1; } else { - if (removeAmt === undefined) removeAmt=-1; - if (addAmt === undefined) addAmt=-1; + if (removeAmt === undefined) { + removeAmt = -1; + } + + if (addAmt === undefined) { + addAmt = -1; + } } // Make sure the @each proxy is set up if anyone is observing @each - if (isWatching(this, '@each')) { get(this, '@each'); } + if (isWatching(this, '@each')) { + get(this, '@each'); + } sendEvent(this, '@array:before', [this, startIdx, removeAmt, addAmt]); - var removing, lim; - if (startIdx>=0 && removeAmt>=0 && get(this, 'hasEnumerableObservers')) { + if (startIdx >= 0 && removeAmt >= 0 && get(this, 'hasEnumerableObservers')) { removing = []; - lim = startIdx+removeAmt; - for(var idx=startIdx;idx=0 && addAmt>=0 && get(this, 'hasEnumerableObservers')) { + if (startIdx >= 0 && addAmt >= 0 && get(this, 'hasEnumerableObservers')) { adding = []; - lim = startIdx+addAmt; - for(var idx=startIdx;idx 0) { arrangedContent.removeObject(item); @@ -18947,10 +33549,8 @@ define("ember-runtime/mixins/sortable", return mid; } }); - - __exports__["default"] = SortableMixin; }); -define("ember-runtime/mixins/target_action_support", +enifed("ember-runtime/mixins/target_action_support", ["ember-metal/core","ember-metal/property_get","ember-metal/property_set","ember-metal/utils","ember-metal/mixin","ember-metal/computed","exports"], function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __exports__) { "use strict"; @@ -19035,7 +33635,7 @@ define("ember-runtime/mixins/target_action_support", this.triggerAction({ action: 'save', target: this.get('controller'), - actionContext: this.get('context'), + actionContext: this.get('context') }); // Sends the `save` action, along with the current context // to the current controller } @@ -19064,9 +33664,9 @@ define("ember-runtime/mixins/target_action_support", */ triggerAction: function(opts) { opts = opts || {}; - var action = opts.action || get(this, 'action'), - target = opts.target || get(this, 'targetObject'), - actionContext = opts.actionContext; + var action = opts.action || get(this, 'action'); + var target = opts.target || get(this, 'targetObject'); + var actionContext = opts.actionContext; function args(options, actionName) { var ret = []; @@ -19100,16 +33700,15 @@ define("ember-runtime/mixins/target_action_support", __exports__["default"] = TargetActionSupport; }); -define("ember-runtime/system/application", +enifed("ember-runtime/system/application", ["ember-runtime/system/namespace","exports"], function(__dependency1__, __exports__) { "use strict"; var Namespace = __dependency1__["default"]; - var Application = Namespace.extend(); - __exports__["default"] = Application; + __exports__["default"] = Namespace.extend(); }); -define("ember-runtime/system/array_proxy", +enifed("ember-runtime/system/array_proxy", ["ember-metal/core","ember-metal/property_get","ember-metal/property_set","ember-metal/utils","ember-metal/computed","ember-metal/mixin","ember-metal/property_events","ember-metal/error","ember-runtime/system/object","ember-runtime/mixins/mutable_array","ember-runtime/mixins/enumerable","ember-runtime/system/string","exports"], function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __dependency9__, __dependency10__, __dependency11__, __dependency12__, __exports__) { "use strict"; @@ -19125,7 +33724,9 @@ define("ember-runtime/system/array_proxy", var beginPropertyChanges = __dependency7__.beginPropertyChanges; var endPropertyChanges = __dependency7__.endPropertyChanges; var EmberError = __dependency8__["default"]; - var EmberObject = __dependency9__["default"];var MutableArray = __dependency10__["default"];var Enumerable = __dependency11__["default"]; + var EmberObject = __dependency9__["default"]; + var MutableArray = __dependency10__["default"]; + var Enumerable = __dependency11__["default"]; var fmt = __dependency12__.fmt; /** @@ -19251,7 +33852,28 @@ define("ember-runtime/system/array_proxy", } }, + /** + Override to implement content array `willChange` observer. + + @method contentArrayWillChange + + @param {Ember.Array} contentArray the content array + @param {Number} start starting index of the change + @param {Number} removeCount count of items removed + @param {Number} addCount count of items added + + */ contentArrayWillChange: K, + /** + Override to implement content array `didChange` observer. + + @method contentArrayDidChange + + @param {Ember.Array} contentArray the content array + @param {Number} start starting index of the change + @param {Number} removeCount count of items removed + @param {Number} addCount count of items added + */ contentArrayDidChange: K, /** @@ -19285,8 +33907,8 @@ define("ember-runtime/system/array_proxy", }, _arrangedContentWillChange: beforeObserver('arrangedContent', function() { - var arrangedContent = get(this, 'arrangedContent'), - len = arrangedContent ? get(arrangedContent, 'length') : 0; + var arrangedContent = get(this, 'arrangedContent'); + var len = arrangedContent ? get(arrangedContent, 'length') : 0; this.arrangedContentArrayWillChange(this, 0, len, undefined); this.arrangedContentWillChange(this); @@ -19295,8 +33917,8 @@ define("ember-runtime/system/array_proxy", }), _arrangedContentDidChange: observer('arrangedContent', function() { - var arrangedContent = get(this, 'arrangedContent'), - len = arrangedContent ? get(arrangedContent, 'length') : 0; + var arrangedContent = get(this, 'arrangedContent'); + var len = arrangedContent ? get(arrangedContent, 'length') : 0; Ember.assert("Can't set ArrayProxy's content to itself", arrangedContent !== this); @@ -19376,9 +33998,10 @@ define("ember-runtime/system/array_proxy", removeAt: function(start, len) { if ('number' === typeof start) { - var content = get(this, 'content'), - arrangedContent = get(this, 'arrangedContent'), - indices = [], i; + var content = get(this, 'content'); + var arrangedContent = get(this, 'arrangedContent'); + var indices = []; + var i; if ((start < 0) || (start >= get(this, 'length'))) { throw new EmberError(OUT_OF_RANGE_EXCEPTION); @@ -19463,7 +34086,7 @@ define("ember-runtime/system/array_proxy", __exports__["default"] = ArrayProxy; }); -define("ember-runtime/system/container", +enifed("ember-runtime/system/container", ["ember-metal/property_set","exports"], function(__dependency1__, __exports__) { "use strict"; @@ -19474,17 +34097,21 @@ define("ember-runtime/system/container", __exports__["default"] = Container; }); -define("ember-runtime/system/core_object", - ["ember-metal/core","ember-metal/property_get","ember-metal/property_set","ember-metal/utils","ember-metal/platform","ember-metal/watching","ember-metal/chains","ember-metal/events","ember-metal/mixin","ember-metal/enumerable_utils","ember-metal/error","ember-runtime/keys","ember-runtime/mixins/action_handler","ember-metal/properties","ember-metal/binding","ember-metal/computed","ember-metal/run_loop","exports"], +enifed("ember-runtime/system/core_object", + ["ember-metal/core","ember-metal/property_get","ember-metal/property_set","ember-metal/utils","ember-metal/platform","ember-metal/watching","ember-metal/chains","ember-metal/events","ember-metal/mixin","ember-metal/enumerable_utils","ember-metal/error","ember-metal/keys","ember-runtime/mixins/action_handler","ember-metal/properties","ember-metal/binding","ember-metal/computed","ember-metal/run_loop","exports"], function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __dependency9__, __dependency10__, __dependency11__, __dependency12__, __dependency13__, __dependency14__, __dependency15__, __dependency16__, __dependency17__, __exports__) { - "use strict"; + // Remove "use strict"; from transpiled module until + // https://bugs.webkit.org/show_bug.cgi?id=138038 is fixed + // + // REMOVE_USE_STRICT: true + /** @module ember @submodule ember-runtime */ var Ember = __dependency1__["default"]; - // Ember.ENV.MANDATORY_SETTER, Ember.assert, Ember.K, Ember.config + // Ember.assert, Ember.K, Ember.config // NOTE: this object should never be included directly. Instead use `Ember.Object`. // We only define this separately so that `Ember.Set` can depend on it. @@ -19492,11 +34119,10 @@ define("ember-runtime/system/core_object", var set = __dependency3__.set; var guidFor = __dependency4__.guidFor; var apply = __dependency4__.apply; - var create = __dependency5__.create; + var o_create = __dependency5__.create; var generateGuid = __dependency4__.generateGuid; var GUID_KEY = __dependency4__.GUID_KEY; var meta = __dependency4__.meta; - var META_KEY = __dependency4__.META_KEY; var makeArray = __dependency4__.makeArray; var rewatch = __dependency6__.rewatch; var finishChains = __dependency7__.finishChains; @@ -19504,9 +34130,9 @@ define("ember-runtime/system/core_object", var IS_BINDING = __dependency9__.IS_BINDING; var Mixin = __dependency9__.Mixin; var required = __dependency9__.required; - var EnumerableUtils = __dependency10__["default"]; + var indexOf = __dependency10__.indexOf; var EmberError = __dependency11__["default"]; - var platform = __dependency5__.platform; + var o_defineProperty = __dependency5__.defineProperty; var keys = __dependency12__["default"]; var ActionHandler = __dependency13__["default"]; var defineProperty = __dependency14__.defineProperty; @@ -19514,17 +34140,14 @@ define("ember-runtime/system/core_object", var ComputedProperty = __dependency16__.ComputedProperty; var run = __dependency17__["default"]; var destroy = __dependency6__.destroy; + var K = __dependency1__.K; + var hasPropertyAccessors = __dependency5__.hasPropertyAccessors; - - var o_create = create, - o_defineProperty = platform.defineProperty, - schedule = run.schedule, - applyMixin = Mixin._apply, - finishPartial = Mixin.finishPartial, - reopen = Mixin.prototype.reopen, - MANDATORY_SETTER = Ember.ENV.MANDATORY_SETTER, - indexOf = EnumerableUtils.indexOf, - K = Ember.K; + var schedule = run.schedule; + var applyMixin = Mixin._apply; + var finishPartial = Mixin.finishPartial; + var reopen = Mixin.prototype.reopen; + var hasCachedComputedProperties = false; var undefinedDescriptor = { configurable: true, @@ -19546,7 +34169,8 @@ define("ember-runtime/system/core_object", // method a lot faster. This is glue code so we want it to be as fast as // possible. - var wasApplied = false, initMixins, initProperties; + var wasApplied = false; + var initMixins, initProperties; var Class = function() { if (!wasApplied) { @@ -19554,7 +34178,8 @@ define("ember-runtime/system/core_object", } o_defineProperty(this, GUID_KEY, nullDescriptor); o_defineProperty(this, '__nextSuper', undefinedDescriptor); - var m = meta(this), proto = m.proto; + var m = meta(this); + var proto = m.proto; m.proto = this; if (initMixins) { // capture locally so we can clear the closed over variable @@ -19625,17 +34250,25 @@ define("ember-runtime/system/core_object", } else { if (typeof this.setUnknownProperty === 'function' && !(keyName in this)) { this.setUnknownProperty(keyName, value); - } else if (MANDATORY_SETTER) { - defineProperty(this, keyName, null, value); // setup mandatory setter } else { - this[keyName] = value; - } + + if (hasPropertyAccessors) { + defineProperty(this, keyName, null, value); // setup mandatory setter + } else { + this[keyName] = value; + } + } } } } } finishPartial(this, m); - apply(this, this.init, arguments); + var length = arguments.length; + var args = new Array(length); + for (var x = 0; x < length; x++) { + args[x] = arguments[x]; + } + apply(this, this.init, args); m.proto = proto; finishChains(this); sendEvent(this, "init"); @@ -19675,10 +34308,14 @@ define("ember-runtime/system/core_object", */ var CoreObject = makeCtor(); CoreObject.toString = function() { return "Ember.CoreObject"; }; - CoreObject.PrototypeMixin = Mixin.create({ reopen: function() { - applyMixin(this, arguments, true); + var length = arguments.length; + var args = new Array(length); + for (var i = 0; i < length; i++) { + args[i] = arguments[i]; + } + applyMixin(this, args, true); return this; }, @@ -19734,7 +34371,7 @@ define("ember-runtime/system/core_object", App.FooBarView = App.BarView.extend({ someNonConcatenatedProperty: ['foo'], - classNames: ['foo'], + classNames: ['foo'] }); var fooBarView = App.FooBarView.create(); @@ -19887,9 +34524,10 @@ define("ember-runtime/system/core_object", @return {String} string representation */ toString: function toString() { - var hasToStringExtension = typeof this.toStringExtension === 'function', - extension = hasToStringExtension ? ":" + this.toStringExtension() : ''; + var hasToStringExtension = typeof this.toStringExtension === 'function'; + var extension = hasToStringExtension ? ":" + this.toStringExtension() : ''; var ret = '<'+this.constructor.toString()+':'+guidFor(this)+extension+'>'; + this.toString = makeToString(ret); return ret; } @@ -19997,8 +34635,9 @@ define("ember-runtime/system/core_object", @param {Mixin} [mixins]* One or more Mixin classes @param {Object} [arguments]* Object containing values to use within the new class */ - extend: function() { - var Class = makeCtor(), proto; + extend: function extend() { + var Class = makeCtor(); + var proto; Class.ClassMixin = Mixin.create(this.ClassMixin); Class.PrototypeMixin = Mixin.create(this.PrototypeMixin); @@ -20029,7 +34668,14 @@ define("ember-runtime/system/core_object", */ createWithMixins: function() { var C = this; - if (arguments.length>0) { this._initMixins(arguments); } + var l= arguments.length; + if (l > 0) { + var args = new Array(l); + for (var i = 0; i < l; i++) { + args[i] = arguments[i]; + } + this._initMixins(args); + } return new C(); }, @@ -20072,7 +34718,14 @@ define("ember-runtime/system/core_object", */ create: function() { var C = this; - if (arguments.length>0) { this._initProperties(arguments); } + var l = arguments.length; + if (l > 0) { + var args = new Array(l); + for (var i = 0; i < l; i++) { + args[i] = arguments[i]; + } + this._initProperties(args); + } return new C(); }, @@ -20107,7 +34760,16 @@ define("ember-runtime/system/core_object", */ reopen: function() { this.willReopen(); - apply(this.PrototypeMixin, reopen, arguments); + + var l = arguments.length; + var args = new Array(l); + if (l > 0) { + for (var i = 0; i < l; i++) { + args[i] = arguments[i]; + } + } + + apply(this.PrototypeMixin, reopen, args); return this; }, @@ -20167,7 +34829,15 @@ define("ember-runtime/system/core_object", @method reopenClass */ reopenClass: function() { - apply(this.ClassMixin, reopen, arguments); + var l = arguments.length; + var args = new Array(l); + if (l > 0) { + for (var i = 0; i < l; i++) { + args[i] = arguments[i]; + } + } + + apply(this.ClassMixin, reopen, args); applyMixin(this, arguments, false); return this; }, @@ -20213,13 +34883,33 @@ define("ember-runtime/system/core_object", @param key {String} property name */ metaForProperty: function(key) { - var meta = this.proto()[META_KEY], - desc = meta && meta.descs[key]; + var meta = this.proto()['__ember_meta__']; + var desc = meta && meta.descs[key]; Ember.assert("metaForProperty() could not find a computed property with key '"+key+"'.", !!desc && desc instanceof ComputedProperty); return desc._meta || {}; }, + _computedProperties: Ember.computed(function() { + hasCachedComputedProperties = true; + var proto = this.proto(); + var descs = meta(proto).descs; + var property; + var properties = []; + + for (var name in descs) { + property = descs[name]; + + if (property instanceof ComputedProperty) { + properties.push({ + name: name, + meta: property._meta + }); + } + } + return properties; + }).readOnly(), + /** Iterate over each computed property for the class, passing its name and any associated metadata (see `metaForProperty`) to the callback. @@ -20229,20 +34919,17 @@ define("ember-runtime/system/core_object", @param {Object} binding */ eachComputedProperty: function(callback, binding) { - var proto = this.proto(), - descs = meta(proto).descs, - empty = {}, - property; + var property, name; + var empty = {}; - for (var name in descs) { - property = descs[name]; + var properties = get(this, '_computedProperties'); - if (property instanceof ComputedProperty) { - callback.call(binding || this, name, property._meta || empty); - } + for (var i = 0, length = properties.length; i < length; i++) { + property = properties[i]; + name = property.name; + callback.call(binding || this, property.name, property.meta || empty); } } - }); ClassMixin.ownerConstructor = CoreObject; @@ -20252,19 +34939,39 @@ define("ember-runtime/system/core_object", } CoreObject.ClassMixin = ClassMixin; + ClassMixin.apply(CoreObject); + CoreObject.reopen({ + didDefineProperty: function(proto, key, value) { + if (hasCachedComputedProperties === false) { return; } + if (value instanceof Ember.ComputedProperty) { + var cache = Ember.meta(this.constructor).cache; + + if (cache._computedProperties !== undefined) { + cache._computedProperties = undefined; + } + } + } + }); + __exports__["default"] = CoreObject; }); -define("ember-runtime/system/deferred", - ["ember-runtime/mixins/deferred","ember-metal/property_get","ember-runtime/system/object","exports"], - function(__dependency1__, __dependency2__, __dependency3__, __exports__) { +enifed("ember-runtime/system/deferred", + ["ember-metal/core","ember-runtime/mixins/deferred","ember-metal/property_get","ember-runtime/system/object","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __exports__) { "use strict"; - var DeferredMixin = __dependency1__["default"]; - var get = __dependency2__.get; - var EmberObject = __dependency3__["default"]; + var Ember = __dependency1__["default"]; + var DeferredMixin = __dependency2__["default"]; + var get = __dependency3__.get; + var EmberObject = __dependency4__["default"]; - var Deferred = EmberObject.extend(DeferredMixin); + var Deferred = EmberObject.extend(DeferredMixin, { + init: function() { + Ember.deprecate('Usage of Ember.Deferred is deprecated.'); + this._super(); + } + }); Deferred.reopenClass({ promise: function(callback, binding) { @@ -20276,7 +34983,7 @@ define("ember-runtime/system/deferred", __exports__["default"] = Deferred; }); -define("ember-runtime/system/each_proxy", +enifed("ember-runtime/system/each_proxy", ["ember-metal/core","ember-metal/property_get","ember-metal/property_set","ember-metal/utils","ember-metal/enumerable_utils","ember-metal/array","ember-runtime/mixins/array","ember-runtime/system/object","ember-metal/computed","ember-metal/observer","ember-metal/events","ember-metal/properties","ember-metal/property_events","exports"], function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __dependency9__, __dependency10__, __dependency11__, __dependency12__, __dependency13__, __exports__) { "use strict"; @@ -20291,7 +34998,7 @@ define("ember-runtime/system/each_proxy", var get = __dependency2__.get; var set = __dependency3__.set; var guidFor = __dependency4__.guidFor; - var EnumerableUtils = __dependency5__["default"]; + var forEach = __dependency5__.forEach; var indexOf = __dependency6__.indexOf; var EmberArray = __dependency7__["default"]; // ES6TODO: WAT? Circular dep? @@ -20310,8 +35017,6 @@ define("ember-runtime/system/each_proxy", var endPropertyChanges = __dependency13__.endPropertyChanges; var changeProperties = __dependency13__.changeProperties; - var forEach = EnumerableUtils.forEach; - var EachArray = EmberObject.extend(EmberArray, { init: function(content, keyName, owner) { @@ -20336,7 +35041,8 @@ define("ember-runtime/system/each_proxy", var IS_OBSERVER = /^.+:(before|change)$/; function addObserverForContentKey(content, keyName, proxy, idx, loc) { - var objects = proxy._objects, guid; + var objects = proxy._objects; + var guid; if (!objects) objects = proxy._objects = {}; while(--loc>=idx) { @@ -20418,7 +35124,8 @@ define("ember-runtime/system/each_proxy", // Invokes whenever the content array itself changes. arrayWillChange: function(content, idx, removedCnt, addedCnt) { - var keys = this._keys, key, lim; + var keys = this._keys; + var key, lim; lim = removedCnt>0 ? idx+removedCnt : -1; beginPropertyChanges(this); @@ -20436,7 +35143,8 @@ define("ember-runtime/system/each_proxy", }, arrayDidChange: function(content, idx, removedCnt, addedCnt) { - var keys = this._keys, lim; + var keys = this._keys; + var lim; lim = addedCnt>0 ? idx+addedCnt : -1; changeProperties(function() { @@ -20477,8 +35185,9 @@ define("ember-runtime/system/each_proxy", if (!keys) keys = this._keys = {}; if (!keys[keyName]) { keys[keyName] = 1; - var content = this._content, - len = get(content, 'length'); + var content = this._content; + var len = get(content, 'length'); + addObserverForContentKey(content, keyName, this, 0, len); } else { keys[keyName]++; @@ -20488,8 +35197,9 @@ define("ember-runtime/system/each_proxy", stopObservingContentKey: function(keyName) { var keys = this._keys; if (keys && (keys[keyName]>0) && (--keys[keyName]<=0)) { - var content = this._content, - len = get(content, 'length'); + var content = this._content; + var len = get(content, 'length'); + removeObserverForContentKey(content, keyName, this, 0, len); } }, @@ -20501,13 +35211,12 @@ define("ember-runtime/system/each_proxy", contentKeyDidChange: function(obj, keyName) { propertyDidChange(this, keyName); } - }); __exports__.EachArray = EachArray; __exports__.EachProxy = EachProxy; }); -define("ember-runtime/system/lazy_load", +enifed("ember-runtime/system/lazy_load", ["ember-metal/core","ember-metal/array","ember-runtime/system/native_array","exports"], function(__dependency1__, __dependency2__, __dependency3__, __exports__) { "use strict"; @@ -20553,9 +35262,9 @@ define("ember-runtime/system/lazy_load", if (object = loaded[name]) { callback(object); } - }; + } - /** + __exports__.onLoad = onLoad;/** Called when an Ember.js package (e.g Ember.Handlebars) has finished loading. Triggers any callbacks registered for this event. @@ -20577,12 +35286,11 @@ define("ember-runtime/system/lazy_load", callback(object); }); } - }; + } - __exports__.onLoad = onLoad; __exports__.runLoadHooks = runLoadHooks; }); -define("ember-runtime/system/namespace", +enifed("ember-runtime/system/namespace", ["ember-metal/core","ember-metal/property_get","ember-metal/array","ember-metal/utils","ember-metal/mixin","ember-runtime/system/object","exports"], function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __exports__) { "use strict"; @@ -20627,7 +35335,7 @@ define("ember-runtime/system/namespace", }, toString: function() { - var name = get(this, 'name'); + var name = get(this, 'name') || get(this, 'modulePrefix'); if (name) { return name; } findNamespaces(); @@ -20639,8 +35347,8 @@ define("ember-runtime/system/namespace", }, destroy: function() { - var namespaces = Namespace.NAMESPACES, - toString = this.toString(); + var namespaces = Namespace.NAMESPACES; + var toString = this.toString(); if (toString) { Ember.lookup[toString] = undefined; @@ -20709,8 +35417,18 @@ define("ember-runtime/system/namespace", var STARTS_WITH_UPPERCASE = /^[A-Z]/; + function tryIsNamespace(lookup, prop) { + try { + var obj = lookup[prop]; + return obj && obj.isNamespace && obj; + } catch (e) { + // continue + } + } + function findNamespaces() { - var lookup = Ember.lookup, obj, isNamespace; + var lookup = Ember.lookup; + var obj, isNamespace; if (Namespace.PROCESSED) { return; } @@ -20723,14 +35441,8 @@ define("ember-runtime/system/namespace", // At times we are not allowed to access certain properties for security reasons. // There are also times where even if we can access them, we are not allowed to access their properties. - try { - obj = lookup[prop]; - isNamespace = obj && obj.isNamespace; - } catch (e) { - continue; - } - - if (isNamespace) { + obj = tryIsNamespace(lookup, prop); + if (obj) { obj[NAME_KEY] = prop; } } @@ -20773,8 +35485,8 @@ define("ember-runtime/system/namespace", } function processAllNamespaces() { - var unprocessedNamespaces = !Namespace.PROCESSED, - unprocessedMixins = Ember.anyUnprocessedMixins; + var unprocessedNamespaces = !Namespace.PROCESSED; + var unprocessedMixins = Ember.anyUnprocessedMixins; if (unprocessedNamespaces) { findNamespaces(); @@ -20782,7 +35494,9 @@ define("ember-runtime/system/namespace", } if (unprocessedNamespaces || unprocessedMixins) { - var namespaces = Namespace.NAMESPACES, namespace; + var namespaces = Namespace.NAMESPACES; + var namespace; + for (var i=0, l=namespaces.length; i=0;idx--) { - if (this[idx] === object) return idx ; - } - return -1; - }, + lastIndexOf: lastIndexOf, copy: function(deep) { if (deep) { @@ -20931,7 +35621,7 @@ define("ember-runtime/system/native_array", if (Array.prototype[methodName]) ignore.push(methodName); }); - if (ignore.length>0) { + if (ignore.length > 0) { NativeArray = NativeArray.without.apply(NativeArray, ignore); } @@ -20999,9 +35689,10 @@ define("ember-runtime/system/native_array", Ember.A = A; // ES6TODO: Setting A onto the object returned by ember-metal/core to avoid circles __exports__.A = A; - __exports__.NativeArray = NativeArray;__exports__["default"] = NativeArray; + __exports__.NativeArray = NativeArray; + __exports__["default"] = NativeArray; }); -define("ember-runtime/system/object", +enifed("ember-runtime/system/object", ["ember-runtime/system/core_object","ember-runtime/mixins/observable","exports"], function(__dependency1__, __dependency2__, __exports__) { "use strict"; @@ -21024,46 +35715,18 @@ define("ember-runtime/system/object", @uses Ember.Observable */ var EmberObject = CoreObject.extend(Observable); - EmberObject.toString = function() { return "Ember.Object"; }; + EmberObject.toString = function() { + return "Ember.Object"; + }; __exports__["default"] = EmberObject; }); -define("ember-runtime/system/object_proxy", - ["ember-metal/core","ember-metal/property_get","ember-metal/property_set","ember-metal/utils","ember-metal/observer","ember-metal/property_events","ember-metal/computed","ember-metal/properties","ember-metal/mixin","ember-runtime/system/string","ember-runtime/system/object","exports"], - function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __dependency9__, __dependency10__, __dependency11__, __exports__) { +enifed("ember-runtime/system/object_proxy", + ["ember-runtime/system/object","ember-runtime/mixins/-proxy","exports"], + function(__dependency1__, __dependency2__, __exports__) { "use strict"; - /** - @module ember - @submodule ember-runtime - */ - var Ember = __dependency1__["default"]; - // Ember.assert - var get = __dependency2__.get; - var set = __dependency3__.set; - var meta = __dependency4__.meta; - var addObserver = __dependency5__.addObserver; - var removeObserver = __dependency5__.removeObserver; - var addBeforeObserver = __dependency5__.addBeforeObserver; - var removeBeforeObserver = __dependency5__.removeBeforeObserver; - var propertyWillChange = __dependency6__.propertyWillChange; - var propertyDidChange = __dependency6__.propertyDidChange; - var computed = __dependency7__.computed; - var defineProperty = __dependency8__.defineProperty; - var observer = __dependency9__.observer; - var fmt = __dependency10__.fmt; - var EmberObject = __dependency11__["default"]; - - function contentPropertyWillChange(content, contentKey) { - var key = contentKey.slice(8); // remove "content." - if (key in this) { return; } // if shadowed in proxy - propertyWillChange(this, key); - } - - function contentPropertyDidChange(content, contentKey) { - var key = contentKey.slice(8); // remove "content." - if (key in this) { return; } // if shadowed in proxy - propertyDidChange(this, key); - } + var EmberObject = __dependency1__["default"]; + var _ProxyMixin = __dependency2__["default"]; /** `Ember.ObjectProxy` forwards all properties not defined by the proxy itself @@ -21131,62 +35794,12 @@ define("ember-runtime/system/object_proxy", @class ObjectProxy @namespace Ember @extends Ember.Object + @extends Ember._ProxyMixin */ - var ObjectProxy = EmberObject.extend({ - /** - The object whose properties will be forwarded. - @property content - @type Ember.Object - @default null - */ - content: null, - _contentDidChange: observer('content', function() { - Ember.assert("Can't set ObjectProxy's content to itself", get(this, 'content') !== this); - }), - - isTruthy: computed.bool('content'), - - _debugContainerKey: null, - - willWatchProperty: function (key) { - var contentKey = 'content.' + key; - addBeforeObserver(this, contentKey, null, contentPropertyWillChange); - addObserver(this, contentKey, null, contentPropertyDidChange); - }, - - didUnwatchProperty: function (key) { - var contentKey = 'content.' + key; - removeBeforeObserver(this, contentKey, null, contentPropertyWillChange); - removeObserver(this, contentKey, null, contentPropertyDidChange); - }, - - unknownProperty: function (key) { - var content = get(this, 'content'); - if (content) { - return get(content, key); - } - }, - - setUnknownProperty: function (key, value) { - var m = meta(this); - if (m.proto === this) { - // if marked as prototype then just defineProperty - // rather than delegate - defineProperty(this, key, null, value); - return value; - } - - var content = get(this, 'content'); - Ember.assert(fmt("Cannot delegate set('%@', %@) to the 'content' property of object proxy %@: its 'content' is undefined.", [key, value, this]), content); - return set(content, key, value); - } - - }); - - __exports__["default"] = ObjectProxy; + __exports__["default"] = EmberObject.extend(_ProxyMixin); }); -define("ember-runtime/system/set", +enifed("ember-runtime/system/set", ["ember-metal/core","ember-metal/property_get","ember-metal/property_set","ember-metal/utils","ember-metal/is_none","ember-runtime/system/string","ember-runtime/system/core_object","ember-runtime/mixins/mutable_enumerable","ember-runtime/mixins/enumerable","ember-runtime/mixins/copyable","ember-runtime/mixins/freezable","ember-metal/error","ember-metal/property_events","ember-metal/mixin","ember-metal/computed","exports"], function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __dependency9__, __dependency10__, __dependency11__, __dependency12__, __dependency13__, __dependency14__, __dependency15__, __exports__) { "use strict"; @@ -21195,7 +35808,7 @@ define("ember-runtime/system/set", @submodule ember-runtime */ var Ember = __dependency1__["default"]; - // Ember.isNone + // Ember.isNone, Ember.A var get = __dependency2__.get; var set = __dependency3__.set; @@ -21311,8 +35924,7 @@ define("ember-runtime/system/set", @uses Ember.Freezable @since Ember 0.9 */ - var Set = CoreObject.extend(MutableEnumerable, Copyable, Freezable, - { + __exports__["default"] = CoreObject.extend(MutableEnumerable, Copyable, Freezable, { // .......................................................... // IMPLEMENT ENUMERABLE APIS @@ -21548,6 +36160,7 @@ define("ember-runtime/system/set", // init: function(items) { + Ember.deprecate('Ember.Set is deprecated and will be removed in a future release.'); this._super(); if (items) this.addObjects(items); }, @@ -21572,10 +36185,10 @@ define("ember-runtime/system/set", if (get(this, 'isFrozen')) throw new EmberError(FROZEN_ERROR); if (isNone(obj)) return this; // nothing to do - var guid = guidFor(obj), - idx = this[guid], - len = get(this, 'length'), - added ; + var guid = guidFor(obj); + var idx = this[guid]; + var len = get(this, 'length'); + var added; if (idx>=0 && idx=0 && idx", [array.join(',')]); } - }); - - - __exports__["default"] = Set; }); -define("ember-runtime/system/string", - ["ember-metal/core","ember-metal/utils","exports"], - function(__dependency1__, __dependency2__, __exports__) { +enifed("ember-runtime/system/string", + ["ember-metal/core","ember-metal/utils","ember-metal/cache","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __exports__) { "use strict"; /** @module ember @@ -21672,27 +36281,80 @@ define("ember-runtime/system/string", */ var Ember = __dependency1__["default"]; // Ember.STRINGS, Ember.FEATURES - var EmberInspect = __dependency2__.inspect; + var isArray = __dependency2__.isArray; + var emberInspect = __dependency2__.inspect; + var Cache = __dependency3__["default"]; var STRING_DASHERIZE_REGEXP = (/[ _]/g); - var STRING_DASHERIZE_CACHE = {}; + + var STRING_DASHERIZE_CACHE = new Cache(1000, function(key) { + return decamelize(key).replace(STRING_DASHERIZE_REGEXP, '-'); + }); + + var CAMELIZE_CACHE = new Cache(1000, function(key) { + return key.replace(STRING_CAMELIZE_REGEXP, function(match, separator, chr) { + return chr ? chr.toUpperCase() : ''; + }).replace(/^([A-Z])/, function(match, separator, chr) { + return match.toLowerCase(); + }); + }); + + var CLASSIFY_CACHE = new Cache(1000, function(str) { + var parts = str.split("."); + var out = []; + + for (var i=0, l=parts.length; i 2) { + cachedFormats = new Array(arguments.length - 1); + + for (var i = 1, l = arguments.length; i < l; i++) { + cachedFormats[i - 1] = arguments[i]; + } + } + // first, replace any ORDERED replacements. var idx = 0; // the current index for non-numerical replacements return str.replace(/%@([0-9]+)?/g, function(s, argIndex) { argIndex = (argIndex) ? parseInt(argIndex, 10) - 1 : idx++; - s = formats[argIndex]; - return (s === null) ? '(null)' : (s === undefined) ? '' : EmberInspect(s); - }) ; + s = cachedFormats[argIndex]; + return (s === null) ? '(null)' : (s === undefined) ? '' : emberInspect(s); + }); } function loc(str, formats) { + if (!isArray(formats) || arguments.length > 2) { + formats = Array.prototype.slice.call(arguments, 1); + } + str = Ember.STRINGS[str] || str; return fmt(str, formats); } @@ -21702,51 +36364,27 @@ define("ember-runtime/system/string", } function decamelize(str) { - return str.replace(STRING_DECAMELIZE_REGEXP, '$1_$2').toLowerCase(); + return DECAMELIZE_CACHE.get(str); } function dasherize(str) { - var cache = STRING_DASHERIZE_CACHE, - hit = cache.hasOwnProperty(str), - ret; - - if (hit) { - return cache[str]; - } else { - ret = decamelize(str).replace(STRING_DASHERIZE_REGEXP,'-'); - cache[str] = ret; - } - - return ret; + return STRING_DASHERIZE_CACHE.get(str); } function camelize(str) { - return str.replace(STRING_CAMELIZE_REGEXP, function(match, separator, chr) { - return chr ? chr.toUpperCase() : ''; - }).replace(/^([A-Z])/, function(match, separator, chr) { - return match.toLowerCase(); - }); + return CAMELIZE_CACHE.get(str); } function classify(str) { - var parts = str.split("."), - out = []; - - for (var i=0, l=parts.length; i 0) { + router['initialURL'] = url; + run(app, 'advanceReadiness'); + delete router['initialURL']; + } else { + run(app, app.handleURL, url); + } + + return app.testHelpers.wait(); + } + + function click(app, selector, context) { + var $el = app.testHelpers.findWithAssert(selector, context); + run($el, 'mousedown'); + + if ($el.is(':input')) { + var type = $el.prop('type'); + if (type !== 'checkbox' && type !== 'radio' && type !== 'hidden') { + run($el, function(){ + // Firefox does not trigger the `focusin` event if the window + // does not have focus. If the document doesn't have focus just + // use trigger('focusin') instead. + if (!document.hasFocus || document.hasFocus()) { + this.focus(); + } else { + this.trigger('focusin'); + } + }); + } + } + + run($el, 'mouseup'); + run($el, 'click'); + + return app.testHelpers.wait(); + } + + function triggerEvent(app, selector, contextOrType, typeOrOptions, possibleOptions){ + var arity = arguments.length; + var context, type, options; + + if (arity === 3) { + // context and options are optional, so this is + // app, selector, type + context = null; + type = contextOrType; + options = {}; + } else if (arity === 4) { + // context and options are optional, so this is + if (typeof typeOrOptions === "object") { // either + // app, selector, type, options + context = null; + type = contextOrType; + options = typeOrOptions; + } else { // or + // app, selector, context, type + context = contextOrType; + type = typeOrOptions; + options = {}; + } + } else { + context = contextOrType; + type = typeOrOptions; + options = possibleOptions; + } + + var $el = app.testHelpers.findWithAssert(selector, context); + + var event = jQuery.Event(type, options); + + run($el, 'trigger', event); + + return app.testHelpers.wait(); + } + + function keyEvent(app, selector, contextOrType, typeOrKeyCode, keyCode) { + var context, type; + + if (typeof keyCode === 'undefined') { + context = null; + keyCode = typeOrKeyCode; + type = contextOrType; + } else { + context = contextOrType; + type = typeOrKeyCode; + } + + return app.testHelpers.triggerEvent(selector, context, type, { keyCode: keyCode, which: keyCode }); + } + + function fillIn(app, selector, contextOrText, text) { + var $el, context; + if (typeof text === 'undefined') { + text = contextOrText; + } else { + context = contextOrText; + } + $el = app.testHelpers.findWithAssert(selector, context); + run(function() { + $el.val(text).change(); + }); + return app.testHelpers.wait(); + } + + function findWithAssert(app, selector, context) { + var $el = app.testHelpers.find(selector, context); + if ($el.length === 0) { + throw new EmberError("Element " + selector + " not found."); + } + return $el; + } + + function find(app, selector, context) { + var $el; + context = context || get(app, 'rootElement'); + $el = app.$(selector, context); + + return $el; + } + + function andThen(app, callback) { + return app.testHelpers.wait(callback(app)); + } + + function wait(app, value) { + return Test.promise(function(resolve) { + // If this is the first async promise, kick off the async test + if (++countAsync === 1) { + Test.adapter.asyncStart(); + } + + // Every 10ms, poll for the async thing to have finished + var watcher = setInterval(function() { + // 1. If the router is loading, keep polling + var routerIsLoading = !!app.__container__.lookup('router:main').router.activeTransition; + if (routerIsLoading) { return; } + + // 2. If there are pending Ajax requests, keep polling + if (Test.pendingAjaxRequests) { return; } + + // 3. If there are scheduled timers or we are inside of a run loop, keep polling + if (run.hasScheduledTimers() || run.currentRunLoop) { return; } + if (Test.waiters && Test.waiters.any(function(waiter) { + var context = waiter[0]; + var callback = waiter[1]; + return !callback.call(context); + })) { return; } + // Stop polling + clearInterval(watcher); + + // If this is the last async promise, end the async test + if (--countAsync === 0) { + Test.adapter.asyncEnd(); + } + + // Synchronously resolve the promise + run(null, resolve, value); + }, 10); + }); + + } + + + /** + * Loads a route, sets up any controllers, and renders any templates associated + * with the route as though a real user had triggered the route change while + * using your app. + * + * Example: + * + * ```javascript + * visit('posts/index').then(function() { + * // assert something + * }); + * ``` + * + * @method visit + * @param {String} url the name of the route + * @return {RSVP.Promise} + */ + asyncHelper('visit', visit); + + /** + * Clicks an element and triggers any actions triggered by the element's `click` + * event. + * + * Example: + * + * ```javascript + * click('.some-jQuery-selector').then(function() { + * // assert something + * }); + * ``` + * + * @method click + * @param {String} selector jQuery selector for finding element on the DOM + * @return {RSVP.Promise} + */ + asyncHelper('click', click); + + /** + * Simulates a key event, e.g. `keypress`, `keydown`, `keyup` with the desired keyCode + * + * Example: + * + * ```javascript + * keyEvent('.some-jQuery-selector', 'keypress', 13).then(function() { + * // assert something + * }); + * ``` + * + * @method keyEvent + * @param {String} selector jQuery selector for finding element on the DOM + * @param {String} type the type of key event, e.g. `keypress`, `keydown`, `keyup` + * @param {Number} keyCode the keyCode of the simulated key event + * @return {RSVP.Promise} + * @since 1.5.0 + */ + asyncHelper('keyEvent', keyEvent); + + /** + * Fills in an input element with some text. + * + * Example: + * + * ```javascript + * fillIn('#email', 'you@example.com').then(function() { + * // assert something + * }); + * ``` + * + * @method fillIn + * @param {String} selector jQuery selector finding an input element on the DOM + * to fill text with + * @param {String} text text to place inside the input element + * @return {RSVP.Promise} + */ + asyncHelper('fillIn', fillIn); + + /** + * Finds an element in the context of the app's container element. A simple alias + * for `app.$(selector)`. + * + * Example: + * + * ```javascript + * var $el = find('.my-selector'); + * ``` + * + * @method find + * @param {String} selector jQuery string selector for element lookup + * @return {Object} jQuery object representing the results of the query + */ + helper('find', find); + + /** + * Like `find`, but throws an error if the element selector returns no results. + * + * Example: + * + * ```javascript + * var $el = findWithAssert('.doesnt-exist'); // throws error + * ``` + * + * @method findWithAssert + * @param {String} selector jQuery selector string for finding an element within + * the DOM + * @return {Object} jQuery object representing the results of the query + * @throws {Error} throws error if jQuery object returned has a length of 0 + */ + helper('findWithAssert', findWithAssert); + + /** + Causes the run loop to process any pending events. This is used to ensure that + any async operations from other helpers (or your assertions) have been processed. + + This is most often used as the return value for the helper functions (see 'click', + 'fillIn','visit',etc). + + Example: + + ```javascript + Ember.Test.registerAsyncHelper('loginUser', function(app, username, password) { + visit('secured/path/here') + .fillIn('#username', username) + .fillIn('#password', username) + .click('.submit') + + return app.testHelpers.wait(); + }); + + @method wait + @param {Object} value The value to be returned. + @return {RSVP.Promise} + */ + asyncHelper('wait', wait); + asyncHelper('andThen', andThen); + + + /** + Returns the currently active route name. + + Example: + + ```javascript + function validateRouteName(){ + equal(currentRouteName(), 'some.path', "correct route was transitioned into."); + } + + visit('/some/path').then(validateRouteName) + ``` + + @method currentRouteName + @return {Object} The name of the currently active route. + @since 1.5.0 + */ + helper('currentRouteName', currentRouteName); + + /** + Returns the current path. + + Example: + + ```javascript + function validateURL(){ + equal(currentPath(), 'some.path.index', "correct path was transitioned into."); + } + + click('#some-link-id').then(validateURL); + ``` + + @method currentPath + @return {Object} The currently active path. + @since 1.5.0 + */ + helper('currentPath', currentPath); + + /** + Returns the current URL. + + Example: + + ```javascript + function validateURL(){ + equal(currentURL(), '/some/path', "correct URL was transitioned into."); + } + + click('#some-link-id').then(validateURL); + ``` + + @method currentURL + @return {Object} The currently active URL. + @since 1.5.0 + */ + helper('currentURL', currentURL); + + /** + Triggers the given DOM event on the element identified by the provided selector. + + Example: + + ```javascript + triggerEvent('#some-elem-id', 'blur'); + ``` + + This is actually used internally by the `keyEvent` helper like so: + + ```javascript + triggerEvent('#some-elem-id', 'keypress', { keyCode: 13 }); + ``` + + @method triggerEvent + @param {String} selector jQuery selector for finding element on the DOM + @param {String} [context] jQuery selector that will limit the selector + argument to find only within the context's children + @param {String} type The event type to be triggered. + @param {Object} [options] The options to be passed to jQuery.Event. + @return {RSVP.Promise} + @since 1.5.0 + */ + asyncHelper('triggerEvent', triggerEvent); + }); +enifed("ember-testing/initializers", + ["ember-runtime/system/lazy_load"], + function(__dependency1__) { + "use strict"; + var onLoad = __dependency1__.onLoad; + + var name = 'deferReadiness in `testing` mode'; + + onLoad('Ember.Application', function(Application) { + if (!Application.initializers[name]) { + Application.initializer({ + name: name, + + initialize: function(container, application){ + if (application.testing) { + application.deferReadiness(); + } + } + }); + } + }); + }); +enifed("ember-testing/setup_for_testing", + ["ember-metal/core","ember-testing/adapters/qunit","ember-views/system/jquery","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __exports__) { + "use strict"; + var Ember = __dependency1__["default"]; + // import Test from "ember-testing/test"; // ES6TODO: fix when cycles are supported + var QUnitAdapter = __dependency2__["default"]; + var jQuery = __dependency3__["default"]; + + var Test, requests; + + function incrementAjaxPendingRequests(_, xhr){ + requests.push(xhr); + Test.pendingAjaxRequests = requests.length; + } + + function decrementAjaxPendingRequests(_, xhr){ + for (var i=0;i') + .css({ position: 'absolute', left: '-1000px', top: '-1000px' }) + .appendTo('body') + .on('click', handler) + .trigger('click') + .remove(); + } + + $(function() { + /* + Determine whether a checkbox checked using jQuery's "click" method will have + the correct value for its checked property. + + If we determine that the current jQuery version exhibits this behavior, + patch it to work correctly as in the commit for the actual fix: + https://github.com/jquery/jquery/commit/1fb2f92. + */ + testCheckboxClick(function() { + if (!this.checked && !$.event.special.click) { + $.event.special.click = { + // For checkbox, fire native event so checked state will be right + trigger: function() { + if ($.nodeName( this, "input" ) && this.type === "checkbox" && this.click) { + this.click(); + return false; + } + } + }; + } + }); + + // Try again to verify that the patch took effect or blow up. + testCheckboxClick(function() { + Ember.warn("clicked checkboxes should be checked! the jQuery patch didn't work", this.checked); + }); + }); + }); +enifed("ember-testing/test", + ["ember-metal/core","ember-metal/run_loop","ember-metal/platform","ember-runtime/compare","ember-runtime/ext/rsvp","ember-testing/setup_for_testing","ember-application/system/application","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __exports__) { + "use strict"; + var Ember = __dependency1__["default"]; + var emberRun = __dependency2__["default"]; + var create = __dependency3__.create; + var compare = __dependency4__["default"]; + var RSVP = __dependency5__["default"]; + var setupForTesting = __dependency6__["default"]; + var EmberApplication = __dependency7__["default"]; + + /** + @module ember + @submodule ember-testing + */ + var slice = [].slice; + var helpers = {}; + var injectHelpersCallbacks = []; + + /** + This is a container for an assortment of testing related functionality: + + * Choose your default test adapter (for your framework of choice). + * Register/Unregister additional test helpers. + * Setup callbacks to be fired when the test helpers are injected into + your application. + + @class Test + @namespace Ember + */ + var Test = { + /** + Hash containing all known test helpers. + + @property _helpers + @private + @since 1.7.0 + */ + _helpers: helpers, + + /** + `registerHelper` is used to register a test helper that will be injected + when `App.injectTestHelpers` is called. + + The helper method will always be called with the current Application as + the first parameter. + + For example: + + ```javascript + Ember.Test.registerHelper('boot', function(app) { + Ember.run(app, app.advanceReadiness); + }); + ``` + + This helper can later be called without arguments because it will be + called with `app` as the first parameter. + + ```javascript + App = Ember.Application.create(); + App.injectTestHelpers(); + boot(); + ``` + + @public + @method registerHelper + @param {String} name The name of the helper method to add. + @param {Function} helperMethod + @param options {Object} + */ + registerHelper: function(name, helperMethod) { + helpers[name] = { + method: helperMethod, + meta: { wait: false } + }; + }, + + /** + `registerAsyncHelper` is used to register an async test helper that will be injected + when `App.injectTestHelpers` is called. + + The helper method will always be called with the current Application as + the first parameter. + + For example: + + ```javascript + Ember.Test.registerAsyncHelper('boot', function(app) { + Ember.run(app, app.advanceReadiness); + }); + ``` + + The advantage of an async helper is that it will not run + until the last async helper has completed. All async helpers + after it will wait for it complete before running. + + + For example: + + ```javascript + Ember.Test.registerAsyncHelper('deletePost', function(app, postId) { + click('.delete-' + postId); + }); + + // ... in your test + visit('/post/2'); + deletePost(2); + visit('/post/3'); + deletePost(3); + ``` + + @public + @method registerAsyncHelper + @param {String} name The name of the helper method to add. + @param {Function} helperMethod + @since 1.2.0 + */ + registerAsyncHelper: function(name, helperMethod) { + helpers[name] = { + method: helperMethod, + meta: { wait: true } + }; + }, + + /** + Remove a previously added helper method. + + Example: + + ```javascript + Ember.Test.unregisterHelper('wait'); + ``` + + @public + @method unregisterHelper + @param {String} name The helper to remove. + */ + unregisterHelper: function(name) { + delete helpers[name]; + delete Test.Promise.prototype[name]; + }, + + /** + Used to register callbacks to be fired whenever `App.injectTestHelpers` + is called. + + The callback will receive the current application as an argument. + + Example: + + ```javascript + Ember.Test.onInjectHelpers(function() { + Ember.$(document).ajaxSend(function() { + Test.pendingAjaxRequests++; + }); + + Ember.$(document).ajaxComplete(function() { + Test.pendingAjaxRequests--; + }); + }); + ``` + + @public + @method onInjectHelpers + @param {Function} callback The function to be called. + */ + onInjectHelpers: function(callback) { + injectHelpersCallbacks.push(callback); + }, + + /** + This returns a thenable tailored for testing. It catches failed + `onSuccess` callbacks and invokes the `Ember.Test.adapter.exception` + callback in the last chained then. + + This method should be returned by async helpers such as `wait`. + + @public + @method promise + @param {Function} resolver The function used to resolve the promise. + */ + promise: function(resolver) { + return new Test.Promise(resolver); + }, + + /** + Used to allow ember-testing to communicate with a specific testing + framework. + + You can manually set it before calling `App.setupForTesting()`. + + Example: + + ```javascript + Ember.Test.adapter = MyCustomAdapter.create() + ``` + + If you do not set it, ember-testing will default to `Ember.Test.QUnitAdapter`. + + @public + @property adapter + @type {Class} The adapter to be used. + @default Ember.Test.QUnitAdapter + */ + adapter: null, + + /** + Replacement for `Ember.RSVP.resolve` + The only difference is this uses + an instance of `Ember.Test.Promise` + + @public + @method resolve + @param {Mixed} The value to resolve + @since 1.2.0 + */ + resolve: function(val) { + return Test.promise(function(resolve) { + return resolve(val); + }); + }, + + /** + This allows ember-testing to play nicely with other asynchronous + events, such as an application that is waiting for a CSS3 + transition or an IndexDB transaction. + + For example: + + ```javascript + Ember.Test.registerWaiter(function() { + return myPendingTransactions() == 0; + }); + ``` + The `context` argument allows you to optionally specify the `this` + with which your callback will be invoked. + + For example: + + ```javascript + Ember.Test.registerWaiter(MyDB, MyDB.hasPendingTransactions); + ``` + + @public + @method registerWaiter + @param {Object} context (optional) + @param {Function} callback + @since 1.2.0 + */ + registerWaiter: function(context, callback) { + if (arguments.length === 1) { + callback = context; + context = null; + } + if (!this.waiters) { + this.waiters = Ember.A(); + } + this.waiters.push([context, callback]); + }, + /** + `unregisterWaiter` is used to unregister a callback that was + registered with `registerWaiter`. + + @public + @method unregisterWaiter + @param {Object} context (optional) + @param {Function} callback + @since 1.2.0 + */ + unregisterWaiter: function(context, callback) { + var pair; + if (!this.waiters) { return; } + if (arguments.length === 1) { + callback = context; + context = null; + } + pair = [context, callback]; + this.waiters = Ember.A(this.waiters.filter(function(elt) { + return compare(elt, pair)!==0; + })); + } + }; + + function helper(app, name) { + var fn = helpers[name].method; + var meta = helpers[name].meta; + + return function() { + var args = slice.call(arguments); + var lastPromise = Test.lastPromise; + + args.unshift(app); + + // some helpers are not async and + // need to return a value immediately. + // example: `find` + if (!meta.wait) { + return fn.apply(app, args); + } + + if (!lastPromise) { + // It's the first async helper in current context + lastPromise = fn.apply(app, args); + } else { + // wait for last helper's promise to resolve + // and then execute + run(function() { + lastPromise = Test.resolve(lastPromise).then(function() { + return fn.apply(app, args); + }); + }); + } + + return lastPromise; + }; + } + + function run(fn) { + if (!emberRun.currentRunLoop) { + emberRun(fn); + } else { + fn(); + } + } + + EmberApplication.reopen({ + /** + This property contains the testing helpers for the current application. These + are created once you call `injectTestHelpers` on your `Ember.Application` + instance. The included helpers are also available on the `window` object by + default, but can be used from this object on the individual application also. + + @property testHelpers + @type {Object} + @default {} + */ + testHelpers: {}, + + /** + This property will contain the original methods that were registered + on the `helperContainer` before `injectTestHelpers` is called. + + When `removeTestHelpers` is called, these methods are restored to the + `helperContainer`. + + @property originalMethods + @type {Object} + @default {} + @private + @since 1.3.0 + */ + originalMethods: {}, + + + /** + This property indicates whether or not this application is currently in + testing mode. This is set when `setupForTesting` is called on the current + application. + + @property testing + @type {Boolean} + @default false + @since 1.3.0 + */ + testing: false, + + /** + This hook defers the readiness of the application, so that you can start + the app when your tests are ready to run. It also sets the router's + location to 'none', so that the window's location will not be modified + (preventing both accidental leaking of state between tests and interference + with your testing framework). + + Example: + + ``` + App.setupForTesting(); + ``` + + @method setupForTesting + */ + setupForTesting: function() { + setupForTesting(); + + this.testing = true; + + this.Router.reopen({ + location: 'none' + }); + }, + + /** + This will be used as the container to inject the test helpers into. By + default the helpers are injected into `window`. + + @property helperContainer + @type {Object} The object to be used for test helpers. + @default window + @since 1.2.0 + */ + helperContainer: window, + + /** + This injects the test helpers into the `helperContainer` object. If an object is provided + it will be used as the helperContainer. If `helperContainer` is not set it will default + to `window`. If a function of the same name has already been defined it will be cached + (so that it can be reset if the helper is removed with `unregisterHelper` or + `removeTestHelpers`). + + Any callbacks registered with `onInjectHelpers` will be called once the + helpers have been injected. + + Example: + ``` + App.injectTestHelpers(); + ``` + + @method injectTestHelpers + */ + injectTestHelpers: function(helperContainer) { + if (helperContainer) { this.helperContainer = helperContainer; } + + this.testHelpers = {}; + for (var name in helpers) { + this.originalMethods[name] = this.helperContainer[name]; + this.testHelpers[name] = this.helperContainer[name] = helper(this, name); + protoWrap(Test.Promise.prototype, name, helper(this, name), helpers[name].meta.wait); + } + + for(var i = 0, l = injectHelpersCallbacks.length; i < l; i++) { + injectHelpersCallbacks[i](this); + } + }, + + /** + This removes all helpers that have been registered, and resets and functions + that were overridden by the helpers. + + Example: + + ```javascript + App.removeTestHelpers(); + ``` + + @public + @method removeTestHelpers + */ + removeTestHelpers: function() { + for (var name in helpers) { + this.helperContainer[name] = this.originalMethods[name]; + delete this.testHelpers[name]; + delete this.originalMethods[name]; + } + } + }); + + // This method is no longer needed + // But still here for backwards compatibility + // of helper chaining + function protoWrap(proto, name, callback, isAsync) { + proto[name] = function() { + var args = arguments; + if (isAsync) { + return callback.apply(this, args); + } else { + return this.then(function() { + return callback.apply(this, args); + }); + } + }; + } + + Test.Promise = function() { + RSVP.Promise.apply(this, arguments); + Test.lastPromise = this; + }; + + Test.Promise.prototype = create(RSVP.Promise.prototype); + Test.Promise.prototype.constructor = Test.Promise; + + // Patch `then` to isolate async methods + // specifically `Ember.Test.lastPromise` + var originalThen = RSVP.Promise.prototype.then; + Test.Promise.prototype.then = function(onSuccess, onFailure) { + return originalThen.call(this, function(val) { + return isolate(onSuccess, val); + }, onFailure); + }; + + // This method isolates nested async methods + // so that they don't conflict with other last promises. + // + // 1. Set `Ember.Test.lastPromise` to null + // 2. Invoke method + // 3. Return the last promise created during method + // 4. Restore `Ember.Test.lastPromise` to original value + function isolate(fn, val) { + var value, lastPromise; + + // Reset lastPromise for nested helpers + Test.lastPromise = null; + + value = fn(val); + + lastPromise = Test.lastPromise; + + // If the method returned a promise + // return that promise. If not, + // return the last async helper's promise + if ((value && (value instanceof Test.Promise)) || !lastPromise) { + return value; + } else { + run(function() { + lastPromise = Test.resolve(lastPromise).then(function() { + return value; + }); + }); + return lastPromise; + } + } + + __exports__["default"] = Test; + }); +enifed("ember-views", + ["ember-runtime","ember-views/system/jquery","ember-views/system/utils","ember-views/system/render_buffer","ember-views/system/ext","ember-views/views/states","ember-views/views/core_view","ember-views/views/view","ember-views/views/container_view","ember-views/views/collection_view","ember-views/views/component","ember-views/system/event_dispatcher","ember-views/mixins/view_target_action_support","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __dependency9__, __dependency10__, __dependency11__, __dependency12__, __dependency13__, __exports__) { "use strict"; /** Ember Views @@ -22492,31 +38317,55 @@ define("ember-views", @main ember-views */ - // BEGIN EXPORTS - Ember.$ = __dependency2__["default"]; + // BEGIN IMPORTS + var Ember = __dependency1__["default"]; + var jQuery = __dependency2__["default"]; + var isSimpleClick = __dependency3__.isSimpleClick; + var RenderBuffer = __dependency4__["default"]; + // for the side effect of extending Ember.run.queues + var cloneStates = __dependency6__.cloneStates; + var states = __dependency6__.states; - Ember.ViewTargetActionSupport = __dependency12__["default"]; - Ember.RenderBuffer = __dependency4__["default"]; + var CoreView = __dependency7__["default"]; + var View = __dependency8__["default"]; + var ContainerView = __dependency9__["default"]; + var CollectionView = __dependency10__["default"]; + var Component = __dependency11__["default"]; + + var EventDispatcher = __dependency12__["default"]; + var ViewTargetActionSupport = __dependency13__["default"]; + // END IMPORTS + + /** + Alias for jQuery + + @method $ + @for Ember + */ + + // BEGIN EXPORTS + Ember.$ = jQuery; + + Ember.ViewTargetActionSupport = ViewTargetActionSupport; + Ember.RenderBuffer = RenderBuffer; var ViewUtils = Ember.ViewUtils = {}; - ViewUtils.setInnerHTML = __dependency3__.setInnerHTML; - ViewUtils.isSimpleClick = __dependency3__.isSimpleClick; + ViewUtils.isSimpleClick = isSimpleClick; - Ember.CoreView = __dependency7__.CoreView; - Ember.View = __dependency7__.View; - Ember.View.states = __dependency6__.states; - Ember.View.cloneStates = __dependency6__.cloneStates; + Ember.CoreView = CoreView; + Ember.View = View; + Ember.View.states = states; + Ember.View.cloneStates = cloneStates; - Ember._ViewCollection = __dependency7__.ViewCollection; - Ember.ContainerView = __dependency8__["default"]; - Ember.CollectionView = __dependency9__["default"]; - Ember.Component = __dependency10__["default"]; - Ember.EventDispatcher = __dependency11__["default"]; + Ember.ContainerView = ContainerView; + Ember.CollectionView = CollectionView; + Ember.Component = Component; + Ember.EventDispatcher = EventDispatcher; // END EXPORTS __exports__["default"] = Ember; }); -define("ember-views/mixins/component_template_deprecation", +enifed("ember-views/mixins/component_template_deprecation", ["ember-metal/core","ember-metal/property_get","ember-metal/mixin","exports"], function(__dependency1__, __dependency2__, __dependency3__, __exports__) { "use strict"; @@ -22537,7 +38386,7 @@ define("ember-views/mixins/component_template_deprecation", @class ComponentTemplateDeprecation @namespace Ember */ - var ComponentTemplateDeprecation = Mixin.create({ + __exports__["default"] = Mixin.create({ /** @private @@ -22559,8 +38408,8 @@ define("ember-views/mixins/component_template_deprecation", // there is another Mixin loaded first. this._super.apply(this, arguments); - var deprecatedProperty, replacementProperty, - layoutSpecified = (props.layoutName || props.layout || get(this, 'layoutName')); + var deprecatedProperty, replacementProperty; + var layoutSpecified = (props.layoutName || props.layout || get(this, 'layoutName')); if (props.templateName && !layoutSpecified) { deprecatedProperty = 'templateName'; @@ -22583,10 +38432,8 @@ define("ember-views/mixins/component_template_deprecation", } } }); - - __exports__["default"] = ComponentTemplateDeprecation; }); -define("ember-views/mixins/view_target_action_support", +enifed("ember-views/mixins/view_target_action_support", ["ember-metal/mixin","ember-runtime/mixins/target_action_support","ember-metal/computed","exports"], function(__dependency1__, __dependency2__, __dependency3__, __exports__) { "use strict"; @@ -22638,7 +38485,7 @@ define("ember-views/mixins/view_target_action_support", @namespace Ember @extends Ember.TargetActionSupport */ - var ViewTargetActionSupport = Mixin.create(TargetActionSupport, { + __exports__["default"] = Mixin.create(TargetActionSupport, { /** @property target */ @@ -22648,12 +38495,32 @@ define("ember-views/mixins/view_target_action_support", */ actionContext: alias('context') }); - - __exports__["default"] = ViewTargetActionSupport; }); -define("ember-views/system/event_dispatcher", - ["ember-metal/core","ember-metal/property_get","ember-metal/property_set","ember-metal/is_none","ember-metal/run_loop","ember-metal/utils","ember-runtime/system/string","ember-runtime/system/object","ember-views/system/jquery","ember-views/views/view","exports"], - function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __dependency9__, __dependency10__, __exports__) { +enifed("ember-views/system/action_manager", + ["exports"], + function(__exports__) { + "use strict"; + /** + @module ember + @submodule ember-views + */ + + function ActionManager() {} + + /** + Global action id hash. + + @private + @property registeredActions + @type Object + */ + ActionManager.registeredActions = {}; + + __exports__["default"] = ActionManager; + }); +enifed("ember-views/system/event_dispatcher", + ["ember-metal/core","ember-metal/property_get","ember-metal/property_set","ember-metal/is_none","ember-metal/run_loop","ember-metal/utils","ember-runtime/system/string","ember-runtime/system/object","ember-views/system/jquery","ember-views/system/action_manager","ember-views/views/view","ember-metal/merge","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __dependency9__, __dependency10__, __dependency11__, __dependency12__, __exports__) { "use strict"; /** @module ember @@ -22670,9 +38537,9 @@ define("ember-views/system/event_dispatcher", var fmt = __dependency7__.fmt; var EmberObject = __dependency8__["default"]; var jQuery = __dependency9__["default"]; - var View = __dependency10__.View; - - var ActionHelper; + var ActionManager = __dependency10__["default"]; + var View = __dependency11__["default"]; + var merge = __dependency12__["default"]; //ES6TODO: // find a better way to do Ember.View.views without global state @@ -22688,7 +38555,7 @@ define("ember-views/system/event_dispatcher", @private @extends Ember.Object */ - var EventDispatcher = EmberObject.extend({ + __exports__["default"] = EmberObject.extend({ /** The set of events names (and associated handler function names) to be setup @@ -22747,6 +38614,35 @@ define("ember-views/system/event_dispatcher", */ rootElement: 'body', + /** + It enables events to be dispatched to the view's `eventManager.` When present, + this object takes precedence over handling of events on the view itself. + + Note that most Ember applications do not use this feature. If your app also + does not use it, consider setting this property to false to gain some performance + improvement by allowing the EventDispatcher to skip the search for the + `eventManager` on the view tree. + + ```javascript + var EventDispatcher = Em.EventDispatcher.extend({ + events: { + click : 'click', + focusin : 'focusIn', + focusout : 'focusOut', + change : 'change' + }, + canDispatchToEventManager: false + }); + container.register('event_dispatcher:main', EventDispatcher); + ``` + + @property canDispatchToEventManager + @type boolean + @default 'true' + @since 1.7.0 + */ + canDispatchToEventManager: true, + /** Sets up event listeners for standard browser events. @@ -22762,8 +38658,7 @@ define("ember-views/system/event_dispatcher", setup: function(addedEvents, rootElement) { var event, events = get(this, 'events'); - jQuery.extend(events, addedEvents || {}); - + merge(events, addedEvents || {}); if (!isNone(rootElement)) { set(this, 'rootElement', rootElement); @@ -22787,20 +38682,13 @@ define("ember-views/system/event_dispatcher", }, /** - Registers an event listener on the document. If the given event is + Registers an event listener on the rootElement. If the given event is triggered, the provided event handler will be triggered on the target view. If the target view does not implement the event handler, or if the handler returns `false`, the parent view will be called. The event will continue to bubble to each successive parent view until it reaches the top. - For example, to have the `mouseDown` method called on the target view when - a `mousedown` event is received from the browser, do the following: - - ```javascript - setupHandler('mousedown', 'mouseDown'); - ``` - @private @method setupHandler @param {Element} rootElement @@ -22811,28 +38699,23 @@ define("ember-views/system/event_dispatcher", var self = this; rootElement.on(event + '.ember', '.ember-view', function(evt, triggeringManager) { - var view = View.views[this.id], - result = true, manager = null; + var view = View.views[this.id]; + var result = true; - manager = self._findNearestEventManager(view, eventName); + var manager = self.canDispatchToEventManager ? self._findNearestEventManager(view, eventName) : null; if (manager && manager !== triggeringManager) { result = self._dispatchEvent(manager, evt, eventName, view); } else if (view) { result = self._bubbleEvent(view, evt, eventName); - } else { - evt.stopPropagation(); } return result; }); rootElement.on(event + '.ember', '[data-ember-action]', function(evt) { - //ES6TODO: Needed for ActionHelper (generally not available in ember-views test suite) - if (!ActionHelper) { ActionHelper = requireModule("ember-routing/helpers/action")["ActionHelper"]; }; - - var actionId = jQuery(evt.currentTarget).attr('data-ember-action'), - action = ActionHelper.registeredActions[actionId]; + var actionId = jQuery(evt.currentTarget).attr('data-ember-action'); + var action = ActionManager.registeredActions[actionId]; // We have to check for action here since in some cases, jQuery will trigger // an event on `removeChild` (i.e. focusout) after we've already torn down the @@ -22880,12 +38763,14 @@ define("ember-views/system/event_dispatcher", var rootElement = get(this, 'rootElement'); jQuery(rootElement).off('.ember', '**').removeClass('ember-application'); return this._super(); + }, + + toString: function() { + return '(EventDispatcher)'; } }); - - __exports__["default"] = EventDispatcher; }); -define("ember-views/system/ext", +enifed("ember-views/system/ext", ["ember-metal/run_loop"], function(__dependency1__) { "use strict"; @@ -22903,7 +38788,7 @@ define("ember-views/system/ext", run._addQueue('render', 'actions'); run._addQueue('afterRender', 'render'); }); -define("ember-views/system/jquery", +enifed("ember-views/system/jquery", ["ember-metal/core","ember-runtime/system/string","ember-metal/enumerable_utils","exports"], function(__dependency1__, __dependency2__, __dependency3__, __exports__) { "use strict"; @@ -22912,8 +38797,7 @@ define("ember-views/system/jquery", var w = __dependency2__.w; // ES6TODO: the functions on EnumerableUtils need their own exports - var EnumerableUtils = __dependency3__["default"]; - var forEach = EnumerableUtils.forEach; + var forEach = __dependency3__.forEach; /** Ember Views @@ -22925,8 +38809,8 @@ define("ember-views/system/jquery", */ var jQuery = (Ember.imports && Ember.imports.jQuery) || (this && this.jQuery); - if (!jQuery && typeof require === 'function') { - jQuery = require('jquery'); + if (!jQuery && typeof eriuqer === 'function') { + jQuery = eriuqer('jquery'); } Ember.assert("Ember Views require jQuery between 1.7 and 2.1", jQuery && (jQuery().jquery.match(/^((1\.(7|8|9|10|11))|(2\.(0|1)))(\.\d+)?(pre|rc\d?)?/) || Ember.ENV.FORCE_JQUERY)); @@ -22948,32 +38832,74 @@ define("ember-views/system/jquery", __exports__["default"] = jQuery; }); -define("ember-views/system/render_buffer", - ["ember-metal/core","ember-metal/property_get","ember-metal/property_set","ember-views/system/utils","ember-views/system/jquery","exports"], - function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __exports__) { +enifed("ember-views/system/render_buffer", + ["ember-views/system/jquery","morph","ember-metal/core","ember-metal/platform","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __exports__) { "use strict"; /** @module ember @submodule ember-views */ - var Ember = __dependency1__["default"]; - // jQuery + var jQuery = __dependency1__["default"]; + var DOMHelper = __dependency2__.DOMHelper; + var Ember = __dependency3__["default"]; + var create = __dependency4__.create; - var get = __dependency2__.get; - var set = __dependency3__.set; - var setInnerHTML = __dependency4__.setInnerHTML; - var jQuery = __dependency5__["default"]; - - function ClassSet() { - this.seen = {}; - this.list = []; + // The HTML spec allows for "omitted start tags". These tags are optional + // when their intended child is the first thing in the parent tag. For + // example, this is a tbody start tag: + // + // + // + // + // + // The tbody may be omitted, and the browser will accept and render: + // + //
    + // + // + // However, the omitted start tag will still be added to the DOM. Here + // we test the string and context to see if the browser is about to + // perform this cleanup, but with a special allowance for disregarding + // "; - return testEl.firstChild.innerHTML === ''; - })(); - - // IE 8 (and likely earlier) likes to move whitespace preceeding - // a script tag to appear after it. This means that we can - // accidentally remove whitespace when updating a morph. - var movesWhitespace = typeof document !== 'undefined' && (function() { - var testEl = document.createElement('div'); - testEl.innerHTML = "Test: Value"; - return testEl.childNodes[0].nodeValue === 'Test:' && - testEl.childNodes[2].nodeValue === ' Value'; - })(); - - // Use this to find children by ID instead of using jQuery - var findChildById = function(element, id) { - if (element.getAttribute('id') === id) { return element; } - - var len = element.childNodes.length, idx, node, found; - for (idx=0; idx 0) { - var len = matches.length, idx; - for (idx=0; idxTest'); - canSet = el.options.length === 1; - } - - innerHTMLTags[tagName] = canSet; - - return canSet; - }; - - var setInnerHTML = function(element, html) { - var tagName = element.tagName; - - if (canSetInnerHTML(tagName)) { - setInnerHTMLWithoutFix(element, html); - } else { - // Firefox versions < 11 do not have support for element.outerHTML. - var outerHTML = element.outerHTML || new XMLSerializer().serializeToString(element); - Ember.assert("Can't set innerHTML on "+element.tagName+" in this browser", outerHTML); - - var startTag = outerHTML.match(new RegExp("<"+tagName+"([^>]*)>", 'i'))[0], - endTag = ''; - - var wrapper = document.createElement('div'); - setInnerHTMLWithoutFix(wrapper, startTag + html + endTag); - element = wrapper.firstChild; - while (element.tagName !== tagName) { - element = element.nextSibling; - } - } - - return element; - }; - function isSimpleClick(event) { - var modifier = event.shiftKey || event.metaKey || event.altKey || event.ctrlKey, - secondaryClick = event.which > 1; // IE9 may return undefined + var modifier = event.shiftKey || event.metaKey || event.altKey || event.ctrlKey; + var secondaryClick = event.which > 1; // IE9 may return undefined return !modifier && !secondaryClick; } - __exports__.setInnerHTML = setInnerHTML; __exports__.isSimpleClick = isSimpleClick; }); -define("ember-views/views/collection_view", - ["ember-metal/core","ember-metal/platform","ember-metal/binding","ember-metal/merge","ember-metal/property_get","ember-metal/property_set","ember-runtime/system/string","ember-views/views/container_view","ember-views/views/view","ember-metal/mixin","ember-runtime/mixins/array","exports"], - function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __dependency9__, __dependency10__, __dependency11__, __exports__) { +enifed("ember-views/views/collection_view", + ["ember-metal/core","ember-metal/platform","ember-metal/binding","ember-metal/merge","ember-metal/property_get","ember-metal/property_set","ember-runtime/system/string","ember-views/views/container_view","ember-views/views/core_view","ember-views/views/view","ember-metal/mixin","ember-handlebars/ext","ember-runtime/mixins/array","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __dependency9__, __dependency10__, __dependency11__, __dependency12__, __dependency13__, __exports__) { "use strict"; /** @@ -23662,11 +39637,12 @@ define("ember-views/views/collection_view", var set = __dependency6__.set; var fmt = __dependency7__.fmt; var ContainerView = __dependency8__["default"]; - var CoreView = __dependency9__.CoreView; - var View = __dependency9__.View; - var observer = __dependency10__.observer; - var beforeObserver = __dependency10__.beforeObserver; - var EmberArray = __dependency11__["default"]; + var CoreView = __dependency9__["default"]; + var View = __dependency10__["default"]; + var observer = __dependency11__.observer; + var beforeObserver = __dependency11__.beforeObserver; + var handlebarsGetView = __dependency12__.handlebarsGetView; + var EmberArray = __dependency13__["default"]; /** `Ember.CollectionView` is an `Ember.View` descendent responsible for managing @@ -23689,27 +39665,32 @@ define("ember-views/views/collection_view", The view for each item in the collection will have its `content` property set to the item. - ## Specifying itemViewClass + ## Specifying `itemViewClass` By default the view class for each item in the managed collection will be an instance of `Ember.View`. You can supply a different class by setting the `CollectionView`'s `itemViewClass` property. - Given an empty `` and the following code: + Given the following application code: ```javascript - someItemsView = Ember.CollectionView.create({ + var App = Ember.Application.create(); + App.ItemListView = Ember.CollectionView.extend({ classNames: ['a-collection'], content: ['A','B','C'], itemViewClass: Ember.View.extend({ template: Ember.Handlebars.compile("the letter: {{view.content}}") }) }); - - someItemsView.appendTo('body'); ``` - Will result in the following HTML structure + And a simple application template: + + ```handlebars + {{view 'item-list'}} + ``` + + The following HTML will result: ```html
    @@ -23725,21 +39706,26 @@ define("ember-views/views/collection_view", "ul", "ol", "table", "thead", "tbody", "tfoot", "tr", or "select" will result in the item views receiving an appropriately matched `tagName` property. - Given an empty `` and the following code: + Given the following application code: ```javascript - anUnorderedListView = Ember.CollectionView.create({ + var App = Ember.Application.create(); + App.UnorderedListView = Ember.CollectionView.create({ tagName: 'ul', content: ['A','B','C'], itemViewClass: Ember.View.extend({ template: Ember.Handlebars.compile("the letter: {{view.content}}") }) }); - - anUnorderedListView.appendTo('body'); ``` - Will result in the following HTML structure + And a simple application template: + + ```handlebars + {{view 'unordered-list-view'}} + ``` + + The following HTML will result: ```html
      @@ -23750,7 +39736,7 @@ define("ember-views/views/collection_view", ``` Additional `tagName` pairs can be provided by adding to - `Ember.CollectionView.CONTAINER_MAP ` + `Ember.CollectionView.CONTAINER_MAP`. For example: ```javascript Ember.CollectionView.CONTAINER_MAP['article'] = 'section' @@ -23763,7 +39749,7 @@ define("ember-views/views/collection_view", `createChildView` method can be overidden: ```javascript - CustomCollectionView = Ember.CollectionView.extend({ + App.CustomCollectionView = Ember.CollectionView.extend({ createChildView: function(viewClass, attrs) { if (attrs.content.kind == 'album') { viewClass = App.AlbumView; @@ -23783,18 +39769,23 @@ define("ember-views/views/collection_view", will be the `CollectionView`s only child. ```javascript - aListWithNothing = Ember.CollectionView.create({ - classNames: ['nothing'] + var App = Ember.Application.create(); + App.ListWithNothing = Ember.CollectionView.create({ + classNames: ['nothing'], content: null, emptyView: Ember.View.extend({ template: Ember.Handlebars.compile("The collection is empty") }) }); - - aListWithNothing.appendTo('body'); ``` - Will result in the following HTML structure + And a simple application template: + + ```handlebars + {{view 'list-with-nothing'}} + ``` + + The following HTML will result: ```html
      @@ -23952,18 +39943,8 @@ define("ember-views/views/collection_view", // Loop through child views that correspond with the removed items. // Note that we loop from the end of the array to the beginning because // we are mutating it as we go. - var childViews = this._childViews, childView, idx, len; - - len = this._childViews.length; - - var removingAll = removedCount === len; - - if (removingAll) { - this.currentState.empty(this); - this.invokeRecursively(function(view) { - view.removedFromDOM = true; - }, false); - } + var childViews = this._childViews; + var childView, idx; for (idx = start + removedCount - 1; idx >= start; idx--) { childView = childViews[idx]; @@ -23986,21 +39967,14 @@ define("ember-views/views/collection_view", @param {Number} added number of object added to content */ arrayDidChange: function(content, start, removed, added) { - var addedViews = [], view, item, idx, len, itemViewClass, - emptyView; + var addedViews = []; + var view, item, idx, len, itemViewClass, emptyView; len = content ? get(content, 'length') : 0; if (len) { itemViewClass = get(this, 'itemViewClass'); - - if ('string' === typeof itemViewClass && isGlobalPath(itemViewClass)) { - itemViewClass = get(itemViewClass) || itemViewClass; - } - - Ember.assert(fmt("itemViewClass must be a subclass of Ember.View, not %@", - [itemViewClass]), - 'string' === typeof itemViewClass || View.detect(itemViewClass)); + itemViewClass = handlebarsGetView(content, itemViewClass, this.container); for (idx = start; idx < start+added; idx++) { item = content.objectAt(idx); @@ -24085,7 +40059,7 @@ define("ember-views/views/collection_view", __exports__["default"] = CollectionView; }); -define("ember-views/views/component", +enifed("ember-views/views/component", ["ember-metal/core","ember-views/mixins/component_template_deprecation","ember-runtime/mixins/target_action_support","ember-views/views/view","ember-metal/property_get","ember-metal/property_set","ember-metal/is_none","ember-metal/computed","exports"], function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __exports__) { "use strict"; @@ -24094,7 +40068,9 @@ define("ember-views/views/component", var ComponentTemplateDeprecation = __dependency2__["default"]; var TargetActionSupport = __dependency3__["default"]; - var View = __dependency4__.View;var get = __dependency5__.get; + var View = __dependency4__["default"]; + + var get = __dependency5__.get; var set = __dependency6__.set; var isNone = __dependency7__.isNone; @@ -24202,6 +40178,7 @@ define("ember-views/views/component", init: function() { this._super(); + set(this, 'origContext', get(this, 'context')); set(this, 'context', this); set(this, 'controller', this); }, @@ -24232,8 +40209,8 @@ define("ember-views/views/component", template: computed(function(key, value) { if (value !== undefined) { return value; } - var templateName = get(this, 'templateName'), - template = this.templateForName(templateName, 'template'); + var templateName = get(this, 'templateName'); + var template = this.templateForName(templateName, 'template'); Ember.assert("You specified the templateName " + templateName + " for " + this + ", but it did not exist.", !templateName || template); @@ -24258,9 +40235,9 @@ define("ember-views/views/component", }, _yield: function(context, options) { - var view = options.data.view, - parentView = this._parentView, - template = get(this, 'template'); + var view = options.data.view; + var parentView = this._parentView; + var template = get(this, 'template'); if (template) { Ember.assert("A Component must have a parent view in order to yield.", parentView); @@ -24270,9 +40247,9 @@ define("ember-views/views/component", tagName: '', _contextView: parentView, template: template, - context: get(parentView, 'context'), + context: options.data.insideGroup ? get(this, 'origContext') : get(parentView, 'context'), controller: get(parentView, 'controller'), - templateData: { keywords: parentView.cloneKeywords() } + templateData: { keywords: parentView.cloneKeywords(), insideGroup: options.data.insideGroup } }); } }, @@ -24371,8 +40348,8 @@ define("ember-views/views/component", @param [context] {*} a context to send with the action */ sendAction: function(action) { - var actionName, - contexts = a_slice.call(arguments, 1); + var actionName; + var contexts = a_slice.call(arguments, 1); // Send the default action if (action === undefined) { @@ -24400,7 +40377,7 @@ define("ember-views/views/component", __exports__["default"] = Component; }); -define("ember-views/views/container_view", +enifed("ember-views/views/container_view", ["ember-metal/core","ember-metal/merge","ember-runtime/mixins/mutable_array","ember-metal/property_get","ember-metal/property_set","ember-views/views/view","ember-views/views/states","ember-metal/error","ember-metal/enumerable_utils","ember-metal/computed","ember-metal/run_loop","ember-metal/properties","ember-views/system/render_buffer","ember-metal/mixin","ember-runtime/system/native_array","exports"], function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __dependency9__, __dependency10__, __dependency11__, __dependency12__, __dependency13__, __dependency14__, __dependency15__, __exports__) { "use strict"; @@ -24412,24 +40389,22 @@ define("ember-views/views/container_view", var get = __dependency4__.get; var set = __dependency5__.set; - var View = __dependency6__.View; - var ViewCollection = __dependency6__.ViewCollection; + var View = __dependency6__["default"]; + var cloneStates = __dependency7__.cloneStates; var EmberViewStates = __dependency7__.states; var EmberError = __dependency8__["default"]; - // ES6TODO: functions on EnumerableUtils should get their own export - var EnumerableUtils = __dependency9__["default"]; - var forEach = EnumerableUtils.forEach; + var forEach = __dependency9__.forEach; var computed = __dependency10__.computed; var run = __dependency11__["default"]; var defineProperty = __dependency12__.defineProperty; - var RenderBuffer = __dependency13__["default"]; + var renderBuffer = __dependency13__["default"]; var observer = __dependency14__.observer; var beforeObserver = __dependency14__.beforeObserver; - var A = __dependency15__.A; + var emberA = __dependency15__.A; /** @module ember @@ -24589,7 +40564,15 @@ define("ember-views/views/container_view", @extends Ember.View */ var ContainerView = View.extend(MutableArray, { - states: states, + isContainer: true, + _states: states, + + willWatchProperty: function(prop){ + Ember.deprecate( + "ContainerViews should not be observed as arrays. This behavior will change in future implementations of ContainerView.", + !prop.match(/\[]/) && prop.indexOf('@') !== 0 + ); + }, init: function() { this._super(); @@ -24625,7 +40608,7 @@ define("ember-views/views/container_view", replace: function(idx, removedCount, addedViews) { var addedCount = addedViews ? get(addedViews, 'length') : 0; var self = this; - Ember.assert("You can't add a child to a container - the child is already a child of another view", A(addedViews).every(function(item) { return !get(item, '_parentView') || get(item, '_parentView') === self; })); + Ember.assert("You can't add a child to a container - the child is already a child of another view", emberA(addedViews).every(function(item) { return !get(item, '_parentView') || get(item, '_parentView') === self; })); this.arrayContentWillChange(idx, removedCount, addedCount); this.childViewsWillChange(this._childViews, idx, removedCount); @@ -24650,7 +40633,7 @@ define("ember-views/views/container_view", length: computed(function () { return this._childViews.length; - }).volatile(), + })["volatile"](), /** Instructs each child view to render to the passed render buffer. @@ -24660,9 +40643,6 @@ define("ember-views/views/container_view", @param {Ember.RenderBuffer} buffer the buffer to render to */ render: function(buffer) { - this.forEachChildView(function(view) { - view.renderToBuffer(buffer); - }); }, instrumentName: 'container', @@ -24781,51 +40761,165 @@ define("ember-views/views/container_view", }, ensureChildrenAreInDOM: function(view) { - var childViews = view._childViews, i, len, childView, previous, buffer, viewCollection = new ViewCollection(); + var childViews = view._childViews; + var renderer = view._renderer; + var i, len, childView; for (i = 0, len = childViews.length; i < len; i++) { childView = childViews[i]; - - if (!buffer) { buffer = RenderBuffer(); buffer._hasElement = false; } - - if (childView.renderToBufferIfNeeded(buffer)) { - viewCollection.push(childView); - } else if (viewCollection.length) { - insertViewCollection(view, viewCollection, previous, buffer); - buffer = null; - previous = childView; - viewCollection.clear(); - } else { - previous = childView; + if (!childView._elementCreated) { + renderer.renderTree(childView, view, i); } } - - if (viewCollection.length) { - insertViewCollection(view, viewCollection, previous, buffer); - } } }); - function insertViewCollection(view, viewCollection, previous, buffer) { - viewCollection.triggerRecursively('willInsertElement'); - - if (previous) { - previous.domManager.after(previous, buffer.string()); - } else { - view.domManager.prepend(view, buffer.string()); - } - - viewCollection.forEach(function(v) { - v.transitionTo('inDOM'); - v.propertyDidChange('element'); - v.triggerRecursively('didInsertElement'); - }); - } - - __exports__["default"] = ContainerView; }); -define("ember-views/views/states", +enifed("ember-views/views/core_view", + ["ember-views/system/renderer","ember-views/views/states","ember-runtime/system/object","ember-runtime/mixins/evented","ember-runtime/mixins/action_handler","ember-metal/property_get","ember-metal/property_set","ember-metal/computed","ember-metal/utils","ember-metal/instrumentation","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __dependency9__, __dependency10__, __exports__) { + "use strict"; + var Rerender = __dependency1__["default"]; + + var cloneStates = __dependency2__.cloneStates; + var states = __dependency2__.states; + var EmberObject = __dependency3__["default"]; + var Evented = __dependency4__["default"]; + var ActionHandler = __dependency5__["default"]; + + var get = __dependency6__.get; + var set = __dependency7__.set; + var computed = __dependency8__.computed; + + var typeOf = __dependency9__.typeOf; + + var instrument = __dependency10__.instrument; + + /** + `Ember.CoreView` is an abstract class that exists to give view-like behavior + to both Ember's main view class `Ember.View` and other classes like + `Ember._SimpleMetamorphView` that don't need the fully functionaltiy of + `Ember.View`. + + Unless you have specific needs for `CoreView`, you will use `Ember.View` + in your applications. + + @class CoreView + @namespace Ember + @extends Ember.Object + @uses Ember.Evented + @uses Ember.ActionHandler + */ + var CoreView = EmberObject.extend(Evented, ActionHandler, { + isView: true, + isVirtual: false, + isContainer: false, + + _states: cloneStates(states), + + init: function() { + this._super(); + this._transitionTo('preRender'); + this._isVisible = get(this, 'isVisible'); + }, + + /** + If the view is currently inserted into the DOM of a parent view, this + property will point to the parent of the view. + + @property parentView + @type Ember.View + @default null + */ + parentView: computed('_parentView', function() { + var parent = this._parentView; + + if (parent && parent.isVirtual) { + return get(parent, 'parentView'); + } else { + return parent; + } + }), + + _state: null, + + _parentView: null, + + // return the current view, not including virtual views + concreteView: computed('parentView', function() { + if (!this.isVirtual) { return this; } + else { return get(this, 'parentView.concreteView'); } + }), + + instrumentName: 'core_view', + + instrumentDetails: function(hash) { + hash.object = this.toString(); + hash.containerKey = this._debugContainerKey; + hash.view = this; + }, + + /** + Override the default event firing from `Ember.Evented` to + also call methods with the given name. + + @method trigger + @param name {String} + @private + */ + trigger: function() { + this._super.apply(this, arguments); + var name = arguments[0]; + var method = this[name]; + if (method) { + var length = arguments.length; + var args = new Array(length - 1); + for (var i = 1; i < length; i++) { + args[i - 1] = arguments[i]; + } + return method.apply(this, args); + } + }, + + has: function(name) { + return typeOf(this[name]) === 'function' || this._super(name); + }, + + destroy: function() { + var parent = this._parentView; + + if (!this._super()) { return; } + + + // destroy the element -- this will avoid each child view destroying + // the element over and over again... + if (!this.removedFromDOM && this._renderer) { + this._renderer.remove(this, true); + } + + // remove from parent if found. Don't call removeFromParent, + // as removeFromParent will try to remove the element from + // the DOM again. + if (parent) { parent.removeChild(this); } + + this._transitionTo('destroying', false); + + return this; + }, + + clearRenderedChildren: Ember.K, + _transitionTo: Ember.K, + destroyElement: Ember.K + }); + + CoreView.reopenClass({ + renderer: new Rerender() + }); + + __exports__["default"] = CoreView; + }); +enifed("ember-views/views/states", ["ember-metal/platform","ember-metal/merge","ember-views/views/states/default","ember-views/views/states/pre_render","ember-views/views/states/in_buffer","ember-views/views/states/has_element","ember-views/views/states/in_dom","ember-views/views/states/destroying","exports"], function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __exports__) { "use strict"; @@ -24854,9 +40948,9 @@ define("ember-views/views/states", } return into; - }; + } - var states = { + __exports__.cloneStates = cloneStates;var states = { _default: _default, preRender: preRender, inDOM: inDOM, @@ -24864,11 +40958,9 @@ define("ember-views/views/states", hasElement: hasElement, destroying: destroying }; - - __exports__.cloneStates = cloneStates; __exports__.states = states; }); -define("ember-views/views/states/default", +enifed("ember-views/views/states/default", ["ember-metal/core","ember-metal/property_get","ember-metal/property_set","ember-metal/run_loop","ember-metal/error","exports"], function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __exports__) { "use strict"; @@ -24883,7 +40975,7 @@ define("ember-views/views/states/default", @module ember @submodule ember-views */ - var _default = { + __exports__["default"] = { // appendChild is only legal while rendering the buffer. appendChild: function() { throw new EmberError("You can't use appendChild outside of the rendering process"); @@ -24903,25 +40995,16 @@ define("ember-views/views/states/default", }, destroyElement: function(view) { - set(view, 'element', null); - if (view._scheduledInsert) { - run.cancel(view._scheduledInsert); - view._scheduledInsert = null; - } + if (view._renderer) + view._renderer.remove(view, false); return view; }, - renderToBufferIfNeeded: function () { - return false; - }, - rerender: Ember.K, invokeObserver: Ember.K }; - - __exports__["default"] = _default; }); -define("ember-views/views/states/destroying", +enifed("ember-views/views/states/destroying", ["ember-metal/merge","ember-metal/platform","ember-runtime/system/string","ember-views/views/states/default","ember-metal/error","exports"], function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __exports__) { "use strict"; @@ -24948,27 +41031,12 @@ define("ember-views/views/states/destroying", }, destroyElement: function() { throw new EmberError(fmt(destroyingError, ['destroyElement'])); - }, - empty: function() { - throw new EmberError(fmt(destroyingError, ['empty'])); - }, - - setElement: function() { - throw new EmberError(fmt(destroyingError, ["set('element', ...)"])); - }, - - renderToBufferIfNeeded: function() { - return false; - }, - - // Since element insertion is scheduled, don't do anything if - // the view has been destroyed between scheduling and execution - insertElement: Ember.K + } }); __exports__["default"] = destroying; }); -define("ember-views/views/states/has_element", +enifed("ember-views/views/states/has_element", ["ember-views/views/states/default","ember-metal/run_loop","ember-metal/merge","ember-metal/platform","ember-views/system/jquery","ember-metal/error","ember-metal/property_get","ember-metal/property_set","exports"], function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __exports__) { "use strict"; @@ -24991,7 +41059,7 @@ define("ember-views/views/states/has_element", merge(hasElement, { $: function(view, sel) { - var elem = get(view, 'element'); + var elem = view.get('concreteView').element; return sel ? jQuery(sel, elem) : jQuery(elem); }, @@ -25002,25 +41070,17 @@ define("ember-views/views/states/has_element", return jQuery("#" + get(view, 'elementId'))[0]; }, - setElement: function(view, value) { - if (value === null) { - view.transitionTo('preRender'); - } else { - throw new EmberError("You cannot set an element to a non-null value when the element is already in the DOM."); - } - - return value; - }, - // once the view has been inserted into the DOM, rerendering is // deferred to allow bindings to synchronize. rerender: function(view) { - view.triggerRecursively('willClearRender'); - - view.clearRenderedChildren(); - - view.domManager.replace(view); - return view; + if (view._root._morph && !view._elementInserted) { + throw new EmberError("Something you did caused a view to re-render after it rendered but before it was inserted into the DOM."); + } + // TODO: should be scheduled with renderer + run.scheduleOnce('render', function () { + if (view.isDestroying) return; + view._renderer.renderTree(view, view._parentView); + }); }, // once the view is already in the DOM, destroying it removes it @@ -25028,27 +41088,10 @@ define("ember-views/views/states/has_element", // preRender state if inDOM. destroyElement: function(view) { - view._notifyWillDestroyElement(); - view.domManager.remove(view); - set(view, 'element', null); - if (view._scheduledInsert) { - run.cancel(view._scheduledInsert); - view._scheduledInsert = null; - } + view._renderer.remove(view, false); return view; }, - empty: function(view) { - var _childViews = view._childViews, len, idx; - if (_childViews) { - len = _childViews.length; - for (idx = 0; idx < len; idx++) { - _childViews[idx]._notifyWillDestroyElement(); - } - } - view.domManager.empty(view); - }, - // Handle events from `Ember.EventDispatcher` handleEvent: function(view, eventName, evt) { if (view.has(eventName)) { @@ -25067,7 +41110,7 @@ define("ember-views/views/states/has_element", __exports__["default"] = hasElement; }); -define("ember-views/views/states/in_buffer", +enifed("ember-views/views/states/in_buffer", ["ember-views/views/states/default","ember-metal/error","ember-metal/core","ember-metal/platform","ember-metal/merge","exports"], function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __exports__) { "use strict"; @@ -25106,58 +41149,22 @@ define("ember-views/views/states/in_buffer", // view will render that view and append the resulting // buffer into its buffer. appendChild: function(view, childView, options) { - var buffer = view.buffer, _childViews = view._childViews; + var buffer = view.buffer; + var _childViews = view._childViews; childView = view.createChildView(childView, options); if (!_childViews.length) { _childViews = view._childViews = _childViews.slice(); } _childViews.push(childView); - childView.renderToBuffer(buffer); + if (!childView._morph) { + buffer.pushChildView(childView); + } view.propertyDidChange('childViews'); return childView; }, - // when a view is rendered in a buffer, destroying the - // element will simply destroy the buffer and put the - // state back into the preRender state. - destroyElement: function(view) { - view.clearBuffer(); - var viewCollection = view._notifyWillDestroyElement(); - viewCollection.transitionTo('preRender', false); - - return view; - }, - - empty: function() { - Ember.assert("Emptying a view in the inBuffer state is not allowed and " + - "should not happen under normal circumstances. Most likely " + - "there is a bug in your application. This may be due to " + - "excessive property change notifications."); - }, - - renderToBufferIfNeeded: function (view, buffer) { - return false; - }, - - // It should be impossible for a rendered view to be scheduled for - // insertion. - insertElement: function() { - throw new EmberError("You can't insert an element that has already been rendered"); - }, - - setElement: function(view, value) { - if (value === null) { - view.transitionTo('preRender'); - } else { - view.clearBuffer(); - view.transitionTo('hasElement'); - } - - return value; - }, - invokeObserver: function(target, observer) { observer.call(target); } @@ -25165,7 +41172,7 @@ define("ember-views/views/states/in_buffer", __exports__["default"] = inBuffer; }); -define("ember-views/views/states/in_dom", +enifed("ember-views/views/states/in_dom", ["ember-metal/core","ember-metal/platform","ember-metal/merge","ember-metal/error","ember-views/views/states/has_element","exports"], function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __exports__) { "use strict"; @@ -25187,7 +41194,7 @@ define("ember-views/views/states/in_dom", merge(inDOM, { enter: function(view) { - if (!View) { View = requireModule('ember-views/views/view')["View"]; } // ES6TODO: this sucks. Have to avoid cycles... + if (!View) { View = requireModule('ember-views/views/view')["default"]; } // ES6TODO: this sucks. Have to avoid cycles... // Register the view for event handling. This hash is used by // Ember.EventDispatcher to dispatch incoming events. @@ -25202,25 +41209,22 @@ define("ember-views/views/states/in_dom", }, exit: function(view) { - if (!View) { View = requireModule('ember-views/views/view')["View"]; } // ES6TODO: this sucks. Have to avoid cycles... + if (!View) { View = requireModule('ember-views/views/view')["default"]; } // ES6TODO: this sucks. Have to avoid cycles... if (!this.isVirtual) delete View.views[view.elementId]; - }, - - insertElement: function(view, fn) { - throw new EmberError("You can't insert an element into the DOM that has already been inserted"); } }); __exports__["default"] = inDOM; }); -define("ember-views/views/states/pre_render", - ["ember-views/views/states/default","ember-metal/platform","ember-metal/merge","exports"], - function(__dependency1__, __dependency2__, __dependency3__, __exports__) { +enifed("ember-views/views/states/pre_render", + ["ember-views/views/states/default","ember-metal/platform","ember-metal/merge","ember-views/system/jquery","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __exports__) { "use strict"; var _default = __dependency1__["default"]; var create = __dependency2__.create; var merge = __dependency3__["default"]; + var jQuery = __dependency4__["default"]; /** @module ember @@ -25228,45 +41232,11 @@ define("ember-views/views/states/pre_render", */ var preRender = create(_default); - merge(preRender, { - // a view leaves the preRender state once its element has been - // created (createElement). - insertElement: function(view, fn) { - view.createElement(); - var viewCollection = view.viewHierarchyCollection(); - - viewCollection.trigger('willInsertElement'); - - fn.call(view); - - // We transition to `inDOM` if the element exists in the DOM - var element = view.get('element'); - if (document.body.contains(element)) { - viewCollection.transitionTo('inDOM', false); - viewCollection.trigger('didInsertElement'); - } - }, - - renderToBufferIfNeeded: function(view, buffer) { - view.renderToBuffer(buffer); - return true; - }, - - empty: Ember.K, - - setElement: function(view, value) { - if (value !== null) { - view.transitionTo('hasElement'); - } - return value; - } - }); - __exports__["default"] = preRender; }); -define("ember-views/views/view", - ["ember-metal/core","ember-metal/error","ember-runtime/system/object","ember-runtime/mixins/evented","ember-runtime/mixins/action_handler","ember-views/system/render_buffer","ember-metal/property_get","ember-metal/property_set","ember-metal/set_properties","ember-metal/run_loop","ember-metal/observer","ember-metal/properties","ember-metal/utils","ember-metal/computed","ember-metal/mixin","ember-metal/is_none","container/container","ember-runtime/system/native_array","ember-metal/instrumentation","ember-runtime/system/string","ember-metal/enumerable_utils","ember-runtime/copy","ember-metal/binding","ember-metal/property_events","ember-views/views/states","ember-views/system/jquery","ember-views/system/ext","exports"], - function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __dependency9__, __dependency10__, __dependency11__, __dependency12__, __dependency13__, __dependency14__, __dependency15__, __dependency16__, __dependency17__, __dependency18__, __dependency19__, __dependency20__, __dependency21__, __dependency22__, __dependency23__, __dependency24__, __dependency25__, __dependency26__, __dependency27__, __exports__) { +enifed("ember-views/views/view", + ["ember-metal/core","ember-runtime/mixins/evented","ember-runtime/system/object","ember-metal/error","ember-metal/property_get","ember-metal/property_set","ember-metal/set_properties","ember-metal/run_loop","ember-metal/observer","ember-metal/properties","ember-metal/utils","ember-metal/computed","ember-metal/mixin","ember-metal/is_none","ember-metal/deprecate_property","ember-runtime/system/native_array","ember-runtime/system/string","ember-metal/enumerable_utils","ember-runtime/copy","ember-metal/binding","ember-metal/property_events","ember-views/system/jquery","ember-views/system/ext","ember-views/views/core_view","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __dependency9__, __dependency10__, __dependency11__, __dependency12__, __dependency13__, __dependency14__, __dependency15__, __dependency16__, __dependency17__, __dependency18__, __dependency19__, __dependency20__, __dependency21__, __dependency22__, __dependency23__, __dependency24__, __exports__) { "use strict"; // Ember.assert, Ember.deprecate, Ember.warn, Ember.TEMPLATES, // Ember.K, jQuery, Ember.lookup, @@ -25274,73 +41244,59 @@ define("ember-views/views/view", // Ember.ENV var Ember = __dependency1__["default"]; - var EmberError = __dependency2__["default"]; + var Evented = __dependency2__["default"]; var EmberObject = __dependency3__["default"]; - var Evented = __dependency4__["default"]; - var ActionHandler = __dependency5__["default"]; - var RenderBuffer = __dependency6__["default"]; - var get = __dependency7__.get; - var set = __dependency8__.set; - var setProperties = __dependency9__["default"]; - var run = __dependency10__["default"]; - var addObserver = __dependency11__.addObserver; - var removeObserver = __dependency11__.removeObserver; + var EmberError = __dependency4__["default"]; + var get = __dependency5__.get; + var set = __dependency6__.set; + var setProperties = __dependency7__["default"]; + var run = __dependency8__["default"]; + var addObserver = __dependency9__.addObserver; + var removeObserver = __dependency9__.removeObserver; - var defineProperty = __dependency12__.defineProperty; - var guidFor = __dependency13__.guidFor; - var meta = __dependency13__.meta; - var computed = __dependency14__.computed; - var observer = __dependency15__.observer; + var defineProperty = __dependency10__.defineProperty; + var deprecateProperty = __dependency10__.deprecateProperty; + var guidFor = __dependency11__.guidFor; + var meta = __dependency11__.meta; + var computed = __dependency12__.computed; + var observer = __dependency13__.observer; - var typeOf = __dependency13__.typeOf; - var isArray = __dependency13__.isArray; - var isNone = __dependency16__.isNone; - var Mixin = __dependency15__.Mixin; - var Container = __dependency17__["default"]; - var A = __dependency18__.A; + var typeOf = __dependency11__.typeOf; + var isArray = __dependency11__.isArray; + var isNone = __dependency14__.isNone; + var Mixin = __dependency13__.Mixin; + var deprecateProperty = __dependency15__.deprecateProperty; + var emberA = __dependency16__.A; - var instrument = __dependency19__.instrument; - - var dasherize = __dependency20__.dasherize; + var dasherize = __dependency17__.dasherize; // ES6TODO: functions on EnumerableUtils should get their own export - var EnumerableUtils = __dependency21__["default"]; - var a_forEach = EnumerableUtils.forEach, - a_addObject = EnumerableUtils.addObject, - a_removeObject = EnumerableUtils.removeObject; + var forEach = __dependency18__.forEach; + var addObject = __dependency18__.addObject; + var removeObject = __dependency18__.removeObject; - var beforeObserver = __dependency15__.beforeObserver; - var copy = __dependency22__["default"]; - var isGlobalPath = __dependency23__.isGlobalPath; + var beforeObserver = __dependency13__.beforeObserver; + var copy = __dependency19__["default"]; + var isGlobalPath = __dependency20__.isGlobalPath; - var propertyWillChange = __dependency24__.propertyWillChange; - var propertyDidChange = __dependency24__.propertyDidChange; + var propertyWillChange = __dependency21__.propertyWillChange; + var propertyDidChange = __dependency21__.propertyDidChange; - var cloneStates = __dependency25__.cloneStates; - var states = __dependency25__.states; - var jQuery = __dependency26__["default"]; + var jQuery = __dependency22__["default"]; // for the side effect of extending Ember.run.queues + var CoreView = __dependency24__["default"]; + /** @module ember @submodule ember-views */ - - var ContainerView; - - function nullViewsBuffer(view) { - view.buffer = null; - - } - - function clearCachedElement(view) { - meta(view).cache.element = undefined; - } - var childViewsProperty = computed(function() { - var childViews = this._childViews, ret = A(), view = this; + var childViews = this._childViews; + var ret = emberA(); + var view = this; - a_forEach(childViews, function(view) { + forEach(childViews, function(view) { var currentChildViews; if (view.isVirtual) { if (currentChildViews = get(view, 'childViews')) { @@ -25352,12 +41308,6 @@ define("ember-views/views/view", }); ret.replace = function (idx, removedCount, addedViews) { - if (!ContainerView) { ContainerView = requireModule('ember-views/views/container_view')['default']; } // ES6TODO: stupid circular dep - - if (view instanceof ContainerView) { - Ember.deprecate("Manipulating an Ember.ContainerView through its childViews property is deprecated. Please use the ContainerView instance itself as an Ember.MutableArray."); - return view.replace(idx, removedCount, addedViews); - } throw new EmberError("childViews is immutable"); }; @@ -25377,240 +41327,6 @@ define("ember-views/views/view", */ Ember.TEMPLATES = {}; - /** - `Ember.CoreView` is an abstract class that exists to give view-like behavior - to both Ember's main view class `Ember.View` and other classes like - `Ember._SimpleMetamorphView` that don't need the fully functionaltiy of - `Ember.View`. - - Unless you have specific needs for `CoreView`, you will use `Ember.View` - in your applications. - - @class CoreView - @namespace Ember - @extends Ember.Object - @uses Ember.Evented - @uses Ember.ActionHandler - */ - - var CoreView = EmberObject.extend(Evented, ActionHandler, { - isView: true, - - states: cloneStates(states), - - init: function() { - this._super(); - this.transitionTo('preRender'); - this._isVisible = get(this, 'isVisible'); - }, - - /** - If the view is currently inserted into the DOM of a parent view, this - property will point to the parent of the view. - - @property parentView - @type Ember.View - @default null - */ - parentView: computed('_parentView', function() { - var parent = this._parentView; - - if (parent && parent.isVirtual) { - return get(parent, 'parentView'); - } else { - return parent; - } - }), - - state: null, - - _parentView: null, - - // return the current view, not including virtual views - concreteView: computed('parentView', function() { - if (!this.isVirtual) { return this; } - else { return get(this, 'parentView.concreteView'); } - }), - - instrumentName: 'core_view', - - instrumentDetails: function(hash) { - hash.object = this.toString(); - hash.containerKey = this._debugContainerKey; - hash.view = this; - }, - - /** - Invoked by the view system when this view needs to produce an HTML - representation. This method will create a new render buffer, if needed, - then apply any default attributes, such as class names and visibility. - Finally, the `render()` method is invoked, which is responsible for - doing the bulk of the rendering. - - You should not need to override this method; instead, implement the - `template` property, or if you need more control, override the `render` - method. - - @method renderToBuffer - @param {Ember.RenderBuffer} buffer the render buffer. If no buffer is - passed, a default buffer, using the current view's `tagName`, will - be used. - @private - */ - renderToBuffer: function(parentBuffer, bufferOperation) { - var name = 'render.' + this.instrumentName, - details = {}; - - this.instrumentDetails(details); - - return instrument(name, details, function instrumentRenderToBuffer() { - return this._renderToBuffer(parentBuffer, bufferOperation); - }, this); - }, - - _renderToBuffer: function(parentBuffer, bufferOperation) { - // If this is the top-most view, start a new buffer. Otherwise, - // create a new buffer relative to the original using the - // provided buffer operation (for example, `insertAfter` will - // insert a new buffer after the "parent buffer"). - var tagName = this.tagName; - - if (tagName === null || tagName === undefined) { - tagName = 'div'; - } - - var buffer = this.buffer = parentBuffer && parentBuffer.begin(tagName) || RenderBuffer(tagName); - this.transitionTo('inBuffer', false); - - this.beforeRender(buffer); - this.render(buffer); - this.afterRender(buffer); - - return buffer; - }, - - /** - Override the default event firing from `Ember.Evented` to - also call methods with the given name. - - @method trigger - @param name {String} - @private - */ - trigger: function(name) { - this._super.apply(this, arguments); - var method = this[name]; - if (method) { - var args = [], i, l; - for (i = 1, l = arguments.length; i < l; i++) { - args.push(arguments[i]); - } - return method.apply(this, args); - } - }, - - deprecatedSendHandles: function(actionName) { - return !!this[actionName]; - }, - - deprecatedSend: function(actionName) { - var args = [].slice.call(arguments, 1); - Ember.assert('' + this + " has the action " + actionName + " but it is not a function", typeof this[actionName] === 'function'); - Ember.deprecate('Action handlers implemented directly on views are deprecated in favor of action handlers on an `actions` object ( action: `' + actionName + '` on ' + this + ')', false); - this[actionName].apply(this, args); - return; - }, - - has: function(name) { - return typeOf(this[name]) === 'function' || this._super(name); - }, - - destroy: function() { - var parent = this._parentView; - - if (!this._super()) { return; } - - // destroy the element -- this will avoid each child view destroying - // the element over and over again... - if (!this.removedFromDOM) { this.destroyElement(); } - - // remove from parent if found. Don't call removeFromParent, - // as removeFromParent will try to remove the element from - // the DOM again. - if (parent) { parent.removeChild(this); } - - this.transitionTo('destroying', false); - - return this; - }, - - clearRenderedChildren: Ember.K, - triggerRecursively: Ember.K, - invokeRecursively: Ember.K, - transitionTo: Ember.K, - destroyElement: Ember.K - }); - - var ViewCollection = function(initialViews) { - var views = this.views = initialViews || []; - this.length = views.length; - }; - - ViewCollection.prototype = { - length: 0, - - trigger: function(eventName) { - var views = this.views, view; - for (var i = 0, l = views.length; i < l; i++) { - view = views[i]; - if (view.trigger) { view.trigger(eventName); } - } - }, - - triggerRecursively: function(eventName) { - var views = this.views; - for (var i = 0, l = views.length; i < l; i++) { - views[i].triggerRecursively(eventName); - } - }, - - invokeRecursively: function(fn) { - var views = this.views, view; - - for (var i = 0, l = views.length; i < l; i++) { - view = views[i]; - fn(view); - } - }, - - transitionTo: function(state, children) { - var views = this.views; - for (var i = 0, l = views.length; i < l; i++) { - views[i].transitionTo(state, children); - } - }, - - push: function() { - this.length += arguments.length; - var views = this.views; - return views.push.apply(views, arguments); - }, - - objectAt: function(idx) { - return this.views[idx]; - }, - - forEach: function(callback) { - var views = this.views; - return a_forEach(views, callback); - }, - - clear: function() { - this.length = 0; - this.views.length = 0; - } - }; - var EMPTY_ARRAY = []; /** @@ -25819,10 +41535,10 @@ define("ember-views/views/view", ```html ``` - - One property can be mapped on to another by placing a ":" between + + One property can be mapped on to another by placing a ":" between the source property and the destination property: - + ```javascript AnchorView = Ember.View.extend({ tagName: 'a', @@ -25830,13 +41546,13 @@ define("ember-views/views/view", url: 'http://google.com' }); ``` - + Will result in view instances with an HTML representation of: ```html ``` - + If the return value of an `attributeBindings` monitored property is a boolean the property will follow HTML's pattern of repeating the attribute's name as its value: @@ -25989,7 +41705,7 @@ define("ember-views/views/view", }); aView = AView.create({ - controller: aController, + controller: aController }); ``` @@ -26023,8 +41739,8 @@ define("ember-views/views/view", ```javascript AViewWithLayout = Ember.View.extend({ - layout: Ember.Handlebars.compile("
      {{yield}}
      ") - template: Ember.Handlebars.compile("I got wrapped"), + layout: Ember.Handlebars.compile("
      {{yield}}
      "), + template: Ember.Handlebars.compile("I got wrapped") }); ``` @@ -26110,8 +41826,9 @@ define("ember-views/views/view", on the descendent. ```javascript - OuterView = Ember.View.extend({ - template: Ember.Handlebars.compile("outer {{#view InnerView}}inner{{/view}} outer"), + var App = Ember.Application.create(); + App.OuterView = Ember.View.extend({ + template: Ember.Handlebars.compile("outer {{#view 'inner'}}inner{{/view}} outer"), eventManager: Ember.Object.create({ mouseEnter: function(event, view) { // view might be instance of either @@ -26121,7 +41838,7 @@ define("ember-views/views/view", }) }); - InnerView = Ember.View.extend({ + App.InnerView = Ember.View.extend({ click: function(event) { // will be called if rendered inside // an OuterView because OuterView's @@ -26265,8 +41982,8 @@ define("ember-views/views/view", template: computed('templateName', function(key, value) { if (value !== undefined) { return value; } - var templateName = get(this, 'templateName'), - template = this.templateForName(templateName, 'template'); + var templateName = get(this, 'templateName'); + var template = this.templateForName(templateName, 'template'); Ember.assert("You specified the templateName " + templateName + " for " + this + ", but it did not exist.", !templateName || template); @@ -26300,8 +42017,8 @@ define("ember-views/views/view", @type Function */ layout: computed(function(key) { - var layoutName = get(this, 'layoutName'), - layout = this.templateForName(layoutName, 'layout'); + var layoutName = get(this, 'layoutName'); + var layout = this.templateForName(layoutName, 'layout'); Ember.assert("You specified the layoutName " + layoutName + " for " + this + ", but it did not exist.", !layoutName || layout); @@ -26317,9 +42034,13 @@ define("ember-views/views/view", if (!name) { return; } Ember.assert("templateNames are not allowed to contain periods: "+name, name.indexOf('.') === -1); - // the defaultContainer is deprecated - var container = this.container || (Container && Container.defaultContainer); - return container && container.lookup('template:' + name); + if (!this.container) { + throw new EmberError('Container was not found when looking up a views template. ' + + 'This is most likely due to manually instantiating an Ember.View. ' + + 'See: http://git.io/EKPpnA'); + } + + return this.container.lookup('template:' + name); }, /** @@ -26341,7 +42062,7 @@ define("ember-views/views/view", } else { return get(this, '_context'); } - }).volatile(), + })["volatile"](), /** Private copy of the view's template context. This can be set directly @@ -26456,8 +42177,8 @@ define("ember-views/views/view", @return Ember.View */ nearestOfType: function(klass) { - var view = get(this, 'parentView'), - isOfType = klass instanceof Mixin ? + var view = get(this, 'parentView'); + var isOfType = klass instanceof Mixin ? function(view) { return klass.detect(view); } : function(view) { return klass.detect(view.constructor); }; @@ -26530,7 +42251,7 @@ define("ember-views/views/view", var templateData = get(this, 'templateData'); var keywords = templateData ? copy(templateData.keywords) : {}; - set(keywords, 'view', get(this, 'concreteView')); + set(keywords, 'view', this.isVirtual ? keywords.view : this); set(keywords, '_view', this); set(keywords, 'controller', get(this, 'controller')); @@ -26603,21 +42324,6 @@ define("ember-views/views/view", return this.currentState.rerender(this); }, - clearRenderedChildren: function() { - var lengthBefore = this.lengthBeforeRender, - lengthAfter = this.lengthAfterRender; - - // If there were child views created during the last call to render(), - // remove them under the assumption that they will be re-created when - // we re-render. - - // VIEW-TODO: Unit test this path. - var childViews = this._childViews; - for (var i=lengthAfter-1; i>=lengthBefore; i--) { - if (childViews[i]) { childViews[i].destroy(); } - } - }, - /** Iterates over the view's `classNameBindings` array, inserts the value of the specified property into the `classNames` array, then creates an @@ -26628,13 +42334,13 @@ define("ember-views/views/view", @private */ _applyClassNameBindings: function(classBindings) { - var classNames = this.classNames, - elem, newClass, dasherizedClass; + var classNames = this.classNames; + var elem, newClass, dasherizedClass; // Loop through all of the configured bindings. These will be either // property names ('isUrgent') or property paths relative to the view // ('content.isUrgent') - a_forEach(classBindings, function(binding) { + forEach(classBindings, function(binding) { Ember.assert("classNameBindings must not have spaces in them. Multiple class name bindings can be provided as elements of an array, e.g. ['foo', ':bar']", binding.indexOf(' ') === -1); @@ -26676,7 +42382,7 @@ define("ember-views/views/view", if (dasherizedClass) { // Ensure that it gets into the classNames array // so it is displayed when we render. - a_addObject(classNames, dasherizedClass); + addObject(classNames, dasherizedClass); // Save a reference to the class name so we can remove it // if the observer fires. Remember that this variable has @@ -26708,13 +42414,15 @@ define("ember-views/views/view", @private */ _applyAttributeBindings: function(buffer, attributeBindings) { - var attributeValue, - unspecifiedAttributeBindings = this._unspecifiedAttributeBindings = this._unspecifiedAttributeBindings || {}; + var attributeValue; + var unspecifiedAttributeBindings = this._unspecifiedAttributeBindings = this._unspecifiedAttributeBindings || {}; - a_forEach(attributeBindings, function(binding) { - var split = binding.split(':'), - property = split[0], - attributeName = split[1] || property; + forEach(attributeBindings, function(binding) { + var split = binding.split(':'); + var property = split[0]; + var attributeName = split[1] || property; + + Ember.assert('You cannot use class as an attributeBinding, use classNameBindings instead.', attributeName !== 'class'); if (property in this) { this._setupAttributeBindingObservation(property, attributeName); @@ -26804,13 +42512,7 @@ define("ember-views/views/view", @property element @type DOMElement */ - element: computed('_parentView', function(key, value) { - if (value !== undefined) { - return this.currentState.setElement(this, value); - } else { - return this.currentState.getElement(this); - } - }), + element: null, /** Returns a jQuery object for this view's element. If you pass in a selector @@ -26829,9 +42531,9 @@ define("ember-views/views/view", }, mutateChildViews: function(callback) { - var childViews = this._childViews, - idx = childViews.length, - view; + var childViews = this._childViews; + var idx = childViews.length; + var view; while(--idx >= 0) { view = childViews[idx]; @@ -26846,8 +42548,8 @@ define("ember-views/views/view", if (!childViews) { return this; } - var len = childViews.length, - view, idx; + var len = childViews.length; + var view, idx; for (idx = 0; idx < len; idx++) { view = childViews[idx]; @@ -26877,14 +42579,13 @@ define("ember-views/views/view", @param {String|DOMElement|jQuery} A selector, element, HTML string, or jQuery object @return {Ember.View} receiver */ - appendTo: function(target) { - // Schedule the DOM element to be created and appended to the given - // element after bindings have synchronized. - this._insertElementLater(function() { - Ember.assert("You tried to append to (" + target + ") but that isn't in the DOM", jQuery(target).length > 0); - Ember.assert("You cannot append to an existing Ember.View. Consider using Ember.ContainerView instead.", !jQuery(target).is('.ember-view') && !jQuery(target).parents().is('.ember-view')); - this.$().appendTo(target); - }); + appendTo: function(selector) { + var target = jQuery(selector); + + Ember.assert("You tried to append to (" + selector + ") but that isn't in the DOM", target.length > 0); + Ember.assert("You cannot append to an existing Ember.View. Consider using Ember.ContainerView instead.", !target.is('.ember-view') && !target.parents().is('.ember-view')); + + this.constructor.renderer.appendTo(this, target[0]); return this; }, @@ -26902,49 +42603,17 @@ define("ember-views/views/view", @param {String|DOMElement|jQuery} target A selector, element, HTML string, or jQuery object @return {Ember.View} received */ - replaceIn: function(target) { - Ember.assert("You tried to replace in (" + target + ") but that isn't in the DOM", jQuery(target).length > 0); - Ember.assert("You cannot replace an existing Ember.View. Consider using Ember.ContainerView instead.", !jQuery(target).is('.ember-view') && !jQuery(target).parents().is('.ember-view')); + replaceIn: function(selector) { + var target = jQuery(selector); - this._insertElementLater(function() { - jQuery(target).empty(); - this.$().appendTo(target); - }); + Ember.assert("You tried to replace in (" + selector + ") but that isn't in the DOM", target.length > 0); + Ember.assert("You cannot replace an existing Ember.View. Consider using Ember.ContainerView instead.", !target.is('.ember-view') && !target.parents().is('.ember-view')); + + this.constructor.renderer.replaceIn(this, target[0]); return this; }, - /** - Schedules a DOM operation to occur during the next render phase. This - ensures that all bindings have finished synchronizing before the view is - rendered. - - To use, pass a function that performs a DOM operation. - - Before your function is called, this view and all child views will receive - the `willInsertElement` event. After your function is invoked, this view - and all of its child views will receive the `didInsertElement` event. - - ```javascript - view._insertElementLater(function() { - this.createElement(); - this.$().appendTo('body'); - }); - ``` - - @method _insertElementLater - @param {Function} fn the function that inserts the element into the DOM - @private - */ - _insertElementLater: function(fn) { - this._scheduledInsert = run.scheduleOnce('render', this, '_insertElement', fn); - }, - - _insertElement: function (fn) { - this._scheduledInsert = null; - this.currentState.insertElement(this, fn); - }, - /** Appends the view's element to the document body. If the view does not have an HTML representation yet, `createElement()` will be called @@ -26978,9 +42647,6 @@ define("ember-views/views/view", // In the interim, we will just re-render if that happens. It is more // important than elements get garbage collected. if (!this.removedFromDOM) { this.destroyElement(); } - this.invokeRecursively(function(view) { - if (view.clearRenderedChildren) { view.clearRenderedChildren(); } - }); }, elementId: null, @@ -27002,20 +42668,20 @@ define("ember-views/views/view", }, /** - Creates a DOM representation of the view and all of its - child views by recursively calling the `render()` method. + Creates a DOM representation of the view and all of its child views by + recursively calling the `render()` method. - After the element has been created, `didInsertElement` will + After the element has been inserted into the DOM, `didInsertElement` will be called on this view and all of its child views. @method createElement @return {Ember.View} receiver */ createElement: function() { - if (get(this, 'element')) { return this; } + if (this.element) { return this; } - var buffer = this.renderToBuffer(); - set(this, 'element', buffer.element()); + this._didCreateElementWithoutMorph = true; + this.constructor.renderer.renderTree(this); return this; }, @@ -27032,6 +42698,9 @@ define("ember-views/views/view", or after the view was re-rendered. Override this function to do any set up that requires an element in the document body. + When a view has children, didInsertElement will be called on the + child view(s) first, bubbling upwards through the hierarchy. + @event didInsertElement */ didInsertElement: Ember.K, @@ -27045,65 +42714,6 @@ define("ember-views/views/view", */ willClearRender: Ember.K, - /** - Run this callback on the current view (unless includeSelf is false) and recursively on child views. - - @method invokeRecursively - @param fn {Function} - @param includeSelf {Boolean} Includes itself if true. - @private - */ - invokeRecursively: function(fn, includeSelf) { - var childViews = (includeSelf === false) ? this._childViews : [this]; - var currentViews, view, currentChildViews; - - while (childViews.length) { - currentViews = childViews.slice(); - childViews = []; - - for (var i=0, l=currentViews.length; i=0; i--) { - childViews[i].removedFromDOM = true; - } - // remove from non-virtual parent view if viewName was specified if (viewName && nonVirtualParentView) { nonVirtualParentView.set(viewName, null); } - childLen = childViews.length; - for (i=childLen-1; i>=0; i--) { - childViews[i].destroy(); - } - return this; }, @@ -27550,16 +43108,18 @@ define("ember-views/views/view", _toggleVisibility: function() { var $el = this.$(); - if (!$el) { return; } - var isVisible = get(this, 'isVisible'); if (this._isVisible === isVisible) { return ; } - $el.toggle(isVisible); - + // It's important to keep these in sync, even if we don't yet have + // an element in the DOM to manipulate: this._isVisible = isVisible; + if (!$el) { return; } + + $el.toggle(isVisible); + if (this._isAncestorHidden()) { return; } if (isVisible) { @@ -27603,25 +43163,17 @@ define("ember-views/views/view", return false; }, - - clearBuffer: function() { - this.invokeRecursively(nullViewsBuffer); - }, - transitionTo: function(state, children) { - var priorState = this.currentState, - currentState = this.currentState = this.states[state]; - this.state = state; + Ember.deprecate("Ember.View#transitionTo has been deprecated, it is for internal use only"); + this._transitionTo(state, children); + }, + _transitionTo: function(state, children) { + var priorState = this.currentState; + var currentState = this.currentState = this._states[state]; + this._state = state; if (priorState && priorState.exit) { priorState.exit(this); } if (currentState.enter) { currentState.enter(this); } - if (state === 'inDOM') { meta(this).cache.element = undefined; } - - if (children !== false) { - this.forEachChildView(function(view) { - view.transitionTo(state); - }); - } }, // ....................................................... @@ -27650,13 +43202,13 @@ define("ember-views/views/view", return; } - var view = this, - stateCheckedObserver = function() { - view.currentState.invokeObserver(this, observer); - }, - scheduledObserver = function() { - run.scheduleOnce('render', this, stateCheckedObserver); - }; + var view = this; + var stateCheckedObserver = function() { + view.currentState.invokeObserver(this, observer); + }; + var scheduledObserver = function() { + run.scheduleOnce('render', this, stateCheckedObserver); + }; addObserver(root, path, target, scheduledObserver); @@ -27666,6 +43218,8 @@ define("ember-views/views/view", } }); + deprecateProperty(View.prototype, 'state', '_state'); + deprecateProperty(View.prototype, 'states', '_states'); /* Describe how the specified actions should behave in the various @@ -27698,48 +43252,6 @@ define("ember-views/views/view", run.once(View, 'notifyMutationListeners'); } - var DOMManager = { - prepend: function(view, html) { - view.$().prepend(html); - notifyMutationListeners(); - }, - - after: function(view, html) { - view.$().after(html); - notifyMutationListeners(); - }, - - html: function(view, html) { - view.$().html(html); - notifyMutationListeners(); - }, - - replace: function(view) { - var element = get(view, 'element'); - - set(view, 'element', null); - - view._insertElementLater(function() { - jQuery(element).replaceWith(get(view, 'element')); - notifyMutationListeners(); - }); - }, - - remove: function(view) { - view.$().remove(); - notifyMutationListeners(); - }, - - empty: function(view) { - view.$().empty(); - notifyMutationListeners(); - } - }; - - View.reopen({ - domManager: DOMManager - }); - View.reopenClass({ /** @@ -27762,11 +43274,10 @@ define("ember-views/views/view", @private */ _parsePropertyPath: function(path) { - var split = path.split(':'), - propertyPath = split[0], - classNames = "", - className, - falsyClassName; + var split = path.split(':'); + var propertyPath = split[0]; + var classNames = ""; + var className, falsyClassName; // check if the property is defined as prop:class or prop:trueClass:falseClass if (split.length > 1) { @@ -27811,9 +43322,9 @@ define("ember-views/views/view", */ _classStringForValue: function(path, val, className, falsyClassName) { if(isArray(val)) { - val = get(val, 'length') !== 0; + val = get(val, 'length') !== 0; } - + // When using the colon syntax, evaluate the truthiness or falsiness // of the value to determine which className to return if (className || falsyClassName) { @@ -27850,7 +43361,7 @@ define("ember-views/views/view", }); var mutation = EmberObject.extend(Evented).create(); - + // TODO MOVE TO RENDERER HOOKS View.addMutationListener = function(callback) { mutation.on('change', callback); }; @@ -27891,7 +43402,12 @@ define("ember-views/views/view", if (isNone(value) || value === false) { // `null`, `undefined` or `false` should remove attribute elem.removeAttr(name); - elem.prop(name, ''); + // In IE8 `prop` couldn't remove attribute when name is `required`. + if (name === 'required') { + elem.removeProp(name); + } else { + elem.prop(name, ''); + } } else if (value !== elem.prop(name)) { // value should always be properties elem.prop(name, value); @@ -27901,11818 +43417,858 @@ define("ember-views/views/view", } }; - __exports__.CoreView = CoreView; - __exports__.View = View; - __exports__.ViewCollection = ViewCollection; + __exports__["default"] = View; }); -})(); - -(function() { -define("metamorph", - [], - function() { +enifed("ember", + ["ember-metal","ember-runtime","ember-handlebars","ember-views","ember-routing","ember-routing-handlebars","ember-application","ember-extension-support"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__) { "use strict"; - // ========================================================================== - // Project: metamorph - // Copyright: ©2014 Tilde, Inc. All rights reserved. - // ========================================================================== - - var K = function() {}, - guid = 0, - disableRange = (function(){ - if ('undefined' !== typeof MetamorphENV) { - return MetamorphENV.DISABLE_RANGE_API; - } else if ('undefined' !== ENV) { - return ENV.DISABLE_RANGE_API; - } else { - return false; - } - })(), - - // Feature-detect the W3C range API, the extended check is for IE9 which only partially supports ranges - supportsRange = (!disableRange) && typeof document !== 'undefined' && ('createRange' in document) && (typeof Range !== 'undefined') && Range.prototype.createContextualFragment, - - // Internet Explorer prior to 9 does not allow setting innerHTML if the first element - // is a "zero-scope" element. This problem can be worked around by making - // the first node an invisible text node. We, like Modernizr, use ­ - needsShy = typeof document !== 'undefined' && (function() { - var testEl = document.createElement('div'); - testEl.innerHTML = "
      "; - testEl.firstChild.innerHTML = ""; - return testEl.firstChild.innerHTML === ''; - })(), - - - // IE 8 (and likely earlier) likes to move whitespace preceeding - // a script tag to appear after it. This means that we can - // accidentally remove whitespace when updating a morph. - movesWhitespace = document && (function() { - var testEl = document.createElement('div'); - testEl.innerHTML = "Test: Value"; - return testEl.childNodes[0].nodeValue === 'Test:' && - testEl.childNodes[2].nodeValue === ' Value'; - })(); - - // Constructor that supports either Metamorph('foo') or new - // Metamorph('foo'); - // - // Takes a string of HTML as the argument. - - var Metamorph = function(html) { - var self; - - if (this instanceof Metamorph) { - self = this; - } else { - self = new K(); - } - - self.innerHTML = html; - var myGuid = 'metamorph-'+(guid++); - self.start = myGuid + '-start'; - self.end = myGuid + '-end'; - - return self; - }; - - K.prototype = Metamorph.prototype; - - var rangeFor, htmlFunc, removeFunc, outerHTMLFunc, appendToFunc, afterFunc, prependFunc, startTagFunc, endTagFunc; - - outerHTMLFunc = function() { - return this.startTag() + this.innerHTML + this.endTag(); - }; - - startTagFunc = function() { - /* - * We replace chevron by its hex code in order to prevent escaping problems. - * Check this thread for more explaination: - * http://stackoverflow.com/questions/8231048/why-use-x3c-instead-of-when-generating-html-from-javascript - */ - return "
    hi
    "; - * div.firstChild.firstChild.tagName //=> "" - * - * If our script markers are inside such a node, we need to find that - * node and use *it* as the marker. - */ - var realNode = function(start) { - while (start.parentNode.tagName === "") { - start = start.parentNode; - } - - return start; - }; - - /* - * When automatically adding a tbody, Internet Explorer inserts the - * tbody immediately before the first . Other browsers create it - * before the first node, no matter what. - * - * This means the the following code: - * - * div = document.createElement("div"); - * div.innerHTML = "
    hi
    - * - * Generates the following DOM in IE: - * - * + div - * + table - * - script id='first' - * + tbody - * + tr - * + td - * - "hi" - * - script id='last' - * - * Which means that the two script tags, even though they were - * inserted at the same point in the hierarchy in the original - * HTML, now have different parents. - * - * This code reparents the first script tag by making it the tbody's - * first child. - * - */ - var fixParentage = function(start, end) { - if (start.parentNode !== end.parentNode) { - end.parentNode.insertBefore(start, end.parentNode.firstChild); - } - }; - - htmlFunc = function(html, outerToo) { - // get the real starting node. see realNode for details. - var start = realNode(document.getElementById(this.start)); - var end = document.getElementById(this.end); - var parentNode = end.parentNode; - var node, nextSibling, last; - - // make sure that the start and end nodes share the same - // parent. If not, fix it. - fixParentage(start, end); - - // remove all of the nodes after the starting placeholder and - // before the ending placeholder. - node = start.nextSibling; - while (node) { - nextSibling = node.nextSibling; - last = node === end; - - // if this is the last node, and we want to remove it as well, - // set the `end` node to the next sibling. This is because - // for the rest of the function, we insert the new nodes - // before the end (note that insertBefore(node, null) is - // the same as appendChild(node)). - // - // if we do not want to remove it, just break. - if (last) { - if (outerToo) { end = node.nextSibling; } else { break; } - } - - node.parentNode.removeChild(node); - - // if this is the last node and we didn't break before - // (because we wanted to remove the outer nodes), break - // now. - if (last) { break; } - - node = nextSibling; - } - - // get the first node for the HTML string, even in cases like - // tables and lists where a simple innerHTML on a div would - // swallow some of the content. - node = firstNodeFor(start.parentNode, html); - - if (outerToo) { - start.parentNode.removeChild(start); - } - - // copy the nodes for the HTML between the starting and ending - // placeholder. - while (node) { - nextSibling = node.nextSibling; - parentNode.insertBefore(node, end); - node = nextSibling; - } - }; - - // remove the nodes in the DOM representing this metamorph. - // - // this includes the starting and ending placeholders. - removeFunc = function() { - var start = realNode(document.getElementById(this.start)); - var end = document.getElementById(this.end); - - this.html(''); - start.parentNode.removeChild(start); - end.parentNode.removeChild(end); - }; - - appendToFunc = function(parentNode) { - var node = firstNodeFor(parentNode, this.outerHTML()); - var nextSibling; - - while (node) { - nextSibling = node.nextSibling; - parentNode.appendChild(node); - node = nextSibling; - } - }; - - afterFunc = function(html) { - // get the real starting node. see realNode for details. - var end = document.getElementById(this.end); - var insertBefore = end.nextSibling; - var parentNode = end.parentNode; - var nextSibling; - var node; - - // get the first node for the HTML string, even in cases like - // tables and lists where a simple innerHTML on a div would - // swallow some of the content. - node = firstNodeFor(parentNode, html); - - // copy the nodes for the HTML between the starting and ending - // placeholder. - while (node) { - nextSibling = node.nextSibling; - parentNode.insertBefore(node, insertBefore); - node = nextSibling; - } - }; - - prependFunc = function(html) { - var start = document.getElementById(this.start); - var parentNode = start.parentNode; - var nextSibling; - var node; - - node = firstNodeFor(parentNode, html); - var insertBefore = start.nextSibling; - - while (node) { - nextSibling = node.nextSibling; - parentNode.insertBefore(node, insertBefore); - node = nextSibling; - } - }; + /* global navigator */ + // require the main entry points for each of these packages + // this is so that the global exports occur properly + + // do this to ensure that Ember.Test is defined properly on the global + // if it is present. + if (Ember.__loader.registry['ember-testing']) { + requireModule('ember-testing'); } - Metamorph.prototype.html = function(html) { - this.checkRemoved(); - if (html === undefined) { return this.innerHTML; } - - htmlFunc.call(this, html); - - this.innerHTML = html; - }; - - Metamorph.prototype.replaceWith = function(html) { - this.checkRemoved(); - htmlFunc.call(this, html, true); - }; - - Metamorph.prototype.remove = removeFunc; - Metamorph.prototype.outerHTML = outerHTMLFunc; - Metamorph.prototype.appendTo = appendToFunc; - Metamorph.prototype.after = afterFunc; - Metamorph.prototype.prepend = prependFunc; - Metamorph.prototype.startTag = startTagFunc; - Metamorph.prototype.endTag = endTagFunc; - - Metamorph.prototype.isRemoved = function() { - var before = document.getElementById(this.start); - var after = document.getElementById(this.end); - - return !before || !after; - }; - - Metamorph.prototype.checkRemoved = function() { - if (this.isRemoved()) { - throw new Error("Cannot perform operations on a Metamorph that is not in the DOM."); - } - }; - - return Metamorph; - }); - -})(); - -(function() { -define("ember-handlebars-compiler", - ["ember-metal/core","exports"], - function(__dependency1__, __exports__) { - "use strict"; /** + Ember + @module ember - @submodule ember-handlebars-compiler */ - var Ember = __dependency1__["default"]; - - // ES6Todo: you'll need to import debugger once debugger is es6'd. - if (typeof Ember.assert === 'undefined') { Ember.assert = function(){}; }; - if (typeof Ember.FEATURES === 'undefined') { Ember.FEATURES = { isEnabled: function(){} }; }; - - var objectCreate = Object.create || function(parent) { - function F() {} - F.prototype = parent; - return new F(); - }; - - // set up for circular references later - var View, Component; - - // ES6Todo: when ember-debug is es6'ed import this. - // var emberAssert = Ember.assert; - var Handlebars = (Ember.imports && Ember.imports.Handlebars) || (this && this.Handlebars); - if (!Handlebars && typeof require === 'function') { - Handlebars = require('handlebars'); - } - - Ember.assert("Ember Handlebars requires Handlebars version 1.0 or 1.1. Include " + - "a SCRIPT tag in the HTML HEAD linking to the Handlebars file " + - "before you link to Ember.", Handlebars); - - Ember.assert("Ember Handlebars requires Handlebars version 1.0 or 1.1, " + - "COMPILER_REVISION expected: 4, got: " + Handlebars.COMPILER_REVISION + - " - Please note: Builds of master may have other COMPILER_REVISION values.", - Handlebars.COMPILER_REVISION === 4); - - /** - Prepares the Handlebars templating library for use inside Ember's view - system. - - The `Ember.Handlebars` object is the standard Handlebars library, extended to - use Ember's `get()` method instead of direct property access, which allows - computed properties to be used inside templates. - - To create an `Ember.Handlebars` template, call `Ember.Handlebars.compile()`. - This will return a function that can be used by `Ember.View` for rendering. - - @class Handlebars - @namespace Ember - */ - var EmberHandlebars = Ember.Handlebars = objectCreate(Handlebars); - - /** - Register a bound helper or custom view helper. - - ## Simple bound helper example - - ```javascript - Ember.Handlebars.helper('capitalize', function(value) { - return value.toUpperCase(); - }); - ``` - - The above bound helper can be used inside of templates as follows: - - ```handlebars - {{capitalize name}} - ``` - - In this case, when the `name` property of the template's context changes, - the rendered value of the helper will update to reflect this change. - - For more examples of bound helpers, see documentation for - `Ember.Handlebars.registerBoundHelper`. - - ## Custom view helper example - - Assuming a view subclass named `App.CalendarView` were defined, a helper - for rendering instances of this view could be registered as follows: - - ```javascript - Ember.Handlebars.helper('calendar', App.CalendarView): - ``` - - The above bound helper can be used inside of templates as follows: - - ```handlebars - {{calendar}} - ``` - - Which is functionally equivalent to: - - ```handlebars - {{view App.CalendarView}} - ``` - - Options in the helper will be passed to the view in exactly the same - manner as with the `view` helper. - - @method helper - @for Ember.Handlebars - @param {String} name - @param {Function|Ember.View} function or view class constructor - @param {String} dependentKeys* - */ - EmberHandlebars.helper = function(name, value) { - if (!View) { View = requireModule('ember-views/views/view')['View']; } // ES6TODO: stupid circular dep - if (!Component) { Component = requireModule('ember-views/views/component')['default']; } // ES6TODO: stupid circular dep - - Ember.assert("You tried to register a component named '" + name + "', but component names must include a '-'", !Component.detect(value) || name.match(/-/)); - - if (View.detect(value)) { - EmberHandlebars.registerHelper(name, EmberHandlebars.makeViewHelper(value)); - } else { - EmberHandlebars.registerBoundHelper.apply(null, arguments); - } - }; - - /** - Returns a helper function that renders the provided ViewClass. - - Used internally by Ember.Handlebars.helper and other methods - involving helper/component registration. - - @private - @method makeViewHelper - @for Ember.Handlebars - @param {Function} ViewClass view class constructor - @since 1.2.0 - */ - EmberHandlebars.makeViewHelper = function(ViewClass) { - return function(options) { - Ember.assert("You can only pass attributes (such as name=value) not bare values to a helper for a View found in '" + ViewClass.toString() + "'", arguments.length < 2); - return EmberHandlebars.helpers.view.call(this, ViewClass, options); - }; - }; - - /** - @class helpers - @namespace Ember.Handlebars - */ - EmberHandlebars.helpers = objectCreate(Handlebars.helpers); - - /** - Override the the opcode compiler and JavaScript compiler for Handlebars. - - @class Compiler - @namespace Ember.Handlebars - @private - @constructor - */ - EmberHandlebars.Compiler = function() {}; - - // Handlebars.Compiler doesn't exist in runtime-only - if (Handlebars.Compiler) { - EmberHandlebars.Compiler.prototype = objectCreate(Handlebars.Compiler.prototype); - } - - EmberHandlebars.Compiler.prototype.compiler = EmberHandlebars.Compiler; - - /** - @class JavaScriptCompiler - @namespace Ember.Handlebars - @private - @constructor - */ - EmberHandlebars.JavaScriptCompiler = function() {}; - - // Handlebars.JavaScriptCompiler doesn't exist in runtime-only - if (Handlebars.JavaScriptCompiler) { - EmberHandlebars.JavaScriptCompiler.prototype = objectCreate(Handlebars.JavaScriptCompiler.prototype); - EmberHandlebars.JavaScriptCompiler.prototype.compiler = EmberHandlebars.JavaScriptCompiler; - } - - - EmberHandlebars.JavaScriptCompiler.prototype.namespace = "Ember.Handlebars"; - - EmberHandlebars.JavaScriptCompiler.prototype.initializeBuffer = function() { - return "''"; - }; - - /** - Override the default buffer for Ember Handlebars. By default, Handlebars - creates an empty String at the beginning of each invocation and appends to - it. Ember's Handlebars overrides this to append to a single shared buffer. - - @private - @method appendToBuffer - @param string {String} - */ - EmberHandlebars.JavaScriptCompiler.prototype.appendToBuffer = function(string) { - return "data.buffer.push("+string+");"; - }; - - // Hacks ahead: - // Handlebars presently has a bug where the `blockHelperMissing` hook - // doesn't get passed the name of the missing helper name, but rather - // gets passed the value of that missing helper evaluated on the current - // context, which is most likely `undefined` and totally useless. - // - // So we alter the compiled template function to pass the name of the helper - // instead, as expected. - // - // This can go away once the following is closed: - // https://github.com/wycats/handlebars.js/issues/634 - - var DOT_LOOKUP_REGEX = /helpers\.(.*?)\)/, - BRACKET_STRING_LOOKUP_REGEX = /helpers\['(.*?)'/, - INVOCATION_SPLITTING_REGEX = /(.*blockHelperMissing\.call\(.*)(stack[0-9]+)(,.*)/; - - EmberHandlebars.JavaScriptCompiler.stringifyLastBlockHelperMissingInvocation = function(source) { - var helperInvocation = source[source.length - 1], - helperName = (DOT_LOOKUP_REGEX.exec(helperInvocation) || BRACKET_STRING_LOOKUP_REGEX.exec(helperInvocation))[1], - matches = INVOCATION_SPLITTING_REGEX.exec(helperInvocation); - - source[source.length - 1] = matches[1] + "'" + helperName + "'" + matches[3]; - }; - - var stringifyBlockHelperMissing = EmberHandlebars.JavaScriptCompiler.stringifyLastBlockHelperMissingInvocation; - - var originalBlockValue = EmberHandlebars.JavaScriptCompiler.prototype.blockValue; - EmberHandlebars.JavaScriptCompiler.prototype.blockValue = function() { - originalBlockValue.apply(this, arguments); - stringifyBlockHelperMissing(this.source); - }; - - var originalAmbiguousBlockValue = EmberHandlebars.JavaScriptCompiler.prototype.ambiguousBlockValue; - EmberHandlebars.JavaScriptCompiler.prototype.ambiguousBlockValue = function() { - originalAmbiguousBlockValue.apply(this, arguments); - stringifyBlockHelperMissing(this.source); - }; - - /** - Rewrite simple mustaches from `{{foo}}` to `{{bind "foo"}}`. This means that - all simple mustaches in Ember's Handlebars will also set up an observer to - keep the DOM up to date when the underlying property changes. - - @private - @method mustache - @for Ember.Handlebars.Compiler - @param mustache - */ - EmberHandlebars.Compiler.prototype.mustache = function(mustache) { - if (!(mustache.params.length || mustache.hash)) { - var id = new Handlebars.AST.IdNode([{ part: '_triageMustache' }]); - - // Update the mustache node to include a hash value indicating whether the original node - // was escaped. This will allow us to properly escape values when the underlying value - // changes and we need to re-render the value. - if (!mustache.escaped) { - mustache.hash = mustache.hash || new Handlebars.AST.HashNode([]); - mustache.hash.pairs.push(["unescaped", new Handlebars.AST.StringNode("true")]); - } - mustache = new Handlebars.AST.MustacheNode([id].concat([mustache.id]), mustache.hash, !mustache.escaped); - } - - return Handlebars.Compiler.prototype.mustache.call(this, mustache); - }; - - /** - Used for precompilation of Ember Handlebars templates. This will not be used - during normal app execution. - - @method precompile - @for Ember.Handlebars - @static - @param {String} string The template to precompile - @param {Boolean} asObject optional parameter, defaulting to true, of whether or not the - compiled template should be returned as an Object or a String - */ - EmberHandlebars.precompile = function(string, asObject) { - var ast = Handlebars.parse(string); - - var options = { - knownHelpers: { - action: true, - unbound: true, - 'bind-attr': true, - template: true, - view: true, - _triageMustache: true - }, - data: true, - stringParams: true - }; - - asObject = asObject === undefined ? true : asObject; - - var environment = new EmberHandlebars.Compiler().compile(ast, options); - return new EmberHandlebars.JavaScriptCompiler().compile(environment, options, undefined, asObject); - }; - - // We don't support this for Handlebars runtime-only - if (Handlebars.compile) { - /** - The entry point for Ember Handlebars. This replaces the default - `Handlebars.compile` and turns on template-local data and String - parameters. - - @method compile - @for Ember.Handlebars - @static - @param {String} string The template to compile - @return {Function} - */ - EmberHandlebars.compile = function(string) { - var ast = Handlebars.parse(string); - var options = { data: true, stringParams: true }; - var environment = new EmberHandlebars.Compiler().compile(ast, options); - var templateSpec = new EmberHandlebars.JavaScriptCompiler().compile(environment, options, undefined, true); - - var template = EmberHandlebars.template(templateSpec); - template.isMethod = false; //Make sure we don't wrap templates with ._super - - return template; - }; - } - - __exports__["default"] = EmberHandlebars; + Ember.deprecate('Usage of Ember is deprecated for Internet Explorer 6 and 7, support will be removed in the next major version.', !navigator.userAgent.match(/MSIE [67]/)); }); -})(); - -(function() { -define("ember-handlebars/component_lookup", - ["ember-runtime/system/object","exports"], - function(__dependency1__, __exports__) { - "use strict"; - var EmberObject = __dependency1__["default"]; - - var ComponentLookup = EmberObject.extend({ - lookupFactory: function(name, container) { - - container = container || this.container; - - var fullName = 'component:' + name, - templateFullName = 'template:components/' + name, - templateRegistered = container && container.has(templateFullName); - - if (templateRegistered) { - container.injection(fullName, 'layout', templateFullName); - } - - var Component = container.lookupFactory(fullName); - - // Only treat as a component if either the component - // or a template has been registered. - if (templateRegistered || Component) { - if (!Component) { - container.register(fullName, Ember.Component); - Component = container.lookupFactory(fullName); - } - return Component; - } - } - }); - - __exports__["default"] = ComponentLookup; - }); -define("ember-handlebars/controls", - ["ember-handlebars/controls/checkbox","ember-handlebars/controls/text_field","ember-handlebars/controls/text_area","ember-metal/core","ember-handlebars-compiler","exports"], - function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __exports__) { - "use strict"; - var Checkbox = __dependency1__["default"]; - var TextField = __dependency2__["default"]; - var TextArea = __dependency3__["default"]; - - var Ember = __dependency4__["default"]; - // Ember.assert - // var emberAssert = Ember.assert; - - var EmberHandlebars = __dependency5__["default"]; - var helpers = EmberHandlebars.helpers; - /** - @module ember - @submodule ember-handlebars-compiler - */ - - /** - - The `{{input}}` helper inserts an HTML `` tag into the template, - with a `type` value of either `text` or `checkbox`. If no `type` is provided, - `text` will be the default value applied. The attributes of `{{input}}` - match those of the native HTML tag as closely as possible for these two types. - - ## Use as text field - An `{{input}}` with no `type` or a `type` of `text` will render an HTML text input. - The following HTML attributes can be set via the helper: - - - - - - - - - - - - -
    `readonly``required``autofocus`
    `value``placeholder``disabled`
    `size``tabindex``maxlength`
    `name``min``max`
    `pattern``accept``autocomplete`
    `autosave``formaction``formenctype`
    `formmethod``formnovalidate``formtarget`
    `height``inputmode``multiple`
    `step``width``form`
    `selectionDirection``spellcheck` 
    - - - When set to a quoted string, these values will be directly applied to the HTML - element. When left unquoted, these values will be bound to a property on the - template's current rendering context (most typically a controller instance). - - ## Unbound: - - ```handlebars - {{input value="http://www.facebook.com"}} - ``` - - - ```html - - ``` - - ## Bound: - - ```javascript - App.ApplicationController = Ember.Controller.extend({ - firstName: "Stanley", - entryNotAllowed: true - }); - ``` - - - ```handlebars - {{input type="text" value=firstName disabled=entryNotAllowed size="50"}} - ``` - - - ```html - - ``` - - ## Extension - - Internally, `{{input type="text"}}` creates an instance of `Ember.TextField`, passing - arguments from the helper to `Ember.TextField`'s `create` method. You can extend the - capabilities of text inputs in your applications by reopening this class. For example, - if you are building a Bootstrap project where `data-*` attributes are used, you - can add one to the `TextField`'s `attributeBindings` property: - - - ```javascript - Ember.TextField.reopen({ - attributeBindings: ['data-error'] - }); - ``` - - Keep in mind when writing `Ember.TextField` subclasses that `Ember.TextField` - itself extends `Ember.Component`, meaning that it does NOT inherit - the `controller` of the parent view. - - See more about [Ember components](api/classes/Ember.Component.html) - - - ## Use as checkbox - - An `{{input}}` with a `type` of `checkbox` will render an HTML checkbox input. - The following HTML attributes can be set via the helper: - - * `checked` - * `disabled` - * `tabindex` - * `indeterminate` - * `name` - * `autofocus` - * `form` - - - When set to a quoted string, these values will be directly applied to the HTML - element. When left unquoted, these values will be bound to a property on the - template's current rendering context (most typically a controller instance). - - ## Unbound: - - ```handlebars - {{input type="checkbox" name="isAdmin"}} - ``` - - ```html - - ``` - - ## Bound: - - ```javascript - App.ApplicationController = Ember.Controller.extend({ - isAdmin: true - }); - ``` - - - ```handlebars - {{input type="checkbox" checked=isAdmin }} - ``` - - - ```html - - ``` - - ## Extension - - Internally, `{{input type="checkbox"}}` creates an instance of `Ember.Checkbox`, passing - arguments from the helper to `Ember.Checkbox`'s `create` method. You can extend the - capablilties of checkbox inputs in your applications by reopening this class. For example, - if you wanted to add a css class to all checkboxes in your application: - - - ```javascript - Ember.Checkbox.reopen({ - classNames: ['my-app-checkbox'] - }); - ``` - - - @method input - @for Ember.Handlebars.helpers - @param {Hash} options - */ - function inputHelper(options) { - Ember.assert('You can only pass attributes to the `input` helper, not arguments', arguments.length < 2); - - var hash = options.hash, - types = options.hashTypes, - inputType = hash.type, - onEvent = hash.on; - - delete hash.type; - delete hash.on; - - if (inputType === 'checkbox') { - Ember.assert("{{input type='checkbox'}} does not support setting `value=someBooleanValue`; you must use `checked=someBooleanValue` instead.", options.hashTypes.value !== 'ID'); - return helpers.view.call(this, Checkbox, options); - } else { - if (inputType) { hash.type = inputType; } - hash.onEvent = onEvent || 'enter'; - return helpers.view.call(this, TextField, options); - } - } - - /** - `{{textarea}}` inserts a new instance of ` - ``` - - Bound: - - In the following example, the `writtenWords` property on `App.ApplicationController` - will be updated live as the user types 'Lots of text that IS bound' into - the text area of their browser's window. - - ```javascript - App.ApplicationController = Ember.Controller.extend({ - writtenWords: "Lots of text that IS bound" - }); - ``` - - ```handlebars - {{textarea value=writtenWords}} - ``` - - Would result in the following HTML: - - ```html - - ``` - - If you wanted a one way binding between the text area and a div tag - somewhere else on your screen, you could use `Ember.computed.oneWay`: - - ```javascript - App.ApplicationController = Ember.Controller.extend({ - writtenWords: "Lots of text that IS bound", - outputWrittenWords: Ember.computed.oneWay("writtenWords") - }); - ``` - - ```handlebars - {{textarea value=writtenWords}} - -
    - {{outputWrittenWords}} -
    - ``` - - Would result in the following HTML: - - ```html - - - <-- the following div will be updated in real time as you type --> - -
    - Lots of text that IS bound -
    - ``` - - Finally, this example really shows the power and ease of Ember when two - properties are bound to eachother via `Ember.computed.alias`. Type into - either text area box and they'll both stay in sync. Note that - `Ember.computed.alias` costs more in terms of performance, so only use it when - your really binding in both directions: - - ```javascript - App.ApplicationController = Ember.Controller.extend({ - writtenWords: "Lots of text that IS bound", - twoWayWrittenWords: Ember.computed.alias("writtenWords") - }); - ``` - - ```handlebars - {{textarea value=writtenWords}} - {{textarea value=twoWayWrittenWords}} - ``` - - ```html - - - <-- both updated in real time --> - - - ``` - - ## Extension - - Internally, `{{textarea}}` creates an instance of `Ember.TextArea`, passing - arguments from the helper to `Ember.TextArea`'s `create` method. You can - extend the capabilities of text areas in your application by reopening this - class. For example, if you are building a Bootstrap project where `data-*` - attributes are used, you can globally add support for a `data-*` attribute - on all `{{textarea}}`s' in your app by reopening `Ember.TextArea` or - `Ember.TextSupport` and adding it to the `attributeBindings` concatenated - property: - - ```javascript - Ember.TextArea.reopen({ - attributeBindings: ['data-error'] - }); - ``` - - Keep in mind when writing `Ember.TextArea` subclasses that `Ember.TextArea` - itself extends `Ember.Component`, meaning that it does NOT inherit - the `controller` of the parent view. - - See more about [Ember components](api/classes/Ember.Component.html) - - @method textarea - @for Ember.Handlebars.helpers - @param {Hash} options - */ - function textareaHelper(options) { - Ember.assert('You can only pass attributes to the `textarea` helper, not arguments', arguments.length < 2); - - var hash = options.hash, - types = options.hashTypes; - - return helpers.view.call(this, TextArea, options); - } - - __exports__.inputHelper = inputHelper; - __exports__.textareaHelper = textareaHelper; - }); -define("ember-handlebars/controls/checkbox", - ["ember-metal/property_get","ember-metal/property_set","ember-views/views/view","exports"], - function(__dependency1__, __dependency2__, __dependency3__, __exports__) { - "use strict"; - var get = __dependency1__.get; - var set = __dependency2__.set; - var View = __dependency3__.View; - - /** - @module ember - @submodule ember-handlebars - */ - - /** - The internal class used to create text inputs when the `{{input}}` - helper is used with `type` of `checkbox`. - - See [handlebars.helpers.input](/api/classes/Ember.Handlebars.helpers.html#method_input) for usage details. - - ## Direct manipulation of `checked` - - The `checked` attribute of an `Ember.Checkbox` object should always be set - through the Ember object or by interacting with its rendered element - representation via the mouse, keyboard, or touch. Updating the value of the - checkbox via jQuery will result in the checked value of the object and its - element losing synchronization. - - ## Layout and LayoutName properties - - Because HTML `input` elements are self closing `layout` and `layoutName` - properties will not be applied. See [Ember.View](/api/classes/Ember.View.html)'s - layout section for more information. - - @class Checkbox - @namespace Ember - @extends Ember.View - */ - var Checkbox = View.extend({ - instrumentDisplay: '{{input type="checkbox"}}', - - classNames: ['ember-checkbox'], - - tagName: 'input', - - attributeBindings: ['type', 'checked', 'indeterminate', 'disabled', 'tabindex', 'name', - 'autofocus', 'required', 'form'], - - type: "checkbox", - checked: false, - disabled: false, - indeterminate: false, - - init: function() { - this._super(); - this.on("change", this, this._updateElementValue); - }, - - didInsertElement: function() { - this._super(); - get(this, 'element').indeterminate = !!get(this, 'indeterminate'); - }, - - _updateElementValue: function() { - set(this, 'checked', this.$().prop('checked')); - } - }); - - __exports__["default"] = Checkbox; - }); -define("ember-handlebars/controls/select", - ["ember-handlebars-compiler","ember-metal/enumerable_utils","ember-metal/property_get","ember-metal/property_set","ember-views/views/view","ember-views/views/collection_view","ember-metal/utils","ember-metal/is_none","ember-metal/computed","ember-runtime/system/native_array","ember-metal/mixin","ember-metal/properties","exports"], - function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __dependency9__, __dependency10__, __dependency11__, __dependency12__, __exports__) { - "use strict"; - /*jshint eqeqeq:false newcap:false */ - - /** - @module ember - @submodule ember-handlebars - */ - - var EmberHandlebars = __dependency1__["default"]; - var EnumerableUtils = __dependency2__["default"]; - var get = __dependency3__.get; - var set = __dependency4__.set; - var View = __dependency5__.View; - var CollectionView = __dependency6__["default"]; - var isArray = __dependency7__.isArray; - var isNone = __dependency8__["default"]; - var computed = __dependency9__.computed; - var A = __dependency10__.A; - var observer = __dependency11__.observer; - var defineProperty = __dependency12__.defineProperty; - - var indexOf = EnumerableUtils.indexOf, - indexesOf = EnumerableUtils.indexesOf, - forEach = EnumerableUtils.forEach, - replace = EnumerableUtils.replace, - precompileTemplate = EmberHandlebars.compile; - - var SelectOption = View.extend({ - instrumentDisplay: 'Ember.SelectOption', - - tagName: 'option', - attributeBindings: ['value', 'selected'], - - defaultTemplate: function(context, options) { - options = { data: options.data, hash: {} }; - EmberHandlebars.helpers.bind.call(context, "view.label", options); - }, - - init: function() { - this.labelPathDidChange(); - this.valuePathDidChange(); - - this._super(); - }, - - selected: computed(function() { - var content = get(this, 'content'), - selection = get(this, 'parentView.selection'); - if (get(this, 'parentView.multiple')) { - return selection && indexOf(selection, content.valueOf()) > -1; - } else { - // Primitives get passed through bindings as objects... since - // `new Number(4) !== 4`, we use `==` below - return content == selection; - } - }).property('content', 'parentView.selection'), - - labelPathDidChange: observer('parentView.optionLabelPath', function() { - var labelPath = get(this, 'parentView.optionLabelPath'); - - if (!labelPath) { return; } - - defineProperty(this, 'label', computed(function() { - return get(this, labelPath); - }).property(labelPath)); - }), - - valuePathDidChange: observer('parentView.optionValuePath', function() { - var valuePath = get(this, 'parentView.optionValuePath'); - - if (!valuePath) { return; } - - defineProperty(this, 'value', computed(function() { - return get(this, valuePath); - }).property(valuePath)); - }) - }); - - var SelectOptgroup = CollectionView.extend({ - instrumentDisplay: 'Ember.SelectOptgroup', - - tagName: 'optgroup', - attributeBindings: ['label'], - - selectionBinding: 'parentView.selection', - multipleBinding: 'parentView.multiple', - optionLabelPathBinding: 'parentView.optionLabelPath', - optionValuePathBinding: 'parentView.optionValuePath', - - itemViewClassBinding: 'parentView.optionView' - }); - - /** - The `Ember.Select` view class renders a - [select](https://developer.mozilla.org/en/HTML/Element/select) HTML element, - allowing the user to choose from a list of options. - - The text and `value` property of each ` - - - ``` - - The `value` attribute of the selected `"); - return buffer; - } - -function program3(depth0,data) { - - var stack1; - stack1 = helpers.each.call(depth0, "view.groupedContent", {hash:{},hashTypes:{},hashContexts:{},inverse:self.noop,fn:self.program(4, program4, data),contexts:[depth0],types:["ID"],data:data}); - if(stack1 || stack1 === 0) { data.buffer.push(stack1); } - else { data.buffer.push(''); } - } -function program4(depth0,data) { - - - data.buffer.push(escapeExpression(helpers.view.call(depth0, "view.groupView", {hash:{ - 'content': ("content"), - 'label': ("label") - },hashTypes:{'content': "ID",'label': "ID"},hashContexts:{'content': depth0,'label': depth0},contexts:[depth0],types:["ID"],data:data}))); - } - -function program6(depth0,data) { - - var stack1; - stack1 = helpers.each.call(depth0, "view.content", {hash:{},hashTypes:{},hashContexts:{},inverse:self.noop,fn:self.program(7, program7, data),contexts:[depth0],types:["ID"],data:data}); - if(stack1 || stack1 === 0) { data.buffer.push(stack1); } - else { data.buffer.push(''); } - } -function program7(depth0,data) { - - - data.buffer.push(escapeExpression(helpers.view.call(depth0, "view.optionView", {hash:{ - 'content': ("") - },hashTypes:{'content': "ID"},hashContexts:{'content': depth0},contexts:[depth0],types:["ID"],data:data}))); - } - - stack1 = helpers['if'].call(depth0, "view.prompt", {hash:{},hashTypes:{},hashContexts:{},inverse:self.noop,fn:self.program(1, program1, data),contexts:[depth0],types:["ID"],data:data}); - if(stack1 || stack1 === 0) { data.buffer.push(stack1); } - stack1 = helpers['if'].call(depth0, "view.optionGroupPath", {hash:{},hashTypes:{},hashContexts:{},inverse:self.program(6, program6, data),fn:self.program(3, program3, data),contexts:[depth0],types:["ID"],data:data}); - if(stack1 || stack1 === 0) { data.buffer.push(stack1); } - return buffer; - -}), - attributeBindings: ['multiple', 'disabled', 'tabindex', 'name', 'required', 'autofocus', - 'form', 'size'], - - /** - The `multiple` attribute of the select element. Indicates whether multiple - options can be selected. - - @property multiple - @type Boolean - @default false - */ - multiple: false, - - /** - The `disabled` attribute of the select element. Indicates whether - the element is disabled from interactions. - - @property disabled - @type Boolean - @default false - */ - disabled: false, - - /** - The `required` attribute of the select element. Indicates whether - a selected option is required for form validation. - - @property required - @type Boolean - @default false - @since 1.5.0 - */ - required: false, - - /** - The list of options. - - If `optionLabelPath` and `optionValuePath` are not overridden, this should - be a list of strings, which will serve simultaneously as labels and values. - - Otherwise, this should be a list of objects. For instance: - - ```javascript - Ember.Select.create({ - content: A([ - { id: 1, firstName: 'Yehuda' }, - { id: 2, firstName: 'Tom' } - ]), - optionLabelPath: 'content.firstName', - optionValuePath: 'content.id' - }); - ``` - - @property content - @type Array - @default null - */ - content: null, - - /** - When `multiple` is `false`, the element of `content` that is currently - selected, if any. - - When `multiple` is `true`, an array of such elements. - - @property selection - @type Object or Array - @default null - */ - selection: null, - - /** - In single selection mode (when `multiple` is `false`), value can be used to - get the current selection's value or set the selection by it's value. - - It is not currently supported in multiple selection mode. - - @property value - @type String - @default null - */ - value: computed(function(key, value) { - if (arguments.length === 2) { return value; } - var valuePath = get(this, 'optionValuePath').replace(/^content\.?/, ''); - return valuePath ? get(this, 'selection.' + valuePath) : get(this, 'selection'); - }).property('selection'), - - /** - If given, a top-most dummy option will be rendered to serve as a user - prompt. - - @property prompt - @type String - @default null - */ - prompt: null, - - /** - The path of the option labels. See [content](/api/classes/Ember.Select.html#property_content). - - @property optionLabelPath - @type String - @default 'content' - */ - optionLabelPath: 'content', - - /** - The path of the option values. See [content](/api/classes/Ember.Select.html#property_content). - - @property optionValuePath - @type String - @default 'content' - */ - optionValuePath: 'content', - - /** - The path of the option group. - When this property is used, `content` should be sorted by `optionGroupPath`. - - @property optionGroupPath - @type String - @default null - */ - optionGroupPath: null, - - /** - The view class for optgroup. - - @property groupView - @type Ember.View - @default Ember.SelectOptgroup - */ - groupView: SelectOptgroup, - - groupedContent: computed(function() { - var groupPath = get(this, 'optionGroupPath'); - var groupedContent = A(); - var content = get(this, 'content') || []; - - forEach(content, function(item) { - var label = get(item, groupPath); - - if (get(groupedContent, 'lastObject.label') !== label) { - groupedContent.pushObject({ - label: label, - content: A() - }); - } - - get(groupedContent, 'lastObject.content').push(item); - }); - - return groupedContent; - }).property('optionGroupPath', 'content.@each'), - - /** - The view class for option. - - @property optionView - @type Ember.View - @default Ember.SelectOption - */ - optionView: SelectOption, - - _change: function() { - if (get(this, 'multiple')) { - this._changeMultiple(); - } else { - this._changeSingle(); - } - }, - - selectionDidChange: observer('selection.@each', function() { - var selection = get(this, 'selection'); - if (get(this, 'multiple')) { - if (!isArray(selection)) { - set(this, 'selection', A([selection])); - return; - } - this._selectionDidChangeMultiple(); - } else { - this._selectionDidChangeSingle(); - } - }), - - valueDidChange: observer('value', function() { - var content = get(this, 'content'), - value = get(this, 'value'), - valuePath = get(this, 'optionValuePath').replace(/^content\.?/, ''), - selectedValue = (valuePath ? get(this, 'selection.' + valuePath) : get(this, 'selection')), - selection; - - if (value !== selectedValue) { - selection = content ? content.find(function(obj) { - return value === (valuePath ? get(obj, valuePath) : obj); - }) : null; - - this.set('selection', selection); - } - }), - - - _triggerChange: function() { - var selection = get(this, 'selection'); - var value = get(this, 'value'); - - if (!isNone(selection)) { this.selectionDidChange(); } - if (!isNone(value)) { this.valueDidChange(); } - - this._change(); - }, - - _changeSingle: function() { - var selectedIndex = this.$()[0].selectedIndex, - content = get(this, 'content'), - prompt = get(this, 'prompt'); - - if (!content || !get(content, 'length')) { return; } - if (prompt && selectedIndex === 0) { set(this, 'selection', null); return; } - - if (prompt) { selectedIndex -= 1; } - set(this, 'selection', content.objectAt(selectedIndex)); - }, - - - _changeMultiple: function() { - var options = this.$('option:selected'), - prompt = get(this, 'prompt'), - offset = prompt ? 1 : 0, - content = get(this, 'content'), - selection = get(this, 'selection'); - - if (!content) { return; } - if (options) { - var selectedIndexes = options.map(function() { - return this.index - offset; - }).toArray(); - var newSelection = content.objectsAt(selectedIndexes); - - if (isArray(selection)) { - replace(selection, 0, get(selection, 'length'), newSelection); - } else { - set(this, 'selection', newSelection); - } - } - }, - - _selectionDidChangeSingle: function() { - var el = this.get('element'); - if (!el) { return; } - - var content = get(this, 'content'), - selection = get(this, 'selection'), - selectionIndex = content ? indexOf(content, selection) : -1, - prompt = get(this, 'prompt'); - - if (prompt) { selectionIndex += 1; } - if (el) { el.selectedIndex = selectionIndex; } - }, - - _selectionDidChangeMultiple: function() { - var content = get(this, 'content'), - selection = get(this, 'selection'), - selectedIndexes = content ? indexesOf(content, selection) : [-1], - prompt = get(this, 'prompt'), - offset = prompt ? 1 : 0, - options = this.$('option'), - adjusted; - - if (options) { - options.each(function() { - adjusted = this.index > -1 ? this.index - offset : -1; - this.selected = indexOf(selectedIndexes, adjusted) > -1; - }); - } - }, - - init: function() { - this._super(); - this.on("didInsertElement", this, this._triggerChange); - this.on("change", this, this._change); - } - }); - - __exports__["default"] = Select - __exports__.Select = Select; - __exports__.SelectOption = SelectOption; - __exports__.SelectOptgroup = SelectOptgroup; - }); -define("ember-handlebars/controls/text_area", - ["ember-metal/property_get","ember-views/views/component","ember-handlebars/controls/text_support","ember-metal/mixin","exports"], - function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __exports__) { - "use strict"; - - /** - @module ember - @submodule ember-handlebars - */ - var get = __dependency1__.get; - var Component = __dependency2__["default"]; - var TextSupport = __dependency3__["default"]; - var observer = __dependency4__.observer; - - /** - The internal class used to create textarea element when the `{{textarea}}` - helper is used. - - See [handlebars.helpers.textarea](/api/classes/Ember.Handlebars.helpers.html#method_textarea) for usage details. - - ## Layout and LayoutName properties - - Because HTML `textarea` elements do not contain inner HTML the `layout` and - `layoutName` properties will not be applied. See [Ember.View](/api/classes/Ember.View.html)'s - layout section for more information. - - @class TextArea - @namespace Ember - @extends Ember.Component - @uses Ember.TextSupport - */ - var TextArea = Component.extend(TextSupport, { - instrumentDisplay: '{{textarea}}', - - classNames: ['ember-text-area'], - - tagName: "textarea", - attributeBindings: ['rows', 'cols', 'name', 'selectionEnd', 'selectionStart', 'wrap'], - rows: null, - cols: null, - - _updateElementValue: observer('value', function() { - // We do this check so cursor position doesn't get affected in IE - var value = get(this, 'value'), - $el = this.$(); - if ($el && value !== $el.val()) { - $el.val(value); - } - }), - - init: function() { - this._super(); - this.on("didInsertElement", this, this._updateElementValue); - } - - }); - - __exports__["default"] = TextArea; - }); -define("ember-handlebars/controls/text_field", - ["ember-metal/property_get","ember-metal/property_set","ember-views/views/component","ember-handlebars/controls/text_support","exports"], - function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __exports__) { - "use strict"; - /** - @module ember - @submodule ember-handlebars - */ - - var get = __dependency1__.get; - var set = __dependency2__.set; - var Component = __dependency3__["default"]; - var TextSupport = __dependency4__["default"]; - - /** - - The internal class used to create text inputs when the `{{input}}` - helper is used with `type` of `text`. - - See [Handlebars.helpers.input](/api/classes/Ember.Handlebars.helpers.html#method_input) for usage details. - - ## Layout and LayoutName properties - - Because HTML `input` elements are self closing `layout` and `layoutName` - properties will not be applied. See [Ember.View](/api/classes/Ember.View.html)'s - layout section for more information. - - @class TextField - @namespace Ember - @extends Ember.Component - @uses Ember.TextSupport - */ - var TextField = Component.extend(TextSupport, { - instrumentDisplay: '{{input type="text"}}', - - classNames: ['ember-text-field'], - tagName: "input", - attributeBindings: ['type', 'value', 'size', 'pattern', 'name', 'min', 'max', - 'accept', 'autocomplete', 'autosave', 'formaction', - 'formenctype', 'formmethod', 'formnovalidate', 'formtarget', - 'height', 'inputmode', 'list', 'multiple', 'pattern', 'step', - 'width'], - - /** - The `value` attribute of the input element. As the user inputs text, this - property is updated live. - - @property value - @type String - @default "" - */ - value: "", - - /** - The `type` attribute of the input element. - - @property type - @type String - @default "text" - */ - type: "text", - - /** - The `size` of the text field in characters. - - @property size - @type String - @default null - */ - size: null, - - /** - The `pattern` attribute of input element. - - @property pattern - @type String - @default null - */ - pattern: null, - - /** - The `min` attribute of input element used with `type="number"` or `type="range"`. - - @property min - @type String - @default null - @since 1.4.0 - */ - min: null, - - /** - The `max` attribute of input element used with `type="number"` or `type="range"`. - - @property max - @type String - @default null - @since 1.4.0 - */ - max: null - }); - - __exports__["default"] = TextField; - }); -define("ember-handlebars/controls/text_support", - ["ember-metal/property_get","ember-metal/property_set","ember-metal/mixin","ember-runtime/mixins/target_action_support","exports"], - function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __exports__) { - "use strict"; - /** - @module ember - @submodule ember-handlebars - */ - - var get = __dependency1__.get; - var set = __dependency2__.set; - var Mixin = __dependency3__.Mixin; - var TargetActionSupport = __dependency4__["default"]; - - /** - Shared mixin used by `Ember.TextField` and `Ember.TextArea`. - - @class TextSupport - @namespace Ember - @uses Ember.TargetActionSupport - @extends Ember.Mixin - @private - */ - var TextSupport = Mixin.create(TargetActionSupport, { - value: "", - - attributeBindings: ['placeholder', 'disabled', 'maxlength', 'tabindex', 'readonly', - 'autofocus', 'form', 'selectionDirection', 'spellcheck', 'required', - 'title', 'autocapitalize', 'autocorrect'], - placeholder: null, - disabled: false, - maxlength: null, - - init: function() { - this._super(); - this.on("focusOut", this, this._elementValueDidChange); - this.on("change", this, this._elementValueDidChange); - this.on("paste", this, this._elementValueDidChange); - this.on("cut", this, this._elementValueDidChange); - this.on("input", this, this._elementValueDidChange); - this.on("keyUp", this, this.interpretKeyEvents); - }, - - /** - The action to be sent when the user presses the return key. - - This is similar to the `{{action}}` helper, but is fired when - the user presses the return key when editing a text field, and sends - the value of the field as the context. - - @property action - @type String - @default null - */ - action: null, - - /** - The event that should send the action. - - Options are: - - * `enter`: the user pressed enter - * `keyPress`: the user pressed a key - - @property onEvent - @type String - @default enter - */ - onEvent: 'enter', - - /** - Whether they `keyUp` event that triggers an `action` to be sent continues - propagating to other views. - - By default, when the user presses the return key on their keyboard and - the text field has an `action` set, the action will be sent to the view's - controller and the key event will stop propagating. - - If you would like parent views to receive the `keyUp` event even after an - action has been dispatched, set `bubbles` to true. - - @property bubbles - @type Boolean - @default false - */ - bubbles: false, - - interpretKeyEvents: function(event) { - var map = TextSupport.KEY_EVENTS; - var method = map[event.keyCode]; - - this._elementValueDidChange(); - if (method) { return this[method](event); } - }, - - _elementValueDidChange: function() { - set(this, 'value', this.$().val()); - }, - - /** - The action to be sent when the user inserts a new line. - - Called by the `Ember.TextSupport` mixin on keyUp if keycode matches 13. - Uses sendAction to send the `enter` action to the controller. - - @method insertNewline - @param {Event} event - */ - insertNewline: function(event) { - sendAction('enter', this, event); - sendAction('insert-newline', this, event); - }, - - /** - Called when the user hits escape. - - Called by the `Ember.TextSupport` mixin on keyUp if keycode matches 27. - Uses sendAction to send the `escape-press` action to the controller. - - @method cancel - @param {Event} event - */ - cancel: function(event) { - sendAction('escape-press', this, event); - }, - - /** - Called when the text area is focused. - - @method focusIn - @param {Event} event - */ - focusIn: function(event) { - sendAction('focus-in', this, event); - }, - - /** - Called when the text area is blurred. - - @method focusOut - @param {Event} event - */ - focusOut: function(event) { - sendAction('focus-out', this, event); - }, - - /** - The action to be sent when the user presses a key. Enabled by setting - the `onEvent` property to `keyPress`. - - Uses sendAction to send the `keyPress` action to the controller. - - @method keyPress - @param {Event} event - */ - keyPress: function(event) { - sendAction('key-press', this, event); - } - - }); - - TextSupport.KEY_EVENTS = { - 13: 'insertNewline', - 27: 'cancel' - }; - - // In principle, this shouldn't be necessary, but the legacy - // sendAction semantics for TextField are different from - // the component semantics so this method normalizes them. - function sendAction(eventName, view, event) { - var action = get(view, eventName), - on = get(view, 'onEvent'), - value = get(view, 'value'); - - // back-compat support for keyPress as an event name even though - // it's also a method name that consumes the event (and therefore - // incompatible with sendAction semantics). - if (on === eventName || (on === 'keyPress' && eventName === 'key-press')) { - view.sendAction('action', value); - } - - view.sendAction(eventName, value); - - if (action || on === eventName) { - if(!get(view, 'bubbles')) { - event.stopPropagation(); - } - } - } - - __exports__["default"] = TextSupport; - }); -define("ember-handlebars/ext", - ["ember-metal/core","ember-runtime/system/string","ember-handlebars-compiler","ember-metal/property_get","ember-metal/binding","ember-metal/error","ember-metal/mixin","ember-metal/is_empty","exports"], - function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __exports__) { - "use strict"; - var Ember = __dependency1__["default"]; - // Ember.FEATURES, Ember.assert, Ember.Handlebars, Ember.lookup - // var emberAssert = Ember.assert; - - var fmt = __dependency2__.fmt; - - var EmberHandlebars = __dependency3__["default"]; - var helpers = EmberHandlebars.helpers; - - var get = __dependency4__.get; - var isGlobalPath = __dependency5__.isGlobalPath; - var EmberError = __dependency6__["default"]; - var IS_BINDING = __dependency7__.IS_BINDING; - - // late bound via requireModule because of circular dependencies. - var resolveHelper, - SimpleHandlebarsView; - - var isEmpty = __dependency8__["default"]; - - var slice = [].slice, originalTemplate = EmberHandlebars.template; - - /** - If a path starts with a reserved keyword, returns the root - that should be used. - - @private - @method normalizePath - @for Ember - @param root {Object} - @param path {String} - @param data {Hash} - */ - function normalizePath(root, path, data) { - var keywords = (data && data.keywords) || {}, - keyword, isKeyword; - - // Get the first segment of the path. For example, if the - // path is "foo.bar.baz", returns "foo". - keyword = path.split('.', 1)[0]; - - // Test to see if the first path is a keyword that has been - // passed along in the view's data hash. If so, we will treat - // that object as the new root. - if (keywords.hasOwnProperty(keyword)) { - // Look up the value in the template's data hash. - root = keywords[keyword]; - isKeyword = true; - - // Handle cases where the entire path is the reserved - // word. In that case, return the object itself. - if (path === keyword) { - path = ''; - } else { - // Strip the keyword from the path and look up - // the remainder from the newly found root. - path = path.substr(keyword.length+1); - } - } - - return { root: root, path: path, isKeyword: isKeyword }; - }; - - - /** - Lookup both on root and on window. If the path starts with - a keyword, the corresponding object will be looked up in the - template's data hash and used to resolve the path. - - @method get - @for Ember.Handlebars - @param {Object} root The object to look up the property on - @param {String} path The path to be lookedup - @param {Object} options The template's option hash - */ - function handlebarsGet(root, path, options) { - var data = options && options.data, - normalizedPath = normalizePath(root, path, data), - value; - - - root = normalizedPath.root; - path = normalizedPath.path; - - value = get(root, path); - - if (value === undefined && root !== Ember.lookup && isGlobalPath(path)) { - value = get(Ember.lookup, path); - } - - - return value; - } - - /** - This method uses `Ember.Handlebars.get` to lookup a value, then ensures - that the value is escaped properly. - - If `unescaped` is a truthy value then the escaping will not be performed. - - @method getEscaped - @for Ember.Handlebars - @param {Object} root The object to look up the property on - @param {String} path The path to be lookedup - @param {Object} options The template's option hash - @since 1.4.0 - */ - function getEscaped(root, path, options) { - var result = handlebarsGet(root, path, options); - - if (result === null || result === undefined) { - result = ""; - } else if (!(result instanceof Handlebars.SafeString)) { - result = String(result); - } - if (!options.hash.unescaped){ - result = Handlebars.Utils.escapeExpression(result); - } - - return result; - }; - - function resolveParams(context, params, options) { - var resolvedParams = [], types = options.types, param, type; - - for (var i=0, l=params.length; i{{user.name}} - -
    -
    {{user.role.label}}
    - {{user.role.id}} - -

    {{user.role.description}}

    -
    - ``` - - `{{with}}` can be our best friend in these cases, - instead of writing `user.role.*` over and over, we use `{{#with user.role}}`. - Now the context within the `{{#with}} .. {{/with}}` block is `user.role` so you can do the following: - - ```handlebars -
    {{user.name}}
    - -
    - {{#with user.role}} -
    {{label}}
    - {{id}} - -

    {{description}}

    - {{/with}} -
    - ``` - - ### `as` operator - - This operator aliases the scope to a new name. It's helpful for semantic clarity and to retain - default scope or to reference from another `{{with}}` block. - - ```handlebars - // posts might not be - {{#with user.posts as blogPosts}} -
    - There are {{blogPosts.length}} blog posts written by {{user.name}}. -
    - - {{#each post in blogPosts}} -
  • {{post.title}}
  • - {{/each}} - {{/with}} - ``` - - Without the `as` operator, it would be impossible to reference `user.name` in the example above. - - NOTE: The alias should not reuse a name from the bound property path. - For example: `{{#with foo.bar as foo}}` is not supported because it attempts to alias using - the first part of the property path, `foo`. Instead, use `{{#with foo.bar as baz}}`. - - ### `controller` option - - Adding `controller='something'` instructs the `{{with}}` helper to create and use an instance of - the specified controller with the new context as its content. - - This is very similar to using an `itemController` option with the `{{each}}` helper. - - ```handlebars - {{#with users.posts controller='userBlogPosts'}} - {{!- The current context is wrapped in our controller instance }} - {{/with}} - ``` - - In the above example, the template provided to the `{{with}}` block is now wrapped in the - `userBlogPost` controller, which provides a very elegant way to decorate the context with custom - functions/properties. - - @method with - @for Ember.Handlebars.helpers - @param {Function} context - @param {Hash} options - @return {String} HTML string - */ - function withHelper(context, options) { - var bindContext, preserveContext, controller, helperName = 'with'; - - if (arguments.length === 4) { - var keywordName, path, rootPath, normalized, contextPath; - - Ember.assert("If you pass more than one argument to the with helper, it must be in the form #with foo as bar", arguments[1] === "as"); - options = arguments[3]; - keywordName = arguments[2]; - path = arguments[0]; - - if (path) { - helperName += ' ' + path + ' as ' + keywordName; - } - - Ember.assert("You must pass a block to the with helper", options.fn && options.fn !== Handlebars.VM.noop); - - var localizedOptions = o_create(options); - localizedOptions.data = o_create(options.data); - localizedOptions.data.keywords = o_create(options.data.keywords || {}); - - if (isGlobalPath(path)) { - contextPath = path; - } else { - normalized = normalizePath(this, path, options.data); - path = normalized.path; - rootPath = normalized.root; - - // This is a workaround for the fact that you cannot bind separate objects - // together. When we implement that functionality, we should use it here. - var contextKey = jQuery.expando + guidFor(rootPath); - localizedOptions.data.keywords[contextKey] = rootPath; - // if the path is '' ("this"), just bind directly to the current context - contextPath = path ? contextKey + '.' + path : contextKey; - } - - localizedOptions.hash.keywordName = keywordName; - localizedOptions.hash.keywordPath = contextPath; - - bindContext = this; - context = path; - options = localizedOptions; - preserveContext = true; - } else { - Ember.assert("You must pass exactly one argument to the with helper", arguments.length === 2); - Ember.assert("You must pass a block to the with helper", options.fn && options.fn !== Handlebars.VM.noop); - - helperName += ' ' + context; - bindContext = options.contexts[0]; - preserveContext = false; - } - - options.helperName = helperName; - options.isWithHelper = true; - - return bind.call(bindContext, context, options, preserveContext, exists); - } - /** - See [boundIf](/api/classes/Ember.Handlebars.helpers.html#method_boundIf) - and [unboundIf](/api/classes/Ember.Handlebars.helpers.html#method_unboundIf) - - @method if - @for Ember.Handlebars.helpers - @param {Function} context - @param {Hash} options - @return {String} HTML string - */ - function ifHelper(context, options) { - Ember.assert("You must pass exactly one argument to the if helper", arguments.length === 2); - Ember.assert("You must pass a block to the if helper", options.fn && options.fn !== Handlebars.VM.noop); - - options.helperName = options.helperName || ('if ' + context); - - if (options.data.isUnbound) { - return helpers.unboundIf.call(options.contexts[0], context, options); - } else { - return helpers.boundIf.call(options.contexts[0], context, options); - } - } - - /** - @method unless - @for Ember.Handlebars.helpers - @param {Function} context - @param {Hash} options - @return {String} HTML string - */ - function unlessHelper(context, options) { - Ember.assert("You must pass exactly one argument to the unless helper", arguments.length === 2); - Ember.assert("You must pass a block to the unless helper", options.fn && options.fn !== Handlebars.VM.noop); - - var fn = options.fn, inverse = options.inverse, helperName = 'unless'; - - if (context) { - helperName += ' ' + context; - } - - options.fn = inverse; - options.inverse = fn; - - options.helperName = options.helperName || helperName; - - if (options.data.isUnbound) { - return helpers.unboundIf.call(options.contexts[0], context, options); - } else { - return helpers.boundIf.call(options.contexts[0], context, options); - } - } - - /** - `bind-attr` allows you to create a binding between DOM element attributes and - Ember objects. For example: - - ```handlebars - imageTitle - ``` - - The above handlebars template will fill the ``'s `src` attribute will - the value of the property referenced with `"imageUrl"` and its `alt` - attribute with the value of the property referenced with `"imageTitle"`. - - If the rendering context of this template is the following object: - - ```javascript - { - imageUrl: 'http://lolcats.info/haz-a-funny', - imageTitle: 'A humorous image of a cat' - } - ``` - - The resulting HTML output will be: - - ```html - A humorous image of a cat - ``` - - `bind-attr` cannot redeclare existing DOM element attributes. The use of `src` - in the following `bind-attr` example will be ignored and the hard coded value - of `src="/failwhale.gif"` will take precedence: - - ```handlebars - imageTitle - ``` - - ### `bind-attr` and the `class` attribute - - `bind-attr` supports a special syntax for handling a number of cases unique - to the `class` DOM element attribute. The `class` attribute combines - multiple discrete values into a single attribute as a space-delimited - list of strings. Each string can be: - - * a string return value of an object's property. - * a boolean return value of an object's property - * a hard-coded value - - A string return value works identically to other uses of `bind-attr`. The - return value of the property will become the value of the attribute. For - example, the following view and template: - - ```javascript - AView = View.extend({ - someProperty: function() { - return "aValue"; - }.property() - }) - ``` - - ```handlebars - - ``` - - A boolean return value will insert a specified class name if the property - returns `true` and remove the class name if the property returns `false`. - - A class name is provided via the syntax - `somePropertyName:class-name-if-true`. - - ```javascript - AView = View.extend({ - someBool: true - }) - ``` - - ```handlebars - - ``` - - Result in the following rendered output: - - ```html - - ``` - - An additional section of the binding can be provided if you want to - replace the existing class instead of removing it when the boolean - value changes: - - ```handlebars - - ``` - - A hard-coded value can be used by prepending `:` to the desired - class name: `:class-name-to-always-apply`. - - ```handlebars - - ``` - - Results in the following rendered output: - - ```html - - ``` - - All three strategies - string return value, boolean return value, and - hard-coded value – can be combined in a single declaration: - - ```handlebars - - ``` - - @method bind-attr - @for Ember.Handlebars.helpers - @param {Hash} options - @return {String} HTML string - */ - function bindAttrHelper(options) { - var attrs = options.hash; - - Ember.assert("You must specify at least one hash argument to bind-attr", !!keys(attrs).length); - - var view = options.data.view; - var ret = []; - - // we relied on the behavior of calling without - // context to mean this === window, but when running - // "use strict", it's possible for this to === undefined; - var ctx = this || window; - - // Generate a unique id for this element. This will be added as a - // data attribute to the element so it can be looked up when - // the bound property changes. - var dataId = ++Ember.uuid; - - // Handle classes differently, as we can bind multiple classes - var classBindings = attrs['class']; - if (classBindings != null) { - var classResults = bindClasses(ctx, classBindings, view, dataId, options); - - ret.push('class="' + Handlebars.Utils.escapeExpression(classResults.join(' ')) + '"'); - delete attrs['class']; - } - - var attrKeys = keys(attrs); - - // For each attribute passed, create an observer and emit the - // current value of the property as an attribute. - forEach.call(attrKeys, function(attr) { - var path = attrs[attr], - normalized; - - Ember.assert(fmt("You must provide an expression as the value of bound attribute. You specified: %@=%@", [attr, path]), typeof path === 'string'); - - normalized = normalizePath(ctx, path, options.data); - - var value = (path === 'this') ? normalized.root : handlebarsGet(ctx, path, options), - type = typeOf(value); - - Ember.assert(fmt("Attributes must be numbers, strings or booleans, not %@", [value]), value === null || value === undefined || type === 'number' || type === 'string' || type === 'boolean'); - - var observer, invoker; - - observer = function observer() { - var result = handlebarsGet(ctx, path, options); - - Ember.assert(fmt("Attributes must be numbers, strings or booleans, not %@", [result]), - result === null || result === undefined || typeof result === 'number' || - typeof result === 'string' || typeof result === 'boolean'); - - var elem = view.$("[data-bindattr-" + dataId + "='" + dataId + "']"); - - // If we aren't able to find the element, it means the element - // to which we were bound has been removed from the view. - // In that case, we can assume the template has been re-rendered - // and we need to clean up the observer. - if (!elem || elem.length === 0) { - removeObserver(normalized.root, normalized.path, invoker); - return; - } - - View.applyAttributeBindings(elem, attr, result); - }; - - // Add an observer to the view for when the property changes. - // When the observer fires, find the element using the - // unique data id and update the attribute to the new value. - // Note: don't add observer when path is 'this' or path - // is whole keyword e.g. {{#each x in list}} ... {{bind-attr attr="x"}} - if (path !== 'this' && !(normalized.isKeyword && normalized.path === '' )) { - view.registerObserver(normalized.root, normalized.path, observer); - } - - // if this changes, also change the logic in ember-views/lib/views/view.js - if ((type === 'string' || (type === 'number' && !isNaN(value)))) { - ret.push(attr + '="' + Handlebars.Utils.escapeExpression(value) + '"'); - } else if (value && type === 'boolean') { - // The developer controls the attr name, so it should always be safe - ret.push(attr + '="' + attr + '"'); - } - }, this); - - // Add the unique identifier - // NOTE: We use all lower-case since Firefox has problems with mixed case in SVG - ret.push('data-bindattr-' + dataId + '="' + dataId + '"'); - return new SafeString(ret.join(' ')); - } - - /** - See `bind-attr` - - @method bindAttr - @for Ember.Handlebars.helpers - @deprecated - @param {Function} context - @param {Hash} options - @return {String} HTML string - */ - function bindAttrHelperDeprecated() { - Ember.warn("The 'bindAttr' view helper is deprecated in favor of 'bind-attr'"); - return helpers['bind-attr'].apply(this, arguments); - } - - /** - Helper that, given a space-separated string of property paths and a context, - returns an array of class names. Calling this method also has the side - effect of setting up observers at those property paths, such that if they - change, the correct class name will be reapplied to the DOM element. - - For example, if you pass the string "fooBar", it will first look up the - "fooBar" value of the context. If that value is true, it will add the - "foo-bar" class to the current element (i.e., the dasherized form of - "fooBar"). If the value is a string, it will add that string as the class. - Otherwise, it will not add any new class name. - - @private - @method bindClasses - @for Ember.Handlebars - @param {Ember.Object} context The context from which to lookup properties - @param {String} classBindings A string, space-separated, of class bindings - to use - @param {View} view The view in which observers should look for the - element to update - @param {Srting} bindAttrId Optional bindAttr id used to lookup elements - @return {Array} An array of class names to add - */ - function bindClasses(context, classBindings, view, bindAttrId, options) { - var ret = [], newClass, value, elem; - - // Helper method to retrieve the property from the context and - // determine which class string to return, based on whether it is - // a Boolean or not. - var classStringForPath = function(root, parsedPath, options) { - var val, - path = parsedPath.path; - - if (path === 'this') { - val = root; - } else if (path === '') { - val = true; - } else { - val = handlebarsGet(root, path, options); - } - - return View._classStringForValue(path, val, parsedPath.className, parsedPath.falsyClassName); - }; - - // For each property passed, loop through and setup - // an observer. - forEach.call(classBindings.split(' '), function(binding) { - - // Variable in which the old class value is saved. The observer function - // closes over this variable, so it knows which string to remove when - // the property changes. - var oldClass; - - var observer, invoker; - - var parsedPath = View._parsePropertyPath(binding), - path = parsedPath.path, - pathRoot = context, - normalized; - - if (path !== '' && path !== 'this') { - normalized = normalizePath(context, path, options.data); - - pathRoot = normalized.root; - path = normalized.path; - } - - // Set up an observer on the context. If the property changes, toggle the - // class name. - observer = function() { - // Get the current value of the property - newClass = classStringForPath(context, parsedPath, options); - elem = bindAttrId ? view.$("[data-bindattr-" + bindAttrId + "='" + bindAttrId + "']") : view.$(); - - // If we can't find the element anymore, a parent template has been - // re-rendered and we've been nuked. Remove the observer. - if (!elem || elem.length === 0) { - removeObserver(pathRoot, path, invoker); - } else { - // If we had previously added a class to the element, remove it. - if (oldClass) { - elem.removeClass(oldClass); - } - - // If necessary, add a new class. Make sure we keep track of it so - // it can be removed in the future. - if (newClass) { - elem.addClass(newClass); - oldClass = newClass; - } else { - oldClass = null; - } - } - }; - - if (path !== '' && path !== 'this') { - view.registerObserver(pathRoot, path, observer); - } - - // We've already setup the observer; now we just need to figure out the - // correct behavior right now on the first pass through. - value = classStringForPath(context, parsedPath, options); - - if (value) { - ret.push(value); - - // Make sure we save the current value so that it can be removed if the - // observer fires. - oldClass = value; - } - }); - - return ret; - }; - - __exports__.bind = bind; - __exports__._triageMustacheHelper = _triageMustacheHelper; - __exports__.resolveHelper = resolveHelper; - __exports__.bindHelper = bindHelper; - __exports__.boundIfHelper = boundIfHelper; - __exports__.unboundIfHelper = unboundIfHelper; - __exports__.withHelper = withHelper; - __exports__.ifHelper = ifHelper; - __exports__.unlessHelper = unlessHelper; - __exports__.bindAttrHelper = bindAttrHelper; - __exports__.bindAttrHelperDeprecated = bindAttrHelperDeprecated; - __exports__.bindClasses = bindClasses; - }); -define("ember-handlebars/helpers/collection", - ["ember-metal/core","ember-metal/utils","ember-handlebars-compiler","ember-runtime/system/string","ember-metal/property_get","ember-handlebars/ext","ember-handlebars/helpers/view","ember-metal/computed","ember-views/views/collection_view","exports"], - function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __dependency9__, __exports__) { - "use strict"; - /** - @module ember - @submodule ember-handlebars - */ - - var Ember = __dependency1__["default"]; - // Ember.assert, Ember.deprecate - var inspect = __dependency2__.inspect; - - // var emberAssert = Ember.assert; - // emberDeprecate = Ember.deprecate; - - var EmberHandlebars = __dependency3__["default"]; - var helpers = EmberHandlebars.helpers; - - var fmt = __dependency4__.fmt; - var get = __dependency5__.get; - var handlebarsGet = __dependency6__.handlebarsGet; - var ViewHelper = __dependency7__.ViewHelper; - var computed = __dependency8__.computed; - var CollectionView = __dependency9__["default"]; - - var alias = computed.alias; - /** - `{{collection}}` is a `Ember.Handlebars` helper for adding instances of - `Ember.CollectionView` to a template. See [Ember.CollectionView](/api/classes/Ember.CollectionView.html) - for additional information on how a `CollectionView` functions. - - `{{collection}}`'s primary use is as a block helper with a `contentBinding` - option pointing towards an `Ember.Array`-compatible object. An `Ember.View` - instance will be created for each item in its `content` property. Each view - will have its own `content` property set to the appropriate item in the - collection. - - The provided block will be applied as the template for each item's view. - - Given an empty `` the following template: - - ```handlebars - {{#collection contentBinding="App.items"}} - Hi {{view.content.name}} - {{/collection}} - ``` - - And the following application code - - ```javascript - App = Ember.Application.create() - App.items = [ - Ember.Object.create({name: 'Dave'}), - Ember.Object.create({name: 'Mary'}), - Ember.Object.create({name: 'Sara'}) - ] - ``` - - Will result in the HTML structure below - - ```html -
    -
    Hi Dave
    -
    Hi Mary
    -
    Hi Sara
    -
    - ``` - - ### Blockless use in a collection - - If you provide an `itemViewClass` option that has its own `template` you can - omit the block. - - The following template: - - ```handlebars - {{collection contentBinding="App.items" itemViewClass="App.AnItemView"}} - ``` - - And application code - - ```javascript - App = Ember.Application.create(); - App.items = [ - Ember.Object.create({name: 'Dave'}), - Ember.Object.create({name: 'Mary'}), - Ember.Object.create({name: 'Sara'}) - ]; - - App.AnItemView = Ember.View.extend({ - template: Ember.Handlebars.compile("Greetings {{view.content.name}}") - }); - ``` - - Will result in the HTML structure below - - ```html -
    -
    Greetings Dave
    -
    Greetings Mary
    -
    Greetings Sara
    -
    - ``` - - ### Specifying a CollectionView subclass - - By default the `{{collection}}` helper will create an instance of - `Ember.CollectionView`. You can supply a `Ember.CollectionView` subclass to - the helper by passing it as the first argument: - - ```handlebars - {{#collection App.MyCustomCollectionClass contentBinding="App.items"}} - Hi {{view.content.name}} - {{/collection}} - ``` - - ### Forwarded `item.*`-named Options - - As with the `{{view}}`, helper options passed to the `{{collection}}` will be - set on the resulting `Ember.CollectionView` as properties. Additionally, - options prefixed with `item` will be applied to the views rendered for each - item (note the camelcasing): - - ```handlebars - {{#collection contentBinding="App.items" - itemTagName="p" - itemClassNames="greeting"}} - Howdy {{view.content.name}} - {{/collection}} - ``` - - Will result in the following HTML structure: - - ```html -
    -

    Howdy Dave

    -

    Howdy Mary

    -

    Howdy Sara

    -
    - ``` - - @method collection - @for Ember.Handlebars.helpers - @param {String} path - @param {Hash} options - @return {String} HTML string - @deprecated Use `{{each}}` helper instead. - */ - function collectionHelper(path, options) { - Ember.deprecate("Using the {{collection}} helper without specifying a class has been deprecated as the {{each}} helper now supports the same functionality.", path !== 'collection'); - - // If no path is provided, treat path param as options. - if (path && path.data && path.data.isRenderData) { - options = path; - path = undefined; - Ember.assert("You cannot pass more than one argument to the collection helper", arguments.length === 1); - } else { - Ember.assert("You cannot pass more than one argument to the collection helper", arguments.length === 2); - } - - var fn = options.fn; - var data = options.data; - var inverse = options.inverse; - var view = options.data.view; - - - var controller, container; - // If passed a path string, convert that into an object. - // Otherwise, just default to the standard class. - var collectionClass; - if (path) { - controller = data.keywords.controller; - container = controller && controller.container; - collectionClass = handlebarsGet(this, path, options) || container.lookupFactory('view:' + path); - Ember.assert(fmt("%@ #collection: Could not find collection class %@", [data.view, path]), !!collectionClass); - } - else { - collectionClass = CollectionView; - } - - var hash = options.hash, itemHash = {}, match; - - // Extract item view class if provided else default to the standard class - var collectionPrototype = collectionClass.proto(), itemViewClass; - - if (hash.itemView) { - controller = data.keywords.controller; - Ember.assert('You specified an itemView, but the current context has no ' + - 'container to look the itemView up in. This probably means ' + - 'that you created a view manually, instead of through the ' + - 'container. Instead, use container.lookup("view:viewName"), ' + - 'which will properly instantiate your view.', - controller && controller.container); - container = controller.container; - itemViewClass = container.lookupFactory('view:' + hash.itemView); - Ember.assert('You specified the itemView ' + hash.itemView + ", but it was " + - "not found at " + container.describe("view:" + hash.itemView) + - " (and it was not registered in the container)", !!itemViewClass); - } else if (hash.itemViewClass) { - itemViewClass = handlebarsGet(collectionPrototype, hash.itemViewClass, options); - } else { - itemViewClass = collectionPrototype.itemViewClass; - } - - Ember.assert(fmt("%@ #collection: Could not find itemViewClass %@", [data.view, itemViewClass]), !!itemViewClass); - - delete hash.itemViewClass; - delete hash.itemView; - - // Go through options passed to the {{collection}} helper and extract options - // that configure item views instead of the collection itself. - for (var prop in hash) { - if (hash.hasOwnProperty(prop)) { - match = prop.match(/^item(.)(.*)$/); - - if (match && prop !== 'itemController') { - // Convert itemShouldFoo -> shouldFoo - itemHash[match[1].toLowerCase() + match[2]] = hash[prop]; - // Delete from hash as this will end up getting passed to the - // {{view}} helper method. - delete hash[prop]; - } - } - } - - if (fn) { - itemHash.template = fn; - delete options.fn; - } - - var emptyViewClass; - if (inverse && inverse !== EmberHandlebars.VM.noop) { - emptyViewClass = get(collectionPrototype, 'emptyViewClass'); - emptyViewClass = emptyViewClass.extend({ - template: inverse, - tagName: itemHash.tagName - }); - } else if (hash.emptyViewClass) { - emptyViewClass = handlebarsGet(this, hash.emptyViewClass, options); - } - if (emptyViewClass) { hash.emptyView = emptyViewClass; } - - if (hash.keyword) { - itemHash._context = this; - } else { - itemHash._context = alias('content'); - } - - var viewOptions = ViewHelper.propertiesFromHTMLOptions({ data: data, hash: itemHash }, this); - hash.itemViewClass = itemViewClass.extend(viewOptions); - - options.helperName = options.helperName || 'collection'; - - return helpers.view.call(this, collectionClass, options); - } - - __exports__["default"] = collectionHelper; - }); -define("ember-handlebars/helpers/debug", - ["ember-metal/core","ember-metal/utils","ember-metal/logger","ember-metal/property_get","ember-handlebars/ext","exports"], - function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __exports__) { - "use strict"; - /*jshint debug:true*/ - - /** - @module ember - @submodule ember-handlebars - */ - var Ember = __dependency1__["default"]; - // Ember.FEATURES, - var inspect = __dependency2__.inspect; - var Logger = __dependency3__["default"]; - - var get = __dependency4__.get; - var normalizePath = __dependency5__.normalizePath; - var handlebarsGet = __dependency5__.handlebarsGet; - - var a_slice = [].slice; - - /** - `log` allows you to output the value of variables in the current rendering - context. `log` also accepts primitive types such as strings or numbers. - - ```handlebars - {{log "myVariable:" myVariable }} - ``` - - @method log - @for Ember.Handlebars.helpers - @param {String} property - */ - function logHelper() { - var params = a_slice.call(arguments, 0, -1), - options = arguments[arguments.length - 1], - logger = Logger.log, - values = [], - allowPrimitives = true; - - for (var i = 0; i < params.length; i++) { - var type = options.types[i]; - - if (type === 'ID' || !allowPrimitives) { - var context = (options.contexts && options.contexts[i]) || this, - normalized = normalizePath(context, params[i], options.data); - - if (normalized.path === 'this') { - values.push(normalized.root); - } else { - values.push(handlebarsGet(normalized.root, normalized.path, options)); - } - } else { - values.push(params[i]); - } - } - - logger.apply(logger, values); - }; - - /** - Execute the `debugger` statement in the current context. - - ```handlebars - {{debugger}} - ``` - - Before invoking the `debugger` statement, there - are a few helpful variables defined in the - body of this helper that you can inspect while - debugging that describe how and where this - helper was invoked: - - - templateContext: this is most likely a controller - from which this template looks up / displays properties - - typeOfTemplateContext: a string description of - what the templateContext is - - For example, if you're wondering why a value `{{foo}}` - isn't rendering as expected within a template, you - could place a `{{debugger}}` statement, and when - the `debugger;` breakpoint is hit, you can inspect - `templateContext`, determine if it's the object you - expect, and/or evaluate expressions in the console - to perform property lookups on the `templateContext`: - - ``` - > templateContext.get('foo') // -> "" - ``` - - @method debugger - @for Ember.Handlebars.helpers - @param {String} property - */ - function debuggerHelper(options) { - - // These are helpful values you can inspect while debugging. - var templateContext = this; - var typeOfTemplateContext = inspect(templateContext); - - debugger; - } - - __exports__.logHelper = logHelper; - __exports__.debuggerHelper = debuggerHelper; - }); -define("ember-handlebars/helpers/each", - ["ember-metal/core","ember-handlebars-compiler","ember-runtime/system/string","ember-metal/property_get","ember-metal/property_set","ember-handlebars/views/metamorph_view","ember-views/views/collection_view","ember-metal/binding","ember-runtime/controllers/controller","ember-runtime/controllers/array_controller","ember-runtime/mixins/array","ember-runtime/copy","ember-metal/run_loop","ember-metal/observer","ember-metal/events","ember-handlebars/ext","ember-metal/computed","exports"], - function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __dependency9__, __dependency10__, __dependency11__, __dependency12__, __dependency13__, __dependency14__, __dependency15__, __dependency16__, __dependency17__, __exports__) { - "use strict"; - - /** - @module ember - @submodule ember-handlebars - */ - var Ember = __dependency1__["default"]; - // Ember.assert;, Ember.K - // var emberAssert = Ember.assert, - var K = Ember.K; - - var EmberHandlebars = __dependency2__["default"]; - var helpers = EmberHandlebars.helpers; - - var fmt = __dependency3__.fmt; - var get = __dependency4__.get; - var set = __dependency5__.set; - var _Metamorph = __dependency6__._Metamorph; - var _MetamorphView = __dependency6__._MetamorphView; - var CollectionView = __dependency7__["default"]; - var Binding = __dependency8__.Binding; - var ControllerMixin = __dependency9__.ControllerMixin; - var ArrayController = __dependency10__["default"]; - var EmberArray = __dependency11__["default"]; - var copy = __dependency12__["default"]; - var run = __dependency13__["default"]; - var addObserver = __dependency14__.addObserver; - var removeObserver = __dependency14__.removeObserver; - var addBeforeObserver = __dependency14__.addBeforeObserver; - var removeBeforeObserver = __dependency14__.removeBeforeObserver; - var on = __dependency15__.on; - var handlebarsGet = __dependency16__.handlebarsGet; - var computed = __dependency17__.computed; - - var handlebarsGet = __dependency16__.handlebarsGet; - - var EachView = CollectionView.extend(_Metamorph, { - - init: function() { - var itemController = get(this, 'itemController'); - var binding; - - if (itemController) { - var controller = get(this, 'controller.container').lookupFactory('controller:array').create({ - _isVirtual: true, - parentController: get(this, 'controller'), - itemController: itemController, - target: get(this, 'controller'), - _eachView: this - }); - - this.disableContentObservers(function() { - set(this, 'content', controller); - binding = new Binding('content', '_eachView.dataSource').oneWay(); - binding.connect(controller); - }); - - set(this, '_arrayController', controller); - } else { - this.disableContentObservers(function() { - binding = new Binding('content', 'dataSource').oneWay(); - binding.connect(this); - }); - } - - return this._super(); - }, - - _assertArrayLike: function(content) { - Ember.assert(fmt("The value that #each loops over must be an Array. You " + - "passed %@, but it should have been an ArrayController", - [content.constructor]), - !ControllerMixin.detect(content) || - (content && content.isGenerated) || - content instanceof ArrayController); - Ember.assert(fmt("The value that #each loops over must be an Array. You passed %@", [(ControllerMixin.detect(content) && content.get('model') !== undefined) ? fmt("'%@' (wrapped in %@)", [content.get('model'), content]) : content]), EmberArray.detect(content)); - }, - - disableContentObservers: function(callback) { - removeBeforeObserver(this, 'content', null, '_contentWillChange'); - removeObserver(this, 'content', null, '_contentDidChange'); - - callback.call(this); - - addBeforeObserver(this, 'content', null, '_contentWillChange'); - addObserver(this, 'content', null, '_contentDidChange'); - }, - - itemViewClass: _MetamorphView, - emptyViewClass: _MetamorphView, - - createChildView: function(view, attrs) { - view = this._super(view, attrs); - - // At the moment, if a container view subclass wants - // to insert keywords, it is responsible for cloning - // the keywords hash. This will be fixed momentarily. - var keyword = get(this, 'keyword'); - var content = get(view, 'content'); - - if (keyword) { - var data = get(view, 'templateData'); - - data = copy(data); - data.keywords = view.cloneKeywords(); - set(view, 'templateData', data); - - // In this case, we do not bind, because the `content` of - // a #each item cannot change. - data.keywords[keyword] = content; - } - - // If {{#each}} is looping over an array of controllers, - // point each child view at their respective controller. - if (content && content.isController) { - set(view, 'controller', content); - } - - return view; - }, - - destroy: function() { - if (!this._super()) { return; } - - var arrayController = get(this, '_arrayController'); - - if (arrayController) { - arrayController.destroy(); - } - - return this; - } - }); - - // Defeatureify doesn't seem to like nested functions that need to be removed - function _addMetamorphCheck() { - EachView.reopen({ - _checkMetamorph: on('didInsertElement', function() { - Ember.assert("The metamorph tags, " + - this.morph.start + " and " + this.morph.end + - ", have different parents.\nThe browser has fixed your template to output valid HTML (for example, check that you have properly closed all tags and have used a TBODY tag when creating a table with '{{#each}}')", - document.getElementById( this.morph.start ).parentNode === - document.getElementById( this.morph.end ).parentNode - ); - }) - }); - } - - // until ember-debug is es6ed - var runInDebug = function(f){f()}; - runInDebug( function() { - _addMetamorphCheck(); - }); - - var GroupedEach = EmberHandlebars.GroupedEach = function(context, path, options) { - var self = this, - normalized = EmberHandlebars.normalizePath(context, path, options.data); - - this.context = context; - this.path = path; - this.options = options; - this.template = options.fn; - this.containingView = options.data.view; - this.normalizedRoot = normalized.root; - this.normalizedPath = normalized.path; - this.content = this.lookupContent(); - - this.addContentObservers(); - this.addArrayObservers(); - - this.containingView.on('willClearRender', function() { - self.destroy(); - }); - }; - - GroupedEach.prototype = { - contentWillChange: function() { - this.removeArrayObservers(); - }, - - contentDidChange: function() { - this.content = this.lookupContent(); - this.addArrayObservers(); - this.rerenderContainingView(); - }, - - contentArrayWillChange: K, - - contentArrayDidChange: function() { - this.rerenderContainingView(); - }, - - lookupContent: function() { - return handlebarsGet(this.normalizedRoot, this.normalizedPath, this.options); - }, - - addArrayObservers: function() { - if (!this.content) { return; } - - this.content.addArrayObserver(this, { - willChange: 'contentArrayWillChange', - didChange: 'contentArrayDidChange' - }); - }, - - removeArrayObservers: function() { - if (!this.content) { return; } - - this.content.removeArrayObserver(this, { - willChange: 'contentArrayWillChange', - didChange: 'contentArrayDidChange' - }); - }, - - addContentObservers: function() { - addBeforeObserver(this.normalizedRoot, this.normalizedPath, this, this.contentWillChange); - addObserver(this.normalizedRoot, this.normalizedPath, this, this.contentDidChange); - }, - - removeContentObservers: function() { - removeBeforeObserver(this.normalizedRoot, this.normalizedPath, this.contentWillChange); - removeObserver(this.normalizedRoot, this.normalizedPath, this.contentDidChange); - }, - - render: function() { - if (!this.content) { return; } - - var content = this.content, - contentLength = get(content, 'length'), - data = this.options.data, - template = this.template; - - data.insideEach = true; - for (var i = 0; i < contentLength; i++) { - template(content.objectAt(i), { data: data }); - } - }, - - rerenderContainingView: function() { - var self = this; - run.scheduleOnce('render', this, function() { - // It's possible it's been destroyed after we enqueued a re-render call. - if (!self.destroyed) { - self.containingView.rerender(); - } - }); - }, - - destroy: function() { - this.removeContentObservers(); - if (this.content) { - this.removeArrayObservers(); - } - this.destroyed = true; - } - }; - - /** - The `{{#each}}` helper loops over elements in a collection, rendering its - block once for each item. It is an extension of the base Handlebars `{{#each}}` - helper: - - ```javascript - Developers = [{name: 'Yehuda'},{name: 'Tom'}, {name: 'Paul'}]; - ``` - - ```handlebars - {{#each Developers}} - {{name}} - {{/each}} - ``` - - `{{each}}` supports an alternative syntax with element naming: - - ```handlebars - {{#each person in Developers}} - {{person.name}} - {{/each}} - ``` - - When looping over objects that do not have properties, `{{this}}` can be used - to render the object: - - ```javascript - DeveloperNames = ['Yehuda', 'Tom', 'Paul'] - ``` - - ```handlebars - {{#each DeveloperNames}} - {{this}} - {{/each}} - ``` - ### {{else}} condition - `{{#each}}` can have a matching `{{else}}`. The contents of this block will render - if the collection is empty. - - ``` - {{#each person in Developers}} - {{person.name}} - {{else}} -

    Sorry, nobody is available for this task.

    - {{/each}} - ``` - ### Specifying a View class for items - If you provide an `itemViewClass` option that references a view class - with its own `template` you can omit the block. - - The following template: - - ```handlebars - {{#view App.MyView }} - {{each view.items itemViewClass="App.AnItemView"}} - {{/view}} - ``` - - And application code - - ```javascript - App = Ember.Application.create({ - MyView: Ember.View.extend({ - items: [ - Ember.Object.create({name: 'Dave'}), - Ember.Object.create({name: 'Mary'}), - Ember.Object.create({name: 'Sara'}) - ] - }) - }); - - App.AnItemView = Ember.View.extend({ - template: Ember.Handlebars.compile("Greetings {{name}}") - }); - ``` - - Will result in the HTML structure below - - ```html -
    -
    Greetings Dave
    -
    Greetings Mary
    -
    Greetings Sara
    -
    - ``` - - If an `itemViewClass` is defined on the helper, and therefore the helper is not - being used as a block, an `emptyViewClass` can also be provided optionally. - The `emptyViewClass` will match the behavior of the `{{else}}` condition - described above. That is, the `emptyViewClass` will render if the collection - is empty. - - ### Representing each item with a Controller. - By default the controller lookup within an `{{#each}}` block will be - the controller of the template where the `{{#each}}` was used. If each - item needs to be presented by a custom controller you can provide a - `itemController` option which references a controller by lookup name. - Each item in the loop will be wrapped in an instance of this controller - and the item itself will be set to the `content` property of that controller. - - This is useful in cases where properties of model objects need transformation - or synthesis for display: - - ```javascript - App.DeveloperController = Ember.ObjectController.extend({ - isAvailableForHire: function() { - return !this.get('content.isEmployed') && this.get('content.isSeekingWork'); - }.property('isEmployed', 'isSeekingWork') - }) - ``` - - ```handlebars - {{#each person in developers itemController="developer"}} - {{person.name}} {{#if person.isAvailableForHire}}Hire me!{{/if}} - {{/each}} - ``` - - Each itemController will receive a reference to the current controller as - a `parentController` property. - - ### (Experimental) Grouped Each - - When used in conjunction with the experimental [group helper](https://github.com/emberjs/group-helper), - you can inform Handlebars to re-render an entire group of items instead of - re-rendering them one at a time (in the event that they are changed en masse - or an item is added/removed). - - ```handlebars - {{#group}} - {{#each people}} - {{firstName}} {{lastName}} - {{/each}} - {{/group}} - ``` - - This can be faster than the normal way that Handlebars re-renders items - in some cases. - - If for some reason you have a group with more than one `#each`, you can make - one of the collections be updated in normal (non-grouped) fashion by setting - the option `groupedRows=true` (counter-intuitive, I know). - - For example, - - ```handlebars - {{dealershipName}} - - {{#group}} - {{#each dealers}} - {{firstName}} {{lastName}} - {{/each}} - - {{#each car in cars groupedRows=true}} - {{car.make}} {{car.model}} {{car.color}} - {{/each}} - {{/group}} - ``` - Any change to `dealershipName` or the `dealers` collection will cause the - entire group to be re-rendered. However, changes to the `cars` collection - will be re-rendered individually (as normal). - - Note that `group` behavior is also disabled by specifying an `itemViewClass`. - - @method each - @for Ember.Handlebars.helpers - @param [name] {String} name for item (used with `in`) - @param [path] {String} path - @param [options] {Object} Handlebars key/value pairs of options - @param [options.itemViewClass] {String} a path to a view class used for each item - @param [options.itemController] {String} name of a controller to be created for each item - @param [options.groupedRows] {boolean} enable normal item-by-item rendering when inside a `#group` helper - */ - function eachHelper(path, options) { - var ctx, helperName = 'each'; - - if (arguments.length === 4) { - Ember.assert("If you pass more than one argument to the each helper, it must be in the form #each foo in bar", arguments[1] === "in"); - - var keywordName = arguments[0]; - - - options = arguments[3]; - path = arguments[2]; - - helperName += ' ' + keywordName + ' in ' + path; - - if (path === '') { path = "this"; } - - options.hash.keyword = keywordName; - - } else if (arguments.length === 1) { - options = path; - path = 'this'; - } else { - helperName += ' ' + path; - } - - options.hash.dataSourceBinding = path; - // Set up emptyView as a metamorph with no tag - //options.hash.emptyViewClass = Ember._MetamorphView; - - // can't rely on this default behavior when use strict - ctx = this || window; - - options.helperName = options.helperName || helperName; - - if (options.data.insideGroup && !options.hash.groupedRows && !options.hash.itemViewClass) { - new GroupedEach(ctx, path, options).render(); - } else { - // ES6TODO: figure out how to do this without global lookup. - return helpers.collection.call(ctx, 'Ember.Handlebars.EachView', options); - } - } - - __exports__.EachView = EachView; - __exports__.GroupedEach = GroupedEach; - __exports__.eachHelper = eachHelper; - }); -define("ember-handlebars/helpers/loc", - ["ember-runtime/system/string","exports"], - function(__dependency1__, __exports__) { - "use strict"; - var loc = __dependency1__.loc; - - /** - @module ember - @submodule ember-handlebars - */ - - // ES6TODO: - // Pretty sure this can be expressed as - // var locHelper EmberStringUtils.loc ? - - /** - Calls [Ember.String.loc](/api/classes/Ember.String.html#method_loc) with the - provided string. - - This is a convenient way to localize text. For example: - - ```html - - ``` - - Take note that `"welcome"` is a string and not an object - reference. - - See [Ember.String.loc](/api/classes/Ember.String.html#method_loc) for how to - set up localized string references. - - @method loc - @for Ember.Handlebars.helpers - @param {String} str The string to format - @see {Ember.String#loc} - */ - function locHelper(str) { - return loc(str); - } - - __exports__["default"] = locHelper; - }); -define("ember-handlebars/helpers/partial", - ["ember-metal/core","ember-metal/is_none","ember-handlebars/ext","ember-handlebars/helpers/binding","exports"], - function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __exports__) { - "use strict"; - var Ember = __dependency1__["default"]; - // Ember.assert - // var emberAssert = Ember.assert; - - var isNone = __dependency2__.isNone; - var handlebarsGet = __dependency3__.handlebarsGet; - var bind = __dependency4__.bind; - - /** - @module ember - @submodule ember-handlebars - */ - - /** - The `partial` helper renders another template without - changing the template context: - - ```handlebars - {{foo}} - {{partial "nav"}} - ``` - - The above example template will render a template named - "_nav", which has the same context as the parent template - it's rendered into, so if the "_nav" template also referenced - `{{foo}}`, it would print the same thing as the `{{foo}}` - in the above example. - - If a "_nav" template isn't found, the `partial` helper will - fall back to a template named "nav". - - ## Bound template names - - The parameter supplied to `partial` can also be a path - to a property containing a template name, e.g.: - - ```handlebars - {{partial someTemplateName}} - ``` - - The above example will look up the value of `someTemplateName` - on the template context (e.g. a controller) and use that - value as the name of the template to render. If the resolved - value is falsy, nothing will be rendered. If `someTemplateName` - changes, the partial will be re-rendered using the new template - name. - - ## Setting the partial's context with `with` - - The `partial` helper can be used in conjunction with the `with` - helper to set a context that will be used by the partial: - - ```handlebars - {{#with currentUser}} - {{partial "user_info"}} - {{/with}} - ``` - - @method partial - @for Ember.Handlebars.helpers - @param {String} partialName the name of the template to render minus the leading underscore - */ - - function partialHelper(name, options) { - - var context = (options.contexts && options.contexts.length) ? options.contexts[0] : this; - - options.helperName = options.helperName || 'partial'; - - if (options.types[0] === "ID") { - // Helper was passed a property path; we need to - // create a binding that will re-render whenever - // this property changes. - options.fn = function(context, fnOptions) { - var partialName = handlebarsGet(context, name, fnOptions); - renderPartial(context, partialName, fnOptions); - }; - - return bind.call(context, name, options, true, exists); - } else { - // Render the partial right into parent template. - renderPartial(context, name, options); - } - } - - function exists(value) { - return !isNone(value); - } - - function renderPartial(context, name, options) { - var nameParts = name.split("/"); - var lastPart = nameParts[nameParts.length - 1]; - - nameParts[nameParts.length - 1] = "_" + lastPart; - - var view = options.data.view; - var underscoredName = nameParts.join("/"); - var template = view.templateForName(underscoredName); - var deprecatedTemplate = !template && view.templateForName(name); - - Ember.assert("Unable to find partial with name '"+name+"'.", template || deprecatedTemplate); - - template = template || deprecatedTemplate; - - template(context, { data: options.data }); - } - - __exports__["default"] = partialHelper; - }); -define("ember-handlebars/helpers/shared", - ["ember-handlebars/ext","exports"], - function(__dependency1__, __exports__) { - "use strict"; - var handlebarsGet = __dependency1__.handlebarsGet; - - function resolvePaths(options) { - var ret = [], - contexts = options.contexts, - roots = options.roots, - data = options.data; - - for (var i=0, l=contexts.length; i - {{#with loggedInUser}} - Last Login: {{lastLogin}} - User Info: {{template "user_info"}} - {{/with}} - - ``` - - ```html - - ``` - - ```handlebars - {{#if isUser}} - {{template "user_info"}} - {{else}} - {{template "unlogged_user_info"}} - {{/if}} - ``` - - This helper looks for templates in the global `Ember.TEMPLATES` hash. If you - add `"; - return testEl.firstChild.innerHTML === ''; - })(); - - // IE 8 (and likely earlier) likes to move whitespace preceeding - // a script tag to appear after it. This means that we can - // accidentally remove whitespace when updating a morph. - var movesWhitespace = typeof document !== 'undefined' && (function() { - var testEl = document.createElement('div'); - testEl.innerHTML = "Test: Value"; - return testEl.childNodes[0].nodeValue === 'Test:' && - testEl.childNodes[2].nodeValue === ' Value'; - })(); - - // Use this to find children by ID instead of using jQuery - var findChildById = function(element, id) { - if (element.getAttribute('id') === id) { return element; } - - var len = element.childNodes.length, idx, node, found; - for (idx=0; idx 0) { - var len = matches.length, idx; - for (idx=0; idxTest'); - canSet = el.options.length === 1; - } - - innerHTMLTags[tagName] = canSet; - - return canSet; - }; - - var setInnerHTML = function(element, html) { - var tagName = element.tagName; - - if (canSetInnerHTML(tagName)) { - setInnerHTMLWithoutFix(element, html); - } else { - // Firefox versions < 11 do not have support for element.outerHTML. - var outerHTML = element.outerHTML || new XMLSerializer().serializeToString(element); - - var startTag = outerHTML.match(new RegExp("<"+tagName+"([^>]*)>", 'i'))[0], - endTag = ''; - - var wrapper = document.createElement('div'); - setInnerHTMLWithoutFix(wrapper, startTag + html + endTag); - element = wrapper.firstChild; - while (element.tagName !== tagName) { - element = element.nextSibling; - } - } - - return element; - }; - function isSimpleClick(event) { - var modifier = event.shiftKey || event.metaKey || event.altKey || event.ctrlKey, - secondaryClick = event.which > 1; // IE9 may return undefined + var modifier = event.shiftKey || event.metaKey || event.altKey || event.ctrlKey; + var secondaryClick = event.which > 1; // IE9 may return undefined return !modifier && !secondaryClick; } - __exports__.setInnerHTML = setInnerHTML; __exports__.isSimpleClick = isSimpleClick; }); -define("ember-views/views/collection_view", - ["ember-metal/core","ember-metal/platform","ember-metal/binding","ember-metal/merge","ember-metal/property_get","ember-metal/property_set","ember-runtime/system/string","ember-views/views/container_view","ember-views/views/view","ember-metal/mixin","ember-runtime/mixins/array","exports"], - function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __dependency9__, __dependency10__, __dependency11__, __exports__) { +enifed("ember-views/views/collection_view", + ["ember-metal/core","ember-metal/platform","ember-metal/binding","ember-metal/merge","ember-metal/property_get","ember-metal/property_set","ember-runtime/system/string","ember-views/views/container_view","ember-views/views/core_view","ember-views/views/view","ember-metal/mixin","ember-handlebars/ext","ember-runtime/mixins/array","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __dependency9__, __dependency10__, __dependency11__, __dependency12__, __dependency13__, __exports__) { "use strict"; /** @@ -23401,11 +37903,12 @@ define("ember-views/views/collection_view", var set = __dependency6__.set; var fmt = __dependency7__.fmt; var ContainerView = __dependency8__["default"]; - var CoreView = __dependency9__.CoreView; - var View = __dependency9__.View; - var observer = __dependency10__.observer; - var beforeObserver = __dependency10__.beforeObserver; - var EmberArray = __dependency11__["default"]; + var CoreView = __dependency9__["default"]; + var View = __dependency10__["default"]; + var observer = __dependency11__.observer; + var beforeObserver = __dependency11__.beforeObserver; + var handlebarsGetView = __dependency12__.handlebarsGetView; + var EmberArray = __dependency13__["default"]; /** `Ember.CollectionView` is an `Ember.View` descendent responsible for managing @@ -23428,27 +37931,32 @@ define("ember-views/views/collection_view", The view for each item in the collection will have its `content` property set to the item. - ## Specifying itemViewClass + ## Specifying `itemViewClass` By default the view class for each item in the managed collection will be an instance of `Ember.View`. You can supply a different class by setting the `CollectionView`'s `itemViewClass` property. - Given an empty `` and the following code: + Given the following application code: ```javascript - someItemsView = Ember.CollectionView.create({ + var App = Ember.Application.create(); + App.ItemListView = Ember.CollectionView.extend({ classNames: ['a-collection'], content: ['A','B','C'], itemViewClass: Ember.View.extend({ template: Ember.Handlebars.compile("the letter: {{view.content}}") }) }); - - someItemsView.appendTo('body'); ``` - Will result in the following HTML structure + And a simple application template: + + ```handlebars + {{view 'item-list'}} + ``` + + The following HTML will result: ```html
    @@ -23464,21 +37972,26 @@ define("ember-views/views/collection_view", "ul", "ol", "table", "thead", "tbody", "tfoot", "tr", or "select" will result in the item views receiving an appropriately matched `tagName` property. - Given an empty `` and the following code: + Given the following application code: ```javascript - anUnorderedListView = Ember.CollectionView.create({ + var App = Ember.Application.create(); + App.UnorderedListView = Ember.CollectionView.create({ tagName: 'ul', content: ['A','B','C'], itemViewClass: Ember.View.extend({ template: Ember.Handlebars.compile("the letter: {{view.content}}") }) }); - - anUnorderedListView.appendTo('body'); ``` - Will result in the following HTML structure + And a simple application template: + + ```handlebars + {{view 'unordered-list-view'}} + ``` + + The following HTML will result: ```html
      @@ -23489,7 +38002,7 @@ define("ember-views/views/collection_view", ``` Additional `tagName` pairs can be provided by adding to - `Ember.CollectionView.CONTAINER_MAP ` + `Ember.CollectionView.CONTAINER_MAP`. For example: ```javascript Ember.CollectionView.CONTAINER_MAP['article'] = 'section' @@ -23502,7 +38015,7 @@ define("ember-views/views/collection_view", `createChildView` method can be overidden: ```javascript - CustomCollectionView = Ember.CollectionView.extend({ + App.CustomCollectionView = Ember.CollectionView.extend({ createChildView: function(viewClass, attrs) { if (attrs.content.kind == 'album') { viewClass = App.AlbumView; @@ -23522,18 +38035,23 @@ define("ember-views/views/collection_view", will be the `CollectionView`s only child. ```javascript - aListWithNothing = Ember.CollectionView.create({ - classNames: ['nothing'] + var App = Ember.Application.create(); + App.ListWithNothing = Ember.CollectionView.create({ + classNames: ['nothing'], content: null, emptyView: Ember.View.extend({ template: Ember.Handlebars.compile("The collection is empty") }) }); - - aListWithNothing.appendTo('body'); ``` - Will result in the following HTML structure + And a simple application template: + + ```handlebars + {{view 'list-with-nothing'}} + ``` + + The following HTML will result: ```html
      @@ -23690,18 +38208,8 @@ define("ember-views/views/collection_view", // Loop through child views that correspond with the removed items. // Note that we loop from the end of the array to the beginning because // we are mutating it as we go. - var childViews = this._childViews, childView, idx, len; - - len = this._childViews.length; - - var removingAll = removedCount === len; - - if (removingAll) { - this.currentState.empty(this); - this.invokeRecursively(function(view) { - view.removedFromDOM = true; - }, false); - } + var childViews = this._childViews; + var childView, idx; for (idx = start + removedCount - 1; idx >= start; idx--) { childView = childViews[idx]; @@ -23724,19 +38232,15 @@ define("ember-views/views/collection_view", @param {Number} added number of object added to content */ arrayDidChange: function(content, start, removed, added) { - var addedViews = [], view, item, idx, len, itemViewClass, - emptyView; + var addedViews = []; + var view, item, idx, len, itemViewClass, emptyView; len = content ? get(content, 'length') : 0; if (len) { itemViewClass = get(this, 'itemViewClass'); + itemViewClass = handlebarsGetView(content, itemViewClass, this.container); - if ('string' === typeof itemViewClass && isGlobalPath(itemViewClass)) { - itemViewClass = get(itemViewClass) || itemViewClass; - } - - for (idx = start; idx < start+added; idx++) { item = content.objectAt(idx); @@ -23820,7 +38324,7 @@ define("ember-views/views/collection_view", __exports__["default"] = CollectionView; }); -define("ember-views/views/component", +enifed("ember-views/views/component", ["ember-metal/core","ember-views/mixins/component_template_deprecation","ember-runtime/mixins/target_action_support","ember-views/views/view","ember-metal/property_get","ember-metal/property_set","ember-metal/is_none","ember-metal/computed","exports"], function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __exports__) { "use strict"; @@ -23829,7 +38333,9 @@ define("ember-views/views/component", var ComponentTemplateDeprecation = __dependency2__["default"]; var TargetActionSupport = __dependency3__["default"]; - var View = __dependency4__.View;var get = __dependency5__.get; + var View = __dependency4__["default"]; + + var get = __dependency5__.get; var set = __dependency6__.set; var isNone = __dependency7__.isNone; @@ -23937,6 +38443,7 @@ define("ember-views/views/component", init: function() { this._super(); + set(this, 'origContext', get(this, 'context')); set(this, 'context', this); set(this, 'controller', this); }, @@ -23967,8 +38474,8 @@ define("ember-views/views/component", template: computed(function(key, value) { if (value !== undefined) { return value; } - var templateName = get(this, 'templateName'), - template = this.templateForName(templateName, 'template'); + var templateName = get(this, 'templateName'); + var template = this.templateForName(templateName, 'template'); return template || get(this, 'defaultTemplate'); @@ -23992,9 +38499,9 @@ define("ember-views/views/component", }, _yield: function(context, options) { - var view = options.data.view, - parentView = this._parentView, - template = get(this, 'template'); + var view = options.data.view; + var parentView = this._parentView; + var template = get(this, 'template'); if (template) { @@ -24003,9 +38510,9 @@ define("ember-views/views/component", tagName: '', _contextView: parentView, template: template, - context: get(parentView, 'context'), + context: options.data.insideGroup ? get(this, 'origContext') : get(parentView, 'context'), controller: get(parentView, 'controller'), - templateData: { keywords: parentView.cloneKeywords() } + templateData: { keywords: parentView.cloneKeywords(), insideGroup: options.data.insideGroup } }); } }, @@ -24104,8 +38611,8 @@ define("ember-views/views/component", @param [context] {*} a context to send with the action */ sendAction: function(action) { - var actionName, - contexts = a_slice.call(arguments, 1); + var actionName; + var contexts = a_slice.call(arguments, 1); // Send the default action if (action === undefined) { @@ -24126,7 +38633,7 @@ define("ember-views/views/component", __exports__["default"] = Component; }); -define("ember-views/views/container_view", +enifed("ember-views/views/container_view", ["ember-metal/core","ember-metal/merge","ember-runtime/mixins/mutable_array","ember-metal/property_get","ember-metal/property_set","ember-views/views/view","ember-views/views/states","ember-metal/error","ember-metal/enumerable_utils","ember-metal/computed","ember-metal/run_loop","ember-metal/properties","ember-views/system/render_buffer","ember-metal/mixin","ember-runtime/system/native_array","exports"], function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __dependency9__, __dependency10__, __dependency11__, __dependency12__, __dependency13__, __dependency14__, __dependency15__, __exports__) { "use strict"; @@ -24138,24 +38645,22 @@ define("ember-views/views/container_view", var get = __dependency4__.get; var set = __dependency5__.set; - var View = __dependency6__.View; - var ViewCollection = __dependency6__.ViewCollection; + var View = __dependency6__["default"]; + var cloneStates = __dependency7__.cloneStates; var EmberViewStates = __dependency7__.states; var EmberError = __dependency8__["default"]; - // ES6TODO: functions on EnumerableUtils should get their own export - var EnumerableUtils = __dependency9__["default"]; - var forEach = EnumerableUtils.forEach; + var forEach = __dependency9__.forEach; var computed = __dependency10__.computed; var run = __dependency11__["default"]; var defineProperty = __dependency12__.defineProperty; - var RenderBuffer = __dependency13__["default"]; + var renderBuffer = __dependency13__["default"]; var observer = __dependency14__.observer; var beforeObserver = __dependency14__.beforeObserver; - var A = __dependency15__.A; + var emberA = __dependency15__.A; /** @module ember @@ -24315,7 +38820,11 @@ define("ember-views/views/container_view", @extends Ember.View */ var ContainerView = View.extend(MutableArray, { - states: states, + isContainer: true, + _states: states, + + willWatchProperty: function(prop){ + }, init: function() { this._super(); @@ -24375,7 +38884,7 @@ define("ember-views/views/container_view", length: computed(function () { return this._childViews.length; - }).volatile(), + })["volatile"](), /** Instructs each child view to render to the passed render buffer. @@ -24385,9 +38894,6 @@ define("ember-views/views/container_view", @param {Ember.RenderBuffer} buffer the buffer to render to */ render: function(buffer) { - this.forEachChildView(function(view) { - view.renderToBuffer(buffer); - }); }, instrumentName: 'container', @@ -24505,51 +39011,165 @@ define("ember-views/views/container_view", }, ensureChildrenAreInDOM: function(view) { - var childViews = view._childViews, i, len, childView, previous, buffer, viewCollection = new ViewCollection(); + var childViews = view._childViews; + var renderer = view._renderer; + var i, len, childView; for (i = 0, len = childViews.length; i < len; i++) { childView = childViews[i]; - - if (!buffer) { buffer = RenderBuffer(); buffer._hasElement = false; } - - if (childView.renderToBufferIfNeeded(buffer)) { - viewCollection.push(childView); - } else if (viewCollection.length) { - insertViewCollection(view, viewCollection, previous, buffer); - buffer = null; - previous = childView; - viewCollection.clear(); - } else { - previous = childView; + if (!childView._elementCreated) { + renderer.renderTree(childView, view, i); } } - - if (viewCollection.length) { - insertViewCollection(view, viewCollection, previous, buffer); - } } }); - function insertViewCollection(view, viewCollection, previous, buffer) { - viewCollection.triggerRecursively('willInsertElement'); - - if (previous) { - previous.domManager.after(previous, buffer.string()); - } else { - view.domManager.prepend(view, buffer.string()); - } - - viewCollection.forEach(function(v) { - v.transitionTo('inDOM'); - v.propertyDidChange('element'); - v.triggerRecursively('didInsertElement'); - }); - } - - __exports__["default"] = ContainerView; }); -define("ember-views/views/states", +enifed("ember-views/views/core_view", + ["ember-views/system/renderer","ember-views/views/states","ember-runtime/system/object","ember-runtime/mixins/evented","ember-runtime/mixins/action_handler","ember-metal/property_get","ember-metal/property_set","ember-metal/computed","ember-metal/utils","ember-metal/instrumentation","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __dependency9__, __dependency10__, __exports__) { + "use strict"; + var Rerender = __dependency1__["default"]; + + var cloneStates = __dependency2__.cloneStates; + var states = __dependency2__.states; + var EmberObject = __dependency3__["default"]; + var Evented = __dependency4__["default"]; + var ActionHandler = __dependency5__["default"]; + + var get = __dependency6__.get; + var set = __dependency7__.set; + var computed = __dependency8__.computed; + + var typeOf = __dependency9__.typeOf; + + var instrument = __dependency10__.instrument; + + /** + `Ember.CoreView` is an abstract class that exists to give view-like behavior + to both Ember's main view class `Ember.View` and other classes like + `Ember._SimpleMetamorphView` that don't need the fully functionaltiy of + `Ember.View`. + + Unless you have specific needs for `CoreView`, you will use `Ember.View` + in your applications. + + @class CoreView + @namespace Ember + @extends Ember.Object + @uses Ember.Evented + @uses Ember.ActionHandler + */ + var CoreView = EmberObject.extend(Evented, ActionHandler, { + isView: true, + isVirtual: false, + isContainer: false, + + _states: cloneStates(states), + + init: function() { + this._super(); + this._transitionTo('preRender'); + this._isVisible = get(this, 'isVisible'); + }, + + /** + If the view is currently inserted into the DOM of a parent view, this + property will point to the parent of the view. + + @property parentView + @type Ember.View + @default null + */ + parentView: computed('_parentView', function() { + var parent = this._parentView; + + if (parent && parent.isVirtual) { + return get(parent, 'parentView'); + } else { + return parent; + } + }), + + _state: null, + + _parentView: null, + + // return the current view, not including virtual views + concreteView: computed('parentView', function() { + if (!this.isVirtual) { return this; } + else { return get(this, 'parentView.concreteView'); } + }), + + instrumentName: 'core_view', + + instrumentDetails: function(hash) { + hash.object = this.toString(); + hash.containerKey = this._debugContainerKey; + hash.view = this; + }, + + /** + Override the default event firing from `Ember.Evented` to + also call methods with the given name. + + @method trigger + @param name {String} + @private + */ + trigger: function() { + this._super.apply(this, arguments); + var name = arguments[0]; + var method = this[name]; + if (method) { + var length = arguments.length; + var args = new Array(length - 1); + for (var i = 1; i < length; i++) { + args[i - 1] = arguments[i]; + } + return method.apply(this, args); + } + }, + + has: function(name) { + return typeOf(this[name]) === 'function' || this._super(name); + }, + + destroy: function() { + var parent = this._parentView; + + if (!this._super()) { return; } + + + // destroy the element -- this will avoid each child view destroying + // the element over and over again... + if (!this.removedFromDOM && this._renderer) { + this._renderer.remove(this, true); + } + + // remove from parent if found. Don't call removeFromParent, + // as removeFromParent will try to remove the element from + // the DOM again. + if (parent) { parent.removeChild(this); } + + this._transitionTo('destroying', false); + + return this; + }, + + clearRenderedChildren: Ember.K, + _transitionTo: Ember.K, + destroyElement: Ember.K + }); + + CoreView.reopenClass({ + renderer: new Rerender() + }); + + __exports__["default"] = CoreView; + }); +enifed("ember-views/views/states", ["ember-metal/platform","ember-metal/merge","ember-views/views/states/default","ember-views/views/states/pre_render","ember-views/views/states/in_buffer","ember-views/views/states/has_element","ember-views/views/states/in_dom","ember-views/views/states/destroying","exports"], function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __exports__) { "use strict"; @@ -24578,9 +39198,9 @@ define("ember-views/views/states", } return into; - }; + } - var states = { + __exports__.cloneStates = cloneStates;var states = { _default: _default, preRender: preRender, inDOM: inDOM, @@ -24588,11 +39208,9 @@ define("ember-views/views/states", hasElement: hasElement, destroying: destroying }; - - __exports__.cloneStates = cloneStates; __exports__.states = states; }); -define("ember-views/views/states/default", +enifed("ember-views/views/states/default", ["ember-metal/core","ember-metal/property_get","ember-metal/property_set","ember-metal/run_loop","ember-metal/error","exports"], function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __exports__) { "use strict"; @@ -24607,7 +39225,7 @@ define("ember-views/views/states/default", @module ember @submodule ember-views */ - var _default = { + __exports__["default"] = { // appendChild is only legal while rendering the buffer. appendChild: function() { throw new EmberError("You can't use appendChild outside of the rendering process"); @@ -24627,25 +39245,16 @@ define("ember-views/views/states/default", }, destroyElement: function(view) { - set(view, 'element', null); - if (view._scheduledInsert) { - run.cancel(view._scheduledInsert); - view._scheduledInsert = null; - } + if (view._renderer) + view._renderer.remove(view, false); return view; }, - renderToBufferIfNeeded: function () { - return false; - }, - rerender: Ember.K, invokeObserver: Ember.K }; - - __exports__["default"] = _default; }); -define("ember-views/views/states/destroying", +enifed("ember-views/views/states/destroying", ["ember-metal/merge","ember-metal/platform","ember-runtime/system/string","ember-views/views/states/default","ember-metal/error","exports"], function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __exports__) { "use strict"; @@ -24672,27 +39281,12 @@ define("ember-views/views/states/destroying", }, destroyElement: function() { throw new EmberError(fmt(destroyingError, ['destroyElement'])); - }, - empty: function() { - throw new EmberError(fmt(destroyingError, ['empty'])); - }, - - setElement: function() { - throw new EmberError(fmt(destroyingError, ["set('element', ...)"])); - }, - - renderToBufferIfNeeded: function() { - return false; - }, - - // Since element insertion is scheduled, don't do anything if - // the view has been destroyed between scheduling and execution - insertElement: Ember.K + } }); __exports__["default"] = destroying; }); -define("ember-views/views/states/has_element", +enifed("ember-views/views/states/has_element", ["ember-views/views/states/default","ember-metal/run_loop","ember-metal/merge","ember-metal/platform","ember-views/system/jquery","ember-metal/error","ember-metal/property_get","ember-metal/property_set","exports"], function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __exports__) { "use strict"; @@ -24715,7 +39309,7 @@ define("ember-views/views/states/has_element", merge(hasElement, { $: function(view, sel) { - var elem = get(view, 'element'); + var elem = view.get('concreteView').element; return sel ? jQuery(sel, elem) : jQuery(elem); }, @@ -24726,25 +39320,17 @@ define("ember-views/views/states/has_element", return jQuery("#" + get(view, 'elementId'))[0]; }, - setElement: function(view, value) { - if (value === null) { - view.transitionTo('preRender'); - } else { - throw new EmberError("You cannot set an element to a non-null value when the element is already in the DOM."); - } - - return value; - }, - // once the view has been inserted into the DOM, rerendering is // deferred to allow bindings to synchronize. rerender: function(view) { - view.triggerRecursively('willClearRender'); - - view.clearRenderedChildren(); - - view.domManager.replace(view); - return view; + if (view._root._morph && !view._elementInserted) { + throw new EmberError("Something you did caused a view to re-render after it rendered but before it was inserted into the DOM."); + } + // TODO: should be scheduled with renderer + run.scheduleOnce('render', function () { + if (view.isDestroying) return; + view._renderer.renderTree(view, view._parentView); + }); }, // once the view is already in the DOM, destroying it removes it @@ -24752,27 +39338,10 @@ define("ember-views/views/states/has_element", // preRender state if inDOM. destroyElement: function(view) { - view._notifyWillDestroyElement(); - view.domManager.remove(view); - set(view, 'element', null); - if (view._scheduledInsert) { - run.cancel(view._scheduledInsert); - view._scheduledInsert = null; - } + view._renderer.remove(view, false); return view; }, - empty: function(view) { - var _childViews = view._childViews, len, idx; - if (_childViews) { - len = _childViews.length; - for (idx = 0; idx < len; idx++) { - _childViews[idx]._notifyWillDestroyElement(); - } - } - view.domManager.empty(view); - }, - // Handle events from `Ember.EventDispatcher` handleEvent: function(view, eventName, evt) { if (view.has(eventName)) { @@ -24791,7 +39360,7 @@ define("ember-views/views/states/has_element", __exports__["default"] = hasElement; }); -define("ember-views/views/states/in_buffer", +enifed("ember-views/views/states/in_buffer", ["ember-views/views/states/default","ember-metal/error","ember-metal/core","ember-metal/platform","ember-metal/merge","exports"], function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __exports__) { "use strict"; @@ -24830,54 +39399,22 @@ define("ember-views/views/states/in_buffer", // view will render that view and append the resulting // buffer into its buffer. appendChild: function(view, childView, options) { - var buffer = view.buffer, _childViews = view._childViews; + var buffer = view.buffer; + var _childViews = view._childViews; childView = view.createChildView(childView, options); if (!_childViews.length) { _childViews = view._childViews = _childViews.slice(); } _childViews.push(childView); - childView.renderToBuffer(buffer); + if (!childView._morph) { + buffer.pushChildView(childView); + } view.propertyDidChange('childViews'); return childView; }, - // when a view is rendered in a buffer, destroying the - // element will simply destroy the buffer and put the - // state back into the preRender state. - destroyElement: function(view) { - view.clearBuffer(); - var viewCollection = view._notifyWillDestroyElement(); - viewCollection.transitionTo('preRender', false); - - return view; - }, - - empty: function() { - }, - - renderToBufferIfNeeded: function (view, buffer) { - return false; - }, - - // It should be impossible for a rendered view to be scheduled for - // insertion. - insertElement: function() { - throw new EmberError("You can't insert an element that has already been rendered"); - }, - - setElement: function(view, value) { - if (value === null) { - view.transitionTo('preRender'); - } else { - view.clearBuffer(); - view.transitionTo('hasElement'); - } - - return value; - }, - invokeObserver: function(target, observer) { observer.call(target); } @@ -24885,7 +39422,7 @@ define("ember-views/views/states/in_buffer", __exports__["default"] = inBuffer; }); -define("ember-views/views/states/in_dom", +enifed("ember-views/views/states/in_dom", ["ember-metal/core","ember-metal/platform","ember-metal/merge","ember-metal/error","ember-views/views/states/has_element","exports"], function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __exports__) { "use strict"; @@ -24907,7 +39444,7 @@ define("ember-views/views/states/in_dom", merge(inDOM, { enter: function(view) { - if (!View) { View = requireModule('ember-views/views/view')["View"]; } // ES6TODO: this sucks. Have to avoid cycles... + if (!View) { View = requireModule('ember-views/views/view')["default"]; } // ES6TODO: this sucks. Have to avoid cycles... // Register the view for event handling. This hash is used by // Ember.EventDispatcher to dispatch incoming events. @@ -24921,25 +39458,22 @@ define("ember-views/views/states/in_dom", }, exit: function(view) { - if (!View) { View = requireModule('ember-views/views/view')["View"]; } // ES6TODO: this sucks. Have to avoid cycles... + if (!View) { View = requireModule('ember-views/views/view')["default"]; } // ES6TODO: this sucks. Have to avoid cycles... if (!this.isVirtual) delete View.views[view.elementId]; - }, - - insertElement: function(view, fn) { - throw new EmberError("You can't insert an element into the DOM that has already been inserted"); } }); __exports__["default"] = inDOM; }); -define("ember-views/views/states/pre_render", - ["ember-views/views/states/default","ember-metal/platform","ember-metal/merge","exports"], - function(__dependency1__, __dependency2__, __dependency3__, __exports__) { +enifed("ember-views/views/states/pre_render", + ["ember-views/views/states/default","ember-metal/platform","ember-metal/merge","ember-views/system/jquery","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __exports__) { "use strict"; var _default = __dependency1__["default"]; var create = __dependency2__.create; var merge = __dependency3__["default"]; + var jQuery = __dependency4__["default"]; /** @module ember @@ -24947,45 +39481,11 @@ define("ember-views/views/states/pre_render", */ var preRender = create(_default); - merge(preRender, { - // a view leaves the preRender state once its element has been - // created (createElement). - insertElement: function(view, fn) { - view.createElement(); - var viewCollection = view.viewHierarchyCollection(); - - viewCollection.trigger('willInsertElement'); - - fn.call(view); - - // We transition to `inDOM` if the element exists in the DOM - var element = view.get('element'); - if (document.body.contains(element)) { - viewCollection.transitionTo('inDOM', false); - viewCollection.trigger('didInsertElement'); - } - }, - - renderToBufferIfNeeded: function(view, buffer) { - view.renderToBuffer(buffer); - return true; - }, - - empty: Ember.K, - - setElement: function(view, value) { - if (value !== null) { - view.transitionTo('hasElement'); - } - return value; - } - }); - __exports__["default"] = preRender; }); -define("ember-views/views/view", - ["ember-metal/core","ember-metal/error","ember-runtime/system/object","ember-runtime/mixins/evented","ember-runtime/mixins/action_handler","ember-views/system/render_buffer","ember-metal/property_get","ember-metal/property_set","ember-metal/set_properties","ember-metal/run_loop","ember-metal/observer","ember-metal/properties","ember-metal/utils","ember-metal/computed","ember-metal/mixin","ember-metal/is_none","container/container","ember-runtime/system/native_array","ember-metal/instrumentation","ember-runtime/system/string","ember-metal/enumerable_utils","ember-runtime/copy","ember-metal/binding","ember-metal/property_events","ember-views/views/states","ember-views/system/jquery","ember-views/system/ext","exports"], - function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __dependency9__, __dependency10__, __dependency11__, __dependency12__, __dependency13__, __dependency14__, __dependency15__, __dependency16__, __dependency17__, __dependency18__, __dependency19__, __dependency20__, __dependency21__, __dependency22__, __dependency23__, __dependency24__, __dependency25__, __dependency26__, __dependency27__, __exports__) { +enifed("ember-views/views/view", + ["ember-metal/core","ember-runtime/mixins/evented","ember-runtime/system/object","ember-metal/error","ember-metal/property_get","ember-metal/property_set","ember-metal/set_properties","ember-metal/run_loop","ember-metal/observer","ember-metal/properties","ember-metal/utils","ember-metal/computed","ember-metal/mixin","ember-metal/is_none","ember-metal/deprecate_property","ember-runtime/system/native_array","ember-runtime/system/string","ember-metal/enumerable_utils","ember-runtime/copy","ember-metal/binding","ember-metal/property_events","ember-views/system/jquery","ember-views/system/ext","ember-views/views/core_view","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __dependency9__, __dependency10__, __dependency11__, __dependency12__, __dependency13__, __dependency14__, __dependency15__, __dependency16__, __dependency17__, __dependency18__, __dependency19__, __dependency20__, __dependency21__, __dependency22__, __dependency23__, __dependency24__, __exports__) { "use strict"; // Ember.assert, Ember.deprecate, Ember.warn, Ember.TEMPLATES, // Ember.K, jQuery, Ember.lookup, @@ -24993,73 +39493,59 @@ define("ember-views/views/view", // Ember.ENV var Ember = __dependency1__["default"]; - var EmberError = __dependency2__["default"]; + var Evented = __dependency2__["default"]; var EmberObject = __dependency3__["default"]; - var Evented = __dependency4__["default"]; - var ActionHandler = __dependency5__["default"]; - var RenderBuffer = __dependency6__["default"]; - var get = __dependency7__.get; - var set = __dependency8__.set; - var setProperties = __dependency9__["default"]; - var run = __dependency10__["default"]; - var addObserver = __dependency11__.addObserver; - var removeObserver = __dependency11__.removeObserver; + var EmberError = __dependency4__["default"]; + var get = __dependency5__.get; + var set = __dependency6__.set; + var setProperties = __dependency7__["default"]; + var run = __dependency8__["default"]; + var addObserver = __dependency9__.addObserver; + var removeObserver = __dependency9__.removeObserver; - var defineProperty = __dependency12__.defineProperty; - var guidFor = __dependency13__.guidFor; - var meta = __dependency13__.meta; - var computed = __dependency14__.computed; - var observer = __dependency15__.observer; + var defineProperty = __dependency10__.defineProperty; + var deprecateProperty = __dependency10__.deprecateProperty; + var guidFor = __dependency11__.guidFor; + var meta = __dependency11__.meta; + var computed = __dependency12__.computed; + var observer = __dependency13__.observer; - var typeOf = __dependency13__.typeOf; - var isArray = __dependency13__.isArray; - var isNone = __dependency16__.isNone; - var Mixin = __dependency15__.Mixin; - var Container = __dependency17__["default"]; - var A = __dependency18__.A; + var typeOf = __dependency11__.typeOf; + var isArray = __dependency11__.isArray; + var isNone = __dependency14__.isNone; + var Mixin = __dependency13__.Mixin; + var deprecateProperty = __dependency15__.deprecateProperty; + var emberA = __dependency16__.A; - var instrument = __dependency19__.instrument; - - var dasherize = __dependency20__.dasherize; + var dasherize = __dependency17__.dasherize; // ES6TODO: functions on EnumerableUtils should get their own export - var EnumerableUtils = __dependency21__["default"]; - var a_forEach = EnumerableUtils.forEach, - a_addObject = EnumerableUtils.addObject, - a_removeObject = EnumerableUtils.removeObject; + var forEach = __dependency18__.forEach; + var addObject = __dependency18__.addObject; + var removeObject = __dependency18__.removeObject; - var beforeObserver = __dependency15__.beforeObserver; - var copy = __dependency22__["default"]; - var isGlobalPath = __dependency23__.isGlobalPath; + var beforeObserver = __dependency13__.beforeObserver; + var copy = __dependency19__["default"]; + var isGlobalPath = __dependency20__.isGlobalPath; - var propertyWillChange = __dependency24__.propertyWillChange; - var propertyDidChange = __dependency24__.propertyDidChange; + var propertyWillChange = __dependency21__.propertyWillChange; + var propertyDidChange = __dependency21__.propertyDidChange; - var cloneStates = __dependency25__.cloneStates; - var states = __dependency25__.states; - var jQuery = __dependency26__["default"]; + var jQuery = __dependency22__["default"]; // for the side effect of extending Ember.run.queues + var CoreView = __dependency24__["default"]; + /** @module ember @submodule ember-views */ - - var ContainerView; - - function nullViewsBuffer(view) { - view.buffer = null; - - } - - function clearCachedElement(view) { - meta(view).cache.element = undefined; - } - var childViewsProperty = computed(function() { - var childViews = this._childViews, ret = A(), view = this; + var childViews = this._childViews; + var ret = emberA(); + var view = this; - a_forEach(childViews, function(view) { + forEach(childViews, function(view) { var currentChildViews; if (view.isVirtual) { if (currentChildViews = get(view, 'childViews')) { @@ -25071,11 +39557,6 @@ define("ember-views/views/view", }); ret.replace = function (idx, removedCount, addedViews) { - if (!ContainerView) { ContainerView = requireModule('ember-views/views/container_view')['default']; } // ES6TODO: stupid circular dep - - if (view instanceof ContainerView) { - return view.replace(idx, removedCount, addedViews); - } throw new EmberError("childViews is immutable"); }; @@ -25094,238 +39575,6 @@ define("ember-views/views/view", */ Ember.TEMPLATES = {}; - /** - `Ember.CoreView` is an abstract class that exists to give view-like behavior - to both Ember's main view class `Ember.View` and other classes like - `Ember._SimpleMetamorphView` that don't need the fully functionaltiy of - `Ember.View`. - - Unless you have specific needs for `CoreView`, you will use `Ember.View` - in your applications. - - @class CoreView - @namespace Ember - @extends Ember.Object - @uses Ember.Evented - @uses Ember.ActionHandler - */ - - var CoreView = EmberObject.extend(Evented, ActionHandler, { - isView: true, - - states: cloneStates(states), - - init: function() { - this._super(); - this.transitionTo('preRender'); - this._isVisible = get(this, 'isVisible'); - }, - - /** - If the view is currently inserted into the DOM of a parent view, this - property will point to the parent of the view. - - @property parentView - @type Ember.View - @default null - */ - parentView: computed('_parentView', function() { - var parent = this._parentView; - - if (parent && parent.isVirtual) { - return get(parent, 'parentView'); - } else { - return parent; - } - }), - - state: null, - - _parentView: null, - - // return the current view, not including virtual views - concreteView: computed('parentView', function() { - if (!this.isVirtual) { return this; } - else { return get(this, 'parentView.concreteView'); } - }), - - instrumentName: 'core_view', - - instrumentDetails: function(hash) { - hash.object = this.toString(); - hash.containerKey = this._debugContainerKey; - hash.view = this; - }, - - /** - Invoked by the view system when this view needs to produce an HTML - representation. This method will create a new render buffer, if needed, - then apply any default attributes, such as class names and visibility. - Finally, the `render()` method is invoked, which is responsible for - doing the bulk of the rendering. - - You should not need to override this method; instead, implement the - `template` property, or if you need more control, override the `render` - method. - - @method renderToBuffer - @param {Ember.RenderBuffer} buffer the render buffer. If no buffer is - passed, a default buffer, using the current view's `tagName`, will - be used. - @private - */ - renderToBuffer: function(parentBuffer, bufferOperation) { - var name = 'render.' + this.instrumentName, - details = {}; - - this.instrumentDetails(details); - - return instrument(name, details, function instrumentRenderToBuffer() { - return this._renderToBuffer(parentBuffer, bufferOperation); - }, this); - }, - - _renderToBuffer: function(parentBuffer, bufferOperation) { - // If this is the top-most view, start a new buffer. Otherwise, - // create a new buffer relative to the original using the - // provided buffer operation (for example, `insertAfter` will - // insert a new buffer after the "parent buffer"). - var tagName = this.tagName; - - if (tagName === null || tagName === undefined) { - tagName = 'div'; - } - - var buffer = this.buffer = parentBuffer && parentBuffer.begin(tagName) || RenderBuffer(tagName); - this.transitionTo('inBuffer', false); - - this.beforeRender(buffer); - this.render(buffer); - this.afterRender(buffer); - - return buffer; - }, - - /** - Override the default event firing from `Ember.Evented` to - also call methods with the given name. - - @method trigger - @param name {String} - @private - */ - trigger: function(name) { - this._super.apply(this, arguments); - var method = this[name]; - if (method) { - var args = [], i, l; - for (i = 1, l = arguments.length; i < l; i++) { - args.push(arguments[i]); - } - return method.apply(this, args); - } - }, - - deprecatedSendHandles: function(actionName) { - return !!this[actionName]; - }, - - deprecatedSend: function(actionName) { - var args = [].slice.call(arguments, 1); - this[actionName].apply(this, args); - return; - }, - - has: function(name) { - return typeOf(this[name]) === 'function' || this._super(name); - }, - - destroy: function() { - var parent = this._parentView; - - if (!this._super()) { return; } - - // destroy the element -- this will avoid each child view destroying - // the element over and over again... - if (!this.removedFromDOM) { this.destroyElement(); } - - // remove from parent if found. Don't call removeFromParent, - // as removeFromParent will try to remove the element from - // the DOM again. - if (parent) { parent.removeChild(this); } - - this.transitionTo('destroying', false); - - return this; - }, - - clearRenderedChildren: Ember.K, - triggerRecursively: Ember.K, - invokeRecursively: Ember.K, - transitionTo: Ember.K, - destroyElement: Ember.K - }); - - var ViewCollection = function(initialViews) { - var views = this.views = initialViews || []; - this.length = views.length; - }; - - ViewCollection.prototype = { - length: 0, - - trigger: function(eventName) { - var views = this.views, view; - for (var i = 0, l = views.length; i < l; i++) { - view = views[i]; - if (view.trigger) { view.trigger(eventName); } - } - }, - - triggerRecursively: function(eventName) { - var views = this.views; - for (var i = 0, l = views.length; i < l; i++) { - views[i].triggerRecursively(eventName); - } - }, - - invokeRecursively: function(fn) { - var views = this.views, view; - - for (var i = 0, l = views.length; i < l; i++) { - view = views[i]; - fn(view); - } - }, - - transitionTo: function(state, children) { - var views = this.views; - for (var i = 0, l = views.length; i < l; i++) { - views[i].transitionTo(state, children); - } - }, - - push: function() { - this.length += arguments.length; - var views = this.views; - return views.push.apply(views, arguments); - }, - - objectAt: function(idx) { - return this.views[idx]; - }, - - forEach: function(callback) { - var views = this.views; - return a_forEach(views, callback); - }, - - clear: function() { - this.length = 0; - this.views.length = 0; - } - }; - var EMPTY_ARRAY = []; /** @@ -25534,10 +39783,10 @@ define("ember-views/views/view", ```html ``` - - One property can be mapped on to another by placing a ":" between + + One property can be mapped on to another by placing a ":" between the source property and the destination property: - + ```javascript AnchorView = Ember.View.extend({ tagName: 'a', @@ -25545,13 +39794,13 @@ define("ember-views/views/view", url: 'http://google.com' }); ``` - + Will result in view instances with an HTML representation of: ```html ``` - + If the return value of an `attributeBindings` monitored property is a boolean the property will follow HTML's pattern of repeating the attribute's name as its value: @@ -25704,7 +39953,7 @@ define("ember-views/views/view", }); aView = AView.create({ - controller: aController, + controller: aController }); ``` @@ -25738,8 +39987,8 @@ define("ember-views/views/view", ```javascript AViewWithLayout = Ember.View.extend({ - layout: Ember.Handlebars.compile("
      {{yield}}
      ") - template: Ember.Handlebars.compile("I got wrapped"), + layout: Ember.Handlebars.compile("
      {{yield}}
      "), + template: Ember.Handlebars.compile("I got wrapped") }); ``` @@ -25825,8 +40074,9 @@ define("ember-views/views/view", on the descendent. ```javascript - OuterView = Ember.View.extend({ - template: Ember.Handlebars.compile("outer {{#view InnerView}}inner{{/view}} outer"), + var App = Ember.Application.create(); + App.OuterView = Ember.View.extend({ + template: Ember.Handlebars.compile("outer {{#view 'inner'}}inner{{/view}} outer"), eventManager: Ember.Object.create({ mouseEnter: function(event, view) { // view might be instance of either @@ -25836,7 +40086,7 @@ define("ember-views/views/view", }) }); - InnerView = Ember.View.extend({ + App.InnerView = Ember.View.extend({ click: function(event) { // will be called if rendered inside // an OuterView because OuterView's @@ -25980,8 +40230,8 @@ define("ember-views/views/view", template: computed('templateName', function(key, value) { if (value !== undefined) { return value; } - var templateName = get(this, 'templateName'), - template = this.templateForName(templateName, 'template'); + var templateName = get(this, 'templateName'); + var template = this.templateForName(templateName, 'template'); return template || get(this, 'defaultTemplate'); @@ -26014,8 +40264,8 @@ define("ember-views/views/view", @type Function */ layout: computed(function(key) { - var layoutName = get(this, 'layoutName'), - layout = this.templateForName(layoutName, 'layout'); + var layoutName = get(this, 'layoutName'); + var layout = this.templateForName(layoutName, 'layout'); return layout || get(this, 'defaultLayout'); @@ -26029,9 +40279,13 @@ define("ember-views/views/view", templateForName: function(name, type) { if (!name) { return; } - // the defaultContainer is deprecated - var container = this.container || (Container && Container.defaultContainer); - return container && container.lookup('template:' + name); + if (!this.container) { + throw new EmberError('Container was not found when looking up a views template. ' + + 'This is most likely due to manually instantiating an Ember.View. ' + + 'See: http://git.io/EKPpnA'); + } + + return this.container.lookup('template:' + name); }, /** @@ -26053,7 +40307,7 @@ define("ember-views/views/view", } else { return get(this, '_context'); } - }).volatile(), + })["volatile"](), /** Private copy of the view's template context. This can be set directly @@ -26167,8 +40421,8 @@ define("ember-views/views/view", @return Ember.View */ nearestOfType: function(klass) { - var view = get(this, 'parentView'), - isOfType = klass instanceof Mixin ? + var view = get(this, 'parentView'); + var isOfType = klass instanceof Mixin ? function(view) { return klass.detect(view); } : function(view) { return klass.detect(view.constructor); }; @@ -26241,7 +40495,7 @@ define("ember-views/views/view", var templateData = get(this, 'templateData'); var keywords = templateData ? copy(templateData.keywords) : {}; - set(keywords, 'view', get(this, 'concreteView')); + set(keywords, 'view', this.isVirtual ? keywords.view : this); set(keywords, '_view', this); set(keywords, 'controller', get(this, 'controller')); @@ -26313,21 +40567,6 @@ define("ember-views/views/view", return this.currentState.rerender(this); }, - clearRenderedChildren: function() { - var lengthBefore = this.lengthBeforeRender, - lengthAfter = this.lengthAfterRender; - - // If there were child views created during the last call to render(), - // remove them under the assumption that they will be re-created when - // we re-render. - - // VIEW-TODO: Unit test this path. - var childViews = this._childViews; - for (var i=lengthAfter-1; i>=lengthBefore; i--) { - if (childViews[i]) { childViews[i].destroy(); } - } - }, - /** Iterates over the view's `classNameBindings` array, inserts the value of the specified property into the `classNames` array, then creates an @@ -26338,13 +40577,13 @@ define("ember-views/views/view", @private */ _applyClassNameBindings: function(classBindings) { - var classNames = this.classNames, - elem, newClass, dasherizedClass; + var classNames = this.classNames; + var elem, newClass, dasherizedClass; // Loop through all of the configured bindings. These will be either // property names ('isUrgent') or property paths relative to the view // ('content.isUrgent') - a_forEach(classBindings, function(binding) { + forEach(classBindings, function(binding) { // Variable in which the old class value is saved. The observer function @@ -26385,7 +40624,7 @@ define("ember-views/views/view", if (dasherizedClass) { // Ensure that it gets into the classNames array // so it is displayed when we render. - a_addObject(classNames, dasherizedClass); + addObject(classNames, dasherizedClass); // Save a reference to the class name so we can remove it // if the observer fires. Remember that this variable has @@ -26417,14 +40656,15 @@ define("ember-views/views/view", @private */ _applyAttributeBindings: function(buffer, attributeBindings) { - var attributeValue, - unspecifiedAttributeBindings = this._unspecifiedAttributeBindings = this._unspecifiedAttributeBindings || {}; + var attributeValue; + var unspecifiedAttributeBindings = this._unspecifiedAttributeBindings = this._unspecifiedAttributeBindings || {}; - a_forEach(attributeBindings, function(binding) { - var split = binding.split(':'), - property = split[0], - attributeName = split[1] || property; + forEach(attributeBindings, function(binding) { + var split = binding.split(':'); + var property = split[0]; + var attributeName = split[1] || property; + if (property in this) { this._setupAttributeBindingObservation(property, attributeName); @@ -26513,13 +40753,7 @@ define("ember-views/views/view", @property element @type DOMElement */ - element: computed('_parentView', function(key, value) { - if (value !== undefined) { - return this.currentState.setElement(this, value); - } else { - return this.currentState.getElement(this); - } - }), + element: null, /** Returns a jQuery object for this view's element. If you pass in a selector @@ -26538,9 +40772,9 @@ define("ember-views/views/view", }, mutateChildViews: function(callback) { - var childViews = this._childViews, - idx = childViews.length, - view; + var childViews = this._childViews; + var idx = childViews.length; + var view; while(--idx >= 0) { view = childViews[idx]; @@ -26555,8 +40789,8 @@ define("ember-views/views/view", if (!childViews) { return this; } - var len = childViews.length, - view, idx; + var len = childViews.length; + var view, idx; for (idx = 0; idx < len; idx++) { view = childViews[idx]; @@ -26586,12 +40820,11 @@ define("ember-views/views/view", @param {String|DOMElement|jQuery} A selector, element, HTML string, or jQuery object @return {Ember.View} receiver */ - appendTo: function(target) { - // Schedule the DOM element to be created and appended to the given - // element after bindings have synchronized. - this._insertElementLater(function() { - this.$().appendTo(target); - }); + appendTo: function(selector) { + var target = jQuery(selector); + + + this.constructor.renderer.appendTo(this, target[0]); return this; }, @@ -26609,47 +40842,15 @@ define("ember-views/views/view", @param {String|DOMElement|jQuery} target A selector, element, HTML string, or jQuery object @return {Ember.View} received */ - replaceIn: function(target) { + replaceIn: function(selector) { + var target = jQuery(selector); + - this._insertElementLater(function() { - jQuery(target).empty(); - this.$().appendTo(target); - }); + this.constructor.renderer.replaceIn(this, target[0]); return this; }, - /** - Schedules a DOM operation to occur during the next render phase. This - ensures that all bindings have finished synchronizing before the view is - rendered. - - To use, pass a function that performs a DOM operation. - - Before your function is called, this view and all child views will receive - the `willInsertElement` event. After your function is invoked, this view - and all of its child views will receive the `didInsertElement` event. - - ```javascript - view._insertElementLater(function() { - this.createElement(); - this.$().appendTo('body'); - }); - ``` - - @method _insertElementLater - @param {Function} fn the function that inserts the element into the DOM - @private - */ - _insertElementLater: function(fn) { - this._scheduledInsert = run.scheduleOnce('render', this, '_insertElement', fn); - }, - - _insertElement: function (fn) { - this._scheduledInsert = null; - this.currentState.insertElement(this, fn); - }, - /** Appends the view's element to the document body. If the view does not have an HTML representation yet, `createElement()` will be called @@ -26683,9 +40884,6 @@ define("ember-views/views/view", // In the interim, we will just re-render if that happens. It is more // important than elements get garbage collected. if (!this.removedFromDOM) { this.destroyElement(); } - this.invokeRecursively(function(view) { - if (view.clearRenderedChildren) { view.clearRenderedChildren(); } - }); }, elementId: null, @@ -26707,20 +40905,20 @@ define("ember-views/views/view", }, /** - Creates a DOM representation of the view and all of its - child views by recursively calling the `render()` method. + Creates a DOM representation of the view and all of its child views by + recursively calling the `render()` method. - After the element has been created, `didInsertElement` will + After the element has been inserted into the DOM, `didInsertElement` will be called on this view and all of its child views. @method createElement @return {Ember.View} receiver */ createElement: function() { - if (get(this, 'element')) { return this; } + if (this.element) { return this; } - var buffer = this.renderToBuffer(); - set(this, 'element', buffer.element()); + this._didCreateElementWithoutMorph = true; + this.constructor.renderer.renderTree(this); return this; }, @@ -26737,6 +40935,9 @@ define("ember-views/views/view", or after the view was re-rendered. Override this function to do any set up that requires an element in the document body. + When a view has children, didInsertElement will be called on the + child view(s) first, bubbling upwards through the hierarchy. + @event didInsertElement */ didInsertElement: Ember.K, @@ -26750,65 +40951,6 @@ define("ember-views/views/view", */ willClearRender: Ember.K, - /** - Run this callback on the current view (unless includeSelf is false) and recursively on child views. - - @method invokeRecursively - @param fn {Function} - @param includeSelf {Boolean} Includes itself if true. - @private - */ - invokeRecursively: function(fn, includeSelf) { - var childViews = (includeSelf === false) ? this._childViews : [this]; - var currentViews, view, currentChildViews; - - while (childViews.length) { - currentViews = childViews.slice(); - childViews = []; - - for (var i=0, l=currentViews.length; i=0; i--) { - childViews[i].removedFromDOM = true; - } - // remove from non-virtual parent view if viewName was specified if (viewName && nonVirtualParentView) { nonVirtualParentView.set(viewName, null); } - childLen = childViews.length; - for (i=childLen-1; i>=0; i--) { - childViews[i].destroy(); - } - return this; }, @@ -27251,16 +41341,18 @@ define("ember-views/views/view", _toggleVisibility: function() { var $el = this.$(); - if (!$el) { return; } - var isVisible = get(this, 'isVisible'); if (this._isVisible === isVisible) { return ; } - $el.toggle(isVisible); - + // It's important to keep these in sync, even if we don't yet have + // an element in the DOM to manipulate: this._isVisible = isVisible; + if (!$el) { return; } + + $el.toggle(isVisible); + if (this._isAncestorHidden()) { return; } if (isVisible) { @@ -27304,25 +41396,16 @@ define("ember-views/views/view", return false; }, - - clearBuffer: function() { - this.invokeRecursively(nullViewsBuffer); - }, - transitionTo: function(state, children) { - var priorState = this.currentState, - currentState = this.currentState = this.states[state]; - this.state = state; + this._transitionTo(state, children); + }, + _transitionTo: function(state, children) { + var priorState = this.currentState; + var currentState = this.currentState = this._states[state]; + this._state = state; if (priorState && priorState.exit) { priorState.exit(this); } if (currentState.enter) { currentState.enter(this); } - if (state === 'inDOM') { meta(this).cache.element = undefined; } - - if (children !== false) { - this.forEachChildView(function(view) { - view.transitionTo(state); - }); - } }, // ....................................................... @@ -27351,13 +41434,13 @@ define("ember-views/views/view", return; } - var view = this, - stateCheckedObserver = function() { - view.currentState.invokeObserver(this, observer); - }, - scheduledObserver = function() { - run.scheduleOnce('render', this, stateCheckedObserver); - }; + var view = this; + var stateCheckedObserver = function() { + view.currentState.invokeObserver(this, observer); + }; + var scheduledObserver = function() { + run.scheduleOnce('render', this, stateCheckedObserver); + }; addObserver(root, path, target, scheduledObserver); @@ -27367,6 +41450,8 @@ define("ember-views/views/view", } }); + deprecateProperty(View.prototype, 'state', '_state'); + deprecateProperty(View.prototype, 'states', '_states'); /* Describe how the specified actions should behave in the various @@ -27399,48 +41484,6 @@ define("ember-views/views/view", run.once(View, 'notifyMutationListeners'); } - var DOMManager = { - prepend: function(view, html) { - view.$().prepend(html); - notifyMutationListeners(); - }, - - after: function(view, html) { - view.$().after(html); - notifyMutationListeners(); - }, - - html: function(view, html) { - view.$().html(html); - notifyMutationListeners(); - }, - - replace: function(view) { - var element = get(view, 'element'); - - set(view, 'element', null); - - view._insertElementLater(function() { - jQuery(element).replaceWith(get(view, 'element')); - notifyMutationListeners(); - }); - }, - - remove: function(view) { - view.$().remove(); - notifyMutationListeners(); - }, - - empty: function(view) { - view.$().empty(); - notifyMutationListeners(); - } - }; - - View.reopen({ - domManager: DOMManager - }); - View.reopenClass({ /** @@ -27463,11 +41506,10 @@ define("ember-views/views/view", @private */ _parsePropertyPath: function(path) { - var split = path.split(':'), - propertyPath = split[0], - classNames = "", - className, - falsyClassName; + var split = path.split(':'); + var propertyPath = split[0]; + var classNames = ""; + var className, falsyClassName; // check if the property is defined as prop:class or prop:trueClass:falseClass if (split.length > 1) { @@ -27512,9 +41554,9 @@ define("ember-views/views/view", */ _classStringForValue: function(path, val, className, falsyClassName) { if(isArray(val)) { - val = get(val, 'length') !== 0; + val = get(val, 'length') !== 0; } - + // When using the colon syntax, evaluate the truthiness or falsiness // of the value to determine which className to return if (className || falsyClassName) { @@ -27551,7 +41593,7 @@ define("ember-views/views/view", }); var mutation = EmberObject.extend(Evented).create(); - + // TODO MOVE TO RENDERER HOOKS View.addMutationListener = function(callback) { mutation.on('change', callback); }; @@ -27592,7 +41634,12 @@ define("ember-views/views/view", if (isNone(value) || value === false) { // `null`, `undefined` or `false` should remove attribute elem.removeAttr(name); - elem.prop(name, ''); + // In IE8 `prop` couldn't remove attribute when name is `required`. + if (name === 'required') { + elem.removeProp(name); + } else { + elem.prop(name, ''); + } } else if (value !== elem.prop(name)) { // value should always be properties elem.prop(name, value); @@ -27602,11695 +41649,857 @@ define("ember-views/views/view", } }; - __exports__.CoreView = CoreView; - __exports__.View = View; - __exports__.ViewCollection = ViewCollection; + __exports__["default"] = View; }); -})(); - -(function() { -define("metamorph", - [], - function() { +enifed("ember", + ["ember-metal","ember-runtime","ember-handlebars","ember-views","ember-routing","ember-routing-handlebars","ember-application","ember-extension-support"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__) { "use strict"; - // ========================================================================== - // Project: metamorph - // Copyright: ©2014 Tilde, Inc. All rights reserved. - // ========================================================================== - - var K = function() {}, - guid = 0, - disableRange = (function(){ - if ('undefined' !== typeof MetamorphENV) { - return MetamorphENV.DISABLE_RANGE_API; - } else if ('undefined' !== ENV) { - return ENV.DISABLE_RANGE_API; - } else { - return false; - } - })(), - - // Feature-detect the W3C range API, the extended check is for IE9 which only partially supports ranges - supportsRange = (!disableRange) && typeof document !== 'undefined' && ('createRange' in document) && (typeof Range !== 'undefined') && Range.prototype.createContextualFragment, - - // Internet Explorer prior to 9 does not allow setting innerHTML if the first element - // is a "zero-scope" element. This problem can be worked around by making - // the first node an invisible text node. We, like Modernizr, use ­ - needsShy = typeof document !== 'undefined' && (function() { - var testEl = document.createElement('div'); - testEl.innerHTML = "
      "; - testEl.firstChild.innerHTML = ""; - return testEl.firstChild.innerHTML === ''; - })(), - - - // IE 8 (and likely earlier) likes to move whitespace preceeding - // a script tag to appear after it. This means that we can - // accidentally remove whitespace when updating a morph. - movesWhitespace = document && (function() { - var testEl = document.createElement('div'); - testEl.innerHTML = "Test: Value"; - return testEl.childNodes[0].nodeValue === 'Test:' && - testEl.childNodes[2].nodeValue === ' Value'; - })(); - - // Constructor that supports either Metamorph('foo') or new - // Metamorph('foo'); - // - // Takes a string of HTML as the argument. - - var Metamorph = function(html) { - var self; - - if (this instanceof Metamorph) { - self = this; - } else { - self = new K(); - } - - self.innerHTML = html; - var myGuid = 'metamorph-'+(guid++); - self.start = myGuid + '-start'; - self.end = myGuid + '-end'; - - return self; - }; - - K.prototype = Metamorph.prototype; - - var rangeFor, htmlFunc, removeFunc, outerHTMLFunc, appendToFunc, afterFunc, prependFunc, startTagFunc, endTagFunc; - - outerHTMLFunc = function() { - return this.startTag() + this.innerHTML + this.endTag(); - }; - - startTagFunc = function() { - /* - * We replace chevron by its hex code in order to prevent escaping problems. - * Check this thread for more explaination: - * http://stackoverflow.com/questions/8231048/why-use-x3c-instead-of-when-generating-html-from-javascript - */ - return "hi"; - * div.firstChild.firstChild.tagName //=> "" - * - * If our script markers are inside such a node, we need to find that - * node and use *it* as the marker. - */ - var realNode = function(start) { - while (start.parentNode.tagName === "") { - start = start.parentNode; - } - - return start; - }; - - /* - * When automatically adding a tbody, Internet Explorer inserts the - * tbody immediately before the first . Other browsers create it - * before the first node, no matter what. - * - * This means the the following code: - * - * div = document.createElement("div"); - * div.innerHTML = "
      hi
      - * - * Generates the following DOM in IE: - * - * + div - * + table - * - script id='first' - * + tbody - * + tr - * + td - * - "hi" - * - script id='last' - * - * Which means that the two script tags, even though they were - * inserted at the same point in the hierarchy in the original - * HTML, now have different parents. - * - * This code reparents the first script tag by making it the tbody's - * first child. - * - */ - var fixParentage = function(start, end) { - if (start.parentNode !== end.parentNode) { - end.parentNode.insertBefore(start, end.parentNode.firstChild); - } - }; - - htmlFunc = function(html, outerToo) { - // get the real starting node. see realNode for details. - var start = realNode(document.getElementById(this.start)); - var end = document.getElementById(this.end); - var parentNode = end.parentNode; - var node, nextSibling, last; - - // make sure that the start and end nodes share the same - // parent. If not, fix it. - fixParentage(start, end); - - // remove all of the nodes after the starting placeholder and - // before the ending placeholder. - node = start.nextSibling; - while (node) { - nextSibling = node.nextSibling; - last = node === end; - - // if this is the last node, and we want to remove it as well, - // set the `end` node to the next sibling. This is because - // for the rest of the function, we insert the new nodes - // before the end (note that insertBefore(node, null) is - // the same as appendChild(node)). - // - // if we do not want to remove it, just break. - if (last) { - if (outerToo) { end = node.nextSibling; } else { break; } - } - - node.parentNode.removeChild(node); - - // if this is the last node and we didn't break before - // (because we wanted to remove the outer nodes), break - // now. - if (last) { break; } - - node = nextSibling; - } - - // get the first node for the HTML string, even in cases like - // tables and lists where a simple innerHTML on a div would - // swallow some of the content. - node = firstNodeFor(start.parentNode, html); - - if (outerToo) { - start.parentNode.removeChild(start); - } - - // copy the nodes for the HTML between the starting and ending - // placeholder. - while (node) { - nextSibling = node.nextSibling; - parentNode.insertBefore(node, end); - node = nextSibling; - } - }; - - // remove the nodes in the DOM representing this metamorph. - // - // this includes the starting and ending placeholders. - removeFunc = function() { - var start = realNode(document.getElementById(this.start)); - var end = document.getElementById(this.end); - - this.html(''); - start.parentNode.removeChild(start); - end.parentNode.removeChild(end); - }; - - appendToFunc = function(parentNode) { - var node = firstNodeFor(parentNode, this.outerHTML()); - var nextSibling; - - while (node) { - nextSibling = node.nextSibling; - parentNode.appendChild(node); - node = nextSibling; - } - }; - - afterFunc = function(html) { - // get the real starting node. see realNode for details. - var end = document.getElementById(this.end); - var insertBefore = end.nextSibling; - var parentNode = end.parentNode; - var nextSibling; - var node; - - // get the first node for the HTML string, even in cases like - // tables and lists where a simple innerHTML on a div would - // swallow some of the content. - node = firstNodeFor(parentNode, html); - - // copy the nodes for the HTML between the starting and ending - // placeholder. - while (node) { - nextSibling = node.nextSibling; - parentNode.insertBefore(node, insertBefore); - node = nextSibling; - } - }; - - prependFunc = function(html) { - var start = document.getElementById(this.start); - var parentNode = start.parentNode; - var nextSibling; - var node; - - node = firstNodeFor(parentNode, html); - var insertBefore = start.nextSibling; - - while (node) { - nextSibling = node.nextSibling; - parentNode.insertBefore(node, insertBefore); - node = nextSibling; - } - }; + /* global navigator */ + // require the main entry points for each of these packages + // this is so that the global exports occur properly + + // do this to ensure that Ember.Test is defined properly on the global + // if it is present. + if (Ember.__loader.registry['ember-testing']) { + requireModule('ember-testing'); } - Metamorph.prototype.html = function(html) { - this.checkRemoved(); - if (html === undefined) { return this.innerHTML; } - - htmlFunc.call(this, html); - - this.innerHTML = html; - }; - - Metamorph.prototype.replaceWith = function(html) { - this.checkRemoved(); - htmlFunc.call(this, html, true); - }; - - Metamorph.prototype.remove = removeFunc; - Metamorph.prototype.outerHTML = outerHTMLFunc; - Metamorph.prototype.appendTo = appendToFunc; - Metamorph.prototype.after = afterFunc; - Metamorph.prototype.prepend = prependFunc; - Metamorph.prototype.startTag = startTagFunc; - Metamorph.prototype.endTag = endTagFunc; - - Metamorph.prototype.isRemoved = function() { - var before = document.getElementById(this.start); - var after = document.getElementById(this.end); - - return !before || !after; - }; - - Metamorph.prototype.checkRemoved = function() { - if (this.isRemoved()) { - throw new Error("Cannot perform operations on a Metamorph that is not in the DOM."); - } - }; - - return Metamorph; - }); - -})(); - -(function() { -define("ember-handlebars-compiler", - ["ember-metal/core","exports"], - function(__dependency1__, __exports__) { - "use strict"; /** + Ember + @module ember - @submodule ember-handlebars-compiler */ - var Ember = __dependency1__["default"]; - - // ES6Todo: you'll need to import debugger once debugger is es6'd. - if (typeof Ember.assert === 'undefined') { Ember.assert = function(){}; }; - if (typeof Ember.FEATURES === 'undefined') { Ember.FEATURES = { isEnabled: function(){} }; }; - - var objectCreate = Object.create || function(parent) { - function F() {} - F.prototype = parent; - return new F(); - }; - - // set up for circular references later - var View, Component; - - // ES6Todo: when ember-debug is es6'ed import this. - // var emberAssert = Ember.assert; - var Handlebars = (Ember.imports && Ember.imports.Handlebars) || (this && this.Handlebars); - if (!Handlebars && typeof require === 'function') { - Handlebars = require('handlebars'); - } - - - - /** - Prepares the Handlebars templating library for use inside Ember's view - system. - - The `Ember.Handlebars` object is the standard Handlebars library, extended to - use Ember's `get()` method instead of direct property access, which allows - computed properties to be used inside templates. - - To create an `Ember.Handlebars` template, call `Ember.Handlebars.compile()`. - This will return a function that can be used by `Ember.View` for rendering. - - @class Handlebars - @namespace Ember - */ - var EmberHandlebars = Ember.Handlebars = objectCreate(Handlebars); - - /** - Register a bound helper or custom view helper. - - ## Simple bound helper example - - ```javascript - Ember.Handlebars.helper('capitalize', function(value) { - return value.toUpperCase(); }); - ``` - - The above bound helper can be used inside of templates as follows: - - ```handlebars - {{capitalize name}} - ``` - - In this case, when the `name` property of the template's context changes, - the rendered value of the helper will update to reflect this change. - - For more examples of bound helpers, see documentation for - `Ember.Handlebars.registerBoundHelper`. - - ## Custom view helper example - - Assuming a view subclass named `App.CalendarView` were defined, a helper - for rendering instances of this view could be registered as follows: - - ```javascript - Ember.Handlebars.helper('calendar', App.CalendarView): - ``` - - The above bound helper can be used inside of templates as follows: - - ```handlebars - {{calendar}} - ``` - - Which is functionally equivalent to: - - ```handlebars - {{view App.CalendarView}} - ``` - - Options in the helper will be passed to the view in exactly the same - manner as with the `view` helper. - - @method helper - @for Ember.Handlebars - @param {String} name - @param {Function|Ember.View} function or view class constructor - @param {String} dependentKeys* - */ - EmberHandlebars.helper = function(name, value) { - if (!View) { View = requireModule('ember-views/views/view')['View']; } // ES6TODO: stupid circular dep - if (!Component) { Component = requireModule('ember-views/views/component')['default']; } // ES6TODO: stupid circular dep - - - if (View.detect(value)) { - EmberHandlebars.registerHelper(name, EmberHandlebars.makeViewHelper(value)); - } else { - EmberHandlebars.registerBoundHelper.apply(null, arguments); - } - }; - - /** - Returns a helper function that renders the provided ViewClass. - - Used internally by Ember.Handlebars.helper and other methods - involving helper/component registration. - - @private - @method makeViewHelper - @for Ember.Handlebars - @param {Function} ViewClass view class constructor - @since 1.2.0 - */ - EmberHandlebars.makeViewHelper = function(ViewClass) { - return function(options) { - return EmberHandlebars.helpers.view.call(this, ViewClass, options); - }; - }; - - /** - @class helpers - @namespace Ember.Handlebars - */ - EmberHandlebars.helpers = objectCreate(Handlebars.helpers); - - /** - Override the the opcode compiler and JavaScript compiler for Handlebars. - - @class Compiler - @namespace Ember.Handlebars - @private - @constructor - */ - EmberHandlebars.Compiler = function() {}; - - // Handlebars.Compiler doesn't exist in runtime-only - if (Handlebars.Compiler) { - EmberHandlebars.Compiler.prototype = objectCreate(Handlebars.Compiler.prototype); - } - - EmberHandlebars.Compiler.prototype.compiler = EmberHandlebars.Compiler; - - /** - @class JavaScriptCompiler - @namespace Ember.Handlebars - @private - @constructor - */ - EmberHandlebars.JavaScriptCompiler = function() {}; - - // Handlebars.JavaScriptCompiler doesn't exist in runtime-only - if (Handlebars.JavaScriptCompiler) { - EmberHandlebars.JavaScriptCompiler.prototype = objectCreate(Handlebars.JavaScriptCompiler.prototype); - EmberHandlebars.JavaScriptCompiler.prototype.compiler = EmberHandlebars.JavaScriptCompiler; - } - - - EmberHandlebars.JavaScriptCompiler.prototype.namespace = "Ember.Handlebars"; - - EmberHandlebars.JavaScriptCompiler.prototype.initializeBuffer = function() { - return "''"; - }; - - /** - Override the default buffer for Ember Handlebars. By default, Handlebars - creates an empty String at the beginning of each invocation and appends to - it. Ember's Handlebars overrides this to append to a single shared buffer. - - @private - @method appendToBuffer - @param string {String} - */ - EmberHandlebars.JavaScriptCompiler.prototype.appendToBuffer = function(string) { - return "data.buffer.push("+string+");"; - }; - - // Hacks ahead: - // Handlebars presently has a bug where the `blockHelperMissing` hook - // doesn't get passed the name of the missing helper name, but rather - // gets passed the value of that missing helper evaluated on the current - // context, which is most likely `undefined` and totally useless. - // - // So we alter the compiled template function to pass the name of the helper - // instead, as expected. - // - // This can go away once the following is closed: - // https://github.com/wycats/handlebars.js/issues/634 - - var DOT_LOOKUP_REGEX = /helpers\.(.*?)\)/, - BRACKET_STRING_LOOKUP_REGEX = /helpers\['(.*?)'/, - INVOCATION_SPLITTING_REGEX = /(.*blockHelperMissing\.call\(.*)(stack[0-9]+)(,.*)/; - - EmberHandlebars.JavaScriptCompiler.stringifyLastBlockHelperMissingInvocation = function(source) { - var helperInvocation = source[source.length - 1], - helperName = (DOT_LOOKUP_REGEX.exec(helperInvocation) || BRACKET_STRING_LOOKUP_REGEX.exec(helperInvocation))[1], - matches = INVOCATION_SPLITTING_REGEX.exec(helperInvocation); - - source[source.length - 1] = matches[1] + "'" + helperName + "'" + matches[3]; - }; - - var stringifyBlockHelperMissing = EmberHandlebars.JavaScriptCompiler.stringifyLastBlockHelperMissingInvocation; - - var originalBlockValue = EmberHandlebars.JavaScriptCompiler.prototype.blockValue; - EmberHandlebars.JavaScriptCompiler.prototype.blockValue = function() { - originalBlockValue.apply(this, arguments); - stringifyBlockHelperMissing(this.source); - }; - - var originalAmbiguousBlockValue = EmberHandlebars.JavaScriptCompiler.prototype.ambiguousBlockValue; - EmberHandlebars.JavaScriptCompiler.prototype.ambiguousBlockValue = function() { - originalAmbiguousBlockValue.apply(this, arguments); - stringifyBlockHelperMissing(this.source); - }; - - /** - Rewrite simple mustaches from `{{foo}}` to `{{bind "foo"}}`. This means that - all simple mustaches in Ember's Handlebars will also set up an observer to - keep the DOM up to date when the underlying property changes. - - @private - @method mustache - @for Ember.Handlebars.Compiler - @param mustache - */ - EmberHandlebars.Compiler.prototype.mustache = function(mustache) { - if (!(mustache.params.length || mustache.hash)) { - var id = new Handlebars.AST.IdNode([{ part: '_triageMustache' }]); - - // Update the mustache node to include a hash value indicating whether the original node - // was escaped. This will allow us to properly escape values when the underlying value - // changes and we need to re-render the value. - if (!mustache.escaped) { - mustache.hash = mustache.hash || new Handlebars.AST.HashNode([]); - mustache.hash.pairs.push(["unescaped", new Handlebars.AST.StringNode("true")]); - } - mustache = new Handlebars.AST.MustacheNode([id].concat([mustache.id]), mustache.hash, !mustache.escaped); - } - - return Handlebars.Compiler.prototype.mustache.call(this, mustache); - }; - - /** - Used for precompilation of Ember Handlebars templates. This will not be used - during normal app execution. - - @method precompile - @for Ember.Handlebars - @static - @param {String} string The template to precompile - @param {Boolean} asObject optional parameter, defaulting to true, of whether or not the - compiled template should be returned as an Object or a String - */ - EmberHandlebars.precompile = function(string, asObject) { - var ast = Handlebars.parse(string); - - var options = { - knownHelpers: { - action: true, - unbound: true, - 'bind-attr': true, - template: true, - view: true, - _triageMustache: true - }, - data: true, - stringParams: true - }; - - asObject = asObject === undefined ? true : asObject; - - var environment = new EmberHandlebars.Compiler().compile(ast, options); - return new EmberHandlebars.JavaScriptCompiler().compile(environment, options, undefined, asObject); - }; - - // We don't support this for Handlebars runtime-only - if (Handlebars.compile) { - /** - The entry point for Ember Handlebars. This replaces the default - `Handlebars.compile` and turns on template-local data and String - parameters. - - @method compile - @for Ember.Handlebars - @static - @param {String} string The template to compile - @return {Function} - */ - EmberHandlebars.compile = function(string) { - var ast = Handlebars.parse(string); - var options = { data: true, stringParams: true }; - var environment = new EmberHandlebars.Compiler().compile(ast, options); - var templateSpec = new EmberHandlebars.JavaScriptCompiler().compile(environment, options, undefined, true); - - var template = EmberHandlebars.template(templateSpec); - template.isMethod = false; //Make sure we don't wrap templates with ._super - - return template; - }; - } - - __exports__["default"] = EmberHandlebars; - }); -})(); - -(function() { -define("ember-handlebars/component_lookup", - ["ember-runtime/system/object","exports"], - function(__dependency1__, __exports__) { - "use strict"; - var EmberObject = __dependency1__["default"]; - - var ComponentLookup = EmberObject.extend({ - lookupFactory: function(name, container) { - - container = container || this.container; - - var fullName = 'component:' + name, - templateFullName = 'template:components/' + name, - templateRegistered = container && container.has(templateFullName); - - if (templateRegistered) { - container.injection(fullName, 'layout', templateFullName); - } - - var Component = container.lookupFactory(fullName); - - // Only treat as a component if either the component - // or a template has been registered. - if (templateRegistered || Component) { - if (!Component) { - container.register(fullName, Ember.Component); - Component = container.lookupFactory(fullName); - } - return Component; - } - } - }); - - __exports__["default"] = ComponentLookup; - }); -define("ember-handlebars/controls", - ["ember-handlebars/controls/checkbox","ember-handlebars/controls/text_field","ember-handlebars/controls/text_area","ember-metal/core","ember-handlebars-compiler","exports"], - function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __exports__) { - "use strict"; - var Checkbox = __dependency1__["default"]; - var TextField = __dependency2__["default"]; - var TextArea = __dependency3__["default"]; - - var Ember = __dependency4__["default"]; - // Ember.assert - // var emberAssert = Ember.assert; - - var EmberHandlebars = __dependency5__["default"]; - var helpers = EmberHandlebars.helpers; - /** - @module ember - @submodule ember-handlebars-compiler - */ - - /** - - The `{{input}}` helper inserts an HTML `` tag into the template, - with a `type` value of either `text` or `checkbox`. If no `type` is provided, - `text` will be the default value applied. The attributes of `{{input}}` - match those of the native HTML tag as closely as possible for these two types. - - ## Use as text field - An `{{input}}` with no `type` or a `type` of `text` will render an HTML text input. - The following HTML attributes can be set via the helper: - - - - - - - - - - - - -
      `readonly``required``autofocus`
      `value``placeholder``disabled`
      `size``tabindex``maxlength`
      `name``min``max`
      `pattern``accept``autocomplete`
      `autosave``formaction``formenctype`
      `formmethod``formnovalidate``formtarget`
      `height``inputmode``multiple`
      `step``width``form`
      `selectionDirection``spellcheck` 
      - - - When set to a quoted string, these values will be directly applied to the HTML - element. When left unquoted, these values will be bound to a property on the - template's current rendering context (most typically a controller instance). - - ## Unbound: - - ```handlebars - {{input value="http://www.facebook.com"}} - ``` - - - ```html - - ``` - - ## Bound: - - ```javascript - App.ApplicationController = Ember.Controller.extend({ - firstName: "Stanley", - entryNotAllowed: true - }); - ``` - - - ```handlebars - {{input type="text" value=firstName disabled=entryNotAllowed size="50"}} - ``` - - - ```html - - ``` - - ## Extension - - Internally, `{{input type="text"}}` creates an instance of `Ember.TextField`, passing - arguments from the helper to `Ember.TextField`'s `create` method. You can extend the - capabilities of text inputs in your applications by reopening this class. For example, - if you are building a Bootstrap project where `data-*` attributes are used, you - can add one to the `TextField`'s `attributeBindings` property: - - - ```javascript - Ember.TextField.reopen({ - attributeBindings: ['data-error'] - }); - ``` - - Keep in mind when writing `Ember.TextField` subclasses that `Ember.TextField` - itself extends `Ember.Component`, meaning that it does NOT inherit - the `controller` of the parent view. - - See more about [Ember components](api/classes/Ember.Component.html) - - - ## Use as checkbox - - An `{{input}}` with a `type` of `checkbox` will render an HTML checkbox input. - The following HTML attributes can be set via the helper: - - * `checked` - * `disabled` - * `tabindex` - * `indeterminate` - * `name` - * `autofocus` - * `form` - - - When set to a quoted string, these values will be directly applied to the HTML - element. When left unquoted, these values will be bound to a property on the - template's current rendering context (most typically a controller instance). - - ## Unbound: - - ```handlebars - {{input type="checkbox" name="isAdmin"}} - ``` - - ```html - - ``` - - ## Bound: - - ```javascript - App.ApplicationController = Ember.Controller.extend({ - isAdmin: true - }); - ``` - - - ```handlebars - {{input type="checkbox" checked=isAdmin }} - ``` - - - ```html - - ``` - - ## Extension - - Internally, `{{input type="checkbox"}}` creates an instance of `Ember.Checkbox`, passing - arguments from the helper to `Ember.Checkbox`'s `create` method. You can extend the - capablilties of checkbox inputs in your applications by reopening this class. For example, - if you wanted to add a css class to all checkboxes in your application: - - - ```javascript - Ember.Checkbox.reopen({ - classNames: ['my-app-checkbox'] - }); - ``` - - - @method input - @for Ember.Handlebars.helpers - @param {Hash} options - */ - function inputHelper(options) { - - var hash = options.hash, - types = options.hashTypes, - inputType = hash.type, - onEvent = hash.on; - - delete hash.type; - delete hash.on; - - if (inputType === 'checkbox') { - return helpers.view.call(this, Checkbox, options); - } else { - if (inputType) { hash.type = inputType; } - hash.onEvent = onEvent || 'enter'; - return helpers.view.call(this, TextField, options); - } - } - - /** - `{{textarea}}` inserts a new instance of ` - ``` - - Bound: - - In the following example, the `writtenWords` property on `App.ApplicationController` - will be updated live as the user types 'Lots of text that IS bound' into - the text area of their browser's window. - - ```javascript - App.ApplicationController = Ember.Controller.extend({ - writtenWords: "Lots of text that IS bound" - }); - ``` - - ```handlebars - {{textarea value=writtenWords}} - ``` - - Would result in the following HTML: - - ```html - - ``` - - If you wanted a one way binding between the text area and a div tag - somewhere else on your screen, you could use `Ember.computed.oneWay`: - - ```javascript - App.ApplicationController = Ember.Controller.extend({ - writtenWords: "Lots of text that IS bound", - outputWrittenWords: Ember.computed.oneWay("writtenWords") - }); - ``` - - ```handlebars - {{textarea value=writtenWords}} - -
      - {{outputWrittenWords}} -
      - ``` - - Would result in the following HTML: - - ```html - - - <-- the following div will be updated in real time as you type --> - -
      - Lots of text that IS bound -
      - ``` - - Finally, this example really shows the power and ease of Ember when two - properties are bound to eachother via `Ember.computed.alias`. Type into - either text area box and they'll both stay in sync. Note that - `Ember.computed.alias` costs more in terms of performance, so only use it when - your really binding in both directions: - - ```javascript - App.ApplicationController = Ember.Controller.extend({ - writtenWords: "Lots of text that IS bound", - twoWayWrittenWords: Ember.computed.alias("writtenWords") - }); - ``` - - ```handlebars - {{textarea value=writtenWords}} - {{textarea value=twoWayWrittenWords}} - ``` - - ```html - - - <-- both updated in real time --> - - - ``` - - ## Extension - - Internally, `{{textarea}}` creates an instance of `Ember.TextArea`, passing - arguments from the helper to `Ember.TextArea`'s `create` method. You can - extend the capabilities of text areas in your application by reopening this - class. For example, if you are building a Bootstrap project where `data-*` - attributes are used, you can globally add support for a `data-*` attribute - on all `{{textarea}}`s' in your app by reopening `Ember.TextArea` or - `Ember.TextSupport` and adding it to the `attributeBindings` concatenated - property: - - ```javascript - Ember.TextArea.reopen({ - attributeBindings: ['data-error'] - }); - ``` - - Keep in mind when writing `Ember.TextArea` subclasses that `Ember.TextArea` - itself extends `Ember.Component`, meaning that it does NOT inherit - the `controller` of the parent view. - - See more about [Ember components](api/classes/Ember.Component.html) - - @method textarea - @for Ember.Handlebars.helpers - @param {Hash} options - */ - function textareaHelper(options) { - - var hash = options.hash, - types = options.hashTypes; - - return helpers.view.call(this, TextArea, options); - } - - __exports__.inputHelper = inputHelper; - __exports__.textareaHelper = textareaHelper; - }); -define("ember-handlebars/controls/checkbox", - ["ember-metal/property_get","ember-metal/property_set","ember-views/views/view","exports"], - function(__dependency1__, __dependency2__, __dependency3__, __exports__) { - "use strict"; - var get = __dependency1__.get; - var set = __dependency2__.set; - var View = __dependency3__.View; - - /** - @module ember - @submodule ember-handlebars - */ - - /** - The internal class used to create text inputs when the `{{input}}` - helper is used with `type` of `checkbox`. - - See [handlebars.helpers.input](/api/classes/Ember.Handlebars.helpers.html#method_input) for usage details. - - ## Direct manipulation of `checked` - - The `checked` attribute of an `Ember.Checkbox` object should always be set - through the Ember object or by interacting with its rendered element - representation via the mouse, keyboard, or touch. Updating the value of the - checkbox via jQuery will result in the checked value of the object and its - element losing synchronization. - - ## Layout and LayoutName properties - - Because HTML `input` elements are self closing `layout` and `layoutName` - properties will not be applied. See [Ember.View](/api/classes/Ember.View.html)'s - layout section for more information. - - @class Checkbox - @namespace Ember - @extends Ember.View - */ - var Checkbox = View.extend({ - instrumentDisplay: '{{input type="checkbox"}}', - - classNames: ['ember-checkbox'], - - tagName: 'input', - - attributeBindings: ['type', 'checked', 'indeterminate', 'disabled', 'tabindex', 'name', - 'autofocus', 'required', 'form'], - - type: "checkbox", - checked: false, - disabled: false, - indeterminate: false, - - init: function() { - this._super(); - this.on("change", this, this._updateElementValue); - }, - - didInsertElement: function() { - this._super(); - get(this, 'element').indeterminate = !!get(this, 'indeterminate'); - }, - - _updateElementValue: function() { - set(this, 'checked', this.$().prop('checked')); - } - }); - - __exports__["default"] = Checkbox; - }); -define("ember-handlebars/controls/select", - ["ember-handlebars-compiler","ember-metal/enumerable_utils","ember-metal/property_get","ember-metal/property_set","ember-views/views/view","ember-views/views/collection_view","ember-metal/utils","ember-metal/is_none","ember-metal/computed","ember-runtime/system/native_array","ember-metal/mixin","ember-metal/properties","exports"], - function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __dependency9__, __dependency10__, __dependency11__, __dependency12__, __exports__) { - "use strict"; - /*jshint eqeqeq:false newcap:false */ - - /** - @module ember - @submodule ember-handlebars - */ - - var EmberHandlebars = __dependency1__["default"]; - var EnumerableUtils = __dependency2__["default"]; - var get = __dependency3__.get; - var set = __dependency4__.set; - var View = __dependency5__.View; - var CollectionView = __dependency6__["default"]; - var isArray = __dependency7__.isArray; - var isNone = __dependency8__["default"]; - var computed = __dependency9__.computed; - var A = __dependency10__.A; - var observer = __dependency11__.observer; - var defineProperty = __dependency12__.defineProperty; - - var indexOf = EnumerableUtils.indexOf, - indexesOf = EnumerableUtils.indexesOf, - forEach = EnumerableUtils.forEach, - replace = EnumerableUtils.replace, - precompileTemplate = EmberHandlebars.compile; - - var SelectOption = View.extend({ - instrumentDisplay: 'Ember.SelectOption', - - tagName: 'option', - attributeBindings: ['value', 'selected'], - - defaultTemplate: function(context, options) { - options = { data: options.data, hash: {} }; - EmberHandlebars.helpers.bind.call(context, "view.label", options); - }, - - init: function() { - this.labelPathDidChange(); - this.valuePathDidChange(); - - this._super(); - }, - - selected: computed(function() { - var content = get(this, 'content'), - selection = get(this, 'parentView.selection'); - if (get(this, 'parentView.multiple')) { - return selection && indexOf(selection, content.valueOf()) > -1; - } else { - // Primitives get passed through bindings as objects... since - // `new Number(4) !== 4`, we use `==` below - return content == selection; - } - }).property('content', 'parentView.selection'), - - labelPathDidChange: observer('parentView.optionLabelPath', function() { - var labelPath = get(this, 'parentView.optionLabelPath'); - - if (!labelPath) { return; } - - defineProperty(this, 'label', computed(function() { - return get(this, labelPath); - }).property(labelPath)); - }), - - valuePathDidChange: observer('parentView.optionValuePath', function() { - var valuePath = get(this, 'parentView.optionValuePath'); - - if (!valuePath) { return; } - - defineProperty(this, 'value', computed(function() { - return get(this, valuePath); - }).property(valuePath)); - }) - }); - - var SelectOptgroup = CollectionView.extend({ - instrumentDisplay: 'Ember.SelectOptgroup', - - tagName: 'optgroup', - attributeBindings: ['label'], - - selectionBinding: 'parentView.selection', - multipleBinding: 'parentView.multiple', - optionLabelPathBinding: 'parentView.optionLabelPath', - optionValuePathBinding: 'parentView.optionValuePath', - - itemViewClassBinding: 'parentView.optionView' - }); - - /** - The `Ember.Select` view class renders a - [select](https://developer.mozilla.org/en/HTML/Element/select) HTML element, - allowing the user to choose from a list of options. - - The text and `value` property of each ` - - - ``` - - The `value` attribute of the selected `"); - return buffer; - } - -function program3(depth0,data) { - - var stack1; - stack1 = helpers.each.call(depth0, "view.groupedContent", {hash:{},hashTypes:{},hashContexts:{},inverse:self.noop,fn:self.program(4, program4, data),contexts:[depth0],types:["ID"],data:data}); - if(stack1 || stack1 === 0) { data.buffer.push(stack1); } - else { data.buffer.push(''); } - } -function program4(depth0,data) { - - - data.buffer.push(escapeExpression(helpers.view.call(depth0, "view.groupView", {hash:{ - 'content': ("content"), - 'label': ("label") - },hashTypes:{'content': "ID",'label': "ID"},hashContexts:{'content': depth0,'label': depth0},contexts:[depth0],types:["ID"],data:data}))); - } - -function program6(depth0,data) { - - var stack1; - stack1 = helpers.each.call(depth0, "view.content", {hash:{},hashTypes:{},hashContexts:{},inverse:self.noop,fn:self.program(7, program7, data),contexts:[depth0],types:["ID"],data:data}); - if(stack1 || stack1 === 0) { data.buffer.push(stack1); } - else { data.buffer.push(''); } - } -function program7(depth0,data) { - - - data.buffer.push(escapeExpression(helpers.view.call(depth0, "view.optionView", {hash:{ - 'content': ("") - },hashTypes:{'content': "ID"},hashContexts:{'content': depth0},contexts:[depth0],types:["ID"],data:data}))); - } - - stack1 = helpers['if'].call(depth0, "view.prompt", {hash:{},hashTypes:{},hashContexts:{},inverse:self.noop,fn:self.program(1, program1, data),contexts:[depth0],types:["ID"],data:data}); - if(stack1 || stack1 === 0) { data.buffer.push(stack1); } - stack1 = helpers['if'].call(depth0, "view.optionGroupPath", {hash:{},hashTypes:{},hashContexts:{},inverse:self.program(6, program6, data),fn:self.program(3, program3, data),contexts:[depth0],types:["ID"],data:data}); - if(stack1 || stack1 === 0) { data.buffer.push(stack1); } - return buffer; - -}), - attributeBindings: ['multiple', 'disabled', 'tabindex', 'name', 'required', 'autofocus', - 'form', 'size'], - - /** - The `multiple` attribute of the select element. Indicates whether multiple - options can be selected. - - @property multiple - @type Boolean - @default false - */ - multiple: false, - - /** - The `disabled` attribute of the select element. Indicates whether - the element is disabled from interactions. - - @property disabled - @type Boolean - @default false - */ - disabled: false, - - /** - The `required` attribute of the select element. Indicates whether - a selected option is required for form validation. - - @property required - @type Boolean - @default false - @since 1.5.0 - */ - required: false, - - /** - The list of options. - - If `optionLabelPath` and `optionValuePath` are not overridden, this should - be a list of strings, which will serve simultaneously as labels and values. - - Otherwise, this should be a list of objects. For instance: - - ```javascript - Ember.Select.create({ - content: A([ - { id: 1, firstName: 'Yehuda' }, - { id: 2, firstName: 'Tom' } - ]), - optionLabelPath: 'content.firstName', - optionValuePath: 'content.id' - }); - ``` - - @property content - @type Array - @default null - */ - content: null, - - /** - When `multiple` is `false`, the element of `content` that is currently - selected, if any. - - When `multiple` is `true`, an array of such elements. - - @property selection - @type Object or Array - @default null - */ - selection: null, - - /** - In single selection mode (when `multiple` is `false`), value can be used to - get the current selection's value or set the selection by it's value. - - It is not currently supported in multiple selection mode. - - @property value - @type String - @default null - */ - value: computed(function(key, value) { - if (arguments.length === 2) { return value; } - var valuePath = get(this, 'optionValuePath').replace(/^content\.?/, ''); - return valuePath ? get(this, 'selection.' + valuePath) : get(this, 'selection'); - }).property('selection'), - - /** - If given, a top-most dummy option will be rendered to serve as a user - prompt. - - @property prompt - @type String - @default null - */ - prompt: null, - - /** - The path of the option labels. See [content](/api/classes/Ember.Select.html#property_content). - - @property optionLabelPath - @type String - @default 'content' - */ - optionLabelPath: 'content', - - /** - The path of the option values. See [content](/api/classes/Ember.Select.html#property_content). - - @property optionValuePath - @type String - @default 'content' - */ - optionValuePath: 'content', - - /** - The path of the option group. - When this property is used, `content` should be sorted by `optionGroupPath`. - - @property optionGroupPath - @type String - @default null - */ - optionGroupPath: null, - - /** - The view class for optgroup. - - @property groupView - @type Ember.View - @default Ember.SelectOptgroup - */ - groupView: SelectOptgroup, - - groupedContent: computed(function() { - var groupPath = get(this, 'optionGroupPath'); - var groupedContent = A(); - var content = get(this, 'content') || []; - - forEach(content, function(item) { - var label = get(item, groupPath); - - if (get(groupedContent, 'lastObject.label') !== label) { - groupedContent.pushObject({ - label: label, - content: A() - }); - } - - get(groupedContent, 'lastObject.content').push(item); - }); - - return groupedContent; - }).property('optionGroupPath', 'content.@each'), - - /** - The view class for option. - - @property optionView - @type Ember.View - @default Ember.SelectOption - */ - optionView: SelectOption, - - _change: function() { - if (get(this, 'multiple')) { - this._changeMultiple(); - } else { - this._changeSingle(); - } - }, - - selectionDidChange: observer('selection.@each', function() { - var selection = get(this, 'selection'); - if (get(this, 'multiple')) { - if (!isArray(selection)) { - set(this, 'selection', A([selection])); - return; - } - this._selectionDidChangeMultiple(); - } else { - this._selectionDidChangeSingle(); - } - }), - - valueDidChange: observer('value', function() { - var content = get(this, 'content'), - value = get(this, 'value'), - valuePath = get(this, 'optionValuePath').replace(/^content\.?/, ''), - selectedValue = (valuePath ? get(this, 'selection.' + valuePath) : get(this, 'selection')), - selection; - - if (value !== selectedValue) { - selection = content ? content.find(function(obj) { - return value === (valuePath ? get(obj, valuePath) : obj); - }) : null; - - this.set('selection', selection); - } - }), - - - _triggerChange: function() { - var selection = get(this, 'selection'); - var value = get(this, 'value'); - - if (!isNone(selection)) { this.selectionDidChange(); } - if (!isNone(value)) { this.valueDidChange(); } - - this._change(); - }, - - _changeSingle: function() { - var selectedIndex = this.$()[0].selectedIndex, - content = get(this, 'content'), - prompt = get(this, 'prompt'); - - if (!content || !get(content, 'length')) { return; } - if (prompt && selectedIndex === 0) { set(this, 'selection', null); return; } - - if (prompt) { selectedIndex -= 1; } - set(this, 'selection', content.objectAt(selectedIndex)); - }, - - - _changeMultiple: function() { - var options = this.$('option:selected'), - prompt = get(this, 'prompt'), - offset = prompt ? 1 : 0, - content = get(this, 'content'), - selection = get(this, 'selection'); - - if (!content) { return; } - if (options) { - var selectedIndexes = options.map(function() { - return this.index - offset; - }).toArray(); - var newSelection = content.objectsAt(selectedIndexes); - - if (isArray(selection)) { - replace(selection, 0, get(selection, 'length'), newSelection); - } else { - set(this, 'selection', newSelection); - } - } - }, - - _selectionDidChangeSingle: function() { - var el = this.get('element'); - if (!el) { return; } - - var content = get(this, 'content'), - selection = get(this, 'selection'), - selectionIndex = content ? indexOf(content, selection) : -1, - prompt = get(this, 'prompt'); - - if (prompt) { selectionIndex += 1; } - if (el) { el.selectedIndex = selectionIndex; } - }, - - _selectionDidChangeMultiple: function() { - var content = get(this, 'content'), - selection = get(this, 'selection'), - selectedIndexes = content ? indexesOf(content, selection) : [-1], - prompt = get(this, 'prompt'), - offset = prompt ? 1 : 0, - options = this.$('option'), - adjusted; - - if (options) { - options.each(function() { - adjusted = this.index > -1 ? this.index - offset : -1; - this.selected = indexOf(selectedIndexes, adjusted) > -1; - }); - } - }, - - init: function() { - this._super(); - this.on("didInsertElement", this, this._triggerChange); - this.on("change", this, this._change); - } - }); - - __exports__["default"] = Select - __exports__.Select = Select; - __exports__.SelectOption = SelectOption; - __exports__.SelectOptgroup = SelectOptgroup; - }); -define("ember-handlebars/controls/text_area", - ["ember-metal/property_get","ember-views/views/component","ember-handlebars/controls/text_support","ember-metal/mixin","exports"], - function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __exports__) { - "use strict"; - - /** - @module ember - @submodule ember-handlebars - */ - var get = __dependency1__.get; - var Component = __dependency2__["default"]; - var TextSupport = __dependency3__["default"]; - var observer = __dependency4__.observer; - - /** - The internal class used to create textarea element when the `{{textarea}}` - helper is used. - - See [handlebars.helpers.textarea](/api/classes/Ember.Handlebars.helpers.html#method_textarea) for usage details. - - ## Layout and LayoutName properties - - Because HTML `textarea` elements do not contain inner HTML the `layout` and - `layoutName` properties will not be applied. See [Ember.View](/api/classes/Ember.View.html)'s - layout section for more information. - - @class TextArea - @namespace Ember - @extends Ember.Component - @uses Ember.TextSupport - */ - var TextArea = Component.extend(TextSupport, { - instrumentDisplay: '{{textarea}}', - - classNames: ['ember-text-area'], - - tagName: "textarea", - attributeBindings: ['rows', 'cols', 'name', 'selectionEnd', 'selectionStart', 'wrap'], - rows: null, - cols: null, - - _updateElementValue: observer('value', function() { - // We do this check so cursor position doesn't get affected in IE - var value = get(this, 'value'), - $el = this.$(); - if ($el && value !== $el.val()) { - $el.val(value); - } - }), - - init: function() { - this._super(); - this.on("didInsertElement", this, this._updateElementValue); - } - - }); - - __exports__["default"] = TextArea; - }); -define("ember-handlebars/controls/text_field", - ["ember-metal/property_get","ember-metal/property_set","ember-views/views/component","ember-handlebars/controls/text_support","exports"], - function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __exports__) { - "use strict"; - /** - @module ember - @submodule ember-handlebars - */ - - var get = __dependency1__.get; - var set = __dependency2__.set; - var Component = __dependency3__["default"]; - var TextSupport = __dependency4__["default"]; - - /** - - The internal class used to create text inputs when the `{{input}}` - helper is used with `type` of `text`. - - See [Handlebars.helpers.input](/api/classes/Ember.Handlebars.helpers.html#method_input) for usage details. - - ## Layout and LayoutName properties - - Because HTML `input` elements are self closing `layout` and `layoutName` - properties will not be applied. See [Ember.View](/api/classes/Ember.View.html)'s - layout section for more information. - - @class TextField - @namespace Ember - @extends Ember.Component - @uses Ember.TextSupport - */ - var TextField = Component.extend(TextSupport, { - instrumentDisplay: '{{input type="text"}}', - - classNames: ['ember-text-field'], - tagName: "input", - attributeBindings: ['type', 'value', 'size', 'pattern', 'name', 'min', 'max', - 'accept', 'autocomplete', 'autosave', 'formaction', - 'formenctype', 'formmethod', 'formnovalidate', 'formtarget', - 'height', 'inputmode', 'list', 'multiple', 'pattern', 'step', - 'width'], - - /** - The `value` attribute of the input element. As the user inputs text, this - property is updated live. - - @property value - @type String - @default "" - */ - value: "", - - /** - The `type` attribute of the input element. - - @property type - @type String - @default "text" - */ - type: "text", - - /** - The `size` of the text field in characters. - - @property size - @type String - @default null - */ - size: null, - - /** - The `pattern` attribute of input element. - - @property pattern - @type String - @default null - */ - pattern: null, - - /** - The `min` attribute of input element used with `type="number"` or `type="range"`. - - @property min - @type String - @default null - @since 1.4.0 - */ - min: null, - - /** - The `max` attribute of input element used with `type="number"` or `type="range"`. - - @property max - @type String - @default null - @since 1.4.0 - */ - max: null - }); - - __exports__["default"] = TextField; - }); -define("ember-handlebars/controls/text_support", - ["ember-metal/property_get","ember-metal/property_set","ember-metal/mixin","ember-runtime/mixins/target_action_support","exports"], - function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __exports__) { - "use strict"; - /** - @module ember - @submodule ember-handlebars - */ - - var get = __dependency1__.get; - var set = __dependency2__.set; - var Mixin = __dependency3__.Mixin; - var TargetActionSupport = __dependency4__["default"]; - - /** - Shared mixin used by `Ember.TextField` and `Ember.TextArea`. - - @class TextSupport - @namespace Ember - @uses Ember.TargetActionSupport - @extends Ember.Mixin - @private - */ - var TextSupport = Mixin.create(TargetActionSupport, { - value: "", - - attributeBindings: ['placeholder', 'disabled', 'maxlength', 'tabindex', 'readonly', - 'autofocus', 'form', 'selectionDirection', 'spellcheck', 'required', - 'title', 'autocapitalize', 'autocorrect'], - placeholder: null, - disabled: false, - maxlength: null, - - init: function() { - this._super(); - this.on("focusOut", this, this._elementValueDidChange); - this.on("change", this, this._elementValueDidChange); - this.on("paste", this, this._elementValueDidChange); - this.on("cut", this, this._elementValueDidChange); - this.on("input", this, this._elementValueDidChange); - this.on("keyUp", this, this.interpretKeyEvents); - }, - - /** - The action to be sent when the user presses the return key. - - This is similar to the `{{action}}` helper, but is fired when - the user presses the return key when editing a text field, and sends - the value of the field as the context. - - @property action - @type String - @default null - */ - action: null, - - /** - The event that should send the action. - - Options are: - - * `enter`: the user pressed enter - * `keyPress`: the user pressed a key - - @property onEvent - @type String - @default enter - */ - onEvent: 'enter', - - /** - Whether they `keyUp` event that triggers an `action` to be sent continues - propagating to other views. - - By default, when the user presses the return key on their keyboard and - the text field has an `action` set, the action will be sent to the view's - controller and the key event will stop propagating. - - If you would like parent views to receive the `keyUp` event even after an - action has been dispatched, set `bubbles` to true. - - @property bubbles - @type Boolean - @default false - */ - bubbles: false, - - interpretKeyEvents: function(event) { - var map = TextSupport.KEY_EVENTS; - var method = map[event.keyCode]; - - this._elementValueDidChange(); - if (method) { return this[method](event); } - }, - - _elementValueDidChange: function() { - set(this, 'value', this.$().val()); - }, - - /** - The action to be sent when the user inserts a new line. - - Called by the `Ember.TextSupport` mixin on keyUp if keycode matches 13. - Uses sendAction to send the `enter` action to the controller. - - @method insertNewline - @param {Event} event - */ - insertNewline: function(event) { - sendAction('enter', this, event); - sendAction('insert-newline', this, event); - }, - - /** - Called when the user hits escape. - - Called by the `Ember.TextSupport` mixin on keyUp if keycode matches 27. - Uses sendAction to send the `escape-press` action to the controller. - - @method cancel - @param {Event} event - */ - cancel: function(event) { - sendAction('escape-press', this, event); - }, - - /** - Called when the text area is focused. - - @method focusIn - @param {Event} event - */ - focusIn: function(event) { - sendAction('focus-in', this, event); - }, - - /** - Called when the text area is blurred. - - @method focusOut - @param {Event} event - */ - focusOut: function(event) { - sendAction('focus-out', this, event); - }, - - /** - The action to be sent when the user presses a key. Enabled by setting - the `onEvent` property to `keyPress`. - - Uses sendAction to send the `keyPress` action to the controller. - - @method keyPress - @param {Event} event - */ - keyPress: function(event) { - sendAction('key-press', this, event); - } - - }); - - TextSupport.KEY_EVENTS = { - 13: 'insertNewline', - 27: 'cancel' - }; - - // In principle, this shouldn't be necessary, but the legacy - // sendAction semantics for TextField are different from - // the component semantics so this method normalizes them. - function sendAction(eventName, view, event) { - var action = get(view, eventName), - on = get(view, 'onEvent'), - value = get(view, 'value'); - - // back-compat support for keyPress as an event name even though - // it's also a method name that consumes the event (and therefore - // incompatible with sendAction semantics). - if (on === eventName || (on === 'keyPress' && eventName === 'key-press')) { - view.sendAction('action', value); - } - - view.sendAction(eventName, value); - - if (action || on === eventName) { - if(!get(view, 'bubbles')) { - event.stopPropagation(); - } - } - } - - __exports__["default"] = TextSupport; - }); -define("ember-handlebars/ext", - ["ember-metal/core","ember-runtime/system/string","ember-handlebars-compiler","ember-metal/property_get","ember-metal/binding","ember-metal/error","ember-metal/mixin","ember-metal/is_empty","exports"], - function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __exports__) { - "use strict"; - var Ember = __dependency1__["default"]; - // Ember.FEATURES, Ember.assert, Ember.Handlebars, Ember.lookup - // var emberAssert = Ember.assert; - - var fmt = __dependency2__.fmt; - - var EmberHandlebars = __dependency3__["default"]; - var helpers = EmberHandlebars.helpers; - - var get = __dependency4__.get; - var isGlobalPath = __dependency5__.isGlobalPath; - var EmberError = __dependency6__["default"]; - var IS_BINDING = __dependency7__.IS_BINDING; - - // late bound via requireModule because of circular dependencies. - var resolveHelper, - SimpleHandlebarsView; - - var isEmpty = __dependency8__["default"]; - - var slice = [].slice, originalTemplate = EmberHandlebars.template; - - /** - If a path starts with a reserved keyword, returns the root - that should be used. - - @private - @method normalizePath - @for Ember - @param root {Object} - @param path {String} - @param data {Hash} - */ - function normalizePath(root, path, data) { - var keywords = (data && data.keywords) || {}, - keyword, isKeyword; - - // Get the first segment of the path. For example, if the - // path is "foo.bar.baz", returns "foo". - keyword = path.split('.', 1)[0]; - - // Test to see if the first path is a keyword that has been - // passed along in the view's data hash. If so, we will treat - // that object as the new root. - if (keywords.hasOwnProperty(keyword)) { - // Look up the value in the template's data hash. - root = keywords[keyword]; - isKeyword = true; - - // Handle cases where the entire path is the reserved - // word. In that case, return the object itself. - if (path === keyword) { - path = ''; - } else { - // Strip the keyword from the path and look up - // the remainder from the newly found root. - path = path.substr(keyword.length+1); - } - } - - return { root: root, path: path, isKeyword: isKeyword }; - }; - - - /** - Lookup both on root and on window. If the path starts with - a keyword, the corresponding object will be looked up in the - template's data hash and used to resolve the path. - - @method get - @for Ember.Handlebars - @param {Object} root The object to look up the property on - @param {String} path The path to be lookedup - @param {Object} options The template's option hash - */ - function handlebarsGet(root, path, options) { - var data = options && options.data, - normalizedPath = normalizePath(root, path, data), - value; - - - root = normalizedPath.root; - path = normalizedPath.path; - - value = get(root, path); - - if (value === undefined && root !== Ember.lookup && isGlobalPath(path)) { - value = get(Ember.lookup, path); - } - - - return value; - } - - /** - This method uses `Ember.Handlebars.get` to lookup a value, then ensures - that the value is escaped properly. - - If `unescaped` is a truthy value then the escaping will not be performed. - - @method getEscaped - @for Ember.Handlebars - @param {Object} root The object to look up the property on - @param {String} path The path to be lookedup - @param {Object} options The template's option hash - @since 1.4.0 - */ - function getEscaped(root, path, options) { - var result = handlebarsGet(root, path, options); - - if (result === null || result === undefined) { - result = ""; - } else if (!(result instanceof Handlebars.SafeString)) { - result = String(result); - } - if (!options.hash.unescaped){ - result = Handlebars.Utils.escapeExpression(result); - } - - return result; - }; - - function resolveParams(context, params, options) { - var resolvedParams = [], types = options.types, param, type; - - for (var i=0, l=params.length; i{{user.name}} - -
      -
      {{user.role.label}}
      - {{user.role.id}} - -

      {{user.role.description}}

      -
      - ``` - - `{{with}}` can be our best friend in these cases, - instead of writing `user.role.*` over and over, we use `{{#with user.role}}`. - Now the context within the `{{#with}} .. {{/with}}` block is `user.role` so you can do the following: - - ```handlebars -
      {{user.name}}
      - -
      - {{#with user.role}} -
      {{label}}
      - {{id}} - -

      {{description}}

      - {{/with}} -
      - ``` - - ### `as` operator - - This operator aliases the scope to a new name. It's helpful for semantic clarity and to retain - default scope or to reference from another `{{with}}` block. - - ```handlebars - // posts might not be - {{#with user.posts as blogPosts}} -
      - There are {{blogPosts.length}} blog posts written by {{user.name}}. -
      - - {{#each post in blogPosts}} -
    • {{post.title}}
    • - {{/each}} - {{/with}} - ``` - - Without the `as` operator, it would be impossible to reference `user.name` in the example above. - - NOTE: The alias should not reuse a name from the bound property path. - For example: `{{#with foo.bar as foo}}` is not supported because it attempts to alias using - the first part of the property path, `foo`. Instead, use `{{#with foo.bar as baz}}`. - - ### `controller` option - - Adding `controller='something'` instructs the `{{with}}` helper to create and use an instance of - the specified controller with the new context as its content. - - This is very similar to using an `itemController` option with the `{{each}}` helper. - - ```handlebars - {{#with users.posts controller='userBlogPosts'}} - {{!- The current context is wrapped in our controller instance }} - {{/with}} - ``` - - In the above example, the template provided to the `{{with}}` block is now wrapped in the - `userBlogPost` controller, which provides a very elegant way to decorate the context with custom - functions/properties. - - @method with - @for Ember.Handlebars.helpers - @param {Function} context - @param {Hash} options - @return {String} HTML string - */ - function withHelper(context, options) { - var bindContext, preserveContext, controller, helperName = 'with'; - - if (arguments.length === 4) { - var keywordName, path, rootPath, normalized, contextPath; - - options = arguments[3]; - keywordName = arguments[2]; - path = arguments[0]; - - if (path) { - helperName += ' ' + path + ' as ' + keywordName; - } - - - var localizedOptions = o_create(options); - localizedOptions.data = o_create(options.data); - localizedOptions.data.keywords = o_create(options.data.keywords || {}); - - if (isGlobalPath(path)) { - contextPath = path; - } else { - normalized = normalizePath(this, path, options.data); - path = normalized.path; - rootPath = normalized.root; - - // This is a workaround for the fact that you cannot bind separate objects - // together. When we implement that functionality, we should use it here. - var contextKey = jQuery.expando + guidFor(rootPath); - localizedOptions.data.keywords[contextKey] = rootPath; - // if the path is '' ("this"), just bind directly to the current context - contextPath = path ? contextKey + '.' + path : contextKey; - } - - localizedOptions.hash.keywordName = keywordName; - localizedOptions.hash.keywordPath = contextPath; - - bindContext = this; - context = path; - options = localizedOptions; - preserveContext = true; - } else { - - helperName += ' ' + context; - bindContext = options.contexts[0]; - preserveContext = false; - } - - options.helperName = helperName; - options.isWithHelper = true; - - return bind.call(bindContext, context, options, preserveContext, exists); - } - /** - See [boundIf](/api/classes/Ember.Handlebars.helpers.html#method_boundIf) - and [unboundIf](/api/classes/Ember.Handlebars.helpers.html#method_unboundIf) - - @method if - @for Ember.Handlebars.helpers - @param {Function} context - @param {Hash} options - @return {String} HTML string - */ - function ifHelper(context, options) { - - options.helperName = options.helperName || ('if ' + context); - - if (options.data.isUnbound) { - return helpers.unboundIf.call(options.contexts[0], context, options); - } else { - return helpers.boundIf.call(options.contexts[0], context, options); - } - } - - /** - @method unless - @for Ember.Handlebars.helpers - @param {Function} context - @param {Hash} options - @return {String} HTML string - */ - function unlessHelper(context, options) { - - var fn = options.fn, inverse = options.inverse, helperName = 'unless'; - - if (context) { - helperName += ' ' + context; - } - - options.fn = inverse; - options.inverse = fn; - - options.helperName = options.helperName || helperName; - - if (options.data.isUnbound) { - return helpers.unboundIf.call(options.contexts[0], context, options); - } else { - return helpers.boundIf.call(options.contexts[0], context, options); - } - } - - /** - `bind-attr` allows you to create a binding between DOM element attributes and - Ember objects. For example: - - ```handlebars - imageTitle - ``` - - The above handlebars template will fill the ``'s `src` attribute will - the value of the property referenced with `"imageUrl"` and its `alt` - attribute with the value of the property referenced with `"imageTitle"`. - - If the rendering context of this template is the following object: - - ```javascript - { - imageUrl: 'http://lolcats.info/haz-a-funny', - imageTitle: 'A humorous image of a cat' - } - ``` - - The resulting HTML output will be: - - ```html - A humorous image of a cat - ``` - - `bind-attr` cannot redeclare existing DOM element attributes. The use of `src` - in the following `bind-attr` example will be ignored and the hard coded value - of `src="/failwhale.gif"` will take precedence: - - ```handlebars - imageTitle - ``` - - ### `bind-attr` and the `class` attribute - - `bind-attr` supports a special syntax for handling a number of cases unique - to the `class` DOM element attribute. The `class` attribute combines - multiple discrete values into a single attribute as a space-delimited - list of strings. Each string can be: - - * a string return value of an object's property. - * a boolean return value of an object's property - * a hard-coded value - - A string return value works identically to other uses of `bind-attr`. The - return value of the property will become the value of the attribute. For - example, the following view and template: - - ```javascript - AView = View.extend({ - someProperty: function() { - return "aValue"; - }.property() - }) - ``` - - ```handlebars - - ``` - - A boolean return value will insert a specified class name if the property - returns `true` and remove the class name if the property returns `false`. - - A class name is provided via the syntax - `somePropertyName:class-name-if-true`. - - ```javascript - AView = View.extend({ - someBool: true - }) - ``` - - ```handlebars - - ``` - - Result in the following rendered output: - - ```html - - ``` - - An additional section of the binding can be provided if you want to - replace the existing class instead of removing it when the boolean - value changes: - - ```handlebars - - ``` - - A hard-coded value can be used by prepending `:` to the desired - class name: `:class-name-to-always-apply`. - - ```handlebars - - ``` - - Results in the following rendered output: - - ```html - - ``` - - All three strategies - string return value, boolean return value, and - hard-coded value – can be combined in a single declaration: - - ```handlebars - - ``` - - @method bind-attr - @for Ember.Handlebars.helpers - @param {Hash} options - @return {String} HTML string - */ - function bindAttrHelper(options) { - var attrs = options.hash; - - - var view = options.data.view; - var ret = []; - - // we relied on the behavior of calling without - // context to mean this === window, but when running - // "use strict", it's possible for this to === undefined; - var ctx = this || window; - - // Generate a unique id for this element. This will be added as a - // data attribute to the element so it can be looked up when - // the bound property changes. - var dataId = ++Ember.uuid; - - // Handle classes differently, as we can bind multiple classes - var classBindings = attrs['class']; - if (classBindings != null) { - var classResults = bindClasses(ctx, classBindings, view, dataId, options); - - ret.push('class="' + Handlebars.Utils.escapeExpression(classResults.join(' ')) + '"'); - delete attrs['class']; - } - - var attrKeys = keys(attrs); - - // For each attribute passed, create an observer and emit the - // current value of the property as an attribute. - forEach.call(attrKeys, function(attr) { - var path = attrs[attr], - normalized; - - - normalized = normalizePath(ctx, path, options.data); - - var value = (path === 'this') ? normalized.root : handlebarsGet(ctx, path, options), - type = typeOf(value); - - - var observer, invoker; - - observer = function observer() { - var result = handlebarsGet(ctx, path, options); - - - var elem = view.$("[data-bindattr-" + dataId + "='" + dataId + "']"); - - // If we aren't able to find the element, it means the element - // to which we were bound has been removed from the view. - // In that case, we can assume the template has been re-rendered - // and we need to clean up the observer. - if (!elem || elem.length === 0) { - removeObserver(normalized.root, normalized.path, invoker); - return; - } - - View.applyAttributeBindings(elem, attr, result); - }; - - // Add an observer to the view for when the property changes. - // When the observer fires, find the element using the - // unique data id and update the attribute to the new value. - // Note: don't add observer when path is 'this' or path - // is whole keyword e.g. {{#each x in list}} ... {{bind-attr attr="x"}} - if (path !== 'this' && !(normalized.isKeyword && normalized.path === '' )) { - view.registerObserver(normalized.root, normalized.path, observer); - } - - // if this changes, also change the logic in ember-views/lib/views/view.js - if ((type === 'string' || (type === 'number' && !isNaN(value)))) { - ret.push(attr + '="' + Handlebars.Utils.escapeExpression(value) + '"'); - } else if (value && type === 'boolean') { - // The developer controls the attr name, so it should always be safe - ret.push(attr + '="' + attr + '"'); - } - }, this); - - // Add the unique identifier - // NOTE: We use all lower-case since Firefox has problems with mixed case in SVG - ret.push('data-bindattr-' + dataId + '="' + dataId + '"'); - return new SafeString(ret.join(' ')); - } - - /** - See `bind-attr` - - @method bindAttr - @for Ember.Handlebars.helpers - @deprecated - @param {Function} context - @param {Hash} options - @return {String} HTML string - */ - function bindAttrHelperDeprecated() { - return helpers['bind-attr'].apply(this, arguments); - } - - /** - Helper that, given a space-separated string of property paths and a context, - returns an array of class names. Calling this method also has the side - effect of setting up observers at those property paths, such that if they - change, the correct class name will be reapplied to the DOM element. - - For example, if you pass the string "fooBar", it will first look up the - "fooBar" value of the context. If that value is true, it will add the - "foo-bar" class to the current element (i.e., the dasherized form of - "fooBar"). If the value is a string, it will add that string as the class. - Otherwise, it will not add any new class name. - - @private - @method bindClasses - @for Ember.Handlebars - @param {Ember.Object} context The context from which to lookup properties - @param {String} classBindings A string, space-separated, of class bindings - to use - @param {View} view The view in which observers should look for the - element to update - @param {Srting} bindAttrId Optional bindAttr id used to lookup elements - @return {Array} An array of class names to add - */ - function bindClasses(context, classBindings, view, bindAttrId, options) { - var ret = [], newClass, value, elem; - - // Helper method to retrieve the property from the context and - // determine which class string to return, based on whether it is - // a Boolean or not. - var classStringForPath = function(root, parsedPath, options) { - var val, - path = parsedPath.path; - - if (path === 'this') { - val = root; - } else if (path === '') { - val = true; - } else { - val = handlebarsGet(root, path, options); - } - - return View._classStringForValue(path, val, parsedPath.className, parsedPath.falsyClassName); - }; - - // For each property passed, loop through and setup - // an observer. - forEach.call(classBindings.split(' '), function(binding) { - - // Variable in which the old class value is saved. The observer function - // closes over this variable, so it knows which string to remove when - // the property changes. - var oldClass; - - var observer, invoker; - - var parsedPath = View._parsePropertyPath(binding), - path = parsedPath.path, - pathRoot = context, - normalized; - - if (path !== '' && path !== 'this') { - normalized = normalizePath(context, path, options.data); - - pathRoot = normalized.root; - path = normalized.path; - } - - // Set up an observer on the context. If the property changes, toggle the - // class name. - observer = function() { - // Get the current value of the property - newClass = classStringForPath(context, parsedPath, options); - elem = bindAttrId ? view.$("[data-bindattr-" + bindAttrId + "='" + bindAttrId + "']") : view.$(); - - // If we can't find the element anymore, a parent template has been - // re-rendered and we've been nuked. Remove the observer. - if (!elem || elem.length === 0) { - removeObserver(pathRoot, path, invoker); - } else { - // If we had previously added a class to the element, remove it. - if (oldClass) { - elem.removeClass(oldClass); - } - - // If necessary, add a new class. Make sure we keep track of it so - // it can be removed in the future. - if (newClass) { - elem.addClass(newClass); - oldClass = newClass; - } else { - oldClass = null; - } - } - }; - - if (path !== '' && path !== 'this') { - view.registerObserver(pathRoot, path, observer); - } - - // We've already setup the observer; now we just need to figure out the - // correct behavior right now on the first pass through. - value = classStringForPath(context, parsedPath, options); - - if (value) { - ret.push(value); - - // Make sure we save the current value so that it can be removed if the - // observer fires. - oldClass = value; - } - }); - - return ret; - }; - - __exports__.bind = bind; - __exports__._triageMustacheHelper = _triageMustacheHelper; - __exports__.resolveHelper = resolveHelper; - __exports__.bindHelper = bindHelper; - __exports__.boundIfHelper = boundIfHelper; - __exports__.unboundIfHelper = unboundIfHelper; - __exports__.withHelper = withHelper; - __exports__.ifHelper = ifHelper; - __exports__.unlessHelper = unlessHelper; - __exports__.bindAttrHelper = bindAttrHelper; - __exports__.bindAttrHelperDeprecated = bindAttrHelperDeprecated; - __exports__.bindClasses = bindClasses; - }); -define("ember-handlebars/helpers/collection", - ["ember-metal/core","ember-metal/utils","ember-handlebars-compiler","ember-runtime/system/string","ember-metal/property_get","ember-handlebars/ext","ember-handlebars/helpers/view","ember-metal/computed","ember-views/views/collection_view","exports"], - function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __dependency9__, __exports__) { - "use strict"; - /** - @module ember - @submodule ember-handlebars - */ - - var Ember = __dependency1__["default"]; - // Ember.assert, Ember.deprecate - var inspect = __dependency2__.inspect; - - // var emberAssert = Ember.assert; - // emberDeprecate = Ember.deprecate; - - var EmberHandlebars = __dependency3__["default"]; - var helpers = EmberHandlebars.helpers; - - var fmt = __dependency4__.fmt; - var get = __dependency5__.get; - var handlebarsGet = __dependency6__.handlebarsGet; - var ViewHelper = __dependency7__.ViewHelper; - var computed = __dependency8__.computed; - var CollectionView = __dependency9__["default"]; - - var alias = computed.alias; - /** - `{{collection}}` is a `Ember.Handlebars` helper for adding instances of - `Ember.CollectionView` to a template. See [Ember.CollectionView](/api/classes/Ember.CollectionView.html) - for additional information on how a `CollectionView` functions. - - `{{collection}}`'s primary use is as a block helper with a `contentBinding` - option pointing towards an `Ember.Array`-compatible object. An `Ember.View` - instance will be created for each item in its `content` property. Each view - will have its own `content` property set to the appropriate item in the - collection. - - The provided block will be applied as the template for each item's view. - - Given an empty `` the following template: - - ```handlebars - {{#collection contentBinding="App.items"}} - Hi {{view.content.name}} - {{/collection}} - ``` - - And the following application code - - ```javascript - App = Ember.Application.create() - App.items = [ - Ember.Object.create({name: 'Dave'}), - Ember.Object.create({name: 'Mary'}), - Ember.Object.create({name: 'Sara'}) - ] - ``` - - Will result in the HTML structure below - - ```html -
      -
      Hi Dave
      -
      Hi Mary
      -
      Hi Sara
      -
      - ``` - - ### Blockless use in a collection - - If you provide an `itemViewClass` option that has its own `template` you can - omit the block. - - The following template: - - ```handlebars - {{collection contentBinding="App.items" itemViewClass="App.AnItemView"}} - ``` - - And application code - - ```javascript - App = Ember.Application.create(); - App.items = [ - Ember.Object.create({name: 'Dave'}), - Ember.Object.create({name: 'Mary'}), - Ember.Object.create({name: 'Sara'}) - ]; - - App.AnItemView = Ember.View.extend({ - template: Ember.Handlebars.compile("Greetings {{view.content.name}}") - }); - ``` - - Will result in the HTML structure below - - ```html -
      -
      Greetings Dave
      -
      Greetings Mary
      -
      Greetings Sara
      -
      - ``` - - ### Specifying a CollectionView subclass - - By default the `{{collection}}` helper will create an instance of - `Ember.CollectionView`. You can supply a `Ember.CollectionView` subclass to - the helper by passing it as the first argument: - - ```handlebars - {{#collection App.MyCustomCollectionClass contentBinding="App.items"}} - Hi {{view.content.name}} - {{/collection}} - ``` - - ### Forwarded `item.*`-named Options - - As with the `{{view}}`, helper options passed to the `{{collection}}` will be - set on the resulting `Ember.CollectionView` as properties. Additionally, - options prefixed with `item` will be applied to the views rendered for each - item (note the camelcasing): - - ```handlebars - {{#collection contentBinding="App.items" - itemTagName="p" - itemClassNames="greeting"}} - Howdy {{view.content.name}} - {{/collection}} - ``` - - Will result in the following HTML structure: - - ```html -
      -

      Howdy Dave

      -

      Howdy Mary

      -

      Howdy Sara

      -
      - ``` - - @method collection - @for Ember.Handlebars.helpers - @param {String} path - @param {Hash} options - @return {String} HTML string - @deprecated Use `{{each}}` helper instead. - */ - function collectionHelper(path, options) { - - // If no path is provided, treat path param as options. - if (path && path.data && path.data.isRenderData) { - options = path; - path = undefined; - } else { - } - - var fn = options.fn; - var data = options.data; - var inverse = options.inverse; - var view = options.data.view; - - - var controller, container; - // If passed a path string, convert that into an object. - // Otherwise, just default to the standard class. - var collectionClass; - if (path) { - controller = data.keywords.controller; - container = controller && controller.container; - collectionClass = handlebarsGet(this, path, options) || container.lookupFactory('view:' + path); - } - else { - collectionClass = CollectionView; - } - - var hash = options.hash, itemHash = {}, match; - - // Extract item view class if provided else default to the standard class - var collectionPrototype = collectionClass.proto(), itemViewClass; - - if (hash.itemView) { - controller = data.keywords.controller; - container = controller.container; - itemViewClass = container.lookupFactory('view:' + hash.itemView); - } else if (hash.itemViewClass) { - itemViewClass = handlebarsGet(collectionPrototype, hash.itemViewClass, options); - } else { - itemViewClass = collectionPrototype.itemViewClass; - } - - - delete hash.itemViewClass; - delete hash.itemView; - - // Go through options passed to the {{collection}} helper and extract options - // that configure item views instead of the collection itself. - for (var prop in hash) { - if (hash.hasOwnProperty(prop)) { - match = prop.match(/^item(.)(.*)$/); - - if (match && prop !== 'itemController') { - // Convert itemShouldFoo -> shouldFoo - itemHash[match[1].toLowerCase() + match[2]] = hash[prop]; - // Delete from hash as this will end up getting passed to the - // {{view}} helper method. - delete hash[prop]; - } - } - } - - if (fn) { - itemHash.template = fn; - delete options.fn; - } - - var emptyViewClass; - if (inverse && inverse !== EmberHandlebars.VM.noop) { - emptyViewClass = get(collectionPrototype, 'emptyViewClass'); - emptyViewClass = emptyViewClass.extend({ - template: inverse, - tagName: itemHash.tagName - }); - } else if (hash.emptyViewClass) { - emptyViewClass = handlebarsGet(this, hash.emptyViewClass, options); - } - if (emptyViewClass) { hash.emptyView = emptyViewClass; } - - if (hash.keyword) { - itemHash._context = this; - } else { - itemHash._context = alias('content'); - } - - var viewOptions = ViewHelper.propertiesFromHTMLOptions({ data: data, hash: itemHash }, this); - hash.itemViewClass = itemViewClass.extend(viewOptions); - - options.helperName = options.helperName || 'collection'; - - return helpers.view.call(this, collectionClass, options); - } - - __exports__["default"] = collectionHelper; - }); -define("ember-handlebars/helpers/debug", - ["ember-metal/core","ember-metal/utils","ember-metal/logger","ember-metal/property_get","ember-handlebars/ext","exports"], - function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __exports__) { - "use strict"; - /*jshint debug:true*/ - - /** - @module ember - @submodule ember-handlebars - */ - var Ember = __dependency1__["default"]; - // Ember.FEATURES, - var inspect = __dependency2__.inspect; - var Logger = __dependency3__["default"]; - - var get = __dependency4__.get; - var normalizePath = __dependency5__.normalizePath; - var handlebarsGet = __dependency5__.handlebarsGet; - - var a_slice = [].slice; - - /** - `log` allows you to output the value of variables in the current rendering - context. `log` also accepts primitive types such as strings or numbers. - - ```handlebars - {{log "myVariable:" myVariable }} - ``` - - @method log - @for Ember.Handlebars.helpers - @param {String} property - */ - function logHelper() { - var params = a_slice.call(arguments, 0, -1), - options = arguments[arguments.length - 1], - logger = Logger.log, - values = [], - allowPrimitives = true; - - for (var i = 0; i < params.length; i++) { - var type = options.types[i]; - - if (type === 'ID' || !allowPrimitives) { - var context = (options.contexts && options.contexts[i]) || this, - normalized = normalizePath(context, params[i], options.data); - - if (normalized.path === 'this') { - values.push(normalized.root); - } else { - values.push(handlebarsGet(normalized.root, normalized.path, options)); - } - } else { - values.push(params[i]); - } - } - - logger.apply(logger, values); - }; - - /** - Execute the `debugger` statement in the current context. - - ```handlebars - {{debugger}} - ``` - - Before invoking the `debugger` statement, there - are a few helpful variables defined in the - body of this helper that you can inspect while - debugging that describe how and where this - helper was invoked: - - - templateContext: this is most likely a controller - from which this template looks up / displays properties - - typeOfTemplateContext: a string description of - what the templateContext is - - For example, if you're wondering why a value `{{foo}}` - isn't rendering as expected within a template, you - could place a `{{debugger}}` statement, and when - the `debugger;` breakpoint is hit, you can inspect - `templateContext`, determine if it's the object you - expect, and/or evaluate expressions in the console - to perform property lookups on the `templateContext`: - - ``` - > templateContext.get('foo') // -> "" - ``` - - @method debugger - @for Ember.Handlebars.helpers - @param {String} property - */ - function debuggerHelper(options) { - - // These are helpful values you can inspect while debugging. - var templateContext = this; - var typeOfTemplateContext = inspect(templateContext); - - debugger; - } - - __exports__.logHelper = logHelper; - __exports__.debuggerHelper = debuggerHelper; - }); -define("ember-handlebars/helpers/each", - ["ember-metal/core","ember-handlebars-compiler","ember-runtime/system/string","ember-metal/property_get","ember-metal/property_set","ember-handlebars/views/metamorph_view","ember-views/views/collection_view","ember-metal/binding","ember-runtime/controllers/controller","ember-runtime/controllers/array_controller","ember-runtime/mixins/array","ember-runtime/copy","ember-metal/run_loop","ember-metal/observer","ember-metal/events","ember-handlebars/ext","ember-metal/computed","exports"], - function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __dependency9__, __dependency10__, __dependency11__, __dependency12__, __dependency13__, __dependency14__, __dependency15__, __dependency16__, __dependency17__, __exports__) { - "use strict"; - - /** - @module ember - @submodule ember-handlebars - */ - var Ember = __dependency1__["default"]; - // Ember.assert;, Ember.K - // var emberAssert = Ember.assert, - var K = Ember.K; - - var EmberHandlebars = __dependency2__["default"]; - var helpers = EmberHandlebars.helpers; - - var fmt = __dependency3__.fmt; - var get = __dependency4__.get; - var set = __dependency5__.set; - var _Metamorph = __dependency6__._Metamorph; - var _MetamorphView = __dependency6__._MetamorphView; - var CollectionView = __dependency7__["default"]; - var Binding = __dependency8__.Binding; - var ControllerMixin = __dependency9__.ControllerMixin; - var ArrayController = __dependency10__["default"]; - var EmberArray = __dependency11__["default"]; - var copy = __dependency12__["default"]; - var run = __dependency13__["default"]; - var addObserver = __dependency14__.addObserver; - var removeObserver = __dependency14__.removeObserver; - var addBeforeObserver = __dependency14__.addBeforeObserver; - var removeBeforeObserver = __dependency14__.removeBeforeObserver; - var on = __dependency15__.on; - var handlebarsGet = __dependency16__.handlebarsGet; - var computed = __dependency17__.computed; - - var handlebarsGet = __dependency16__.handlebarsGet; - - var EachView = CollectionView.extend(_Metamorph, { - - init: function() { - var itemController = get(this, 'itemController'); - var binding; - - if (itemController) { - var controller = get(this, 'controller.container').lookupFactory('controller:array').create({ - _isVirtual: true, - parentController: get(this, 'controller'), - itemController: itemController, - target: get(this, 'controller'), - _eachView: this - }); - - this.disableContentObservers(function() { - set(this, 'content', controller); - binding = new Binding('content', '_eachView.dataSource').oneWay(); - binding.connect(controller); - }); - - set(this, '_arrayController', controller); - } else { - this.disableContentObservers(function() { - binding = new Binding('content', 'dataSource').oneWay(); - binding.connect(this); - }); - } - - return this._super(); - }, - - _assertArrayLike: function(content) { - }, - - disableContentObservers: function(callback) { - removeBeforeObserver(this, 'content', null, '_contentWillChange'); - removeObserver(this, 'content', null, '_contentDidChange'); - - callback.call(this); - - addBeforeObserver(this, 'content', null, '_contentWillChange'); - addObserver(this, 'content', null, '_contentDidChange'); - }, - - itemViewClass: _MetamorphView, - emptyViewClass: _MetamorphView, - - createChildView: function(view, attrs) { - view = this._super(view, attrs); - - // At the moment, if a container view subclass wants - // to insert keywords, it is responsible for cloning - // the keywords hash. This will be fixed momentarily. - var keyword = get(this, 'keyword'); - var content = get(view, 'content'); - - if (keyword) { - var data = get(view, 'templateData'); - - data = copy(data); - data.keywords = view.cloneKeywords(); - set(view, 'templateData', data); - - // In this case, we do not bind, because the `content` of - // a #each item cannot change. - data.keywords[keyword] = content; - } - - // If {{#each}} is looping over an array of controllers, - // point each child view at their respective controller. - if (content && content.isController) { - set(view, 'controller', content); - } - - return view; - }, - - destroy: function() { - if (!this._super()) { return; } - - var arrayController = get(this, '_arrayController'); - - if (arrayController) { - arrayController.destroy(); - } - - return this; - } - }); - - // Defeatureify doesn't seem to like nested functions that need to be removed - function _addMetamorphCheck() { - EachView.reopen({ - _checkMetamorph: on('didInsertElement', function() { - }) - }); - } - - // until ember-debug is es6ed - var runInDebug = function(f){f()}; - - var GroupedEach = EmberHandlebars.GroupedEach = function(context, path, options) { - var self = this, - normalized = EmberHandlebars.normalizePath(context, path, options.data); - - this.context = context; - this.path = path; - this.options = options; - this.template = options.fn; - this.containingView = options.data.view; - this.normalizedRoot = normalized.root; - this.normalizedPath = normalized.path; - this.content = this.lookupContent(); - - this.addContentObservers(); - this.addArrayObservers(); - - this.containingView.on('willClearRender', function() { - self.destroy(); - }); - }; - - GroupedEach.prototype = { - contentWillChange: function() { - this.removeArrayObservers(); - }, - - contentDidChange: function() { - this.content = this.lookupContent(); - this.addArrayObservers(); - this.rerenderContainingView(); - }, - - contentArrayWillChange: K, - - contentArrayDidChange: function() { - this.rerenderContainingView(); - }, - - lookupContent: function() { - return handlebarsGet(this.normalizedRoot, this.normalizedPath, this.options); - }, - - addArrayObservers: function() { - if (!this.content) { return; } - - this.content.addArrayObserver(this, { - willChange: 'contentArrayWillChange', - didChange: 'contentArrayDidChange' - }); - }, - - removeArrayObservers: function() { - if (!this.content) { return; } - - this.content.removeArrayObserver(this, { - willChange: 'contentArrayWillChange', - didChange: 'contentArrayDidChange' - }); - }, - - addContentObservers: function() { - addBeforeObserver(this.normalizedRoot, this.normalizedPath, this, this.contentWillChange); - addObserver(this.normalizedRoot, this.normalizedPath, this, this.contentDidChange); - }, - - removeContentObservers: function() { - removeBeforeObserver(this.normalizedRoot, this.normalizedPath, this.contentWillChange); - removeObserver(this.normalizedRoot, this.normalizedPath, this.contentDidChange); - }, - - render: function() { - if (!this.content) { return; } - - var content = this.content, - contentLength = get(content, 'length'), - data = this.options.data, - template = this.template; - - data.insideEach = true; - for (var i = 0; i < contentLength; i++) { - template(content.objectAt(i), { data: data }); - } - }, - - rerenderContainingView: function() { - var self = this; - run.scheduleOnce('render', this, function() { - // It's possible it's been destroyed after we enqueued a re-render call. - if (!self.destroyed) { - self.containingView.rerender(); - } - }); - }, - - destroy: function() { - this.removeContentObservers(); - if (this.content) { - this.removeArrayObservers(); - } - this.destroyed = true; - } - }; - - /** - The `{{#each}}` helper loops over elements in a collection, rendering its - block once for each item. It is an extension of the base Handlebars `{{#each}}` - helper: - - ```javascript - Developers = [{name: 'Yehuda'},{name: 'Tom'}, {name: 'Paul'}]; - ``` - - ```handlebars - {{#each Developers}} - {{name}} - {{/each}} - ``` - - `{{each}}` supports an alternative syntax with element naming: - - ```handlebars - {{#each person in Developers}} - {{person.name}} - {{/each}} - ``` - - When looping over objects that do not have properties, `{{this}}` can be used - to render the object: - - ```javascript - DeveloperNames = ['Yehuda', 'Tom', 'Paul'] - ``` - - ```handlebars - {{#each DeveloperNames}} - {{this}} - {{/each}} - ``` - ### {{else}} condition - `{{#each}}` can have a matching `{{else}}`. The contents of this block will render - if the collection is empty. - - ``` - {{#each person in Developers}} - {{person.name}} - {{else}} -

      Sorry, nobody is available for this task.

      - {{/each}} - ``` - ### Specifying a View class for items - If you provide an `itemViewClass` option that references a view class - with its own `template` you can omit the block. - - The following template: - - ```handlebars - {{#view App.MyView }} - {{each view.items itemViewClass="App.AnItemView"}} - {{/view}} - ``` - - And application code - - ```javascript - App = Ember.Application.create({ - MyView: Ember.View.extend({ - items: [ - Ember.Object.create({name: 'Dave'}), - Ember.Object.create({name: 'Mary'}), - Ember.Object.create({name: 'Sara'}) - ] - }) - }); - - App.AnItemView = Ember.View.extend({ - template: Ember.Handlebars.compile("Greetings {{name}}") - }); - ``` - - Will result in the HTML structure below - - ```html -
      -
      Greetings Dave
      -
      Greetings Mary
      -
      Greetings Sara
      -
      - ``` - - If an `itemViewClass` is defined on the helper, and therefore the helper is not - being used as a block, an `emptyViewClass` can also be provided optionally. - The `emptyViewClass` will match the behavior of the `{{else}}` condition - described above. That is, the `emptyViewClass` will render if the collection - is empty. - - ### Representing each item with a Controller. - By default the controller lookup within an `{{#each}}` block will be - the controller of the template where the `{{#each}}` was used. If each - item needs to be presented by a custom controller you can provide a - `itemController` option which references a controller by lookup name. - Each item in the loop will be wrapped in an instance of this controller - and the item itself will be set to the `content` property of that controller. - - This is useful in cases where properties of model objects need transformation - or synthesis for display: - - ```javascript - App.DeveloperController = Ember.ObjectController.extend({ - isAvailableForHire: function() { - return !this.get('content.isEmployed') && this.get('content.isSeekingWork'); - }.property('isEmployed', 'isSeekingWork') - }) - ``` - - ```handlebars - {{#each person in developers itemController="developer"}} - {{person.name}} {{#if person.isAvailableForHire}}Hire me!{{/if}} - {{/each}} - ``` - - Each itemController will receive a reference to the current controller as - a `parentController` property. - - ### (Experimental) Grouped Each - - When used in conjunction with the experimental [group helper](https://github.com/emberjs/group-helper), - you can inform Handlebars to re-render an entire group of items instead of - re-rendering them one at a time (in the event that they are changed en masse - or an item is added/removed). - - ```handlebars - {{#group}} - {{#each people}} - {{firstName}} {{lastName}} - {{/each}} - {{/group}} - ``` - - This can be faster than the normal way that Handlebars re-renders items - in some cases. - - If for some reason you have a group with more than one `#each`, you can make - one of the collections be updated in normal (non-grouped) fashion by setting - the option `groupedRows=true` (counter-intuitive, I know). - - For example, - - ```handlebars - {{dealershipName}} - - {{#group}} - {{#each dealers}} - {{firstName}} {{lastName}} - {{/each}} - - {{#each car in cars groupedRows=true}} - {{car.make}} {{car.model}} {{car.color}} - {{/each}} - {{/group}} - ``` - Any change to `dealershipName` or the `dealers` collection will cause the - entire group to be re-rendered. However, changes to the `cars` collection - will be re-rendered individually (as normal). - - Note that `group` behavior is also disabled by specifying an `itemViewClass`. - - @method each - @for Ember.Handlebars.helpers - @param [name] {String} name for item (used with `in`) - @param [path] {String} path - @param [options] {Object} Handlebars key/value pairs of options - @param [options.itemViewClass] {String} a path to a view class used for each item - @param [options.itemController] {String} name of a controller to be created for each item - @param [options.groupedRows] {boolean} enable normal item-by-item rendering when inside a `#group` helper - */ - function eachHelper(path, options) { - var ctx, helperName = 'each'; - - if (arguments.length === 4) { - - var keywordName = arguments[0]; - - - options = arguments[3]; - path = arguments[2]; - - helperName += ' ' + keywordName + ' in ' + path; - - if (path === '') { path = "this"; } - - options.hash.keyword = keywordName; - - } else if (arguments.length === 1) { - options = path; - path = 'this'; - } else { - helperName += ' ' + path; - } - - options.hash.dataSourceBinding = path; - // Set up emptyView as a metamorph with no tag - //options.hash.emptyViewClass = Ember._MetamorphView; - - // can't rely on this default behavior when use strict - ctx = this || window; - - options.helperName = options.helperName || helperName; - - if (options.data.insideGroup && !options.hash.groupedRows && !options.hash.itemViewClass) { - new GroupedEach(ctx, path, options).render(); - } else { - // ES6TODO: figure out how to do this without global lookup. - return helpers.collection.call(ctx, 'Ember.Handlebars.EachView', options); - } - } - - __exports__.EachView = EachView; - __exports__.GroupedEach = GroupedEach; - __exports__.eachHelper = eachHelper; - }); -define("ember-handlebars/helpers/loc", - ["ember-runtime/system/string","exports"], - function(__dependency1__, __exports__) { - "use strict"; - var loc = __dependency1__.loc; - - /** - @module ember - @submodule ember-handlebars - */ - - // ES6TODO: - // Pretty sure this can be expressed as - // var locHelper EmberStringUtils.loc ? - - /** - Calls [Ember.String.loc](/api/classes/Ember.String.html#method_loc) with the - provided string. - - This is a convenient way to localize text. For example: - - ```html - - ``` - - Take note that `"welcome"` is a string and not an object - reference. - - See [Ember.String.loc](/api/classes/Ember.String.html#method_loc) for how to - set up localized string references. - - @method loc - @for Ember.Handlebars.helpers - @param {String} str The string to format - @see {Ember.String#loc} - */ - function locHelper(str) { - return loc(str); - } - - __exports__["default"] = locHelper; - }); -define("ember-handlebars/helpers/partial", - ["ember-metal/core","ember-metal/is_none","ember-handlebars/ext","ember-handlebars/helpers/binding","exports"], - function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __exports__) { - "use strict"; - var Ember = __dependency1__["default"]; - // Ember.assert - // var emberAssert = Ember.assert; - - var isNone = __dependency2__.isNone; - var handlebarsGet = __dependency3__.handlebarsGet; - var bind = __dependency4__.bind; - - /** - @module ember - @submodule ember-handlebars - */ - - /** - The `partial` helper renders another template without - changing the template context: - - ```handlebars - {{foo}} - {{partial "nav"}} - ``` - - The above example template will render a template named - "_nav", which has the same context as the parent template - it's rendered into, so if the "_nav" template also referenced - `{{foo}}`, it would print the same thing as the `{{foo}}` - in the above example. - - If a "_nav" template isn't found, the `partial` helper will - fall back to a template named "nav". - - ## Bound template names - - The parameter supplied to `partial` can also be a path - to a property containing a template name, e.g.: - - ```handlebars - {{partial someTemplateName}} - ``` - - The above example will look up the value of `someTemplateName` - on the template context (e.g. a controller) and use that - value as the name of the template to render. If the resolved - value is falsy, nothing will be rendered. If `someTemplateName` - changes, the partial will be re-rendered using the new template - name. - - ## Setting the partial's context with `with` - - The `partial` helper can be used in conjunction with the `with` - helper to set a context that will be used by the partial: - - ```handlebars - {{#with currentUser}} - {{partial "user_info"}} - {{/with}} - ``` - - @method partial - @for Ember.Handlebars.helpers - @param {String} partialName the name of the template to render minus the leading underscore - */ - - function partialHelper(name, options) { - - var context = (options.contexts && options.contexts.length) ? options.contexts[0] : this; - - options.helperName = options.helperName || 'partial'; - - if (options.types[0] === "ID") { - // Helper was passed a property path; we need to - // create a binding that will re-render whenever - // this property changes. - options.fn = function(context, fnOptions) { - var partialName = handlebarsGet(context, name, fnOptions); - renderPartial(context, partialName, fnOptions); - }; - - return bind.call(context, name, options, true, exists); - } else { - // Render the partial right into parent template. - renderPartial(context, name, options); - } - } - - function exists(value) { - return !isNone(value); - } - - function renderPartial(context, name, options) { - var nameParts = name.split("/"); - var lastPart = nameParts[nameParts.length - 1]; - - nameParts[nameParts.length - 1] = "_" + lastPart; - - var view = options.data.view; - var underscoredName = nameParts.join("/"); - var template = view.templateForName(underscoredName); - var deprecatedTemplate = !template && view.templateForName(name); - - - template = template || deprecatedTemplate; - - template(context, { data: options.data }); - } - - __exports__["default"] = partialHelper; - }); -define("ember-handlebars/helpers/shared", - ["ember-handlebars/ext","exports"], - function(__dependency1__, __exports__) { - "use strict"; - var handlebarsGet = __dependency1__.handlebarsGet; - - function resolvePaths(options) { - var ret = [], - contexts = options.contexts, - roots = options.roots, - data = options.data; - - for (var i=0, l=contexts.length; i - {{#with loggedInUser}} - Last Login: {{lastLogin}} - User Info: {{template "user_info"}} - {{/with}} - - ``` - - ```html - - ``` - - ```handlebars - {{#if isUser}} - {{template "user_info"}} - {{else}} - {{template "unlogged_user_info"}} - {{/if}} - ``` - - This helper looks for templates in the global `Ember.TEMPLATES` hash. If you - add `