diff --git a/gui/default/vendor/angular/README.md b/gui/default/vendor/angular/README.md index 7bdff1ada..f727b0ce5 100644 --- a/gui/default/vendor/angular/README.md +++ b/gui/default/vendor/angular/README.md @@ -1,6 +1,6 @@ The files contained herein are: - - angular 1.5.3 + - angular 1.2.9 - angular-translate 2.9.0.1 - angular-translate-loader-static-files 2.11.0 - angular-dirPagination 759009c \ No newline at end of file diff --git a/gui/default/vendor/angular/angular.js b/gui/default/vendor/angular/angular.js index 5e6fb2c36..197110e88 100644 --- a/gui/default/vendor/angular/angular.js +++ b/gui/default/vendor/angular/angular.js @@ -1,6 +1,6 @@ /** - * @license AngularJS v1.5.3 - * (c) 2010-2016 Google, Inc. http://angularjs.org + * @license AngularJS v1.2.9 + * (c) 2010-2014 Google, Inc. http://angularjs.org * License: MIT */ (function(window, document, undefined) {'use strict'; @@ -30,168 +30,163 @@ * should all be static strings, not variables or general expressions. * * @param {string} module The namespace to use for the new minErr instance. - * @param {function} ErrorConstructor Custom error constructor to be instantiated when returning - * error from returned function, for cases when a particular type of error is useful. - * @returns {function(code:string, template:string, ...templateArgs): Error} minErr instance + * @returns {function(string, string, ...): Error} instance */ -function minErr(module, ErrorConstructor) { - ErrorConstructor = ErrorConstructor || Error; - return function() { - var SKIP_INDEXES = 2; +function minErr(module) { + return function () { + var code = arguments[0], + prefix = '[' + (module ? module + ':' : '') + code + '] ', + template = arguments[1], + templateArgs = arguments, + stringify = function (obj) { + if (typeof obj === 'function') { + return obj.toString().replace(/ \{[\s\S]*$/, ''); + } else if (typeof obj === 'undefined') { + return 'undefined'; + } else if (typeof obj !== 'string') { + return JSON.stringify(obj); + } + return obj; + }, + message, i; - var templateArgs = arguments, - code = templateArgs[0], - message = '[' + (module ? module + ':' : '') + code + '] ', - template = templateArgs[1], - paramPrefix, i; + message = prefix + template.replace(/\{\d+\}/g, function (match) { + var index = +match.slice(1, -1), arg; - message += template.replace(/\{\d+\}/g, function(match) { - var index = +match.slice(1, -1), - shiftedIndex = index + SKIP_INDEXES; - - if (shiftedIndex < templateArgs.length) { - return toDebugString(templateArgs[shiftedIndex]); + if (index + 2 < templateArgs.length) { + arg = templateArgs[index + 2]; + if (typeof arg === 'function') { + return arg.toString().replace(/ ?\{[\s\S]*$/, ''); + } else if (typeof arg === 'undefined') { + return 'undefined'; + } else if (typeof arg !== 'string') { + return toJson(arg); + } + return arg; } - return match; }); - message += '\nhttp://errors.angularjs.org/1.5.3/' + + message = message + '\nhttp://errors.angularjs.org/1.2.9/' + (module ? module + '/' : '') + code; - - for (i = SKIP_INDEXES, paramPrefix = '?'; i < templateArgs.length; i++, paramPrefix = '&') { - message += paramPrefix + 'p' + (i - SKIP_INDEXES) + '=' + - encodeURIComponent(toDebugString(templateArgs[i])); + for (i = 2; i < arguments.length; i++) { + message = message + (i == 2 ? '?' : '&') + 'p' + (i-2) + '=' + + encodeURIComponent(stringify(arguments[i])); } - return new ErrorConstructor(message); + return new Error(message); }; } /* We need to tell jshint what variables are being exported */ -/* global angular: true, - msie: true, - jqLite: true, - jQuery: true, - slice: true, - splice: true, - push: true, - toString: true, - ngMinErr: true, - angularModule: true, - uid: true, - REGEX_STRING_REGEXP: true, - VALIDITY_STATE_PROPERTY: true, +/* global + -angular, + -msie, + -jqLite, + -jQuery, + -slice, + -push, + -toString, + -ngMinErr, + -_angular, + -angularModule, + -nodeName_, + -uid, - lowercase: true, - uppercase: true, - manualLowercase: true, - manualUppercase: true, - nodeName_: true, - isArrayLike: true, - forEach: true, - forEachSorted: true, - reverseParams: true, - nextUid: true, - setHashKey: true, - extend: true, - toInt: true, - inherit: true, - merge: true, - noop: true, - identity: true, - valueFn: true, - isUndefined: true, - isDefined: true, - isObject: true, - isBlankObject: true, - isString: true, - isNumber: true, - isDate: true, - isArray: true, - isFunction: true, - isRegExp: true, - isWindow: true, - isScope: true, - isFile: true, - isFormData: true, - isBlob: true, - isBoolean: true, - isPromiseLike: true, - trim: true, - escapeForRegexp: true, - isElement: true, - makeMap: true, - includes: true, - arrayRemove: true, - copy: true, - shallowCopy: true, - equals: true, - csp: true, - jq: true, - concat: true, - sliceArgs: true, - bind: true, - toJsonReplacer: true, - toJson: true, - fromJson: true, - convertTimezoneToLocal: true, - timezoneToOffset: true, - startingTag: true, - tryDecodeURIComponent: true, - parseKeyValue: true, - toKeyValue: true, - encodeUriSegment: true, - encodeUriQuery: true, - angularInit: true, - bootstrap: true, - getTestability: true, - snake_case: true, - bindJQuery: true, - assertArg: true, - assertArgFn: true, - assertNotHasOwnProperty: true, - getter: true, - getBlockNodes: true, - hasOwnProperty: true, - createMap: true, + -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, - NODE_TYPE_ELEMENT: true, - NODE_TYPE_ATTRIBUTE: true, - NODE_TYPE_TEXT: true, - NODE_TYPE_COMMENT: true, - NODE_TYPE_DOCUMENT: true, - NODE_TYPE_DOCUMENT_FRAGMENT: true, */ //////////////////////////////////// /** - * @ngdoc module - * @name ng - * @module ng - * @description + * @ngdoc function + * @name angular.lowercase + * @function * - * # 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. - * - *
+ * @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 REGEX_STRING_REGEXP = /^\/(.+)\/([a-z]*)$/; -// 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'; - -var hasOwnProperty = Object.prototype.hasOwnProperty; - -var lowercase = function(string) {return isString(string) ? string.toLowerCase() : string;}; -var uppercase = function(string) {return isString(string) ? string.toUpperCase() : string;}; +/** + * @ngdoc function + * @name angular.uppercase + * @function + * + * @description Converts the specified string to uppercase. + * @param {string} string String to be converted to uppercase. + * @returns {string} Uppercased string. + */ +var uppercase = function(string){return isString(string) ? string.toUpperCase() : string;}; var manualLowercase = function(s) { @@ -210,34 +205,38 @@ var manualUppercase = function(s) { // String#toLowerCase and String#toUpperCase don't produce correct results in browsers with Turkish // locale, for this reason we need to detect this case and redefine lowercase/uppercase methods -// with correct but slower alternatives. See https://github.com/angular/angular.js/issues/11387 +// with correct but slower alternatives. if ('i' !== 'I'.toLowerCase()) { lowercase = manualLowercase; uppercase = manualUppercase; } -var - msie, // holds major version number for IE, or NaN if UA is not IE. +var /** holds major version number for IE or NaN for real browsers */ + msie, jqLite, // delay binding since jQuery could be loaded after us. jQuery, // delay binding slice = [].slice, - splice = [].splice, push = [].push, toString = Object.prototype.toString, - getPrototypeOf = Object.getPrototypeOf, ngMinErr = minErr('ng'), + + _angular = window.angular, /** @name angular */ angular = window.angular || (window.angular = {}), angularModule, - uid = 0; + nodeName_, + uid = ['0', '0', '0']; /** - * documentMode is an IE-only property - * http://msdn.microsoft.com/en-us/library/ie/cc196988(v=vs.85).aspx + * IE 11 changed the format of the UserAgent string. + * See http://msdn.microsoft.com/en-us/library/ms537503.aspx */ -msie = document.documentMode; +msie = int((/msie (\d+)/.exec(lowercase(navigator.userAgent)) || [])[1]); +if (isNaN(msie)) { + msie = int((/trident\/.*; rv:(\d+)/.exec(lowercase(navigator.userAgent)) || [])[1]); +} /** @@ -247,99 +246,68 @@ msie = document.documentMode; * String ...) */ function isArrayLike(obj) { + if (obj == null || isWindow(obj)) { + return false; + } - // `null`, `undefined` and `window` are not array-like - if (obj == null || isWindow(obj)) return false; + var length = obj.length; - // arrays, strings and jQuery/jqLite objects are array like - // * jqLite is either the jQuery or jqLite constructor function - // * we have to check the existence of jqLite first as this method is called - // via the forEach method when constructing the jqLite object in the first place - if (isArray(obj) || isString(obj) || (jqLite && obj instanceof jqLite)) return true; - - // Support: iOS 8.2 (not reproducible in simulator) - // "length" in obj used to prevent JIT error (gh-11508) - var length = "length" in Object(obj) && obj.length; - - // NodeList objects (with `item` method) and - // other objects with suitable length characteristics are array-like - return isNumber(length) && - (length >= 0 && ((length - 1) in obj || obj instanceof Array) || typeof obj.item == 'function'); + if (obj.nodeType === 1 && length) { + return true; + } + return isString(obj) || isArray(obj) || length === 0 || + typeof length === 'number' && length > 0 && (length - 1) in obj; } /** * @ngdoc function * @name angular.forEach - * @module ng - * @kind function + * @function * * @description * Invokes the `iterator` function once for each item in `obj` collection, which can be either an - * object or an array. The `iterator` function is invoked with `iterator(value, key, obj)`, where `value` - * is the value of an object property or an array element, `key` is the object property key or - * array element index and obj is the `obj` itself. Specifying a `context` for the function is optional. + * object or an array. The `iterator` function is invoked with `iterator(value, key)`, where `value` + * 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. * - * It is worth noting that `.forEach` does not iterate over inherited properties because it filters + * It is worth nothing that `.forEach` does not iterate over inherited properties because it filters * using the `hasOwnProperty` method. * - * Unlike ES262's - * [Array.prototype.forEach](http://www.ecma-international.org/ecma-262/5.1/#sec-15.4.4.18), - * providing 'undefined' or 'null' values for `obj` will not throw a TypeError, but rather just - * return the value provided. - * - ```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. * @param {Object=} context Object to become context (`this`) for the iterator function. * @returns {Object|Array} Reference to `obj`. */ - function forEach(obj, iterator, context) { - var key, length; + var key; if (obj) { - if (isFunction(obj)) { + if (isFunction(obj)){ for (key in obj) { // 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, obj); - } - } - } else if (isArray(obj) || isArrayLike(obj)) { - var isPrimitive = typeof obj !== 'object'; - for (key = 0, length = obj.length; key < length; key++) { - if (isPrimitive || key in obj) { - iterator.call(context, obj[key], key, obj); + iterator.call(context, obj[key], key); } } } else if (obj.forEach && obj.forEach !== forEach) { - obj.forEach(iterator, context, obj); - } else if (isBlankObject(obj)) { - // createMap() fast path --- Safe to avoid hasOwnProperty check because prototype chain is empty - for (key in obj) { - iterator.call(context, obj[key], key, obj); - } - } else if (typeof obj.hasOwnProperty === 'function') { - // Slow path for objects inheriting Object.prototype, hasOwnProperty check needed + obj.forEach(iterator, context); + } else if (isArrayLike(obj)) { + for (key = 0; key < obj.length; key++) + iterator.call(context, obj[key], key); + } else { for (key in obj) { if (obj.hasOwnProperty(key)) { - iterator.call(context, obj[key], key, obj); - } - } - } else { - // Slow path for objects which do not have a method `hasOwnProperty` - for (key in obj) { - if (hasOwnProperty.call(obj, key)) { - iterator.call(context, obj[key], key, obj); + iterator.call(context, obj[key], key); } } } @@ -347,9 +315,19 @@ function forEach(obj, iterator, context) { return obj; } +function sortedKeys(obj) { + var keys = []; + for (var key in obj) { + if (obj.hasOwnProperty(key)) { + keys.push(key); + } + } + return keys.sort(); +} + function forEachSorted(obj, iterator, context) { - var keys = Object.keys(obj).sort(); - for (var i = 0; i < keys.length; i++) { + var keys = sortedKeys(obj); + for ( var i = 0; i < keys.length; i++) { iterator.call(context, obj[keys[i]], keys[i]); } return keys; @@ -362,21 +340,37 @@ function forEachSorted(obj, iterator, context) { * @returns {function(*, string)} */ function reverseParams(iteratorFn) { - return function(value, key) {iteratorFn(key, value);}; + return function(value, key) { iteratorFn(key, value); }; } /** - * A consistent way of creating unique IDs in angular. + * A consistent way of creating unique IDs in angular. The ID is a sequence of alpha numeric + * characters such as '012ABC'. The reason why we are not using simply a number counter is that + * 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. * - * Using simple numbers allows us to generate 28.6 million unique ids per second for 10 years before - * we hit number precision issues in JavaScript. - * - * Math.pow(2,53) / 60 / 60 / 24 / 365 / 10 = 28.6M - * - * @returns {number} an unique alpha-numeric string + * @returns an unique alpha-numeric string */ function nextUid() { - return ++uid; + var index = uid.length; + var digit; + + while(index) { + index--; + digit = uid[index].charCodeAt(0); + if (digit == 57 /*'9'*/) { + uid[index] = 'A'; + return uid.join(''); + } + if (digit == 90 /*'Z'*/) { + uid[index] = '0'; + } else { + uid[index] = String.fromCharCode(digit + 1); + return uid.join(''); + } + } + uid.unshift('0'); + return uid.join(''); } @@ -388,117 +382,62 @@ function nextUid() { function setHashKey(obj, h) { if (h) { obj.$$hashKey = h; - } else { + } + else { delete obj.$$hashKey; } } - -function baseExtend(dst, objs, deep) { - var h = dst.$$hashKey; - - for (var i = 0, ii = objs.length; i < ii; ++i) { - var obj = objs[i]; - if (!isObject(obj) && !isFunction(obj)) continue; - var keys = Object.keys(obj); - for (var j = 0, jj = keys.length; j < jj; j++) { - var key = keys[j]; - var src = obj[key]; - - if (deep && isObject(src)) { - if (isDate(src)) { - dst[key] = new Date(src.valueOf()); - } else if (isRegExp(src)) { - dst[key] = new RegExp(src); - } else if (src.nodeName) { - dst[key] = src.cloneNode(true); - } else if (isElement(src)) { - dst[key] = src.clone(); - } else { - if (!isObject(dst[key])) dst[key] = isArray(src) ? [] : {}; - baseExtend(dst[key], [src], true); - } - } else { - dst[key] = src; - } - } - } - - setHashKey(dst, h); - return dst; -} - /** * @ngdoc function * @name angular.extend - * @module ng - * @kind function + * @function * * @description - * Extends the destination object `dst` by copying own enumerable properties from the `src` object(s) - * to `dst`. You can specify multiple `src` objects. If you want to preserve original objects, you can do so - * by passing an empty object as the target: `var object = angular.extend({}, object1, object2)`. - * - * **Note:** Keep in mind that `angular.extend` does not support recursive merge (deep copy). Use - * {@link angular.merge} for this. + * Extends the destination object `dst` by copying all of the properties from the `src` object(s) + * to `dst`. You can specify multiple `src` objects. * * @param {Object} dst Destination object. * @param {...Object} src Source object(s). * @returns {Object} Reference to `dst`. */ function extend(dst) { - return baseExtend(dst, slice.call(arguments, 1), false); + var h = dst.$$hashKey; + forEach(arguments, function(obj){ + if (obj !== dst) { + forEach(obj, function(value, key){ + dst[key] = value; + }); + } + }); + + setHashKey(dst,h); + return dst; } - -/** -* @ngdoc function -* @name angular.merge -* @module ng -* @kind function -* -* @description -* Deeply extends the destination object `dst` by copying own enumerable properties from the `src` object(s) -* to `dst`. You can specify multiple `src` objects. If you want to preserve original objects, you can do so -* by passing an empty object as the target: `var object = angular.merge({}, object1, object2)`. -* -* Unlike {@link angular.extend extend()}, `merge()` recursively descends into object properties of source -* objects, performing a deep copy. -* -* @param {Object} dst Destination object. -* @param {...Object} src Source object(s). -* @returns {Object} Reference to `dst`. -*/ -function merge(dst) { - return baseExtend(dst, slice.call(arguments, 1), true); -} - - - -function toInt(str) { +function int(str) { return parseInt(str, 10); } function inherit(parent, extra) { - return extend(Object.create(parent), extra); + return extend(new (extend(function() {}, {prototype:parent}))(), extra); } /** * @ngdoc function * @name angular.noop - * @module ng - * @kind function + * @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 = []; @@ -507,37 +446,28 @@ noop.$inject = []; /** * @ngdoc function * @name angular.identity - * @module ng - * @kind function + * @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 = []; -function valueFn(value) {return function valueRef() {return value;};} - -function hasCustomToString(obj) { - return isFunction(obj.toString) && obj.toString !== toString; -} - +function valueFn(value) {return function() {return value;};} /** * @ngdoc function * @name angular.isUndefined - * @module ng - * @kind function + * @function * * @description * Determines if a reference is undefined. @@ -545,14 +475,13 @@ function hasCustomToString(obj) { * @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 - * @module ng - * @kind function + * @function * * @description * Determines if a reference is defined. @@ -560,43 +489,28 @@ 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 - * @module ng - * @kind function + * @function * * @description * Determines if a reference is an `Object`. Unlike `typeof` in JavaScript, `null`s are not - * considered to be objects. Note that JavaScript arrays are objects. + * considered to be objects. * * @param {*} value Reference to check. * @returns {boolean} True if `value` is an `Object` but not `null`. */ -function isObject(value) { - // http://jsperf.com/isobject4 - return value !== null && typeof value === 'object'; -} - - -/** - * Determine if a value is an object with a null prototype - * - * @returns {boolean} True if `value` is an `Object` with a null prototype - */ -function isBlankObject(value) { - return value !== null && typeof value === 'object' && !getPrototypeOf(value); -} +function isObject(value){return value != null && typeof value === 'object';} /** * @ngdoc function * @name angular.isString - * @module ng - * @kind function + * @function * * @description * Determines if a reference is a `String`. @@ -604,35 +518,27 @@ function isBlankObject(value) { * @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 - * @module ng - * @kind function + * @function * * @description * Determines if a reference is a `Number`. * - * This includes the "special" numbers `NaN`, `+Infinity` and `-Infinity`. - * - * If you wish to exclude these then you can use the native - * [`isFinite'](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/isFinite) - * method. - * * @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 - * @module ng - * @kind function + * @function * * @description * Determines if a value is a date. @@ -640,7 +546,7 @@ function isNumber(value) {return typeof value === 'number';} * @param {*} value Reference to check. * @returns {boolean} True if `value` is a `Date`. */ -function isDate(value) { +function isDate(value){ return toString.call(value) === '[object Date]'; } @@ -648,8 +554,7 @@ function isDate(value) { /** * @ngdoc function * @name angular.isArray - * @module ng - * @kind function + * @function * * @description * Determines if a reference is an `Array`. @@ -657,13 +562,15 @@ function isDate(value) { * @param {*} value Reference to check. * @returns {boolean} True if `value` is an `Array`. */ -var isArray = Array.isArray; +function isArray(value) { + return toString.call(value) === '[object Array]'; +} + /** * @ngdoc function * @name angular.isFunction - * @module ng - * @kind function + * @function * * @description * Determines if a reference is a `Function`. @@ -671,7 +578,7 @@ var isArray = Array.isArray; * @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';} /** @@ -694,7 +601,7 @@ function isRegExp(value) { * @returns {boolean} True if `obj` is a window obj. */ function isWindow(obj) { - return obj && obj.window === obj; + return obj && obj.document && obj.location && obj.alert && obj.setInterval; } @@ -708,54 +615,30 @@ function isFile(obj) { } -function isFormData(obj) { - return toString.call(obj) === '[object FormData]'; -} - - -function isBlob(obj) { - return toString.call(obj) === '[object Blob]'; -} - - function isBoolean(value) { return typeof value === 'boolean'; } -function isPromiseLike(obj) { - return obj && isFunction(obj.then); -} - - -var TYPED_ARRAY_REGEXP = /^\[object (?:Uint8|Uint8Clamped|Uint16|Uint32|Int8|Int16|Int32|Float32|Float64)Array\]$/; -function isTypedArray(value) { - return value && isNumber(value.length) && TYPED_ARRAY_REGEXP.test(toString.call(value)); -} - -function isArrayBuffer(obj) { - return toString.call(obj) === '[object ArrayBuffer]'; -} - - -var trim = function(value) { - return isString(value) ? value.trim() : value; -}; - -// Copied from: -// http://docs.closure-library.googlecode.com/git/local_closure_goog_string_string.js.source.html#line1021 -// Prereq: s is a string. -var escapeForRegexp = function(s) { - return s.replace(/([-()\[\]{}+?*.$\^|,:#= 0) { + var index = indexOf(array, value); + if (index >=0) array.splice(index, 1); + return value; +} + +function isLeafNode (node) { + if (node) { + switch (node.nodeName) { + case "OPTION": + case "PRE": + case "TITLE": + return true; + } } - return index; + return false; } /** * @ngdoc function * @name angular.copy - * @module ng - * @kind function + * @function * * @description * Creates a deep copy of `source`, which should be an object or an array. * * * If no destination is supplied, a copy of the object or array is created. - * * If a destination is provided, all of its elements (for arrays) or properties (for objects) + * * If a destination is provided, all of its elements (for array) or properties (for objects) * are deleted and then all elements/properties from the source are copied to it. * * If `source` is not an object or array (inc. `null` and `undefined`), `source` is returned. * * If `source` is identical to 'destination' an exception will be thrown. @@ -820,9 +766,9 @@ function arrayRemove(array, value) { * @returns {*} The copy or updated `destination`, if `destination` was specified. * * @example -
This renders because the controller does not fail to - instantiate, by using explicit annotation style (see - script.js for details) -
-This renders because the controller does not fail to - instantiate, by using explicit annotation style - (see script.js for details) -
-The controller could not be instantiated, due to relying - on automatic function annotations (which are disabled in - strict mode). As such, the content of this section is not - interpolated, and there should be an error in your web console. -
-* // Create a new module * var myModule = angular.module('myModule', []); * @@ -1995,28 +1490,28 @@ function setupModuleLoader(window) { * myModule.value('appName', 'MyCoolApp'); * * // configure existing services inside initialization blocks. - * myModule.config(['$locationProvider', function($locationProvider) { + * myModule.config(function($locationProvider) { * // Configure existing providers * $locationProvider.hashPrefix('!'); - * }]); - * ``` + * }); + ** * Then you can create an injector and load your modules like this: * - * ```js - * var injector = angular.injector(['ng', 'myModule']) - * ``` + *
+ * 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.
* module.animation('.animation-name', function($inject1, $inject2) { * return { * eventName : function(element, done) { @@ -2172,86 +1650,64 @@ function setupModuleLoader(window) { * } * } * }) - * ``` + ** - * See {@link ng.$animateProvider#register $animateProvider.register()} and + * See {@link ngAnimate.$animateProvider#register $animateProvider.register()} and * {@link ngAnimate ngAnimate module} for more information. */ - animation: invokeLaterAndSetModuleName('$animateProvider', 'register'), + animation: invokeLater('$animateProvider', 'register'), /** * @ngdoc method * @name angular.Module#filter - * @module ng - * @param {string} name Filter name - this must be a valid angular expression identifier + * @methodOf angular.Module + * @param {string} name Filter name. * @param {Function} filterFactory Factory function for creating new instance of filter. * @description * See {@link ng.$filterProvider#register $filterProvider.register()}. - * - *
* // create an injector * var $injector = angular.injector(['ng']); * * // use the injector to kick off your application * // use the type inference to auto inject arguments, or use implicit injection - * $injector.invoke(function($rootScope, $compile, $document) { + * $injector.invoke(function($rootScope, $compile, $document){ * $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 + * application has been bootstrapped. You can do this using 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 @@ -3804,7 +2966,7 @@ var $$HashMapProvider = [function() { * 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 = $('*/ /** - * @ngdoc module - * @name auto + * @ngdoc overview + * @name AUTO * @description * - * Implicit module which gets automatically added to each {@link auto.$injector $injector}. + * Implicit module which gets automatically added to each {@link AUTO.$injector $injector}. */ -var ARROW_ARG = /^([^\(]+?)=>/; -var FN_ARGS = /^[^\(]*\(\s*([^\)]*)\)/m; +var FN_ARGS = /^function\s*[^\(]*\(\s*([^\)]*)\)/m; var FN_ARG_SPLIT = /,/; var FN_ARG = /^\s*(_?)(\S+?)\1\s*$/; var STRIP_COMMENTS = /((\/\/.*$)|(\/\*[\s\S]*?\*\/))/mg; var $injectorMinErr = minErr('$injector'); - -function extractArgs(fn) { - var fnText = fn.toString().replace(STRIP_COMMENTS, ''), - args = fnText.match(ARROW_ARG) || fnText.match(FN_ARGS); - return args; -} - -function anonFn(fn) { - // For anonymous functions, showing at the very least the function signature can help in - // debugging. - var args = extractArgs(fn); - if (args) { - return 'function(' + (args[1] || '').replace(/[\s\r\n]+/, ' ') + ')'; - } - return 'fn'; -} - -function annotate(fn, strictDi, name) { +function annotate(fn) { var $inject, + fnText, argDecl, last; - if (typeof fn === 'function') { + if (typeof fn == 'function') { if (!($inject = fn.$inject)) { $inject = []; if (fn.length) { - if (strictDi) { - if (!isString(name) || !name) { - name = fn.name || anonFn(fn); - } - throw $injectorMinErr('strictdi', - '{0} is not using explicit annotation and cannot be invoked in strict mode', name); - } - argDecl = extractArgs(fn); - forEach(argDecl[1].split(FN_ARG_SPLIT), function(arg) { - arg.replace(FN_ARG, function(all, underscore, name) { + fnText = fn.toString().replace(STRIP_COMMENTS, ''); + argDecl = fnText.match(FN_ARGS); + forEach(argDecl[1].split(FN_ARG_SPLIT), function(arg){ + arg.replace(FN_ARG, function(all, underscore, name){ $inject.push(name); }); }); @@ -3885,31 +3024,32 @@ function annotate(fn, strictDi, name) { /////////////////////////////////////// /** - * @ngdoc service - * @name $injector + * @ngdoc object + * @name AUTO.$injector + * @function * * @description * * `$injector` is used to retrieve object instances as defined by - * {@link auto.$provide provider}, instantiate types, invoke methods, + * {@link AUTO.$provide provider}, instantiate types, invoke methods, * and load modules. * * The following always holds true: * - * ```js + *{{content.label}}'); * $(document.body).append($div); * @@ -3812,60 +2974,37 @@ var $$HashMapProvider = [function() { * var scope = angular.element($div).scope(); * $compile($div)(scope); * }); - * ``` + *
* var $injector = angular.injector(); * expect($injector.get('$injector')).toBe($injector); - * expect($injector.invoke(function($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){}); * @@ -3920,18 +3060,16 @@ function annotate(fn, strictDi, name) { * * // inline * $injector.invoke(['serviceA', function(serviceA){}]); - * ``` + ** * ## Inference * * In JavaScript calling `toString()` on a function returns the function definition. The definition - * can then be parsed and the function arguments can be extracted. This method of discovering - * annotations is disallowed when the injector is in strict mode. - * *NOTE:* This does not work with minification, and obfuscation tools since these tools change the - * argument names. + * can then be parsed and the function arguments can be extracted. *NOTE:* This does not work with + * minification, and obfuscation tools since these tools change the argument names. * * ## `$inject` Annotation - * By adding an `$inject` property onto a function the injection parameters can be specified. + * By adding a `$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. @@ -3939,25 +3077,26 @@ function annotate(fn, strictDi, name) { /** * @ngdoc method - * @name $injector#get + * @name AUTO.$injector#get + * @methodOf AUTO.$injector * * @description * Return an instance of the service. * * @param {string} name The name of the instance to retrieve. - * @param {string=} caller An optional string to provide the origin of the function call for error messages. * @return {*} The instance. */ /** * @ngdoc method - * @name $injector#invoke + * @name AUTO.$injector#invoke + * @methodOf AUTO.$injector * * @description * Invoke the method and supply the method arguments from the `$injector`. * - * @param {Function|Array.
* // Given * function MyController($scope, $route) { * // ... @@ -4012,9 +3154,7 @@ function annotate(fn, strictDi, name) { * * // Then * expect(injector.annotate(MyController)).toEqual(['$scope', '$route']); - * ``` - * - * You can disallow this method by using strict injection mode. + ** * This method does not work with code minification / obfuscation. For this reason the following * annotation strategies are supported. @@ -4023,7 +3163,7 @@ function annotate(fn, strictDi, name) { * * 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) { * // ... @@ -4033,7 +3173,7 @@ function annotate(fn, strictDi, name) { * * // Then * expect(injector.annotate(MyController)).toEqual(['$scope', '$route']); - * ``` + ** * # The array notation * @@ -4041,7 +3181,7 @@ function annotate(fn, strictDi, name) { * 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) { * // ... @@ -4063,13 +3203,11 @@ function annotate(fn, strictDi, name) { * expect(injector.annotate( * ['$compile', '$rootScope', function(obfus_$compile, obfus_$rootScope) {}]) * ).toEqual(['$compile', '$rootScope']); - * ``` + ** - * @param {Function|Array.
* // Define the eventTracker provider * function EventTrackerProvider() { * var trackingUrl = '/track'; @@ -4209,110 +3350,102 @@ function annotate(fn, strictDi, name) { * expect(postSpy.mostRecentCall.args[1]).toEqual({ 'login': 1 }); * })); * }); - * ``` + **/ /** * @ngdoc method - * @name $provide#factory + * @name AUTO.$provide#factory + * @methodOf AUTO.$provide * @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. - * @param {Function|Array.
* $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 $provide#service + * @name AUTO.$provide#service + * @methodOf AUTO.$provide * @description * * Register a **service constructor**, which will be invoked with `new` to create the service * instance. - * This is short for registering a service where its provider's `$get` property is a factory - * function that returns an instance instantiated by the injector from the service constructor - * function. + * 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. * - * Internally it looks a bit like this: - * - * ``` - * { - * $get: function() { - * return $injector.instantiate(constructor); - * } - * } - * ``` - * - * - * You should use {@link auto.$provide#service $provide.service(class)} if you define your service + * You should use {@link AUTO.$provide#methods_service $provide.service(class)} if you define your service * as a type/class. * * @param {string} name The name of the instance. - * @param {Function|Array.
+ * $provide.service('ping', ['$http', function($http) { + * var Ping = function() { + * this.$http = $http; + * }; + * + * Ping.prototype.send = function() { + * return this.$http.get('/ping'); + * }; + * + * return Ping; + * }]); + ** You would then inject and use this service like this: - * ```js + *
* someModule.controller('Ctrl', ['ping', function(ping) { * ping.send(); * }]); - * ``` + **/ /** * @ngdoc method - * @name $provide#value + * @name AUTO.$provide#value + * @methodOf AUTO.$provide * @description * - * 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 + * 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**. That also means it is not possible to inject other services into a value service. + * service**. * * 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}. + * an Angular + * {@link AUTO.$provide#decorator decorator}. * * @param {string} name The name of the instance. * @param {*} value The value. @@ -4320,7 +3453,7 @@ function annotate(fn, strictDi, name) { * * @example * Here are some examples of creating value services. - * ```js + *
* $provide.value('ADMIN_USER', 'admin'); * * $provide.value('RoleLookup', { admin: 0, writer: 1, reader: 2 }); @@ -4328,22 +3461,20 @@ function annotate(fn, strictDi, name) { * $provide.value('halfOf', function(value) { * return value / 2; * }); - * ``` + **/ /** * @ngdoc method - * @name $provide#constant + * @name AUTO.$provide#constant + * @methodOf AUTO.$provide * @description * - * Register a **constant service** with the {@link auto.$injector $injector}, such as a string, - * a number, an array, an object or a function. Like the {@link auto.$provide#value value}, it is not - * possible to inject other services into a constant. - * - * But unlike {@link auto.$provide#value value}, a constant can be + * 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 * 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. @@ -4351,7 +3482,7 @@ function annotate(fn, strictDi, name) { * * @example * Here a some examples of creating constants: - * ```js + *
* $provide.constant('SHARD_HEIGHT', 306); * * $provide.constant('MY_COLOURS', ['red', 'blue', 'grey']); @@ -4359,24 +3490,25 @@ function annotate(fn, strictDi, name) { * $provide.constant('double', function(value) { * return value * 2; * }); - * ``` + **/ /** * @ngdoc method - * @name $provide#decorator + * @name AUTO.$provide#decorator + * @methodOf AUTO.$provide * @description * - * 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 behavior of the + * 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. * * @param {string} name The name of the service to decorate. - * @param {Function|Array.
+ * $provider.decorator('$log', ['$delegate', function($delegate) { * $delegate.warn = $delegate.error; * return $delegate; * }]); - * ``` + **/ -function createInjector(modulesToLoad, strictDi) { - strictDi = (strictDi === true); +function createInjector(modulesToLoad) { var INSTANTIATING = {}, providerSuffix = 'Provider', path = [], - loadedModules = new HashMap([], true), + loadedModules = new HashMap(), providerCache = { $provide: { provider: supportObject(provider), @@ -4411,26 +3542,18 @@ function createInjector(modulesToLoad, strictDi) { } }, providerInjector = (providerCache.$injector = - createInternalInjector(providerCache, function(serviceName, caller) { - if (angular.isString(caller)) { - path.push(caller); - } + createInternalInjector(providerCache, function() { throw $injectorMinErr('unpr', "Unknown provider: {0}", path.join(' <- ')); })), instanceCache = {}, - protoInstanceInjector = - createInternalInjector(instanceCache, function(serviceName, caller) { - var provider = providerInjector.get(serviceName + providerSuffix, caller); - return instanceInjector.invoke( - provider.$get, provider, undefined, serviceName); - }), - instanceInjector = protoInstanceInjector; + instanceInjector = (instanceCache.$injector = + createInternalInjector(instanceCache, function(servicename) { + var provider = providerInjector.get(servicename + providerSuffix); + return instanceInjector.invoke(provider.$get, provider); + })); - providerCache['$injector' + providerSuffix] = { $get: valueFn(protoInstanceInjector) }; - var runBlocks = loadModules(modulesToLoad); - instanceInjector = protoInstanceInjector.get('$injector'); - instanceInjector.strictDi = strictDi; - forEach(runBlocks, function(fn) { if (fn) instanceInjector.invoke(fn); }); + + forEach(loadModules(modulesToLoad), function(fn) { instanceInjector.invoke(fn || noop); }); return instanceInjector; @@ -4459,21 +3582,7 @@ function createInjector(modulesToLoad, strictDi) { return providerCache[name + providerSuffix] = provider_; } - function enforceReturnValue(name, factory) { - return function enforcedReturnValue() { - var result = instanceInjector.invoke(factory, this); - if (isUndefined(result)) { - throw $injectorMinErr('undef', "Provider '{0}' must return a value from $get factory method.", name); - } - return result; - }; - } - - function factory(name, factoryFn, enforce) { - return provider(name, { - $get: enforce !== false ? enforceReturnValue(name, factoryFn) : factoryFn - }); - } + function factory(name, factoryFn) { return provider(name, { $get: factoryFn }); } function service(name, constructor) { return factory(name, ['$injector', function($injector) { @@ -4481,7 +3590,7 @@ function createInjector(modulesToLoad, strictDi) { }]); } - function value(name, val) { return factory(name, valueFn(val), false); } + function value(name, val) { return factory(name, valueFn(val)); } function constant(name, value) { assertNotHasOwnProperty(name, 'constant'); @@ -4502,29 +3611,23 @@ function createInjector(modulesToLoad, strictDi) { //////////////////////////////////// // Module Loading //////////////////////////////////// - function loadModules(modulesToLoad) { - assertArg(isUndefined(modulesToLoad) || isArray(modulesToLoad), 'modulesToLoad', 'not an array'); - var runBlocks = [], moduleFn; + function loadModules(modulesToLoad){ + var runBlocks = [], moduleFn, invokeQueue, i, ii; forEach(modulesToLoad, function(module) { if (loadedModules.get(module)) return; loadedModules.put(module, true); - function runInvokeQueue(queue) { - var i, ii; - for (i = 0, ii = queue.length; i < ii; i++) { - var invokeArgs = queue[i], - provider = providerInjector.get(invokeArgs[0]); - - provider[invokeArgs[1]].apply(provider, invokeArgs[2]); - } - } - try { if (isString(module)) { moduleFn = angularModule(module); runBlocks = runBlocks.concat(loadModules(moduleFn.requires)).concat(moduleFn._runBlocks); - runInvokeQueue(moduleFn._invokeQueue); - runInvokeQueue(moduleFn._configBlocks); + + for(invokeQueue = moduleFn._invokeQueue, i = 0, ii = invokeQueue.length; i < ii; i++) { + var invokeArgs = invokeQueue[i], + provider = providerInjector.get(invokeArgs[0]); + + provider[invokeArgs[1]].apply(provider, invokeArgs[2]); + } } else if (isFunction(module)) { runBlocks.push(providerInjector.invoke(module)); } else if (isArray(module)) { @@ -4557,18 +3660,17 @@ function createInjector(modulesToLoad, strictDi) { function createInternalInjector(cache, factory) { - function getService(serviceName, caller) { + function getService(serviceName) { if (cache.hasOwnProperty(serviceName)) { if (cache[serviceName] === INSTANTIATING) { - throw $injectorMinErr('cdep', 'Circular dependency found: {0}', - serviceName + ' <- ' + path.join(' <- ')); + throw $injectorMinErr('cdep', 'Circular dependency found: {0}', path.join(' <- ')); } return cache[serviceName]; } else { try { path.unshift(serviceName); cache[serviceName] = INSTANTIATING; - return cache[serviceName] = factory(serviceName, caller); + return cache[serviceName] = factory(serviceName); } catch (err) { if (cache[serviceName] === INSTANTIATING) { delete cache[serviceName]; @@ -4580,72 +3682,52 @@ function createInjector(modulesToLoad, strictDi) { } } - - function injectionArgs(fn, locals, serviceName) { + function invoke(fn, self, locals){ var args = [], - $inject = createInjector.$$annotate(fn, strictDi, serviceName); + $inject = annotate(fn), + length, i, + key; - for (var i = 0, length = $inject.length; i < length; i++) { - var key = $inject[i]; + for(i = 0, length = $inject.length; i < length; i++) { + key = $inject[i]; if (typeof key !== 'string') { throw $injectorMinErr('itkn', 'Incorrect injection token! Expected service name as string, got {0}', key); } - args.push(locals && locals.hasOwnProperty(key) ? locals[key] : - getService(key, serviceName)); + args.push( + locals && locals.hasOwnProperty(key) + ? locals[key] + : getService(key) + ); } - return args; + if (!fn.$inject) { + // this means that we must be an array. + fn = fn[length]; + } + + // http://jsperf.com/angularjs-invoke-apply-vs-switch + // #5388 + return fn.apply(self, args); } - function isClass(func) { - // IE 9-11 do not support classes and IE9 leaks with the code below. - if (msie <= 11) { - return false; - } - // Workaround for MS Edge. - // Check https://connect.microsoft.com/IE/Feedback/Details/2211653 - return typeof func === 'function' - && /^(?:class\s|constructor\()/.test(Function.prototype.toString.call(func)); - } + function instantiate(Type, locals) { + var Constructor = function() {}, + instance, returnedValue; - function invoke(fn, self, locals, serviceName) { - if (typeof locals === 'string') { - serviceName = locals; - locals = null; - } - - var args = injectionArgs(fn, locals, serviceName); - if (isArray(fn)) { - fn = fn[fn.length - 1]; - } - - if (!isClass(fn)) { - // http://jsperf.com/angularjs-invoke-apply-vs-switch - // #5388 - return fn.apply(self, args); - } else { - args.unshift(null); - return new (Function.prototype.bind.apply(fn, args))(); - } - } - - - function instantiate(Type, locals, serviceName) { // Check if Type is annotated and use just the given function at n-1 as parameter // e.g. someModule.factory('greeter', ['$window', function(renamed$window) {}]); - var ctor = (isArray(Type) ? Type[Type.length - 1] : Type); - var args = injectionArgs(Type, locals, serviceName); - // Empty object at position 0 is ignored for invocation with `new`, but required. - args.unshift(null); - return new (Function.prototype.bind.apply(ctor, args))(); - } + Constructor.prototype = (isArray(Type) ? Type[Type.length - 1] : Type).prototype; + instance = new Constructor(); + returnedValue = invoke(Type, instance, locals); + return isObject(returnedValue) || isFunction(returnedValue) ? returnedValue : instance; + } return { invoke: invoke, instantiate: instantiate, get: getService, - annotate: createInjector.$$annotate, + annotate: annotate, has: function(name) { return providerCache.hasOwnProperty(name + providerSuffix) || cache.hasOwnProperty(name); } @@ -4653,272 +3735,99 @@ function createInjector(modulesToLoad, strictDi) { } } -createInjector.$$annotate = annotate; - /** - * @ngdoc provider - * @name $anchorScrollProvider + * @ngdoc function + * @name ng.$anchorScroll + * @requires $window + * @requires $location + * @requires $rootScope * * @description - * Use `$anchorScrollProvider` to disable automatic scrolling whenever - * {@link ng.$location#hash $location.hash()} changes. + * When called, it checks current value of `$location.hash()` and scroll to related element, + * according to rules specified in + * {@link http://dev.w3.org/html5/spec/Overview.html#the-indicated-part-of-the-document Html5 spec}. + * + * It also watches the `$location.hash()` and scrolls whenever it changes to match any anchor. + * This can be disabled by calling `$anchorScrollProvider.disableAutoScrolling()`. + * + * @example +
* return { - * //enter, leave, move signature - * eventFn : function(element, done, options) { - * //code to run the animation - * //once complete, then run done() - * return function endFunction(wasCancelled) { - * //code to cancel the animation - * } - * } - * } - * ``` + * eventFn : function(element, done) { + * //code to run the animation + * //once complete, then run done() + * return function cancellationFunction() { + * //code to cancel the animation + * } + * } + * } + ** - * @param {string} name The name of the animation (this is what the class-based CSS value will be compared to). - * @param {Function} factory The factory function that will be executed to return the animation + * @param {string} name The name of the animation. + * @param {function} factory The factory function that will be executed to return the animation * object. */ this.register = function(name, factory) { - if (name && name.charAt(0) !== '.') { - throw $animateMinErr('notcsel', "Expecting class selector starting with '.' got '{0}'.", name); - } - var key = name + '-animation'; - provider.$$registeredAnimations[name.substr(1)] = key; + if (name && name.charAt(0) != '.') throw $animateMinErr('notcsel', + "Expecting class selector starting with '.' got '{0}'.", name); + this.$$selectors[name.substr(1)] = key; $provide.factory(key, factory); }; /** - * @ngdoc method - * @name $animateProvider#classNameFilter + * @ngdoc function + * @name ng.$animateProvider#classNameFilter + * @methodOf ng.$animateProvider * * @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 that is triggered. - * When setting the `classNameFilter` value, animations will only be performed on elements + * 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) { + if(arguments.length === 1) { this.$$classNameFilter = (expression instanceof RegExp) ? expression : null; - if (this.$$classNameFilter) { - var reservedRegex = new RegExp("(\\s+|\\/)" + NG_ANIMATE_CLASSNAME + "(\\s+|\\/)"); - if (reservedRegex.test(this.$$classNameFilter.toString())) { - throw $animateMinErr('nongcls','$animateProvider.classNameFilter(regex) prohibits accepting a regex value which matches/contains the "{0}" CSS class.', NG_ANIMATE_CLASSNAME); - - } - } } return this.$$classNameFilter; }; - this.$get = ['$$animateQueue', function($$animateQueue) { - function domInsert(element, parentElement, afterElement) { - // if for some reason the previous element was removed - // from the dom sometime before this code runs then let's - // just stick to using the parent element as the anchor - if (afterElement) { - var afterNode = extractElementNode(afterElement); - if (afterNode && !afterNode.parentNode && !afterNode.previousElementSibling) { - afterElement = null; - } - } - afterElement ? afterElement.after(element) : parentElement.prepend(element); - } + this.$get = ['$timeout', function($timeout) { /** - * @ngdoc service - * @name $animate - * @description The $animate service exposes a series of DOM utility methods that provide support - * for animation hooks. The default behavior is the application of DOM operations, however, - * when an animation is detected (and animations are enabled), $animate will do the heavy lifting - * to ensure that animation runs with the triggered DOM operation. * - * By default $animate doesn't trigger any animations. This is because the `ngAnimate` module isn't - * included and only when it is active then the animation hooks that `$animate` triggers will be - * functional. Once active then all structural `ng-` directives will trigger animations as they perform - * their DOM-related operations (enter, leave and move). Other directives such as `ngClass`, - * `ngShow`, `ngHide` and `ngMessages` also provide support for animations. + * @ngdoc object + * @name ng.$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 + * high-level animation hooks for CSS and JavaScript. * - * It is recommended that the`$animate` service is always used when executing DOM-related procedures within directives. + * $animate is available in the AngularJS core, however, the ngAnimate module must be included + * to enable full out animation support. Otherwise, $animate will only perform simple DOM + * manipulation operations. * - * To learn more about enabling animation support, click here to visit the - * {@link ngAnimate ngAnimate module page}. + * To learn more about enabling animation support, click here to visit the {@link ngAnimate + * ngAnimate module page} as well as the {@link ngAnimate.$animate ngAnimate $animate service + * page}. */ return { - // we don't call it directly since non-existant arguments may - // be interpreted as null within the sub enabled function /** * - * @ngdoc method - * @name $animate#on - * @kind function - * @description Sets up an event listener to fire whenever the animation event (enter, leave, move, etc...) - * has fired on the given element or among any of its children. Once the listener is fired, the provided callback - * is fired with the following params: - * - * ```js - * $animate.on('enter', container, - * function callback(element, phase) { - * // cool we detected an enter animation within the container - * } - * ); - * ``` - * - * @param {string} event the animation event that will be captured (e.g. enter, leave, move, addClass, removeClass, etc...) - * @param {DOMElement} container the container element that will capture each of the animation events that are fired on itself - * as well as among its children - * @param {Function} callback the callback function that will be fired when the listener is triggered - * - * The arguments present in the callback function are: - * * `element` - The captured DOM element that the animation was fired on. - * * `phase` - The phase of the animation. The two possible phases are **start** (when the animation starts) and **close** (when it ends). + * @ngdoc function + * @name ng.$animate#enter + * @methodOf ng.$animate + * @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 + * a child (if the after element is not present) + * @param {jQuery/jqLite element} 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 + * inserted into the DOM */ - on: $$animateQueue.on, - - /** - * - * @ngdoc method - * @name $animate#off - * @kind function - * @description Deregisters an event listener based on the event which has been associated with the provided element. This method - * can be used in three different ways depending on the arguments: - * - * ```js - * // remove all the animation event listeners listening for `enter` - * $animate.off('enter'); - * - * // remove all the animation event listeners listening for `enter` on the given element and its children - * $animate.off('enter', container); - * - * // remove the event listener function provided by `callback` that is set - * // to listen for `enter` on the given `container` as well as its children - * $animate.off('enter', container, callback); - * ``` - * - * @param {string} event the animation event (e.g. enter, leave, move, addClass, removeClass, etc...) - * @param {DOMElement=} container the container element the event listener was placed on - * @param {Function=} callback the callback function that was registered as the listener - */ - off: $$animateQueue.off, - - /** - * @ngdoc method - * @name $animate#pin - * @kind function - * @description Associates the provided element with a host parent element to allow the element to be animated even if it exists - * outside of the DOM structure of the Angular application. By doing so, any animation triggered via `$animate` can be issued on the - * element despite being outside the realm of the application or within another application. Say for example if the application - * was bootstrapped on an element that is somewhere inside of the `` tag, but we wanted to allow for an element to be situated - * as a direct child of `document.body`, then this can be achieved by pinning the element via `$animate.pin(element)`. Keep in mind - * that calling `$animate.pin(element, parentElement)` will not actually insert into the DOM anywhere; it will just create the association. - * - * Note that this feature is only active when the `ngAnimate` module is used. - * - * @param {DOMElement} element the external element that will be pinned - * @param {DOMElement} parentElement the host parent element that will be associated with the external element - */ - pin: $$animateQueue.pin, - - /** - * - * @ngdoc method - * @name $animate#enabled - * @kind function - * @description Used to get and set whether animations are enabled or not on the entire application or on an element and its children. This - * function can be called in four ways: - * - * ```js - * // returns true or false - * $animate.enabled(); - * - * // changes the enabled state for all animations - * $animate.enabled(false); - * $animate.enabled(true); - * - * // returns true or false if animations are enabled for an element - * $animate.enabled(element); - * - * // changes the enabled state for an element and its children - * $animate.enabled(element, true); - * $animate.enabled(element, false); - * ``` - * - * @param {DOMElement=} element the element that will be considered for checking/setting the enabled state - * @param {boolean=} enabled whether or not the animations will be enabled for the element - * - * @return {boolean} whether or not animations are enabled - */ - enabled: $$animateQueue.enabled, - - /** - * @ngdoc method - * @name $animate#cancel - * @kind function - * @description Cancels the provided animation. - * - * @param {Promise} animationPromise The animation promise that is returned when an animation is started. - */ - cancel: function(runner) { - runner.end && runner.end(); + enter : function(element, parent, after, done) { + if (after) { + after.after(element); + } else { + if (!parent || !parent[0]) { + parent = after.parent(); + } + parent.append(element); + } + done && $timeout(done, 0, false); }, /** * - * @ngdoc method - * @name $animate#enter - * @kind function - * @description Inserts the element into the DOM either after the `after` element (if provided) or - * as the first child within the `parent` element and then triggers an animation. - * A promise is returned that will be resolved during the next digest once the animation - * has completed. - * - * @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 (so long as the after element is not present) - * @param {DOMElement=} after the sibling element after which the element will be appended - * @param {object=} options an optional collection of options/styles that will be applied to the element - * - * @return {Promise} the animation callback promise + * @ngdoc function + * @name ng.$animate#leave + * @methodOf ng.$animate + * @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 + * removed from the DOM */ - enter: function(element, parent, after, options) { - parent = parent && jqLite(parent); - after = after && jqLite(after); - parent = parent || after.parent(); - domInsert(element, parent, after); - return $$animateQueue.push(element, 'enter', prepareAnimateOptions(options)); + leave : function(element, done) { + element.remove(); + done && $timeout(done, 0, false); }, /** * - * @ngdoc method - * @name $animate#move - * @kind function - * @description Inserts (moves) the element into its new position in the DOM either after - * the `after` element (if provided) or as the first child within the `parent` element - * and then triggers an animation. A promise is returned that will be resolved - * during the next digest once the animation has completed. - * - * @param {DOMElement} element the element which will be moved into the new DOM position - * @param {DOMElement} parent the parent element which will append the element as - * a child (so long as the after element is not present) - * @param {DOMElement=} after the sibling element after which the element will be appended - * @param {object=} options an optional collection of options/styles that will be applied to the element - * - * @return {Promise} the animation callback promise + * @ngdoc function + * @name ng.$animate#move + * @methodOf ng.$animate + * @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 + * DOM + * @param {jQuery/jqLite element} 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 + * positioned next to + * @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, options) { - parent = parent && jqLite(parent); - after = after && jqLite(after); - parent = parent || after.parent(); - domInsert(element, parent, after); - return $$animateQueue.push(element, 'move', prepareAnimateOptions(options)); + move : function(element, parent, after, done) { + // Do not remove element before insert. Removing will cause data associated with the + // element to be dropped. Insert will implicitly do the remove. + this.enter(element, parent, after, done); }, /** - * @ngdoc method - * @name $animate#leave - * @kind function - * @description Triggers an animation and then removes the element from the DOM. - * When the function is called a promise is returned that will be resolved during the next - * digest once the animation has completed. * - * @param {DOMElement} element the element which will be removed from the DOM - * @param {object=} options an optional collection of options/styles that will be applied to the element - * - * @return {Promise} the animation callback promise + * @ngdoc function + * @name ng.$animate#addClass + * @methodOf ng.$animate + * @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 + * 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 + * className value has been added to the element */ - leave: function(element, options) { - return $$animateQueue.push(element, 'leave', prepareAnimateOptions(options), function() { - element.remove(); + addClass : function(element, className, done) { + className = isString(className) ? + className : + isArray(className) ? className.join(' ') : ''; + forEach(element, function (element) { + jqLiteAddClass(element, className); }); + done && $timeout(done, 0, false); }, /** - * @ngdoc method - * @name $animate#addClass - * @kind function * - * @description Triggers an addClass animation surrounding the addition of the provided CSS class(es). Upon - * execution, the addClass operation will only be handled after the next digest and it will not trigger an - * animation if element already contains the CSS class or if the class is removed at a later step. - * Note that class-based animations are treated differently compared to structural animations - * (like enter, move and leave) since the CSS classes may be added/removed at different points - * depending if CSS or JavaScript animations are used. - * - * @param {DOMElement} element the element which the CSS classes will be applied to - * @param {string} className the CSS class(es) that will be added (multiple classes are separated via spaces) - * @param {object=} options an optional collection of options/styles that will be applied to the element - * - * @return {Promise} the animation callback promise + * @ngdoc function + * @name ng.$animate#removeClass + * @methodOf ng.$animate + * @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 + * 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 + * className value has been removed from the element */ - addClass: function(element, className, options) { - options = prepareAnimateOptions(options); - options.addClass = mergeClasses(options.addclass, className); - return $$animateQueue.push(element, 'addClass', options); + removeClass : function(element, className, done) { + className = isString(className) ? + className : + isArray(className) ? className.join(' ') : ''; + forEach(element, function (element) { + jqLiteRemoveClass(element, className); + }); + done && $timeout(done, 0, false); }, - /** - * @ngdoc method - * @name $animate#removeClass - * @kind function - * - * @description Triggers a removeClass animation surrounding the removal of the provided CSS class(es). Upon - * execution, the removeClass operation will only be handled after the next digest and it will not trigger an - * animation if element does not contain the CSS class or if the class is added at a later step. - * Note that class-based animations are treated differently compared to structural animations - * (like enter, move and leave) since the CSS classes may be added/removed at different points - * depending if CSS or JavaScript animations are used. - * - * @param {DOMElement} element the element which the CSS classes will be applied to - * @param {string} className the CSS class(es) that will be removed (multiple classes are separated via spaces) - * @param {object=} options an optional collection of options/styles that will be applied to the element - * - * @return {Promise} the animation callback promise - */ - removeClass: function(element, className, options) { - options = prepareAnimateOptions(options); - options.removeClass = mergeClasses(options.removeClass, className); - return $$animateQueue.push(element, 'removeClass', options); - }, - - /** - * @ngdoc method - * @name $animate#setClass - * @kind function - * - * @description Performs both the addition and removal of a CSS classes on an element and (during the process) - * triggers an animation surrounding the class addition/removal. Much like `$animate.addClass` and - * `$animate.removeClass`, `setClass` will only evaluate the classes being added/removed once a digest has - * passed. Note that class-based animations are treated differently compared to structural animations - * (like enter, move and leave) since the CSS classes may be added/removed at different points - * depending if CSS or JavaScript animations are used. - * - * @param {DOMElement} element the element which the CSS classes will be applied to - * @param {string} add the CSS class(es) that will be added (multiple classes are separated via spaces) - * @param {string} remove the CSS class(es) that will be removed (multiple classes are separated via spaces) - * @param {object=} options an optional collection of options/styles that will be applied to the element - * - * @return {Promise} the animation callback promise - */ - setClass: function(element, add, remove, options) { - options = prepareAnimateOptions(options); - options.addClass = mergeClasses(options.addClass, add); - options.removeClass = mergeClasses(options.removeClass, remove); - return $$animateQueue.push(element, 'setClass', options); - }, - - /** - * @ngdoc method - * @name $animate#animate - * @kind function - * - * @description Performs an inline animation on the element which applies the provided to and from CSS styles to the element. - * If any detected CSS transition, keyframe or JavaScript matches the provided className value, then the animation will take - * on the provided styles. For example, if a transition animation is set for the given classNamem, then the provided `from` and - * `to` styles will be applied alongside the given transition. If the CSS style provided in `from` does not have a corresponding - * style in `to`, the style in `from` is applied immediately, and no animation is run. - * If a JavaScript animation is detected then the provided styles will be given in as function parameters into the `animate` - * method (or as part of the `options` parameter): - * - * ```js - * ngModule.animation('.my-inline-animation', function() { - * return { - * animate : function(element, from, to, done, options) { - * //animation - * done(); - * } - * } - * }); - * ``` - * - * @param {DOMElement} element the element which the CSS styles will be applied to - * @param {object} from the from (starting) CSS styles that will be applied to the element and across the animation. - * @param {object} to the to (destination) CSS styles that will be applied to the element and across the animation. - * @param {string=} className an optional CSS class that will be applied to the element for the duration of the animation. If - * this value is left as empty then a CSS class of `ng-inline-animate` will be applied to the element. - * (Note that if no animation is detected then this value will not be applied to the element.) - * @param {object=} options an optional collection of options/styles that will be applied to the element - * - * @return {Promise} the animation callback promise - */ - animate: function(element, from, to, className, options) { - options = prepareAnimateOptions(options); - options.from = options.from ? extend(options.from, from) : from; - options.to = options.to ? extend(options.to, to) : to; - - className = className || 'ng-inline-animate'; - options.tempClasses = mergeClasses(options.tempClasses, className); - return $$animateQueue.push(element, 'animate', options); - } + enabled : noop }; }]; }]; -var $$AnimateAsyncRunFactoryProvider = function() { - this.$get = ['$$rAF', function($$rAF) { - var waitQueue = []; - - function waitForTick(fn) { - waitQueue.push(fn); - if (waitQueue.length > 1) return; - $$rAF(function() { - for (var i = 0; i < waitQueue.length; i++) { - waitQueue[i](); - } - waitQueue = []; - }); - } - - return function() { - var passed = false; - waitForTick(function() { - passed = true; - }); - return function(callback) { - passed ? callback() : waitForTick(callback); - }; - }; - }]; -}; - -var $$AnimateRunnerFactoryProvider = function() { - this.$get = ['$q', '$sniffer', '$$animateAsyncRun', '$document', '$timeout', - function($q, $sniffer, $$animateAsyncRun, $document, $timeout) { - - var INITIAL_STATE = 0; - var DONE_PENDING_STATE = 1; - var DONE_COMPLETE_STATE = 2; - - AnimateRunner.chain = function(chain, callback) { - var index = 0; - - next(); - function next() { - if (index === chain.length) { - callback(true); - return; - } - - chain[index](function(response) { - if (response === false) { - callback(false); - return; - } - index++; - next(); - }); - } - }; - - AnimateRunner.all = function(runners, callback) { - var count = 0; - var status = true; - forEach(runners, function(runner) { - runner.done(onProgress); - }); - - function onProgress(response) { - status = status && response; - if (++count === runners.length) { - callback(status); - } - } - }; - - function AnimateRunner(host) { - this.setHost(host); - - var rafTick = $$animateAsyncRun(); - var timeoutTick = function(fn) { - $timeout(fn, 0, false); - }; - - this._doneCallbacks = []; - this._tick = function(fn) { - var doc = $document[0]; - - // the document may not be ready or attached - // to the module for some internal tests - if (doc && doc.hidden) { - timeoutTick(fn); - } else { - rafTick(fn); - } - }; - this._state = 0; - } - - AnimateRunner.prototype = { - setHost: function(host) { - this.host = host || {}; - }, - - done: function(fn) { - if (this._state === DONE_COMPLETE_STATE) { - fn(); - } else { - this._doneCallbacks.push(fn); - } - }, - - progress: noop, - - getPromise: function() { - if (!this.promise) { - var self = this; - this.promise = $q(function(resolve, reject) { - self.done(function(status) { - status === false ? reject() : resolve(); - }); - }); - } - return this.promise; - }, - - then: function(resolveHandler, rejectHandler) { - return this.getPromise().then(resolveHandler, rejectHandler); - }, - - 'catch': function(handler) { - return this.getPromise()['catch'](handler); - }, - - 'finally': function(handler) { - return this.getPromise()['finally'](handler); - }, - - pause: function() { - if (this.host.pause) { - this.host.pause(); - } - }, - - resume: function() { - if (this.host.resume) { - this.host.resume(); - } - }, - - end: function() { - if (this.host.end) { - this.host.end(); - } - this._resolve(true); - }, - - cancel: function() { - if (this.host.cancel) { - this.host.cancel(); - } - this._resolve(false); - }, - - complete: function(response) { - var self = this; - if (self._state === INITIAL_STATE) { - self._state = DONE_PENDING_STATE; - self._tick(function() { - self._resolve(response); - }); - } - }, - - _resolve: function(response) { - if (this._state !== DONE_COMPLETE_STATE) { - forEach(this._doneCallbacks, function(fn) { - fn(response); - }); - this._doneCallbacks.length = 0; - this._state = DONE_COMPLETE_STATE; - } - } - }; - - return AnimateRunner; - }]; -}; - -/** - * @ngdoc service - * @name $animateCss - * @kind object - * - * @description - * This is the core version of `$animateCss`. By default, only when the `ngAnimate` is included, - * then the `$animateCss` service will actually perform animations. - * - * Click here {@link ngAnimate.$animateCss to read the documentation for $animateCss}. - */ -var $CoreAnimateCssProvider = function() { - this.$get = ['$$rAF', '$q', '$$AnimateRunner', function($$rAF, $q, $$AnimateRunner) { - - return function(element, initialOptions) { - // all of the animation functions should create - // a copy of the options data, however, if a - // parent service has already created a copy then - // we should stick to using that - var options = initialOptions || {}; - if (!options.$$prepared) { - options = copy(options); - } - - // there is no point in applying the styles since - // there is no animation that goes on at all in - // this version of $animateCss. - if (options.cleanupStyles) { - options.from = options.to = null; - } - - if (options.from) { - element.css(options.from); - options.from = null; - } - - /* jshint newcap: false */ - var closed, runner = new $$AnimateRunner(); - return { - start: run, - end: run - }; - - function run() { - $$rAF(function() { - applyAnimationContents(); - if (!closed) { - runner.complete(); - } - closed = true; - }); - return runner; - } - - function applyAnimationContents() { - if (options.addClass) { - element.addClass(options.addClass); - options.addClass = null; - } - if (options.removeClass) { - element.removeClass(options.removeClass); - options.removeClass = null; - } - if (options.to) { - element.css(options.to); - options.to = null; - } - } - }; - }]; -}; - -/* global stripHash: true */ - /** * ! This is a private undocumented service ! * - * @name $browser + * @name ng.$browser * @requires $log * @description * This object has two goals: @@ -5795,11 +4080,13 @@ var $CoreAnimateCssProvider = function() { /** * @param {object} window The global window object. * @param {object} document jQuery wrapped document. - * @param {object} $log window.console or an object with the same interface. + * @param {function()} XHR XMLHttpRequest constructor. + * @param {object} $log console.log or an object with the same interface. * @param {object} $sniffer $sniffer service */ function Browser(window, document, $log, $sniffer) { var self = this, + rawDocument = document[0], location = window.location, history = window.history, setTimeout = window.setTimeout, @@ -5825,7 +4112,7 @@ function Browser(window, document, $log, $sniffer) { } finally { outstandingRequestCount--; if (outstandingRequestCount === 0) { - while (outstandingRequestCallbacks.length) { + while(outstandingRequestCallbacks.length) { try { outstandingRequestCallbacks.pop()(); } catch (e) { @@ -5836,11 +4123,6 @@ function Browser(window, document, $log, $sniffer) { } } - function getHash(url) { - var index = url.indexOf('#'); - return index === -1 ? '' : url.substr(index); - } - /** * @private * Note: this method is used only by scenario runner @@ -5848,6 +4130,11 @@ function Browser(window, document, $log, $sniffer) { * @param {function()} callback Function that will be called when no outstanding request */ self.notifyWhenNoOutstandingRequests = function(callback) { + // force browser to execute all pollFns - this is needed so that cookies and other pollers fire + // at some deterministic time in respect to the test runner's actions. Leaving things up to the + // regular poller would result in flaky tests. + forEach(pollFns, function(pollFn){ pollFn(); }); + if (outstandingRequestCount === 0) { callback(); } else { @@ -5855,27 +4142,56 @@ function Browser(window, document, $log, $sniffer) { } }; + ////////////////////////////////////////////////////////////// + // Poll Watcher API + ////////////////////////////////////////////////////////////// + var pollFns = [], + pollTimeout; + + /** + * @name ng.$browser#addPollFn + * @methodOf ng.$browser + * + * @param {function()} fn Poll function to add + * + * @description + * Adds a function to the list of functions that poller periodically executes, + * and starts polling if not started yet. + * + * @returns {function()} the added function + */ + self.addPollFn = function(fn) { + if (isUndefined(pollTimeout)) startPoller(100, setTimeout); + pollFns.push(fn); + return fn; + }; + + /** + * @param {number} interval How often should browser call poll functions (ms) + * @param {function()} setTimeout Reference to a real or fake `setTimeout` function. + * + * @description + * Configures the poller to run in the specified intervals, using the specified + * setTimeout fn and kicks it off. + */ + function startPoller(interval, setTimeout) { + (function check() { + forEach(pollFns, function(pollFn){ pollFn(); }); + pollTimeout = setTimeout(check, interval); + })(); + } + ////////////////////////////////////////////////////////////// // URL API ////////////////////////////////////////////////////////////// - var cachedState, lastHistoryState, - lastBrowserUrl = location.href, + var lastBrowserUrl = location.href, baseElement = document.find('base'), - pendingLocation = null, - getCurrentState = !$sniffer.history ? noop : function getCurrentState() { - try { - return history.state; - } catch (e) { - // MSIE can reportedly throw when there is no state (UNCONFIRMED). - } - }; - - cacheState(); - lastHistoryState = cachedState; + newLocation = null; /** - * @name $browser#url + * @name ng.$browser#url + * @methodOf ng.$browser * * @description * GETTER: @@ -5891,120 +4207,59 @@ function Browser(window, document, $log, $sniffer) { * {@link ng.$location $location service} to change url. * * @param {string} url New url (when used as setter) - * @param {boolean=} replace Should new url replace current history record? - * @param {object=} state object to use with pushState/replaceState + * @param {boolean=} replace Should new url replace current history record ? */ - self.url = function(url, replace, state) { - // In modern browsers `history.state` is `null` by default; treating it separately - // from `undefined` would cause `$browser.url('/foo')` to change `history.state` - // to undefined via `pushState`. Instead, let's change `undefined` to `null` here. - if (isUndefined(state)) { - state = null; - } - + self.url = function(url, replace) { // 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) { - var sameState = lastHistoryState === state; - - // Don't change anything if previous and current URLs and states match. This also prevents - // IE<10 from getting into redirect loop when in LocationHashbangInHtml5Url mode. - // See https://github.com/angular/angular.js/commit/ffb2701 - if (lastBrowserUrl === url && (!$sniffer.history || sameState)) { - return self; - } - var sameBase = lastBrowserUrl && stripHash(lastBrowserUrl) === stripHash(url); + if (lastBrowserUrl == url) return; lastBrowserUrl = url; - lastHistoryState = state; - // 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 ($sniffer.history && (!sameBase || !sameState)) { - history[replace ? 'replaceState' : 'pushState'](state, '', url); - cacheState(); - // Do the assignment again so that those two variables are referentially identical. - lastHistoryState = cachedState; - } else { - if (!sameBase || pendingLocation) { - pendingLocation = url; + if ($sniffer.history) { + if (replace) history.replaceState(null, '', url); + else { + history.pushState(null, '', url); + // Crazy Opera Bug: http://my.opera.com/community/forums/topic.dml?id=1185462 + baseElement.attr('href', baseElement.attr('href')); } + } else { + newLocation = url; if (replace) { location.replace(url); - } else if (!sameBase) { - location.href = url; } else { - location.hash = getHash(url); - } - if (location.href !== url) { - pendingLocation = url; + location.href = url; } } return self; // getter } else { - // - pendingLocation is needed as browsers don't allow to read out - // the new location.href if a reload happened or if there is a bug like in iOS 9 (see - // https://openradar.appspot.com/22186109). + // - newLocation is a workaround for an IE7-9 issue with location.replace and location.href + // methods not updating location.href synchronously. // - the replacement is a workaround for https://bugzilla.mozilla.org/show_bug.cgi?id=407172 - return pendingLocation || location.href.replace(/%27/g,"'"); + return newLocation || location.href.replace(/%27/g,"'"); } }; - /** - * @name $browser#state - * - * @description - * This method is a getter. - * - * Return history.state or null if history.state is undefined. - * - * @returns {object} state - */ - self.state = function() { - return cachedState; - }; - var urlChangeListeners = [], urlChangeInit = false; - function cacheStateAndFireUrlChange() { - pendingLocation = null; - cacheState(); - fireUrlChange(); - } - - // This variable should be used *only* inside the cacheState function. - var lastCachedState = null; - function cacheState() { - // This should be the only place in $browser where `history.state` is read. - cachedState = getCurrentState(); - cachedState = isUndefined(cachedState) ? null : cachedState; - - // Prevent callbacks fo fire twice if both hashchange & popstate were fired. - if (equals(cachedState, lastCachedState)) { - cachedState = lastCachedState; - } - lastCachedState = cachedState; - } - function fireUrlChange() { - if (lastBrowserUrl === self.url() && lastHistoryState === cachedState) { - return; - } + newLocation = null; + if (lastBrowserUrl == self.url()) return; lastBrowserUrl = self.url(); - lastHistoryState = cachedState; forEach(urlChangeListeners, function(listener) { - listener(self.url(), cachedState); + listener(self.url()); }); } /** - * @name $browser#onUrlChange + * @name ng.$browser#onUrlChange + * @methodOf ng.$browser + * @TODO(vojta): refactor to use node's syntax for events * * @description * Register callback function that will be called, when url changes. @@ -6025,16 +4280,17 @@ 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 // changed by push/replaceState // html5 history api - popstate event - if ($sniffer.history) jqLite(window).on('popstate', cacheStateAndFireUrlChange); + if ($sniffer.history) jqLite(window).on('popstate', fireUrlChange); // hashchange event - jqLite(window).on('hashchange', cacheStateAndFireUrlChange); + if ($sniffer.hashchange) jqLite(window).on('hashchange', fireUrlChange); + // polling + else self.addPollFn(fireUrlChange); urlChangeInit = true; } @@ -6043,43 +4299,105 @@ function Browser(window, document, $log, $sniffer) { return callback; }; - /** - * @private - * Remove popstate and hashchange handler from window. - * - * NOTE: this api is intended for use only by $rootScope. - */ - self.$$applicationDestroyed = function() { - jqLite(window).off('hashchange popstate', cacheStateAndFireUrlChange); - }; - - /** - * 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 $browser#baseHref + * @name ng.$browser#baseHref + * @methodOf ng.$browser * * @description * Returns current
+ * * var cache = $cacheFactory('cacheId'); * expect($cacheFactory.get('cacheId')).toBe(cache); * expect($cacheFactory.get('noSuchCacheId')).not.toBeDefined(); @@ -6151,9 +4469,9 @@ function $BrowserProvider() { * cache.put("another key", "another value"); * * // We've specified no options on creation - * expect(cache.info()).toEqual({id: 'cacheId', size: 2}); - * - * ``` + * expect(cache.info()).toEqual({id: 'cacheId', size: 2}); + * + ** * * @param {string} cacheId Name or id of the newly created cache. @@ -6171,48 +4489,6 @@ function $BrowserProvider() { * - `{void}` `removeAll()` — Removes all cached values. * - `{void}` `destroy()` — Removes references to this cache from $cacheFactory. * - * @example -
Cached Values
-Cache Info
-+ * + * + * + * + * ... + * + *+ * * **Note:** the `script` tag containing the template does not need to be included in the `head` of - * 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 + * the document, but it must be below the `ng-app` definition. + * + * Adding via the $templateCache service: + * + *
* 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}. * */ @@ -6535,17 +4697,6 @@ function $TemplateCacheProvider() { }]; } -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Any commits to this file should be reviewed with security in mind. * - * Changes to this file can potentially create security vulnerabilities. * - * An approval from 2 Core members with history of modifying * - * this file is required. * - * * - * Does the change somehow allow for arbitrary javascript to be executed? * - * Or allows for someone to change the prototype of built-in objects? * - * Or gives undesired access to variables likes document or window? * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - /* ! VARIABLE/FUNCTION NAMING CONVENTIONS THAT APPLY TO THIS FILE! * * DOM-related variables: @@ -6565,16 +4716,16 @@ function $TemplateCacheProvider() { /** - * @ngdoc service - * @name $compile - * @kind function + * @ngdoc function + * @name ng.$compile + * @function * * @description * 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#directive directives}. + * {@link ng.$compileProvider#methods_directive directives}. * *
* var myModule = angular.module(...); * * myModule.directive('directiveName', function factory(injectables) { @@ -6605,13 +4756,11 @@ function $TemplateCacheProvider() { * template: '', // or // function(tElement, tAttrs) { ... }, * // or * // templateUrl: 'directive.html', // or // function(tElement, tAttrs) { ... }, + * replace: false, * transclude: false, * restrict: 'A', - * templateNamespace: 'html', * scope: false, * controller: function($scope, $element, $attrs, $transclude, otherInjectables) { ... }, - * controllerAs: 'stringIdentifier', - * bindToController: false, * require: 'siblingDirectiveName', // or // ['^parentDirectiveName', '?optionalDirectiveName', '?^optionalParent'], * compile: function compile(tElement, tAttrs, transclude) { * return { @@ -6631,7 +4780,7 @@ function $TemplateCacheProvider() { * }; * return directiveDefinitionObject; * }); - * ``` + ** *
* var myModule = angular.module(...); * * myModule.directive('directiveName', function factory(injectables) { @@ -6650,22 +4799,15 @@ function $TemplateCacheProvider() { * // or * // return function postLink(scope, iElement, iAttrs) { ... } * }); - * ``` + ** * * * ### Directive Definition Object * - * The directive definition object provides instructions to the {@link ng.$compile + * The directive definition object provides instructions to the {@link api/ng.$compile * compiler}. The attributes are: * - * #### `multiElement` - * When this property is set to true, the HTML compiler will collect DOM nodes between - * nodes with the attributes `directive-name-start` and `directive-name-end`, and group them - * together as the directive elements. It is recommended that this feature be used on directives - * which are not strictly behavioral (such as {@link ngClick}), and which - * do not manipulate or replace child nodes (such as {@link ngInclude}). - * * #### `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 @@ -6677,294 +4819,150 @@ function $TemplateCacheProvider() { * #### `terminal` * If set to true then the current `priority` will be the last set of directives * which will execute (any directives at the current priority will still execute - * as the order of execution on same `priority` is undefined). Note that expressions - * and other directives used in the directive's template will also be excluded from execution. + * as the order of execution on same `priority` is undefined). * * #### `scope` - * The scope property can be `true`, an object or a falsy value: + * **If set to `true`,** then a new scope will be created for this directive. If multiple directives on the + * same element request a new scope, only one new scope is created. The new scope rule does not + * apply for the root of the template since the root of the template always gets a new scope. * - * * **falsy:** No scope will be created for the directive. The directive will use its parent's scope. + * **If set to `{}` (object hash),** then a new "isolate" scope is created. The 'isolate' scope differs from + * normal scope in that it does not prototypically inherit from the parent scope. This is useful + * when creating reusable components, which should not accidentally read or modify data in the + * parent scope. * - * * **`true`:** A new child scope that prototypically inherits from its parent will be created for - * the directive's element. If multiple directives on the same element request a new scope, - * only one new scope is created. The new scope rule does not apply for the root of the template - * since the root of the template always gets a new scope. - * - * * **`{...}` (an object hash):** A new "isolate" scope is created for the directive's element. The - * 'isolate' scope differs from normal scope in that it does not prototypically inherit from its parent - * scope. This is useful when creating reusable components, which should not accidentally read or modify - * data in the parent scope. - * - * The 'isolate' scope object hash defines a set of local scope properties derived from attributes on the - * directive's element. These local properties are useful for aliasing values for templates. The keys in - * the object hash map to the name of the property on the isolate scope; the values define how the property - * is bound to the parent scope, via matching attributes on the directive's element: + * The 'isolate' scope takes an object hash which defines a set of local scope properties + * derived from the parent scope. These local properties are useful for aliasing values for + * templates. Locals definition is a hash of local scope property to its source: * * * `@` or `@attr` - bind a local scope property to the value of DOM attribute. The result is - * always a string since DOM attributes are strings. If no `attr` name is specified then the - * attribute name is assumed to be the same as the local name. Given `
* 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 ng.$rootScope.Scope Scope} - The scope to be used by the - * directive for registering {@link ng.$rootScope.Scope#$watch watches}. + * * `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}. * * * `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 @@ -7028,23 +5016,15 @@ function $TemplateCacheProvider() { * * `iAttrs` - instance attributes - Normalized list of attributes declared on this element shared * between all directive linking functions. * - * * `controller` - the directive's required controller instance(s) - Instances are shared - * among all directives, which allows the directives to use the controllers as a communication - * channel. The exact value depends on the directive's `require` property: - * * no controller(s) required: the directive's own controller, or `undefined` if it doesn't have one - * * `string`: the controller instance - * * `array`: array of controller instances - * - * If a required controller cannot be found, and it is optional, the instance is `null`, - * otherwise the {@link error:$compile:ctreq Missing Required Controller} error is thrown. - * - * Note that you can also require the directive's own controller - it will be made available like - * any other controller. + * * `controller` - a controller instance - A controller instance if at least one directive on the + * 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. - * This is the same as the `$transclude` - * parameter of directive controllers, see there for details. - * `function([scope], cloneLinkingFn, futureParentElement)`. + * 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 * @@ -7053,166 +5033,18 @@ function $TemplateCacheProvider() { * * #### Post-linking function * - * Executed after the child elements are linked. - * - * Note that child elements that contain `templateUrl` directives will not have been compiled - * and linked since they are waiting for their template to load asynchronously and their own - * compilation and linking has been suspended until that occurs. - * - * It is safe to do DOM transformation in the post-linking function on elements that are not waiting - * for their async templates to be resolved. - * - * - * ### Transclusion - * - * Transclusion is the process of extracting a collection of DOM elements from one part of the DOM and - * copying them to another part of the DOM, while maintaining their connection to the original AngularJS - * scope from where they were taken. - * - * Transclusion is used (often with {@link ngTransclude}) to insert the - * original contents of a directive's element into a specified place in the template of the directive. - * The benefit of transclusion, over simply moving the DOM elements manually, is that the transcluded - * content has access to the properties on the scope from which it was taken, even if the directive - * has isolated scope. - * See the {@link guide/directive#creating-a-directive-that-wraps-other-elements Directives Guide}. - * - * This makes it possible for the widget to have private state for its template, while the transcluded - * content has access to its originating scope. - * - *
* function linkingFn(scope, elm, attrs, ctrl) { * // get the attribute value * console.log(attrs.ngModel); @@ -7239,19 +5071,19 @@ function $TemplateCacheProvider() { * console.log('ngModel has changed value to ' + value); * }); * } - * ``` + ** - * ## Example + * Below is an example using `$compileProvider`. * *
* 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: - * ```js + *{{total}}
')(scope); - * ``` + *
* var templateElement = angular.element('* * * For information on how the compiler works, see the @@ -7382,8 +5184,9 @@ function $TemplateCacheProvider() { var $compileMinErr = minErr('$compile'); /** - * @ngdoc provider - * @name $compileProvider + * @ngdoc service + * @name ng.$compileProvider + * @function * * @description */ @@ -7391,105 +5194,19 @@ $CompileProvider.$inject = ['$provide', '$$sanitizeUriProvider']; function $CompileProvider($provide, $$sanitizeUriProvider) { var hasDirectives = {}, Suffix = 'Directive', - COMMENT_DIRECTIVE_REGEXP = /^\s*directive\:\s*([\w\-]+)\s+(.*)$/, - CLASS_DIRECTIVE_REGEXP = /(([\w\-]+)(?:\:([^;]+))?;?)/, - ALL_OR_NOTHING_ATTRS = makeMap('ngSrc,ngSrcset,src,srcset'), - REQUIRE_PREFIX_REGEXP = /^(?:(\^\^?)?(\?)?(\^\^?)?)?/; + 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 // 'on' and be composed of only English letters. var EVENT_HANDLER_ATTR_REGEXP = /^(on[a-z]+|formaction)$/; - var bindingCache = createMap(); - - function parseIsolateBindings(scope, directiveName, isController) { - var LOCAL_REGEXP = /^\s*([@&<]|=(\*?))(\??)\s*(\w*)\s*$/; - - var bindings = {}; - - forEach(scope, function(definition, scopeName) { - if (definition in bindingCache) { - bindings[scopeName] = bindingCache[definition]; - return; - } - var match = definition.match(LOCAL_REGEXP); - - if (!match) { - throw $compileMinErr('iscp', - "Invalid {3} for directive '{0}'." + - " Definition: {... {1}: '{2}' ...}", - directiveName, scopeName, definition, - (isController ? "controller bindings definition" : - "isolate scope definition")); - } - - bindings[scopeName] = { - mode: match[1][0], - collection: match[2] === '*', - optional: match[3] === '?', - attrName: match[4] || scopeName - }; - if (match[4]) { - bindingCache[definition] = bindings[scopeName]; - } - }); - - return bindings; - } - - function parseDirectiveBindings(directive, directiveName) { - var bindings = { - isolateScope: null, - bindToController: null - }; - if (isObject(directive.scope)) { - if (directive.bindToController === true) { - bindings.bindToController = parseIsolateBindings(directive.scope, - directiveName, true); - bindings.isolateScope = {}; - } else { - bindings.isolateScope = parseIsolateBindings(directive.scope, - directiveName, false); - } - } - if (isObject(directive.bindToController)) { - bindings.bindToController = - parseIsolateBindings(directive.bindToController, directiveName, true); - } - if (isObject(bindings.bindToController)) { - var controller = directive.controller; - var controllerAs = directive.controllerAs; - if (!controller) { - // There is no controller, there may or may not be a controllerAs property - throw $compileMinErr('noctrl', - "Cannot bind to controller without directive '{0}'s controller.", - directiveName); - } else if (!identifierForController(controller, controllerAs)) { - // There is a controller, but no identifier or controllerAs property - throw $compileMinErr('noident', - "Cannot bind to controller without identifier for directive '{0}'.", - directiveName); - } - } - return bindings; - } - - function assertValidDirectiveName(name) { - var letter = name.charAt(0); - if (!letter || letter !== lowercase(letter)) { - throw $compileMinErr('baddir', "Directive/Component name '{0}' is invalid. The first character must be a lowercase letter", name); - } - if (name !== name.trim()) { - throw $compileMinErr('baddir', - "Directive/Component name '{0}' is invalid. The name should not contain leading or trailing whitespaces", - name); - } - } /** - * @ngdoc method - * @name $compileProvider#directive - * @kind function + * @ngdoc function + * @name ng.$compileProvider#directive + * @methodOf ng.$compileProvider + * @function * * @description * Register a new directive with the compiler. @@ -7497,14 +5214,13 @@ function $CompileProvider($provide, $$sanitizeUriProvider) { * @param {string|Object} name Name of the directive in camel-case (i.e.{{total}}
'), * scope = ....; * @@ -7372,7 +5174,7 @@ function $TemplateCacheProvider() { * }); * * //now we have reference to the cloned DOM via `clonedElement` - * ``` + *
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 the
- * {@link guide/directive directive guide} and the {@link $compile compile API} for more info.
+ * @param {function|Array} directiveFactory An injectable directive factory function. See
+ * {@link guide/directive} for more info.
* @returns {ng.$compileProvider} Self for chaining.
*/
- this.directive = function registerDirective(name, directiveFactory) {
+ this.directive = function registerDirective(name, directiveFactory) {
assertNotHasOwnProperty(name, 'directive');
if (isString(name)) {
- assertValidDirectiveName(name);
assertArg(directiveFactory, 'directiveFactory');
if (!hasDirectives.hasOwnProperty(name)) {
hasDirectives[name] = [];
@@ -7523,8 +5239,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
directive.index = index;
directive.name = directive.name || name;
directive.require = directive.require || (directive.controller && directive.name);
- directive.restrict = directive.restrict || 'EA';
- directive.$$moduleName = directiveFactory.$$moduleName;
+ directive.restrict = directive.restrict || 'A';
directives.push(directive);
} catch (e) {
$exceptionHandler(e);
@@ -7540,142 +5255,18 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
return this;
};
- /**
- * @ngdoc method
- * @name $compileProvider#component
- * @module ng
- * @param {string} name Name of the component in camelCase (i.e. `myComp` which will match `$document title:
-window.document title:
-+ * 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. * - *
+ * $http({method: 'GET', url: '/someUrl'}). + * success(function(data, status, headers, config) { * // this callback will be called asynchronously * // when the response is available - * }, function errorCallback(response) { + * }). + * error(function(data, status, headers, config) { * // called asynchronously if an error occurs * // or server returns response with an error status. * }); - * ``` + ** - * The response object has these properties: - * - * - **data** – `{string|Object}` – The response body transformed with the transform - * functions. - * - **status** – `{number}` – HTTP status code of the response. - * - **headers** – `{function([headerName])}` – Header getter function. - * - **config** – `{Object}` – The configuration object that was used to generate the request. - * - **statusText** – `{string}` – HTTP status text of the response. + * Since the returned value of calling the $http function is a `promise`, you can also use + * the `then` method to register callbacks, and these callbacks will receive a single argument – + * an object representing the response. See the API signature and type info below for more + * details. * * A response status code between 200 and 299 is considered a success status and * will result in the success callback being called. Note that if the response is a redirect, * XMLHttpRequest will transparently follow it, meaning that the error callback will not be * called for such responses. * + * # 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. * - * ## Shortcut methods - * - * Shortcut methods are also available. All shortcut methods require passing in the URL, and - * request data must be passed in for POST/PUT requests. An optional config can be passed as the - * last argument. - * - * ```js - * $http.get('/someUrl', config).then(successCallback, errorCallback); - * $http.post('/someUrl', data, config).then(successCallback, errorCallback); + * ``` + * $scope.$apply(function() { + * $http(...); + * }); * ``` * - * Complete list of shortcut methods: - * - * - {@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} - * - * - * ## Writing Unit Tests that use $http - * 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. + * # 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. * * ``` * $httpBackend.expectGET(...); - * $http.get(...); + * $scope.$apply(function() { + * $http.get(...); + * }); * $httpBackend.flush(); * ``` * - * ## Deprecation Notice - *
+ * $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} + * + * + * # Setting HTTP Headers * * The $http service will automatically add certain HTTP headers to all requests. These defaults * can be fully configured by accessing the `$httpProvider.defaults.headers` configuration @@ -10675,140 +7128,74 @@ function $HttpProvider() { * To add or overwrite these defaults, simply add or remove a property from these configuration * objects. To add headers for an HTTP method other than POST or PUT, simply add a new object * with the lowercased HTTP method name as the key, e.g. - * `$httpProvider.defaults.headers.get = { 'My-Header' : 'value' }`. + * `$httpProvider.defaults.headers.get = { 'My-Header' : 'value' }. * * The defaults can also be set at runtime via the `$http.defaults` object in the same * fashion. For example: * * ``` * module.run(function($http) { - * $http.defaults.headers.common.Authorization = 'Basic YmVlcDpib29w'; + * $http.defaults.headers.common.Authentication = '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' } - * } + * # Transforming Requests and Responses * - * $http(req).then(function(){...}, function(){...}); - * ``` + * Both requests and responses can be transformed using transform functions. By default, Angular + * applies these transformations: * - * ## Transforming Requests and Responses - * - * Both requests and responses can be transformed using transformation functions: `transformRequest` - * and `transformResponse`. These properties can be a single function that returns - * the transformed value (`function(data, headersGetter, status)`) or an array of such transformation functions, - * which allows you to `push` or `unshift` a new transformation function into the transformation chain. - * - *
* // 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; + * return config || $q.when(config); * }, * * // optional method @@ -10862,7 +7249,7 @@ function $HttpProvider() { * // optional method * 'response': function(response) { * // do something on success - * return response; + * return response || $q.when(response); * }, * * // optional method @@ -10891,50 +7278,96 @@ function $HttpProvider() { * } * }; * }); - * ``` + ** - * ## Security Considerations + * # Response interceptors (DEPRECATED) + * + * Before you start creating interceptors, be sure to understand the + * {@link ng.$q $q and deferred/promise APIs}. + * + * For purposes of global error handling, authentication or any kind of synchronous or + * asynchronous preprocessing of received responses, it is desirable to be able to intercept + * responses for http requests before they are handed over to the application code that + * initiated these requests. The response interceptors leverage the {@link ng.$q + * promise apis} to fulfil this need for both synchronous and asynchronous preprocessing. + * + * The interceptors are service factories that are registered with the $httpProvider by + * adding them to the `$httpProvider.responseInterceptors` array. The factory is called and + * injected with dependencies (if specified) and returns the interceptor — a function that + * takes a {@link ng.$q promise} and returns the original or a new promise. + * + *
+ * // register the interceptor as a service + * $provide.factory('myHttpInterceptor', function($q, dependency1, dependency2) { + * return function(promise) { + * return promise.then(function(response) { + * // do something on success + * return response; + * }, function(response) { + * // do something on error + * if (canRecover(response)) { + * return responseOrNewPromise + * } + * return $q.reject(response); + * }); + * } + * }); + * + * $httpProvider.responseInterceptors.push('myHttpInterceptor'); + * + * + * // register the interceptor via an anonymous factory + * $httpProvider.responseInterceptors.push(function($q, dependency1, dependency2) { + * return function(promise) { + * // same as above + * } + * }); + *+ * + * + * # Security Considerations * * When designing web applications, consider security threats from: * - * - [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) + * - {@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} * * Both server and the client must cooperate in order to eliminate these threats. Angular comes * pre-configured with strategies that address these issues, but for this to work backend server * cooperation is required. * - * ### JSON Vulnerability Protection + * ## JSON Vulnerability Protection * - * 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 + * 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 * 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 + * ## Cross Site Request Forgery (XSRF) Protection * - * [XSRF](http://en.wikipedia.org/wiki/Cross-site_request_forgery) is an attack technique by - * which the attacker can trick an authenticated user into unknowingly executing actions on your - * website. 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 JavaScript that runs on your domain could read the - * cookie, your server can be assured that the XHR came from JavaScript running on your domain. - * The header will not be set for cross-domain requests. + * {@link http://en.wikipedia.org/wiki/Cross-site_request_forgery XSRF} is a technique by which + * an unauthorized site can gain your user's private data. Angular provides 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 + * JavaScript that runs on your domain could read the cookie, your server can be assured that + * the XHR came from JavaScript running on your domain. The header will not be set for + * cross-domain requests. * * To take advantage of this, your server needs to set a token in a JavaScript readable session * cookie called `XSRF-TOKEN` on the first HTTP GET request. On subsequent XHR requests the @@ -10942,85 +7375,84 @@ 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 [salt](https://en.wikipedia.org/wiki/Salt_(cryptography)) + * authentication cookie with a {@link https://en.wikipedia.org/wiki/Salt_(cryptography) salt} * for added security. * * The name of the headers can be specified using the xsrfHeaderName and xsrfCookieName * properties of either $httpProvider.defaults at config-time, $http.defaults at run-time, * or the per-request config object. * - * In order to prevent collisions in environments where multiple Angular apps share the - * same domain or subdomain, we recommend that each application uses unique cookie name. * * @param {object} config Object describing the request to be made and how it should be * processed. The object has following properties: * * - **method** – `{string}` – HTTP method (e.g. 'GET', 'POST', etc) * - **url** – `{string}` – Absolute or relative URL of the resource that is being requested. - * - **params** – `{Object.