diff --git a/resources/assets/scripts/base/angular.js b/resources/assets/scripts/base/angular.js index a924ef52..40eedc0e 100644 --- a/resources/assets/scripts/base/angular.js +++ b/resources/assets/scripts/base/angular.js @@ -1,6 +1,6 @@ /** - * @license AngularJS v1.2.0 - * (c) 2010-2012 Google, Inc. http://angularjs.org + * @license AngularJS v1.2.29 + * (c) 2010-2014 Google, Inc. http://angularjs.org * License: MIT */ (function(window, document, undefined) {'use strict'; @@ -30,7 +30,7 @@ * should all be static strings, not variables or general expressions. * * @param {string} module The namespace to use for the new minErr instance. - * @returns {function(string, string, ...): Error} instance + * @returns {function(code:string, template:string, ...templateArgs): Error} minErr instance */ function minErr(module) { @@ -40,11 +40,11 @@ function minErr(module) { template = arguments[1], templateArgs = arguments, stringify = function (obj) { - if (isFunction(obj)) { + if (typeof obj === 'function') { return obj.toString().replace(/ \{[\s\S]*$/, ''); - } else if (isUndefined(obj)) { + } else if (typeof obj === 'undefined') { return 'undefined'; - } else if (!isString(obj)) { + } else if (typeof obj !== 'string') { return JSON.stringify(obj); } return obj; @@ -56,11 +56,11 @@ function minErr(module) { if (index + 2 < templateArgs.length) { arg = templateArgs[index + 2]; - if (isFunction(arg)) { + if (typeof arg === 'function') { return arg.toString().replace(/ ?\{[\s\S]*$/, ''); - } else if (isUndefined(arg)) { + } else if (typeof arg === 'undefined') { return 'undefined'; - } else if (!isString(arg)) { + } else if (typeof arg !== 'string') { return toJson(arg); } return arg; @@ -68,7 +68,7 @@ function minErr(module) { return match; }); - message = message + '\nhttp://errors.angularjs.org/' + version.full + '/' + + message = message + '\nhttp://errors.angularjs.org/1.2.29/' + (module ? module + '/' : '') + code; for (i = 2; i < arguments.length; i++) { message = message + (i == 2 ? '?' : '&') + 'p' + (i-2) + '=' + @@ -80,107 +80,129 @@ function minErr(module) { } /* We need to tell jshint what variables are being exported */ -/* global - -angular, - -msie, - -jqLite, - -jQuery, - -slice, - -push, - -toString, - -ngMinErr, - -_angular, - -angularModule, - -nodeName_, - -uid, - - -lowercase, - -uppercase, - -manualLowercase, - -manualUppercase, - -nodeName_, - -isArrayLike, - -forEach, - -sortedKeys, - -forEachSorted, - -reverseParams, - -nextUid, - -setHashKey, - -extend, - -int, - -inherit, - -noop, - -identity, - -valueFn, - -isUndefined, - -isDefined, - -isObject, - -isString, - -isNumber, - -isDate, - -isArray, - -isFunction, - -isRegExp, - -isWindow, - -isScope, - -isFile, - -isBoolean, - -trim, - -isElement, - -makeMap, - -map, - -size, - -includes, - -indexOf, - -arrayRemove, - -isLeafNode, - -copy, - -shallowCopy, - -equals, - -csp, - -concat, - -sliceArgs, - -bind, - -toJsonReplacer, - -toJson, - -fromJson, - -toBoolean, - -startingTag, - -tryDecodeURIComponent, - -parseKeyValue, - -toKeyValue, - -encodeUriSegment, - -encodeUriQuery, - -angularInit, - -bootstrap, - -snake_case, - -bindJQuery, - -assertArg, - -assertArgFn, - -assertNotHasOwnProperty, - -getter, - -getBlockElements +/* global angular: true, + msie: true, + jqLite: true, + jQuery: true, + slice: true, + push: true, + toString: true, + ngMinErr: true, + angularModule: true, + nodeName_: true, + uid: true, + VALIDITY_STATE_PROPERTY: true, + lowercase: true, + uppercase: true, + manualLowercase: true, + manualUppercase: true, + nodeName_: true, + isArrayLike: true, + forEach: true, + sortedKeys: true, + forEachSorted: true, + reverseParams: true, + nextUid: true, + setHashKey: true, + extend: true, + int: true, + inherit: true, + noop: true, + identity: true, + valueFn: true, + isUndefined: true, + isDefined: true, + isObject: true, + isString: true, + isNumber: true, + isDate: true, + isArray: true, + isFunction: true, + isRegExp: true, + isWindow: true, + isScope: true, + isFile: true, + isBlob: true, + isBoolean: true, + isPromiseLike: true, + trim: true, + isElement: true, + makeMap: true, + map: true, + size: true, + includes: true, + indexOf: true, + arrayRemove: true, + isLeafNode: true, + copy: true, + shallowCopy: true, + equals: true, + csp: true, + concat: true, + sliceArgs: true, + bind: true, + toJsonReplacer: true, + toJson: true, + fromJson: true, + toBoolean: true, + startingTag: true, + tryDecodeURIComponent: true, + parseKeyValue: true, + toKeyValue: true, + encodeUriSegment: true, + encodeUriQuery: true, + angularInit: true, + bootstrap: true, + snake_case: true, + bindJQuery: true, + assertArg: true, + assertArgFn: true, + assertNotHasOwnProperty: true, + getter: true, + getBlockElements: true, + hasOwnProperty: true, */ //////////////////////////////////// +/** + * @ngdoc module + * @name ng + * @module ng + * @description + * + * # ng (core module) + * The ng module is loaded by default when an AngularJS application is started. The module itself + * contains the essential components for an AngularJS application to function. The table below + * lists a high level breakdown of each of the services/factories, filters, directives and testing + * components available within this core module. + * + *
+ */ + +// The name of a form control's ValidityState property. +// This is used so that it's possible for internal tests to create mock ValidityStates. +var VALIDITY_STATE_PROPERTY = 'validity'; + /** * @ngdoc function * @name angular.lowercase - * @function + * @module ng + * @kind function * * @description Converts the specified string to lowercase. * @param {string} string String to be converted to lowercase. * @returns {string} Lowercased string. */ var lowercase = function(string){return isString(string) ? string.toLowerCase() : string;}; - +var hasOwnProperty = Object.prototype.hasOwnProperty; /** * @ngdoc function * @name angular.uppercase - * @function + * @module ng + * @kind function * * @description Converts the specified string to uppercase. * @param {string} string String to be converted to uppercase. @@ -212,8 +234,8 @@ if ('i' !== 'I'.toLowerCase()) { } -var /** holds major version number for IE or NaN for real browsers */ - msie, +var + msie, // holds major version number for IE, or NaN if UA is not IE. jqLite, // delay binding since jQuery could be loaded after us. jQuery, // delay binding slice = [].slice, @@ -221,8 +243,6 @@ var /** holds major version number for IE or NaN for real browsers */ toString = Object.prototype.toString, ngMinErr = minErr('ng'), - - _angular = window.angular, /** @name angular */ angular = window.angular || (window.angular = {}), angularModule, @@ -263,7 +283,8 @@ function isArrayLike(obj) { /** * @ngdoc function * @name angular.forEach - * @function + * @module ng + * @kind function * * @description * Invokes the `iterator` function once for each item in `obj` collection, which can be either an @@ -271,16 +292,17 @@ function isArrayLike(obj) { * is the value of an object property or an array element and `key` is the object property key or * array element index. Specifying a `context` for the function is optional. * - * Note: this function was previously known as `angular.foreach`. + * It is worth noting that `.forEach` does not iterate over inherited properties because it filters + * using the `hasOwnProperty` method. * -+ ```js var values = {name: 'misko', gender: 'male'}; var log = []; - angular.forEach(values, function(value, key){ + angular.forEach(values, function(value, key) { this.push(key + ': ' + value); }, log); - expect(log).toEqual(['name: misko', 'gender:male']); -+ expect(log).toEqual(['name: misko', 'gender: male']); + ``` * * @param {Object|Array} obj Object to iterate over. * @param {Function} iterator Iterator function. @@ -290,17 +312,20 @@ function isArrayLike(obj) { function forEach(obj, iterator, context) { var key; if (obj) { - if (isFunction(obj)){ + if (isFunction(obj)) { for (key in obj) { - if (key != 'prototype' && key != 'length' && key != 'name' && obj.hasOwnProperty(key)) { + // Need to check if hasOwnProperty exists, + // as on IE8 the result of querySelectorAll is an object without a hasOwnProperty function + if (key != 'prototype' && key != 'length' && key != 'name' && (!obj.hasOwnProperty || obj.hasOwnProperty(key))) { iterator.call(context, obj[key], key); } } - } else if (obj.forEach && obj.forEach !== forEach) { - obj.forEach(iterator, context); - } else if (isArrayLike(obj)) { - for (key = 0; key < obj.length; key++) + } else if (isArray(obj) || isArrayLike(obj)) { + for (key = 0; key < obj.length; key++) { iterator.call(context, obj[key], key); + } + } else if (obj.forEach && obj.forEach !== forEach) { + obj.forEach(iterator, context); } else { for (key in obj) { if (obj.hasOwnProperty(key)) { @@ -346,7 +371,7 @@ function reverseParams(iteratorFn) { * the number string gets longer over time, and it can also overflow, where as the nextId * will grow much slower, it is a string, and it will never overflow. * - * @returns an unique alpha-numeric string + * @returns {string} an unique alpha-numeric string */ function nextUid() { var index = uid.length; @@ -388,10 +413,11 @@ function setHashKey(obj, h) { /** * @ngdoc function * @name angular.extend - * @function + * @module ng + * @kind function * * @description - * Extends the destination object `dst` by copying all of the properties from the `src` object(s) + * Extends the destination object `dst` by copying own enumerable properties from the `src` object(s) * to `dst`. You can specify multiple `src` objects. * * @param {Object} dst Destination object. @@ -400,9 +426,9 @@ function setHashKey(obj, h) { */ function extend(dst) { var h = dst.$$hashKey; - forEach(arguments, function(obj){ + forEach(arguments, function(obj) { if (obj !== dst) { - forEach(obj, function(value, key){ + forEach(obj, function(value, key) { dst[key] = value; }); } @@ -424,17 +450,18 @@ function inherit(parent, extra) { /** * @ngdoc function * @name angular.noop - * @function + * @module ng + * @kind function * * @description * A function that performs no operations. This function can be useful when writing code in the * functional style. -
+ ```js function foo(callback) { var result = calculateResult(); (callback || angular.noop)(result); } -+ ``` */ function noop() {} noop.$inject = []; @@ -443,17 +470,20 @@ noop.$inject = []; /** * @ngdoc function * @name angular.identity - * @function + * @module ng + * @kind function * * @description * A function that returns its first argument. This function is useful when writing code in the * functional style. * -
+ ```js function transformer(transformationFn, value) { return (transformationFn || angular.identity)(value); }; -+ ``` + * @param {*} value to be returned. + * @returns {*} the value passed in. */ function identity($) {return $;} identity.$inject = []; @@ -464,7 +494,8 @@ function valueFn(value) {return function() {return value;};} /** * @ngdoc function * @name angular.isUndefined - * @function + * @module ng + * @kind function * * @description * Determines if a reference is undefined. @@ -472,13 +503,14 @@ function valueFn(value) {return function() {return value;};} * @param {*} value Reference to check. * @returns {boolean} True if `value` is undefined. */ -function isUndefined(value){return typeof value == 'undefined';} +function isUndefined(value){return typeof value === 'undefined';} /** * @ngdoc function * @name angular.isDefined - * @function + * @module ng + * @kind function * * @description * Determines if a reference is defined. @@ -486,28 +518,30 @@ function isUndefined(value){return typeof value == 'undefined';} * @param {*} value Reference to check. * @returns {boolean} True if `value` is defined. */ -function isDefined(value){return typeof value != 'undefined';} +function isDefined(value){return typeof value !== 'undefined';} /** * @ngdoc function * @name angular.isObject - * @function + * @module ng + * @kind function * * @description * Determines if a reference is an `Object`. Unlike `typeof` in JavaScript, `null`s are not - * considered to be objects. + * considered to be objects. Note that JavaScript arrays are objects. * * @param {*} value Reference to check. * @returns {boolean} True if `value` is an `Object` but not `null`. */ -function isObject(value){return value != null && typeof value == 'object';} +function isObject(value){return value != null && typeof value === 'object';} /** * @ngdoc function * @name angular.isString - * @function + * @module ng + * @kind function * * @description * Determines if a reference is a `String`. @@ -515,13 +549,14 @@ function isObject(value){return value != null && typeof value == 'object';} * @param {*} value Reference to check. * @returns {boolean} True if `value` is a `String`. */ -function isString(value){return typeof value == 'string';} +function isString(value){return typeof value === 'string';} /** * @ngdoc function * @name angular.isNumber - * @function + * @module ng + * @kind function * * @description * Determines if a reference is a `Number`. @@ -529,13 +564,14 @@ function isString(value){return typeof value == 'string';} * @param {*} value Reference to check. * @returns {boolean} True if `value` is a `Number`. */ -function isNumber(value){return typeof value == 'number';} +function isNumber(value){return typeof value === 'number';} /** * @ngdoc function * @name angular.isDate - * @function + * @module ng + * @kind function * * @description * Determines if a value is a date. @@ -543,15 +579,16 @@ function isNumber(value){return typeof value == 'number';} * @param {*} value Reference to check. * @returns {boolean} True if `value` is a `Date`. */ -function isDate(value){ - return toString.apply(value) == '[object Date]'; +function isDate(value) { + return toString.call(value) === '[object Date]'; } /** * @ngdoc function * @name angular.isArray - * @function + * @module ng + * @kind function * * @description * Determines if a reference is an `Array`. @@ -559,15 +596,20 @@ function isDate(value){ * @param {*} value Reference to check. * @returns {boolean} True if `value` is an `Array`. */ -function isArray(value) { - return toString.apply(value) == '[object Array]'; -} - +var isArray = (function() { + if (!isFunction(Array.isArray)) { + return function(value) { + return toString.call(value) === '[object Array]'; + }; + } + return Array.isArray; +})(); /** * @ngdoc function * @name angular.isFunction - * @function + * @module ng + * @kind function * * @description * Determines if a reference is a `Function`. @@ -575,7 +617,7 @@ function isArray(value) { * @param {*} value Reference to check. * @returns {boolean} True if `value` is a `Function`. */ -function isFunction(value){return typeof value == 'function';} +function isFunction(value){return typeof value === 'function';} /** @@ -586,7 +628,7 @@ function isFunction(value){return typeof value == 'function';} * @returns {boolean} True if `value` is a `RegExp`. */ function isRegExp(value) { - return toString.apply(value) == '[object RegExp]'; + return toString.call(value) === '[object RegExp]'; } @@ -608,12 +650,22 @@ function isScope(obj) { function isFile(obj) { - return toString.apply(obj) === '[object File]'; + return toString.call(obj) === '[object File]'; +} + + +function isBlob(obj) { + return toString.call(obj) === '[object Blob]'; } function isBoolean(value) { - return typeof value == 'boolean'; + return typeof value === 'boolean'; +} + + +function isPromiseLike(obj) { + return obj && isFunction(obj.then); } @@ -623,7 +675,7 @@ var trim = (function() { // TODO: we should move this into IE/ES5 polyfill if (!String.prototype.trim) { return function(value) { - return isString(value) ? value.replace(/^\s*/, '').replace(/\s*$/, '') : value; + return isString(value) ? value.replace(/^\s\s*/, '').replace(/\s\s*$/, '') : value; }; } return function(value) { @@ -635,7 +687,8 @@ var trim = (function() { /** * @ngdoc function * @name angular.isElement - * @function + * @module ng + * @kind function * * @description * Determines if a reference is a DOM element (or wrapped jQuery element). @@ -644,16 +697,16 @@ var trim = (function() { * @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.prop && node.attr && 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, ...} */ -function makeMap(str){ +function makeMap(str) { var obj = {}, items = str.split(","), i; for ( i = 0; i < items.length; i++ ) obj[ items[i] ] = true; @@ -700,7 +753,7 @@ function size(obj, ownPropsOnly) { if (isArray(obj) || isString(obj)) { return obj.length; - } else if (isObject(obj)){ + } else if (isObject(obj)) { for (key in obj) if (!ownPropsOnly || obj.hasOwnProperty(key)) count++; @@ -717,7 +770,7 @@ function includes(array, obj) { function indexOf(array, obj) { if (array.indexOf) return array.indexOf(obj); - for ( var i = 0; i < array.length; i++) { + for (var i = 0; i < array.length; i++) { if (obj === array[i]) return i; } return -1; @@ -745,7 +798,8 @@ function isLeafNode (node) { /** * @ngdoc function * @name angular.copy - * @function + * @module ng + * @kind function * * @description * Creates a deep copy of `source`, which should be an object or an array. @@ -763,9 +817,9 @@ function isLeafNode (node) { * @returns {*} The copy or updated `destination`, if `destination` was specified. * * @example -
{{heading}} | + *
---|
{{fill}} | + *
+ * ```js * // Create a new module * var myModule = angular.module('myModule', []); * @@ -1465,30 +1640,36 @@ function setupModuleLoader(window) { * myModule.value('appName', 'MyCoolApp'); * * // configure existing services inside initialization blocks. - * myModule.config(function($locationProvider) { + * myModule.config(['$locationProvider', function($locationProvider) { * // Configure existing providers * $locationProvider.hashPrefix('!'); - * }); - *+ * }]); + * ``` * * Then you can create an injector and load your modules like this: * - *
- * var injector = angular.injector(['ng', 'MyModule']) - *+ * ```js + * var injector = angular.injector(['ng', 'myModule']) + * ``` * * However it's more likely that you'll just use * {@link ng.directive:ngApp ngApp} or * {@link angular.bootstrap} to simplify this process for you. * * @param {!string} name The name of the module to create or retrieve. - * @param {Array.
+ * ```js * module.animation('.animation-name', function($inject1, $inject2) { * return { * eventName : function(element, done) { @@ -1619,7 +1801,7 @@ function setupModuleLoader(window) { * } * } * }) - *+ * ``` * * See {@link ngAnimate.$animateProvider#register $animateProvider.register()} and * {@link ngAnimate ngAnimate module} for more information. @@ -1629,7 +1811,7 @@ function setupModuleLoader(window) { /** * @ngdoc method * @name angular.Module#filter - * @methodOf angular.Module + * @module ng * @param {string} name Filter name. * @param {Function} filterFactory Factory function for creating new instance of filter. * @description @@ -1640,7 +1822,7 @@ function setupModuleLoader(window) { /** * @ngdoc method * @name angular.Module#controller - * @methodOf angular.Module + * @module ng * @param {string|Object} name Controller name, or an object map of controllers where the * keys are the names and the values are the constructors. * @param {Function} constructor Controller constructor function. @@ -1652,31 +1834,33 @@ function setupModuleLoader(window) { /** * @ngdoc method * @name angular.Module#directive - * @methodOf angular.Module + * @module ng * @param {string|Object} name Directive name, or an object map of directives where the * keys are the names and the values are the factories. * @param {Function} directiveFactory Factory function for creating new instance of * directives. * @description - * See {@link ng.$compileProvider#methods_directive $compileProvider.directive()}. + * See {@link ng.$compileProvider#directive $compileProvider.directive()}. */ directive: invokeLater('$compileProvider', 'directive'), /** * @ngdoc method * @name angular.Module#config - * @methodOf angular.Module + * @module ng * @param {Function} configFn Execute this function on module load. Useful for service * configuration. * @description * Use this method to register work which needs to be performed on module loading. + * For more about how to configure services, see + * {@link providers#providers_provider-recipe Provider Recipe}. */ config: config, /** * @ngdoc method * @name angular.Module#run - * @methodOf angular.Module + * @module ng * @param {Function} initializationFn Execute this function after injector creation. * Useful for application initialization. * @description @@ -1713,12 +1897,11 @@ function setupModuleLoader(window) { } -/* global - angularModule: true, - version: true, +/* global angularModule: true, + version: true, - $LocaleProvider, - $CompileProvider, + $LocaleProvider, + $CompileProvider, htmlAnchorDirective, inputDirective, @@ -1741,6 +1924,7 @@ function setupModuleLoader(window) { ngHideDirective, ngIfDirective, ngIncludeDirective, + ngIncludeFillContentDirective, ngInitDirective, ngNonBindableDirective, ngPluralizeDirective, @@ -1778,18 +1962,22 @@ function setupModuleLoader(window) { $ParseProvider, $RootScopeProvider, $QProvider, + $$SanitizeUriProvider, $SceProvider, $SceDelegateProvider, $SnifferProvider, $TemplateCacheProvider, $TimeoutProvider, + $$RAFProvider, + $$AsyncCallbackProvider, $WindowProvider */ /** - * @ngdoc property + * @ngdoc object * @name angular.version + * @module ng * @description * An object that contains information about the current AngularJS version. This object has the * following properties: @@ -1801,11 +1989,11 @@ function setupModuleLoader(window) { * - `codeName` – `{string}` – Code name of the release, such as "jiggling-armfat". */ var version = { - full: '1.2.0', // all of these placeholder strings will be replaced by grunt's + full: '1.2.29', // all of these placeholder strings will be replaced by grunt's major: 1, // package task - minor: "NG_VERSION_MINOR", - dot: 0, - codeName: 'timely-delivery' + minor: 2, + dot: 29, + codeName: 'ultimate-deprecation' }; @@ -1818,11 +2006,11 @@ function publishExternalAPI(angular){ 'element': jqLite, 'forEach': forEach, 'injector': createInjector, - 'noop':noop, - 'bind':bind, + 'noop': noop, + 'bind': bind, 'toJson': toJson, 'fromJson': fromJson, - 'identity':identity, + 'identity': identity, 'isUndefined': isUndefined, 'isDefined': isDefined, 'isString': isString, @@ -1849,6 +2037,10 @@ function publishExternalAPI(angular){ angularModule('ng', ['ngLocale'], ['$provide', function ngModule($provide) { + // $$sanitizeUriProvider needs to be before $compileProvider as it is used by it. + $provide.provider({ + $$sanitizeUri: $$SanitizeUriProvider + }); $provide.provider('$compile', $CompileProvider). directive({ a: htmlAnchorDirective, @@ -1889,6 +2081,9 @@ function publishExternalAPI(angular){ ngRequired: requiredDirective, ngValue: ngValueDirective }). + directive({ + ngInclude: ngIncludeFillContentDirective + }). directive(ngAttributeAliasDirectives). directive(ngEventDirectives); $provide.provider({ @@ -1914,18 +2109,18 @@ function publishExternalAPI(angular){ $sniffer: $SnifferProvider, $templateCache: $TemplateCacheProvider, $timeout: $TimeoutProvider, - $window: $WindowProvider + $window: $WindowProvider, + $$rAF: $$RAFProvider, + $$asyncCallback : $$AsyncCallbackProvider }); } ]); } -/* global - - -JQLitePrototype, - -addEventListenerFn, - -removeEventListenerFn, - -BOOLEAN_ATTR +/* global JQLitePrototype: true, + addEventListenerFn: true, + removeEventListenerFn: true, + BOOLEAN_ATTR: true */ ////////////////////////////////// @@ -1935,7 +2130,8 @@ function publishExternalAPI(angular){ /** * @ngdoc function * @name angular.element - * @function + * @module ng + * @kind function * * @description * Wraps a raw DOM element or HTML string as a [jQuery](http://jquery.com) element. @@ -1960,12 +2156,13 @@ function publishExternalAPI(angular){ * - [`after()`](http://api.jquery.com/after/) * - [`append()`](http://api.jquery.com/append/) * - [`attr()`](http://api.jquery.com/attr/) - * - [`bind()`](http://api.jquery.com/on/) - Does not support namespaces, selectors or eventData + * - [`bind()`](http://api.jquery.com/bind/) - Does not support namespaces, selectors or eventData * - [`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/) + * - [`css()`](http://api.jquery.com/css/) - Only retrieves inline-styles, does not call `getComputedStyles()` * - [`data()`](http://api.jquery.com/data/) + * - [`empty()`](http://api.jquery.com/empty/) * - [`eq()`](http://api.jquery.com/eq/) * - [`find()`](http://api.jquery.com/find/) - Limited to lookups by tag name * - [`hasClass()`](http://api.jquery.com/hasClass/) @@ -1973,6 +2170,7 @@ function publishExternalAPI(angular){ * - [`next()`](http://api.jquery.com/next/) - Does not support selectors * - [`on()`](http://api.jquery.com/on/) - Does not support namespaces, selectors or eventData * - [`off()`](http://api.jquery.com/off/) - Does not support namespaces or selectors + * - [`one()`](http://api.jquery.com/one/) - Does not support namespaces or selectors * - [`parent()`](http://api.jquery.com/parent/) - Does not support selectors * - [`prepend()`](http://api.jquery.com/prepend/) * - [`prop()`](http://api.jquery.com/prop/) @@ -1985,7 +2183,7 @@ function publishExternalAPI(angular){ * - [`text()`](http://api.jquery.com/text/) * - [`toggleClass()`](http://api.jquery.com/toggleClass/) * - [`triggerHandler()`](http://api.jquery.com/triggerHandler/) - Passes a dummy event object to handlers. - * - [`unbind()`](http://api.jquery.com/off/) - Does not support namespaces + * - [`unbind()`](http://api.jquery.com/unbind/) - Does not support namespaces * - [`val()`](http://api.jquery.com/val/) * - [`wrap()`](http://api.jquery.com/wrap/) * @@ -2003,9 +2201,9 @@ function publishExternalAPI(angular){ * camelCase directive name, then the controller for this directive will be retrieved (e.g. * `'ngModel'`). * - `injector()` - retrieves the injector of the current element or its parent. - * - `scope()` - retrieves the {@link api/ng.$rootScope.Scope scope} of the current + * - `scope()` - retrieves the {@link ng.$rootScope.Scope scope} of the current * element or its parent. - * - `isolateScope()` - retrieves an isolate {@link api/ng.$rootScope.Scope scope} if one is attached directly to the + * - `isolateScope()` - retrieves an isolate {@link ng.$rootScope.Scope scope} if one is attached directly to the * current element. This getter should be used only on elements that contain a directive which starts a new isolate * scope. Calling `scope()` on this element always returns the original non-isolate scope. * - `inheritedData()` - same as `data()`, but walks up the DOM until a value is found or the top @@ -2015,8 +2213,9 @@ function publishExternalAPI(angular){ * @returns {Object} jQuery object. */ +JQLite.expando = 'ng339'; + var jqCache = JQLite.cache = {}, - jqName = JQLite.expando = 'ng-' + new Date().getTime(), jqId = 1, addEventListenerFn = (window.document.addEventListener ? function(element, type, fn) {element.addEventListener(type, fn, false);} @@ -2025,6 +2224,14 @@ var jqCache = JQLite.cache = {}, ? function(element, type, fn) {element.removeEventListener(type, fn, false); } : function(element, type, fn) {element.detachEvent('on' + type, fn); }); +/* + * !!! This is an undocumented "private" function !!! + */ +var jqData = JQLite._data = function(node) { + //jQuery always returns an object on cache miss + return this.cache[node[this.expando]] || {}; +}; + function jqNextId() { return ++jqId; } @@ -2088,11 +2295,83 @@ function jqLitePatchJQueryRemove(name, dispatchThis, filterElems, getterIfNoArgu } } +var SINGLE_TAG_REGEXP = /^<(\w+)\s*\/?>(?:<\/\1>|)$/; +var HTML_REGEXP = /<|?\w+;/; +var TAG_NAME_REGEXP = /<([\w:]+)/; +var XHTML_TAG_REGEXP = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi; + +var wrapMap = { + 'option': [1, ''], + + 'thead': [1, '
+ * ```js * // create an injector * var $injector = angular.injector(['ng']); * @@ -2877,16 +3224,38 @@ HashMap.prototype = { * $compile($document)($rootScope); * $rootScope.$digest(); * }); - *+ * ``` + * + * Sometimes you want to get access to the injector of a currently running Angular app + * from outside Angular. Perhaps, you want to inject and compile some markup after the + * application has been bootstrapped. You can do this using the extra `injector()` added + * to JQuery/jqLite elements. See {@link angular.element}. + * + * *This is fairly rare but could be the case if a third party library is injecting the + * markup.* + * + * In the following example a new block of HTML containing a `ng-controller` + * directive is added to the end of the document body by JQuery. We then compile and link + * it into the current AngularJS scope. + * + * ```js + * var $div = $('
+ * ```js * var $injector = angular.injector(); * expect($injector.get('$injector')).toBe($injector); * expect($injector.invoke(function($injector){ * return $injector; - * }).toBe($injector); - *+ * })).toBe($injector); + * ``` * * # Injection Function Annotation * * JavaScript does not have annotations, and annotations are needed for dependency injection. The * following are all valid ways of annotating function with injection arguments and are equivalent. * - *
+ * ```js * // inferred (only works if code not minified/obfuscated) * $injector.invoke(function(serviceA){}); * @@ -2963,7 +3331,7 @@ function annotate(fn) { * * // inline * $injector.invoke(['serviceA', function(serviceA){}]); - *+ * ``` * * ## Inference * @@ -2972,7 +3340,7 @@ function annotate(fn) { * minification, and obfuscation tools since these tools change the argument names. * * ## `$inject` Annotation - * By adding a `$inject` property onto a function the injection parameters can be specified. + * By adding an `$inject` property onto a function the injection parameters can be specified. * * ## Inline * As an array of injection names, where the last item in the array is the function to call. @@ -2980,8 +3348,7 @@ function annotate(fn) { /** * @ngdoc method - * @name AUTO.$injector#get - * @methodOf AUTO.$injector + * @name $injector#get * * @description * Return an instance of the service. @@ -2992,13 +3359,12 @@ function annotate(fn) { /** * @ngdoc method - * @name AUTO.$injector#invoke - * @methodOf AUTO.$injector + * @name $injector#invoke * * @description * Invoke the method and supply the method arguments from the `$injector`. * - * @param {!function} fn The function to invoke. Function parameters are injected according to the + * @param {!Function} fn The function to invoke. Function parameters are injected according to the * {@link guide/di $inject Annotation} rules. * @param {Object=} self The `this` for the invoked method. * @param {Object=} locals Optional object. If preset then any argument names are read from this @@ -3008,26 +3374,24 @@ function annotate(fn) { /** * @ngdoc method - * @name AUTO.$injector#has - * @methodOf AUTO.$injector + * @name $injector#has * * @description - * Allows the user to query if the particular service exist. + * Allows the user to query if the particular service exists. * - * @param {string} Name of the service to query. - * @returns {boolean} returns true if injector has given service. + * @param {string} name Name of the service to query. + * @returns {boolean} `true` if injector has given service. */ /** * @ngdoc method - * @name AUTO.$injector#instantiate - * @methodOf AUTO.$injector + * @name $injector#instantiate * @description - * Create a new instance of JS type. The method takes a constructor function invokes the new - * operator and supplies all of the arguments to the constructor function as specified by the + * Create a new instance of JS type. The method takes a constructor function, invokes the new + * operator, and supplies all of the arguments to the constructor function as specified by the * constructor annotation. * - * @param {function} Type Annotated constructor function. + * @param {Function} Type Annotated constructor function. * @param {Object=} locals Optional object. If preset then any argument names are read from this * object first, before the `$injector` is consulted. * @returns {Object} new instance of `Type`. @@ -3035,8 +3399,7 @@ function annotate(fn) { /** * @ngdoc method - * @name AUTO.$injector#annotate - * @methodOf AUTO.$injector + * @name $injector#annotate * * @description * Returns an array of service names which the function is requesting for injection. This API is @@ -3049,7 +3412,7 @@ function annotate(fn) { * The simplest form is to extract the dependencies from the arguments of the function. This is done * by converting the function into a string using `toString()` method and extracting the argument * names. - *
+ * ```js * // Given * function MyController($scope, $route) { * // ... @@ -3057,7 +3420,7 @@ function annotate(fn) { * * // Then * expect(injector.annotate(MyController)).toEqual(['$scope', '$route']); - *+ * ``` * * This method does not work with code minification / obfuscation. For this reason the following * annotation strategies are supported. @@ -3066,17 +3429,17 @@ function annotate(fn) { * * If a function has an `$inject` property and its value is an array of strings, then the strings * represent names of services to be injected into the function. - *
+ * ```js * // 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']); - *+ * ``` * * # The array notation * @@ -3084,7 +3447,7 @@ function annotate(fn) { * is very inconvenient. In these situations using the array notation to specify the dependencies in * a way that survives minification is a better choice: * - *
+ * ```js * // We wish to write this (not minification / obfuscation safe) * injector.invoke(function($compile, $rootScope) { * // ... @@ -3106,9 +3469,9 @@ function annotate(fn) { * expect(injector.annotate( * ['$compile', '$rootScope', function(obfus_$compile, obfus_$rootScope) {}]) * ).toEqual(['$compile', '$rootScope']); - *+ * ``` * - * @param {function|Array.
+ * ```js * // Define the eventTracker provider * function EventTrackerProvider() { * var trackingUrl = '/track'; @@ -3253,19 +3613,18 @@ function annotate(fn) { * expect(postSpy.mostRecentCall.args[1]).toEqual({ 'login': 1 }); * })); * }); - *+ * ``` */ /** * @ngdoc method - * @name AUTO.$provide#factory - * @methodOf AUTO.$provide + * @name $provide#factory * @description * * Register a **service factory**, which will be called to return the service instance. * This is short for registering a service where its provider consists of only a `$get` property, * which is the given service factory function. - * You should use {@link AUTO.$provide#factory $provide.factory(getFn)} if you do not need to + * You should use {@link auto.$provide#factory $provide.factory(getFn)} if you do not need to * configure your service in a provider. * * @param {string} name The name of the instance. @@ -3275,26 +3634,25 @@ function annotate(fn) { * * @example * Here is an example of registering a service - *
+ * ```js * $provide.factory('ping', ['$http', function($http) { * return function ping() { * return $http.send('/ping'); * }; * }]); - *+ * ``` * You would then inject and use this service like this: - *
+ * ```js * someModule.controller('Ctrl', ['ping', function(ping) { * ping(); * }]); - *+ * ``` */ /** * @ngdoc method - * @name AUTO.$provide#service - * @methodOf AUTO.$provide + * @name $provide#service * @description * * Register a **service constructor**, which will be invoked with `new` to create the service @@ -3302,8 +3660,8 @@ function annotate(fn) { * This is short for registering a service where its provider's `$get` property is the service * constructor function that will be used to instantiate the service instance. * - * You should use {@link AUTO.$provide#methods_service $provide.service(class)} if you define your service - * as a type/class. This is common when using {@link http://coffeescript.org CoffeeScript}. + * You should use {@link auto.$provide#service $provide.service(class)} if you define your service + * as a type/class. * * @param {string} name The name of the instance. * @param {Function} constructor A class (constructor function) that will be instantiated. @@ -3311,31 +3669,34 @@ function annotate(fn) { * * @example * Here is an example of registering a service using - * {@link AUTO.$provide#methods_service $provide.service(class)} that is defined as a CoffeeScript class. - *
- * class Ping - * constructor: (@$http)-> - * send: ()=> - * @$http.get('/ping') + * {@link auto.$provide#service $provide.service(class)}. + * ```js + * var Ping = function($http) { + * this.$http = $http; + * }; * - * $provide.service('ping', ['$http', Ping]) - *+ * Ping.$inject = ['$http']; + * + * Ping.prototype.send = function() { + * return this.$http.get('/ping'); + * }; + * $provide.service('ping', Ping); + * ``` * You would then inject and use this service like this: - *
- * someModule.controller 'Ctrl', ['ping', (ping)-> - * ping.send() - * ] - *+ * ```js + * someModule.controller('Ctrl', ['ping', function(ping) { + * ping.send(); + * }]); + * ``` */ /** * @ngdoc method - * @name AUTO.$provide#value - * @methodOf AUTO.$provide + * @name $provide#value * @description * - * Register a **value service** with the {@link AUTO.$injector $injector}, such as a string, a + * Register a **value service** with the {@link auto.$injector $injector}, such as a string, a * number, an array, an object or a function. This is short for registering a service where its * provider's `$get` property is a factory function that takes no arguments and returns the **value * service**. @@ -3343,7 +3704,7 @@ function annotate(fn) { * Value services are similar to constant services, except that they cannot be injected into a * module configuration function (see {@link angular.Module#config}) but they can be overridden by * an Angular - * {@link AUTO.$provide#decorator decorator}. + * {@link auto.$provide#decorator decorator}. * * @param {string} name The name of the instance. * @param {*} value The value. @@ -3351,28 +3712,27 @@ function annotate(fn) { * * @example * Here are some examples of creating value services. - *
- * $provide.constant('ADMIN_USER', 'admin'); + * ```js + * $provide.value('ADMIN_USER', 'admin'); * - * $provide.constant('RoleLookup', { admin: 0, writer: 1, reader: 2 }); + * $provide.value('RoleLookup', { admin: 0, writer: 1, reader: 2 }); * - * $provide.constant('halfOf', function(value) { + * $provide.value('halfOf', function(value) { * return value / 2; * }); - *+ * ``` */ /** * @ngdoc method - * @name AUTO.$provide#constant - * @methodOf AUTO.$provide + * @name $provide#constant * @description * * Register a **constant service**, such as a string, a number, an array, an object or a function, - * with the {@link AUTO.$injector $injector}. Unlike {@link AUTO.$provide#value value} it can be + * with the {@link auto.$injector $injector}. Unlike {@link auto.$provide#value value} it can be * injected into a module configuration function (see {@link angular.Module#config}) and it cannot - * be overridden by an Angular {@link AUTO.$provide#decorator decorator}. + * be overridden by an Angular {@link auto.$provide#decorator decorator}. * * @param {string} name The name of the constant. * @param {*} value The constant value. @@ -3380,7 +3740,7 @@ function annotate(fn) { * * @example * Here a some examples of creating constants: - *
+ * ```js * $provide.constant('SHARD_HEIGHT', 306); * * $provide.constant('MY_COLOURS', ['red', 'blue', 'grey']); @@ -3388,17 +3748,16 @@ function annotate(fn) { * $provide.constant('double', function(value) { * return value * 2; * }); - *+ * ``` */ /** * @ngdoc method - * @name AUTO.$provide#decorator - * @methodOf AUTO.$provide + * @name $provide#decorator * @description * - * Register a **service decorator** with the {@link AUTO.$injector $injector}. A service decorator + * Register a **service decorator** with the {@link auto.$injector $injector}. A service decorator * intercepts the creation of a service, allowing it to override or modify the behaviour of the * service. The object returned by the decorator may be the original service, or a new service * object which replaces or wraps and delegates to the original service. @@ -3406,7 +3765,7 @@ function annotate(fn) { * @param {string} name The name of the service to decorate. * @param {function()} decorator This function will be invoked when the service needs to be * instantiated and should return the decorated service instance. The function is called using - * the {@link AUTO.$injector#invoke injector.invoke} method and is therefore fully injectable. + * 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, @@ -3415,12 +3774,12 @@ function annotate(fn) { * @example * Here we decorate the {@link ng.$log $log} service to convert warnings to errors by intercepting * calls to {@link ng.$log#error $log.warn()}. - *
- * $provider.decorator('$log', ['$delegate', function($delegate) { + * ```js + * $provide.decorator('$log', ['$delegate', function($delegate) { * $delegate.warn = $delegate.error; * return $delegate; * }]); - *+ * ``` */ @@ -3428,7 +3787,7 @@ function createInjector(modulesToLoad) { var INSTANTIATING = {}, providerSuffix = 'Provider', path = [], - loadedModules = new HashMap(), + loadedModules = new HashMap([], true), providerCache = { $provide: { provider: supportObject(provider), @@ -3561,7 +3920,8 @@ function createInjector(modulesToLoad) { function getService(serviceName) { if (cache.hasOwnProperty(serviceName)) { if (cache[serviceName] === INSTANTIATING) { - throw $injectorMinErr('cdep', 'Circular dependency found: {0}', path.join(' <- ')); + throw $injectorMinErr('cdep', 'Circular dependency found: {0}', + serviceName + ' <- ' + path.join(' <- ')); } return cache[serviceName]; } else { @@ -3569,6 +3929,11 @@ function createInjector(modulesToLoad) { path.unshift(serviceName); cache[serviceName] = INSTANTIATING; return cache[serviceName] = factory(serviceName); + } catch (err) { + if (cache[serviceName] === INSTANTIATING) { + delete cache[serviceName]; + } + throw err; } finally { path.shift(); } @@ -3593,29 +3958,13 @@ function createInjector(modulesToLoad) { : getService(key) ); } - if (!fn.$inject) { - // this means that we must be an array. + if (isArray(fn)) { fn = fn[length]; } - - // Performance optimization: http://jsperf.com/apply-vs-call-vs-invoke - switch (self ? -1 : args.length) { - case 0: return fn(); - case 1: return fn(args[0]); - case 2: return fn(args[0], args[1]); - case 3: return fn(args[0], args[1], args[2]); - case 4: return fn(args[0], args[1], args[2], args[3]); - case 5: return fn(args[0], args[1], args[2], args[3], args[4]); - case 6: return fn(args[0], args[1], args[2], args[3], args[4], args[5]); - case 7: return fn(args[0], args[1], args[2], args[3], args[4], args[5], args[6]); - case 8: return fn(args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7]); - case 9: return fn(args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], - args[8]); - case 10: return fn(args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], - args[8], args[9]); - default: return fn.apply(self, args); - } + // http://jsperf.com/angularjs-invoke-apply-vs-switch + // #5388 + return fn.apply(self, args); } function instantiate(Type, locals) { @@ -3644,16 +3993,17 @@ function createInjector(modulesToLoad) { } /** - * @ngdoc function - * @name ng.$anchorScroll + * @ngdoc service + * @name $anchorScroll + * @kind function * @requires $window * @requires $location * @requires $rootScope * * @description - * When called, it checks current value of `$location.hash()` and scroll to related element, + * When called, it checks current value of `$location.hash()` and scrolls to the related element, * according to rules specified in - * {@link http://dev.w3.org/html5/spec/Overview.html#the-indicated-part-of-the-document Html5 spec}. + * [Html5 spec](http://dev.w3.org/html5/spec/Overview.html#the-indicated-part-of-the-document). * * It also watches the `$location.hash()` and scrolls whenever it changes to match any anchor. * This can be disabled by calling `$anchorScrollProvider.disableAutoScrolling()`. @@ -3675,7 +4025,7 @@ function createInjector(modulesToLoad) { // call $anchorScroll() $anchorScroll(); - } + }; }
+ * ```js * return { * eventFn : function(element, done) { * //code to run the animation @@ -3790,10 +4152,10 @@ var $AnimateProvider = ['$provide', function($provide) { * } * } * } - *+ * ``` * * @param {string} name The name of the animation. - * @param {function} factory The factory function that will be executed to return the animation + * @param {Function} factory The factory function that will be executed to return the animation * object. */ this.register = function(name, factory) { @@ -3804,12 +4166,37 @@ var $AnimateProvider = ['$provide', function($provide) { $provide.factory(key, factory); }; - this.$get = ['$timeout', function($timeout) { + /** + * @ngdoc method + * @name $animateProvider#classNameFilter + * + * @description + * Sets and/or returns the CSS class regular expression that is checked when performing + * an animation. Upon bootstrap the classNameFilter value is not set at all and will + * therefore enable $animate to attempt to perform an animation on any element. + * When setting the classNameFilter value, animations will only be performed on elements + * that successfully match the filter expression. This in turn can boost performance + * for low-powered devices as well as applications containing a lot of structural operations. + * @param {RegExp=} expression The className expression which will be checked against all animations + * @return {RegExp} The current CSS className expression value. If null then there is no expression value + */ + this.classNameFilter = function(expression) { + if(arguments.length === 1) { + this.$$classNameFilter = (expression instanceof RegExp) ? expression : null; + } + return this.$$classNameFilter; + }; + + this.$get = ['$timeout', '$$asyncCallback', function($timeout, $$asyncCallback) { + + function async(fn) { + fn && $$asyncCallback(fn); + } /** * - * @ngdoc object - * @name ng.$animate + * @ngdoc service + * @name $animate * @description The $animate service provides rudimentary DOM manipulation functions to * insert, remove and move elements within the DOM, as well as adding and removing classes. * This service is the core service used by the ngAnimate $animator service which provides @@ -3827,65 +4214,63 @@ var $AnimateProvider = ['$provide', function($provide) { /** * - * @ngdoc function - * @name ng.$animate#enter - * @methodOf ng.$animate - * @function + * @ngdoc method + * @name $animate#enter + * @kind function * @description Inserts the element into the DOM either after the `after` element or within * the `parent` element. Once complete, the done() callback will be fired (if provided). - * @param {jQuery/jqLite element} element the element which will be inserted into the DOM - * @param {jQuery/jqLite element} parent the parent element which will append the element as + * @param {DOMElement} element the element which will be inserted into the DOM + * @param {DOMElement} parent the parent element which will append the element as * a child (if the after element is not present) - * @param {jQuery/jqLite element} after the sibling element which will append the element + * @param {DOMElement} after the sibling element which will append the element * after itself - * @param {function=} done callback function that will be called after the element has been + * @param {Function=} done callback function that will be called after the element has been * inserted into the DOM */ enter : function(element, parent, after, done) { - var afterNode = after && after[after.length - 1]; - var parentNode = parent && parent[0] || afterNode && afterNode.parentNode; - // IE does not like undefined so we have to pass null. - var afterNextSibling = (afterNode && afterNode.nextSibling) || null; - forEach(element, function(node) { - parentNode.insertBefore(node, afterNextSibling); - }); - done && $timeout(done, 0, false); + if (after) { + after.after(element); + } else { + if (!parent || !parent[0]) { + parent = after.parent(); + } + parent.append(element); + } + async(done); }, /** * - * @ngdoc function - * @name ng.$animate#leave - * @methodOf ng.$animate - * @function + * @ngdoc method + * @name $animate#leave + * @kind function * @description Removes the element from the DOM. Once complete, the done() callback will be * fired (if provided). - * @param {jQuery/jqLite element} element the element which will be removed from the DOM - * @param {function=} done callback function that will be called after the element has been + * @param {DOMElement} element the element which will be removed from the DOM + * @param {Function=} done callback function that will be called after the element has been * removed from the DOM */ leave : function(element, done) { element.remove(); - done && $timeout(done, 0, false); + async(done); }, /** * - * @ngdoc function - * @name ng.$animate#move - * @methodOf ng.$animate - * @function + * @ngdoc method + * @name $animate#move + * @kind function * @description Moves the position of the provided element within the DOM to be placed * either after the `after` element or inside of the `parent` element. Once complete, the * done() callback will be fired (if provided). * - * @param {jQuery/jqLite element} element the element which will be moved around within the + * @param {DOMElement} element the element which will be moved around within the * DOM - * @param {jQuery/jqLite element} parent the parent element where the element will be + * @param {DOMElement} parent the parent element where the element will be * inserted into (if the after element is not present) - * @param {jQuery/jqLite element} after the sibling element where the element will be + * @param {DOMElement} after the sibling element where the element will be * positioned next to - * @param {function=} done the callback function (if provided) that will be fired after the + * @param {Function=} done the callback function (if provided) that will be fired after the * element has been moved to its new position */ move : function(element, parent, after, done) { @@ -3896,16 +4281,15 @@ var $AnimateProvider = ['$provide', function($provide) { /** * - * @ngdoc function - * @name ng.$animate#addClass - * @methodOf ng.$animate - * @function + * @ngdoc method + * @name $animate#addClass + * @kind function * @description Adds the provided className CSS class value to the provided element. Once * complete, the done() callback will be fired (if provided). - * @param {jQuery/jqLite element} element the element which will have the className value + * @param {DOMElement} element the element which will have the className value * added to it * @param {string} className the CSS class which will be added to the element - * @param {function=} done the callback function (if provided) that will be fired after the + * @param {Function=} done the callback function (if provided) that will be fired after the * className value has been added to the element */ addClass : function(element, className, done) { @@ -3915,21 +4299,20 @@ var $AnimateProvider = ['$provide', function($provide) { forEach(element, function (element) { jqLiteAddClass(element, className); }); - done && $timeout(done, 0, false); + async(done); }, /** * - * @ngdoc function - * @name ng.$animate#removeClass - * @methodOf ng.$animate - * @function + * @ngdoc method + * @name $animate#removeClass + * @kind function * @description Removes the provided className CSS class value from the provided element. * Once complete, the done() callback will be fired (if provided). - * @param {jQuery/jqLite element} element the element which will have the className value + * @param {DOMElement} element the element which will have the className value * removed from it * @param {string} className the CSS class which will be removed from the element - * @param {function=} done the callback function (if provided) that will be fired after the + * @param {Function=} done the callback function (if provided) that will be fired after the * className value has been removed from the element */ removeClass : function(element, className, done) { @@ -3939,7 +4322,29 @@ var $AnimateProvider = ['$provide', function($provide) { forEach(element, function (element) { jqLiteRemoveClass(element, className); }); - done && $timeout(done, 0, false); + async(done); + }, + + /** + * + * @ngdoc method + * @name $animate#setClass + * @kind function + * @description Adds and/or removes the given CSS classes to and from the element. + * Once complete, the done() callback will be fired (if provided). + * @param {DOMElement} element the element which will have its CSS classes changed + * removed from it + * @param {string} add the CSS classes which will be added to the element + * @param {string} remove the CSS class which will be removed from the element + * @param {Function=} done the callback function (if provided) that will be fired after the + * CSS classes have been set on the element + */ + setClass : function(element, add, remove, done) { + forEach(element, function (element) { + jqLiteAddClass(element, add); + jqLiteRemoveClass(element, remove); + }); + async(done); }, enabled : noop @@ -3947,10 +4352,22 @@ var $AnimateProvider = ['$provide', function($provide) { }]; }]; +function $$AsyncCallbackProvider(){ + this.$get = ['$$rAF', '$timeout', function($$rAF, $timeout) { + return $$rAF.supported + ? function(fn) { return $$rAF(fn); } + : function(fn) { + return $timeout(fn, 0, false); + }; + }]; +} + +/* global stripHash: true */ + /** * ! This is a private undocumented service ! * - * @name ng.$browser + * @name $browser * @requires $log * @description * This object has two goals: @@ -4008,6 +4425,11 @@ function Browser(window, document, $log, $sniffer) { } } + function getHash(url) { + var index = url.indexOf('#'); + return index === -1 ? '' : url.substr(index + 1); + } + /** * @private * Note: this method is used only by scenario runner @@ -4034,8 +4456,7 @@ function Browser(window, document, $log, $sniffer) { pollTimeout; /** - * @name ng.$browser#addPollFn - * @methodOf ng.$browser + * @name $browser#addPollFn * * @param {function()} fn Poll function to add * @@ -4072,11 +4493,10 @@ function Browser(window, document, $log, $sniffer) { var lastBrowserUrl = location.href, baseElement = document.find('base'), - newLocation = null; + reloadLocation = null; /** - * @name ng.$browser#url - * @methodOf ng.$browser + * @name $browser#url * * @description * GETTER: @@ -4095,14 +4515,20 @@ function Browser(window, document, $log, $sniffer) { * @param {boolean=} replace Should new url replace current history record ? */ self.url = function(url, replace) { - // Android Browser BFCache causes location reference to become stale. + // Android Browser BFCache causes location, history reference to become stale. if (location !== window.location) location = window.location; + if (history !== window.history) history = window.history; // setter if (url) { if (lastBrowserUrl == url) return; + var sameBase = lastBrowserUrl && stripHash(lastBrowserUrl) === stripHash(url); lastBrowserUrl = url; - if ($sniffer.history) { + // Don't use history API if only the hash changed + // due to a bug in IE10/IE11 which leads + // to not firing a `hashchange` nor `popstate` event + // in some cases (see #9143). + if (!sameBase && $sniffer.history) { if (replace) history.replaceState(null, '', url); else { history.pushState(null, '', url); @@ -4110,20 +4536,24 @@ function Browser(window, document, $log, $sniffer) { baseElement.attr('href', baseElement.attr('href')); } } else { - newLocation = url; + if (!sameBase) { + reloadLocation = url; + } if (replace) { location.replace(url); - } else { + } else if (!sameBase) { location.href = url; + } else { + location.hash = getHash(url); } } return self; // getter } else { - // - newLocation is a workaround for an IE7-9 issue with location.replace and location.href - // methods not updating location.href synchronously. + // - reloadLocation is needed as browsers don't allow to read out + // the new location.href if a reload happened. // - the replacement is a workaround for https://bugzilla.mozilla.org/show_bug.cgi?id=407172 - return newLocation || location.href.replace(/%27/g,"'"); + return reloadLocation || location.href.replace(/%27/g,"'"); } }; @@ -4131,7 +4561,6 @@ function Browser(window, document, $log, $sniffer) { urlChangeInit = false; function fireUrlChange() { - newLocation = null; if (lastBrowserUrl == self.url()) return; lastBrowserUrl = self.url(); @@ -4141,14 +4570,12 @@ function Browser(window, document, $log, $sniffer) { } /** - * @name ng.$browser#onUrlChange - * @methodOf ng.$browser - * @TODO(vojta): refactor to use node's syntax for events + * @name $browser#onUrlChange * * @description * Register callback function that will be called, when url changes. * - * It's only called when the url is changed by outside of angular: + * It's only called when the url is changed from outside of angular: * - user types different url into address bar * - user clicks on history (forward/back) button * - user clicks on a link @@ -4164,6 +4591,7 @@ function Browser(window, document, $log, $sniffer) { * @return {function(string)} Returns the registered listener fn - handy if the fn is anonymous. */ self.onUrlChange = function(callback) { + // TODO(vojta): refactor to use node's syntax for events if (!urlChangeInit) { // We listen on both (hashchange/popstate) when available, as some browsers (e.g. Opera) // don't fire popstate when user change the address bar and don't fire hashchange when url @@ -4183,23 +4611,29 @@ function Browser(window, document, $log, $sniffer) { return callback; }; + /** + * Checks whether the url has changed outside of Angular. + * Needs to be exported to be able to check for changes that have been done in sync, + * as hashchange/popstate events fire in async. + */ + self.$$checkUrlChange = fireUrlChange; + ////////////////////////////////////////////////////////////// // Misc API ////////////////////////////////////////////////////////////// /** - * @name ng.$browser#baseHref - * @methodOf ng.$browser + * @name $browser#baseHref * * @description * Returns current
+ * ```js * * var cache = $cacheFactory('cacheId'); * expect($cacheFactory.get('cacheId')).toBe(cache); @@ -4355,7 +4787,7 @@ function $BrowserProvider(){ * // We've specified no options on creation * expect(cache.info()).toEqual({id: 'cacheId', size: 2}); * - *+ * ``` * * * @param {string} cacheId Name or id of the newly created cache. @@ -4373,6 +4805,48 @@ function $BrowserProvider(){ * - `{void}` `removeAll()` — Removes all cached values. * - `{void}` `destroy()` — Removes references to this cache from $cacheFactory. * + * @example +
Cached Values
+Cache Info
+- * - * - * - * - * ... - * - *+ * + * ```html + * + * ``` * * **Note:** the `script` tag containing the template does not need to be included in the `head` of - * the document, but it must be below the `ng-app` definition. + * the document, but it must be a descendent of the {@link ng.$rootElement $rootElement} (IE, + * element with ng-app attribute), otherwise the template will be ignored. * * Adding via the $templateCache service: * - *
+ * ```js * var myApp = angular.module('myApp', []); * myApp.run(function($templateCache) { * $templateCache.put('templateId.html', 'This is the content of the template'); * }); - *+ * ``` * * To retrieve the template later, simply use it in your HTML: - *
+ * ```html * - *+ * ``` * * or get it via Javascript: - *
+ * ```js * $templateCache.get('templateId.html') - *+ * ``` * * See {@link ng.$cacheFactory $cacheFactory}. * @@ -4600,16 +5186,16 @@ function $TemplateCacheProvider() { /** - * @ngdoc function - * @name ng.$compile - * @function + * @ngdoc service + * @name $compile + * @kind function * * @description - * Compiles a piece of HTML string or DOM into a template and produces a template function, which + * Compiles an HTML string or DOM into a template and produces a template function, which * can then be used to link {@link ng.$rootScope.Scope `scope`} and the template together. * * The compilation is a process of walking the DOM tree and matching DOM elements to - * {@link ng.$compileProvider#methods_directive directives}. + * {@link ng.$compileProvider#directive directives}. * *
+ * ```js * var myModule = angular.module(...); * * myModule.directive('directiveName', function factory(injectables) { @@ -4640,11 +5226,11 @@ function $TemplateCacheProvider() { * template: '', // or // function(tElement, tAttrs) { ... }, * // or * // templateUrl: 'directive.html', // or // function(tElement, tAttrs) { ... }, - * replace: false, * transclude: false, * restrict: 'A', * scope: false, * controller: function($scope, $element, $attrs, $transclude, otherInjectables) { ... }, + * controllerAs: 'stringAlias', * require: 'siblingDirectiveName', // or // ['^parentDirectiveName', '?optionalDirectiveName', '?^optionalParent'], * compile: function compile(tElement, tAttrs, transclude) { * return { @@ -4664,7 +5250,7 @@ function $TemplateCacheProvider() { * }; * return directiveDefinitionObject; * }); - *+ * ``` * *
+ * ```js * var myModule = angular.module(...); * * myModule.directive('directiveName', function factory(injectables) { @@ -4683,21 +5269,22 @@ function $TemplateCacheProvider() { * // or * // return function postLink(scope, iElement, iAttrs) { ... } * }); - *+ * ``` * * * * ### Directive Definition Object * - * The directive definition object provides instructions to the {@link api/ng.$compile + * The directive definition object provides instructions to the {@link ng.$compile * compiler}. The attributes are: * * #### `priority` * When there are multiple directives defined on a single DOM element, sometimes it * is necessary to specify the order in which the directives are applied. The `priority` is used * to sort the directives before their `compile` functions get called. Priority is defined as a - * number. Directives with greater numerical `priority` are compiled first. The order of directives with - * the same priority is undefined. The default priority is `0`. + * number. Directives with greater numerical `priority` are compiled first. Pre-link functions + * are also run in priority order, but post-link functions are run in reverse order. The order + * of directives with the same priority is undefined. The default priority is `0`. * * #### `terminal` * If set to true then the current `priority` will be the last set of directives @@ -4742,7 +5329,7 @@ function $TemplateCacheProvider() { * local name. Given `
+ * ```js * function compile(tElement, tAttrs, transclude) { ... } - *+ * ``` * * The compile function deals with transforming the template DOM. Since most directives do not do - * template transformation, it is not used often. Examples that require compile functions are - * directives that transform template DOM, such as {@link - * api/ng.directive:ngRepeat ngRepeat}, or load the contents - * asynchronously, such as {@link api/ngRoute.directive:ngView ngView}. The - * compile function takes the following arguments. + * template transformation, it is not used often. The compile function takes the following arguments: * * * `tElement` - template element - The element where the directive has been declared. It is * safe to do template transformation on the element and child elements only. @@ -4852,7 +5451,7 @@ function $TemplateCacheProvider() { * * `tAttrs` - template attributes - Normalized list of attributes declared on this element shared * between all directive compile functions. * - * * `transclude` - A transclude linking function: `function(scope, cloneLinkingFn)`. + * * `transclude` - [*DEPRECATED*!] A transclude linking function: `function(scope, cloneLinkingFn)` * *
- * function link(scope, iElement, iAttrs, controller) { ... } - *+ * ```js + * function link(scope, iElement, iAttrs, controller, transcludeFn) { ... } + * ``` * * The link function is responsible for registering DOM listeners as well as updating the DOM. It is * executed after the template has been cloned. This is where most of the directive logic will be * put. * - * * `scope` - {@link api/ng.$rootScope.Scope Scope} - The scope to be used by the - * directive for registering {@link api/ng.$rootScope.Scope#methods_$watch watches}. + * * `scope` - {@link ng.$rootScope.Scope Scope} - The scope to be used by the + * directive for registering {@link ng.$rootScope.Scope#$watch watches}. * * * `iElement` - instance element - The element where the directive is to be used. It is safe to * manipulate the children of the element only in `postLink` function since the children have @@ -4896,6 +5511,10 @@ function $TemplateCacheProvider() { * element defines a controller. The controller is shared among all the directives, which allows * the directives to use the controllers as a communication channel. * + * * `transcludeFn` - A transclude linking function pre-bound to the correct transclusion scope. + * The scope can be overridden by an optional first argument. This is the same as the `$transclude` + * parameter of directive controllers. + * `function([scope], cloneLinkingFn)`. * * * #### Pre-linking function @@ -4910,7 +5529,7 @@ function $TemplateCacheProvider() { * * ### Attributes * - * The {@link api/ng.$compile.directive.Attributes Attributes} object - passed as a parameter in the + * The {@link ng.$compile.directive.Attributes Attributes} object - passed as a parameter in the * `link()` or `compile()` functions. It has a variety of uses. * * accessing *Normalized attribute names:* @@ -4930,7 +5549,7 @@ function $TemplateCacheProvider() { * the only way to easily get the actual value because during the linking phase the interpolation * hasn't been evaluated yet and so the value is at this time set to `undefined`. * - *
+ * ```js * function linkingFn(scope, elm, attrs, ctrl) { * // get the attribute value * console.log(attrs.ngModel); @@ -4943,19 +5562,19 @@ function $TemplateCacheProvider() { * console.log('ngModel has changed value to ' + value); * }); * } - *+ * ``` * - * Below is an example using `$compileProvider`. + * ## Example * *
+ * ```js * var element = $compile('+ * ``` * * - if on the other hand, you need the element to be cloned, the view reference from the original * example would not point to the clone, but rather to the original template that was cloned. In * this case, you can access the clone via the cloneAttachFn: - *{{total}}
')(scope); - *
- * var templateHTML = angular.element('+ * //now we have reference to the cloned DOM via `clonedElement` + * ``` * * * For information on how the compiler works, see the @@ -5056,20 +5678,18 @@ function $TemplateCacheProvider() { var $compileMinErr = minErr('$compile'); /** - * @ngdoc service - * @name ng.$compileProvider - * @function + * @ngdoc provider + * @name $compileProvider + * @kind function * * @description */ -$CompileProvider.$inject = ['$provide']; -function $CompileProvider($provide) { +$CompileProvider.$inject = ['$provide', '$$sanitizeUriProvider']; +function $CompileProvider($provide, $$sanitizeUriProvider) { var hasDirectives = {}, Suffix = 'Directive', - COMMENT_DIRECTIVE_REGEXP = /^\s*directive\:\s*([\d\w\-_]+)\s+(.*)$/, - CLASS_DIRECTIVE_REGEXP = /(([\d\w\-_]+)(?:\:([^;]+))?;?)/, - aHrefSanitizationWhitelist = /^\s*(https?|ftp|mailto|tel|file):/, - imgSrcSanitizationWhitelist = /^\s*(https?|ftp|file):|data:image\//; + COMMENT_DIRECTIVE_REGEXP = /^\s*directive\:\s*([\d\w_\-]+)\s+(.*)$/, + CLASS_DIRECTIVE_REGEXP = /(([\d\w_\-]+)(?:\:([^;]+))?;?)/; // Ref: http://developers.whatwg.org/webappapis.html#event-handler-idl-attributes // The assumption is that future DOM event attribute names will begin with @@ -5077,10 +5697,9 @@ function $CompileProvider($provide) { var EVENT_HANDLER_ATTR_REGEXP = /^(on[a-z]+|formaction)$/; /** - * @ngdoc function - * @name ng.$compileProvider#directive - * @methodOf ng.$compileProvider - * @function + * @ngdoc method + * @name $compileProvider#directive + * @kind function * * @description * Register a new directive with the compiler. @@ -5088,7 +5707,7 @@ function $CompileProvider($provide) { * @param {string|Object} name Name of the directive in camel-case (i.e.{{total}}
'), + * ```js + * var templateElement = angular.element('{{total}}
'), * scope = ....; * - * var clonedElement = $compile(templateHTML)(scope, function(clonedElement, scope) { + * var clonedElement = $compile(templateElement)(scope, function(clonedElement, scope) { * //attach the clone to DOM document at the right place * }); * - * //now we have reference to the cloned DOM via `clone` - *
ngBind
which
* will match as ng-bind
), or an object map of directives where the keys are the
* names and the values are the factories.
- * @param {function|Array} directiveFactory An injectable directive factory function. See
+ * @param {Function|Array} directiveFactory An injectable directive factory function. See
* {@link guide/directive} for more info.
* @returns {ng.$compileProvider} Self for chaining.
*/
@@ -5131,10 +5750,9 @@ function $CompileProvider($provide) {
/**
- * @ngdoc function
- * @name ng.$compileProvider#aHrefSanitizationWhitelist
- * @methodOf ng.$compileProvider
- * @function
+ * @ngdoc method
+ * @name $compileProvider#aHrefSanitizationWhitelist
+ * @kind function
*
* @description
* Retrieves or overrides the default regular expression that is used for whitelisting of safe
@@ -5153,18 +5771,18 @@ function $CompileProvider($provide) {
*/
this.aHrefSanitizationWhitelist = function(regexp) {
if (isDefined(regexp)) {
- aHrefSanitizationWhitelist = regexp;
+ $$sanitizeUriProvider.aHrefSanitizationWhitelist(regexp);
return this;
+ } else {
+ return $$sanitizeUriProvider.aHrefSanitizationWhitelist();
}
- return aHrefSanitizationWhitelist;
};
/**
- * @ngdoc function
- * @name ng.$compileProvider#imgSrcSanitizationWhitelist
- * @methodOf ng.$compileProvider
- * @function
+ * @ngdoc method
+ * @name $compileProvider#imgSrcSanitizationWhitelist
+ * @kind function
*
* @description
* Retrieves or overrides the default regular expression that is used for whitelisting of safe
@@ -5183,18 +5801,18 @@ function $CompileProvider($provide) {
*/
this.imgSrcSanitizationWhitelist = function(regexp) {
if (isDefined(regexp)) {
- imgSrcSanitizationWhitelist = regexp;
+ $$sanitizeUriProvider.imgSrcSanitizationWhitelist(regexp);
return this;
+ } else {
+ return $$sanitizeUriProvider.imgSrcSanitizationWhitelist();
}
- return imgSrcSanitizationWhitelist;
};
-
this.$get = [
'$injector', '$interpolate', '$exceptionHandler', '$http', '$templateCache', '$parse',
- '$controller', '$rootScope', '$document', '$sce', '$animate',
+ '$controller', '$rootScope', '$document', '$sce', '$animate', '$$sanitizeUri',
function($injector, $interpolate, $exceptionHandler, $http, $templateCache, $parse,
- $controller, $rootScope, $document, $sce, $animate) {
+ $controller, $rootScope, $document, $sce, $animate, $$sanitizeUri) {
var Attributes = function(element, attr) {
this.$$element = element;
@@ -5202,14 +5820,28 @@ function $CompileProvider($provide) {
};
Attributes.prototype = {
+ /**
+ * @ngdoc method
+ * @name $compile.directive.Attributes#$normalize
+ * @kind function
+ *
+ * @description
+ * Converts an attribute name (e.g. dash/colon/underscore-delimited string, optionally prefixed with `x-` or
+ * `data-`) to its normalized, camelCase form.
+ *
+ * Also there is special case for Moz prefix starting with upper case letter.
+ *
+ * For further information check out the guide on {@link guide/directive#matching-directives Matching Directives}
+ *
+ * @param {string} name Name to normalize
+ */
$normalize: directiveNormalize,
/**
- * @ngdoc function
- * @name ng.$compile.directive.Attributes#$addClass
- * @methodOf ng.$compile.directive.Attributes
- * @function
+ * @ngdoc method
+ * @name $compile.directive.Attributes#$addClass
+ * @kind function
*
* @description
* Adds the CSS class value specified by the classVal parameter to the element. If animations
@@ -5224,10 +5856,9 @@ function $CompileProvider($provide) {
},
/**
- * @ngdoc function
- * @name ng.$compile.directive.Attributes#$removeClass
- * @methodOf ng.$compile.directive.Attributes
- * @function
+ * @ngdoc method
+ * @name $compile.directive.Attributes#$removeClass
+ * @kind function
*
* @description
* Removes the CSS class value specified by the classVal parameter from the element. If
@@ -5241,6 +5872,31 @@ function $CompileProvider($provide) {
}
},
+ /**
+ * @ngdoc method
+ * @name $compile.directive.Attributes#$updateClass
+ * @kind function
+ *
+ * @description
+ * Adds and removes the appropriate CSS class values to the element based on the difference
+ * between the new and old CSS class values (specified as newClasses and oldClasses).
+ *
+ * @param {string} newClasses The current CSS className value
+ * @param {string} oldClasses The former CSS className value
+ */
+ $updateClass : function(newClasses, oldClasses) {
+ var toAdd = tokenDifference(newClasses, oldClasses);
+ var toRemove = tokenDifference(oldClasses, newClasses);
+
+ if(toAdd.length === 0) {
+ $animate.removeClass(this.$$element, toRemove);
+ } else if(toRemove.length === 0) {
+ $animate.addClass(this.$$element, toAdd);
+ } else {
+ $animate.setClass(this.$$element, toAdd, toRemove);
+ }
+ },
+
/**
* Set a normalized attribute on the element in a way such that all directives
* can share the attribute. This function properly handles boolean attributes.
@@ -5251,59 +5907,44 @@ function $CompileProvider($provide) {
* @param {string=} attrName Optional none normalized name. Defaults to key.
*/
$set: function(key, value, writeAttr, attrName) {
- //special case for class attribute addition + removal
- //so that class changes can tap into the animation
- //hooks provided by the $animate service
- if(key == 'class') {
- value = value || '';
- var current = this.$$element.attr('class') || '';
- this.$removeClass(tokenDifference(current, value).join(' '));
- this.$addClass(tokenDifference(value, current).join(' '));
+ // TODO: decide whether or not to throw an error if "class"
+ //is set through this function since it may cause $updateClass to
+ //become unstable.
+
+ var booleanKey = getBooleanAttrName(this.$$element[0], key),
+ normalizedVal,
+ nodeName;
+
+ if (booleanKey) {
+ this.$$element.prop(key, value);
+ attrName = booleanKey;
+ }
+
+ this[key] = value;
+
+ // translate normalized key to actual key
+ if (attrName) {
+ this.$attr[key] = attrName;
} else {
- var booleanKey = getBooleanAttrName(this.$$element[0], key),
- normalizedVal,
- nodeName;
-
- if (booleanKey) {
- this.$$element.prop(key, value);
- attrName = booleanKey;
+ attrName = this.$attr[key];
+ if (!attrName) {
+ this.$attr[key] = attrName = snake_case(key, '-');
}
+ }
- this[key] = value;
+ nodeName = nodeName_(this.$$element);
- // translate normalized key to actual key
- if (attrName) {
- this.$attr[key] = attrName;
+ // sanitize a[href] and img[src] values
+ if ((nodeName === 'A' && key === 'href') ||
+ (nodeName === 'IMG' && key === 'src')) {
+ this[key] = value = $$sanitizeUri(value, key === 'src');
+ }
+
+ if (writeAttr !== false) {
+ if (value === null || value === undefined) {
+ this.$$element.removeAttr(attrName);
} else {
- attrName = this.$attr[key];
- if (!attrName) {
- this.$attr[key] = attrName = snake_case(key, '-');
- }
- }
-
- nodeName = nodeName_(this.$$element);
-
- // sanitize a[href] and img[src] values
- if ((nodeName === 'A' && key === 'href') ||
- (nodeName === 'IMG' && key === 'src')) {
- // NOTE: urlResolve() doesn't support IE < 8 so we don't sanitize for that case.
- if (!msie || msie >= 8 ) {
- normalizedVal = urlResolve(value).href;
- if (normalizedVal !== '') {
- if ((key === 'href' && !normalizedVal.match(aHrefSanitizationWhitelist)) ||
- (key === 'src' && !normalizedVal.match(imgSrcSanitizationWhitelist))) {
- this[key] = value = 'unsafe:' + normalizedVal;
- }
- }
- }
- }
-
- if (writeAttr !== false) {
- if (value === null || value === undefined) {
- this.$$element.removeAttr(attrName);
- } else {
- this.$$element.attr(attrName, value);
- }
+ this.$$element.attr(attrName, value);
}
}
@@ -5316,30 +5957,13 @@ function $CompileProvider($provide) {
$exceptionHandler(e);
}
});
-
- function tokenDifference(str1, str2) {
- var values = [],
- tokens1 = str1.split(/\s+/),
- tokens2 = str2.split(/\s+/);
-
- outer:
- for(var i=0;i$document title:
+window.document title:
++ * ```js * angular.module('exceptionOverride', []).factory('$exceptionHandler', function () { * return function (exception, cause) { * exception.message += ' (caused by "' + cause + '")'; * throw exception; * }; * }); - *+ * ``` * * This example will override the normal action of `$exceptionHandler`, to make angular * exceptions fail hard when they happen, instead of just logging to the console. @@ -6667,11 +7433,7 @@ function parseHeaders(headers) { val = trim(line.substr(i + 1)); if (key) { - if (parsed[key]) { - parsed[key] += ', ' + val; - } else { - parsed[key] = val; - } + parsed[key] = parsed[key] ? parsed[key] + ', ' + val : val; } }); @@ -6713,7 +7475,7 @@ function headersGetter(headers) { * * @param {*} data Data to transform. * @param {function(string=)} headers Http headers getter fn. - * @param {(function|Array.
+ * ```js * $http({method: 'GET', url: '/someUrl'}). * success(function(data, status, headers, config) { * // this callback will be called asynchronously @@ -6861,7 +7659,7 @@ function $HttpProvider() { * // called asynchronously if an error occurs * // or server returns response with an error status. * }); - *+ * ``` * * 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 – @@ -6873,53 +7671,36 @@ function $HttpProvider() { * XMLHttpRequest will transparently follow it, meaning that the error callback will not be * called for such responses. * - * # Calling $http from outside AngularJS - * The `$http` service will not actually send the request until the next `$digest()` is - * executed. Normally this is not an issue, since almost all the time your call to `$http` will - * be from within a `$apply()` block. - * If you are calling `$http` from outside Angular, then you should wrap it in a call to - * `$apply` to cause a $digest to occur and also to handle errors in the block correctly. - * - * ``` - * $scope.$apply(function() { - * $http(...); - * }); - * ``` - * * # Writing Unit Tests that use $http - * When unit testing you are mostly responsible for scheduling the `$digest` cycle. If you do - * not trigger a `$digest` before calling `$httpBackend.flush()` then the request will not have - * been made and `$httpBackend.expect(...)` expectations will fail. The solution is to run the - * code that calls the `$http()` method inside a $apply block as explained in the previous - * section. + * When unit testing (using {@link ngMock ngMock}), it is necessary to call + * {@link ngMock.$httpBackend#flush $httpBackend.flush()} to flush each pending + * request using trained responses. * * ``` * $httpBackend.expectGET(...); - * $scope.$apply(function() { - * $http.get(...); - * }); + * $http.get(...); * $httpBackend.flush(); * ``` * * # Shortcut methods * - * 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: + * Shortcut methods are also available. All shortcut methods require passing in the URL, and + * request data must be passed in for POST/PUT requests. * - *
+ * ```js * $http.get('/someUrl').success(successCallback); * $http.post('/someUrl', data).success(successCallback); - *+ * ``` * * Complete list of shortcut methods: * - * - {@link ng.$http#methods_get $http.get} - * - {@link ng.$http#methods_head $http.head} - * - {@link ng.$http#methods_post $http.post} - * - {@link ng.$http#methods_put $http.put} - * - {@link ng.$http#methods_delete $http.delete} - * - {@link ng.$http#methods_jsonp $http.jsonp} + * - {@link ng.$http#get $http.get} + * - {@link ng.$http#head $http.head} + * - {@link ng.$http#post $http.post} + * - {@link ng.$http#put $http.put} + * - {@link ng.$http#delete $http.delete} + * - {@link ng.$http#jsonp $http.jsonp} + * - {@link ng.$http#patch $http.patch} * * * # Setting HTTP Headers @@ -6941,9 +7722,32 @@ function $HttpProvider() { * `$httpProvider.defaults.headers.get = { 'My-Header' : 'value' }. * * The defaults can also be set at runtime via the `$http.defaults` object in the same - * fashion. In addition, you can supply a `headers` property in the config object passed when + * fashion. For example: + * + * ``` + * module.run(function($http) { + * $http.defaults.headers.common.Authorization = 'Basic YmVlcDpib29w' + * }); + * ``` + * + * In addition, you can supply a `headers` property in the config object passed when * calling `$http(config)`, which overrides the defaults without changing them globally. * + * To explicitly remove a header automatically added via $httpProvider.defaults.headers on a per request basis, + * Use the `headers` property, setting the desired header to `undefined`. For example: + * + * ```js + * var req = { + * method: 'POST', + * url: 'http://example.com', + * headers: { + * 'Content-Type': undefined + * }, + * data: { test: 'test' }, + * } + * + * $http(req).success(function(){...}).error(function(){...}); + * ``` * * # Transforming Requests and Responses * @@ -6965,7 +7769,9 @@ function $HttpProvider() { * 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. + * transformation functions to these properties directly without the array wrapper. These defaults + * are again available on the $http factory at run-time, which may be useful if you have run-time + * services you wish to be involved in your transformations. * * Similarly, to locally override the request/response transforms, augment the * `transformRequest` and/or `transformResponse` properties of the configuration object passed @@ -6974,9 +7780,11 @@ function $HttpProvider() { * * # Caching * - * 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. + * To enable caching, set the request configuration `cache` property to `true` (to use default + * cache) or to a custom cache object (built with {@link ng.$cacheFactory `$cacheFactory`}). + * When the cache is enabled, `$http` stores the response from the server in the specified + * cache. The next time the same request is made, 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. @@ -6985,9 +7793,13 @@ function $HttpProvider() { * 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 from the first request. * - * A custom default cache built with $cacheFactory can be provided in $http.defaults.cache. - * To skip it, set configuration property `cache` to `false`. + * You can change the default cache to a new object (built with + * {@link ng.$cacheFactory `$cacheFactory`}) by updating the + * {@link ng.$http#properties_defaults `$http.defaults.cache`} property. All requests who set + * their `cache` property to `true` will now use this cache object. * + * If you set the default cache to `false` then only requests that specify their own custom + * cache object will be cached. * * # Interceptors * @@ -7007,26 +7819,26 @@ function $HttpProvider() { * * There are two kinds of interceptors (and two kinds of rejection interceptors): * - * * `request`: interceptors get called with http `config` object. The function is free to - * modify the `config` or create a new one. The function needs to return the `config` - * directly or as a promise. + * * `request`: interceptors get called with a http `config` object. The function is free to + * modify the `config` object or create a new one. The function needs to return the `config` + * object directly, or a promise containing the `config` or a new `config` object. * * `requestError`: interceptor gets called when a previous interceptor threw an error or * resolved with a rejection. * * `response`: interceptors get called with http `response` object. The function is free to - * modify the `response` or create a new one. The function needs to return the `response` - * directly or as a promise. + * modify the `response` object or create a new one. The function needs to return the `response` + * object directly, or as a promise containing the `response` or a new `response` object. * * `responseError`: interceptor gets called when a previous interceptor threw an error or * resolved with a rejection. * * - *
+ * ```js * // register the interceptor as a service * $provide.factory('myHttpInterceptor', function($q, dependency1, dependency2) { * return { * // optional method * 'request': function(config) { * // do something on success - * return config || $q.when(config); + * return config; * }, * * // optional method @@ -7043,7 +7855,7 @@ function $HttpProvider() { * // optional method * 'response': function(response) { * // do something on success - * return response || $q.when(response); + * return response; * }, * * // optional method @@ -7053,25 +7865,26 @@ function $HttpProvider() { * return responseOrNewPromise * } * return $q.reject(rejection); - * }; - * } + * } + * }; * }); * * $httpProvider.interceptors.push('myHttpInterceptor'); * * - * // register the interceptor via an anonymous factory + * // alternatively, register the interceptor via an anonymous factory * $httpProvider.interceptors.push(function($q, dependency1, dependency2) { * return { * 'request': function(config) { * // same as above * }, + * * 'response': function(response) { * // same as above * } * }; * }); - *+ * ``` * * # Response interceptors (DEPRECATED) * @@ -7089,7 +7902,7 @@ function $HttpProvider() { * 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. * - *
+ * ```js * // register the interceptor as a service * $provide.factory('myHttpInterceptor', function($q, dependency1, dependency2) { * return function(promise) { @@ -7115,16 +7928,15 @@ function $HttpProvider() { * // same as above * } * }); - *+ * ``` * * * # 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} - * - {@link http://en.wikipedia.org/wiki/Cross-site_request_forgery XSRF} + * - [JSON vulnerability](http://haacked.com/archive/2008/11/20/anatomy-of-a-subtle-json-vulnerability.aspx) + * - [XSRF](http://en.wikipedia.org/wiki/Cross-site_request_forgery) * * 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 @@ -7132,29 +7944,29 @@ function $HttpProvider() { * * ## JSON Vulnerability Protection * - * A {@link http://haacked.com/archive/2008/11/20/anatomy-of-a-subtle-json-vulnerability.aspx - * 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 + * A [JSON vulnerability](http://haacked.com/archive/2008/11/20/anatomy-of-a-subtle-json-vulnerability.aspx) + * allows third party website to turn your JSON resource URL into + * [JSONP](http://en.wikipedia.org/wiki/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: - *
+ * ```js * ['one','two'] - *+ * ``` * * which is vulnerable to attack, your server can return: - *
+ * ```js * )]}', * ['one','two'] - *+ * ``` * * Angular will strip the prefix, before processing the JSON. * * * ## Cross Site Request Forgery (XSRF) Protection * - * {@link http://en.wikipedia.org/wiki/Cross-site_request_forgery XSRF} is a technique by which + * [XSRF](http://en.wikipedia.org/wiki/Cross-site_request_forgery) is a technique by which * 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 * (by default, `XSRF-TOKEN`) and sets it as an HTTP header (`X-XSRF-TOKEN`). Since only @@ -7168,11 +7980,12 @@ function $HttpProvider() { * 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 a {@link https://en.wikipedia.org/wiki/Salt_(cryptography) salt} + * authentication cookie with a [salt](https://en.wikipedia.org/wiki/Salt_(cryptography)) * for added security. * * The name of the headers can be specified using the xsrfHeaderName and xsrfCookieName - * properties of either $httpProvider.defaults, or the per-request config object. + * properties of either $httpProvider.defaults at config-time, $http.defaults at run-time, + * or the per-request config object. * * * @param {object} config Object describing the request to be made and how it should be @@ -7203,11 +8016,11 @@ function $HttpProvider() { * caching. * - **timeout** – `{number|Promise}` – timeout in milliseconds, or {@link ng.$q promise} * that should abort the request when resolved. - * - **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. - * - **responseType** - `{string}` - see {@link - * https://developer.mozilla.org/en-US/docs/DOM/XMLHttpRequest#responseType requestType}. + * - **withCredentials** - `{boolean}` - whether to set the `withCredentials` flag on the + * XHR object. See [requests with credentials](https://developer.mozilla.org/docs/Web/HTTP/Access_control_CORS#Requests_with_credentials) + * for more information. + * - **responseType** - `{string}` - see + * [requestType](https://developer.mozilla.org/en-US/docs/DOM/XMLHttpRequest#responseType). * * @returns {HttpPromise} Returns a {@link ng.$q promise} object with the * standard `then` method and two http specific methods: `success` and `error`. The `then` @@ -7222,29 +8035,30 @@ function $HttpProvider() { * - **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. + * - **statusText** – `{string}` – HTTP status text of the response. * * @property {Array.