diff --git a/bower.json b/bower.json
index 7fd7a4cf4ab..c71b0b7dea0 100644
--- a/bower.json
+++ b/bower.json
@@ -15,10 +15,10 @@
"dependencies": {
"jquery": "3.1.0",
"lodash": "4.15.0",
- "angular": "1.5.3",
- "angular-route": "1.5.3",
- "angular-mocks": "1.5.3",
- "angular-sanitize": "1.5.3",
+ "angular": "1.5.8",
+ "angular-route": "1.5.8",
+ "angular-mocks": "1.5.8",
+ "angular-sanitize": "1.5.8",
"angular-native-dragdrop": "1.2.2",
"angular-bindonce": "0.3.3"
}
diff --git a/public/app/core/routes/bundle_loader.ts b/public/app/core/routes/bundle_loader.ts
index 3d275aeda36..473ac66b4b9 100644
--- a/public/app/core/routes/bundle_loader.ts
+++ b/public/app/core/routes/bundle_loader.ts
@@ -2,21 +2,22 @@
export class BundleLoader {
lazy: any;
- loadingDefer: any;
constructor(bundleName) {
+ var defer = null;
+
this.lazy = ["$q", "$route", "$rootScope", ($q, $route, $rootScope) => {
- if (this.loadingDefer) {
- return this.loadingDefer.promise;
+ if (defer) {
+ return defer.promise;
}
- this.loadingDefer = $q.defer();
+ defer = $q.defer();
System.import(bundleName).then(() => {
- this.loadingDefer.resolve();
+ defer.resolve();
});
- return this.loadingDefer.promise;
+ return defer.promise;
}];
}
diff --git a/public/vendor/angular-mocks/.bower.json b/public/vendor/angular-mocks/.bower.json
index 563c2635a8a..119ddaab59a 100644
--- a/public/vendor/angular-mocks/.bower.json
+++ b/public/vendor/angular-mocks/.bower.json
@@ -1,20 +1,20 @@
{
"name": "angular-mocks",
- "version": "1.5.3",
+ "version": "1.5.8",
"license": "MIT",
"main": "./angular-mocks.js",
"ignore": [],
"dependencies": {
- "angular": "1.5.3"
+ "angular": "1.5.8"
},
"homepage": "https://github.com/angular/bower-angular-mocks",
- "_release": "1.5.3",
+ "_release": "1.5.8",
"_resolution": {
"type": "version",
- "tag": "v1.5.3",
- "commit": "319557fe710cecc11e12c772cc1abb8098d29ccb"
+ "tag": "v1.5.8",
+ "commit": "482eefcf6b03057c5fcddb9750e460f458ee3487"
},
"_source": "https://github.com/angular/bower-angular-mocks.git",
- "_target": "1.5.3",
+ "_target": "1.5.8",
"_originalSource": "angular-mocks"
}
\ No newline at end of file
diff --git a/public/vendor/angular-mocks/LICENSE.md b/public/vendor/angular-mocks/LICENSE.md
new file mode 100644
index 00000000000..2c395eef1ba
--- /dev/null
+++ b/public/vendor/angular-mocks/LICENSE.md
@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) 2016 Angular
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/public/vendor/angular-mocks/README.md b/public/vendor/angular-mocks/README.md
index 440cce9b78a..61b9d8c0831 100644
--- a/public/vendor/angular-mocks/README.md
+++ b/public/vendor/angular-mocks/README.md
@@ -20,7 +20,7 @@ You can `require` ngMock modules:
var angular = require('angular');
angular.module('myMod', [
require('angular-animate'),
- require('angular-mocks/ngMock')
+ require('angular-mocks/ngMock'),
require('angular-mocks/ngAnimateMock')
]);
```
diff --git a/public/vendor/angular-mocks/angular-mocks.js b/public/vendor/angular-mocks/angular-mocks.js
index a1fc2fcf7ae..42f19b7aeab 100644
--- a/public/vendor/angular-mocks/angular-mocks.js
+++ b/public/vendor/angular-mocks/angular-mocks.js
@@ -1,9 +1,9 @@
/**
- * @license AngularJS v1.5.3
+ * @license AngularJS v1.5.8
* (c) 2010-2016 Google, Inc. http://angularjs.org
* License: MIT
*/
-(function(window, angular, undefined) {
+(function(window, angular) {
'use strict';
@@ -13,6 +13,7 @@
* @description
*
* Namespace from 'angular-mocks.js' which contains testing related code.
+ *
*/
angular.mock = {};
@@ -24,7 +25,7 @@ angular.mock = {};
* @description
* This service is a mock implementation of {@link ng.$browser}. It provides fake
* implementation for commonly used browser apis that are hard to test, e.g. setTimeout, xhr,
- * cookies, etc...
+ * cookies, etc.
*
* The api of this service is the same as that of the real {@link ng.$browser $browser}, except
* that there are several helper methods available which can be used in tests.
@@ -112,19 +113,29 @@ angular.mock.$Browser = function() {
* @param {number=} number of milliseconds to flush. See {@link #defer.now}
*/
self.defer.flush = function(delay) {
+ var nextTime;
+
if (angular.isDefined(delay)) {
- self.defer.now += delay;
+ // A delay was passed so compute the next time
+ nextTime = self.defer.now + delay;
} else {
if (self.deferredFns.length) {
- self.defer.now = self.deferredFns[self.deferredFns.length - 1].time;
+ // No delay was passed so set the next time so that it clears the deferred queue
+ nextTime = self.deferredFns[self.deferredFns.length - 1].time;
} else {
+ // No delay passed, but there are no deferred tasks so flush - indicates an error!
throw new Error('No deferred tasks to be flushed');
}
}
- while (self.deferredFns.length && self.deferredFns[0].time <= self.defer.now) {
+ while (self.deferredFns.length && self.deferredFns[0].time <= nextTime) {
+ // Increment the time and call the next deferred function
+ self.defer.now = self.deferredFns[0].time;
self.deferredFns.shift().fn();
}
+
+ // Ensure that the current time is correct
+ self.defer.now = nextTime;
};
self.$$baseHref = '/';
@@ -226,13 +237,13 @@ angular.mock.$ExceptionHandlerProvider = function() {
* @param {string} mode Mode of operation, defaults to `rethrow`.
*
* - `log`: Sometimes it is desirable to test that an error is thrown, for this case the `log`
- * mode stores an array of errors in `$exceptionHandler.errors`, to allow later
- * assertion of them. See {@link ngMock.$log#assertEmpty assertEmpty()} and
- * {@link ngMock.$log#reset reset()}
+ * mode stores an array of errors in `$exceptionHandler.errors`, to allow later assertion of
+ * them. See {@link ngMock.$log#assertEmpty assertEmpty()} and
+ * {@link ngMock.$log#reset reset()}.
* - `rethrow`: If any errors are passed to the handler in tests, it typically means that there
- * is a bug in the application or test, so this mock will make these tests fail.
- * For any implementations that expect exceptions to be thrown, the `rethrow` mode
- * will also maintain a log of thrown errors.
+ * is a bug in the application or test, so this mock will make these tests fail. For any
+ * implementations that expect exceptions to be thrown, the `rethrow` mode will also maintain
+ * a log of thrown errors in `$exceptionHandler.errors`.
*/
this.mode = function(mode) {
@@ -766,6 +777,8 @@ angular.mock.TzDate.prototype = Date.prototype;
* @description
* Mock implementation of the {@link ng.$animate `$animate`} service. Exposes two additional methods
* for testing animations.
+ *
+ * You need to require the `ngAnimateMock` module in your test suite for instance `beforeEach(module('ngAnimateMock'))`
*/
angular.mock.animate = angular.module('ngAnimateMock', ['ng'])
@@ -931,13 +944,10 @@ angular.mock.animate = angular.module('ngAnimateMock', ['ng'])
* @name angular.mock.dump
* @description
*
- * *NOTE*: this is not an injectable instance, just a globally available function.
+ * *NOTE*: This is not an injectable instance, just a globally available function.
*
- * Method for serializing common angular objects (scope, elements, etc..) into strings, useful for
- * debugging.
- *
- * This method is also available on window, where it can be used to display objects on debug
- * console.
+ * Method for serializing common angular objects (scope, elements, etc..) into strings.
+ * It is useful for logging objects to the console when debugging.
*
* @param {*} object - any object to turn into string.
* @return {string} a serialized string of the argument
@@ -1003,8 +1013,10 @@ angular.mock.dump = function(object) {
* Fake HTTP backend implementation suitable for unit testing applications that use the
* {@link ng.$http $http service}.
*
- * *Note*: For fake HTTP backend implementation suitable for end-to-end testing or backend-less
+ *
+ * **Note**: For fake HTTP backend implementation suitable for end-to-end testing or backend-less
* development please see {@link ngMockE2E.$httpBackend e2e $httpBackend mock}.
+ *
*
* During unit testing, we want our unit tests to run quickly and have no external dependencies so
* we don’t want to send [XHR](https://developer.mozilla.org/en/xmlhttprequest) or
@@ -1328,12 +1340,15 @@ function createHttpBackendMock($rootScope, $timeout, $delegate, $browser) {
}
// TODO(vojta): change params to: method, url, data, headers, callback
- function $httpBackend(method, url, data, callback, headers, timeout, withCredentials, responseType) {
+ function $httpBackend(method, url, data, callback, headers, timeout, withCredentials, responseType, eventHandlers, uploadEventHandlers) {
var xhr = new MockXhr(),
expectation = expectations[0],
wasExpected = false;
+ xhr.$$events = eventHandlers;
+ xhr.upload.$$events = uploadEventHandlers;
+
function prettyPrint(data) {
return (angular.isString(data) || angular.isFunction(data) || data instanceof RegExp)
? data
@@ -1393,7 +1408,7 @@ function createHttpBackendMock($rootScope, $timeout, $delegate, $browser) {
// if $browser specified, we do auto flush all requests
($browser ? $browser.defer : responsesPush)(wrapResponse(definition));
} else if (definition.passThrough) {
- $delegate(method, url, data, callback, headers, timeout, withCredentials, responseType);
+ $delegate(method, url, data, callback, headers, timeout, withCredentials, responseType, eventHandlers, uploadEventHandlers);
} else throw new Error('No response defined !');
return;
}
@@ -1423,12 +1438,14 @@ function createHttpBackendMock($rootScope, $timeout, $delegate, $browser) {
* order to change how a matched request is handled.
*
* - respond –
- * `{function([status,] data[, headers, statusText])
- * | function(function(method, url, data, headers, params)}`
+ * ```js
+ * {function([status,] data[, headers, statusText])
+ * | function(function(method, url, data, headers, params)}
+ * ```
* – The respond method takes a set of static data to be returned or a function that can
- * return an array containing response status (number), response data (string), response
- * headers (Object), and the text for the status (string). The respond method returns the
- * `requestHandler` object for possible overrides.
+ * return an array containing response status (number), response data (Array|Object|string),
+ * response headers (Object), and the text for the status (string). The respond method returns
+ * the `requestHandler` object for possible overrides.
*/
$httpBackend.when = function(method, url, data, headers, keys) {
var definition = new MockHttpExpectation(method, url, data, headers, keys),
@@ -1613,12 +1630,14 @@ function createHttpBackendMock($rootScope, $timeout, $delegate, $browser) {
* order to change how a matched request is handled.
*
* - respond –
- * `{function([status,] data[, headers, statusText])
- * | function(function(method, url, data, headers, params)}`
+ * ```
+ * { function([status,] data[, headers, statusText])
+ * | function(function(method, url, data, headers, params)}
+ * ```
* – The respond method takes a set of static data to be returned or a function that can
- * return an array containing response status (number), response data (string), response
- * headers (Object), and the text for the status (string). The respond method returns the
- * `requestHandler` object for possible overrides.
+ * return an array containing response status (number), response data (Array|Object|string),
+ * response headers (Object), and the text for the status (string). The respond method returns
+ * the `requestHandler` object for possible overrides.
*/
$httpBackend.expect = function(method, url, data, headers, keys) {
var expectation = new MockHttpExpectation(method, url, data, headers, keys),
@@ -1868,6 +1887,15 @@ function createHttpBackendMock($rootScope, $timeout, $delegate, $browser) {
function MockHttpExpectation(method, url, data, headers, keys) {
+ function getUrlParams(u) {
+ var params = u.slice(u.indexOf('?') + 1).split('&');
+ return params.sort();
+ }
+
+ function compareUrl(u) {
+ return (url.slice(0, url.indexOf('?')) == u.slice(0, u.indexOf('?')) && getUrlParams(url).join() == getUrlParams(u).join());
+ }
+
this.data = data;
this.headers = headers;
@@ -1883,7 +1911,7 @@ function MockHttpExpectation(method, url, data, headers, keys) {
if (!url) return true;
if (angular.isFunction(url.test)) return url.test(u);
if (angular.isFunction(url)) return url(u);
- return url == u;
+ return (url == u || compareUrl(u));
};
this.matchHeaders = function(h) {
@@ -2012,6 +2040,20 @@ function MockXhr() {
};
this.abort = angular.noop;
+
+ // This section simulates the events on a real XHR object (and the upload object)
+ // When we are testing $httpBackend (inside the angular project) we make partial use of this
+ // but store the events directly ourselves on `$$events`, instead of going through the `addEventListener`
+ this.$$events = {};
+ this.addEventListener = function(name, listener) {
+ if (angular.isUndefined(this.$$events[name])) this.$$events[name] = [];
+ this.$$events[name].push(listener);
+ };
+
+ this.upload = {
+ $$events: {},
+ addEventListener: this.addEventListener
+ };
}
@@ -2166,9 +2208,15 @@ angular.mock.$RootElementProvider = function() {
angular.mock.$ControllerDecorator = ['$delegate', function($delegate) {
return function(expression, locals, later, ident) {
if (later && typeof later === 'object') {
- var create = $delegate(expression, locals, true, ident);
- angular.extend(create.instance, later);
- return create();
+ var instantiate = $delegate(expression, locals, true, ident);
+ angular.extend(instantiate.instance, later);
+
+ var instance = instantiate();
+ if (instance !== instantiate.instance) {
+ angular.extend(instance, later);
+ }
+
+ return instance;
}
return $delegate(expression, locals, later, ident);
};
@@ -2181,8 +2229,8 @@ angular.mock.$ControllerDecorator = ['$delegate', function($delegate) {
* A service that can be used to create instances of component controllers.
*
* Be aware that the controller will be instantiated and attached to the scope as specified in
- * the component definition object. That means that you must always provide a `$scope` object
- * in the `locals` param.
+ * the component definition object. If you do not provide a `$scope` object in the `locals` param
+ * then the helper will create a new isolated scope as a child of `$rootScope`.
*
* @param {string} componentName the name of the component whose controller we want to instantiate
* @param {Object} locals Injection locals for Controller.
@@ -2192,7 +2240,7 @@ angular.mock.$ControllerDecorator = ['$delegate', function($delegate) {
* @return {Object} Instance of requested controller.
*/
angular.mock.$ComponentControllerProvider = ['$compileProvider', function($compileProvider) {
- this.$get = ['$controller','$injector', function($controller,$injector) {
+ this.$get = ['$controller','$injector', '$rootScope', function($controller, $injector, $rootScope) {
return function $componentController(componentName, locals, bindings, ident) {
// get all directives associated to the component name
var directives = $injector.get(componentName + 'Directive');
@@ -2210,6 +2258,9 @@ angular.mock.$ComponentControllerProvider = ['$compileProvider', function($compi
}
// get the info of the component
var directiveInfo = candidateDirectives[0];
+ // create a scope if needed
+ locals = locals || {};
+ locals.$scope = locals.$scope || $rootScope.$new(true);
return $controller(directiveInfo.controller, locals, bindings, ident || directiveInfo.controllerAs);
};
}];
@@ -2231,6 +2282,34 @@ angular.mock.$ComponentControllerProvider = ['$compileProvider', function($compi
*
*
*
+ * @installation
+ *
+ * First, download the file:
+ * * [Google CDN](https://developers.google.com/speed/libraries/devguide#angularjs) e.g.
+ * `"//ajax.googleapis.com/ajax/libs/angularjs/X.Y.Z/angular-mocks.js"`
+ * * [NPM](https://www.npmjs.com/) e.g. `npm install angular-mocks@X.Y.Z`
+ * * [Bower](http://bower.io) e.g. `bower install angular-mocks#X.Y.Z`
+ * * [code.angularjs.org](https://code.angularjs.org/) (discouraged for production use) e.g.
+ * `"//code.angularjs.org/X.Y.Z/angular-mocks.js"`
+ *
+ * where X.Y.Z is the AngularJS version you are running.
+ *
+ * Then, configure your test runner to load `angular-mocks.js` after `angular.js`.
+ * This example uses Karma:
+ *
+ * ```
+ * config.set({
+ * files: [
+ * 'build/angular.js', // and other module files you need
+ * 'build/angular-mocks.js',
+ * '',
+ * ''
+ * ]
+ * });
+ * ```
+ *
+ * Including the `angular-mocks.js` file automatically adds the `ngMock` module, so your tests
+ * are ready to go!
*/
angular.module('ngMock', ['ng']).provider({
$browser: angular.mock.$BrowserProvider,
@@ -2259,6 +2338,7 @@ angular.module('ngMock', ['ng']).provider({
* the {@link ngMockE2E.$httpBackend e2e $httpBackend} mock.
*/
angular.module('ngMockE2E', ['ng']).config(['$provide', function($provide) {
+ $provide.value('$httpBackend', angular.injector(['ng']).get('$httpBackend'));
$provide.decorator('$httpBackend', angular.mock.e2e.$httpBackendDecorator);
}]);
@@ -2270,8 +2350,10 @@ angular.module('ngMockE2E', ['ng']).config(['$provide', function($provide) {
* Fake HTTP backend implementation suitable for end-to-end testing or backend-less development of
* applications that use the {@link ng.$http $http service}.
*
- * *Note*: For fake http backend implementation suitable for unit testing please see
+ *
+ * **Note**: For fake http backend implementation suitable for unit testing please see
* {@link ngMock.$httpBackend unit-testing $httpBackend mock}.
+ *
*
* This implementation can be used to respond with static or dynamic responses via the `when` api
* and its shortcuts (`whenGET`, `whenPOST`, etc) and optionally pass through requests to the
@@ -2292,9 +2374,9 @@ angular.module('ngMockE2E', ['ng']).config(['$provide', function($provide) {
* on the `ngMockE2E` and your application modules and defines the fake backend:
*
* ```js
- * myAppDev = angular.module('myAppDev', ['myApp', 'ngMockE2E']);
+ * var myAppDev = angular.module('myAppDev', ['myApp', 'ngMockE2E']);
* myAppDev.run(function($httpBackend) {
- * phones = [{name: 'phone1'}, {name: 'phone2'}];
+ * var phones = [{name: 'phone1'}, {name: 'phone2'}];
*
* // returns the current list of phones
* $httpBackend.whenGET('/phones').respond(phones);
@@ -2305,12 +2387,74 @@ angular.module('ngMockE2E', ['ng']).config(['$provide', function($provide) {
* phones.push(phone);
* return [200, phone, {}];
* });
- * $httpBackend.whenGET(/^\/templates\//).passThrough();
+ * $httpBackend.whenGET(/^\/templates\//).passThrough(); // Requests for templare are handled by the real server
* //...
* });
* ```
*
* Afterwards, bootstrap your app with this new module.
+ *
+ * ## Example
+ *
+ *
+ * var myApp = angular.module('myApp', []);
+ *
+ * myApp.controller('main', function($http) {
+ * var ctrl = this;
+ *
+ * ctrl.phones = [];
+ * ctrl.newPhone = {
+ * name: ''
+ * };
+ *
+ * ctrl.getPhones = function() {
+ * $http.get('/phones').then(function(response) {
+ * ctrl.phones = response.data;
+ * });
+ * };
+ *
+ * ctrl.addPhone = function(phone) {
+ * $http.post('/phones', phone).then(function() {
+ * ctrl.newPhone = {name: ''};
+ * return ctrl.getPhones();
+ * });
+ * };
+ *
+ * ctrl.getPhones();
+ * });
+ *
+ *
+ * var myAppDev = angular.module('myAppE2E', ['myApp', 'ngMockE2E']);
+ *
+ * myAppDev.run(function($httpBackend) {
+ * var phones = [{name: 'phone1'}, {name: 'phone2'}];
+ *
+ * // returns the current list of phones
+ * $httpBackend.whenGET('/phones').respond(phones);
+ *
+ * // adds a new phone to the phones array
+ * $httpBackend.whenPOST('/phones').respond(function(method, url, data) {
+ * var phone = angular.fromJson(data);
+ * phones.push(phone);
+ * return [200, phone, {}];
+ * });
+ * });
+ *
+ *
+ *
+ *
+ *
Phones
+ *
+ *
{{phone.name}}
+ *
+ *
+ *
+ *
+ *
+ *
*/
/**
@@ -2333,11 +2477,13 @@ angular.module('ngMockE2E', ['ng']).config(['$provide', function($provide) {
* `respond` or `passThrough` again in order to change how a matched request is handled.
*
* - respond –
- * `{function([status,] data[, headers, statusText])
- * | function(function(method, url, data, headers, params)}`
+ * ```
+ * { function([status,] data[, headers, statusText])
+ * | function(function(method, url, data, headers, params)}
+ * ```
* – The respond method takes a set of static data to be returned or a function that can return
- * an array containing response status (number), response data (string), response headers
- * (Object), and the text for the status (string).
+ * an array containing response status (number), response data (Array|Object|string), response
+ * headers (Object), and the text for the status (string).
* - passThrough – `{function()}` – Any request matching a backend definition with
* `passThrough` handler will be passed through to the real backend (an XHR request will be made
* to the server.)
@@ -2791,7 +2937,7 @@ angular.mock.$RootScopeDecorator = ['$delegate', function($delegate) {
angular.forEach(angular.callbacks, function(val, key) {
delete angular.callbacks[key];
});
- angular.callbacks.counter = 0;
+ angular.callbacks.$$counter = 0;
};
(window.beforeEach || window.setup)(module.$$beforeEach);
@@ -2894,11 +3040,17 @@ angular.mock.$RootScopeDecorator = ['$delegate', function($delegate) {
this.stack = e.stack + '\n' + errorForStack.stack;
if (e.stackArray) this.stackArray = e.stackArray;
};
- ErrorAddingDeclarationLocationStack.prototype.toString = Error.prototype.toString;
+ ErrorAddingDeclarationLocationStack.prototype = Error.prototype;
window.inject = angular.mock.inject = function() {
var blockFns = Array.prototype.slice.call(arguments, 0);
var errorForStack = new Error('Declaration Location');
+ // IE10+ and PhanthomJS do not set stack trace information, until the error is thrown
+ if (!errorForStack.stack) {
+ try {
+ throw errorForStack;
+ } catch (e) {}
+ }
return wasInjectorCreated() ? workFn.call(currentSpec) : workFn;
/////////////////////
function workFn() {
diff --git a/public/vendor/angular-mocks/bower.json b/public/vendor/angular-mocks/bower.json
index 4ce65bbc809..3a3d60a6b06 100644
--- a/public/vendor/angular-mocks/bower.json
+++ b/public/vendor/angular-mocks/bower.json
@@ -1,10 +1,10 @@
{
"name": "angular-mocks",
- "version": "1.5.3",
+ "version": "1.5.8",
"license": "MIT",
"main": "./angular-mocks.js",
"ignore": [],
"dependencies": {
- "angular": "1.5.3"
+ "angular": "1.5.8"
}
}
diff --git a/public/vendor/angular-mocks/package.json b/public/vendor/angular-mocks/package.json
index 42d78038650..631e187985b 100644
--- a/public/vendor/angular-mocks/package.json
+++ b/public/vendor/angular-mocks/package.json
@@ -1,6 +1,6 @@
{
"name": "angular-mocks",
- "version": "1.5.3",
+ "version": "1.5.8",
"description": "AngularJS mocks for testing",
"main": "angular-mocks.js",
"scripts": {
@@ -23,5 +23,12 @@
"bugs": {
"url": "https://github.com/angular/angular.js/issues"
},
- "homepage": "http://angularjs.org"
+ "homepage": "http://angularjs.org",
+ "jspm": {
+ "shim": {
+ "angular-mocks": {
+ "deps": ["angular"]
+ }
+ }
+ }
}
diff --git a/public/vendor/angular-route/.bower.json b/public/vendor/angular-route/.bower.json
index e059146ff2d..9639a728a0e 100644
--- a/public/vendor/angular-route/.bower.json
+++ b/public/vendor/angular-route/.bower.json
@@ -1,20 +1,20 @@
{
"name": "angular-route",
- "version": "1.5.3",
+ "version": "1.5.8",
"license": "MIT",
"main": "./angular-route.js",
"ignore": [],
"dependencies": {
- "angular": "1.5.3"
+ "angular": "1.5.8"
},
"homepage": "https://github.com/angular/bower-angular-route",
- "_release": "1.5.3",
+ "_release": "1.5.8",
"_resolution": {
"type": "version",
- "tag": "v1.5.3",
- "commit": "750e4833612071d30993c8e4a547a6982eba3b84"
+ "tag": "v1.5.8",
+ "commit": "e96eff424fdd9689061659603ca59470375bf024"
},
"_source": "https://github.com/angular/bower-angular-route.git",
- "_target": "1.5.3",
+ "_target": "1.5.8",
"_originalSource": "angular-route"
}
\ No newline at end of file
diff --git a/public/vendor/angular-route/LICENSE.md b/public/vendor/angular-route/LICENSE.md
new file mode 100644
index 00000000000..2c395eef1ba
--- /dev/null
+++ b/public/vendor/angular-route/LICENSE.md
@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) 2016 Angular
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/public/vendor/angular-route/angular-route.js b/public/vendor/angular-route/angular-route.js
index 3c9a4e8595e..6654d83afef 100644
--- a/public/vendor/angular-route/angular-route.js
+++ b/public/vendor/angular-route/angular-route.js
@@ -1,9 +1,43 @@
/**
- * @license AngularJS v1.5.3
+ * @license AngularJS v1.5.8
* (c) 2010-2016 Google, Inc. http://angularjs.org
* License: MIT
*/
-(function(window, angular, undefined) {'use strict';
+(function(window, angular) {'use strict';
+
+/* global shallowCopy: true */
+
+/**
+ * Creates a shallow copy of an object, an array or a primitive.
+ *
+ * Assumes that there are no proto properties for objects.
+ */
+function shallowCopy(src, dst) {
+ if (isArray(src)) {
+ dst = dst || [];
+
+ for (var i = 0, ii = src.length; i < ii; i++) {
+ dst[i] = src[i];
+ }
+ } else if (isObject(src)) {
+ dst = dst || {};
+
+ for (var key in src) {
+ if (!(key.charAt(0) === '$' && key.charAt(1) === '$')) {
+ dst[key] = src[key];
+ }
+ }
+ }
+
+ return dst || src;
+}
+
+/* global shallowCopy: false */
+
+// There are necessary for `shallowCopy()` (included via `src/shallowCopy.js`).
+// They are initialized inside the `$RouteProvider`, to ensure `window.angular` is available.
+var isArray;
+var isObject;
/**
* @ngdoc module
@@ -22,11 +56,7 @@
*/
/* global -ngRouteModule */
var ngRouteModule = angular.module('ngRoute', ['ng']).
- provider('$route', $RouteProvider).
- // Ensure `$route` will be instantiated in time to capture the initial
- // `$locationChangeSuccess` event. This is necessary in case `ngView` is
- // included in an asynchronously loaded template.
- run(['$route', angular.noop]),
+ provider('$route', $RouteProvider),
$routeMinErr = angular.$$minErr('ngRoute');
/**
@@ -44,6 +74,9 @@ var ngRouteModule = angular.module('ngRoute', ['ng']).
* Requires the {@link ngRoute `ngRoute`} module to be installed.
*/
function $RouteProvider() {
+ isArray = angular.isArray;
+ isObject = angular.isObject;
+
function inherit(parent, extra) {
return angular.extend(Object.create(parent), extra);
}
@@ -163,7 +196,7 @@ function $RouteProvider() {
*/
this.when = function(path, route) {
//copy original route object to preserve params inherited from proto chain
- var routeCopy = angular.copy(route);
+ var routeCopy = shallowCopy(route);
if (angular.isUndefined(routeCopy.reloadOnSearch)) {
routeCopy.reloadOnSearch = true;
}
@@ -608,35 +641,7 @@ function $RouteProvider() {
}
$q.when(nextRoute).
- then(function() {
- if (nextRoute) {
- var locals = angular.extend({}, nextRoute.resolve),
- template, templateUrl;
-
- angular.forEach(locals, function(value, key) {
- locals[key] = angular.isString(value) ?
- $injector.get(value) : $injector.invoke(value, null, null, key);
- });
-
- if (angular.isDefined(template = nextRoute.template)) {
- if (angular.isFunction(template)) {
- template = template(nextRoute.params);
- }
- } else if (angular.isDefined(templateUrl = nextRoute.templateUrl)) {
- if (angular.isFunction(templateUrl)) {
- templateUrl = templateUrl(nextRoute.params);
- }
- if (angular.isDefined(templateUrl)) {
- nextRoute.loadedTemplateUrl = $sce.valueOf(templateUrl);
- template = $templateRequest(templateUrl);
- }
- }
- if (angular.isDefined(template)) {
- locals['$template'] = template;
- }
- return $q.all(locals);
- }
- }).
+ then(resolveLocals).
then(function(locals) {
// after route change
if (nextRoute == $route.current) {
@@ -654,6 +659,41 @@ function $RouteProvider() {
}
}
+ function resolveLocals(route) {
+ if (route) {
+ var locals = angular.extend({}, route.resolve);
+ angular.forEach(locals, function(value, key) {
+ locals[key] = angular.isString(value) ?
+ $injector.get(value) :
+ $injector.invoke(value, null, null, key);
+ });
+ var template = getTemplateFor(route);
+ if (angular.isDefined(template)) {
+ locals['$template'] = template;
+ }
+ return $q.all(locals);
+ }
+ }
+
+
+ function getTemplateFor(route) {
+ var template, templateUrl;
+ if (angular.isDefined(template = route.template)) {
+ if (angular.isFunction(template)) {
+ template = template(route.params);
+ }
+ } else if (angular.isDefined(templateUrl = route.templateUrl)) {
+ if (angular.isFunction(templateUrl)) {
+ templateUrl = templateUrl(route.params);
+ }
+ if (angular.isDefined(templateUrl)) {
+ route.loadedTemplateUrl = $sce.valueOf(templateUrl);
+ template = $templateRequest(templateUrl);
+ }
+ }
+ return template;
+ }
+
/**
* @returns {Object} the current active route, by matching it against the URL
@@ -760,6 +800,13 @@ ngRouteModule.directive('ngView', ngViewFillContentFactory);
*
* The enter and leave animation occur concurrently.
*
+ * @knownIssue If `ngView` is contained in an asynchronously loaded template (e.g. in another
+ * directive's templateUrl or in a template loaded using `ngInclude`), then you need to
+ * make sure that `$route` is instantiated in time to capture the initial
+ * `$locationChangeStart` event and load the appropriate view. One way to achieve this
+ * is to have it as a dependency in a `.run` block:
+ * `myModule.run(['$route', function() {}]);`
+ *
* @scope
* @priority 400
* @param {string=} onload Expression to evaluate whenever the view updates.
diff --git a/public/vendor/angular-route/angular-route.min.js b/public/vendor/angular-route/angular-route.min.js
index 5d2e84f9498..2fa073f61aa 100644
--- a/public/vendor/angular-route/angular-route.min.js
+++ b/public/vendor/angular-route/angular-route.min.js
@@ -1,15 +1,16 @@
/*
- AngularJS v1.5.3
+ AngularJS v1.5.8
(c) 2010-2016 Google, Inc. http://angularjs.org
License: MIT
*/
-(function(r,d,C){'use strict';function x(s,h,g){return{restrict:"ECA",terminal:!0,priority:400,transclude:"element",link:function(a,c,b,f,y){function k(){n&&(g.cancel(n),n=null);l&&(l.$destroy(),l=null);m&&(n=g.leave(m),n.then(function(){n=null}),m=null)}function z(){var b=s.current&&s.current.locals;if(d.isDefined(b&&b.$template)){var b=a.$new(),f=s.current;m=y(b,function(b){g.enter(b,null,m||c).then(function(){!d.isDefined(u)||u&&!a.$eval(u)||h()});k()});l=f.scope=b;l.$emit("$viewContentLoaded");
-l.$eval(v)}else k()}var l,m,n,u=b.autoscroll,v=b.onload||"";a.$on("$routeChangeSuccess",z);z()}}}function A(d,h,g){return{restrict:"ECA",priority:-400,link:function(a,c){var b=g.current,f=b.locals;c.html(f.$template);var y=d(c.contents());if(b.controller){f.$scope=a;var k=h(b.controller,f);b.controllerAs&&(a[b.controllerAs]=k);c.data("$ngControllerController",k);c.children().data("$ngControllerController",k)}a[b.resolveAs||"$resolve"]=f;y(a)}}}r=d.module("ngRoute",["ng"]).provider("$route",function(){function s(a,
-c){return d.extend(Object.create(a),c)}function h(a,d){var b=d.caseInsensitiveMatch,f={originalPath:a,regexp:a},g=f.keys=[];a=a.replace(/([().])/g,"\\$1").replace(/(\/)?:(\w+)(\*\?|[\?\*])?/g,function(a,d,b,c){a="?"===c||"*?"===c?"?":null;c="*"===c||"*?"===c?"*":null;g.push({name:b,optional:!!a});d=d||"";return""+(a?"":d)+"(?:"+(a?d:"")+(c&&"(.+?)"||"([^/]+)")+(a||"")+")"+(a||"")}).replace(/([\/$\*])/g,"\\$1");f.regexp=new RegExp("^"+a+"$",b?"i":"");return f}var g={};this.when=function(a,c){var b=
-d.copy(c);d.isUndefined(b.reloadOnSearch)&&(b.reloadOnSearch=!0);d.isUndefined(b.caseInsensitiveMatch)&&(b.caseInsensitiveMatch=this.caseInsensitiveMatch);g[a]=d.extend(b,a&&h(a,b));if(a){var f="/"==a[a.length-1]?a.substr(0,a.length-1):a+"/";g[f]=d.extend({redirectTo:a},h(f,b))}return this};this.caseInsensitiveMatch=!1;this.otherwise=function(a){"string"===typeof a&&(a={redirectTo:a});this.when(null,a);return this};this.$get=["$rootScope","$location","$routeParams","$q","$injector","$templateRequest",
-"$sce",function(a,c,b,f,h,k,r){function l(b){var e=t.current;(x=(p=n())&&e&&p.$$route===e.$$route&&d.equals(p.pathParams,e.pathParams)&&!p.reloadOnSearch&&!v)||!e&&!p||a.$broadcast("$routeChangeStart",p,e).defaultPrevented&&b&&b.preventDefault()}function m(){var w=t.current,e=p;if(x)w.params=e.params,d.copy(w.params,b),a.$broadcast("$routeUpdate",w);else if(e||w)v=!1,(t.current=e)&&e.redirectTo&&(d.isString(e.redirectTo)?c.path(u(e.redirectTo,e.params)).search(e.params).replace():c.url(e.redirectTo(e.pathParams,
-c.path(),c.search())).replace()),f.when(e).then(function(){if(e){var a=d.extend({},e.resolve),b,c;d.forEach(a,function(b,e){a[e]=d.isString(b)?h.get(b):h.invoke(b,null,null,e)});d.isDefined(b=e.template)?d.isFunction(b)&&(b=b(e.params)):d.isDefined(c=e.templateUrl)&&(d.isFunction(c)&&(c=c(e.params)),d.isDefined(c)&&(e.loadedTemplateUrl=r.valueOf(c),b=k(c)));d.isDefined(b)&&(a.$template=b);return f.all(a)}}).then(function(c){e==t.current&&(e&&(e.locals=c,d.copy(e.params,b)),a.$broadcast("$routeChangeSuccess",
-e,w))},function(b){e==t.current&&a.$broadcast("$routeChangeError",e,w,b)})}function n(){var a,b;d.forEach(g,function(f,g){var q;if(q=!b){var h=c.path();q=f.keys;var l={};if(f.regexp)if(h=f.regexp.exec(h)){for(var k=1,n=h.length;k
*
*
- * @param {boolean=} regexp New regexp to whitelist urls with.
+ * @param {boolean=} flag Enable or disable SVG support in the sanitizer.
* @returns {boolean|ng.$sanitizeProvider} Returns the currently configured value if called
* without an argument or self for chaining otherwise.
*/
this.enableSvg = function(enableSvg) {
- if (angular.isDefined(enableSvg)) {
+ if (isDefined(enableSvg)) {
svgEnabled = enableSvg;
return this;
} else {
return svgEnabled;
}
};
+
+ //////////////////////////////////////////////////////////////////////////////////////////////////
+ // Private stuff
+ //////////////////////////////////////////////////////////////////////////////////////////////////
+
+ bind = angular.bind;
+ extend = angular.extend;
+ forEach = angular.forEach;
+ isDefined = angular.isDefined;
+ lowercase = angular.lowercase;
+ noop = angular.noop;
+
+ htmlParser = htmlParserImpl;
+ htmlSanitizeWriter = htmlSanitizeWriterImpl;
+
+ // Regular Expressions for parsing tags and attributes
+ var SURROGATE_PAIR_REGEXP = /[\uD800-\uDBFF][\uDC00-\uDFFF]/g,
+ // Match everything outside of normal chars and " (quote character)
+ NON_ALPHANUMERIC_REGEXP = /([^\#-~ |!])/g;
+
+
+ // Good source of info about elements and attributes
+ // http://dev.w3.org/html5/spec/Overview.html#semantics
+ // http://simon.html5.org/html-elements
+
+ // Safe Void Elements - HTML5
+ // http://dev.w3.org/html5/spec/Overview.html#void-elements
+ var voidElements = toMap("area,br,col,hr,img,wbr");
+
+ // Elements that you can, intentionally, leave open (and which close themselves)
+ // http://dev.w3.org/html5/spec/Overview.html#optional-tags
+ var optionalEndTagBlockElements = toMap("colgroup,dd,dt,li,p,tbody,td,tfoot,th,thead,tr"),
+ optionalEndTagInlineElements = toMap("rp,rt"),
+ optionalEndTagElements = extend({},
+ optionalEndTagInlineElements,
+ optionalEndTagBlockElements);
+
+ // Safe Block Elements - HTML5
+ var blockElements = extend({}, optionalEndTagBlockElements, toMap("address,article," +
+ "aside,blockquote,caption,center,del,dir,div,dl,figure,figcaption,footer,h1,h2,h3,h4,h5," +
+ "h6,header,hgroup,hr,ins,map,menu,nav,ol,pre,section,table,ul"));
+
+ // Inline Elements - HTML5
+ var inlineElements = extend({}, optionalEndTagInlineElements, toMap("a,abbr,acronym,b," +
+ "bdi,bdo,big,br,cite,code,del,dfn,em,font,i,img,ins,kbd,label,map,mark,q,ruby,rp,rt,s," +
+ "samp,small,span,strike,strong,sub,sup,time,tt,u,var"));
+
+ // SVG Elements
+ // https://wiki.whatwg.org/wiki/Sanitization_rules#svg_Elements
+ // Note: the elements animate,animateColor,animateMotion,animateTransform,set are intentionally omitted.
+ // They can potentially allow for arbitrary javascript to be executed. See #11290
+ var svgElements = toMap("circle,defs,desc,ellipse,font-face,font-face-name,font-face-src,g,glyph," +
+ "hkern,image,linearGradient,line,marker,metadata,missing-glyph,mpath,path,polygon,polyline," +
+ "radialGradient,rect,stop,svg,switch,text,title,tspan");
+
+ // Blocked Elements (will be stripped)
+ var blockedElements = toMap("script,style");
+
+ var validElements = extend({},
+ voidElements,
+ blockElements,
+ inlineElements,
+ optionalEndTagElements);
+
+ //Attributes that have href and hence need to be sanitized
+ var uriAttrs = toMap("background,cite,href,longdesc,src,xlink:href");
+
+ var htmlAttrs = toMap('abbr,align,alt,axis,bgcolor,border,cellpadding,cellspacing,class,clear,' +
+ 'color,cols,colspan,compact,coords,dir,face,headers,height,hreflang,hspace,' +
+ 'ismap,lang,language,nohref,nowrap,rel,rev,rows,rowspan,rules,' +
+ 'scope,scrolling,shape,size,span,start,summary,tabindex,target,title,type,' +
+ 'valign,value,vspace,width');
+
+ // SVG attributes (without "id" and "name" attributes)
+ // https://wiki.whatwg.org/wiki/Sanitization_rules#svg_Attributes
+ var svgAttrs = toMap('accent-height,accumulate,additive,alphabetic,arabic-form,ascent,' +
+ 'baseProfile,bbox,begin,by,calcMode,cap-height,class,color,color-rendering,content,' +
+ 'cx,cy,d,dx,dy,descent,display,dur,end,fill,fill-rule,font-family,font-size,font-stretch,' +
+ 'font-style,font-variant,font-weight,from,fx,fy,g1,g2,glyph-name,gradientUnits,hanging,' +
+ 'height,horiz-adv-x,horiz-origin-x,ideographic,k,keyPoints,keySplines,keyTimes,lang,' +
+ 'marker-end,marker-mid,marker-start,markerHeight,markerUnits,markerWidth,mathematical,' +
+ 'max,min,offset,opacity,orient,origin,overline-position,overline-thickness,panose-1,' +
+ 'path,pathLength,points,preserveAspectRatio,r,refX,refY,repeatCount,repeatDur,' +
+ 'requiredExtensions,requiredFeatures,restart,rotate,rx,ry,slope,stemh,stemv,stop-color,' +
+ 'stop-opacity,strikethrough-position,strikethrough-thickness,stroke,stroke-dasharray,' +
+ 'stroke-dashoffset,stroke-linecap,stroke-linejoin,stroke-miterlimit,stroke-opacity,' +
+ 'stroke-width,systemLanguage,target,text-anchor,to,transform,type,u1,u2,underline-position,' +
+ 'underline-thickness,unicode,unicode-range,units-per-em,values,version,viewBox,visibility,' +
+ 'width,widths,x,x-height,x1,x2,xlink:actuate,xlink:arcrole,xlink:role,xlink:show,xlink:title,' +
+ 'xlink:type,xml:base,xml:lang,xml:space,xmlns,xmlns:xlink,y,y1,y2,zoomAndPan', true);
+
+ var validAttrs = extend({},
+ uriAttrs,
+ svgAttrs,
+ htmlAttrs);
+
+ function toMap(str, lowercaseKeys) {
+ var obj = {}, items = str.split(','), i;
+ for (i = 0; i < items.length; i++) {
+ obj[lowercaseKeys ? lowercase(items[i]) : items[i]] = true;
+ }
+ return obj;
+ }
+
+ var inertBodyElement;
+ (function(window) {
+ var doc;
+ if (window.document && window.document.implementation) {
+ doc = window.document.implementation.createHTMLDocument("inert");
+ } else {
+ throw $sanitizeMinErr('noinert', "Can't create an inert html document");
+ }
+ var docElement = doc.documentElement || doc.getDocumentElement();
+ var bodyElements = docElement.getElementsByTagName('body');
+
+ // usually there should be only one body element in the document, but IE doesn't have any, so we need to create one
+ if (bodyElements.length === 1) {
+ inertBodyElement = bodyElements[0];
+ } else {
+ var html = doc.createElement('html');
+ inertBodyElement = doc.createElement('body');
+ html.appendChild(inertBodyElement);
+ doc.appendChild(html);
+ }
+ })(window);
+
+ /**
+ * @example
+ * htmlParser(htmlString, {
+ * start: function(tag, attrs) {},
+ * end: function(tag) {},
+ * chars: function(text) {},
+ * comment: function(text) {}
+ * });
+ *
+ * @param {string} html string
+ * @param {object} handler
+ */
+ function htmlParserImpl(html, handler) {
+ if (html === null || html === undefined) {
+ html = '';
+ } else if (typeof html !== 'string') {
+ html = '' + html;
+ }
+ inertBodyElement.innerHTML = html;
+
+ //mXSS protection
+ var mXSSAttempts = 5;
+ do {
+ if (mXSSAttempts === 0) {
+ throw $sanitizeMinErr('uinput', "Failed to sanitize html because the input is unstable");
+ }
+ mXSSAttempts--;
+
+ // strip custom-namespaced attributes on IE<=11
+ if (window.document.documentMode) {
+ stripCustomNsAttrs(inertBodyElement);
+ }
+ html = inertBodyElement.innerHTML; //trigger mXSS
+ inertBodyElement.innerHTML = html;
+ } while (html !== inertBodyElement.innerHTML);
+
+ var node = inertBodyElement.firstChild;
+ while (node) {
+ switch (node.nodeType) {
+ case 1: // ELEMENT_NODE
+ handler.start(node.nodeName.toLowerCase(), attrToMap(node.attributes));
+ break;
+ case 3: // TEXT NODE
+ handler.chars(node.textContent);
+ break;
+ }
+
+ var nextNode;
+ if (!(nextNode = node.firstChild)) {
+ if (node.nodeType == 1) {
+ handler.end(node.nodeName.toLowerCase());
+ }
+ nextNode = node.nextSibling;
+ if (!nextNode) {
+ while (nextNode == null) {
+ node = node.parentNode;
+ if (node === inertBodyElement) break;
+ nextNode = node.nextSibling;
+ if (node.nodeType == 1) {
+ handler.end(node.nodeName.toLowerCase());
+ }
+ }
+ }
+ }
+ node = nextNode;
+ }
+
+ while (node = inertBodyElement.firstChild) {
+ inertBodyElement.removeChild(node);
+ }
+ }
+
+ function attrToMap(attrs) {
+ var map = {};
+ for (var i = 0, ii = attrs.length; i < ii; i++) {
+ var attr = attrs[i];
+ map[attr.name] = attr.value;
+ }
+ return map;
+ }
+
+
+ /**
+ * Escapes all potentially dangerous characters, so that the
+ * resulting string can be safely inserted into attribute or
+ * element text.
+ * @param value
+ * @returns {string} escaped text
+ */
+ function encodeEntities(value) {
+ return value.
+ replace(/&/g, '&').
+ replace(SURROGATE_PAIR_REGEXP, function(value) {
+ var hi = value.charCodeAt(0);
+ var low = value.charCodeAt(1);
+ return '' + (((hi - 0xD800) * 0x400) + (low - 0xDC00) + 0x10000) + ';';
+ }).
+ replace(NON_ALPHANUMERIC_REGEXP, function(value) {
+ return '' + value.charCodeAt(0) + ';';
+ }).
+ replace(//g, '>');
+ }
+
+ /**
+ * create an HTML/XML writer which writes to buffer
+ * @param {Array} buf use buf.join('') to get out sanitized html string
+ * @returns {object} in the form of {
+ * start: function(tag, attrs) {},
+ * end: function(tag) {},
+ * chars: function(text) {},
+ * comment: function(text) {}
+ * }
+ */
+ function htmlSanitizeWriterImpl(buf, uriValidator) {
+ var ignoreCurrentElement = false;
+ var out = bind(buf, buf.push);
+ return {
+ start: function(tag, attrs) {
+ tag = lowercase(tag);
+ if (!ignoreCurrentElement && blockedElements[tag]) {
+ ignoreCurrentElement = tag;
+ }
+ if (!ignoreCurrentElement && validElements[tag] === true) {
+ out('<');
+ out(tag);
+ forEach(attrs, function(value, key) {
+ var lkey = lowercase(key);
+ var isImage = (tag === 'img' && lkey === 'src') || (lkey === 'background');
+ if (validAttrs[lkey] === true &&
+ (uriAttrs[lkey] !== true || uriValidator(value, isImage))) {
+ out(' ');
+ out(key);
+ out('="');
+ out(encodeEntities(value));
+ out('"');
+ }
+ });
+ out('>');
+ }
+ },
+ end: function(tag) {
+ tag = lowercase(tag);
+ if (!ignoreCurrentElement && validElements[tag] === true && voidElements[tag] !== true) {
+ out('');
+ out(tag);
+ out('>');
+ }
+ if (tag == ignoreCurrentElement) {
+ ignoreCurrentElement = false;
+ }
+ },
+ chars: function(chars) {
+ if (!ignoreCurrentElement) {
+ out(encodeEntities(chars));
+ }
+ }
+ };
+ }
+
+
+ /**
+ * When IE9-11 comes across an unknown namespaced attribute e.g. 'xlink:foo' it adds 'xmlns:ns1' attribute to declare
+ * ns1 namespace and prefixes the attribute with 'ns1' (e.g. 'ns1:xlink:foo'). This is undesirable since we don't want
+ * to allow any of these custom attributes. This method strips them all.
+ *
+ * @param node Root element to process
+ */
+ function stripCustomNsAttrs(node) {
+ if (node.nodeType === window.Node.ELEMENT_NODE) {
+ var attrs = node.attributes;
+ for (var i = 0, l = attrs.length; i < l; i++) {
+ var attrNode = attrs[i];
+ var attrName = attrNode.name.toLowerCase();
+ if (attrName === 'xmlns:ns1' || attrName.lastIndexOf('ns1:', 0) === 0) {
+ node.removeAttributeNode(attrNode);
+ i--;
+ l--;
+ }
+ }
+ }
+
+ var nextNode = node.firstChild;
+ if (nextNode) {
+ stripCustomNsAttrs(nextNode);
+ }
+
+ nextNode = node.nextSibling;
+ if (nextNode) {
+ stripCustomNsAttrs(nextNode);
+ }
+ }
}
function sanitizeText(chars) {
var buf = [];
- var writer = htmlSanitizeWriter(buf, angular.noop);
+ var writer = htmlSanitizeWriter(buf, noop);
writer.chars(chars);
return buf.join('');
}
-// Regular Expressions for parsing tags and attributes
-var SURROGATE_PAIR_REGEXP = /[\uD800-\uDBFF][\uDC00-\uDFFF]/g,
- // Match everything outside of normal chars and " (quote character)
- NON_ALPHANUMERIC_REGEXP = /([^\#-~ |!])/g;
-
-
-// Good source of info about elements and attributes
-// http://dev.w3.org/html5/spec/Overview.html#semantics
-// http://simon.html5.org/html-elements
-
-// Safe Void Elements - HTML5
-// http://dev.w3.org/html5/spec/Overview.html#void-elements
-var voidElements = toMap("area,br,col,hr,img,wbr");
-
-// Elements that you can, intentionally, leave open (and which close themselves)
-// http://dev.w3.org/html5/spec/Overview.html#optional-tags
-var optionalEndTagBlockElements = toMap("colgroup,dd,dt,li,p,tbody,td,tfoot,th,thead,tr"),
- optionalEndTagInlineElements = toMap("rp,rt"),
- optionalEndTagElements = angular.extend({},
- optionalEndTagInlineElements,
- optionalEndTagBlockElements);
-
-// Safe Block Elements - HTML5
-var blockElements = angular.extend({}, optionalEndTagBlockElements, toMap("address,article," +
- "aside,blockquote,caption,center,del,dir,div,dl,figure,figcaption,footer,h1,h2,h3,h4,h5," +
- "h6,header,hgroup,hr,ins,map,menu,nav,ol,pre,section,table,ul"));
-
-// Inline Elements - HTML5
-var inlineElements = angular.extend({}, optionalEndTagInlineElements, toMap("a,abbr,acronym,b," +
- "bdi,bdo,big,br,cite,code,del,dfn,em,font,i,img,ins,kbd,label,map,mark,q,ruby,rp,rt,s," +
- "samp,small,span,strike,strong,sub,sup,time,tt,u,var"));
-
-// SVG Elements
-// https://wiki.whatwg.org/wiki/Sanitization_rules#svg_Elements
-// Note: the elements animate,animateColor,animateMotion,animateTransform,set are intentionally omitted.
-// They can potentially allow for arbitrary javascript to be executed. See #11290
-var svgElements = toMap("circle,defs,desc,ellipse,font-face,font-face-name,font-face-src,g,glyph," +
- "hkern,image,linearGradient,line,marker,metadata,missing-glyph,mpath,path,polygon,polyline," +
- "radialGradient,rect,stop,svg,switch,text,title,tspan");
-
-// Blocked Elements (will be stripped)
-var blockedElements = toMap("script,style");
-
-var validElements = angular.extend({},
- voidElements,
- blockElements,
- inlineElements,
- optionalEndTagElements);
-
-//Attributes that have href and hence need to be sanitized
-var uriAttrs = toMap("background,cite,href,longdesc,src,xlink:href");
-
-var htmlAttrs = toMap('abbr,align,alt,axis,bgcolor,border,cellpadding,cellspacing,class,clear,' +
- 'color,cols,colspan,compact,coords,dir,face,headers,height,hreflang,hspace,' +
- 'ismap,lang,language,nohref,nowrap,rel,rev,rows,rowspan,rules,' +
- 'scope,scrolling,shape,size,span,start,summary,tabindex,target,title,type,' +
- 'valign,value,vspace,width');
-
-// SVG attributes (without "id" and "name" attributes)
-// https://wiki.whatwg.org/wiki/Sanitization_rules#svg_Attributes
-var svgAttrs = toMap('accent-height,accumulate,additive,alphabetic,arabic-form,ascent,' +
- 'baseProfile,bbox,begin,by,calcMode,cap-height,class,color,color-rendering,content,' +
- 'cx,cy,d,dx,dy,descent,display,dur,end,fill,fill-rule,font-family,font-size,font-stretch,' +
- 'font-style,font-variant,font-weight,from,fx,fy,g1,g2,glyph-name,gradientUnits,hanging,' +
- 'height,horiz-adv-x,horiz-origin-x,ideographic,k,keyPoints,keySplines,keyTimes,lang,' +
- 'marker-end,marker-mid,marker-start,markerHeight,markerUnits,markerWidth,mathematical,' +
- 'max,min,offset,opacity,orient,origin,overline-position,overline-thickness,panose-1,' +
- 'path,pathLength,points,preserveAspectRatio,r,refX,refY,repeatCount,repeatDur,' +
- 'requiredExtensions,requiredFeatures,restart,rotate,rx,ry,slope,stemh,stemv,stop-color,' +
- 'stop-opacity,strikethrough-position,strikethrough-thickness,stroke,stroke-dasharray,' +
- 'stroke-dashoffset,stroke-linecap,stroke-linejoin,stroke-miterlimit,stroke-opacity,' +
- 'stroke-width,systemLanguage,target,text-anchor,to,transform,type,u1,u2,underline-position,' +
- 'underline-thickness,unicode,unicode-range,units-per-em,values,version,viewBox,visibility,' +
- 'width,widths,x,x-height,x1,x2,xlink:actuate,xlink:arcrole,xlink:role,xlink:show,xlink:title,' +
- 'xlink:type,xml:base,xml:lang,xml:space,xmlns,xmlns:xlink,y,y1,y2,zoomAndPan', true);
-
-var validAttrs = angular.extend({},
- uriAttrs,
- svgAttrs,
- htmlAttrs);
-
-function toMap(str, lowercaseKeys) {
- var obj = {}, items = str.split(','), i;
- for (i = 0; i < items.length; i++) {
- obj[lowercaseKeys ? angular.lowercase(items[i]) : items[i]] = true;
- }
- return obj;
-}
-
-var inertBodyElement;
-(function(window) {
- var doc;
- if (window.document && window.document.implementation) {
- doc = window.document.implementation.createHTMLDocument("inert");
- } else {
- throw $sanitizeMinErr('noinert', "Can't create an inert html document");
- }
- var docElement = doc.documentElement || doc.getDocumentElement();
- var bodyElements = docElement.getElementsByTagName('body');
-
- // usually there should be only one body element in the document, but IE doesn't have any, so we need to create one
- if (bodyElements.length === 1) {
- inertBodyElement = bodyElements[0];
- } else {
- var html = doc.createElement('html');
- inertBodyElement = doc.createElement('body');
- html.appendChild(inertBodyElement);
- doc.appendChild(html);
- }
-})(window);
-
-/**
- * @example
- * htmlParser(htmlString, {
- * start: function(tag, attrs) {},
- * end: function(tag) {},
- * chars: function(text) {},
- * comment: function(text) {}
- * });
- *
- * @param {string} html string
- * @param {object} handler
- */
-function htmlParser(html, handler) {
- if (html === null || html === undefined) {
- html = '';
- } else if (typeof html !== 'string') {
- html = '' + html;
- }
- inertBodyElement.innerHTML = html;
-
- //mXSS protection
- var mXSSAttempts = 5;
- do {
- if (mXSSAttempts === 0) {
- throw $sanitizeMinErr('uinput', "Failed to sanitize html because the input is unstable");
- }
- mXSSAttempts--;
-
- // strip custom-namespaced attributes on IE<=11
- if (document.documentMode <= 11) {
- stripCustomNsAttrs(inertBodyElement);
- }
- html = inertBodyElement.innerHTML; //trigger mXSS
- inertBodyElement.innerHTML = html;
- } while (html !== inertBodyElement.innerHTML);
-
- var node = inertBodyElement.firstChild;
- while (node) {
- switch (node.nodeType) {
- case 1: // ELEMENT_NODE
- handler.start(node.nodeName.toLowerCase(), attrToMap(node.attributes));
- break;
- case 3: // TEXT NODE
- handler.chars(node.textContent);
- break;
- }
-
- var nextNode;
- if (!(nextNode = node.firstChild)) {
- if (node.nodeType == 1) {
- handler.end(node.nodeName.toLowerCase());
- }
- nextNode = node.nextSibling;
- if (!nextNode) {
- while (nextNode == null) {
- node = node.parentNode;
- if (node === inertBodyElement) break;
- nextNode = node.nextSibling;
- if (node.nodeType == 1) {
- handler.end(node.nodeName.toLowerCase());
- }
- }
- }
- }
- node = nextNode;
- }
-
- while (node = inertBodyElement.firstChild) {
- inertBodyElement.removeChild(node);
- }
-}
-
-function attrToMap(attrs) {
- var map = {};
- for (var i = 0, ii = attrs.length; i < ii; i++) {
- var attr = attrs[i];
- map[attr.name] = attr.value;
- }
- return map;
-}
-
-
-/**
- * Escapes all potentially dangerous characters, so that the
- * resulting string can be safely inserted into attribute or
- * element text.
- * @param value
- * @returns {string} escaped text
- */
-function encodeEntities(value) {
- return value.
- replace(/&/g, '&').
- replace(SURROGATE_PAIR_REGEXP, function(value) {
- var hi = value.charCodeAt(0);
- var low = value.charCodeAt(1);
- return '' + (((hi - 0xD800) * 0x400) + (low - 0xDC00) + 0x10000) + ';';
- }).
- replace(NON_ALPHANUMERIC_REGEXP, function(value) {
- return '' + value.charCodeAt(0) + ';';
- }).
- replace(//g, '>');
-}
-
-/**
- * create an HTML/XML writer which writes to buffer
- * @param {Array} buf use buf.join('') to get out sanitized html string
- * @returns {object} in the form of {
- * start: function(tag, attrs) {},
- * end: function(tag) {},
- * chars: function(text) {},
- * comment: function(text) {}
- * }
- */
-function htmlSanitizeWriter(buf, uriValidator) {
- var ignoreCurrentElement = false;
- var out = angular.bind(buf, buf.push);
- return {
- start: function(tag, attrs) {
- tag = angular.lowercase(tag);
- if (!ignoreCurrentElement && blockedElements[tag]) {
- ignoreCurrentElement = tag;
- }
- if (!ignoreCurrentElement && validElements[tag] === true) {
- out('<');
- out(tag);
- angular.forEach(attrs, function(value, key) {
- var lkey=angular.lowercase(key);
- var isImage = (tag === 'img' && lkey === 'src') || (lkey === 'background');
- if (validAttrs[lkey] === true &&
- (uriAttrs[lkey] !== true || uriValidator(value, isImage))) {
- out(' ');
- out(key);
- out('="');
- out(encodeEntities(value));
- out('"');
- }
- });
- out('>');
- }
- },
- end: function(tag) {
- tag = angular.lowercase(tag);
- if (!ignoreCurrentElement && validElements[tag] === true && voidElements[tag] !== true) {
- out('');
- out(tag);
- out('>');
- }
- if (tag == ignoreCurrentElement) {
- ignoreCurrentElement = false;
- }
- },
- chars: function(chars) {
- if (!ignoreCurrentElement) {
- out(encodeEntities(chars));
- }
- }
- };
-}
-
-
-/**
- * When IE9-11 comes across an unknown namespaced attribute e.g. 'xlink:foo' it adds 'xmlns:ns1' attribute to declare
- * ns1 namespace and prefixes the attribute with 'ns1' (e.g. 'ns1:xlink:foo'). This is undesirable since we don't want
- * to allow any of these custom attributes. This method strips them all.
- *
- * @param node Root element to process
- */
-function stripCustomNsAttrs(node) {
- if (node.nodeType === Node.ELEMENT_NODE) {
- var attrs = node.attributes;
- for (var i = 0, l = attrs.length; i < l; i++) {
- var attrNode = attrs[i];
- var attrName = attrNode.name.toLowerCase();
- if (attrName === 'xmlns:ns1' || attrName.indexOf('ns1:') === 0) {
- node.removeAttributeNode(attrNode);
- i--;
- l--;
- }
- }
- }
-
- var nextNode = node.firstChild;
- if (nextNode) {
- stripCustomNsAttrs(nextNode);
- }
-
- nextNode = node.nextSibling;
- if (nextNode) {
- stripCustomNsAttrs(nextNode);
- }
-}
-
-
-
// define ngSanitize module and register $sanitize service
angular.module('ngSanitize', []).provider('$sanitize', $SanitizeProvider);
-/* global sanitizeText: false */
-
/**
* @ngdoc filter
* @name linky
@@ -653,12 +671,20 @@ angular.module('ngSanitize').filter('linky', ['$sanitize', function($sanitize) {
MAILTO_REGEXP = /^mailto:/i;
var linkyMinErr = angular.$$minErr('linky');
+ var isDefined = angular.isDefined;
+ var isFunction = angular.isFunction;
+ var isObject = angular.isObject;
var isString = angular.isString;
return function(text, target, attributes) {
if (text == null || text === '') return text;
if (!isString(text)) throw linkyMinErr('notstring', 'Expected string but received: {0}', text);
+ var attributesFn =
+ isFunction(attributes) ? attributes :
+ isObject(attributes) ? function getAttributesObject() {return attributes;} :
+ function getEmptyAttributesObject() {return {};};
+
var match;
var raw = text;
var html = [];
@@ -687,19 +713,14 @@ angular.module('ngSanitize').filter('linky', ['$sanitize', function($sanitize) {
}
function addLink(url, text) {
- var key;
+ var key, linkAttributes = attributesFn(url);
html.push('=document.documentMode&&n(g);a=g.innerHTML;g.innerHTML=a}while(a!==g.innerHTML);for(b=g.firstChild;b;){switch(b.nodeType){case 1:c.start(b.nodeName.toLowerCase(),E(b.attributes));
-break;case 3:c.chars(b.textContent)}var d;if(!(d=b.firstChild)&&(1==b.nodeType&&c.end(b.nodeName.toLowerCase()),d=b.nextSibling,!d))for(;null==d;){b=b.parentNode;if(b===g)break;d=b.nextSibling;1==b.nodeType&&c.end(b.nodeName.toLowerCase())}b=d}for(;b=g.firstChild;)g.removeChild(b)}function E(a){for(var c={},b=0,d=a.length;b/g,">")}function v(a,c){var b=!1,d=e.bind(a,a.push);return{start:function(a,f){a=e.lowercase(a);!b&&H[a]&&(b=a);b||!0!==t[a]||(d("<"),d(a),e.forEach(f,function(b,f){var g=e.lowercase(f),h="img"===a&&"src"===g||"background"===g;!0!==I[g]||!0===y[g]&&!c(b,h)||(d(" "),d(f),d('="'),d(x(b)),d('"'))}),d(">"))},end:function(a){a=e.lowercase(a);b||!0!==t[a]||!0===z[a]||(d(""),d(a),d(">"));a==
-b&&(b=!1)},chars:function(a){b||d(x(a))}}}function n(a){if(a.nodeType===Node.ELEMENT_NODE)for(var c=a.attributes,b=0,d=c.length;b"\u201d\u2019]/i,b=/^mailto:/i,d=e.$$minErr("linky"),g=e.isString;return function(f,h,m){function k(a){a&&p.push(C(a))}function q(a,b){var c;p.push("');k(b);p.push("")}if(null==f||""===f)return f;if(!g(f))throw d("notstring",f);for(var r=f,p=[],s,n;f=r.match(c);)s=f[0],f[2]||f[4]||(s=(f[3]?"http://":"mailto:")+s),n=f.index,k(r.substr(0,n)),q(s,f[0].replace(b,"")),r=r.substring(n+f[0].length);k(r);return a(p.join(""))}}])})(window,window.angular);
+(function(s,g){'use strict';function H(g){var l=[];t(l,A).chars(g);return l.join("")}var B=g.$$minErr("$sanitize"),C,l,D,E,q,A,F,t;g.module("ngSanitize",[]).provider("$sanitize",function(){function k(a,e){var b={},c=a.split(","),h;for(h=0;h/g,">")}function u(a){if(a.nodeType===s.Node.ELEMENT_NODE)for(var e=a.attributes,b=0,c=e.length;b"))},end:function(a){a=
+q(a);b||!0!==w[a]||!0===y[a]||(c(""),c(a),c(">"));a==b&&(b=!1)},chars:function(a){b||c(G(a))}}};var J=/[\uD800-\uDBFF][\uDC00-\uDFFF]/g,K=/([^\#-~ |!])/g,y=k("area,br,col,hr,img,wbr"),d=k("colgroup,dd,dt,li,p,tbody,td,tfoot,th,thead,tr"),r=k("rp,rt"),p=l({},r,d),d=l({},d,k("address,article,aside,blockquote,caption,center,del,dir,div,dl,figure,figcaption,footer,h1,h2,h3,h4,h5,h6,header,hgroup,hr,ins,map,menu,nav,ol,pre,section,table,ul")),r=l({},r,k("a,abbr,acronym,b,bdi,bdo,big,br,cite,code,del,dfn,em,font,i,img,ins,kbd,label,map,mark,q,ruby,rp,rt,s,samp,small,span,strike,strong,sub,sup,time,tt,u,var")),
+x=k("circle,defs,desc,ellipse,font-face,font-face-name,font-face-src,g,glyph,hkern,image,linearGradient,line,marker,metadata,missing-glyph,mpath,path,polygon,polyline,radialGradient,rect,stop,svg,switch,text,title,tspan"),z=k("script,style"),w=l({},y,d,r,p),n=k("background,cite,href,longdesc,src,xlink:href"),p=k("abbr,align,alt,axis,bgcolor,border,cellpadding,cellspacing,class,clear,color,cols,colspan,compact,coords,dir,face,headers,height,hreflang,hspace,ismap,lang,language,nohref,nowrap,rel,rev,rows,rowspan,rules,scope,scrolling,shape,size,span,start,summary,tabindex,target,title,type,valign,value,vspace,width"),
+r=k("accent-height,accumulate,additive,alphabetic,arabic-form,ascent,baseProfile,bbox,begin,by,calcMode,cap-height,class,color,color-rendering,content,cx,cy,d,dx,dy,descent,display,dur,end,fill,fill-rule,font-family,font-size,font-stretch,font-style,font-variant,font-weight,from,fx,fy,g1,g2,glyph-name,gradientUnits,hanging,height,horiz-adv-x,horiz-origin-x,ideographic,k,keyPoints,keySplines,keyTimes,lang,marker-end,marker-mid,marker-start,markerHeight,markerUnits,markerWidth,mathematical,max,min,offset,opacity,orient,origin,overline-position,overline-thickness,panose-1,path,pathLength,points,preserveAspectRatio,r,refX,refY,repeatCount,repeatDur,requiredExtensions,requiredFeatures,restart,rotate,rx,ry,slope,stemh,stemv,stop-color,stop-opacity,strikethrough-position,strikethrough-thickness,stroke,stroke-dasharray,stroke-dashoffset,stroke-linecap,stroke-linejoin,stroke-miterlimit,stroke-opacity,stroke-width,systemLanguage,target,text-anchor,to,transform,type,u1,u2,underline-position,underline-thickness,unicode,unicode-range,units-per-em,values,version,viewBox,visibility,width,widths,x,x-height,x1,x2,xlink:actuate,xlink:arcrole,xlink:role,xlink:show,xlink:title,xlink:type,xml:base,xml:lang,xml:space,xmlns,xmlns:xlink,y,y1,y2,zoomAndPan",
+!0),m=l({},n,r,p),f;(function(a){if(a.document&&a.document.implementation)a=a.document.implementation.createHTMLDocument("inert");else throw B("noinert");var e=(a.documentElement||a.getDocumentElement()).getElementsByTagName("body");1===e.length?f=e[0]:(e=a.createElement("html"),f=a.createElement("body"),e.appendChild(f),a.appendChild(e))})(s)});g.module("ngSanitize").filter("linky",["$sanitize",function(k){var l=/((ftp|https?):\/\/|(www\.)|(mailto:)?[A-Za-z0-9._%+-]+@)\S*[^\s.;,(){}<>"\u201d\u2019]/i,
+q=/^mailto:/i,u=g.$$minErr("linky"),v=g.isDefined,s=g.isFunction,t=g.isObject,y=g.isString;return function(d,g,p){function x(a){a&&m.push(H(a))}function z(a,b){var c,d=w(a);m.push("');x(b);m.push("")}if(null==d||""===d)return d;if(!y(d))throw u("notstring",d);for(var w=s(p)?p:t(p)?function(){return p}:function(){return{}},n=d,m=[],f,a;d=n.match(l);)f=d[0],d[2]||
+d[4]||(f=(d[3]?"http://":"mailto:")+f),a=d.index,x(n.substr(0,a)),z(f,d[0].replace(q,"")),n=n.substring(a+d[0].length);x(n);return k(m.join(""))}}])})(window,window.angular);
//# sourceMappingURL=angular-sanitize.min.js.map
diff --git a/public/vendor/angular-sanitize/angular-sanitize.min.js.map b/public/vendor/angular-sanitize/angular-sanitize.min.js.map
index 7276abd2dc0..8d2a1a981e8 100644
--- a/public/vendor/angular-sanitize/angular-sanitize.min.js.map
+++ b/public/vendor/angular-sanitize/angular-sanitize.min.js.map
@@ -1,8 +1,8 @@
{
"version":3,
"file":"angular-sanitize.min.js",
-"lineCount":14,
-"mappings":"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",
+"lineCount":15,
+"mappings":"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",
"sources":["angular-sanitize.js"],
-"names":["window","angular","undefined","sanitizeText","chars","buf","htmlSanitizeWriter","writer","noop","join","toMap","str","lowercaseKeys","obj","items","split","i","length","lowercase","htmlParser","html","handler","inertBodyElement","innerHTML","mXSSAttempts","$sanitizeMinErr","document","documentMode","stripCustomNsAttrs","node","firstChild","nodeType","start","nodeName","toLowerCase","attrToMap","attributes","textContent","nextNode","end","nextSibling","parentNode","removeChild","attrs","map","ii","attr","name","value","encodeEntities","replace","SURROGATE_PAIR_REGEXP","hi","charCodeAt","low","NON_ALPHANUMERIC_REGEXP","uriValidator","ignoreCurrentElement","out","bind","push","tag","blockedElements","validElements","forEach","key","lkey","isImage","validAttrs","uriAttrs","voidElements","Node","ELEMENT_NODE","l","attrNode","attrName","indexOf","removeAttributeNode","$$minErr","optionalEndTagBlockElements","optionalEndTagInlineElements","optionalEndTagElements","extend","blockElements","inlineElements","svgElements","htmlAttrs","svgAttrs","implementation","doc","createHTMLDocument","bodyElements","getElementsByTagName","documentElement","getDocumentElement","createElement","appendChild","module","provider","$SanitizeProvider","svgEnabled","$get","$$sanitizeUri","uri","test","enableSvg","this.enableSvg","isDefined","filter","$sanitize","LINKY_URL_REGEXP","MAILTO_REGEXP","linkyMinErr","isString","text","target","addText","addLink","url","isFunction","isObject","raw","match","index","substr","substring"]
+"names":["window","angular","sanitizeText","chars","buf","htmlSanitizeWriter","writer","noop","join","$sanitizeMinErr","$$minErr","bind","extend","forEach","isDefined","lowercase","htmlParser","module","provider","$SanitizeProvider","toMap","str","lowercaseKeys","obj","items","split","i","length","attrToMap","attrs","map","ii","attr","name","value","encodeEntities","replace","SURROGATE_PAIR_REGEXP","hi","charCodeAt","low","NON_ALPHANUMERIC_REGEXP","stripCustomNsAttrs","node","nodeType","Node","ELEMENT_NODE","attributes","l","attrNode","attrName","toLowerCase","lastIndexOf","removeAttributeNode","nextNode","firstChild","nextSibling","svgEnabled","$get","$$sanitizeUri","validElements","svgElements","html","uri","isImage","test","enableSvg","this.enableSvg","htmlParserImpl","handler","undefined","inertBodyElement","innerHTML","mXSSAttempts","document","documentMode","start","nodeName","textContent","end","parentNode","removeChild","htmlSanitizeWriterImpl","uriValidator","ignoreCurrentElement","out","push","tag","blockedElements","key","lkey","validAttrs","uriAttrs","voidElements","optionalEndTagBlockElements","optionalEndTagInlineElements","optionalEndTagElements","blockElements","inlineElements","htmlAttrs","svgAttrs","implementation","doc","createHTMLDocument","bodyElements","getElementsByTagName","documentElement","getDocumentElement","createElement","appendChild","filter","$sanitize","LINKY_URL_REGEXP","MAILTO_REGEXP","linkyMinErr","isFunction","isObject","isString","text","target","addText","addLink","url","linkAttributes","attributesFn","getAttributesObject","getEmptyAttributesObject","raw","match","index","substr","substring"]
}
diff --git a/public/vendor/angular-sanitize/bower.json b/public/vendor/angular-sanitize/bower.json
index 008752d2fcb..19810229328 100644
--- a/public/vendor/angular-sanitize/bower.json
+++ b/public/vendor/angular-sanitize/bower.json
@@ -1,10 +1,10 @@
{
"name": "angular-sanitize",
- "version": "1.5.3",
+ "version": "1.5.8",
"license": "MIT",
"main": "./angular-sanitize.js",
"ignore": [],
"dependencies": {
- "angular": "1.5.3"
+ "angular": "1.5.8"
}
}
diff --git a/public/vendor/angular-sanitize/package.json b/public/vendor/angular-sanitize/package.json
index 3be0b4facd5..a49308ecf65 100644
--- a/public/vendor/angular-sanitize/package.json
+++ b/public/vendor/angular-sanitize/package.json
@@ -1,6 +1,6 @@
{
"name": "angular-sanitize",
- "version": "1.5.3",
+ "version": "1.5.8",
"description": "AngularJS module for sanitizing HTML",
"main": "index.js",
"scripts": {
@@ -22,5 +22,12 @@
"bugs": {
"url": "https://github.com/angular/angular.js/issues"
},
- "homepage": "http://angularjs.org"
+ "homepage": "http://angularjs.org",
+ "jspm": {
+ "shim": {
+ "angular-sanitize": {
+ "deps": ["angular"]
+ }
+ }
+ }
}
diff --git a/public/vendor/angular/.bower.json b/public/vendor/angular/.bower.json
index 15b19d6c48b..8eb867dcfc7 100644
--- a/public/vendor/angular/.bower.json
+++ b/public/vendor/angular/.bower.json
@@ -1,18 +1,18 @@
{
"name": "angular",
- "version": "1.5.3",
+ "version": "1.5.8",
"license": "MIT",
"main": "./angular.js",
"ignore": [],
"dependencies": {},
"homepage": "https://github.com/angular/bower-angular",
- "_release": "1.5.3",
+ "_release": "1.5.8",
"_resolution": {
"type": "version",
- "tag": "v1.5.3",
- "commit": "5a07c5107b4d24f41744a02b07717d55bad88e70"
+ "tag": "v1.5.8",
+ "commit": "7e0e546eb6caedbb298c91a9f6bf7de7eeaa4ad2"
},
"_source": "https://github.com/angular/bower-angular.git",
- "_target": "1.5.3",
+ "_target": "1.5.8",
"_originalSource": "angular"
}
\ No newline at end of file
diff --git a/public/vendor/angular/LICENSE.md b/public/vendor/angular/LICENSE.md
new file mode 100644
index 00000000000..2c395eef1ba
--- /dev/null
+++ b/public/vendor/angular/LICENSE.md
@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) 2016 Angular
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/public/vendor/angular/angular.js b/public/vendor/angular/angular.js
index 5e6fb2c363d..54f65588f46 100644
--- a/public/vendor/angular/angular.js
+++ b/public/vendor/angular/angular.js
@@ -1,9 +1,9 @@
/**
- * @license AngularJS v1.5.3
+ * @license AngularJS v1.5.8
* (c) 2010-2016 Google, Inc. http://angularjs.org
* License: MIT
*/
-(function(window, document, undefined) {'use strict';
+(function(window) {'use strict';
/**
* @description
@@ -57,7 +57,7 @@ function minErr(module, ErrorConstructor) {
return match;
});
- message += '\nhttp://errors.angularjs.org/1.5.3/' +
+ message += '\nhttp://errors.angularjs.org/1.5.8/' +
(module ? module + '/' : '') + code;
for (i = SKIP_INDEXES, paramPrefix = '?'; i < templateArgs.length; i++, paramPrefix = '&') {
@@ -126,7 +126,6 @@ function minErr(module, ErrorConstructor) {
includes: true,
arrayRemove: true,
copy: true,
- shallowCopy: true,
equals: true,
csp: true,
jq: true,
@@ -171,6 +170,7 @@ function minErr(module, ErrorConstructor) {
* @ngdoc module
* @name ng
* @module ng
+ * @installation
* @description
*
* # ng (core module)
@@ -237,7 +237,7 @@ var
* documentMode is an IE-only property
* http://msdn.microsoft.com/en-us/library/ie/cc196988(v=vs.85).aspx
*/
-msie = document.documentMode;
+msie = window.document.documentMode;
/**
@@ -515,12 +515,22 @@ noop.$inject = [];
* functional style.
*
```js
- function transformer(transformationFn, value) {
- return (transformationFn || angular.identity)(value);
- };
+ function transformer(transformationFn, value) {
+ return (transformationFn || angular.identity)(value);
+ };
+
+ // E.g.
+ function getResult(fn, input) {
+ return (fn || angular.identity)(input);
+ };
+
+ getResult(function(n) { return n * 2; }, 21); // returns 42
+ getResult(null, 21); // returns 21
+ getResult(undefined, 21); // returns 21
```
- * @param {*} value to be returned.
- * @returns {*} the value passed in.
+ *
+ * @param {*} value to be returned.
+ * @returns {*} the value passed in.
*/
function identity($) {return $;}
identity.$inject = [];
@@ -765,8 +775,8 @@ var escapeForRegexp = function(s) {
*/
function isElement(node) {
return !!(node &&
- (node.nodeName // we are a direct element
- || (node.prop && node.attr && node.find))); // we have an on and find method part of jQuery API
+ (node.nodeName // We are a direct element.
+ || (node.prop && node.attr && node.find))); // We have an on and find method part of jQuery API.
}
/**
@@ -811,7 +821,13 @@ function arrayRemove(array, value) {
* * If a destination is provided, all of its elements (for arrays) or properties (for objects)
* are deleted and then all elements/properties from the source are copied to it.
* * If `source` is not an object or array (inc. `null` and `undefined`), `source` is returned.
- * * If `source` is identical to 'destination' an exception will be thrown.
+ * * If `source` is identical to `destination` an exception will be thrown.
+ *
+ *
+ *
+ * Only enumerable properties are taken into account. Non-enumerable properties (both on `source`
+ * and on `destination`) will be ignored.
+ *
*
* @param {*} source The source that will be used to make a copy.
* Can be any type, including primitives, `null`, and `undefined`.
@@ -820,41 +836,42 @@ function arrayRemove(array, value) {
* @returns {*} The copy or updated `destination`, if `destination` was specified.
*
* @example
-
-
-
-
-
form = {{user | json}}
-
master = {{master | json}}
-
+
+
+
+
+
form = {{user | json}}
+
master = {{master | json}}
+
+
+
+ // Module: copyExample
+ angular.
+ module('copyExample', []).
+ controller('ExampleController', ['$scope', function($scope) {
+ $scope.master = {};
-
-
-
+ $scope.reset();
+ }]);
+
+
*/
function copy(source, destination) {
var stackSource = [];
@@ -961,7 +978,7 @@ function copy(source, destination) {
case '[object Uint8ClampedArray]':
case '[object Uint16Array]':
case '[object Uint32Array]':
- return new source.constructor(copyElement(source.buffer));
+ return new source.constructor(copyElement(source.buffer), source.byteOffset, source.length);
case '[object ArrayBuffer]':
//Support: IE10
@@ -993,31 +1010,6 @@ function copy(source, destination) {
}
}
-/**
- * Creates a shallow copy of an object, an array or a primitive.
- *
- * Assumes that there are no proto properties for objects.
- */
-function shallowCopy(src, dst) {
- if (isArray(src)) {
- dst = dst || [];
-
- for (var i = 0, ii = src.length; i < ii; i++) {
- dst[i] = src[i];
- }
- } else if (isObject(src)) {
- dst = dst || {};
-
- for (var key in src) {
- if (!(key.charAt(0) === '$' && key.charAt(1) === '$')) {
- dst[key] = src[key];
- }
- }
- }
-
- return dst || src;
-}
-
/**
* @ngdoc function
@@ -1047,6 +1039,41 @@ function shallowCopy(src, dst) {
* @param {*} o1 Object or value to compare.
* @param {*} o2 Object or value to compare.
* @returns {boolean} True if arguments are equal.
+ *
+ * @example
+
+
+
+
+
+
+
+ angular.module('equalsExample', []).controller('ExampleController', ['$scope', function($scope) {
+ $scope.user1 = {};
+ $scope.user2 = {};
+ $scope.result;
+ $scope.compare = function() {
+ $scope.result = angular.equals($scope.user1, $scope.user2);
+ };
+ }]);
+
+
*/
function equals(o1, o2) {
if (o1 === o2) return true;
@@ -1093,8 +1120,8 @@ var csp = function() {
if (!isDefined(csp.rules)) {
- var ngCspElement = (document.querySelector('[ng-csp]') ||
- document.querySelector('[data-ng-csp]'));
+ var ngCspElement = (window.document.querySelector('[ng-csp]') ||
+ window.document.querySelector('[data-ng-csp]'));
if (ngCspElement) {
var ngCspAttribute = ngCspElement.getAttribute('ng-csp') ||
@@ -1169,7 +1196,7 @@ var jq = function() {
var i, ii = ngAttrPrefixes.length, prefix, name;
for (i = 0; i < ii; ++i) {
prefix = ngAttrPrefixes[i];
- if (el = document.querySelector('[' + prefix.replace(':', '\\:') + 'jq]')) {
+ if (el = window.document.querySelector('[' + prefix.replace(':', '\\:') + 'jq]')) {
name = el.getAttribute(prefix + 'jq');
break;
}
@@ -1221,7 +1248,7 @@ function bind(self, fn) {
: fn.call(self);
};
} else {
- // in IE, native methods are not functions so they cannot be bound (note: they don't need to be)
+ // In IE, native methods are not functions so they cannot be bound (note: they don't need to be).
return fn;
}
}
@@ -1234,7 +1261,7 @@ function toJsonReplacer(key, value) {
val = undefined;
} else if (isWindow(value)) {
val = '$WINDOW';
- } else if (value && document === value) {
+ } else if (value && window.document === value) {
val = '$DOCUMENT';
} else if (isScope(value)) {
val = '$SCOPE';
@@ -1258,6 +1285,27 @@ function toJsonReplacer(key, value) {
* @param {boolean|number} [pretty=2] If set to true, the JSON output will contain newlines and whitespace.
* If set to an integer, the JSON output will contain that many spaces per indentation.
* @returns {string|undefined} JSON-ified string representing `obj`.
+ * @knownIssue
+ *
+ * The Safari browser throws a `RangeError` instead of returning `null` when it tries to stringify a `Date`
+ * object with an invalid date value. The only reliable way to prevent this is to monkeypatch the
+ * `Date.prototype.toJSON` method as follows:
+ *
+ * ```
+ * var _DatetoJSON = Date.prototype.toJSON;
+ * Date.prototype.toJSON = function() {
+ * try {
+ * return _DatetoJSON.call(this);
+ * } catch(e) {
+ * if (e instanceof RangeError) {
+ * return null;
+ * }
+ * throw e;
+ * }
+ * };
+ * ```
+ *
+ * See https://github.com/angular/angular.js/pull/14221 for more information.
*/
function toJson(obj, pretty) {
if (isUndefined(obj)) return undefined;
@@ -1348,7 +1396,7 @@ function tryDecodeURIComponent(value) {
try {
return decodeURIComponent(value);
} catch (e) {
- // Ignore any invalid uri component
+ // Ignore any invalid uri component.
}
}
@@ -1593,7 +1641,7 @@ function angularInit(element, bootstrap) {
module,
config = {};
- // The element `element` has priority over any other element
+ // The element `element` has priority over any other element.
forEach(ngAttrPrefixes, function(prefix) {
var name = prefix + 'app';
@@ -1686,11 +1734,11 @@ function bootstrap(element, modules, config) {
element = jqLite(element);
if (element.injector()) {
- var tag = (element[0] === document) ? 'document' : startingTag(element);
- //Encode angle brackets to prevent input from being sanitized to empty string #8683
+ var tag = (element[0] === window.document) ? 'document' : startingTag(element);
+ // Encode angle brackets to prevent input from being sanitized to empty string #8683.
throw ngMinErr(
'btstrpd',
- "App Already Bootstrapped with this Element '{0}'",
+ "App already bootstrapped with this element '{0}'",
tag.replace(/,'<').replace(/>/,'>'));
}
@@ -2137,9 +2185,9 @@ function setupModuleLoader(window) {
* @ngdoc method
* @name angular.Module#decorator
* @module ng
- * @param {string} The name of the service to decorate.
- * @param {Function} This function will be invoked when the service needs to be
- * instantiated and should return the decorated service instance.
+ * @param {string} name The name of the service to decorate.
+ * @param {Function} decorFn This function will be invoked when the service needs to be
+ * instantiated and should return the decorated service instance.
* @description
* See {@link auto.$provide#decorator $provide.decorator()}.
*/
@@ -2302,7 +2350,34 @@ function setupModuleLoader(window) {
}
-/* global: toDebugString: true */
+/* global shallowCopy: true */
+
+/**
+ * Creates a shallow copy of an object, an array or a primitive.
+ *
+ * Assumes that there are no proto properties for objects.
+ */
+function shallowCopy(src, dst) {
+ if (isArray(src)) {
+ dst = dst || [];
+
+ for (var i = 0, ii = src.length; i < ii; i++) {
+ dst[i] = src[i];
+ }
+ } else if (isObject(src)) {
+ dst = dst || {};
+
+ for (var key in src) {
+ if (!(key.charAt(0) === '$' && key.charAt(1) === '$')) {
+ dst[key] = src[key];
+ }
+ }
+ }
+
+ return dst || src;
+}
+
+/* global toDebugString: true */
function serializeObject(obj) {
var seen = [];
@@ -2406,6 +2481,7 @@ function toDebugString(obj) {
$HttpParamSerializerJQLikeProvider,
$HttpBackendProvider,
$xhrFactoryProvider,
+ $jsonpCallbacksProvider,
$LocationProvider,
$LogProvider,
$ParseProvider,
@@ -2443,11 +2519,11 @@ function toDebugString(obj) {
* - `codeName` – `{string}` – Code name of the release, such as "jiggling-armfat".
*/
var version = {
- full: '1.5.3', // all of these placeholder strings will be replaced by grunt's
+ full: '1.5.8', // all of these placeholder strings will be replaced by grunt's
major: 1, // package task
minor: 5,
- dot: 3,
- codeName: 'diplohaplontic-meiosis'
+ dot: 8,
+ codeName: 'arbitrary-fallbacks'
};
@@ -2478,7 +2554,7 @@ function publishExternalAPI(angular) {
'isDate': isDate,
'lowercase': lowercase,
'uppercase': uppercase,
- 'callbacks': {counter: 0},
+ 'callbacks': {$$counter: 0},
'getTestability': getTestability,
'$$minErr': minErr,
'$$csp': csp,
@@ -2567,6 +2643,7 @@ function publishExternalAPI(angular) {
$httpParamSerializerJQLike: $HttpParamSerializerJQLikeProvider,
$httpBackend: $HttpBackendProvider,
$xhrFactory: $xhrFactoryProvider,
+ $jsonpCallbacks: $jsonpCallbacksProvider,
$location: $LocationProvider,
$log: $LogProvider,
$parse: $ParseProvider,
@@ -2643,7 +2720,7 @@ function publishExternalAPI(angular) {
* ## Angular's jqLite
* jqLite provides only the following jQuery methods:
*
- * - [`addClass()`](http://api.jquery.com/addClass/)
+ * - [`addClass()`](http://api.jquery.com/addClass/) - Does not support a function as first argument
* - [`after()`](http://api.jquery.com/after/)
* - [`append()`](http://api.jquery.com/append/)
* - [`attr()`](http://api.jquery.com/attr/) - Does not support functions as parameters
@@ -2670,12 +2747,12 @@ function publishExternalAPI(angular) {
* - [`ready()`](http://api.jquery.com/ready/)
* - [`remove()`](http://api.jquery.com/remove/)
* - [`removeAttr()`](http://api.jquery.com/removeAttr/)
- * - [`removeClass()`](http://api.jquery.com/removeClass/)
+ * - [`removeClass()`](http://api.jquery.com/removeClass/) - Does not support a function as first argument
* - [`removeData()`](http://api.jquery.com/removeData/)
* - [`replaceWith()`](http://api.jquery.com/replaceWith/)
* - [`text()`](http://api.jquery.com/text/)
- * - [`toggleClass()`](http://api.jquery.com/toggleClass/)
- * - [`triggerHandler()`](http://api.jquery.com/triggerHandler/) - Passes a dummy event object to handlers.
+ * - [`toggleClass()`](http://api.jquery.com/toggleClass/) - Does not support a function as first argument
+ * - [`triggerHandler()`](http://api.jquery.com/triggerHandler/) - Passes a dummy event object to handlers
* - [`unbind()`](http://api.jquery.com/unbind/) - Does not support namespaces or event object as parameter
* - [`val()`](http://api.jquery.com/val/)
* - [`wrap()`](http://api.jquery.com/wrap/)
@@ -2704,6 +2781,9 @@ function publishExternalAPI(angular) {
* - `inheritedData()` - same as `data()`, but walks up the DOM until a value is found or the top
* parent element is reached.
*
+ * @knownIssue You cannot spy on `angular.element` if you are using Jasmine version 1.x. See
+ * https://github.com/angular/angular.js/issues/14251 for more information.
+ *
* @param {string|DOMElement} element HTML string or DOMElement to be wrapped into jQuery.
* @returns {Object} jQuery object.
*/
@@ -2802,7 +2882,7 @@ function jqLiteBuildFragment(html, context) {
nodes.push(context.createTextNode(html));
} else {
// Convert html into DOM nodes
- tmp = tmp || fragment.appendChild(context.createElement("div"));
+ tmp = fragment.appendChild(context.createElement("div"));
tag = (TAG_NAME_REGEXP.exec(html) || ["", ""])[1].toLowerCase();
wrap = wrapMap[tag] || wrapMap._default;
tmp.innerHTML = wrap[1] + html.replace(XHTML_TAG_REGEXP, "<$1>$2>") + wrap[2];
@@ -2830,7 +2910,7 @@ function jqLiteBuildFragment(html, context) {
}
function jqLiteParseHTML(html, context) {
- context = context || document;
+ context = context || window.document;
var parsed;
if ((parsed = SINGLE_TAG_REGEXP.exec(html))) {
@@ -2856,7 +2936,7 @@ function jqLiteWrapNode(node, wrapper) {
// IE9-11 has no method "contains" in SVG element and in Node.prototype. Bug #10259.
-var jqLiteContains = Node.prototype.contains || function(arg) {
+var jqLiteContains = window.Node.prototype.contains || function(arg) {
// jshint bitwise: false
return !!(this.compareDocumentPosition(arg) & 16);
// jshint bitwise: true
@@ -3128,8 +3208,8 @@ var JQLitePrototype = JQLite.prototype = {
}
// check if document is already loaded
- if (document.readyState === 'complete') {
- setTimeout(trigger);
+ if (window.document.readyState === 'complete') {
+ window.setTimeout(trigger);
} else {
this.on('DOMContentLoaded', trigger); // works for modern browsers and IE9
// we can not use jqLite since we are not done loading and jQuery could be loaded later.
@@ -3819,6 +3899,7 @@ var $$HashMapProvider = [function() {
/**
* @ngdoc module
* @name auto
+ * @installation
* @description
*
* Implicit module which gets automatically added to each {@link auto.$injector $injector}.
@@ -3831,8 +3912,16 @@ var FN_ARG = /^\s*(_?)(\S+?)\1\s*$/;
var STRIP_COMMENTS = /((\/\/.*$)|(\/\*[\s\S]*?\*\/))/mg;
var $injectorMinErr = minErr('$injector');
+function stringifyFn(fn) {
+ // Support: Chrome 50-51 only
+ // Creating a new string by adding `' '` at the end, to hack around some bug in Chrome v50/51
+ // (See https://github.com/angular/angular.js/issues/14487.)
+ // TODO (gkalpak): Remove workaround when Chrome v52 is released
+ return Function.prototype.toString.call(fn) + ' ';
+}
+
function extractArgs(fn) {
- var fnText = fn.toString().replace(STRIP_COMMENTS, ''),
+ var fnText = stringifyFn(fn).replace(STRIP_COMMENTS, ''),
args = fnText.match(ARROW_ARG) || fnText.match(FN_ARGS);
return args;
}
@@ -4100,18 +4189,20 @@ function annotate(fn, strictDi, name) {
* 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.$provide#provider provider(name, 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
+ * * {@link auto.$provide#constant constant(name, 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
+ * * {@link auto.$provide#value value(name, 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`,
+ * * {@link auto.$provide#factory factory(name, fn)} - registers a service **factory function**
* 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`
+ * * {@link auto.$provide#service service(name, Fn)} - registers a **constructor function**
* that will be wrapped in a **service provider** object, whose `$get` property will instantiate
* a new object using the given constructor function.
+ * * {@link auto.$provide#decorator decorator(name, decorFn)} - registers a **decorator function** that
+ * will be able to modify or replace the implementation of another service.
*
* See the individual methods for more information and examples.
*/
@@ -4368,18 +4459,20 @@ function annotate(fn, strictDi, name) {
* @name $provide#decorator
* @description
*
- * Register a **service decorator** with the {@link auto.$injector $injector}. A service decorator
+ * Register a **decorator function** with the {@link auto.$injector $injector}. A decorator function
* intercepts the creation of a service, allowing it to override or modify the behavior 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.
+ * service. The return value of the decorator function may be the original service, or a new service
+ * that replaces (or wraps and delegates to) the original service.
+ *
+ * You can find out more about using decorators in the {@link guide/decorators} guide.
*
* @param {string} name The name of the service to decorate.
* @param {Function|Array.} decorator This function will be invoked when the service needs to be
- * instantiated and should return the decorated service instance. The function is called using
+ * provided 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,
+ * * `$delegate` - The original service instance, which can be replaced, monkey patched, configured,
* decorated or delegated to.
*
* @example
@@ -4602,10 +4695,10 @@ function createInjector(modulesToLoad, strictDi) {
if (msie <= 11) {
return false;
}
- // Workaround for MS Edge.
- // Check https://connect.microsoft.com/IE/Feedback/Details/2211653
+ // Support: Edge 12-13 only
+ // See: https://developer.microsoft.com/en-us/microsoft-edge/platform/issues/6156135/
return typeof func === 'function'
- && /^(?:class\s|constructor\()/.test(Function.prototype.toString.call(func));
+ && /^(?:class\b|constructor\()/.test(stringifyFn(func));
}
function invoke(fn, self, locals, serviceName) {
@@ -4696,7 +4789,7 @@ function $AnchorScrollProvider() {
* When called, it scrolls to the element related to the specified `hash` or (if omitted) to the
* current value of {@link ng.$location#hash $location.hash()}, according to the rules specified
* in the
- * [HTML5 spec](http://www.w3.org/html/wg/drafts/html/master/browsers.html#the-indicated-part-of-the-document).
+ * [HTML5 spec](http://www.w3.org/html/wg/drafts/html/master/browsers.html#an-indicated-part-of-the-document).
*
* It also watches the {@link ng.$location#hash $location.hash()} and automatically scrolls to
* match any anchor whenever it changes. This can be disabled by calling
@@ -5252,6 +5345,9 @@ var $AnimateProvider = ['$provide', function($provide) {
* // remove all the animation event listeners listening for `enter`
* $animate.off('enter');
*
+ * // remove listeners for all animation events from the container element
+ * $animate.off(container);
+ *
* // remove all the animation event listeners listening for `enter` on the given element and its children
* $animate.off('enter', container);
*
@@ -5260,7 +5356,9 @@ var $AnimateProvider = ['$provide', function($provide) {
* $animate.off('enter', container, callback);
* ```
*
- * @param {string} event the animation event (e.g. enter, leave, move, addClass, removeClass, etc...)
+ * @param {string|DOMElement} event|container the animation event (e.g. enter, leave, move,
+ * addClass, removeClass, etc...), or the container element. If it is the element, all other
+ * arguments are ignored.
* @param {DOMElement=} container the container element the event listener was placed on
* @param {Function=} callback the callback function that was registered as the listener
*/
@@ -5341,7 +5439,13 @@ var $AnimateProvider = ['$provide', function($provide) {
* @param {DOMElement} parent the parent element which will append the element as
* a child (so long as the after element is not present)
* @param {DOMElement=} after the sibling element after which the element will be appended
- * @param {object=} options an optional collection of options/styles that will be applied to the element
+ * @param {object=} options an optional collection of options/styles that will be applied to the element.
+ * The object can have the following properties:
+ *
+ * - **addClass** - `{string}` - space-separated CSS classes to add to element
+ * - **from** - `{Object}` - CSS properties & values at the beginning of animation. Must have matching `to`
+ * - **removeClass** - `{string}` - space-separated CSS classes to remove from element
+ * - **to** - `{Object}` - CSS properties & values at end of animation. Must have matching `from`
*
* @return {Promise} the animation callback promise
*/
@@ -5367,7 +5471,13 @@ var $AnimateProvider = ['$provide', function($provide) {
* @param {DOMElement} parent the parent element which will append the element as
* a child (so long as the after element is not present)
* @param {DOMElement=} after the sibling element after which the element will be appended
- * @param {object=} options an optional collection of options/styles that will be applied to the element
+ * @param {object=} options an optional collection of options/styles that will be applied to the element.
+ * The object can have the following properties:
+ *
+ * - **addClass** - `{string}` - space-separated CSS classes to add to element
+ * - **from** - `{Object}` - CSS properties & values at the beginning of animation. Must have matching `to`
+ * - **removeClass** - `{string}` - space-separated CSS classes to remove from element
+ * - **to** - `{Object}` - CSS properties & values at end of animation. Must have matching `from`
*
* @return {Promise} the animation callback promise
*/
@@ -5388,7 +5498,13 @@ var $AnimateProvider = ['$provide', function($provide) {
* digest once the animation has completed.
*
* @param {DOMElement} element the element which will be removed from the DOM
- * @param {object=} options an optional collection of options/styles that will be applied to the element
+ * @param {object=} options an optional collection of options/styles that will be applied to the element.
+ * The object can have the following properties:
+ *
+ * - **addClass** - `{string}` - space-separated CSS classes to add to element
+ * - **from** - `{Object}` - CSS properties & values at the beginning of animation. Must have matching `to`
+ * - **removeClass** - `{string}` - space-separated CSS classes to remove from element
+ * - **to** - `{Object}` - CSS properties & values at end of animation. Must have matching `from`
*
* @return {Promise} the animation callback promise
*/
@@ -5412,7 +5528,13 @@ var $AnimateProvider = ['$provide', function($provide) {
*
* @param {DOMElement} element the element which the CSS classes will be applied to
* @param {string} className the CSS class(es) that will be added (multiple classes are separated via spaces)
- * @param {object=} options an optional collection of options/styles that will be applied to the element
+ * @param {object=} options an optional collection of options/styles that will be applied to the element.
+ * The object can have the following properties:
+ *
+ * - **addClass** - `{string}` - space-separated CSS classes to add to element
+ * - **from** - `{Object}` - CSS properties & values at the beginning of animation. Must have matching `to`
+ * - **removeClass** - `{string}` - space-separated CSS classes to remove from element
+ * - **to** - `{Object}` - CSS properties & values at end of animation. Must have matching `from`
*
* @return {Promise} the animation callback promise
*/
@@ -5436,7 +5558,13 @@ var $AnimateProvider = ['$provide', function($provide) {
*
* @param {DOMElement} element the element which the CSS classes will be applied to
* @param {string} className the CSS class(es) that will be removed (multiple classes are separated via spaces)
- * @param {object=} options an optional collection of options/styles that will be applied to the element
+ * @param {object=} options an optional collection of options/styles that will be applied to the element.
+ * The object can have the following properties:
+ *
+ * - **addClass** - `{string}` - space-separated CSS classes to add to element
+ * - **from** - `{Object}` - CSS properties & values at the beginning of animation. Must have matching `to`
+ * - **removeClass** - `{string}` - space-separated CSS classes to remove from element
+ * - **to** - `{Object}` - CSS properties & values at end of animation. Must have matching `from`
*
* @return {Promise} the animation callback promise
*/
@@ -5461,7 +5589,13 @@ var $AnimateProvider = ['$provide', function($provide) {
* @param {DOMElement} element the element which the CSS classes will be applied to
* @param {string} add the CSS class(es) that will be added (multiple classes are separated via spaces)
* @param {string} remove the CSS class(es) that will be removed (multiple classes are separated via spaces)
- * @param {object=} options an optional collection of options/styles that will be applied to the element
+ * @param {object=} options an optional collection of options/styles that will be applied to the element.
+ * The object can have the following properties:
+ *
+ * - **addClass** - `{string}` - space-separated CSS classes to add to element
+ * - **from** - `{Object}` - CSS properties & values at the beginning of animation. Must have matching `to`
+ * - **removeClass** - `{string}` - space-separated CSS classes to remove from element
+ * - **to** - `{Object}` - CSS properties & values at end of animation. Must have matching `from`
*
* @return {Promise} the animation callback promise
*/
@@ -5502,7 +5636,13 @@ var $AnimateProvider = ['$provide', function($provide) {
* @param {string=} className an optional CSS class that will be applied to the element for the duration of the animation. If
* this value is left as empty then a CSS class of `ng-inline-animate` will be applied to the element.
* (Note that if no animation is detected then this value will not be applied to the element.)
- * @param {object=} options an optional collection of options/styles that will be applied to the element
+ * @param {object=} options an optional collection of options/styles that will be applied to the element.
+ * The object can have the following properties:
+ *
+ * - **addClass** - `{string}` - space-separated CSS classes to add to element
+ * - **from** - `{Object}` - CSS properties & values at the beginning of animation. Must have matching `to`
+ * - **removeClass** - `{string}` - space-separated CSS classes to remove from element
+ * - **to** - `{Object}` - CSS properties & values at end of animation. Must have matching `from`
*
* @return {Promise} the animation callback promise
*/
@@ -5929,7 +6069,7 @@ function Browser(window, document, $log, $sniffer) {
// Do the assignment again so that those two variables are referentially identical.
lastHistoryState = cachedState;
} else {
- if (!sameBase || pendingLocation) {
+ if (!sameBase) {
pendingLocation = url;
}
if (replace) {
@@ -5943,6 +6083,9 @@ function Browser(window, document, $log, $sniffer) {
pendingLocation = url;
}
}
+ if (pendingLocation) {
+ pendingLocation = url;
+ }
return self;
// getter
} else {
@@ -6587,8 +6730,9 @@ function $TemplateCacheProvider() {
* There are many different options for a directive.
*
* The difference resides in the return value of the factory function.
- * You can either return a "Directive Definition Object" (see below) that defines the directive properties,
- * or just the `postLink` function (all other properties will have the default values).
+ * You can either return a {@link $compile#directive-definition-object Directive Definition Object (see below)}
+ * that defines the directive properties, or just the `postLink` function (all other properties will have
+ * the default values).
*
*
* **Best Practice:** It's recommended to use the "directive definition object" form.
@@ -6652,6 +6796,125 @@ function $TemplateCacheProvider() {
* });
* ```
*
+ * ### Life-cycle hooks
+ * Directive controllers can provide the following methods that are called by Angular at points in the life-cycle of the
+ * directive:
+ * * `$onInit()` - Called on each controller after all the controllers on an element have been constructed and
+ * had their bindings initialized (and before the pre & post linking functions for the directives on
+ * this element). This is a good place to put initialization code for your controller.
+ * * `$onChanges(changesObj)` - Called whenever one-way (`<`) or interpolation (`@`) bindings are updated. The
+ * `changesObj` is a hash whose keys are the names of the bound properties that have changed, and the values are an
+ * object of the form `{ currentValue, previousValue, isFirstChange() }`. Use this hook to trigger updates within a
+ * component such as cloning the bound value to prevent accidental mutation of the outer value.
+ * * `$doCheck()` - Called on each turn of the digest cycle. Provides an opportunity to detect and act on
+ * changes. Any actions that you wish to take in response to the changes that you detect must be
+ * invoked from this hook; implementing this has no effect on when `$onChanges` is called. For example, this hook
+ * could be useful if you wish to perform a deep equality check, or to check a Date object, changes to which would not
+ * be detected by Angular's change detector and thus not trigger `$onChanges`. This hook is invoked with no arguments;
+ * if detecting changes, you must store the previous value(s) for comparison to the current values.
+ * * `$onDestroy()` - Called on a controller when its containing scope is destroyed. Use this hook for releasing
+ * external resources, watches and event handlers. Note that components have their `$onDestroy()` hooks called in
+ * the same order as the `$scope.$broadcast` events are triggered, which is top down. This means that parent
+ * components will have their `$onDestroy()` hook called before child components.
+ * * `$postLink()` - Called after this controller's element and its children have been linked. Similar to the post-link
+ * function this hook can be used to set up DOM event handlers and do direct DOM manipulation.
+ * Note that child elements that contain `templateUrl` directives will not have been compiled and linked since
+ * they are waiting for their template to load asynchronously and their own compilation and linking has been
+ * suspended until that occurs.
+ *
+ * #### Comparison with Angular 2 life-cycle hooks
+ * Angular 2 also uses life-cycle hooks for its components. While the Angular 1 life-cycle hooks are similar there are
+ * some differences that you should be aware of, especially when it comes to moving your code from Angular 1 to Angular 2:
+ *
+ * * Angular 1 hooks are prefixed with `$`, such as `$onInit`. Angular 2 hooks are prefixed with `ng`, such as `ngOnInit`.
+ * * Angular 1 hooks can be defined on the controller prototype or added to the controller inside its constructor.
+ * In Angular 2 you can only define hooks on the prototype of the Component class.
+ * * Due to the differences in change-detection, you may get many more calls to `$doCheck` in Angular 1 than you would to
+ * `ngDoCheck` in Angular 2
+ * * Changes to the model inside `$doCheck` will trigger new turns of the digest loop, which will cause the changes to be
+ * propagated throughout the application.
+ * Angular 2 does not allow the `ngDoCheck` hook to trigger a change outside of the component. It will either throw an
+ * error or do nothing depending upon the state of `enableProdMode()`.
+ *
+ * #### Life-cycle hook examples
+ *
+ * This example shows how you can check for mutations to a Date object even though the identity of the object
+ * has not changed.
+ *
+ *
+ *
+ * angular.module('do-check-module', [])
+ * .component('app', {
+ * template:
+ * 'Month: ' +
+ * 'Date: {{ $ctrl.date }}' +
+ * '',
+ * controller: function() {
+ * this.date = new Date();
+ * this.month = this.date.getMonth();
+ * this.updateDate = function() {
+ * this.date.setMonth(this.month);
+ * };
+ * }
+ * })
+ * .component('test', {
+ * bindings: { date: '<' },
+ * template:
+ * '
{{ $ctrl.log | json }}
',
+ * controller: function() {
+ * var previousValue;
+ * this.log = [];
+ * this.$doCheck = function() {
+ * var currentValue = this.date && this.date.valueOf();
+ * if (previousValue !== currentValue) {
+ * this.log.push('doCheck: date mutated: ' + this.date);
+ * previousValue = currentValue;
+ * }
+ * };
+ * }
+ * });
+ *
+ *
+ *
+ *
+ *
+ *
+ * This example show how you might use `$doCheck` to trigger changes in your component's inputs even if the
+ * actual identity of the component doesn't change. (Be aware that cloning and deep equality checks on large
+ * arrays or objects can have a negative impact on your application performance)
+ *
+ *
+ *
+ *
',
+ * controller: function() {
+ * this.log = [];
+ *
+ * this.$doCheck = function() {
+ * if (this.items_ref !== this.items) {
+ * this.log.push('doCheck: items changed');
+ * this.items_ref = this.items;
+ * }
+ * if (!angular.equals(this.items_clone, this.items)) {
+ * this.log.push('doCheck: items mutated');
+ * this.items_clone = angular.copy(this.items);
+ * }
+ * };
+ * }
+ * });
+ *
+ *
*
*
* ### Directive Definition Object
@@ -6827,25 +7090,6 @@ function $TemplateCacheProvider() {
* The `$transclude` function also has a method on it, `$transclude.isSlotFilled(slotName)`, which returns
* `true` if the specified slot contains content (i.e. one or more DOM nodes).
*
- * The controller can provide the following methods that act as life-cycle hooks:
- * * `$onInit()` - Called on each controller after all the controllers on an element have been constructed and
- * had their bindings initialized (and before the pre & post linking functions for the directives on
- * this element). This is a good place to put initialization code for your controller.
- * * `$onChanges(changesObj)` - Called whenever one-way (`<`) or interpolation (`@`) bindings are updated. The
- * `changesObj` is a hash whose keys are the names of the bound properties that have changed, and the values are an
- * object of the form `{ currentValue: ..., previousValue: ... }`. Use this hook to trigger updates within a component
- * such as cloning the bound value to prevent accidental mutation of the outer value.
- * * `$onDestroy()` - Called on a controller when its containing scope is destroyed. Use this hook for releasing
- * external resources, watches and event handlers. Note that components have their `$onDestroy()` hooks called in
- * the same order as the `$scope.$broadcast` events are triggered, which is top down. This means that parent
- * components will have their `$onDestroy()` hook called before child components.
- * * `$postLink()` - Called after this controller's element and its children have been linked. Similar to the post-link
- * function this hook can be used to set up DOM event handlers and do direct DOM manipulation.
- * Note that child elements that contain `templateUrl` directives will not have been compiled and linked since
- * they are waiting for their template to load asynchronously and their own compilation and linking has been
- * suspended until that occurs.
- *
- *
* #### `require`
* Require another directive and inject its controller as the fourth argument to the linking function. The
* `require` property can be a string, an array or an object:
@@ -6859,8 +7103,9 @@ function $TemplateCacheProvider() {
* If the `require` property is an object and `bindToController` is truthy, then the required controllers are
* bound to the controller using the keys of the `require` property. This binding occurs after all the controllers
* have been constructed but before `$onInit` is called.
+ * If the name of the required controller is the same as the local name (the key), the name can be
+ * omitted. For example, `{parentDir: '^^'}` is equivalent to `{parentDir: '^^parentDir'}`.
* See the {@link $compileProvider#component} helper for an example of how this can be used.
- *
* If no such required directive(s) can be found, or if the directive does not have a controller, then an error is
* raised (unless no link function is specified and the required controllers are not being bound to the directive
* controller, in which case error checking is skipped). The name can be prefixed with:
@@ -7042,8 +7287,8 @@ function $TemplateCacheProvider() {
* any other controller.
*
* * `transcludeFn` - A transclude linking function pre-bound to the correct transclusion scope.
- * This is the same as the `$transclude`
- * parameter of directive controllers, see there for details.
+ * This is the same as the `$transclude` parameter of directive controllers,
+ * see {@link ng.$compile#-controller- the controller section for details}.
* `function([scope], cloneLinkingFn, futureParentElement)`.
*
* #### Pre-linking function
@@ -7381,6 +7626,9 @@ function $TemplateCacheProvider() {
var $compileMinErr = minErr('$compile');
+function UNINITIALIZED_VALUE() {}
+var _UNINITIALIZED_VALUE = new UNINITIALIZED_VALUE();
+
/**
* @ngdoc provider
* @name $compileProvider
@@ -7405,7 +7653,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
function parseIsolateBindings(scope, directiveName, isController) {
var LOCAL_REGEXP = /^\s*([@&<]|=(\*?))(\??)\s*(\w*)\s*$/;
- var bindings = {};
+ var bindings = createMap();
forEach(scope, function(definition, scopeName) {
if (definition in bindingCache) {
@@ -7486,6 +7734,20 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
}
}
+ function getDirectiveRequire(directive) {
+ var require = directive.require || (directive.controller && directive.name);
+
+ if (!isArray(require) && isObject(require)) {
+ forEach(require, function(value, key) {
+ var match = value.match(REQUIRE_PREFIX_REGEXP);
+ var name = value.substring(match[0].length);
+ if (!name) require[key] = match[0] + key;
+ });
+ }
+
+ return require;
+ }
+
/**
* @ngdoc method
* @name $compileProvider#directive
@@ -7522,7 +7784,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
directive.priority = directive.priority || 0;
directive.index = index;
directive.name = directive.name || name;
- directive.require = directive.require || (directive.controller && directive.name);
+ directive.require = getDirectiveRequire(directive);
directive.restrict = directive.restrict || 'EA';
directive.$$moduleName = directiveFactory.$$moduleName;
directives.push(directive);
@@ -7579,6 +7841,9 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
* See {@link ng.$compile#-bindtocontroller- `bindToController`}.
* - `transclude` – `{boolean=}` – whether {@link $compile#transclusion content transclusion} is enabled.
* Disabled by default.
+ * - `require` - `{Object=}` - requires the controllers of other directives and binds them to
+ * this component's controller. The object keys specify the property names under which the required
+ * controllers (object values) will be bound. See {@link ng.$compile#-require- `require`}.
* - `$...` – additional properties to attach to the directive factory function and the controller
* constructor function. (This is used by the component router to annotate)
*
@@ -7624,7 +7889,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
* See also {@link ng.$compileProvider#directive $compileProvider.directive()}.
*/
this.component = function registerComponent(name, options) {
- var controller = options.controller || noop;
+ var controller = options.controller || function() {};
function factory($injector) {
function makeInjectable(fn) {
@@ -7638,7 +7903,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
}
var template = (!options.template && !options.templateUrl ? '' : options.template);
- return {
+ var ddo = {
controller: controller,
controllerAs: identifierForController(options.controller) || options.controllerAs || '$ctrl',
template: makeInjectable(template),
@@ -7649,14 +7914,27 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
restrict: 'E',
require: options.require
};
+
+ // Copy annotations (starting with $) over to the DDO
+ forEach(options, function(val, key) {
+ if (key.charAt(0) === '$') ddo[key] = val;
+ });
+
+ return ddo;
}
- // Copy any annotation properties (starting with $) over to the factory function
+ // TODO(pete) remove the following `forEach` before we release 1.6.0
+ // The component-router@0.2.0 looks for the annotations on the controller constructor
+ // Nothing in Angular looks for annotations on the factory function but we can't remove
+ // it from 1.5.x yet.
+
+ // Copy any annotation properties (starting with $) over to the factory and controller constructor functions
// These could be used by libraries such as the new component router
forEach(options, function(val, key) {
if (key.charAt(0) === '$') {
factory[key] = val;
- controller[key] = val;
+ // Don't try to copy over annotations to named controller
+ if (isFunction(controller)) controller[key] = val;
}
});
@@ -7793,7 +8071,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
$controller, $rootScope, $sce, $animate, $$sanitizeUri) {
var SIMPLE_ATTR_NAME = /^\w/;
- var specialAttrHolder = document.createElement('div');
+ var specialAttrHolder = window.document.createElement('div');
@@ -7812,11 +8090,19 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
}
// We must run this hook in an apply since the $$postDigest runs outside apply
$rootScope.$apply(function() {
+ var errors = [];
for (var i = 0, ii = onChangesQueue.length; i < ii; ++i) {
- onChangesQueue[i]();
+ try {
+ onChangesQueue[i]();
+ } catch (e) {
+ errors.push(e);
+ }
}
// Reset the queue to trigger a new schedule next time there is a change
onChangesQueue = undefined;
+ if (errors.length) {
+ throw errors;
+ }
});
} finally {
onChangesTtl++;
@@ -7963,7 +8249,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
(nodeName === 'img' && key === 'src')) {
// sanitize a[href] and img[src] values
this[key] = value = $$sanitizeUri(value, key === 'src');
- } else if (nodeName === 'img' && key === 'srcset') {
+ } else if (nodeName === 'img' && key === 'srcset' && isDefined(value)) {
// sanitize img[srcset] values
var result = "";
@@ -8122,9 +8408,10 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
compile.$$createComment = function(directiveName, comment) {
var content = '';
if (debugInfoEnabled) {
- content = ' ' + (directiveName || '') + ': ' + (comment || '') + ' ';
+ content = ' ' + (directiveName || '') + ': ';
+ if (comment) content += comment + ' ';
}
- return document.createComment(content);
+ return window.document.createComment(content);
};
return compile;
@@ -8147,7 +8434,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
var domNode = $compileNodes[i];
if (domNode.nodeType === NODE_TYPE_TEXT && domNode.nodeValue.match(NOT_EMPTY) /* non-empty */) {
- jqLiteWrapNode(domNode, $compileNodes[i] = document.createElement('span'));
+ jqLiteWrapNode(domNode, $compileNodes[i] = window.document.createElement('span'));
}
}
@@ -8456,19 +8743,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
addTextInterpolateDirective(directives, node.nodeValue);
break;
case NODE_TYPE_COMMENT: /* Comment */
- try {
- match = COMMENT_DIRECTIVE_REGEXP.exec(node.nodeValue);
- if (match) {
- nName = directiveNormalize(match[1]);
- if (addDirective(directives, nName, 'M', maxPriority, ignoreDirective)) {
- attrs[nName] = trim(match[2]);
- }
- }
- } catch (e) {
- // turns out that under some circumstances IE9 throws errors when one attempts to read
- // comment's node value.
- // Just ignore it and continue. (Can't seem to reproduce in test case.)
- }
+ collectCommentDirectives(node, directives, attrs, maxPriority, ignoreDirective);
break;
}
@@ -8476,6 +8751,24 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
return directives;
}
+ function collectCommentDirectives(node, directives, attrs, maxPriority, ignoreDirective) {
+ // function created because of performance, try/catch disables
+ // the optimization of the whole function #14848
+ try {
+ var match = COMMENT_DIRECTIVE_REGEXP.exec(node.nodeValue);
+ if (match) {
+ var nName = directiveNormalize(match[1]);
+ if (addDirective(directives, nName, 'M', maxPriority, ignoreDirective)) {
+ attrs[nName] = trim(match[2]);
+ }
+ }
+ } catch (e) {
+ // turns out that under some circumstances IE9 throws errors when one attempts to read
+ // comment's node value.
+ // Just ignore it and continue. (Can't seem to reproduce in test case.)
+ }
+ }
+
/**
* Given a node with an directive-start it collects all of the siblings until it finds
* directive-end.
@@ -8840,7 +9133,9 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
replaceDirective = directive;
}
+ /* jshint -W021 */
nodeLinkFn = compileTemplateUrl(directives.splice(i, directives.length - i), $compileNode,
+ /* jshint +W021 */
templateAttrs, jqCollection, hasTranscludeDirective && childTranscludeFn, preLinkFns, postLinkFns, {
controllerDirectives: controllerDirectives,
newScopeDirective: (newScopeDirective !== directive) && newScopeDirective,
@@ -8852,10 +9147,11 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
} else if (directive.compile) {
try {
linkFn = directive.compile($compileNode, templateAttrs, childTranscludeFn);
+ var context = directive.$$originalDirective || directive;
if (isFunction(linkFn)) {
- addLinkFns(null, linkFn, attrStart, attrEnd);
+ addLinkFns(null, bind(context, linkFn), attrStart, attrEnd);
} else if (linkFn) {
- addLinkFns(linkFn.pre, linkFn.post, attrStart, attrEnd);
+ addLinkFns(bind(context, linkFn.pre), bind(context, linkFn.post), attrStart, attrEnd);
}
} catch (e) {
$exceptionHandler(e, startingTag($compileNode));
@@ -8904,7 +9200,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
function nodeLinkFn(childLinkFn, scope, linkNode, $rootElement, boundTranscludeFn) {
var i, ii, linkFn, isolateScope, controllerScope, elementControllers, transcludeFn, $element,
- attrs, removeScopeBindingWatches, removeControllerBindingWatches;
+ attrs, scopeBindingInfo;
if (compileNode === linkNode) {
attrs = templateAttrs;
@@ -8943,11 +9239,11 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
compile.$$addScopeClass($element, true);
isolateScope.$$isolateBindings =
newIsolateScopeDirective.$$isolateBindings;
- removeScopeBindingWatches = initializeDirectiveBindings(scope, attrs, isolateScope,
+ scopeBindingInfo = initializeDirectiveBindings(scope, attrs, isolateScope,
isolateScope.$$isolateBindings,
newIsolateScopeDirective);
- if (removeScopeBindingWatches) {
- isolateScope.$on('$destroy', removeScopeBindingWatches);
+ if (scopeBindingInfo.removeWatches) {
+ isolateScope.$on('$destroy', scopeBindingInfo.removeWatches);
}
}
@@ -8958,8 +9254,10 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
var bindings = controllerDirective.$$bindings.bindToController;
if (controller.identifier && bindings) {
- removeControllerBindingWatches =
+ controller.bindingInfo =
initializeDirectiveBindings(controllerScope, attrs, controller.instance, bindings, controllerDirective);
+ } else {
+ controller.bindingInfo = {};
}
var controllerResult = controller();
@@ -8968,8 +9266,8 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
// from setupControllers
controller.instance = controllerResult;
$element.data('$' + controllerDirective.name + 'Controller', controllerResult);
- removeControllerBindingWatches && removeControllerBindingWatches();
- removeControllerBindingWatches =
+ controller.bindingInfo.removeWatches && controller.bindingInfo.removeWatches();
+ controller.bindingInfo =
initializeDirectiveBindings(controllerScope, attrs, controller.instance, bindings, controllerDirective);
}
}
@@ -8985,8 +9283,23 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
// Handle the init and destroy lifecycle hooks on all controllers that have them
forEach(elementControllers, function(controller) {
var controllerInstance = controller.instance;
+ if (isFunction(controllerInstance.$onChanges)) {
+ try {
+ controllerInstance.$onChanges(controller.bindingInfo.initialChanges);
+ } catch (e) {
+ $exceptionHandler(e);
+ }
+ }
if (isFunction(controllerInstance.$onInit)) {
- controllerInstance.$onInit();
+ try {
+ controllerInstance.$onInit();
+ } catch (e) {
+ $exceptionHandler(e);
+ }
+ }
+ if (isFunction(controllerInstance.$doCheck)) {
+ controllerScope.$watch(function() { controllerInstance.$doCheck(); });
+ controllerInstance.$doCheck();
}
if (isFunction(controllerInstance.$onDestroy)) {
controllerScope.$on('$destroy', function callOnDestroyHook() {
@@ -9250,18 +9563,16 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
// copy the new attributes on the old attrs object
forEach(src, function(value, key) {
- if (key == 'class') {
- safeAddClass($element, value);
- dst['class'] = (dst['class'] ? dst['class'] + ' ' : '') + value;
- } else if (key == 'style') {
- $element.attr('style', $element.attr('style') + ';' + value);
- dst['style'] = (dst['style'] ? dst['style'] + ';' : '') + value;
- // `dst` will never contain hasOwnProperty as DOM parser won't let it.
- // You will get an "InvalidCharacterError: DOM Exception 5" error if you
- // have an attribute like "has-own-property" or "data-has-own-property", etc.
- } else if (key.charAt(0) != '$' && !dst.hasOwnProperty(key)) {
+ // Check if we already set this attribute in the loop above.
+ // `dst` will never contain hasOwnProperty as DOM parser won't let it.
+ // You will get an "InvalidCharacterError: DOM Exception 5" error if you
+ // have an attribute like "has-own-property" or "data-has-own-property", etc.
+ if (!dst.hasOwnProperty(key) && key.charAt(0) !== '$') {
dst[key] = value;
- dstAttr[key] = srcAttr[key];
+
+ if (key !== 'class' && key !== 'style') {
+ dstAttr[key] = srcAttr[key];
+ }
}
});
}
@@ -9441,7 +9752,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
switch (type) {
case 'svg':
case 'math':
- var wrapper = document.createElement('div');
+ var wrapper = window.document.createElement('div');
wrapper.innerHTML = '<' + type + '>' + template + '' + type + '>';
return wrapper.childNodes[0].childNodes;
default:
@@ -9585,7 +9896,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
// - remove them from the DOM
// - allow them to still be traversed with .nextSibling
// - allow a single fragment.qSA to fetch all elements being removed
- var fragment = document.createDocumentFragment();
+ var fragment = window.document.createDocumentFragment();
for (i = 0; i < removeCount; i++) {
fragment.appendChild(elementsToRemove[i]);
}
@@ -9631,11 +9942,12 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
// only occurs for isolate scopes and new scopes with controllerAs.
function initializeDirectiveBindings(scope, attrs, destination, bindings, directive) {
var removeWatchCollection = [];
+ var initialChanges = {};
var changes;
forEach(bindings, function initializeBinding(definition, scopeName) {
var attrName = definition.attrName,
optional = definition.optional,
- mode = definition.mode, // @, =, or &
+ mode = definition.mode, // @, =, <, or &
lastValue,
parentGet, parentSet, compare, removeWatch;
@@ -9646,7 +9958,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
destination[scopeName] = attrs[attrName] = void 0;
}
attrs.$observe(attrName, function(value) {
- if (isString(value)) {
+ if (isString(value) || isBoolean(value)) {
var oldValue = destination[scopeName];
recordChanges(scopeName, value, oldValue);
destination[scopeName] = value;
@@ -9663,6 +9975,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
// the value to boolean rather than a string, so we special case this situation
destination[scopeName] = lastValue;
}
+ initialChanges[scopeName] = new SimpleChange(_UNINITIALIZED_VALUE, destination[scopeName]);
break;
case '=':
@@ -9717,12 +10030,16 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
parentGet = $parse(attrs[attrName]);
- destination[scopeName] = parentGet(scope);
+ var initialValue = destination[scopeName] = parentGet(scope);
+ initialChanges[scopeName] = new SimpleChange(_UNINITIALIZED_VALUE, destination[scopeName]);
- removeWatch = scope.$watch(parentGet, function parentValueWatchAction(newParentValue) {
- var oldValue = destination[scopeName];
- recordChanges(scopeName, newParentValue, oldValue);
- destination[scopeName] = newParentValue;
+ removeWatch = scope.$watch(parentGet, function parentValueWatchAction(newValue, oldValue) {
+ if (oldValue === newValue) {
+ if (oldValue === initialValue) return;
+ oldValue = initialValue;
+ }
+ recordChanges(scopeName, newValue, oldValue);
+ destination[scopeName] = newValue;
}, parentGet.literal);
removeWatchCollection.push(removeWatch);
@@ -9759,7 +10076,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
previousValue = changes[key].previousValue;
}
// Store this change
- changes[key] = {previousValue: previousValue, currentValue: currentValue};
+ changes[key] = new SimpleChange(previousValue, currentValue);
}
}
@@ -9769,15 +10086,25 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
changes = undefined;
}
- return removeWatchCollection.length && function removeWatches() {
- for (var i = 0, ii = removeWatchCollection.length; i < ii; ++i) {
- removeWatchCollection[i]();
+ return {
+ initialChanges: initialChanges,
+ removeWatches: removeWatchCollection.length && function removeWatches() {
+ for (var i = 0, ii = removeWatchCollection.length; i < ii; ++i) {
+ removeWatchCollection[i]();
+ }
}
};
}
}];
}
+function SimpleChange(previous, current) {
+ this.previousValue = previous;
+ this.currentValue = current;
+}
+SimpleChange.prototype.isFirstChange = function() { return this.previousValue === _UNINITIALIZED_VALUE; };
+
+
var PREFIX_REGEXP = /^((?:x|data)[\:\-_])/i;
/**
* Converts all accepted directives format into proper directive name.
@@ -10106,17 +10433,20 @@ function $DocumentProvider() {
*
* ## Example:
*
- * ```js
- * angular.module('exceptionOverride', []).factory('$exceptionHandler', function() {
- * return function(exception, cause) {
- * exception.message += ' (caused by "' + cause + '")';
- * throw exception;
- * };
- * });
- * ```
+ * The example below will overwrite the default `$exceptionHandler` in order to (a) log uncaught
+ * errors to the backend for later inspection by the developers and (b) to use `$log.warn()` instead
+ * of `$log.error()`.
*
- * This example will override the normal action of `$exceptionHandler`, to make angular
- * exceptions fail hard when they happen, instead of just logging to the console.
+ * ```js
+ * angular.
+ * module('exceptionOverwrite', []).
+ * factory('$exceptionHandler', ['$log', 'logErrorsToBackend', function($log, logErrorsToBackend) {
+ * return function myExceptionHandler(exception, cause) {
+ * logErrorsToBackend(exception, cause);
+ * $log.warn(exception, cause);
+ * };
+ * }]);
+ * ```
*
*
* Note, that code executed in event-listeners (even those registered using jqLite's `on`/`bind`
@@ -10127,7 +10457,7 @@ function $DocumentProvider() {
* `try { ... } catch(e) { $exceptionHandler(e); }`
*
* @param {Error} exception Exception associated with the error.
- * @param {string=} cause optional information about the context in which
+ * @param {string=} cause Optional information about the context in which
* the error was thrown.
*
*/
@@ -10197,7 +10527,7 @@ function $HttpParamSerializerProvider() {
* * `{'foo': 'bar'}` results in `foo=bar`
* * `{'foo': Date.now()}` results in `foo=2015-04-01T09%3A50%3A49.262Z` (`toISOString()` and encoded representation of a Date object)
* * `{'foo': ['bar', 'baz']}` results in `foo=bar&foo=baz` (repeated key for each array element)
- * * `{'foo': {'bar':'baz'}}` results in `foo=%7B%22bar%22%3A%22baz%22%7D"` (stringified and encoded representation of an object)
+ * * `{'foo': {'bar':'baz'}}` results in `foo=%7B%22bar%22%3A%22baz%22%7D` (stringified and encoded representation of an object)
*
* Note that serializer will sort the request parameters alphabetically.
* */
@@ -10612,10 +10942,13 @@ function $HttpProvider() {
* - **config** – `{Object}` – The configuration object that was used to generate the request.
* - **statusText** – `{string}` – HTTP status text of the response.
*
- * A response status code between 200 and 299 is considered a success status and
- * will result in the success callback being called. Note that if the response is a redirect,
- * XMLHttpRequest will transparently follow it, meaning that the error callback will not be
- * called for such responses.
+ * A response status code between 200 and 299 is considered a success status and will result in
+ * the success callback being called. Any response status code outside of that range is
+ * considered an error status and will result in the error callback being called.
+ * Also, status codes less than -1 are normalized to zero. -1 usually means the request was
+ * aborted, e.g. using a `config.timeout`.
+ * Note that if the response is a redirect, XMLHttpRequest will transparently follow it, meaning
+ * that the outcome (success or error) will be determined by the final response status code.
*
*
* ## Shortcut methods
@@ -10717,7 +11050,7 @@ function $HttpProvider() {
* That means changes to the properties of `data` are not local to the transform function (since Javascript passes objects by reference).
* For example, when calling `$http.get(url, $scope.myObject)`, modifications to the object's properties in a transformRequest
* function will be reflected on the scope and in any templates where the object is data-bound.
- * To prevent his, transform functions should have no side-effects.
+ * To prevent this, transform functions should have no side-effects.
* If you need to modify properties, it is recommended to make a copy of the data, or create new object to return.
*
*
@@ -10745,7 +11078,7 @@ function $HttpProvider() {
*
* ### Overriding the Default Transformations Per Request
*
- * If you wish override the request/response transformations only for a single request then provide
+ * If you wish to override the request/response transformations only for a single request then provide
* `transformRequest` and/or `transformResponse` properties on the configuration object passed
* into `$http`.
*
@@ -10788,7 +11121,7 @@ function $HttpProvider() {
* * cache a specific response - set config.cache value to TRUE or to a cache object
*
* If caching is enabled, but neither the default cache nor config.cache are set to a cache object,
- * then the default `$cacheFactory($http)` object is used.
+ * then the default `$cacheFactory("$http")` object is used.
*
* The default cache value can be set by updating the
* {@link ng.$http#defaults `$http.defaults.cache`} property or the
@@ -10963,6 +11296,12 @@ function $HttpProvider() {
* - **headers** – `{Object}` – Map of strings or functions which return strings representing
* HTTP headers to send to the server. If the return value of a function is null, the
* header will not be sent. Functions accept a config object as an argument.
+ * - **eventHandlers** - `{Object}` - Event listeners to be bound to the XMLHttpRequest object.
+ * To bind events to the XMLHttpRequest upload object, use `uploadEventHandlers`.
+ * The handler will be called in the context of a `$apply` block.
+ * - **uploadEventHandlers** - `{Object}` - Event listeners to be bound to the XMLHttpRequest upload
+ * object. To bind events to the XMLHttpRequest object, use `eventHandlers`.
+ * The handler will be called in the context of a `$apply` block.
* - **xsrfHeaderName** – `{string}` – Name of HTTP header to populate with the XSRF token.
* - **xsrfCookieName** – `{string}` – Name of cookie containing the XSRF token.
* - **transformRequest** –
@@ -11110,48 +11449,25 @@ function $HttpProvider() {
config.headers = mergeHeaders(requestConfig);
config.method = uppercase(config.method);
config.paramSerializer = isString(config.paramSerializer) ?
- $injector.get(config.paramSerializer) : config.paramSerializer;
+ $injector.get(config.paramSerializer) : config.paramSerializer;
- var serverRequest = function(config) {
- var headers = config.headers;
- var reqData = transformData(config.data, headersGetter(headers), undefined, config.transformRequest);
-
- // strip content-type if data is undefined
- if (isUndefined(reqData)) {
- forEach(headers, function(value, header) {
- if (lowercase(header) === 'content-type') {
- delete headers[header];
- }
- });
- }
-
- if (isUndefined(config.withCredentials) && !isUndefined(defaults.withCredentials)) {
- config.withCredentials = defaults.withCredentials;
- }
-
- // send request
- return sendReq(config, reqData).then(transformResponse, transformResponse);
- };
-
- var chain = [serverRequest, undefined];
+ var requestInterceptors = [];
+ var responseInterceptors = [];
var promise = $q.when(config);
// apply interceptors
forEach(reversedInterceptors, function(interceptor) {
if (interceptor.request || interceptor.requestError) {
- chain.unshift(interceptor.request, interceptor.requestError);
+ requestInterceptors.unshift(interceptor.request, interceptor.requestError);
}
if (interceptor.response || interceptor.responseError) {
- chain.push(interceptor.response, interceptor.responseError);
+ responseInterceptors.push(interceptor.response, interceptor.responseError);
}
});
- while (chain.length) {
- var thenFn = chain.shift();
- var rejectFn = chain.shift();
-
- promise = promise.then(thenFn, rejectFn);
- }
+ promise = chainInterceptors(promise, requestInterceptors);
+ promise = promise.then(serverRequest);
+ promise = chainInterceptors(promise, responseInterceptors);
if (useLegacyPromise) {
promise.success = function(fn) {
@@ -11178,14 +11494,18 @@ function $HttpProvider() {
return promise;
- function transformResponse(response) {
- // make a copy since the response must be cacheable
- var resp = extend({}, response);
- resp.data = transformData(response.data, response.headers, response.status,
- config.transformResponse);
- return (isSuccess(response.status))
- ? resp
- : $q.reject(resp);
+
+ function chainInterceptors(promise, interceptors) {
+ for (var i = 0, ii = interceptors.length; i < ii;) {
+ var thenFn = interceptors[i++];
+ var rejectFn = interceptors[i++];
+
+ promise = promise.then(thenFn, rejectFn);
+ }
+
+ interceptors.length = 0;
+
+ return promise;
}
function executeHeaderFns(headers, config) {
@@ -11229,6 +11549,37 @@ function $HttpProvider() {
// execute if header value is a function for merged headers
return executeHeaderFns(reqHeaders, shallowCopy(config));
}
+
+ function serverRequest(config) {
+ var headers = config.headers;
+ var reqData = transformData(config.data, headersGetter(headers), undefined, config.transformRequest);
+
+ // strip content-type if data is undefined
+ if (isUndefined(reqData)) {
+ forEach(headers, function(value, header) {
+ if (lowercase(header) === 'content-type') {
+ delete headers[header];
+ }
+ });
+ }
+
+ if (isUndefined(config.withCredentials) && !isUndefined(defaults.withCredentials)) {
+ config.withCredentials = defaults.withCredentials;
+ }
+
+ // send request
+ return sendReq(config, reqData).then(transformResponse, transformResponse);
+ }
+
+ function transformResponse(response) {
+ // make a copy since the response must be cacheable
+ var resp = extend({}, response);
+ resp.data = transformData(response.data, response.headers, response.status,
+ config.transformResponse);
+ return (isSuccess(response.status))
+ ? resp
+ : $q.reject(resp);
+ }
}
$http.pendingRequests = [];
@@ -11275,6 +11626,8 @@ function $HttpProvider() {
*
* @description
* Shortcut method to perform `JSONP` request.
+ * If you would like to customise where and how the callbacks are stored then try overriding
+ * or decorating the {@link $jsonpCallbacks} service.
*
* @param {string} url Relative or absolute URL specifying the destination of the request.
* The name of the callback should be the string `JSON_CALLBACK`.
@@ -11421,11 +11774,35 @@ function $HttpProvider() {
}
$httpBackend(config.method, url, reqData, done, reqHeaders, config.timeout,
- config.withCredentials, config.responseType);
+ config.withCredentials, config.responseType,
+ createApplyHandlers(config.eventHandlers),
+ createApplyHandlers(config.uploadEventHandlers));
}
return promise;
+ function createApplyHandlers(eventHandlers) {
+ if (eventHandlers) {
+ var applyHandlers = {};
+ forEach(eventHandlers, function(eventHandler, key) {
+ applyHandlers[key] = function(event) {
+ if (useApplyAsync) {
+ $rootScope.$applyAsync(callEventHandler);
+ } else if ($rootScope.$$phase) {
+ callEventHandler();
+ } else {
+ $rootScope.$apply(callEventHandler);
+ }
+
+ function callEventHandler() {
+ eventHandler(event);
+ }
+ };
+ });
+ return applyHandlers;
+ }
+ }
+
/**
* Callback registered to $httpBackend():
@@ -11524,7 +11901,7 @@ function $xhrFactoryProvider() {
/**
* @ngdoc service
* @name $httpBackend
- * @requires $window
+ * @requires $jsonpCallbacks
* @requires $document
* @requires $xhrFactory
*
@@ -11539,28 +11916,24 @@ function $xhrFactoryProvider() {
* $httpBackend} which can be trained with responses.
*/
function $HttpBackendProvider() {
- this.$get = ['$browser', '$window', '$document', '$xhrFactory', function($browser, $window, $document, $xhrFactory) {
- return createHttpBackend($browser, $xhrFactory, $browser.defer, $window.angular.callbacks, $document[0]);
+ this.$get = ['$browser', '$jsonpCallbacks', '$document', '$xhrFactory', function($browser, $jsonpCallbacks, $document, $xhrFactory) {
+ return createHttpBackend($browser, $xhrFactory, $browser.defer, $jsonpCallbacks, $document[0]);
}];
}
function createHttpBackend($browser, createXhr, $browserDefer, callbacks, rawDocument) {
// TODO(vojta): fix the signature
- return function(method, url, post, callback, headers, timeout, withCredentials, responseType) {
+ return function(method, url, post, callback, headers, timeout, withCredentials, responseType, eventHandlers, uploadEventHandlers) {
$browser.$$incOutstandingRequestCount();
url = url || $browser.url();
- if (lowercase(method) == 'jsonp') {
- var callbackId = '_' + (callbacks.counter++).toString(36);
- callbacks[callbackId] = function(data) {
- callbacks[callbackId].data = data;
- callbacks[callbackId].called = true;
- };
-
- var jsonpDone = jsonpReq(url.replace('JSON_CALLBACK', 'angular.callbacks.' + callbackId),
- callbackId, function(status, text) {
- completeRequest(callback, status, callbacks[callbackId].data, "", text);
- callbacks[callbackId] = noop;
+ if (lowercase(method) === 'jsonp') {
+ var callbackPath = callbacks.createCallback(url);
+ var jsonpDone = jsonpReq(url, callbackPath, function(status, text) {
+ // jsonpReq only ever sets status to 200 (OK), 404 (ERROR) or -1 (WAITING)
+ var response = (status === 200) && callbacks.getResponse(callbackPath);
+ completeRequest(callback, status, response, "", text);
+ callbacks.removeCallback(callbackPath);
});
} else {
@@ -11606,6 +11979,14 @@ function createHttpBackend($browser, createXhr, $browserDefer, callbacks, rawDoc
xhr.onerror = requestError;
xhr.onabort = requestError;
+ forEach(eventHandlers, function(value, key) {
+ xhr.addEventListener(key, value);
+ });
+
+ forEach(uploadEventHandlers, function(value, key) {
+ xhr.upload.addEventListener(key, value);
+ });
+
if (withCredentials) {
xhr.withCredentials = true;
}
@@ -11654,7 +12035,8 @@ function createHttpBackend($browser, createXhr, $browserDefer, callbacks, rawDoc
}
};
- function jsonpReq(url, callbackId, done) {
+ function jsonpReq(url, callbackPath, done) {
+ url = url.replace('JSON_CALLBACK', callbackPath);
// we can't use jQuery/jqLite here because jQuery does crazy stuff with script elements, e.g.:
// - fetches local scripts via XHR and evals them
// - adds and immediately removes script elements from the document
@@ -11672,7 +12054,7 @@ function createHttpBackend($browser, createXhr, $browserDefer, callbacks, rawDoc
var text = "unknown";
if (event) {
- if (event.type === "load" && !callbacks[callbackId].called) {
+ if (event.type === "load" && !callbacks.wasCalled(callbackPath)) {
event = { type: "error" };
}
text = event.type;
@@ -11871,7 +12253,7 @@ function $InterpolateProvider() {
*
* `allOrNothing` is useful for interpolating URLs. `ngSrc` and `ngSrcset` use this behavior.
*
- * ####Escaped Interpolation
+ * #### Escaped Interpolation
* $interpolate provides a mechanism for escaping interpolation markers. Start and end markers
* can be escaped by preceding each of their characters with a REVERSE SOLIDUS U+005C (backslash).
* It will be rendered as a regular start/end marker, and will not be interpreted as an expression
@@ -11907,6 +12289,30 @@ function $InterpolateProvider() {
*
*
*
+ * @knownIssue
+ * It is currently not possible for an interpolated expression to contain the interpolation end
+ * symbol. For example, `{{ '}}' }}` will be incorrectly interpreted as `{{ ' }}` + `' }}`, i.e.
+ * an interpolated expression consisting of a single-quote (`'`) and the `' }}` string.
+ *
+ * @knownIssue
+ * All directives and components must use the standard `{{` `}}` interpolation symbols
+ * in their templates. If you change the application interpolation symbols the {@link $compile}
+ * service will attempt to denormalize the standard symbols to the custom symbols.
+ * The denormalization process is not clever enough to know not to replace instances of the standard
+ * symbols where they would not normally be treated as interpolation symbols. For example in the following
+ * code snippet the closing braces of the literal object will get incorrectly denormalized:
+ *
+ * ```
+ *
+ * ```
+ *
+ * See https://github.com/angular/angular.js/pull/14610#issuecomment-219401099 for more information.
+ *
* @param {string} text The text with markup to interpolate.
* @param {boolean=} mustHaveExpression if set to true then the interpolation string must have
* embedded expression in order to return an interpolation function. Strings with no
@@ -12270,6 +12676,87 @@ function $IntervalProvider() {
}];
}
+/**
+ * @ngdoc service
+ * @name $jsonpCallbacks
+ * @requires $window
+ * @description
+ * This service handles the lifecycle of callbacks to handle JSONP requests.
+ * Override this service if you wish to customise where the callbacks are stored and
+ * how they vary compared to the requested url.
+ */
+var $jsonpCallbacksProvider = function() {
+ this.$get = ['$window', function($window) {
+ var callbacks = $window.angular.callbacks;
+ var callbackMap = {};
+
+ function createCallback(callbackId) {
+ var callback = function(data) {
+ callback.data = data;
+ callback.called = true;
+ };
+ callback.id = callbackId;
+ return callback;
+ }
+
+ return {
+ /**
+ * @ngdoc method
+ * @name $jsonpCallbacks#createCallback
+ * @param {string} url the url of the JSONP request
+ * @returns {string} the callback path to send to the server as part of the JSONP request
+ * @description
+ * {@link $httpBackend} calls this method to create a callback and get hold of the path to the callback
+ * to pass to the server, which will be used to call the callback with its payload in the JSONP response.
+ */
+ createCallback: function(url) {
+ var callbackId = '_' + (callbacks.$$counter++).toString(36);
+ var callbackPath = 'angular.callbacks.' + callbackId;
+ var callback = createCallback(callbackId);
+ callbackMap[callbackPath] = callbacks[callbackId] = callback;
+ return callbackPath;
+ },
+ /**
+ * @ngdoc method
+ * @name $jsonpCallbacks#wasCalled
+ * @param {string} callbackPath the path to the callback that was sent in the JSONP request
+ * @returns {boolean} whether the callback has been called, as a result of the JSONP response
+ * @description
+ * {@link $httpBackend} calls this method to find out whether the JSONP response actually called the
+ * callback that was passed in the request.
+ */
+ wasCalled: function(callbackPath) {
+ return callbackMap[callbackPath].called;
+ },
+ /**
+ * @ngdoc method
+ * @name $jsonpCallbacks#getResponse
+ * @param {string} callbackPath the path to the callback that was sent in the JSONP request
+ * @returns {*} the data received from the response via the registered callback
+ * @description
+ * {@link $httpBackend} calls this method to get hold of the data that was provided to the callback
+ * in the JSONP response.
+ */
+ getResponse: function(callbackPath) {
+ return callbackMap[callbackPath].data;
+ },
+ /**
+ * @ngdoc method
+ * @name $jsonpCallbacks#removeCallback
+ * @param {string} callbackPath the path to the callback that was sent in the JSONP request
+ * @description
+ * {@link $httpBackend} calls this method to remove the callback after the JSONP request has
+ * completed or timed-out.
+ */
+ removeCallback: function(callbackPath) {
+ var callback = callbackMap[callbackPath];
+ delete callbacks[callback.id];
+ delete callbackMap[callbackPath];
+ }
+ };
+ }];
+};
+
/**
* @ngdoc service
* @name $locale
@@ -12329,17 +12816,20 @@ function parseAppUrl(relativeUrl, locationObj) {
}
}
+function startsWith(haystack, needle) {
+ return haystack.lastIndexOf(needle, 0) === 0;
+}
/**
*
- * @param {string} begin
- * @param {string} whole
- * @returns {string} returns text from whole after begin or undefined if it does not begin with
- * expected string.
+ * @param {string} base
+ * @param {string} url
+ * @returns {string} returns text from `url` after `base` or `undefined` if it does not begin with
+ * the expected string.
*/
-function beginsWith(begin, whole) {
- if (whole.indexOf(begin) === 0) {
- return whole.substr(begin.length);
+function stripBaseUrl(base, url) {
+ if (startsWith(url, base)) {
+ return url.substr(base.length);
}
}
@@ -12385,7 +12875,7 @@ function LocationHtml5Url(appBase, appBaseNoFile, basePrefix) {
* @private
*/
this.$$parse = function(url) {
- var pathUrl = beginsWith(appBaseNoFile, url);
+ var pathUrl = stripBaseUrl(appBaseNoFile, url);
if (!isString(pathUrl)) {
throw $locationMinErr('ipthprfx', 'Invalid url "{0}", missing path prefix "{1}".', url,
appBaseNoFile);
@@ -12422,14 +12912,14 @@ function LocationHtml5Url(appBase, appBaseNoFile, basePrefix) {
var appUrl, prevAppUrl;
var rewrittenUrl;
- if (isDefined(appUrl = beginsWith(appBase, url))) {
+ if (isDefined(appUrl = stripBaseUrl(appBase, url))) {
prevAppUrl = appUrl;
- if (isDefined(appUrl = beginsWith(basePrefix, appUrl))) {
- rewrittenUrl = appBaseNoFile + (beginsWith('/', appUrl) || appUrl);
+ if (isDefined(appUrl = stripBaseUrl(basePrefix, appUrl))) {
+ rewrittenUrl = appBaseNoFile + (stripBaseUrl('/', appUrl) || appUrl);
} else {
rewrittenUrl = appBase + prevAppUrl;
}
- } else if (isDefined(appUrl = beginsWith(appBaseNoFile, url))) {
+ } else if (isDefined(appUrl = stripBaseUrl(appBaseNoFile, url))) {
rewrittenUrl = appBaseNoFile + appUrl;
} else if (appBaseNoFile == url + '/') {
rewrittenUrl = appBaseNoFile;
@@ -12463,14 +12953,14 @@ function LocationHashbangUrl(appBase, appBaseNoFile, hashPrefix) {
* @private
*/
this.$$parse = function(url) {
- var withoutBaseUrl = beginsWith(appBase, url) || beginsWith(appBaseNoFile, url);
+ var withoutBaseUrl = stripBaseUrl(appBase, url) || stripBaseUrl(appBaseNoFile, url);
var withoutHashUrl;
if (!isUndefined(withoutBaseUrl) && withoutBaseUrl.charAt(0) === '#') {
// The rest of the url starts with a hash so we have
// got either a hashbang path or a plain hash fragment
- withoutHashUrl = beginsWith(hashPrefix, withoutBaseUrl);
+ withoutHashUrl = stripBaseUrl(hashPrefix, withoutBaseUrl);
if (isUndefined(withoutHashUrl)) {
// There was no hashbang prefix so we just have a hash fragment
withoutHashUrl = withoutBaseUrl;
@@ -12518,7 +13008,7 @@ function LocationHashbangUrl(appBase, appBaseNoFile, hashPrefix) {
var firstPathSegmentMatch;
//Get the relative path from the input URL.
- if (url.indexOf(base) === 0) {
+ if (startsWith(url, base)) {
url = url.replace(base, '');
}
@@ -12581,7 +13071,7 @@ function LocationHashbangInHtml5Url(appBase, appBaseNoFile, hashPrefix) {
if (appBase == stripHash(url)) {
rewrittenUrl = url;
- } else if ((appUrl = beginsWith(appBaseNoFile, url))) {
+ } else if ((appUrl = stripBaseUrl(appBaseNoFile, url))) {
rewrittenUrl = appBase + hashPrefix + appUrl;
} else if (appBaseNoFile === url + '/') {
rewrittenUrl = appBaseNoFile;
@@ -12606,6 +13096,12 @@ function LocationHashbangInHtml5Url(appBase, appBaseNoFile, hashPrefix) {
var locationPrototype = {
+ /**
+ * Ensure absolute url is initialized.
+ * @private
+ */
+ $$absUrl:'',
+
/**
* Are we in html5 mode?
* @private
@@ -12763,7 +13259,7 @@ var locationPrototype = {
* ```
*
* @param {(string|number)=} path New path
- * @return {string} path
+ * @return {(string|object)} path if called with no parameters, or `$location` if called with a parameter
*/
path: locationGetterSetter('$$path', function(path) {
path = path !== null ? path.toString() : '';
@@ -13189,7 +13685,7 @@ function $LocationProvider() {
// update $location when $browser url changes
$browser.onUrlChange(function(newUrl, newState) {
- if (isUndefined(beginsWith(appBaseNoFile, newUrl))) {
+ if (isUndefined(stripBaseUrl(appBaseNoFile, newUrl))) {
// If we are navigating outside of the app then force a reload
$window.location.href = newUrl;
return;
@@ -13584,7 +14080,7 @@ Lexer.prototype = {
this.readString(ch);
} else if (this.isNumber(ch) || ch === '.' && this.isNumber(this.peek())) {
this.readNumber();
- } else if (this.isIdent(ch)) {
+ } else if (this.isIdentifierStart(this.peekMultichar())) {
this.readIdent();
} else if (this.is(ch, '(){}[].,;:?')) {
this.tokens.push({index: this.index, text: ch});
@@ -13628,12 +14124,49 @@ Lexer.prototype = {
ch === '\n' || ch === '\v' || ch === '\u00A0');
},
- isIdent: function(ch) {
+ isIdentifierStart: function(ch) {
+ return this.options.isIdentifierStart ?
+ this.options.isIdentifierStart(ch, this.codePointAt(ch)) :
+ this.isValidIdentifierStart(ch);
+ },
+
+ isValidIdentifierStart: function(ch) {
return ('a' <= ch && ch <= 'z' ||
'A' <= ch && ch <= 'Z' ||
'_' === ch || ch === '$');
},
+ isIdentifierContinue: function(ch) {
+ return this.options.isIdentifierContinue ?
+ this.options.isIdentifierContinue(ch, this.codePointAt(ch)) :
+ this.isValidIdentifierContinue(ch);
+ },
+
+ isValidIdentifierContinue: function(ch, cp) {
+ return this.isValidIdentifierStart(ch, cp) || this.isNumber(ch);
+ },
+
+ codePointAt: function(ch) {
+ if (ch.length === 1) return ch.charCodeAt(0);
+ /*jshint bitwise: false*/
+ return (ch.charCodeAt(0) << 10) + ch.charCodeAt(1) - 0x35FDC00;
+ /*jshint bitwise: true*/
+ },
+
+ peekMultichar: function() {
+ var ch = this.text.charAt(this.index);
+ var peek = this.peek();
+ if (!peek) {
+ return ch;
+ }
+ var cp1 = ch.charCodeAt(0);
+ var cp2 = peek.charCodeAt(0);
+ if (cp1 >= 0xD800 && cp1 <= 0xDBFF && cp2 >= 0xDC00 && cp2 <= 0xDFFF) {
+ return ch + peek;
+ }
+ return ch;
+ },
+
isExpOperator: function(ch) {
return (ch === '-' || ch === '+' || this.isNumber(ch));
},
@@ -13682,12 +14215,13 @@ Lexer.prototype = {
readIdent: function() {
var start = this.index;
+ this.index += this.peekMultichar().length;
while (this.index < this.text.length) {
- var ch = this.text.charAt(this.index);
- if (!(this.isIdent(ch) || this.isNumber(ch))) {
+ var ch = this.peekMultichar();
+ if (!this.isIdentifierContinue(ch)) {
break;
}
- this.index++;
+ this.index += ch.length;
}
this.tokens.push({
index: start,
@@ -13941,7 +14475,7 @@ AST.prototype = {
var args = [];
if (this.peekToken().text !== ')') {
do {
- args.push(this.expression());
+ args.push(this.filterChain());
} while (this.expect(','));
}
return args;
@@ -13987,13 +14521,28 @@ AST.prototype = {
property = {type: AST.Property, kind: 'init'};
if (this.peek().constant) {
property.key = this.constant();
+ property.computed = false;
+ this.consume(':');
+ property.value = this.expression();
} else if (this.peek().identifier) {
property.key = this.identifier();
+ property.computed = false;
+ if (this.peek(':')) {
+ this.consume(':');
+ property.value = this.expression();
+ } else {
+ property.value = property.key;
+ }
+ } else if (this.peek('[')) {
+ this.consume('[');
+ property.key = this.expression();
+ this.consume(']');
+ property.computed = true;
+ this.consume(':');
+ property.value = this.expression();
} else {
this.throwError("invalid key", this.peek());
}
- this.consume(':');
- property.value = this.expression();
properties.push(property);
} while (this.expect(','));
}
@@ -14162,7 +14711,7 @@ function findConstantAndWatchExpressions(ast, $filter) {
argsToWatch = [];
forEach(ast.properties, function(property) {
findConstantAndWatchExpressions(property.value, $filter);
- allConstants = allConstants && property.value.constant;
+ allConstants = allConstants && property.value.constant && !property.computed;
if (!property.value.constant) {
argsToWatch.push.apply(argsToWatch, property.value.toWatch);
}
@@ -14334,7 +14883,7 @@ ASTCompiler.prototype = {
},
recurse: function(ast, intoId, nameId, recursionFn, create, skipWatchIdCheck) {
- var left, right, self = this, args, expression;
+ var left, right, self = this, args, expression, computed;
recursionFn = recursionFn || noop;
if (!skipWatchIdCheck && isDefined(ast.watchId)) {
intoId = intoId || this.nextId();
@@ -14531,17 +15080,41 @@ ASTCompiler.prototype = {
break;
case AST.ObjectExpression:
args = [];
+ computed = false;
forEach(ast.properties, function(property) {
- self.recurse(property.value, self.nextId(), undefined, function(expr) {
- args.push(self.escape(
- property.key.type === AST.Identifier ? property.key.name :
- ('' + property.key.value)) +
- ':' + expr);
- });
+ if (property.computed) {
+ computed = true;
+ }
});
- expression = '{' + args.join(',') + '}';
- this.assign(intoId, expression);
- recursionFn(expression);
+ if (computed) {
+ intoId = intoId || this.nextId();
+ this.assign(intoId, '{}');
+ forEach(ast.properties, function(property) {
+ if (property.computed) {
+ left = self.nextId();
+ self.recurse(property.key, left);
+ } else {
+ left = property.key.type === AST.Identifier ?
+ property.key.name :
+ ('' + property.key.value);
+ }
+ right = self.nextId();
+ self.recurse(property.value, right);
+ self.assign(self.member(intoId, left, property.computed), right);
+ });
+ } else {
+ forEach(ast.properties, function(property) {
+ self.recurse(property.value, ast.constant ? undefined : self.nextId(), undefined, function(expr) {
+ args.push(self.escape(
+ property.key.type === AST.Identifier ? property.key.name :
+ ('' + property.key.value)) +
+ ':' + expr);
+ });
+ });
+ expression = '{' + args.join(',') + '}';
+ this.assign(intoId, expression);
+ }
+ recursionFn(intoId || expression);
break;
case AST.ThisExpression:
this.assign(intoId, 's');
@@ -14617,7 +15190,13 @@ ASTCompiler.prototype = {
},
nonComputedMember: function(left, right) {
- return left + '.' + right;
+ var SAFE_IDENTIFIER = /[$_a-zA-Z][$_a-zA-Z0-9]*/;
+ var UNSAFE_CHARACTERS = /[^$_a-zA-Z0-9]/g;
+ if (SAFE_IDENTIFIER.test(right)) {
+ return left + '.' + right;
+ } else {
+ return left + '["' + right.replace(UNSAFE_CHARACTERS, this.stringEscapeFn) + '"]';
+ }
},
computedMember: function(left, right) {
@@ -14861,16 +15440,28 @@ ASTInterpreter.prototype = {
case AST.ObjectExpression:
args = [];
forEach(ast.properties, function(property) {
- args.push({key: property.key.type === AST.Identifier ?
- property.key.name :
- ('' + property.key.value),
- value: self.recurse(property.value)
- });
+ if (property.computed) {
+ args.push({key: self.recurse(property.key),
+ computed: true,
+ value: self.recurse(property.value)
+ });
+ } else {
+ args.push({key: property.key.type === AST.Identifier ?
+ property.key.name :
+ ('' + property.key.value),
+ computed: false,
+ value: self.recurse(property.value)
+ });
+ }
});
return function(scope, locals, assign, inputs) {
var value = {};
for (var i = 0; i < args.length; ++i) {
- value[args[i].key] = args[i].value(scope, locals, assign, inputs);
+ if (args[i].computed) {
+ value[args[i].key(scope, locals, assign, inputs)] = args[i].value(scope, locals, assign, inputs);
+ } else {
+ value[args[i].key] = args[i].value(scope, locals, assign, inputs);
+ }
}
return context ? {value: value} : value;
};
@@ -15180,6 +15771,7 @@ function $ParseProvider() {
'null': null,
'undefined': undefined
};
+ var identStart, identContinue;
/**
* @ngdoc method
@@ -15196,17 +15788,50 @@ function $ParseProvider() {
literals[literalName] = literalValue;
};
+ /**
+ * @ngdoc method
+ * @name $parseProvider#setIdentifierFns
+ * @description
+ *
+ * Allows defining the set of characters that are allowed in Angular expressions. The function
+ * `identifierStart` will get called to know if a given character is a valid character to be the
+ * first character for an identifier. The function `identifierContinue` will get called to know if
+ * a given character is a valid character to be a follow-up identifier character. The functions
+ * `identifierStart` and `identifierContinue` will receive as arguments the single character to be
+ * identifier and the character code point. These arguments will be `string` and `numeric`. Keep in
+ * mind that the `string` parameter can be two characters long depending on the character
+ * representation. It is expected for the function to return `true` or `false`, whether that
+ * character is allowed or not.
+ *
+ * Since this function will be called extensivelly, keep the implementation of these functions fast,
+ * as the performance of these functions have a direct impact on the expressions parsing speed.
+ *
+ * @param {function=} identifierStart The function that will decide whether the given character is
+ * a valid identifier start character.
+ * @param {function=} identifierContinue The function that will decide whether the given character is
+ * a valid identifier continue character.
+ */
+ this.setIdentifierFns = function(identifierStart, identifierContinue) {
+ identStart = identifierStart;
+ identContinue = identifierContinue;
+ return this;
+ };
+
this.$get = ['$filter', function($filter) {
var noUnsafeEval = csp().noUnsafeEval;
var $parseOptions = {
csp: noUnsafeEval,
expensiveChecks: false,
- literals: copy(literals)
+ literals: copy(literals),
+ isIdentifierStart: isFunction(identStart) && identStart,
+ isIdentifierContinue: isFunction(identContinue) && identContinue
},
$parseOptionsExpensive = {
csp: noUnsafeEval,
expensiveChecks: true,
- literals: copy(literals)
+ literals: copy(literals),
+ isIdentifierStart: isFunction(identStart) && identStart,
+ isIdentifierContinue: isFunction(identContinue) && identContinue
};
var runningChecksEnabled = false;
@@ -15577,7 +16202,7 @@ function $ParseProvider() {
*
* **Methods**
*
- * - `then(successCallback, errorCallback, notifyCallback)` – regardless of when the promise was or
+ * - `then(successCallback, [errorCallback], [notifyCallback])` – regardless of when the promise was or
* will be resolved or rejected, `then` calls one of the success or error callbacks asynchronously
* as soon as the result is available. The callbacks are called with a single argument: the result
* or rejection reason. Additionally, the notify callback may be called zero or more times to
@@ -15588,7 +16213,8 @@ function $ParseProvider() {
* with the value which is resolved in that promise using
* [promise chaining](http://www.html5rocks.com/en/tutorials/es6/promises/#toc-promises-queues)).
* It also notifies via the return value of the `notifyCallback` method. The promise cannot be
- * resolved or rejected from the notifyCallback method.
+ * resolved or rejected from the notifyCallback method. The errorCallback and notifyCallback
+ * arguments are optional.
*
* - `catch(errorCallback)` – shorthand for `promise.then(null, errorCallback)`
*
@@ -16003,6 +16629,30 @@ function qFactory(nextTick, exceptionHandler) {
return deferred.promise;
}
+ /**
+ * @ngdoc method
+ * @name $q#race
+ * @kind function
+ *
+ * @description
+ * Returns a promise that resolves or rejects as soon as one of those promises
+ * resolves or rejects, with the value or reason from that promise.
+ *
+ * @param {Array.|Object.} promises An array or hash of promises.
+ * @returns {Promise} a promise that resolves or rejects as soon as one of the `promises`
+ * resolves or rejects, with the value or reason from that promise.
+ */
+
+ function race(promises) {
+ var deferred = defer();
+
+ forEach(promises, function(promise) {
+ when(promise).then(deferred.resolve, deferred.reject);
+ });
+
+ return deferred.promise;
+ }
+
var $Q = function Q(resolver) {
if (!isFunction(resolver)) {
throw $qMinErr('norslvr', "Expected resolverFn, got '{0}'", resolver);
@@ -16032,6 +16682,7 @@ function qFactory(nextTick, exceptionHandler) {
$Q.when = when;
$Q.resolve = resolve;
$Q.all = all;
+ $Q.race = race;
return $Q;
}
@@ -16835,15 +17486,19 @@ function $RootScopeProvider() {
dirty = false;
current = target;
- while (asyncQueue.length) {
+ // It's safe for asyncQueuePosition to be a local variable here because this loop can't
+ // be reentered recursively. Calling $digest from a function passed to $applyAsync would
+ // lead to a '$digest already in progress' error.
+ for (var asyncQueuePosition = 0; asyncQueuePosition < asyncQueue.length; asyncQueuePosition++) {
try {
- asyncTask = asyncQueue.shift();
+ asyncTask = asyncQueue[asyncQueuePosition];
asyncTask.scope.$eval(asyncTask.expression, asyncTask.locals);
} catch (e) {
$exceptionHandler(e);
}
lastDirtyWatch = null;
}
+ asyncQueue.length = 0;
traverseScopesLoop:
do { // "traverse the scopes" loop
@@ -16914,13 +17569,15 @@ function $RootScopeProvider() {
clearPhase();
- while (postDigestQueue.length) {
+ // postDigestQueuePosition isn't local here because this loop can be reentered recursively.
+ while (postDigestQueuePosition < postDigestQueue.length) {
try {
- postDigestQueue.shift()();
+ postDigestQueue[postDigestQueuePosition++]();
} catch (e) {
$exceptionHandler(e);
}
}
+ postDigestQueue.length = postDigestQueuePosition = 0;
},
@@ -17375,6 +18032,8 @@ function $RootScopeProvider() {
var postDigestQueue = $rootScope.$$postDigestQueue = [];
var applyAsyncQueue = $rootScope.$$applyAsyncQueue = [];
+ var postDigestQueuePosition = 0;
+
return $rootScope;
@@ -17943,7 +18602,7 @@ function $SceDelegateProvider() {
* You can ensure your document is in standards mode and not quirks mode by adding ``
* to the top of your HTML document.
*
- * SCE assists in writing code in way that (a) is secure by default and (b) makes auditing for
+ * SCE assists in writing code in a way that (a) is secure by default and (b) makes auditing for
* security vulnerabilities such as XSS, clickjacking, etc. a lot easier.
*
* Here's an example of a binding in a privileged context:
@@ -18620,7 +19279,7 @@ function $SnifferProvider() {
for (var prop in bodyStyle) {
if (match = vendorRegex.exec(prop)) {
vendorPrefix = match[0];
- vendorPrefix = vendorPrefix.substr(0, 1).toUpperCase() + vendorPrefix.substr(1);
+ vendorPrefix = vendorPrefix[0].toUpperCase() + vendorPrefix.substr(1);
break;
}
}
@@ -18743,7 +19402,7 @@ function $TemplateRequestProvider() {
// are included in there. This also makes Angular accept any script
// directive, no matter its name. However, we still need to unwrap trusted
// types.
- if (!isString(tpl) || !$templateCache.get(tpl)) {
+ if (!isString(tpl) || isUndefined($templateCache.get(tpl))) {
tpl = $sce.getTrustedResourceUrl(tpl);
}
@@ -19001,7 +19660,7 @@ function $TimeoutProvider() {
// doesn't know about mocked locations and resolves URLs to the real document - which is
// exactly the behavior needed here. There is little value is mocking these out for this
// service.
-var urlParsingNode = document.createElement("a");
+var urlParsingNode = window.document.createElement("a");
var originUrl = urlResolve(window.location.href);
@@ -19375,10 +20034,11 @@ function $FilterProvider($provide) {
* - `Object`: A pattern object can be used to filter specific properties on objects contained
* by `array`. For example `{name:"M", phone:"1"}` predicate will return an array of items
* which have property `name` containing "M" and property `phone` containing "1". A special
- * property name `$` can be used (as in `{$:"text"}`) to accept a match against any
- * property of the object or its nested object properties. That's equivalent to the simple
- * substring match with a `string` as described above. The predicate can be negated by prefixing
- * the string with `!`.
+ * property name (`$` by default) can be used (e.g. as in `{$: "text"}`) to accept a match
+ * against any property of the object or its nested object properties. That's equivalent to the
+ * simple substring match with a `string` as described above. The special property name can be
+ * overwritten, using the `anyPropertyKey` parameter.
+ * The predicate can be negated by prefixing the string with `!`.
* For example `{name: "!M"}` predicate will return an array of items which have property `name`
* not containing "M".
*
@@ -19412,6 +20072,9 @@ function $FilterProvider($provide) {
* Primitive values are converted to strings. Objects are not compared against primitives,
* unless they have a custom `toString` method (e.g. `Date` objects).
*
+ * @param {string=} anyPropertyKey The special property name that matches against any property.
+ * By default `$`.
+ *
* @example
@@ -19480,8 +20143,9 @@ function $FilterProvider($provide) {
*/
+
function filterFilter() {
- return function(array, expression, comparator) {
+ return function(array, expression, comparator, anyPropertyKey) {
if (!isArrayLike(array)) {
if (array == null) {
return array;
@@ -19490,6 +20154,7 @@ function filterFilter() {
}
}
+ anyPropertyKey = anyPropertyKey || '$';
var expressionType = getTypeForFilter(expression);
var predicateFn;
var matchAgainstAnyProp;
@@ -19506,7 +20171,7 @@ function filterFilter() {
//jshint -W086
case 'object':
//jshint +W086
- predicateFn = createPredicateFn(expression, comparator, matchAgainstAnyProp);
+ predicateFn = createPredicateFn(expression, comparator, anyPropertyKey, matchAgainstAnyProp);
break;
default:
return array;
@@ -19517,8 +20182,8 @@ function filterFilter() {
}
// Helper functions for `filterFilter`
-function createPredicateFn(expression, comparator, matchAgainstAnyProp) {
- var shouldMatchPrimitives = isObject(expression) && ('$' in expression);
+function createPredicateFn(expression, comparator, anyPropertyKey, matchAgainstAnyProp) {
+ var shouldMatchPrimitives = isObject(expression) && (anyPropertyKey in expression);
var predicateFn;
if (comparator === true) {
@@ -19546,25 +20211,25 @@ function createPredicateFn(expression, comparator, matchAgainstAnyProp) {
predicateFn = function(item) {
if (shouldMatchPrimitives && !isObject(item)) {
- return deepCompare(item, expression.$, comparator, false);
+ return deepCompare(item, expression[anyPropertyKey], comparator, anyPropertyKey, false);
}
- return deepCompare(item, expression, comparator, matchAgainstAnyProp);
+ return deepCompare(item, expression, comparator, anyPropertyKey, matchAgainstAnyProp);
};
return predicateFn;
}
-function deepCompare(actual, expected, comparator, matchAgainstAnyProp, dontMatchWholeObject) {
+function deepCompare(actual, expected, comparator, anyPropertyKey, matchAgainstAnyProp, dontMatchWholeObject) {
var actualType = getTypeForFilter(actual);
var expectedType = getTypeForFilter(expected);
if ((expectedType === 'string') && (expected.charAt(0) === '!')) {
- return !deepCompare(actual, expected.substring(1), comparator, matchAgainstAnyProp);
+ return !deepCompare(actual, expected.substring(1), comparator, anyPropertyKey, matchAgainstAnyProp);
} else if (isArray(actual)) {
// In case `actual` is an array, consider it a match
// if ANY of it's items matches `expected`
return actual.some(function(item) {
- return deepCompare(item, expected, comparator, matchAgainstAnyProp);
+ return deepCompare(item, expected, comparator, anyPropertyKey, matchAgainstAnyProp);
});
}
@@ -19573,11 +20238,11 @@ function deepCompare(actual, expected, comparator, matchAgainstAnyProp, dontMatc
var key;
if (matchAgainstAnyProp) {
for (key in actual) {
- if ((key.charAt(0) !== '$') && deepCompare(actual[key], expected, comparator, true)) {
+ if ((key.charAt(0) !== '$') && deepCompare(actual[key], expected, comparator, anyPropertyKey, true)) {
return true;
}
}
- return dontMatchWholeObject ? false : deepCompare(actual, expected, comparator, false);
+ return dontMatchWholeObject ? false : deepCompare(actual, expected, comparator, anyPropertyKey, false);
} else if (expectedType === 'object') {
for (key in expected) {
var expectedVal = expected[key];
@@ -19585,9 +20250,9 @@ function deepCompare(actual, expected, comparator, matchAgainstAnyProp, dontMatc
continue;
}
- var matchAnyProperty = key === '$';
+ var matchAnyProperty = key === anyPropertyKey;
var actualVal = matchAnyProperty ? actual : actual[key];
- if (!deepCompare(actualVal, expectedVal, comparator, matchAnyProperty, matchAnyProperty)) {
+ if (!deepCompare(actualVal, expectedVal, comparator, anyPropertyKey, matchAnyProperty, matchAnyProperty)) {
return false;
}
}
@@ -19701,7 +20366,9 @@ function currencyFilter($locale) {
* @param {(number|string)=} fractionSize Number of decimal places to round the number to.
* If this is not provided then the fraction size is computed from the current locale's number
* formatting pattern. In the case of the default locale, it will be 3.
- * @returns {string} Number rounded to fractionSize and places a “,” after each third digit.
+ * @returns {string} Number rounded to `fractionSize` appropriately formatted based on the current
+ * locale (e.g., in the en_US locale it will have "." as the decimal separator and
+ * include "," group separators after each third digit).
*
* @example
@@ -19923,7 +20590,7 @@ function formatNumber(number, pattern, groupSep, decimalSep, fractionSize) {
// extract decimals digits
if (integerLen > 0) {
- decimals = digits.splice(integerLen);
+ decimals = digits.splice(integerLen, digits.length);
} else {
decimals = digits;
digits = [0];
@@ -19932,10 +20599,10 @@ function formatNumber(number, pattern, groupSep, decimalSep, fractionSize) {
// format the integer digits with grouping separators
var groups = [];
if (digits.length >= pattern.lgSize) {
- groups.unshift(digits.splice(-pattern.lgSize).join(''));
+ groups.unshift(digits.splice(-pattern.lgSize, digits.length).join(''));
}
while (digits.length > pattern.gSize) {
- groups.unshift(digits.splice(-pattern.gSize).join(''));
+ groups.unshift(digits.splice(-pattern.gSize, digits.length).join(''));
}
if (digits.length) {
groups.unshift(digits.join(''));
@@ -20323,21 +20990,22 @@ var uppercaseFilter = valueFn(uppercase);
* @kind function
*
* @description
- * Creates a new array or string containing only a specified number of elements. The elements
- * are taken from either the beginning or the end of the source array, string or number, as specified by
- * the value and sign (positive or negative) of `limit`. If a number is used as input, it is
- * converted to a string.
+ * Creates a new array or string containing only a specified number of elements. The elements are
+ * taken from either the beginning or the end of the source array, string or number, as specified by
+ * the value and sign (positive or negative) of `limit`. Other array-like objects are also supported
+ * (e.g. array subclasses, NodeLists, jqLite/jQuery collections etc). If a number is used as input,
+ * it is converted to a string.
*
- * @param {Array|string|number} input Source array, string or number to be limited.
- * @param {string|number} limit The length of the returned array or string. If the `limit` number
+ * @param {Array|ArrayLike|string|number} input - Array/array-like, string or number to be limited.
+ * @param {string|number} limit - The length of the returned array or string. If the `limit` number
* is positive, `limit` number of items from the beginning of the source array/string are copied.
* If the number is negative, `limit` number of items from the end of the source array/string
* are copied. The `limit` will be trimmed if it exceeds `array.length`. If `limit` is undefined,
* the input will be returned unchanged.
- * @param {(string|number)=} begin Index at which to begin limitation. As a negative index, `begin`
- * indicates an offset from the end of `input`. Defaults to `0`.
- * @returns {Array|string} A new sub-array or substring of length `limit` or less if input array
- * had less than `limit` elements.
+ * @param {(string|number)=} begin - Index at which to begin limitation. As a negative index,
+ * `begin` indicates an offset from the end of `input`. Defaults to `0`.
+ * @returns {Array|string} A new sub-array or substring of length `limit` or less if the input had
+ * less than `limit` elements.
*
* @example
@@ -20425,67 +21093,157 @@ function limitToFilter() {
if (isNaN(limit)) return input;
if (isNumber(input)) input = input.toString();
- if (!isArray(input) && !isString(input)) return input;
+ if (!isArrayLike(input)) return input;
begin = (!begin || isNaN(begin)) ? 0 : toInt(begin);
begin = (begin < 0) ? Math.max(0, input.length + begin) : begin;
if (limit >= 0) {
- return input.slice(begin, begin + limit);
+ return sliceFn(input, begin, begin + limit);
} else {
if (begin === 0) {
- return input.slice(limit, input.length);
+ return sliceFn(input, limit, input.length);
} else {
- return input.slice(Math.max(0, begin + limit), begin);
+ return sliceFn(input, Math.max(0, begin + limit), begin);
}
}
};
}
+function sliceFn(input, begin, end) {
+ if (isString(input)) return input.slice(begin, end);
+
+ return slice.call(input, begin, end);
+}
+
/**
* @ngdoc filter
* @name orderBy
* @kind function
*
* @description
- * Orders a specified `array` by the `expression` predicate. It is ordered alphabetically
- * for strings and numerically for numbers. Note: if you notice numbers are not being sorted
- * as expected, make sure they are actually being saved as numbers and not strings.
- * Array-like values (e.g. NodeLists, jQuery objects, TypedArrays, Strings, etc) are also supported.
+ * Returns an array containing the items from the specified `collection`, ordered by a `comparator`
+ * function based on the values computed using the `expression` predicate.
*
- * @param {Array} array The array (or array-like object) to sort.
- * @param {function(*)|string|Array.<(function(*)|string)>=} expression A predicate to be
- * used by the comparator to determine the order of elements.
+ * For example, `[{id: 'foo'}, {id: 'bar'}] | orderBy:'id'` would result in
+ * `[{id: 'bar'}, {id: 'foo'}]`.
+ *
+ * The `collection` can be an Array or array-like object (e.g. NodeList, jQuery object, TypedArray,
+ * String, etc).
+ *
+ * The `expression` can be a single predicate, or a list of predicates each serving as a tie-breaker
+ * for the preceeding one. The `expression` is evaluated against each item and the output is used
+ * for comparing with other items.
+ *
+ * You can change the sorting order by setting `reverse` to `true`. By default, items are sorted in
+ * ascending order.
+ *
+ * The comparison is done using the `comparator` function. If none is specified, a default, built-in
+ * comparator is used (see below for details - in a nutshell, it compares numbers numerically and
+ * strings alphabetically).
+ *
+ * ### Under the hood
+ *
+ * Ordering the specified `collection` happens in two phases:
+ *
+ * 1. All items are passed through the predicate (or predicates), and the returned values are saved
+ * along with their type (`string`, `number` etc). For example, an item `{label: 'foo'}`, passed
+ * through a predicate that extracts the value of the `label` property, would be transformed to:
+ * ```
+ * {
+ * value: 'foo',
+ * type: 'string',
+ * index: ...
+ * }
+ * ```
+ * 2. The comparator function is used to sort the items, based on the derived values, types and
+ * indices.
+ *
+ * If you use a custom comparator, it will be called with pairs of objects of the form
+ * `{value: ..., type: '...', index: ...}` and is expected to return `0` if the objects are equal
+ * (as far as the comparator is concerned), `-1` if the 1st one should be ranked higher than the
+ * second, or `1` otherwise.
+ *
+ * In order to ensure that the sorting will be deterministic across platforms, if none of the
+ * specified predicates can distinguish between two items, `orderBy` will automatically introduce a
+ * dummy predicate that returns the item's index as `value`.
+ * (If you are using a custom comparator, make sure it can handle this predicate as well.)
+ *
+ * Finally, in an attempt to simplify things, if a predicate returns an object as the extracted
+ * value for an item, `orderBy` will try to convert that object to a primitive value, before passing
+ * it to the comparator. The following rules govern the conversion:
+ *
+ * 1. If the object has a `valueOf()` method that returns a primitive, its return value will be
+ * used instead.
+ * (If the object has a `valueOf()` method that returns another object, then the returned object
+ * will be used in subsequent steps.)
+ * 2. If the object has a custom `toString()` method (i.e. not the one inherited from `Object`) that
+ * returns a primitive, its return value will be used instead.
+ * (If the object has a `toString()` method that returns another object, then the returned object
+ * will be used in subsequent steps.)
+ * 3. No conversion; the object itself is used.
+ *
+ * ### The default comparator
+ *
+ * The default, built-in comparator should be sufficient for most usecases. In short, it compares
+ * numbers numerically, strings alphabetically (and case-insensitively), for objects falls back to
+ * using their index in the original collection, and sorts values of different types by type.
+ *
+ * More specifically, it follows these steps to determine the relative order of items:
+ *
+ * 1. If the compared values are of different types, compare the types themselves alphabetically.
+ * 2. If both values are of type `string`, compare them alphabetically in a case- and
+ * locale-insensitive way.
+ * 3. If both values are objects, compare their indices instead.
+ * 4. Otherwise, return:
+ * - `0`, if the values are equal (by strict equality comparison, i.e. using `===`).
+ * - `-1`, if the 1st value is "less than" the 2nd value (compared using the `<` operator).
+ * - `1`, otherwise.
+ *
+ * **Note:** If you notice numbers not being sorted as expected, make sure they are actually being
+ * saved as numbers and not strings.
+ *
+ * @param {Array|ArrayLike} collection - The collection (array or array-like object) to sort.
+ * @param {(Function|string|Array.)=} expression - A predicate (or list of
+ * predicates) to be used by the comparator to determine the order of elements.
*
* Can be one of:
*
- * - `function`: Getter function. The result of this function will be sorted using the
- * `<`, `===`, `>` operator.
- * - `string`: An Angular expression. The result of this expression is used to compare elements
- * (for example `name` to sort by a property called `name` or `name.substr(0, 3)` to sort by
- * 3 first characters of a property called `name`). The result of a constant expression
- * is interpreted as a property name to be used in comparisons (for example `"special name"`
- * to sort object by the value of their `special name` property). An expression can be
- * optionally prefixed with `+` or `-` to control ascending or descending sort order
- * (for example, `+name` or `-name`). If no property is provided, (e.g. `'+'`) then the array
- * element itself is used to compare where sorting.
- * - `Array`: An array of function or string predicates. The first predicate in the array
- * is used for sorting, but when two items are equivalent, the next predicate is used.
+ * - `Function`: A getter function. This function will be called with each item as argument and
+ * the return value will be used for sorting.
+ * - `string`: An Angular expression. This expression will be evaluated against each item and the
+ * result will be used for sorting. For example, use `'label'` to sort by a property called
+ * `label` or `'label.substring(0, 3)'` to sort by the first 3 characters of the `label`
+ * property.
+ * (The result of a constant expression is interpreted as a property name to be used for
+ * comparison. For example, use `'"special name"'` (note the extra pair of quotes) to sort by a
+ * property called `special name`.)
+ * An expression can be optionally prefixed with `+` or `-` to control the sorting direction,
+ * ascending or descending. For example, `'+label'` or `'-label'`. If no property is provided,
+ * (e.g. `'+'` or `'-'`), the collection element itself is used in comparisons.
+ * - `Array`: An array of function and/or string predicates. If a predicate cannot determine the
+ * relative order of two items, the next predicate is used as a tie-breaker.
*
- * If the predicate is missing or empty then it defaults to `'+'`.
+ * **Note:** If the predicate is missing or empty then it defaults to `'+'`.
*
- * @param {boolean=} reverse Reverse the order of the array.
- * @returns {Array} Sorted copy of the source array.
+ * @param {boolean=} reverse - If `true`, reverse the sorting order.
+ * @param {(Function)=} comparator - The comparator function used to determine the relative order of
+ * value pairs. If omitted, the built-in comparator will be used.
+ *
+ * @returns {Array} - The sorted array.
*
*
* @example
- * The example below demonstrates a simple ngRepeat, where the data is sorted
- * by age in descending order (predicate is set to `'-age'`).
- * `reverse` is not set, which means it defaults to `false`.
-
+ * ### Ordering a table with `ngRepeat`
+ *
+ * The example below demonstrates a simple {@link ngRepeat ngRepeat}, where the data is sorted by
+ * age in descending order (expression is set to `'-age'`). The `comparator` is not set, which means
+ * it defaults to the built-in comparator.
+ *
+
-
+
Name
Phone Number
@@ -20500,43 +21258,77 @@ function limitToFilter() {
- angular.module('orderByExample', [])
+ angular.module('orderByExample1', [])
.controller('ExampleController', ['$scope', function($scope) {
- $scope.friends =
- [{name:'John', phone:'555-1212', age:10},
- {name:'Mary', phone:'555-9876', age:19},
- {name:'Mike', phone:'555-4321', age:21},
- {name:'Adam', phone:'555-5678', age:35},
- {name:'Julie', phone:'555-8765', age:29}];
+ $scope.friends = [
+ {name: 'John', phone: '555-1212', age: 10},
+ {name: 'Mary', phone: '555-9876', age: 19},
+ {name: 'Mike', phone: '555-4321', age: 21},
+ {name: 'Adam', phone: '555-5678', age: 35},
+ {name: 'Julie', phone: '555-8765', age: 29}
+ ];
}]);
+
+ .friends {
+ border-collapse: collapse;
+ }
+
+ .friends th {
+ border-bottom: 1px solid;
+ }
+ .friends td, .friends th {
+ border-left: 1px solid;
+ padding: 5px 10px;
+ }
+ .friends td:first-child, .friends th:first-child {
+ border-left: none;
+ }
+
+
+ // Element locators
+ var names = element.all(by.repeater('friends').column('friend.name'));
+
+ it('should sort friends by age in reverse order', function() {
+ expect(names.get(0).getText()).toBe('Adam');
+ expect(names.get(1).getText()).toBe('Julie');
+ expect(names.get(2).getText()).toBe('Mike');
+ expect(names.get(3).getText()).toBe('Mary');
+ expect(names.get(4).getText()).toBe('John');
+ });
+
+ *
*
- * The predicate and reverse parameters can be controlled dynamically through scope properties,
- * as shown in the next example.
* @example
-
+ * ### Changing parameters dynamically
+ *
+ * All parameters can be changed dynamically. The next example shows how you can make the columns of
+ * a table sortable, by binding the `expression` and `reverse` parameters to scope properties.
+ *
+
-
-
-
- angular.module('orderByExample', [])
- .controller('ExampleController', ['$scope', '$filter', function($scope, $filter) {
- var orderBy = $filter('orderBy');
- $scope.friends = [
- { name: 'John', phone: '555-1212', age: 10 },
- { name: 'Mary', phone: '555-9876', age: 19 },
- { name: 'Mike', phone: '555-4321', age: 21 },
- { name: 'Adam', phone: '555-5678', age: 35 },
- { name: 'Julie', phone: '555-8765', age: 29 }
- ];
- $scope.order = function(predicate) {
- $scope.predicate = predicate;
- $scope.reverse = ($scope.predicate === predicate) ? !$scope.reverse : false;
- $scope.friends = orderBy($scope.friends, predicate, $scope.reverse);
- };
- $scope.order('age', true);
- }]);
-
-
-
- .sortorder:after {
- content: '\25b2';
- }
- .sortorder.reverse:after {
- content: '\25bc';
- }
-
-
*/
orderByFilter.$inject = ['$parse'];
function orderByFilter($parse) {
- return function(array, sortPredicate, reverseOrder) {
+ return function(array, sortPredicate, reverseOrder, compareFn) {
if (array == null) return array;
if (!isArrayLike(array)) {
@@ -20648,11 +21675,12 @@ function orderByFilter($parse) {
if (!isArray(sortPredicate)) { sortPredicate = [sortPredicate]; }
if (sortPredicate.length === 0) { sortPredicate = ['+']; }
- var predicates = processPredicates(sortPredicate, reverseOrder);
- // Add a predicate at the end that evaluates to the element index. This makes the
- // sort stable as it works as a tie-breaker when all the input predicates cannot
- // distinguish between two elements.
- predicates.push({ get: function() { return {}; }, descending: reverseOrder ? -1 : 1});
+ var predicates = processPredicates(sortPredicate);
+
+ var descending = reverseOrder ? -1 : 1;
+
+ // Define the `compare()` function. Use a default comparator if none is specified.
+ var compare = isFunction(compareFn) ? compareFn : defaultCompare;
// The next three lines are a version of a Swartzian Transform idiom from Perl
// (sometimes called the Decorate-Sort-Undecorate idiom)
@@ -20664,8 +21692,12 @@ function orderByFilter($parse) {
return array;
function getComparisonObject(value, index) {
+ // NOTE: We are adding an extra `tieBreaker` value based on the element's index.
+ // This will be used to keep the sort stable when none of the input predicates can
+ // distinguish between two elements.
return {
value: value,
+ tieBreaker: {value: index, type: 'number', index: index},
predicateValues: predicates.map(function(predicate) {
return getPredicateValue(predicate.get(value), index);
})
@@ -20673,18 +21705,19 @@ function orderByFilter($parse) {
}
function doComparison(v1, v2) {
- var result = 0;
- for (var index=0, length = predicates.length; index < length; ++index) {
- result = compare(v1.predicateValues[index], v2.predicateValues[index]) * predicates[index].descending;
- if (result) break;
+ for (var i = 0, ii = predicates.length; i < ii; i++) {
+ var result = compare(v1.predicateValues[i], v2.predicateValues[i]);
+ if (result) {
+ return result * predicates[i].descending * descending;
+ }
}
- return result;
+
+ return compare(v1.tieBreaker, v2.tieBreaker) * descending;
}
};
- function processPredicates(sortPredicate, reverseOrder) {
- reverseOrder = reverseOrder ? -1 : 1;
- return sortPredicate.map(function(predicate) {
+ function processPredicates(sortPredicates) {
+ return sortPredicates.map(function(predicate) {
var descending = 1, get = identity;
if (isFunction(predicate)) {
@@ -20702,7 +21735,7 @@ function orderByFilter($parse) {
}
}
}
- return { get: get, descending: descending * reverseOrder };
+ return {get: get, descending: descending};
});
}
@@ -20717,9 +21750,9 @@ function orderByFilter($parse) {
}
}
- function objectValue(value, index) {
+ function objectValue(value) {
// If `valueOf` is a valid function use that
- if (typeof value.valueOf === 'function') {
+ if (isFunction(value.valueOf)) {
value = value.valueOf();
if (isPrimitive(value)) return value;
}
@@ -20728,8 +21761,8 @@ function orderByFilter($parse) {
value = value.toString();
if (isPrimitive(value)) return value;
}
- // We have a basic object so we use the position of the object in the collection
- return index;
+
+ return value;
}
function getPredicateValue(value, index) {
@@ -20737,23 +21770,39 @@ function orderByFilter($parse) {
if (value === null) {
type = 'string';
value = 'null';
- } else if (type === 'string') {
- value = value.toLowerCase();
} else if (type === 'object') {
- value = objectValue(value, index);
+ value = objectValue(value);
}
- return { value: value, type: type };
+ return {value: value, type: type, index: index};
}
- function compare(v1, v2) {
+ function defaultCompare(v1, v2) {
var result = 0;
- if (v1.type === v2.type) {
- if (v1.value !== v2.value) {
- result = v1.value < v2.value ? -1 : 1;
+ var type1 = v1.type;
+ var type2 = v2.type;
+
+ if (type1 === type2) {
+ var value1 = v1.value;
+ var value2 = v2.value;
+
+ if (type1 === 'string') {
+ // Compare strings case-insensitively
+ value1 = value1.toLowerCase();
+ value2 = value2.toLowerCase();
+ } else if (type1 === 'object') {
+ // For basic objects, use the position of the object
+ // in the collection instead of the value
+ if (isObject(value1)) value1 = v1.index;
+ if (isObject(value2)) value2 = v2.index;
+ }
+
+ if (value1 !== value2) {
+ result = value1 < value2 ? -1 : 1;
}
} else {
- result = v1.type < v2.type ? -1 : 1;
+ result = type1 < type2 ? -1 : 1;
}
+
return result;
}
}
@@ -21033,9 +22082,11 @@ var htmlAnchorDirective = valueFn({
*
* @description
*
- * Sets the `readOnly` attribute on the element, if the expression inside `ngReadonly` is truthy.
+ * Sets the `readonly` attribute on the element, if the expression inside `ngReadonly` is truthy.
+ * Note that `readonly` applies only to `input` elements with specific types. [See the input docs on
+ * MDN](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input#attr-readonly) for more information.
*
- * A special directive is necessary because we cannot use interpolation inside the `readOnly`
+ * A special directive is necessary because we cannot use interpolation inside the `readonly`
* attribute. See the {@link guide/interpolation interpolation guide} for more info.
*
* @example
@@ -21072,6 +22123,13 @@ var htmlAnchorDirective = valueFn({
* A special directive is necessary because we cannot use interpolation inside the `selected`
* attribute. See the {@link guide/interpolation interpolation guide} for more info.
*
+ *
+ * **Note:** `ngSelected` does not interact with the `select` and `ngModel` directives, it only
+ * sets the `selected` attribute on the element. If you are using `ngModel` on the select, you
+ * should not use `ngSelected` on the options, as `ngModel` will set the select value and
+ * selected options.
+ *
+ *
* @example
@@ -21108,6 +22166,11 @@ var htmlAnchorDirective = valueFn({
* A special directive is necessary because we cannot use interpolation inside the `open`
* attribute. See the {@link guide/interpolation interpolation guide} for more info.
*
+ * ## A note about browser compatibility
+ *
+ * Edge, Firefox, and Internet Explorer do not support the `details` element, it is
+ * recommended to use {@link ng.ngShow} and {@link ng.ngHide} instead.
+ *
* @example
@@ -21798,7 +22861,9 @@ var ISO_DATE_REGEXP = /^\d{4,}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d:[0-5]\d\.\d+(?:[+-
// 9. Fragment
// 1111111111111111 222 333333 44444 555555555555555555555555 666 77777777 8888888 999
var URL_REGEXP = /^[a-z][a-z\d.+-]*:\/*(?:[^:@]+(?::[^@]+)?@)?(?:[^\s:/?#]+|\[[a-f\d:]+\])(?::\d+)?(?:\/[^?#]*)?(?:\?[^#]*)?(?:#.*)?$/i;
-var EMAIL_REGEXP = /^[a-z0-9!#$%&'*+\/=?^_`{|}~.-]+@[a-z0-9]([a-z0-9-]*[a-z0-9])?(\.[a-z0-9]([a-z0-9-]*[a-z0-9])?)*$/i;
+/* jshint maxlen:220 */
+var EMAIL_REGEXP = /^(?=.{1,254}$)(?=.{1,64}@)[-!#$%&'*+\/0-9=?A-Z^_`a-z{|}~]+(\.[-!#$%&'*+\/0-9=?A-Z^_`a-z{|}~]+)*@[A-Za-z0-9]([A-Za-z0-9-]{0,61}[A-Za-z0-9])?(\.[A-Za-z0-9]([A-Za-z0-9-]{0,61}[A-Za-z0-9])?)*$/;
+/* jshint maxlen:200 */
var NUMBER_REGEXP = /^\s*(\-|\+)?(\d+|(\d*(\.\d*)))([eE][+-]?\d+)?\s*$/;
var DATE_REGEXP = /^(\d{4,})-(\d{2})-(\d{2})$/;
var DATETIMELOCAL_REGEXP = /^(\d{4,})-(\d\d)-(\d\d)T(\d\d):(\d\d)(?::(\d\d)(\.\d{1,3})?)?$/;
@@ -21874,11 +22939,11 @@ var inputType = {
Single word only!
- text = {{example.text}}
- myForm.input.$valid = {{myForm.input.$valid}}
- myForm.input.$error = {{myForm.input.$error}}
- myForm.$valid = {{myForm.$valid}}
- myForm.$error.required = {{!!myForm.$error.required}}
+ text = {{example.text}}
+ myForm.input.$valid = {{myForm.input.$valid}}
+ myForm.input.$error = {{myForm.input.$error}}
+ myForm.$valid = {{myForm.$valid}}
+ myForm.$error.required = {{!!myForm.$error.required}}
@@ -23183,7 +24248,7 @@ function numberInputType(scope, element, attr, ctrl, $sniffer, $browser) {
attr.$observe('min', function(val) {
if (isDefined(val) && !isNumber(val)) {
- val = parseFloat(val, 10);
+ val = parseFloat(val);
}
minVal = isNumber(val) && !isNaN(val) ? val : undefined;
// TODO(matsko): implement validateLater to reduce number of validations
@@ -23199,7 +24264,7 @@ function numberInputType(scope, element, attr, ctrl, $sniffer, $browser) {
attr.$observe('max', function(val) {
if (isDefined(val) && !isNumber(val)) {
- val = parseFloat(val, 10);
+ val = parseFloat(val);
}
maxVal = isNumber(val) && !isNaN(val) ? val : undefined;
// TODO(matsko): implement validateLater to reduce number of validations
@@ -23757,8 +24822,9 @@ var ngBindHtmlDirective = ['$sce', '$parse', '$compile', function($sce, $parse,
restrict: 'A',
compile: function ngBindHtmlCompile(tElement, tAttrs) {
var ngBindHtmlGetter = $parse(tAttrs.ngBindHtml);
- var ngBindHtmlWatch = $parse(tAttrs.ngBindHtml, function getStringValue(value) {
- return (value || '').toString();
+ var ngBindHtmlWatch = $parse(tAttrs.ngBindHtml, function sceValueOf(val) {
+ // Unwrap the value to compare the actual inner safe value, not the wrapper object.
+ return $sce.valueOf(val);
});
$compile.$$addBindingClass(tElement);
@@ -23766,9 +24832,9 @@ var ngBindHtmlDirective = ['$sce', '$parse', '$compile', function($sce, $parse,
$compile.$$addBindingInfo(element, attr.ngBindHtml);
scope.$watch(ngBindHtmlWatch, function ngBindHtmlWatchAction() {
- // we re-evaluate the expr because we want a TrustedValueHolderType
- // for $sce, not a string
- element.html($sce.getTrustedHtml(ngBindHtmlGetter(scope)) || '');
+ // The watched value is the unwrapped value. To avoid re-escaping, use the direct getter.
+ var value = ngBindHtmlGetter(scope);
+ element.html($sce.getTrustedHtml(value) || '');
});
};
}
@@ -23921,7 +24987,9 @@ function classDirective(name, selector) {
}
function ngClassWatchAction(newVal) {
- if (selector === true || scope.$index % 2 === selector) {
+ // jshint bitwise: false
+ if (selector === true || (scope.$index & 1) === selector) {
+ // jshint bitwise: true
var newClasses = arrayClasses(newVal || []);
if (!oldVal) {
addClasses(newClasses);
@@ -23930,7 +24998,11 @@ function classDirective(name, selector) {
updateClasses(oldClasses, newClasses);
}
}
- oldVal = shallowCopy(newVal);
+ if (isArray(newVal)) {
+ oldVal = newVal.map(function(v) { return shallowCopy(v); });
+ } else {
+ oldVal = shallowCopy(newVal);
+ }
}
}
};
@@ -23999,6 +25071,11 @@ function classDirective(name, selector) {
* When the expression changes, the previously added classes are removed and only then are the
* new classes added.
*
+ * @knownIssue
+ * You should not use {@link guide/interpolation interpolation} in the value of the `class`
+ * attribute, when using the `ngClass` directive on the same element.
+ * See {@link guide/interpolation#known-issues here} for more info.
+ *
* @animations
* | Animation | Occurs |
* |----------------------------------|-------------------------------------|
@@ -25646,7 +26723,7 @@ var ngIncludeFillContentDirective = ['$compile',
// support innerHTML, so detect this here and try to generate the contents
// specially.
$element.empty();
- $compile(jqLiteBuildFragment(ctrl.template, document).childNodes)(scope,
+ $compile(jqLiteBuildFragment(ctrl.template, window.document).childNodes)(scope,
function namespaceAdaptedClone(clone) {
$element.append(clone);
}, {futureParentElement: $element});
@@ -27560,7 +28637,7 @@ var NG_OPTIONS_REGEXP = /^\s*([\s\S]+?)(?:\s+as\s+([\s\S]+?))?(?:\s+group\s+by\s
// jshint maxlen: 100
-var ngOptionsDirective = ['$compile', '$parse', function($compile, $parse) {
+var ngOptionsDirective = ['$compile', '$document', '$parse', function($compile, $document, $parse) {
function parseOptionsExpression(optionsExp, selectElement, scope) {
@@ -27721,8 +28798,8 @@ var ngOptionsDirective = ['$compile', '$parse', function($compile, $parse) {
// we can't just jqLite('
*/
var ngTranscludeMinErr = minErr('ngTransclude');
-var ngTranscludeDirective = ngDirective({
- restrict: 'EAC',
- link: function($scope, $element, $attrs, controller, $transclude) {
+var ngTranscludeDirective = ['$compile', function($compile) {
+ return {
+ restrict: 'EAC',
+ terminal: true,
+ compile: function ngTranscludeCompile(tElement) {
- if ($attrs.ngTransclude === $attrs.$attr.ngTransclude) {
- // If the attribute is of the form: `ng-transclude="ng-transclude"`
- // then treat it like the default
- $attrs.ngTransclude = '';
+ // Remove and cache any original content to act as a fallback
+ var fallbackLinkFn = $compile(tElement.contents());
+ tElement.empty();
+
+ return function ngTranscludePostLink($scope, $element, $attrs, controller, $transclude) {
+
+ if (!$transclude) {
+ throw ngTranscludeMinErr('orphan',
+ 'Illegal use of ngTransclude directive in the template! ' +
+ 'No parent directive that requires a transclusion found. ' +
+ 'Element: {0}',
+ startingTag($element));
+ }
+
+
+ // If the attribute is of the form: `ng-transclude="ng-transclude"` then treat it like the default
+ if ($attrs.ngTransclude === $attrs.$attr.ngTransclude) {
+ $attrs.ngTransclude = '';
+ }
+ var slotName = $attrs.ngTransclude || $attrs.ngTranscludeSlot;
+
+ // If the slot is required and no transclusion content is provided then this call will throw an error
+ $transclude(ngTranscludeCloneAttachFn, null, slotName);
+
+ // If the slot is optional and no transclusion content is provided then use the fallback content
+ if (slotName && !$transclude.isSlotFilled(slotName)) {
+ useFallbackContent();
+ }
+
+ function ngTranscludeCloneAttachFn(clone, transcludedScope) {
+ if (clone.length) {
+ $element.append(clone);
+ } else {
+ useFallbackContent();
+ // There is nothing linked against the transcluded scope since no content was available,
+ // so it should be safe to clean up the generated scope.
+ transcludedScope.$destroy();
+ }
+ }
+
+ function useFallbackContent() {
+ // Since this is the fallback content rather than the transcluded content,
+ // we link against the scope of this directive rather than the transcluded scope
+ fallbackLinkFn($scope, function(clone) {
+ $element.append(clone);
+ });
+ }
+ };
}
-
- function ngTranscludeCloneAttachFn(clone) {
- if (clone.length) {
- $element.empty();
- $element.append(clone);
- }
- }
-
- if (!$transclude) {
- throw ngTranscludeMinErr('orphan',
- 'Illegal use of ngTransclude directive in the template! ' +
- 'No parent directive that requires a transclusion found. ' +
- 'Element: {0}',
- startingTag($element));
- }
-
- // If there is no slot name defined or the slot name is not optional
- // then transclude the slot
- var slotName = $attrs.ngTransclude || $attrs.ngTranscludeSlot;
- $transclude(ngTranscludeCloneAttachFn, null, slotName);
- }
-});
+ };
+}];
/**
* @ngdoc directive
@@ -29742,7 +30795,7 @@ var SelectController =
//
// We can't just jqLite('