Update XStatic-Angular to 1.8.2
Related-Bug: #1927261 Change-Id: I8238e020df05825f6731499d027c0fd12cc2c00d
This commit is contained in:
parent
8c1eb54d83
commit
030dabe172
@ -11,9 +11,9 @@ NAME = __name__.split('.')[-1] # package name (e.g. 'foo' or 'foo_bar')
|
||||
# please use a all-lowercase valid python
|
||||
# package name
|
||||
|
||||
VERSION = '1.5.8' # version of the packaged files, please use the upstream
|
||||
VERSION = '1.8.2' # version of the packaged files, please use the upstream
|
||||
# version number
|
||||
BUILD = '0' # our package build number, so we can release new builds
|
||||
BUILD = '1' # our package build number, so we can release new builds
|
||||
# with fixes for xstatic stuff.
|
||||
PACKAGE_VERSION = VERSION + '.' + BUILD # version used for PyPi
|
||||
|
||||
|
652
xstatic/pkg/angular/data/angular-animate.js
vendored
652
xstatic/pkg/angular/data/angular-animate.js
vendored
File diff suppressed because it is too large
Load Diff
131
xstatic/pkg/angular/data/angular-aria.js
vendored
131
xstatic/pkg/angular/data/angular-aria.js
vendored
@ -1,6 +1,6 @@
|
||||
/**
|
||||
* @license AngularJS v1.5.8
|
||||
* (c) 2010-2016 Google, Inc. http://angularjs.org
|
||||
* @license AngularJS v1.8.2
|
||||
* (c) 2010-2020 Google, Inc. http://angularjs.org
|
||||
* License: MIT
|
||||
*/
|
||||
(function(window, angular) {'use strict';
|
||||
@ -15,30 +15,28 @@
|
||||
* attributes that convey state or semantic information about the application for users
|
||||
* of assistive technologies, such as screen readers.
|
||||
*
|
||||
* <div doc-module-components="ngAria"></div>
|
||||
*
|
||||
* ## Usage
|
||||
*
|
||||
* For ngAria to do its magic, simply include the module `ngAria` as a dependency. The following
|
||||
* directives are supported:
|
||||
* `ngModel`, `ngChecked`, `ngReadonly`, `ngRequired`, `ngValue`, `ngDisabled`, `ngShow`, `ngHide`, `ngClick`,
|
||||
* `ngDblClick`, and `ngMessages`.
|
||||
* `ngModel`, `ngChecked`, `ngReadonly`, `ngRequired`, `ngValue`, `ngDisabled`, `ngShow`, `ngHide`,
|
||||
* `ngClick`, `ngDblClick`, and `ngMessages`.
|
||||
*
|
||||
* Below is a more detailed breakdown of the attributes handled by ngAria:
|
||||
*
|
||||
* | Directive | Supported Attributes |
|
||||
* |---------------------------------------------|----------------------------------------------------------------------------------------|
|
||||
* | Directive | Supported Attributes |
|
||||
* |---------------------------------------------|-----------------------------------------------------------------------------------------------------|
|
||||
* | {@link ng.directive:ngModel ngModel} | aria-checked, aria-valuemin, aria-valuemax, aria-valuenow, aria-invalid, aria-required, input roles |
|
||||
* | {@link ng.directive:ngDisabled ngDisabled} | aria-disabled |
|
||||
* | {@link ng.directive:ngRequired ngRequired} | aria-required
|
||||
* | {@link ng.directive:ngChecked ngChecked} | aria-checked
|
||||
* | {@link ng.directive:ngReadonly ngReadonly} | aria-readonly |
|
||||
* | {@link ng.directive:ngValue ngValue} | aria-checked |
|
||||
* | {@link ng.directive:ngShow ngShow} | aria-hidden |
|
||||
* | {@link ng.directive:ngHide ngHide} | aria-hidden |
|
||||
* | {@link ng.directive:ngDblclick ngDblclick} | tabindex |
|
||||
* | {@link module:ngMessages ngMessages} | aria-live |
|
||||
* | {@link ng.directive:ngClick ngClick} | tabindex, keypress event, button role |
|
||||
* | {@link ng.directive:ngDisabled ngDisabled} | aria-disabled |
|
||||
* | {@link ng.directive:ngRequired ngRequired} | aria-required |
|
||||
* | {@link ng.directive:ngChecked ngChecked} | aria-checked |
|
||||
* | {@link ng.directive:ngReadonly ngReadonly} | aria-readonly |
|
||||
* | {@link ng.directive:ngValue ngValue} | aria-checked |
|
||||
* | {@link ng.directive:ngShow ngShow} | aria-hidden |
|
||||
* | {@link ng.directive:ngHide ngHide} | aria-hidden |
|
||||
* | {@link ng.directive:ngDblclick ngDblclick} | tabindex |
|
||||
* | {@link module:ngMessages ngMessages} | aria-live |
|
||||
* | {@link ng.directive:ngClick ngClick} | tabindex, keydown event, button role |
|
||||
*
|
||||
* Find out more information about each directive by reading the
|
||||
* {@link guide/accessibility ngAria Developer Guide}.
|
||||
@ -53,19 +51,25 @@
|
||||
* <md-checkbox ng-disabled="disabled" aria-disabled="true">
|
||||
* ```
|
||||
*
|
||||
* ## Disabling Attributes
|
||||
* It's possible to disable individual attributes added by ngAria with the
|
||||
* ## Disabling Specific Attributes
|
||||
* It is possible to disable individual attributes added by ngAria with the
|
||||
* {@link ngAria.$ariaProvider#config config} method. For more details, see the
|
||||
* {@link guide/accessibility Developer Guide}.
|
||||
*
|
||||
* ## Disabling `ngAria` on Specific Elements
|
||||
* It is possible to make `ngAria` ignore a specific element, by adding the `ng-aria-disable`
|
||||
* attribute on it. Note that only the element itself (and not its child elements) will be ignored.
|
||||
*/
|
||||
/* global -ngAriaModule */
|
||||
var ARIA_DISABLE_ATTR = 'ngAriaDisable';
|
||||
|
||||
var ngAriaModule = angular.module('ngAria', ['ng']).
|
||||
info({ angularVersion: '"1.8.2"' }).
|
||||
provider('$aria', $AriaProvider);
|
||||
|
||||
/**
|
||||
* Internal Utilities
|
||||
*/
|
||||
var nodeBlackList = ['BUTTON', 'A', 'INPUT', 'TEXTAREA', 'SELECT', 'DETAILS', 'SUMMARY'];
|
||||
var nativeAriaNodeNames = ['BUTTON', 'A', 'INPUT', 'TEXTAREA', 'SELECT', 'DETAILS', 'SUMMARY'];
|
||||
|
||||
var isNodeOneOf = function(elem, nodeTypeArray) {
|
||||
if (nodeTypeArray.indexOf(elem[0].nodeName) !== -1) {
|
||||
@ -75,6 +79,7 @@ var isNodeOneOf = function(elem, nodeTypeArray) {
|
||||
/**
|
||||
* @ngdoc provider
|
||||
* @name $ariaProvider
|
||||
* @this
|
||||
*
|
||||
* @description
|
||||
*
|
||||
@ -103,7 +108,7 @@ function $AriaProvider() {
|
||||
ariaInvalid: true,
|
||||
ariaValue: true,
|
||||
tabindex: true,
|
||||
bindKeypress: true,
|
||||
bindKeydown: true,
|
||||
bindRoleForClick: true
|
||||
};
|
||||
|
||||
@ -119,12 +124,15 @@ function $AriaProvider() {
|
||||
* - **ariaDisabled** – `{boolean}` – Enables/disables aria-disabled tags
|
||||
* - **ariaRequired** – `{boolean}` – Enables/disables aria-required tags
|
||||
* - **ariaInvalid** – `{boolean}` – Enables/disables aria-invalid tags
|
||||
* - **ariaValue** – `{boolean}` – Enables/disables aria-valuemin, aria-valuemax and aria-valuenow tags
|
||||
* - **ariaValue** – `{boolean}` – Enables/disables aria-valuemin, aria-valuemax and
|
||||
* aria-valuenow tags
|
||||
* - **tabindex** – `{boolean}` – Enables/disables tabindex tags
|
||||
* - **bindKeypress** – `{boolean}` – Enables/disables keypress event binding on `div` and
|
||||
* `li` elements with ng-click
|
||||
* - **bindRoleForClick** – `{boolean}` – Adds role=button to non-interactive elements like `div`
|
||||
* using ng-click, making them more accessible to users of assistive technologies
|
||||
* - **bindKeydown** – `{boolean}` – Enables/disables keyboard event binding on non-interactive
|
||||
* elements (such as `div` or `li`) using ng-click, making them more accessible to users of
|
||||
* assistive technologies
|
||||
* - **bindRoleForClick** – `{boolean}` – Adds role=button to non-interactive elements (such as
|
||||
* `div` or `li`) using ng-click, making them more accessible to users of assistive
|
||||
* technologies
|
||||
*
|
||||
* @description
|
||||
* Enables/disables various ARIA attributes
|
||||
@ -133,10 +141,12 @@ function $AriaProvider() {
|
||||
config = angular.extend(config, newConfig);
|
||||
};
|
||||
|
||||
function watchExpr(attrName, ariaAttr, nodeBlackList, negate) {
|
||||
function watchExpr(attrName, ariaAttr, nativeAriaNodeNames, negate) {
|
||||
return function(scope, elem, attr) {
|
||||
if (attr.hasOwnProperty(ARIA_DISABLE_ATTR)) return;
|
||||
|
||||
var ariaCamelName = attr.$normalize(ariaAttr);
|
||||
if (config[ariaCamelName] && !isNodeOneOf(elem, nodeBlackList) && !attr[ariaCamelName]) {
|
||||
if (config[ariaCamelName] && !isNodeOneOf(elem, nativeAriaNodeNames) && !attr[ariaCamelName]) {
|
||||
scope.$watch(attr[attrName], function(boolVal) {
|
||||
// ensure boolean value
|
||||
boolVal = negate ? !boolVal : !!boolVal;
|
||||
@ -150,7 +160,6 @@ function $AriaProvider() {
|
||||
* @name $aria
|
||||
*
|
||||
* @description
|
||||
* @priority 200
|
||||
*
|
||||
* The $aria service contains helper methods for applying common
|
||||
* [ARIA](http://www.w3.org/TR/wai-aria/) attributes to HTML directives.
|
||||
@ -161,7 +170,7 @@ function $AriaProvider() {
|
||||
*
|
||||
*```js
|
||||
* ngAriaModule.directive('ngDisabled', ['$aria', function($aria) {
|
||||
* return $aria.$$watchExpr('ngDisabled', 'aria-disabled', nodeBlackList, false);
|
||||
* return $aria.$$watchExpr('ngDisabled', 'aria-disabled', nativeAriaNodeNames, false);
|
||||
* }])
|
||||
*```
|
||||
* Shown above, the ngAria module creates a directive with the same signature as the
|
||||
@ -213,28 +222,31 @@ ngAriaModule.directive('ngShow', ['$aria', function($aria) {
|
||||
return $aria.$$watchExpr('ngHide', 'aria-hidden', [], false);
|
||||
}])
|
||||
.directive('ngValue', ['$aria', function($aria) {
|
||||
return $aria.$$watchExpr('ngValue', 'aria-checked', nodeBlackList, false);
|
||||
return $aria.$$watchExpr('ngValue', 'aria-checked', nativeAriaNodeNames, false);
|
||||
}])
|
||||
.directive('ngChecked', ['$aria', function($aria) {
|
||||
return $aria.$$watchExpr('ngChecked', 'aria-checked', nodeBlackList, false);
|
||||
return $aria.$$watchExpr('ngChecked', 'aria-checked', nativeAriaNodeNames, false);
|
||||
}])
|
||||
.directive('ngReadonly', ['$aria', function($aria) {
|
||||
return $aria.$$watchExpr('ngReadonly', 'aria-readonly', nodeBlackList, false);
|
||||
return $aria.$$watchExpr('ngReadonly', 'aria-readonly', nativeAriaNodeNames, false);
|
||||
}])
|
||||
.directive('ngRequired', ['$aria', function($aria) {
|
||||
return $aria.$$watchExpr('ngRequired', 'aria-required', nodeBlackList, false);
|
||||
return $aria.$$watchExpr('ngRequired', 'aria-required', nativeAriaNodeNames, false);
|
||||
}])
|
||||
.directive('ngModel', ['$aria', function($aria) {
|
||||
|
||||
function shouldAttachAttr(attr, normalizedAttr, elem, allowBlacklistEls) {
|
||||
return $aria.config(normalizedAttr) && !elem.attr(attr) && (allowBlacklistEls || !isNodeOneOf(elem, nodeBlackList));
|
||||
function shouldAttachAttr(attr, normalizedAttr, elem, allowNonAriaNodes) {
|
||||
return $aria.config(normalizedAttr) &&
|
||||
!elem.attr(attr) &&
|
||||
(allowNonAriaNodes || !isNodeOneOf(elem, nativeAriaNodeNames)) &&
|
||||
(elem.attr('type') !== 'hidden' || elem[0].nodeName !== 'INPUT');
|
||||
}
|
||||
|
||||
function shouldAttachRole(role, elem) {
|
||||
// if element does not have role attribute
|
||||
// AND element type is equal to role (if custom element has a type equaling shape) <-- remove?
|
||||
// AND element is not INPUT
|
||||
return !elem.attr('role') && (elem.attr('type') === role) && (elem[0].nodeName !== 'INPUT');
|
||||
// AND element is not in nativeAriaNodeNames
|
||||
return !elem.attr('role') && (elem.attr('type') === role) && !isNodeOneOf(elem, nativeAriaNodeNames);
|
||||
}
|
||||
|
||||
function getShape(attr, elem) {
|
||||
@ -251,17 +263,11 @@ ngAriaModule.directive('ngShow', ['$aria', function($aria) {
|
||||
require: 'ngModel',
|
||||
priority: 200, //Make sure watches are fired after any other directives that affect the ngModel value
|
||||
compile: function(elem, attr) {
|
||||
if (attr.hasOwnProperty(ARIA_DISABLE_ATTR)) return;
|
||||
|
||||
var shape = getShape(attr, elem);
|
||||
|
||||
return {
|
||||
pre: function(scope, elem, attr, ngModel) {
|
||||
if (shape === 'checkbox') {
|
||||
//Use the input[checkbox] $isEmpty implementation for elements with checkbox roles
|
||||
ngModel.$isEmpty = function(value) {
|
||||
return value === false;
|
||||
};
|
||||
}
|
||||
},
|
||||
post: function(scope, elem, attr, ngModel) {
|
||||
var needsTabIndex = shouldAttachAttr('tabindex', 'tabindex', elem, false);
|
||||
|
||||
@ -270,6 +276,8 @@ ngAriaModule.directive('ngShow', ['$aria', function($aria) {
|
||||
}
|
||||
|
||||
function getRadioReaction(newVal) {
|
||||
// Strict comparison would cause a BC
|
||||
// eslint-disable-next-line eqeqeq
|
||||
var boolVal = (attr.value == ngModel.$viewValue);
|
||||
elem.attr('aria-checked', boolVal);
|
||||
}
|
||||
@ -346,13 +354,15 @@ ngAriaModule.directive('ngShow', ['$aria', function($aria) {
|
||||
};
|
||||
}])
|
||||
.directive('ngDisabled', ['$aria', function($aria) {
|
||||
return $aria.$$watchExpr('ngDisabled', 'aria-disabled', nodeBlackList, false);
|
||||
return $aria.$$watchExpr('ngDisabled', 'aria-disabled', nativeAriaNodeNames, false);
|
||||
}])
|
||||
.directive('ngMessages', function() {
|
||||
return {
|
||||
restrict: 'A',
|
||||
require: '?ngMessages',
|
||||
link: function(scope, elem, attr, ngMessages) {
|
||||
if (attr.hasOwnProperty(ARIA_DISABLE_ATTR)) return;
|
||||
|
||||
if (!elem.attr('aria-live')) {
|
||||
elem.attr('aria-live', 'assertive');
|
||||
}
|
||||
@ -363,10 +373,12 @@ ngAriaModule.directive('ngShow', ['$aria', function($aria) {
|
||||
return {
|
||||
restrict: 'A',
|
||||
compile: function(elem, attr) {
|
||||
var fn = $parse(attr.ngClick, /* interceptorFn */ null, /* expensiveChecks */ true);
|
||||
if (attr.hasOwnProperty(ARIA_DISABLE_ATTR)) return;
|
||||
|
||||
var fn = $parse(attr.ngClick);
|
||||
return function(scope, elem, attr) {
|
||||
|
||||
if (!isNodeOneOf(elem, nodeBlackList)) {
|
||||
if (!isNodeOneOf(elem, nativeAriaNodeNames)) {
|
||||
|
||||
if ($aria.config('bindRoleForClick') && !elem.attr('role')) {
|
||||
elem.attr('role', 'button');
|
||||
@ -376,10 +388,17 @@ ngAriaModule.directive('ngShow', ['$aria', function($aria) {
|
||||
elem.attr('tabindex', 0);
|
||||
}
|
||||
|
||||
if ($aria.config('bindKeypress') && !attr.ngKeypress) {
|
||||
elem.on('keypress', function(event) {
|
||||
if ($aria.config('bindKeydown') && !attr.ngKeydown && !attr.ngKeypress && !attr.ngKeyup) {
|
||||
elem.on('keydown', function(event) {
|
||||
var keyCode = event.which || event.keyCode;
|
||||
if (keyCode === 32 || keyCode === 13) {
|
||||
|
||||
if (keyCode === 13 || keyCode === 32) {
|
||||
// If the event is triggered on a non-interactive element ...
|
||||
if (nativeAriaNodeNames.indexOf(event.target.nodeName) === -1 && !event.target.isContentEditable) {
|
||||
// ... prevent the default browser behavior (e.g. scrolling when pressing spacebar)
|
||||
// See https://github.com/angular/angular.js/issues/16664
|
||||
event.preventDefault();
|
||||
}
|
||||
scope.$apply(callback);
|
||||
}
|
||||
|
||||
@ -395,7 +414,9 @@ ngAriaModule.directive('ngShow', ['$aria', function($aria) {
|
||||
}])
|
||||
.directive('ngDblclick', ['$aria', function($aria) {
|
||||
return function(scope, elem, attr) {
|
||||
if ($aria.config('tabindex') && !elem.attr('tabindex') && !isNodeOneOf(elem, nodeBlackList)) {
|
||||
if (attr.hasOwnProperty(ARIA_DISABLE_ATTR)) return;
|
||||
|
||||
if ($aria.config('tabindex') && !elem.attr('tabindex') && !isNodeOneOf(elem, nativeAriaNodeNames)) {
|
||||
elem.attr('tabindex', 0);
|
||||
}
|
||||
};
|
||||
|
117
xstatic/pkg/angular/data/angular-cookies.js
vendored
117
xstatic/pkg/angular/data/angular-cookies.js
vendored
@ -1,6 +1,6 @@
|
||||
/**
|
||||
* @license AngularJS v1.5.8
|
||||
* (c) 2010-2016 Google, Inc. http://angularjs.org
|
||||
* @license AngularJS v1.8.2
|
||||
* (c) 2010-2020 Google, Inc. http://angularjs.org
|
||||
* License: MIT
|
||||
*/
|
||||
(function(window, angular) {'use strict';
|
||||
@ -10,25 +10,21 @@
|
||||
* @name ngCookies
|
||||
* @description
|
||||
*
|
||||
* # ngCookies
|
||||
*
|
||||
* The `ngCookies` module provides a convenient wrapper for reading and writing browser cookies.
|
||||
*
|
||||
*
|
||||
* <div doc-module-components="ngCookies"></div>
|
||||
*
|
||||
* See {@link ngCookies.$cookies `$cookies`} for usage.
|
||||
*/
|
||||
|
||||
|
||||
angular.module('ngCookies', ['ng']).
|
||||
info({ angularVersion: '"1.8.2"' }).
|
||||
/**
|
||||
* @ngdoc provider
|
||||
* @name $cookiesProvider
|
||||
* @description
|
||||
* Use `$cookiesProvider` to change the default behavior of the {@link ngCookies.$cookies $cookies} service.
|
||||
* */
|
||||
provider('$cookies', [function $CookiesProvider() {
|
||||
provider('$cookies', [/** @this */function $CookiesProvider() {
|
||||
/**
|
||||
* @ngdoc property
|
||||
* @name $cookiesProvider#defaults
|
||||
@ -47,10 +43,24 @@ angular.module('ngCookies', ['ng']).
|
||||
* or a Date object indicating the exact date/time this cookie will expire.
|
||||
* - **secure** - `{boolean}` - If `true`, then the cookie will only be available through a
|
||||
* secured connection.
|
||||
* - **samesite** - `{string}` - prevents the browser from sending the cookie along with cross-site requests.
|
||||
* Accepts the values `lax` and `strict`. See the [OWASP Wiki](https://www.owasp.org/index.php/SameSite)
|
||||
* for more info. Note that as of May 2018, not all browsers support `SameSite`,
|
||||
* so it cannot be used as a single measure against Cross-Site-Request-Forgery (CSRF) attacks.
|
||||
*
|
||||
* Note: By default, the address that appears in your `<base>` tag will be used as the path.
|
||||
* This is important so that cookies will be visible for all routes when html5mode is enabled.
|
||||
*
|
||||
* @example
|
||||
*
|
||||
* ```js
|
||||
* angular.module('cookiesProviderExample', ['ngCookies'])
|
||||
* .config(['$cookiesProvider', function($cookiesProvider) {
|
||||
* // Setting default options
|
||||
* $cookiesProvider.defaults.domain = 'foo.com';
|
||||
* $cookiesProvider.defaults.secure = true;
|
||||
* }]);
|
||||
* ```
|
||||
**/
|
||||
var defaults = this.defaults = {};
|
||||
|
||||
@ -66,7 +76,7 @@ angular.module('ngCookies', ['ng']).
|
||||
* Provides read/write access to browser's cookies.
|
||||
*
|
||||
* <div class="alert alert-info">
|
||||
* Up until Angular 1.3, `$cookies` exposed properties that represented the
|
||||
* Up until AngularJS 1.3, `$cookies` exposed properties that represented the
|
||||
* current browser cookie values. In version 1.4, this behavior has changed, and
|
||||
* `$cookies` now provides a standard api of getters, setters etc.
|
||||
* </div>
|
||||
@ -179,86 +189,6 @@ angular.module('ngCookies', ['ng']).
|
||||
}];
|
||||
}]);
|
||||
|
||||
angular.module('ngCookies').
|
||||
/**
|
||||
* @ngdoc service
|
||||
* @name $cookieStore
|
||||
* @deprecated
|
||||
* @requires $cookies
|
||||
*
|
||||
* @description
|
||||
* Provides a key-value (string-object) storage, that is backed by session cookies.
|
||||
* Objects put or retrieved from this storage are automatically serialized or
|
||||
* deserialized by angular's toJson/fromJson.
|
||||
*
|
||||
* Requires the {@link ngCookies `ngCookies`} module to be installed.
|
||||
*
|
||||
* <div class="alert alert-danger">
|
||||
* **Note:** The $cookieStore service is **deprecated**.
|
||||
* Please use the {@link ngCookies.$cookies `$cookies`} service instead.
|
||||
* </div>
|
||||
*
|
||||
* @example
|
||||
*
|
||||
* ```js
|
||||
* angular.module('cookieStoreExample', ['ngCookies'])
|
||||
* .controller('ExampleController', ['$cookieStore', function($cookieStore) {
|
||||
* // Put cookie
|
||||
* $cookieStore.put('myFavorite','oatmeal');
|
||||
* // Get cookie
|
||||
* var favoriteCookie = $cookieStore.get('myFavorite');
|
||||
* // Removing a cookie
|
||||
* $cookieStore.remove('myFavorite');
|
||||
* }]);
|
||||
* ```
|
||||
*/
|
||||
factory('$cookieStore', ['$cookies', function($cookies) {
|
||||
|
||||
return {
|
||||
/**
|
||||
* @ngdoc method
|
||||
* @name $cookieStore#get
|
||||
*
|
||||
* @description
|
||||
* Returns the value of given cookie key
|
||||
*
|
||||
* @param {string} key Id to use for lookup.
|
||||
* @returns {Object} Deserialized cookie value, undefined if the cookie does not exist.
|
||||
*/
|
||||
get: function(key) {
|
||||
return $cookies.getObject(key);
|
||||
},
|
||||
|
||||
/**
|
||||
* @ngdoc method
|
||||
* @name $cookieStore#put
|
||||
*
|
||||
* @description
|
||||
* Sets a value for given cookie key
|
||||
*
|
||||
* @param {string} key Id for the `value`.
|
||||
* @param {Object} value Value to be stored.
|
||||
*/
|
||||
put: function(key, value) {
|
||||
$cookies.putObject(key, value);
|
||||
},
|
||||
|
||||
/**
|
||||
* @ngdoc method
|
||||
* @name $cookieStore#remove
|
||||
*
|
||||
* @description
|
||||
* Remove given cookie
|
||||
*
|
||||
* @param {string} key Id of the key-value pair to delete.
|
||||
*/
|
||||
remove: function(key) {
|
||||
$cookies.remove(key);
|
||||
}
|
||||
};
|
||||
|
||||
}]);
|
||||
|
||||
/**
|
||||
* @name $$cookieWriter
|
||||
* @requires $document
|
||||
@ -292,6 +222,7 @@ function $$CookieWriter($document, $log, $browser) {
|
||||
str += options.domain ? ';domain=' + options.domain : '';
|
||||
str += expires ? ';expires=' + expires.toUTCString() : '';
|
||||
str += options.secure ? ';secure' : '';
|
||||
str += options.samesite ? ';samesite=' + options.samesite : '';
|
||||
|
||||
// per http://www.ietf.org/rfc/rfc2109.txt browser must allow at minimum:
|
||||
// - 300 cookies
|
||||
@ -299,9 +230,9 @@ function $$CookieWriter($document, $log, $browser) {
|
||||
// - 4096 bytes per cookie
|
||||
var cookieLength = str.length + 1;
|
||||
if (cookieLength > 4096) {
|
||||
$log.warn("Cookie '" + name +
|
||||
"' possibly not set or overflowed because it was too large (" +
|
||||
cookieLength + " > 4096 bytes)!");
|
||||
$log.warn('Cookie \'' + name +
|
||||
'\' possibly not set or overflowed because it was too large (' +
|
||||
cookieLength + ' > 4096 bytes)!');
|
||||
}
|
||||
|
||||
return str;
|
||||
@ -314,7 +245,7 @@ function $$CookieWriter($document, $log, $browser) {
|
||||
|
||||
$$CookieWriter.$inject = ['$document', '$log', '$browser'];
|
||||
|
||||
angular.module('ngCookies').provider('$$cookieWriter', function $$CookieWriterProvider() {
|
||||
angular.module('ngCookies').provider('$$cookieWriter', /** @this */ function $$CookieWriterProvider() {
|
||||
this.$get = $$CookieWriter;
|
||||
});
|
||||
|
||||
|
138
xstatic/pkg/angular/data/angular-loader.js
vendored
138
xstatic/pkg/angular/data/angular-loader.js
vendored
@ -1,6 +1,6 @@
|
||||
/**
|
||||
* @license AngularJS v1.5.8
|
||||
* (c) 2010-2016 Google, Inc. http://angularjs.org
|
||||
* @license AngularJS v1.8.2
|
||||
* (c) 2010-2020 Google, Inc. http://angularjs.org
|
||||
* License: MIT
|
||||
*/
|
||||
|
||||
@ -9,9 +9,17 @@
|
||||
|
||||
/* global toDebugString: true */
|
||||
|
||||
function serializeObject(obj) {
|
||||
function serializeObject(obj, maxDepth) {
|
||||
var seen = [];
|
||||
|
||||
// There is no direct way to stringify object until reaching a specific depth
|
||||
// and a very deep object can cause a performance issue, so we copy the object
|
||||
// based on this specific depth and then stringify it.
|
||||
if (isValidObjectMaxDepth(maxDepth)) {
|
||||
// This file is also included in `angular-loader`, so `copy()` might not always be available in
|
||||
// the closure. Therefore, it is lazily retrieved as `angular.copy()` when needed.
|
||||
obj = angular.copy(obj, null, maxDepth);
|
||||
}
|
||||
return JSON.stringify(obj, function(key, val) {
|
||||
val = toJsonReplacer(key, val);
|
||||
if (isObject(val)) {
|
||||
@ -24,13 +32,13 @@ function serializeObject(obj) {
|
||||
});
|
||||
}
|
||||
|
||||
function toDebugString(obj) {
|
||||
function toDebugString(obj, maxDepth) {
|
||||
if (typeof obj === 'function') {
|
||||
return obj.toString().replace(/ \{[\s\S]*$/, '');
|
||||
} else if (isUndefined(obj)) {
|
||||
return 'undefined';
|
||||
} else if (typeof obj !== 'string') {
|
||||
return serializeObject(obj);
|
||||
return serializeObject(obj, maxDepth);
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
@ -39,7 +47,7 @@ function toDebugString(obj) {
|
||||
* @description
|
||||
*
|
||||
* This object provides a utility for producing rich Error messages within
|
||||
* Angular. It can be called as follows:
|
||||
* AngularJS. It can be called as follows:
|
||||
*
|
||||
* var exampleMinErr = minErr('example');
|
||||
* throw exampleMinErr('one', 'This {0} is {1}', foo, bar);
|
||||
@ -56,7 +64,7 @@ function toDebugString(obj) {
|
||||
* Since data will be parsed statically during a build step, some restrictions
|
||||
* are applied with respect to how minErr instances are created and called.
|
||||
* Instances should have names of the form namespaceMinErr for a minErr created
|
||||
* using minErr('namespace') . Error codes, namespaces and template strings
|
||||
* using minErr('namespace'). Error codes, namespaces and template strings
|
||||
* should all be static strings, not variables or general expressions.
|
||||
*
|
||||
* @param {string} module The namespace to use for the new minErr instance.
|
||||
@ -67,32 +75,41 @@ function toDebugString(obj) {
|
||||
|
||||
function minErr(module, ErrorConstructor) {
|
||||
ErrorConstructor = ErrorConstructor || Error;
|
||||
return function() {
|
||||
var SKIP_INDEXES = 2;
|
||||
|
||||
var templateArgs = arguments,
|
||||
code = templateArgs[0],
|
||||
var url = 'https://errors.angularjs.org/"1.8.2"/';
|
||||
var regex = url.replace('.', '\\.') + '[\\s\\S]*';
|
||||
var errRegExp = new RegExp(regex, 'g');
|
||||
|
||||
return function() {
|
||||
var code = arguments[0],
|
||||
template = arguments[1],
|
||||
message = '[' + (module ? module + ':' : '') + code + '] ',
|
||||
template = templateArgs[1],
|
||||
templateArgs = sliceArgs(arguments, 2).map(function(arg) {
|
||||
return toDebugString(arg, minErrConfig.objectMaxDepth);
|
||||
}),
|
||||
paramPrefix, i;
|
||||
|
||||
message += template.replace(/\{\d+\}/g, function(match) {
|
||||
var index = +match.slice(1, -1),
|
||||
shiftedIndex = index + SKIP_INDEXES;
|
||||
// A minErr message has two parts: the message itself and the url that contains the
|
||||
// encoded message.
|
||||
// The message's parameters can contain other error messages which also include error urls.
|
||||
// To prevent the messages from getting too long, we strip the error urls from the parameters.
|
||||
|
||||
if (shiftedIndex < templateArgs.length) {
|
||||
return toDebugString(templateArgs[shiftedIndex]);
|
||||
message += template.replace(/\{\d+\}/g, function(match) {
|
||||
var index = +match.slice(1, -1);
|
||||
|
||||
if (index < templateArgs.length) {
|
||||
return templateArgs[index].replace(errRegExp, '');
|
||||
}
|
||||
|
||||
return match;
|
||||
});
|
||||
|
||||
message += '\nhttp://errors.angularjs.org/1.5.8/' +
|
||||
(module ? module + '/' : '') + code;
|
||||
message += '\n' + url + (module ? module + '/' : '') + code;
|
||||
|
||||
for (i = SKIP_INDEXES, paramPrefix = '?'; i < templateArgs.length; i++, paramPrefix = '&') {
|
||||
message += paramPrefix + 'p' + (i - SKIP_INDEXES) + '=' +
|
||||
encodeURIComponent(toDebugString(templateArgs[i]));
|
||||
if (minErrConfig.urlErrorParamsEnabled) {
|
||||
for (i = 0, paramPrefix = '?'; i < templateArgs.length; i++, paramPrefix = '&') {
|
||||
message += paramPrefix + 'p' + i + '=' + encodeURIComponent(templateArgs[i]);
|
||||
}
|
||||
}
|
||||
|
||||
return new ErrorConstructor(message);
|
||||
@ -105,7 +122,7 @@ function minErr(module, ErrorConstructor) {
|
||||
* @module ng
|
||||
* @description
|
||||
*
|
||||
* Interface for configuring angular {@link angular.module modules}.
|
||||
* Interface for configuring AngularJS {@link angular.module modules}.
|
||||
*/
|
||||
|
||||
function setupModuleLoader(window) {
|
||||
@ -132,9 +149,9 @@ function setupModuleLoader(window) {
|
||||
* @module ng
|
||||
* @description
|
||||
*
|
||||
* The `angular.module` is a global place for creating, registering and retrieving Angular
|
||||
* The `angular.module` is a global place for creating, registering and retrieving AngularJS
|
||||
* modules.
|
||||
* All modules (angular core or 3rd party) that should be available to an application must be
|
||||
* All modules (AngularJS core or 3rd party) that should be available to an application must be
|
||||
* registered using this mechanism.
|
||||
*
|
||||
* Passing one argument retrieves an existing {@link angular.Module},
|
||||
@ -178,6 +195,9 @@ function setupModuleLoader(window) {
|
||||
* @returns {angular.Module} new module with the {@link angular.Module} api.
|
||||
*/
|
||||
return function module(name, requires, configFn) {
|
||||
|
||||
var info = {};
|
||||
|
||||
var assertNotHasOwnProperty = function(name, context) {
|
||||
if (name === 'hasOwnProperty') {
|
||||
throw ngMinErr('badname', 'hasOwnProperty is not a valid {0} name', context);
|
||||
@ -190,9 +210,9 @@ function setupModuleLoader(window) {
|
||||
}
|
||||
return ensure(modules, name, function() {
|
||||
if (!requires) {
|
||||
throw $injectorMinErr('nomod', "Module '{0}' is not available! You either misspelled " +
|
||||
"the module name or forgot to load it. If registering a module ensure that you " +
|
||||
"specify the dependencies as the second argument.", name);
|
||||
throw $injectorMinErr('nomod', 'Module \'{0}\' is not available! You either misspelled ' +
|
||||
'the module name or forgot to load it. If registering a module ensure that you ' +
|
||||
'specify the dependencies as the second argument.', name);
|
||||
}
|
||||
|
||||
/** @type {!Array.<Array.<*>>} */
|
||||
@ -213,6 +233,45 @@ function setupModuleLoader(window) {
|
||||
_configBlocks: configBlocks,
|
||||
_runBlocks: runBlocks,
|
||||
|
||||
/**
|
||||
* @ngdoc method
|
||||
* @name angular.Module#info
|
||||
* @module ng
|
||||
*
|
||||
* @param {Object=} info Information about the module
|
||||
* @returns {Object|Module} The current info object for this module if called as a getter,
|
||||
* or `this` if called as a setter.
|
||||
*
|
||||
* @description
|
||||
* Read and write custom information about this module.
|
||||
* For example you could put the version of the module in here.
|
||||
*
|
||||
* ```js
|
||||
* angular.module('myModule', []).info({ version: '1.0.0' });
|
||||
* ```
|
||||
*
|
||||
* The version could then be read back out by accessing the module elsewhere:
|
||||
*
|
||||
* ```
|
||||
* var version = angular.module('myModule').info().version;
|
||||
* ```
|
||||
*
|
||||
* You can also retrieve this information during runtime via the
|
||||
* {@link $injector#modules `$injector.modules`} property:
|
||||
*
|
||||
* ```js
|
||||
* var version = $injector.modules['myModule'].info().version;
|
||||
* ```
|
||||
*/
|
||||
info: function(value) {
|
||||
if (isDefined(value)) {
|
||||
if (!isObject(value)) throw ngMinErr('aobj', 'Argument \'{0}\' must be an object', 'value');
|
||||
info = value;
|
||||
return this;
|
||||
}
|
||||
return info;
|
||||
},
|
||||
|
||||
/**
|
||||
* @ngdoc property
|
||||
* @name angular.Module#requires
|
||||
@ -302,7 +361,7 @@ function setupModuleLoader(window) {
|
||||
* @description
|
||||
* See {@link auto.$provide#decorator $provide.decorator()}.
|
||||
*/
|
||||
decorator: invokeLaterAndSetModuleName('$provide', 'decorator'),
|
||||
decorator: invokeLaterAndSetModuleName('$provide', 'decorator', configBlocks),
|
||||
|
||||
/**
|
||||
* @ngdoc method
|
||||
@ -342,13 +401,13 @@ function setupModuleLoader(window) {
|
||||
* @ngdoc method
|
||||
* @name angular.Module#filter
|
||||
* @module ng
|
||||
* @param {string} name Filter name - this must be a valid angular expression identifier
|
||||
* @param {string} name Filter name - this must be a valid AngularJS expression identifier
|
||||
* @param {Function} filterFactory Factory function for creating new instance of filter.
|
||||
* @description
|
||||
* See {@link ng.$filterProvider#register $filterProvider.register()}.
|
||||
*
|
||||
* <div class="alert alert-warning">
|
||||
* **Note:** Filter names must be valid angular {@link expression} identifiers, such as `uppercase` or `orderBy`.
|
||||
* **Note:** Filter names must be valid AngularJS {@link expression} identifiers, such as `uppercase` or `orderBy`.
|
||||
* Names with special characters, such as hyphens and dots, are not allowed. If you wish to namespace
|
||||
* your filters, then you can use capitalization (`myappSubsectionFilterx`) or underscores
|
||||
* (`myapp_subsection_filterx`).
|
||||
@ -385,7 +444,8 @@ function setupModuleLoader(window) {
|
||||
* @ngdoc method
|
||||
* @name angular.Module#component
|
||||
* @module ng
|
||||
* @param {string} name Name of the component in camel-case (i.e. myComp which will match as my-comp)
|
||||
* @param {string|Object} name Name of the component in camelCase (i.e. `myComp` which will match `<my-comp>`),
|
||||
* or an object map of components where the keys are the names and the values are the component definition objects.
|
||||
* @param {Object} options Component definition object (a simplified
|
||||
* {@link ng.$compile#directive-definition-object directive definition object})
|
||||
*
|
||||
@ -401,7 +461,13 @@ function setupModuleLoader(window) {
|
||||
* @param {Function} configFn Execute this function on module load. Useful for service
|
||||
* configuration.
|
||||
* @description
|
||||
* Use this method to register work which needs to be performed on module loading.
|
||||
* Use this method to configure services by injecting their
|
||||
* {@link angular.Module#provider `providers`}, e.g. for adding routes to the
|
||||
* {@link ngRoute.$routeProvider $routeProvider}.
|
||||
*
|
||||
* Note that you can only inject {@link angular.Module#provider `providers`} and
|
||||
* {@link angular.Module#constant `constants`} into this function.
|
||||
*
|
||||
* For more about how to configure services, see
|
||||
* {@link providers#provider-recipe Provider Recipe}.
|
||||
*/
|
||||
@ -448,10 +514,11 @@ function setupModuleLoader(window) {
|
||||
* @param {string} method
|
||||
* @returns {angular.Module}
|
||||
*/
|
||||
function invokeLaterAndSetModuleName(provider, method) {
|
||||
function invokeLaterAndSetModuleName(provider, method, queue) {
|
||||
if (!queue) queue = invokeQueue;
|
||||
return function(recipeName, factoryFunction) {
|
||||
if (factoryFunction && isFunction(factoryFunction)) factoryFunction.$$moduleName = name;
|
||||
invokeQueue.push([provider, method, arguments]);
|
||||
queue.push([provider, method, arguments]);
|
||||
return moduleInstance;
|
||||
};
|
||||
}
|
||||
@ -481,4 +548,3 @@ setupModuleLoader(window);
|
||||
* } }
|
||||
*/
|
||||
angular.Module;
|
||||
|
||||
|
156
xstatic/pkg/angular/data/angular-message-format.js
vendored
156
xstatic/pkg/angular/data/angular-message-format.js
vendored
@ -1,6 +1,6 @@
|
||||
/**
|
||||
* @license AngularJS v1.5.8
|
||||
* (c) 2010-2016 Google, Inc. http://angularjs.org
|
||||
* @license AngularJS v1.8.2
|
||||
* (c) 2010-2020 Google, Inc. http://angularjs.org
|
||||
* License: MIT
|
||||
*/
|
||||
(function(window, angular) {'use strict';
|
||||
@ -13,22 +13,14 @@
|
||||
/* global isFunction: false */
|
||||
/* global noop: false */
|
||||
/* global toJson: false */
|
||||
|
||||
function stringify(value) {
|
||||
if (value == null /* null/undefined */) { return ''; }
|
||||
switch (typeof value) {
|
||||
case 'string': return value;
|
||||
case 'number': return '' + value;
|
||||
default: return toJson(value);
|
||||
}
|
||||
}
|
||||
/* global $$stringify: false */
|
||||
|
||||
// Convert an index into the string into line/column for use in error messages
|
||||
// As such, this doesn't have to be efficient.
|
||||
function indexToLineAndColumn(text, index) {
|
||||
var lines = text.split(/\n/g);
|
||||
for (var i=0; i < lines.length; i++) {
|
||||
var line=lines[i];
|
||||
for (var i = 0; i < lines.length; i++) {
|
||||
var line = lines[i];
|
||||
if (index >= line.length) {
|
||||
index -= line.length;
|
||||
} else {
|
||||
@ -47,7 +39,7 @@ function parseTextLiteral(text) {
|
||||
parsedFn['$$watchDelegate'] = function watchDelegate(scope, listener, objectEquality) {
|
||||
var unwatch = scope['$watch'](noop,
|
||||
function textLiteralWatcher() {
|
||||
if (isFunction(listener)) { listener.call(null, text, text, scope); }
|
||||
listener(text, text, scope);
|
||||
unwatch();
|
||||
},
|
||||
objectEquality);
|
||||
@ -64,14 +56,14 @@ function subtractOffset(expressionFn, offset) {
|
||||
return expressionFn;
|
||||
}
|
||||
function minusOffset(value) {
|
||||
return (value == void 0) ? value : value - offset;
|
||||
return (value == null) ? value : value - offset;
|
||||
}
|
||||
function parsedFn(context) { return minusOffset(expressionFn(context)); }
|
||||
var unwatch;
|
||||
parsedFn['$$watchDelegate'] = function watchDelegate(scope, listener, objectEquality) {
|
||||
unwatch = scope['$watch'](expressionFn,
|
||||
function pluralExpressionWatchListener(newValue, oldValue) {
|
||||
if (isFunction(listener)) { listener.call(null, minusOffset(newValue), minusOffset(oldValue), scope); }
|
||||
listener(minusOffset(newValue), minusOffset(oldValue), scope);
|
||||
},
|
||||
objectEquality);
|
||||
return unwatch;
|
||||
@ -96,7 +88,7 @@ function MessageSelectorBase(expressionFn, choices) {
|
||||
var self = this;
|
||||
this.expressionFn = expressionFn;
|
||||
this.choices = choices;
|
||||
if (choices["other"] === void 0) {
|
||||
if (choices['other'] === undefined) {
|
||||
throw $interpolateMinErr('reqother', '“other” is a required option.');
|
||||
}
|
||||
this.parsedFn = function(context) { return self.getResult(context); };
|
||||
@ -130,7 +122,7 @@ function MessageSelectorWatchers(msgSelector, scope, listener, objectEquality) {
|
||||
this.msgSelector = msgSelector;
|
||||
this.listener = listener;
|
||||
this.objectEquality = objectEquality;
|
||||
this.lastMessage = void 0;
|
||||
this.lastMessage = undefined;
|
||||
this.messageFnWatcher = noop;
|
||||
var expressionFnListener = function(newValue, oldValue) { return self.expressionFnListener(newValue, oldValue); };
|
||||
this.expressionFnWatcher = scope['$watch'](msgSelector.expressionFn, expressionFnListener, objectEquality);
|
||||
@ -145,9 +137,7 @@ MessageSelectorWatchers.prototype.expressionFnListener = function expressionFnLi
|
||||
};
|
||||
|
||||
MessageSelectorWatchers.prototype.messageFnListener = function messageFnListener(newMessage, oldMessage) {
|
||||
if (isFunction(this.listener)) {
|
||||
this.listener.call(null, newMessage, newMessage === oldMessage ? newMessage : this.lastMessage, this.scope);
|
||||
}
|
||||
this.listener.call(null, newMessage, newMessage === oldMessage ? newMessage : this.lastMessage, this.scope);
|
||||
this.lastMessage = newMessage;
|
||||
};
|
||||
|
||||
@ -170,7 +160,7 @@ SelectMessageProto.prototype = MessageSelectorBase.prototype;
|
||||
|
||||
SelectMessage.prototype = new SelectMessageProto();
|
||||
SelectMessage.prototype.categorizeValue = function categorizeSelectValue(value) {
|
||||
return (this.choices[value] !== void 0) ? value : "other";
|
||||
return (this.choices[value] !== undefined) ? value : 'other';
|
||||
};
|
||||
|
||||
/**
|
||||
@ -190,12 +180,12 @@ PluralMessageProto.prototype = MessageSelectorBase.prototype;
|
||||
PluralMessage.prototype = new PluralMessageProto();
|
||||
PluralMessage.prototype.categorizeValue = function categorizePluralValue(value) {
|
||||
if (isNaN(value)) {
|
||||
return "other";
|
||||
} else if (this.choices[value] !== void 0) {
|
||||
return 'other';
|
||||
} else if (this.choices[value] !== undefined) {
|
||||
return value;
|
||||
} else {
|
||||
var category = this.pluralCat(value - this.offset);
|
||||
return (this.choices[category] !== void 0) ? category : "other";
|
||||
return (this.choices[category] !== undefined) ? category : 'other';
|
||||
}
|
||||
};
|
||||
|
||||
@ -264,7 +254,7 @@ InterpolationParts.prototype.getExpressionValues = function getExpressionValues(
|
||||
InterpolationParts.prototype.getResult = function getResult(expressionValues) {
|
||||
for (var i = 0; i < this.expressionIndices.length; i++) {
|
||||
var expressionValue = expressionValues[i];
|
||||
if (this.allOrNothing && expressionValue === void 0) return;
|
||||
if (this.allOrNothing && expressionValue === undefined) return;
|
||||
this.textParts[this.expressionIndices[i]] = expressionValue;
|
||||
}
|
||||
return this.textParts.join('');
|
||||
@ -275,7 +265,7 @@ InterpolationParts.prototype.toParsedFn = function toParsedFn(mustHaveExpression
|
||||
var self = this;
|
||||
this.flushPartialText();
|
||||
if (mustHaveExpression && this.expressionFns.length === 0) {
|
||||
return void 0;
|
||||
return undefined;
|
||||
}
|
||||
if (this.textParts.length === 0) {
|
||||
return parseTextLiteral('');
|
||||
@ -284,7 +274,7 @@ InterpolationParts.prototype.toParsedFn = function toParsedFn(mustHaveExpression
|
||||
$interpolateMinErr['throwNoconcat'](originalText);
|
||||
}
|
||||
if (this.expressionFns.length === 0) {
|
||||
if (this.textParts.length != 1) { this.errorInParseLogic(); }
|
||||
if (this.textParts.length !== 1) { this.errorInParseLogic(); }
|
||||
return parseTextLiteral(this.textParts[0]);
|
||||
}
|
||||
var parsedFn = function(context) {
|
||||
@ -311,7 +301,7 @@ InterpolationParts.prototype.watchDelegate = function watchDelegate(scope, liste
|
||||
function InterpolationPartsWatcher(interpolationParts, scope, listener, objectEquality) {
|
||||
this.interpolationParts = interpolationParts;
|
||||
this.scope = scope;
|
||||
this.previousResult = (void 0);
|
||||
this.previousResult = (undefined);
|
||||
this.listener = listener;
|
||||
var self = this;
|
||||
this.expressionFnsWatcher = scope['$watchGroup'](interpolationParts.expressionFns, function(newExpressionValues, oldExpressionValues) {
|
||||
@ -321,9 +311,7 @@ function InterpolationPartsWatcher(interpolationParts, scope, listener, objectEq
|
||||
|
||||
InterpolationPartsWatcher.prototype.watchListener = function watchListener(newExpressionValues, oldExpressionValues) {
|
||||
var result = this.interpolationParts.getResult(newExpressionValues);
|
||||
if (isFunction(this.listener)) {
|
||||
this.listener.call(null, result, newExpressionValues === oldExpressionValues ? result : this.previousResult, this.scope);
|
||||
}
|
||||
this.listener.call(null, result, newExpressionValues === oldExpressionValues ? result : this.previousResult, this.scope);
|
||||
this.previousResult = result;
|
||||
};
|
||||
|
||||
@ -423,7 +411,7 @@ MessageFormatParser.prototype.popState = function popState() {
|
||||
MessageFormatParser.prototype.matchRe = function matchRe(re, search) {
|
||||
re.lastIndex = this.index;
|
||||
var match = re.exec(this.text);
|
||||
if (match != null && (search === true || (match.index == this.index))) {
|
||||
if (match != null && (search === true || (match.index === this.index))) {
|
||||
this.index = re.lastIndex;
|
||||
return match;
|
||||
}
|
||||
@ -461,7 +449,7 @@ MessageFormatParser.prototype.errorInParseLogic = function errorInParseLogic() {
|
||||
};
|
||||
|
||||
MessageFormatParser.prototype.assertRuleOrNull = function assertRuleOrNull(rule) {
|
||||
if (rule === void 0) {
|
||||
if (rule === undefined) {
|
||||
this.errorInParseLogic();
|
||||
}
|
||||
};
|
||||
@ -477,7 +465,7 @@ MessageFormatParser.prototype.errorExpecting = function errorExpecting() {
|
||||
position.line, position.column, this.text);
|
||||
}
|
||||
var word = match[1];
|
||||
if (word == "select" || word == "plural") {
|
||||
if (word === 'select' || word === 'plural') {
|
||||
position = indexToLineAndColumn(this.text, this.index);
|
||||
throw $interpolateMinErr('reqcomma',
|
||||
'Expected a comma after the keyword “{0}” at line {1}, column {2} of text “{3}”',
|
||||
@ -505,7 +493,7 @@ MessageFormatParser.prototype.ruleString = function ruleString() {
|
||||
MessageFormatParser.prototype.startStringAtMatch = function startStringAtMatch(match) {
|
||||
this.stringStartIndex = match.index;
|
||||
this.stringQuote = match[0];
|
||||
this.stringInterestsRe = this.stringQuote == "'" ? SQUOTED_STRING_INTEREST_RE : DQUOTED_STRING_INTEREST_RE;
|
||||
this.stringInterestsRe = this.stringQuote === '\'' ? SQUOTED_STRING_INTEREST_RE : DQUOTED_STRING_INTEREST_RE;
|
||||
this.rule = this.ruleInsideString;
|
||||
};
|
||||
|
||||
@ -519,8 +507,7 @@ MessageFormatParser.prototype.ruleInsideString = function ruleInsideString() {
|
||||
'The string beginning at line {0}, column {1} is unterminated in text “{2}”',
|
||||
position.line, position.column, this.text);
|
||||
}
|
||||
var chars = match[0];
|
||||
if (match == this.stringQuote) {
|
||||
if (match[0] === this.stringQuote) {
|
||||
this.rule = null;
|
||||
}
|
||||
};
|
||||
@ -533,8 +520,8 @@ MessageFormatParser.prototype.rulePluralOrSelect = function rulePluralOrSelect()
|
||||
}
|
||||
var argType = match[1];
|
||||
switch (argType) {
|
||||
case "plural": this.rule = this.rulePluralStyle; break;
|
||||
case "select": this.rule = this.ruleSelectStyle; break;
|
||||
case 'plural': this.rule = this.rulePluralStyle; break;
|
||||
case 'select': this.rule = this.ruleSelectStyle; break;
|
||||
default: this.errorInParseLogic();
|
||||
}
|
||||
};
|
||||
@ -552,7 +539,7 @@ MessageFormatParser.prototype.ruleSelectStyle = function ruleSelectStyle() {
|
||||
};
|
||||
|
||||
var NUMBER_RE = /[0]|(?:[1-9][0-9]*)/g;
|
||||
var PLURAL_OFFSET_RE = new RegExp("\\s*offset\\s*:\\s*(" + NUMBER_RE.source + ")", "g");
|
||||
var PLURAL_OFFSET_RE = new RegExp('\\s*offset\\s*:\\s*(' + NUMBER_RE.source + ')', 'g');
|
||||
|
||||
MessageFormatParser.prototype.rulePluralOffset = function rulePluralOffset() {
|
||||
var match = this.matchRe(PLURAL_OFFSET_RE);
|
||||
@ -562,7 +549,7 @@ MessageFormatParser.prototype.rulePluralOffset = function rulePluralOffset() {
|
||||
};
|
||||
|
||||
MessageFormatParser.prototype.assertChoiceKeyIsNew = function assertChoiceKeyIsNew(choiceKey, index) {
|
||||
if (this.choices[choiceKey] !== void 0) {
|
||||
if (this.choices[choiceKey] !== undefined) {
|
||||
var position = indexToLineAndColumn(this.text, index);
|
||||
throw $interpolateMinErr('dupvalue',
|
||||
'The choice “{0}” is specified more than once. Duplicate key is at line {1}, column {2} in text “{3}”',
|
||||
@ -583,7 +570,7 @@ MessageFormatParser.prototype.ruleSelectKeyword = function ruleSelectKeyword() {
|
||||
this.rule = this.ruleMessageText;
|
||||
};
|
||||
|
||||
var EXPLICIT_VALUE_OR_KEYWORD_RE = new RegExp("\\s*(?:(?:=(" + NUMBER_RE.source + "))|(\\w+))", "g");
|
||||
var EXPLICIT_VALUE_OR_KEYWORD_RE = new RegExp('\\s*(?:(?:=(' + NUMBER_RE.source + '))|(\\w+))', 'g');
|
||||
MessageFormatParser.prototype.rulePluralValueOrKeyword = function rulePluralValueOrKeyword() {
|
||||
var match = this.matchRe(EXPLICIT_VALUE_OR_KEYWORD_RE);
|
||||
if (match == null) {
|
||||
@ -600,7 +587,7 @@ MessageFormatParser.prototype.rulePluralValueOrKeyword = function rulePluralValu
|
||||
this.rule = this.ruleMessageText;
|
||||
};
|
||||
|
||||
var BRACE_OPEN_RE = /\s*{/g;
|
||||
var BRACE_OPEN_RE = /\s*\{/g;
|
||||
var BRACE_CLOSE_RE = /}/g;
|
||||
MessageFormatParser.prototype.ruleMessageText = function ruleMessageText() {
|
||||
if (!this.consumeRe(BRACE_OPEN_RE)) {
|
||||
@ -620,7 +607,7 @@ var INTERP_OR_END_MESSAGE_RE = /\\.|{{|}/g;
|
||||
var INTERP_OR_PLURALVALUE_OR_END_MESSAGE_RE = /\\.|{{|#|}/g;
|
||||
var ESCAPE_OR_MUSTACHE_BEGIN_RE = /\\.|{{/g;
|
||||
MessageFormatParser.prototype.advanceInInterpolationOrMessageText = function advanceInInterpolationOrMessageText() {
|
||||
var currentIndex = this.index, match, re;
|
||||
var currentIndex = this.index, match;
|
||||
if (this.ruleChoiceKeyword == null) { // interpolation
|
||||
match = this.searchRe(ESCAPE_OR_MUSTACHE_BEGIN_RE);
|
||||
if (match == null) { // End of interpolation text. Nothing more to process.
|
||||
@ -629,7 +616,7 @@ MessageFormatParser.prototype.advanceInInterpolationOrMessageText = function adv
|
||||
return null;
|
||||
}
|
||||
} else {
|
||||
match = this.searchRe(this.ruleChoiceKeyword == this.rulePluralValueOrKeyword ?
|
||||
match = this.searchRe(this.ruleChoiceKeyword === this.rulePluralValueOrKeyword ?
|
||||
INTERP_OR_PLURALVALUE_OR_END_MESSAGE_RE : INTERP_OR_END_MESSAGE_RE);
|
||||
if (match == null) {
|
||||
var position = indexToLineAndColumn(this.text, this.msgStartIndex);
|
||||
@ -654,20 +641,20 @@ MessageFormatParser.prototype.ruleInInterpolationOrMessageText = function ruleIn
|
||||
this.rule = null;
|
||||
return;
|
||||
}
|
||||
if (token[0] == "\\") {
|
||||
if (token[0] === '\\') {
|
||||
// unescape next character and continue
|
||||
this.interpolationParts.addText(this.textPart + token[1]);
|
||||
return;
|
||||
}
|
||||
this.interpolationParts.addText(this.textPart);
|
||||
if (token == "{{") {
|
||||
if (token === '{{') {
|
||||
this.pushState();
|
||||
this.ruleStack.push(this.ruleEndMustacheInInterpolationOrMessage);
|
||||
this.rule = this.ruleEnteredMustache;
|
||||
} else if (token == "}") {
|
||||
} else if (token === '}') {
|
||||
this.choices[this.choiceKey] = this.interpolationParts.toParsedFn(/*mustHaveExpression=*/false, this.text);
|
||||
this.rule = this.ruleChoiceKeyword;
|
||||
} else if (token == "#") {
|
||||
} else if (token === '#') {
|
||||
this.interpolationParts.addExpressionFn(this.expressionMinusOffsetFn);
|
||||
} else {
|
||||
this.errorInParseLogic();
|
||||
@ -691,7 +678,7 @@ MessageFormatParser.prototype.ruleInInterpolation = function ruleInInterpolation
|
||||
return;
|
||||
}
|
||||
var token = match[0];
|
||||
if (token[0] == "\\") {
|
||||
if (token[0] === '\\') {
|
||||
// unescape next character and continue
|
||||
this.interpolationParts.addText(this.text.substring(currentIndex, match.index) + token[1]);
|
||||
return;
|
||||
@ -738,7 +725,7 @@ MessageFormatParser.prototype.ruleEndMustache = function ruleEndMustache() {
|
||||
// day), then the result *has* to be a string and those rules would have already set
|
||||
// this.parsedFn. If there was no MessageFormat extension, then there is no requirement to
|
||||
// stringify the result and parsedFn isn't set. We set it here. While we could have set it
|
||||
// unconditionally when exiting the Angular expression, I intend for us to not just replace
|
||||
// unconditionally when exiting the AngularJS expression, I intend for us to not just replace
|
||||
// $interpolate, but also to replace $parse in a future version (so ng-bind can work), and in
|
||||
// such a case we do not want to unnecessarily stringify something if it's not going to be used
|
||||
// in a string context.
|
||||
@ -757,18 +744,18 @@ MessageFormatParser.prototype.ruleAngularExpression = function ruleAngularExpres
|
||||
|
||||
function getEndOperator(opBegin) {
|
||||
switch (opBegin) {
|
||||
case "{": return "}";
|
||||
case "[": return "]";
|
||||
case "(": return ")";
|
||||
case '{': return '}';
|
||||
case '[': return ']';
|
||||
case '(': return ')';
|
||||
default: return null;
|
||||
}
|
||||
}
|
||||
|
||||
function getBeginOperator(opEnd) {
|
||||
switch (opEnd) {
|
||||
case "}": return "{";
|
||||
case "]": return "[";
|
||||
case ")": return "(";
|
||||
case '}': return '{';
|
||||
case ']': return '[';
|
||||
case ')': return '(';
|
||||
default: return null;
|
||||
}
|
||||
}
|
||||
@ -778,12 +765,11 @@ function getBeginOperator(opEnd) {
|
||||
// should support any other type of start/end interpolation symbol.
|
||||
var INTERESTING_OPERATORS_RE = /[[\]{}()'",]/g;
|
||||
MessageFormatParser.prototype.ruleInAngularExpression = function ruleInAngularExpression() {
|
||||
var startIndex = this.index;
|
||||
var match = this.searchRe(INTERESTING_OPERATORS_RE);
|
||||
var position;
|
||||
if (match == null) {
|
||||
if (this.angularOperatorStack.length === 0) {
|
||||
// This is the end of the Angular expression so this is actually a
|
||||
// This is the end of the AngularJS expression so this is actually a
|
||||
// success. Note that when inside an interpolation, this means we even
|
||||
// consumed the closing interpolation symbols if they were curlies. This
|
||||
// is NOT an error at this point but will become an error further up the
|
||||
@ -799,16 +785,16 @@ MessageFormatParser.prototype.ruleInAngularExpression = function ruleInAngularEx
|
||||
}
|
||||
var innermostOperator = this.angularOperatorStack[0];
|
||||
throw $interpolateMinErr('badexpr',
|
||||
'Unexpected end of Angular expression. Expecting operator “{0}” at the end of the text “{1}”',
|
||||
'Unexpected end of AngularJS expression. Expecting operator “{0}” at the end of the text “{1}”',
|
||||
this.getEndOperator(innermostOperator), this.text);
|
||||
}
|
||||
var operator = match[0];
|
||||
if (operator == "'" || operator == '"') {
|
||||
if (operator === '\'' || operator === '"') {
|
||||
this.ruleStack.push(this.ruleInAngularExpression);
|
||||
this.startStringAtMatch(match);
|
||||
return;
|
||||
}
|
||||
if (operator == ",") {
|
||||
if (operator === ',') {
|
||||
if (this.trustedContext) {
|
||||
position = indexToLineAndColumn(this.text, this.index);
|
||||
throw $interpolateMinErr('unsafe',
|
||||
@ -836,7 +822,7 @@ MessageFormatParser.prototype.ruleInAngularExpression = function ruleInAngularEx
|
||||
this.errorInParseLogic();
|
||||
}
|
||||
if (this.angularOperatorStack.length > 0) {
|
||||
if (beginOperator == this.angularOperatorStack[0]) {
|
||||
if (beginOperator === this.angularOperatorStack[0]) {
|
||||
this.angularOperatorStack.shift();
|
||||
return;
|
||||
}
|
||||
@ -864,7 +850,6 @@ MessageFormatParser.prototype.ruleInAngularExpression = function ruleInAngularEx
|
||||
/* global noop: true */
|
||||
/* global toJson: true */
|
||||
/* global MessageFormatParser: false */
|
||||
/* global stringify: false */
|
||||
|
||||
/**
|
||||
* @ngdoc module
|
||||
@ -875,7 +860,7 @@ MessageFormatParser.prototype.ruleInAngularExpression = function ruleInAngularEx
|
||||
*
|
||||
* ## What is ngMessageFormat?
|
||||
*
|
||||
* The ngMessageFormat module extends the Angular {@link ng.$interpolate `$interpolate`} service
|
||||
* The ngMessageFormat module extends the AngularJS {@link ng.$interpolate `$interpolate`} service
|
||||
* with a syntax for handling pluralization and gender specific messages, which is based on the
|
||||
* [ICU MessageFormat syntax][ICU].
|
||||
*
|
||||
@ -909,9 +894,9 @@ MessageFormatParser.prototype.ruleInAngularExpression = function ruleInAngularEx
|
||||
* this.gender = gender;
|
||||
* }
|
||||
*
|
||||
* var alice = new Person("Alice", "female"),
|
||||
* bob = new Person("Bob", "male"),
|
||||
* ashley = new Person("Ashley", "");
|
||||
* var alice = new Person('Alice', 'female'),
|
||||
* bob = new Person('Bob', 'male'),
|
||||
* ashley = new Person('Ashley', '');
|
||||
*
|
||||
* angular.module('msgFmtExample', ['ngMessageFormat'])
|
||||
* .controller('AppController', ['$scope', function($scope) {
|
||||
@ -952,11 +937,11 @@ MessageFormatParser.prototype.ruleInAngularExpression = function ruleInAngularEx
|
||||
* this.gender = gender;
|
||||
* }
|
||||
*
|
||||
* var alice = new Person("Alice", "female"),
|
||||
* bob = new Person("Bob", "male"),
|
||||
* sarah = new Person("Sarah", "female"),
|
||||
* harry = new Person("Harry Potter", "male"),
|
||||
* ashley = new Person("Ashley", "");
|
||||
* var alice = new Person('Alice', 'female'),
|
||||
* bob = new Person('Bob', 'male'),
|
||||
* sarah = new Person('Sarah', 'female'),
|
||||
* harry = new Person('Harry Potter', 'male'),
|
||||
* ashley = new Person('Ashley', '');
|
||||
*
|
||||
* angular.module('msgFmtExample', ['ngMessageFormat'])
|
||||
* .controller('AppController', ['$scope', function($scope) {
|
||||
@ -1012,10 +997,10 @@ MessageFormatParser.prototype.ruleInAngularExpression = function ruleInAngularEx
|
||||
* this.gender = gender;
|
||||
* }
|
||||
*
|
||||
* var alice = new Person("Alice", "female"),
|
||||
* bob = new Person("Bob", "male"),
|
||||
* harry = new Person("Harry Potter", "male"),
|
||||
* ashley = new Person("Ashley", "");
|
||||
* var alice = new Person('Alice', 'female'),
|
||||
* bob = new Person('Bob', 'male'),
|
||||
* harry = new Person('Harry Potter', 'male'),
|
||||
* ashley = new Person('Ashley', '');
|
||||
*
|
||||
* angular.module('msgFmtExample', ['ngMessageFormat'])
|
||||
* .controller('AppController', ['$scope', function($scope) {
|
||||
@ -1028,13 +1013,13 @@ MessageFormatParser.prototype.ruleInAngularExpression = function ruleInAngularEx
|
||||
*/
|
||||
|
||||
var $$MessageFormatFactory = ['$parse', '$locale', '$sce', '$exceptionHandler', function $$messageFormat(
|
||||
$parse, $locale, $sce, $exceptionHandler) {
|
||||
$parse, $locale, $sce, $exceptionHandler) {
|
||||
|
||||
function getStringifier(trustedContext, allOrNothing, text) {
|
||||
return function stringifier(value) {
|
||||
try {
|
||||
value = trustedContext ? $sce['getTrusted'](trustedContext, value) : $sce['valueOf'](value);
|
||||
return allOrNothing && (value === void 0) ? value : stringify(value);
|
||||
return allOrNothing && (value === undefined) ? value : $$stringify(value);
|
||||
} catch (err) {
|
||||
$exceptionHandler($interpolateMinErr['interr'](text, err));
|
||||
}
|
||||
@ -1055,7 +1040,7 @@ var $$MessageFormatFactory = ['$parse', '$locale', '$sce', '$exceptionHandler',
|
||||
}];
|
||||
|
||||
var $$interpolateDecorator = ['$$messageFormat', '$delegate', function $$interpolateDecorator($$messageFormat, $interpolate) {
|
||||
if ($interpolate['startSymbol']() != "{{" || $interpolate['endSymbol']() != "}}") {
|
||||
if ($interpolate['startSymbol']() !== '{{' || $interpolate['endSymbol']() !== '}}') {
|
||||
throw $interpolateMinErr('nochgmustache', 'angular-message-format.js currently does not allow you to use custom start and end symbols for interpolation.');
|
||||
}
|
||||
var interpolate = $$messageFormat['interpolate'];
|
||||
@ -1068,14 +1053,17 @@ var $interpolateMinErr;
|
||||
var isFunction;
|
||||
var noop;
|
||||
var toJson;
|
||||
var $$stringify;
|
||||
|
||||
var module = window['angular']['module']('ngMessageFormat', ['ng']);
|
||||
module['factory']('$$messageFormat', $$MessageFormatFactory);
|
||||
module['config'](['$provide', function($provide) {
|
||||
var ngModule = window['angular']['module']('ngMessageFormat', ['ng']);
|
||||
ngModule['info']({ 'angularVersion': '"1.8.2"' });
|
||||
ngModule['factory']('$$messageFormat', $$MessageFormatFactory);
|
||||
ngModule['config'](['$provide', function($provide) {
|
||||
$interpolateMinErr = window['angular']['$interpolateMinErr'];
|
||||
isFunction = window['angular']['isFunction'];
|
||||
noop = window['angular']['noop'];
|
||||
toJson = window['angular']['toJson'];
|
||||
$$stringify = window['angular']['$$stringify'];
|
||||
|
||||
$provide['decorator']('$interpolate', $$interpolateDecorator);
|
||||
}]);
|
||||
|
224
xstatic/pkg/angular/data/angular-messages.js
vendored
224
xstatic/pkg/angular/data/angular-messages.js
vendored
@ -1,6 +1,6 @@
|
||||
/**
|
||||
* @license AngularJS v1.5.8
|
||||
* (c) 2010-2016 Google, Inc. http://angularjs.org
|
||||
* @license AngularJS v1.8.2
|
||||
* (c) 2010-2020 Google, Inc. http://angularjs.org
|
||||
* License: MIT
|
||||
*/
|
||||
(function(window, angular) {'use strict';
|
||||
@ -23,9 +23,9 @@ var jqLite;
|
||||
* sequencing based on the order of how the messages are defined in the template.
|
||||
*
|
||||
* Currently, the ngMessages module only contains the code for the `ngMessages`, `ngMessagesInclude`
|
||||
* `ngMessage` and `ngMessageExp` directives.
|
||||
* `ngMessage`, `ngMessageExp` and `ngMessageDefault` directives.
|
||||
*
|
||||
* # Usage
|
||||
* ## Usage
|
||||
* The `ngMessages` directive allows keys in a key/value collection to be associated with a child element
|
||||
* (or 'message') that will show or hide based on the truthiness of that key's value in the collection. A common use
|
||||
* case for `ngMessages` is to display error messages for inputs using the `$error` object exposed by the
|
||||
@ -69,7 +69,7 @@ var jqLite;
|
||||
* By default, `ngMessages` will only display one message for a particular key/value collection at any time. If more
|
||||
* than one message (or error) key is currently true, then which message is shown is determined by the order of messages
|
||||
* in the HTML template code (messages declared first are prioritised). This mechanism means the developer does not have
|
||||
* to prioritise messages using custom JavaScript code.
|
||||
* to prioritize messages using custom JavaScript code.
|
||||
*
|
||||
* Given the following error object for our example (which informs us that the field `myField` currently has both the
|
||||
* `required` and `email` errors):
|
||||
@ -200,7 +200,7 @@ var jqLite;
|
||||
*
|
||||
* Feel free to use other structural directives such as ng-if and ng-switch to further control
|
||||
* what messages are active and when. Be careful, if you place ng-message on the same element
|
||||
* as these structural directives, Angular may not be able to determine if a message is active
|
||||
* as these structural directives, AngularJS may not be able to determine if a message is active
|
||||
* or not. Therefore it is best to place the ng-message on a child element of the structural
|
||||
* directive.
|
||||
*
|
||||
@ -262,16 +262,36 @@ var jqLite;
|
||||
* .some-message.ng-leave.ng-leave-active {}
|
||||
* ```
|
||||
*
|
||||
* {@link ngAnimate Click here} to learn how to use JavaScript animations or to learn more about ngAnimate.
|
||||
* {@link ngAnimate See the ngAnimate docs} to learn how to use JavaScript animations or to learn
|
||||
* more about ngAnimate.
|
||||
*
|
||||
* ## Displaying a default message
|
||||
* If the ngMessages renders no inner ngMessage directive (i.e. when none of the truthy
|
||||
* keys are matched by a defined message), then it will render a default message
|
||||
* using the {@link ngMessageDefault} directive.
|
||||
* Note that matched messages will always take precedence over unmatched messages. That means
|
||||
* the default message will not be displayed when another message is matched. This is also
|
||||
* true for `ng-messages-multiple`.
|
||||
*
|
||||
* ```html
|
||||
* <div ng-messages="myForm.myField.$error" role="alert">
|
||||
* <div ng-message="required">This field is required</div>
|
||||
* <div ng-message="minlength">This field is too short</div>
|
||||
* <div ng-message-default>This field has an input error</div>
|
||||
* </div>
|
||||
* ```
|
||||
*
|
||||
|
||||
*/
|
||||
angular.module('ngMessages', [], function initAngularHelpers() {
|
||||
// Access helpers from angular core.
|
||||
// Access helpers from AngularJS core.
|
||||
// Do it inside a `config` block to ensure `window.angular` is available.
|
||||
forEach = angular.forEach;
|
||||
isArray = angular.isArray;
|
||||
isString = angular.isString;
|
||||
jqLite = angular.element;
|
||||
})
|
||||
.info({ angularVersion: '"1.8.2"' })
|
||||
|
||||
/**
|
||||
* @ngdoc directive
|
||||
@ -290,8 +310,11 @@ angular.module('ngMessages', [], function initAngularHelpers() {
|
||||
* at a time and this depends on the prioritization of the messages within the template. (This can
|
||||
* be changed by using the `ng-messages-multiple` or `multiple` attribute on the directive container.)
|
||||
*
|
||||
* A remote template can also be used to promote message reusability and messages can also be
|
||||
* overridden.
|
||||
* A remote template can also be used (With {@link ngMessagesInclude}) to promote message
|
||||
* reusability and messages can also be overridden.
|
||||
*
|
||||
* A default message can also be displayed when no `ngMessage` directive is inserted, using the
|
||||
* {@link ngMessageDefault} directive.
|
||||
*
|
||||
* {@link module:ngMessages Click here} to learn more about `ngMessages` and `ngMessage`.
|
||||
*
|
||||
@ -302,6 +325,7 @@ angular.module('ngMessages', [], function initAngularHelpers() {
|
||||
* <ANY ng-message="stringValue">...</ANY>
|
||||
* <ANY ng-message="stringValue1, stringValue2, ...">...</ANY>
|
||||
* <ANY ng-message-exp="expressionValue">...</ANY>
|
||||
* <ANY ng-message-default>...</ANY>
|
||||
* </ANY>
|
||||
*
|
||||
* <!-- or by using element directives -->
|
||||
@ -309,10 +333,11 @@ angular.module('ngMessages', [], function initAngularHelpers() {
|
||||
* <ng-message when="stringValue">...</ng-message>
|
||||
* <ng-message when="stringValue1, stringValue2, ...">...</ng-message>
|
||||
* <ng-message when-exp="expressionValue">...</ng-message>
|
||||
* <ng-message-default>...</ng-message-default>
|
||||
* </ng-messages>
|
||||
* ```
|
||||
*
|
||||
* @param {string} ngMessages an angular expression evaluating to a key/value object
|
||||
* @param {string} ngMessages an AngularJS expression evaluating to a key/value object
|
||||
* (this is typically the $error object on an ngModel instance).
|
||||
* @param {string=} ngMessagesMultiple|multiple when set, all messages will be displayed with true
|
||||
*
|
||||
@ -337,6 +362,7 @@ angular.module('ngMessages', [], function initAngularHelpers() {
|
||||
* <div ng-message="required">You did not enter a field</div>
|
||||
* <div ng-message="minlength">Your field is too short</div>
|
||||
* <div ng-message="maxlength">Your field is too long</div>
|
||||
* <div ng-message-default>This field has an input error</div>
|
||||
* </div>
|
||||
* </form>
|
||||
* </file>
|
||||
@ -352,7 +378,7 @@ angular.module('ngMessages', [], function initAngularHelpers() {
|
||||
return {
|
||||
require: 'ngMessages',
|
||||
restrict: 'AE',
|
||||
controller: ['$element', '$scope', '$attrs', function($element, $scope, $attrs) {
|
||||
controller: ['$element', '$scope', '$attrs', function NgMessagesCtrl($element, $scope, $attrs) {
|
||||
var ctrl = this;
|
||||
var latestKey = 0;
|
||||
var nextAttachId = 0;
|
||||
@ -374,6 +400,7 @@ angular.module('ngMessages', [], function initAngularHelpers() {
|
||||
|
||||
var unmatchedMessages = [];
|
||||
var matchedKeys = {};
|
||||
var truthyKeys = 0;
|
||||
var messageItem = ctrl.head;
|
||||
var messageFound = false;
|
||||
var totalMessages = 0;
|
||||
@ -386,13 +413,17 @@ angular.module('ngMessages', [], function initAngularHelpers() {
|
||||
var messageUsed = false;
|
||||
if (!messageFound) {
|
||||
forEach(collection, function(value, key) {
|
||||
if (!messageUsed && truthy(value) && messageCtrl.test(key)) {
|
||||
// this is to prevent the same error name from showing up twice
|
||||
if (matchedKeys[key]) return;
|
||||
matchedKeys[key] = true;
|
||||
if (truthy(value) && !messageUsed) {
|
||||
truthyKeys++;
|
||||
|
||||
messageUsed = true;
|
||||
messageCtrl.attach();
|
||||
if (messageCtrl.test(key)) {
|
||||
// this is to prevent the same error name from showing up twice
|
||||
if (matchedKeys[key]) return;
|
||||
matchedKeys[key] = true;
|
||||
|
||||
messageUsed = true;
|
||||
messageCtrl.attach();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
@ -412,48 +443,60 @@ angular.module('ngMessages', [], function initAngularHelpers() {
|
||||
messageCtrl.detach();
|
||||
});
|
||||
|
||||
unmatchedMessages.length !== totalMessages
|
||||
? $animate.setClass($element, ACTIVE_CLASS, INACTIVE_CLASS)
|
||||
: $animate.setClass($element, INACTIVE_CLASS, ACTIVE_CLASS);
|
||||
var messageMatched = unmatchedMessages.length !== totalMessages;
|
||||
var attachDefault = ctrl.default && !messageMatched && truthyKeys > 0;
|
||||
|
||||
if (attachDefault) {
|
||||
ctrl.default.attach();
|
||||
} else if (ctrl.default) {
|
||||
ctrl.default.detach();
|
||||
}
|
||||
|
||||
if (messageMatched || attachDefault) {
|
||||
$animate.setClass($element, ACTIVE_CLASS, INACTIVE_CLASS);
|
||||
} else {
|
||||
$animate.setClass($element, INACTIVE_CLASS, ACTIVE_CLASS);
|
||||
}
|
||||
};
|
||||
|
||||
$scope.$watchCollection($attrs.ngMessages || $attrs['for'], ctrl.render);
|
||||
|
||||
// If the element is destroyed, proactively destroy all the currently visible messages
|
||||
$element.on('$destroy', function() {
|
||||
forEach(messages, function(item) {
|
||||
item.message.detach();
|
||||
});
|
||||
});
|
||||
|
||||
this.reRender = function() {
|
||||
if (!renderLater) {
|
||||
renderLater = true;
|
||||
$scope.$evalAsync(function() {
|
||||
if (renderLater) {
|
||||
cachedCollection && ctrl.render(cachedCollection);
|
||||
if (renderLater && cachedCollection) {
|
||||
ctrl.render(cachedCollection);
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
this.register = function(comment, messageCtrl) {
|
||||
var nextKey = latestKey.toString();
|
||||
messages[nextKey] = {
|
||||
message: messageCtrl
|
||||
};
|
||||
insertMessageNode($element[0], comment, nextKey);
|
||||
comment.$$ngMessageNode = nextKey;
|
||||
latestKey++;
|
||||
this.register = function(comment, messageCtrl, isDefault) {
|
||||
if (isDefault) {
|
||||
ctrl.default = messageCtrl;
|
||||
} else {
|
||||
var nextKey = latestKey.toString();
|
||||
messages[nextKey] = {
|
||||
message: messageCtrl
|
||||
};
|
||||
insertMessageNode($element[0], comment, nextKey);
|
||||
comment.$$ngMessageNode = nextKey;
|
||||
latestKey++;
|
||||
}
|
||||
|
||||
ctrl.reRender();
|
||||
};
|
||||
|
||||
this.deregister = function(comment) {
|
||||
var key = comment.$$ngMessageNode;
|
||||
delete comment.$$ngMessageNode;
|
||||
removeMessageNode($element[0], comment, key);
|
||||
delete messages[key];
|
||||
this.deregister = function(comment, isDefault) {
|
||||
if (isDefault) {
|
||||
delete ctrl.default;
|
||||
} else {
|
||||
var key = comment.$$ngMessageNode;
|
||||
delete comment.$$ngMessageNode;
|
||||
removeMessageNode($element[0], comment, key);
|
||||
delete messages[key];
|
||||
}
|
||||
ctrl.reRender();
|
||||
};
|
||||
|
||||
@ -500,6 +543,9 @@ angular.module('ngMessages', [], function initAngularHelpers() {
|
||||
function removeMessageNode(parent, comment, key) {
|
||||
var messageNode = messages[key];
|
||||
|
||||
// This message node may have already been removed by a call to deregister()
|
||||
if (!messageNode) return;
|
||||
|
||||
var match = findPreviousMessage(parent, comment);
|
||||
if (match) {
|
||||
match.next = messageNode.next;
|
||||
@ -594,6 +640,7 @@ angular.module('ngMessages', [], function initAngularHelpers() {
|
||||
* @name ngMessage
|
||||
* @restrict AE
|
||||
* @scope
|
||||
* @priority 1
|
||||
*
|
||||
* @description
|
||||
* `ngMessage` is a directive with the purpose to show and hide a particular message.
|
||||
@ -632,10 +679,8 @@ angular.module('ngMessages', [], function initAngularHelpers() {
|
||||
* @scope
|
||||
*
|
||||
* @description
|
||||
* `ngMessageExp` is a directive with the purpose to show and hide a particular message.
|
||||
* For `ngMessageExp` to operate, a parent `ngMessages` directive on a parent DOM element
|
||||
* must be situated since it determines which messages are visible based on the state
|
||||
* of the provided key/value map that `ngMessages` listens on.
|
||||
* `ngMessageExp` is the same as {@link directive:ngMessage `ngMessage`}, but instead of a static
|
||||
* value, it accepts an expression to be evaluated for the message key.
|
||||
*
|
||||
* @usage
|
||||
* ```html
|
||||
@ -654,9 +699,41 @@ angular.module('ngMessages', [], function initAngularHelpers() {
|
||||
*
|
||||
* @param {expression} ngMessageExp|whenExp an expression value corresponding to the message key.
|
||||
*/
|
||||
.directive('ngMessageExp', ngMessageDirectiveFactory());
|
||||
.directive('ngMessageExp', ngMessageDirectiveFactory())
|
||||
|
||||
function ngMessageDirectiveFactory() {
|
||||
/**
|
||||
* @ngdoc directive
|
||||
* @name ngMessageDefault
|
||||
* @restrict AE
|
||||
* @scope
|
||||
*
|
||||
* @description
|
||||
* `ngMessageDefault` is a directive with the purpose to show and hide a default message for
|
||||
* {@link directive:ngMessages}, when none of provided messages matches.
|
||||
*
|
||||
* More information about using `ngMessageDefault` can be found in the
|
||||
* {@link module:ngMessages `ngMessages` module documentation}.
|
||||
*
|
||||
* @usage
|
||||
* ```html
|
||||
* <!-- using attribute directives -->
|
||||
* <ANY ng-messages="expression" role="alert">
|
||||
* <ANY ng-message="stringValue">...</ANY>
|
||||
* <ANY ng-message="stringValue1, stringValue2, ...">...</ANY>
|
||||
* <ANY ng-message-default>...</ANY>
|
||||
* </ANY>
|
||||
*
|
||||
* <!-- or by using element directives -->
|
||||
* <ng-messages for="expression" role="alert">
|
||||
* <ng-message when="stringValue">...</ng-message>
|
||||
* <ng-message when="stringValue1, stringValue2, ...">...</ng-message>
|
||||
* <ng-message-default>...</ng-message-default>
|
||||
* </ng-messages>
|
||||
*
|
||||
*/
|
||||
.directive('ngMessageDefault', ngMessageDirectiveFactory(true));
|
||||
|
||||
function ngMessageDirectiveFactory(isDefault) {
|
||||
return ['$animate', function($animate) {
|
||||
return {
|
||||
restrict: 'AE',
|
||||
@ -665,25 +742,28 @@ function ngMessageDirectiveFactory() {
|
||||
terminal: true,
|
||||
require: '^^ngMessages',
|
||||
link: function(scope, element, attrs, ngMessagesCtrl, $transclude) {
|
||||
var commentNode = element[0];
|
||||
var commentNode, records, staticExp, dynamicExp;
|
||||
|
||||
var records;
|
||||
var staticExp = attrs.ngMessage || attrs.when;
|
||||
var dynamicExp = attrs.ngMessageExp || attrs.whenExp;
|
||||
var assignRecords = function(items) {
|
||||
records = items
|
||||
? (isArray(items)
|
||||
? items
|
||||
: items.split(/[\s,]+/))
|
||||
: null;
|
||||
ngMessagesCtrl.reRender();
|
||||
};
|
||||
if (!isDefault) {
|
||||
commentNode = element[0];
|
||||
staticExp = attrs.ngMessage || attrs.when;
|
||||
dynamicExp = attrs.ngMessageExp || attrs.whenExp;
|
||||
|
||||
if (dynamicExp) {
|
||||
assignRecords(scope.$eval(dynamicExp));
|
||||
scope.$watchCollection(dynamicExp, assignRecords);
|
||||
} else {
|
||||
assignRecords(staticExp);
|
||||
var assignRecords = function(items) {
|
||||
records = items
|
||||
? (isArray(items)
|
||||
? items
|
||||
: items.split(/[\s,]+/))
|
||||
: null;
|
||||
ngMessagesCtrl.reRender();
|
||||
};
|
||||
|
||||
if (dynamicExp) {
|
||||
assignRecords(scope.$eval(dynamicExp));
|
||||
scope.$watchCollection(dynamicExp, assignRecords);
|
||||
} else {
|
||||
assignRecords(staticExp);
|
||||
}
|
||||
}
|
||||
|
||||
var currentElement, messageCtrl;
|
||||
@ -705,8 +785,10 @@ function ngMessageDirectiveFactory() {
|
||||
// by another structural directive then it's time
|
||||
// to deregister the message from the controller
|
||||
currentElement.on('$destroy', function() {
|
||||
// If the message element was removed via a call to `detach` then `currentElement` will be null
|
||||
// So this handler only handles cases where something else removed the message element.
|
||||
if (currentElement && currentElement.$$attachId === $$attachId) {
|
||||
ngMessagesCtrl.deregister(commentNode);
|
||||
ngMessagesCtrl.deregister(commentNode, isDefault);
|
||||
messageCtrl.detach();
|
||||
}
|
||||
newScope.$destroy();
|
||||
@ -721,6 +803,14 @@ function ngMessageDirectiveFactory() {
|
||||
$animate.leave(elm);
|
||||
}
|
||||
}
|
||||
}, isDefault);
|
||||
|
||||
// We need to ensure that this directive deregisters itself when it no longer exists
|
||||
// Normally this is done when the attached element is destroyed; but if this directive
|
||||
// gets removed before we attach the message to the DOM there is nothing to watch
|
||||
// in which case we must deregister when the containing scope is destroyed.
|
||||
scope.$on('$destroy', function() {
|
||||
ngMessagesCtrl.deregister(commentNode, isDefault);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
1136
xstatic/pkg/angular/data/angular-mocks.js
vendored
1136
xstatic/pkg/angular/data/angular-mocks.js
vendored
File diff suppressed because it is too large
Load Diff
24
xstatic/pkg/angular/data/angular-parse-ext.js
vendored
24
xstatic/pkg/angular/data/angular-parse-ext.js
vendored
@ -1,6 +1,6 @@
|
||||
/**
|
||||
* @license AngularJS v1.5.8
|
||||
* (c) 2010-2016 Google, Inc. http://angularjs.org
|
||||
* @license AngularJS v1.8.2
|
||||
* (c) 2010-2020 Google, Inc. http://angularjs.org
|
||||
* License: MIT
|
||||
*/
|
||||
(function(window, angular) {'use strict';
|
||||
@ -1223,24 +1223,27 @@ function IDC_Y(cp) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/* eslint-disable new-cap */
|
||||
|
||||
/**
|
||||
* @ngdoc module
|
||||
* @name ngParseExt
|
||||
* @packageName angular-parse-ext
|
||||
*
|
||||
* @description
|
||||
*
|
||||
* # ngParseExt
|
||||
*
|
||||
* The `ngParseExt` module provides functionality to allow Unicode characters in
|
||||
* identifiers inside Angular expressions.
|
||||
*
|
||||
*
|
||||
* <div doc-module-components="ngParseExt"></div>
|
||||
* identifiers inside AngularJS expressions.
|
||||
*
|
||||
* This module allows the usage of any identifier that follows ES6 identifier naming convention
|
||||
* to be used as an identifier in an Angular expression. ES6 delegates some of the identifier
|
||||
* to be used as an identifier in an AngularJS expression. ES6 delegates some of the identifier
|
||||
* rules definition to Unicode, this module uses ES6 and Unicode 8.0 identifiers convention.
|
||||
*
|
||||
* <div class="alert alert-warning">
|
||||
* You cannot use Unicode characters for variable names in the {@link ngRepeat} or {@link ngOptions}
|
||||
* expressions (e.g. `ng-repeat="f in поля"`), because even with `ngParseExt` included, these
|
||||
* special expressions are not parsed by the {@link $parse} service.
|
||||
* </div>
|
||||
*/
|
||||
|
||||
/* global angularParseExtModule: true,
|
||||
@ -1265,7 +1268,8 @@ function isValidIdentifierContinue(ch, cp) {
|
||||
angular.module('ngParseExt', [])
|
||||
.config(['$parseProvider', function($parseProvider) {
|
||||
$parseProvider.setIdentifierFns(isValidIdentifierStart, isValidIdentifierContinue);
|
||||
}]);
|
||||
}])
|
||||
.info({ angularVersion: '"1.8.2"' });
|
||||
|
||||
|
||||
})(window, window.angular);
|
||||
|
592
xstatic/pkg/angular/data/angular-resource.js
vendored
592
xstatic/pkg/angular/data/angular-resource.js
vendored
@ -1,6 +1,6 @@
|
||||
/**
|
||||
* @license AngularJS v1.5.8
|
||||
* (c) 2010-2016 Google, Inc. http://angularjs.org
|
||||
* @license AngularJS v1.8.2
|
||||
* (c) 2010-2020 Google, Inc. http://angularjs.org
|
||||
* License: MIT
|
||||
*/
|
||||
(function(window, angular) {'use strict';
|
||||
@ -53,14 +53,9 @@ function shallowClearAndCopy(src, dst) {
|
||||
* @name ngResource
|
||||
* @description
|
||||
*
|
||||
* # ngResource
|
||||
*
|
||||
* The `ngResource` module provides interaction support with RESTful services
|
||||
* via the $resource service.
|
||||
*
|
||||
*
|
||||
* <div doc-module-components="ngResource"></div>
|
||||
*
|
||||
* See {@link ngResource.$resourceProvider} and {@link ngResource.$resource} for usage.
|
||||
*/
|
||||
|
||||
@ -120,30 +115,35 @@ function shallowClearAndCopy(src, dst) {
|
||||
*
|
||||
* @param {Object=} paramDefaults Default values for `url` parameters. These can be overridden in
|
||||
* `actions` methods. If a parameter value is a function, it will be called every time
|
||||
* a param value needs to be obtained for a request (unless the param was overridden). The function
|
||||
* will be passed the current data value as an argument.
|
||||
* a param value needs to be obtained for a request (unless the param was overridden). The
|
||||
* function will be passed the current data value as an argument.
|
||||
*
|
||||
* Each key value in the parameter object is first bound to url template if present and then any
|
||||
* excess keys are appended to the url search query after the `?`.
|
||||
*
|
||||
* Given a template `/path/:verb` and parameter `{verb:'greet', salutation:'Hello'}` results in
|
||||
* Given a template `/path/:verb` and parameter `{verb: 'greet', salutation: 'Hello'}` results in
|
||||
* URL `/path/greet?salutation=Hello`.
|
||||
*
|
||||
* If the parameter value is prefixed with `@`, then the value for that parameter will be
|
||||
* extracted from the corresponding property on the `data` object (provided when calling a
|
||||
* "non-GET" action method).
|
||||
* extracted from the corresponding property on the `data` object (provided when calling actions
|
||||
* with a request body).
|
||||
* For example, if the `defaultParam` object is `{someParam: '@someProp'}` then the value of
|
||||
* `someParam` will be `data.someProp`.
|
||||
* Note that the parameter will be ignored, when calling a "GET" action method (i.e. an action
|
||||
* method that does not accept a request body)
|
||||
* method that does not accept a request body).
|
||||
*
|
||||
* @param {Object.<Object>=} actions Hash with declaration of custom actions that should extend
|
||||
* the default set of resource actions. The declaration should be created in the format of {@link
|
||||
* ng.$http#usage $http.config}:
|
||||
* @param {Object.<Object>=} actions Hash with declaration of custom actions that will be available
|
||||
* in addition to the default set of resource actions (see below). If a custom action has the same
|
||||
* key as a default action (e.g. `save`), then the default action will be *overwritten*, and not
|
||||
* extended.
|
||||
*
|
||||
* {action1: {method:?, params:?, isArray:?, headers:?, ...},
|
||||
* action2: {method:?, params:?, isArray:?, headers:?, ...},
|
||||
* ...}
|
||||
* The declaration should be created in the format of {@link ng.$http#usage $http.config}:
|
||||
*
|
||||
* {
|
||||
* action1: {method:?, params:?, isArray:?, headers:?, ...},
|
||||
* action2: {method:?, params:?, isArray:?, headers:?, ...},
|
||||
* ...
|
||||
* }
|
||||
*
|
||||
* Where:
|
||||
*
|
||||
@ -155,46 +155,58 @@ function shallowClearAndCopy(src, dst) {
|
||||
* the parameter value is a function, it will be called every time when a param value needs to
|
||||
* be obtained for a request (unless the param was overridden). The function will be passed the
|
||||
* current data value as an argument.
|
||||
* - **`url`** – {string} – action specific `url` override. The url templating is supported just
|
||||
* - **`url`** – {string} – Action specific `url` override. The url templating is supported just
|
||||
* like for the resource-level urls.
|
||||
* - **`isArray`** – {boolean=} – If true then the returned object for this action is an array,
|
||||
* see `returns` section.
|
||||
* - **`transformRequest`** –
|
||||
* `{function(data, headersGetter)|Array.<function(data, headersGetter)>}` –
|
||||
* transform function or an array of such functions. The transform function takes the http
|
||||
* Transform function or an array of such functions. The transform function takes the http
|
||||
* request body and headers and returns its transformed (typically serialized) version.
|
||||
* By default, transformRequest will contain one function that checks if the request data is
|
||||
* an object and serializes to using `angular.toJson`. To prevent this behavior, set
|
||||
* an object and serializes it using `angular.toJson`. To prevent this behavior, set
|
||||
* `transformRequest` to an empty array: `transformRequest: []`
|
||||
* - **`transformResponse`** –
|
||||
* `{function(data, headersGetter)|Array.<function(data, headersGetter)>}` –
|
||||
* transform function or an array of such functions. The transform function takes the http
|
||||
* response body and headers and returns its transformed (typically deserialized) version.
|
||||
* `{function(data, headersGetter, status)|Array.<function(data, headersGetter, status)>}` –
|
||||
* Transform function or an array of such functions. The transform function takes the HTTP
|
||||
* response body, headers and status and returns its transformed (typically deserialized)
|
||||
* version.
|
||||
* By default, transformResponse will contain one function that checks if the response looks
|
||||
* like a JSON string and deserializes it using `angular.fromJson`. To prevent this behavior,
|
||||
* set `transformResponse` to an empty array: `transformResponse: []`
|
||||
* - **`cache`** – `{boolean|Cache}` – If true, a default $http cache will be used to cache the
|
||||
* GET request, otherwise if a cache instance built with
|
||||
* {@link ng.$cacheFactory $cacheFactory}, this cache will be used for
|
||||
* caching.
|
||||
* - **`timeout`** – `{number}` – timeout in milliseconds.<br />
|
||||
* - **`cache`** – `{boolean|Cache}` – A boolean value or object created with
|
||||
* {@link ng.$cacheFactory `$cacheFactory`} to enable or disable caching of the HTTP response.
|
||||
* See {@link $http#caching $http Caching} for more information.
|
||||
* - **`timeout`** – `{number}` – Timeout in milliseconds.<br />
|
||||
* **Note:** In contrast to {@link ng.$http#usage $http.config}, {@link ng.$q promises} are
|
||||
* **not** supported in $resource, because the same value would be used for multiple requests.
|
||||
* **not** supported in `$resource`, because the same value would be used for multiple requests.
|
||||
* If you are looking for a way to cancel requests, you should use the `cancellable` option.
|
||||
* - **`cancellable`** – `{boolean}` – if set to true, the request made by a "non-instance" call
|
||||
* will be cancelled (if not already completed) by calling `$cancelRequest()` on the call's
|
||||
* return value. Calling `$cancelRequest()` for a non-cancellable or an already
|
||||
* completed/cancelled request will have no effect.<br />
|
||||
* - **`withCredentials`** - `{boolean}` - whether to set the `withCredentials` flag on the
|
||||
* - **`cancellable`** – `{boolean}` – If true, the request made by a "non-instance" call will be
|
||||
* cancelled (if not already completed) by calling `$cancelRequest()` on the call's return
|
||||
* value. Calling `$cancelRequest()` for a non-cancellable or an already completed/cancelled
|
||||
* request will have no effect.
|
||||
* - **`withCredentials`** – `{boolean}` – Whether to set the `withCredentials` flag on the
|
||||
* XHR object. See
|
||||
* [requests with credentials](https://developer.mozilla.org/en/http_access_control#section_5)
|
||||
* [XMLHttpRequest.withCredentials](https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/withCredentials)
|
||||
* for more information.
|
||||
* - **`responseType`** - `{string}` - see
|
||||
* [requestType](https://developer.mozilla.org/en-US/docs/DOM/XMLHttpRequest#responseType).
|
||||
* - **`interceptor`** - `{Object=}` - The interceptor object has two optional methods -
|
||||
* `response` and `responseError`. Both `response` and `responseError` interceptors get called
|
||||
* with `http response` object. See {@link ng.$http $http interceptors}.
|
||||
*
|
||||
* - **`responseType`** – `{string}` – See
|
||||
* [XMLHttpRequest.responseType](https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/responseType).
|
||||
* - **`interceptor`** – `{Object=}` – The interceptor object has four optional methods -
|
||||
* `request`, `requestError`, `response`, and `responseError`. See
|
||||
* {@link ng.$http#interceptors $http interceptors} for details. Note that
|
||||
* `request`/`requestError` interceptors are applied before calling `$http`, thus before any
|
||||
* global `$http` interceptors. Also, rejecting or throwing an error inside the `request`
|
||||
* interceptor will result in calling the `responseError` interceptor.
|
||||
* The resource instance or collection is available on the `resource` property of the
|
||||
* `http response` object passed to `response`/`responseError` interceptors.
|
||||
* Keep in mind that the associated promise will be resolved with the value returned by the
|
||||
* response interceptors. Make sure you return an appropriate value and not the `response`
|
||||
* object passed as input. For reference, the default `response` interceptor (which gets applied
|
||||
* if you don't specify a custom one) returns `response.resource`.<br />
|
||||
* See {@link ngResource.$resource#using-interceptors below} for an example of using
|
||||
* interceptors in `$resource`.
|
||||
* - **`hasBody`** – `{boolean}` – If true, then the request will have a body.
|
||||
* If not specified, then only POST, PUT and PATCH requests will have a body. *
|
||||
* @param {Object} options Hash with custom settings that should extend the
|
||||
* default `$resourceProvider` behavior. The supported options are:
|
||||
*
|
||||
@ -207,27 +219,29 @@ function shallowClearAndCopy(src, dst) {
|
||||
* @returns {Object} A resource "class" object with methods for the default set of resource actions
|
||||
* optionally extended with custom `actions`. The default set contains these actions:
|
||||
* ```js
|
||||
* { 'get': {method:'GET'},
|
||||
* 'save': {method:'POST'},
|
||||
* 'query': {method:'GET', isArray:true},
|
||||
* 'remove': {method:'DELETE'},
|
||||
* 'delete': {method:'DELETE'} };
|
||||
* {
|
||||
* 'get': {method: 'GET'},
|
||||
* 'save': {method: 'POST'},
|
||||
* 'query': {method: 'GET', isArray: true},
|
||||
* 'remove': {method: 'DELETE'},
|
||||
* 'delete': {method: 'DELETE'}
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* Calling these methods invoke an {@link ng.$http} with the specified http method,
|
||||
* destination and parameters. When the data is returned from the server then the object is an
|
||||
* instance of the resource class. The actions `save`, `remove` and `delete` are available on it
|
||||
* as methods with the `$` prefix. This allows you to easily perform CRUD operations (create,
|
||||
* read, update, delete) on server-side data like this:
|
||||
* Calling these methods invoke {@link ng.$http} with the specified http method, destination and
|
||||
* parameters. When the data is returned from the server then the object is an instance of the
|
||||
* resource class. The actions `save`, `remove` and `delete` are available on it as methods with
|
||||
* the `$` prefix. This allows you to easily perform CRUD operations (create, read, update,
|
||||
* delete) on server-side data like this:
|
||||
* ```js
|
||||
* var User = $resource('/user/:userId', {userId:'@id'});
|
||||
* var user = User.get({userId:123}, function() {
|
||||
* var User = $resource('/user/:userId', {userId: '@id'});
|
||||
* User.get({userId: 123}).$promise.then(function(user) {
|
||||
* user.abc = true;
|
||||
* user.$save();
|
||||
* });
|
||||
* ```
|
||||
*
|
||||
* It is important to realize that invoking a $resource object method immediately returns an
|
||||
* It is important to realize that invoking a `$resource` object method immediately returns an
|
||||
* empty reference (object or array depending on `isArray`). Once the data is returned from the
|
||||
* server the existing reference is populated with the actual data. This is a useful trick since
|
||||
* usually the resource is assigned to a model which is then rendered by the view. Having an empty
|
||||
@ -238,37 +252,43 @@ function shallowClearAndCopy(src, dst) {
|
||||
* The action methods on the class object or instance object can be invoked with the following
|
||||
* parameters:
|
||||
*
|
||||
* - HTTP GET "class" actions: `Resource.action([parameters], [success], [error])`
|
||||
* - non-GET "class" actions: `Resource.action([parameters], postData, [success], [error])`
|
||||
* - non-GET instance actions: `instance.$action([parameters], [success], [error])`
|
||||
* - "class" actions without a body: `Resource.action([parameters], [success], [error])`
|
||||
* - "class" actions with a body: `Resource.action([parameters], postData, [success], [error])`
|
||||
* - instance actions: `instance.$action([parameters], [success], [error])`
|
||||
*
|
||||
*
|
||||
* Success callback is called with (value, responseHeaders) arguments, where the value is
|
||||
* the populated resource instance or collection object. The error callback is called
|
||||
* with (httpResponse) argument.
|
||||
* When calling instance methods, the instance itself is used as the request body (if the action
|
||||
* should have a body). By default, only actions using `POST`, `PUT` or `PATCH` have request
|
||||
* bodies, but you can use the `hasBody` configuration option to specify whether an action
|
||||
* should have a body or not (regardless of its HTTP method).
|
||||
*
|
||||
* Class actions return empty instance (with additional properties below).
|
||||
* Instance actions return promise of the action.
|
||||
*
|
||||
* Success callback is called with (value (Object|Array), responseHeaders (Function),
|
||||
* status (number), statusText (string)) arguments, where `value` is the populated resource
|
||||
* instance or collection object. The error callback is called with (httpResponse) argument.
|
||||
*
|
||||
* Class actions return an empty instance (with the additional properties listed below).
|
||||
* Instance actions return a promise for the operation.
|
||||
*
|
||||
* The Resource instances and collections have these additional properties:
|
||||
*
|
||||
* - `$promise`: the {@link ng.$q promise} of the original server interaction that created this
|
||||
* - `$promise`: The {@link ng.$q promise} of the original server interaction that created this
|
||||
* instance or collection.
|
||||
*
|
||||
* On success, the promise is resolved with the same resource instance or collection object,
|
||||
* updated with data from server. This makes it easy to use in
|
||||
* {@link ngRoute.$routeProvider resolve section of $routeProvider.when()} to defer view
|
||||
* updated with data from server. This makes it easy to use in the
|
||||
* {@link ngRoute.$routeProvider `resolve` section of `$routeProvider.when()`} to defer view
|
||||
* rendering until the resource(s) are loaded.
|
||||
*
|
||||
* On failure, the promise is rejected with the {@link ng.$http http response} object, without
|
||||
* the `resource` property.
|
||||
* On failure, the promise is rejected with the {@link ng.$http http response} object.
|
||||
*
|
||||
* If an interceptor object was provided, the promise will instead be resolved with the value
|
||||
* returned by the interceptor.
|
||||
* returned by the response interceptor (on success) or responceError interceptor (on failure).
|
||||
*
|
||||
* - `$resolved`: `true` after first server interaction is completed (either with success or
|
||||
* rejection), `false` before that. Knowing if the Resource has been resolved is useful in
|
||||
* data-binding.
|
||||
* data-binding. If there is a response/responseError interceptor and it returns a promise,
|
||||
* `$resolved` will wait for that too.
|
||||
*
|
||||
* The Resource instances and collections have these additional methods:
|
||||
*
|
||||
@ -279,138 +299,145 @@ function shallowClearAndCopy(src, dst) {
|
||||
*
|
||||
* - `toJSON`: It returns a simple object without any of the extra properties added as part of
|
||||
* the Resource API. This object can be serialized through {@link angular.toJson} safely
|
||||
* without attaching Angular-specific fields. Notice that `JSON.stringify` (and
|
||||
* without attaching AngularJS-specific fields. Notice that `JSON.stringify` (and
|
||||
* `angular.toJson`) automatically use this method when serializing a Resource instance
|
||||
* (see [MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify#toJSON()_behavior)).
|
||||
* (see [MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify#toJSON%28%29_behavior)).
|
||||
*
|
||||
* @example
|
||||
*
|
||||
* # Credit card resource
|
||||
* ### Basic usage
|
||||
*
|
||||
* ```js
|
||||
// Define CreditCard class
|
||||
var CreditCard = $resource('/user/:userId/card/:cardId',
|
||||
{userId:123, cardId:'@id'}, {
|
||||
charge: {method:'POST', params:{charge:true}}
|
||||
});
|
||||
```js
|
||||
// Define a CreditCard class
|
||||
var CreditCard = $resource('/users/:userId/cards/:cardId',
|
||||
{userId: 123, cardId: '@id'}, {
|
||||
charge: {method: 'POST', params: {charge: true}}
|
||||
});
|
||||
|
||||
// We can retrieve a collection from the server
|
||||
var cards = CreditCard.query(function() {
|
||||
// GET: /user/123/card
|
||||
// server returns: [ {id:456, number:'1234', name:'Smith'} ];
|
||||
var cards = CreditCard.query();
|
||||
// GET: /users/123/cards
|
||||
// server returns: [{id: 456, number: '1234', name: 'Smith'}]
|
||||
|
||||
// Wait for the request to complete
|
||||
cards.$promise.then(function() {
|
||||
var card = cards[0];
|
||||
// each item is an instance of CreditCard
|
||||
expect(card instanceof CreditCard).toEqual(true);
|
||||
card.name = "J. Smith";
|
||||
// non GET methods are mapped onto the instances
|
||||
card.$save();
|
||||
// POST: /user/123/card/456 {id:456, number:'1234', name:'J. Smith'}
|
||||
// server returns: {id:456, number:'1234', name: 'J. Smith'};
|
||||
|
||||
// our custom method is mapped as well.
|
||||
card.$charge({amount:9.99});
|
||||
// POST: /user/123/card/456?amount=9.99&charge=true {id:456, number:'1234', name:'J. Smith'}
|
||||
// Each item is an instance of CreditCard
|
||||
expect(card instanceof CreditCard).toEqual(true);
|
||||
|
||||
// Non-GET methods are mapped onto the instances
|
||||
card.name = 'J. Smith';
|
||||
card.$save();
|
||||
// POST: /users/123/cards/456 {id: 456, number: '1234', name: 'J. Smith'}
|
||||
// server returns: {id: 456, number: '1234', name: 'J. Smith'}
|
||||
|
||||
// Our custom method is mapped as well (since it uses POST)
|
||||
card.$charge({amount: 9.99});
|
||||
// POST: /users/123/cards/456?amount=9.99&charge=true {id: 456, number: '1234', name: 'J. Smith'}
|
||||
});
|
||||
|
||||
// we can create an instance as well
|
||||
var newCard = new CreditCard({number:'0123'});
|
||||
newCard.name = "Mike Smith";
|
||||
newCard.$save();
|
||||
// POST: /user/123/card {number:'0123', name:'Mike Smith'}
|
||||
// server returns: {id:789, number:'0123', name: 'Mike Smith'};
|
||||
expect(newCard.id).toEqual(789);
|
||||
* ```
|
||||
// We can create an instance as well
|
||||
var newCard = new CreditCard({number: '0123'});
|
||||
newCard.name = 'Mike Smith';
|
||||
|
||||
var savePromise = newCard.$save();
|
||||
// POST: /users/123/cards {number: '0123', name: 'Mike Smith'}
|
||||
// server returns: {id: 789, number: '0123', name: 'Mike Smith'}
|
||||
|
||||
savePromise.then(function() {
|
||||
// Once the promise is resolved, the created instance
|
||||
// is populated with the data returned by the server
|
||||
expect(newCard.id).toEqual(789);
|
||||
});
|
||||
```
|
||||
*
|
||||
* The object returned from this function execution is a resource "class" which has "static" method
|
||||
* for each action in the definition.
|
||||
* The object returned from a call to `$resource` is a resource "class" which has one "static"
|
||||
* method for each action in the definition.
|
||||
*
|
||||
* Calling these methods invoke `$http` on the `url` template with the given `method`, `params` and
|
||||
* `headers`.
|
||||
* Calling these methods invokes `$http` on the `url` template with the given HTTP `method`,
|
||||
* `params` and `headers`.
|
||||
*
|
||||
* @example
|
||||
*
|
||||
* # User resource
|
||||
* ### Accessing the response
|
||||
*
|
||||
* When the data is returned from the server then the object is an instance of the resource type and
|
||||
* all of the non-GET methods are available with `$` prefix. This allows you to easily support CRUD
|
||||
* operations (create, read, update, delete) on server-side data.
|
||||
|
||||
*
|
||||
```js
|
||||
var User = $resource('/user/:userId', {userId:'@id'});
|
||||
User.get({userId:123}, function(user) {
|
||||
var User = $resource('/users/:userId', {userId: '@id'});
|
||||
User.get({userId: 123}).$promise.then(function(user) {
|
||||
user.abc = true;
|
||||
user.$save();
|
||||
});
|
||||
```
|
||||
*
|
||||
* It's worth noting that the success callback for `get`, `query` and other methods gets passed
|
||||
* in the response that came from the server as well as $http header getter function, so one
|
||||
* could rewrite the above example and get access to http headers as:
|
||||
* It's worth noting that the success callback for `get`, `query` and other methods gets called with
|
||||
* the resource instance (populated with the data that came from the server) as well as an `$http`
|
||||
* header getter function, the HTTP status code and the response status text. So one could rewrite
|
||||
* the above example and get access to HTTP headers as follows:
|
||||
*
|
||||
```js
|
||||
var User = $resource('/user/:userId', {userId:'@id'});
|
||||
User.get({userId:123}, function(user, getResponseHeaders){
|
||||
var User = $resource('/users/:userId', {userId: '@id'});
|
||||
User.get({userId: 123}, function(user, getResponseHeaders) {
|
||||
user.abc = true;
|
||||
user.$save(function(user, putResponseHeaders) {
|
||||
//user => saved user object
|
||||
//putResponseHeaders => $http header getter
|
||||
// `user` => saved `User` object
|
||||
// `putResponseHeaders` => `$http` header getter
|
||||
});
|
||||
});
|
||||
```
|
||||
*
|
||||
* You can also access the raw `$http` promise via the `$promise` property on the object returned
|
||||
* @example
|
||||
*
|
||||
```
|
||||
var User = $resource('/user/:userId', {userId:'@id'});
|
||||
User.get({userId:123})
|
||||
.$promise.then(function(user) {
|
||||
$scope.user = user;
|
||||
});
|
||||
* ### Creating custom actions
|
||||
*
|
||||
* In this example we create a custom method on our resource to make a PUT request:
|
||||
*
|
||||
```js
|
||||
var app = angular.module('app', ['ngResource']);
|
||||
|
||||
// Some APIs expect a PUT request in the format URL/object/ID
|
||||
// Here we are creating an 'update' method
|
||||
app.factory('Notes', ['$resource', function($resource) {
|
||||
return $resource('/notes/:id', {id: '@id'}, {
|
||||
update: {method: 'PUT'}
|
||||
});
|
||||
}]);
|
||||
|
||||
// In our controller we get the ID from the URL using `$location`
|
||||
app.controller('NotesCtrl', ['$location', 'Notes', function($location, Notes) {
|
||||
// First, retrieve the corresponding `Note` object from the server
|
||||
// (Assuming a URL of the form `.../notes?id=XYZ`)
|
||||
var noteId = $location.search().id;
|
||||
var note = Notes.get({id: noteId});
|
||||
|
||||
note.$promise.then(function() {
|
||||
note.content = 'Hello, world!';
|
||||
|
||||
// Now call `update` to save the changes on the server
|
||||
Notes.update(note);
|
||||
// This will PUT /notes/ID with the note object as the request payload
|
||||
|
||||
// Since `update` is a non-GET method, it will also be available on the instance
|
||||
// (prefixed with `$`), so we could replace the `Note.update()` call with:
|
||||
//note.$update();
|
||||
});
|
||||
}]);
|
||||
```
|
||||
*
|
||||
* @example
|
||||
*
|
||||
* # Creating a custom 'PUT' request
|
||||
*
|
||||
* In this example we create a custom method on our resource to make a PUT request
|
||||
* ```js
|
||||
* var app = angular.module('app', ['ngResource', 'ngRoute']);
|
||||
*
|
||||
* // Some APIs expect a PUT request in the format URL/object/ID
|
||||
* // Here we are creating an 'update' method
|
||||
* app.factory('Notes', ['$resource', function($resource) {
|
||||
* return $resource('/notes/:id', null,
|
||||
* {
|
||||
* 'update': { method:'PUT' }
|
||||
* });
|
||||
* }]);
|
||||
*
|
||||
* // In our controller we get the ID from the URL using ngRoute and $routeParams
|
||||
* // We pass in $routeParams and our Notes factory along with $scope
|
||||
* app.controller('NotesCtrl', ['$scope', '$routeParams', 'Notes',
|
||||
function($scope, $routeParams, Notes) {
|
||||
* // First get a note object from the factory
|
||||
* var note = Notes.get({ id:$routeParams.id });
|
||||
* $id = note.id;
|
||||
*
|
||||
* // Now call update passing in the ID first then the object you are updating
|
||||
* Notes.update({ id:$id }, note);
|
||||
*
|
||||
* // This will PUT /notes/ID with the note object in the request payload
|
||||
* }]);
|
||||
* ```
|
||||
*
|
||||
* @example
|
||||
*
|
||||
* # Cancelling requests
|
||||
* ### Cancelling requests
|
||||
*
|
||||
* If an action's configuration specifies that it is cancellable, you can cancel the request related
|
||||
* to an instance or collection (as long as it is a result of a "non-instance" call):
|
||||
*
|
||||
```js
|
||||
// ...defining the `Hotel` resource...
|
||||
var Hotel = $resource('/api/hotel/:id', {id: '@id'}, {
|
||||
var Hotel = $resource('/api/hotels/:id', {id: '@id'}, {
|
||||
// Let's make the `query()` method cancellable
|
||||
query: {method: 'get', isArray: true, cancellable: true}
|
||||
});
|
||||
@ -420,18 +447,60 @@ function shallowClearAndCopy(src, dst) {
|
||||
this.onDestinationChanged = function onDestinationChanged(destination) {
|
||||
// We don't care about any pending request for hotels
|
||||
// in a different destination any more
|
||||
this.availableHotels.$cancelRequest();
|
||||
if (this.availableHotels) {
|
||||
this.availableHotels.$cancelRequest();
|
||||
}
|
||||
|
||||
// Let's query for hotels in '<destination>'
|
||||
// (calls: /api/hotel?location=<destination>)
|
||||
// Let's query for hotels in `destination`
|
||||
// (calls: /api/hotels?location=<destination>)
|
||||
this.availableHotels = Hotel.query({location: destination});
|
||||
};
|
||||
```
|
||||
*
|
||||
* @example
|
||||
*
|
||||
* ### Using interceptors
|
||||
*
|
||||
* You can use interceptors to transform the request or response, perform additional operations, and
|
||||
* modify the returned instance/collection. The following example, uses `request` and `response`
|
||||
* interceptors to augment the returned instance with additional info:
|
||||
*
|
||||
```js
|
||||
var Thing = $resource('/api/things/:id', {id: '@id'}, {
|
||||
save: {
|
||||
method: 'POST',
|
||||
interceptor: {
|
||||
request: function(config) {
|
||||
// Before the request is sent out, store a timestamp on the request config
|
||||
config.requestTimestamp = Date.now();
|
||||
return config;
|
||||
},
|
||||
response: function(response) {
|
||||
// Get the instance from the response object
|
||||
var instance = response.resource;
|
||||
|
||||
// Augment the instance with a custom `saveLatency` property, computed as the time
|
||||
// between sending the request and receiving the response.
|
||||
instance.saveLatency = Date.now() - response.config.requestTimestamp;
|
||||
|
||||
// Return the instance
|
||||
return instance;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
Thing.save({foo: 'bar'}).$promise.then(function(thing) {
|
||||
console.log('That thing was saved in ' + thing.saveLatency + 'ms.');
|
||||
});
|
||||
```
|
||||
*
|
||||
*/
|
||||
angular.module('ngResource', ['ng']).
|
||||
provider('$resource', function() {
|
||||
var PROTOCOL_AND_DOMAIN_REGEX = /^https?:\/\/[^\/]*/;
|
||||
info({ angularVersion: '"1.8.2"' }).
|
||||
provider('$resource', function ResourceProvider() {
|
||||
var PROTOCOL_AND_IPV6_REGEX = /^https?:\/\/\[[^\]]*][^/]*/;
|
||||
|
||||
var provider = this;
|
||||
|
||||
/**
|
||||
@ -475,11 +544,11 @@ angular.module('ngResource', ['ng']).
|
||||
* ```js
|
||||
* angular.
|
||||
* module('myApp').
|
||||
* config(['resourceProvider', function ($resourceProvider) {
|
||||
* config(['$resourceProvider', function ($resourceProvider) {
|
||||
* $resourceProvider.defaults.actions.update = {
|
||||
* method: 'PUT'
|
||||
* };
|
||||
* });
|
||||
* }]);
|
||||
* ```
|
||||
*
|
||||
* Or you can even overwrite the whole `actions` list and specify your own:
|
||||
@ -487,9 +556,9 @@ angular.module('ngResource', ['ng']).
|
||||
* ```js
|
||||
* angular.
|
||||
* module('myApp').
|
||||
* config(['resourceProvider', function ($resourceProvider) {
|
||||
* config(['$resourceProvider', function ($resourceProvider) {
|
||||
* $resourceProvider.defaults.actions = {
|
||||
* create: {method: 'POST'}
|
||||
* create: {method: 'POST'},
|
||||
* get: {method: 'GET'},
|
||||
* getAll: {method: 'GET', isArray:true},
|
||||
* update: {method: 'PUT'},
|
||||
@ -519,49 +588,15 @@ angular.module('ngResource', ['ng']).
|
||||
this.$get = ['$http', '$log', '$q', '$timeout', function($http, $log, $q, $timeout) {
|
||||
|
||||
var noop = angular.noop,
|
||||
forEach = angular.forEach,
|
||||
extend = angular.extend,
|
||||
copy = angular.copy,
|
||||
isFunction = angular.isFunction;
|
||||
|
||||
/**
|
||||
* We need our custom method because encodeURIComponent is too aggressive and doesn't follow
|
||||
* http://www.ietf.org/rfc/rfc3986.txt with regards to the character set
|
||||
* (pchar) allowed in path segments:
|
||||
* segment = *pchar
|
||||
* pchar = unreserved / pct-encoded / sub-delims / ":" / "@"
|
||||
* pct-encoded = "%" HEXDIG HEXDIG
|
||||
* unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~"
|
||||
* sub-delims = "!" / "$" / "&" / "'" / "(" / ")"
|
||||
* / "*" / "+" / "," / ";" / "="
|
||||
*/
|
||||
function encodeUriSegment(val) {
|
||||
return encodeUriQuery(val, true).
|
||||
replace(/%26/gi, '&').
|
||||
replace(/%3D/gi, '=').
|
||||
replace(/%2B/gi, '+');
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This method is intended for encoding *key* or *value* parts of query component. We need a
|
||||
* custom method because encodeURIComponent is too aggressive and encodes stuff that doesn't
|
||||
* have to be encoded per http://tools.ietf.org/html/rfc3986:
|
||||
* query = *( pchar / "/" / "?" )
|
||||
* pchar = unreserved / pct-encoded / sub-delims / ":" / "@"
|
||||
* unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~"
|
||||
* pct-encoded = "%" HEXDIG HEXDIG
|
||||
* sub-delims = "!" / "$" / "&" / "'" / "(" / ")"
|
||||
* / "*" / "+" / "," / ";" / "="
|
||||
*/
|
||||
function encodeUriQuery(val, pctEncodeSpaces) {
|
||||
return encodeURIComponent(val).
|
||||
replace(/%40/gi, '@').
|
||||
replace(/%3A/gi, ':').
|
||||
replace(/%24/g, '$').
|
||||
replace(/%2C/gi, ',').
|
||||
replace(/%20/g, (pctEncodeSpaces ? '%20' : '+'));
|
||||
}
|
||||
forEach = angular.forEach,
|
||||
extend = angular.extend,
|
||||
copy = angular.copy,
|
||||
isArray = angular.isArray,
|
||||
isDefined = angular.isDefined,
|
||||
isFunction = angular.isFunction,
|
||||
isNumber = angular.isNumber,
|
||||
encodeUriQuery = angular.$$encodeUriQuery,
|
||||
encodeUriSegment = angular.$$encodeUriSegment;
|
||||
|
||||
function Route(template, defaults) {
|
||||
this.template = template;
|
||||
@ -575,42 +610,42 @@ angular.module('ngResource', ['ng']).
|
||||
url = actionUrl || self.template,
|
||||
val,
|
||||
encodedVal,
|
||||
protocolAndDomain = '';
|
||||
protocolAndIpv6 = '';
|
||||
|
||||
var urlParams = self.urlParams = {};
|
||||
var urlParams = self.urlParams = Object.create(null);
|
||||
forEach(url.split(/\W/), function(param) {
|
||||
if (param === 'hasOwnProperty') {
|
||||
throw $resourceMinErr('badname', "hasOwnProperty is not a valid parameter name.");
|
||||
throw $resourceMinErr('badname', 'hasOwnProperty is not a valid parameter name.');
|
||||
}
|
||||
if (!(new RegExp("^\\d+$").test(param)) && param &&
|
||||
(new RegExp("(^|[^\\\\]):" + param + "(\\W|$)").test(url))) {
|
||||
if (!(new RegExp('^\\d+$').test(param)) && param &&
|
||||
(new RegExp('(^|[^\\\\]):' + param + '(\\W|$)').test(url))) {
|
||||
urlParams[param] = {
|
||||
isQueryParamValue: (new RegExp("\\?.*=:" + param + "(?:\\W|$)")).test(url)
|
||||
isQueryParamValue: (new RegExp('\\?.*=:' + param + '(?:\\W|$)')).test(url)
|
||||
};
|
||||
}
|
||||
});
|
||||
url = url.replace(/\\:/g, ':');
|
||||
url = url.replace(PROTOCOL_AND_DOMAIN_REGEX, function(match) {
|
||||
protocolAndDomain = match;
|
||||
url = url.replace(PROTOCOL_AND_IPV6_REGEX, function(match) {
|
||||
protocolAndIpv6 = match;
|
||||
return '';
|
||||
});
|
||||
|
||||
params = params || {};
|
||||
forEach(self.urlParams, function(paramInfo, urlParam) {
|
||||
val = params.hasOwnProperty(urlParam) ? params[urlParam] : self.defaults[urlParam];
|
||||
if (angular.isDefined(val) && val !== null) {
|
||||
if (isDefined(val) && val !== null) {
|
||||
if (paramInfo.isQueryParamValue) {
|
||||
encodedVal = encodeUriQuery(val, true);
|
||||
} else {
|
||||
encodedVal = encodeUriSegment(val);
|
||||
}
|
||||
url = url.replace(new RegExp(":" + urlParam + "(\\W|$)", "g"), function(match, p1) {
|
||||
url = url.replace(new RegExp(':' + urlParam + '(\\W|$)', 'g'), function(match, p1) {
|
||||
return encodedVal + p1;
|
||||
});
|
||||
} else {
|
||||
url = url.replace(new RegExp("(\/?):" + urlParam + "(\\W|$)", "g"), function(match,
|
||||
url = url.replace(new RegExp('(/?):' + urlParam + '(\\W|$)', 'g'), function(match,
|
||||
leadingSlashes, tail) {
|
||||
if (tail.charAt(0) == '/') {
|
||||
if (tail.charAt(0) === '/') {
|
||||
return tail;
|
||||
} else {
|
||||
return leadingSlashes + tail;
|
||||
@ -624,11 +659,12 @@ angular.module('ngResource', ['ng']).
|
||||
url = url.replace(/\/+$/, '') || '/';
|
||||
}
|
||||
|
||||
// then replace collapse `/.` if found in the last URL path segment before the query
|
||||
// E.g. `http://url.com/id./format?q=x` becomes `http://url.com/id.format?q=x`
|
||||
// Collapse `/.` if found in the last URL path segment before the query.
|
||||
// E.g. `http://url.com/id/.format?q=x` becomes `http://url.com/id.format?q=x`.
|
||||
url = url.replace(/\/\.(?=\w+($|\?))/, '.');
|
||||
// replace escaped `/\.` with `/.`
|
||||
config.url = protocolAndDomain + url.replace(/\/\\\./, '/.');
|
||||
// Replace escaped `/\.` with `/.`.
|
||||
// (If `\.` comes from a param value, it will be encoded as `%5C.`.)
|
||||
config.url = protocolAndIpv6 + url.replace(/\/(\\|%5C)\./, '/.');
|
||||
|
||||
|
||||
// set params - delegate param encoding to $http
|
||||
@ -652,7 +688,7 @@ angular.module('ngResource', ['ng']).
|
||||
actionParams = extend({}, paramDefaults, actionParams);
|
||||
forEach(actionParams, function(value, key) {
|
||||
if (isFunction(value)) { value = value(data); }
|
||||
ids[key] = value && value.charAt && value.charAt(0) == '@' ?
|
||||
ids[key] = value && value.charAt && value.charAt(0) === '@' ?
|
||||
lookupDottedPath(data, value.substr(1)) : value;
|
||||
});
|
||||
return ids;
|
||||
@ -670,17 +706,17 @@ angular.module('ngResource', ['ng']).
|
||||
var data = extend({}, this);
|
||||
delete data.$promise;
|
||||
delete data.$resolved;
|
||||
delete data.$cancelRequest;
|
||||
return data;
|
||||
};
|
||||
|
||||
forEach(actions, function(action, name) {
|
||||
var hasBody = /^(POST|PUT|PATCH)$/i.test(action.method);
|
||||
var hasBody = action.hasBody === true || (action.hasBody !== false && /^(POST|PUT|PATCH)$/i.test(action.method));
|
||||
var numericTimeout = action.timeout;
|
||||
var cancellable = angular.isDefined(action.cancellable) ? action.cancellable :
|
||||
(options && angular.isDefined(options.cancellable)) ? options.cancellable :
|
||||
provider.defaults.cancellable;
|
||||
var cancellable = isDefined(action.cancellable) ?
|
||||
action.cancellable : route.defaults.cancellable;
|
||||
|
||||
if (numericTimeout && !angular.isNumber(numericTimeout)) {
|
||||
if (numericTimeout && !isNumber(numericTimeout)) {
|
||||
$log.debug('ngResource:\n' +
|
||||
' Only numeric values are allowed as `timeout`.\n' +
|
||||
' Promises are not supported in $resource, because the same value would ' +
|
||||
@ -691,54 +727,61 @@ angular.module('ngResource', ['ng']).
|
||||
}
|
||||
|
||||
Resource[name] = function(a1, a2, a3, a4) {
|
||||
var params = {}, data, success, error;
|
||||
var params = {}, data, onSuccess, onError;
|
||||
|
||||
/* jshint -W086 */ /* (purposefully fall through case statements) */
|
||||
switch (arguments.length) {
|
||||
case 4:
|
||||
error = a4;
|
||||
success = a3;
|
||||
//fallthrough
|
||||
onError = a4;
|
||||
onSuccess = a3;
|
||||
// falls through
|
||||
case 3:
|
||||
case 2:
|
||||
if (isFunction(a2)) {
|
||||
if (isFunction(a1)) {
|
||||
success = a1;
|
||||
error = a2;
|
||||
onSuccess = a1;
|
||||
onError = a2;
|
||||
break;
|
||||
}
|
||||
|
||||
success = a2;
|
||||
error = a3;
|
||||
//fallthrough
|
||||
onSuccess = a2;
|
||||
onError = a3;
|
||||
// falls through
|
||||
} else {
|
||||
params = a1;
|
||||
data = a2;
|
||||
success = a3;
|
||||
onSuccess = a3;
|
||||
break;
|
||||
}
|
||||
// falls through
|
||||
case 1:
|
||||
if (isFunction(a1)) success = a1;
|
||||
if (isFunction(a1)) onSuccess = a1;
|
||||
else if (hasBody) data = a1;
|
||||
else params = a1;
|
||||
break;
|
||||
case 0: break;
|
||||
default:
|
||||
throw $resourceMinErr('badargs',
|
||||
"Expected up to 4 arguments [params, data, success, error], got {0} arguments",
|
||||
'Expected up to 4 arguments [params, data, success, error], got {0} arguments',
|
||||
arguments.length);
|
||||
}
|
||||
/* jshint +W086 */ /* (purposefully fall through case statements) */
|
||||
|
||||
var isInstanceCall = this instanceof Resource;
|
||||
var value = isInstanceCall ? data : (action.isArray ? [] : new Resource(data));
|
||||
var httpConfig = {};
|
||||
var requestInterceptor = action.interceptor && action.interceptor.request || undefined;
|
||||
var requestErrorInterceptor = action.interceptor && action.interceptor.requestError ||
|
||||
undefined;
|
||||
var responseInterceptor = action.interceptor && action.interceptor.response ||
|
||||
defaultResponseInterceptor;
|
||||
var responseErrorInterceptor = action.interceptor && action.interceptor.responseError ||
|
||||
undefined;
|
||||
$q.reject;
|
||||
var successCallback = onSuccess ? function(val) {
|
||||
onSuccess(val, response.headers, response.status, response.statusText);
|
||||
} : undefined;
|
||||
var errorCallback = onError || undefined;
|
||||
var timeoutDeferred;
|
||||
var numericTimeoutPromise;
|
||||
var response;
|
||||
|
||||
forEach(action, function(value, key) {
|
||||
switch (key) {
|
||||
@ -767,23 +810,28 @@ angular.module('ngResource', ['ng']).
|
||||
extend({}, extractParams(data, action.params || {}), params),
|
||||
action.url);
|
||||
|
||||
var promise = $http(httpConfig).then(function(response) {
|
||||
var data = response.data;
|
||||
// Start the promise chain
|
||||
var promise = $q.
|
||||
resolve(httpConfig).
|
||||
then(requestInterceptor).
|
||||
catch(requestErrorInterceptor).
|
||||
then($http);
|
||||
|
||||
promise = promise.then(function(resp) {
|
||||
var data = resp.data;
|
||||
|
||||
if (data) {
|
||||
// Need to convert action.isArray to boolean in case it is undefined
|
||||
// jshint -W018
|
||||
if (angular.isArray(data) !== (!!action.isArray)) {
|
||||
if (isArray(data) !== (!!action.isArray)) {
|
||||
throw $resourceMinErr('badcfg',
|
||||
'Error in resource configuration for action `{0}`. Expected response to ' +
|
||||
'contain an {1} but got an {2} (Request: {3} {4})', name, action.isArray ? 'array' : 'object',
|
||||
angular.isArray(data) ? 'array' : 'object', httpConfig.method, httpConfig.url);
|
||||
isArray(data) ? 'array' : 'object', httpConfig.method, httpConfig.url);
|
||||
}
|
||||
// jshint +W018
|
||||
if (action.isArray) {
|
||||
value.length = 0;
|
||||
forEach(data, function(item) {
|
||||
if (typeof item === "object") {
|
||||
if (typeof item === 'object') {
|
||||
value.push(new Resource(item));
|
||||
} else {
|
||||
// Valid JSON values may be string literals, and these should not be converted
|
||||
@ -798,30 +846,27 @@ angular.module('ngResource', ['ng']).
|
||||
value.$promise = promise; // Restore the promise
|
||||
}
|
||||
}
|
||||
response.resource = value;
|
||||
|
||||
return response;
|
||||
}, function(response) {
|
||||
(error || noop)(response);
|
||||
return $q.reject(response);
|
||||
resp.resource = value;
|
||||
response = resp;
|
||||
return responseInterceptor(resp);
|
||||
}, function(rejectionOrResponse) {
|
||||
rejectionOrResponse.resource = value;
|
||||
response = rejectionOrResponse;
|
||||
return responseErrorInterceptor(rejectionOrResponse);
|
||||
});
|
||||
|
||||
promise['finally'](function() {
|
||||
promise = promise['finally'](function() {
|
||||
value.$resolved = true;
|
||||
if (!isInstanceCall && cancellable) {
|
||||
value.$cancelRequest = angular.noop;
|
||||
value.$cancelRequest = noop;
|
||||
$timeout.cancel(numericTimeoutPromise);
|
||||
timeoutDeferred = numericTimeoutPromise = httpConfig.timeout = null;
|
||||
}
|
||||
});
|
||||
|
||||
promise = promise.then(
|
||||
function(response) {
|
||||
var value = responseInterceptor(response);
|
||||
(success || noop)(value, response.headers);
|
||||
return value;
|
||||
},
|
||||
responseErrorInterceptor);
|
||||
// Run the `success`/`error` callbacks, but do not let them affect the returned promise.
|
||||
promise.then(successCallback, errorCallback);
|
||||
|
||||
if (!isInstanceCall) {
|
||||
// we are creating instance / collection
|
||||
@ -829,13 +874,20 @@ angular.module('ngResource', ['ng']).
|
||||
// - return the instance / collection
|
||||
value.$promise = promise;
|
||||
value.$resolved = false;
|
||||
if (cancellable) value.$cancelRequest = timeoutDeferred.resolve;
|
||||
if (cancellable) value.$cancelRequest = cancelRequest;
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
// instance call
|
||||
return promise;
|
||||
|
||||
function cancelRequest(value) {
|
||||
promise.catch(noop);
|
||||
if (timeoutDeferred !== null) {
|
||||
timeoutDeferred.resolve(value);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@ -848,10 +900,6 @@ angular.module('ngResource', ['ng']).
|
||||
};
|
||||
});
|
||||
|
||||
Resource.bind = function(additionalParamDefaults) {
|
||||
return resourceFactory(url, extend({}, paramDefaults, additionalParamDefaults), actions);
|
||||
};
|
||||
|
||||
return Resource;
|
||||
}
|
||||
|
||||
|
416
xstatic/pkg/angular/data/angular-route.js
vendored
416
xstatic/pkg/angular/data/angular-route.js
vendored
@ -1,6 +1,6 @@
|
||||
/**
|
||||
* @license AngularJS v1.5.8
|
||||
* (c) 2010-2016 Google, Inc. http://angularjs.org
|
||||
* @license AngularJS v1.8.2
|
||||
* (c) 2010-2020 Google, Inc. http://angularjs.org
|
||||
* License: MIT
|
||||
*/
|
||||
(function(window, angular) {'use strict';
|
||||
@ -32,43 +32,51 @@ function shallowCopy(src, dst) {
|
||||
return dst || src;
|
||||
}
|
||||
|
||||
/* global routeToRegExp: false */
|
||||
/* global shallowCopy: false */
|
||||
|
||||
// There are necessary for `shallowCopy()` (included via `src/shallowCopy.js`).
|
||||
// `isArray` and `isObject` 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;
|
||||
var isDefined;
|
||||
var noop;
|
||||
|
||||
/**
|
||||
* @ngdoc module
|
||||
* @name ngRoute
|
||||
* @description
|
||||
*
|
||||
* # ngRoute
|
||||
*
|
||||
* The `ngRoute` module provides routing and deeplinking services and directives for angular apps.
|
||||
* The `ngRoute` module provides routing and deeplinking services and directives for AngularJS apps.
|
||||
*
|
||||
* ## Example
|
||||
* See {@link ngRoute.$route#example $route} for an example of configuring and using `ngRoute`.
|
||||
* See {@link ngRoute.$route#examples $route} for an example of configuring and using `ngRoute`.
|
||||
*
|
||||
*
|
||||
* <div doc-module-components="ngRoute"></div>
|
||||
*/
|
||||
/* global -ngRouteModule */
|
||||
var ngRouteModule = angular.module('ngRoute', ['ng']).
|
||||
provider('$route', $RouteProvider),
|
||||
$routeMinErr = angular.$$minErr('ngRoute');
|
||||
/* global -ngRouteModule */
|
||||
var ngRouteModule = angular.
|
||||
module('ngRoute', []).
|
||||
info({ angularVersion: '"1.8.2"' }).
|
||||
provider('$route', $RouteProvider).
|
||||
// Ensure `$route` will be instantiated in time to capture the initial `$locationChangeSuccess`
|
||||
// event (unless explicitly disabled). This is necessary in case `ngView` is included in an
|
||||
// asynchronously loaded template.
|
||||
run(instantiateRoute);
|
||||
var $routeMinErr = angular.$$minErr('ngRoute');
|
||||
var isEagerInstantiationEnabled;
|
||||
|
||||
|
||||
/**
|
||||
* @ngdoc provider
|
||||
* @name $routeProvider
|
||||
* @this
|
||||
*
|
||||
* @description
|
||||
*
|
||||
* Used for configuring routes.
|
||||
*
|
||||
* ## Example
|
||||
* See {@link ngRoute.$route#example $route} for an example of configuring and using `ngRoute`.
|
||||
* See {@link ngRoute.$route#examples $route} for an example of configuring and using `ngRoute`.
|
||||
*
|
||||
* ## Dependencies
|
||||
* Requires the {@link ngRoute `ngRoute`} module to be installed.
|
||||
@ -76,6 +84,8 @@ var ngRouteModule = angular.module('ngRoute', ['ng']).
|
||||
function $RouteProvider() {
|
||||
isArray = angular.isArray;
|
||||
isObject = angular.isObject;
|
||||
isDefined = angular.isDefined;
|
||||
noop = angular.noop;
|
||||
|
||||
function inherit(parent, extra) {
|
||||
return angular.extend(Object.create(parent), extra);
|
||||
@ -112,12 +122,12 @@ function $RouteProvider() {
|
||||
*
|
||||
* Object properties:
|
||||
*
|
||||
* - `controller` – `{(string|function()=}` – Controller fn that should be associated with
|
||||
* - `controller` – `{(string|Function)=}` – Controller fn that should be associated with
|
||||
* newly created scope or the name of a {@link angular.Module#controller registered
|
||||
* controller} if passed as a string.
|
||||
* - `controllerAs` – `{string=}` – An identifier name for a reference to the controller.
|
||||
* If present, the controller will be published to scope under the `controllerAs` name.
|
||||
* - `template` – `{string=|function()=}` – html template as a string or a function that
|
||||
* - `template` – `{(string|Function)=}` – html template as a string or a function that
|
||||
* returns an html template as a string which should be used by {@link
|
||||
* ngRoute.directive:ngView ngView} or {@link ng.directive:ngInclude ngInclude} directives.
|
||||
* This property takes precedence over `templateUrl`.
|
||||
@ -127,7 +137,9 @@ function $RouteProvider() {
|
||||
* - `{Array.<Object>}` - route parameters extracted from the current
|
||||
* `$location.path()` by applying the current route
|
||||
*
|
||||
* - `templateUrl` – `{string=|function()=}` – path or function that returns a path to an html
|
||||
* One of `template` or `templateUrl` is required.
|
||||
*
|
||||
* - `templateUrl` – `{(string|Function)=}` – path or function that returns a path to an html
|
||||
* template that should be used by {@link ngRoute.directive:ngView ngView}.
|
||||
*
|
||||
* If `templateUrl` is a function, it will be called with the following parameters:
|
||||
@ -135,7 +147,9 @@ function $RouteProvider() {
|
||||
* - `{Array.<Object>}` - route parameters extracted from the current
|
||||
* `$location.path()` by applying the current route
|
||||
*
|
||||
* - `resolve` - `{Object.<string, function>=}` - An optional map of dependencies which should
|
||||
* One of `templateUrl` or `template` is required.
|
||||
*
|
||||
* - `resolve` - `{Object.<string, Function>=}` - An optional map of dependencies which should
|
||||
* be injected into the controller. If any of these dependencies are promises, the router
|
||||
* will wait for them all to be resolved or one to be rejected before the controller is
|
||||
* instantiated.
|
||||
@ -155,7 +169,7 @@ function $RouteProvider() {
|
||||
* The map object is:
|
||||
*
|
||||
* - `key` – `{string}`: a name of a dependency to be injected into the controller.
|
||||
* - `factory` - `{string|function}`: If `string` then it is an alias for a service.
|
||||
* - `factory` - `{string|Function}`: If `string` then it is an alias for a service.
|
||||
* Otherwise if function, then it is {@link auto.$injector#invoke injected}
|
||||
* and the return value is treated as the dependency. If the result is a promise, it is
|
||||
* resolved before its value is injected into the controller. Be aware that
|
||||
@ -165,7 +179,7 @@ function $RouteProvider() {
|
||||
* - `resolveAs` - `{string=}` - The name under which the `resolve` map will be available on
|
||||
* the scope of the route. If omitted, defaults to `$resolve`.
|
||||
*
|
||||
* - `redirectTo` – `{(string|function())=}` – value to update
|
||||
* - `redirectTo` – `{(string|Function)=}` – value to update
|
||||
* {@link ng.$location $location} path with and trigger route redirection.
|
||||
*
|
||||
* If `redirectTo` is a function, it will be called with the following parameters:
|
||||
@ -176,13 +190,48 @@ function $RouteProvider() {
|
||||
* - `{Object}` - current `$location.search()`
|
||||
*
|
||||
* The custom `redirectTo` function is expected to return a string which will be used
|
||||
* to update `$location.path()` and `$location.search()`.
|
||||
* to update `$location.url()`. If the function throws an error, no further processing will
|
||||
* take place and the {@link ngRoute.$route#$routeChangeError $routeChangeError} event will
|
||||
* be fired.
|
||||
*
|
||||
* Routes that specify `redirectTo` will not have their controllers, template functions
|
||||
* or resolves called, the `$location` will be changed to the redirect url and route
|
||||
* processing will stop. The exception to this is if the `redirectTo` is a function that
|
||||
* returns `undefined`. In this case the route transition occurs as though there was no
|
||||
* redirection.
|
||||
*
|
||||
* - `resolveRedirectTo` – `{Function=}` – a function that will (eventually) return the value
|
||||
* to update {@link ng.$location $location} URL with and trigger route redirection. In
|
||||
* contrast to `redirectTo`, dependencies can be injected into `resolveRedirectTo` and the
|
||||
* return value can be either a string or a promise that will be resolved to a string.
|
||||
*
|
||||
* Similar to `redirectTo`, if the return value is `undefined` (or a promise that gets
|
||||
* resolved to `undefined`), no redirection takes place and the route transition occurs as
|
||||
* though there was no redirection.
|
||||
*
|
||||
* If the function throws an error or the returned promise gets rejected, no further
|
||||
* processing will take place and the
|
||||
* {@link ngRoute.$route#$routeChangeError $routeChangeError} event will be fired.
|
||||
*
|
||||
* `redirectTo` takes precedence over `resolveRedirectTo`, so specifying both on the same
|
||||
* route definition, will cause the latter to be ignored.
|
||||
*
|
||||
* - `[reloadOnUrl=true]` - `{boolean=}` - reload route when any part of the URL changes
|
||||
* (including the path) even if the new URL maps to the same route.
|
||||
*
|
||||
* If the option is set to `false` and the URL in the browser changes, but the new URL maps
|
||||
* to the same route, then a `$routeUpdate` event is broadcasted on the root scope (without
|
||||
* reloading the route).
|
||||
*
|
||||
* - `[reloadOnSearch=true]` - `{boolean=}` - reload route when only `$location.search()`
|
||||
* or `$location.hash()` changes.
|
||||
*
|
||||
* If the option is set to `false` and url in the browser changes, then
|
||||
* `$routeUpdate` event is broadcasted on the root scope.
|
||||
* If the option is set to `false` and the URL in the browser changes, then a `$routeUpdate`
|
||||
* event is broadcasted on the root scope (without reloading the route).
|
||||
*
|
||||
* <div class="alert alert-warning">
|
||||
* **Note:** This option has no effect if `reloadOnUrl` is set to `false`.
|
||||
* </div>
|
||||
*
|
||||
* - `[caseInsensitiveMatch=false]` - `{boolean=}` - match routes without being case sensitive
|
||||
*
|
||||
@ -197,6 +246,9 @@ function $RouteProvider() {
|
||||
this.when = function(path, route) {
|
||||
//copy original route object to preserve params inherited from proto chain
|
||||
var routeCopy = shallowCopy(route);
|
||||
if (angular.isUndefined(routeCopy.reloadOnUrl)) {
|
||||
routeCopy.reloadOnUrl = true;
|
||||
}
|
||||
if (angular.isUndefined(routeCopy.reloadOnSearch)) {
|
||||
routeCopy.reloadOnSearch = true;
|
||||
}
|
||||
@ -205,18 +257,19 @@ function $RouteProvider() {
|
||||
}
|
||||
routes[path] = angular.extend(
|
||||
routeCopy,
|
||||
path && pathRegExp(path, routeCopy)
|
||||
{originalPath: path},
|
||||
path && routeToRegExp(path, routeCopy)
|
||||
);
|
||||
|
||||
// create redirection for trailing slashes
|
||||
if (path) {
|
||||
var redirectPath = (path[path.length - 1] == '/')
|
||||
var redirectPath = (path[path.length - 1] === '/')
|
||||
? path.substr(0, path.length - 1)
|
||||
: path + '/';
|
||||
|
||||
routes[redirectPath] = angular.extend(
|
||||
{redirectTo: path},
|
||||
pathRegExp(redirectPath, routeCopy)
|
||||
{originalPath: path, redirectTo: path},
|
||||
routeToRegExp(redirectPath, routeCopy)
|
||||
);
|
||||
}
|
||||
|
||||
@ -234,47 +287,6 @@ function $RouteProvider() {
|
||||
*/
|
||||
this.caseInsensitiveMatch = false;
|
||||
|
||||
/**
|
||||
* @param path {string} path
|
||||
* @param opts {Object} options
|
||||
* @return {?Object}
|
||||
*
|
||||
* @description
|
||||
* Normalizes the given path, returning a regular expression
|
||||
* and the original path.
|
||||
*
|
||||
* Inspired by pathRexp in visionmedia/express/lib/utils.js.
|
||||
*/
|
||||
function pathRegExp(path, opts) {
|
||||
var insensitive = opts.caseInsensitiveMatch,
|
||||
ret = {
|
||||
originalPath: path,
|
||||
regexp: path
|
||||
},
|
||||
keys = ret.keys = [];
|
||||
|
||||
path = path
|
||||
.replace(/([().])/g, '\\$1')
|
||||
.replace(/(\/)?:(\w+)(\*\?|[\?\*])?/g, function(_, slash, key, option) {
|
||||
var optional = (option === '?' || option === '*?') ? '?' : null;
|
||||
var star = (option === '*' || option === '*?') ? '*' : null;
|
||||
keys.push({ name: key, optional: !!optional });
|
||||
slash = slash || '';
|
||||
return ''
|
||||
+ (optional ? '' : slash)
|
||||
+ '(?:'
|
||||
+ (optional ? slash : '')
|
||||
+ (star && '(.+?)' || '([^/]+)')
|
||||
+ (optional || '')
|
||||
+ ')'
|
||||
+ (optional || '');
|
||||
})
|
||||
.replace(/([\/$\*])/g, '\\$1');
|
||||
|
||||
ret.regexp = new RegExp('^' + path + '$', insensitive ? 'i' : '');
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* @ngdoc method
|
||||
* @name $routeProvider#otherwise
|
||||
@ -295,6 +307,47 @@ function $RouteProvider() {
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* @ngdoc method
|
||||
* @name $routeProvider#eagerInstantiationEnabled
|
||||
* @kind function
|
||||
*
|
||||
* @description
|
||||
* Call this method as a setter to enable/disable eager instantiation of the
|
||||
* {@link ngRoute.$route $route} service upon application bootstrap. You can also call it as a
|
||||
* getter (i.e. without any arguments) to get the current value of the
|
||||
* `eagerInstantiationEnabled` flag.
|
||||
*
|
||||
* Instantiating `$route` early is necessary for capturing the initial
|
||||
* {@link ng.$location#$locationChangeStart $locationChangeStart} event and navigating to the
|
||||
* appropriate route. Usually, `$route` is instantiated in time by the
|
||||
* {@link ngRoute.ngView ngView} directive. Yet, in cases where `ngView` is included in an
|
||||
* asynchronously loaded template (e.g. in another directive's template), the directive factory
|
||||
* might not be called soon enough for `$route` to be instantiated _before_ the initial
|
||||
* `$locationChangeSuccess` event is fired. Eager instantiation ensures that `$route` is always
|
||||
* instantiated in time, regardless of when `ngView` will be loaded.
|
||||
*
|
||||
* The default value is true.
|
||||
*
|
||||
* **Note**:<br />
|
||||
* You may want to disable the default behavior when unit-testing modules that depend on
|
||||
* `ngRoute`, in order to avoid an unexpected request for the default route's template.
|
||||
*
|
||||
* @param {boolean=} enabled - If provided, update the internal `eagerInstantiationEnabled` flag.
|
||||
*
|
||||
* @returns {*} The current value of the `eagerInstantiationEnabled` flag if used as a getter or
|
||||
* itself (for chaining) if used as a setter.
|
||||
*/
|
||||
isEagerInstantiationEnabled = true;
|
||||
this.eagerInstantiationEnabled = function eagerInstantiationEnabled(enabled) {
|
||||
if (isDefined(enabled)) {
|
||||
isEagerInstantiationEnabled = enabled;
|
||||
return this;
|
||||
}
|
||||
|
||||
return isEagerInstantiationEnabled;
|
||||
};
|
||||
|
||||
|
||||
this.$get = ['$rootScope',
|
||||
'$location',
|
||||
@ -303,7 +356,8 @@ function $RouteProvider() {
|
||||
'$injector',
|
||||
'$templateRequest',
|
||||
'$sce',
|
||||
function($rootScope, $location, $routeParams, $q, $injector, $templateRequest, $sce) {
|
||||
'$browser',
|
||||
function($rootScope, $location, $routeParams, $q, $injector, $templateRequest, $sce, $browser) {
|
||||
|
||||
/**
|
||||
* @ngdoc service
|
||||
@ -388,12 +442,12 @@ function $RouteProvider() {
|
||||
* })
|
||||
*
|
||||
* .controller('BookController', function($scope, $routeParams) {
|
||||
* $scope.name = "BookController";
|
||||
* $scope.name = 'BookController';
|
||||
* $scope.params = $routeParams;
|
||||
* })
|
||||
*
|
||||
* .controller('ChapterController', function($scope, $routeParams) {
|
||||
* $scope.name = "ChapterController";
|
||||
* $scope.name = 'ChapterController';
|
||||
* $scope.params = $routeParams;
|
||||
* })
|
||||
*
|
||||
@ -426,15 +480,15 @@ function $RouteProvider() {
|
||||
* it('should load and compile correct template', function() {
|
||||
* element(by.linkText('Moby: Ch1')).click();
|
||||
* var content = element(by.css('[ng-view]')).getText();
|
||||
* expect(content).toMatch(/controller\: ChapterController/);
|
||||
* expect(content).toMatch(/Book Id\: Moby/);
|
||||
* expect(content).toMatch(/Chapter Id\: 1/);
|
||||
* expect(content).toMatch(/controller: ChapterController/);
|
||||
* expect(content).toMatch(/Book Id: Moby/);
|
||||
* expect(content).toMatch(/Chapter Id: 1/);
|
||||
*
|
||||
* element(by.partialLinkText('Scarlet')).click();
|
||||
*
|
||||
* content = element(by.css('[ng-view]')).getText();
|
||||
* expect(content).toMatch(/controller\: BookController/);
|
||||
* expect(content).toMatch(/Book Id\: Scarlet/);
|
||||
* expect(content).toMatch(/controller: BookController/);
|
||||
* expect(content).toMatch(/Book Id: Scarlet/);
|
||||
* });
|
||||
* </file>
|
||||
* </example>
|
||||
@ -482,12 +536,14 @@ function $RouteProvider() {
|
||||
* @name $route#$routeChangeError
|
||||
* @eventType broadcast on root scope
|
||||
* @description
|
||||
* Broadcasted if any of the resolve promises are rejected.
|
||||
* Broadcasted if a redirection function fails or any redirection or resolve promises are
|
||||
* rejected.
|
||||
*
|
||||
* @param {Object} angularEvent Synthetic event object
|
||||
* @param {Route} current Current route information.
|
||||
* @param {Route} previous Previous route information.
|
||||
* @param {Route} rejection Rejection of the promise. Usually the error of the failed promise.
|
||||
* @param {Route} rejection The thrown error or the rejection reason of the promise. Usually
|
||||
* the rejection reason is the error that caused the promise to get rejected.
|
||||
*/
|
||||
|
||||
/**
|
||||
@ -495,8 +551,9 @@ function $RouteProvider() {
|
||||
* @name $route#$routeUpdate
|
||||
* @eventType broadcast on root scope
|
||||
* @description
|
||||
* The `reloadOnSearch` property has been set to false, and we are reusing the same
|
||||
* instance of the Controller.
|
||||
* Broadcasted if the same instance of a route (including template, controller instance,
|
||||
* resolved dependencies, etc.) is being reused. This can happen if either `reloadOnSearch` or
|
||||
* `reloadOnUrl` has been set to `false`.
|
||||
*
|
||||
* @param {Object} angularEvent Synthetic event object
|
||||
* @param {Route} current Current/previous route information.
|
||||
@ -556,7 +613,7 @@ function $RouteProvider() {
|
||||
// interpolate modifies newParams, only query params are left
|
||||
$location.search(newParams);
|
||||
} else {
|
||||
throw $routeMinErr('norout', 'Tried updating route when with no current route');
|
||||
throw $routeMinErr('norout', 'Tried updating route with no current route');
|
||||
}
|
||||
}
|
||||
};
|
||||
@ -604,9 +661,7 @@ function $RouteProvider() {
|
||||
var lastRoute = $route.current;
|
||||
|
||||
preparedRoute = parseRoute();
|
||||
preparedRouteIsUpdateOnly = preparedRoute && lastRoute && preparedRoute.$$route === lastRoute.$$route
|
||||
&& angular.equals(preparedRoute.pathParams, lastRoute.pathParams)
|
||||
&& !preparedRoute.reloadOnSearch && !forceReload;
|
||||
preparedRouteIsUpdateOnly = isNavigationUpdateOnly(preparedRoute, lastRoute);
|
||||
|
||||
if (!preparedRouteIsUpdateOnly && (lastRoute || preparedRoute)) {
|
||||
if ($rootScope.$broadcast('$routeChangeStart', preparedRoute, lastRoute).defaultPrevented) {
|
||||
@ -628,37 +683,112 @@ function $RouteProvider() {
|
||||
} else if (nextRoute || lastRoute) {
|
||||
forceReload = false;
|
||||
$route.current = nextRoute;
|
||||
if (nextRoute) {
|
||||
if (nextRoute.redirectTo) {
|
||||
if (angular.isString(nextRoute.redirectTo)) {
|
||||
$location.path(interpolate(nextRoute.redirectTo, nextRoute.params)).search(nextRoute.params)
|
||||
.replace();
|
||||
} else {
|
||||
$location.url(nextRoute.redirectTo(nextRoute.pathParams, $location.path(), $location.search()))
|
||||
.replace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$q.when(nextRoute).
|
||||
then(resolveLocals).
|
||||
then(function(locals) {
|
||||
// after route change
|
||||
if (nextRoute == $route.current) {
|
||||
if (nextRoute) {
|
||||
nextRoute.locals = locals;
|
||||
angular.copy(nextRoute.params, $routeParams);
|
||||
}
|
||||
$rootScope.$broadcast('$routeChangeSuccess', nextRoute, lastRoute);
|
||||
}
|
||||
}, function(error) {
|
||||
if (nextRoute == $route.current) {
|
||||
var nextRoutePromise = $q.resolve(nextRoute);
|
||||
|
||||
$browser.$$incOutstandingRequestCount('$route');
|
||||
|
||||
nextRoutePromise.
|
||||
then(getRedirectionData).
|
||||
then(handlePossibleRedirection).
|
||||
then(function(keepProcessingRoute) {
|
||||
return keepProcessingRoute && nextRoutePromise.
|
||||
then(resolveLocals).
|
||||
then(function(locals) {
|
||||
// after route change
|
||||
if (nextRoute === $route.current) {
|
||||
if (nextRoute) {
|
||||
nextRoute.locals = locals;
|
||||
angular.copy(nextRoute.params, $routeParams);
|
||||
}
|
||||
$rootScope.$broadcast('$routeChangeSuccess', nextRoute, lastRoute);
|
||||
}
|
||||
});
|
||||
}).catch(function(error) {
|
||||
if (nextRoute === $route.current) {
|
||||
$rootScope.$broadcast('$routeChangeError', nextRoute, lastRoute, error);
|
||||
}
|
||||
}).finally(function() {
|
||||
// Because `commitRoute()` is called from a `$rootScope.$evalAsync` block (see
|
||||
// `$locationWatch`), this `$$completeOutstandingRequest()` call will not cause
|
||||
// `outstandingRequestCount` to hit zero. This is important in case we are redirecting
|
||||
// to a new route which also requires some asynchronous work.
|
||||
|
||||
$browser.$$completeOutstandingRequest(noop, '$route');
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function getRedirectionData(route) {
|
||||
var data = {
|
||||
route: route,
|
||||
hasRedirection: false
|
||||
};
|
||||
|
||||
if (route) {
|
||||
if (route.redirectTo) {
|
||||
if (angular.isString(route.redirectTo)) {
|
||||
data.path = interpolate(route.redirectTo, route.params);
|
||||
data.search = route.params;
|
||||
data.hasRedirection = true;
|
||||
} else {
|
||||
var oldPath = $location.path();
|
||||
var oldSearch = $location.search();
|
||||
var newUrl = route.redirectTo(route.pathParams, oldPath, oldSearch);
|
||||
|
||||
if (angular.isDefined(newUrl)) {
|
||||
data.url = newUrl;
|
||||
data.hasRedirection = true;
|
||||
}
|
||||
}
|
||||
} else if (route.resolveRedirectTo) {
|
||||
return $q.
|
||||
resolve($injector.invoke(route.resolveRedirectTo)).
|
||||
then(function(newUrl) {
|
||||
if (angular.isDefined(newUrl)) {
|
||||
data.url = newUrl;
|
||||
data.hasRedirection = true;
|
||||
}
|
||||
|
||||
return data;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
function handlePossibleRedirection(data) {
|
||||
var keepProcessingRoute = true;
|
||||
|
||||
if (data.route !== $route.current) {
|
||||
keepProcessingRoute = false;
|
||||
} else if (data.hasRedirection) {
|
||||
var oldUrl = $location.url();
|
||||
var newUrl = data.url;
|
||||
|
||||
if (newUrl) {
|
||||
$location.
|
||||
url(newUrl).
|
||||
replace();
|
||||
} else {
|
||||
newUrl = $location.
|
||||
path(data.path).
|
||||
search(data.search).
|
||||
replace().
|
||||
url();
|
||||
}
|
||||
|
||||
if (newUrl !== oldUrl) {
|
||||
// Exit out and don't process current next value,
|
||||
// wait for next location change from redirect
|
||||
keepProcessingRoute = false;
|
||||
}
|
||||
}
|
||||
|
||||
return keepProcessingRoute;
|
||||
}
|
||||
|
||||
function resolveLocals(route) {
|
||||
if (route) {
|
||||
var locals = angular.extend({}, route.resolve);
|
||||
@ -675,7 +805,6 @@ function $RouteProvider() {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function getTemplateFor(route) {
|
||||
var template, templateUrl;
|
||||
if (angular.isDefined(template = route.template)) {
|
||||
@ -694,7 +823,6 @@ function $RouteProvider() {
|
||||
return template;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @returns {Object} the current active route, by matching it against the URL
|
||||
*/
|
||||
@ -713,6 +841,29 @@ function $RouteProvider() {
|
||||
return match || routes[null] && inherit(routes[null], {params: {}, pathParams:{}});
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Object} newRoute - The new route configuration (as returned by `parseRoute()`).
|
||||
* @param {Object} oldRoute - The previous route configuration (as returned by `parseRoute()`).
|
||||
* @returns {boolean} Whether this is an "update-only" navigation, i.e. the URL maps to the same
|
||||
* route and it can be reused (based on the config and the type of change).
|
||||
*/
|
||||
function isNavigationUpdateOnly(newRoute, oldRoute) {
|
||||
// IF this is not a forced reload
|
||||
return !forceReload
|
||||
// AND both `newRoute`/`oldRoute` are defined
|
||||
&& newRoute && oldRoute
|
||||
// AND they map to the same Route Definition Object
|
||||
&& (newRoute.$$route === oldRoute.$$route)
|
||||
// AND `reloadOnUrl` is disabled
|
||||
&& (!newRoute.reloadOnUrl
|
||||
// OR `reloadOnSearch` is disabled
|
||||
|| (!newRoute.reloadOnSearch
|
||||
// AND both routes have the same path params
|
||||
&& angular.equals(newRoute.pathParams, oldRoute.pathParams)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns {string} interpolation of the redirect path with the parameters
|
||||
*/
|
||||
@ -734,6 +885,14 @@ function $RouteProvider() {
|
||||
}];
|
||||
}
|
||||
|
||||
instantiateRoute.$inject = ['$injector'];
|
||||
function instantiateRoute($injector) {
|
||||
if (isEagerInstantiationEnabled) {
|
||||
// Instantiate `$route`
|
||||
$injector.get('$route');
|
||||
}
|
||||
}
|
||||
|
||||
ngRouteModule.provider('$routeParams', $RouteParamsProvider);
|
||||
|
||||
|
||||
@ -741,6 +900,7 @@ ngRouteModule.provider('$routeParams', $RouteParamsProvider);
|
||||
* @ngdoc service
|
||||
* @name $routeParams
|
||||
* @requires $route
|
||||
* @this
|
||||
*
|
||||
* @description
|
||||
* The `$routeParams` service allows you to retrieve the current set of route parameters.
|
||||
@ -784,7 +944,6 @@ ngRouteModule.directive('ngView', ngViewFillContentFactory);
|
||||
* @restrict ECA
|
||||
*
|
||||
* @description
|
||||
* # Overview
|
||||
* `ngView` is a directive that complements the {@link ngRoute.$route $route} service by
|
||||
* including the rendered template of the current route into the main layout (`index.html`) file.
|
||||
* Every time the current route changes, the included view changes with it according to the
|
||||
@ -800,13 +959,6 @@ 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.
|
||||
@ -917,17 +1069,17 @@ ngRouteModule.directive('ngView', ngViewFillContentFactory);
|
||||
$locationProvider.html5Mode(true);
|
||||
}])
|
||||
.controller('MainCtrl', ['$route', '$routeParams', '$location',
|
||||
function($route, $routeParams, $location) {
|
||||
function MainCtrl($route, $routeParams, $location) {
|
||||
this.$route = $route;
|
||||
this.$location = $location;
|
||||
this.$routeParams = $routeParams;
|
||||
}])
|
||||
.controller('BookCtrl', ['$routeParams', function($routeParams) {
|
||||
this.name = "BookCtrl";
|
||||
.controller('BookCtrl', ['$routeParams', function BookCtrl($routeParams) {
|
||||
this.name = 'BookCtrl';
|
||||
this.params = $routeParams;
|
||||
}])
|
||||
.controller('ChapterCtrl', ['$routeParams', function($routeParams) {
|
||||
this.name = "ChapterCtrl";
|
||||
.controller('ChapterCtrl', ['$routeParams', function ChapterCtrl($routeParams) {
|
||||
this.name = 'ChapterCtrl';
|
||||
this.params = $routeParams;
|
||||
}]);
|
||||
|
||||
@ -937,15 +1089,15 @@ ngRouteModule.directive('ngView', ngViewFillContentFactory);
|
||||
it('should load and compile correct template', function() {
|
||||
element(by.linkText('Moby: Ch1')).click();
|
||||
var content = element(by.css('[ng-view]')).getText();
|
||||
expect(content).toMatch(/controller\: ChapterCtrl/);
|
||||
expect(content).toMatch(/Book Id\: Moby/);
|
||||
expect(content).toMatch(/Chapter Id\: 1/);
|
||||
expect(content).toMatch(/controller: ChapterCtrl/);
|
||||
expect(content).toMatch(/Book Id: Moby/);
|
||||
expect(content).toMatch(/Chapter Id: 1/);
|
||||
|
||||
element(by.partialLinkText('Scarlet')).click();
|
||||
|
||||
content = element(by.css('[ng-view]')).getText();
|
||||
expect(content).toMatch(/controller\: BookCtrl/);
|
||||
expect(content).toMatch(/Book Id\: Scarlet/);
|
||||
expect(content).toMatch(/controller: BookCtrl/);
|
||||
expect(content).toMatch(/Book Id: Scarlet/);
|
||||
});
|
||||
</file>
|
||||
</example>
|
||||
@ -988,8 +1140,8 @@ function ngViewFactory($route, $anchorScroll, $animate) {
|
||||
}
|
||||
if (currentElement) {
|
||||
previousLeaveAnimation = $animate.leave(currentElement);
|
||||
previousLeaveAnimation.then(function() {
|
||||
previousLeaveAnimation = null;
|
||||
previousLeaveAnimation.done(function(response) {
|
||||
if (response !== false) previousLeaveAnimation = null;
|
||||
});
|
||||
currentElement = null;
|
||||
}
|
||||
@ -1010,8 +1162,8 @@ function ngViewFactory($route, $anchorScroll, $animate) {
|
||||
// function is called before linking the content, which would apply child
|
||||
// directives to non existing elements.
|
||||
var clone = $transclude(newScope, function(clone) {
|
||||
$animate.enter(clone, null, currentElement || $element).then(function onNgViewEnter() {
|
||||
if (angular.isDefined(autoScrollExp)
|
||||
$animate.enter(clone, null, currentElement || $element).done(function onNgViewEnter(response) {
|
||||
if (response !== false && angular.isDefined(autoScrollExp)
|
||||
&& (!autoScrollExp || scope.$eval(autoScrollExp))) {
|
||||
$anchorScroll();
|
||||
}
|
||||
|
349
xstatic/pkg/angular/data/angular-sanitize.js
vendored
349
xstatic/pkg/angular/data/angular-sanitize.js
vendored
@ -1,6 +1,6 @@
|
||||
/**
|
||||
* @license AngularJS v1.5.8
|
||||
* (c) 2010-2016 Google, Inc. http://angularjs.org
|
||||
* @license AngularJS v1.8.2
|
||||
* (c) 2010-2020 Google, Inc. http://angularjs.org
|
||||
* License: MIT
|
||||
*/
|
||||
(function(window, angular) {'use strict';
|
||||
@ -20,9 +20,11 @@ var $sanitizeMinErr = angular.$$minErr('$sanitize');
|
||||
var bind;
|
||||
var extend;
|
||||
var forEach;
|
||||
var isArray;
|
||||
var isDefined;
|
||||
var lowercase;
|
||||
var noop;
|
||||
var nodeContains;
|
||||
var htmlParser;
|
||||
var htmlSanitizeWriter;
|
||||
|
||||
@ -31,13 +33,8 @@ var htmlSanitizeWriter;
|
||||
* @name ngSanitize
|
||||
* @description
|
||||
*
|
||||
* # ngSanitize
|
||||
*
|
||||
* The `ngSanitize` module provides functionality to sanitize HTML.
|
||||
*
|
||||
*
|
||||
* <div doc-module-components="ngSanitize"></div>
|
||||
*
|
||||
* See {@link ngSanitize.$sanitize `$sanitize`} for usage.
|
||||
*/
|
||||
|
||||
@ -49,13 +46,12 @@ var htmlSanitizeWriter;
|
||||
* @description
|
||||
* Sanitizes an html string by stripping all potentially dangerous tokens.
|
||||
*
|
||||
* The input is sanitized by parsing the HTML into tokens. All safe tokens (from a whitelist) are
|
||||
* then serialized back to properly escaped html string. This means that no unsafe input can make
|
||||
* The input is sanitized by parsing the HTML into tokens. All safe tokens (from a trusted URI list) are
|
||||
* then serialized back to a properly escaped HTML string. This means that no unsafe input can make
|
||||
* it into the returned string.
|
||||
*
|
||||
* The whitelist for URL sanitization of attribute values is configured using the functions
|
||||
* `aHrefSanitizationWhitelist` and `imgSrcSanitizationWhitelist` of {@link ng.$compileProvider
|
||||
* `$compileProvider`}.
|
||||
* The trusted URIs for URL sanitization of attribute values is configured using the functions
|
||||
* `aHrefSanitizationTrustedUrlList` and `imgSrcSanitizationTrustedUrlList` of {@link $compileProvider}.
|
||||
*
|
||||
* The input may also contain SVG markup if this is enabled via {@link $sanitizeProvider}.
|
||||
*
|
||||
@ -63,7 +59,7 @@ var htmlSanitizeWriter;
|
||||
* @returns {string} Sanitized HTML.
|
||||
*
|
||||
* @example
|
||||
<example module="sanitizeExample" deps="angular-sanitize.js">
|
||||
<example module="sanitizeExample" deps="angular-sanitize.js" name="sanitize-service">
|
||||
<file name="index.html">
|
||||
<script>
|
||||
angular.module('sanitizeExample', ['ngSanitize'])
|
||||
@ -112,19 +108,19 @@ var htmlSanitizeWriter;
|
||||
</file>
|
||||
<file name="protractor.js" type="protractor">
|
||||
it('should sanitize the html snippet by default', function() {
|
||||
expect(element(by.css('#bind-html-with-sanitize div')).getInnerHtml()).
|
||||
expect(element(by.css('#bind-html-with-sanitize div')).getAttribute('innerHTML')).
|
||||
toBe('<p>an html\n<em>click here</em>\nsnippet</p>');
|
||||
});
|
||||
|
||||
it('should inline raw snippet if bound to a trusted value', function() {
|
||||
expect(element(by.css('#bind-html-with-trust div')).getInnerHtml()).
|
||||
expect(element(by.css('#bind-html-with-trust div')).getAttribute('innerHTML')).
|
||||
toBe("<p style=\"color:blue\">an html\n" +
|
||||
"<em onmouseover=\"this.textContent='PWN3D!'\">click here</em>\n" +
|
||||
"snippet</p>");
|
||||
});
|
||||
|
||||
it('should escape snippet without any filter', function() {
|
||||
expect(element(by.css('#bind-default div')).getInnerHtml()).
|
||||
expect(element(by.css('#bind-default div')).getAttribute('innerHTML')).
|
||||
toBe("<p style=\"color:blue\">an html\n" +
|
||||
"<em onmouseover=\"this.textContent='PWN3D!'\">click here</em>\n" +
|
||||
"snippet</p>");
|
||||
@ -133,11 +129,11 @@ var htmlSanitizeWriter;
|
||||
it('should update', function() {
|
||||
element(by.model('snippet')).clear();
|
||||
element(by.model('snippet')).sendKeys('new <b onclick="alert(1)">text</b>');
|
||||
expect(element(by.css('#bind-html-with-sanitize div')).getInnerHtml()).
|
||||
expect(element(by.css('#bind-html-with-sanitize div')).getAttribute('innerHTML')).
|
||||
toBe('new <b>text</b>');
|
||||
expect(element(by.css('#bind-html-with-trust div')).getInnerHtml()).toBe(
|
||||
expect(element(by.css('#bind-html-with-trust div')).getAttribute('innerHTML')).toBe(
|
||||
'new <b onclick="alert(1)">text</b>');
|
||||
expect(element(by.css('#bind-default div')).getInnerHtml()).toBe(
|
||||
expect(element(by.css('#bind-default div')).getAttribute('innerHTML')).toBe(
|
||||
"new <b onclick=\"alert(1)\">text</b>");
|
||||
});
|
||||
</file>
|
||||
@ -148,14 +144,17 @@ var htmlSanitizeWriter;
|
||||
/**
|
||||
* @ngdoc provider
|
||||
* @name $sanitizeProvider
|
||||
* @this
|
||||
*
|
||||
* @description
|
||||
* Creates and configures {@link $sanitize} instance.
|
||||
*/
|
||||
function $SanitizeProvider() {
|
||||
var hasBeenInstantiated = false;
|
||||
var svgEnabled = false;
|
||||
|
||||
this.$get = ['$$sanitizeUri', function($$sanitizeUri) {
|
||||
hasBeenInstantiated = true;
|
||||
if (svgEnabled) {
|
||||
extend(validElements, svgElements);
|
||||
}
|
||||
@ -196,7 +195,7 @@ function $SanitizeProvider() {
|
||||
* </div>
|
||||
*
|
||||
* @param {boolean=} flag Enable or disable SVG support in the sanitizer.
|
||||
* @returns {boolean|ng.$sanitizeProvider} Returns the currently configured value if called
|
||||
* @returns {boolean|$sanitizeProvider} Returns the currently configured value if called
|
||||
* without an argument or self for chaining otherwise.
|
||||
*/
|
||||
this.enableSvg = function(enableSvg) {
|
||||
@ -208,6 +207,105 @@ function $SanitizeProvider() {
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @ngdoc method
|
||||
* @name $sanitizeProvider#addValidElements
|
||||
* @kind function
|
||||
*
|
||||
* @description
|
||||
* Extends the built-in lists of valid HTML/SVG elements, i.e. elements that are considered safe
|
||||
* and are not stripped off during sanitization. You can extend the following lists of elements:
|
||||
*
|
||||
* - `htmlElements`: A list of elements (tag names) to extend the current list of safe HTML
|
||||
* elements. HTML elements considered safe will not be removed during sanitization. All other
|
||||
* elements will be stripped off.
|
||||
*
|
||||
* - `htmlVoidElements`: This is similar to `htmlElements`, but marks the elements as
|
||||
* "void elements" (similar to HTML
|
||||
* [void elements](https://rawgit.com/w3c/html/html5.1-2/single-page.html#void-elements)). These
|
||||
* elements have no end tag and cannot have content.
|
||||
*
|
||||
* - `svgElements`: This is similar to `htmlElements`, but for SVG elements. This list is only
|
||||
* taken into account if SVG is {@link ngSanitize.$sanitizeProvider#enableSvg enabled} for
|
||||
* `$sanitize`.
|
||||
*
|
||||
* <div class="alert alert-info">
|
||||
* This method must be called during the {@link angular.Module#config config} phase. Once the
|
||||
* `$sanitize` service has been instantiated, this method has no effect.
|
||||
* </div>
|
||||
*
|
||||
* <div class="alert alert-warning">
|
||||
* Keep in mind that extending the built-in lists of elements may expose your app to XSS or
|
||||
* other vulnerabilities. Be very mindful of the elements you add.
|
||||
* </div>
|
||||
*
|
||||
* @param {Array<String>|Object} elements - A list of valid HTML elements or an object with one or
|
||||
* more of the following properties:
|
||||
* - **htmlElements** - `{Array<String>}` - A list of elements to extend the current list of
|
||||
* HTML elements.
|
||||
* - **htmlVoidElements** - `{Array<String>}` - A list of elements to extend the current list of
|
||||
* void HTML elements; i.e. elements that do not have an end tag.
|
||||
* - **svgElements** - `{Array<String>}` - A list of elements to extend the current list of SVG
|
||||
* elements. The list of SVG elements is only taken into account if SVG is
|
||||
* {@link ngSanitize.$sanitizeProvider#enableSvg enabled} for `$sanitize`.
|
||||
*
|
||||
* Passing an array (`[...]`) is equivalent to passing `{htmlElements: [...]}`.
|
||||
*
|
||||
* @return {$sanitizeProvider} Returns self for chaining.
|
||||
*/
|
||||
this.addValidElements = function(elements) {
|
||||
if (!hasBeenInstantiated) {
|
||||
if (isArray(elements)) {
|
||||
elements = {htmlElements: elements};
|
||||
}
|
||||
|
||||
addElementsTo(svgElements, elements.svgElements);
|
||||
addElementsTo(voidElements, elements.htmlVoidElements);
|
||||
addElementsTo(validElements, elements.htmlVoidElements);
|
||||
addElementsTo(validElements, elements.htmlElements);
|
||||
}
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @ngdoc method
|
||||
* @name $sanitizeProvider#addValidAttrs
|
||||
* @kind function
|
||||
*
|
||||
* @description
|
||||
* Extends the built-in list of valid attributes, i.e. attributes that are considered safe and are
|
||||
* not stripped off during sanitization.
|
||||
*
|
||||
* **Note**:
|
||||
* The new attributes will not be treated as URI attributes, which means their values will not be
|
||||
* sanitized as URIs using `$compileProvider`'s
|
||||
* {@link ng.$compileProvider#aHrefSanitizationTrustedUrlList aHrefSanitizationTrustedUrlList} and
|
||||
* {@link ng.$compileProvider#imgSrcSanitizationTrustedUrlList imgSrcSanitizationTrustedUrlList}.
|
||||
*
|
||||
* <div class="alert alert-info">
|
||||
* This method must be called during the {@link angular.Module#config config} phase. Once the
|
||||
* `$sanitize` service has been instantiated, this method has no effect.
|
||||
* </div>
|
||||
*
|
||||
* <div class="alert alert-warning">
|
||||
* Keep in mind that extending the built-in list of attributes may expose your app to XSS or
|
||||
* other vulnerabilities. Be very mindful of the attributes you add.
|
||||
* </div>
|
||||
*
|
||||
* @param {Array<String>} attrs - A list of valid attributes.
|
||||
*
|
||||
* @returns {$sanitizeProvider} Returns self for chaining.
|
||||
*/
|
||||
this.addValidAttrs = function(attrs) {
|
||||
if (!hasBeenInstantiated) {
|
||||
extend(validAttrs, arrayToMap(attrs, true));
|
||||
}
|
||||
return this;
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Private stuff
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
@ -215,17 +313,23 @@ function $SanitizeProvider() {
|
||||
bind = angular.bind;
|
||||
extend = angular.extend;
|
||||
forEach = angular.forEach;
|
||||
isArray = angular.isArray;
|
||||
isDefined = angular.isDefined;
|
||||
lowercase = angular.lowercase;
|
||||
lowercase = angular.$$lowercase;
|
||||
noop = angular.noop;
|
||||
|
||||
htmlParser = htmlParserImpl;
|
||||
htmlSanitizeWriter = htmlSanitizeWriterImpl;
|
||||
|
||||
nodeContains = window.Node.prototype.contains || /** @this */ function(arg) {
|
||||
// eslint-disable-next-line no-bitwise
|
||||
return !!(this.compareDocumentPosition(arg) & 16);
|
||||
};
|
||||
|
||||
// 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;
|
||||
NON_ALPHANUMERIC_REGEXP = /([^#-~ |!])/g;
|
||||
|
||||
|
||||
// Good source of info about elements and attributes
|
||||
@ -234,36 +338,36 @@ function $SanitizeProvider() {
|
||||
|
||||
// Safe Void Elements - HTML5
|
||||
// http://dev.w3.org/html5/spec/Overview.html#void-elements
|
||||
var voidElements = toMap("area,br,col,hr,img,wbr");
|
||||
var voidElements = stringToMap('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"),
|
||||
var optionalEndTagBlockElements = stringToMap('colgroup,dd,dt,li,p,tbody,td,tfoot,th,thead,tr'),
|
||||
optionalEndTagInlineElements = stringToMap('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"));
|
||||
var blockElements = extend({}, optionalEndTagBlockElements, stringToMap('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"));
|
||||
var inlineElements = extend({}, optionalEndTagInlineElements, stringToMap('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");
|
||||
var svgElements = stringToMap('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 blockedElements = stringToMap('script,style');
|
||||
|
||||
var validElements = extend({},
|
||||
voidElements,
|
||||
@ -272,9 +376,9 @@ function $SanitizeProvider() {
|
||||
optionalEndTagElements);
|
||||
|
||||
//Attributes that have href and hence need to be sanitized
|
||||
var uriAttrs = toMap("background,cite,href,longdesc,src,xlink:href");
|
||||
var uriAttrs = stringToMap('background,cite,href,longdesc,src,xlink:href,xml:base');
|
||||
|
||||
var htmlAttrs = toMap('abbr,align,alt,axis,bgcolor,border,cellpadding,cellspacing,class,clear,' +
|
||||
var htmlAttrs = stringToMap('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,' +
|
||||
@ -282,7 +386,7 @@ function $SanitizeProvider() {
|
||||
|
||||
// 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,' +
|
||||
var svgAttrs = stringToMap('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,' +
|
||||
@ -303,35 +407,74 @@ function $SanitizeProvider() {
|
||||
svgAttrs,
|
||||
htmlAttrs);
|
||||
|
||||
function toMap(str, lowercaseKeys) {
|
||||
var obj = {}, items = str.split(','), i;
|
||||
function stringToMap(str, lowercaseKeys) {
|
||||
return arrayToMap(str.split(','), lowercaseKeys);
|
||||
}
|
||||
|
||||
function arrayToMap(items, lowercaseKeys) {
|
||||
var obj = {}, 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");
|
||||
function addElementsTo(elementsMap, newElements) {
|
||||
if (newElements && newElements.length) {
|
||||
extend(elementsMap, arrayToMap(newElements));
|
||||
}
|
||||
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);
|
||||
/**
|
||||
* Create an inert document that contains the dirty HTML that needs sanitizing.
|
||||
* We use the DOMParser API by default and fall back to createHTMLDocument if DOMParser is not
|
||||
* available.
|
||||
*/
|
||||
var getInertBodyElement /* function(html: string): HTMLBodyElement */ = (function(window, document) {
|
||||
if (isDOMParserAvailable()) {
|
||||
return getInertBodyElement_DOMParser;
|
||||
}
|
||||
})(window);
|
||||
|
||||
if (!document || !document.implementation) {
|
||||
throw $sanitizeMinErr('noinert', 'Can\'t create an inert html document');
|
||||
}
|
||||
var inertDocument = document.implementation.createHTMLDocument('inert');
|
||||
var inertBodyElement = (inertDocument.documentElement || inertDocument.getDocumentElement()).querySelector('body');
|
||||
return getInertBodyElement_InertDocument;
|
||||
|
||||
function isDOMParserAvailable() {
|
||||
try {
|
||||
return !!getInertBodyElement_DOMParser('');
|
||||
} catch (e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function getInertBodyElement_DOMParser(html) {
|
||||
// We add this dummy element to ensure that the rest of the content is parsed as expected
|
||||
// e.g. leading whitespace is maintained and tags like `<meta>` do not get hoisted to the `<head>` tag.
|
||||
html = '<remove></remove>' + html;
|
||||
try {
|
||||
var body = new window.DOMParser().parseFromString(html, 'text/html').body;
|
||||
body.firstChild.remove();
|
||||
return body;
|
||||
} catch (e) {
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
function getInertBodyElement_InertDocument(html) {
|
||||
inertBodyElement.innerHTML = html;
|
||||
|
||||
// Support: IE 9-11 only
|
||||
// strip custom-namespaced attributes on IE<=11
|
||||
if (document.documentMode) {
|
||||
stripCustomNsAttrs(inertBodyElement);
|
||||
}
|
||||
|
||||
return inertBodyElement;
|
||||
}
|
||||
})(window, window.document);
|
||||
|
||||
/**
|
||||
* @example
|
||||
@ -351,22 +494,21 @@ function $SanitizeProvider() {
|
||||
} else if (typeof html !== 'string') {
|
||||
html = '' + html;
|
||||
}
|
||||
inertBodyElement.innerHTML = html;
|
||||
|
||||
var inertBodyElement = getInertBodyElement(html);
|
||||
if (!inertBodyElement) return '';
|
||||
|
||||
//mXSS protection
|
||||
var mXSSAttempts = 5;
|
||||
do {
|
||||
if (mXSSAttempts === 0) {
|
||||
throw $sanitizeMinErr('uinput', "Failed to sanitize html because the input is unstable");
|
||||
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;
|
||||
// trigger mXSS if it is going to happen by reading and writing the innerHTML
|
||||
html = inertBodyElement.innerHTML;
|
||||
inertBodyElement = getInertBodyElement(html);
|
||||
} while (html !== inertBodyElement.innerHTML);
|
||||
|
||||
var node = inertBodyElement.firstChild;
|
||||
@ -382,16 +524,16 @@ function $SanitizeProvider() {
|
||||
|
||||
var nextNode;
|
||||
if (!(nextNode = node.firstChild)) {
|
||||
if (node.nodeType == 1) {
|
||||
if (node.nodeType === 1) {
|
||||
handler.end(node.nodeName.toLowerCase());
|
||||
}
|
||||
nextNode = node.nextSibling;
|
||||
nextNode = getNonDescendant('nextSibling', node);
|
||||
if (!nextNode) {
|
||||
while (nextNode == null) {
|
||||
node = node.parentNode;
|
||||
node = getNonDescendant('parentNode', node);
|
||||
if (node === inertBodyElement) break;
|
||||
nextNode = node.nextSibling;
|
||||
if (node.nodeType == 1) {
|
||||
nextNode = getNonDescendant('nextSibling', node);
|
||||
if (node.nodeType === 1) {
|
||||
handler.end(node.nodeName.toLowerCase());
|
||||
}
|
||||
}
|
||||
@ -400,7 +542,7 @@ function $SanitizeProvider() {
|
||||
node = nextNode;
|
||||
}
|
||||
|
||||
while (node = inertBodyElement.firstChild) {
|
||||
while ((node = inertBodyElement.firstChild)) {
|
||||
inertBodyElement.removeChild(node);
|
||||
}
|
||||
}
|
||||
@ -481,6 +623,7 @@ function $SanitizeProvider() {
|
||||
out(tag);
|
||||
out('>');
|
||||
}
|
||||
// eslint-disable-next-line eqeqeq
|
||||
if (tag == ignoreCurrentElement) {
|
||||
ignoreCurrentElement = false;
|
||||
}
|
||||
@ -502,29 +645,37 @@ function $SanitizeProvider() {
|
||||
* @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--;
|
||||
while (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);
|
||||
}
|
||||
var nextNode = node.firstChild;
|
||||
if (nextNode) {
|
||||
stripCustomNsAttrs(nextNode);
|
||||
}
|
||||
|
||||
nextNode = node.nextSibling;
|
||||
if (nextNode) {
|
||||
stripCustomNsAttrs(nextNode);
|
||||
node = getNonDescendant('nextSibling', node);
|
||||
}
|
||||
}
|
||||
|
||||
function getNonDescendant(propName, node) {
|
||||
// An element is clobbered if its `propName` property points to one of its descendants
|
||||
var nextNode = node[propName];
|
||||
if (nextNode && nodeContains.call(node, nextNode)) {
|
||||
throw $sanitizeMinErr('elclob', 'Failed to sanitize html because the element is clobbered: {0}', node.outerHTML || node.outerText);
|
||||
}
|
||||
return nextNode;
|
||||
}
|
||||
}
|
||||
|
||||
function sanitizeText(chars) {
|
||||
@ -536,7 +687,9 @@ function sanitizeText(chars) {
|
||||
|
||||
|
||||
// define ngSanitize module and register $sanitize service
|
||||
angular.module('ngSanitize', []).provider('$sanitize', $SanitizeProvider);
|
||||
angular.module('ngSanitize', [])
|
||||
.provider('$sanitize', $SanitizeProvider)
|
||||
.info({ angularVersion: '"1.8.2"' });
|
||||
|
||||
/**
|
||||
* @ngdoc filter
|
||||
@ -544,13 +697,13 @@ angular.module('ngSanitize', []).provider('$sanitize', $SanitizeProvider);
|
||||
* @kind function
|
||||
*
|
||||
* @description
|
||||
* Finds links in text input and turns them into html links. Supports `http/https/ftp/mailto` and
|
||||
* Finds links in text input and turns them into html links. Supports `http/https/ftp/sftp/mailto` and
|
||||
* plain email address links.
|
||||
*
|
||||
* Requires the {@link ngSanitize `ngSanitize`} module to be installed.
|
||||
*
|
||||
* @param {string} text Input text.
|
||||
* @param {string} target Window (`_blank|_self|_parent|_top`) or named frame to open links in.
|
||||
* @param {string} [target] Window (`_blank|_self|_parent|_top`) or named frame to open links in.
|
||||
* @param {object|function(url)} [attributes] Add custom attributes to the link element.
|
||||
*
|
||||
* Can be one of:
|
||||
@ -568,7 +721,7 @@ angular.module('ngSanitize', []).provider('$sanitize', $SanitizeProvider);
|
||||
<span ng-bind-html="linky_expression | linky"></span>
|
||||
*
|
||||
* @example
|
||||
<example module="linkyExample" deps="angular-sanitize.js">
|
||||
<example module="linkyExample" deps="angular-sanitize.js" name="linky-filter">
|
||||
<file name="index.html">
|
||||
<div ng-controller="ExampleController">
|
||||
Snippet: <textarea ng-model="snippet" cols="60" rows="3"></textarea>
|
||||
@ -616,10 +769,10 @@ angular.module('ngSanitize', []).provider('$sanitize', $SanitizeProvider);
|
||||
angular.module('linkyExample', ['ngSanitize'])
|
||||
.controller('ExampleController', ['$scope', function($scope) {
|
||||
$scope.snippet =
|
||||
'Pretty text with some links:\n'+
|
||||
'http://angularjs.org/,\n'+
|
||||
'mailto:us@somewhere.org,\n'+
|
||||
'another@somewhere.org,\n'+
|
||||
'Pretty text with some links:\n' +
|
||||
'http://angularjs.org/,\n' +
|
||||
'mailto:us@somewhere.org,\n' +
|
||||
'another@somewhere.org,\n' +
|
||||
'and one more: ftp://127.0.0.1/.';
|
||||
$scope.snippetWithSingleURL = 'http://angularjs.org/';
|
||||
}]);
|
||||
@ -667,7 +820,7 @@ angular.module('ngSanitize', []).provider('$sanitize', $SanitizeProvider);
|
||||
*/
|
||||
angular.module('ngSanitize').filter('linky', ['$sanitize', function($sanitize) {
|
||||
var LINKY_URL_REGEXP =
|
||||
/((ftp|https?):\/\/|(www\.)|(mailto:)?[A-Za-z0-9._%+-]+@)\S*[^\s.;,(){}<>"\u201d\u2019]/i,
|
||||
/((s?ftp|https?):\/\/|(www\.)|(mailto:)?[A-Za-z0-9._%+-]+@)\S*[^\s.;,(){}<>"\u201d\u2019]/i,
|
||||
MAILTO_REGEXP = /^mailto:/i;
|
||||
|
||||
var linkyMinErr = angular.$$minErr('linky');
|
||||
|
23823
xstatic/pkg/angular/data/angular-scenario.js
vendored
23823
xstatic/pkg/angular/data/angular-scenario.js
vendored
File diff suppressed because it is too large
Load Diff
459
xstatic/pkg/angular/data/angular-touch.js
vendored
459
xstatic/pkg/angular/data/angular-touch.js
vendored
@ -1,135 +1,38 @@
|
||||
/**
|
||||
* @license AngularJS v1.5.8
|
||||
* (c) 2010-2016 Google, Inc. http://angularjs.org
|
||||
* @license AngularJS v1.8.2
|
||||
* (c) 2010-2020 Google, Inc. http://angularjs.org
|
||||
* License: MIT
|
||||
*/
|
||||
(function(window, angular) {'use strict';
|
||||
|
||||
/* global ngTouchClickDirectiveFactory: false,
|
||||
*/
|
||||
|
||||
/**
|
||||
* @ngdoc module
|
||||
* @name ngTouch
|
||||
* @description
|
||||
*
|
||||
* # ngTouch
|
||||
*
|
||||
* The `ngTouch` module provides touch events and other helpers for touch-enabled devices.
|
||||
* The `ngTouch` module provides helpers for touch-enabled devices.
|
||||
* The implementation is based on jQuery Mobile touch event handling
|
||||
* ([jquerymobile.com](http://jquerymobile.com/)).
|
||||
*
|
||||
* ([jquerymobile.com](http://jquerymobile.com/)). *
|
||||
*
|
||||
* See {@link ngTouch.$swipe `$swipe`} for usage.
|
||||
*
|
||||
* <div doc-module-components="ngTouch"></div>
|
||||
*
|
||||
* @deprecated
|
||||
* sinceVersion="1.7.0"
|
||||
* The ngTouch module with the {@link ngTouch.$swipe `$swipe`} service and
|
||||
* the {@link ngTouch.ngSwipeLeft} and {@link ngTouch.ngSwipeRight} directives are
|
||||
* deprecated. Instead, stand-alone libraries for touch handling and gesture interaction
|
||||
* should be used, for example [HammerJS](https://hammerjs.github.io/) (which is also used by
|
||||
* Angular).
|
||||
*/
|
||||
|
||||
// define ngTouch module
|
||||
/* global -ngTouch */
|
||||
/* global ngTouch */
|
||||
var ngTouch = angular.module('ngTouch', []);
|
||||
|
||||
ngTouch.provider('$touch', $TouchProvider);
|
||||
ngTouch.info({ angularVersion: '"1.8.2"' });
|
||||
|
||||
function nodeName_(element) {
|
||||
return angular.lowercase(element.nodeName || (element[0] && element[0].nodeName));
|
||||
}
|
||||
|
||||
/**
|
||||
* @ngdoc provider
|
||||
* @name $touchProvider
|
||||
*
|
||||
* @description
|
||||
* The `$touchProvider` allows enabling / disabling {@link ngTouch.ngClick ngTouch's ngClick directive}.
|
||||
*/
|
||||
$TouchProvider.$inject = ['$provide', '$compileProvider'];
|
||||
function $TouchProvider($provide, $compileProvider) {
|
||||
|
||||
/**
|
||||
* @ngdoc method
|
||||
* @name $touchProvider#ngClickOverrideEnabled
|
||||
*
|
||||
* @param {boolean=} enabled update the ngClickOverrideEnabled state if provided, otherwise just return the
|
||||
* current ngClickOverrideEnabled state
|
||||
* @returns {*} current value if used as getter or itself (chaining) if used as setter
|
||||
*
|
||||
* @kind function
|
||||
*
|
||||
* @description
|
||||
* Call this method to enable/disable {@link ngTouch.ngClick ngTouch's ngClick directive}. If enabled,
|
||||
* the default ngClick directive will be replaced by a version that eliminates the 300ms delay for
|
||||
* click events on browser for touch-devices.
|
||||
*
|
||||
* The default is `false`.
|
||||
*
|
||||
*/
|
||||
var ngClickOverrideEnabled = false;
|
||||
var ngClickDirectiveAdded = false;
|
||||
this.ngClickOverrideEnabled = function(enabled) {
|
||||
if (angular.isDefined(enabled)) {
|
||||
|
||||
if (enabled && !ngClickDirectiveAdded) {
|
||||
ngClickDirectiveAdded = true;
|
||||
|
||||
// Use this to identify the correct directive in the delegate
|
||||
ngTouchClickDirectiveFactory.$$moduleName = 'ngTouch';
|
||||
$compileProvider.directive('ngClick', ngTouchClickDirectiveFactory);
|
||||
|
||||
$provide.decorator('ngClickDirective', ['$delegate', function($delegate) {
|
||||
if (ngClickOverrideEnabled) {
|
||||
// drop the default ngClick directive
|
||||
$delegate.shift();
|
||||
} else {
|
||||
// drop the ngTouch ngClick directive if the override has been re-disabled (because
|
||||
// we cannot de-register added directives)
|
||||
var i = $delegate.length - 1;
|
||||
while (i >= 0) {
|
||||
if ($delegate[i].$$moduleName === 'ngTouch') {
|
||||
$delegate.splice(i, 1);
|
||||
break;
|
||||
}
|
||||
i--;
|
||||
}
|
||||
}
|
||||
|
||||
return $delegate;
|
||||
}]);
|
||||
}
|
||||
|
||||
ngClickOverrideEnabled = enabled;
|
||||
return this;
|
||||
}
|
||||
|
||||
return ngClickOverrideEnabled;
|
||||
};
|
||||
|
||||
/**
|
||||
* @ngdoc service
|
||||
* @name $touch
|
||||
* @kind object
|
||||
*
|
||||
* @description
|
||||
* Provides the {@link ngTouch.$touch#ngClickOverrideEnabled `ngClickOverrideEnabled`} method.
|
||||
*
|
||||
*/
|
||||
this.$get = function() {
|
||||
return {
|
||||
/**
|
||||
* @ngdoc method
|
||||
* @name $touch#ngClickOverrideEnabled
|
||||
*
|
||||
* @returns {*} current value of `ngClickOverrideEnabled` set in the {@link ngTouch.$touchProvider $touchProvider},
|
||||
* i.e. if {@link ngTouch.ngClick ngTouch's ngClick} directive is enabled.
|
||||
*
|
||||
* @kind function
|
||||
*/
|
||||
ngClickOverrideEnabled: function() {
|
||||
return ngClickOverrideEnabled;
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
return angular.$$lowercase(element.nodeName || (element[0] && element[0].nodeName));
|
||||
}
|
||||
|
||||
/* global ngTouch: false */
|
||||
@ -138,6 +41,11 @@ function $TouchProvider($provide, $compileProvider) {
|
||||
* @ngdoc service
|
||||
* @name $swipe
|
||||
*
|
||||
* @deprecated
|
||||
* sinceVersion="1.7.0"
|
||||
*
|
||||
* See the {@link ngTouch module} documentation for more information.
|
||||
*
|
||||
* @description
|
||||
* The `$swipe` service is a service that abstracts the messier details of hold-and-drag swipe
|
||||
* behavior, to make implementing swipe-related directives more convenient.
|
||||
@ -249,13 +157,17 @@ ngTouch.factory('$swipe', [function() {
|
||||
totalX = 0;
|
||||
totalY = 0;
|
||||
lastPos = startCoords;
|
||||
eventHandlers['start'] && eventHandlers['start'](startCoords, event);
|
||||
if (eventHandlers['start']) {
|
||||
eventHandlers['start'](startCoords, event);
|
||||
}
|
||||
});
|
||||
var events = getEvents(pointerTypes, 'cancel');
|
||||
if (events) {
|
||||
element.on(events, function(event) {
|
||||
active = false;
|
||||
eventHandlers['cancel'] && eventHandlers['cancel'](event);
|
||||
if (eventHandlers['cancel']) {
|
||||
eventHandlers['cancel'](event);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@ -284,325 +196,41 @@ ngTouch.factory('$swipe', [function() {
|
||||
if (totalY > totalX) {
|
||||
// Allow native scrolling to take over.
|
||||
active = false;
|
||||
eventHandlers['cancel'] && eventHandlers['cancel'](event);
|
||||
if (eventHandlers['cancel']) {
|
||||
eventHandlers['cancel'](event);
|
||||
}
|
||||
return;
|
||||
} else {
|
||||
// Prevent the browser from scrolling.
|
||||
event.preventDefault();
|
||||
eventHandlers['move'] && eventHandlers['move'](coords, event);
|
||||
if (eventHandlers['move']) {
|
||||
eventHandlers['move'](coords, event);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
element.on(getEvents(pointerTypes, 'end'), function(event) {
|
||||
if (!active) return;
|
||||
active = false;
|
||||
eventHandlers['end'] && eventHandlers['end'](getCoordinates(event), event);
|
||||
if (eventHandlers['end']) {
|
||||
eventHandlers['end'](getCoordinates(event), event);
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
}]);
|
||||
|
||||
/* global ngTouch: false,
|
||||
nodeName_: false
|
||||
*/
|
||||
|
||||
/**
|
||||
* @ngdoc directive
|
||||
* @name ngClick
|
||||
* @deprecated
|
||||
*
|
||||
* @description
|
||||
* <div class="alert alert-danger">
|
||||
* **DEPRECATION NOTICE**: Beginning with Angular 1.5, this directive is deprecated and by default **disabled**.
|
||||
* The directive will receive no further support and might be removed from future releases.
|
||||
* If you need the directive, you can enable it with the {@link ngTouch.$touchProvider $touchProvider#ngClickOverrideEnabled}
|
||||
* function. We also recommend that you migrate to [FastClick](https://github.com/ftlabs/fastclick).
|
||||
* To learn more about the 300ms delay, this [Telerik article](http://developer.telerik.com/featured/300-ms-click-delay-ios-8/)
|
||||
* gives a good overview.
|
||||
* </div>
|
||||
* A more powerful replacement for the default ngClick designed to be used on touchscreen
|
||||
* devices. Most mobile browsers wait about 300ms after a tap-and-release before sending
|
||||
* the click event. This version handles them immediately, and then prevents the
|
||||
* following click event from propagating.
|
||||
*
|
||||
* Requires the {@link ngTouch `ngTouch`} module to be installed.
|
||||
*
|
||||
* This directive can fall back to using an ordinary click event, and so works on desktop
|
||||
* browsers as well as mobile.
|
||||
*
|
||||
* This directive also sets the CSS class `ng-click-active` while the element is being held
|
||||
* down (by a mouse click or touch) so you can restyle the depressed element if you wish.
|
||||
*
|
||||
* @element ANY
|
||||
* @param {expression} ngClick {@link guide/expression Expression} to evaluate
|
||||
* upon tap. (Event object is available as `$event`)
|
||||
*
|
||||
* @example
|
||||
<example module="ngClickExample" deps="angular-touch.js">
|
||||
<file name="index.html">
|
||||
<button ng-click="count = count + 1" ng-init="count=0">
|
||||
Increment
|
||||
</button>
|
||||
count: {{ count }}
|
||||
</file>
|
||||
<file name="script.js">
|
||||
angular.module('ngClickExample', ['ngTouch']);
|
||||
</file>
|
||||
</example>
|
||||
*/
|
||||
|
||||
var ngTouchClickDirectiveFactory = ['$parse', '$timeout', '$rootElement',
|
||||
function($parse, $timeout, $rootElement) {
|
||||
var TAP_DURATION = 750; // Shorter than 750ms is a tap, longer is a taphold or drag.
|
||||
var MOVE_TOLERANCE = 12; // 12px seems to work in most mobile browsers.
|
||||
var PREVENT_DURATION = 2500; // 2.5 seconds maximum from preventGhostClick call to click
|
||||
var CLICKBUSTER_THRESHOLD = 25; // 25 pixels in any dimension is the limit for busting clicks.
|
||||
|
||||
var ACTIVE_CLASS_NAME = 'ng-click-active';
|
||||
var lastPreventedTime;
|
||||
var touchCoordinates;
|
||||
var lastLabelClickCoordinates;
|
||||
|
||||
|
||||
// TAP EVENTS AND GHOST CLICKS
|
||||
//
|
||||
// Why tap events?
|
||||
// Mobile browsers detect a tap, then wait a moment (usually ~300ms) to see if you're
|
||||
// double-tapping, and then fire a click event.
|
||||
//
|
||||
// This delay sucks and makes mobile apps feel unresponsive.
|
||||
// So we detect touchstart, touchcancel and touchend ourselves and determine when
|
||||
// the user has tapped on something.
|
||||
//
|
||||
// What happens when the browser then generates a click event?
|
||||
// The browser, of course, also detects the tap and fires a click after a delay. This results in
|
||||
// tapping/clicking twice. We do "clickbusting" to prevent it.
|
||||
//
|
||||
// How does it work?
|
||||
// We attach global touchstart and click handlers, that run during the capture (early) phase.
|
||||
// So the sequence for a tap is:
|
||||
// - global touchstart: Sets an "allowable region" at the point touched.
|
||||
// - element's touchstart: Starts a touch
|
||||
// (- touchcancel ends the touch, no click follows)
|
||||
// - element's touchend: Determines if the tap is valid (didn't move too far away, didn't hold
|
||||
// too long) and fires the user's tap handler. The touchend also calls preventGhostClick().
|
||||
// - preventGhostClick() removes the allowable region the global touchstart created.
|
||||
// - The browser generates a click event.
|
||||
// - The global click handler catches the click, and checks whether it was in an allowable region.
|
||||
// - If preventGhostClick was called, the region will have been removed, the click is busted.
|
||||
// - If the region is still there, the click proceeds normally. Therefore clicks on links and
|
||||
// other elements without ngTap on them work normally.
|
||||
//
|
||||
// This is an ugly, terrible hack!
|
||||
// Yeah, tell me about it. The alternatives are using the slow click events, or making our users
|
||||
// deal with the ghost clicks, so I consider this the least of evils. Fortunately Angular
|
||||
// encapsulates this ugly logic away from the user.
|
||||
//
|
||||
// Why not just put click handlers on the element?
|
||||
// We do that too, just to be sure. If the tap event caused the DOM to change,
|
||||
// it is possible another element is now in that position. To take account for these possibly
|
||||
// distinct elements, the handlers are global and care only about coordinates.
|
||||
|
||||
// Checks if the coordinates are close enough to be within the region.
|
||||
function hit(x1, y1, x2, y2) {
|
||||
return Math.abs(x1 - x2) < CLICKBUSTER_THRESHOLD && Math.abs(y1 - y2) < CLICKBUSTER_THRESHOLD;
|
||||
}
|
||||
|
||||
// Checks a list of allowable regions against a click location.
|
||||
// Returns true if the click should be allowed.
|
||||
// Splices out the allowable region from the list after it has been used.
|
||||
function checkAllowableRegions(touchCoordinates, x, y) {
|
||||
for (var i = 0; i < touchCoordinates.length; i += 2) {
|
||||
if (hit(touchCoordinates[i], touchCoordinates[i + 1], x, y)) {
|
||||
touchCoordinates.splice(i, i + 2);
|
||||
return true; // allowable region
|
||||
}
|
||||
}
|
||||
return false; // No allowable region; bust it.
|
||||
}
|
||||
|
||||
// Global click handler that prevents the click if it's in a bustable zone and preventGhostClick
|
||||
// was called recently.
|
||||
function onClick(event) {
|
||||
if (Date.now() - lastPreventedTime > PREVENT_DURATION) {
|
||||
return; // Too old.
|
||||
}
|
||||
|
||||
var touches = event.touches && event.touches.length ? event.touches : [event];
|
||||
var x = touches[0].clientX;
|
||||
var y = touches[0].clientY;
|
||||
// Work around desktop Webkit quirk where clicking a label will fire two clicks (on the label
|
||||
// and on the input element). Depending on the exact browser, this second click we don't want
|
||||
// to bust has either (0,0), negative coordinates, or coordinates equal to triggering label
|
||||
// click event
|
||||
if (x < 1 && y < 1) {
|
||||
return; // offscreen
|
||||
}
|
||||
if (lastLabelClickCoordinates &&
|
||||
lastLabelClickCoordinates[0] === x && lastLabelClickCoordinates[1] === y) {
|
||||
return; // input click triggered by label click
|
||||
}
|
||||
// reset label click coordinates on first subsequent click
|
||||
if (lastLabelClickCoordinates) {
|
||||
lastLabelClickCoordinates = null;
|
||||
}
|
||||
// remember label click coordinates to prevent click busting of trigger click event on input
|
||||
if (nodeName_(event.target) === 'label') {
|
||||
lastLabelClickCoordinates = [x, y];
|
||||
}
|
||||
|
||||
// Look for an allowable region containing this click.
|
||||
// If we find one, that means it was created by touchstart and not removed by
|
||||
// preventGhostClick, so we don't bust it.
|
||||
if (checkAllowableRegions(touchCoordinates, x, y)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// If we didn't find an allowable region, bust the click.
|
||||
event.stopPropagation();
|
||||
event.preventDefault();
|
||||
|
||||
// Blur focused form elements
|
||||
event.target && event.target.blur && event.target.blur();
|
||||
}
|
||||
|
||||
|
||||
// Global touchstart handler that creates an allowable region for a click event.
|
||||
// This allowable region can be removed by preventGhostClick if we want to bust it.
|
||||
function onTouchStart(event) {
|
||||
var touches = event.touches && event.touches.length ? event.touches : [event];
|
||||
var x = touches[0].clientX;
|
||||
var y = touches[0].clientY;
|
||||
touchCoordinates.push(x, y);
|
||||
|
||||
$timeout(function() {
|
||||
// Remove the allowable region.
|
||||
for (var i = 0; i < touchCoordinates.length; i += 2) {
|
||||
if (touchCoordinates[i] == x && touchCoordinates[i + 1] == y) {
|
||||
touchCoordinates.splice(i, i + 2);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}, PREVENT_DURATION, false);
|
||||
}
|
||||
|
||||
// On the first call, attaches some event handlers. Then whenever it gets called, it creates a
|
||||
// zone around the touchstart where clicks will get busted.
|
||||
function preventGhostClick(x, y) {
|
||||
if (!touchCoordinates) {
|
||||
$rootElement[0].addEventListener('click', onClick, true);
|
||||
$rootElement[0].addEventListener('touchstart', onTouchStart, true);
|
||||
touchCoordinates = [];
|
||||
}
|
||||
|
||||
lastPreventedTime = Date.now();
|
||||
|
||||
checkAllowableRegions(touchCoordinates, x, y);
|
||||
}
|
||||
|
||||
// Actual linking function.
|
||||
return function(scope, element, attr) {
|
||||
var clickHandler = $parse(attr.ngClick),
|
||||
tapping = false,
|
||||
tapElement, // Used to blur the element after a tap.
|
||||
startTime, // Used to check if the tap was held too long.
|
||||
touchStartX,
|
||||
touchStartY;
|
||||
|
||||
function resetState() {
|
||||
tapping = false;
|
||||
element.removeClass(ACTIVE_CLASS_NAME);
|
||||
}
|
||||
|
||||
element.on('touchstart', function(event) {
|
||||
tapping = true;
|
||||
tapElement = event.target ? event.target : event.srcElement; // IE uses srcElement.
|
||||
// Hack for Safari, which can target text nodes instead of containers.
|
||||
if (tapElement.nodeType == 3) {
|
||||
tapElement = tapElement.parentNode;
|
||||
}
|
||||
|
||||
element.addClass(ACTIVE_CLASS_NAME);
|
||||
|
||||
startTime = Date.now();
|
||||
|
||||
// Use jQuery originalEvent
|
||||
var originalEvent = event.originalEvent || event;
|
||||
var touches = originalEvent.touches && originalEvent.touches.length ? originalEvent.touches : [originalEvent];
|
||||
var e = touches[0];
|
||||
touchStartX = e.clientX;
|
||||
touchStartY = e.clientY;
|
||||
});
|
||||
|
||||
element.on('touchcancel', function(event) {
|
||||
resetState();
|
||||
});
|
||||
|
||||
element.on('touchend', function(event) {
|
||||
var diff = Date.now() - startTime;
|
||||
|
||||
// Use jQuery originalEvent
|
||||
var originalEvent = event.originalEvent || event;
|
||||
var touches = (originalEvent.changedTouches && originalEvent.changedTouches.length) ?
|
||||
originalEvent.changedTouches :
|
||||
((originalEvent.touches && originalEvent.touches.length) ? originalEvent.touches : [originalEvent]);
|
||||
var e = touches[0];
|
||||
var x = e.clientX;
|
||||
var y = e.clientY;
|
||||
var dist = Math.sqrt(Math.pow(x - touchStartX, 2) + Math.pow(y - touchStartY, 2));
|
||||
|
||||
if (tapping && diff < TAP_DURATION && dist < MOVE_TOLERANCE) {
|
||||
// Call preventGhostClick so the clickbuster will catch the corresponding click.
|
||||
preventGhostClick(x, y);
|
||||
|
||||
// Blur the focused element (the button, probably) before firing the callback.
|
||||
// This doesn't work perfectly on Android Chrome, but seems to work elsewhere.
|
||||
// I couldn't get anything to work reliably on Android Chrome.
|
||||
if (tapElement) {
|
||||
tapElement.blur();
|
||||
}
|
||||
|
||||
if (!angular.isDefined(attr.disabled) || attr.disabled === false) {
|
||||
element.triggerHandler('click', [event]);
|
||||
}
|
||||
}
|
||||
|
||||
resetState();
|
||||
});
|
||||
|
||||
// Hack for iOS Safari's benefit. It goes searching for onclick handlers and is liable to click
|
||||
// something else nearby.
|
||||
element.onclick = function(event) { };
|
||||
|
||||
// Actual click handler.
|
||||
// There are three different kinds of clicks, only two of which reach this point.
|
||||
// - On desktop browsers without touch events, their clicks will always come here.
|
||||
// - On mobile browsers, the simulated "fast" click will call this.
|
||||
// - But the browser's follow-up slow click will be "busted" before it reaches this handler.
|
||||
// Therefore it's safe to use this directive on both mobile and desktop.
|
||||
element.on('click', function(event, touchend) {
|
||||
scope.$apply(function() {
|
||||
clickHandler(scope, {$event: (touchend || event)});
|
||||
});
|
||||
});
|
||||
|
||||
element.on('mousedown', function(event) {
|
||||
element.addClass(ACTIVE_CLASS_NAME);
|
||||
});
|
||||
|
||||
element.on('mousemove mouseup', function(event) {
|
||||
element.removeClass(ACTIVE_CLASS_NAME);
|
||||
});
|
||||
|
||||
};
|
||||
}];
|
||||
|
||||
/* global ngTouch: false */
|
||||
|
||||
/**
|
||||
* @ngdoc directive
|
||||
* @name ngSwipeLeft
|
||||
*
|
||||
* @deprecated
|
||||
* sinceVersion="1.7.0"
|
||||
*
|
||||
* See the {@link ngTouch module} documentation for more information.
|
||||
*
|
||||
* @description
|
||||
* Specify custom behavior when an element is swiped to the left on a touchscreen device.
|
||||
* A leftward swipe is a quick, right-to-left slide of the finger.
|
||||
@ -619,7 +247,7 @@ var ngTouchClickDirectiveFactory = ['$parse', '$timeout', '$rootElement',
|
||||
* upon left swipe. (Event object is available as `$event`)
|
||||
*
|
||||
* @example
|
||||
<example module="ngSwipeLeftExample" deps="angular-touch.js">
|
||||
<example module="ngSwipeLeftExample" deps="angular-touch.js" name="ng-swipe-left">
|
||||
<file name="index.html">
|
||||
<div ng-show="!showActions" ng-swipe-left="showActions = true">
|
||||
Some list content, like an email in the inbox
|
||||
@ -639,6 +267,11 @@ var ngTouchClickDirectiveFactory = ['$parse', '$timeout', '$rootElement',
|
||||
* @ngdoc directive
|
||||
* @name ngSwipeRight
|
||||
*
|
||||
* @deprecated
|
||||
* sinceVersion="1.7.0"
|
||||
*
|
||||
* See the {@link ngTouch module} documentation for more information.
|
||||
*
|
||||
* @description
|
||||
* Specify custom behavior when an element is swiped to the right on a touchscreen device.
|
||||
* A rightward swipe is a quick, left-to-right slide of the finger.
|
||||
@ -652,7 +285,7 @@ var ngTouchClickDirectiveFactory = ['$parse', '$timeout', '$rootElement',
|
||||
* upon right swipe. (Event object is available as `$event`)
|
||||
*
|
||||
* @example
|
||||
<example module="ngSwipeRightExample" deps="angular-touch.js">
|
||||
<example module="ngSwipeRightExample" deps="angular-touch.js" name="ng-swipe-right">
|
||||
<file name="index.html">
|
||||
<div ng-show="!showActions" ng-swipe-left="showActions = true">
|
||||
Some list content, like an email in the inbox
|
||||
|
18408
xstatic/pkg/angular/data/angular.js
vendored
18408
xstatic/pkg/angular/data/angular.js
vendored
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
@ -1 +1 @@
|
||||
{"raw":"v1.5.8","major":1,"minor":5,"patch":8,"prerelease":[],"build":[],"version":"1.5.8","codeName":"arbitrary-fallbacks","full":"1.5.8","branch":"v1.5.x","cdn":{"raw":"v1.5.7","major":1,"minor":5,"patch":7,"prerelease":[],"build":[],"version":"1.5.7","docsUrl":"http://code.angularjs.org/1.5.7/docs"}}
|
||||
{"raw":"v1.8.2","major":1,"minor":8,"patch":2,"prerelease":[],"build":[],"version":"1.8.2","codeName":"meteoric-mining","full":"1.8.2","branch":"v1.8.x","cdn":{"raw":"v1.8.2","major":1,"minor":8,"patch":2,"prerelease":[],"build":[],"version":"1.8.2","docsUrl":"http://code.angularjs.org/1.8.2/docs"}}
|
||||
|
@ -1 +1 @@
|
||||
1.5.8
|
||||
1.8.2
|
||||
|
Loading…
Reference in New Issue
Block a user