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