template_app/vendor/assets/javascripts/angular.js in deano-1.2.0 vs template_app/vendor/assets/javascripts/angular.js in deano-1.2.1

- old
+ new

@@ -1,7 +1,7 @@ /** - * @license AngularJS v1.0.5 + * @license AngularJS v1.0.7 * (c) 2010-2012 Google, Inc. http://angularjs.org * License: MIT */ (function(window, document, undefined) { 'use strict'; @@ -32,16 +32,16 @@ var uppercase = function(string){return isString(string) ? string.toUpperCase() : string;}; var manualLowercase = function(s) { return isString(s) - ? s.replace(/[A-Z]/g, function(ch) {return fromCharCode(ch.charCodeAt(0) | 32);}) + ? s.replace(/[A-Z]/g, function(ch) {return String.fromCharCode(ch.charCodeAt(0) | 32);}) : s; }; var manualUppercase = function(s) { return isString(s) - ? s.replace(/[a-z]/g, function(ch) {return fromCharCode(ch.charCodeAt(0) & ~32);}) + ? s.replace(/[a-z]/g, function(ch) {return String.fromCharCode(ch.charCodeAt(0) & ~32);}) : s; }; // String#toLowerCase and String#toUpperCase don't produce correct results in browsers with Turkish @@ -50,13 +50,11 @@ if ('i' !== 'I'.toLowerCase()) { lowercase = manualLowercase; uppercase = manualUppercase; } -function fromCharCode(code) {return String.fromCharCode(code);} - var /** holds major version number for IE or NaN for real browsers */ msie = int((/msie (\d+)/.exec(lowercase(navigator.userAgent)) || [])[1]), jqLite, // delay binding since jQuery could be loaded after us. jQuery, // delay binding slice = [].slice, @@ -67,11 +65,34 @@ angular = window.angular || (window.angular = {}), angularModule, nodeName_, uid = ['0', '0', '0']; + /** + * @private + * @param {*} obj + * @return {boolean} Returns true if `obj` is an array or array-like object (NodeList, Arguments, ...) + */ +function isArrayLike(obj) { + if (!obj || (typeof obj.length !== 'number')) return false; + + // We have on object which has length property. Should we treat it as array? + if (typeof obj.hasOwnProperty != 'function' && + typeof obj.constructor != 'function') { + // This is here for IE8: it is a bogus object treat it as array; + return true; + } else { + return obj instanceof JQLite || // JQLite + (jQuery && obj instanceof jQuery) || // jQuery + toString.call(obj) !== '[object Object]' || // some browser native object + typeof obj.callee === 'function'; // arguments (on IE8 looks like regular obj) + } +} + + +/** * @ngdoc function * @name angular.forEach * @function * * @description @@ -94,34 +115,10 @@ * @param {Object|Array} obj Object to iterate over. * @param {Function} iterator Iterator function. * @param {Object=} context Object to become context (`this`) for the iterator function. * @returns {Object|Array} Reference to `obj`. */ - - -/** - * @private - * @param {*} obj - * @return {boolean} Returns true if `obj` is an array or array-like object (NodeList, Arguments, ...) - */ -function isArrayLike(obj) { - if (!obj || (typeof obj.length !== 'number')) return false; - - // We have on object which has length property. Should we treat it as array? - if (typeof obj.hasOwnProperty != 'function' && - typeof obj.constructor != 'function') { - // This is here for IE8: it is a bogus object treat it as array; - return true; - } else { - return obj instanceof JQLite || // JQLite - (jQuery && obj instanceof jQuery) || // jQuery - toString.call(obj) !== '[object Object]' || // some browser native object - typeof obj.callee === 'function'; // arguments (on IE8 looks like regular obj) - } -} - - function forEach(obj, iterator, context) { var key; if (obj) { if (isFunction(obj)){ for (key in obj) { @@ -201,30 +198,49 @@ } uid.unshift('0'); return uid.join(''); } + /** + * Set or clear the hashkey for an object. + * @param obj object + * @param h the hashkey (!truthy to delete the hashkey) + */ +function setHashKey(obj, h) { + if (h) { + obj.$$hashKey = h; + } + else { + delete obj.$$hashKey; + } +} + +/** * @ngdoc function * @name angular.extend * @function * * @description * Extends the destination object `dst` by copying all of the properties from the `src` object(s) * to `dst`. You can specify multiple `src` objects. * * @param {Object} dst Destination object. * @param {...Object} src Source object(s). + * @returns {Object} Reference to `dst`. */ function extend(dst) { + var h = dst.$$hashKey; forEach(arguments, function(obj){ if (obj !== dst) { forEach(obj, function(value, key){ dst[key] = value; }); } }); + + setHashKey(dst,h); return dst; } function int(str) { return parseInt(str, 10); @@ -575,16 +591,18 @@ destination.length = 0; for ( var i = 0; i < source.length; i++) { destination.push(copy(source[i])); } } else { + var h = destination.$$hashKey; forEach(destination, function(value, key){ delete destination[key]; }); for ( var key in source) { destination[key] = copy(source[key]); } + setHashKey(destination,h); } } return destination; } @@ -620,11 +638,11 @@ * * Both values are NaN. (In JavasScript, NaN == NaN => false. But we consider two NaN as equal) * * During a property comparision, properties of `function` type and properties with names * that begin with `$` are ignored. * - * Scope and DOMWindow objects are being compared only be identify (`===`). + * Scope and DOMWindow objects are being compared only by identify (`===`). * * @param {*} o1 Object or value to compare. * @param {*} o2 Object or value to compare. * @returns {boolean} True if arguments are equal. */ @@ -680,11 +698,11 @@ * @name angular.bind * @function * * @description * Returns a function which calls function `fn` bound to `self` (`self` becomes the `this` for - * `fn`). You can supply optional `args` that are are prebound to the function. This feature is also + * `fn`). You can supply optional `args` that are prebound to the function. This feature is also * known as [function currying](http://en.wikipedia.org/wiki/Currying). * * @param {Object} self Context which `fn` should be evaluated in. * @param {function()} fn Function to be bound. * @param {...*} args Optional arguments to be prebound to the `fn` function call. @@ -859,11 +877,11 @@ return encodeURIComponent(val). replace(/%40/gi, '@'). replace(/%3A/gi, ':'). replace(/%24/g, '$'). replace(/%2C/gi, ','). - replace((pctEncodeSpaces ? null : /%20/g), '+'); + replace(/%20/g, (pctEncodeSpaces ? '%20' : '+')); } /** * @ngdoc directive @@ -873,11 +891,11 @@ * @param {angular.Module} ngApp an optional application * {@link angular.module module} name to load. * * @description * - * Use this directive to auto-bootstrap on application. Only + * Use this directive to auto-bootstrap an application. Only * one directive can be used per HTML document. The directive * designates the root of the application and is typically placed * at the root of the page. * * In the example below if the `ngApp` directive would not be placed @@ -948,26 +966,42 @@ * @param {Element} element DOM element which is the root of angular application. * @param {Array<String|Function>=} modules an array of module declarations. See: {@link angular.module modules} * @returns {AUTO.$injector} Returns the newly created injector for this app. */ function bootstrap(element, modules) { - element = jqLite(element); - modules = modules || []; - modules.unshift(['$provide', function($provide) { - $provide.value('$rootElement', element); - }]); - modules.unshift('ng'); - var injector = createInjector(modules); - injector.invoke( - ['$rootScope', '$rootElement', '$compile', '$injector', function(scope, element, compile, injector){ - scope.$apply(function() { - element.data('$injector', injector); - compile(element)(scope); - }); - }] - ); - return injector; + var resumeBootstrapInternal = function() { + element = jqLite(element); + modules = modules || []; + modules.unshift(['$provide', function($provide) { + $provide.value('$rootElement', element); + }]); + modules.unshift('ng'); + var injector = createInjector(modules); + injector.invoke(['$rootScope', '$rootElement', '$compile', '$injector', + function(scope, element, compile, injector) { + scope.$apply(function() { + element.data('$injector', injector); + compile(element)(scope); + }); + }] + ); + return injector; + }; + + var NG_DEFER_BOOTSTRAP = /^NG_DEFER_BOOTSTRAP!/; + + if (window && !NG_DEFER_BOOTSTRAP.test(window.name)) { + return resumeBootstrapInternal(); + } + + window.name = window.name.replace(NG_DEFER_BOOTSTRAP, ''); + angular.resumeBootstrap = function(extraModules) { + forEach(extraModules, function(module) { + modules.push(module); + }); + resumeBootstrapInternal(); + }; } var SNAKE_CASE_REGEXP = /[A-Z]/g; function snake_case(name, separator){ separator = separator || '_'; @@ -996,11 +1030,11 @@ } angular.element = jqLite; } /** - * throw error of the argument is falsy. + * throw error if the argument is falsy. */ function assertArg(arg, name, reason) { if (!arg) { throw new Error("Argument '" + (name || '?') + "' is " + (reason || "required")); } @@ -1270,22 +1304,22 @@ * @name angular.version * @description * An object that contains information about the current AngularJS version. This object has the * following properties: * - * - `full` – `{string}` – Full version string, such as "0.9.18". - * - `major` – `{number}` – Major version number, such as "0". - * - `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". + * - `full` – `{string}` – Full version string, such as "0.9.18". + * - `major` – `{number}` – Major version number, such as "0". + * - `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.0.5', // all of these placeholder strings will be replaced by rake's - major: 1, // compile task + full: '1.0.7', // all of these placeholder strings will be replaced by grunt's + major: 1, // package task minor: 0, - dot: 5, - codeName: 'flatulent-propulsion' + dot: 7, + codeName: 'monochromatic-rainbow' }; function publishExternalAPI(angular){ extend(angular, { @@ -1426,22 +1460,22 @@ * * - [addClass()](http://api.jquery.com/addClass/) * - [after()](http://api.jquery.com/after/) * - [append()](http://api.jquery.com/append/) * - [attr()](http://api.jquery.com/attr/) - * - [bind()](http://api.jquery.com/bind/) - * - [children()](http://api.jquery.com/children/) + * - [bind()](http://api.jquery.com/bind/) - Does not support namespaces + * - [children()](http://api.jquery.com/children/) - Does not support selectors * - [clone()](http://api.jquery.com/clone/) * - [contents()](http://api.jquery.com/contents/) * - [css()](http://api.jquery.com/css/) * - [data()](http://api.jquery.com/data/) * - [eq()](http://api.jquery.com/eq/) - * - [find()](http://api.jquery.com/find/) - Limited to lookups by tag name. + * - [find()](http://api.jquery.com/find/) - Limited to lookups by tag name * - [hasClass()](http://api.jquery.com/hasClass/) * - [html()](http://api.jquery.com/html/) - * - [next()](http://api.jquery.com/next/) - * - [parent()](http://api.jquery.com/parent/) + * - [next()](http://api.jquery.com/next/) - Does not support selectors + * - [parent()](http://api.jquery.com/parent/) - Does not support selectors * - [prepend()](http://api.jquery.com/prepend/) * - [prop()](http://api.jquery.com/prop/) * - [ready()](http://api.jquery.com/ready/) * - [remove()](http://api.jquery.com/remove/) * - [removeAttr()](http://api.jquery.com/removeAttr/) @@ -1449,11 +1483,11 @@ * - [removeData()](http://api.jquery.com/removeData/) * - [replaceWith()](http://api.jquery.com/replaceWith/) * - [text()](http://api.jquery.com/text/) * - [toggleClass()](http://api.jquery.com/toggleClass/) * - [triggerHandler()](http://api.jquery.com/triggerHandler/) - Doesn't pass native event objects to handlers. - * - [unbind()](http://api.jquery.com/unbind/) + * - [unbind()](http://api.jquery.com/unbind/) - Does not support namespaces * - [val()](http://api.jquery.com/val/) * - [wrap()](http://api.jquery.com/wrap/) * * ## In addtion to the above, Angular provides additional methods to both jQuery and jQuery lite: * @@ -1996,27 +2030,47 @@ forEach(type.split(' '), function(type){ var eventFns = events[type]; if (!eventFns) { if (type == 'mouseenter' || type == 'mouseleave') { - var counter = 0; + var contains = document.body.contains || document.body.compareDocumentPosition ? + function( a, b ) { + var adown = a.nodeType === 9 ? a.documentElement : a, + bup = b && b.parentNode; + return a === bup || !!( bup && bup.nodeType === 1 && ( + adown.contains ? + adown.contains( bup ) : + a.compareDocumentPosition && a.compareDocumentPosition( bup ) & 16 + )); + } : + function( a, b ) { + if ( b ) { + while ( (b = b.parentNode) ) { + if ( b === a ) { + return true; + } + } + } + return false; + }; - events.mouseenter = []; - events.mouseleave = []; + events[type] = []; - bindFn(element, 'mouseover', function(event) { - counter++; - if (counter == 1) { - handle(event, 'mouseenter'); + // Refer to jQuery's implementation of mouseenter & mouseleave + // Read about mouseenter and mouseleave: + // http://www.quirksmode.org/js/events_mouse.html#link8 + var eventmap = { mouseleave : "mouseout", mouseenter : "mouseover"} + bindFn(element, eventmap[type], function(event) { + var ret, target = this, related = event.relatedTarget; + // For mousenter/leave call the handler if related is outside the target. + // NB: No relatedTarget if the mouse left/entered the browser window + if ( !related || (related !== target && !contains(target, related)) ){ + handle(event, type); } + }); - bindFn(element, 'mouseout', function(event) { - counter --; - if (counter == 0) { - handle(event, 'mouseleave'); - } - }); + } else { addEventListenerFn(element, type, handle); events[type] = []; } eventFns = events[type] @@ -2328,11 +2382,11 @@ }); fn.$inject = $inject; } } else if (isArray(fn)) { last = fn.length - 1; - assertArgFn(fn[last], 'fn') + assertArgFn(fn[last], 'fn'); $inject = fn.slice(0, last); } else { assertArgFn(fn, 'fn', true); } return $inject; @@ -2362,23 +2416,23 @@ * </pre> * * # Injection Function Annotation * * JavaScript does not have annotations, and annotations are needed for dependency injection. The - * following ways are all valid way of annotating function with injection arguments and are equivalent. + * following are all valid ways of annotating function with injection arguments and are equivalent. * * <pre> * // inferred (only works if code not minified/obfuscated) - * $inject.invoke(function(serviceA){}); + * $injector.invoke(function(serviceA){}); * * // annotated * function explicit(serviceA) {}; * explicit.$inject = ['serviceA']; - * $inject.invoke(explicit); + * $injector.invoke(explicit); * * // inline - * $inject.invoke(['serviceA', function(serviceA){}]); + * $injector.invoke(['serviceA', function(serviceA){}]); * </pre> * * ## Inference * * In JavaScript calling `toString()` on a function returns the function definition. The definition can then be @@ -2491,11 +2545,11 @@ * // We are forced to write break inlining * var tmpFn = function(obfuscatedCompile, obfuscatedRootScope) { * // ... * }; * tmpFn.$inject = ['$compile', '$rootScope']; - * injector.invoke(tempFn); + * injector.invoke(tmpFn); * * // To better support inline function the inline annotation is supported * injector.invoke(['$compile', '$rootScope', function(obfCompile, obfRootScope) { * // ... * }]); @@ -2520,11 +2574,11 @@ * @name AUTO.$provide * * @description * * Use `$provide` to register new providers with the `$injector`. The providers are the factories for the instance. - * The providers share the same name as the instance they create with the `Provider` suffixed to them. + * The providers share the same name as the instance they create with `Provider` suffixed to them. * * A provider is an object with a `$get()` method. The injector calls the `$get` method to create a new instance of * a service. The Provider can have additional methods which would allow for configuration of the provider. * * <pre> @@ -2544,11 +2598,11 @@ * * describe('Greeter', function(){ * * beforeEach(module(function($provide) { * $provide.provider('greet', GreetProvider); - * }); + * })); * * it('should greet', inject(function(greet) { * expect(greet('angular')).toEqual('Hello angular!'); * })); * @@ -2557,13 +2611,11 @@ * greetProvider.salutation('Ahoj'); * }); * inject(function(greet) { * expect(greet('angular')).toEqual('Ahoj angular!'); * }); - * )}; - * - * }); + * }); * </pre> */ /** * @ngdoc method @@ -2653,11 +2705,11 @@ * returned instance may be the original instance, or a new instance which delegates to the * original instance. * * @param {string} name The name of the service to decorate. * @param {function()} decorator This function will be invoked when the service needs to be - * instanciated. The function is called using the {@link AUTO.$injector#invoke + * instantiated. The function is called using the {@link AUTO.$injector#invoke * injector.invoke} method and is therefore fully injectable. Local injection arguments: * * * `$delegate` - The original service instance, which can be monkey patched, configured, * decorated or delegated to. */ @@ -2853,10 +2905,12 @@ function instantiate(Type, locals) { var Constructor = function() {}, instance, returnedValue; + // Check if Type is annotated and use just the given function at n-1 as parameter + // e.g. someModule.factory('greeter', ['$window', function(renamed$window) {}]); Constructor.prototype = (isArray(Type) ? Type[Type.length - 1] : Type).prototype; instance = new Constructor(); returnedValue = invoke(Type, instance, locals); return isObject(returnedValue) ? returnedValue : instance; @@ -2868,10 +2922,11 @@ get: getService, annotate: annotate }; } } + /** * @ngdoc function * @name ng.$anchorScroll * @requires $window * @requires $location @@ -3232,11 +3287,17 @@ for (i = 0; i < cookieArray.length; i++) { cookie = cookieArray[i]; index = cookie.indexOf('='); if (index > 0) { //ignore nameless cookies - lastCookies[unescape(cookie.substring(0, index))] = unescape(cookie.substring(index + 1)); + var name = unescape(cookie.substring(0, index)); + // the first value that is seen for a cookie is the most + // specific one. values for the same cookie name that + // follow are for less specific paths. + if (lastCookies[name] === undefined) { + lastCookies[name] = unescape(cookie.substring(index + 1)); + } } } } return lastCookies; } @@ -3296,10 +3357,11 @@ this.$get = ['$window', '$log', '$sniffer', '$document', function( $window, $log, $sniffer, $document){ return new Browser($window, $document, $log, $sniffer); }]; } + /** * @ngdoc object * @name ng.$cacheFactory * * @description @@ -3307,20 +3369,20 @@ * * * @param {string} cacheId Name or id of the newly created cache. * @param {object=} options Options object that specifies the cache behavior. Properties: * - * - `{number=}` `capacity` — turns the cache into LRU cache. + * - `{number=}` `capacity` — turns the cache into LRU cache. * * @returns {object} Newly created cache object with the following set of methods: * - * - `{object}` `info()` — Returns id, size, and options of cache. - * - `{void}` `put({string} key, {*} value)` — Puts a new key-value pair into the cache. - * - `{{*}}` `get({string} key)` — Returns cached value for `key` or undefined for cache miss. - * - `{void}` `remove({string} key)` — Removes a key-value pair from the cache. - * - `{void}` `removeAll()` — Removes all cached values. - * - `{void}` `destroy()` — Removes references to this cache from $cacheFactory. + * - `{object}` `info()` — Returns id, size, and options of cache. + * - `{void}` `put({string} key, {*} value)` — Puts a new key-value pair into the cache. + * - `{{*}}` `get({string} key)` — Returns cached value for `key` or undefined for cache miss. + * - `{void}` `remove({string} key)` — Removes a key-value pair from the cache. + * - `{void}` `removeAll()` — Removes all cached values. + * - `{void}` `destroy()` — Removes references to this cache from $cacheFactory. * */ function $CacheFactoryProvider() { this.$get = function() { @@ -3623,11 +3685,11 @@ var hasDirectives = {}, Suffix = 'Directive', COMMENT_DIRECTIVE_REGEXP = /^\s*directive\:\s*([\d\w\-_]+)\s+(.*)$/, CLASS_DIRECTIVE_REGEXP = /(([\d\w\-_]+)(?:\:([^;]+))?;?)/, MULTI_ROOT_TEMPLATE_ERROR = 'Template must have exactly one root element. was: ', - urlSanitizationWhitelist = /^\s*(https?|ftp|mailto):/; + urlSanitizationWhitelist = /^\s*(https?|ftp|mailto|file):/; /** * @ngdoc function * @name ng.$compileProvider#directive @@ -3825,11 +3887,11 @@ //================================ function compile($compileNodes, transcludeFn, maxPriority) { if (!($compileNodes instanceof jqLite)) { - // jquery always rewraps, where as we need to preserve the original selector so that we can modify it. + // jquery always rewraps, whereas we need to preserve the original selector so that we can modify it. $compileNodes = jqLite($compileNodes); } // We can not compile top level text elements since text nodes can be merged and we will // not be able to attach scope data to them, so we will wrap them in <span> forEach($compileNodes, function(node, index){ @@ -3877,11 +3939,11 @@ * Compile function matches each node in nodeList against the directives. Once all directives * for a particular node are collected their compile functions are executed. The compile * functions return values - the linking functions - are combined into a composite linking * function, which is the a linking function for the node. * - * @param {NodeList} nodeList an array of nodes to compile + * @param {NodeList} nodeList an array of nodes or NodeList to compile * @param {function(angular.Scope[, cloneAttachFn]} transcludeFn A linking function, where the * scope argument is auto-generated to the new child of the transcluded parent scope. * @param {DOMElement=} $rootElement If the nodeList is the root of the compilation tree then the * rootElement must be set the jqLite collection of the compile root. This is * needed so that the jqLite collection items can be replaced with widgets. @@ -3900,11 +3962,11 @@ nodeLinkFn = (directives.length) ? applyDirectivesToNode(directives, nodeList[i], attrs, transcludeFn, $rootElement) : null; - childLinkFn = (nodeLinkFn && nodeLinkFn.terminal || !nodeList[i].childNodes.length) + childLinkFn = (nodeLinkFn && nodeLinkFn.terminal || !nodeList[i].childNodes || !nodeList[i].childNodes.length) ? null : compileNodes(nodeList[i].childNodes, nodeLinkFn ? nodeLinkFn.transclude : transcludeFn); linkFns.push(nodeLinkFn); @@ -4036,25 +4098,25 @@ return directives; } /** - * Once the directives have been collected their compile functions is executed. This method + * Once the directives have been collected, their compile functions are executed. This method * is responsible for inlining directive templates as well as terminating the application - * of the directives if the terminal directive has been reached.. + * of the directives if the terminal directive has been reached. * * @param {Array} directives Array of collected directives to execute their compile function. * this needs to be pre-sorted by priority order. * @param {Node} compileNode The raw DOM node to apply the compile functions to * @param {Object} templateAttrs The shared attribute function * @param {function(angular.Scope[, cloneAttachFn]} transcludeFn A linking function, where the * scope argument is auto-generated to the new child of the transcluded parent scope. - * @param {DOMElement} $rootElement If we are working on the root of the compile tree then this - * argument has the root jqLite array so that we can replace widgets on it. + * @param {JQLite} jqCollection If we are working on the root of the compile tree then this + * argument has the root jqLite array so that we can replace nodes on it. * @returns linkFn */ - function applyDirectivesToNode(directives, compileNode, templateAttrs, transcludeFn, $rootElement) { + function applyDirectivesToNode(directives, compileNode, templateAttrs, transcludeFn, jqCollection) { var terminalPriority = -Number.MAX_VALUE, preLinkFns = [], postLinkFns = [], newScopeDirective = null, newIsolateScopeDirective = null, @@ -4104,11 +4166,11 @@ if (directiveValue == 'element') { $template = jqLite(compileNode); $compileNode = templateAttrs.$$element = jqLite(document.createComment(' ' + directiveName + ': ' + templateAttrs[directiveName] + ' ')); compileNode = $compileNode[0]; - replaceWith($rootElement, jqLite($template[0]), compileNode); + replaceWith(jqCollection, jqLite($template[0]), compileNode); childTranscludeFn = compile($template, transcludeFn, terminalPriority); } else { $template = jqLite(JQLiteClone(compileNode)).contents(); $compileNode.html(''); // clear contents childTranscludeFn = compile($template, transcludeFn); @@ -4128,11 +4190,11 @@ if ($template.length != 1 || compileNode.nodeType !== 1) { throw new Error(MULTI_ROOT_TEMPLATE_ERROR + directiveValue); } - replaceWith($rootElement, $compileNode, compileNode); + replaceWith(jqCollection, $compileNode, compileNode); var newTemplateAttrs = {$attr: {}}; // combine directives from the original node and from the template: // - take the array of directives for this element @@ -4156,11 +4218,11 @@ if (directive.templateUrl) { assertNoDuplicate('template', templateDirective, directive, $compileNode); templateDirective = directive; nodeLinkFn = compileTemplateUrl(directives.splice(i, directives.length - i), - nodeLinkFn, $compileNode, templateAttrs, $rootElement, directive.replace, + nodeLinkFn, $compileNode, templateAttrs, jqCollection, directive.replace, childTranscludeFn); ii = directives.length; } else if (directive.compile) { try { linkFn = directive.compile($compileNode, templateAttrs, childTranscludeFn); @@ -4289,11 +4351,11 @@ case '&': { parentGet = $parse(attrs[attrName]); scope[scopeName] = function(locals) { return parentGet(parentScope, locals); - } + }; break; } default: { throw Error('Invalid isolate scope definition for directive ' + @@ -4459,11 +4521,11 @@ $compileNode.html(content); } directives.unshift(derivedSyncDirective); afterTemplateNodeLinkFn = applyDirectivesToNode(directives, compileNode, tAttrs, childTranscludeFn); - afterTemplateChildLinkFn = compileNodes($compileNode.contents(), childTranscludeFn); + afterTemplateChildLinkFn = compileNodes($compileNode[0].childNodes, childTranscludeFn); while(linkQueue.length) { var controller = linkQueue.pop(), linkRootElement = linkQueue.pop(), @@ -4724,11 +4786,11 @@ * @return {Object} Instance of given controller. * * @description * `$controller` service is responsible for instantiating controllers. * - * It's just simple call to {@link AUTO.$injector $injector}, but extracted into + * It's just a simple call to {@link AUTO.$injector $injector}, but extracted into * a service, so that one can override this service with {@link https://gist.github.com/1649788 * BC version}. */ return function(constructor, locals) { if(isString(constructor)) { @@ -4777,11 +4839,11 @@ * @param {string=} cause optional information about the context in which * the error was thrown. * */ function $ExceptionHandlerProvider() { - this.$get = ['$log', function($log){ + this.$get = ['$log', function($log) { return function(exception, cause) { $log.error.apply($log, arguments); }; }]; } @@ -4965,11 +5027,11 @@ return $interpolate; }]; } -var URL_MATCH = /^([^:]+):\/\/(\w+:{0,1}\w*@)?([\w\.-]*)(:([0-9]+))?(\/[^\?#]*)?(\?([^#]*))?(#(.*))?$/, +var URL_MATCH = /^([^:]+):\/\/(\w+:{0,1}\w*@)?(\{?[\w\.-]*\}?)(:([0-9]+))?(\/[^\?#]*)?(\?([^#]*))?(#(.*))?$/, PATH_MATCH = /^([^\?#]*)?(\?([^#]*))?(#(.*))?$/, HASH_MATCH = PATH_MATCH, DEFAULT_PORTS = {'http': 80, 'https': 443, 'ftp': 21}; @@ -5044,11 +5106,12 @@ function convertToHashbangUrl(url, basePath, hashPrefix) { var match = matchUrl(url); // already hashbang url - if (decodeURIComponent(match.path) == basePath) { + if (decodeURIComponent(match.path) == basePath && !isUndefined(match.hash) && + match.hash.indexOf(hashPrefix) === 0) { return url; // convert html5 url -> hashbang url } else { var search = match.search && '?' + match.search || '', hash = match.hash && '#' + match.hash || '', @@ -5541,10 +5604,14 @@ } // update $location when $browser url changes $browser.onUrlChange(function(newUrl) { if ($location.absUrl() != newUrl) { + if ($rootScope.$broadcast('$locationChangeStart', newUrl, $location.absUrl()).defaultPrevented) { + $browser.url($location.absUrl()); + return; + } $rootScope.$evalAsync(function() { var oldUrl = $location.absUrl(); $location.$$parse(newUrl); afterLocationChange(oldUrl); @@ -5849,14 +5916,14 @@ fn:function() {return number;}}); } function readIdent() { var ident = "", start = index, - lastDot, peekIndex, methodName; + lastDot, peekIndex, methodName, ch; while (index < text.length) { - var ch = text.charAt(index); + ch = text.charAt(index); if (ch == '.' || isIdent(ch) || isNumber(ch)) { if (ch == '.') lastDot = index; ident += ch; } else { break; @@ -5866,11 +5933,11 @@ //check if this is not a method invocation and if it is back out to last dot if (lastDot) { peekIndex = index; while(peekIndex < text.length) { - var ch = text.charAt(peekIndex); + ch = text.charAt(peekIndex); if (ch == '(') { methodName = ident.substr(lastDot - start + 1); ident = ident.substr(0, lastDot - start); index = peekIndex; break; @@ -6119,12 +6186,12 @@ if (!left.assign) { throwError("implies assignment but [" + text.substring(0, token.index) + "] can not be assigned to", token); } right = logicalOR(); - return function(self, locals){ - return left.assign(self, right(self, locals), locals); + return function(scope, locals){ + return left.assign(scope, right(scope, locals), locals); }; } else { return left; } } @@ -6237,16 +6304,16 @@ function _fieldAccess(object) { var field = expect().text; var getter = getterFn(field, csp); return extend( - function(self, locals) { - return getter(object(self, locals), locals); + function(scope, locals, self) { + return getter(self || object(scope, locals), locals); }, { - assign:function(self, value, locals) { - return setter(object(self, locals), field, value); + assign:function(scope, value, locals) { + return setter(object(scope, locals), field, value); } } ); } @@ -6283,18 +6350,18 @@ do { argsFn.push(expression()); } while (expect(',')); } consume(')'); - return function(self, locals){ + return function(scope, locals){ var args = [], - context = contextGetter ? contextGetter(self, locals) : self; + context = contextGetter ? contextGetter(scope, locals) : scope; for ( var i = 0; i < argsFn.length; i++) { - args.push(argsFn[i](self, locals)); + args.push(argsFn[i](scope, locals)); } - var fnPtr = fn(self, locals) || noop; + var fnPtr = fn(scope, locals, context) || noop; // IE stupidity! return fnPtr.apply ? fnPtr.apply(context, args) : fnPtr(args[0], args[1], args[2], args[3], args[4]); }; @@ -6332,12 +6399,11 @@ consume('}'); return function(self, locals){ var object = {}; for ( var i = 0; i < keyValues.length; i++) { var keyValue = keyValues[i]; - var value = keyValue.value(self, locals); - object[keyValue.key] = value; + object[keyValue.key] = keyValue.value(self, locals); } return object; }; } } @@ -6455,11 +6521,11 @@ } pathVal = pathVal.$$v; } return pathVal; }; -}; +} function getterFn(path, csp) { if (getterFnCache.hasOwnProperty(path)) { return getterFnCache[path]; } @@ -6470,11 +6536,11 @@ if (csp) { fn = (pathKeysLength < 6) ? cspSafeGetterFn(pathKeys[0], pathKeys[1], pathKeys[2], pathKeys[3], pathKeys[4]) : function(scope, locals) { - var i = 0, val + var i = 0, val; do { val = cspSafeGetterFn( pathKeys[i++], pathKeys[i++], pathKeys[i++], pathKeys[i++], pathKeys[i++] )(scope, locals); @@ -6535,13 +6601,13 @@ * * * @param {string} expression String expression to compile. * @returns {function(context, locals)} a function which represents the compiled expression: * - * * `context` – `{object}` – an object against which any expressions embedded in the strings + * * `context` – `{object}` – an object against which any expressions embedded in the strings * are evaluated against (tipically a scope object). - * * `locals` – `{object=}` – local variables context object, useful for overriding values in + * * `locals` – `{object=}` – local variables context object, useful for overriding values in * `context`. * * The return function also has an `assign` property, if the expression is assignable, which * allows one to set values to expressions. * @@ -6626,18 +6692,18 @@ * The purpose of the deferred object is to expose the associated Promise instance as well as APIs * that can be used for signaling the successful or unsuccessful completion of the task. * * **Methods** * - * - `resolve(value)` – resolves the derived promise with the `value`. If the value is a rejection + * - `resolve(value)` – resolves the derived promise with the `value`. If the value is a rejection * constructed via `$q.reject`, the promise will be rejected instead. - * - `reject(reason)` – rejects the derived promise with the `reason`. This is equivalent to + * - `reject(reason)` – rejects the derived promise with the `reason`. This is equivalent to * resolving it with a rejection constructed via `$q.reject`. * * **Properties** * - * - promise – `{Promise}` – promise object associated with this deferred. + * - promise – `{Promise}` – promise object associated with this deferred. * * * # The Promise API * * A new promise instance is created when a deferred instance is created and can be retrieved by @@ -6646,11 +6712,11 @@ * The purpose of the promise object is to allow for interested parties to get access to the result * of the deferred task when it completes. * * **Methods** * - * - `then(successCallback, errorCallback)` – regardless of when the promise was or will be resolved + * - `then(successCallback, errorCallback)` – regardless of when the promise was or will be resolved * or rejected calls one of the success or error callbacks asynchronously as soon as the result * is available. The callbacks are called with a single argument the result or rejection reason. * * This method *returns a new promise* which is resolved or rejected via the return value of the * `successCallback` or `errorCallback`. @@ -6683,31 +6749,31 @@ * - $q is integrated with the {@link ng.$rootScope.Scope} Scope model observation * mechanism in angular, which means faster propagation of resolution or rejection into your * models and avoiding unnecessary browser repaints, which would result in flickering UI. * - $q promises are recognized by the templating engine in angular, which means that in templates * you can treat promises attached to a scope as if they were the resulting values. - * - Q has many more features that $q, but that comes at a cost of bytes. $q is tiny, but contains + * - Q has many more features than $q, but that comes at a cost of bytes. $q is tiny, but contains * all the important functionality needed for common async tasks. - * + * * # Testing - * + * * <pre> * it('should simulate promise', inject(function($q, $rootScope) { * var deferred = $q.defer(); * var promise = deferred.promise; * var resolvedValue; - * + * * promise.then(function(value) { resolvedValue = value; }); * expect(resolvedValue).toBeUndefined(); - * + * * // Simulate resolving of promise * deferred.resolve(123); * // Note that the 'then' function does not get called synchronously. * // This is because we want the promise API to always be async, whether or not * // it got called synchronously or asynchronously. * expect(resolvedValue).toBeUndefined(); - * + * * // Propagate promise resolution to 'then' functions using $apply(). * $rootScope.$apply(); * expect(resolvedValue).toEqual(123); * }); * </pre> @@ -6878,14 +6944,11 @@ * Wraps an object that might be a value or a (3rd party) then-able promise into a $q promise. * This is useful when you are dealing with an object that might or might not be a promise, or if * the promise comes from a source that can't be trusted. * * @param {*} value Value or a promise - * @returns {Promise} Returns a single promise that will be resolved with an array of values, - * each value corresponding to the promise at the same index in the `promises` array. If any of - * the promises is resolved with a rejection, this resulting promise will be resolved with the - * same rejection. + * @returns {Promise} Returns a promise of the passed value or promise */ var when = function(value, callback, errback) { var result = defer(), done; @@ -7007,31 +7070,31 @@ * @param {Object} route Mapping information to be assigned to `$route.current` on route * match. * * Object properties: * - * - `controller` – `{(string|function()=}` – Controller fn that should be associated with newly + * - `controller` – `{(string|function()=}` – Controller fn that should be associated with newly * created scope or the name of a {@link angular.Module#controller registered controller} * if passed as a string. - * - `template` – `{string=}` – html template as a string that should be used by + * - `template` – `{string=}` – html template as a string that should be used by * {@link ng.directive:ngView ngView} or * {@link ng.directive:ngInclude ngInclude} directives. * this property takes precedence over `templateUrl`. - * - `templateUrl` – `{string=}` – path to an html template that should be used by + * - `templateUrl` – `{string=}` – path to an html template that should be used by * {@link ng.directive:ngView ngView}. * - `resolve` - `{Object.<string, function>=}` - An optional map of dependencies which should * be injected into the controller. If any of these dependencies are promises, they will be * resolved and converted to a value before the controller is instantiated and the * `$routeChangeSuccess` event is fired. The map object is: * - * - `key` – `{string}`: a name of a dependency to be injected into the controller. + * - `key` – `{string}`: a name of a dependency to be injected into the controller. * - `factory` - `{string|function}`: If `string` then it is an alias for a service. * Otherwise if function, then it is {@link api/AUTO.$injector#invoke injected} * and the return value is treated as the dependency. If the result is a promise, it is resolved * before its value is injected into the controller. * - * - `redirectTo` – {(string|function())=} – value to update + * - `redirectTo` – {(string|function())=} – value to update * {@link ng.$location $location} path with and trigger route redirection. * * If `redirectTo` is a function, it will be called with the following parameters: * * - `{Object.<string>}` - route parameters extracted from the current @@ -7238,12 +7301,13 @@ * @description * Broadcasted after a route dependencies are resolved. * {@link ng.directive:ngView ngView} listens for the directive * to instantiate the controller and render the view. * + * @param {Object} angularEvent Synthetic event object. * @param {Route} current Current route information. - * @param {Route} previous Previous route information. + * @param {Route|Undefined} previous Previous route information, or undefined if current is first route entered. */ /** * @ngdoc event * @name ng.$route#$routeChangeError @@ -7337,11 +7401,11 @@ function updateRoute() { var next = parseRoute(), last = $route.current; - if (next && last && next.$route === last.$route + if (next && last && next.$$route === last.$$route && equals(next.pathParams, last.pathParams) && !next.reloadOnSearch && !forceReload) { last.params = next.params; copy(last.params, $routeParams); $rootScope.$broadcast('$routeUpdate', last); } else if (next || last) { @@ -7416,11 +7480,11 @@ forEach(routes, function(route, path) { if (!match && (params = switchRouteMatcher($location.path(), path))) { match = inherit(route, { params: extend({}, $location.search(), params), pathParams: params}); - match.$route = route; + match.$$route = route; } }); // No route matched; fallback to "otherwise" route return match || routes[null] && inherit(routes[null], {params: {}, pathParams:{}}); } @@ -7476,26 +7540,26 @@ } /** * DESIGN NOTES * - * The design decisions behind the scope ware heavily favored for speed and memory consumption. + * The design decisions behind the scope are heavily favored for speed and memory consumption. * * The typical use of scope is to watch the expressions, which most of the time return the same * value as last time so we optimize the operation. * - * Closures construction is expensive from speed as well as memory: - * - no closures, instead ups prototypical inheritance for API + * Closures construction is expensive in terms of speed as well as memory: + * - No closures, instead use prototypical inheritance for API * - Internal state needs to be stored on scope directly, which means that private state is * exposed as $$____ properties * * Loop operations are optimized by using while(count--) { ... } * - this means that in order to keep the same order of execution as addition we have to add - * items to the array at the begging (shift) instead of at the end (push) + * items to the array at the beginning (shift) instead of at the end (push) * * Child scopes are created and removed often - * - Using array would be slow since inserts in meddle are expensive so we use linked list + * - Using an array would be slow since inserts in middle are expensive so we use linked list * * There are few watches then a lot of observers. This is why you don't want the observer to be * implemented in the same way as watch. Watch requires return of initialization function which * are expensive to construct. */ @@ -7513,11 +7577,11 @@ * @ngdoc function * @name ng.$rootScopeProvider#digestTtl * @methodOf ng.$rootScopeProvider * @description * - * Sets the number of digest iteration the scope should attempt to execute before giving up and + * Sets the number of digest iterations the scope should attempt to execute before giving up and * assuming that the model is unstable. * * The current default is 10 iterations. * * @param {number} limit The number of digest iterations. @@ -7793,11 +7857,11 @@ * @name ng.$rootScope.Scope#$digest * @methodOf ng.$rootScope.Scope * @function * * @description - * Process all of the {@link ng.$rootScope.Scope#$watch watchers} of the current scope and its children. + * Processes all of the {@link ng.$rootScope.Scope#$watch watchers} of the current scope and its children. * Because a {@link ng.$rootScope.Scope#$watch watcher}'s listener can change the model, the * `$digest()` keeps calling the {@link ng.$rootScope.Scope#$watch watchers} until no more listeners are * firing. This means that it is possible to get into an infinite loop. This function will throw * `'Maximum iteration limit exceeded.'` if the number of iterations exceeds 10. * @@ -8135,11 +8199,11 @@ * The event life cycle starts at the scope on which `$emit` was called. All * {@link ng.$rootScope.Scope#$on listeners} listening for `name` event on this scope get notified. * Afterwards, the event traverses upwards toward the root scope and calls all registered * listeners along the way. The event will stop propagating if one of the listeners cancels it. * - * Any exception emmited from the {@link ng.$rootScope.Scope#$on listeners} will be passed + * Any exception emitted from the {@link ng.$rootScope.Scope#$on listeners} will be passed * onto the {@link ng.$exceptionHandler $exceptionHandler} service. * * @param {string} name Event name to emit. * @param {...*} args Optional set of arguments which will be passed onto the event listeners. * @return {Object} Event object, see {@link ng.$rootScope.Scope#$on} @@ -8204,11 +8268,11 @@ * calls all registered listeners along the way. The event cannot be canceled. * * Any exception emmited from the {@link ng.$rootScope.Scope#$on listeners} will be passed * onto the {@link ng.$exceptionHandler $exceptionHandler} service. * - * @param {string} name Event name to emit. + * @param {string} name Event name to broadcast. * @param {...*} args Optional set of arguments which will be passed onto the event listeners. * @return {Object} Event object, see {@link ng.$rootScope.Scope#$on} */ $broadcast: function(name, args) { var target = this, @@ -8350,14 +8414,27 @@ * suffer from window globality. * * @example <doc:example> <doc:source> - <input ng-init="$window = $service('$window'); greeting='Hello World!'" type="text" ng-model="greeting" /> - <button ng-click="$window.alert(greeting)">ALERT</button> + <script> + function Ctrl($scope, $window) { + $scope.$window = $window; + $scope.greeting = 'Hello, World!'; + } + </script> + <div ng-controller="Ctrl"> + <input type="text" ng-model="greeting" /> + <button ng-click="$window.alert(greeting)">ALERT</button> + </div> </doc:source> <doc:scenario> + it('should display the greeting in the input box', function() { + input('greeting').enter('Hello, E2E Tests'); + // If we click the button it will block the test runner + // element(':button').click(); + }); </doc:scenario> </doc:example> */ function $WindowProvider(){ this.$get = valueFn(window); @@ -8506,27 +8583,27 @@ * @requires $q * @requires $injector * * @description * The `$http` service is a core Angular service that facilitates communication with the remote - * HTTP servers via browser's {@link https://developer.mozilla.org/en/xmlhttprequest + * HTTP servers via the browser's {@link https://developer.mozilla.org/en/xmlhttprequest * XMLHttpRequest} object or via {@link http://en.wikipedia.org/wiki/JSONP JSONP}. * * For unit testing applications that use `$http` service, see * {@link ngMock.$httpBackend $httpBackend mock}. * * For a higher level of abstraction, please check out the {@link ngResource.$resource * $resource} service. * * The $http API is based on the {@link ng.$q deferred/promise APIs} exposed by - * the $q service. While for simple usage patters this doesn't matter much, for advanced usage, - * it is important to familiarize yourself with these apis and guarantees they provide. + * the $q service. While for simple usage patterns this doesn't matter much, for advanced usage + * it is important to familiarize yourself with these APIs and the guarantees they provide. * * * # General usage - * The `$http` service is a function which takes a single argument — a configuration object — - * that is used to generate an http request and returns a {@link ng.$q promise} + * The `$http` service is a function which takes a single argument — a configuration object — + * that is used to generate an HTTP request and returns a {@link ng.$q promise} * with two $http specific methods: `success` and `error`. * * <pre> * $http({method: 'GET', url: '/someUrl'}). * success(function(data, status, headers, config) { @@ -8537,25 +8614,25 @@ * // called asynchronously if an error occurs * // or server returns response with an error status. * }); * </pre> * - * Since the returned value of calling the $http function is a Promise object, you can also use - * the `then` method to register callbacks, and these callbacks will receive a single argument – - * an object representing the response. See the api signature and type info below for more + * Since the returned value of calling the $http function is a `promise`, you can also use + * the `then` method to register callbacks, and these callbacks will receive a single argument – + * an object representing the response. See the API signature and type info below for more * details. * - * A response status code that falls in the [200, 300) range is considered a success status and + * A response status code between 200 and 299 is considered a success status and * will result in the success callback being called. Note that if the response is a redirect, * XMLHttpRequest will transparently follow it, meaning that the error callback will not be * called for such responses. * * # Shortcut methods * - * Since all invocation of the $http service require definition of the http method and url and - * POST and PUT requests require response body/data to be provided as well, shortcut methods - * were created to simplify using the api: + * Since all invocations of the $http service require passing in an HTTP method and URL, and + * POST/PUT requests require request data to be provided as well, shortcut methods + * were created: * * <pre> * $http.get('/someUrl').success(successCallback); * $http.post('/someUrl', data).success(successCallback); * </pre> @@ -8570,64 +8647,68 @@ * - {@link ng.$http#jsonp $http.jsonp} * * * # Setting HTTP Headers * - * The $http service will automatically add certain http headers to all requests. These defaults + * The $http service will automatically add certain HTTP headers to all requests. These defaults * can be fully configured by accessing the `$httpProvider.defaults.headers` configuration * object, which currently contains this default configuration: * * - `$httpProvider.defaults.headers.common` (headers that are common for all requests): * - `Accept: application/json, text/plain, * / *` * - `X-Requested-With: XMLHttpRequest` - * - `$httpProvider.defaults.headers.post`: (header defaults for HTTP POST requests) + * - `$httpProvider.defaults.headers.post`: (header defaults for POST requests) * - `Content-Type: application/json` - * - `$httpProvider.defaults.headers.put` (header defaults for HTTP PUT requests) + * - `$httpProvider.defaults.headers.put` (header defaults for PUT requests) * - `Content-Type: application/json` * - * To add or overwrite these defaults, simply add or remove a property from this configuration + * To add or overwrite these defaults, simply add or remove a property from these configuration * objects. To add headers for an HTTP method other than POST or PUT, simply add a new object - * with name equal to the lower-cased http method name, e.g. + * with the lowercased HTTP method name as the key, e.g. * `$httpProvider.defaults.headers.get['My-Header']='value'`. * - * Additionally, the defaults can be set at runtime via the `$http.defaults` object in a similar - * fassion as described above. + * Additionally, the defaults can be set at runtime via the `$http.defaults` object in the same + * fashion. * * * # Transforming Requests and Responses * * Both requests and responses can be transformed using transform functions. By default, Angular * applies these transformations: * * Request transformations: * - * - if the `data` property of the request config object contains an object, serialize it into + * - If the `data` property of the request configuration object contains an object, serialize it into * JSON format. * * Response transformations: * - * - if XSRF prefix is detected, strip it (see Security Considerations section below) - * - if json response is detected, deserialize it using a JSON parser + * - If XSRF prefix is detected, strip it (see Security Considerations section below). + * - If JSON response is detected, deserialize it using a JSON parser. * - * To override these transformation locally, specify transform functions as `transformRequest` - * and/or `transformResponse` properties of the config object. To globally override the default - * transforms, override the `$httpProvider.defaults.transformRequest` and - * `$httpProvider.defaults.transformResponse` properties of the `$httpProvider`. + * To globally augment or override the default transforms, modify the `$httpProvider.defaults.transformRequest` and + * `$httpProvider.defaults.transformResponse` properties. These properties are by default an + * array of transform functions, which allows you to `push` or `unshift` a new transformation function into the + * transformation chain. You can also decide to completely override any default transformations by assigning your + * transformation functions to these properties directly without the array wrapper. * + * Similarly, to locally override the request/response transforms, augment the `transformRequest` and/or + * `transformResponse` properties of the configuration object passed into `$http`. * + * * # Caching * - * To enable caching set the configuration property `cache` to `true`. When the cache is + * To enable caching, set the configuration property `cache` to `true`. When the cache is * enabled, `$http` stores the response from the server in local cache. Next time the * response is served from the cache without sending a request to the server. * * Note that even if the response is served from cache, delivery of the data is asynchronous in * the same way that real requests are. * - * If there are multiple GET requests for the same url that should be cached using the same + * If there are multiple GET requests for the same URL that should be cached using the same * cache, but the cache is not populated yet, only one request to the server will be made and - * the remaining requests will be fulfilled using the response for the first request. + * the remaining requests will be fulfilled using the response from the first request. * * * # Response interceptors * * Before you start creating interceptors, be sure to understand the @@ -8639,11 +8720,11 @@ * initiated these requests. The response interceptors leverage the {@link ng.$q * promise apis} to fulfil this need for both synchronous and asynchronous preprocessing. * * The interceptors are service factories that are registered with the $httpProvider by * adding them to the `$httpProvider.responseInterceptors` array. The factory is called and - * injected with dependencies (if specified) and returns the interceptor — a function that + * injected with dependencies (if specified) and returns the interceptor — a function that * takes a {@link ng.$q promise} and returns the original or a new promise. * * <pre> * // register the interceptor as a service * $provide.factory('myHttpInterceptor', function($q, dependency1, dependency2) { @@ -8675,22 +8756,22 @@ * # Security Considerations * * When designing web applications, consider security threats from: * * - {@link http://haacked.com/archive/2008/11/20/anatomy-of-a-subtle-json-vulnerability.aspx - * JSON Vulnerability} + * JSON vulnerability} * - {@link http://en.wikipedia.org/wiki/Cross-site_request_forgery XSRF} * * Both server and the client must cooperate in order to eliminate these threats. Angular comes * pre-configured with strategies that address these issues, but for this to work backend server * cooperation is required. * * ## JSON Vulnerability Protection * * A {@link http://haacked.com/archive/2008/11/20/anatomy-of-a-subtle-json-vulnerability.aspx - * JSON Vulnerability} allows third party web-site to turn your JSON resource URL into - * {@link http://en.wikipedia.org/wiki/JSON#JSONP JSONP} request under some conditions. To + * JSON vulnerability} allows third party website to turn your JSON resource URL into + * {@link http://en.wikipedia.org/wiki/JSONP JSONP} request under some conditions. To * counter this your server can prefix all JSON requests with following string `")]}',\n"`. * Angular will automatically strip the prefix before processing it as JSON. * * For example if your server needs to return: * <pre> @@ -8707,45 +8788,45 @@ * * * ## Cross Site Request Forgery (XSRF) Protection * * {@link http://en.wikipedia.org/wiki/Cross-site_request_forgery XSRF} is a technique by which - * an unauthorized site can gain your user's private data. Angular provides following mechanism + * an unauthorized site can gain your user's private data. Angular provides a mechanism * to counter XSRF. When performing XHR requests, the $http service reads a token from a cookie * called `XSRF-TOKEN` and sets it as the HTTP header `X-XSRF-TOKEN`. Since only JavaScript that * runs on your domain could read the cookie, your server can be assured that the XHR came from * JavaScript running on your domain. * * To take advantage of this, your server needs to set a token in a JavaScript readable session - * cookie called `XSRF-TOKEN` on first HTTP GET request. On subsequent non-GET requests the + * cookie called `XSRF-TOKEN` on the first HTTP GET request. On subsequent XHR requests the * server can verify that the cookie matches `X-XSRF-TOKEN` HTTP header, and therefore be sure - * that only JavaScript running on your domain could have read the token. The token must be - * unique for each user and must be verifiable by the server (to prevent the JavaScript making + * that only JavaScript running on your domain could have sent the request. The token must be + * unique for each user and must be verifiable by the server (to prevent the JavaScript from making * up its own tokens). We recommend that the token is a digest of your site's authentication - * cookie with {@link http://en.wikipedia.org/wiki/Rainbow_table salt for added security}. + * cookie with a {@link https://en.wikipedia.org/wiki/Salt_(cryptography) salt} for added security. * * * @param {object} config Object describing the request to be made and how it should be * processed. The object has following properties: * - * - **method** – `{string}` – HTTP method (e.g. 'GET', 'POST', etc) - * - **url** – `{string}` – Absolute or relative URL of the resource that is being requested. - * - **params** – `{Object.<string|Object>}` – Map of strings or objects which will be turned to + * - **method** – `{string}` – HTTP method (e.g. 'GET', 'POST', etc) + * - **url** – `{string}` – Absolute or relative URL of the resource that is being requested. + * - **params** – `{Object.<string|Object>}` – Map of strings or objects which will be turned to * `?key1=value1&key2=value2` after the url. If the value is not a string, it will be JSONified. - * - **data** – `{string|Object}` – Data to be sent as the request message data. - * - **headers** – `{Object}` – Map of strings representing HTTP headers to send to the server. - * - **transformRequest** – `{function(data, headersGetter)|Array.<function(data, headersGetter)>}` – + * - **data** – `{string|Object}` – Data to be sent as the request message data. + * - **headers** – `{Object}` – Map of strings representing HTTP headers to send to the server. + * - **transformRequest** – `{function(data, headersGetter)|Array.<function(data, headersGetter)>}` – * transform function or an array of such functions. The transform function takes the http * request body and headers and returns its transformed (typically serialized) version. - * - **transformResponse** – `{function(data, headersGetter)|Array.<function(data, headersGetter)>}` – + * - **transformResponse** – `{function(data, headersGetter)|Array.<function(data, headersGetter)>}` – * transform function or an array of such functions. The transform function takes the http * response body and headers and returns its transformed (typically deserialized) version. - * - **cache** – `{boolean|Cache}` – If true, a default $http cache will be used to cache the + * - **cache** – `{boolean|Cache}` – If true, a default $http cache will be used to cache the * GET request, otherwise if a cache instance built with * {@link ng.$cacheFactory $cacheFactory}, this cache will be used for * caching. - * - **timeout** – `{number}` – timeout in milliseconds. + * - **timeout** – `{number}` – timeout in milliseconds. * - **withCredentials** - `{boolean}` - whether to to set the `withCredentials` flag on the * XHR object. See {@link https://developer.mozilla.org/en/http_access_control#section_5 * requests with credentials} for more information. * * @returns {HttpPromise} Returns a {@link ng.$q promise} object with the @@ -8754,14 +8835,14 @@ * response object. The `success` and `error` methods take a single argument - a function that * will be called when the request succeeds or fails respectively. The arguments passed into * these functions are destructured representation of the response object passed into the * `then` method. The response object has these properties: * - * - **data** – `{string|Object}` – The response body transformed with the transform functions. - * - **status** – `{number}` – HTTP status code of the response. - * - **headers** – `{function([headerName])}` – Header getter function. - * - **config** – `{Object}` – The configuration object that was used to generate the request. + * - **data** – `{string|Object}` – The response body transformed with the transform functions. + * - **status** – `{number}` – HTTP status code of the response. + * - **headers** – `{function([headerName])}` – Header getter function. + * - **config** – `{Object}` – The configuration object that was used to generate the request. * * @property {Array.<Object>} pendingRequests Array of config objects for currently pending * requests. This is primarily meant to be used for debugging purposes. * * @@ -8897,11 +8978,11 @@ * @ngdoc method * @name ng.$http#get * @methodOf ng.$http * * @description - * Shortcut method to perform `GET` request + * Shortcut method to perform `GET` request. * * @param {string} url Relative or absolute URL specifying the destination of the request * @param {Object=} config Optional configuration object * @returns {HttpPromise} Future object */ @@ -8910,11 +8991,11 @@ * @ngdoc method * @name ng.$http#delete * @methodOf ng.$http * * @description - * Shortcut method to perform `DELETE` request + * Shortcut method to perform `DELETE` request. * * @param {string} url Relative or absolute URL specifying the destination of the request * @param {Object=} config Optional configuration object * @returns {HttpPromise} Future object */ @@ -8923,11 +9004,11 @@ * @ngdoc method * @name ng.$http#head * @methodOf ng.$http * * @description - * Shortcut method to perform `HEAD` request + * Shortcut method to perform `HEAD` request. * * @param {string} url Relative or absolute URL specifying the destination of the request * @param {Object=} config Optional configuration object * @returns {HttpPromise} Future object */ @@ -8936,11 +9017,11 @@ * @ngdoc method * @name ng.$http#jsonp * @methodOf ng.$http * * @description - * Shortcut method to perform `JSONP` request + * Shortcut method to perform `JSONP` request. * * @param {string} url Relative or absolute URL specifying the destination of the request. * Should contain `JSON_CALLBACK` string. * @param {Object=} config Optional configuration object * @returns {HttpPromise} Future object @@ -8951,11 +9032,11 @@ * @ngdoc method * @name ng.$http#post * @methodOf ng.$http * * @description - * Shortcut method to perform `POST` request + * Shortcut method to perform `POST` request. * * @param {string} url Relative or absolute URL specifying the destination of the request * @param {*} data Request content * @param {Object=} config Optional configuration object * @returns {HttpPromise} Future object @@ -8965,11 +9046,11 @@ * @ngdoc method * @name ng.$http#put * @methodOf ng.$http * * @description - * Shortcut method to perform `PUT` request + * Shortcut method to perform `PUT` request. * * @param {string} url Relative or absolute URL specifying the destination of the request * @param {*} data Request content * @param {Object=} config Optional configuration object * @returns {HttpPromise} Future object @@ -9017,11 +9098,11 @@ }); } /** - * Makes the request + * Makes the request. * * !!! ACCESSES CLOSURE VARS: * $httpBackend, $config, $log, $rootScope, defaultCache, $http.pendingRequests */ function sendReq(config, reqData, reqHeaders) { @@ -9127,10 +9208,11 @@ } }]; } + var XHR = window.XMLHttpRequest || function() { try { return new ActiveXObject("Msxml2.XMLHTTP.6.0"); } catch (e1) {} try { return new ActiveXObject("Msxml2.XMLHTTP.3.0"); } catch (e2) {} try { return new ActiveXObject("Msxml2.XMLHTTP"); } catch (e3) {} throw new Error("This browser does not support XMLHttpRequest."); @@ -9284,11 +9366,11 @@ * * @description * $locale service provides localization rules for various Angular components. As of right now the * only public api is: * - * * `id` – `{string}` – locale id formatted as `languageId-countryId` (e.g. `en-us`) + * * `id` – `{string}` – locale id formatted as `languageId-countryId` (e.g. `en-us`) */ function $LocaleProvider(){ this.$get = function() { return { id: 'en-us', @@ -9363,21 +9445,21 @@ * @description * Angular's wrapper for `window.setTimeout`. The `fn` function is wrapped into a try/catch * block and delegates any exceptions to * {@link ng.$exceptionHandler $exceptionHandler} service. * - * The return value of registering a timeout function is a promise which will be resolved when + * The return value of registering a timeout function is a promise, which will be resolved when * the timeout is reached and the timeout function is executed. * - * To cancel a the timeout request, call `$timeout.cancel(promise)`. + * To cancel a timeout request, call `$timeout.cancel(promise)`. * * In tests you can use {@link ngMock.$timeout `$timeout.flush()`} to * synchronously flush the queue of deferred functions. * - * @param {function()} fn A function, who's execution should be delayed. + * @param {function()} fn A function, whose execution should be delayed. * @param {number=} [delay=0] Delay in milliseconds. - * @param {boolean=} [invokeApply=true] If set to false skips model dirty checking, otherwise + * @param {boolean=} [invokeApply=true] If set to `false` skips model dirty checking, otherwise * will invoke `fn` within the {@link ng.$rootScope.Scope#$apply $apply} block. * @returns {Promise} Promise that will be resolved when the timeout is reached. The value this * promise will be resolved with is the return value of the `fn` function. */ function timeout(fn, delay, invokeApply) { @@ -9413,11 +9495,11 @@ * @ngdoc function * @name ng.$timeout#cancel * @methodOf ng.$timeout * * @description - * Cancels a task associated with the `promise`. As a result of this the promise will be + * Cancels a task associated with the `promise`. As a result of this, the promise will be * resolved with a rejection. * * @param {Promise=} promise Promise returned by the `$timeout` function. * @returns {boolean} Returns `true` if the task hasn't executed yet and was successfully * canceled. @@ -9439,11 +9521,11 @@ * @name ng.$filterProvider * @description * * Filters are just functions which transform input to an output. However filters need to be Dependency Injected. To * achieve this a filter definition consists of a factory function which is annotated with dependencies and is - * responsible for creating a the filter function. + * responsible for creating a filter function. * * <pre> * // Filter registration * function MyModule($provide, $filterProvider) { * // create a service to demonstrate injection (not always needed) @@ -9501,11 +9583,11 @@ * @description * Filters are used for formatting data displayed to the user. * * The general syntax in templates is as follows: * - * {{ expression | [ filter_name ] }} + * {{ expression [| filter_name[:parameter_value] ... ] }} * * @param {String} name Name of the filter function to retrieve * @return {Function} the filter function */ $FilterProvider.$inject = ['$provide']; @@ -9577,26 +9659,26 @@ {name:'Adam', phone:'555-5678'}, {name:'Julie', phone:'555-8765'}]"></div> Search: <input ng-model="searchText"> <table id="searchTextResults"> - <tr><th>Name</th><th>Phone</th><tr> + <tr><th>Name</th><th>Phone</th></tr> <tr ng-repeat="friend in friends | filter:searchText"> <td>{{friend.name}}</td> <td>{{friend.phone}}</td> - <tr> + </tr> </table> <hr> Any: <input ng-model="search.$"> <br> Name only <input ng-model="search.name"><br> - Phone only <input ng-model="search.phone"Ã¥><br> + Phone only <input ng-model="search.phone"><br> <table id="searchObjResults"> - <tr><th>Name</th><th>Phone</th><tr> + <tr><th>Name</th><th>Phone</th></tr> <tr ng-repeat="friend in friends | filter:search"> <td>{{friend.name}}</td> <td>{{friend.phone}}</td> - <tr> + </tr> </table> </doc:source> <doc:scenario> it('should search across all fields when filtering with a string', function() { input('searchText').enter('m'); @@ -9760,11 +9842,11 @@ * * If the input is not a number an empty string is returned. * * @param {number|string} number Number to format. * @param {(number|string)=} [fractionSize=2] Number of decimal places to round the number to. - * @returns {string} Number rounded to decimalPlaces and places a “,” after each third digit. + * @returns {string} Number rounded to decimalPlaces and places a “,” after each third digit. * * @example <doc:example> <doc:source> <script> @@ -9889,10 +9971,11 @@ return neg + num; } function dateGetter(name, size, offset, trim) { + offset = offset || 0; return function(date) { var value = date['get' + name](); if (offset > 0 || value > -offset) value += offset; if (value === 0 && offset == -12 ) value = 12; @@ -9911,11 +9994,12 @@ function timeZoneGetter(date) { var zone = -1 * date.getTimezoneOffset(); var paddedZone = (zone >= 0) ? "+" : ""; - paddedZone += padNumber(zone / 60, 2) + padNumber(Math.abs(zone % 60), 2); + paddedZone += padNumber(Math[zone > 0 ? 'floor' : 'ceil'](zone / 60), 2) + + padNumber(Math.abs(zone % 60), 2); return paddedZone; } function ampmGetter(date, formats) { @@ -9977,11 +10061,11 @@ * * `'mm'`: Minute in hour, padded (00-59) * * `'m'`: Minute in hour (0-59) * * `'ss'`: Second in minute, padded (00-59) * * `'s'`: Second in minute (0-59) * * `'a'`: am/pm marker - * * `'Z'`: 4 digit (+sign) representation of the timezone offset (-1200-1200) + * * `'Z'`: 4 digit (+sign) representation of the timezone offset (-1200-+1200) * * `format` string can also be one of the following predefined * {@link guide/i18n localizable formats}: * * * `'medium'`: equivalent to `'MMM d, y h:mm:ss a'` for en_US locale @@ -9998,11 +10082,11 @@ * `format` string can contain literal values. These need to be quoted with single quotes (e.g. * `"h 'in the morning'"`). In order to output single quote, use two single quotes in a sequence * (e.g. `"h o''clock"`). * * @param {(Date|number|string)} date Date to format either as Date object, milliseconds (string or - * number) or various ISO 8601 datetime string formats (e.g. yyyy-MM-ddTHH:mm:ss.SSSZ and it's + * number) or various ISO 8601 datetime string formats (e.g. yyyy-MM-ddTHH:mm:ss.SSSZ and its * shorter versions like yyyy-MM-ddTHH:mmZ, yyyy-MM-dd or yyyyMMddTHHmmssZ). If no timezone is * specified in the string input, the time is considered to be in the local timezone. * @param {string=} format Formatting rules (see Description). If not specified, * `mediumDate` is used. * @returns {string} Formatted string or the input if input is not recognized as date/millis. @@ -10289,16 +10373,16 @@ <tr> <th><a href="" ng-click="predicate = 'name'; reverse=false">Name</a> (<a href ng-click="predicate = '-name'; reverse=false">^</a>)</th> <th><a href="" ng-click="predicate = 'phone'; reverse=!reverse">Phone Number</a></th> <th><a href="" ng-click="predicate = 'age'; reverse=!reverse">Age</a></th> - <tr> + </tr> <tr ng-repeat="friend in friends | orderBy:predicate:reverse"> <td>{{friend.name}}</td> <td>{{friend.phone}}</td> <td>{{friend.age}}</td> - <tr> + </tr> </table> </div> </doc:source> <doc:scenario> it('should be reverse ordered by aged', function() { @@ -10763,11 +10847,11 @@ * @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`), + * - 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. * * @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. @@ -11116,12 +11200,12 @@ * Text input with number validation and transformation. Sets the `number` validation * error if not a valid number. * * @param {string} ngModel Assignable angular expression to data-bind to. * @param {string=} name Property name of the form under which the control is published. - * @param {string=} min Sets the `min` validation error key if the value entered is less then `min`. - * @param {string=} max Sets the `max` validation error key if the value entered is greater then `min`. + * @param {string=} min Sets the `min` validation error key if the value entered is less than `min`. + * @param {string=} max Sets the `max` validation error key if the value entered is greater than `max`. * @param {string=} required Sets `required` validation error key if the value is not entered. * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to * the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of * `required` when you want to data-bind to the `required` attribute. * @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than @@ -11429,27 +11513,36 @@ if ($sniffer.hasEvent('input')) { element.bind('input', listener); } else { var timeout; + var deferListener = function() { + if (!timeout) { + timeout = $browser.defer(function() { + listener(); + timeout = null; + }); + } + }; + element.bind('keydown', function(event) { var key = event.keyCode; // ignore // command modifiers arrows if (key === 91 || (15 < key && key < 19) || (37 <= key && key <= 40)) return; - if (!timeout) { - timeout = $browser.defer(function() { - listener(); - timeout = null; - }); - } + deferListener(); }); // if user paste into input using mouse, we need "change" event to catch it element.bind('change', listener); + + // if user modifies input value using context menu in IE, we need "paste" and "cut" events to catch it + if ($sniffer.hasEvent('paste')) { + element.bind('paste cut', deferListener); + } } ctrl.$render = function() { element.val(isEmpty(ctrl.$viewValue) ? '' : ctrl.$viewValue); @@ -11744,11 +11837,11 @@ <hr> <tt>user = {{user}}</tt><br/> <tt>myForm.userName.$valid = {{myForm.userName.$valid}}</tt><br> <tt>myForm.userName.$error = {{myForm.userName.$error}}</tt><br> <tt>myForm.lastName.$valid = {{myForm.lastName.$valid}}</tt><br> - <tt>myForm.userName.$error = {{myForm.lastName.$error}}</tt><br> + <tt>myForm.lastName.$error = {{myForm.lastName.$error}}</tt><br> <tt>myForm.$valid = {{myForm.$valid}}</tt><br> <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br> <tt>myForm.$error.minlength = {{!!myForm.$error.minlength}}</tt><br> <tt>myForm.$error.maxlength = {{!!myForm.$error.maxlength}}</tt><br> </div> @@ -12007,11 +12100,11 @@ * * This method should be called from within a DOM event handler. * For example {@link ng.directive:input input} or * {@link ng.directive:select select} directives call it. * - * It internally calls all `formatters` and if resulted value is valid, updates the model and + * It internally calls all `parsers` and if resulted value is valid, updates the model and * calls all registered change listeners. * * @param {string} value Value from the view. */ this.$setViewValue = function(value) { @@ -12313,11 +12406,11 @@ * expression changes. * * Typically, you don't use `ngBind` directly, but instead you use the double curly markup like * `{{ expression }}` which is similar but less verbose. * - * Once scenario in which the use of `ngBind` is prefered over `{{ expression }}` binding is when + * One scenario in which the use of `ngBind` is preferred over `{{ expression }}` binding is when * it's desirable to put bindings into template that is momentarily displayed by the browser in its * raw state before Angular compiles it. Since `ngBind` is an element attribute, it makes the * bindings invisible to the user while the page is loading. * * An alternative solution to this problem would be using the @@ -12454,13 +12547,13 @@ }); if (name !== 'ngClass') { scope.$watch('$index', function($index, old$index) { - var mod = $index % 2; - if (mod !== old$index % 2) { - if (mod == selector) { + var mod = $index & 1; + if (mod !== old$index & 1) { + if (mod === selector) { addClass(scope.$eval(attr[name])); } else { removeClass(scope.$eval(attr[name])); } } @@ -12468,16 +12561,16 @@ } function ngClassWatchAction(newVal) { if (selector === true || scope.$index % 2 === selector) { - if (oldVal && (newVal !== oldVal)) { + if (oldVal && !equals(newVal,oldVal)) { removeClass(oldVal); } addClass(newVal); } - oldVal = newVal; + oldVal = copy(newVal); } function removeClass(classVal) { if (isObject(classVal) && !isArray(classVal)) { @@ -12599,11 +12692,11 @@ /** * @ngdoc directive * @name ng.directive:ngClassEven * * @description - * The `ngClassOdd` and `ngClassEven` works exactly as + * The `ngClassOdd` and `ngClassEven` directives work exactly as * {@link ng.directive:ngClass ngClass}, except it works in * conjunction with `ngRepeat` and takes affect only on odd (even) rows. * * This directive can be applied only within a scope of an * {@link ng.directive:ngRepeat ngRepeat}. @@ -12657,11 +12750,11 @@ * * `ngCloak` works in cooperation with a css rule that is embedded within `angular.js` and * `angular.min.js` files. Following is the css rule: * * <pre> - * [ng\:cloak], [ng-cloak], .ng-cloak { + * [ng\:cloak], [ng-cloak], [data-ng-cloak], [x-ng-cloak], .ng-cloak, .x-ng-cloak { * display: none; * } * </pre> * * When this css rule is loaded by the browser, all html elements (including their children) that @@ -12711,17 +12804,16 @@ * The `ngController` directive assigns behavior to a scope. This is a key aspect of how angular * supports the principles behind the Model-View-Controller design pattern. * * MVC components in angular: * - * * Model — The Model is data in scope properties; scopes are attached to the DOM. - * * View — The template (HTML with data bindings) is rendered into the View. - * * Controller — The `ngController` directive specifies a Controller class; the class has + * * Model — The Model is data in scope properties; scopes are attached to the DOM. + * * View — The template (HTML with data bindings) is rendered into the View. + * * Controller — The `ngController` directive specifies a Controller class; the class has * methods that typically express the business logic behind the application. * - * Note that an alternative way to define controllers is via the `{@link ng.$route}` - * service. + * Note that an alternative way to define controllers is via the {@link ng.$route $route} service. * * @element ANY * @scope * @param {expression} ngController Name of a globally accessible constructor function or an * {@link guide/expression expression} that on the current scope evaluates to a @@ -12808,20 +12900,36 @@ /** * @ngdoc directive * @name ng.directive:ngCsp * @priority 1000 * + * @element html * @description * Enables [CSP (Content Security Policy)](https://developer.mozilla.org/en/Security/CSP) support. - * This directive should be used on the root element of the application (typically the `<html>` - * element or other element with the {@link ng.directive:ngApp ngApp} - * directive). * - * If enabled the performance of template expression evaluator will suffer slightly, so don't enable - * this mode unless you need it. + * This is necessary when developing things like Google Chrome Extensions. * - * @element html + * CSP forbids apps to use `eval` or `Function(string)` generated functions (among other things). + * For us to be compatible, we just need to implement the "getterFn" in $parse without violating + * any of these restrictions. + * + * AngularJS uses `Function(string)` generated functions as a speed optimization. By applying `ngCsp` + * it is be possible to opt into the CSP compatible mode. When this mode is on AngularJS will + * evaluate all expressions up to 30% slower than in non-CSP mode, but no security violations will + * be raised. + * + * In order to use this feature put `ngCsp` directive on the root element of the application. + * + * @example + * This example shows how to apply the `ngCsp` directive to the `html` tag. + <pre> + <!doctype html> + <html ng-app ng-csp> + ... + ... + </html> + </pre> */ var ngCspDirective = ['$sniffer', function($sniffer) { return { priority: 1000, @@ -13442,11 +13550,11 @@ var value = parseFloat(scope.$eval(numberExp)); if (!isNaN(value)) { //if explicit number rule such as 1, 2, 3... is defined, just use it. Otherwise, //check it against pluralization rules in $locale service - if (!whens[value]) value = $locale.pluralCat(value - offset); + if (!(value in whens)) value = $locale.pluralCat(value - offset); return whensExpFns[value](scope, element, true); } else { return ''; } }, function ngPluralizeWatchAction(newVal) { @@ -13465,28 +13573,28 @@ * instance gets its own scope, where the given loop variable is set to the current collection item, * and `$index` is set to the item index or key. * * Special properties are exposed on the local scope of each template instance, including: * - * * `$index` – `{number}` – iterator offset of the repeated element (0..length-1) - * * `$first` – `{boolean}` – true if the repeated element is first in the iterator. - * * `$middle` – `{boolean}` – true if the repeated element is between the first and last in the iterator. - * * `$last` – `{boolean}` – true if the repeated element is last in the iterator. + * * `$index` – `{number}` – iterator offset of the repeated element (0..length-1) + * * `$first` – `{boolean}` – true if the repeated element is first in the iterator. + * * `$middle` – `{boolean}` – true if the repeated element is between the first and last in the iterator. + * * `$last` – `{boolean}` – true if the repeated element is last in the iterator. * * * @element ANY * @scope * @priority 1000 * @param {repeat_expression} ngRepeat The expression indicating how to enumerate a collection. Two * formats are currently supported: * - * * `variable in expression` – where variable is the user defined loop variable and `expression` + * * `variable in expression` – where variable is the user defined loop variable and `expression` * is a scope expression giving the collection to enumerate. * * For example: `track in cd.tracks`. * - * * `(key, value) in expression` – where `key` and `value` can be any user defined identifiers, + * * `(key, value) in expression` – where `key` and `value` can be any user defined identifiers, * and `expression` is the scope expression giving the collection to enumerate. * * For example: `(name, age) in {'adam':10, 'amalie':12}`. * * @example @@ -13550,11 +13658,11 @@ collection = scope.$eval(rhs), cursor = iterStartElement, // current position of the node // Same as lastOrder but it has the current state. It will become the // lastOrder on the next iteration. nextOrder = new HashQueueMap(), - arrayLength, + arrayBound, childScope, key, value, // key/value of iteration array, last; // last object information {scope, element, index} @@ -13571,11 +13679,11 @@ array.sort(); } else { array = collection || []; } - arrayLength = array.length; + arrayBound = array.length-1; // we are not using forEach for perf reasons (trying to avoid #call) for (index = 0, length = array.length; index < length; index++) { key = (collection === array) ? index : array[index]; value = collection[key]; @@ -13608,11 +13716,11 @@ childScope[valueIdent] = value; if (keyIdent) childScope[keyIdent] = key; childScope.$index = index; childScope.$first = (index === 0); - childScope.$last = (index === (arrayLength - 1)); + childScope.$last = (index === arrayBound); childScope.$middle = !(childScope.$first || childScope.$last); if (!last) { linker(childScope, function(clone){ cursor.after(clone); @@ -13775,15 +13883,17 @@ * @restrict EA * * @description * Conditionally change the DOM structure. * - * @usageContent - * <ANY ng-switch-when="matchValue1">...</ANY> + * @usage + * <ANY ng-switch="expression"> + * <ANY ng-switch-when="matchValue1">...</ANY> * <ANY ng-switch-when="matchValue2">...</ANY> * ... * <ANY ng-switch-default>...</ANY> + * </ANY> * * @scope * @param {*} ngSwitch|on expression to match against <tt>ng-switch-when</tt>. * @paramDescription * On child elments add: @@ -14159,11 +14269,11 @@ * # `ngOptions` * * Optionally `ngOptions` attribute can be used to dynamically generate a list of `<option>` * elements for a `<select>` element using an array or an object obtained by evaluating the * `ngOptions` expression. - *˝˝ + *˝˝ * When an item in the select menu is select, the value of array element or object property * represented by the selected option will be bound to the model identified by the `ngModel` * directive of the parent select element. * * Optionally, a single hard-coded `<option>` element, with the value set to an empty string, can @@ -14173,11 +14283,12 @@ * Note: `ngOptions` provides iterator facility for `<option>` element which should be used instead * of {@link ng.directive:ngRepeat ngRepeat} when you want the * `select` model to be bound to a non-string value. This is because an option element can currently * be bound to string values only. * - * @param {string} name assignable expression to data-bind to. + * @param {string} ngModel Assignable angular expression to data-bind to. + * @param {string=} name Property name of the form under which the control is published. * @param {string=} required The control is considered valid only if value is entered. * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to * the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of * `required` when you want to data-bind to the `required` attribute. * @param {comprehension_expression=} ngOptions in one of the following forms: @@ -14268,11 +14379,11 @@ </doc:example> */ var ngOptionsDirective = valueFn({ terminal: true }); var selectDirective = ['$compile', '$parse', function($compile, $parse) { - //00001111100000000000222200000000000000000000003333000000000000044444444444444444000000000555555555555555550000000666666666666666660000000000000007777 + //0000111110000000000022220000000000000000000000333300000000000000444444444444444440000000005555555555555555500000006666666666666666600000000000000077770 var NG_OPTIONS_REGEXP = /^\s*(.*?)(?:\s+as\s+(.*?))?(?:\s+group\s+by\s+(.*))?\s+for\s+(?:([\$\w][\$\w\d]*)|(?:\(\s*([\$\w][\$\w\d]*)\s*,\s*([\$\w][\$\w\d]*)\s*\)))\s+in\s+(.*)$/, nullModelCtrl = {$setViewValue: noop}; return { restrict: 'E', @@ -14540,14 +14651,10 @@ element, label; if (multiple) { selectedSet = new HashMap(modelValue); - } else if (modelValue === null || nullOption) { - // if we are not multiselect, and we are null then we have to add the nullOption - optionGroups[''].push({selected:modelValue === null, id:'', label:''}); - selectedSet = true; } // We now build up the list of options we need (we merge later) for (index = 0; length = keys.length, index < length; index++) { locals[valueName] = values[keyName ? locals[keyName]=keys[index]:index]; @@ -14568,13 +14675,18 @@ id: keyName ? keys[index] : index, // either the index into array or key from object label: label, selected: selected // determine if we should be selected }); } - if (!multiple && !selectedSet) { - // nothing was selected, we have to insert the undefined item - optionGroups[''].unshift({id:'?', label:'', selected:true}); + if (!multiple) { + if (nullOption || modelValue === null) { + // insert null option if we have a placeholder, or the model is null + optionGroups[''].unshift({id:'', label:'', selected:!selectedSet}); + } else if (!selectedSet) { + // option could not be found, we have to insert the undefined item + optionGroups[''].unshift({id:'?', label:'', selected:true}); + } } // Now we need to update the list of DOM nodes to match the optionGroups we computed above for (groupIndex = 0, groupLength = optionGroupNames.length; groupIndex < groupLength; @@ -14614,11 +14726,12 @@ lastElement.text(existingOption.label = option.label); } if (existingOption.id !== option.id) { lastElement.val(existingOption.id = option.id); } - if (existingOption.element.selected !== option.selected) { + // lastElement.prop('selected') provided by jQuery has side-effects + if (lastElement[0].selected !== option.selected) { lastElement.prop('selected', (existingOption.selected = option.selected)); } } else { // grow elements @@ -14717,9 +14830,10 @@ var styleDirective = valueFn({ restrict: 'E', terminal: true }); + //try to bind to jquery now so that one can write angular.element().read() //but we will rebind on bootstrap again. bindJQuery(); publishExternalAPI(angular); \ No newline at end of file