/bower_components/angular/angular.js |
@@ -1,13 +1,63 @@ |
/** |
* @license AngularJS v1.6.3 |
* @license AngularJS v1.6.5 |
* (c) 2010-2017 Google, Inc. http://angularjs.org |
* License: MIT |
*/ |
(function(window) {'use strict'; |
|
/* exported |
minErrConfig, |
errorHandlingConfig, |
isValidObjectMaxDepth |
*/ |
|
var minErrConfig = { |
objectMaxDepth: 5 |
}; |
|
/** |
* @ngdoc function |
* @name angular.errorHandlingConfig |
* @module ng |
* @kind function |
* |
* @description |
* Configure several aspects of error handling in AngularJS if used as a setter or return the |
* current configuration if used as a getter. The following options are supported: |
* |
* - **objectMaxDepth**: The maximum depth to which objects are traversed when stringified for error messages. |
* |
* Omitted or undefined options will leave the corresponding configuration values unchanged. |
* |
* @param {Object=} config - The configuration object. May only contain the options that need to be |
* updated. Supported keys: |
* |
* * `objectMaxDepth` **{Number}** - The max depth for stringifying objects. Setting to a |
* non-positive or non-numeric value, removes the max depth limit. |
* Default: 5 |
*/ |
function errorHandlingConfig(config) { |
if (isObject(config)) { |
if (isDefined(config.objectMaxDepth)) { |
minErrConfig.objectMaxDepth = isValidObjectMaxDepth(config.objectMaxDepth) ? config.objectMaxDepth : NaN; |
} |
} else { |
return minErrConfig; |
} |
} |
|
/** |
* @private |
* @param {Number} maxDepth |
* @return {boolean} |
*/ |
function isValidObjectMaxDepth(maxDepth) { |
return isNumber(maxDepth) && maxDepth > 0; |
} |
|
/** |
* @description |
* |
* This object provides a utility for producing rich Error messages within |
* Angular. It can be called as follows: |
* |
@@ -56,7 +106,7 @@ |
return match; |
}); |
|
message += '\nhttp://errors.angularjs.org/1.6.3/' + |
message += '\nhttp://errors.angularjs.org/1.6.5/' + |
(module ? module + '/' : '') + code; |
|
for (i = 0, paramPrefix = '?'; i < templateArgs.length; i++, paramPrefix = '&') { |
@@ -112,6 +162,7 @@ |
isNumber, |
isNumberNaN, |
isDate, |
isError, |
isArray, |
isFunction, |
isRegExp, |
@@ -129,6 +180,7 @@ |
includes, |
arrayRemove, |
copy, |
simpleCompare, |
equals, |
csp, |
jq, |
@@ -195,51 +247,7 @@ |
|
var hasOwnProperty = Object.prototype.hasOwnProperty; |
|
var minErrConfig = { |
objectMaxDepth: 5 |
}; |
|
/** |
* @ngdoc function |
* @name angular.errorHandlingConfig |
* @module ng |
* @kind function |
* |
* @description |
* Configure several aspects of error handling in AngularJS if used as a setter or return the |
* current configuration if used as a getter. The following options are supported: |
* |
* - **objectMaxDepth**: The maximum depth to which objects are traversed when stringified for error messages. |
* |
* Omitted or undefined options will leave the corresponding configuration values unchanged. |
* |
* @param {Object=} config - The configuration object. May only contain the options that need to be |
* updated. Supported keys: |
* |
* * `objectMaxDepth` **{Number}** - The max depth for stringifying objects. Setting to a |
* non-positive or non-numeric value, removes the max depth limit. |
* Default: 5 |
*/ |
function errorHandlingConfig(config) { |
if (isObject(config)) { |
if (isDefined(config.objectMaxDepth)) { |
minErrConfig.objectMaxDepth = isValidObjectMaxDepth(config.objectMaxDepth) ? config.objectMaxDepth : NaN; |
} |
} else { |
return minErrConfig; |
} |
} |
|
/** |
* @private |
* @param {Number} maxDepth |
* @return {boolean} |
*/ |
function isValidObjectMaxDepth(maxDepth) { |
return isNumber(maxDepth) && maxDepth > 0; |
} |
|
/** |
* @ngdoc function |
* @name angular.lowercase |
* @module ng |
@@ -546,6 +554,20 @@ |
* Unlike {@link angular.extend extend()}, `merge()` recursively descends into object properties of source |
* objects, performing a deep copy. |
* |
* @deprecated |
* sinceVersion="1.6.5" |
* This function is deprecated, but will not be removed in the 1.x lifecycle. |
* There are edge cases (see {@link angular.merge#known-issues known issues}) that are not |
* supported by this function. We suggest |
* using [lodash's merge()](https://lodash.com/docs/4.17.4#merge) instead. |
* |
* @knownIssue |
* This is a list of (known) object types that are not handled correctly by this function: |
* - [`Blob`](https://developer.mozilla.org/docs/Web/API/Blob) |
* - [`MediaStream`](https://developer.mozilla.org/docs/Web/API/MediaStream) |
* - [`CanvasGradient`](https://developer.mozilla.org/docs/Web/API/CanvasGradient) |
* - AngularJS {@link $rootScope.Scope scopes}; |
* |
* @param {Object} dst Destination object. |
* @param {...Object} src Source object(s). |
* @returns {Object} Reference to `dst`. |
@@ -756,6 +778,24 @@ |
var isArray = Array.isArray; |
|
/** |
* @description |
* Determines if a reference is an `Error`. |
* Loosely based on https://www.npmjs.com/package/iserror |
* |
* @param {*} value Reference to check. |
* @returns {boolean} True if `value` is an `Error`. |
*/ |
function isError(value) { |
var tag = toString.call(value); |
switch (tag) { |
case '[object Error]': return true; |
case '[object Exception]': return true; |
case '[object DOMException]': return true; |
default: return value instanceof Error; |
} |
} |
|
/** |
* @ngdoc function |
* @name angular.isFunction |
* @module ng |
@@ -1107,6 +1147,10 @@ |
} |
|
|
// eslint-disable-next-line no-self-compare |
function simpleCompare(a, b) { return a === b || (a !== a && b !== b); } |
|
|
/** |
* @ngdoc function |
* @name angular.equals |
@@ -1187,7 +1231,7 @@ |
} |
} else if (isDate(o1)) { |
if (!isDate(o2)) return false; |
return equals(o1.getTime(), o2.getTime()); |
return simpleCompare(o1.getTime(), o2.getTime()); |
} else if (isRegExp(o1)) { |
if (!isRegExp(o2)) return false; |
return o1.toString() === o2.toString(); |
@@ -1431,7 +1475,7 @@ |
|
var ALL_COLONS = /:/g; |
function timezoneToOffset(timezone, fallback) { |
// Support: IE 9-11 only, Edge 13-14+ |
// Support: IE 9-11 only, Edge 13-15+ |
// IE/Edge do not "understand" colon (`:`) in timezone |
timezone = timezone.replace(ALL_COLONS, ''); |
var requestedTimezoneOffset = Date.parse('Jan 01, 1970 00:00:00 ' + timezone) / 60000; |
@@ -1458,12 +1502,7 @@ |
* @returns {string} Returns the string representation of the element. |
*/ |
function startingTag(element) { |
element = jqLite(element).clone(); |
try { |
// turns out IE does not let you set .html() on elements which |
// are not allowed to have children. So we just ignore it. |
element.empty(); |
} catch (e) { /* empty */ } |
element = jqLite(element).clone().empty(); |
var elemHtml = jqLite('<div>').append(element).html(); |
try { |
return element[0].nodeType === NODE_TYPE_TEXT ? lowercase(elemHtml) : |
@@ -1601,6 +1640,7 @@ |
var script = document.currentScript; |
|
if (!script) { |
// Support: IE 9-11 only |
// IE does not have `document.currentScript` |
return true; |
} |
@@ -2592,7 +2632,7 @@ |
return dst || src; |
} |
|
/* global toDebugString: true */ |
/* exported toDebugString */ |
|
function serializeObject(obj, maxDepth) { |
var seen = []; |
@@ -2601,7 +2641,9 @@ |
// 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)) { |
obj = copy(obj, null, 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); |
@@ -2742,11 +2784,11 @@ |
var version = { |
// These placeholder strings will be replaced by grunt's `build` task. |
// They need to be double- or single-quoted. |
full: '1.6.3', |
full: '1.6.5', |
major: 1, |
minor: 6, |
dot: 3, |
codeName: 'scriptalicious-bootstrapping' |
dot: 5, |
codeName: 'toffee-salinization' |
}; |
|
|
@@ -2892,7 +2934,7 @@ |
}); |
} |
]) |
.info({ angularVersion: '1.6.3' }); |
.info({ angularVersion: '1.6.5' }); |
} |
|
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * |
@@ -3096,12 +3138,6 @@ |
return false; |
} |
|
function jqLiteCleanData(nodes) { |
for (var i = 0, ii = nodes.length; i < ii; i++) { |
jqLiteRemoveData(nodes[i]); |
} |
} |
|
function jqLiteBuildFragment(html, context) { |
var tmp, tag, wrap, |
fragment = context.createDocumentFragment(), |
@@ -3204,13 +3240,10 @@ |
} |
|
function jqLiteDealoc(element, onlyDescendants) { |
if (!onlyDescendants) jqLiteRemoveData(element); |
if (!onlyDescendants && jqLiteAcceptsData(element)) jqLite.cleanData([element]); |
|
if (element.querySelectorAll) { |
var descendants = element.querySelectorAll('*'); |
for (var i = 0, l = descendants.length; i < l; i++) { |
jqLiteRemoveData(descendants[i]); |
} |
jqLite.cleanData(element.querySelectorAll('*')); |
} |
} |
|
@@ -3508,7 +3541,11 @@ |
data: jqLiteData, |
removeData: jqLiteRemoveData, |
hasData: jqLiteHasData, |
cleanData: jqLiteCleanData |
cleanData: function jqLiteCleanData(nodes) { |
for (var i = 0, ii = nodes.length; i < ii; i++) { |
jqLiteRemoveData(nodes[i]); |
} |
} |
}, function(fn, name) { |
JQLite[name] = fn; |
}); |
@@ -5486,6 +5523,7 @@ |
var $AnimateProvider = ['$provide', /** @this */ function($provide) { |
var provider = this; |
var classNameFilter = null; |
var customFilter = null; |
|
this.$$registeredAnimations = Object.create(null); |
|
@@ -5540,6 +5578,51 @@ |
|
/** |
* @ngdoc method |
* @name $animateProvider#customFilter |
* |
* @description |
* Sets and/or returns the custom filter function that is used to "filter" animations, i.e. |
* determine if an animation is allowed or not. When no filter is specified (the default), no |
* animation will be blocked. Setting the `customFilter` value will only allow animations for |
* which the filter function's return value is truthy. |
* |
* This allows to easily create arbitrarily complex rules for filtering animations, such as |
* allowing specific events only, or enabling animations on specific subtrees of the DOM, etc. |
* Filtering animations can also boost performance for low-powered devices, as well as |
* applications containing a lot of structural operations. |
* |
* <div class="alert alert-success"> |
* **Best Practice:** |
* Keep the filtering function as lean as possible, because it will be called for each DOM |
* action (e.g. insertion, removal, class change) performed by "animation-aware" directives. |
* See {@link guide/animations#which-directives-support-animations- here} for a list of built-in |
* directives that support animations. |
* Performing computationally expensive or time-consuming operations on each call of the |
* filtering function can make your animations sluggish. |
* </div> |
* |
* **Note:** If present, `customFilter` will be checked before |
* {@link $animateProvider#classNameFilter classNameFilter}. |
* |
* @param {Function=} filterFn - The filter function which will be used to filter all animations. |
* If a falsy value is returned, no animation will be performed. The function will be called |
* with the following arguments: |
* - **node** `{DOMElement}` - The DOM element to be animated. |
* - **event** `{String}` - The name of the animation event (e.g. `enter`, `leave`, `addClass` |
* etc). |
* - **options** `{Object}` - A collection of options/styles used for the animation. |
* @return {Function} The current filter function or `null` if there is none set. |
*/ |
this.customFilter = function(filterFn) { |
if (arguments.length === 1) { |
customFilter = isFunction(filterFn) ? filterFn : null; |
} |
|
return customFilter; |
}; |
|
/** |
* @ngdoc method |
* @name $animateProvider#classNameFilter |
* |
* @description |
@@ -5549,6 +5632,11 @@ |
* When setting the `classNameFilter` value, animations will only be performed on elements |
* that successfully match the filter expression. This in turn can boost performance |
* for low-powered devices as well as applications containing a lot of structural operations. |
* |
* **Note:** If present, `classNameFilter` will be checked after |
* {@link $animateProvider#customFilter customFilter}. If `customFilter` is present and returns |
* false, `classNameFilter` will not be checked. |
* |
* @param {RegExp=} expression The className expression which will be checked against all animations |
* @return {RegExp} The current CSS className expression value. If null then there is no expression value |
*/ |
@@ -7369,9 +7457,9 @@ |
* initialized. |
* |
* <div class="alert alert-warning"> |
* **Deprecation warning:** although bindings for non-ES6 class controllers are currently |
* bound to `this` before the controller constructor is called, this use is now deprecated. Please place initialization |
* code that relies upon bindings inside a `$onInit` method on the controller, instead. |
* **Deprecation warning:** if `$compileProcvider.preAssignBindingsEnabled(true)` was called, bindings for non-ES6 class |
* controllers are bound to `this` before the controller constructor is called but this use is now deprecated. Please |
* place initialization code that relies upon bindings inside a `$onInit` method on the controller, instead. |
* </div> |
* |
* It is also possible to set `bindToController` to an object hash with the same format as the `scope` property. |
@@ -8138,7 +8226,8 @@ |
* @ngdoc method |
* @name $compileProvider#component |
* @module ng |
* @param {string} name Name of the component in camelCase (i.e. `myComp` which will match `<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}), |
* with the following properties (all optional): |
@@ -8221,6 +8310,11 @@ |
* See also {@link ng.$compileProvider#directive $compileProvider.directive()}. |
*/ |
this.component = function registerComponent(name, options) { |
if (!isString(name)) { |
forEach(name, reverseParams(bind(this, registerComponent))); |
return this; |
} |
|
var controller = options.controller || function() {}; |
|
function factory($injector) { |
@@ -8384,7 +8478,14 @@ |
* |
* If disabled (false), the compiler calls the constructor first before assigning bindings. |
* |
* The default value is true in Angular 1.5.x but will switch to false in Angular 1.6.x. |
* The default value is false. |
* |
* @deprecated |
* sinceVersion="1.6.0" |
* removeVersion="1.7.0" |
* |
* This method and the option to assign the bindings before calling the controller's constructor |
* will be removed in v1.7.0. |
*/ |
var preAssignBindingsEnabled = false; |
this.preAssignBindingsEnabled = function(enabled) { |
@@ -10149,7 +10250,7 @@ |
} |
linkQueue = null; |
}).catch(function(error) { |
if (error instanceof Error) { |
if (isError(error)) { |
$exceptionHandler(error); |
} |
}); |
@@ -10474,8 +10575,7 @@ |
if (parentGet.literal) { |
compare = equals; |
} else { |
// eslint-disable-next-line no-self-compare |
compare = function simpleCompare(a, b) { return a === b || (a !== a && b !== b); }; |
compare = simpleCompare; |
} |
parentSet = parentGet.assign || function() { |
// reset the change, or we will throw this exception on every $digest |
@@ -10550,9 +10650,7 @@ |
}); |
|
function recordChanges(key, currentValue, previousValue) { |
if (isFunction(destination.$onChanges) && currentValue !== previousValue && |
// eslint-disable-next-line no-self-compare |
(currentValue === currentValue || previousValue === previousValue)) { |
if (isFunction(destination.$onChanges) && !simpleCompare(currentValue, previousValue)) { |
// If we have not already scheduled the top level onChangesQueue handler then do so now |
if (!onChangesQueue) { |
scope.$$postDigest(flushOnChangesQueue); |
@@ -11167,7 +11265,12 @@ |
if (tempData) { |
var contentType = headers('Content-Type'); |
if ((contentType && (contentType.indexOf(APPLICATION_JSON) === 0)) || isJsonLike(tempData)) { |
data = fromJson(tempData); |
try { |
data = fromJson(tempData); |
} catch (e) { |
throw $httpMinErr('baddata', 'Data must be a valid JSON object. Received: "{0}". ' + |
'Parse error: "{1}"', data, e); |
} |
} |
} |
} |
@@ -11290,12 +11393,6 @@ |
* {@link ng.$cacheFactory `$cacheFactory`} to enable or disable caching of HTTP responses |
* by default. See {@link $http#caching $http Caching} for more information. |
* |
* - **`defaults.xsrfCookieName`** - {string} - Name of cookie containing the XSRF token. |
* Defaults value is `'XSRF-TOKEN'`. |
* |
* - **`defaults.xsrfHeaderName`** - {string} - Name of HTTP header to populate with the |
* XSRF token. Defaults value is `'X-XSRF-TOKEN'`. |
* |
* - **`defaults.headers`** - {Object} - Default headers for all $http requests. |
* Refer to {@link ng.$http#setting-http-headers $http} for documentation on |
* setting default headers. |
@@ -11304,6 +11401,9 @@ |
* - **`defaults.headers.put`** |
* - **`defaults.headers.patch`** |
* |
* - **`defaults.jsonpCallbackParam`** - `{string}` - the name of the query parameter that passes the name of the |
* callback in a JSONP request. The value of this parameter will be replaced with the expression generated by the |
* {@link $jsonpCallbacks} service. Defaults to `'callback'`. |
* |
* - **`defaults.paramSerializer`** - `{string|function(Object<string,string>):string}` - A function |
* used to the prepare string representation of request parameters (specified as an object). |
@@ -11310,10 +11410,30 @@ |
* If specified as string, it is interpreted as a function registered with the {@link auto.$injector $injector}. |
* Defaults to {@link ng.$httpParamSerializer $httpParamSerializer}. |
* |
* - **`defaults.jsonpCallbackParam`** - `{string}` - the name of the query parameter that passes the name of the |
* callback in a JSONP request. The value of this parameter will be replaced with the expression generated by the |
* {@link $jsonpCallbacks} service. Defaults to `'callback'`. |
* - **`defaults.transformRequest`** - |
* `{Array<function(data, headersGetter)>|function(data, headersGetter)}` - |
* An array of functions (or a single function) which are applied to the request data. |
* By default, this is an array with one request transformation function: |
* |
* - If the `data` property of the request configuration object contains an object, serialize it |
* into JSON format. |
* |
* - **`defaults.transformResponse`** - |
* `{Array<function(data, headersGetter, status)>|function(data, headersGetter, status)}` - |
* An array of functions (or a single function) which are applied to the response data. By default, |
* this is an array which applies one response transformation function that does two things: |
* |
* - If XSRF prefix is detected, strip it |
* (see {@link ng.$http#security-considerations Security Considerations in the $http docs}). |
* - If the `Content-Type` is `application/json` or the response looks like JSON, |
* deserialize it using a JSON parser. |
* |
* - **`defaults.xsrfCookieName`** - {string} - Name of cookie containing the XSRF token. |
* Defaults value is `'XSRF-TOKEN'`. |
* |
* - **`defaults.xsrfHeaderName`** - {string} - Name of HTTP header to populate with the |
* XSRF token. Defaults value is `'X-XSRF-TOKEN'`. |
* |
**/ |
var defaults = this.defaults = { |
// transform incoming response data |
@@ -11576,15 +11696,18 @@ |
* |
* Angular provides the following default transformations: |
* |
* Request transformations (`$httpProvider.defaults.transformRequest` and `$http.defaults.transformRequest`): |
* Request transformations (`$httpProvider.defaults.transformRequest` and `$http.defaults.transformRequest`) is |
* an array with one function that does the following: |
* |
* - If the `data` property of the request configuration object contains an object, serialize it |
* into JSON format. |
* |
* Response transformations (`$httpProvider.defaults.transformResponse` and `$http.defaults.transformResponse`): |
* Response transformations (`$httpProvider.defaults.transformResponse` and `$http.defaults.transformResponse`) is |
* an array with one function that does the following: |
* |
* - If XSRF prefix is detected, strip it (see Security Considerations section below). |
* - If JSON response is detected, deserialize it using a JSON parser. |
* - If the `Content-Type` is `application/json` or the response looks like JSON, |
* deserialize it using a JSON parser. |
* |
* |
* ### Overriding the Default Transformations Per Request |
@@ -13072,7 +13195,7 @@ |
* @param {boolean=} [invokeApply=true] If set to `false` skips model dirty checking, otherwise |
* will invoke `fn` within the {@link ng.$rootScope.Scope#$apply $apply} block. |
* @param {...*=} Pass additional parameters to the executed function. |
* @returns {promise} A promise which will be notified on each iteration. |
* @returns {promise} A promise which will be notified on each iteration. It will resolve once all iterations of the interval complete. |
* |
* @example |
* <example module="intervalExample" name="interval-service"> |
@@ -13221,7 +13344,7 @@ |
interval.cancel = function(promise) { |
if (promise && promise.$$intervalId in intervals) { |
// Interval cancels should not report as unhandled promise. |
intervals[promise.$$intervalId].promise.catch(noop); |
markQExceptionHandled(intervals[promise.$$intervalId].promise); |
intervals[promise.$$intervalId].reject('canceled'); |
$window.clearInterval(promise.$$intervalId); |
delete intervals[promise.$$intervalId]; |
@@ -14363,6 +14486,14 @@ |
* |
* The main purpose of this service is to simplify debugging and troubleshooting. |
* |
* To reveal the location of the calls to `$log` in the JavaScript console, |
* you can "blackbox" the AngularJS source in your browser: |
* |
* [Mozilla description of blackboxing](https://developer.mozilla.org/en-US/docs/Tools/Debugger/How_to/Black_box_a_source). |
* [Chrome description of blackboxing](https://developer.chrome.com/devtools/docs/blackboxing). |
* |
* Note: Not all browsers support blackboxing. |
* |
* The default is to log `debug` messages. You can use |
* {@link ng.$logProvider ng.$logProvider#debugEnabled} to change this. |
* |
@@ -14484,7 +14615,7 @@ |
}; |
|
function formatError(arg) { |
if (arg instanceof Error) { |
if (isError(arg)) { |
if (arg.stack && formatStackTrace) { |
arg = (arg.message && arg.stack.indexOf(arg.message) === -1) |
? 'Error: ' + arg.message + '\n' + arg.stack |
@@ -14498,29 +14629,17 @@ |
|
function consoleLog(type) { |
var console = $window.console || {}, |
logFn = console[type] || console.log || noop, |
hasApply = false; |
logFn = console[type] || console.log || noop; |
|
// Note: reading logFn.apply throws an error in IE11 in IE8 document mode. |
// The reason behind this is that console.log has type "object" in IE8... |
try { |
hasApply = !!logFn.apply; |
} catch (e) { /* empty */ } |
|
if (hasApply) { |
return function() { |
var args = []; |
forEach(arguments, function(arg) { |
args.push(formatError(arg)); |
}); |
return logFn.apply(console, args); |
}; |
} |
|
// we are IE which either doesn't have window.console => this is noop and we do nothing, |
// or we are IE where console.log doesn't have apply so we log at least first 2 args |
return function(arg1, arg2) { |
logFn(arg1, arg2 == null ? '' : arg2); |
return function() { |
var args = []; |
forEach(arguments, function(arg) { |
args.push(formatError(arg)); |
}); |
// Support: IE 9 only |
// console methods don't inherit from Function.prototype in IE 9 so we can't |
// call `logFn.apply(console, args)` directly. |
return Function.prototype.apply.call(logFn, console, args); |
}; |
} |
}]; |
@@ -15148,15 +15267,47 @@ |
return !fn.$stateful; |
} |
|
function findConstantAndWatchExpressions(ast, $filter) { |
var PURITY_ABSOLUTE = 1; |
var PURITY_RELATIVE = 2; |
|
// Detect nodes which could depend on non-shallow state of objects |
function isPure(node, parentIsPure) { |
switch (node.type) { |
// Computed members might invoke a stateful toString() |
case AST.MemberExpression: |
if (node.computed) { |
return false; |
} |
break; |
|
// Unary always convert to primative |
case AST.UnaryExpression: |
return PURITY_ABSOLUTE; |
|
// The binary + operator can invoke a stateful toString(). |
case AST.BinaryExpression: |
return node.operator !== '+' ? PURITY_ABSOLUTE : false; |
|
// Functions / filters probably read state from within objects |
case AST.CallExpression: |
return false; |
} |
|
return (undefined === parentIsPure) ? PURITY_RELATIVE : parentIsPure; |
} |
|
function findConstantAndWatchExpressions(ast, $filter, parentIsPure) { |
var allConstants; |
var argsToWatch; |
var isStatelessFilter; |
|
var astIsPure = ast.isPure = isPure(ast, parentIsPure); |
|
switch (ast.type) { |
case AST.Program: |
allConstants = true; |
forEach(ast.body, function(expr) { |
findConstantAndWatchExpressions(expr.expression, $filter); |
findConstantAndWatchExpressions(expr.expression, $filter, astIsPure); |
allConstants = allConstants && expr.expression.constant; |
}); |
ast.constant = allConstants; |
@@ -15166,26 +15317,26 @@ |
ast.toWatch = []; |
break; |
case AST.UnaryExpression: |
findConstantAndWatchExpressions(ast.argument, $filter); |
findConstantAndWatchExpressions(ast.argument, $filter, astIsPure); |
ast.constant = ast.argument.constant; |
ast.toWatch = ast.argument.toWatch; |
break; |
case AST.BinaryExpression: |
findConstantAndWatchExpressions(ast.left, $filter); |
findConstantAndWatchExpressions(ast.right, $filter); |
findConstantAndWatchExpressions(ast.left, $filter, astIsPure); |
findConstantAndWatchExpressions(ast.right, $filter, astIsPure); |
ast.constant = ast.left.constant && ast.right.constant; |
ast.toWatch = ast.left.toWatch.concat(ast.right.toWatch); |
break; |
case AST.LogicalExpression: |
findConstantAndWatchExpressions(ast.left, $filter); |
findConstantAndWatchExpressions(ast.right, $filter); |
findConstantAndWatchExpressions(ast.left, $filter, astIsPure); |
findConstantAndWatchExpressions(ast.right, $filter, astIsPure); |
ast.constant = ast.left.constant && ast.right.constant; |
ast.toWatch = ast.constant ? [] : [ast]; |
break; |
case AST.ConditionalExpression: |
findConstantAndWatchExpressions(ast.test, $filter); |
findConstantAndWatchExpressions(ast.alternate, $filter); |
findConstantAndWatchExpressions(ast.consequent, $filter); |
findConstantAndWatchExpressions(ast.test, $filter, astIsPure); |
findConstantAndWatchExpressions(ast.alternate, $filter, astIsPure); |
findConstantAndWatchExpressions(ast.consequent, $filter, astIsPure); |
ast.constant = ast.test.constant && ast.alternate.constant && ast.consequent.constant; |
ast.toWatch = ast.constant ? [] : [ast]; |
break; |
@@ -15194,9 +15345,9 @@ |
ast.toWatch = [ast]; |
break; |
case AST.MemberExpression: |
findConstantAndWatchExpressions(ast.object, $filter); |
findConstantAndWatchExpressions(ast.object, $filter, astIsPure); |
if (ast.computed) { |
findConstantAndWatchExpressions(ast.property, $filter); |
findConstantAndWatchExpressions(ast.property, $filter, astIsPure); |
} |
ast.constant = ast.object.constant && (!ast.computed || ast.property.constant); |
ast.toWatch = [ast]; |
@@ -15206,7 +15357,7 @@ |
allConstants = isStatelessFilter; |
argsToWatch = []; |
forEach(ast.arguments, function(expr) { |
findConstantAndWatchExpressions(expr, $filter); |
findConstantAndWatchExpressions(expr, $filter, astIsPure); |
allConstants = allConstants && expr.constant; |
if (!expr.constant) { |
argsToWatch.push.apply(argsToWatch, expr.toWatch); |
@@ -15216,8 +15367,8 @@ |
ast.toWatch = isStatelessFilter ? argsToWatch : [ast]; |
break; |
case AST.AssignmentExpression: |
findConstantAndWatchExpressions(ast.left, $filter); |
findConstantAndWatchExpressions(ast.right, $filter); |
findConstantAndWatchExpressions(ast.left, $filter, astIsPure); |
findConstantAndWatchExpressions(ast.right, $filter, astIsPure); |
ast.constant = ast.left.constant && ast.right.constant; |
ast.toWatch = [ast]; |
break; |
@@ -15225,7 +15376,7 @@ |
allConstants = true; |
argsToWatch = []; |
forEach(ast.elements, function(expr) { |
findConstantAndWatchExpressions(expr, $filter); |
findConstantAndWatchExpressions(expr, $filter, astIsPure); |
allConstants = allConstants && expr.constant; |
if (!expr.constant) { |
argsToWatch.push.apply(argsToWatch, expr.toWatch); |
@@ -15238,13 +15389,13 @@ |
allConstants = true; |
argsToWatch = []; |
forEach(ast.properties, function(property) { |
findConstantAndWatchExpressions(property.value, $filter); |
findConstantAndWatchExpressions(property.value, $filter, astIsPure); |
allConstants = allConstants && property.value.constant && !property.computed; |
if (!property.value.constant) { |
argsToWatch.push.apply(argsToWatch, property.value.toWatch); |
} |
if (property.computed) { |
findConstantAndWatchExpressions(property.key, $filter); |
findConstantAndWatchExpressions(property.key, $filter, astIsPure); |
if (!property.key.constant) { |
argsToWatch.push.apply(argsToWatch, property.key.toWatch); |
} |
@@ -15295,15 +15446,13 @@ |
return ast.constant; |
} |
|
function ASTCompiler(astBuilder, $filter) { |
this.astBuilder = astBuilder; |
function ASTCompiler($filter) { |
this.$filter = $filter; |
} |
|
ASTCompiler.prototype = { |
compile: function(expression) { |
compile: function(ast) { |
var self = this; |
var ast = this.astBuilder.ast(expression); |
this.state = { |
nextId: 0, |
filters: {}, |
@@ -15331,7 +15480,7 @@ |
var intoId = self.nextId(); |
self.recurse(watch, intoId); |
self.return_(intoId); |
self.state.inputs.push(fnKey); |
self.state.inputs.push({name: fnKey, isPure: watch.isPure}); |
watch.watchId = key; |
}); |
this.state.computing = 'fn'; |
@@ -15358,8 +15507,6 @@ |
ifDefined, |
plusFn); |
this.state = this.stage = undefined; |
fn.literal = isLiteral(ast); |
fn.constant = isConstant(ast); |
return fn; |
}, |
|
@@ -15369,13 +15516,16 @@ |
|
watchFns: function() { |
var result = []; |
var fns = this.state.inputs; |
var inputs = this.state.inputs; |
var self = this; |
forEach(fns, function(name) { |
result.push('var ' + name + '=' + self.generateFunction(name, 's')); |
forEach(inputs, function(input) { |
result.push('var ' + input.name + '=' + self.generateFunction(input.name, 's')); |
if (input.isPure) { |
result.push(input.name, '.isPure=' + JSON.stringify(input.isPure) + ';'); |
} |
}); |
if (fns.length) { |
result.push('fn.inputs=[' + fns.join(',') + '];'); |
if (inputs.length) { |
result.push('fn.inputs=[' + inputs.map(function(i) { return i.name; }).join(',') + '];'); |
} |
return result.join(''); |
}, |
@@ -15762,15 +15912,13 @@ |
}; |
|
|
function ASTInterpreter(astBuilder, $filter) { |
this.astBuilder = astBuilder; |
function ASTInterpreter($filter) { |
this.$filter = $filter; |
} |
|
ASTInterpreter.prototype = { |
compile: function(expression) { |
compile: function(ast) { |
var self = this; |
var ast = this.astBuilder.ast(expression); |
findConstantAndWatchExpressions(ast, self.$filter); |
var assignable; |
var assign; |
@@ -15783,6 +15931,7 @@ |
inputs = []; |
forEach(toWatch, function(watch, key) { |
var input = self.recurse(watch); |
input.isPure = watch.isPure; |
watch.input = input; |
inputs.push(input); |
watch.watchId = key; |
@@ -15809,8 +15958,6 @@ |
if (inputs) { |
fn.inputs = inputs; |
} |
fn.literal = isLiteral(ast); |
fn.constant = isConstant(ast); |
return fn; |
}, |
|
@@ -16139,20 +16286,21 @@ |
/** |
* @constructor |
*/ |
var Parser = function Parser(lexer, $filter, options) { |
this.lexer = lexer; |
this.$filter = $filter; |
this.options = options; |
function Parser(lexer, $filter, options) { |
this.ast = new AST(lexer, options); |
this.astCompiler = options.csp ? new ASTInterpreter(this.ast, $filter) : |
new ASTCompiler(this.ast, $filter); |
}; |
this.astCompiler = options.csp ? new ASTInterpreter($filter) : |
new ASTCompiler($filter); |
} |
|
Parser.prototype = { |
constructor: Parser, |
|
parse: function(text) { |
return this.astCompiler.compile(text); |
var ast = this.ast.ast(text); |
var fn = this.astCompiler.compile(ast); |
fn.literal = isLiteral(ast); |
fn.constant = isConstant(ast); |
return fn; |
} |
}; |
|
@@ -16321,7 +16469,7 @@ |
return newValue === oldValueOfValue; |
} |
|
if (typeof newValue === 'object' && !compareObjectIdentity) { |
if (typeof newValue === 'object') { |
|
// attempt to convert the value to a primitive type |
// TODO(docs): add a note to docs that by implementing valueOf even objects and arrays can |
@@ -16328,7 +16476,7 @@ |
// be cheaply dirty-checked |
newValue = getValueOf(newValue); |
|
if (typeof newValue === 'object') { |
if (typeof newValue === 'object' && !compareObjectIdentity) { |
// objects/arrays are not supported - deep-watching them would be too expensive |
return false; |
} |
@@ -16350,7 +16498,7 @@ |
inputExpressions = inputExpressions[0]; |
return scope.$watch(function expressionInputWatch(scope) { |
var newInputValue = inputExpressions(scope); |
if (!expressionInputDirtyCheck(newInputValue, oldInputValueOf, parsedExpression.literal)) { |
if (!expressionInputDirtyCheck(newInputValue, oldInputValueOf, inputExpressions.isPure)) { |
lastResult = parsedExpression(scope, undefined, undefined, [newInputValue]); |
oldInputValueOf = newInputValue && getValueOf(newInputValue); |
} |
@@ -16370,7 +16518,7 @@ |
|
for (var i = 0, ii = inputExpressions.length; i < ii; i++) { |
var newInputValue = inputExpressions[i](scope); |
if (changed || (changed = !expressionInputDirtyCheck(newInputValue, oldInputValueOfValues[i], parsedExpression.literal))) { |
if (changed || (changed = !expressionInputDirtyCheck(newInputValue, oldInputValueOfValues[i], inputExpressions[i].isPure))) { |
oldInputValues[i] = newInputValue; |
oldInputValueOfValues[i] = newInputValue && getValueOf(newInputValue); |
} |
@@ -16468,17 +16616,26 @@ |
|
// Propagate $$watchDelegates other then inputsWatchDelegate |
useInputs = !parsedExpression.inputs; |
if (parsedExpression.$$watchDelegate && |
parsedExpression.$$watchDelegate !== inputsWatchDelegate) { |
fn.$$watchDelegate = parsedExpression.$$watchDelegate; |
if (watchDelegate && watchDelegate !== inputsWatchDelegate) { |
fn.$$watchDelegate = watchDelegate; |
fn.inputs = parsedExpression.inputs; |
} else if (!interceptorFn.$stateful) { |
// If there is an interceptor, but no watchDelegate then treat the interceptor like |
// we treat filters - it is assumed to be a pure function unless flagged with $stateful |
// Treat interceptor like filters - assume non-stateful by default and use the inputsWatchDelegate |
fn.$$watchDelegate = inputsWatchDelegate; |
fn.inputs = parsedExpression.inputs ? parsedExpression.inputs : [parsedExpression]; |
} |
|
if (fn.inputs) { |
fn.inputs = fn.inputs.map(function(e) { |
// Remove the isPure flag of inputs when it is not absolute because they are now wrapped in a |
// potentially non-pure interceptor function. |
if (e.isPure === PURITY_RELATIVE) { |
return function depurifier(s) { return e(s); }; |
} |
return e; |
}); |
} |
|
return fn; |
} |
}]; |
@@ -16764,7 +16921,7 @@ |
* @param {function(function)} nextTick Function for executing functions in the next turn. |
* @param {function(...*)} exceptionHandler Function into which unexpected exceptions are passed for |
* debugging purposes. |
@ param {=boolean} errorOnUnhandledRejections Whether an error should be generated on unhandled |
* @param {boolean=} errorOnUnhandledRejections Whether an error should be generated on unhandled |
* promises rejections. |
* @returns {object} Promise manager. |
*/ |
@@ -16835,7 +16992,7 @@ |
state.pending = undefined; |
try { |
for (var i = 0, ii = pending.length; i < ii; ++i) { |
state.pur = true; |
markQStateExceptionHandled(state); |
promise = pending[i][0]; |
fn = pending[i][state.status]; |
try { |
@@ -16862,10 +17019,10 @@ |
// eslint-disable-next-line no-unmodified-loop-condition |
while (!queueSize && checkQueue.length) { |
var toCheck = checkQueue.shift(); |
if (!toCheck.pur) { |
toCheck.pur = true; |
if (!isStateExceptionHandled(toCheck)) { |
markQStateExceptionHandled(toCheck); |
var errorMessage = 'Possibly unhandled rejection: ' + toDebugString(toCheck.value); |
if (toCheck.value instanceof Error) { |
if (isError(toCheck.value)) { |
exceptionHandler(toCheck.value, errorMessage); |
} else { |
exceptionHandler(errorMessage); |
@@ -16875,7 +17032,7 @@ |
} |
|
function scheduleProcessQueue(state) { |
if (errorOnUnhandledRejections && !state.pending && state.status === 2 && !state.pur) { |
if (errorOnUnhandledRejections && !state.pending && state.status === 2 && !isStateExceptionHandled(state)) { |
if (queueSize === 0 && checkQueue.length === 0) { |
nextTick(processChecks); |
} |
@@ -17156,6 +17313,16 @@ |
return $Q; |
} |
|
function isStateExceptionHandled(state) { |
return !!state.pur; |
} |
function markQStateExceptionHandled(state) { |
state.pur = true; |
} |
function markQExceptionHandled(q) { |
markQStateExceptionHandled(q.$$state); |
} |
|
/** @this */ |
function $$RAFProvider() { //rAF |
this.$get = ['$window', '$timeout', function($window, $timeout) { |
@@ -17636,6 +17803,12 @@ |
* values are examined for changes on every call to `$digest`. |
* - The `listener` is called whenever any expression in the `watchExpressions` array changes. |
* |
* `$watchGroup` is more performant than watching each expression individually, and should be |
* used when the listener does not need to know which expression has changed. |
* If the listener needs to know which expression has changed, |
* {@link ng.$rootScope.Scope#$watch $watch()} or |
* {@link ng.$rootScope.Scope#$watchCollection $watchCollection()} should be used. |
* |
* @param {Array.<string|Function(scope)>} watchExpressions Array of expressions that will be individually |
* watched using {@link ng.$rootScope.Scope#$watch $watch()} |
* |
@@ -17644,7 +17817,34 @@ |
* The `newValues` array contains the current values of the `watchExpressions`, with the indexes matching |
* those of `watchExpression` |
* and the `oldValues` array contains the previous values of the `watchExpressions`, with the indexes matching |
* those of `watchExpression` |
* those of `watchExpression`. |
* |
* Note that `newValues` and `oldValues` reflect the differences in each **individual** |
* expression, and not the difference of the values between each call of the listener. |
* That means the difference between `newValues` and `oldValues` cannot be used to determine |
* which expression has changed / remained stable: |
* |
* ```js |
* |
* $scope.$watchGroup(['v1', 'v2'], function(newValues, oldValues) { |
* console.log(newValues, oldValues); |
* }); |
* |
* // newValues, oldValues initially |
* // [undefined, undefined], [undefined, undefined] |
* |
* $scope.v1 = 'a'; |
* $scope.v2 = 'a'; |
* |
* // ['a', 'a'], [undefined, undefined] |
* |
* $scope.v2 = 'b' |
* |
* // v1 hasn't changed since it became `'a'`, therefore its oldValue is still `undefined` |
* // ['a', 'b'], [undefined, 'a'] |
* |
* ``` |
* |
* The `scope` refers to the current scope. |
* @returns {function()} Returns a de-registration function for all listeners. |
*/ |
@@ -18687,12 +18887,21 @@ |
var $sceMinErr = minErr('$sce'); |
|
var SCE_CONTEXTS = { |
// HTML is used when there's HTML rendered (e.g. ng-bind-html, iframe srcdoc binding). |
HTML: 'html', |
|
// Style statements or stylesheets. Currently unused in AngularJS. |
CSS: 'css', |
|
// An URL used in a context where it does not refer to a resource that loads code. Currently |
// unused in AngularJS. |
URL: 'url', |
// RESOURCE_URL is a subtype of URL used in contexts where a privileged resource is sourced from a |
// url. (e.g. ng-include, script src, templateUrl) |
|
// RESOURCE_URL is a subtype of URL used where the referred-to resource could be interpreted as |
// code. (e.g. ng-include, script src binding, templateUrl) |
RESOURCE_URL: 'resourceUrl', |
|
// Script. Currently unused in AngularJS. |
JS: 'js' |
}; |
|
@@ -18754,6 +18963,16 @@ |
* `$sceDelegate` is a service that is used by the `$sce` service to provide {@link ng.$sce Strict |
* Contextual Escaping (SCE)} services to AngularJS. |
* |
* For an overview of this service and the functionnality it provides in AngularJS, see the main |
* page for {@link ng.$sce SCE}. The current page is targeted for developers who need to alter how |
* SCE works in their application, which shouldn't be needed in most cases. |
* |
* <div class="alert alert-danger"> |
* AngularJS strongly relies on contextual escaping for the security of bindings: disabling or |
* modifying this might cause cross site scripting (XSS) vulnerabilities. For libraries owners, |
* changes to this service will also influence users, so be extra careful and document your changes. |
* </div> |
* |
* Typically, you would configure or override the {@link ng.$sceDelegate $sceDelegate} instead of |
* the `$sce` service to customize the way Strict Contextual Escaping works in AngularJS. This is |
* because, while the `$sce` provides numerous shorthand methods, etc., you really only need to |
@@ -18779,11 +18998,15 @@ |
* @description |
* |
* The `$sceDelegateProvider` provider allows developers to configure the {@link ng.$sceDelegate |
* $sceDelegate} service. This allows one to get/set the whitelists and blacklists used to ensure |
* that the URLs used for sourcing Angular templates are safe. Refer {@link |
* ng.$sceDelegateProvider#resourceUrlWhitelist $sceDelegateProvider.resourceUrlWhitelist} and |
* {@link ng.$sceDelegateProvider#resourceUrlBlacklist $sceDelegateProvider.resourceUrlBlacklist} |
* $sceDelegate service}, used as a delegate for {@link ng.$sce Strict Contextual Escaping (SCE)}. |
* |
* The `$sceDelegateProvider` allows one to get/set the whitelists and blacklists used to ensure |
* that the URLs used for sourcing AngularJS templates and other script-running URLs are safe (all |
* places that use the `$sce.RESOURCE_URL` context). See |
* {@link ng.$sceDelegateProvider#resourceUrlWhitelist $sceDelegateProvider.resourceUrlWhitelist} |
* and |
* {@link ng.$sceDelegateProvider#resourceUrlBlacklist $sceDelegateProvider.resourceUrlBlacklist}, |
* |
* For the general details about this service in Angular, read the main page for {@link ng.$sce |
* Strict Contextual Escaping (SCE)}. |
* |
@@ -18811,6 +19034,13 @@ |
* ]); |
* }); |
* ``` |
* Note that an empty whitelist will block every resource URL from being loaded, and will require |
* you to manually mark each one as trusted with `$sce.trustAsResourceUrl`. However, templates |
* requested by {@link ng.$templateRequest $templateRequest} that are present in |
* {@link ng.$templateCache $templateCache} will not go through this check. If you have a mechanism |
* to populate your templates in that cache at config time, then it is a good idea to remove 'self' |
* from that whitelist. This helps to mitigate the security impact of certain types of issues, like |
* for instance attacker-controlled `ng-includes`. |
*/ |
|
function $SceDelegateProvider() { |
@@ -18826,23 +19056,23 @@ |
* @kind function |
* |
* @param {Array=} whitelist When provided, replaces the resourceUrlWhitelist with the value |
* provided. This must be an array or null. A snapshot of this array is used so further |
* changes to the array are ignored. |
* provided. This must be an array or null. A snapshot of this array is used so further |
* changes to the array are ignored. |
* Follow {@link ng.$sce#resourceUrlPatternItem this link} for a description of the items |
* allowed in this array. |
* |
* Follow {@link ng.$sce#resourceUrlPatternItem this link} for a description of the items |
* allowed in this array. |
* @return {Array} The currently set whitelist array. |
* |
* <div class="alert alert-warning"> |
* **Note:** an empty whitelist array will block all URLs! |
* </div> |
* @description |
* Sets/Gets the whitelist of trusted resource URLs. |
* |
* @return {Array} the currently set whitelist array. |
* |
* The **default value** when no whitelist has been explicitly set is `['self']` allowing only |
* same origin resource requests. |
* |
* @description |
* Sets/Gets the whitelist of trusted resource URLs. |
* <div class="alert alert-warning"> |
* **Note:** the default whitelist of 'self' is not recommended if your app shares its origin |
* with other apps! It is a good idea to limit it to only your application's directory. |
* </div> |
*/ |
this.resourceUrlWhitelist = function(value) { |
if (arguments.length) { |
@@ -18857,25 +19087,23 @@ |
* @kind function |
* |
* @param {Array=} blacklist When provided, replaces the resourceUrlBlacklist with the value |
* provided. This must be an array or null. A snapshot of this array is used so further |
* changes to the array are ignored. |
* provided. This must be an array or null. A snapshot of this array is used so further |
* changes to the array are ignored.</p><p> |
* Follow {@link ng.$sce#resourceUrlPatternItem this link} for a description of the items |
* allowed in this array.</p><p> |
* The typical usage for the blacklist is to **block |
* [open redirects](http://cwe.mitre.org/data/definitions/601.html)** served by your domain as |
* these would otherwise be trusted but actually return content from the redirected domain. |
* </p><p> |
* Finally, **the blacklist overrides the whitelist** and has the final say. |
* |
* Follow {@link ng.$sce#resourceUrlPatternItem this link} for a description of the items |
* allowed in this array. |
* @return {Array} The currently set blacklist array. |
* |
* The typical usage for the blacklist is to **block |
* [open redirects](http://cwe.mitre.org/data/definitions/601.html)** served by your domain as |
* these would otherwise be trusted but actually return content from the redirected domain. |
* @description |
* Sets/Gets the blacklist of trusted resource URLs. |
* |
* Finally, **the blacklist overrides the whitelist** and has the final say. |
* |
* @return {Array} the currently set blacklist array. |
* |
* The **default value** when no whitelist has been explicitly set is the empty array (i.e. there |
* is no blacklist.) |
* |
* @description |
* Sets/Gets the blacklist of trusted resource URLs. |
*/ |
|
this.resourceUrlBlacklist = function(value) { |
@@ -18959,17 +19187,24 @@ |
* @name $sceDelegate#trustAs |
* |
* @description |
* Returns an object that is trusted by angular for use in specified strict |
* contextual escaping contexts (such as ng-bind-html, ng-include, any src |
* attribute interpolation, any dom event binding attribute interpolation |
* such as for onclick, etc.) that uses the provided value. |
* See {@link ng.$sce $sce} for enabling strict contextual escaping. |
* Returns a trusted representation of the parameter for the specified context. This trusted |
* object will later on be used as-is, without any security check, by bindings or directives |
* that require this security context. |
* For instance, marking a string as trusted for the `$sce.HTML` context will entirely bypass |
* the potential `$sanitize` call in corresponding `$sce.HTML` bindings or directives, such as |
* `ng-bind-html`. Note that in most cases you won't need to call this function: if you have the |
* sanitizer loaded, passing the value itself will render all the HTML that does not pose a |
* security risk. |
* |
* @param {string} type The kind of context in which this value is safe for use. e.g. url, |
* resourceUrl, html, js and css. |
* @param {*} value The value that that should be considered trusted/safe. |
* @returns {*} A value that can be used to stand in for the provided `value` in places |
* where Angular expects a $sce.trustAs() return value. |
* See {@link ng.$sceDelegate#getTrusted getTrusted} for the function that will consume those |
* trusted values, and {@link ng.$sce $sce} for general documentation about strict contextual |
* escaping. |
* |
* @param {string} type The context in which this value is safe for use, e.g. `$sce.URL`, |
* `$sce.RESOURCE_URL`, `$sce.HTML`, `$sce.JS` or `$sce.CSS`. |
* |
* @param {*} value The value that should be considered trusted. |
* @return {*} A trusted representation of value, that can be used in the given context. |
*/ |
function trustAs(type, trustedValue) { |
var Constructor = (byType.hasOwnProperty(type) ? byType[type] : null); |
@@ -19001,11 +19236,11 @@ |
* ng.$sceDelegate#trustAs `$sceDelegate.trustAs`}. |
* |
* If the passed parameter is not a value that had been returned by {@link |
* ng.$sceDelegate#trustAs `$sceDelegate.trustAs`}, returns it as-is. |
* ng.$sceDelegate#trustAs `$sceDelegate.trustAs`}, it must be returned as-is. |
* |
* @param {*} value The result of a prior {@link ng.$sceDelegate#trustAs `$sceDelegate.trustAs`} |
* call or anything else. |
* @returns {*} The `value` that was originally provided to {@link ng.$sceDelegate#trustAs |
* call or anything else. |
* @return {*} The `value` that was originally provided to {@link ng.$sceDelegate#trustAs |
* `$sceDelegate.trustAs`} if `value` is the result of such a call. Otherwise, returns |
* `value` unchanged. |
*/ |
@@ -19022,20 +19257,21 @@ |
* @name $sceDelegate#getTrusted |
* |
* @description |
* Takes the result of a {@link ng.$sceDelegate#trustAs `$sceDelegate.trustAs`} call and |
* returns the originally supplied value if the queried context type is a supertype of the |
* created type. If this condition isn't satisfied, throws an exception. |
* Takes any input, and either returns a value that's safe to use in the specified context, or |
* throws an exception. |
* |
* <div class="alert alert-danger"> |
* Disabling auto-escaping is extremely dangerous, it usually creates a Cross Site Scripting |
* (XSS) vulnerability in your application. |
* </div> |
* In practice, there are several cases. When given a string, this function runs checks |
* and sanitization to make it safe without prior assumptions. When given the result of a {@link |
* ng.$sceDelegate#trustAs `$sceDelegate.trustAs`} call, it returns the originally supplied |
* value if that value's context is valid for this call's context. Finally, this function can |
* also throw when there is no way to turn `maybeTrusted` in a safe value (e.g., no sanitization |
* is available or possible.) |
* |
* @param {string} type The kind of context in which this value is to be used. |
* @param {string} type The context in which this value is to be used (such as `$sce.HTML`). |
* @param {*} maybeTrusted The result of a prior {@link ng.$sceDelegate#trustAs |
* `$sceDelegate.trustAs`} call. |
* @returns {*} The value the was originally provided to {@link ng.$sceDelegate#trustAs |
* `$sceDelegate.trustAs`} if valid in this context. Otherwise, throws an exception. |
* `$sceDelegate.trustAs`} call, or anything else (which will not be considered trusted.) |
* @return {*} A version of the value that's safe to use in the given context, or throws an |
* exception if this is impossible. |
*/ |
function getTrusted(type, maybeTrusted) { |
if (maybeTrusted === null || isUndefined(maybeTrusted) || maybeTrusted === '') { |
@@ -19042,13 +19278,17 @@ |
return maybeTrusted; |
} |
var constructor = (byType.hasOwnProperty(type) ? byType[type] : null); |
// If maybeTrusted is a trusted class instance or subclass instance, then unwrap and return |
// as-is. |
if (constructor && maybeTrusted instanceof constructor) { |
return maybeTrusted.$$unwrapTrustedValue(); |
} |
// If we get here, then we may only take one of two actions. |
// 1. sanitize the value for the requested type, or |
// 2. throw an exception. |
// Otherwise, if we get here, then we may either make it safe, or throw an exception. This |
// depends on the context: some are sanitizatible (HTML), some use whitelists (RESOURCE_URL), |
// some are impossible to do (JS). This step isn't implemented for CSS and URL, as AngularJS |
// has no corresponding sinks. |
if (type === SCE_CONTEXTS.RESOURCE_URL) { |
// RESOURCE_URL uses a whitelist. |
if (isResourceUrlAllowedByPolicy(maybeTrusted)) { |
return maybeTrusted; |
} else { |
@@ -19057,8 +19297,10 @@ |
maybeTrusted.toString()); |
} |
} else if (type === SCE_CONTEXTS.HTML) { |
// htmlSanitizer throws its own error when no sanitizer is available. |
return htmlSanitizer(maybeTrusted); |
} |
// Default error when the $sce service has no way to make the input safe. |
throw $sceMinErr('unsafe', 'Attempting to use an unsafe value in a safe context.'); |
} |
|
@@ -19094,22 +19336,28 @@ |
* |
* # Strict Contextual Escaping |
* |
* Strict Contextual Escaping (SCE) is a mode in which AngularJS requires bindings in certain |
* contexts to result in a value that is marked as safe to use for that context. One example of |
* such a context is binding arbitrary html controlled by the user via `ng-bind-html`. We refer |
* to these contexts as privileged or SCE contexts. |
* Strict Contextual Escaping (SCE) is a mode in which AngularJS constrains bindings to only render |
* trusted values. Its goal is to assist in writing code in a way that (a) is secure by default, and |
* (b) makes auditing for security vulnerabilities such as XSS, clickjacking, etc. a lot easier. |
* |
* As of version 1.2, Angular ships with SCE enabled by default. |
* ## Overview |
* |
* Note: When enabled (the default), IE<11 in quirks mode is not supported. In this mode, IE<11 allow |
* one to execute arbitrary javascript by the use of the expression() syntax. Refer |
* <http://blogs.msdn.com/b/ie/archive/2008/10/16/ending-expressions.aspx> to learn more about them. |
* You can ensure your document is in standards mode and not quirks mode by adding `<!doctype html>` |
* to the top of your HTML document. |
* To systematically block XSS security bugs, AngularJS treats all values as untrusted by default in |
* HTML or sensitive URL bindings. When binding untrusted values, AngularJS will automatically |
* run security checks on them (sanitizations, whitelists, depending on context), or throw when it |
* cannot guarantee the security of the result. That behavior depends strongly on contexts: HTML |
* can be sanitized, but template URLs cannot, for instance. |
* |
* SCE assists in writing code in a way that (a) is secure by default and (b) makes auditing for |
* security vulnerabilities such as XSS, clickjacking, etc. a lot easier. |
* To illustrate this, consider the `ng-bind-html` directive. It renders its value directly as HTML: |
* we call that the *context*. When given an untrusted input, AngularJS will attempt to sanitize it |
* before rendering if a sanitizer is available, and throw otherwise. To bypass sanitization and |
* render the input as-is, you will need to mark it as trusted for that context before attempting |
* to bind it. |
* |
* As of version 1.2, AngularJS ships with SCE enabled by default. |
* |
* ## In practice |
* |
* Here's an example of a binding in a privileged context: |
* |
* ``` |
@@ -19118,10 +19366,10 @@ |
* ``` |
* |
* Notice that `ng-bind-html` is bound to `userHtml` controlled by the user. With SCE |
* disabled, this application allows the user to render arbitrary HTML into the DIV. |
* In a more realistic example, one may be rendering user comments, blog articles, etc. via |
* bindings. (HTML is just one example of a context where rendering user controlled input creates |
* security vulnerabilities.) |
* disabled, this application allows the user to render arbitrary HTML into the DIV, which would |
* be an XSS security bug. In a more realistic example, one may be rendering user comments, blog |
* articles, etc. via bindings. (HTML is just one example of a context where rendering user |
* controlled input creates security vulnerabilities.) |
* |
* For the case of HTML, you might use a library, either on the client side, or on the server side, |
* to sanitize unsafe HTML before binding to the value and rendering it in the document. |
@@ -19131,25 +19379,29 @@ |
* ensure that you didn't accidentally delete the line that sanitized the value, or renamed some |
* properties/fields and forgot to update the binding to the sanitized value? |
* |
* To be secure by default, you want to ensure that any such bindings are disallowed unless you can |
* determine that something explicitly says it's safe to use a value for binding in that |
* context. You can then audit your code (a simple grep would do) to ensure that this is only done |
* for those values that you can easily tell are safe - because they were received from your server, |
* sanitized by your library, etc. You can organize your codebase to help with this - perhaps |
* allowing only the files in a specific directory to do this. Ensuring that the internal API |
* exposed by that code doesn't markup arbitrary values as safe then becomes a more manageable task. |
* To be secure by default, AngularJS makes sure bindings go through that sanitization, or |
* any similar validation process, unless there's a good reason to trust the given value in this |
* context. That trust is formalized with a function call. This means that as a developer, you |
* can assume all untrusted bindings are safe. Then, to audit your code for binding security issues, |
* you just need to ensure the values you mark as trusted indeed are safe - because they were |
* received from your server, sanitized by your library, etc. You can organize your codebase to |
* help with this - perhaps allowing only the files in a specific directory to do this. |
* Ensuring that the internal API exposed by that code doesn't markup arbitrary values as safe then |
* becomes a more manageable task. |
* |
* In the case of AngularJS' SCE service, one uses {@link ng.$sce#trustAs $sce.trustAs} |
* (and shorthand methods such as {@link ng.$sce#trustAsHtml $sce.trustAsHtml}, etc.) to |
* obtain values that will be accepted by SCE / privileged contexts. |
* build the trusted versions of your values. |
* |
* |
* ## How does it work? |
* |
* In privileged contexts, directives and code will bind to the result of {@link ng.$sce#getTrusted |
* $sce.getTrusted(context, value)} rather than to the value directly. Directives use {@link |
* ng.$sce#parseAs $sce.parseAs} rather than `$parse` to watch attribute bindings, which performs the |
* {@link ng.$sce#getTrusted $sce.getTrusted} behind the scenes on non-constant literals. |
* $sce.getTrusted(context, value)} rather than to the value directly. Think of this function as |
* a way to enforce the required security context in your data sink. Directives use {@link |
* ng.$sce#parseAs $sce.parseAs} rather than `$parse` to watch attribute bindings, which performs |
* the {@link ng.$sce#getTrusted $sce.getTrusted} behind the scenes on non-constant literals. Also, |
* when binding without directives, AngularJS will understand the context of your bindings |
* automatically. |
* |
* As an example, {@link ng.directive:ngBindHtml ngBindHtml} uses {@link |
* ng.$sce#parseAsHtml $sce.parseAsHtml(binding expression)}. Here's the actual code (slightly |
@@ -19190,12 +19442,13 @@ |
* It's important to remember that SCE only applies to interpolation expressions. |
* |
* If your expressions are constant literals, they're automatically trusted and you don't need to |
* call `$sce.trustAs` on them (remember to include the `ngSanitize` module) (e.g. |
* `<div ng-bind-html="'<b>implicitly trusted</b>'"></div>`) just works. |
* call `$sce.trustAs` on them (e.g. |
* `<div ng-bind-html="'<b>implicitly trusted</b>'"></div>`) just works. The `$sceDelegate` will |
* also use the `$sanitize` service if it is available when binding untrusted values to |
* `$sce.HTML` context. AngularJS provides an implementation in `angular-sanitize.js`, and if you |
* wish to use it, you will also need to depend on the {@link ngSanitize `ngSanitize`} module in |
* your application. |
* |
* Additionally, `a[href]` and `img[src]` automatically sanitize their URLs and do not pass them |
* through {@link ng.$sce#getTrusted $sce.getTrusted}. SCE doesn't play a role here. |
* |
* The included {@link ng.$sceDelegate $sceDelegate} comes with sane defaults to allow you to load |
* templates in `ng-include` from your application's domain without having to even know about SCE. |
* It blocks loading templates from other domains or loading templates over http from an https |
@@ -19212,12 +19465,18 @@ |
* |
* | Context | Notes | |
* |---------------------|----------------| |
* | `$sce.HTML` | For HTML that's safe to source into the application. The {@link ng.directive:ngBindHtml ngBindHtml} directive uses this context for bindings. If an unsafe value is encountered and the {@link ngSanitize $sanitize} module is present this will sanitize the value instead of throwing an error. | |
* | `$sce.CSS` | For CSS that's safe to source into the application. Currently unused. Feel free to use it in your own directives. | |
* | `$sce.URL` | For URLs that are safe to follow as links. Currently unused (`<a href=` and `<img src=` sanitize their urls and don't constitute an SCE context. | |
* | `$sce.RESOURCE_URL` | For URLs that are not only safe to follow as links, but whose contents are also safe to include in your application. Examples include `ng-include`, `src` / `ngSrc` bindings for tags other than `IMG`, `VIDEO`, `AUDIO`, `SOURCE`, and `TRACK` (e.g. `IFRAME`, `OBJECT`, etc.) <br><br>Note that `$sce.RESOURCE_URL` makes a stronger statement about the URL than `$sce.URL` does and therefore contexts requiring values trusted for `$sce.RESOURCE_URL` can be used anywhere that values trusted for `$sce.URL` are required. | |
* | `$sce.JS` | For JavaScript that is safe to execute in your application's context. Currently unused. Feel free to use it in your own directives. | |
* | `$sce.HTML` | For HTML that's safe to source into the application. The {@link ng.directive:ngBindHtml ngBindHtml} directive uses this context for bindings. If an unsafe value is encountered, and the {@link ngSanitize.$sanitize $sanitize} service is available (implemented by the {@link ngSanitize ngSanitize} module) this will sanitize the value instead of throwing an error. | |
* | `$sce.CSS` | For CSS that's safe to source into the application. Currently, no bindings require this context. Feel free to use it in your own directives. | |
* | `$sce.URL` | For URLs that are safe to follow as links. Currently unused (`<a href=`, `<img src=`, and some others sanitize their urls and don't constitute an SCE context.) | |
* | `$sce.RESOURCE_URL` | For URLs that are not only safe to follow as links, but whose contents are also safe to include in your application. Examples include `ng-include`, `src` / `ngSrc` bindings for tags other than `IMG`, `VIDEO`, `AUDIO`, `SOURCE`, and `TRACK` (e.g. `IFRAME`, `OBJECT`, etc.) <br><br>Note that `$sce.RESOURCE_URL` makes a stronger statement about the URL than `$sce.URL` does (it's not just the URL that matters, but also what is at the end of it), and therefore contexts requiring values trusted for `$sce.RESOURCE_URL` can be used anywhere that values trusted for `$sce.URL` are required. | |
* | `$sce.JS` | For JavaScript that is safe to execute in your application's context. Currently, no bindings require this context. Feel free to use it in your own directives. | |
* |
* |
* Be aware that `a[href]` and `img[src]` automatically sanitize their URLs and do not pass them |
* through {@link ng.$sce#getTrusted $sce.getTrusted}. There's no CSS-, URL-, or JS-context bindings |
* in AngularJS currently, so their corresponding `$sce.trustAs` functions aren't useful yet. This |
* might evolve. |
* |
* ## Format of items in {@link ng.$sceDelegateProvider#resourceUrlWhitelist resourceUrlWhitelist}/{@link ng.$sceDelegateProvider#resourceUrlBlacklist Blacklist} <a name="resourceUrlPatternItem"></a> |
* |
* Each element in these arrays must be one of the following: |
@@ -19335,7 +19594,8 @@ |
* for little coding overhead. It will be much harder to take an SCE disabled application and |
* either secure it on your own or enable SCE at a later stage. It might make sense to disable SCE |
* for cases where you have a lot of existing code that was written before SCE was introduced and |
* you're migrating them a module at a time. |
* you're migrating them a module at a time. Also do note that this is an app-wide setting, so if |
* you are writing a library, you will cause security bugs applications using it. |
* |
* That said, here's how you can completely disable SCE: |
* |
@@ -19342,7 +19602,7 @@ |
* ``` |
* angular.module('myAppWithSceDisabledmyApp', []).config(function($sceProvider) { |
* // Completely disable SCE. For demonstration purposes only! |
* // Do not use in new projects. |
* // Do not use in new projects or libraries. |
* $sceProvider.enabled(false); |
* }); |
* ``` |
@@ -19357,8 +19617,8 @@ |
* @name $sceProvider#enabled |
* @kind function |
* |
* @param {boolean=} value If provided, then enables/disables SCE. |
* @return {boolean} true if SCE is enabled, false otherwise. |
* @param {boolean=} value If provided, then enables/disables SCE application-wide. |
* @return {boolean} True if SCE is enabled, false otherwise. |
* |
* @description |
* Enables/disables SCE and returns the current value. |
@@ -19412,9 +19672,9 @@ |
* getTrusted($sce.RESOURCE_URL, value) succeeding implies that getTrusted($sce.URL, value) |
* will also succeed. |
* |
* Inheritance happens to capture this in a natural way. In some future, we |
* may not use inheritance anymore. That is OK because no code outside of |
* sce.js and sceSpecs.js would need to be aware of this detail. |
* Inheritance happens to capture this in a natural way. In some future, we may not use |
* inheritance anymore. That is OK because no code outside of sce.js and sceSpecs.js would need to |
* be aware of this detail. |
*/ |
|
this.$get = ['$parse', '$sceDelegate', function( |
@@ -19436,8 +19696,8 @@ |
* @name $sce#isEnabled |
* @kind function |
* |
* @return {Boolean} true if SCE is enabled, false otherwise. If you want to set the value, you |
* have to do it at module config time on {@link ng.$sceProvider $sceProvider}. |
* @return {Boolean} True if SCE is enabled, false otherwise. If you want to set the value, you |
* have to do it at module config time on {@link ng.$sceProvider $sceProvider}. |
* |
* @description |
* Returns a boolean indicating if SCE is enabled. |
@@ -19464,14 +19724,14 @@ |
* wraps the expression in a call to {@link ng.$sce#getTrusted $sce.getTrusted(*type*, |
* *result*)} |
* |
* @param {string} type The kind of SCE context in which this result will be used. |
* @param {string} type The SCE context in which this result will be used. |
* @param {string} expression String expression to compile. |
* @returns {function(context, locals)} a function which represents the compiled expression: |
* @return {function(context, locals)} A function which represents the compiled expression: |
* |
* * `context` – `{object}` – an object against which any expressions embedded in the strings |
* are evaluated against (typically a scope object). |
* * `locals` – `{object=}` – local variables context object, useful for overriding values in |
* `context`. |
* * `context` – `{object}` – an object against which any expressions embedded in the |
* strings are evaluated against (typically a scope object). |
* * `locals` – `{object=}` – local variables context object, useful for overriding values |
* in `context`. |
*/ |
sce.parseAs = function sceParseAs(type, expr) { |
var parsed = $parse(expr); |
@@ -19489,18 +19749,18 @@ |
* @name $sce#trustAs |
* |
* @description |
* Delegates to {@link ng.$sceDelegate#trustAs `$sceDelegate.trustAs`}. As such, |
* returns an object that is trusted by angular for use in specified strict contextual |
* escaping contexts (such as ng-bind-html, ng-include, any src attribute |
* interpolation, any dom event binding attribute interpolation such as for onclick, etc.) |
* that uses the provided value. See * {@link ng.$sce $sce} for enabling strict contextual |
* escaping. |
* Delegates to {@link ng.$sceDelegate#trustAs `$sceDelegate.trustAs`}. As such, returns a |
* wrapped object that represents your value, and the trust you have in its safety for the given |
* context. AngularJS can then use that value as-is in bindings of the specified secure context. |
* This is used in bindings for `ng-bind-html`, `ng-include`, and most `src` attribute |
* interpolations. See {@link ng.$sce $sce} for strict contextual escaping. |
* |
* @param {string} type The kind of context in which this value is safe for use. e.g. url, |
* resourceUrl, html, js and css. |
* @param {*} value The value that that should be considered trusted/safe. |
* @returns {*} A value that can be used to stand in for the provided `value` in places |
* where Angular expects a $sce.trustAs() return value. |
* @param {string} type The context in which this value is safe for use, e.g. `$sce.URL`, |
* `$sce.RESOURCE_URL`, `$sce.HTML`, `$sce.JS` or `$sce.CSS`. |
* |
* @param {*} value The value that that should be considered trusted. |
* @return {*} A wrapped version of value that can be used as a trusted variant of your `value` |
* in the context you specified. |
*/ |
|
/** |
@@ -19511,15 +19771,27 @@ |
* Shorthand method. `$sce.trustAsHtml(value)` → |
* {@link ng.$sceDelegate#trustAs `$sceDelegate.trustAs($sce.HTML, value)`} |
* |
* @param {*} value The value to trustAs. |
* @returns {*} An object that can be passed to {@link ng.$sce#getTrustedHtml |
* $sce.getTrustedHtml(value)} to obtain the original value. (privileged directives |
* only accept expressions that are either literal constants or are the |
* return value of {@link ng.$sce#trustAs $sce.trustAs}.) |
* @param {*} value The value to mark as trusted for `$sce.HTML` context. |
* @return {*} A wrapped version of value that can be used as a trusted variant of your `value` |
* in `$sce.HTML` context (like `ng-bind-html`). |
*/ |
|
/** |
* @ngdoc method |
* @name $sce#trustAsCss |
* |
* @description |
* Shorthand method. `$sce.trustAsCss(value)` → |
* {@link ng.$sceDelegate#trustAs `$sceDelegate.trustAs($sce.CSS, value)`} |
* |
* @param {*} value The value to mark as trusted for `$sce.CSS` context. |
* @return {*} A wrapped version of value that can be used as a trusted variant |
* of your `value` in `$sce.CSS` context. This context is currently unused, so there are |
* almost no reasons to use this function so far. |
*/ |
|
/** |
* @ngdoc method |
* @name $sce#trustAsUrl |
* |
* @description |
@@ -19526,11 +19798,10 @@ |
* Shorthand method. `$sce.trustAsUrl(value)` → |
* {@link ng.$sceDelegate#trustAs `$sceDelegate.trustAs($sce.URL, value)`} |
* |
* @param {*} value The value to trustAs. |
* @returns {*} An object that can be passed to {@link ng.$sce#getTrustedUrl |
* $sce.getTrustedUrl(value)} to obtain the original value. (privileged directives |
* only accept expressions that are either literal constants or are the |
* return value of {@link ng.$sce#trustAs $sce.trustAs}.) |
* @param {*} value The value to mark as trusted for `$sce.URL` context. |
* @return {*} A wrapped version of value that can be used as a trusted variant of your `value` |
* in `$sce.URL` context. That context is currently unused, so there are almost no reasons |
* to use this function so far. |
*/ |
|
/** |
@@ -19541,11 +19812,10 @@ |
* Shorthand method. `$sce.trustAsResourceUrl(value)` → |
* {@link ng.$sceDelegate#trustAs `$sceDelegate.trustAs($sce.RESOURCE_URL, value)`} |
* |
* @param {*} value The value to trustAs. |
* @returns {*} An object that can be passed to {@link ng.$sce#getTrustedResourceUrl |
* $sce.getTrustedResourceUrl(value)} to obtain the original value. (privileged directives |
* only accept expressions that are either literal constants or are the return |
* value of {@link ng.$sce#trustAs $sce.trustAs}.) |
* @param {*} value The value to mark as trusted for `$sce.RESOURCE_URL` context. |
* @return {*} A wrapped version of value that can be used as a trusted variant of your `value` |
* in `$sce.RESOURCE_URL` context (template URLs in `ng-include`, most `src` attribute |
* bindings, ...) |
*/ |
|
/** |
@@ -19556,11 +19826,10 @@ |
* Shorthand method. `$sce.trustAsJs(value)` → |
* {@link ng.$sceDelegate#trustAs `$sceDelegate.trustAs($sce.JS, value)`} |
* |
* @param {*} value The value to trustAs. |
* @returns {*} An object that can be passed to {@link ng.$sce#getTrustedJs |
* $sce.getTrustedJs(value)} to obtain the original value. (privileged directives |
* only accept expressions that are either literal constants or are the |
* return value of {@link ng.$sce#trustAs $sce.trustAs}.) |
* @param {*} value The value to mark as trusted for `$sce.JS` context. |
* @return {*} A wrapped version of value that can be used as a trusted variant of your `value` |
* in `$sce.JS` context. That context is currently unused, so there are almost no reasons to |
* use this function so far. |
*/ |
|
/** |
@@ -19569,16 +19838,17 @@ |
* |
* @description |
* Delegates to {@link ng.$sceDelegate#getTrusted `$sceDelegate.getTrusted`}. As such, |
* takes the result of a {@link ng.$sce#trustAs `$sce.trustAs`}() call and returns the |
* originally supplied value if the queried context type is a supertype of the created type. |
* If this condition isn't satisfied, throws an exception. |
* takes any input, and either returns a value that's safe to use in the specified context, |
* or throws an exception. This function is aware of trusted values created by the `trustAs` |
* function and its shorthands, and when contexts are appropriate, returns the unwrapped value |
* as-is. Finally, this function can also throw when there is no way to turn `maybeTrusted` in a |
* safe value (e.g., no sanitization is available or possible.) |
* |
* @param {string} type The kind of context in which this value is to be used. |
* @param {*} maybeTrusted The result of a prior {@link ng.$sce#trustAs `$sce.trustAs`} |
* call. |
* @returns {*} The value the was originally provided to |
* {@link ng.$sce#trustAs `$sce.trustAs`} if valid in this context. |
* Otherwise, throws an exception. |
* @param {string} type The context in which this value is to be used. |
* @param {*} maybeTrusted The result of a prior {@link ng.$sce#trustAs |
* `$sce.trustAs`} call, or anything else (which will not be considered trusted.) |
* @return {*} A version of the value that's safe to use in the given context, or throws an |
* exception if this is impossible. |
*/ |
|
/** |
@@ -19590,7 +19860,7 @@ |
* {@link ng.$sceDelegate#getTrusted `$sceDelegate.getTrusted($sce.HTML, value)`} |
* |
* @param {*} value The value to pass to `$sce.getTrusted`. |
* @returns {*} The return value of `$sce.getTrusted($sce.HTML, value)` |
* @return {*} The return value of `$sce.getTrusted($sce.HTML, value)` |
*/ |
|
/** |
@@ -19602,7 +19872,7 @@ |
* {@link ng.$sceDelegate#getTrusted `$sceDelegate.getTrusted($sce.CSS, value)`} |
* |
* @param {*} value The value to pass to `$sce.getTrusted`. |
* @returns {*} The return value of `$sce.getTrusted($sce.CSS, value)` |
* @return {*} The return value of `$sce.getTrusted($sce.CSS, value)` |
*/ |
|
/** |
@@ -19614,7 +19884,7 @@ |
* {@link ng.$sceDelegate#getTrusted `$sceDelegate.getTrusted($sce.URL, value)`} |
* |
* @param {*} value The value to pass to `$sce.getTrusted`. |
* @returns {*} The return value of `$sce.getTrusted($sce.URL, value)` |
* @return {*} The return value of `$sce.getTrusted($sce.URL, value)` |
*/ |
|
/** |
@@ -19626,7 +19896,7 @@ |
* {@link ng.$sceDelegate#getTrusted `$sceDelegate.getTrusted($sce.RESOURCE_URL, value)`} |
* |
* @param {*} value The value to pass to `$sceDelegate.getTrusted`. |
* @returns {*} The return value of `$sce.getTrusted($sce.RESOURCE_URL, value)` |
* @return {*} The return value of `$sce.getTrusted($sce.RESOURCE_URL, value)` |
*/ |
|
/** |
@@ -19638,7 +19908,7 @@ |
* {@link ng.$sceDelegate#getTrusted `$sceDelegate.getTrusted($sce.JS, value)`} |
* |
* @param {*} value The value to pass to `$sce.getTrusted`. |
* @returns {*} The return value of `$sce.getTrusted($sce.JS, value)` |
* @return {*} The return value of `$sce.getTrusted($sce.JS, value)` |
*/ |
|
/** |
@@ -19650,12 +19920,12 @@ |
* {@link ng.$sce#parseAs `$sce.parseAs($sce.HTML, value)`} |
* |
* @param {string} expression String expression to compile. |
* @returns {function(context, locals)} a function which represents the compiled expression: |
* @return {function(context, locals)} A function which represents the compiled expression: |
* |
* * `context` – `{object}` – an object against which any expressions embedded in the strings |
* are evaluated against (typically a scope object). |
* * `locals` – `{object=}` – local variables context object, useful for overriding values in |
* `context`. |
* * `context` – `{object}` – an object against which any expressions embedded in the |
* strings are evaluated against (typically a scope object). |
* * `locals` – `{object=}` – local variables context object, useful for overriding values |
* in `context`. |
*/ |
|
/** |
@@ -19667,12 +19937,12 @@ |
* {@link ng.$sce#parseAs `$sce.parseAs($sce.CSS, value)`} |
* |
* @param {string} expression String expression to compile. |
* @returns {function(context, locals)} a function which represents the compiled expression: |
* @return {function(context, locals)} A function which represents the compiled expression: |
* |
* * `context` – `{object}` – an object against which any expressions embedded in the strings |
* are evaluated against (typically a scope object). |
* * `locals` – `{object=}` – local variables context object, useful for overriding values in |
* `context`. |
* * `context` – `{object}` – an object against which any expressions embedded in the |
* strings are evaluated against (typically a scope object). |
* * `locals` – `{object=}` – local variables context object, useful for overriding values |
* in `context`. |
*/ |
|
/** |
@@ -19684,12 +19954,12 @@ |
* {@link ng.$sce#parseAs `$sce.parseAs($sce.URL, value)`} |
* |
* @param {string} expression String expression to compile. |
* @returns {function(context, locals)} a function which represents the compiled expression: |
* @return {function(context, locals)} A function which represents the compiled expression: |
* |
* * `context` – `{object}` – an object against which any expressions embedded in the strings |
* are evaluated against (typically a scope object). |
* * `locals` – `{object=}` – local variables context object, useful for overriding values in |
* `context`. |
* * `context` – `{object}` – an object against which any expressions embedded in the |
* strings are evaluated against (typically a scope object). |
* * `locals` – `{object=}` – local variables context object, useful for overriding values |
* in `context`. |
*/ |
|
/** |
@@ -19701,12 +19971,12 @@ |
* {@link ng.$sce#parseAs `$sce.parseAs($sce.RESOURCE_URL, value)`} |
* |
* @param {string} expression String expression to compile. |
* @returns {function(context, locals)} a function which represents the compiled expression: |
* @return {function(context, locals)} A function which represents the compiled expression: |
* |
* * `context` – `{object}` – an object against which any expressions embedded in the strings |
* are evaluated against (typically a scope object). |
* * `locals` – `{object=}` – local variables context object, useful for overriding values in |
* `context`. |
* * `context` – `{object}` – an object against which any expressions embedded in the |
* strings are evaluated against (typically a scope object). |
* * `locals` – `{object=}` – local variables context object, useful for overriding values |
* in `context`. |
*/ |
|
/** |
@@ -19718,12 +19988,12 @@ |
* {@link ng.$sce#parseAs `$sce.parseAs($sce.JS, value)`} |
* |
* @param {string} expression String expression to compile. |
* @returns {function(context, locals)} a function which represents the compiled expression: |
* @return {function(context, locals)} A function which represents the compiled expression: |
* |
* * `context` – `{object}` – an object against which any expressions embedded in the strings |
* are evaluated against (typically a scope object). |
* * `locals` – `{object=}` – local variables context object, useful for overriding values in |
* `context`. |
* * `context` – `{object}` – an object against which any expressions embedded in the |
* strings are evaluated against (typically a scope object). |
* * `locals` – `{object=}` – local variables context object, useful for overriding values |
* in `context`. |
*/ |
|
// Shorthand delegations. |
@@ -20149,7 +20419,7 @@ |
timeout.cancel = function(promise) { |
if (promise && promise.$$timeoutId in deferreds) { |
// Timeout cancels should not report an unhandled promise. |
deferreds[promise.$$timeoutId].promise.catch(noop); |
markQExceptionHandled(deferreds[promise.$$timeoutId].promise); |
deferreds[promise.$$timeoutId].reject('canceled'); |
delete deferreds[promise.$$timeoutId]; |
return $browser.defer.cancel(promise.$$timeoutId); |
@@ -20583,8 +20853,9 @@ |
* The final result is an array of those elements that the predicate returned true for. |
* |
* @param {function(actual, expected)|true|false} [comparator] Comparator which is used in |
* determining if the expected value (from the filter expression) and actual value (from |
* the object in the array) should be considered a match. |
* determining if values retrieved using `expression` (when it is not a function) should be |
* considered a match based on the expected value (from the filter expression) and actual |
* value (from the object in the array). |
* |
* Can be one of: |
* |
@@ -21279,7 +21550,7 @@ |
GGGG: longEraGetter |
}; |
|
var DATE_FORMATS_SPLIT = /((?:[^yMLdHhmsaZEwG']+)|(?:'(?:[^']|'')*')|(?:E+|y+|M+|L+|d+|H+|h+|m+|s+|a|Z|G+|w+))(.*)/, |
var DATE_FORMATS_SPLIT = /((?:[^yMLdHhmsaZEwG']+)|(?:'(?:[^']|'')*')|(?:E+|y+|M+|L+|d+|H+|h+|m+|s+|a|Z|G+|w+))([\s\S]*)/, |
NUMBER_STRING = /^-?\d+$/; |
|
/** |
@@ -21338,6 +21609,8 @@ |
* `"h 'in the morning'"`). In order to output a single quote, escape it - i.e., two single quotes in a sequence |
* (e.g. `"h 'o''clock'"`). |
* |
* Any other characters in the `format` string will be output as-is. |
* |
* @param {(Date|number|string)} date Date to format either as Date object, milliseconds (string or |
* number) or various ISO 8601 datetime string formats (e.g. yyyy-MM-ddTHH:mm:ss.sssZ and its |
* shorter versions like yyyy-MM-ddTHH:mmZ, yyyy-MM-dd or yyyyMMddTHHmmssZ). If no timezone is |
@@ -21500,6 +21773,9 @@ |
* @kind function |
* @description |
* Converts string to lowercase. |
* |
* See the {@link ng.uppercase uppercase filter documentation} for a functionally identical example. |
* |
* @see angular.lowercase |
*/ |
var lowercaseFilter = valueFn(lowercase); |
@@ -21511,7 +21787,23 @@ |
* @kind function |
* @description |
* Converts string to uppercase. |
* @see angular.uppercase |
* @example |
<example module="uppercaseFilterExample" name="filter-uppercase"> |
<file name="index.html"> |
<script> |
angular.module('uppercaseFilterExample', []) |
.controller('ExampleController', ['$scope', function($scope) { |
$scope.title = 'This is a title'; |
}]); |
</script> |
<div ng-controller="ExampleController"> |
<!-- This title should be formatted normally --> |
<h1>{{title}}</h1> |
<!-- This title should be capitalized --> |
<h1>{{title | uppercase}}</h1> |
</div> |
</file> |
</example> |
*/ |
var uppercaseFilter = valueFn(uppercase); |
|
@@ -21700,6 +21992,9 @@ |
* dummy predicate that returns the item's index as `value`. |
* (If you are using a custom comparator, make sure it can handle this predicate as well.) |
* |
* If a custom comparator still can't distinguish between two items, then they will be sorted based |
* on their index using the built-in comparator. |
* |
* Finally, in an attempt to simplify things, if a predicate returns an object as the extracted |
* value for an item, `orderBy` will try to convert that object to a primitive value, before passing |
* it to the comparator. The following rules govern the conversion: |
@@ -22246,7 +22541,7 @@ |
} |
} |
|
return compare(v1.tieBreaker, v2.tieBreaker) * descending; |
return (compare(v1.tieBreaker, v2.tieBreaker) || defaultCompare(v1.tieBreaker, v2.tieBreaker)) * descending; |
} |
}; |
|
@@ -22849,17 +23144,23 @@ |
* @property {boolean} $dirty True if user has already interacted with the form. |
* @property {boolean} $valid True if all of the containing forms and controls are valid. |
* @property {boolean} $invalid True if at least one containing control or form is invalid. |
* @property {boolean} $pending True if at least one containing control or form is pending. |
* @property {boolean} $submitted True if user has submitted the form even if its invalid. |
* |
* @property {Object} $error Is an object hash, containing references to controls or |
* forms with failing validators, where: |
* @property {Object} $pending An object hash, containing references to controls or forms with |
* pending validators, where: |
* |
* - keys are validations tokens (error names). |
* - values are arrays of controls or forms that have a pending validator for the given error name. |
* |
* See {@link form.FormController#$error $error} for a list of built-in validation tokens. |
* |
* @property {Object} $error An object hash, containing references to controls or forms with failing |
* validators, where: |
* |
* - keys are validation tokens (error names), |
* - values are arrays of controls or forms that have a failing validator for given error name. |
* - values are arrays of controls or forms that have a failing validator for the given error name. |
* |
* Built-in validation tokens: |
* |
* - `email` |
* - `max` |
* - `maxlength` |
@@ -23105,9 +23406,24 @@ |
* @name form.FormController#$setValidity |
* |
* @description |
* Sets the validity of a form control. |
* Change the validity state of the form, and notify the parent form (if any). |
* |
* This method will also propagate to parent forms. |
* Application developers will rarely need to call this method directly. It is used internally, by |
* {@link ngModel.NgModelController#$setValidity NgModelController.$setValidity()}, to propagate a |
* control's validity state to the parent `FormController`. |
* |
* @param {string} validationErrorKey Name of the validator. The `validationErrorKey` will be |
* assigned to either `$error[validationErrorKey]` or `$pending[validationErrorKey]` (for |
* unfulfilled `$asyncValidators`), so that it is available for data-binding. The |
* `validationErrorKey` should be in camelCase and will get converted into dash-case for |
* class name. Example: `myError` will result in `ng-valid-my-error` and |
* `ng-invalid-my-error` classes and can be bound to as `{{ someForm.$error.myError }}`. |
* @param {boolean} isValid Whether the current state is valid (true), invalid (false), pending |
* (undefined), or skipped (null). Pending is used for unfulfilled `$asyncValidators`. |
* Skipped is used by AngularJS when validators do not run because of parse errors and when |
* `$asyncValidators` do not run because any of the `$validators` failed. |
* @param {NgModelController | FormController} controller - The controller whose validity state is |
* triggering the change. |
*/ |
addSetValidityMethod({ |
clazz: FormController, |
@@ -28297,7 +28613,9 @@ |
|
this.$$currentValidationRunId = 0; |
|
this.$$scope = $scope; |
// https://github.com/angular/angular.js/issues/15833 |
// Prevent `$$scope` from being iterated over by `copy` when NgModelController is deep watched |
Object.defineProperty(this, '$$scope', {value: $scope}); |
this.$$attr = $attr; |
this.$$element = $element; |
this.$$animate = $animate; |
@@ -28906,8 +29224,8 @@ |
// -> scope value did not change since the last digest as |
// ng-change executes in apply phase |
// 4. view should be changed back to 'a' |
ctrl.$$scope.$watch(function ngModelWatch() { |
var modelValue = ctrl.$$ngModelGet(ctrl.$$scope); |
ctrl.$$scope.$watch(function ngModelWatch(scope) { |
var modelValue = ctrl.$$ngModelGet(scope); |
|
// if scope model value and ngModel value are out of sync |
// TODO(perf): why not move this to the action fn? |
@@ -28956,7 +29274,7 @@ |
* (for unfulfilled `$asyncValidators`), so that it is available for data-binding. |
* The `validationErrorKey` should be in camelCase and will get converted into dash-case |
* for class name. Example: `myError` will result in `ng-valid-my-error` and `ng-invalid-my-error` |
* class and can be bound to as `{{someForm.someControl.$error.myError}}` . |
* classes and can be bound to as `{{ someForm.someControl.$error.myError }}`. |
* @param {boolean} isValid Whether the current state is valid (true), invalid (false), pending (undefined), |
* or skipped (null). Pending is used for unfulfilled `$asyncValidators`. |
* Skipped is used by Angular when validators do not run because of parse errors and |
@@ -30031,7 +30349,8 @@ |
} |
|
|
// we can't just jqLite('<option>') since jqLite is not smart enough |
// Support: IE 9 only |
// We can't just jqLite('<option>') since jqLite is not smart enough |
// to create it in <select> and IE barfs otherwise. |
var optionTemplate = window.document.createElement('option'), |
optGroupTemplate = window.document.createElement('optgroup'); |
@@ -30052,6 +30371,9 @@ |
} |
} |
|
// The empty option will be compiled and rendered before we first generate the options |
selectElement.empty(); |
|
var providedEmptyOption = !!selectCtrl.emptyOption; |
|
var unknownOption = jqLite(optionTemplate.cloneNode(false)); |
@@ -30073,12 +30395,15 @@ |
if (!multiple) { |
|
selectCtrl.writeValue = function writeNgOptionsValue(value) { |
var selectedOption = options.selectValueMap[selectElement.val()]; |
// The options might not be defined yet when ngModel tries to render |
if (!options) return; |
|
var selectedOption = selectElement[0].options[selectElement[0].selectedIndex]; |
var option = options.getOptionFromViewValue(value); |
|
// Make sure to remove the selected attribute from the previously selected option |
// Otherwise, screen readers might get confused |
if (selectedOption) selectedOption.element.removeAttribute('selected'); |
if (selectedOption) selectedOption.removeAttribute('selected'); |
|
if (option) { |
// Don't update the option when it is already selected. |
@@ -30088,7 +30413,6 @@ |
|
if (selectElement[0].value !== option.selectValue) { |
selectCtrl.removeUnknownOption(); |
selectCtrl.unselectEmptyOption(); |
|
selectElement[0].value = option.selectValue; |
option.element.selected = true; |
@@ -30096,14 +30420,7 @@ |
|
option.element.setAttribute('selected', 'selected'); |
} else { |
|
if (providedEmptyOption) { |
selectCtrl.selectEmptyOption(); |
} else if (selectCtrl.unknownOption.parent().length) { |
selectCtrl.updateUnknownOption(value); |
} else { |
selectCtrl.renderUnknownOption(value); |
} |
selectCtrl.selectUnknownOrEmptyOption(value); |
} |
}; |
|
@@ -30132,9 +30449,11 @@ |
} else { |
|
selectCtrl.writeValue = function writeNgOptionsMultiple(values) { |
// The options might not be defined yet when ngModel tries to render |
if (!options) return; |
|
// Only set `<option>.selected` if necessary, in order to prevent some browsers from |
// scrolling to `<option>` elements that are outside the `<select>` element's viewport. |
|
var selectedOptions = values && values.map(getAndUpdateSelectedOption) || []; |
|
options.items.forEach(function(option) { |
@@ -30176,13 +30495,11 @@ |
|
if (providedEmptyOption) { |
|
// we need to remove it before calling selectElement.empty() because otherwise IE will |
// remove the label from the element. wtf? |
selectCtrl.emptyOption.remove(); |
|
// compile the element since there might be bindings in it |
$compile(selectCtrl.emptyOption)(scope); |
|
selectElement.prepend(selectCtrl.emptyOption); |
|
if (selectCtrl.emptyOption[0].nodeType === NODE_TYPE_COMMENT) { |
// This means the empty option has currently no actual DOM node, probably because |
// it has been modified by a transclusion directive. |
@@ -30200,8 +30517,12 @@ |
ngModelCtrl.$render(); |
|
optionEl.on('$destroy', function() { |
var needsRerender = selectCtrl.$isEmptyOptionSelected(); |
|
selectCtrl.hasEmptyOption = false; |
selectCtrl.emptyOption = undefined; |
|
if (needsRerender) ngModelCtrl.$render(); |
}); |
} |
}; |
@@ -30214,12 +30535,6 @@ |
|
} |
|
selectElement.empty(); |
|
// We need to do this here to ensure that the options object is defined |
// when we first hit it in writeNgOptionsValue |
updateOptions(); |
|
// We will re-render the option elements if the option values or labels change |
scope.$watchCollection(ngOptions.getWatchables, updateOptions); |
|
@@ -30243,7 +30558,8 @@ |
function updateOptionElement(option, element) { |
option.element = element; |
element.disabled = option.disabled; |
// NOTE: The label must be set before the value, otherwise IE10/11/EDGE create unresponsive |
// Support: IE 11 only, Edge 12-13 only |
// NOTE: The label must be set before the value, otherwise IE 11 & Edge create unresponsive |
// selects in certain circumstances when multiple selects are next to each other and display |
// the option list in listbox style, i.e. the select is [multiple], or specifies a [size]. |
// See https://github.com/angular/angular.js/issues/11314 for more info. |
@@ -30279,11 +30595,6 @@ |
|
var groupElementMap = {}; |
|
// Ensure that the empty option is always there if it was explicitly provided |
if (providedEmptyOption) { |
selectElement.prepend(selectCtrl.emptyOption); |
} |
|
options.items.forEach(function addOption(option) { |
var groupElement; |
|
@@ -30328,7 +30639,6 @@ |
ngModelCtrl.$render(); |
} |
} |
|
} |
} |
|
@@ -31016,7 +31326,7 @@ |
// Store a list of elements from previous run. This is a hash where key is the item from the |
// iterator, and the value is objects with following properties. |
// - scope: bound scope |
// - element: previous element. |
// - clone: previous element. |
// - index: position |
// |
// We are using no-proto object so that we don't need to guard against inherited props via |
@@ -32119,7 +32429,7 @@ |
var noopNgModelController = { $setViewValue: noop, $render: noop }; |
|
function setOptionSelectedStatus(optionEl, value) { |
optionEl.prop('selected', value); // needed for IE |
optionEl.prop('selected', value); |
/** |
* When unselecting an option, setting the property to null / false should be enough |
* However, screenreaders might react to the selected attribute instead, see |
@@ -32133,10 +32443,120 @@ |
/** |
* @ngdoc type |
* @name select.SelectController |
* |
* @description |
* The controller for the `<select>` directive. This provides support for reading |
* and writing the selected value(s) of the control and also coordinates dynamically |
* added `<option>` elements, perhaps by an `ngRepeat` directive. |
* The controller for the {@link ng.select select} directive. The controller exposes |
* a few utility methods that can be used to augment the behavior of a regular or an |
* {@link ng.ngOptions ngOptions} select element. |
* |
* @example |
* ### Set a custom error when the unknown option is selected |
* |
* This example sets a custom error "unknownValue" on the ngModelController |
* when the select element's unknown option is selected, i.e. when the model is set to a value |
* that is not matched by any option. |
* |
* <example name="select-unknown-value-error" module="staticSelect"> |
* <file name="index.html"> |
* <div ng-controller="ExampleController"> |
* <form name="myForm"> |
* <label for="testSelect"> Single select: </label><br> |
* <select name="testSelect" ng-model="selected" unknown-value-error> |
* <option value="option-1">Option 1</option> |
* <option value="option-2">Option 2</option> |
* </select><br> |
* <span ng-if="myForm.testSelect.$error.unknownValue">Error: The current model doesn't match any option</span> |
* |
* <button ng-click="forceUnknownOption()">Force unknown option</button><br> |
* </form> |
* </div> |
* </file> |
* <file name="app.js"> |
* angular.module('staticSelect', []) |
* .controller('ExampleController', ['$scope', function($scope) { |
* $scope.selected = null; |
* |
* $scope.forceUnknownOption = function() { |
* $scope.selected = 'nonsense'; |
* }; |
* }]) |
* .directive('unknownValueError', function() { |
* return { |
* require: ['ngModel', 'select'], |
* link: function(scope, element, attrs, ctrls) { |
* var ngModelCtrl = ctrls[0]; |
* var selectCtrl = ctrls[1]; |
* |
* ngModelCtrl.$validators.unknownValue = function(modelValue, viewValue) { |
* if (selectCtrl.$isUnknownOptionSelected()) { |
* return false; |
* } |
* |
* return true; |
* }; |
* } |
* |
* }; |
* }); |
* </file> |
*</example> |
* |
* |
* @example |
* ### Set the "required" error when the unknown option is selected. |
* |
* By default, the "required" error on the ngModelController is only set on a required select |
* when the empty option is selected. This example adds a custom directive that also sets the |
* error when the unknown option is selected. |
* |
* <example name="select-unknown-value-required" module="staticSelect"> |
* <file name="index.html"> |
* <div ng-controller="ExampleController"> |
* <form name="myForm"> |
* <label for="testSelect"> Select: </label><br> |
* <select name="testSelect" ng-model="selected" unknown-value-required> |
* <option value="option-1">Option 1</option> |
* <option value="option-2">Option 2</option> |
* </select><br> |
* <span ng-if="myForm.testSelect.$error.required">Error: Please select a value</span><br> |
* |
* <button ng-click="forceUnknownOption()">Force unknown option</button><br> |
* </form> |
* </div> |
* </file> |
* <file name="app.js"> |
* angular.module('staticSelect', []) |
* .controller('ExampleController', ['$scope', function($scope) { |
* $scope.selected = null; |
* |
* $scope.forceUnknownOption = function() { |
* $scope.selected = 'nonsense'; |
* }; |
* }]) |
* .directive('unknownValueRequired', function() { |
* return { |
* priority: 1, // This directive must run after the required directive has added its validator |
* require: ['ngModel', 'select'], |
* link: function(scope, element, attrs, ctrls) { |
* var ngModelCtrl = ctrls[0]; |
* var selectCtrl = ctrls[1]; |
* |
* var originalRequiredValidator = ngModelCtrl.$validators.required; |
* |
* ngModelCtrl.$validators.required = function() { |
* if (attrs.required && selectCtrl.$isUnknownOptionSelected()) { |
* return false; |
* } |
* |
* return originalRequiredValidator.apply(this, arguments); |
* }; |
* } |
* }; |
* }); |
* </file> |
*</example> |
* |
* |
*/ |
var SelectController = |
['$element', '$scope', /** @this */ function($element, $scope) { |
@@ -32154,15 +32574,18 @@ |
// does not match any of the options. When it is rendered the value of the unknown |
// option is '? XXX ?' where XXX is the hashKey of the value that is not known. |
// |
// Support: IE 9 only |
// We can't just jqLite('<option>') since jqLite is not smart enough |
// to create it in <select> and IE barfs otherwise. |
self.unknownOption = jqLite(window.document.createElement('option')); |
|
// The empty option is an option with the value '' that te application developer can |
// provide inside the select. When the model changes to a value that doesn't match an option, |
// it is selected - so if an empty option is provided, no unknown option is generated. |
// However, the empty option is not removed when the model matches an option. It is always selectable |
// and indicates that a "null" selection has been made. |
// The empty option is an option with the value '' that the application developer can |
// provide inside the select. It is always selectable and indicates that a "null" selection has |
// been made by the user. |
// If the select has an empty option, and the model of the select is set to "undefined" or "null", |
// the empty option is selected. |
// If the model is set to a different unmatched value, the unknown option is rendered and |
// selected, i.e both are present, because a "null" selection and an unknown value are different. |
self.hasEmptyOption = false; |
self.emptyOption = undefined; |
|
@@ -32198,7 +32621,7 @@ |
|
self.unselectEmptyOption = function() { |
if (self.hasEmptyOption) { |
self.emptyOption.removeAttr('selected'); |
setOptionSelectedStatus(self.emptyOption, false); |
} |
}; |
|
@@ -32240,14 +32663,7 @@ |
var selectedOption = $element[0].options[$element[0].selectedIndex]; |
setOptionSelectedStatus(jqLite(selectedOption), true); |
} else { |
if (value == null && self.emptyOption) { |
self.removeUnknownOption(); |
self.selectEmptyOption(); |
} else if (self.unknownOption.parent().length) { |
self.updateUnknownOption(value); |
} else { |
self.renderUnknownOption(value); |
} |
self.selectUnknownOrEmptyOption(value); |
} |
}; |
|
@@ -32290,7 +32706,60 @@ |
return !!optionsMap.get(value); |
}; |
|
/** |
* @ngdoc method |
* @name select.SelectController#$hasEmptyOption |
* |
* @description |
* |
* Returns `true` if the select element currently has an empty option |
* element, i.e. an option that signifies that the select is empty / the selection is null. |
* |
*/ |
self.$hasEmptyOption = function() { |
return self.hasEmptyOption; |
}; |
|
/** |
* @ngdoc method |
* @name select.SelectController#$isUnknownOptionSelected |
* |
* @description |
* |
* Returns `true` if the select element's unknown option is selected. The unknown option is added |
* and automatically selected whenever the select model doesn't match any option. |
* |
*/ |
self.$isUnknownOptionSelected = function() { |
// Presence of the unknown option means it is selected |
return $element[0].options[0] === self.unknownOption[0]; |
}; |
|
/** |
* @ngdoc method |
* @name select.SelectController#$isEmptyOptionSelected |
* |
* @description |
* |
* Returns `true` if the select element has an empty option and this empty option is currently |
* selected. Returns `false` if the select element has no empty option or it is not selected. |
* |
*/ |
self.$isEmptyOptionSelected = function() { |
return self.hasEmptyOption && $element[0].options[$element[0].selectedIndex] === self.emptyOption[0]; |
}; |
|
self.selectUnknownOrEmptyOption = function(value) { |
if (value == null && self.emptyOption) { |
self.removeUnknownOption(); |
self.selectEmptyOption(); |
} else if (self.unknownOption.parent().length) { |
self.updateUnknownOption(value); |
} else { |
self.renderUnknownOption(value); |
} |
}; |
|
var renderScheduled = false; |
function scheduleRender() { |
if (renderScheduled) return; |
@@ -32438,6 +32907,9 @@ |
* the content of the `value` attribute or the textContent of the `<option>`, if the value attribute is missing. |
* Value and textContent can be interpolated. |
* |
* The {@link select.SelectController select controller} exposes utility functions that can be used |
* to manipulate the select's behavior. |
* |
* ## Matching model and option values |
* |
* In general, the match between the model and an option is evaluated by strictly comparing the model |
@@ -32490,6 +32962,19 @@ |
* @param {string=} ngAttrSize sets the size of the select element dynamically. Uses the |
* {@link guide/interpolation#-ngattr-for-binding-to-arbitrary-attributes ngAttr} directive. |
* |
* |
* @knownIssue |
* |
* In Firefox, the select model is only updated when the select element is blurred. For example, |
* when switching between options with the keyboard, the select model is only set to the |
* currently selected option when the select is blurred, e.g via tab key or clicking the mouse |
* outside the select. |
* |
* This is due to an ambiguity in the select element specification. See the |
* [issue on the Firefox bug tracker](https://bugzilla.mozilla.org/show_bug.cgi?id=126379) |
* for more information, and this |
* [Github comment for a workaround](https://github.com/angular/angular.js/issues/9134#issuecomment-130800488) |
* |
* @example |
* ### Simple `select` elements with static options |
* |
@@ -32734,10 +33219,11 @@ |
includes(value, selectCtrl.selectValueMap[option.value])); |
var currentlySelected = option.selected; |
|
// IE and Edge, adding options to the selection via shift+click/UP/DOWN, |
// Support: IE 9-11 only, Edge 12-15+ |
// In IE and Edge adding options to the selection via shift+click/UP/DOWN |
// will de-select already selected options if "selected" on those options was set |
// more than once (i.e. when the options were already selected) |
// So we only modify the selected property if neccessary. |
// So we only modify the selected property if necessary. |
// Note: this behavior cannot be replicated via unit tests because it only shows in the |
// actual user interface. |
if (shouldBeSelected !== currentlySelected) { |