diff --git a/trunk/SiprpWebFichasClinicas/WebContent/static/html/app/Documents/DocumentsController.js b/trunk/SiprpWebFichasClinicas/WebContent/static/html/app/Documents/DocumentsController.js index 09dfe56d..70b49056 100644 --- a/trunk/SiprpWebFichasClinicas/WebContent/static/html/app/Documents/DocumentsController.js +++ b/trunk/SiprpWebFichasClinicas/WebContent/static/html/app/Documents/DocumentsController.js @@ -14,6 +14,9 @@ destroy: 'removerDocumento' } }); + + $scope.btnValue = "Cancelar"; + $scope.isSaved = false; $scope.list = function(){ @@ -38,6 +41,9 @@ $scope.showList = false; $scope.showEdit = true; + + $scope.btnValue = "Cancelar"; + $scope.isSaved = false; }; $scope.edit = function(selected){ @@ -55,6 +61,9 @@ { $scope.fileInputDocument.reset(); } + + $scope.btnValue = "Cancelar"; + $scope.isSaved = false; }; $scope.save = function(){ @@ -64,8 +73,6 @@ if(isValid) { $scope.uploadDocument(); - $scope.list(); - $rootScope.$emit('ondocumentsave'); } }; @@ -117,6 +124,11 @@ //$scope.selected.Picture = data.Picture; //$scope.userPicture.update($scope.editing); + + $scope.list(); + $rootScope.$emit('ondocumentsave'); + $scope.btnValue = "Voltar"; + $scope.isSaved = true; }); } }; diff --git a/trunk/SiprpWebFichasClinicas/WebContent/static/html/app/Documents/DocumentsView.html b/trunk/SiprpWebFichasClinicas/WebContent/static/html/app/Documents/DocumentsView.html index 0d37adcc..d11834bc 100644 --- a/trunk/SiprpWebFichasClinicas/WebContent/static/html/app/Documents/DocumentsView.html +++ b/trunk/SiprpWebFichasClinicas/WebContent/static/html/app/Documents/DocumentsView.html @@ -54,7 +54,7 @@
+ ```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.
@@ -214,17 +312,20 @@ function isArrayLike(obj) {
function forEach(obj, iterator, context) {
var key;
if (obj) {
- if (isFunction(obj)){
+ if (isFunction(obj)) {
for (key in obj) {
- if (key != 'prototype' && key != 'length' && key != 'name' && obj.hasOwnProperty(key)) {
+ // Need to check if hasOwnProperty exists,
+ // as on IE8 the result of querySelectorAll is an object without a hasOwnProperty function
+ if (key != 'prototype' && key != 'length' && key != 'name' && (!obj.hasOwnProperty || obj.hasOwnProperty(key))) {
iterator.call(context, obj[key], key);
}
}
- } else if (obj.forEach && obj.forEach !== forEach) {
- obj.forEach(iterator, context);
- } else if (isArrayLike(obj)) {
- for (key = 0; key < obj.length; key++)
+ } else if (isArray(obj) || isArrayLike(obj)) {
+ for (key = 0; key < obj.length; key++) {
iterator.call(context, obj[key], key);
+ }
+ } else if (obj.forEach && obj.forEach !== forEach) {
+ obj.forEach(iterator, context);
} else {
for (key in obj) {
if (obj.hasOwnProperty(key)) {
@@ -261,7 +362,7 @@ 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); };
}
/**
@@ -270,7 +371,7 @@ function reverseParams(iteratorFn) {
* the number string gets longer over time, and it can also overflow, where as the nextId
* will grow much slower, it is a string, and it will never overflow.
*
- * @returns an unique alpha-numeric string
+ * @returns {string} an unique alpha-numeric string
*/
function nextUid() {
var index = uid.length;
@@ -312,10 +413,11 @@ function setHashKey(obj, h) {
/**
* @ngdoc function
* @name angular.extend
- * @function
+ * @module ng
+ * @kind function
*
* @description
- * Extends the destination object `dst` by copying all of the properties from the `src` object(s)
+ * Extends the destination object `dst` by copying own enumerable properties from the `src` object(s)
* to `dst`. You can specify multiple `src` objects.
*
* @param {Object} dst Destination object.
@@ -324,9 +426,9 @@ function setHashKey(obj, h) {
*/
function extend(dst) {
var h = dst.$$hashKey;
- forEach(arguments, function(obj){
+ forEach(arguments, function(obj) {
if (obj !== dst) {
- forEach(obj, function(value, key){
+ forEach(obj, function(value, key) {
dst[key] = value;
});
}
@@ -348,17 +450,18 @@ function inherit(parent, extra) {
/**
* @ngdoc function
* @name angular.noop
- * @function
+ * @module ng
+ * @kind function
*
* @description
* A function that performs no operations. This function can be useful when writing code in the
* functional style.
-
+ ```js
function foo(callback) {
var result = calculateResult();
(callback || angular.noop)(result);
}
-
+ ```
*/
function noop() {}
noop.$inject = [];
@@ -367,17 +470,18 @@ noop.$inject = [];
/**
* @ngdoc function
* @name angular.identity
- * @function
+ * @module ng
+ * @kind function
*
* @description
* A function that returns its first argument. This function is useful when writing code in the
* functional style.
*
-
+ ```js
function transformer(transformationFn, value) {
return (transformationFn || angular.identity)(value);
};
-
+ ```
*/
function identity($) {return $;}
identity.$inject = [];
@@ -388,7 +492,8 @@ function valueFn(value) {return function() {return value;};}
/**
* @ngdoc function
* @name angular.isUndefined
- * @function
+ * @module ng
+ * @kind function
*
* @description
* Determines if a reference is undefined.
@@ -396,13 +501,14 @@ function valueFn(value) {return function() {return value;};}
* @param {*} value Reference to check.
* @returns {boolean} True if `value` is undefined.
*/
-function isUndefined(value){return typeof value == 'undefined';}
+function isUndefined(value){return typeof value === 'undefined';}
/**
* @ngdoc function
* @name angular.isDefined
- * @function
+ * @module ng
+ * @kind function
*
* @description
* Determines if a reference is defined.
@@ -410,28 +516,30 @@ function isUndefined(value){return typeof value == 'undefined';}
* @param {*} value Reference to check.
* @returns {boolean} True if `value` is defined.
*/
-function isDefined(value){return typeof value != 'undefined';}
+function isDefined(value){return typeof value !== 'undefined';}
/**
* @ngdoc function
* @name angular.isObject
- * @function
+ * @module ng
+ * @kind function
*
* @description
* Determines if a reference is an `Object`. Unlike `typeof` in JavaScript, `null`s are not
- * considered to be objects.
+ * considered to be objects. Note that JavaScript arrays are objects.
*
* @param {*} value Reference to check.
* @returns {boolean} True if `value` is an `Object` but not `null`.
*/
-function isObject(value){return value != null && typeof value == 'object';}
+function isObject(value){return value != null && typeof value === 'object';}
/**
* @ngdoc function
* @name angular.isString
- * @function
+ * @module ng
+ * @kind function
*
* @description
* Determines if a reference is a `String`.
@@ -439,13 +547,14 @@ function isObject(value){return value != null && typeof value == 'object';}
* @param {*} value Reference to check.
* @returns {boolean} True if `value` is a `String`.
*/
-function isString(value){return typeof value == 'string';}
+function isString(value){return typeof value === 'string';}
/**
* @ngdoc function
* @name angular.isNumber
- * @function
+ * @module ng
+ * @kind function
*
* @description
* Determines if a reference is a `Number`.
@@ -453,13 +562,14 @@ function isString(value){return typeof value == 'string';}
* @param {*} value Reference to check.
* @returns {boolean} True if `value` is a `Number`.
*/
-function isNumber(value){return typeof value == 'number';}
+function isNumber(value){return typeof value === 'number';}
/**
* @ngdoc function
* @name angular.isDate
- * @function
+ * @module ng
+ * @kind function
*
* @description
* Determines if a value is a date.
@@ -467,15 +577,16 @@ function isNumber(value){return typeof value == 'number';}
* @param {*} value Reference to check.
* @returns {boolean} True if `value` is a `Date`.
*/
-function isDate(value){
- return toString.apply(value) == '[object Date]';
+function isDate(value) {
+ return toString.call(value) === '[object Date]';
}
/**
* @ngdoc function
* @name angular.isArray
- * @function
+ * @module ng
+ * @kind function
*
* @description
* Determines if a reference is an `Array`.
@@ -483,15 +594,20 @@ function isDate(value){
* @param {*} value Reference to check.
* @returns {boolean} True if `value` is an `Array`.
*/
-function isArray(value) {
- return toString.apply(value) == '[object Array]';
-}
-
+var isArray = (function() {
+ if (!isFunction(Array.isArray)) {
+ return function(value) {
+ return toString.call(value) === '[object Array]';
+ };
+ }
+ return Array.isArray;
+})();
/**
* @ngdoc function
* @name angular.isFunction
- * @function
+ * @module ng
+ * @kind function
*
* @description
* Determines if a reference is a `Function`.
@@ -499,7 +615,7 @@ function isArray(value) {
* @param {*} value Reference to check.
* @returns {boolean} True if `value` is a `Function`.
*/
-function isFunction(value){return typeof value == 'function';}
+function isFunction(value){return typeof value === 'function';}
/**
@@ -510,7 +626,7 @@ function isFunction(value){return typeof value == 'function';}
* @returns {boolean} True if `value` is a `RegExp`.
*/
function isRegExp(value) {
- return toString.apply(value) == '[object RegExp]';
+ return toString.call(value) === '[object RegExp]';
}
@@ -532,12 +648,22 @@ function isScope(obj) {
function isFile(obj) {
- return toString.apply(obj) === '[object File]';
+ return toString.call(obj) === '[object File]';
+}
+
+
+function isBlob(obj) {
+ return toString.call(obj) === '[object Blob]';
}
function isBoolean(value) {
- return typeof value == 'boolean';
+ return typeof value === 'boolean';
+}
+
+
+function isPromiseLike(obj) {
+ return obj && isFunction(obj.then);
}
@@ -547,7 +673,7 @@ var trim = (function() {
// TODO: we should move this into IE/ES5 polyfill
if (!String.prototype.trim) {
return function(value) {
- return isString(value) ? value.replace(/^\s*/, '').replace(/\s*$/, '') : value;
+ return isString(value) ? value.replace(/^\s\s*/, '').replace(/\s\s*$/, '') : value;
};
}
return function(value) {
@@ -559,7 +685,8 @@ var trim = (function() {
/**
* @ngdoc function
* @name angular.isElement
- * @function
+ * @module ng
+ * @kind function
*
* @description
* Determines if a reference is a DOM element (or wrapped jQuery element).
@@ -568,16 +695,16 @@ var trim = (function() {
* @returns {boolean} True if `value` is a DOM element (or wrapped jQuery element).
*/
function isElement(node) {
- return node &&
+ return !!(node &&
(node.nodeName // we are a direct element
- || (node.on && node.find)); // we have an on and find method part of jQuery API
+ || (node.prop && node.attr && node.find))); // we have an on and find method part of jQuery API
}
/**
* @param str 'key1,key2,...'
* @returns {object} in the form of {key1:true, key2:true, ...}
*/
-function makeMap(str){
+function makeMap(str) {
var obj = {}, items = str.split(","), i;
for ( i = 0; i < items.length; i++ )
obj[ items[i] ] = true;
@@ -620,17 +747,17 @@ function map(obj, iterator, context) {
* @returns {number} The size of `obj` or `0` if `obj` is neither an object nor an array.
*/
function size(obj, ownPropsOnly) {
- var size = 0, key;
+ var count = 0, key;
if (isArray(obj) || isString(obj)) {
return obj.length;
- } else if (isObject(obj)){
+ } else if (isObject(obj)) {
for (key in obj)
if (!ownPropsOnly || obj.hasOwnProperty(key))
- size++;
+ count++;
}
- return size;
+ return count;
}
@@ -641,7 +768,7 @@ function includes(array, obj) {
function indexOf(array, obj) {
if (array.indexOf) return array.indexOf(obj);
- for ( var i = 0; i < array.length; i++) {
+ for (var i = 0; i < array.length; i++) {
if (obj === array[i]) return i;
}
return -1;
@@ -669,7 +796,8 @@ function isLeafNode (node) {
/**
* @ngdoc function
* @name angular.copy
- * @function
+ * @module ng
+ * @kind function
*
* @description
* Creates a deep copy of `source`, which should be an object or an array.
@@ -677,87 +805,163 @@ function isLeafNode (node) {
* * If no destination is supplied, a copy of the object or array is created.
* * 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, `source` is returned.
- *
- * Note: this function is used to augment the Object type in Angular expressions. See
- * {@link ng.$filter} for more information about Angular arrays.
+ * * 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.
*
* @param {*} source The source that will be used to make a copy.
* Can be any type, including primitives, `null`, and `undefined`.
* @param {(Object|Array)=} destination Destination into which the source is copied. If
* provided, must be of the same type as `source`.
* @returns {*} The copy or updated `destination`, if `destination` was specified.
+ *
+ * @example
+ form = {{user | json}}
+ master = {{master | json}}
+ | {{heading}} | + *
|---|
| {{fill}} | + *
+ * ```js
* // Create a new module
* var myModule = angular.module('myModule', []);
*
@@ -1298,38 +1638,45 @@ function setupModuleLoader(window) {
* myModule.value('appName', 'MyCoolApp');
*
* // configure existing services inside initialization blocks.
- * myModule.config(function($locationProvider) {
+ * myModule.config(['$locationProvider', function($locationProvider) {
* // Configure existing providers
* $locationProvider.hashPrefix('!');
- * });
- *
+ * }]);
+ * ```
*
* Then you can create an injector and load your modules like this:
*
- * - * var injector = angular.injector(['ng', 'MyModule']) - *+ * ```js + * var injector = angular.injector(['ng', 'myModule']) + * ``` * * However it's more likely that you'll just use * {@link ng.directive:ngApp ngApp} or * {@link angular.bootstrap} to simplify this process for you. * * @param {!string} name The name of the module to create or retrieve. - * @param {Array.
+ * ```js
* module.animation('.animation-name', function($inject1, $inject2) {
* return {
* eventName : function(element, done) {
@@ -1448,7 +1799,7 @@ function setupModuleLoader(window) {
* }
* }
* })
- *
+ * ```
*
* See {@link ngAnimate.$animateProvider#register $animateProvider.register()} and
* {@link ngAnimate ngAnimate module} for more information.
@@ -1458,7 +1809,7 @@ function setupModuleLoader(window) {
/**
* @ngdoc method
* @name angular.Module#filter
- * @methodOf angular.Module
+ * @module ng
* @param {string} name Filter name.
* @param {Function} filterFactory Factory function for creating new instance of filter.
* @description
@@ -1469,8 +1820,9 @@ function setupModuleLoader(window) {
/**
* @ngdoc method
* @name angular.Module#controller
- * @methodOf angular.Module
- * @param {string} name Controller name.
+ * @module ng
+ * @param {string|Object} name Controller name, or an object map of controllers where the
+ * keys are the names and the values are the constructors.
* @param {Function} constructor Controller constructor function.
* @description
* See {@link ng.$controllerProvider#register $controllerProvider.register()}.
@@ -1480,8 +1832,9 @@ function setupModuleLoader(window) {
/**
* @ngdoc method
* @name angular.Module#directive
- * @methodOf angular.Module
- * @param {string} name directive name
+ * @module ng
+ * @param {string|Object} name Directive name, or an object map of directives where the
+ * keys are the names and the values are the factories.
* @param {Function} directiveFactory Factory function for creating new instance of
* directives.
* @description
@@ -1492,18 +1845,20 @@ function setupModuleLoader(window) {
/**
* @ngdoc method
* @name angular.Module#config
- * @methodOf angular.Module
+ * @module ng
* @param {Function} configFn Execute this function on module load. Useful for service
* configuration.
* @description
* Use this method to register work which needs to be performed on module loading.
+ * For more about how to configure services, see
+ * {@link providers#providers_provider-recipe Provider Recipe}.
*/
config: config,
/**
* @ngdoc method
* @name angular.Module#run
- * @methodOf angular.Module
+ * @module ng
* @param {Function} initializationFn Execute this function after injector creation.
* Useful for application initialization.
* @description
@@ -1532,7 +1887,7 @@ function setupModuleLoader(window) {
return function() {
invokeQueue[insertMethod || 'push']([provider, method, arguments]);
return moduleInstance;
- }
+ };
}
});
};
@@ -1540,9 +1895,87 @@ function setupModuleLoader(window) {
}
+/* global angularModule: true,
+ version: true,
+
+ $LocaleProvider,
+ $CompileProvider,
+
+ htmlAnchorDirective,
+ inputDirective,
+ inputDirective,
+ formDirective,
+ scriptDirective,
+ selectDirective,
+ styleDirective,
+ optionDirective,
+ ngBindDirective,
+ ngBindHtmlDirective,
+ ngBindTemplateDirective,
+ ngClassDirective,
+ ngClassEvenDirective,
+ ngClassOddDirective,
+ ngCspDirective,
+ ngCloakDirective,
+ ngControllerDirective,
+ ngFormDirective,
+ ngHideDirective,
+ ngIfDirective,
+ ngIncludeDirective,
+ ngIncludeFillContentDirective,
+ ngInitDirective,
+ ngNonBindableDirective,
+ ngPluralizeDirective,
+ ngRepeatDirective,
+ ngShowDirective,
+ ngStyleDirective,
+ ngSwitchDirective,
+ ngSwitchWhenDirective,
+ ngSwitchDefaultDirective,
+ ngOptionsDirective,
+ ngTranscludeDirective,
+ ngModelDirective,
+ ngListDirective,
+ ngChangeDirective,
+ requiredDirective,
+ requiredDirective,
+ ngValueDirective,
+ ngAttributeAliasDirectives,
+ ngEventDirectives,
+
+ $AnchorScrollProvider,
+ $AnimateProvider,
+ $BrowserProvider,
+ $CacheFactoryProvider,
+ $ControllerProvider,
+ $DocumentProvider,
+ $ExceptionHandlerProvider,
+ $FilterProvider,
+ $InterpolateProvider,
+ $IntervalProvider,
+ $HttpProvider,
+ $HttpBackendProvider,
+ $LocationProvider,
+ $LogProvider,
+ $ParseProvider,
+ $RootScopeProvider,
+ $QProvider,
+ $$SanitizeUriProvider,
+ $SceProvider,
+ $SceDelegateProvider,
+ $SnifferProvider,
+ $TemplateCacheProvider,
+ $TimeoutProvider,
+ $$RAFProvider,
+ $$AsyncCallbackProvider,
+ $WindowProvider
+*/
+
+
/**
- * @ngdoc property
+ * @ngdoc object
* @name angular.version
+ * @module ng
* @description
* An object that contains information about the current AngularJS version. This object has the
* following properties:
@@ -1554,11 +1987,11 @@ function setupModuleLoader(window) {
* - `codeName` – `{string}` – Code name of the release, such as "jiggling-armfat".
*/
var version = {
- full: '1.2.0-rc.2', // all of these placeholder strings will be replaced by grunt's
+ full: '1.2.26', // all of these placeholder strings will be replaced by grunt's
major: 1, // package task
minor: 2,
- dot: 0,
- codeName: 'barehand-atomsplitting'
+ dot: 26,
+ codeName: 'captivating-disinterest'
};
@@ -1571,11 +2004,11 @@ function publishExternalAPI(angular){
'element': jqLite,
'forEach': forEach,
'injector': createInjector,
- 'noop':noop,
- 'bind':bind,
+ 'noop': noop,
+ 'bind': bind,
'toJson': toJson,
'fromJson': fromJson,
- 'identity':identity,
+ 'identity': identity,
'isUndefined': isUndefined,
'isDefined': isDefined,
'isString': isString,
@@ -1584,12 +2017,13 @@ function publishExternalAPI(angular){
'isNumber': isNumber,
'isElement': isElement,
'isArray': isArray,
- '$$minErr': minErr,
'version': version,
'isDate': isDate,
'lowercase': lowercase,
'uppercase': uppercase,
- 'callbacks': {counter: 0}
+ 'callbacks': {counter: 0},
+ '$$minErr': minErr,
+ '$$csp': csp
});
angularModule = setupModuleLoader(window);
@@ -1601,6 +2035,10 @@ function publishExternalAPI(angular){
angularModule('ng', ['ngLocale'], ['$provide',
function ngModule($provide) {
+ // $$sanitizeUriProvider needs to be before $compileProvider as it is used by it.
+ $provide.provider({
+ $$sanitizeUri: $$SanitizeUriProvider
+ });
$provide.provider('$compile', $CompileProvider).
directive({
a: htmlAnchorDirective,
@@ -1617,7 +2055,6 @@ function publishExternalAPI(angular){
ngClass: ngClassDirective,
ngClassEven: ngClassEvenDirective,
ngClassOdd: ngClassOddDirective,
- ngCsp: ngCspDirective,
ngCloak: ngCloakDirective,
ngController: ngControllerDirective,
ngForm: ngFormDirective,
@@ -1642,6 +2079,9 @@ function publishExternalAPI(angular){
ngRequired: requiredDirective,
ngValue: ngValueDirective
}).
+ directive({
+ ngInclude: ngIncludeFillContentDirective
+ }).
directive(ngAttributeAliasDirectives).
directive(ngEventDirectives);
$provide.provider({
@@ -1654,6 +2094,7 @@ function publishExternalAPI(angular){
$exceptionHandler: $ExceptionHandlerProvider,
$filter: $FilterProvider,
$interpolate: $InterpolateProvider,
+ $interval: $IntervalProvider,
$http: $HttpProvider,
$httpBackend: $HttpBackendProvider,
$location: $LocationProvider,
@@ -1667,12 +2108,19 @@ function publishExternalAPI(angular){
$templateCache: $TemplateCacheProvider,
$timeout: $TimeoutProvider,
$window: $WindowProvider,
- $$urlUtils: $$UrlUtilsProvider
+ $$rAF: $$RAFProvider,
+ $$asyncCallback : $$AsyncCallbackProvider
});
}
]);
}
+/* global JQLitePrototype: true,
+ addEventListenerFn: true,
+ removeEventListenerFn: true,
+ BOOLEAN_ATTR: true
+*/
+
//////////////////////////////////
//JQLite
//////////////////////////////////
@@ -1680,76 +2128,82 @@ function publishExternalAPI(angular){
/**
* @ngdoc function
* @name angular.element
- * @function
+ * @module ng
+ * @kind function
*
* @description
* Wraps a raw DOM element or HTML string as a [jQuery](http://jquery.com) element.
- * `angular.element` can be either an alias for [jQuery](http://api.jquery.com/jQuery/) function, if
- * jQuery is available, or a function that wraps the element or string in Angular's jQuery lite
- * implementation (commonly referred to as jqLite).
*
- * Real jQuery always takes precedence over jqLite, provided it was loaded before `DOMContentLoaded`
- * event fired.
+ * If jQuery is available, `angular.element` is an alias for the
+ * [jQuery](http://api.jquery.com/jQuery/) function. If jQuery is not available, `angular.element`
+ * delegates to Angular's built-in subset of jQuery, called "jQuery lite" or "jqLite."
+ *
+ *
+ * ```js
* // create an injector
* var $injector = angular.injector(['ng']);
*
@@ -2595,16 +3222,38 @@ HashMap.prototype = {
* $compile($document)($rootScope);
* $rootScope.$digest();
* });
- *
+ * ```
+ *
+ * Sometimes you want to get access to the injector of a currently running Angular app
+ * from outside Angular. Perhaps, you want to inject and compile some markup after the
+ * application has been bootstrapped. You can do this using the extra `injector()` added
+ * to JQuery/jqLite elements. See {@link angular.element}.
+ *
+ * *This is fairly rare but could be the case if a third party library is injecting the
+ * markup.*
+ *
+ * In the following example a new block of HTML containing a `ng-controller`
+ * directive is added to the end of the document body by JQuery. We then compile and link
+ * it into the current AngularJS scope.
+ *
+ * ```js
+ * var $div = $('
+ * ```js
* var $injector = angular.injector();
* expect($injector.get('$injector')).toBe($injector);
* expect($injector.invoke(function($injector){
* return $injector;
* }).toBe($injector);
- *
+ * ```
*
* # 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){});
*
@@ -2681,16 +3330,16 @@ function annotate(fn) {
*
* // 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. *NOTE:* This does not work with minification, and obfuscation
- * tools since these tools change the argument names.
+ * In JavaScript calling `toString()` on a function returns the function definition. The definition
+ * 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 a `$inject` property onto a function the injection parameters can be specified.
+ * By adding an `$inject` property onto a function the injection parameters can be specified.
*
* ## Inline
* As an array of injection names, where the last item in the array is the function to call.
@@ -2698,8 +3347,7 @@ function annotate(fn) {
/**
* @ngdoc method
- * @name AUTO.$injector#get
- * @methodOf AUTO.$injector
+ * @name $injector#get
*
* @description
* Return an instance of the service.
@@ -2710,26 +3358,25 @@ function annotate(fn) {
/**
* @ngdoc method
- * @name AUTO.$injector#invoke
- * @methodOf AUTO.$injector
+ * @name $injector#invoke
*
* @description
* Invoke the method and supply the method arguments from the `$injector`.
*
- * @param {!function} fn The function to invoke. The function arguments come form the function annotation.
+ * @param {!Function} fn The function to invoke. Function parameters are injected according to the
+ * {@link guide/di $inject Annotation} rules.
* @param {Object=} self The `this` for the invoked method.
- * @param {Object=} locals Optional object. If preset then any argument names are read from this object first, before
- * the `$injector` is consulted.
+ * @param {Object=} locals Optional object. If preset then any argument names are read from this
+ * object first, before the `$injector` is consulted.
* @returns {*} the value returned by the invoked `fn` function.
*/
/**
* @ngdoc method
- * @name AUTO.$injector#has
- * @methodOf AUTO.$injector
+ * @name $injector#has
*
* @description
- * Allows the user to query if the particular service exist.
+ * Allows the user to query if the particular service exists.
*
* @param {string} Name of the service to query.
* @returns {boolean} returns true if injector has given service.
@@ -2737,33 +3384,34 @@ function annotate(fn) {
/**
* @ngdoc method
- * @name AUTO.$injector#instantiate
- * @methodOf AUTO.$injector
+ * @name $injector#instantiate
* @description
- * Create a new instance of JS type. The method takes a constructor function invokes the new operator and supplies
- * all of the arguments to the constructor function as specified by the constructor annotation.
+ * Create a new instance of JS type. The method takes a constructor function, invokes the new
+ * operator, and supplies all of the arguments to the constructor function as specified by the
+ * constructor annotation.
*
- * @param {function} Type Annotated constructor function.
- * @param {Object=} locals Optional object. If preset then any argument names are read from this object first, before
- * the `$injector` is consulted.
+ * @param {Function} Type Annotated constructor function.
+ * @param {Object=} locals Optional object. If preset then any argument names are read from this
+ * object first, before the `$injector` is consulted.
* @returns {Object} new instance of `Type`.
*/
/**
* @ngdoc method
- * @name AUTO.$injector#annotate
- * @methodOf AUTO.$injector
+ * @name $injector#annotate
*
* @description
- * Returns an array of service names which the function is requesting for injection. This API is used by the injector
- * to determine which services need to be injected into the function when the function is invoked. There are three
- * ways in which the function can be annotated with the needed dependencies.
+ * Returns an array of service names which the function is requesting for injection. This API is
+ * used by the injector to determine which services need to be injected into the function when the
+ * function is invoked. There are three ways in which the function can be annotated with the needed
+ * dependencies.
*
* # Argument names
*
- * The simplest form is to extract the dependencies from the arguments of the function. This is done by converting
- * the function into a string using `toString()` method and extracting the argument names.
- *
+ * The simplest form is to extract the dependencies from the arguments of the function. This is done
+ * by converting the function into a string using `toString()` method and extracting the argument
+ * names.
+ * ```js
* // Given
* function MyController($scope, $route) {
* // ...
@@ -2771,34 +3419,34 @@ function annotate(fn) {
*
* // Then
* expect(injector.annotate(MyController)).toEqual(['$scope', '$route']);
- *
+ * ```
*
- * This method does not work with code minification / obfuscation. For this reason the following annotation strategies
- * are supported.
+ * This method does not work with code minification / obfuscation. For this reason the following
+ * annotation strategies are supported.
*
* # The `$inject` property
*
- * 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.
- *
+ * If a function has an `$inject` property and its value is an array of strings, then the strings
+ * represent names of services to be injected into the function.
+ * ```js
* // Given
* var MyController = function(obfuscatedScope, obfuscatedRoute) {
* // ...
* }
* // Define function dependencies
- * MyController.$inject = ['$scope', '$route'];
+ * MyController['$inject'] = ['$scope', '$route'];
*
* // Then
* expect(injector.annotate(MyController)).toEqual(['$scope', '$route']);
- *
+ * ```
*
* # The array notation
*
- * It is often desirable to inline Injected functions and that's when setting the `$inject` property is very
- * inconvenient. In these situations using the array notation to specify the dependencies in a way that survives
- * minification is a better choice:
+ * It is often desirable to inline Injected functions and that's when setting the `$inject` property
+ * 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) {
* // ...
@@ -2820,10 +3468,10 @@ function annotate(fn) {
* expect(injector.annotate(
* ['$compile', '$rootScope', function(obfus_$compile, obfus_$rootScope) {}])
* ).toEqual(['$compile', '$rootScope']);
- *
+ * ```
*
- * @param {function|Array.
- * function GreetProvider() {
- * var salutation = 'Hello';
- *
- * this.salutation = function(text) {
- * salutation = text;
- * };
- *
- * this.$get = function() {
- * return function (name) {
- * return salutation + ' ' + name + '!';
- * };
- * };
- * }
- *
- * describe('Greeter', function(){
- *
- * beforeEach(module(function($provide) {
- * $provide.provider('greet', GreetProvider);
- * }));
- *
- * it('should greet', inject(function(greet) {
- * expect(greet('angular')).toEqual('Hello angular!');
- * }));
- *
- * it('should allow configuration of salutation', function() {
- * module(function(greetProvider) {
- * greetProvider.salutation('Ahoj');
- * });
- * inject(function(greet) {
- * expect(greet('angular')).toEqual('Ahoj angular!');
- * });
- * });
- *
+ * The {@link auto.$provide $provide} service has a number of methods for registering components
+ * with the {@link auto.$injector $injector}. Many of these functions are also exposed on
+ * {@link angular.Module}.
+ *
+ * An Angular **service** is a singleton object created by a **service factory**. These **service
+ * factories** are functions which, in turn, are created by a **service provider**.
+ * The **service providers** are constructor functions. When instantiated they must contain a
+ * property called `$get`, which holds the **service factory** function.
+ *
+ * When you request a service, the {@link auto.$injector $injector} is responsible for finding the
+ * correct **service provider**, instantiating it and then calling its `$get` **service factory**
+ * function to get the instance of the **service**.
+ *
+ * Often services have no configuration options and there is no need to add methods to the service
+ * provider. The provider will be no more than a constructor function with a `$get` property. For
+ * these cases the {@link auto.$provide $provide} service has additional helper methods to register
+ * services without specifying a provider.
+ *
+ * * {@link auto.$provide#provider provider(provider)} - registers a **service provider** with the
+ * {@link auto.$injector $injector}
+ * * {@link auto.$provide#constant constant(obj)} - registers a value/object that can be accessed by
+ * providers and services.
+ * * {@link auto.$provide#value value(obj)} - registers a value/object that can only be accessed by
+ * services, not providers.
+ * * {@link auto.$provide#factory factory(fn)} - registers a service **factory function**, `fn`,
+ * that will be wrapped in a **service provider** object, whose `$get` property will contain the
+ * given factory function.
+ * * {@link auto.$provide#service service(class)} - registers a **constructor function**, `class`
+ * that will be wrapped in a **service provider** object, whose `$get` property will instantiate
+ * a new object using the given constructor function.
+ *
+ * See the individual methods for more information and examples.
*/
/**
* @ngdoc method
- * @name AUTO.$provide#provider
- * @methodOf AUTO.$provide
+ * @name $provide#provider
* @description
*
- * Register a provider for a service. The providers can be retrieved and can have additional configuration methods.
+ * Register a **provider function** with the {@link auto.$injector $injector}. Provider functions
+ * are constructor functions, whose instances are responsible for "providing" a factory for a
+ * service.
+ *
+ * Service provider names start with the name of the service they provide followed by `Provider`.
+ * For example, the {@link ng.$log $log} service has a provider called
+ * {@link ng.$logProvider $logProvider}.
+ *
+ * Service provider objects can have additional methods which allow configuration of the provider
+ * and its service. Importantly, you can configure what kind of service is created by the `$get`
+ * method, or how that service will act. For example, the {@link ng.$logProvider $logProvider} has a
+ * method {@link ng.$logProvider#debugEnabled debugEnabled}
+ * which lets you specify whether the {@link ng.$log $log} service will log debug messages to the
+ * console or not.
*
- * @param {string} name The name of the instance. NOTE: the provider will be available under `name + 'Provider'` key.
+ * @param {string} name The name of the instance. NOTE: the provider will be available under `name +
+ 'Provider'` key.
* @param {(Object|function())} provider If the provider is:
*
* - `Object`: then it should have a `$get` method. The `$get` method will be invoked using
- * {@link AUTO.$injector#invoke $injector.invoke()} when an instance needs to be created.
+ * {@link auto.$injector#invoke $injector.invoke()} when an instance needs to be created.
* - `Constructor`: a new instance of the provider will be created using
- * {@link AUTO.$injector#instantiate $injector.instantiate()}, then treated as `object`.
+ * {@link auto.$injector#instantiate $injector.instantiate()}, then treated as `object`.
*
* @returns {Object} registered provider instance
+
+ * @example
+ *
+ * The following example shows how to create a simple event tracking service and register it using
+ * {@link auto.$provide#provider $provide.provider()}.
+ *
+ * ```js
+ * // Define the eventTracker provider
+ * function EventTrackerProvider() {
+ * var trackingUrl = '/track';
+ *
+ * // A provider method for configuring where the tracked events should been saved
+ * this.setTrackingUrl = function(url) {
+ * trackingUrl = url;
+ * };
+ *
+ * // The service factory function
+ * this.$get = ['$http', function($http) {
+ * var trackedEvents = {};
+ * return {
+ * // Call this to track an event
+ * event: function(event) {
+ * var count = trackedEvents[event] || 0;
+ * count += 1;
+ * trackedEvents[event] = count;
+ * return count;
+ * },
+ * // Call this to save the tracked events to the trackingUrl
+ * save: function() {
+ * $http.post(trackingUrl, trackedEvents);
+ * }
+ * };
+ * }];
+ * }
+ *
+ * describe('eventTracker', function() {
+ * var postSpy;
+ *
+ * beforeEach(module(function($provide) {
+ * // Register the eventTracker provider
+ * $provide.provider('eventTracker', EventTrackerProvider);
+ * }));
+ *
+ * beforeEach(module(function(eventTrackerProvider) {
+ * // Configure eventTracker provider
+ * eventTrackerProvider.setTrackingUrl('/custom-track');
+ * }));
+ *
+ * it('tracks events', inject(function(eventTracker) {
+ * expect(eventTracker.event('login')).toEqual(1);
+ * expect(eventTracker.event('login')).toEqual(2);
+ * }));
+ *
+ * it('saves to the tracking url', inject(function(eventTracker, $http) {
+ * postSpy = spyOn($http, 'post');
+ * eventTracker.event('login');
+ * eventTracker.save();
+ * expect(postSpy).toHaveBeenCalled();
+ * expect(postSpy.mostRecentCall.args[0]).not.toEqual('/track');
+ * expect(postSpy.mostRecentCall.args[0]).toEqual('/custom-track');
+ * expect(postSpy.mostRecentCall.args[1]).toEqual({ 'login': 1 });
+ * }));
+ * });
+ * ```
*/
/**
* @ngdoc method
- * @name AUTO.$provide#factory
- * @methodOf AUTO.$provide
+ * @name $provide#factory
* @description
*
- * A short hand for configuring services if only `$get` method is required.
+ * 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
+ * configure your service in a provider.
*
* @param {string} name The name of the instance.
- * @param {function()} $getFn The $getFn for the instance creation. Internally this is a short hand for
- * `$provide.provider(name, {$get: $getFn})`.
+ * @param {function()} $getFn The $getFn for the instance creation. Internally this is a short hand
+ * for `$provide.provider(name, {$get: $getFn})`.
* @returns {Object} registered provider instance
+ *
+ * @example
+ * Here is an example of registering a service
+ * ```js
+ * $provide.factory('ping', ['$http', function($http) {
+ * return function ping() {
+ * return $http.send('/ping');
+ * };
+ * }]);
+ * ```
+ * You would then inject and use this service like this:
+ * ```js
+ * someModule.controller('Ctrl', ['ping', function(ping) {
+ * ping();
+ * }]);
+ * ```
*/
/**
* @ngdoc method
- * @name AUTO.$provide#service
- * @methodOf AUTO.$provide
+ * @name $provide#service
* @description
*
- * A short hand for registering service of given class.
+ * 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 the service
+ * constructor function that will be used to instantiate the service instance.
+ *
+ * You should use {@link auto.$provide#service $provide.service(class)} if you define your service
+ * as a type/class.
*
* @param {string} name The name of the instance.
* @param {Function} constructor A class (constructor function) that will be instantiated.
* @returns {Object} registered provider instance
+ *
+ * @example
+ * Here is an example of registering a service using
+ * {@link auto.$provide#service $provide.service(class)}.
+ * ```js
+ * var Ping = function($http) {
+ * this.$http = $http;
+ * };
+ *
+ * Ping.$inject = ['$http'];
+ *
+ * Ping.prototype.send = function() {
+ * return this.$http.get('/ping');
+ * };
+ * $provide.service('ping', Ping);
+ * ```
+ * You would then inject and use this service like this:
+ * ```js
+ * someModule.controller('Ctrl', ['ping', function(ping) {
+ * ping.send();
+ * }]);
+ * ```
*/
/**
* @ngdoc method
- * @name AUTO.$provide#value
- * @methodOf AUTO.$provide
+ * @name $provide#value
* @description
*
- * A short hand for configuring services if the `$get` method is a constant.
+ * 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**.
+ *
+ * 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}.
*
* @param {string} name The name of the instance.
* @param {*} value The value.
* @returns {Object} registered provider instance
+ *
+ * @example
+ * Here are some examples of creating value services.
+ * ```js
+ * $provide.value('ADMIN_USER', 'admin');
+ *
+ * $provide.value('RoleLookup', { admin: 0, writer: 1, reader: 2 });
+ *
+ * $provide.value('halfOf', function(value) {
+ * return value / 2;
+ * });
+ * ```
*/
/**
* @ngdoc method
- * @name AUTO.$provide#constant
- * @methodOf AUTO.$provide
+ * @name $provide#constant
* @description
*
- * A constant value, but unlike {@link AUTO.$provide#value value} it can be injected
- * into configuration function (other modules) and it is not interceptable by
- * {@link AUTO.$provide#decorator decorator}.
+ * 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}.
*
* @param {string} name The name of the constant.
* @param {*} value The constant value.
* @returns {Object} registered instance
+ *
+ * @example
+ * Here a some examples of creating constants:
+ * ```js
+ * $provide.constant('SHARD_HEIGHT', 306);
+ *
+ * $provide.constant('MY_COLOURS', ['red', 'blue', 'grey']);
+ *
+ * $provide.constant('double', function(value) {
+ * return value * 2;
+ * });
+ * ```
*/
/**
* @ngdoc method
- * @name AUTO.$provide#decorator
- * @methodOf AUTO.$provide
+ * @name $provide#decorator
* @description
*
- * Decoration of service, allows the decorator to intercept the service instance creation. The
- * returned instance may be the original instance, or a new instance which delegates to the
- * original instance.
+ * 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()} decorator This function will be invoked when the service needs to be
- * instantiated. The function is called using the {@link AUTO.$injector#invoke
- * injector.invoke} method and is therefore fully injectable. Local injection arguments:
+ * instantiated and should return the decorated service instance. The function is called using
+ * the {@link auto.$injector#invoke injector.invoke} method and is therefore fully injectable.
+ * Local injection arguments:
*
* * `$delegate` - The original service instance, which can be monkey patched, configured,
* decorated or delegated to.
+ *
+ * @example
+ * Here we decorate the {@link ng.$log $log} service to convert warnings to errors by intercepting
+ * calls to {@link ng.$log#error $log.warn()}.
+ * ```js
+ * $provide.decorator('$log', ['$delegate', function($delegate) {
+ * $delegate.warn = $delegate.error;
+ * return $delegate;
+ * }]);
+ * ```
*/
@@ -2981,7 +3786,7 @@ function createInjector(modulesToLoad) {
var INSTANTIATING = {},
providerSuffix = 'Provider',
path = [],
- loadedModules = new HashMap(),
+ loadedModules = new HashMap([], true),
providerCache = {
$provide: {
provider: supportObject(provider),
@@ -3019,10 +3824,11 @@ function createInjector(modulesToLoad) {
} else {
return delegate(key, value);
}
- }
+ };
}
function provider(name, provider_) {
+ assertNotHasOwnProperty(name, 'service');
if (isFunction(provider_) || isArray(provider_)) {
provider_ = providerInjector.instantiate(provider_);
}
@@ -3040,9 +3846,10 @@ function createInjector(modulesToLoad) {
}]);
}
- function value(name, value) { return factory(name, valueFn(value)); }
+ function value(name, val) { return factory(name, valueFn(val)); }
function constant(name, value) {
+ assertNotHasOwnProperty(name, 'constant');
providerCache[name] = value;
instanceCache[name] = value;
}
@@ -3061,17 +3868,17 @@ function createInjector(modulesToLoad) {
// Module Loading
////////////////////////////////////
function loadModules(modulesToLoad){
- var runBlocks = [];
+ var runBlocks = [], moduleFn, invokeQueue, i, ii;
forEach(modulesToLoad, function(module) {
if (loadedModules.get(module)) return;
loadedModules.put(module, true);
try {
if (isString(module)) {
- var moduleFn = angularModule(module);
+ moduleFn = angularModule(module);
runBlocks = runBlocks.concat(loadModules(moduleFn.requires)).concat(moduleFn._runBlocks);
- for(var invokeQueue = moduleFn._invokeQueue, i = 0, ii = invokeQueue.length; i < ii; i++) {
+ for(invokeQueue = moduleFn._invokeQueue, i = 0, ii = invokeQueue.length; i < ii; i++) {
var invokeArgs = invokeQueue[i],
provider = providerInjector.get(invokeArgs[0]);
@@ -3089,12 +3896,15 @@ function createInjector(modulesToLoad) {
module = module[module.length - 1];
}
if (e.message && e.stack && e.stack.indexOf(e.message) == -1) {
- // Safari & FF's stack traces don't contain error.message content unlike those of Chrome and IE
+ // Safari & FF's stack traces don't contain error.message content
+ // unlike those of Chrome and IE
// So if stack doesn't contain message, we create a new string that contains both.
// Since error.stack is read-only in Safari, I'm overriding e and not e.stack here.
+ /* jshint -W022 */
e = e.message + '\n' + e.stack;
}
- throw $injectorMinErr('modulerr', "Failed to instantiate module {0} due to:\n{1}", module, e.stack || e.message || e);
+ throw $injectorMinErr('modulerr', "Failed to instantiate module {0} due to:\n{1}",
+ module, e.stack || e.message || e);
}
});
return runBlocks;
@@ -3109,7 +3919,8 @@ function createInjector(modulesToLoad) {
function getService(serviceName) {
if (cache.hasOwnProperty(serviceName)) {
if (cache[serviceName] === INSTANTIATING) {
- throw $injectorMinErr('cdep', 'Circular dependency found: {0}', path.join(' <- '));
+ throw $injectorMinErr('cdep', 'Circular dependency found: {0}',
+ serviceName + ' <- ' + path.join(' <- '));
}
return cache[serviceName];
} else {
@@ -3117,6 +3928,11 @@ function createInjector(modulesToLoad) {
path.unshift(serviceName);
cache[serviceName] = INSTANTIATING;
return cache[serviceName] = factory(serviceName);
+ } catch (err) {
+ if (cache[serviceName] === INSTANTIATING) {
+ delete cache[serviceName];
+ }
+ throw err;
} finally {
path.shift();
}
@@ -3132,7 +3948,8 @@ function createInjector(modulesToLoad) {
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);
+ throw $injectorMinErr('itkn',
+ 'Incorrect injection token! Expected service name as string, got {0}', key);
}
args.push(
locals && locals.hasOwnProperty(key)
@@ -3140,27 +3957,13 @@ function createInjector(modulesToLoad) {
: getService(key)
);
}
- if (!fn.$inject) {
- // this means that we must be an array.
+ if (isArray(fn)) {
fn = fn[length];
}
-
- // Performance optimization: http://jsperf.com/apply-vs-call-vs-invoke
- switch (self ? -1 : args.length) {
- case 0: return fn();
- case 1: return fn(args[0]);
- case 2: return fn(args[0], args[1]);
- case 3: return fn(args[0], args[1], args[2]);
- case 4: return fn(args[0], args[1], args[2], args[3]);
- case 5: return fn(args[0], args[1], args[2], args[3], args[4]);
- case 6: return fn(args[0], args[1], args[2], args[3], args[4], args[5]);
- case 7: return fn(args[0], args[1], args[2], args[3], args[4], args[5], args[6]);
- case 8: return fn(args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7]);
- case 9: return fn(args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8]);
- case 10: return fn(args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8], args[9]);
- default: return fn.apply(self, args);
- }
+ // http://jsperf.com/angularjs-invoke-apply-vs-switch
+ // #5388
+ return fn.apply(self, args);
}
function instantiate(Type, locals) {
@@ -3173,7 +3976,7 @@ function createInjector(modulesToLoad) {
instance = new Constructor();
returnedValue = invoke(Type, instance, locals);
- return isObject(returnedValue) ? returnedValue : instance;
+ return isObject(returnedValue) || isFunction(returnedValue) ? returnedValue : instance;
}
return {
@@ -3189,21 +3992,55 @@ function createInjector(modulesToLoad) {
}
/**
- * @ngdoc function
- * @name ng.$anchorScroll
+ * @ngdoc service
+ * @name $anchorScroll
+ * @kind function
* @requires $window
* @requires $location
* @requires $rootScope
*
* @description
- * When called, it checks current value of `$location.hash()` and scroll to related element,
+ * When called, it checks current value of `$location.hash()` and scrolls to the related element,
* according to rules specified in
- * {@link http://dev.w3.org/html5/spec/Overview.html#the-indicated-part-of-the-document Html5 spec}.
+ * [Html5 spec](http://dev.w3.org/html5/spec/Overview.html#the-indicated-part-of-the-document).
*
- * It also watches the `$location.hash()` and scroll whenever it changes to match any anchor.
+ * It also watches the `$location.hash()` and scrolls whenever it changes to match any anchor.
* This can be disabled by calling `$anchorScrollProvider.disableAutoScrolling()`.
- */
-function $AnchorScrollProvider() {
+ *
+ * @example
+
+ * ```js
* return {
* eventFn : function(element, done) {
* //code to run the animation
@@ -3298,10 +4138,11 @@ var $AnimateProvider = ['$provide', function($provide) {
* }
* }
* }
- *
+ * ```
*
* @param {string} name The name of the animation.
- * @param {function} factory The factory function that will be executed to return the animation object.
+ * @param {Function} factory The factory function that will be executed to return the animation
+ * object.
*/
this.register = function(name, factory) {
var key = name + '-animation';
@@ -3311,82 +4152,112 @@ var $AnimateProvider = ['$provide', function($provide) {
$provide.factory(key, factory);
};
- this.$get = ['$timeout', function($timeout) {
+ /**
+ * @ngdoc method
+ * @name $animateProvider#classNameFilter
+ *
+ * @description
+ * Sets and/or returns the CSS class regular expression that is checked when performing
+ * an animation. Upon bootstrap the classNameFilter value is not set at all and will
+ * therefore enable $animate to attempt to perform an animation on any element.
+ * When setting the classNameFilter value, animations will only be performed on elements
+ * that successfully match the filter expression. This in turn can boost performance
+ * for low-powered devices as well as applications containing a lot of structural operations.
+ * @param {RegExp=} expression The className expression which will be checked against all animations
+ * @return {RegExp} The current CSS className expression value. If null then there is no expression value
+ */
+ this.classNameFilter = function(expression) {
+ if(arguments.length === 1) {
+ this.$$classNameFilter = (expression instanceof RegExp) ? expression : null;
+ }
+ return this.$$classNameFilter;
+ };
+
+ this.$get = ['$timeout', '$$asyncCallback', function($timeout, $$asyncCallback) {
+
+ function async(fn) {
+ fn && $$asyncCallback(fn);
+ }
/**
- * @ngdoc object
- * @name ng.$animate
*
- * @description
- * The $animate service provides rudimentary DOM manipulation functions to insert, remove, 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.
+ * @ngdoc service
+ * @name $animate
+ * @description The $animate service provides rudimentary DOM manipulation functions to
+ * insert, remove and move elements within the DOM, as well as adding and removing classes.
+ * This service is the core service used by the ngAnimate $animator service which provides
+ * high-level animation hooks for CSS and JavaScript.
*
- * $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.
+ * $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}
- * as well as the {@link ngAnimate.$animate ngAnimate $animate service 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 {
/**
- * @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
+ * @ngdoc method
+ * @name $animate#enter
+ * @kind function
+ * @description Inserts the element into the DOM either after the `after` element or within
+ * the `parent` element. Once complete, the done() callback will be fired (if provided).
+ * @param {DOMElement} element the element which will be inserted into the DOM
+ * @param {DOMElement} parent the parent element which will append the element as
+ * a child (if the after element is not present)
+ * @param {DOMElement} after the sibling element which will append the element
+ * after itself
+ * @param {Function=} done callback function that will be called after the element has been
+ * inserted into the DOM
*/
enter : function(element, parent, after, done) {
- var afterNode = after && after[after.length - 1];
- var parentNode = parent && parent[0] || afterNode && afterNode.parentNode;
- // IE does not like undefined so we have to pass null.
- var afterNextSibling = (afterNode && afterNode.nextSibling) || null;
- forEach(element, function(node) {
- parentNode.insertBefore(node, afterNextSibling);
- });
- done && $timeout(done, 0, false);
+ if (after) {
+ after.after(element);
+ } else {
+ if (!parent || !parent[0]) {
+ parent = after.parent();
+ }
+ parent.append(element);
+ }
+ async(done);
},
/**
- * @ngdoc function
- * @name ng.$animate#leave
- * @methodOf ng.$animate
- * @function
- *
- * @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
+ * @ngdoc method
+ * @name $animate#leave
+ * @kind function
+ * @description Removes the element from the DOM. Once complete, the done() callback will be
+ * fired (if provided).
+ * @param {DOMElement} element the element which will be removed from the DOM
+ * @param {Function=} done callback function that will be called after the element has been
+ * removed from the DOM
*/
leave : function(element, done) {
element.remove();
- done && $timeout(done, 0, false);
+ async(done);
},
/**
- * @ngdoc function
- * @name ng.$animate#move
- * @methodOf ng.$animate
- * @function
*
- * @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).
+ * @ngdoc method
+ * @name $animate#move
+ * @kind function
+ * @description Moves the position of the provided element within the DOM to be placed
+ * either after the `after` element or inside of the `parent` element. Once complete, the
+ * done() callback will be fired (if provided).
*
- * @param {jQuery/jqLite element} element the element which will be moved around within the 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 it's new position
+ * @param {DOMElement} element the element which will be moved around within the
+ * DOM
+ * @param {DOMElement} parent the parent element where the element will be
+ * inserted into (if the after element is not present)
+ * @param {DOMElement} after the sibling element where the element will be
+ * positioned next to
+ * @param {Function=} done the callback function (if provided) that will be fired after the
+ * element has been moved to its new position
*/
move : function(element, parent, after, done) {
// Do not remove element before insert. Removing will cause data associated with the
@@ -3395,45 +4266,71 @@ var $AnimateProvider = ['$provide', function($provide) {
},
/**
- * @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
+ * @ngdoc method
+ * @name $animate#addClass
+ * @kind function
+ * @description Adds the provided className CSS class value to the provided element. Once
+ * complete, the done() callback will be fired (if provided).
+ * @param {DOMElement} element the element which will have the className value
+ * added to it
* @param {string} className the CSS class which will be added to the element
- * @param {function=} done the callback function (if provided) that will be fired after the className value has been 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
*/
addClass : function(element, className, done) {
className = isString(className) ?
className :
isArray(className) ? className.join(' ') : '';
- element.addClass(className);
- done && $timeout(done, 0, false);
+ forEach(element, function (element) {
+ jqLiteAddClass(element, className);
+ });
+ async(done);
},
/**
- * @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
+ * @ngdoc method
+ * @name $animate#removeClass
+ * @kind function
+ * @description Removes the provided className CSS class value from the provided element.
+ * Once complete, the done() callback will be fired (if provided).
+ * @param {DOMElement} element the element which will have the className value
+ * removed from it
* @param {string} className the CSS class which will be removed from the element
- * @param {function=} done the callback function (if provided) that will be fired after the className value has been 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
*/
removeClass : function(element, className, done) {
className = isString(className) ?
className :
isArray(className) ? className.join(' ') : '';
- element.removeClass(className);
- done && $timeout(done, 0, false);
+ forEach(element, function (element) {
+ jqLiteRemoveClass(element, className);
+ });
+ async(done);
+ },
+
+ /**
+ *
+ * @ngdoc method
+ * @name $animate#setClass
+ * @kind function
+ * @description Adds and/or removes the given CSS classes to and from the element.
+ * Once complete, the done() callback will be fired (if provided).
+ * @param {DOMElement} element the element which will have its CSS classes changed
+ * removed from it
+ * @param {string} add the CSS classes which will be added to the element
+ * @param {string} remove the CSS class which will be removed from the element
+ * @param {Function=} done the callback function (if provided) that will be fired after the
+ * CSS classes have been set on the element
+ */
+ setClass : function(element, add, remove, done) {
+ forEach(element, function (element) {
+ jqLiteAddClass(element, add);
+ jqLiteRemoveClass(element, remove);
+ });
+ async(done);
},
enabled : noop
@@ -3441,10 +4338,20 @@ var $AnimateProvider = ['$provide', function($provide) {
}];
}];
+function $$AsyncCallbackProvider(){
+ this.$get = ['$$rAF', '$timeout', function($$rAF, $timeout) {
+ return $$rAF.supported
+ ? function(fn) { return $$rAF(fn); }
+ : function(fn) {
+ return $timeout(fn, 0, false);
+ };
+ }];
+}
+
/**
* ! This is a private undocumented service !
*
- * @name ng.$browser
+ * @name $browser
* @requires $log
* @description
* This object has two goals:
@@ -3528,8 +4435,7 @@ function Browser(window, document, $log, $sniffer) {
pollTimeout;
/**
- * @name ng.$browser#addPollFn
- * @methodOf ng.$browser
+ * @name $browser#addPollFn
*
* @param {function()} fn Poll function to add
*
@@ -3566,11 +4472,10 @@ function Browser(window, document, $log, $sniffer) {
var lastBrowserUrl = location.href,
baseElement = document.find('base'),
- replacedUrl = null;
+ newLocation = null;
/**
- * @name ng.$browser#url
- * @methodOf ng.$browser
+ * @name $browser#url
*
* @description
* GETTER:
@@ -3589,6 +4494,10 @@ function Browser(window, document, $log, $sniffer) {
* @param {boolean=} replace Should new url replace current history record ?
*/
self.url = function(url, replace) {
+ // Android Browser BFCache causes location, history reference to become stale.
+ if (location !== window.location) location = window.location;
+ if (history !== window.history) history = window.history;
+
// setter
if (url) {
if (lastBrowserUrl == url) return;
@@ -3601,21 +4510,20 @@ function Browser(window, document, $log, $sniffer) {
baseElement.attr('href', baseElement.attr('href'));
}
} else {
+ newLocation = url;
if (replace) {
location.replace(url);
- replacedUrl = url;
} else {
location.href = url;
- replacedUrl = null;
}
}
return self;
// getter
} else {
- // - the replacedUrl is a workaround for an IE8-9 issue with location.replace method that doesn't update
- // location.href synchronously
+ // - 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 replacedUrl || location.href.replace(/%27/g,"'");
+ return newLocation || location.href.replace(/%27/g,"'");
}
};
@@ -3623,6 +4531,7 @@ function Browser(window, document, $log, $sniffer) {
urlChangeInit = false;
function fireUrlChange() {
+ newLocation = null;
if (lastBrowserUrl == self.url()) return;
lastBrowserUrl = self.url();
@@ -3632,14 +4541,12 @@ function Browser(window, document, $log, $sniffer) {
}
/**
- * @name ng.$browser#onUrlChange
- * @methodOf ng.$browser
- * @TODO(vojta): refactor to use node's syntax for events
+ * @name $browser#onUrlChange
*
* @description
* Register callback function that will be called, when url changes.
*
- * It's only called when the url is changed by outside of angular:
+ * It's only called when the url is changed from outside of angular:
* - user types different url into address bar
* - user clicks on history (forward/back) button
* - user clicks on a link
@@ -3655,6 +4562,7 @@ function Browser(window, document, $log, $sniffer) {
* @return {function(string)} Returns the registered listener fn - handy if the fn is anonymous.
*/
self.onUrlChange = function(callback) {
+ // TODO(vojta): refactor to use node's syntax for events
if (!urlChangeInit) {
// We listen on both (hashchange/popstate) when available, as some browsers (e.g. Opera)
// don't fire popstate when user change the address bar and don't fire hashchange when url
@@ -3674,19 +4582,29 @@ function Browser(window, document, $log, $sniffer) {
return callback;
};
+ /**
+ * Checks whether the url has changed outside of Angular.
+ * Needs to be exported to be able to check for changes that have been done in sync,
+ * as hashchange/popstate events fire in async.
+ */
+ self.$$checkUrlChange = fireUrlChange;
+
//////////////////////////////////////////////////////////////
// Misc API
//////////////////////////////////////////////////////////////
/**
+ * @name $browser#baseHref
+ *
+ * @description
* Returns current
- *
+ * Factory that constructs {@link $cacheFactory.Cache Cache} objects and gives access to
+ * them.
+ *
+ * ```js
+ *
* var cache = $cacheFactory('cacheId');
* expect($cacheFactory.get('cacheId')).toBe(cache);
* expect($cacheFactory.get('noSuchCacheId')).not.toBeDefined();
*
* cache.put("key", "value");
* cache.put("another key", "another value");
- *
- * expect(cache.info()).toEqual({id: 'cacheId', size: 2}); // Since we've specified no options on creation
- *
- *
+ *
+ * // We've specified no options on creation
+ * expect(cache.info()).toEqual({id: 'cacheId', size: 2});
+ *
+ * ```
*
*
* @param {string} cacheId Name or id of the newly created cache.
@@ -3846,12 +4769,55 @@ function $BrowserProvider(){
* @returns {object} Newly created cache object with the following set of methods:
*
* - `{object}` `info()` — Returns id, size, and options of cache.
- * - `{{*}}` `put({string} key, {*} value)` — Puts a new key-value pair into the cache and returns it.
+ * - `{{*}}` `put({string} key, {*} value)` — Puts a new key-value pair into the cache and returns
+ * it.
* - `{{*}}` `get({string} key)` — Returns cached value for `key` or undefined for cache miss.
* - `{void}` `remove({string} key)` — Removes a key-value pair from the cache.
* - `{void}` `removeAll()` — Removes all cached values.
* - `{void}` `destroy()` — Removes references to this cache from $cacheFactory.
*
+ * @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 below the `ng-app` definition. - * + * + * ```html + * + * ``` + * + * **Note:** the `script` tag containing the template does not need to be included in the `head` of + * the document, but it must be below the `ng-app` definition. + * * Adding via the $templateCache service: - * - *
+ *
+ * ```js
* var myApp = angular.module('myApp', []);
* myApp.run(function($templateCache) {
* $templateCache.put('templateId.html', 'This is the content of the template');
* });
- *
- *
+ * ```
+ *
* To retrieve the template later, simply use it in your HTML:
- * + * ```html * - *- * + * ``` + * * or get it via Javascript: - *
+ * ```js
* $templateCache.get('templateId.html')
- *
- *
+ * ```
+ *
* See {@link ng.$cacheFactory $cacheFactory}.
*
*/
@@ -4079,28 +5156,390 @@ function $TemplateCacheProvider() {
/**
- * @ngdoc function
- * @name ng.$compile
- * @function
+ * @ngdoc service
+ * @name $compile
+ * @kind function
*
* @description
- * Compiles a piece of HTML string or DOM into a template and produces a template function, which
- * can then be used to link {@link ng.$rootScope.Scope scope} and the template together.
+ * 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}.
+ *
+ *
+ * ```js
* var element = $compile('{{total}}
')(scope);
- *
+ * ```
*
* - 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:
- *
- * var templateHTML = angular.element('{{total}}
'),
+ * ```js
+ * var templateElement = angular.element('{{total}}
'),
* scope = ....;
*
- * var clonedElement = $compile(templateHTML)(scope, function(clonedElement, scope) {
+ * var clonedElement = $compile(templateElement)(scope, function(clonedElement, scope) {
* //attach the clone to DOM document at the right place
* });
*
- * //now we have reference to the cloned DOM via `clone`
- *
+ * //now we have reference to the cloned DOM via `clonedElement`
+ * ```
*
*
* For information on how the compiler works, see the
@@ -4201,42 +5643,41 @@ function $TemplateCacheProvider() {
var $compileMinErr = minErr('$compile');
/**
- * @ngdoc service
- * @name ng.$compileProvider
- * @function
+ * @ngdoc provider
+ * @name $compileProvider
+ * @kind function
*
* @description
*/
-$CompileProvider.$inject = ['$provide'];
-function $CompileProvider($provide) {
+$CompileProvider.$inject = ['$provide', '$$sanitizeUriProvider'];
+function $CompileProvider($provide, $$sanitizeUriProvider) {
var hasDirectives = {},
Suffix = 'Directive',
- COMMENT_DIRECTIVE_REGEXP = /^\s*directive\:\s*([\d\w\-_]+)\s+(.*)$/,
- CLASS_DIRECTIVE_REGEXP = /(([\d\w\-_]+)(?:\:([^;]+))?;?)/,
- aHrefSanitizationWhitelist = /^\s*(https?|ftp|mailto|file):/,
- imgSrcSanitizationWhitelist = /^\s*(https?|ftp|file):|data:image\//;
+ COMMENT_DIRECTIVE_REGEXP = /^\s*directive\:\s*([\d\w_\-]+)\s+(.*)$/,
+ CLASS_DIRECTIVE_REGEXP = /(([\d\w_\-]+)(?:\:([^;]+))?;?)/;
// Ref: http://developers.whatwg.org/webappapis.html#event-handler-idl-attributes
// The assumption is that future DOM event attribute names will begin with
// 'on' and be composed of only English letters.
- var EVENT_HANDLER_ATTR_REGEXP = /^(on[a-z]*|formaction)$/;
+ var EVENT_HANDLER_ATTR_REGEXP = /^(on[a-z]+|formaction)$/;
/**
- * @ngdoc function
- * @name ng.$compileProvider#directive
- * @methodOf ng.$compileProvider
- * @function
+ * @ngdoc method
+ * @name $compileProvider#directive
+ * @kind function
*
* @description
* Register a new directive with the compiler.
*
- * @param {string} name Name of the directive in camel-case. (ie ngBind which will match as
- * ng-bind).
- * @param {function|Array} directiveFactory An injectable directive factory function. See {@link guide/directive} for more
- * info.
+ * @param {string|Object} name Name of the directive in camel-case (i.e. 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
+ * {@link guide/directive} for more info.
* @returns {ng.$compileProvider} Self for chaining.
*/
this.directive = function registerDirective(name, directiveFactory) {
+ assertNotHasOwnProperty(name, 'directive');
if (isString(name)) {
assertArg(directiveFactory, 'directiveFactory');
if (!hasDirectives.hasOwnProperty(name)) {
@@ -4244,7 +5685,7 @@ function $CompileProvider($provide) {
$provide.factory(name + Suffix, ['$injector', '$exceptionHandler',
function($injector, $exceptionHandler) {
var directives = [];
- forEach(hasDirectives[name], function(directiveFactory) {
+ forEach(hasDirectives[name], function(directiveFactory, index) {
try {
var directive = $injector.invoke(directiveFactory);
if (isFunction(directive)) {
@@ -4253,6 +5694,7 @@ function $CompileProvider($provide) {
directive.compile = valueFn(directive.link);
}
directive.priority = directive.priority || 0;
+ directive.index = index;
directive.name = directive.name || name;
directive.require = directive.require || (directive.controller && directive.name);
directive.restrict = directive.restrict || 'A';
@@ -4273,10 +5715,9 @@ function $CompileProvider($provide) {
/**
- * @ngdoc function
- * @name ng.$compileProvider#aHrefSanitizationWhitelist
- * @methodOf ng.$compileProvider
- * @function
+ * @ngdoc method
+ * @name $compileProvider#aHrefSanitizationWhitelist
+ * @kind function
*
* @description
* Retrieves or overrides the default regular expression that is used for whitelisting of safe
@@ -4295,18 +5736,18 @@ function $CompileProvider($provide) {
*/
this.aHrefSanitizationWhitelist = function(regexp) {
if (isDefined(regexp)) {
- aHrefSanitizationWhitelist = regexp;
+ $$sanitizeUriProvider.aHrefSanitizationWhitelist(regexp);
return this;
+ } else {
+ return $$sanitizeUriProvider.aHrefSanitizationWhitelist();
}
- return aHrefSanitizationWhitelist;
};
/**
- * @ngdoc function
- * @name ng.$compileProvider#imgSrcSanitizationWhitelist
- * @methodOf ng.$compileProvider
- * @function
+ * @ngdoc method
+ * @name $compileProvider#imgSrcSanitizationWhitelist
+ * @kind function
*
* @description
* Retrieves or overrides the default regular expression that is used for whitelisting of safe
@@ -4314,10 +5755,10 @@ function $CompileProvider($provide) {
*
* The sanitization is a security measure aimed at prevent XSS attacks via html links.
*
- * Any url about to be assigned to img[src] via data-binding is first normalized and turned into an
- * absolute url. Afterwards, the url is matched against the `imgSrcSanitizationWhitelist` regular
- * expression. If a match is found, the original url is written into the dom. Otherwise, the
- * absolute url is prefixed with `'unsafe:'` string and only then is it written into the DOM.
+ * Any url about to be assigned to img[src] via data-binding is first normalized and turned into
+ * an absolute url. Afterwards, the url is matched against the `imgSrcSanitizationWhitelist`
+ * regular expression. If a match is found, the original url is written into the dom. Otherwise,
+ * the absolute url is prefixed with `'unsafe:'` string and only then is it written into the DOM.
*
* @param {RegExp=} regexp New regexp to whitelist urls with.
* @returns {RegExp|ng.$compileProvider} Current RegExp if called without value or self for
@@ -4325,18 +5766,18 @@ function $CompileProvider($provide) {
*/
this.imgSrcSanitizationWhitelist = function(regexp) {
if (isDefined(regexp)) {
- imgSrcSanitizationWhitelist = regexp;
+ $$sanitizeUriProvider.imgSrcSanitizationWhitelist(regexp);
return this;
+ } else {
+ return $$sanitizeUriProvider.imgSrcSanitizationWhitelist();
}
- return imgSrcSanitizationWhitelist;
};
-
this.$get = [
'$injector', '$interpolate', '$exceptionHandler', '$http', '$templateCache', '$parse',
- '$controller', '$rootScope', '$document', '$sce', '$$urlUtils', '$animate',
+ '$controller', '$rootScope', '$document', '$sce', '$animate', '$$sanitizeUri',
function($injector, $interpolate, $exceptionHandler, $http, $templateCache, $parse,
- $controller, $rootScope, $document, $sce, $$urlUtils, $animate) {
+ $controller, $rootScope, $document, $sce, $animate, $$sanitizeUri) {
var Attributes = function(element, attr) {
this.$$element = element;
@@ -4348,10 +5789,9 @@ function $CompileProvider($provide) {
/**
- * @ngdoc function
- * @name ng.$compile.directive.Attributes#$addClass
- * @methodOf ng.$compile.directive.Attributes
- * @function
+ * @ngdoc method
+ * @name $compile.directive.Attributes#$addClass
+ * @kind function
*
* @description
* Adds the CSS class value specified by the classVal parameter to the element. If animations
@@ -4366,14 +5806,13 @@ function $CompileProvider($provide) {
},
/**
- * @ngdoc function
- * @name ng.$compile.directive.Attributes#$removeClass
- * @methodOf ng.$compile.directive.Attributes
- * @function
+ * @ngdoc method
+ * @name $compile.directive.Attributes#$removeClass
+ * @kind function
*
* @description
- * Removes the CSS class value specified by the classVal parameter from the element. If animations
- * are enabled then an animation will be triggered for the class removal.
+ * Removes the CSS class value specified by the classVal parameter from the element. If
+ * animations are enabled then an animation will be triggered for the class removal.
*
* @param {string} classVal The className value that will be removed from the element
*/
@@ -4383,6 +5822,31 @@ function $CompileProvider($provide) {
}
},
+ /**
+ * @ngdoc method
+ * @name $compile.directive.Attributes#$updateClass
+ * @kind function
+ *
+ * @description
+ * Adds and removes the appropriate CSS class values to the element based on the difference
+ * between the new and old CSS class values (specified as newClasses and oldClasses).
+ *
+ * @param {string} newClasses The current CSS className value
+ * @param {string} oldClasses The former CSS className value
+ */
+ $updateClass : function(newClasses, oldClasses) {
+ var toAdd = tokenDifference(newClasses, oldClasses);
+ var toRemove = tokenDifference(oldClasses, newClasses);
+
+ if(toAdd.length === 0) {
+ $animate.removeClass(this.$$element, toRemove);
+ } else if(toRemove.length === 0) {
+ $animate.addClass(this.$$element, toAdd);
+ } else {
+ $animate.setClass(this.$$element, toAdd, toRemove);
+ }
+ },
+
/**
* Set a normalized attribute on the element in a way such that all directives
* can share the attribute. This function properly handles boolean attributes.
@@ -4393,59 +5857,44 @@ function $CompileProvider($provide) {
* @param {string=} attrName Optional none normalized name. Defaults to key.
*/
$set: function(key, value, writeAttr, attrName) {
- //special case for class attribute addition + removal
- //so that class changes can tap into the animation
- //hooks provided by the $animate service
- if(key == 'class') {
- value = value || '';
- var current = this.$$element.attr('class') || '';
- this.$removeClass(tokenDifference(current, value).join(' '));
- this.$addClass(tokenDifference(value, current).join(' '));
- } else {
- var booleanKey = getBooleanAttrName(this.$$element[0], key),
- normalizedVal,
- nodeName;
+ // TODO: decide whether or not to throw an error if "class"
+ //is set through this function since it may cause $updateClass to
+ //become unstable.
- if (booleanKey) {
- this.$$element.prop(key, value);
- attrName = booleanKey;
- }
+ var booleanKey = getBooleanAttrName(this.$$element[0], key),
+ normalizedVal,
+ nodeName;
- this[key] = value;
+ if (booleanKey) {
+ this.$$element.prop(key, value);
+ attrName = booleanKey;
+ }
- // translate normalized key to actual key
- if (attrName) {
- this.$attr[key] = attrName;
- } else {
- attrName = this.$attr[key];
- if (!attrName) {
- this.$attr[key] = attrName = snake_case(key, '-');
- }
- }
+ this[key] = value;
- nodeName = nodeName_(this.$$element);
-
- // sanitize a[href] and img[src] values
- if ((nodeName === 'A' && key === 'href') ||
- (nodeName === 'IMG' && key === 'src')) {
- // NOTE: $$urlUtils.resolve() doesn't support IE < 8 so we don't sanitize for that case.
- if (!msie || msie >= 8 ) {
- normalizedVal = $$urlUtils.resolve(value);
- if (normalizedVal !== '') {
- if ((key === 'href' && !normalizedVal.match(aHrefSanitizationWhitelist)) ||
- (key === 'src' && !normalizedVal.match(imgSrcSanitizationWhitelist))) {
- this[key] = value = 'unsafe:' + normalizedVal;
- }
- }
- }
+ // translate normalized key to actual key
+ if (attrName) {
+ this.$attr[key] = attrName;
+ } else {
+ attrName = this.$attr[key];
+ if (!attrName) {
+ this.$attr[key] = attrName = snake_case(key, '-');
}
+ }
- if (writeAttr !== false) {
- if (value === null || value === undefined) {
- this.$$element.removeAttr(attrName);
- } else {
- this.$$element.attr(attrName, value);
- }
+ nodeName = nodeName_(this.$$element);
+
+ // sanitize a[href] and img[src] values
+ if ((nodeName === 'A' && key === 'href') ||
+ (nodeName === 'IMG' && key === 'src')) {
+ this[key] = value = $$sanitizeUri(value, key === 'src');
+ }
+
+ if (writeAttr !== false) {
+ if (value === null || value === undefined) {
+ this.$$element.removeAttr(attrName);
+ } else {
+ this.$$element.attr(attrName, value);
}
}
@@ -4458,32 +5907,26 @@ function $CompileProvider($provide) {
$exceptionHandler(e);
}
});
-
- function tokenDifference(str1, str2) {
- var values = [],
- tokens1 = str1.split(/\s+/),
- tokens2 = str2.split(/\s+/);
-
- outer:
- for(var i=0;i$document title:
+window.document title:
+
+ * ```js
* $http({method: 'GET', url: '/someUrl'}).
* success(function(data, status, headers, config) {
* // this callback will be called asynchronously
@@ -5846,7 +7600,7 @@ function $HttpProvider() {
* // called asynchronously if an error occurs
* // or server returns response with an error status.
* });
- *
+ * ```
*
* Since the returned value of calling the $http function is a `promise`, you can also use
* the `then` method to register callbacks, and these callbacks will receive a single argument –
@@ -5858,16 +7612,26 @@ function $HttpProvider() {
* XMLHttpRequest will transparently follow it, meaning that the error callback will not be
* called for such responses.
*
+ * # 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.
+ *
+ * ```
+ * $httpBackend.expectGET(...);
+ * $http.get(...);
+ * $httpBackend.flush();
+ * ```
+ *
* # Shortcut methods
*
- * Since all invocations of the $http service require passing in an HTTP method and URL, and
- * POST/PUT requests require request data to be provided as well, shortcut methods
- * were created:
+ * Shortcut methods are also available. All shortcut methods require passing in the URL, and
+ * request data must be passed in for POST/PUT requests.
*
- *
+ * ```js
* $http.get('/someUrl').success(successCallback);
* $http.post('/someUrl', data).success(successCallback);
- *
+ * ```
*
* Complete list of shortcut methods:
*
@@ -5877,6 +7641,7 @@ function $HttpProvider() {
* - {@link ng.$http#put $http.put}
* - {@link ng.$http#delete $http.delete}
* - {@link ng.$http#jsonp $http.jsonp}
+ * - {@link ng.$http#patch $http.patch}
*
*
* # Setting HTTP Headers
@@ -5895,10 +7660,19 @@ 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:
*
- * Additionally, the defaults can be set at runtime via the `$http.defaults` object in the same
- * fashion.
+ * ```
+ * module.run(function($http) {
+ * $http.defaults.headers.common.Authorization = 'Basic YmVlcDpib29w'
+ * });
+ * ```
+ *
+ * In addition, you can supply a `headers` property in the config object passed when
+ * calling `$http(config)`, which overrides the defaults without changing them globally.
*
*
* # Transforming Requests and Responses
@@ -5908,29 +7682,35 @@ function $HttpProvider() {
*
* Request transformations:
*
- * - If the `data` property of the request configuration object contains an object, serialize it into
- * JSON format.
+ * - If the `data` property of the request configuration object contains an object, serialize it
+ * into JSON format.
*
* Response transformations:
*
* - If XSRF prefix is detected, strip it (see Security Considerations section below).
* - If JSON response is detected, deserialize it using a JSON parser.
*
- * To globally augment or override the default transforms, modify the `$httpProvider.defaults.transformRequest` and
- * `$httpProvider.defaults.transformResponse` properties. These properties are by default an
- * array of transform functions, which allows you to `push` or `unshift` a new transformation function into the
- * transformation chain. You can also decide to completely override any default transformations by assigning your
- * transformation functions to these properties directly without the array wrapper.
+ * To globally augment or override the default transforms, modify the
+ * `$httpProvider.defaults.transformRequest` and `$httpProvider.defaults.transformResponse`
+ * properties. These properties are by default an array of transform functions, which allows you
+ * to `push` or `unshift` a new transformation function into the transformation chain. You can
+ * also decide to completely override any default transformations by assigning your
+ * transformation functions to these properties directly without the array wrapper. These defaults
+ * are again available on the $http factory at run-time, which may be useful if you have run-time
+ * services you wish to be involved in your transformations.
*
- * Similarly, to locally override the request/response transforms, augment the `transformRequest` and/or
- * `transformResponse` properties of the configuration object passed into `$http`.
+ * Similarly, to locally override the request/response transforms, augment the
+ * `transformRequest` and/or `transformResponse` properties of the configuration object passed
+ * into `$http`.
*
*
* # Caching
*
- * To enable caching, set the configuration property `cache` to `true`. When the cache is
- * enabled, `$http` stores the response from the server in local cache. Next time the
- * response is served from the cache without sending a request to the server.
+ * To enable caching, set the request configuration `cache` property to `true` (to use default
+ * cache) or to a custom cache object (built with {@link ng.$cacheFactory `$cacheFactory`}).
+ * When the cache is enabled, `$http` stores the response from the server in the specified
+ * cache. The next time the same request is made, the response is served from the cache without
+ * sending a request to the server.
*
* Note that even if the response is served from cache, delivery of the data is asynchronous in
* the same way that real requests are.
@@ -5939,9 +7719,13 @@ function $HttpProvider() {
* cache, but the cache is not populated yet, only one request to the server will be made and
* the remaining requests will be fulfilled using the response from the first request.
*
- * A custom default cache built with $cacheFactory can be provided in $http.defaults.cache.
- * To skip it, set configuration property `cache` to `false`.
+ * You can change the default cache to a new object (built with
+ * {@link ng.$cacheFactory `$cacheFactory`}) by updating the
+ * {@link ng.$http#properties_defaults `$http.defaults.cache`} property. All requests who set
+ * their `cache` property to `true` will now use this cache object.
*
+ * If you set the default cache to `false` then only requests that specify their own custom
+ * cache object will be cached.
*
* # Interceptors
*
@@ -5961,26 +7745,26 @@ function $HttpProvider() {
*
* There are two kinds of interceptors (and two kinds of rejection interceptors):
*
- * * `request`: interceptors get called with http `config` object. The function is free to modify
- * the `config` or create a new one. The function needs to return the `config` directly or as a
- * promise.
- * * `requestError`: interceptor gets called when a previous interceptor threw an error or resolved
- * with a rejection.
- * * `response`: interceptors get called with http `response` object. The function is free to modify
- * the `response` or create a new one. The function needs to return the `response` directly or as a
- * promise.
- * * `responseError`: interceptor gets called when a previous interceptor threw an error or resolved
- * with a rejection.
+ * * `request`: interceptors get called with a http `config` object. The function is free to
+ * modify the `config` object or create a new one. The function needs to return the `config`
+ * object directly, or a promise containing the `config` or a new `config` object.
+ * * `requestError`: interceptor gets called when a previous interceptor threw an error or
+ * resolved with a rejection.
+ * * `response`: interceptors get called with http `response` object. The function is free to
+ * modify the `response` object or create a new one. The function needs to return the `response`
+ * object directly, or as a promise containing the `response` or a new `response` object.
+ * * `responseError`: interceptor gets called when a previous interceptor threw an error or
+ * resolved with a rejection.
*
*
- *
+ * ```js
* // register the interceptor as a service
* $provide.factory('myHttpInterceptor', function($q, dependency1, dependency2) {
* return {
* // optional method
* 'request': function(config) {
* // do something on success
- * return config || $q.when(config);
+ * return config;
* },
*
* // optional method
@@ -5997,7 +7781,7 @@ function $HttpProvider() {
* // optional method
* 'response': function(response) {
* // do something on success
- * return response || $q.when(response);
+ * return response;
* },
*
* // optional method
@@ -6007,24 +7791,26 @@ function $HttpProvider() {
* return responseOrNewPromise
* }
* return $q.reject(rejection);
- * };
- * }
+ * }
+ * };
* });
*
* $httpProvider.interceptors.push('myHttpInterceptor');
*
*
- * // register the interceptor via an anonymous factory
+ * // alternatively, register the interceptor via an anonymous factory
* $httpProvider.interceptors.push(function($q, dependency1, dependency2) {
* return {
* 'request': function(config) {
* // same as above
* },
+ *
* 'response': function(response) {
* // same as above
* }
+ * };
* });
- *
+ * ```
*
* # Response interceptors (DEPRECATED)
*
@@ -6042,7 +7828,7 @@ function $HttpProvider() {
* injected with dependencies (if specified) and returns the interceptor — a function that
* takes a {@link ng.$q promise} and returns the original or a new promise.
*
- *
+ * ```js
* // register the interceptor as a service
* $provide.factory('myHttpInterceptor', function($q, dependency1, dependency2) {
* return function(promise) {
@@ -6068,16 +7854,15 @@ function $HttpProvider() {
* // same as above
* }
* });
- *
+ * ```
*
*
* # Security Considerations
*
* When designing web applications, consider security threats from:
*
- * - {@link http://haacked.com/archive/2008/11/20/anatomy-of-a-subtle-json-vulnerability.aspx
- * JSON vulnerability}
- * - {@link http://en.wikipedia.org/wiki/Cross-site_request_forgery XSRF}
+ * - [JSON vulnerability](http://haacked.com/archive/2008/11/20/anatomy-of-a-subtle-json-vulnerability.aspx)
+ * - [XSRF](http://en.wikipedia.org/wiki/Cross-site_request_forgery)
*
* Both server and the client must cooperate in order to eliminate these threats. Angular comes
* pre-configured with strategies that address these issues, but for this to work backend server
@@ -6085,29 +7870,29 @@ function $HttpProvider() {
*
* ## JSON Vulnerability Protection
*
- * A {@link http://haacked.com/archive/2008/11/20/anatomy-of-a-subtle-json-vulnerability.aspx
- * JSON vulnerability} allows third party website to turn your JSON resource URL into
- * {@link http://en.wikipedia.org/wiki/JSONP JSONP} request under some conditions. To
+ * A [JSON vulnerability](http://haacked.com/archive/2008/11/20/anatomy-of-a-subtle-json-vulnerability.aspx)
+ * allows third party website to turn your JSON resource URL into
+ * [JSONP](http://en.wikipedia.org/wiki/JSONP) request under some conditions. To
* counter this your server can prefix all JSON requests with following string `")]}',\n"`.
* Angular will automatically strip the prefix before processing it as JSON.
*
* For example if your server needs to return:
- *
+ * ```js
* ['one','two']
- *
+ * ```
*
* which is vulnerable to attack, your server can return:
- *
+ * ```js
* )]}',
* ['one','two']
- *
+ * ```
*
* Angular will strip the prefix, before processing the JSON.
*
*
* ## Cross Site Request Forgery (XSRF) Protection
*
- * {@link http://en.wikipedia.org/wiki/Cross-site_request_forgery XSRF} is a technique by which
+ * [XSRF](http://en.wikipedia.org/wiki/Cross-site_request_forgery) is a technique by which
* an unauthorized site can gain your user's private data. Angular provides a mechanism
* to counter XSRF. When performing XHR requests, the $http service reads a token from a cookie
* (by default, `XSRF-TOKEN`) and sets it as an HTTP header (`X-XSRF-TOKEN`). Since only
@@ -6119,12 +7904,14 @@ function $HttpProvider() {
* cookie called `XSRF-TOKEN` on the first HTTP GET request. On subsequent XHR requests the
* server can verify that the cookie matches `X-XSRF-TOKEN` HTTP header, and therefore be sure
* that only JavaScript running on your domain could have sent the request. The token must be
- * unique for each user and must be verifiable by the server (to prevent the JavaScript from making
- * up its own tokens). We recommend that the token is a digest of your site's authentication
- * cookie with a {@link https://en.wikipedia.org/wiki/Salt_(cryptography) salt} for added security.
+ * 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))
+ * for added security.
*
* The name of the headers can be specified using the xsrfHeaderName and xsrfCookieName
- * properties of either $httpProvider.defaults, or the per-request config object.
+ * properties of either $httpProvider.defaults at config-time, $http.defaults at run-time,
+ * or the per-request config object.
*
*
* @param {object} config Object describing the request to be made and how it should be
@@ -6132,18 +7919,21 @@ function $HttpProvider() {
*
* - **method** – `{string}` – HTTP method (e.g. 'GET', 'POST', etc)
* - **url** – `{string}` – Absolute or relative URL of the resource that is being requested.
- * - **params** – `{Object.