vendor/assets/javascripts/angular-scenario.js in angularjs-rails-1.2.3 vs vendor/assets/javascripts/angular-scenario.js in angularjs-rails-1.2.4

- old
+ new

@@ -9788,11 +9788,11 @@ } })( window ); /** - * @license AngularJS v1.2.3 + * @license AngularJS v1.2.4 * (c) 2010-2014 Google, Inc. http://angularjs.org * License: MIT */ (function(window, document){ var _jQuery = window.jQuery.noConflict(true); @@ -9858,11 +9858,11 @@ return arg; } return match; }); - message = message + '\nhttp://errors.angularjs.org/1.2.3/' + + message = message + '\nhttp://errors.angularjs.org/1.2.4/' + (module ? module + '/' : '') + code; for (i = 2; i < arguments.length; i++) { message = message + (i == 2 ? '?' : '&') + 'p' + (i-2) + '=' + encodeURIComponent(stringify(arguments[i])); } @@ -10434,13 +10434,13 @@ * * @param {*} value Reference to check. * @returns {boolean} True if `value` is a DOM element (or wrapped jQuery element). */ function isElement(node) { - return node && + return !!(node && (node.nodeName // we are a direct element - || (node.on && node.find)); // we have an on and find method part of jQuery API + || (node.on && node.find))); // we have an on and find method part of jQuery API } /** * @param str 'key1,key2,...' * @returns {object} in the form of {key1:true, key2:true, ...} @@ -10637,11 +10637,11 @@ function shallowCopy(src, dst) { dst = dst || {}; for(var key in src) { // shallowCopy is only ever called by $compile nodeLinkFn, which has control over src - // so we don't need to worry hasOwnProperty here + // so we don't need to worry about using our custom hasOwnProperty here if (src.hasOwnProperty(key) && key.substr(0, 2) !== '$$') { dst[key] = src[key]; } } @@ -11199,27 +11199,29 @@ } return obj; } /** - * Return the siblings between `startNode` and `endNode`, inclusive - * @param {Object} object with `startNode` and `endNode` properties + * Return the DOM siblings between the first and last node in the given array. + * @param {Array} array like object * @returns jQlite object containing the elements */ -function getBlockElements(block) { - if (block.startNode === block.endNode) { - return jqLite(block.startNode); +function getBlockElements(nodes) { + var startNode = nodes[0], + endNode = nodes[nodes.length - 1]; + if (startNode === endNode) { + return jqLite(startNode); } - var element = block.startNode; + var element = startNode; var elements = [element]; do { element = element.nextSibling; if (!element) break; elements.push(element); - } while (element !== block.endNode); + } while (element !== endNode); return jqLite(elements); } /** @@ -11616,15 +11618,15 @@ * - `minor` – `{number}` – Minor version number, such as "9". * - `dot` – `{number}` – Dot version number, such as "18". * - `codeName` – `{string}` – Code name of the release, such as "jiggling-armfat". */ var version = { - full: '1.2.3', // all of these placeholder strings will be replaced by grunt's + full: '1.2.4', // all of these placeholder strings will be replaced by grunt's major: 1, // package task minor: 2, - dot: 3, - codeName: 'unicorn-zapper' + dot: 4, + codeName: 'wormhole-baster' }; function publishExternalAPI(angular){ extend(angular, { @@ -12561,11 +12563,15 @@ } return elm; }, find: function(element, selector) { - return element.getElementsByTagName(selector); + if (element.getElementsByTagName) { + return element.getElementsByTagName(selector); + } else { + return []; + } }, clone: jqLiteClone, triggerHandler: function(element, eventName, eventData) { @@ -12891,11 +12897,11 @@ * // Given * var MyController = function(obfuscatedScope, obfuscatedRoute) { * // ... * } * // Define function dependencies - * MyController.$inject = ['$scope', '$route']; + * MyController['$inject'] = ['$scope', '$route']; * * // Then * expect(injector.annotate(MyController)).toEqual(['$scope', '$route']); * </pre> * @@ -14593,11 +14599,11 @@ * found, or if the directive does not have a controller, then an error is raised. The name can be prefixed with: * * * (no prefix) - Locate the required controller on the current element. Throw an error if not found. * * `?` - Attempt to locate the required controller or pass `null` to the `link` fn if not found. * * `^` - Locate the required controller by searching the element's parents. Throw an error if not found. - * * `?^` - Attempt to locate the required controller by searching the element's parentsor pass `null` to the + * * `?^` - Attempt to locate the required controller by searching the element's parents or pass `null` to the * `link` fn if not found. * * * #### `controllerAs` * Controller alias at the directive scope. An alias for the controller so it @@ -15332,11 +15338,11 @@ if (childTranscludeFn || (!boundTranscludeFn && transcludeFn)) { nodeLinkFn(childLinkFn, childScope, node, $rootElement, createBoundTranscludeFn(scope, childTranscludeFn || transcludeFn) ); } else { - nodeLinkFn(childLinkFn, childScope, node, undefined, boundTranscludeFn); + nodeLinkFn(childLinkFn, childScope, node, $rootElement, boundTranscludeFn); } } else if (childLinkFn) { childLinkFn(scope, node.childNodes, undefined, boundTranscludeFn); } } @@ -15839,17 +15845,17 @@ if (parentValue !== isolateScope[scopeName]) { // we are out of sync and need to copy if (parentValue !== lastValue) { // parent changed and it has precedence - lastValue = isolateScope[scopeName] = parentValue; + isolateScope[scopeName] = parentValue; } else { // if the parent can be assigned then do so - parentSet(scope, parentValue = lastValue = isolateScope[scopeName]); + parentSet(scope, parentValue = isolateScope[scopeName]); } } - return parentValue; + return lastValue = parentValue; }); break; case '&': parentGet = $parse(attrs[attrName]); @@ -17838,12 +17844,12 @@ * interpolation markup. * * <pre> var $interpolate = ...; // injected - var exp = $interpolate('Hello {{name}}!'); - expect(exp({name:'Angular'}).toEqual('Hello Angular!'); + var exp = $interpolate('Hello {{name | uppercase}}!'); + expect(exp({name:'Angular'}).toEqual('Hello ANGULAR!'); </pre> * * * @param {string} text The text with markup to interpolate. * @param {boolean=} mustHaveExpression if set to true then the interpolation string must have @@ -19037,27 +19043,28 @@ return name; } function ensureSafeObject(obj, fullExpression) { // nifty check if obj is Function that is fast and works across iframes and other contexts - if (obj && obj.constructor === obj) { - throw $parseMinErr('isecfn', - 'Referencing Function in Angular expressions is disallowed! Expression: {0}', - fullExpression); - } else if (// isWindow(obj) - obj && obj.document && obj.location && obj.alert && obj.setInterval) { - throw $parseMinErr('isecwindow', - 'Referencing the Window in Angular expressions is disallowed! Expression: {0}', - fullExpression); - } else if (// isElement(obj) - obj && (obj.nodeName || (obj.on && obj.find))) { - throw $parseMinErr('isecdom', - 'Referencing DOM nodes in Angular expressions is disallowed! Expression: {0}', - fullExpression); - } else { - return obj; + if (obj) { + if (obj.constructor === obj) { + throw $parseMinErr('isecfn', + 'Referencing Function in Angular expressions is disallowed! Expression: {0}', + fullExpression); + } else if (// isWindow(obj) + obj.document && obj.location && obj.alert && obj.setInterval) { + throw $parseMinErr('isecwindow', + 'Referencing the Window in Angular expressions is disallowed! Expression: {0}', + fullExpression); + } else if (// isElement(obj) + obj.children && (obj.nodeName || (obj.on && obj.find))) { + throw $parseMinErr('isecdom', + 'Referencing DOM nodes in Angular expressions is disallowed! Expression: {0}', + fullExpression); + } } + return obj; } var OPERATORS = { /* jshint bitwise : false */ 'null':function(){return null;}, @@ -20811,10 +20818,11 @@ * {@link guide/scope developer guide on scopes}. */ function $RootScopeProvider(){ var TTL = 10; var $rootScopeMinErr = minErr('$rootScope'); + var lastDirtyWatch = null; this.digestTtl = function(value) { if (arguments.length) { TTL = value; } @@ -20912,25 +20920,25 @@ * * @returns {Object} The newly created child scope. * */ $new: function(isolate) { - var Child, + var ChildScope, child; if (isolate) { child = new Scope(); child.$root = this.$root; // ensure that there is just one async queue per $rootScope and its children child.$$asyncQueue = this.$$asyncQueue; child.$$postDigestQueue = this.$$postDigestQueue; } else { - Child = function() {}; // should be anonymous; This is so that when the minifier munges + ChildScope = function() {}; // should be anonymous; This is so that when the minifier munges // the name it does not become random set of chars. This will then show up as class // name in the debugger. - Child.prototype = this; - child = new Child(); + ChildScope.prototype = this; + child = new ChildScope(); child.$id = nextUid(); } child['this'] = child; child.$$listeners = {}; child.$parent = this; @@ -21006,11 +21014,11 @@ scope.$digest(); expect(scope.counter).toEqual(1); - // Using a listener function + // Using a listener function var food; scope.foodCounter = 0; expect(scope.foodCounter).toEqual(0); scope.$watch( // This is the listener function @@ -21031,11 +21039,11 @@ expect(scope.foodCounter).toEqual(0); // Update food and run digest. Now the counter will increment food = 'cheeseburger'; scope.$digest(); - expect(scope.foodCounter).toEqual(1); + expect(scope.foodCounter).toEqual(1); * </pre> * * * @@ -21065,10 +21073,12 @@ get: get, exp: watchExp, eq: !!objectEquality }; + lastDirtyWatch = null; + // in the case user pass string, we need to compile it, do we really need this ? if (!isFunction(listener)) { var listenFn = compileToFn(listener || noop, 'listener'); watcher.fn = function(newVal, oldVal, scope) {listenFn(scope);}; } @@ -21293,73 +21303,91 @@ watchLog = [], logIdx, logMsg, asyncTask; beginPhase('$digest'); + lastDirtyWatch = null; + do { // "while dirty" loop dirty = false; current = target; while(asyncQueue.length) { try { asyncTask = asyncQueue.shift(); asyncTask.scope.$eval(asyncTask.expression); } catch (e) { + clearPhase(); $exceptionHandler(e); } + lastDirtyWatch = null; } + traverseScopesLoop: do { // "traverse the scopes" loop if ((watchers = current.$$watchers)) { // process our watches length = watchers.length; while (length--) { try { watch = watchers[length]; // Most common watches are on primitives, in which case we can short // circuit it with === operator, only when === fails do we use .equals - if (watch && (value = watch.get(current)) !== (last = watch.last) && - !(watch.eq - ? equals(value, last) - : (typeof value == 'number' && typeof last == 'number' - && isNaN(value) && isNaN(last)))) { - dirty = true; - watch.last = watch.eq ? copy(value) : value; - watch.fn(value, ((last === initWatchVal) ? value : last), current); - if (ttl < 5) { - logIdx = 4 - ttl; - if (!watchLog[logIdx]) watchLog[logIdx] = []; - logMsg = (isFunction(watch.exp)) - ? 'fn: ' + (watch.exp.name || watch.exp.toString()) - : watch.exp; - logMsg += '; newVal: ' + toJson(value) + '; oldVal: ' + toJson(last); - watchLog[logIdx].push(logMsg); + if (watch) { + if ((value = watch.get(current)) !== (last = watch.last) && + !(watch.eq + ? equals(value, last) + : (typeof value == 'number' && typeof last == 'number' + && isNaN(value) && isNaN(last)))) { + dirty = true; + lastDirtyWatch = watch; + watch.last = watch.eq ? copy(value) : value; + watch.fn(value, ((last === initWatchVal) ? value : last), current); + if (ttl < 5) { + logIdx = 4 - ttl; + if (!watchLog[logIdx]) watchLog[logIdx] = []; + logMsg = (isFunction(watch.exp)) + ? 'fn: ' + (watch.exp.name || watch.exp.toString()) + : watch.exp; + logMsg += '; newVal: ' + toJson(value) + '; oldVal: ' + toJson(last); + watchLog[logIdx].push(logMsg); + } + } else if (watch === lastDirtyWatch) { + // If the most recently dirty watcher is now clean, short circuit since the remaining watchers + // have already been tested. + dirty = false; + break traverseScopesLoop; } } } catch (e) { + clearPhase(); $exceptionHandler(e); } } } // Insanity Warning: scope depth-first traversal // yes, this code is a bit crazy, but it works and we have tests to prove it! // this piece should be kept in sync with the traversal in $broadcast - if (!(next = (current.$$childHead || (current !== target && current.$$nextSibling)))) { + if (!(next = (current.$$childHead || + (current !== target && current.$$nextSibling)))) { while(current !== target && !(next = current.$$nextSibling)) { current = current.$parent; } } } while ((current = next)); + // `break traverseScopesLoop;` takes us to here + if(dirty && !(ttl--)) { clearPhase(); throw $rootScopeMinErr('infdig', '{0} $digest() iterations reached. Aborting!\n' + 'Watchers fired in the last 5 iterations: {1}', TTL, toJson(watchLog)); } + } while (dirty || asyncQueue.length); clearPhase(); while(postDigestQueue.length) { @@ -21408,15 +21436,16 @@ * Note that, in AngularJS, there is also a `$destroy` jQuery event, which can be used to * clean up DOM bindings before an element is removed from the DOM. */ $destroy: function() { // we can't destroy the root scope or a scope that has been already destroyed - if ($rootScope == this || this.$$destroyed) return; + if (this.$$destroyed) return; var parent = this.$parent; this.$broadcast('$destroy'); this.$$destroyed = true; + if (this === $rootScope) return; if (parent.$$childHead == this) parent.$$childHead = this.$$nextSibling; if (parent.$$childTail == this) parent.$$childTail = this.$$prevSibling; if (this.$$prevSibling) this.$$prevSibling.$$nextSibling = this.$$nextSibling; if (this.$$nextSibling) this.$$nextSibling.$$prevSibling = this.$$prevSibling; @@ -21450,11 +21479,11 @@ * * @param {(string|function())=} expression An angular expression to be executed. * * - `string`: execute using the rules as defined in {@link guide/expression expression}. * - `function(scope)`: execute the function with the current `scope` parameter. - * + * * @param {(object)=} locals Local variables object, useful for overriding values in scope. * @returns {*} The result of evaluating the expression. */ $eval: function(expr, locals) { return $parse(expr)(this, locals); @@ -23318,17 +23347,19 @@ * @example <doc:example> <doc:source> <script> function Ctrl($scope, $window) { - $scope.$window = $window; $scope.greeting = 'Hello, World!'; + $scope.doGreeting = function(greeting) { + $window.alert(greeting); + }; } </script> <div ng-controller="Ctrl"> <input type="text" ng-model="greeting" /> - <button ng-click="$window.alert(greeting)">ALERT</button> + <button ng-click="doGreeting(greeting)">ALERT</button> </div> </doc:source> <doc:scenario> it('should display the greeting in the input box', function() { input('greeting').enter('Hello, E2E Tests'); @@ -24831,13 +24862,26 @@ * @property {boolean} $invalid True if at least one containing control or form is invalid. * * @property {Object} $error Is an object hash, containing references to all invalid controls or * forms, where: * - * - keys are validation tokens (error names) — such as `required`, `url` or `email`, - * - values are arrays of controls or forms that are invalid with given error. + * - keys are validation tokens (error names), + * - values are arrays of controls or forms that are invalid for given error name. * + * + * Built-in validation tokens: + * + * - `email` + * - `max` + * - `maxlength` + * - `min` + * - `minlength` + * - `number` + * - `pattern` + * - `required` + * - `url` + * * @description * `FormController` keeps track of all its controls and nested forms as well as state of them, * such as being valid/invalid or dirty/pristine. * * Each {@link ng.directive:form form} directive creates an instance @@ -26127,44 +26171,11 @@ expect(contentEditable.prop('className')).toMatch(/ng-invalid-required/); }); </file> * </example> * - * ## Isolated Scope Pitfall * - * Note that if you have a directive with an isolated scope, you cannot require `ngModel` - * since the model value will be looked up on the isolated scope rather than the outer scope. - * When the directive updates the model value, calling `ngModel.$setViewValue()` the property - * on the outer scope will not be updated. However you can get around this by using $parent. - * - * Here is an example of this situation. You'll notice that the first div is not updating the input. - * However the second div can update the input properly. - * - * <example module="badIsolatedDirective"> - <file name="script.js"> - angular.module('badIsolatedDirective', []).directive('isolate', function() { - return { - require: 'ngModel', - scope: { }, - template: '<input ng-model="innerModel">', - link: function(scope, element, attrs, ngModel) { - scope.$watch('innerModel', function(value) { - console.log(value); - ngModel.$setViewValue(value); - }); - } - }; - }); - </file> - <file name="index.html"> - <input ng-model="someModel"/> - <div isolate ng-model="someModel"></div> - <div isolate ng-model="$parent.someModel"></div> - </file> - * </example> - * - * */ var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$parse', function($scope, $exceptionHandler, $attr, $element, $parse) { this.$viewValue = Number.NaN; this.$modelValue = Number.NaN; @@ -26306,11 +26317,11 @@ * {@link ng.directive:select select} directives call it. * * It will update the $viewValue, then pass this value through each of the functions in `$parsers`, * which includes any validators. The value that comes out of this `$parsers` pipeline, be applied to * `$modelValue` and the **expression** specified in the `ng-model` attribute. - * + * * Lastly, all the registered change listeners, in the `$viewChangeListeners` list, are called. * * Note that calling this function does not trigger a `$digest`. * * @param {string} value Value from the view. @@ -26363,10 +26374,12 @@ if (ctrl.$viewValue !== value) { ctrl.$viewValue = value; ctrl.$render(); } } + + return value; }); }]; /** @@ -27856,13 +27869,16 @@ if (toBoolean(value)) { if (!childScope) { childScope = $scope.$new(); $transclude(childScope, function (clone) { + clone[clone.length++] = document.createComment(' end ngIf: ' + $attr.ngIf + ' '); + // Note: We only need the first/last node of the cloned nodes. + // However, we need to keep the reference to the jqlite wrapper as it might be changed later + // by a directive with templateUrl when it's template arrives. block = { - startNode: clone[0], - endNode: clone[clone.length++] = document.createComment(' end ngIf: ' + $attr.ngIf + ' ') + clone: clone }; $animate.enter(clone, $element.parent(), $element); }); } } else { @@ -27871,11 +27887,11 @@ childScope.$destroy(); childScope = null; } if (block) { - $animate.leave(getBlockElements(block)); + $animate.leave(getBlockElements(block.clone)); block = null; } } }); } @@ -28114,10 +28130,12 @@ * {@link api/ng.directive:ngRepeat `ngRepeat`}, as seen in the demo below. Besides this case, you * should use {@link guide/controller controllers} rather than `ngInit` * to initialize values on a scope. * </div> * + * @priority 450 + * * @element ANY * @param {expression} ngInit {@link guide/expression Expression} to eval. * * @example <doc:example> @@ -28145,10 +28163,11 @@ }); </doc:scenario> </doc:example> */ var ngInitDirective = ngDirective({ + priority: 450, compile: function() { return { pre: function(scope, element, attrs) { scope.$eval(attrs.ngInit); } @@ -28702,11 +28721,11 @@ nextBlockMap[trackById] = block; nextBlockOrder[index] = block; } else if (nextBlockMap.hasOwnProperty(trackById)) { // restore lastBlockMap forEach(nextBlockOrder, function(block) { - if (block && block.startNode) lastBlockMap[block.id] = block; + if (block && block.scope) lastBlockMap[block.id] = block; }); // This is a duplicate and we need to throw an error throw ngRepeatMinErr('dupes', "Duplicates in a repeater are not allowed. Use 'track by' expression to specify unique keys. Repeater: {0}, Duplicate key: {1}", expression, trackById); } else { @@ -28719,11 +28738,11 @@ // remove existing items for (key in lastBlockMap) { // lastBlockMap is our own object so we don't need to use special hasOwnPropertyFn if (lastBlockMap.hasOwnProperty(key)) { block = lastBlockMap[key]; - elementsToRemove = getBlockElements(block); + elementsToRemove = getBlockElements(block.clone); $animate.leave(elementsToRemove); forEach(elementsToRemove, function(element) { element[NG_REMOVED] = true; }); block.scope.$destroy(); } } @@ -28731,27 +28750,27 @@ // we are not using forEach for perf reasons (trying to avoid #call) for (index = 0, length = collectionKeys.length; index < length; index++) { key = (collection === collectionKeys) ? index : collectionKeys[index]; value = collection[key]; block = nextBlockOrder[index]; - if (nextBlockOrder[index - 1]) previousNode = nextBlockOrder[index - 1].endNode; + if (nextBlockOrder[index - 1]) previousNode = getBlockEnd(nextBlockOrder[index - 1]); - if (block.startNode) { + if (block.scope) { // if we have already seen this object, then we need to reuse the // associated scope/element childScope = block.scope; nextNode = previousNode; do { nextNode = nextNode.nextSibling; } while(nextNode && nextNode[NG_REMOVED]); - if (block.startNode != nextNode) { + if (getBlockStart(block) != nextNode) { // existing item which got moved - $animate.move(getBlockElements(block), null, jqLite(previousNode)); + $animate.move(getBlockElements(block.clone), null, jqLite(previousNode)); } - previousNode = block.endNode; + previousNode = getBlockEnd(block); } else { // new item which we don't know about childScope = $scope.$new(); } @@ -28763,25 +28782,35 @@ childScope.$middle = !(childScope.$first || childScope.$last); // jshint bitwise: false childScope.$odd = !(childScope.$even = (index&1) === 0); // jshint bitwise: true - if (!block.startNode) { + if (!block.scope) { $transclude(childScope, function(clone) { clone[clone.length++] = document.createComment(' end ngRepeat: ' + expression + ' '); $animate.enter(clone, null, jqLite(previousNode)); previousNode = clone; block.scope = childScope; - block.startNode = previousNode && previousNode.endNode ? previousNode.endNode : clone[0]; - block.endNode = clone[clone.length - 1]; + // Note: We only need the first/last node of the cloned nodes. + // However, we need to keep the reference to the jqlite wrapper as it might be changed later + // by a directive with templateUrl when it's template arrives. + block.clone = clone; nextBlockMap[block.id] = block; }); } } lastBlockMap = nextBlockMap; }); } }; + + function getBlockStart(block) { + return block.clone[0]; + } + + function getBlockEnd(block) { + return block.clone[block.clone.length - 1]; + } }]; /** * @ngdoc directive * @name ng.directive:ngShow \ No newline at end of file