| /** |
| * @license Angular v8.1.1 |
| * (c) 2010-2019 Google LLC. https://angular.io/ |
| * License: MIT |
| */ |
| |
| (function (global, factory) { |
| typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('rxjs'), require('rxjs/operators')) : |
| typeof define === 'function' && define.amd ? define('@angular/core', ['exports', 'rxjs', 'rxjs/operators'], factory) : |
| (global = global || self, factory((global.ng = global.ng || {}, global.ng.core = {}), global.rxjs, global.rxjs.operators)); |
| }(this, function (exports, rxjs, operators) { 'use strict'; |
| |
| /*! *****************************************************************************
|
| Copyright (c) Microsoft Corporation. All rights reserved.
|
| Licensed under the Apache License, Version 2.0 (the "License"); you may not use
|
| this file except in compliance with the License. You may obtain a copy of the
|
| License at http://www.apache.org/licenses/LICENSE-2.0
|
|
|
| THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
| KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED
|
| WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE,
|
| MERCHANTABLITY OR NON-INFRINGEMENT.
|
|
|
| See the Apache Version 2.0 License for specific language governing permissions
|
| and limitations under the License.
|
| ***************************************************************************** */
|
| /* global Reflect, Promise */
|
|
|
| var extendStatics = function(d, b) {
|
| extendStatics = Object.setPrototypeOf ||
|
| ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
|
| function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
|
| return extendStatics(d, b);
|
| };
|
|
|
| function __extends(d, b) {
|
| extendStatics(d, b);
|
| function __() { this.constructor = d; }
|
| d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
|
| }
|
|
|
| var __assign = function() {
|
| __assign = Object.assign || function __assign(t) {
|
| for (var s, i = 1, n = arguments.length; i < n; i++) {
|
| s = arguments[i];
|
| for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p];
|
| }
|
| return t;
|
| };
|
| return __assign.apply(this, arguments);
|
| };
|
|
|
| function __decorate(decorators, target, key, desc) {
|
| var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
| if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
| else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
| return c > 3 && r && Object.defineProperty(target, key, r), r;
|
| }
|
|
|
| function __param(paramIndex, decorator) {
|
| return function (target, key) { decorator(target, key, paramIndex); }
|
| }
|
|
|
| function __metadata(metadataKey, metadataValue) {
|
| if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(metadataKey, metadataValue);
|
| }
|
|
|
| function __values(o) {
|
| var m = typeof Symbol === "function" && o[Symbol.iterator], i = 0;
|
| if (m) return m.call(o);
|
| return {
|
| next: function () {
|
| if (o && i >= o.length) o = void 0;
|
| return { value: o && o[i++], done: !o };
|
| }
|
| };
|
| }
|
|
|
| function __read(o, n) {
|
| var m = typeof Symbol === "function" && o[Symbol.iterator];
|
| if (!m) return o;
|
| var i = m.call(o), r, ar = [], e;
|
| try {
|
| while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value);
|
| }
|
| catch (error) { e = { error: error }; }
|
| finally {
|
| try {
|
| if (r && !r.done && (m = i["return"])) m.call(i);
|
| }
|
| finally { if (e) throw e.error; }
|
| }
|
| return ar;
|
| }
|
|
|
| function __spread() {
|
| for (var ar = [], i = 0; i < arguments.length; i++)
|
| ar = ar.concat(__read(arguments[i]));
|
| return ar;
|
| } |
| |
| /** |
| * @license |
| * Copyright Google Inc. All Rights Reserved. |
| * |
| * Use of this source code is governed by an MIT-style license that can be |
| * found in the LICENSE file at https://angular.io/license |
| */ |
| var ANNOTATIONS = '__annotations__'; |
| var PARAMETERS = '__parameters__'; |
| var PROP_METADATA = '__prop__metadata__'; |
| /** |
| * @suppress {globalThis} |
| */ |
| function makeDecorator(name, props, parentClass, additionalProcessing, typeFn) { |
| var metaCtor = makeMetadataCtor(props); |
| function DecoratorFactory() { |
| var _a; |
| var args = []; |
| for (var _i = 0; _i < arguments.length; _i++) { |
| args[_i] = arguments[_i]; |
| } |
| if (this instanceof DecoratorFactory) { |
| metaCtor.call.apply(metaCtor, __spread([this], args)); |
| return this; |
| } |
| var annotationInstance = new ((_a = DecoratorFactory).bind.apply(_a, __spread([void 0], args)))(); |
| return function TypeDecorator(cls) { |
| if (typeFn) |
| typeFn.apply(void 0, __spread([cls], args)); |
| // Use of Object.defineProperty is important since it creates non-enumerable property which |
| // prevents the property is copied during subclassing. |
| var annotations = cls.hasOwnProperty(ANNOTATIONS) ? |
| cls[ANNOTATIONS] : |
| Object.defineProperty(cls, ANNOTATIONS, { value: [] })[ANNOTATIONS]; |
| annotations.push(annotationInstance); |
| if (additionalProcessing) |
| additionalProcessing(cls); |
| return cls; |
| }; |
| } |
| if (parentClass) { |
| DecoratorFactory.prototype = Object.create(parentClass.prototype); |
| } |
| DecoratorFactory.prototype.ngMetadataName = name; |
| DecoratorFactory.annotationCls = DecoratorFactory; |
| return DecoratorFactory; |
| } |
| function makeMetadataCtor(props) { |
| return function ctor() { |
| var args = []; |
| for (var _i = 0; _i < arguments.length; _i++) { |
| args[_i] = arguments[_i]; |
| } |
| if (props) { |
| var values = props.apply(void 0, __spread(args)); |
| for (var propName in values) { |
| this[propName] = values[propName]; |
| } |
| } |
| }; |
| } |
| function makeParamDecorator(name, props, parentClass) { |
| var metaCtor = makeMetadataCtor(props); |
| function ParamDecoratorFactory() { |
| var _a; |
| var args = []; |
| for (var _i = 0; _i < arguments.length; _i++) { |
| args[_i] = arguments[_i]; |
| } |
| if (this instanceof ParamDecoratorFactory) { |
| metaCtor.apply(this, args); |
| return this; |
| } |
| var annotationInstance = new ((_a = ParamDecoratorFactory).bind.apply(_a, __spread([void 0], args)))(); |
| ParamDecorator.annotation = annotationInstance; |
| return ParamDecorator; |
| function ParamDecorator(cls, unusedKey, index) { |
| // Use of Object.defineProperty is important since it creates non-enumerable property which |
| // prevents the property is copied during subclassing. |
| var parameters = cls.hasOwnProperty(PARAMETERS) ? |
| cls[PARAMETERS] : |
| Object.defineProperty(cls, PARAMETERS, { value: [] })[PARAMETERS]; |
| // there might be gaps if some in between parameters do not have annotations. |
| // we pad with nulls. |
| while (parameters.length <= index) { |
| parameters.push(null); |
| } |
| (parameters[index] = parameters[index] || []).push(annotationInstance); |
| return cls; |
| } |
| } |
| if (parentClass) { |
| ParamDecoratorFactory.prototype = Object.create(parentClass.prototype); |
| } |
| ParamDecoratorFactory.prototype.ngMetadataName = name; |
| ParamDecoratorFactory.annotationCls = ParamDecoratorFactory; |
| return ParamDecoratorFactory; |
| } |
| function makePropDecorator(name, props, parentClass, additionalProcessing) { |
| var metaCtor = makeMetadataCtor(props); |
| function PropDecoratorFactory() { |
| var _a; |
| var args = []; |
| for (var _i = 0; _i < arguments.length; _i++) { |
| args[_i] = arguments[_i]; |
| } |
| if (this instanceof PropDecoratorFactory) { |
| metaCtor.apply(this, args); |
| return this; |
| } |
| var decoratorInstance = new ((_a = PropDecoratorFactory).bind.apply(_a, __spread([void 0], args)))(); |
| function PropDecorator(target, name) { |
| var constructor = target.constructor; |
| // Use of Object.defineProperty is important since it creates non-enumerable property which |
| // prevents the property is copied during subclassing. |
| var meta = constructor.hasOwnProperty(PROP_METADATA) ? |
| constructor[PROP_METADATA] : |
| Object.defineProperty(constructor, PROP_METADATA, { value: {} })[PROP_METADATA]; |
| meta[name] = meta.hasOwnProperty(name) && meta[name] || []; |
| meta[name].unshift(decoratorInstance); |
| if (additionalProcessing) |
| additionalProcessing.apply(void 0, __spread([target, name], args)); |
| } |
| return PropDecorator; |
| } |
| if (parentClass) { |
| PropDecoratorFactory.prototype = Object.create(parentClass.prototype); |
| } |
| PropDecoratorFactory.prototype.ngMetadataName = name; |
| PropDecoratorFactory.annotationCls = PropDecoratorFactory; |
| return PropDecoratorFactory; |
| } |
| |
| /** |
| * @license |
| * Copyright Google Inc. All Rights Reserved. |
| * |
| * Use of this source code is governed by an MIT-style license that can be |
| * found in the LICENSE file at https://angular.io/license |
| */ |
| var ɵ0 = function (token) { return ({ token: token }); }; |
| /** |
| * Inject decorator and metadata. |
| * |
| * @Annotation |
| * @publicApi |
| */ |
| var Inject = makeParamDecorator('Inject', ɵ0); |
| /** |
| * Optional decorator and metadata. |
| * |
| * @Annotation |
| * @publicApi |
| */ |
| var Optional = makeParamDecorator('Optional'); |
| /** |
| * Self decorator and metadata. |
| * |
| * @Annotation |
| * @publicApi |
| */ |
| var Self = makeParamDecorator('Self'); |
| /** |
| * SkipSelf decorator and metadata. |
| * |
| * @Annotation |
| * @publicApi |
| */ |
| var SkipSelf = makeParamDecorator('SkipSelf'); |
| /** |
| * Host decorator and metadata. |
| * |
| * @Annotation |
| * @publicApi |
| */ |
| var Host = makeParamDecorator('Host'); |
| var ɵ1 = function (attributeName) { return ({ attributeName: attributeName }); }; |
| /** |
| * Attribute decorator and metadata. |
| * |
| * @Annotation |
| * @publicApi |
| */ |
| var Attribute = makeParamDecorator('Attribute', ɵ1); |
| |
| /** |
| * @license |
| * Copyright Google Inc. All Rights Reserved. |
| * |
| * Use of this source code is governed by an MIT-style license that can be |
| * found in the LICENSE file at https://angular.io/license |
| */ |
| (function (InjectFlags) { |
| // TODO(alxhub): make this 'const' when ngc no longer writes exports of it into ngfactory files. |
| /** Check self and check parent injector if needed */ |
| InjectFlags[InjectFlags["Default"] = 0] = "Default"; |
| /** |
| * Specifies that an injector should retrieve a dependency from any injector until reaching the |
| * host element of the current component. (Only used with Element Injector) |
| */ |
| InjectFlags[InjectFlags["Host"] = 1] = "Host"; |
| /** Don't ascend to ancestors of the node requesting injection. */ |
| InjectFlags[InjectFlags["Self"] = 2] = "Self"; |
| /** Skip the node that is requesting injection. */ |
| InjectFlags[InjectFlags["SkipSelf"] = 4] = "SkipSelf"; |
| /** Inject `defaultValue` instead if token not found. */ |
| InjectFlags[InjectFlags["Optional"] = 8] = "Optional"; |
| })(exports.InjectFlags || (exports.InjectFlags = {})); |
| |
| /** |
| * @license |
| * Copyright Google Inc. All Rights Reserved. |
| * |
| * Use of this source code is governed by an MIT-style license that can be |
| * found in the LICENSE file at https://angular.io/license |
| */ |
| function getClosureSafeProperty(objWithPropertyToExtract) { |
| for (var key in objWithPropertyToExtract) { |
| if (objWithPropertyToExtract[key] === getClosureSafeProperty) { |
| return key; |
| } |
| } |
| throw Error('Could not find renamed property on target object.'); |
| } |
| /** |
| * Sets properties on a target object from a source object, but only if |
| * the property doesn't already exist on the target object. |
| * @param target The target to set properties on |
| * @param source The source of the property keys and values to set |
| */ |
| function fillProperties(target, source) { |
| for (var key in source) { |
| if (source.hasOwnProperty(key) && !target.hasOwnProperty(key)) { |
| target[key] = source[key]; |
| } |
| } |
| } |
| |
| /** |
| * @license |
| * Copyright Google Inc. All Rights Reserved. |
| * |
| * Use of this source code is governed by an MIT-style license that can be |
| * found in the LICENSE file at https://angular.io/license |
| */ |
| /** |
| * Construct an `InjectableDef` which defines how a token will be constructed by the DI system, and |
| * in which injectors (if any) it will be available. |
| * |
| * This should be assigned to a static `ngInjectableDef` field on a type, which will then be an |
| * `InjectableType`. |
| * |
| * Options: |
| * * `providedIn` determines which injectors will include the injectable, by either associating it |
| * with an `@NgModule` or other `InjectorType`, or by specifying that this injectable should be |
| * provided in the `'root'` injector, which will be the application-level injector in most apps. |
| * * `factory` gives the zero argument function which will create an instance of the injectable. |
| * The factory can call `inject` to access the `Injector` and request injection of dependencies. |
| * |
| * @codeGenApi |
| */ |
| function ɵɵdefineInjectable(opts) { |
| return { |
| token: opts.token, providedIn: opts.providedIn || null, factory: opts.factory, |
| value: undefined, |
| }; |
| } |
| /** |
| * @deprecated in v8, delete after v10. This API should be used only be generated code, and that |
| * code should now use ɵɵdefineInjectable instead. |
| * @publicApi |
| */ |
| var defineInjectable = ɵɵdefineInjectable; |
| /** |
| * Construct an `InjectorDef` which configures an injector. |
| * |
| * This should be assigned to a static `ngInjectorDef` field on a type, which will then be an |
| * `InjectorType`. |
| * |
| * Options: |
| * |
| * * `factory`: an `InjectorType` is an instantiable type, so a zero argument `factory` function to |
| * create the type must be provided. If that factory function needs to inject arguments, it can |
| * use the `inject` function. |
| * * `providers`: an optional array of providers to add to the injector. Each provider must |
| * either have a factory or point to a type which has an `ngInjectableDef` static property (the |
| * type must be an `InjectableType`). |
| * * `imports`: an optional array of imports of other `InjectorType`s or `InjectorTypeWithModule`s |
| * whose providers will also be added to the injector. Locally provided types will override |
| * providers from imports. |
| * |
| * @publicApi |
| */ |
| function ɵɵdefineInjector(options) { |
| return { |
| factory: options.factory, providers: options.providers || [], imports: options.imports || [], |
| }; |
| } |
| /** |
| * Read the `ngInjectableDef` for `type` in a way which is immune to accidentally reading inherited |
| * value. |
| * |
| * @param type A type which may have its own (non-inherited) `ngInjectableDef`. |
| */ |
| function getInjectableDef(type) { |
| var def = type[NG_INJECTABLE_DEF]; |
| // The definition read above may come from a base class. `hasOwnProperty` is not sufficient to |
| // distinguish this case, as in older browsers (e.g. IE10) static property inheritance is |
| // implemented by copying the properties. |
| // |
| // Instead, the ngInjectableDef's token is compared to the type, and if they don't match then the |
| // property was not defined directly on the type itself, and was likely inherited. The definition |
| // is only returned if the type matches the def.token. |
| return def && def.token === type ? def : null; |
| } |
| /** |
| * Read the `ngInjectableDef` for `type` or read the `ngInjectableDef` from one of its ancestors. |
| * |
| * @param type A type which may have `ngInjectableDef`, via inheritance. |
| * |
| * @deprecated Will be removed in v10, where an error will occur in the scenario if we find the |
| * `ngInjectableDef` on an ancestor only. |
| */ |
| function getInheritedInjectableDef(type) { |
| if (type && type[NG_INJECTABLE_DEF]) { |
| // TODO(FW-1307): Re-add ngDevMode when closure can handle it |
| // ngDevMode && |
| console.warn("DEPRECATED: DI is instantiating a token \"" + type.name + "\" that inherits its @Injectable decorator but does not provide one itself.\n" + |
| ("This will become an error in v10. Please add @Injectable() to the \"" + type.name + "\" class.")); |
| return type[NG_INJECTABLE_DEF]; |
| } |
| else { |
| return null; |
| } |
| } |
| /** |
| * Read the `ngInjectorDef` type in a way which is immune to accidentally reading inherited value. |
| * |
| * @param type type which may have `ngInjectorDef` |
| */ |
| function getInjectorDef(type) { |
| return type && type.hasOwnProperty(NG_INJECTOR_DEF) ? type[NG_INJECTOR_DEF] : null; |
| } |
| var NG_INJECTABLE_DEF = getClosureSafeProperty({ ngInjectableDef: getClosureSafeProperty }); |
| var NG_INJECTOR_DEF = getClosureSafeProperty({ ngInjectorDef: getClosureSafeProperty }); |
| |
| /** |
| * @license |
| * Copyright Google Inc. All Rights Reserved. |
| * |
| * Use of this source code is governed by an MIT-style license that can be |
| * found in the LICENSE file at https://angular.io/license |
| */ |
| function stringify(token) { |
| if (typeof token === 'string') { |
| return token; |
| } |
| if (token instanceof Array) { |
| return '[' + token.map(stringify).join(', ') + ']'; |
| } |
| if (token == null) { |
| return '' + token; |
| } |
| if (token.overriddenName) { |
| return "" + token.overriddenName; |
| } |
| if (token.name) { |
| return "" + token.name; |
| } |
| var res = token.toString(); |
| if (res == null) { |
| return '' + res; |
| } |
| var newLineIndex = res.indexOf('\n'); |
| return newLineIndex === -1 ? res : res.substring(0, newLineIndex); |
| } |
| |
| /** |
| * @license |
| * Copyright Google Inc. All Rights Reserved. |
| * |
| * Use of this source code is governed by an MIT-style license that can be |
| * found in the LICENSE file at https://angular.io/license |
| */ |
| var __forward_ref__ = getClosureSafeProperty({ __forward_ref__: getClosureSafeProperty }); |
| /** |
| * Allows to refer to references which are not yet defined. |
| * |
| * For instance, `forwardRef` is used when the `token` which we need to refer to for the purposes of |
| * DI is declared, but not yet defined. It is also used when the `token` which we use when creating |
| * a query is not yet defined. |
| * |
| * @usageNotes |
| * ### Example |
| * {@example core/di/ts/forward_ref/forward_ref_spec.ts region='forward_ref'} |
| * @publicApi |
| */ |
| function forwardRef(forwardRefFn) { |
| forwardRefFn.__forward_ref__ = forwardRef; |
| forwardRefFn.toString = function () { return stringify(this()); }; |
| return forwardRefFn; |
| } |
| /** |
| * Lazily retrieves the reference value from a forwardRef. |
| * |
| * Acts as the identity function when given a non-forward-ref value. |
| * |
| * @usageNotes |
| * ### Example |
| * |
| * {@example core/di/ts/forward_ref/forward_ref_spec.ts region='resolve_forward_ref'} |
| * |
| * @see `forwardRef` |
| * @publicApi |
| */ |
| function resolveForwardRef(type) { |
| var fn = type; |
| if (typeof fn === 'function' && fn.hasOwnProperty(__forward_ref__) && |
| fn.__forward_ref__ === forwardRef) { |
| return fn(); |
| } |
| else { |
| return type; |
| } |
| } |
| |
| /** |
| * @license |
| * Copyright Google Inc. All Rights Reserved. |
| * |
| * Use of this source code is governed by an MIT-style license that can be |
| * found in the LICENSE file at https://angular.io/license |
| */ |
| var __globalThis = typeof globalThis !== 'undefined' && globalThis; |
| var __window = typeof window !== 'undefined' && window; |
| var __self = typeof self !== 'undefined' && typeof WorkerGlobalScope !== 'undefined' && |
| self instanceof WorkerGlobalScope && self; |
| var __global = typeof global !== 'undefined' && global; |
| // Always use __globalThis if available, which is the spec-defined global variable across all |
| // environments, then fallback to __global first, because in Node tests both __global and |
| // __window may be defined and _global should be __global in that case. |
| var _global = __globalThis || __global || __window || __self; |
| |
| /** |
| * @license |
| * Copyright Google Inc. All Rights Reserved. |
| * |
| * Use of this source code is governed by an MIT-style license that can be |
| * found in the LICENSE file at https://angular.io/license |
| */ |
| var R3ResolvedDependencyType; |
| (function (R3ResolvedDependencyType) { |
| R3ResolvedDependencyType[R3ResolvedDependencyType["Token"] = 0] = "Token"; |
| R3ResolvedDependencyType[R3ResolvedDependencyType["Attribute"] = 1] = "Attribute"; |
| })(R3ResolvedDependencyType || (R3ResolvedDependencyType = {})); |
| |
| /** |
| * @license |
| * Copyright Google Inc. All Rights Reserved. |
| * |
| * Use of this source code is governed by an MIT-style license that can be |
| * found in the LICENSE file at https://angular.io/license |
| */ |
| function getCompilerFacade() { |
| var globalNg = _global['ng']; |
| if (!globalNg || !globalNg.ɵcompilerFacade) { |
| throw new Error("Angular JIT compilation failed: '@angular/compiler' not loaded!\n" + |
| " - JIT compilation is discouraged for production use-cases! Consider AOT mode instead.\n" + |
| " - Did you bootstrap using '@angular/platform-browser-dynamic' or '@angular/platform-server'?\n" + |
| " - Alternatively provide the compiler with 'import \"@angular/compiler\";' before bootstrapping."); |
| } |
| return globalNg.ɵcompilerFacade; |
| } |
| |
| /** |
| * @license |
| * Copyright Google Inc. All Rights Reserved. |
| * |
| * Use of this source code is governed by an MIT-style license that can be |
| * found in the LICENSE file at https://angular.io/license |
| */ |
| /** |
| * Creates a token that can be used in a DI Provider. |
| * |
| * Use an `InjectionToken` whenever the type you are injecting is not reified (does not have a |
| * runtime representation) such as when injecting an interface, callable type, array or |
| * parameterized type. |
| * |
| * `InjectionToken` is parameterized on `T` which is the type of object which will be returned by |
| * the `Injector`. This provides additional level of type safety. |
| * |
| * ``` |
| * interface MyInterface {...} |
| * var myInterface = injector.get(new InjectionToken<MyInterface>('SomeToken')); |
| * // myInterface is inferred to be MyInterface. |
| * ``` |
| * |
| * When creating an `InjectionToken`, you can optionally specify a factory function which returns |
| * (possibly by creating) a default value of the parameterized type `T`. This sets up the |
| * `InjectionToken` using this factory as a provider as if it was defined explicitly in the |
| * application's root injector. If the factory function, which takes zero arguments, needs to inject |
| * dependencies, it can do so using the `inject` function. See below for an example. |
| * |
| * Additionally, if a `factory` is specified you can also specify the `providedIn` option, which |
| * overrides the above behavior and marks the token as belonging to a particular `@NgModule`. As |
| * mentioned above, `'root'` is the default value for `providedIn`. |
| * |
| * @usageNotes |
| * ### Basic Example |
| * |
| * ### Plain InjectionToken |
| * |
| * {@example core/di/ts/injector_spec.ts region='InjectionToken'} |
| * |
| * ### Tree-shakable InjectionToken |
| * |
| * {@example core/di/ts/injector_spec.ts region='ShakableInjectionToken'} |
| * |
| * |
| * @publicApi |
| */ |
| var InjectionToken = /** @class */ (function () { |
| function InjectionToken(_desc, options) { |
| this._desc = _desc; |
| /** @internal */ |
| this.ngMetadataName = 'InjectionToken'; |
| this.ngInjectableDef = undefined; |
| if (typeof options == 'number') { |
| // This is a special hack to assign __NG_ELEMENT_ID__ to this instance. |
| // __NG_ELEMENT_ID__ is Used by Ivy to determine bloom filter id. |
| // We are using it to assign `-1` which is used to identify `Injector`. |
| this.__NG_ELEMENT_ID__ = options; |
| } |
| else if (options !== undefined) { |
| this.ngInjectableDef = ɵɵdefineInjectable({ |
| token: this, |
| providedIn: options.providedIn || 'root', |
| factory: options.factory, |
| }); |
| } |
| } |
| InjectionToken.prototype.toString = function () { return "InjectionToken " + this._desc; }; |
| return InjectionToken; |
| }()); |
| |
| /** |
| * @license |
| * Copyright Google Inc. All Rights Reserved. |
| * |
| * Use of this source code is governed by an MIT-style license that can be |
| * found in the LICENSE file at https://angular.io/license |
| */ |
| /** |
| * An InjectionToken that gets the current `Injector` for `createInjector()`-style injectors. |
| * |
| * Requesting this token instead of `Injector` allows `StaticInjector` to be tree-shaken from a |
| * project. |
| * |
| * @publicApi |
| */ |
| var INJECTOR = new InjectionToken('INJECTOR', -1 // `-1` is used by Ivy DI system as special value to recognize it as `Injector`. |
| ); |
| var _THROW_IF_NOT_FOUND = new Object(); |
| var THROW_IF_NOT_FOUND = _THROW_IF_NOT_FOUND; |
| var NG_TEMP_TOKEN_PATH = 'ngTempTokenPath'; |
| var NG_TOKEN_PATH = 'ngTokenPath'; |
| var NEW_LINE = /\n/gm; |
| var NO_NEW_LINE = 'ɵ'; |
| var SOURCE = '__source'; |
| var ɵ0$1 = getClosureSafeProperty; |
| var USE_VALUE = getClosureSafeProperty({ provide: String, useValue: ɵ0$1 }); |
| /** |
| * Current injector value used by `inject`. |
| * - `undefined`: it is an error to call `inject` |
| * - `null`: `inject` can be called but there is no injector (limp-mode). |
| * - Injector instance: Use the injector for resolution. |
| */ |
| var _currentInjector = undefined; |
| function setCurrentInjector(injector) { |
| var former = _currentInjector; |
| _currentInjector = injector; |
| return former; |
| } |
| /** |
| * Current implementation of inject. |
| * |
| * By default, it is `injectInjectorOnly`, which makes it `Injector`-only aware. It can be changed |
| * to `directiveInject`, which brings in the `NodeInjector` system of ivy. It is designed this |
| * way for two reasons: |
| * 1. `Injector` should not depend on ivy logic. |
| * 2. To maintain tree shake-ability we don't want to bring in unnecessary code. |
| */ |
| var _injectImplementation; |
| /** |
| * Sets the current inject implementation. |
| */ |
| function setInjectImplementation(impl) { |
| var previous = _injectImplementation; |
| _injectImplementation = impl; |
| return previous; |
| } |
| function injectInjectorOnly(token, flags) { |
| if (flags === void 0) { flags = exports.InjectFlags.Default; } |
| if (_currentInjector === undefined) { |
| throw new Error("inject() must be called from an injection context"); |
| } |
| else if (_currentInjector === null) { |
| return injectRootLimpMode(token, undefined, flags); |
| } |
| else { |
| return _currentInjector.get(token, flags & exports.InjectFlags.Optional ? null : undefined, flags); |
| } |
| } |
| function ɵɵinject(token, flags) { |
| if (flags === void 0) { flags = exports.InjectFlags.Default; } |
| return (_injectImplementation || injectInjectorOnly)(token, flags); |
| } |
| /** |
| * Injects a token from the currently active injector. |
| * |
| * Must be used in the context of a factory function such as one defined for an |
| * `InjectionToken`. Throws an error if not called from such a context. |
| * |
| * Within such a factory function, using this function to request injection of a dependency |
| * is faster and more type-safe than providing an additional array of dependencies |
| * (as has been common with `useFactory` providers). |
| * |
| * @param token The injection token for the dependency to be injected. |
| * @param flags Optional flags that control how injection is executed. |
| * The flags correspond to injection strategies that can be specified with |
| * parameter decorators `@Host`, `@Self`, `@SkipSef`, and `@Optional`. |
| * @returns True if injection is successful, null otherwise. |
| * |
| * @usageNotes |
| * |
| * ### Example |
| * |
| * {@example core/di/ts/injector_spec.ts region='ShakableInjectionToken'} |
| * |
| * @publicApi |
| */ |
| var inject = ɵɵinject; |
| /** |
| * Injects `root` tokens in limp mode. |
| * |
| * If no injector exists, we can still inject tree-shakable providers which have `providedIn` set to |
| * `"root"`. This is known as the limp mode injection. In such case the value is stored in the |
| * `InjectableDef`. |
| */ |
| function injectRootLimpMode(token, notFoundValue, flags) { |
| var injectableDef = getInjectableDef(token); |
| if (injectableDef && injectableDef.providedIn == 'root') { |
| return injectableDef.value === undefined ? injectableDef.value = injectableDef.factory() : |
| injectableDef.value; |
| } |
| if (flags & exports.InjectFlags.Optional) |
| return null; |
| if (notFoundValue !== undefined) |
| return notFoundValue; |
| throw new Error("Injector: NOT_FOUND [" + stringify(token) + "]"); |
| } |
| function injectArgs(types) { |
| var args = []; |
| for (var i = 0; i < types.length; i++) { |
| var arg = resolveForwardRef(types[i]); |
| if (Array.isArray(arg)) { |
| if (arg.length === 0) { |
| throw new Error('Arguments array must have arguments.'); |
| } |
| var type = undefined; |
| var flags = exports.InjectFlags.Default; |
| for (var j = 0; j < arg.length; j++) { |
| var meta = arg[j]; |
| if (meta instanceof Optional || meta.ngMetadataName === 'Optional' || meta === Optional) { |
| flags |= exports.InjectFlags.Optional; |
| } |
| else if (meta instanceof SkipSelf || meta.ngMetadataName === 'SkipSelf' || meta === SkipSelf) { |
| flags |= exports.InjectFlags.SkipSelf; |
| } |
| else if (meta instanceof Self || meta.ngMetadataName === 'Self' || meta === Self) { |
| flags |= exports.InjectFlags.Self; |
| } |
| else if (meta instanceof Inject || meta === Inject) { |
| type = meta.token; |
| } |
| else { |
| type = meta; |
| } |
| } |
| args.push(ɵɵinject(type, flags)); |
| } |
| else { |
| args.push(ɵɵinject(arg)); |
| } |
| } |
| return args; |
| } |
| var NullInjector = /** @class */ (function () { |
| function NullInjector() { |
| } |
| NullInjector.prototype.get = function (token, notFoundValue) { |
| if (notFoundValue === void 0) { notFoundValue = THROW_IF_NOT_FOUND; } |
| if (notFoundValue === THROW_IF_NOT_FOUND) { |
| // Intentionally left behind: With dev tools open the debugger will stop here. There is no |
| // reason why correctly written application should cause this exception. |
| // TODO(misko): uncomment the next line once `ngDevMode` works with closure. |
| // if(ngDevMode) debugger; |
| var error = new Error("NullInjectorError: No provider for " + stringify(token) + "!"); |
| error.name = 'NullInjectorError'; |
| throw error; |
| } |
| return notFoundValue; |
| }; |
| return NullInjector; |
| }()); |
| function catchInjectorError(e, token, injectorErrorName, source) { |
| var tokenPath = e[NG_TEMP_TOKEN_PATH]; |
| if (token[SOURCE]) { |
| tokenPath.unshift(token[SOURCE]); |
| } |
| e.message = formatError('\n' + e.message, tokenPath, injectorErrorName, source); |
| e[NG_TOKEN_PATH] = tokenPath; |
| e[NG_TEMP_TOKEN_PATH] = null; |
| throw e; |
| } |
| function formatError(text, obj, injectorErrorName, source) { |
| if (source === void 0) { source = null; } |
| text = text && text.charAt(0) === '\n' && text.charAt(1) == NO_NEW_LINE ? text.substr(2) : text; |
| var context = stringify(obj); |
| if (obj instanceof Array) { |
| context = obj.map(stringify).join(' -> '); |
| } |
| else if (typeof obj === 'object') { |
| var parts = []; |
| for (var key in obj) { |
| if (obj.hasOwnProperty(key)) { |
| var value = obj[key]; |
| parts.push(key + ':' + (typeof value === 'string' ? JSON.stringify(value) : stringify(value))); |
| } |
| } |
| context = "{" + parts.join(', ') + "}"; |
| } |
| return "" + injectorErrorName + (source ? '(' + source + ')' : '') + "[" + context + "]: " + text.replace(NEW_LINE, '\n '); |
| } |
| |
| /** |
| * @license |
| * Copyright Google Inc. All Rights Reserved. |
| * |
| * Use of this source code is governed by an MIT-style license that can be |
| * found in the LICENSE file at https://angular.io/license |
| */ |
| /** |
| * A mapping of the @angular/core API surface used in generated expressions to the actual symbols. |
| * |
| * This should be kept up to date with the public exports of @angular/core. |
| */ |
| var angularCoreDiEnv = { |
| 'ɵɵdefineInjectable': ɵɵdefineInjectable, |
| 'ɵɵdefineInjector': ɵɵdefineInjector, |
| 'ɵɵinject': ɵɵinject, |
| 'ɵɵgetFactoryOf': getFactoryOf, |
| }; |
| function getFactoryOf(type) { |
| var typeAny = type; |
| var def = getInjectableDef(typeAny) || getInjectorDef(typeAny); |
| if (!def || def.factory === undefined) { |
| return null; |
| } |
| return def.factory; |
| } |
| |
| /** |
| * @license |
| * Copyright Google Inc. All Rights Reserved. |
| * |
| * Use of this source code is governed by an MIT-style license that can be |
| * found in the LICENSE file at https://angular.io/license |
| */ |
| /** |
| * @description |
| * |
| * Represents a type that a Component or other object is instances of. |
| * |
| * An example of a `Type` is `MyCustomComponent` class, which in JavaScript is be represented by |
| * the `MyCustomComponent` constructor function. |
| * |
| * @publicApi |
| */ |
| var Type = Function; |
| function isType(v) { |
| return typeof v === 'function'; |
| } |
| |
| /** |
| * @license |
| * Copyright Google Inc. All Rights Reserved. |
| * |
| * Use of this source code is governed by an MIT-style license that can be |
| * found in the LICENSE file at https://angular.io/license |
| */ |
| /** |
| * Attention: These regex has to hold even if the code is minified! |
| */ |
| var DELEGATE_CTOR = /^function\s+\S+\(\)\s*{[\s\S]+\.apply\(this,\s*arguments\)/; |
| var INHERITED_CLASS = /^class\s+[A-Za-z\d$_]*\s*extends\s+[^{]+{/; |
| var INHERITED_CLASS_WITH_CTOR = /^class\s+[A-Za-z\d$_]*\s*extends\s+[^{]+{[\s\S]*constructor\s*\(/; |
| var INHERITED_CLASS_WITH_DELEGATE_CTOR = /^class\s+[A-Za-z\d$_]*\s*extends\s+[^{]+{[\s\S]*constructor\s*\(\)\s*{\s+super\(\.\.\.arguments\)/; |
| /** |
| * Determine whether a stringified type is a class which delegates its constructor |
| * to its parent. |
| * |
| * This is not trivial since compiled code can actually contain a constructor function |
| * even if the original source code did not. For instance, when the child class contains |
| * an initialized instance property. |
| */ |
| function isDelegateCtor(typeStr) { |
| return DELEGATE_CTOR.test(typeStr) || INHERITED_CLASS_WITH_DELEGATE_CTOR.test(typeStr) || |
| (INHERITED_CLASS.test(typeStr) && !INHERITED_CLASS_WITH_CTOR.test(typeStr)); |
| } |
| var ReflectionCapabilities = /** @class */ (function () { |
| function ReflectionCapabilities(reflect) { |
| this._reflect = reflect || _global['Reflect']; |
| } |
| ReflectionCapabilities.prototype.isReflectionEnabled = function () { return true; }; |
| ReflectionCapabilities.prototype.factory = function (t) { return function () { |
| var args = []; |
| for (var _i = 0; _i < arguments.length; _i++) { |
| args[_i] = arguments[_i]; |
| } |
| return new (t.bind.apply(t, __spread([void 0], args)))(); |
| }; }; |
| /** @internal */ |
| ReflectionCapabilities.prototype._zipTypesAndAnnotations = function (paramTypes, paramAnnotations) { |
| var result; |
| if (typeof paramTypes === 'undefined') { |
| result = new Array(paramAnnotations.length); |
| } |
| else { |
| result = new Array(paramTypes.length); |
| } |
| for (var i = 0; i < result.length; i++) { |
| // TS outputs Object for parameters without types, while Traceur omits |
| // the annotations. For now we preserve the Traceur behavior to aid |
| // migration, but this can be revisited. |
| if (typeof paramTypes === 'undefined') { |
| result[i] = []; |
| } |
| else if (paramTypes[i] && paramTypes[i] != Object) { |
| result[i] = [paramTypes[i]]; |
| } |
| else { |
| result[i] = []; |
| } |
| if (paramAnnotations && paramAnnotations[i] != null) { |
| result[i] = result[i].concat(paramAnnotations[i]); |
| } |
| } |
| return result; |
| }; |
| ReflectionCapabilities.prototype._ownParameters = function (type, parentCtor) { |
| var typeStr = type.toString(); |
| // If we have no decorators, we only have function.length as metadata. |
| // In that case, to detect whether a child class declared an own constructor or not, |
| // we need to look inside of that constructor to check whether it is |
| // just calling the parent. |
| // This also helps to work around for https://github.com/Microsoft/TypeScript/issues/12439 |
| // that sets 'design:paramtypes' to [] |
| // if a class inherits from another class but has no ctor declared itself. |
| if (isDelegateCtor(typeStr)) { |
| return null; |
| } |
| // Prefer the direct API. |
| if (type.parameters && type.parameters !== parentCtor.parameters) { |
| return type.parameters; |
| } |
| // API of tsickle for lowering decorators to properties on the class. |
| var tsickleCtorParams = type.ctorParameters; |
| if (tsickleCtorParams && tsickleCtorParams !== parentCtor.ctorParameters) { |
| // Newer tsickle uses a function closure |
| // Retain the non-function case for compatibility with older tsickle |
| var ctorParameters = typeof tsickleCtorParams === 'function' ? tsickleCtorParams() : tsickleCtorParams; |
| var paramTypes_1 = ctorParameters.map(function (ctorParam) { return ctorParam && ctorParam.type; }); |
| var paramAnnotations_1 = ctorParameters.map(function (ctorParam) { |
| return ctorParam && convertTsickleDecoratorIntoMetadata(ctorParam.decorators); |
| }); |
| return this._zipTypesAndAnnotations(paramTypes_1, paramAnnotations_1); |
| } |
| // API for metadata created by invoking the decorators. |
| var paramAnnotations = type.hasOwnProperty(PARAMETERS) && type[PARAMETERS]; |
| var paramTypes = this._reflect && this._reflect.getOwnMetadata && |
| this._reflect.getOwnMetadata('design:paramtypes', type); |
| if (paramTypes || paramAnnotations) { |
| return this._zipTypesAndAnnotations(paramTypes, paramAnnotations); |
| } |
| // If a class has no decorators, at least create metadata |
| // based on function.length. |
| // Note: We know that this is a real constructor as we checked |
| // the content of the constructor above. |
| return new Array(type.length).fill(undefined); |
| }; |
| ReflectionCapabilities.prototype.parameters = function (type) { |
| // Note: only report metadata if we have at least one class decorator |
| // to stay in sync with the static reflector. |
| if (!isType(type)) { |
| return []; |
| } |
| var parentCtor = getParentCtor(type); |
| var parameters = this._ownParameters(type, parentCtor); |
| if (!parameters && parentCtor !== Object) { |
| parameters = this.parameters(parentCtor); |
| } |
| return parameters || []; |
| }; |
| ReflectionCapabilities.prototype._ownAnnotations = function (typeOrFunc, parentCtor) { |
| // Prefer the direct API. |
| if (typeOrFunc.annotations && typeOrFunc.annotations !== parentCtor.annotations) { |
| var annotations = typeOrFunc.annotations; |
| if (typeof annotations === 'function' && annotations.annotations) { |
| annotations = annotations.annotations; |
| } |
| return annotations; |
| } |
| // API of tsickle for lowering decorators to properties on the class. |
| if (typeOrFunc.decorators && typeOrFunc.decorators !== parentCtor.decorators) { |
| return convertTsickleDecoratorIntoMetadata(typeOrFunc.decorators); |
| } |
| // API for metadata created by invoking the decorators. |
| if (typeOrFunc.hasOwnProperty(ANNOTATIONS)) { |
| return typeOrFunc[ANNOTATIONS]; |
| } |
| return null; |
| }; |
| ReflectionCapabilities.prototype.annotations = function (typeOrFunc) { |
| if (!isType(typeOrFunc)) { |
| return []; |
| } |
| var parentCtor = getParentCtor(typeOrFunc); |
| var ownAnnotations = this._ownAnnotations(typeOrFunc, parentCtor) || []; |
| var parentAnnotations = parentCtor !== Object ? this.annotations(parentCtor) : []; |
| return parentAnnotations.concat(ownAnnotations); |
| }; |
| ReflectionCapabilities.prototype._ownPropMetadata = function (typeOrFunc, parentCtor) { |
| // Prefer the direct API. |
| if (typeOrFunc.propMetadata && |
| typeOrFunc.propMetadata !== parentCtor.propMetadata) { |
| var propMetadata = typeOrFunc.propMetadata; |
| if (typeof propMetadata === 'function' && propMetadata.propMetadata) { |
| propMetadata = propMetadata.propMetadata; |
| } |
| return propMetadata; |
| } |
| // API of tsickle for lowering decorators to properties on the class. |
| if (typeOrFunc.propDecorators && |
| typeOrFunc.propDecorators !== parentCtor.propDecorators) { |
| var propDecorators_1 = typeOrFunc.propDecorators; |
| var propMetadata_1 = {}; |
| Object.keys(propDecorators_1).forEach(function (prop) { |
| propMetadata_1[prop] = convertTsickleDecoratorIntoMetadata(propDecorators_1[prop]); |
| }); |
| return propMetadata_1; |
| } |
| // API for metadata created by invoking the decorators. |
| if (typeOrFunc.hasOwnProperty(PROP_METADATA)) { |
| return typeOrFunc[PROP_METADATA]; |
| } |
| return null; |
| }; |
| ReflectionCapabilities.prototype.propMetadata = function (typeOrFunc) { |
| if (!isType(typeOrFunc)) { |
| return {}; |
| } |
| var parentCtor = getParentCtor(typeOrFunc); |
| var propMetadata = {}; |
| if (parentCtor !== Object) { |
| var parentPropMetadata_1 = this.propMetadata(parentCtor); |
| Object.keys(parentPropMetadata_1).forEach(function (propName) { |
| propMetadata[propName] = parentPropMetadata_1[propName]; |
| }); |
| } |
| var ownPropMetadata = this._ownPropMetadata(typeOrFunc, parentCtor); |
| if (ownPropMetadata) { |
| Object.keys(ownPropMetadata).forEach(function (propName) { |
| var decorators = []; |
| if (propMetadata.hasOwnProperty(propName)) { |
| decorators.push.apply(decorators, __spread(propMetadata[propName])); |
| } |
| decorators.push.apply(decorators, __spread(ownPropMetadata[propName])); |
| propMetadata[propName] = decorators; |
| }); |
| } |
| return propMetadata; |
| }; |
| ReflectionCapabilities.prototype.ownPropMetadata = function (typeOrFunc) { |
| if (!isType(typeOrFunc)) { |
| return {}; |
| } |
| return this._ownPropMetadata(typeOrFunc, getParentCtor(typeOrFunc)) || {}; |
| }; |
| ReflectionCapabilities.prototype.hasLifecycleHook = function (type, lcProperty) { |
| return type instanceof Type && lcProperty in type.prototype; |
| }; |
| ReflectionCapabilities.prototype.guards = function (type) { return {}; }; |
| ReflectionCapabilities.prototype.getter = function (name) { return new Function('o', 'return o.' + name + ';'); }; |
| ReflectionCapabilities.prototype.setter = function (name) { |
| return new Function('o', 'v', 'return o.' + name + ' = v;'); |
| }; |
| ReflectionCapabilities.prototype.method = function (name) { |
| var functionBody = "if (!o." + name + ") throw new Error('\"" + name + "\" is undefined');\n return o." + name + ".apply(o, args);"; |
| return new Function('o', 'args', functionBody); |
| }; |
| // There is not a concept of import uri in Js, but this is useful in developing Dart applications. |
| ReflectionCapabilities.prototype.importUri = function (type) { |
| // StaticSymbol |
| if (typeof type === 'object' && type['filePath']) { |
| return type['filePath']; |
| } |
| // Runtime type |
| return "./" + stringify(type); |
| }; |
| ReflectionCapabilities.prototype.resourceUri = function (type) { return "./" + stringify(type); }; |
| ReflectionCapabilities.prototype.resolveIdentifier = function (name, moduleUrl, members, runtime) { |
| return runtime; |
| }; |
| ReflectionCapabilities.prototype.resolveEnum = function (enumIdentifier, name) { return enumIdentifier[name]; }; |
| return ReflectionCapabilities; |
| }()); |
| function convertTsickleDecoratorIntoMetadata(decoratorInvocations) { |
| if (!decoratorInvocations) { |
| return []; |
| } |
| return decoratorInvocations.map(function (decoratorInvocation) { |
| var decoratorType = decoratorInvocation.type; |
| var annotationCls = decoratorType.annotationCls; |
| var annotationArgs = decoratorInvocation.args ? decoratorInvocation.args : []; |
| return new (annotationCls.bind.apply(annotationCls, __spread([void 0], annotationArgs)))(); |
| }); |
| } |
| function getParentCtor(ctor) { |
| var parentProto = ctor.prototype ? Object.getPrototypeOf(ctor.prototype) : null; |
| var parentCtor = parentProto ? parentProto.constructor : null; |
| // Note: We always use `Object` as the null value |
| // to simplify checking later on. |
| return parentCtor || Object; |
| } |
| |
| /** |
| * @license |
| * Copyright Google Inc. All Rights Reserved. |
| * |
| * Use of this source code is governed by an MIT-style license that can be |
| * found in the LICENSE file at https://angular.io/license |
| */ |
| var _reflect = null; |
| function getReflect() { |
| return (_reflect = _reflect || new ReflectionCapabilities()); |
| } |
| function reflectDependencies(type) { |
| return convertDependencies(getReflect().parameters(type)); |
| } |
| function convertDependencies(deps) { |
| var compiler = getCompilerFacade(); |
| return deps.map(function (dep) { return reflectDependency(compiler, dep); }); |
| } |
| function reflectDependency(compiler, dep) { |
| var meta = { |
| token: null, |
| host: false, |
| optional: false, |
| resolved: compiler.R3ResolvedDependencyType.Token, |
| self: false, |
| skipSelf: false, |
| }; |
| function setTokenAndResolvedType(token) { |
| meta.resolved = compiler.R3ResolvedDependencyType.Token; |
| meta.token = token; |
| } |
| if (Array.isArray(dep)) { |
| if (dep.length === 0) { |
| throw new Error('Dependency array must have arguments.'); |
| } |
| for (var j = 0; j < dep.length; j++) { |
| var param = dep[j]; |
| if (param === undefined) { |
| // param may be undefined if type of dep is not set by ngtsc |
| continue; |
| } |
| else if (param instanceof Optional || param.__proto__.ngMetadataName === 'Optional') { |
| meta.optional = true; |
| } |
| else if (param instanceof SkipSelf || param.__proto__.ngMetadataName === 'SkipSelf') { |
| meta.skipSelf = true; |
| } |
| else if (param instanceof Self || param.__proto__.ngMetadataName === 'Self') { |
| meta.self = true; |
| } |
| else if (param instanceof Host || param.__proto__.ngMetadataName === 'Host') { |
| meta.host = true; |
| } |
| else if (param instanceof Inject) { |
| meta.token = param.token; |
| } |
| else if (param instanceof Attribute) { |
| if (param.attributeName === undefined) { |
| throw new Error("Attribute name must be defined."); |
| } |
| meta.token = param.attributeName; |
| meta.resolved = compiler.R3ResolvedDependencyType.Attribute; |
| } |
| else { |
| setTokenAndResolvedType(param); |
| } |
| } |
| } |
| else { |
| setTokenAndResolvedType(dep); |
| } |
| return meta; |
| } |
| |
| /** |
| * @license |
| * Copyright Google Inc. All Rights Reserved. |
| * |
| * Use of this source code is governed by an MIT-style license that can be |
| * found in the LICENSE file at https://angular.io/license |
| */ |
| /** |
| * Compile an Angular injectable according to its `Injectable` metadata, and patch the resulting |
| * `ngInjectableDef` onto the injectable type. |
| */ |
| function compileInjectable(type, srcMeta) { |
| var def = null; |
| // if NG_INJECTABLE_DEF is already defined on this class then don't overwrite it |
| if (type.hasOwnProperty(NG_INJECTABLE_DEF)) |
| return; |
| Object.defineProperty(type, NG_INJECTABLE_DEF, { |
| get: function () { |
| if (def === null) { |
| // Allow the compilation of a class with a `@Injectable()` decorator without parameters |
| var meta = srcMeta || { providedIn: null }; |
| var hasAProvider = isUseClassProvider(meta) || isUseFactoryProvider(meta) || |
| isUseValueProvider(meta) || isUseExistingProvider(meta); |
| var compilerMeta = { |
| name: type.name, |
| type: type, |
| typeArgumentCount: 0, |
| providedIn: meta.providedIn, |
| ctorDeps: reflectDependencies(type), |
| userDeps: undefined, |
| }; |
| if ((isUseClassProvider(meta) || isUseFactoryProvider(meta)) && meta.deps !== undefined) { |
| compilerMeta.userDeps = convertDependencies(meta.deps); |
| } |
| if (!hasAProvider) { |
| // In the case the user specifies a type provider, treat it as {provide: X, useClass: X}. |
| // The deps will have been reflected above, causing the factory to create the class by |
| // calling |
| // its constructor with injected deps. |
| compilerMeta.useClass = type; |
| } |
| else if (isUseClassProvider(meta)) { |
| // The user explicitly specified useClass, and may or may not have provided deps. |
| compilerMeta.useClass = meta.useClass; |
| } |
| else if (isUseValueProvider(meta)) { |
| // The user explicitly specified useValue. |
| compilerMeta.useValue = meta.useValue; |
| } |
| else if (isUseFactoryProvider(meta)) { |
| // The user explicitly specified useFactory. |
| compilerMeta.useFactory = meta.useFactory; |
| } |
| else if (isUseExistingProvider(meta)) { |
| // The user explicitly specified useExisting. |
| compilerMeta.useExisting = meta.useExisting; |
| } |
| else { |
| // Can't happen - either hasAProvider will be false, or one of the providers will be set. |
| throw new Error("Unreachable state."); |
| } |
| def = getCompilerFacade().compileInjectable(angularCoreDiEnv, "ng:///" + type.name + "/ngInjectableDef.js", compilerMeta); |
| } |
| return def; |
| }, |
| }); |
| } |
| var ɵ0$2 = getClosureSafeProperty; |
| var USE_VALUE$1 = getClosureSafeProperty({ provide: String, useValue: ɵ0$2 }); |
| function isUseClassProvider(meta) { |
| return meta.useClass !== undefined; |
| } |
| function isUseValueProvider(meta) { |
| return USE_VALUE$1 in meta; |
| } |
| function isUseFactoryProvider(meta) { |
| return meta.useFactory !== undefined; |
| } |
| function isUseExistingProvider(meta) { |
| return meta.useExisting !== undefined; |
| } |
| |
| /** |
| * @license |
| * Copyright Google Inc. All Rights Reserved. |
| * |
| * Use of this source code is governed by an MIT-style license that can be |
| * found in the LICENSE file at https://angular.io/license |
| */ |
| var ɵ0$3 = getClosureSafeProperty; |
| var USE_VALUE$2 = getClosureSafeProperty({ provide: String, useValue: ɵ0$3 }); |
| var EMPTY_ARRAY = []; |
| function convertInjectableProviderToFactory(type, provider) { |
| if (!provider) { |
| var reflectionCapabilities = new ReflectionCapabilities(); |
| var deps_1 = reflectionCapabilities.parameters(type); |
| // TODO - convert to flags. |
| return function () { return new (type.bind.apply(type, __spread([void 0], injectArgs(deps_1))))(); }; |
| } |
| if (USE_VALUE$2 in provider) { |
| var valueProvider_1 = provider; |
| return function () { return valueProvider_1.useValue; }; |
| } |
| else if (provider.useExisting) { |
| var existingProvider_1 = provider; |
| return function () { return ɵɵinject(existingProvider_1.useExisting); }; |
| } |
| else if (provider.useFactory) { |
| var factoryProvider_1 = provider; |
| return function () { return factoryProvider_1.useFactory.apply(factoryProvider_1, __spread(injectArgs(factoryProvider_1.deps || EMPTY_ARRAY))); }; |
| } |
| else if (provider.useClass) { |
| var classProvider_1 = provider; |
| var deps_2 = provider.deps; |
| if (!deps_2) { |
| var reflectionCapabilities = new ReflectionCapabilities(); |
| deps_2 = reflectionCapabilities.parameters(type); |
| } |
| return function () { |
| var _a; |
| return new ((_a = classProvider_1.useClass).bind.apply(_a, __spread([void 0], injectArgs(deps_2))))(); |
| }; |
| } |
| else { |
| var deps_3 = provider.deps; |
| if (!deps_3) { |
| var reflectionCapabilities = new ReflectionCapabilities(); |
| deps_3 = reflectionCapabilities.parameters(type); |
| } |
| return function () { return new (type.bind.apply(type, __spread([void 0], injectArgs(deps_3))))(); }; |
| } |
| } |
| |
| /** |
| * @license |
| * Copyright Google Inc. All Rights Reserved. |
| * |
| * Use of this source code is governed by an MIT-style license that can be |
| * found in the LICENSE file at https://angular.io/license |
| */ |
| var ɵ0$4 = function (type, meta) { return SWITCH_COMPILE_INJECTABLE(type, meta); }; |
| /** |
| * Injectable decorator and metadata. |
| * |
| * @Annotation |
| * @publicApi |
| */ |
| var Injectable = makeDecorator('Injectable', undefined, undefined, undefined, ɵ0$4); |
| /** |
| * Supports @Injectable() in JIT mode for Render2. |
| */ |
| function render2CompileInjectable(injectableType, options) { |
| if (options && options.providedIn !== undefined && !getInjectableDef(injectableType)) { |
| injectableType.ngInjectableDef = ɵɵdefineInjectable({ |
| token: injectableType, |
| providedIn: options.providedIn, |
| factory: convertInjectableProviderToFactory(injectableType, options), |
| }); |
| } |
| } |
| var SWITCH_COMPILE_INJECTABLE__POST_R3__ = compileInjectable; |
| var SWITCH_COMPILE_INJECTABLE__PRE_R3__ = render2CompileInjectable; |
| var SWITCH_COMPILE_INJECTABLE = SWITCH_COMPILE_INJECTABLE__PRE_R3__; |
| |
| /** |
| * @license |
| * Copyright Google Inc. All Rights Reserved. |
| * |
| * Use of this source code is governed by an MIT-style license that can be |
| * found in the LICENSE file at https://angular.io/license |
| */ |
| function ngDevModeResetPerfCounters() { |
| var locationString = typeof location !== 'undefined' ? location.toString() : ''; |
| var newCounters = { |
| namedConstructors: locationString.indexOf('ngDevMode=namedConstructors') != -1, |
| firstTemplatePass: 0, |
| tNode: 0, |
| tView: 0, |
| rendererCreateTextNode: 0, |
| rendererSetText: 0, |
| rendererCreateElement: 0, |
| rendererAddEventListener: 0, |
| rendererSetAttribute: 0, |
| rendererRemoveAttribute: 0, |
| rendererSetProperty: 0, |
| rendererSetClassName: 0, |
| rendererAddClass: 0, |
| rendererRemoveClass: 0, |
| rendererSetStyle: 0, |
| rendererRemoveStyle: 0, |
| rendererDestroy: 0, |
| rendererDestroyNode: 0, |
| rendererMoveNode: 0, |
| rendererRemoveNode: 0, |
| rendererAppendChild: 0, |
| rendererInsertBefore: 0, |
| rendererCreateComment: 0, |
| styleMap: 0, |
| styleMapCacheMiss: 0, |
| classMap: 0, |
| classMapCacheMiss: 0, |
| stylingProp: 0, |
| stylingPropCacheMiss: 0, |
| stylingApply: 0, |
| stylingApplyCacheMiss: 0, |
| }; |
| // Make sure to refer to ngDevMode as ['ngDevMode'] for closure. |
| var allowNgDevModeTrue = locationString.indexOf('ngDevMode=false') === -1; |
| _global['ngDevMode'] = allowNgDevModeTrue && newCounters; |
| return newCounters; |
| } |
| /** |
| * This checks to see if the `ngDevMode` has been set. If yes, |
| * then we honor it, otherwise we default to dev mode with additional checks. |
| * |
| * The idea is that unless we are doing production build where we explicitly |
| * set `ngDevMode == false` we should be helping the developer by providing |
| * as much early warning and errors as possible. |
| * |
| * NOTE: changes to the `ngDevMode` name must be synced with `compiler-cli/src/tooling.ts`. |
| */ |
| if (typeof ngDevMode === 'undefined' || ngDevMode) { |
| ngDevModeResetPerfCounters(); |
| } |
| |
| /** Called when directives inject each other (creating a circular dependency) */ |
| function throwCyclicDependencyError(token) { |
| throw new Error("Cannot instantiate cyclic dependency! " + token); |
| } |
| /** Called when there are multiple component selectors that match a given node */ |
| function throwMultipleComponentError(tNode) { |
| throw new Error("Multiple components match node with tagname " + tNode.tagName); |
| } |
| /** Throws an ExpressionChangedAfterChecked error if checkNoChanges mode is on. */ |
| function throwErrorIfNoChangesMode(creationMode, oldValue, currValue) { |
| var msg = "ExpressionChangedAfterItHasBeenCheckedError: Expression has changed after it was checked. Previous value: '" + oldValue + "'. Current value: '" + currValue + "'."; |
| if (creationMode) { |
| msg += |
| " It seems like the view has been created after its parent and its children have been dirty checked." + |
| " Has it been created in a change detection hook ?"; |
| } |
| // TODO: include debug context |
| throw new Error(msg); |
| } |
| function throwMixedMultiProviderError() { |
| throw new Error("Cannot mix multi providers and regular providers"); |
| } |
| function throwInvalidProviderError(ngModuleType, providers, provider) { |
| var ngModuleDetail = ''; |
| if (ngModuleType && providers) { |
| var providerDetail = providers.map(function (v) { return v == provider ? '?' + provider + '?' : '...'; }); |
| ngModuleDetail = |
| " - only instances of Provider and Type are allowed, got: [" + providerDetail.join(', ') + "]"; |
| } |
| throw new Error("Invalid provider for the NgModule '" + stringify(ngModuleType) + "'" + ngModuleDetail); |
| } |
| |
| /** |
| * @license |
| * Copyright Google Inc. All Rights Reserved. |
| * |
| * Use of this source code is governed by an MIT-style license that can be |
| * found in the LICENSE file at https://angular.io/license |
| */ |
| /** |
| * An internal token whose presence in an injector indicates that the injector should treat itself |
| * as a root scoped injector when processing requests for unknown tokens which may indicate |
| * they are provided in the root scope. |
| */ |
| var APP_ROOT = new InjectionToken('The presence of this token marks an injector as being the root injector.'); |
| |
| /** |
| * @license |
| * Copyright Google Inc. All Rights Reserved. |
| * |
| * Use of this source code is governed by an MIT-style license that can be |
| * found in the LICENSE file at https://angular.io/license |
| */ |
| /** |
| * Marker which indicates that a value has not yet been created from the factory function. |
| */ |
| var NOT_YET = {}; |
| /** |
| * Marker which indicates that the factory function for a token is in the process of being called. |
| * |
| * If the injector is asked to inject a token with its value set to CIRCULAR, that indicates |
| * injection of a dependency has recursively attempted to inject the original token, and there is |
| * a circular dependency among the providers. |
| */ |
| var CIRCULAR = {}; |
| var EMPTY_ARRAY$1 = []; |
| /** |
| * A lazily initialized NullInjector. |
| */ |
| var NULL_INJECTOR = undefined; |
| function getNullInjector() { |
| if (NULL_INJECTOR === undefined) { |
| NULL_INJECTOR = new NullInjector(); |
| } |
| return NULL_INJECTOR; |
| } |
| /** |
| * Create a new `Injector` which is configured using a `defType` of `InjectorType<any>`s. |
| * |
| * @publicApi |
| */ |
| function createInjector(defType, parent, additionalProviders, name) { |
| if (parent === void 0) { parent = null; } |
| if (additionalProviders === void 0) { additionalProviders = null; } |
| parent = parent || getNullInjector(); |
| return new R3Injector(defType, additionalProviders, parent, name); |
| } |
| var R3Injector = /** @class */ (function () { |
| function R3Injector(def, additionalProviders, parent, source) { |
| var _this = this; |
| if (source === void 0) { source = null; } |
| this.parent = parent; |
| /** |
| * Map of tokens to records which contain the instances of those tokens. |
| */ |
| this.records = new Map(); |
| /** |
| * The transitive set of `InjectorType`s which define this injector. |
| */ |
| this.injectorDefTypes = new Set(); |
| /** |
| * Set of values instantiated by this injector which contain `ngOnDestroy` lifecycle hooks. |
| */ |
| this.onDestroy = new Set(); |
| this._destroyed = false; |
| // Start off by creating Records for every provider declared in every InjectorType |
| // included transitively in `def`. |
| var dedupStack = []; |
| deepForEach([def], function (injectorDef) { return _this.processInjectorType(injectorDef, [], dedupStack); }); |
| additionalProviders && deepForEach(additionalProviders, function (provider) { return _this.processProvider(provider, def, additionalProviders); }); |
| // Make sure the INJECTOR token provides this injector. |
| this.records.set(INJECTOR, makeRecord(undefined, this)); |
| // Detect whether this injector has the APP_ROOT_SCOPE token and thus should provide |
| // any injectable scoped to APP_ROOT_SCOPE. |
| this.isRootInjector = this.records.has(APP_ROOT); |
| // Eagerly instantiate the InjectorType classes themselves. |
| this.injectorDefTypes.forEach(function (defType) { return _this.get(defType); }); |
| // Source name, used for debugging |
| this.source = source || (typeof def === 'object' ? null : stringify(def)); |
| } |
| Object.defineProperty(R3Injector.prototype, "destroyed", { |
| /** |
| * Flag indicating that this injector was previously destroyed. |
| */ |
| get: function () { return this._destroyed; }, |
| enumerable: true, |
| configurable: true |
| }); |
| /** |
| * Destroy the injector and release references to every instance or provider associated with it. |
| * |
| * Also calls the `OnDestroy` lifecycle hooks of every instance that was created for which a |
| * hook was found. |
| */ |
| R3Injector.prototype.destroy = function () { |
| this.assertNotDestroyed(); |
| // Set destroyed = true first, in case lifecycle hooks re-enter destroy(). |
| this._destroyed = true; |
| try { |
| // Call all the lifecycle hooks. |
| this.onDestroy.forEach(function (service) { return service.ngOnDestroy(); }); |
| } |
| finally { |
| // Release all references. |
| this.records.clear(); |
| this.onDestroy.clear(); |
| this.injectorDefTypes.clear(); |
| } |
| }; |
| R3Injector.prototype.get = function (token, notFoundValue, flags) { |
| if (notFoundValue === void 0) { notFoundValue = THROW_IF_NOT_FOUND; } |
| if (flags === void 0) { flags = exports.InjectFlags.Default; } |
| this.assertNotDestroyed(); |
| // Set the injection context. |
| var previousInjector = setCurrentInjector(this); |
| try { |
| // Check for the SkipSelf flag. |
| if (!(flags & exports.InjectFlags.SkipSelf)) { |
| // SkipSelf isn't set, check if the record belongs to this injector. |
| var record = this.records.get(token); |
| if (record === undefined) { |
| // No record, but maybe the token is scoped to this injector. Look for an ngInjectableDef |
| // with a scope matching this injector. |
| var def = couldBeInjectableType(token) && getInjectableDef(token); |
| if (def && this.injectableDefInScope(def)) { |
| // Found an ngInjectableDef and it's scoped to this injector. Pretend as if it was here |
| // all along. |
| record = makeRecord(injectableDefOrInjectorDefFactory(token), NOT_YET); |
| this.records.set(token, record); |
| } |
| } |
| // If a record was found, get the instance for it and return it. |
| if (record !== undefined) { |
| return this.hydrate(token, record); |
| } |
| } |
| // Select the next injector based on the Self flag - if self is set, the next injector is |
| // the NullInjector, otherwise it's the parent. |
| var nextInjector = !(flags & exports.InjectFlags.Self) ? this.parent : getNullInjector(); |
| return nextInjector.get(token, flags & exports.InjectFlags.Optional ? null : notFoundValue); |
| } |
| catch (e) { |
| if (e.name === 'NullInjectorError') { |
| var path = e[NG_TEMP_TOKEN_PATH] = e[NG_TEMP_TOKEN_PATH] || []; |
| path.unshift(stringify(token)); |
| if (previousInjector) { |
| // We still have a parent injector, keep throwing |
| throw e; |
| } |
| else { |
| // Format & throw the final error message when we don't have any previous injector |
| return catchInjectorError(e, token, 'R3InjectorError', this.source); |
| } |
| } |
| else { |
| throw e; |
| } |
| } |
| finally { |
| // Lastly, clean up the state by restoring the previous injector. |
| setCurrentInjector(previousInjector); |
| } |
| }; |
| R3Injector.prototype.toString = function () { |
| var tokens = [], records = this.records; |
| records.forEach(function (v, token) { return tokens.push(stringify(token)); }); |
| return "R3Injector[" + tokens.join(', ') + "]"; |
| }; |
| R3Injector.prototype.assertNotDestroyed = function () { |
| if (this._destroyed) { |
| throw new Error('Injector has already been destroyed.'); |
| } |
| }; |
| /** |
| * Add an `InjectorType` or `InjectorTypeWithProviders` and all of its transitive providers |
| * to this injector. |
| * |
| * If an `InjectorTypeWithProviders` that declares providers besides the type is specified, |
| * the function will return "true" to indicate that the providers of the type definition need |
| * to be processed. This allows us to process providers of injector types after all imports of |
| * an injector definition are processed. (following View Engine semantics: see FW-1349) |
| */ |
| R3Injector.prototype.processInjectorType = function (defOrWrappedDef, parents, dedupStack) { |
| var _this = this; |
| defOrWrappedDef = resolveForwardRef(defOrWrappedDef); |
| if (!defOrWrappedDef) |
| return false; |
| // Either the defOrWrappedDef is an InjectorType (with ngInjectorDef) or an |
| // InjectorDefTypeWithProviders (aka ModuleWithProviders). Detecting either is a megamorphic |
| // read, so care is taken to only do the read once. |
| // First attempt to read the ngInjectorDef. |
| var def = getInjectorDef(defOrWrappedDef); |
| // If that's not present, then attempt to read ngModule from the InjectorDefTypeWithProviders. |
| var ngModule = (def == null) && defOrWrappedDef.ngModule || undefined; |
| // Determine the InjectorType. In the case where `defOrWrappedDef` is an `InjectorType`, |
| // then this is easy. In the case of an InjectorDefTypeWithProviders, then the definition type |
| // is the `ngModule`. |
| var defType = (ngModule === undefined) ? defOrWrappedDef : ngModule; |
| // Check for circular dependencies. |
| if (ngDevMode && parents.indexOf(defType) !== -1) { |
| var defName = stringify(defType); |
| throw new Error("Circular dependency in DI detected for type " + defName + ". Dependency path: " + parents.map(function (defType) { return stringify(defType); }).join(' > ') + " > " + defName + "."); |
| } |
| // Check for multiple imports of the same module |
| var isDuplicate = dedupStack.indexOf(defType) !== -1; |
| // Finally, if defOrWrappedType was an `InjectorDefTypeWithProviders`, then the actual |
| // `InjectorDef` is on its `ngModule`. |
| if (ngModule !== undefined) { |
| def = getInjectorDef(ngModule); |
| } |
| // If no definition was found, it might be from exports. Remove it. |
| if (def == null) { |
| return false; |
| } |
| // Track the InjectorType and add a provider for it. |
| this.injectorDefTypes.add(defType); |
| this.records.set(defType, makeRecord(def.factory, NOT_YET)); |
| // Add providers in the same way that @NgModule resolution did: |
| // First, include providers from any imports. |
| if (def.imports != null && !isDuplicate) { |
| // Before processing defType's imports, add it to the set of parents. This way, if it ends |
| // up deeply importing itself, this can be detected. |
| ngDevMode && parents.push(defType); |
| // Add it to the set of dedups. This way we can detect multiple imports of the same module |
| dedupStack.push(defType); |
| var importTypesWithProviders_1; |
| try { |
| deepForEach(def.imports, function (imported) { |
| if (_this.processInjectorType(imported, parents, dedupStack)) { |
| if (importTypesWithProviders_1 === undefined) |
| importTypesWithProviders_1 = []; |
| // If the processed import is an injector type with providers, we store it in the |
| // list of import types with providers, so that we can process those afterwards. |
| importTypesWithProviders_1.push(imported); |
| } |
| }); |
| } |
| finally { |
| // Remove it from the parents set when finished. |
| ngDevMode && parents.pop(); |
| } |
| // Imports which are declared with providers (TypeWithProviders) need to be processed |
| // after all imported modules are processed. This is similar to how View Engine |
| // processes/merges module imports in the metadata resolver. See: FW-1349. |
| if (importTypesWithProviders_1 !== undefined) { |
| var _loop_1 = function (i) { |
| var _a = importTypesWithProviders_1[i], ngModule_1 = _a.ngModule, providers = _a.providers; |
| deepForEach(providers, function (provider) { return _this.processProvider(provider, ngModule_1, providers || EMPTY_ARRAY$1); }); |
| }; |
| for (var i = 0; i < importTypesWithProviders_1.length; i++) { |
| _loop_1(i); |
| } |
| } |
| } |
| // Next, include providers listed on the definition itself. |
| var defProviders = def.providers; |
| if (defProviders != null && !isDuplicate) { |
| var injectorType_1 = defOrWrappedDef; |
| deepForEach(defProviders, function (provider) { return _this.processProvider(provider, injectorType_1, defProviders); }); |
| } |
| return (ngModule !== undefined && |
| defOrWrappedDef.providers !== undefined); |
| }; |
| /** |
| * Process a `SingleProvider` and add it. |
| */ |
| R3Injector.prototype.processProvider = function (provider, ngModuleType, providers) { |
| // Determine the token from the provider. Either it's its own token, or has a {provide: ...} |
| // property. |
| provider = resolveForwardRef(provider); |
| var token = isTypeProvider(provider) ? provider : resolveForwardRef(provider && provider.provide); |
| // Construct a `Record` for the provider. |
| var record = providerToRecord(provider, ngModuleType, providers); |
| if (!isTypeProvider(provider) && provider.multi === true) { |
| // If the provider indicates that it's a multi-provider, process it specially. |
| // First check whether it's been defined already. |
| var multiRecord_1 = this.records.get(token); |
| if (multiRecord_1) { |
| // It has. Throw a nice error if |
| if (multiRecord_1.multi === undefined) { |
| throwMixedMultiProviderError(); |
| } |
| } |
| else { |
| multiRecord_1 = makeRecord(undefined, NOT_YET, true); |
| multiRecord_1.factory = function () { return injectArgs(multiRecord_1.multi); }; |
| this.records.set(token, multiRecord_1); |
| } |
| token = provider; |
| multiRecord_1.multi.push(provider); |
| } |
| else { |
| var existing = this.records.get(token); |
| if (existing && existing.multi !== undefined) { |
| throwMixedMultiProviderError(); |
| } |
| } |
| this.records.set(token, record); |
| }; |
| R3Injector.prototype.hydrate = function (token, record) { |
| if (record.value === CIRCULAR) { |
| throwCyclicDependencyError(stringify(token)); |
| } |
| else if (record.value === NOT_YET) { |
| record.value = CIRCULAR; |
| record.value = record.factory(); |
| } |
| if (typeof record.value === 'object' && record.value && hasOnDestroy(record.value)) { |
| this.onDestroy.add(record.value); |
| } |
| return record.value; |
| }; |
| R3Injector.prototype.injectableDefInScope = function (def) { |
| if (!def.providedIn) { |
| return false; |
| } |
| else if (typeof def.providedIn === 'string') { |
| return def.providedIn === 'any' || (def.providedIn === 'root' && this.isRootInjector); |
| } |
| else { |
| return this.injectorDefTypes.has(def.providedIn); |
| } |
| }; |
| return R3Injector; |
| }()); |
| function injectableDefOrInjectorDefFactory(token) { |
| // Most tokens will have an ngInjectableDef directly on them, which specifies a factory directly. |
| var injectableDef = getInjectableDef(token); |
| if (injectableDef !== null) { |
| return injectableDef.factory; |
| } |
| // If the token is an NgModule, it's also injectable but the factory is on its ngInjectorDef. |
| var injectorDef = getInjectorDef(token); |
| if (injectorDef !== null) { |
| return injectorDef.factory; |
| } |
| // InjectionTokens should have an ngInjectableDef and thus should be handled above. |
| // If it's missing that, it's an error. |
| if (token instanceof InjectionToken) { |
| throw new Error("Token " + stringify(token) + " is missing an ngInjectableDef definition."); |
| } |
| // Undecorated types can sometimes be created if they have no constructor arguments. |
| if (token instanceof Function) { |
| return getUndecoratedInjectableFactory(token); |
| } |
| // There was no way to resolve a factory for this token. |
| throw new Error('unreachable'); |
| } |
| function getUndecoratedInjectableFactory(token) { |
| // If the token has parameters then it has dependencies that we cannot resolve implicitly. |
| var paramLength = token.length; |
| if (paramLength > 0) { |
| var args = new Array(paramLength).fill('?'); |
| throw new Error("Can't resolve all parameters for " + stringify(token) + ": (" + args.join(', ') + ")."); |
| } |
| // The constructor function appears to have no parameters. |
| // This might be because it inherits from a super-class. In which case, use an ngInjectableDef |
| // from an ancestor if there is one. |
| // Otherwise this really is a simple class with no dependencies, so return a factory that |
| // just instantiates the zero-arg constructor. |
| var inheritedInjectableDef = getInheritedInjectableDef(token); |
| if (inheritedInjectableDef !== null) { |
| return function () { return inheritedInjectableDef.factory(token); }; |
| } |
| else { |
| return function () { return new token(); }; |
| } |
| } |
| function providerToRecord(provider, ngModuleType, providers) { |
| var factory = providerToFactory(provider, ngModuleType, providers); |
| if (isValueProvider(provider)) { |
| return makeRecord(undefined, provider.useValue); |
| } |
| else { |
| return makeRecord(factory, NOT_YET); |
| } |
| } |
| /** |
| * Converts a `SingleProvider` into a factory function. |
| * |
| * @param provider provider to convert to factory |
| */ |
| function providerToFactory(provider, ngModuleType, providers) { |
| var factory = undefined; |
| if (isTypeProvider(provider)) { |
| return injectableDefOrInjectorDefFactory(resolveForwardRef(provider)); |
| } |
| else { |
| if (isValueProvider(provider)) { |
| factory = function () { return resolveForwardRef(provider.useValue); }; |
| } |
| else if (isExistingProvider(provider)) { |
| factory = function () { return ɵɵinject(resolveForwardRef(provider.useExisting)); }; |
| } |
| else if (isFactoryProvider(provider)) { |
| factory = function () { return provider.useFactory.apply(provider, __spread(injectArgs(provider.deps || []))); }; |
| } |
| else { |
| var classRef_1 = resolveForwardRef(provider && |
| (provider.useClass || provider.provide)); |
| if (!classRef_1) { |
| throwInvalidProviderError(ngModuleType, providers, provider); |
| } |
| if (hasDeps(provider)) { |
| factory = function () { return new ((classRef_1).bind.apply((classRef_1), __spread([void 0], injectArgs(provider.deps))))(); }; |
| } |
| else { |
| return injectableDefOrInjectorDefFactory(classRef_1); |
| } |
| } |
| } |
| return factory; |
| } |
| function makeRecord(factory, value, multi) { |
| if (multi === void 0) { multi = false; } |
| return { |
| factory: factory, |
| value: value, |
| multi: multi ? [] : undefined, |
| }; |
| } |
| function deepForEach(input, fn) { |
| input.forEach(function (value) { return Array.isArray(value) ? deepForEach(value, fn) : fn(value); }); |
| } |
| function isValueProvider(value) { |
| return value !== null && typeof value == 'object' && USE_VALUE in value; |
| } |
| function isExistingProvider(value) { |
| return !!(value && value.useExisting); |
| } |
| function isFactoryProvider(value) { |
| return !!(value && value.useFactory); |
| } |
| function isTypeProvider(value) { |
| return typeof value === 'function'; |
| } |
| function isClassProvider(value) { |
| return !!value.useClass; |
| } |
| function hasDeps(value) { |
| return !!value.deps; |
| } |
| function hasOnDestroy(value) { |
| return value !== null && typeof value === 'object' && |
| typeof value.ngOnDestroy === 'function'; |
| } |
| function couldBeInjectableType(value) { |
| return (typeof value === 'function') || |
| (typeof value === 'object' && value instanceof InjectionToken); |
| } |
| |
| /** |
| * @license |
| * Copyright Google Inc. All Rights Reserved. |
| * |
| * Use of this source code is governed by an MIT-style license that can be |
| * found in the LICENSE file at https://angular.io/license |
| */ |
| function INJECTOR_IMPL__PRE_R3__(providers, parent, name) { |
| return new StaticInjector(providers, parent, name); |
| } |
| function INJECTOR_IMPL__POST_R3__(providers, parent, name) { |
| return createInjector({ name: name }, parent, providers, name); |
| } |
| var INJECTOR_IMPL = INJECTOR_IMPL__PRE_R3__; |
| /** |
| * Concrete injectors implement this interface. |
| * |
| * For more details, see the ["Dependency Injection Guide"](guide/dependency-injection). |
| * |
| * @usageNotes |
| * ### Example |
| * |
| * {@example core/di/ts/injector_spec.ts region='Injector'} |
| * |
| * `Injector` returns itself when given `Injector` as a token: |
| * |
| * {@example core/di/ts/injector_spec.ts region='injectInjector'} |
| * |
| * @publicApi |
| */ |
| var Injector = /** @class */ (function () { |
| function Injector() { |
| } |
| /** |
| * Create a new Injector which is configure using `StaticProvider`s. |
| * |
| * @usageNotes |
| * ### Example |
| * |
| * {@example core/di/ts/provider_spec.ts region='ConstructorProvider'} |
| */ |
| Injector.create = function (options, parent) { |
| if (Array.isArray(options)) { |
| return INJECTOR_IMPL(options, parent, ''); |
| } |
| else { |
| return INJECTOR_IMPL(options.providers, options.parent, options.name || ''); |
| } |
| }; |
| Injector.THROW_IF_NOT_FOUND = THROW_IF_NOT_FOUND; |
| Injector.NULL = new NullInjector(); |
| /** @nocollapse */ |
| Injector.ngInjectableDef = ɵɵdefineInjectable({ |
| token: Injector, |
| providedIn: 'any', |
| factory: function () { return ɵɵinject(INJECTOR); }, |
| }); |
| /** |
| * @internal |
| * @nocollapse |
| */ |
| Injector.__NG_ELEMENT_ID__ = -1; |
| return Injector; |
| }()); |
| var IDENT = function (value) { |
| return value; |
| }; |
| var EMPTY = []; |
| var CIRCULAR$1 = IDENT; |
| var MULTI_PROVIDER_FN = function () { |
| return Array.prototype.slice.call(arguments); |
| }; |
| var NO_NEW_LINE$1 = 'ɵ'; |
| var StaticInjector = /** @class */ (function () { |
| function StaticInjector(providers, parent, source) { |
| if (parent === void 0) { parent = Injector.NULL; } |
| if (source === void 0) { source = null; } |
| this.parent = parent; |
| this.source = source; |
| var records = this._records = new Map(); |
| records.set(Injector, { token: Injector, fn: IDENT, deps: EMPTY, value: this, useNew: false }); |
| records.set(INJECTOR, { token: INJECTOR, fn: IDENT, deps: EMPTY, value: this, useNew: false }); |
| recursivelyProcessProviders(records, providers); |
| } |
| StaticInjector.prototype.get = function (token, notFoundValue, flags) { |
| if (flags === void 0) { flags = exports.InjectFlags.Default; } |
| var record = this._records.get(token); |
| try { |
| return tryResolveToken(token, record, this._records, this.parent, notFoundValue, flags); |
| } |
| catch (e) { |
| return catchInjectorError(e, token, 'StaticInjectorError', this.source); |
| } |
| }; |
| StaticInjector.prototype.toString = function () { |
| var tokens = [], records = this._records; |
| records.forEach(function (v, token) { return tokens.push(stringify(token)); }); |
| return "StaticInjector[" + tokens.join(', ') + "]"; |
| }; |
| return StaticInjector; |
| }()); |
| function resolveProvider(provider) { |
| var deps = computeDeps(provider); |
| var fn = IDENT; |
| var value = EMPTY; |
| var useNew = false; |
| var provide = resolveForwardRef(provider.provide); |
| if (USE_VALUE in provider) { |
| // We need to use USE_VALUE in provider since provider.useValue could be defined as undefined. |
| value = provider.useValue; |
| } |
| else if (provider.useFactory) { |
| fn = provider.useFactory; |
| } |
| else if (provider.useExisting) ; |
| else if (provider.useClass) { |
| useNew = true; |
| fn = resolveForwardRef(provider.useClass); |
| } |
| else if (typeof provide == 'function') { |
| useNew = true; |
| fn = provide; |
| } |
| else { |
| throw staticError('StaticProvider does not have [useValue|useFactory|useExisting|useClass] or [provide] is not newable', provider); |
| } |
| return { deps: deps, fn: fn, useNew: useNew, value: value }; |
| } |
| function multiProviderMixError(token) { |
| return staticError('Cannot mix multi providers and regular providers', token); |
| } |
| function recursivelyProcessProviders(records, provider) { |
| if (provider) { |
| provider = resolveForwardRef(provider); |
| if (provider instanceof Array) { |
| // if we have an array recurse into the array |
| for (var i = 0; i < provider.length; i++) { |
| recursivelyProcessProviders(records, provider[i]); |
| } |
| } |
| else if (typeof provider === 'function') { |
| // Functions were supported in ReflectiveInjector, but are not here. For safety give useful |
| // error messages |
| throw staticError('Function/Class not supported', provider); |
| } |
| else if (provider && typeof provider === 'object' && provider.provide) { |
| // At this point we have what looks like a provider: {provide: ?, ....} |
| var token = resolveForwardRef(provider.provide); |
| var resolvedProvider = resolveProvider(provider); |
| if (provider.multi === true) { |
| // This is a multi provider. |
| var multiProvider = records.get(token); |
| if (multiProvider) { |
| if (multiProvider.fn !== MULTI_PROVIDER_FN) { |
| throw multiProviderMixError(token); |
| } |
| } |
| else { |
| // Create a placeholder factory which will look up the constituents of the multi provider. |
| records.set(token, multiProvider = { |
| token: provider.provide, |
| deps: [], |
| useNew: false, |
| fn: MULTI_PROVIDER_FN, |
| value: EMPTY |
| }); |
| } |
| // Treat the provider as the token. |
| token = provider; |
| multiProvider.deps.push({ token: token, options: 6 /* Default */ }); |
| } |
| var record = records.get(token); |
| if (record && record.fn == MULTI_PROVIDER_FN) { |
| throw multiProviderMixError(token); |
| } |
| records.set(token, resolvedProvider); |
| } |
| else { |
| throw staticError('Unexpected provider', provider); |
| } |
| } |
| } |
| function tryResolveToken(token, record, records, parent, notFoundValue, flags) { |
| try { |
| return resolveToken(token, record, records, parent, notFoundValue, flags); |
| } |
| catch (e) { |
| // ensure that 'e' is of type Error. |
| if (!(e instanceof Error)) { |
| e = new Error(e); |
| } |
| var path = e[NG_TEMP_TOKEN_PATH] = e[NG_TEMP_TOKEN_PATH] || []; |
| path.unshift(token); |
| if (record && record.value == CIRCULAR$1) { |
| // Reset the Circular flag. |
| record.value = EMPTY; |
| } |
| throw e; |
| } |
| } |
| function resolveToken(token, record, records, parent, notFoundValue, flags) { |
| var _a; |
| var value; |
| if (record && !(flags & exports.InjectFlags.SkipSelf)) { |
| // If we don't have a record, this implies that we don't own the provider hence don't know how |
| // to resolve it. |
| value = record.value; |
| if (value == CIRCULAR$1) { |
| throw Error(NO_NEW_LINE$1 + 'Circular dependency'); |
| } |
| else if (value === EMPTY) { |
| record.value = CIRCULAR$1; |
| var obj = undefined; |
| var useNew = record.useNew; |
| var fn = record.fn; |
| var depRecords = record.deps; |
| var deps = EMPTY; |
| if (depRecords.length) { |
| deps = []; |
| for (var i = 0; i < depRecords.length; i++) { |
| var depRecord = depRecords[i]; |
| var options = depRecord.options; |
| var childRecord = options & 2 /* CheckSelf */ ? records.get(depRecord.token) : undefined; |
| deps.push(tryResolveToken( |
| // Current Token to resolve |
| depRecord.token, |
| // A record which describes how to resolve the token. |
| // If undefined, this means we don't have such a record |
| childRecord, |
| // Other records we know about. |
| records, |
| // If we don't know how to resolve dependency and we should not check parent for it, |
| // than pass in Null injector. |
| !childRecord && !(options & 4 /* CheckParent */) ? Injector.NULL : parent, options & 1 /* Optional */ ? null : Injector.THROW_IF_NOT_FOUND, exports.InjectFlags.Default)); |
| } |
| } |
| record.value = value = useNew ? new ((_a = fn).bind.apply(_a, __spread([void 0], deps)))() : fn.apply(obj, deps); |
| } |
| } |
| else if (!(flags & exports.InjectFlags.Self)) { |
| value = parent.get(token, notFoundValue, exports.InjectFlags.Default); |
| } |
| return value; |
| } |
| function computeDeps(provider) { |
| var deps = EMPTY; |
| var providerDeps = provider.deps; |
| if (providerDeps && providerDeps.length) { |
| deps = []; |
| for (var i = 0; i < providerDeps.length; i++) { |
| var options = 6 /* Default */; |
| var token = resolveForwardRef(providerDeps[i]); |
| if (token instanceof Array) { |
| for (var j = 0, annotations = token; j < annotations.length; j++) { |
| var annotation = annotations[j]; |
| if (annotation instanceof Optional || annotation == Optional) { |
| options = options | 1 /* Optional */; |
| } |
| else if (annotation instanceof SkipSelf || annotation == SkipSelf) { |
| options = options & ~2 /* CheckSelf */; |
| } |
| else if (annotation instanceof Self || annotation == Self) { |
| options = options & ~4 /* CheckParent */; |
| } |
| else if (annotation instanceof Inject) { |
| token = annotation.token; |
| } |
| else { |
| token = resolveForwardRef(annotation); |
| } |
| } |
| } |
| deps.push({ token: token, options: options }); |
| } |
| } |
| else if (provider.useExisting) { |
| var token = resolveForwardRef(provider.useExisting); |
| deps = [{ token: token, options: 6 /* Default */ }]; |
| } |
| else if (!providerDeps && !(USE_VALUE in provider)) { |
| // useValue & useExisting are the only ones which are exempt from deps all others need it. |
| throw staticError('\'deps\' required', provider); |
| } |
| return deps; |
| } |
| function staticError(text, obj) { |
| return new Error(formatError(text, obj, 'StaticInjectorError')); |
| } |
| |
| /** |
| * @license |
| * Copyright Google Inc. All Rights Reserved. |
| * |
| * Use of this source code is governed by an MIT-style license that can be |
| * found in the LICENSE file at https://angular.io/license |
| */ |
| var ERROR_DEBUG_CONTEXT = 'ngDebugContext'; |
| var ERROR_ORIGINAL_ERROR = 'ngOriginalError'; |
| var ERROR_LOGGER = 'ngErrorLogger'; |
| function wrappedError(message, originalError) { |
| var msg = message + " caused by: " + (originalError instanceof Error ? originalError.message : originalError); |
| var error = Error(msg); |
| error[ERROR_ORIGINAL_ERROR] = originalError; |
| return error; |
| } |
| |
| /** |
| * @license |
| * Copyright Google Inc. All Rights Reserved. |
| * |
| * Use of this source code is governed by an MIT-style license that can be |
| * found in the LICENSE file at https://angular.io/license |
| */ |
| function findFirstClosedCycle(keys) { |
| var res = []; |
| for (var i = 0; i < keys.length; ++i) { |
| if (res.indexOf(keys[i]) > -1) { |
| res.push(keys[i]); |
| return res; |
| } |
| res.push(keys[i]); |
| } |
| return res; |
| } |
| function constructResolvingPath(keys) { |
| if (keys.length > 1) { |
| var reversed = findFirstClosedCycle(keys.slice().reverse()); |
| var tokenStrs = reversed.map(function (k) { return stringify(k.token); }); |
| return ' (' + tokenStrs.join(' -> ') + ')'; |
| } |
| return ''; |
| } |
| function injectionError(injector, key, constructResolvingMessage, originalError) { |
| var keys = [key]; |
| var errMsg = constructResolvingMessage(keys); |
| var error = (originalError ? wrappedError(errMsg, originalError) : Error(errMsg)); |
| error.addKey = addKey; |
| error.keys = keys; |
| error.injectors = [injector]; |
| error.constructResolvingMessage = constructResolvingMessage; |
| error[ERROR_ORIGINAL_ERROR] = originalError; |
| return error; |
| } |
| function addKey(injector, key) { |
| this.injectors.push(injector); |
| this.keys.push(key); |
| // Note: This updated message won't be reflected in the `.stack` property |
| this.message = this.constructResolvingMessage(this.keys); |
| } |
| /** |
| * Thrown when trying to retrieve a dependency by key from {@link Injector}, but the |
| * {@link Injector} does not have a {@link Provider} for the given key. |
| * |
| * @usageNotes |
| * ### Example |
| * |
| * ```typescript |
| * class A { |
| * constructor(b:B) {} |
| * } |
| * |
| * expect(() => Injector.resolveAndCreate([A])).toThrowError(); |
| * ``` |
| */ |
| function noProviderError(injector, key) { |
| return injectionError(injector, key, function (keys) { |
| var first = stringify(keys[0].token); |
| return "No provider for " + first + "!" + constructResolvingPath(keys); |
| }); |
| } |
| /** |
| * Thrown when dependencies form a cycle. |
| * |
| * @usageNotes |
| * ### Example |
| * |
| * ```typescript |
| * var injector = Injector.resolveAndCreate([ |
| * {provide: "one", useFactory: (two) => "two", deps: [[new Inject("two")]]}, |
| * {provide: "two", useFactory: (one) => "one", deps: [[new Inject("one")]]} |
| * ]); |
| * |
| * expect(() => injector.get("one")).toThrowError(); |
| * ``` |
| * |
| * Retrieving `A` or `B` throws a `CyclicDependencyError` as the graph above cannot be constructed. |
| */ |
| function cyclicDependencyError(injector, key) { |
| return injectionError(injector, key, function (keys) { |
| return "Cannot instantiate cyclic dependency!" + constructResolvingPath(keys); |
| }); |
| } |
| /** |
| * Thrown when a constructing type returns with an Error. |
| * |
| * The `InstantiationError` class contains the original error plus the dependency graph which caused |
| * this object to be instantiated. |
| * |
| * @usageNotes |
| * ### Example |
| * |
| * ```typescript |
| * class A { |
| * constructor() { |
| * throw new Error('message'); |
| * } |
| * } |
| * |
| * var injector = Injector.resolveAndCreate([A]); |
| |
| * try { |
| * injector.get(A); |
| * } catch (e) { |
| * expect(e instanceof InstantiationError).toBe(true); |
| * expect(e.originalException.message).toEqual("message"); |
| * expect(e.originalStack).toBeDefined(); |
| * } |
| * ``` |
| */ |
| function instantiationError(injector, originalException, originalStack, key) { |
| return injectionError(injector, key, function (keys) { |
| var first = stringify(keys[0].token); |
| return originalException.message + ": Error during instantiation of " + first + "!" + constructResolvingPath(keys) + "."; |
| }, originalException); |
| } |
| /** |
| * Thrown when an object other then {@link Provider} (or `Type`) is passed to {@link Injector} |
| * creation. |
| * |
| * @usageNotes |
| * ### Example |
| * |
| * ```typescript |
| * expect(() => Injector.resolveAndCreate(["not a type"])).toThrowError(); |
| * ``` |
| */ |
| function invalidProviderError(provider) { |
| return Error("Invalid provider - only instances of Provider and Type are allowed, got: " + provider); |
| } |
| /** |
| * Thrown when the class has no annotation information. |
| * |
| * Lack of annotation information prevents the {@link Injector} from determining which dependencies |
| * need to be injected into the constructor. |
| * |
| * @usageNotes |
| * ### Example |
| * |
| * ```typescript |
| * class A { |
| * constructor(b) {} |
| * } |
| * |
| * expect(() => Injector.resolveAndCreate([A])).toThrowError(); |
| * ``` |
| * |
| * This error is also thrown when the class not marked with {@link Injectable} has parameter types. |
| * |
| * ```typescript |
| * class B {} |
| * |
| * class A { |
| * constructor(b:B) {} // no information about the parameter types of A is available at runtime. |
| * } |
| * |
| * expect(() => Injector.resolveAndCreate([A,B])).toThrowError(); |
| * ``` |
| * |
| */ |
| function noAnnotationError(typeOrFunc, params) { |
| var signature = []; |
| for (var i = 0, ii = params.length; i < ii; i++) { |
| var parameter = params[i]; |
| if (!parameter || parameter.length == 0) { |
| signature.push('?'); |
| } |
| else { |
| signature.push(parameter.map(stringify).join(' ')); |
| } |
| } |
| return Error('Cannot resolve all parameters for \'' + stringify(typeOrFunc) + '\'(' + |
| signature.join(', ') + '). ' + |
| 'Make sure that all the parameters are decorated with Inject or have valid type annotations and that \'' + |
| stringify(typeOrFunc) + '\' is decorated with Injectable.'); |
| } |
| /** |
| * Thrown when getting an object by index. |
| * |
| * @usageNotes |
| * ### Example |
| * |
| * ```typescript |
| * class A {} |
| * |
| * var injector = Injector.resolveAndCreate([A]); |
| * |
| * expect(() => injector.getAt(100)).toThrowError(); |
| * ``` |
| * |
| */ |
| function outOfBoundsError(index) { |
| return Error("Index " + index + " is out-of-bounds."); |
| } |
| // TODO: add a working example after alpha38 is released |
| /** |
| * Thrown when a multi provider and a regular provider are bound to the same token. |
| * |
| * @usageNotes |
| * ### Example |
| * |
| * ```typescript |
| * expect(() => Injector.resolveAndCreate([ |
| * { provide: "Strings", useValue: "string1", multi: true}, |
| * { provide: "Strings", useValue: "string2", multi: false} |
| * ])).toThrowError(); |
| * ``` |
| */ |
| function mixingMultiProvidersWithRegularProvidersError(provider1, provider2) { |
| return Error("Cannot mix multi providers and regular providers, got: " + provider1 + " " + provider2); |
| } |
| |
| /** |
| * @license |
| * Copyright Google Inc. All Rights Reserved. |
| * |
| * Use of this source code is governed by an MIT-style license that can be |
| * found in the LICENSE file at https://angular.io/license |
| */ |
| /** |
| * A unique object used for retrieving items from the {@link ReflectiveInjector}. |
| * |
| * Keys have: |
| * - a system-wide unique `id`. |
| * - a `token`. |
| * |
| * `Key` is used internally by {@link ReflectiveInjector} because its system-wide unique `id` allows |
| * the |
| * injector to store created objects in a more efficient way. |
| * |
| * `Key` should not be created directly. {@link ReflectiveInjector} creates keys automatically when |
| * resolving |
| * providers. |
| * |
| * @deprecated No replacement |
| * @publicApi |
| */ |
| var ReflectiveKey = /** @class */ (function () { |
| /** |
| * Private |
| */ |
| function ReflectiveKey(token, id) { |
| this.token = token; |
| this.id = id; |
| if (!token) { |
| throw new Error('Token must be defined!'); |
| } |
| this.displayName = stringify(this.token); |
| } |
| /** |
| * Retrieves a `Key` for a token. |
| */ |
| ReflectiveKey.get = function (token) { |
| return _globalKeyRegistry.get(resolveForwardRef(token)); |
| }; |
| Object.defineProperty(ReflectiveKey, "numberOfKeys", { |
| /** |
| * @returns the number of keys registered in the system. |
| */ |
| get: function () { return _globalKeyRegistry.numberOfKeys; }, |
| enumerable: true, |
| configurable: true |
| }); |
| return ReflectiveKey; |
| }()); |
| var KeyRegistry = /** @class */ (function () { |
| function KeyRegistry() { |
| this._allKeys = new Map(); |
| } |
| KeyRegistry.prototype.get = function (token) { |
| if (token instanceof ReflectiveKey) |
| return token; |
| if (this._allKeys.has(token)) { |
| return this._allKeys.get(token); |
| } |
| var newKey = new ReflectiveKey(token, ReflectiveKey.numberOfKeys); |
| this._allKeys.set(token, newKey); |
| return newKey; |
| }; |
| Object.defineProperty(KeyRegistry.prototype, "numberOfKeys", { |
| get: function () { return this._allKeys.size; }, |
| enumerable: true, |
| configurable: true |
| }); |
| return KeyRegistry; |
| }()); |
| var _globalKeyRegistry = new KeyRegistry(); |
| |
| /** |
| * @license |
| * Copyright Google Inc. All Rights Reserved. |
| * |
| * Use of this source code is governed by an MIT-style license that can be |
| * found in the LICENSE file at https://angular.io/license |
| */ |
| /** |
| * Provides access to reflection data about symbols. Used internally by Angular |
| * to power dependency injection and compilation. |
| */ |
| var Reflector = /** @class */ (function () { |
| function Reflector(reflectionCapabilities) { |
| this.reflectionCapabilities = reflectionCapabilities; |
| } |
| Reflector.prototype.updateCapabilities = function (caps) { this.reflectionCapabilities = caps; }; |
| Reflector.prototype.factory = function (type) { return this.reflectionCapabilities.factory(type); }; |
| Reflector.prototype.parameters = function (typeOrFunc) { |
| return this.reflectionCapabilities.parameters(typeOrFunc); |
| }; |
| Reflector.prototype.annotations = function (typeOrFunc) { |
| return this.reflectionCapabilities.annotations(typeOrFunc); |
| }; |
| Reflector.prototype.propMetadata = function (typeOrFunc) { |
| return this.reflectionCapabilities.propMetadata(typeOrFunc); |
| }; |
| Reflector.prototype.hasLifecycleHook = function (type, lcProperty) { |
| return this.reflectionCapabilities.hasLifecycleHook(type, lcProperty); |
| }; |
| Reflector.prototype.getter = function (name) { return this.reflectionCapabilities.getter(name); }; |
| Reflector.prototype.setter = function (name) { return this.reflectionCapabilities.setter(name); }; |
| Reflector.prototype.method = function (name) { return this.reflectionCapabilities.method(name); }; |
| Reflector.prototype.importUri = function (type) { return this.reflectionCapabilities.importUri(type); }; |
| Reflector.prototype.resourceUri = function (type) { return this.reflectionCapabilities.resourceUri(type); }; |
| Reflector.prototype.resolveIdentifier = function (name, moduleUrl, members, runtime) { |
| return this.reflectionCapabilities.resolveIdentifier(name, moduleUrl, members, runtime); |
| }; |
| Reflector.prototype.resolveEnum = function (identifier, name) { |
| return this.reflectionCapabilities.resolveEnum(identifier, name); |
| }; |
| return Reflector; |
| }()); |
| |
| /** |
| * @license |
| * Copyright Google Inc. All Rights Reserved. |
| * |
| * Use of this source code is governed by an MIT-style license that can be |
| * found in the LICENSE file at https://angular.io/license |
| */ |
| /** |
| * The {@link Reflector} used internally in Angular to access metadata |
| * about symbols. |
| */ |
| var reflector = new Reflector(new ReflectionCapabilities()); |
| |
| /** |
| * @license |
| * Copyright Google Inc. All Rights Reserved. |
| * |
| * Use of this source code is governed by an MIT-style license that can be |
| * found in the LICENSE file at https://angular.io/license |
| */ |
| /** |
| * `Dependency` is used by the framework to extend DI. |
| * This is internal to Angular and should not be used directly. |
| */ |
| var ReflectiveDependency = /** @class */ (function () { |
| function ReflectiveDependency(key, optional, visibility) { |
| this.key = key; |
| this.optional = optional; |
| this.visibility = visibility; |
| } |
| ReflectiveDependency.fromKey = function (key) { |
| return new ReflectiveDependency(key, false, null); |
| }; |
| return ReflectiveDependency; |
| }()); |
| var _EMPTY_LIST = []; |
| var ResolvedReflectiveProvider_ = /** @class */ (function () { |
| function ResolvedReflectiveProvider_(key, resolvedFactories, multiProvider) { |
| this.key = key; |
| this.resolvedFactories = resolvedFactories; |
| this.multiProvider = multiProvider; |
| this.resolvedFactory = this.resolvedFactories[0]; |
| } |
| return ResolvedReflectiveProvider_; |
| }()); |
| /** |
| * An internal resolved representation of a factory function created by resolving `Provider`. |
| * @publicApi |
| */ |
| var ResolvedReflectiveFactory = /** @class */ (function () { |
| function ResolvedReflectiveFactory( |
| /** |
| * Factory function which can return an instance of an object represented by a key. |
| */ |
| factory, |
| /** |
| * Arguments (dependencies) to the `factory` function. |
| */ |
| dependencies) { |
| this.factory = factory; |
| this.dependencies = dependencies; |
| } |
| return ResolvedReflectiveFactory; |
| }()); |
| /** |
| * Resolve a single provider. |
| */ |
| function resolveReflectiveFactory(provider) { |
| var factoryFn; |
| var resolvedDeps; |
| if (provider.useClass) { |
| var useClass = resolveForwardRef(provider.useClass); |
| factoryFn = reflector.factory(useClass); |
| resolvedDeps = _dependenciesFor(useClass); |
| } |
| else if (provider.useExisting) { |
| factoryFn = function (aliasInstance) { return aliasInstance; }; |
| resolvedDeps = [ReflectiveDependency.fromKey(ReflectiveKey.get(provider.useExisting))]; |
| } |
| else if (provider.useFactory) { |
| factoryFn = provider.useFactory; |
| resolvedDeps = constructDependencies(provider.useFactory, provider.deps); |
| } |
| else { |
| factoryFn = function () { return provider.useValue; }; |
| resolvedDeps = _EMPTY_LIST; |
| } |
| return new ResolvedReflectiveFactory(factoryFn, resolvedDeps); |
| } |
| /** |
| * Converts the `Provider` into `ResolvedProvider`. |
| * |
| * `Injector` internally only uses `ResolvedProvider`, `Provider` contains convenience provider |
| * syntax. |
| */ |
| function resolveReflectiveProvider(provider) { |
| return new ResolvedReflectiveProvider_(ReflectiveKey.get(provider.provide), [resolveReflectiveFactory(provider)], provider.multi || false); |
| } |
| /** |
| * Resolve a list of Providers. |
| */ |
| function resolveReflectiveProviders(providers) { |
| var normalized = _normalizeProviders(providers, []); |
| var resolved = normalized.map(resolveReflectiveProvider); |
| var resolvedProviderMap = mergeResolvedReflectiveProviders(resolved, new Map()); |
| return Array.from(resolvedProviderMap.values()); |
| } |
| /** |
| * Merges a list of ResolvedProviders into a list where each key is contained exactly once and |
| * multi providers have been merged. |
| */ |
| function mergeResolvedReflectiveProviders(providers, normalizedProvidersMap) { |
| for (var i = 0; i < providers.length; i++) { |
| var provider = providers[i]; |
| var existing = normalizedProvidersMap.get(provider.key.id); |
| if (existing) { |
| if (provider.multiProvider !== existing.multiProvider) { |
| throw mixingMultiProvidersWithRegularProvidersError(existing, provider); |
| } |
| if (provider.multiProvider) { |
| for (var j = 0; j < provider.resolvedFactories.length; j++) { |
| existing.resolvedFactories.push(provider.resolvedFactories[j]); |
| } |
| } |
| else { |
| normalizedProvidersMap.set(provider.key.id, provider); |
| } |
| } |
| else { |
| var resolvedProvider = void 0; |
| if (provider.multiProvider) { |
| resolvedProvider = new ResolvedReflectiveProvider_(provider.key, provider.resolvedFactories.slice(), provider.multiProvider); |
| } |
| else { |
| resolvedProvider = provider; |
| } |
| normalizedProvidersMap.set(provider.key.id, resolvedProvider); |
| } |
| } |
| return normalizedProvidersMap; |
| } |
| function _normalizeProviders(providers, res) { |
| providers.forEach(function (b) { |
| if (b instanceof Type) { |
| res.push({ provide: b, useClass: b }); |
| } |
| else if (b && typeof b == 'object' && b.provide !== undefined) { |
| res.push(b); |
| } |
| else if (b instanceof Array) { |
| _normalizeProviders(b, res); |
| } |
| else { |
| throw invalidProviderError(b); |
| } |
| }); |
| return res; |
| } |
| function constructDependencies(typeOrFunc, dependencies) { |
| if (!dependencies) { |
| return _dependenciesFor(typeOrFunc); |
| } |
| else { |
| var params_1 = dependencies.map(function (t) { return [t]; }); |
| return dependencies.map(function (t) { return _extractToken(typeOrFunc, t, params_1); }); |
| } |
| } |
| function _dependenciesFor(typeOrFunc) { |
| var params = reflector.parameters(typeOrFunc); |
| if (!params) |
| return []; |
| if (params.some(function (p) { return p == null; })) { |
| throw noAnnotationError(typeOrFunc, params); |
| } |
| return params.map(function (p) { return _extractToken(typeOrFunc, p, params); }); |
| } |
| function _extractToken(typeOrFunc, metadata, params) { |
| var token = null; |
| var optional = false; |
| if (!Array.isArray(metadata)) { |
| if (metadata instanceof Inject) { |
| return _createDependency(metadata.token, optional, null); |
| } |
| else { |
| return _createDependency(metadata, optional, null); |
| } |
| } |
| var visibility = null; |
| for (var i = 0; i < metadata.length; ++i) { |
| var paramMetadata = metadata[i]; |
| if (paramMetadata instanceof Type) { |
| token = paramMetadata; |
| } |
| else if (paramMetadata instanceof Inject) { |
| token = paramMetadata.token; |
| } |
| else if (paramMetadata instanceof Optional) { |
| optional = true; |
| } |
| else if (paramMetadata instanceof Self || paramMetadata instanceof SkipSelf) { |
| visibility = paramMetadata; |
| } |
| else if (paramMetadata instanceof InjectionToken) { |
| token = paramMetadata; |
| } |
| } |
| token = resolveForwardRef(token); |
| if (token != null) { |
| return _createDependency(token, optional, visibility); |
| } |
| else { |
| throw noAnnotationError(typeOrFunc, params); |
| } |
| } |
| function _createDependency(token, optional, visibility) { |
| return new ReflectiveDependency(ReflectiveKey.get(token), optional, visibility); |
| } |
| |
| /** |
| * @license |
| * Copyright Google Inc. All Rights Reserved. |
| * |
| * Use of this source code is governed by an MIT-style license that can be |
| * found in the LICENSE file at https://angular.io/license |
| */ |
| // Threshold for the dynamic version |
| var UNDEFINED = new Object(); |
| /** |
| * A ReflectiveDependency injection container used for instantiating objects and resolving |
| * dependencies. |
| * |
| * An `Injector` is a replacement for a `new` operator, which can automatically resolve the |
| * constructor dependencies. |
| * |
| * In typical use, application code asks for the dependencies in the constructor and they are |
| * resolved by the `Injector`. |
| * |
| * @usageNotes |
| * ### Example |
| * |
| * The following example creates an `Injector` configured to create `Engine` and `Car`. |
| * |
| * ```typescript |
| * @Injectable() |
| * class Engine { |
| * } |
| * |
| * @Injectable() |
| * class Car { |
| * constructor(public engine:Engine) {} |
| * } |
| * |
| * var injector = ReflectiveInjector.resolveAndCreate([Car, Engine]); |
| * var car = injector.get(Car); |
| * expect(car instanceof Car).toBe(true); |
| * expect(car.engine instanceof Engine).toBe(true); |
| * ``` |
| * |
| * Notice, we don't use the `new` operator because we explicitly want to have the `Injector` |
| * resolve all of the object's dependencies automatically. |
| * |
| * @deprecated from v5 - slow and brings in a lot of code, Use `Injector.create` instead. |
| * @publicApi |
| */ |
| var ReflectiveInjector = /** @class */ (function () { |
| function ReflectiveInjector() { |
| } |
| /** |
| * Turns an array of provider definitions into an array of resolved providers. |
| * |
| * A resolution is a process of flattening multiple nested arrays and converting individual |
| * providers into an array of `ResolvedReflectiveProvider`s. |
| * |
| * @usageNotes |
| * ### Example |
| * |
| * ```typescript |
| * @Injectable() |
| * class Engine { |
| * } |
| * |
| * @Injectable() |
| * class Car { |
| * constructor(public engine:Engine) {} |
| * } |
| * |
| * var providers = ReflectiveInjector.resolve([Car, [[Engine]]]); |
| * |
| * expect(providers.length).toEqual(2); |
| * |
| * expect(providers[0] instanceof ResolvedReflectiveProvider).toBe(true); |
| * expect(providers[0].key.displayName).toBe("Car"); |
| * expect(providers[0].dependencies.length).toEqual(1); |
| * expect(providers[0].factory).toBeDefined(); |
| * |
| * expect(providers[1].key.displayName).toBe("Engine"); |
| * }); |
| * ``` |
| * |
| */ |
| ReflectiveInjector.resolve = function (providers) { |
| return resolveReflectiveProviders(providers); |
| }; |
| /** |
| * Resolves an array of providers and creates an injector from those providers. |
| * |
| * The passed-in providers can be an array of `Type`, `Provider`, |
| * or a recursive array of more providers. |
| * |
| * @usageNotes |
| * ### Example |
| * |
| * ```typescript |
| * @Injectable() |
| * class Engine { |
| * } |
| * |
| * @Injectable() |
| * class Car { |
| * constructor(public engine:Engine) {} |
| * } |
| * |
| * var injector = ReflectiveInjector.resolveAndCreate([Car, Engine]); |
| * expect(injector.get(Car) instanceof Car).toBe(true); |
| * ``` |
| */ |
| ReflectiveInjector.resolveAndCreate = function (providers, parent) { |
| var ResolvedReflectiveProviders = ReflectiveInjector.resolve(providers); |
| return ReflectiveInjector.fromResolvedProviders(ResolvedReflectiveProviders, parent); |
| }; |
| /** |
| * Creates an injector from previously resolved providers. |
| * |
| * This API is the recommended way to construct injectors in performance-sensitive parts. |
| * |
| * @usageNotes |
| * ### Example |
| * |
| * ```typescript |
| * @Injectable() |
| * class Engine { |
| * } |
| * |
| * @Injectable() |
| * class Car { |
| * constructor(public engine:Engine) {} |
| * } |
| * |
| * var providers = ReflectiveInjector.resolve([Car, Engine]); |
| * var injector = ReflectiveInjector.fromResolvedProviders(providers); |
| * expect(injector.get(Car) instanceof Car).toBe(true); |
| * ``` |
| */ |
| ReflectiveInjector.fromResolvedProviders = function (providers, parent) { |
| return new ReflectiveInjector_(providers, parent); |
| }; |
| return ReflectiveInjector; |
| }()); |
| var ReflectiveInjector_ = /** @class */ (function () { |
| /** |
| * Private |
| */ |
| function ReflectiveInjector_(_providers, _parent) { |
| /** @internal */ |
| this._constructionCounter = 0; |
| this._providers = _providers; |
| this.parent = _parent || null; |
| var len = _providers.length; |
| this.keyIds = new Array(len); |
| this.objs = new Array(len); |
| for (var i = 0; i < len; i++) { |
| this.keyIds[i] = _providers[i].key.id; |
| this.objs[i] = UNDEFINED; |
| } |
| } |
| ReflectiveInjector_.prototype.get = function (token, notFoundValue) { |
| if (notFoundValue === void 0) { notFoundValue = THROW_IF_NOT_FOUND; } |
| return this._getByKey(ReflectiveKey.get(token), null, notFoundValue); |
| }; |
| ReflectiveInjector_.prototype.resolveAndCreateChild = function (providers) { |
| var ResolvedReflectiveProviders = ReflectiveInjector.resolve(providers); |
| return this.createChildFromResolved(ResolvedReflectiveProviders); |
| }; |
| ReflectiveInjector_.prototype.createChildFromResolved = function (providers) { |
| var inj = new ReflectiveInjector_(providers); |
| inj.parent = this; |
| return inj; |
| }; |
| ReflectiveInjector_.prototype.resolveAndInstantiate = function (provider) { |
| return this.instantiateResolved(ReflectiveInjector.resolve([provider])[0]); |
| }; |
| ReflectiveInjector_.prototype.instantiateResolved = function (provider) { |
| return this._instantiateProvider(provider); |
| }; |
| ReflectiveInjector_.prototype.getProviderAtIndex = function (index) { |
| if (index < 0 || index >= this._providers.length) { |
| throw outOfBoundsError(index); |
| } |
| return this._providers[index]; |
| }; |
| /** @internal */ |
| ReflectiveInjector_.prototype._new = function (provider) { |
| if (this._constructionCounter++ > this._getMaxNumberOfObjects()) { |
| throw cyclicDependencyError(this, provider.key); |
| } |
| return this._instantiateProvider(provider); |
| }; |
| ReflectiveInjector_.prototype._getMaxNumberOfObjects = function () { return this.objs.length; }; |
| ReflectiveInjector_.prototype._instantiateProvider = function (provider) { |
| if (provider.multiProvider) { |
| var res = new Array(provider.resolvedFactories.length); |
| for (var i = 0; i < provider.resolvedFactories.length; ++i) { |
| res[i] = this._instantiate(provider, provider.resolvedFactories[i]); |
| } |
| return res; |
| } |
| else { |
| return this._instantiate(provider, provider.resolvedFactories[0]); |
| } |
| }; |
| ReflectiveInjector_.prototype._instantiate = function (provider, ResolvedReflectiveFactory) { |
| var _this = this; |
| var factory = ResolvedReflectiveFactory.factory; |
| var deps; |
| try { |
| deps = |
| ResolvedReflectiveFactory.dependencies.map(function (dep) { return _this._getByReflectiveDependency(dep); }); |
| } |
| catch (e) { |
| if (e.addKey) { |
| e.addKey(this, provider.key); |
| } |
| throw e; |
| } |
| var obj; |
| try { |
| obj = factory.apply(void 0, __spread(deps)); |
| } |
| catch (e) { |
| throw instantiationError(this, e, e.stack, provider.key); |
| } |
| return obj; |
| }; |
| ReflectiveInjector_.prototype._getByReflectiveDependency = function (dep) { |
| return this._getByKey(dep.key, dep.visibility, dep.optional ? null : THROW_IF_NOT_FOUND); |
| }; |
| ReflectiveInjector_.prototype._getByKey = function (key, visibility, notFoundValue) { |
| if (key === ReflectiveInjector_.INJECTOR_KEY) { |
| return this; |
| } |
| if (visibility instanceof Self) { |
| return this._getByKeySelf(key, notFoundValue); |
| } |
| else { |
| return this._getByKeyDefault(key, notFoundValue, visibility); |
| } |
| }; |
| ReflectiveInjector_.prototype._getObjByKeyId = function (keyId) { |
| for (var i = 0; i < this.keyIds.length; i++) { |
| if (this.keyIds[i] === keyId) { |
| if (this.objs[i] === UNDEFINED) { |
| this.objs[i] = this._new(this._providers[i]); |
| } |
| return this.objs[i]; |
| } |
| } |
| return UNDEFINED; |
| }; |
| /** @internal */ |
| ReflectiveInjector_.prototype._throwOrNull = function (key, notFoundValue) { |
| if (notFoundValue !== THROW_IF_NOT_FOUND) { |
| return notFoundValue; |
| } |
| else { |
| throw noProviderError(this, key); |
| } |
| }; |
| /** @internal */ |
| ReflectiveInjector_.prototype._getByKeySelf = function (key, notFoundValue) { |
| var obj = this._getObjByKeyId(key.id); |
| return (obj !== UNDEFINED) ? obj : this._throwOrNull(key, notFoundValue); |
| }; |
| /** @internal */ |
| ReflectiveInjector_.prototype._getByKeyDefault = function (key, notFoundValue, visibility) { |
| var inj; |
| if (visibility instanceof SkipSelf) { |
| inj = this.parent; |
| } |
| else { |
| inj = this; |
| } |
| while (inj instanceof ReflectiveInjector_) { |
| var inj_ = inj; |
| var obj = inj_._getObjByKeyId(key.id); |
| if (obj !== UNDEFINED) |
| return obj; |
| inj = inj_.parent; |
| } |
| if (inj !== null) { |
| return inj.get(key.token, notFoundValue); |
| } |
| else { |
| return this._throwOrNull(key, notFoundValue); |
| } |
| }; |
| Object.defineProperty(ReflectiveInjector_.prototype, "displayName", { |
| get: function () { |
| var providers = _mapProviders(this, function (b) { return ' "' + b.key.displayName + '" '; }) |
| .join(', '); |
| return "ReflectiveInjector(providers: [" + providers + "])"; |
| }, |
| enumerable: true, |
| configurable: true |
| }); |
| ReflectiveInjector_.prototype.toString = function () { return this.displayName; }; |
| ReflectiveInjector_.INJECTOR_KEY = ReflectiveKey.get(Injector); |
| return ReflectiveInjector_; |
| }()); |
| function _mapProviders(injector, fn) { |
| var res = new Array(injector._providers.length); |
| for (var i = 0; i < injector._providers.length; ++i) { |
| res[i] = fn(injector.getProviderAtIndex(i)); |
| } |
| return res; |
| } |
| |
| /** |
| * @license |
| * Copyright Google Inc. All Rights Reserved. |
| * |
| * Use of this source code is governed by an MIT-style license that can be |
| * found in the LICENSE file at https://angular.io/license |
| */ |
| |
| /** |
| * @license |
| * Copyright Google Inc. All Rights Reserved. |
| * |
| * Use of this source code is governed by an MIT-style license that can be |
| * found in the LICENSE file at https://angular.io/license |
| */ |
| |
| /** |
| * @license |
| * Copyright Google Inc. All Rights Reserved. |
| * |
| * Use of this source code is governed by an MIT-style license that can be |
| * found in the LICENSE file at https://angular.io/license |
| */ |
| /** |
| * A DI token that you can use to create a virtual [provider](guide/glossary#provider) |
| * that will populate the `entryComponents` field of components and NgModules |
| * based on its `useValue` property value. |
| * All components that are referenced in the `useValue` value (either directly |
| * or in a nested array or map) are added to the `entryComponents` property. |
| * |
| * @usageNotes |
| * |
| * The following example shows how the router can populate the `entryComponents` |
| * field of an NgModule based on a router configuration that refers |
| * to components. |
| * |
| * ```typescript |
| * // helper function inside the router |
| * function provideRoutes(routes) { |
| * return [ |
| * {provide: ROUTES, useValue: routes}, |
| * {provide: ANALYZE_FOR_ENTRY_COMPONENTS, useValue: routes, multi: true} |
| * ]; |
| * } |
| * |
| * // user code |
| * let routes = [ |
| * {path: '/root', component: RootComp}, |
| * {path: '/teams', component: TeamsComp} |
| * ]; |
| * |
| * @NgModule({ |
| * providers: [provideRoutes(routes)] |
| * }) |
| * class ModuleWithRoutes {} |
| * ``` |
| * |
| * @publicApi |
| */ |
| var ANALYZE_FOR_ENTRY_COMPONENTS = new InjectionToken('AnalyzeForEntryComponents'); |
| /** |
| * Base class for query metadata. |
| * |
| * @see `ContentChildren`. |
| * @see `ContentChild`. |
| * @see `ViewChildren`. |
| * @see `ViewChild`. |
| * |
| * @publicApi |
| */ |
| var Query = /** @class */ (function () { |
| function Query() { |
| } |
| return Query; |
| }()); |
| var ɵ0$5 = function (selector, data) { |
| if (data === void 0) { data = {}; } |
| return (__assign({ selector: selector, first: false, isViewQuery: false, descendants: false }, data)); |
| }; |
| /** |
| * ContentChildren decorator and metadata. |
| * |
| * |
| * @Annotation |
| * @publicApi |
| */ |
| var ContentChildren = makePropDecorator('ContentChildren', ɵ0$5, Query); |
| var ɵ1$1 = function (selector, data) { |
| if (data === void 0) { data = {}; } |
| return (__assign({ selector: selector, first: true, isViewQuery: false, descendants: true }, data)); |
| }; |
| /** |
| * ContentChild decorator and metadata. |
| * |
| * |
| * @Annotation |
| * |
| * @publicApi |
| */ |
| var ContentChild = makePropDecorator('ContentChild', ɵ1$1, Query); |
| var ɵ2 = function (selector, data) { |
| if (data === void 0) { data = {}; } |
| return (__assign({ selector: selector, first: false, isViewQuery: true, descendants: true }, data)); |
| }; |
| /** |
| * ViewChildren decorator and metadata. |
| * |
| * @Annotation |
| * @publicApi |
| */ |
| var ViewChildren = makePropDecorator('ViewChildren', ɵ2, Query); |
| var ɵ3 = function (selector, data) { |
| return (__assign({ selector: selector, first: true, isViewQuery: true, descendants: true }, data)); |
| }; |
| /** |
| * ViewChild decorator and metadata. |
| * |
| * @Annotation |
| * @publicApi |
| */ |
| var ViewChild = makePropDecorator('ViewChild', ɵ3, Query); |
| |
| /** |
| * @license |
| * Copyright Google Inc. All Rights Reserved. |
| * |
| * Use of this source code is governed by an MIT-style license that can be |
| * found in the LICENSE file at https://angular.io/license |
| */ |
| (function (ChangeDetectionStrategy) { |
| /** |
| * Use the `CheckOnce` strategy, meaning that automatic change detection is deactivated |
| * until reactivated by setting the strategy to `Default` (`CheckAlways`). |
| * Change detection can still be explicitly invoked. |
| * This strategy applies to all child directives and cannot be overridden. |
| */ |
| ChangeDetectionStrategy[ChangeDetectionStrategy["OnPush"] = 0] = "OnPush"; |
| /** |
| * Use the default `CheckAlways` strategy, in which change detection is automatic until |
| * explicitly deactivated. |
| */ |
| ChangeDetectionStrategy[ChangeDetectionStrategy["Default"] = 1] = "Default"; |
| })(exports.ChangeDetectionStrategy || (exports.ChangeDetectionStrategy = {})); |
| (function (ChangeDetectorStatus) { |
| /** |
| * A state in which, after calling `detectChanges()`, the change detector |
| * state becomes `Checked`, and must be explicitly invoked or reactivated. |
| */ |
| ChangeDetectorStatus[ChangeDetectorStatus["CheckOnce"] = 0] = "CheckOnce"; |
| /** |
| * A state in which change detection is skipped until the change detector mode |
| * becomes `CheckOnce`. |
| */ |
| ChangeDetectorStatus[ChangeDetectorStatus["Checked"] = 1] = "Checked"; |
| /** |
| * A state in which change detection continues automatically until explicitly |
| * deactivated. |
| */ |
| ChangeDetectorStatus[ChangeDetectorStatus["CheckAlways"] = 2] = "CheckAlways"; |
| /** |
| * A state in which a change detector sub tree is not a part of the main tree and |
| * should be skipped. |
| */ |
| ChangeDetectorStatus[ChangeDetectorStatus["Detached"] = 3] = "Detached"; |
| /** |
| * Indicates that the change detector encountered an error checking a binding |
| * or calling a directive lifecycle method and is now in an inconsistent state. Change |
| * detectors in this state do not detect changes. |
| */ |
| ChangeDetectorStatus[ChangeDetectorStatus["Errored"] = 4] = "Errored"; |
| /** |
| * Indicates that the change detector has been destroyed. |
| */ |
| ChangeDetectorStatus[ChangeDetectorStatus["Destroyed"] = 5] = "Destroyed"; |
| })(exports.ɵChangeDetectorStatus || (exports.ɵChangeDetectorStatus = {})); |
| /** |
| * Reports whether a given strategy is currently the default for change detection. |
| * @param changeDetectionStrategy The strategy to check. |
| * @returns True if the given strategy is the current default, false otherwise. |
| * @see `ChangeDetectorStatus` |
| * @see `ChangeDetectorRef` |
| */ |
| function isDefaultChangeDetectionStrategy(changeDetectionStrategy) { |
| return changeDetectionStrategy == null || |
| changeDetectionStrategy === exports.ChangeDetectionStrategy.Default; |
| } |
| |
| /** |
| * @license |
| * Copyright Google Inc. All Rights Reserved. |
| * |
| * Use of this source code is governed by an MIT-style license that can be |
| * found in the LICENSE file at https://angular.io/license |
| */ |
| /** |
| * Used to resolve resource URLs on `@Component` when used with JIT compilation. |
| * |
| * Example: |
| * ``` |
| * @Component({ |
| * selector: 'my-comp', |
| * templateUrl: 'my-comp.html', // This requires asynchronous resolution |
| * }) |
| * class MyComponent{ |
| * } |
| * |
| * // Calling `renderComponent` will fail because `renderComponent` is a synchronous process |
| * // and `MyComponent`'s `@Component.templateUrl` needs to be resolved asynchronously. |
| * |
| * // Calling `resolveComponentResources()` will resolve `@Component.templateUrl` into |
| * // `@Component.template`, which allows `renderComponent` to proceed in a synchronous manner. |
| * |
| * // Use browser's `fetch()` function as the default resource resolution strategy. |
| * resolveComponentResources(fetch).then(() => { |
| * // After resolution all URLs have been converted into `template` strings. |
| * renderComponent(MyComponent); |
| * }); |
| * |
| * ``` |
| * |
| * NOTE: In AOT the resolution happens during compilation, and so there should be no need |
| * to call this method outside JIT mode. |
| * |
| * @param resourceResolver a function which is responsible for returning a `Promise` to the |
| * contents of the resolved URL. Browser's `fetch()` method is a good default implementation. |
| */ |
| function resolveComponentResources(resourceResolver) { |
| // Store all promises which are fetching the resources. |
| var componentResolved = []; |
| // Cache so that we don't fetch the same resource more than once. |
| var urlMap = new Map(); |
| function cachedResourceResolve(url) { |
| var promise = urlMap.get(url); |
| if (!promise) { |
| var resp = resourceResolver(url); |
| urlMap.set(url, promise = resp.then(unwrapResponse)); |
| } |
| return promise; |
| } |
| componentResourceResolutionQueue.forEach(function (component, type) { |
| var promises = []; |
| if (component.templateUrl) { |
| promises.push(cachedResourceResolve(component.templateUrl).then(function (template) { |
| component.template = template; |
| })); |
| } |
| var styleUrls = component.styleUrls; |
| var styles = component.styles || (component.styles = []); |
| var styleOffset = component.styles.length; |
| styleUrls && styleUrls.forEach(function (styleUrl, index) { |
| styles.push(''); // pre-allocate array. |
| promises.push(cachedResourceResolve(styleUrl).then(function (style) { |
| styles[styleOffset + index] = style; |
| styleUrls.splice(styleUrls.indexOf(styleUrl), 1); |
| if (styleUrls.length == 0) { |
| component.styleUrls = undefined; |
| } |
| })); |
| }); |
| var fullyResolved = Promise.all(promises).then(function () { return componentDefResolved(type); }); |
| componentResolved.push(fullyResolved); |
| }); |
| clearResolutionOfComponentResourcesQueue(); |
| return Promise.all(componentResolved).then(function () { return undefined; }); |
| } |
| var componentResourceResolutionQueue = new Map(); |
| // Track when existing ngComponentDef for a Type is waiting on resources. |
| var componentDefPendingResolution = new Set(); |
| function maybeQueueResolutionOfComponentResources(type, metadata) { |
| if (componentNeedsResolution(metadata)) { |
| componentResourceResolutionQueue.set(type, metadata); |
| componentDefPendingResolution.add(type); |
| } |
| } |
| function componentNeedsResolution(component) { |
| return !!((component.templateUrl && !component.hasOwnProperty('template')) || |
| component.styleUrls && component.styleUrls.length); |
| } |
| function clearResolutionOfComponentResourcesQueue() { |
| var old = componentResourceResolutionQueue; |
| componentResourceResolutionQueue = new Map(); |
| return old; |
| } |
| function isComponentResourceResolutionQueueEmpty() { |
| return componentResourceResolutionQueue.size === 0; |
| } |
| function unwrapResponse(response) { |
| return typeof response == 'string' ? response : response.text(); |
| } |
| function componentDefResolved(type) { |
| componentDefPendingResolution.delete(type); |
| } |
| |
| /** |
| * @license |
| * Copyright Google Inc. All Rights Reserved. |
| * |
| * Use of this source code is governed by an MIT-style license that can be |
| * found in the LICENSE file at https://angular.io/license |
| */ |
| (function (ViewEncapsulation) { |
| /** |
| * Emulate `Native` scoping of styles by adding an attribute containing surrogate id to the Host |
| * Element and pre-processing the style rules provided via {@link Component#styles styles} or |
| * {@link Component#styleUrls styleUrls}, and adding the new Host Element attribute to all |
| * selectors. |
| * |
| * This is the default option. |
| */ |
| ViewEncapsulation[ViewEncapsulation["Emulated"] = 0] = "Emulated"; |
| /** |
| * @deprecated v6.1.0 - use {ViewEncapsulation.ShadowDom} instead. |
| * Use the native encapsulation mechanism of the renderer. |
| * |
| * For the DOM this means using the deprecated [Shadow DOM |
| * v0](https://w3c.github.io/webcomponents/spec/shadow/) and |
| * creating a ShadowRoot for Component's Host Element. |
| */ |
| ViewEncapsulation[ViewEncapsulation["Native"] = 1] = "Native"; |
| /** |
| * Don't provide any template or style encapsulation. |
| */ |
| ViewEncapsulation[ViewEncapsulation["None"] = 2] = "None"; |
| /** |
| * Use Shadow DOM to encapsulate styles. |
| * |
| * For the DOM this means using modern [Shadow |
| * DOM](https://w3c.github.io/webcomponents/spec/shadow/) and |
| * creating a ShadowRoot for Component's Host Element. |
| */ |
| ViewEncapsulation[ViewEncapsulation["ShadowDom"] = 3] = "ShadowDom"; |
| })(exports.ViewEncapsulation || (exports.ViewEncapsulation = {})); |
| |
| /** |
| * @license |
| * Copyright Google Inc. All Rights Reserved. |
| * |
| * Use of this source code is governed by an MIT-style license that can be |
| * found in the LICENSE file at https://angular.io/license |
| */ |
| /** |
| * Convince closure compiler that the wrapped function has no side-effects. |
| * |
| * Closure compiler always assumes that `toString` has no side-effects. We use this quirk to |
| * allow us to execute a function but have closure compiler mark the call as no-side-effects. |
| * It is important that the return value for the `noSideEffects` function be assigned |
| * to something which is retained otherwise the call to `noSideEffects` will be removed by closure |
| * compiler. |
| */ |
| function noSideEffects(fn) { |
| return '' + { toString: fn }; |
| } |
| |
| /** |
| * @license |
| * Copyright Google Inc. All Rights Reserved. |
| * |
| * Use of this source code is governed by an MIT-style license that can be |
| * found in the LICENSE file at https://angular.io/license |
| */ |
| /** |
| * This file contains reuseable "empty" symbols that can be used as default return values |
| * in different parts of the rendering code. Because the same symbols are returned, this |
| * allows for identity checks against these values to be consistently used by the framework |
| * code. |
| */ |
| var EMPTY_OBJ = {}; |
| var EMPTY_ARRAY$2 = []; |
| // freezing the values prevents any code from accidentally inserting new values in |
| if (typeof ngDevMode !== 'undefined' && ngDevMode) { |
| // These property accesses can be ignored because ngDevMode will be set to false |
| // when optimizing code and the whole if statement will be dropped. |
| // tslint:disable-next-line:no-toplevel-property-access |
| Object.freeze(EMPTY_OBJ); |
| // tslint:disable-next-line:no-toplevel-property-access |
| Object.freeze(EMPTY_ARRAY$2); |
| } |
| |
| /** |
| * @license |
| * Copyright Google Inc. All Rights Reserved. |
| * |
| * Use of this source code is governed by an MIT-style license that can be |
| * found in the LICENSE file at https://angular.io/license |
| */ |
| var NG_COMPONENT_DEF = getClosureSafeProperty({ ngComponentDef: getClosureSafeProperty }); |
| var NG_DIRECTIVE_DEF = getClosureSafeProperty({ ngDirectiveDef: getClosureSafeProperty }); |
| var NG_PIPE_DEF = getClosureSafeProperty({ ngPipeDef: getClosureSafeProperty }); |
| var NG_MODULE_DEF = getClosureSafeProperty({ ngModuleDef: getClosureSafeProperty }); |
| var NG_LOCALE_ID_DEF = getClosureSafeProperty({ ngLocaleIdDef: getClosureSafeProperty }); |
| var NG_BASE_DEF = getClosureSafeProperty({ ngBaseDef: getClosureSafeProperty }); |
| /** |
| * If a directive is diPublic, bloomAdd sets a property on the type with this constant as |
| * the key and the directive's unique ID as the value. This allows us to map directives to their |
| * bloom filter bit for DI. |
| */ |
| // TODO(misko): This is wrong. The NG_ELEMENT_ID should never be minified. |
| var NG_ELEMENT_ID = getClosureSafeProperty({ __NG_ELEMENT_ID__: getClosureSafeProperty }); |
| |
| /** |
| * @license |
| * Copyright Google Inc. All Rights Reserved. |
| * |
| * Use of this source code is governed by an MIT-style license that can be |
| * found in the LICENSE file at https://angular.io/license |
| */ |
| var _renderCompCount = 0; |
| /** |
| * Create a component definition object. |
| * |
| * |
| * # Example |
| * ``` |
| * class MyDirective { |
| * // Generated by Angular Template Compiler |
| * // [Symbol] syntax will not be supported by TypeScript until v2.7 |
| * static ngComponentDef = defineComponent({ |
| * ... |
| * }); |
| * } |
| * ``` |
| * @codeGenApi |
| */ |
| function ɵɵdefineComponent(componentDefinition) { |
| var type = componentDefinition.type; |
| var typePrototype = type.prototype; |
| var declaredInputs = {}; |
| var def = { |
| type: type, |
| providersResolver: null, |
| consts: componentDefinition.consts, |
| vars: componentDefinition.vars, |
| factory: componentDefinition.factory, |
| template: componentDefinition.template || null, |
| ngContentSelectors: componentDefinition.ngContentSelectors, |
| hostBindings: componentDefinition.hostBindings || null, |
| contentQueries: componentDefinition.contentQueries || null, |
| declaredInputs: declaredInputs, |
| inputs: null, |
| outputs: null, |
| exportAs: componentDefinition.exportAs || null, |
| onChanges: null, |
| onInit: typePrototype.ngOnInit || null, |
| doCheck: typePrototype.ngDoCheck || null, |
| afterContentInit: typePrototype.ngAfterContentInit || null, |
| afterContentChecked: typePrototype.ngAfterContentChecked || null, |
| afterViewInit: typePrototype.ngAfterViewInit || null, |
| afterViewChecked: typePrototype.ngAfterViewChecked || null, |
| onDestroy: typePrototype.ngOnDestroy || null, |
| onPush: componentDefinition.changeDetection === exports.ChangeDetectionStrategy.OnPush, |
| directiveDefs: null, |
| pipeDefs: null, |
| selectors: componentDefinition.selectors, |
| viewQuery: componentDefinition.viewQuery || null, |
| features: componentDefinition.features || null, |
| data: componentDefinition.data || {}, |
| // TODO(misko): convert ViewEncapsulation into const enum so that it can be used directly in the |
| // next line. Also `None` should be 0 not 2. |
| encapsulation: componentDefinition.encapsulation || exports.ViewEncapsulation.Emulated, |
| id: 'c', |
| styles: componentDefinition.styles || EMPTY_ARRAY$2, |
| _: null, |
| setInput: null, |
| schemas: componentDefinition.schemas || null, |
| tView: null, |
| }; |
| def._ = noSideEffects(function () { |
| var directiveTypes = componentDefinition.directives; |
| var feature = componentDefinition.features; |
| var pipeTypes = componentDefinition.pipes; |
| def.id += _renderCompCount++; |
| def.inputs = invertObject(componentDefinition.inputs, declaredInputs), |
| def.outputs = invertObject(componentDefinition.outputs), |
| feature && feature.forEach(function (fn) { return fn(def); }); |
| def.directiveDefs = directiveTypes ? |
| function () { return (typeof directiveTypes === 'function' ? directiveTypes() : directiveTypes) |
| .map(extractDirectiveDef); } : |
| null; |
| def.pipeDefs = pipeTypes ? |
| function () { return (typeof pipeTypes === 'function' ? pipeTypes() : pipeTypes).map(extractPipeDef); } : |
| null; |
| // Add ngInjectableDef so components are reachable through the module injector by default |
| // (unless it has already been set by the @Injectable decorator). This is mostly to |
| // support injecting components in tests. In real application code, components should |
| // be retrieved through the node injector, so this isn't a problem. |
| if (!type.hasOwnProperty(NG_INJECTABLE_DEF)) { |
| type[NG_INJECTABLE_DEF] = |
| ɵɵdefineInjectable({ token: type, factory: componentDefinition.factory }); |
| } |
| }); |
| return def; |
| } |
| /** |
| * @codeGenApi |
| */ |
| function ɵɵsetComponentScope(type, directives, pipes) { |
| var def = type.ngComponentDef; |
| def.directiveDefs = function () { return directives.map(extractDirectiveDef); }; |
| def.pipeDefs = function () { return pipes.map(extractPipeDef); }; |
| } |
| function extractDirectiveDef(type) { |
| var def = getComponentDef(type) || getDirectiveDef(type); |
| if (ngDevMode && !def) { |
| throw new Error("'" + type.name + "' is neither 'ComponentType' or 'DirectiveType'."); |
| } |
| return def; |
| } |
| function extractPipeDef(type) { |
| var def = getPipeDef(type); |
| if (ngDevMode && !def) { |
| throw new Error("'" + type.name + "' is not a 'PipeType'."); |
| } |
| return def; |
| } |
| /** |
| * @codeGenApi |
| */ |
| function ɵɵdefineNgModule(def) { |
| var res = { |
| type: def.type, |
| bootstrap: def.bootstrap || EMPTY_ARRAY$2, |
| declarations: def.declarations || EMPTY_ARRAY$2, |
| imports: def.imports || EMPTY_ARRAY$2, |
| exports: def.exports || EMPTY_ARRAY$2, |
| transitiveCompileScopes: null, |
| schemas: def.schemas || null, |
| id: def.id || null, |
| }; |
| return res; |
| } |
| /** |
| * Adds the module metadata that is necessary to compute the module's transitive scope to an |
| * existing module definition. |
| * |
| * Scope metadata of modules is not used in production builds, so calls to this function can be |
| * marked pure to tree-shake it from the bundle, allowing for all referenced declarations |
| * to become eligible for tree-shaking as well. |
| * |
| * @codeGenApi |
| */ |
| function ɵɵsetNgModuleScope(type, scope) { |
| return noSideEffects(function () { |
| var ngModuleDef = getNgModuleDef(type, true); |
| ngModuleDef.declarations = scope.declarations || EMPTY_ARRAY$2; |
| ngModuleDef.imports = scope.imports || EMPTY_ARRAY$2; |
| ngModuleDef.exports = scope.exports || EMPTY_ARRAY$2; |
| }); |
| } |
| /** |
| * Inverts an inputs or outputs lookup such that the keys, which were the |
| * minified keys, are part of the values, and the values are parsed so that |
| * the publicName of the property is the new key |
| * |
| * e.g. for |
| * |
| * ``` |
| * class Comp { |
| * @Input() |
| * propName1: string; |
| * |
| * @Input('publicName2') |
| * declaredPropName2: number; |
| * } |
| * ``` |
| * |
| * will be serialized as |
| * |
| * ``` |
| * { |
| * propName1: 'propName1', |
| * declaredPropName2: ['publicName2', 'declaredPropName2'], |
| * } |
| * ``` |
| * |
| * which is than translated by the minifier as: |
| * |
| * ``` |
| * { |
| * minifiedPropName1: 'propName1', |
| * minifiedPropName2: ['publicName2', 'declaredPropName2'], |
| * } |
| * ``` |
| * |
| * becomes: (public name => minifiedName) |
| * |
| * ``` |
| * { |
| * 'propName1': 'minifiedPropName1', |
| * 'publicName2': 'minifiedPropName2', |
| * } |
| * ``` |
| * |
| * Optionally the function can take `secondary` which will result in: (public name => declared name) |
| * |
| * ``` |
| * { |
| * 'propName1': 'propName1', |
| * 'publicName2': 'declaredPropName2', |
| * } |
| * ``` |
| * |
| |
| */ |
| function invertObject(obj, secondary) { |
| if (obj == null) |
| return EMPTY_OBJ; |
| var newLookup = {}; |
| for (var minifiedKey in obj) { |
| if (obj.hasOwnProperty(minifiedKey)) { |
| var publicName = obj[minifiedKey]; |
| var declaredName = publicName; |
| if (Array.isArray(publicName)) { |
| declaredName = publicName[1]; |
| publicName = publicName[0]; |
| } |
| newLookup[publicName] = minifiedKey; |
| if (secondary) { |
| (secondary[publicName] = declaredName); |
| } |
| } |
| } |
| return newLookup; |
| } |
| /** |
| * Create a base definition |
| * |
| * # Example |
| * ```ts |
| * class ShouldBeInherited { |
| * static ngBaseDef = ɵɵdefineBase({ |
| * ... |
| * }) |
| * } |
| * ``` |
| * |
| * @param baseDefinition The base definition parameters |
| * |
| * @codeGenApi |
| */ |
| function ɵɵdefineBase(baseDefinition) { |
| var declaredInputs = {}; |
| return { |
| inputs: invertObject(baseDefinition.inputs, declaredInputs), |
| declaredInputs: declaredInputs, |
| outputs: invertObject(baseDefinition.outputs), |
| viewQuery: baseDefinition.viewQuery || null, |
| contentQueries: baseDefinition.contentQueries || null, |
| hostBindings: baseDefinition.hostBindings || null |
| }; |
| } |
| /** |
| * Create a directive definition object. |
| * |
| * # Example |
| * ```ts |
| * class MyDirective { |
| * // Generated by Angular Template Compiler |
| * // [Symbol] syntax will not be supported by TypeScript until v2.7 |
| * static ngDirectiveDef = ɵɵdefineDirective({ |
| * ... |
| * }); |
| * } |
| * ``` |
| * |
| * @codeGenApi |
| */ |
| var ɵɵdefineDirective = ɵɵdefineComponent; |
| /** |
| * Create a pipe definition object. |
| * |
| * # Example |
| * ``` |
| * class MyPipe implements PipeTransform { |
| * // Generated by Angular Template Compiler |
| * static ngPipeDef = definePipe({ |
| * ... |
| * }); |
| * } |
| * ``` |
| * @param pipeDef Pipe definition generated by the compiler |
| * |
| * @codeGenApi |
| */ |
| function ɵɵdefinePipe(pipeDef) { |
| return { |
| name: pipeDef.name, |
| factory: pipeDef.factory, |
| pure: pipeDef.pure !== false, |
| onDestroy: pipeDef.type.prototype.ngOnDestroy || null |
| }; |
| } |
| /** |
| * The following getter methods retrieve the definition form the type. Currently the retrieval |
| * honors inheritance, but in the future we may change the rule to require that definitions are |
| * explicit. This would require some sort of migration strategy. |
| */ |
| function getComponentDef(type) { |
| return type[NG_COMPONENT_DEF] || null; |
| } |
| function getDirectiveDef(type) { |
| return type[NG_DIRECTIVE_DEF] || null; |
| } |
| function getPipeDef(type) { |
| return type[NG_PIPE_DEF] || null; |
| } |
| function getBaseDef(type) { |
| return type[NG_BASE_DEF] || null; |
| } |
| function getNgModuleDef(type, throwNotFound) { |
| var ngModuleDef = type[NG_MODULE_DEF] || null; |
| if (!ngModuleDef && throwNotFound === true) { |
| throw new Error("Type " + stringify(type) + " does not have 'ngModuleDef' property."); |
| } |
| return ngModuleDef; |
| } |
| function getNgLocaleIdDef(type) { |
| return type[NG_LOCALE_ID_DEF] || null; |
| } |
| |
| /** |
| * @license |
| * Copyright Google Inc. All Rights Reserved. |
| * |
| * Use of this source code is governed by an MIT-style license that can be |
| * found in the LICENSE file at https://angular.io/license |
| */ |
| /** |
| * Returns whether the values are different from a change detection stand point. |
| * |
| * Constraints are relaxed in checkNoChanges mode. See `devModeEqual` for details. |
| */ |
| function isDifferent(a, b) { |
| // NaN is the only value that is not equal to itself so the first |
| // test checks if both a and b are not NaN |
| return !(a !== a && b !== b) && a !== b; |
| } |
| /** |
| * Used for stringify render output in Ivy. |
| * Important! This function is very performance-sensitive and we should |
| * be extra careful not to introduce megamorphic reads in it. |
| */ |
| function renderStringify(value) { |
| if (typeof value === 'string') |
| return value; |
| if (value == null) |
| return ''; |
| return '' + value; |
| } |
| /** |
| * Used to stringify a value so that it can be displayed in an error message. |
| * Important! This function contains a megamorphic read and should only be |
| * used for error messages. |
| */ |
| function stringifyForError(value) { |
| if (typeof value === 'function') |
| return value.name || value.toString(); |
| if (typeof value === 'object' && value != null && typeof value.type === 'function') { |
| return value.type.name || value.type.toString(); |
| } |
| return renderStringify(value); |
| } |
| var ɵ0$6 = function () { |
| return (typeof requestAnimationFrame !== 'undefined' && requestAnimationFrame || // browser only |
| setTimeout // everything else |
| ).bind(_global); |
| }; |
| var defaultScheduler = (ɵ0$6)(); |
| /** |
| * |
| * @codeGenApi |
| */ |
| function ɵɵresolveWindow(element) { |
| return { name: 'window', target: element.ownerDocument.defaultView }; |
| } |
| /** |
| * |
| * @codeGenApi |
| */ |
| function ɵɵresolveDocument(element) { |
| return { name: 'document', target: element.ownerDocument }; |
| } |
| /** |
| * |
| * @codeGenApi |
| */ |
| function ɵɵresolveBody(element) { |
| return { name: 'body', target: element.ownerDocument.body }; |
| } |
| /** |
| * The special delimiter we use to separate property names, prefixes, and suffixes |
| * in property binding metadata. See storeBindingMetadata(). |
| * |
| * We intentionally use the Unicode "REPLACEMENT CHARACTER" (U+FFFD) as a delimiter |
| * because it is a very uncommon character that is unlikely to be part of a user's |
| * property names or interpolation strings. If it is in fact used in a property |
| * binding, DebugElement.properties will not return the correct value for that |
| * binding. However, there should be no runtime effect for real applications. |
| * |
| * This character is typically rendered as a question mark inside of a diamond. |
| * See https://en.wikipedia.org/wiki/Specials_(Unicode_block) |
| * |
| */ |
| var INTERPOLATION_DELIMITER = "\uFFFD"; |
| /** |
| * Determines whether or not the given string is a property metadata string. |
| * See storeBindingMetadata(). |
| */ |
| function isPropMetadataString(str) { |
| return str.indexOf(INTERPOLATION_DELIMITER) >= 0; |
| } |
| /** |
| * Unwrap a value which might be behind a closure (for forward declaration reasons). |
| */ |
| function maybeUnwrapFn(value) { |
| if (value instanceof Function) { |
| return value(); |
| } |
| else { |
| return value; |
| } |
| } |
| |
| /** |
| * @license |
| * Copyright Google Inc. All Rights Reserved. |
| * |
| * Use of this source code is governed by an MIT-style license that can be |
| * found in the LICENSE file at https://angular.io/license |
| */ |
| // Below are constants for LView indices to help us look up LView members |
| // without having to remember the specific indices. |
| // Uglify will inline these when minifying so there shouldn't be a cost. |
| var HOST = 0; |
| var TVIEW = 1; |
| var FLAGS = 2; |
| var PARENT = 3; |
| var NEXT = 4; |
| var QUERIES = 5; |
| var T_HOST = 6; |
| var BINDING_INDEX = 7; |
| var CLEANUP = 8; |
| var CONTEXT = 9; |
| var INJECTOR$1 = 10; |
| var RENDERER_FACTORY = 11; |
| var RENDERER = 12; |
| var SANITIZER = 13; |
| var CHILD_HEAD = 14; |
| var CHILD_TAIL = 15; |
| var CONTENT_QUERIES = 16; |
| var DECLARATION_VIEW = 17; |
| var PREORDER_HOOK_FLAGS = 18; |
| /** Size of LView's header. Necessary to adjust for it when setting slots. */ |
| var HEADER_OFFSET = 20; |
| |
| /** |
| * @license |
| * Copyright Google Inc. All Rights Reserved. |
| * |
| * Use of this source code is governed by an MIT-style license that can be |
| * found in the LICENSE file at https://angular.io/license |
| */ |
| function assertEqual(actual, expected, msg) { |
| if (actual != expected) { |
| throwError(msg); |
| } |
| } |
| function assertNotEqual(actual, expected, msg) { |
| if (actual == expected) { |
| throwError(msg); |
| } |
| } |
| function assertNotSame(actual, expected, msg) { |
| if (actual === expected) { |
| throwError(msg); |
| } |
| } |
| function assertLessThan(actual, expected, msg) { |
| if (actual >= expected) { |
| throwError(msg); |
| } |
| } |
| function assertGreaterThan(actual, expected, msg) { |
| if (actual <= expected) { |
| throwError(msg); |
| } |
| } |
| function assertDefined(actual, msg) { |
| if (actual == null) { |
| throwError(msg); |
| } |
| } |
| function throwError(msg) { |
| // tslint:disable-next-line |
| debugger; // Left intentionally for better debugger experience. |
| throw new Error("ASSERTION ERROR: " + msg); |
| } |
| function assertDomNode(node) { |
| // If we're in a worker, `Node` will not be defined. |
| assertEqual((typeof Node !== 'undefined' && node instanceof Node) || |
| (typeof node === 'object' && node.constructor.name === 'WebWorkerRenderNode'), true, "The provided value must be an instance of a DOM Node but got " + stringify(node)); |
| } |
| function assertDataInRange(arr, index) { |
| var maxLen = arr ? arr.length : 0; |
| assertLessThan(index, maxLen, "Index expected to be less than " + maxLen + " but got " + index); |
| } |
| |
| /** |
| * @license |
| * Copyright Google Inc. All Rights Reserved. |
| * |
| * Use of this source code is governed by an MIT-style license that can be |
| * found in the LICENSE file at https://angular.io/license |
| */ |
| /** |
| * Special location which allows easy identification of type. If we have an array which was |
| * retrieved from the `LView` and that array has `true` at `TYPE` location, we know it is |
| * `LContainer`. |
| */ |
| var TYPE = 1; |
| /** |
| * Below are constants for LContainer indices to help us look up LContainer members |
| * without having to remember the specific indices. |
| * Uglify will inline these when minifying so there shouldn't be a cost. |
| */ |
| var ACTIVE_INDEX = 2; |
| // PARENT, NEXT, QUERIES and T_HOST are indices 3, 4, 5 and 6. |
| // As we already have these constants in LView, we don't need to re-create them. |
| var NATIVE = 7; |
| var VIEW_REFS = 8; |
| /** |
| * Size of LContainer's header. Represents the index after which all views in the |
| * container will be inserted. We need to keep a record of current views so we know |
| * which views are already in the DOM (and don't need to be re-added) and so we can |
| * remove views from the DOM when they are no longer required. |
| */ |
| var CONTAINER_HEADER_OFFSET = 9; |
| |
| /** |
| * @license |
| * Copyright Google Inc. All Rights Reserved. |
| * |
| * Use of this source code is governed by an MIT-style license that can be |
| * found in the LICENSE file at https://angular.io/license |
| */ |
| /** |
| * This property will be monkey-patched on elements, components and directives |
| */ |
| var MONKEY_PATCH_KEY_NAME = '__ngContext__'; |
| |
| /** |
| * @license |
| * Copyright Google Inc. All Rights Reserved. |
| * |
| * Use of this source code is governed by an MIT-style license that can be |
| * found in the LICENSE file at https://angular.io/license |
| */ |
| /** |
| * For efficiency reasons we often put several different data types (`RNode`, `LView`, `LContainer`, |
| * `StylingContext`) in same location in `LView`. This is because we don't want to pre-allocate |
| * space for it because the storage is sparse. This file contains utilities for dealing with such |
| * data types. |
| * |
| * How do we know what is stored at a given location in `LView`. |
| * - `Array.isArray(value) === false` => `RNode` (The normal storage value) |
| * - `Array.isArray(value) === true` => then the `value[0]` represents the wrapped value. |
| * - `typeof value[TYPE] === 'object'` => `LView` |
| * - This happens when we have a component at a given location |
| * - `typeof value[TYPE] === 'number'` => `StylingContext` |
| * - This happens when we have style/class binding at a given location. |
| * - `typeof value[TYPE] === true` => `LContainer` |
| * - This happens when we have `LContainer` binding at a given location. |
| * |
| * |
| * NOTE: it is assumed that `Array.isArray` and `typeof` operations are very efficient. |
| */ |
| /** |
| * Returns `RNode`. |
| * @param value wrapped value of `RNode`, `LView`, `LContainer`, `StylingContext` |
| */ |
| function unwrapRNode(value) { |
| while (Array.isArray(value)) { |
| value = value[HOST]; |
| } |
| return value; |
| } |
| /** |
| * True if `value` is `LView`. |
| * @param value wrapped value of `RNode`, `LView`, `LContainer`, `StylingContext` |
| */ |
| function isLView(value) { |
| return Array.isArray(value) && typeof value[TYPE] === 'object'; |
| } |
| /** |
| * True if `value` is `LContainer`. |
| * @param value wrapped value of `RNode`, `LView`, `LContainer`, `StylingContext` |
| */ |
| function isLContainer(value) { |
| return Array.isArray(value) && value[TYPE] === true; |
| } |
| /** |
| * True if `value` is `StylingContext`. |
| * @param value wrapped value of `RNode`, `LView`, `LContainer`, `StylingContext` |
| */ |
| function isStylingContext(value) { |
| return Array.isArray(value) && typeof value[TYPE] === 'number'; |
| } |
| /** |
| * Retrieves an element value from the provided `viewData`, by unwrapping |
| * from any containers, component views, or style contexts. |
| */ |
| function getNativeByIndex(index, lView) { |
| return unwrapRNode(lView[index + HEADER_OFFSET]); |
| } |
| function getNativeByTNode(tNode, hostView) { |
| return unwrapRNode(hostView[tNode.index]); |
| } |
| /** |
| * A helper function that returns `true` if a given `TNode` has any matching directives. |
| */ |
| function hasDirectives(tNode) { |
| return tNode.directiveEnd > tNode.directiveStart; |
| } |
| function getTNode(index, view) { |
| ngDevMode && assertGreaterThan(index, -1, 'wrong index for TNode'); |
| ngDevMode && assertLessThan(index, view[TVIEW].data.length, 'wrong index for TNode'); |
| return view[TVIEW].data[index + HEADER_OFFSET]; |
| } |
| /** Retrieves a value from any `LView` or `TData`. */ |
| function loadInternal(view, index) { |
| ngDevMode && assertDataInRange(view, index + HEADER_OFFSET); |
| return view[index + HEADER_OFFSET]; |
| } |
| function getComponentViewByIndex(nodeIndex, hostView) { |
| // Could be an LView or an LContainer. If LContainer, unwrap to find LView. |
| var slotValue = hostView[nodeIndex]; |
| var lView = isLView(slotValue) ? slotValue : slotValue[HOST]; |
| return lView; |
| } |
| function isContentQueryHost(tNode) { |
| return (tNode.flags & 4 /* hasContentQuery */) !== 0; |
| } |
| function isComponent(tNode) { |
| return (tNode.flags & 1 /* isComponent */) === 1 /* isComponent */; |
| } |
| function isComponentDef(def) { |
| return def.template !== null; |
| } |
| function isRootView(target) { |
| return (target[FLAGS] & 512 /* IsRoot */) !== 0; |
| } |
| /** |
| * Returns the monkey-patch value data present on the target (which could be |
| * a component, directive or a DOM node). |
| */ |
| function readPatchedData(target) { |
| ngDevMode && assertDefined(target, 'Target expected'); |
| return target[MONKEY_PATCH_KEY_NAME]; |
| } |
| function readPatchedLView(target) { |
| var value = readPatchedData(target); |
| if (value) { |
| return Array.isArray(value) ? value : value.lView; |
| } |
| return null; |
| } |
| /** |
| * Returns a boolean for whether the view is attached to the change detection tree. |
| * |
| * Note: This determines whether a view should be checked, not whether it's inserted |
| * into a container. For that, you'll want `viewAttachedToContainer` below. |
| */ |
| function viewAttachedToChangeDetector(view) { |
| return (view[FLAGS] & 128 /* Attached */) === 128 /* Attached */; |
| } |
| /** Returns a boolean for whether the view is attached to a container. */ |
| function viewAttachedToContainer(view) { |
| return isLContainer(view[PARENT]); |
| } |
| /** |
| * Resets the pre-order hook flags of the view. |
| * @param lView the LView on which the flags are reset |
| */ |
| function resetPreOrderHookFlags(lView) { |
| lView[PREORDER_HOOK_FLAGS] = 0; |
| } |
| |
| /** |
| * @license |
| * Copyright Google Inc. All Rights Reserved. |
| * |
| * Use of this source code is governed by an MIT-style license that can be |
| * found in the LICENSE file at https://angular.io/license |
| */ |
| function assertComponentType(actual, msg) { |
| if (msg === void 0) { msg = 'Type passed in is not ComponentType, it does not have \'ngComponentDef\' property.'; } |
| if (!getComponentDef(actual)) { |
| throwError(msg); |
| } |
| } |
| function assertNgModuleType(actual, msg) { |
| if (msg === void 0) { msg = 'Type passed in is not NgModuleType, it does not have \'ngModuleDef\' property.'; } |
| if (!getNgModuleDef(actual)) { |
| throwError(msg); |
| } |
| } |
| function assertPreviousIsParent(isParent) { |
| assertEqual(isParent, true, 'previousOrParentTNode should be a parent'); |
| } |
| function assertHasParent(tNode) { |
| assertDefined(tNode, 'previousOrParentTNode should exist!'); |
| assertDefined(tNode.parent, 'previousOrParentTNode should have a parent'); |
| } |
| function assertLContainerOrUndefined(value) { |
| value && assertEqual(isLContainer(value), true, 'Expecting LContainer or undefined or null'); |
| } |
| function assertLContainer(value) { |
| assertDefined(value, 'LContainer must be defined'); |
| assertEqual(isLContainer(value), true, 'Expecting LContainer'); |
| } |
| function assertLViewOrUndefined(value) { |
| value && assertEqual(isLView(value), true, 'Expecting LView or undefined or null'); |
| } |
| function assertLView(value) { |
| assertDefined(value, 'LView must be defined'); |
| assertEqual(isLView(value), true, 'Expecting LView'); |
| } |
| |
| /** |
| * @license |
| * Copyright Google Inc. All Rights Reserved. |
| * |
| * Use of this source code is governed by an MIT-style license that can be |
| * found in the LICENSE file at https://angular.io/license |
| */ |
| /** |
| * Adds all directive lifecycle hooks from the given `DirectiveDef` to the given `TView`. |
| * |
| * Must be run *only* on the first template pass. |
| * |
| * Sets up the pre-order hooks on the provided `tView`, |
| * see {@link HookData} for details about the data structure. |
| * |
| * @param directiveIndex The index of the directive in LView |
| * @param directiveDef The definition containing the hooks to setup in tView |
| * @param tView The current TView |
| * @param nodeIndex The index of the node to which the directive is attached |
| * @param initialPreOrderHooksLength the number of pre-order hooks already registered before the |
| * current process, used to know if the node index has to be added to the array. If it is -1, |
| * the node index is never added. |
| * @param initialPreOrderCheckHooksLength same as previous for pre-order check hooks |
| */ |
| function registerPreOrderHooks(directiveIndex, directiveDef, tView, nodeIndex, initialPreOrderHooksLength, initialPreOrderCheckHooksLength) { |
| ngDevMode && |
| assertEqual(tView.firstTemplatePass, true, 'Should only be called on first template pass'); |
| var onChanges = directiveDef.onChanges, onInit = directiveDef.onInit, doCheck = directiveDef.doCheck; |
| if (initialPreOrderHooksLength >= 0 && |
| (!tView.preOrderHooks || initialPreOrderHooksLength === tView.preOrderHooks.length) && |
| (onChanges || onInit || doCheck)) { |
| (tView.preOrderHooks || (tView.preOrderHooks = [])).push(nodeIndex); |
| } |
| if (initialPreOrderCheckHooksLength >= 0 && |
| (!tView.preOrderCheckHooks || |
| initialPreOrderCheckHooksLength === tView.preOrderCheckHooks.length) && |
| (onChanges || doCheck)) { |
| (tView.preOrderCheckHooks || (tView.preOrderCheckHooks = [])).push(nodeIndex); |
| } |
| if (onChanges) { |
| (tView.preOrderHooks || (tView.preOrderHooks = [])).push(directiveIndex, onChanges); |
| (tView.preOrderCheckHooks || (tView.preOrderCheckHooks = [])).push(directiveIndex, onChanges); |
| } |
| if (onInit) { |
| (tView.preOrderHooks || (tView.preOrderHooks = [])).push(-directiveIndex, onInit); |
| } |
| if (doCheck) { |
| (tView.preOrderHooks || (tView.preOrderHooks = [])).push(directiveIndex, doCheck); |
| (tView.preOrderCheckHooks || (tView.preOrderCheckHooks = [])).push(directiveIndex, doCheck); |
| } |
| } |
| /** |
| * |
| * Loops through the directives on the provided `tNode` and queues hooks to be |
| * run that are not initialization hooks. |
| * |
| * Should be executed during `elementEnd()` and similar to |
| * preserve hook execution order. Content, view, and destroy hooks for projected |
| * components and directives must be called *before* their hosts. |
| * |
| * Sets up the content, view, and destroy hooks on the provided `tView`, |
| * see {@link HookData} for details about the data structure. |
| * |
| * NOTE: This does not set up `onChanges`, `onInit` or `doCheck`, those are set up |
| * separately at `elementStart`. |
| * |
| * @param tView The current TView |
| * @param tNode The TNode whose directives are to be searched for hooks to queue |
| */ |
| function registerPostOrderHooks(tView, tNode) { |
| if (tView.firstTemplatePass) { |
| // It's necessary to loop through the directives at elementEnd() (rather than processing in |
| // directiveCreate) so we can preserve the current hook order. Content, view, and destroy |
| // hooks for projected components and directives must be called *before* their hosts. |
| for (var i = tNode.directiveStart, end = tNode.directiveEnd; i < end; i++) { |
| var directiveDef = tView.data[i]; |
| if (directiveDef.afterContentInit) { |
| (tView.contentHooks || (tView.contentHooks = [])).push(-i, directiveDef.afterContentInit); |
| } |
| if (directiveDef.afterContentChecked) { |
| (tView.contentHooks || (tView.contentHooks = [])).push(i, directiveDef.afterContentChecked); |
| (tView.contentCheckHooks || (tView.contentCheckHooks = [])).push(i, directiveDef.afterContentChecked); |
| } |
| if (directiveDef.afterViewInit) { |
| (tView.viewHooks || (tView.viewHooks = [])).push(-i, directiveDef.afterViewInit); |
| } |
| if (directiveDef.afterViewChecked) { |
| (tView.viewHooks || (tView.viewHooks = [])).push(i, directiveDef.afterViewChecked); |
| (tView.viewCheckHooks || (tView.viewCheckHooks = [])).push(i, directiveDef.afterViewChecked); |
| } |
| if (directiveDef.onDestroy != null) { |
| (tView.destroyHooks || (tView.destroyHooks = [])).push(i, directiveDef.onDestroy); |
| } |
| } |
| } |
| } |
| /** |
| * Executing hooks requires complex logic as we need to deal with 2 constraints. |
| * |
| * 1. Init hooks (ngOnInit, ngAfterContentInit, ngAfterViewInit) must all be executed once and only |
| * once, across many change detection cycles. This must be true even if some hooks throw, or if |
| * some recursively trigger a change detection cycle. |
| * To solve that, it is required to track the state of the execution of these init hooks. |
| * This is done by storing and maintaining flags in the view: the {@link InitPhaseState}, |
| * and the index within that phase. They can be seen as a cursor in the following structure: |
| * [[onInit1, onInit2], [afterContentInit1], [afterViewInit1, afterViewInit2, afterViewInit3]] |
| * They are are stored as flags in LView[FLAGS]. |
| * |
| * 2. Pre-order hooks can be executed in batches, because of the select instruction. |
| * To be able to pause and resume their execution, we also need some state about the hook's array |
| * that is being processed: |
| * - the index of the next hook to be executed |
| * - the number of init hooks already found in the processed part of the array |
| * They are are stored as flags in LView[PREORDER_HOOK_FLAGS]. |
| */ |
| /** |
| * Executes necessary hooks at the start of executing a template. |
| * |
| * Executes hooks that are to be run during the initialization of a directive such |
| * as `onChanges`, `onInit`, and `doCheck`. |
| * |
| * @param lView The current view |
| * @param tView Static data for the view containing the hooks to be executed |
| * @param checkNoChangesMode Whether or not we're in checkNoChanges mode. |
| * @param @param currentNodeIndex 2 cases depending the the value: |
| * - undefined: execute hooks only from the saved index until the end of the array (pre-order case, |
| * when flushing the remaining hooks) |
| * - number: execute hooks only from the saved index until that node index exclusive (pre-order |
| * case, when executing select(number)) |
| */ |
| function executePreOrderHooks(currentView, tView, checkNoChangesMode, currentNodeIndex) { |
| if (!checkNoChangesMode) { |
| executeHooks(currentView, tView.preOrderHooks, tView.preOrderCheckHooks, checkNoChangesMode, 0 /* OnInitHooksToBeRun */, currentNodeIndex !== undefined ? currentNodeIndex : null); |
| } |
| } |
| /** |
| * Executes hooks against the given `LView` based off of whether or not |
| * This is the first pass. |
| * |
| * @param currentView The view instance data to run the hooks against |
| * @param firstPassHooks An array of hooks to run if we're in the first view pass |
| * @param checkHooks An Array of hooks to run if we're not in the first view pass. |
| * @param checkNoChangesMode Whether or not we're in no changes mode. |
| * @param initPhaseState the current state of the init phase |
| * @param currentNodeIndex 3 cases depending the the value: |
| * - undefined: all hooks from the array should be executed (post-order case) |
| * - null: execute hooks only from the saved index until the end of the array (pre-order case, when |
| * flushing the remaining hooks) |
| * - number: execute hooks only from the saved index until that node index exclusive (pre-order |
| * case, when executing select(number)) |
| */ |
| function executeHooks(currentView, firstPassHooks, checkHooks, checkNoChangesMode, initPhaseState, currentNodeIndex) { |
| if (checkNoChangesMode) |
| return; |
| var hooksToCall = (currentView[FLAGS] & 3 /* InitPhaseStateMask */) === initPhaseState ? |
| firstPassHooks : |
| checkHooks; |
| if (hooksToCall) { |
| callHooks(currentView, hooksToCall, initPhaseState, currentNodeIndex); |
| } |
| // The init phase state must be always checked here as it may have been recursively updated |
| if (currentNodeIndex == null && |
| (currentView[FLAGS] & 3 /* InitPhaseStateMask */) === initPhaseState && |
| initPhaseState !== 3 /* InitPhaseCompleted */) { |
| currentView[FLAGS] &= 1023 /* IndexWithinInitPhaseReset */; |
| currentView[FLAGS] += 1 /* InitPhaseStateIncrementer */; |
| } |
| } |
| /** |
| * Calls lifecycle hooks with their contexts, skipping init hooks if it's not |
| * the first LView pass |
| * |
| * @param currentView The current view |
| * @param arr The array in which the hooks are found |
| * @param initPhaseState the current state of the init phase |
| * @param currentNodeIndex 3 cases depending the the value: |
| * - undefined: all hooks from the array should be executed (post-order case) |
| * - null: execute hooks only from the saved index until the end of the array (pre-order case, when |
| * flushing the remaining hooks) |
| * - number: execute hooks only from the saved index until that node index exclusive (pre-order |
| * case, when executing select(number)) |
| */ |
| function callHooks(currentView, arr, initPhase, currentNodeIndex) { |
| var startIndex = currentNodeIndex !== undefined ? |
| (currentView[PREORDER_HOOK_FLAGS] & 65535 /* IndexOfTheNextPreOrderHookMaskMask */) : |
| 0; |
| var nodeIndexLimit = currentNodeIndex != null ? currentNodeIndex : -1; |
| var lastNodeIndexFound = 0; |
| for (var i = startIndex; i < arr.length; i++) { |
| var hook = arr[i + 1]; |
| if (typeof hook === 'number') { |
| lastNodeIndexFound = arr[i]; |
| if (currentNodeIndex != null && lastNodeIndexFound >= currentNodeIndex) { |
| break; |
| } |
| } |
| else { |
| var isInitHook = arr[i] < 0; |
| if (isInitHook) |
| currentView[PREORDER_HOOK_FLAGS] += 65536 /* NumberOfInitHooksCalledIncrementer */; |
| if (lastNodeIndexFound < nodeIndexLimit || nodeIndexLimit == -1) { |
| callHook(currentView, initPhase, arr, i); |
| currentView[PREORDER_HOOK_FLAGS] = |
| (currentView[PREORDER_HOOK_FLAGS] & 4294901760 /* NumberOfInitHooksCalledMask */) + i + |
| 2; |
| } |
| i++; |
| } |
| } |
| } |
| /** |
| * Execute one hook against the current `LView`. |
| * |
| * @param currentView The current view |
| * @param initPhaseState the current state of the init phase |
| * @param arr The array in which the hooks are found |
| * @param i The current index within the hook data array |
| */ |
| function callHook(currentView, initPhase, arr, i) { |
| var isInitHook = arr[i] < 0; |
| var hook = arr[i + 1]; |
| var directiveIndex = isInitHook ? -arr[i] : arr[i]; |
| var directive = currentView[directiveIndex]; |
| if (isInitHook) { |
| var indexWithintInitPhase = currentView[FLAGS] >> 10 /* IndexWithinInitPhaseShift */; |
| // The init phase state must be always checked here as it may have been recursively |
| // updated |
| if (indexWithintInitPhase < |
| (currentView[PREORDER_HOOK_FLAGS] >> 16 /* NumberOfInitHooksCalledShift */) && |
| (currentView[FLAGS] & 3 /* InitPhaseStateMask */) === initPhase) { |
| currentView[FLAGS] += 1024 /* IndexWithinInitPhaseIncrementer */; |
| hook.call(directive); |
| } |
| } |
| else { |
| hook.call(directive); |
| } |
| } |
| |
| var stylingContext = null; |
| /** |
| * Gets the most recent styling context value. |
| * |
| * Note that only one styling context is stored at a given time. |
| */ |
| function getCachedStylingContext() { |
| return stylingContext; |
| } |
| /** |
| * Sets the most recent styling context value. |
| * |
| * Note that only one styling context is stored at a given time. |
| * |
| * @param context The styling context value that will be stored |
| */ |
| function setCachedStylingContext(context) { |
| stylingContext = context; |
| } |
| |
| /** |
| * @license |
| * Copyright Google Inc. All Rights Reserved. |
| * |
| * Use of this source code is governed by an MIT-style license that can be |
| * found in the LICENSE file at https://angular.io/license |
| */ |
| /** |
| * Store the element depth count. This is used to identify the root elements of the template |
| * so that we can than attach `LView` to only those elements. |
| */ |
| var elementDepthCount; |
| function getElementDepthCount() { |
| // top level variables should not be exported for performance reasons (PERF_NOTES.md) |
| return elementDepthCount; |
| } |
| function increaseElementDepthCount() { |
| elementDepthCount++; |
| } |
| function decreaseElementDepthCount() { |
| elementDepthCount--; |
| } |
| var currentDirectiveDef = null; |
| function getCurrentDirectiveDef() { |
| // top level variables should not be exported for performance reasons (PERF_NOTES.md) |
| return currentDirectiveDef; |
| } |
| function setCurrentDirectiveDef(def) { |
| currentDirectiveDef = def; |
| } |
| /** |
| * Stores whether directives should be matched to elements. |
| * |
| * When template contains `ngNonBindable` than we need to prevent the runtime form matching |
| * directives on children of that element. |
| * |
| * Example: |
| * ``` |
| * <my-comp my-directive> |
| * Should match component / directive. |
| * </my-comp> |
| * <div ngNonBindable> |
| * <my-comp my-directive> |
| * Should not match component / directive because we are in ngNonBindable. |
| * </my-comp> |
| * </div> |
| * ``` |
| */ |
| var bindingsEnabled; |
| function getBindingsEnabled() { |
| // top level variables should not be exported for performance reasons (PERF_NOTES.md) |
| return bindingsEnabled; |
| } |
| /** |
| * Enables directive matching on elements. |
| * |
| * * Example: |
| * ``` |
| * <my-comp my-directive> |
| * Should match component / directive. |
| * </my-comp> |
| * <div ngNonBindable> |
| * <!-- ɵɵdisableBindings() --> |
| * <my-comp my-directive> |
| * Should not match component / directive because we are in ngNonBindable. |
| * </my-comp> |
| * <!-- ɵɵenableBindings() --> |
| * </div> |
| * ``` |
| * |
| * @codeGenApi |
| */ |
| function ɵɵenableBindings() { |
| bindingsEnabled = true; |
| } |
| /** |
| * Disables directive matching on element. |
| * |
| * * Example: |
| * ``` |
| * <my-comp my-directive> |
| * Should match component / directive. |
| * </my-comp> |
| * <div ngNonBindable> |
| * <!-- ɵɵdisableBindings() --> |
| * <my-comp my-directive> |
| * Should not match component / directive because we are in ngNonBindable. |
| * </my-comp> |
| * <!-- ɵɵenableBindings() --> |
| * </div> |
| * ``` |
| * |
| * @codeGenApi |
| */ |
| function ɵɵdisableBindings() { |
| bindingsEnabled = false; |
| } |
| function getLView() { |
| return lView; |
| } |
| /** |
| * Used as the starting directive id value. |
| * |
| * All subsequent directives are incremented from this value onwards. |
| * The reason why this value is `1` instead of `0` is because the `0` |
| * value is reserved for the template. |
| */ |
| var MIN_DIRECTIVE_ID = 1; |
| var activeDirectiveId = MIN_DIRECTIVE_ID; |
| /** |
| * Position depth (with respect from leaf to root) in a directive sub-class inheritance chain. |
| */ |
| var activeDirectiveSuperClassDepthPosition = 0; |
| /** |
| * Total count of how many directives are a part of an inheritance chain. |
| * |
| * When directives are sub-classed (extended) from one to another, Angular |
| * needs to keep track of exactly how many were encountered so it can accurately |
| * generate the next directive id (once the next directive id is visited). |
| * Normally the next directive id just a single incremented value from the |
| * previous one, however, if the previous directive is a part of an inheritance |
| * chain (a series of sub-classed directives) then the incremented value must |
| * also take into account the total amount of sub-classed values. |
| * |
| * Note that this value resets back to zero once the next directive is |
| * visited (when `incrementActiveDirectiveId` or `setActiveHostElement` |
| * is called). |
| */ |
| var activeDirectiveSuperClassHeight = 0; |
| /** |
| * Sets the active directive host element and resets the directive id value |
| * (when the provided elementIndex value has changed). |
| * |
| * @param elementIndex the element index value for the host element where |
| * the directive/component instance lives |
| */ |
| function setActiveHostElement(elementIndex) { |
| if (elementIndex === void 0) { elementIndex = null; } |
| if (_selectedIndex !== elementIndex) { |
| setSelectedIndex(elementIndex == null ? -1 : elementIndex); |
| activeDirectiveId = elementIndex == null ? 0 : MIN_DIRECTIVE_ID; |
| activeDirectiveSuperClassDepthPosition = 0; |
| activeDirectiveSuperClassHeight = 0; |
| } |
| } |
| /** |
| * Returns the current id value of the current directive. |
| * |
| * For example we have an element that has two directives on it: |
| * <div dir-one dir-two></div> |
| * |
| * dirOne->hostBindings() (id == 1) |
| * dirTwo->hostBindings() (id == 2) |
| * |
| * Note that this is only active when `hostBinding` functions are being processed. |
| * |
| * Note that directive id values are specific to an element (this means that |
| * the same id value could be present on another element with a completely |
| * different set of directives). |
| */ |
| function getActiveDirectiveId() { |
| return activeDirectiveId; |
| } |
| /** |
| * Increments the current directive id value. |
| * |
| * For example we have an element that has two directives on it: |
| * <div dir-one dir-two></div> |
| * |
| * dirOne->hostBindings() (index = 1) |
| * // increment |
| * dirTwo->hostBindings() (index = 2) |
| * |
| * Depending on whether or not a previous directive had any inherited |
| * directives present, that value will be incremented in addition |
| * to the id jumping up by one. |
| * |
| * Note that this is only active when `hostBinding` functions are being processed. |
| * |
| * Note that directive id values are specific to an element (this means that |
| * the same id value could be present on another element with a completely |
| * different set of directives). |
| */ |
| function incrementActiveDirectiveId() { |
| activeDirectiveId += 1 + activeDirectiveSuperClassHeight; |
| // because we are dealing with a new directive this |
| // means we have exited out of the inheritance chain |
| activeDirectiveSuperClassDepthPosition = 0; |
| activeDirectiveSuperClassHeight = 0; |
| } |
| /** |
| * Set the current super class (reverse inheritance) position depth for a directive. |
| * |
| * For example we have two directives: Child and Other (but Child is a sub-class of Parent) |
| * <div child-dir other-dir></div> |
| * |
| * // increment |
| * parentInstance->hostBindings() (depth = 1) |
| * // decrement |
| * childInstance->hostBindings() (depth = 0) |
| * otherInstance->hostBindings() (depth = 0 b/c it's a different directive) |
| * |
| * Note that this is only active when `hostBinding` functions are being processed. |
| */ |
| function adjustActiveDirectiveSuperClassDepthPosition(delta) { |
| activeDirectiveSuperClassDepthPosition += delta; |
| // we keep track of the height value so that when the next directive is visited |
| // then Angular knows to generate a new directive id value which has taken into |
| // account how many sub-class directives were a part of the previous directive. |
| activeDirectiveSuperClassHeight = |
| Math.max(activeDirectiveSuperClassHeight, activeDirectiveSuperClassDepthPosition); |
| } |
| /** |
| * Returns he current depth of the super/sub class inheritance chain. |
| * |
| * This will return how many inherited directive/component classes |
| * exist in the current chain. |
| * |
| * ```typescript |
| * @Directive({ selector: '[super-dir]' }) |
| * class SuperDir {} |
| * |
| * @Directive({ selector: '[sub-dir]' }) |
| * class SubDir extends SuperDir {} |
| * |
| * // if `<div sub-dir>` is used then the super class height is `1` |
| * // if `<div super-dir>` is used then the super class height is `0` |
| * ``` |
| */ |
| function getActiveDirectiveSuperClassHeight() { |
| return activeDirectiveSuperClassHeight; |
| } |
| /** |
| * Returns the current super class (reverse inheritance) depth for a directive. |
| * |
| * This is designed to help instruction code distinguish different hostBindings |
| * calls from each other when a directive has extended from another directive. |
| * Normally using the directive id value is enough, but with the case |
| * of parent/sub-class directive inheritance more information is required. |
| * |
| * Note that this is only active when `hostBinding` functions are being processed. |
| */ |
| function getActiveDirectiveSuperClassDepth() { |
| return activeDirectiveSuperClassDepthPosition; |
| } |
| /** |
| * Restores `contextViewData` to the given OpaqueViewState instance. |
| * |
| * Used in conjunction with the getCurrentView() instruction to save a snapshot |
| * of the current view and restore it when listeners are invoked. This allows |
| * walking the declaration view tree in listeners to get vars from parent views. |
| * |
| * @param viewToRestore The OpaqueViewState instance to restore. |
| * |
| * @codeGenApi |
| */ |
| function ɵɵrestoreView(viewToRestore) { |
| contextLView = viewToRestore; |
| } |
| /** Used to set the parent property when nodes are created and track query results. */ |
| var previousOrParentTNode; |
| function getPreviousOrParentTNode() { |
| // top level variables should not be exported for performance reasons (PERF_NOTES.md) |
| return previousOrParentTNode; |
| } |
| function setPreviousOrParentTNode(tNode, _isParent) { |
| previousOrParentTNode = tNode; |
| isParent = _isParent; |
| } |
| function setTNodeAndViewData(tNode, view) { |
| ngDevMode && assertLViewOrUndefined(view); |
| previousOrParentTNode = tNode; |
| lView = view; |
| } |
| /** |
| * If `isParent` is: |
| * - `true`: then `previousOrParentTNode` points to a parent node. |
| * - `false`: then `previousOrParentTNode` points to previous node (sibling). |
| */ |
| var isParent; |
| function getIsParent() { |
| // top level variables should not be exported for performance reasons (PERF_NOTES.md) |
| return isParent; |
| } |
| function setIsNotParent() { |
| isParent = false; |
| } |
| function setIsParent() { |
| isParent = true; |
| } |
| /** Checks whether a given view is in creation mode */ |
| function isCreationMode(view) { |
| if (view === void 0) { view = lView; } |
| return (view[FLAGS] & 4 /* CreationMode */) === 4 /* CreationMode */; |
| } |
| /** |
| * State of the current view being processed. |
| * |
| * An array of nodes (text, element, container, etc), pipes, their bindings, and |
| * any local variables that need to be stored between invocations. |
| */ |
| var lView; |
| /** |
| * The last viewData retrieved by nextContext(). |
| * Allows building nextContext() and reference() calls. |
| * |
| * e.g. const inner = x().$implicit; const outer = x().$implicit; |
| */ |
| var contextLView = null; |
| function getContextLView() { |
| // top level variables should not be exported for performance reasons (PERF_NOTES.md) |
| return contextLView; |
| } |
| /** |
| * In this mode, any changes in bindings will throw an ExpressionChangedAfterChecked error. |
| * |
| * Necessary to support ChangeDetectorRef.checkNoChanges(). |
| */ |
| var checkNoChangesMode = false; |
| function getCheckNoChangesMode() { |
| // top level variables should not be exported for performance reasons (PERF_NOTES.md) |
| return checkNoChangesMode; |
| } |
| function setCheckNoChangesMode(mode) { |
| checkNoChangesMode = mode; |
| } |
| /** |
| * The root index from which pure function instructions should calculate their binding |
| * indices. In component views, this is TView.bindingStartIndex. In a host binding |
| * context, this is the TView.expandoStartIndex + any dirs/hostVars before the given dir. |
| */ |
| var bindingRootIndex = -1; |
| // top level variables should not be exported for performance reasons (PERF_NOTES.md) |
| function getBindingRoot() { |
| return bindingRootIndex; |
| } |
| function setBindingRoot(value) { |
| bindingRootIndex = value; |
| } |
| /** |
| * Current index of a View or Content Query which needs to be processed next. |
| * We iterate over the list of Queries and increment current query index at every step. |
| */ |
| var currentQueryIndex = 0; |
| function getCurrentQueryIndex() { |
| // top level variables should not be exported for performance reasons (PERF_NOTES.md) |
| return currentQueryIndex; |
| } |
| function setCurrentQueryIndex(value) { |
| currentQueryIndex = value; |
| } |
| /** |
| * Swap the current state with a new state. |
| * |
| * For performance reasons we store the state in the top level of the module. |
| * This way we minimize the number of properties to read. Whenever a new view |
| * is entered we have to store the state for later, and when the view is |
| * exited the state has to be restored |
| * |
| * @param newView New state to become active |
| * @param host Element to which the View is a child of |
| * @returns the previous state; |
| */ |
| function enterView(newView, hostTNode) { |
| ngDevMode && assertLViewOrUndefined(newView); |
| var oldView = lView; |
| if (newView) { |
| var tView = newView[TVIEW]; |
| bindingRootIndex = tView.bindingStartIndex; |
| } |
| previousOrParentTNode = hostTNode; |
| isParent = true; |
| lView = contextLView = newView; |
| return oldView; |
| } |
| function nextContextImpl(level) { |
| if (level === void 0) { level = 1; } |
| contextLView = walkUpViews(level, contextLView); |
| return contextLView[CONTEXT]; |
| } |
| function walkUpViews(nestingLevel, currentView) { |
| while (nestingLevel > 0) { |
| ngDevMode && assertDefined(currentView[DECLARATION_VIEW], 'Declaration view should be defined if nesting level is greater than 0.'); |
| currentView = currentView[DECLARATION_VIEW]; |
| nestingLevel--; |
| } |
| return currentView; |
| } |
| /** |
| * Resets the application state. |
| */ |
| function resetComponentState() { |
| isParent = false; |
| previousOrParentTNode = null; |
| elementDepthCount = 0; |
| bindingsEnabled = true; |
| } |
| /** |
| * Used in lieu of enterView to make it clear when we are exiting a child view. This makes |
| * the direction of traversal (up or down the view tree) a bit clearer. |
| * |
| * @param newView New state to become active |
| * @param safeToRunHooks Whether the runtime is in a state where running lifecycle hooks is valid. |
| * This is not always the case (for example, the application may have crashed and `leaveView` is |
| * being executed while unwinding the call stack). |
| */ |
| function leaveView(newView, safeToRunHooks) { |
| var tView = lView[TVIEW]; |
| if (isCreationMode(lView)) { |
| lView[FLAGS] &= ~4 /* CreationMode */; |
| } |
| else { |
| try { |
| resetPreOrderHookFlags(lView); |
| safeToRunHooks && executeHooks(lView, tView.viewHooks, tView.viewCheckHooks, checkNoChangesMode, 2 /* AfterViewInitHooksToBeRun */, undefined); |
| } |
| finally { |
| // Views are clean and in update mode after being checked, so these bits are cleared |
| lView[FLAGS] &= ~(64 /* Dirty */ | 8 /* FirstLViewPass */); |
| lView[BINDING_INDEX] = tView.bindingStartIndex; |
| } |
| } |
| setCachedStylingContext(null); |
| enterView(newView, null); |
| } |
| var _selectedIndex = -1; |
| /** |
| * Gets the most recent index passed to {@link select} |
| * |
| * Used with {@link property} instruction (and more in the future) to identify the index in the |
| * current `LView` to act on. |
| */ |
| function getSelectedIndex() { |
| return _selectedIndex; |
| } |
| /** |
| * Sets the most recent index passed to {@link select} |
| * |
| * Used with {@link property} instruction (and more in the future) to identify the index in the |
| * current `LView` to act on. |
| */ |
| function setSelectedIndex(index) { |
| _selectedIndex = index; |
| // remove the styling context from the cache |
| // because we are now on a different element |
| setCachedStylingContext(null); |
| } |
| var _currentNamespace = null; |
| /** |
| * Sets the namespace used to create elements to `'http://www.w3.org/2000/svg'` in global state. |
| * |
| * @codeGenApi |
| */ |
| function ɵɵnamespaceSVG() { |
| _currentNamespace = 'http://www.w3.org/2000/svg'; |
| } |
| /** |
| * Sets the namespace used to create elements to `'http://www.w3.org/1998/MathML/'` in global state. |
| * |
| * @codeGenApi |
| */ |
| function ɵɵnamespaceMathML() { |
| _currentNamespace = 'http://www.w3.org/1998/MathML/'; |
| } |
| /** |
| * Sets the namespace used to create elements no `null`, which forces element creation to use |
| * `createElement` rather than `createElementNS`. |
| * |
| * @codeGenApi |
| */ |
| function ɵɵnamespaceHTML() { |
| _currentNamespace = null; |
| } |
| function getNamespace() { |
| return _currentNamespace; |
| } |
| |
| /** |
| * @license |
| * Copyright Google Inc. All Rights Reserved. |
| * |
| * Use of this source code is governed by an MIT-style license that can be |
| * found in the LICENSE file at https://angular.io/license |
| */ |
| var BRAND = '__SANITIZER_TRUSTED_BRAND__'; |
| function allowSanitizationBypass(value, type) { |
| return (value instanceof String && value[BRAND] === type); |
| } |
| /** |
| * Mark `html` string as trusted. |
| * |
| * This function wraps the trusted string in `String` and brands it in a way which makes it |
| * recognizable to {@link htmlSanitizer} to be trusted implicitly. |
| * |
| * @param trustedHtml `html` string which needs to be implicitly trusted. |
| * @returns a `html` `String` which has been branded to be implicitly trusted. |
| */ |
| function bypassSanitizationTrustHtml(trustedHtml) { |
| return bypassSanitizationTrustString(trustedHtml, "Html" /* Html */); |
| } |
| /** |
| * Mark `style` string as trusted. |
| * |
| * This function wraps the trusted string in `String` and brands it in a way which makes it |
| * recognizable to {@link styleSanitizer} to be trusted implicitly. |
| * |
| * @param trustedStyle `style` string which needs to be implicitly trusted. |
| * @returns a `style` `String` which has been branded to be implicitly trusted. |
| */ |
| function bypassSanitizationTrustStyle(trustedStyle) { |
| return bypassSanitizationTrustString(trustedStyle, "Style" /* Style */); |
| } |
| /** |
| * Mark `script` string as trusted. |
| * |
| * This function wraps the trusted string in `String` and brands it in a way which makes it |
| * recognizable to {@link scriptSanitizer} to be trusted implicitly. |
| * |
| * @param trustedScript `script` string which needs to be implicitly trusted. |
| * @returns a `script` `String` which has been branded to be implicitly trusted. |
| */ |
| function bypassSanitizationTrustScript(trustedScript) { |
| return bypassSanitizationTrustString(trustedScript, "Script" /* Script */); |
| } |
| /** |
| * Mark `url` string as trusted. |
| * |
| * This function wraps the trusted string in `String` and brands it in a way which makes it |
| * recognizable to {@link urlSanitizer} to be trusted implicitly. |
| * |
| * @param trustedUrl `url` string which needs to be implicitly trusted. |
| * @returns a `url` `String` which has been branded to be implicitly trusted. |
| */ |
| function bypassSanitizationTrustUrl(trustedUrl) { |
| return bypassSanitizationTrustString(trustedUrl, "Url" /* Url */); |
| } |
| /** |
| * Mark `url` string as trusted. |
| * |
| * This function wraps the trusted string in `String` and brands it in a way which makes it |
| * recognizable to {@link resourceUrlSanitizer} to be trusted implicitly. |
| * |
| * @param trustedResourceUrl `url` string which needs to be implicitly trusted. |
| * @returns a `url` `String` which has been branded to be implicitly trusted. |
| */ |
| function bypassSanitizationTrustResourceUrl(trustedResourceUrl) { |
| return bypassSanitizationTrustString(trustedResourceUrl, "ResourceUrl" /* ResourceUrl */); |
| } |
| function bypassSanitizationTrustString(trustedString, mode) { |
| var trusted = new String(trustedString); |
| trusted[BRAND] = mode; |
| return trusted; |
| } |
| |
| /** |
| * @license |
| * Copyright Google Inc. All Rights Reserved. |
| * |
| * Use of this source code is governed by an MIT-style license that can be |
| * found in the LICENSE file at https://angular.io/license |
| */ |
| /** |
| * This file is used to control if the default rendering pipeline should be `ViewEngine` or `Ivy`. |
| * |
| * For more information on how to run and debug tests with either Ivy or View Engine (legacy), |
| * please see [BAZEL.md](./docs/BAZEL.md). |
| */ |
| var _devMode = true; |
| var _runModeLocked = false; |
| /** |
| * Returns whether Angular is in development mode. After called once, |
| * the value is locked and won't change any more. |
| * |
| * By default, this is true, unless a user calls `enableProdMode` before calling this. |
| * |
| * @publicApi |
| */ |
| function isDevMode() { |
| _runModeLocked = true; |
| return _devMode; |
| } |
| /** |
| * Disable Angular's development mode, which turns off assertions and other |
| * checks within the framework. |
| * |
| * One important assertion this disables verifies that a change detection pass |
| * does not result in additional changes to any bindings (also known as |
| * unidirectional data flow). |
| * |
| * @publicApi |
| */ |
| function enableProdMode() { |
| if (_runModeLocked) { |
| throw new Error('Cannot enable prod mode after platform setup.'); |
| } |
| _devMode = false; |
| } |
| |
| /** |
| * @license |
| * Copyright Google Inc. All Rights Reserved. |
| * |
| * Use of this source code is governed by an MIT-style license that can be |
| * found in the LICENSE file at https://angular.io/license |
| */ |
| /** |
| * This helper class is used to get hold of an inert tree of DOM elements containing dirty HTML |
| * that needs sanitizing. |
| * Depending upon browser support we must use one of three strategies for doing this. |
| * Support: Safari 10.x -> XHR strategy |
| * Support: Firefox -> DomParser strategy |
| * Default: InertDocument strategy |
| */ |
| var InertBodyHelper = /** @class */ (function () { |
| function InertBodyHelper(defaultDoc) { |
| this.defaultDoc = defaultDoc; |
| this.inertDocument = this.defaultDoc.implementation.createHTMLDocument('sanitization-inert'); |
| this.inertBodyElement = this.inertDocument.body; |
| if (this.inertBodyElement == null) { |
| // usually there should be only one body element in the document, but IE doesn't have any, so |
| // we need to create one. |
| var inertHtml = this.inertDocument.createElement('html'); |
| this.inertDocument.appendChild(inertHtml); |
| this.inertBodyElement = this.inertDocument.createElement('body'); |
| inertHtml.appendChild(this.inertBodyElement); |
| } |
| this.inertBodyElement.innerHTML = '<svg><g onload="this.parentNode.remove()"></g></svg>'; |
| if (this.inertBodyElement.querySelector && !this.inertBodyElement.querySelector('svg')) { |
| // We just hit the Safari 10.1 bug - which allows JS to run inside the SVG G element |
| // so use the XHR strategy. |
| this.getInertBodyElement = this.getInertBodyElement_XHR; |
| return; |
| } |
| this.inertBodyElement.innerHTML = |
| '<svg><p><style><img src="</style><img src=x onerror=alert(1)//">'; |
| if (this.inertBodyElement.querySelector && this.inertBodyElement.querySelector('svg img')) { |
| // We just hit the Firefox bug - which prevents the inner img JS from being sanitized |
| // so use the DOMParser strategy, if it is available. |
| // If the DOMParser is not available then we are not in Firefox (Server/WebWorker?) so we |
| // fall through to the default strategy below. |
| if (isDOMParserAvailable()) { |
| this.getInertBodyElement = this.getInertBodyElement_DOMParser; |
| return; |
| } |
| } |
| // None of the bugs were hit so it is safe for us to use the default InertDocument strategy |
| this.getInertBodyElement = this.getInertBodyElement_InertDocument; |
| } |
| /** |
| * Use XHR to create and fill an inert body element (on Safari 10.1) |
| * See |
| * https://github.com/cure53/DOMPurify/blob/a992d3a75031cb8bb032e5ea8399ba972bdf9a65/src/purify.js#L439-L449 |
| */ |
| InertBodyHelper.prototype.getInertBodyElement_XHR = function (html) { |
| // We add these extra elements to ensure that the rest of the content is parsed as expected |
| // e.g. leading whitespace is maintained and tags like `<meta>` do not get hoisted to the |
| // `<head>` tag. |
| html = '<body><remove></remove>' + html + '</body>'; |
| try { |
| html = encodeURI(html); |
| } |
| catch (_a) { |
| return null; |
| } |
| var xhr = new XMLHttpRequest(); |
| xhr.responseType = 'document'; |
| xhr.open('GET', 'data:text/html;charset=utf-8,' + html, false); |
| xhr.send(undefined); |
| var body = xhr.response.body; |
| body.removeChild(body.firstChild); |
| return body; |
| }; |
| /** |
| * Use DOMParser to create and fill an inert body element (on Firefox) |
| * See https://github.com/cure53/DOMPurify/releases/tag/0.6.7 |
| * |
| */ |
| InertBodyHelper.prototype.getInertBodyElement_DOMParser = function (html) { |
| // We add these extra elements to ensure that the rest of the content is parsed as expected |
| // e.g. leading whitespace is maintained and tags like `<meta>` do not get hoisted to the |
| // `<head>` tag. |
| html = '<body><remove></remove>' + html + '</body>'; |
| try { |
| var body = new window |
| .DOMParser() |
| .parseFromString(html, 'text/html') |
| .body; |
| body.removeChild(body.firstChild); |
| return body; |
| } |
| catch (_a) { |
| return null; |
| } |
| }; |
| /** |
| * Use an HTML5 `template` element, if supported, or an inert body element created via |
| * `createHtmlDocument` to create and fill an inert DOM element. |
| * This is the default sane strategy to use if the browser does not require one of the specialised |
| * strategies above. |
| */ |
| InertBodyHelper.prototype.getInertBodyElement_InertDocument = function (html) { |
| // Prefer using <template> element if supported. |
| var templateEl = this.inertDocument.createElement('template'); |
| if ('content' in templateEl) { |
| templateEl.innerHTML = html; |
| return templateEl; |
| } |
| this.inertBodyElement.innerHTML = html; |
| // Support: IE 9-11 only |
| // strip custom-namespaced attributes on IE<=11 |
| if (this.defaultDoc.documentMode) { |
| this.stripCustomNsAttrs(this.inertBodyElement); |
| } |
| return this.inertBodyElement; |
| }; |
| /** |
| * When IE9-11 comes across an unknown namespaced attribute e.g. 'xlink:foo' it adds 'xmlns:ns1' |
| * attribute to declare ns1 namespace and prefixes the attribute with 'ns1' (e.g. |
| * 'ns1:xlink:foo'). |
| * |
| * This is undesirable since we don't want to allow any of these custom attributes. This method |
| * strips them all. |
| */ |
| InertBodyHelper.prototype.stripCustomNsAttrs = function (el) { |
| var elAttrs = el.attributes; |
| // loop backwards so that we can support removals. |
| for (var i = elAttrs.length - 1; 0 < i; i--) { |
| var attrib = elAttrs.item(i); |
| var attrName = attrib.name; |
| if (attrName === 'xmlns:ns1' || attrName.indexOf('ns1:') === 0) { |
| el.removeAttribute(attrName); |
| } |
| } |
| var childNode = el.firstChild; |
| while (childNode) { |
| if (childNode.nodeType === Node.ELEMENT_NODE) |
| this.stripCustomNsAttrs(childNode); |
| childNode = childNode.nextSibling; |
| } |
| }; |
| return InertBodyHelper; |
| }()); |
| /** |
| * We need to determine whether the DOMParser exists in the global context. |
| * The try-catch is because, on some browsers, trying to access this property |
| * on window can actually throw an error. |
| * |
| * @suppress {uselessCode} |
| */ |
| function isDOMParserAvailable() { |
| try { |
| return !!window.DOMParser; |
| } |
| catch (_a) { |
| return false; |
| } |
| } |
| |
| /** |
| * @license |
| * Copyright Google Inc. All Rights Reserved. |
| * |
| * Use of this source code is governed by an MIT-style license that can be |
| * found in the LICENSE file at https://angular.io/license |
| */ |
| /** |
| * A pattern that recognizes a commonly useful subset of URLs that are safe. |
| * |
| * This regular expression matches a subset of URLs that will not cause script |
| * execution if used in URL context within a HTML document. Specifically, this |
| * regular expression matches if (comment from here on and regex copied from |
| * Soy's EscapingConventions): |
| * (1) Either an allowed protocol (http, https, mailto or ftp). |
| * (2) or no protocol. A protocol must be followed by a colon. The below |
| * allows that by allowing colons only after one of the characters [/?#]. |
| * A colon after a hash (#) must be in the fragment. |
| * Otherwise, a colon after a (?) must be in a query. |
| * Otherwise, a colon after a single solidus (/) must be in a path. |
| * Otherwise, a colon after a double solidus (//) must be in the authority |
| * (before port). |
| * |
| * The pattern disallows &, used in HTML entity declarations before |
| * one of the characters in [/?#]. This disallows HTML entities used in the |
| * protocol name, which should never happen, e.g. "http" for "http". |
| * It also disallows HTML entities in the first path part of a relative path, |
| * e.g. "foo<bar/baz". Our existing escaping functions should not produce |
| * that. More importantly, it disallows masking of a colon, |
| * e.g. "javascript:...". |
| * |
| * This regular expression was taken from the Closure sanitization library. |
| */ |
| var SAFE_URL_PATTERN = /^(?:(?:https?|mailto|ftp|tel|file):|[^&:/?#]*(?:[/?#]|$))/gi; |
| /** A pattern that matches safe data URLs. Only matches image, video and audio types. */ |
| var DATA_URL_PATTERN = /^data:(?:image\/(?:bmp|gif|jpeg|jpg|png|tiff|webp)|video\/(?:mpeg|mp4|ogg|webm)|audio\/(?:mp3|oga|ogg|opus));base64,[a-z0-9+\/]+=*$/i; |
| function _sanitizeUrl(url) { |
| url = String(url); |
| if (url.match(SAFE_URL_PATTERN) || url.match(DATA_URL_PATTERN)) |
| return url; |
| if (isDevMode()) { |
| console.warn("WARNING: sanitizing unsafe URL value " + url + " (see http://g.co/ng/security#xss)"); |
| } |
| return 'unsafe:' + url; |
| } |
| function sanitizeSrcset(srcset) { |
| srcset = String(srcset); |
| return srcset.split(',').map(function (srcset) { return _sanitizeUrl(srcset.trim()); }).join(', '); |
| } |
| |
| /** |
| * @license |
| * Copyright Google Inc. All Rights Reserved. |
| * |
| * Use of this source code is governed by an MIT-style license that can be |
| * found in the LICENSE file at https://angular.io/license |
| */ |
| function tagSet(tags) { |
| var e_1, _a; |
| var res = {}; |
| try { |
| for (var _b = __values(tags.split(',')), _c = _b.next(); !_c.done; _c = _b.next()) { |
| var t = _c.value; |
| res[t] = true; |
| } |
| } |
| catch (e_1_1) { e_1 = { error: e_1_1 }; } |
| finally { |
| try { |
| if (_c && !_c.done && (_a = _b.return)) _a.call(_b); |
| } |
| finally { if (e_1) throw e_1.error; } |
| } |
| return res; |
| } |
| function merge() { |
| var e_2, _a; |
| var sets = []; |
| for (var _i = 0; _i < arguments.length; _i++) { |
| sets[_i] = arguments[_i]; |
| } |
| var res = {}; |
| try { |
| for (var sets_1 = __values(sets), sets_1_1 = sets_1.next(); !sets_1_1.done; sets_1_1 = sets_1.next()) { |
| var s = sets_1_1.value; |
| for (var v in s) { |
| if (s.hasOwnProperty(v)) |
| res[v] = true; |
| } |
| } |
| } |
| catch (e_2_1) { e_2 = { error: e_2_1 }; } |
| finally { |
| try { |
| if (sets_1_1 && !sets_1_1.done && (_a = sets_1.return)) _a.call(sets_1); |
| } |
| finally { if (e_2) throw e_2.error; } |
| } |
| return res; |
| } |
| // Good source of info about elements and attributes |
| // http://dev.w3.org/html5/spec/Overview.html#semantics |
| // http://simon.html5.org/html-elements |
| // Safe Void Elements - HTML5 |
| // http://dev.w3.org/html5/spec/Overview.html#void-elements |
| var VOID_ELEMENTS = tagSet('area,br,col,hr,img,wbr'); |
| // Elements that you can, intentionally, leave open (and which close themselves) |
| // http://dev.w3.org/html5/spec/Overview.html#optional-tags |
| var OPTIONAL_END_TAG_BLOCK_ELEMENTS = tagSet('colgroup,dd,dt,li,p,tbody,td,tfoot,th,thead,tr'); |
| var OPTIONAL_END_TAG_INLINE_ELEMENTS = tagSet('rp,rt'); |
| var OPTIONAL_END_TAG_ELEMENTS = merge(OPTIONAL_END_TAG_INLINE_ELEMENTS, OPTIONAL_END_TAG_BLOCK_ELEMENTS); |
| // Safe Block Elements - HTML5 |
| var BLOCK_ELEMENTS = merge(OPTIONAL_END_TAG_BLOCK_ELEMENTS, tagSet('address,article,' + |
| 'aside,blockquote,caption,center,del,details,dialog,dir,div,dl,figure,figcaption,footer,h1,h2,h3,h4,h5,' + |
| 'h6,header,hgroup,hr,ins,main,map,menu,nav,ol,pre,section,summary,table,ul')); |
| // Inline Elements - HTML5 |
| var INLINE_ELEMENTS = merge(OPTIONAL_END_TAG_INLINE_ELEMENTS, tagSet('a,abbr,acronym,audio,b,' + |
| 'bdi,bdo,big,br,cite,code,del,dfn,em,font,i,img,ins,kbd,label,map,mark,picture,q,ruby,rp,rt,s,' + |
| 'samp,small,source,span,strike,strong,sub,sup,time,track,tt,u,var,video')); |
| var VALID_ELEMENTS = merge(VOID_ELEMENTS, BLOCK_ELEMENTS, INLINE_ELEMENTS, OPTIONAL_END_TAG_ELEMENTS); |
| // Attributes that have href and hence need to be sanitized |
| var URI_ATTRS = tagSet('background,cite,href,itemtype,longdesc,poster,src,xlink:href'); |
| // Attributes that have special href set hence need to be sanitized |
| var SRCSET_ATTRS = tagSet('srcset'); |
| var HTML_ATTRS = tagSet('abbr,accesskey,align,alt,autoplay,axis,bgcolor,border,cellpadding,cellspacing,class,clear,color,cols,colspan,' + |
| 'compact,controls,coords,datetime,default,dir,download,face,headers,height,hidden,hreflang,hspace,' + |
| 'ismap,itemscope,itemprop,kind,label,lang,language,loop,media,muted,nohref,nowrap,open,preload,rel,rev,role,rows,rowspan,rules,' + |
| 'scope,scrolling,shape,size,sizes,span,srclang,start,summary,tabindex,target,title,translate,type,usemap,' + |
| 'valign,value,vspace,width'); |
| // Accessibility attributes as per WAI-ARIA 1.1 (W3C Working Draft 14 December 2018) |
| var ARIA_ATTRS = tagSet('aria-activedescendant,aria-atomic,aria-autocomplete,aria-busy,aria-checked,aria-colcount,aria-colindex,' + |
| 'aria-colspan,aria-controls,aria-current,aria-describedby,aria-details,aria-disabled,aria-dropeffect,' + |
| 'aria-errormessage,aria-expanded,aria-flowto,aria-grabbed,aria-haspopup,aria-hidden,aria-invalid,' + |
| 'aria-keyshortcuts,aria-label,aria-labelledby,aria-level,aria-live,aria-modal,aria-multiline,' + |
| 'aria-multiselectable,aria-orientation,aria-owns,aria-placeholder,aria-posinset,aria-pressed,aria-readonly,' + |
| 'aria-relevant,aria-required,aria-roledescription,aria-rowcount,aria-rowindex,aria-rowspan,aria-selected,' + |
| 'aria-setsize,aria-sort,aria-valuemax,aria-valuemin,aria-valuenow,aria-valuetext'); |
| // NB: This currently consciously doesn't support SVG. SVG sanitization has had several security |
| // issues in the past, so it seems safer to leave it out if possible. If support for binding SVG via |
| // innerHTML is required, SVG attributes should be added here. |
| // NB: Sanitization does not allow <form> elements or other active elements (<button> etc). Those |
| // can be sanitized, but they increase security surface area without a legitimate use case, so they |
| // are left out here. |
| var VALID_ATTRS = merge(URI_ATTRS, SRCSET_ATTRS, HTML_ATTRS, ARIA_ATTRS); |
| // Elements whose content should not be traversed/preserved, if the elements themselves are invalid. |
| // |
| // Typically, `<invalid>Some content</invalid>` would traverse (and in this case preserve) |
| // `Some content`, but strip `invalid-element` opening/closing tags. For some elements, though, we |
| // don't want to preserve the content, if the elements themselves are going to be removed. |
| var SKIP_TRAVERSING_CONTENT_IF_INVALID_ELEMENTS = tagSet('script,style,template'); |
| /** |
| * SanitizingHtmlSerializer serializes a DOM fragment, stripping out any unsafe elements and unsafe |
| * attributes. |
| */ |
| var SanitizingHtmlSerializer = /** @class */ (function () { |
| function SanitizingHtmlSerializer() { |
| // Explicitly track if something was stripped, to avoid accidentally warning of sanitization just |
| // because characters were re-encoded. |
| this.sanitizedSomething = false; |
| this.buf = []; |
| } |
| SanitizingHtmlSerializer.prototype.sanitizeChildren = function (el) { |
| // This cannot use a TreeWalker, as it has to run on Angular's various DOM adapters. |
| // However this code never accesses properties off of `document` before deleting its contents |
| // again, so it shouldn't be vulnerable to DOM clobbering. |
| var current = el.firstChild; |
| var traverseContent = true; |
| while (current) { |
| if (current.nodeType === Node.ELEMENT_NODE) { |
| traverseContent = this.startElement(current); |
| } |
| else if (current.nodeType === Node.TEXT_NODE) { |
| this.chars(current.nodeValue); |
| } |
| else { |
| // Strip non-element, non-text nodes. |
| this.sanitizedSomething = true; |
| } |
| if (traverseContent && current.firstChild) { |
| current = current.firstChild; |
| continue; |
| } |
| while (current) { |
| // Leaving the element. Walk up and to the right, closing tags as we go. |
| if (current.nodeType === Node.ELEMENT_NODE) { |
| this.endElement(current); |
| } |
| var next = this.checkClobberedElement(current, current.nextSibling); |
| if (next) { |
| current = next; |
| break; |
| } |
| current = this.checkClobberedElement(current, current.parentNode); |
| } |
| } |
| return this.buf.join(''); |
| }; |
| /** |
| * Sanitizes an opening element tag (if valid) and returns whether the element's contents should |
| * be traversed. Element content must always be traversed (even if the element itself is not |
| * valid/safe), unless the element is one of `SKIP_TRAVERSING_CONTENT_IF_INVALID_ELEMENTS`. |
| * |
| * @param element The element to sanitize. |
| * @return True if the element's contents should be traversed. |
| */ |
| SanitizingHtmlSerializer.prototype.startElement = function (element) { |
| var tagName = element.nodeName.toLowerCase(); |
| if (!VALID_ELEMENTS.hasOwnProperty(tagName)) { |
| this.sanitizedSomething = true; |
| return !SKIP_TRAVERSING_CONTENT_IF_INVALID_ELEMENTS.hasOwnProperty(tagName); |
| } |
| this.buf.push('<'); |
| this.buf.push(tagName); |
| var elAttrs = element.attributes; |
| for (var i = 0; i < elAttrs.length; i++) { |
| var elAttr = elAttrs.item(i); |
| var attrName = elAttr.name; |
| var lower = attrName.toLowerCase(); |
| if (!VALID_ATTRS.hasOwnProperty(lower)) { |
| this.sanitizedSomething = true; |
| continue; |
| } |
| var value = elAttr.value; |
| // TODO(martinprobst): Special case image URIs for data:image/... |
| if (URI_ATTRS[lower]) |
| value = _sanitizeUrl(value); |
| if (SRCSET_ATTRS[lower]) |
| value = sanitizeSrcset(value); |
| this.buf.push(' ', attrName, '="', encodeEntities(value), '"'); |
| } |
| this.buf.push('>'); |
| return true; |
| }; |
| SanitizingHtmlSerializer.prototype.endElement = function (current) { |
| var tagName = current.nodeName.toLowerCase(); |
| if (VALID_ELEMENTS.hasOwnProperty(tagName) && !VOID_ELEMENTS.hasOwnProperty(tagName)) { |
| this.buf.push('</'); |
| this.buf.push(tagName); |
| this.buf.push('>'); |
| } |
| }; |
| SanitizingHtmlSerializer.prototype.chars = function (chars) { this.buf.push(encodeEntities(chars)); }; |
| SanitizingHtmlSerializer.prototype.checkClobberedElement = function (node, nextNode) { |
| if (nextNode && |
| (node.compareDocumentPosition(nextNode) & |
| Node.DOCUMENT_POSITION_CONTAINED_BY) === Node.DOCUMENT_POSITION_CONTAINED_BY) { |
| throw new Error("Failed to sanitize html because the element is clobbered: " + node.outerHTML); |
| } |
| return nextNode; |
| }; |
| return SanitizingHtmlSerializer; |
| }()); |
| // Regular Expressions for parsing tags and attributes |
| var SURROGATE_PAIR_REGEXP = /[\uD800-\uDBFF][\uDC00-\uDFFF]/g; |
| // ! to ~ is the ASCII range. |
| var NON_ALPHANUMERIC_REGEXP = /([^\#-~ |!])/g; |
| /** |
| * Escapes all potentially dangerous characters, so that the |
| * resulting string can be safely inserted into attribute or |
| * element text. |
| * @param value |
| */ |
| function encodeEntities(value) { |
| return value.replace(/&/g, '&') |
| .replace(SURROGATE_PAIR_REGEXP, function (match) { |
| var hi = match.charCodeAt(0); |
| var low = match.charCodeAt(1); |
| return '&#' + (((hi - 0xD800) * 0x400) + (low - 0xDC00) + 0x10000) + ';'; |
| }) |
| .replace(NON_ALPHANUMERIC_REGEXP, function (match) { return '&#' + match.charCodeAt(0) + ';'; }) |
| .replace(/</g, '<') |
| .replace(/>/g, '>'); |
| } |
| var inertBodyHelper; |
| /** |
| * Sanitizes the given unsafe, untrusted HTML fragment, and returns HTML text that is safe to add to |
| * the DOM in a browser environment. |
| */ |
| function _sanitizeHtml(defaultDoc, unsafeHtmlInput) { |
| var inertBodyElement = null; |
| try { |
| inertBodyHelper = inertBodyHelper || new InertBodyHelper(defaultDoc); |
| // Make sure unsafeHtml is actually a string (TypeScript types are not enforced at runtime). |
| var unsafeHtml = unsafeHtmlInput ? String(unsafeHtmlInput) : ''; |
| inertBodyElement = inertBodyHelper.getInertBodyElement(unsafeHtml); |
| // mXSS protection. Repeatedly parse the document to make sure it stabilizes, so that a browser |
| // trying to auto-correct incorrect HTML cannot cause formerly inert HTML to become dangerous. |
| var mXSSAttempts = 5; |
| var parsedHtml = unsafeHtml; |
| do { |
| if (mXSSAttempts === 0) { |
| throw new Error('Failed to sanitize html because the input is unstable'); |
| } |
| mXSSAttempts--; |
| unsafeHtml = parsedHtml; |
| parsedHtml = inertBodyElement.innerHTML; |
| inertBodyElement = inertBodyHelper.getInertBodyElement(unsafeHtml); |
| } while (unsafeHtml !== parsedHtml); |
| var sanitizer = new SanitizingHtmlSerializer(); |
| var safeHtml = sanitizer.sanitizeChildren(getTemplateContent(inertBodyElement) || inertBodyElement); |
| if (isDevMode() && sanitizer.sanitizedSomething) { |
| console.warn('WARNING: sanitizing HTML stripped some content, see http://g.co/ng/security#xss'); |
| } |
| return safeHtml; |
| } |
| finally { |
| // In case anything goes wrong, clear out inertElement to reset the entire DOM structure. |
| if (inertBodyElement) { |
| var parent_1 = getTemplateContent(inertBodyElement) || inertBodyElement; |
| while (parent_1.firstChild) { |
| parent_1.removeChild(parent_1.firstChild); |
| } |
| } |
| } |
| } |
| function getTemplateContent(el) { |
| return 'content' in el /** Microsoft/TypeScript#21517 */ && isTemplateElement(el) ? |
| el.content : |
| null; |
| } |
| function isTemplateElement(el) { |
| return el.nodeType === Node.ELEMENT_NODE && el.nodeName === 'TEMPLATE'; |
| } |
| |
| /** |
| * @license |
| * Copyright Google Inc. All Rights Reserved. |
| * |
| * Use of this source code is governed by an MIT-style license that can be |
| * found in the LICENSE file at https://angular.io/license |
| */ |
| (function (SecurityContext) { |
| SecurityContext[SecurityContext["NONE"] = 0] = "NONE"; |
| SecurityContext[SecurityContext["HTML"] = 1] = "HTML"; |
| SecurityContext[SecurityContext["STYLE"] = 2] = "STYLE"; |
| SecurityContext[SecurityContext["SCRIPT"] = 3] = "SCRIPT"; |
| SecurityContext[SecurityContext["URL"] = 4] = "URL"; |
| SecurityContext[SecurityContext["RESOURCE_URL"] = 5] = "RESOURCE_URL"; |
| })(exports.SecurityContext || (exports.SecurityContext = {})); |
| /** |
| * Sanitizer is used by the views to sanitize potentially dangerous values. |
| * |
| * @publicApi |
| */ |
| var Sanitizer = /** @class */ (function () { |
| function Sanitizer() { |
| } |
| return Sanitizer; |
| }()); |
| |
| /** |
| * @license |
| * Copyright Google Inc. All Rights Reserved. |
| * |
| * Use of this source code is governed by an MIT-style license that can be |
| * found in the LICENSE file at https://angular.io/license |
| */ |
| /** |
| * Regular expression for safe style values. |
| * |
| * Quotes (" and ') are allowed, but a check must be done elsewhere to ensure they're balanced. |
| * |
| * ',' allows multiple values to be assigned to the same property (e.g. background-attachment or |
| * font-family) and hence could allow multiple values to get injected, but that should pose no risk |
| * of XSS. |
| * |
| * The function expression checks only for XSS safety, not for CSS validity. |
| * |
| * This regular expression was taken from the Closure sanitization library, and augmented for |
| * transformation values. |
| */ |
| var VALUES = '[-,."\'%_!# a-zA-Z0-9]+'; |
| var TRANSFORMATION_FNS = '(?:matrix|translate|scale|rotate|skew|perspective)(?:X|Y|3d)?'; |
| var COLOR_FNS = '(?:rgb|hsl)a?'; |
| var GRADIENTS = '(?:repeating-)?(?:linear|radial)-gradient'; |
| var CSS3_FNS = '(?:calc|attr)'; |
| var FN_ARGS = '\\([-0-9.%, #a-zA-Z]+\\)'; |
| var SAFE_STYLE_VALUE = new RegExp("^(" + VALUES + "|" + |
| ("(?:" + TRANSFORMATION_FNS + "|" + COLOR_FNS + "|" + GRADIENTS + "|" + CSS3_FNS + ")") + |
| (FN_ARGS + ")$"), 'g'); |
| /** |
| * Matches a `url(...)` value with an arbitrary argument as long as it does |
| * not contain parentheses. |
| * |
| * The URL value still needs to be sanitized separately. |
| * |
| * `url(...)` values are a very common use case, e.g. for `background-image`. With carefully crafted |
| * CSS style rules, it is possible to construct an information leak with `url` values in CSS, e.g. |
| * by observing whether scroll bars are displayed, or character ranges used by a font face |
| * definition. |
| * |
| * Angular only allows binding CSS values (as opposed to entire CSS rules), so it is unlikely that |
| * binding a URL value without further cooperation from the page will cause an information leak, and |
| * if so, it is just a leak, not a full blown XSS vulnerability. |
| * |
| * Given the common use case, low likelihood of attack vector, and low impact of an attack, this |
| * code is permissive and allows URLs that sanitize otherwise. |
| */ |
| var URL_RE = /^url\(([^)]+)\)$/; |
| /** |
| * Checks that quotes (" and ') are properly balanced inside a string. Assumes |
| * that neither escape (\) nor any other character that could result in |
| * breaking out of a string parsing context are allowed; |
| * see http://www.w3.org/TR/css3-syntax/#string-token-diagram. |
| * |
| * This code was taken from the Closure sanitization library. |
| */ |
| function hasBalancedQuotes(value) { |
| var outsideSingle = true; |
| var outsideDouble = true; |
| for (var i = 0; i < value.length; i++) { |
| var c = value.charAt(i); |
| if (c === '\'' && outsideDouble) { |
| outsideSingle = !outsideSingle; |
| } |
| else if (c === '"' && outsideSingle) { |
| outsideDouble = !outsideDouble; |
| } |
| } |
| return outsideSingle && outsideDouble; |
| } |
| /** |
| * Sanitizes the given untrusted CSS style property value (i.e. not an entire object, just a single |
| * value) and returns a value that is safe to use in a browser environment. |
| */ |
| function _sanitizeStyle(value) { |
| value = String(value).trim(); // Make sure it's actually a string. |
| if (!value) |
| return ''; |
| // Single url(...) values are supported, but only for URLs that sanitize cleanly. See above for |
| // reasoning behind this. |
| var urlMatch = value.match(URL_RE); |
| if ((urlMatch && _sanitizeUrl(urlMatch[1]) === urlMatch[1]) || |
| value.match(SAFE_STYLE_VALUE) && hasBalancedQuotes(value)) { |
| return value; // Safe style values. |
| } |
| if (isDevMode()) { |
| console.warn("WARNING: sanitizing unsafe style value " + value + " (see http://g.co/ng/security#xss)."); |
| } |
| return 'unsafe'; |
| } |
| |
| /** |
| * @license |
| * Copyright Google Inc. All Rights Reserved. |
| * |
| * Use of this source code is governed by an MIT-style license that can be |
| * found in the LICENSE file at https://angular.io/license |
| */ |
| /** |
| * An `html` sanitizer which converts untrusted `html` **string** into trusted string by removing |
| * dangerous content. |
| * |
| * This method parses the `html` and locates potentially dangerous content (such as urls and |
| * javascript) and removes it. |
| * |
| * It is possible to mark a string as trusted by calling {@link bypassSanitizationTrustHtml}. |
| * |
| * @param unsafeHtml untrusted `html`, typically from the user. |
| * @returns `html` string which is safe to display to user, because all of the dangerous javascript |
| * and urls have been removed. |
| * |
| * @publicApi |
| */ |
| function ɵɵsanitizeHtml(unsafeHtml) { |
| var sanitizer = getSanitizer(); |
| if (sanitizer) { |
| return sanitizer.sanitize(exports.SecurityContext.HTML, unsafeHtml) || ''; |
| } |
| if (allowSanitizationBypass(unsafeHtml, "Html" /* Html */)) { |
| return unsafeHtml.toString(); |
| } |
| return _sanitizeHtml(document, renderStringify(unsafeHtml)); |
| } |
| /** |
| * A `style` sanitizer which converts untrusted `style` **string** into trusted string by removing |
| * dangerous content. |
| * |
| * This method parses the `style` and locates potentially dangerous content (such as urls and |
| * javascript) and removes it. |
| * |
| * It is possible to mark a string as trusted by calling {@link bypassSanitizationTrustStyle}. |
| * |
| * @param unsafeStyle untrusted `style`, typically from the user. |
| * @returns `style` string which is safe to bind to the `style` properties, because all of the |
| * dangerous javascript and urls have been removed. |
| * |
| * @publicApi |
| */ |
| function ɵɵsanitizeStyle(unsafeStyle) { |
| var sanitizer = getSanitizer(); |
| if (sanitizer) { |
| return sanitizer.sanitize(exports.SecurityContext.STYLE, unsafeStyle) || ''; |
| } |
| if (allowSanitizationBypass(unsafeStyle, "Style" /* Style */)) { |
| return unsafeStyle.toString(); |
| } |
| return _sanitizeStyle(renderStringify(unsafeStyle)); |
| } |
| /** |
| * A `url` sanitizer which converts untrusted `url` **string** into trusted string by removing |
| * dangerous |
| * content. |
| * |
| * This method parses the `url` and locates potentially dangerous content (such as javascript) and |
| * removes it. |
| * |
| * It is possible to mark a string as trusted by calling {@link bypassSanitizationTrustUrl}. |
| * |
| * @param unsafeUrl untrusted `url`, typically from the user. |
| * @returns `url` string which is safe to bind to the `src` properties such as `<img src>`, because |
| * all of the dangerous javascript has been removed. |
| * |
| * @publicApi |
| */ |
| function ɵɵsanitizeUrl(unsafeUrl) { |
| var sanitizer = getSanitizer(); |
| if (sanitizer) { |
| return sanitizer.sanitize(exports.SecurityContext.URL, unsafeUrl) || ''; |
| } |
| if (allowSanitizationBypass(unsafeUrl, "Url" /* Url */)) { |
| return unsafeUrl.toString(); |
| } |
| return _sanitizeUrl(renderStringify(unsafeUrl)); |
| } |
| /** |
| * A `url` sanitizer which only lets trusted `url`s through. |
| * |
| * This passes only `url`s marked trusted by calling {@link bypassSanitizationTrustResourceUrl}. |
| * |
| * @param unsafeResourceUrl untrusted `url`, typically from the user. |
| * @returns `url` string which is safe to bind to the `src` properties such as `<img src>`, because |
| * only trusted `url`s have been allowed to pass. |
| * |
| * @publicApi |
| */ |
| function ɵɵsanitizeResourceUrl(unsafeResourceUrl) { |
| var sanitizer = getSanitizer(); |
| if (sanitizer) { |
| return sanitizer.sanitize(exports.SecurityContext.RESOURCE_URL, unsafeResourceUrl) || ''; |
| } |
| if (allowSanitizationBypass(unsafeResourceUrl, "ResourceUrl" /* ResourceUrl */)) { |
| return unsafeResourceUrl.toString(); |
| } |
| throw new Error('unsafe value used in a resource URL context (see http://g.co/ng/security#xss)'); |
| } |
| /** |
| * A `script` sanitizer which only lets trusted javascript through. |
| * |
| * This passes only `script`s marked trusted by calling {@link |
| * bypassSanitizationTrustScript}. |
| * |
| * @param unsafeScript untrusted `script`, typically from the user. |
| * @returns `url` string which is safe to bind to the `<script>` element such as `<img src>`, |
| * because only trusted `scripts` have been allowed to pass. |
| * |
| * @publicApi |
| */ |
| function ɵɵsanitizeScript(unsafeScript) { |
| var sanitizer = getSanitizer(); |
| if (sanitizer) { |
| return sanitizer.sanitize(exports.SecurityContext.SCRIPT, unsafeScript) || ''; |
| } |
| if (allowSanitizationBypass(unsafeScript, "Script" /* Script */)) { |
| return unsafeScript.toString(); |
| } |
| throw new Error('unsafe value used in a script context'); |
| } |
| /** |
| * Detects which sanitizer to use for URL property, based on tag name and prop name. |
| * |
| * The rules are based on the RESOURCE_URL context config from |
| * `packages/compiler/src/schema/dom_security_schema.ts`. |
| * If tag and prop names don't match Resource URL schema, use URL sanitizer. |
| */ |
| function getUrlSanitizer(tag, prop) { |
| if ((prop === 'src' && (tag === 'embed' || tag === 'frame' || tag === 'iframe' || |
| tag === 'media' || tag === 'script')) || |
| (prop === 'href' && (tag === 'base' || tag === 'link'))) { |
| return ɵɵsanitizeResourceUrl; |
| } |
| return ɵɵsanitizeUrl; |
| } |
| /** |
| * Sanitizes URL, selecting sanitizer function based on tag and property names. |
| * |
| * This function is used in case we can't define security context at compile time, when only prop |
| * name is available. This happens when we generate host bindings for Directives/Components. The |
| * host element is unknown at compile time, so we defer calculation of specific sanitizer to |
| * runtime. |
| * |
| * @param unsafeUrl untrusted `url`, typically from the user. |
| * @param tag target element tag name. |
| * @param prop name of the property that contains the value. |
| * @returns `url` string which is safe to bind. |
| * |
| * @publicApi |
| */ |
| function ɵɵsanitizeUrlOrResourceUrl(unsafeUrl, tag, prop) { |
| return getUrlSanitizer(tag, prop)(unsafeUrl); |
| } |
| /** |
| * The default style sanitizer will handle sanitization for style properties by |
| * sanitizing any CSS property that can include a `url` value (usually image-based properties) |
| * |
| * @publicApi |
| */ |
| var ɵɵdefaultStyleSanitizer = function (prop, value, mode) { |
| mode = mode || 3 /* ValidateAndSanitize */; |
| var doSanitizeValue = true; |
| if (mode & 1 /* ValidateProperty */) { |
| doSanitizeValue = prop === 'background-image' || prop === 'background' || |
| prop === 'border-image' || prop === 'filter' || prop === 'list-style' || |
| prop === 'list-style-image' || prop === 'clip-path'; |
| } |
| if (mode & 2 /* SanitizeOnly */) { |
| return doSanitizeValue ? ɵɵsanitizeStyle(value) : value; |
| } |
| else { |
| return doSanitizeValue; |
| } |
| }; |
| function validateAgainstEventProperties(name) { |
| if (name.toLowerCase().startsWith('on')) { |
| var msg = "Binding to event property '" + name + "' is disallowed for security reasons, " + |
| ("please use (" + name.slice(2) + ")=...") + |
| ("\nIf '" + name + "' is a directive input, make sure the directive is imported by the") + |
| " current module."; |
| throw new Error(msg); |
| } |
| } |
| function validateAgainstEventAttributes(name) { |
| if (name.toLowerCase().startsWith('on')) { |
| var msg = "Binding to event attribute '" + name + "' is disallowed for security reasons, " + |
| ("please use (" + name.slice(2) + ")=..."); |
| throw new Error(msg); |
| } |
| } |
| function getSanitizer() { |
| var lView = getLView(); |
| return lView && lView[SANITIZER]; |
| } |
| |
| /** |
| * @license |
| * Copyright Google Inc. All Rights Reserved. |
| * |
| * Use of this source code is governed by an MIT-style license that can be |
| * found in the LICENSE file at https://angular.io/license |
| */ |
| var TNODE = 8; |
| var PARENT_INJECTOR = 8; |
| var INJECTOR_BLOOM_PARENT_SIZE = 9; |
| var NO_PARENT_INJECTOR = -1; |
| /** |
| * Each injector is saved in 9 contiguous slots in `LView` and 9 contiguous slots in |
| * `TView.data`. This allows us to store information about the current node's tokens (which |
| * can be shared in `TView`) as well as the tokens of its ancestor nodes (which cannot be |
| * shared, so they live in `LView`). |
| * |
| * Each of these slots (aside from the last slot) contains a bloom filter. This bloom filter |
| * determines whether a directive is available on the associated node or not. This prevents us |
| * from searching the directives array at this level unless it's probable the directive is in it. |
| * |
| * See: https://en.wikipedia.org/wiki/Bloom_filter for more about bloom filters. |
| * |
| * Because all injectors have been flattened into `LView` and `TViewData`, they cannot typed |
| * using interfaces as they were previously. The start index of each `LInjector` and `TInjector` |
| * will differ based on where it is flattened into the main array, so it's not possible to know |
| * the indices ahead of time and save their types here. The interfaces are still included here |
| * for documentation purposes. |
| * |
| * export interface LInjector extends Array<any> { |
| * |
| * // Cumulative bloom for directive IDs 0-31 (IDs are % BLOOM_SIZE) |
| * [0]: number; |
| * |
| * // Cumulative bloom for directive IDs 32-63 |
| * [1]: number; |
| * |
| * // Cumulative bloom for directive IDs 64-95 |
| * [2]: number; |
| * |
| * // Cumulative bloom for directive IDs 96-127 |
| * [3]: number; |
| * |
| * // Cumulative bloom for directive IDs 128-159 |
| * [4]: number; |
| * |
| * // Cumulative bloom for directive IDs 160 - 191 |
| * [5]: number; |
| * |
| * // Cumulative bloom for directive IDs 192 - 223 |
| * [6]: number; |
| * |
| * // Cumulative bloom for directive IDs 224 - 255 |
| * [7]: number; |
| * |
| * // We need to store a reference to the injector's parent so DI can keep looking up |
| * // the injector tree until it finds the dependency it's looking for. |
| * [PARENT_INJECTOR]: number; |
| * } |
| * |
| * export interface TInjector extends Array<any> { |
| * |
| * // Shared node bloom for directive IDs 0-31 (IDs are % BLOOM_SIZE) |
| * [0]: number; |
| * |
| * // Shared node bloom for directive IDs 32-63 |
| * [1]: number; |
| * |
| * // Shared node bloom for directive IDs 64-95 |
| * [2]: number; |
| * |
| * // Shared node bloom for directive IDs 96-127 |
| * [3]: number; |
| * |
| * // Shared node bloom for directive IDs 128-159 |
| * [4]: number; |
| * |
| * // Shared node bloom for directive IDs 160 - 191 |
| * [5]: number; |
| * |
| * // Shared node bloom for directive IDs 192 - 223 |
| * [6]: number; |
| * |
| * // Shared node bloom for directive IDs 224 - 255 |
| * [7]: number; |
| * |
| * // Necessary to find directive indices for a particular node. |
| * [TNODE]: TElementNode|TElementContainerNode|TContainerNode; |
| * } |
| */ |
| /** |
| * Factory for creating instances of injectors in the NodeInjector. |
| * |
| * This factory is complicated by the fact that it can resolve `multi` factories as well. |
| * |
| * NOTE: Some of the fields are optional which means that this class has two hidden classes. |
| * - One without `multi` support (most common) |
| * - One with `multi` values, (rare). |
| * |
| * Since VMs can cache up to 4 inline hidden classes this is OK. |
| * |
| * - Single factory: Only `resolving` and `factory` is defined. |
| * - `providers` factory: `componentProviders` is a number and `index = -1`. |
| * - `viewProviders` factory: `componentProviders` is a number and `index` points to `providers`. |
| */ |
| var NodeInjectorFactory = /** @class */ (function () { |
| function NodeInjectorFactory( |
| /** |
| * Factory to invoke in order to create a new instance. |
| */ |
| factory, |
| /** |
| * Set to `true` if the token is declared in `viewProviders` (or if it is component). |
| */ |
| isViewProvider, injectImplementation) { |
| this.factory = factory; |
| /** |
| * Marker set to true during factory invocation to see if we get into recursive loop. |
| * Recursive loop causes an error to be displayed. |
| */ |
| this.resolving = false; |
| this.canSeeViewProviders = isViewProvider; |
| this.injectImpl = injectImplementation; |
| } |
| return NodeInjectorFactory; |
| }()); |
| function isFactory(obj) { |
| // See: https://jsperf.com/instanceof-vs-getprototypeof |
| return obj !== null && typeof obj == 'object' && |
| Object.getPrototypeOf(obj) == NodeInjectorFactory.prototype; |
| } |
| |
| /** |
| * @license |
| * Copyright Google Inc. All Rights Reserved. |
| * |
| * Use of this source code is governed by an MIT-style license that can be |
| * found in the LICENSE file at https://angular.io/license |
| */ |
| function assertNodeType(tNode, type) { |
| assertDefined(tNode, 'should be called with a TNode'); |
| assertEqual(tNode.type, type, "should be a " + typeName(type)); |
| } |
| function assertNodeOfPossibleTypes(tNode) { |
| var types = []; |
| for (var _i = 1; _i < arguments.length; _i++) { |
| types[_i - 1] = arguments[_i]; |
| } |
| assertDefined(tNode, 'should be called with a TNode'); |
| var found = types.some(function (type) { return tNode.type === type; }); |
| assertEqual(found, true, "Should be one of " + types.map(typeName).join(', ') + " but got " + typeName(tNode.type)); |
| } |
| function typeName(type) { |
| if (type == 1 /* Projection */) |
| return 'Projection'; |
| if (type == 0 /* Container */) |
| return 'Container'; |
| if (type == 2 /* View */) |
| return 'View'; |
| if (type == 3 /* Element */) |
| return 'Element'; |
| if (type == 4 /* ElementContainer */) |
| return 'ElementContainer'; |
| return '<unknown>'; |
| } |
| |
| /** |
| * @license |
| * Copyright Google Inc. All Rights Reserved. |
| * |
| * Use of this source code is governed by an MIT-style license that can be |
| * found in the LICENSE file at https://angular.io/license |
| */ |
| // TODO: cleanup once the code is merged in angular/angular |
| var RendererStyleFlags3; |
| (function (RendererStyleFlags3) { |
| RendererStyleFlags3[RendererStyleFlags3["Important"] = 1] = "Important"; |
| RendererStyleFlags3[RendererStyleFlags3["DashCase"] = 2] = "DashCase"; |
| })(RendererStyleFlags3 || (RendererStyleFlags3 = {})); |
| /** Returns whether the `renderer` is a `ProceduralRenderer3` */ |
| function isProceduralRenderer(renderer) { |
| return !!(renderer.listen); |
| } |
| var ɵ0$7 = function (hostElement, rendererType) { return document; }; |
| var domRendererFactory3 = { |
| createRenderer: ɵ0$7 |
| }; |
| |
| /** |
| * @license |
| * Copyright Google Inc. All Rights Reserved. |
| * |
| * Use of this source code is governed by an MIT-style license that can be |
| * found in the LICENSE file at https://angular.io/license |
| */ |
| /** Returns the matching `LContext` data for a given DOM node, directive or component instance. |
| * |
| * This function will examine the provided DOM element, component, or directive instance\'s |
| * monkey-patched property to derive the `LContext` data. Once called then the monkey-patched |
| * value will be that of the newly created `LContext`. |
| * |
| * If the monkey-patched value is the `LView` instance then the context value for that |
| * target will be created and the monkey-patch reference will be updated. Therefore when this |
| * function is called it may mutate the provided element\'s, component\'s or any of the associated |
| * directive\'s monkey-patch values. |
| * |
| * If the monkey-patch value is not detected then the code will walk up the DOM until an element |
| * is found which contains a monkey-patch reference. When that occurs then the provided element |
| * will be updated with a new context (which is then returned). If the monkey-patch value is not |
| * detected for a component/directive instance then it will throw an error (all components and |
| * directives should be automatically monkey-patched by ivy). |
| * |
| * @param target Component, Directive or DOM Node. |
| */ |
| function getLContext(target) { |
| var mpValue = readPatchedData(target); |
| if (mpValue) { |
| // only when it's an array is it considered an LView instance |
| // ... otherwise it's an already constructed LContext instance |
| if (Array.isArray(mpValue)) { |
| var lView = mpValue; |
| var nodeIndex = void 0; |
| var component = undefined; |
| var directives = undefined; |
| if (isComponentInstance(target)) { |
| nodeIndex = findViaComponent(lView, target); |
| if (nodeIndex == -1) { |
| throw new Error('The provided component was not found in the application'); |
| } |
| component = target; |
| } |
| else if (isDirectiveInstance(target)) { |
| nodeIndex = findViaDirective(lView, target); |
| if (nodeIndex == -1) { |
| throw new Error('The provided directive was not found in the application'); |
| } |
| directives = getDirectivesAtNodeIndex(nodeIndex, lView, false); |
| } |
| else { |
| nodeIndex = findViaNativeElement(lView, target); |
| if (nodeIndex == -1) { |
| return null; |
| } |
| } |
| // the goal is not to fill the entire context full of data because the lookups |
| // are expensive. Instead, only the target data (the element, component, container, ICU |
| // expression or directive details) are filled into the context. If called multiple times |
| // with different target values then the missing target data will be filled in. |
| var native = unwrapRNode(lView[nodeIndex]); |
| var existingCtx = readPatchedData(native); |
| var context = (existingCtx && !Array.isArray(existingCtx)) ? |
| existingCtx : |
| createLContext(lView, nodeIndex, native); |
| // only when the component has been discovered then update the monkey-patch |
| if (component && context.component === undefined) { |
| context.component = component; |
| attachPatchData(context.component, context); |
| } |
| // only when the directives have been discovered then update the monkey-patch |
| if (directives && context.directives === undefined) { |
| context.directives = directives; |
| for (var i = 0; i < directives.length; i++) { |
| attachPatchData(directives[i], context); |
| } |
| } |
| attachPatchData(context.native, context); |
| mpValue = context; |
| } |
| } |
| else { |
| var rElement = target; |
| ngDevMode && assertDomNode(rElement); |
| // if the context is not found then we need to traverse upwards up the DOM |
| // to find the nearest element that has already been monkey patched with data |
| var parent_1 = rElement; |
| while (parent_1 = parent_1.parentNode) { |
| var parentContext = readPatchedData(parent_1); |
| if (parentContext) { |
| var lView = void 0; |
| if (Array.isArray(parentContext)) { |
| lView = parentContext; |
| } |
| else { |
| lView = parentContext.lView; |
| } |
| // the edge of the app was also reached here through another means |
| // (maybe because the DOM was changed manually). |
| if (!lView) { |
| return null; |
| } |
| var index = findViaNativeElement(lView, rElement); |
| if (index >= 0) { |
| var native = unwrapRNode(lView[index]); |
| var context = createLContext(lView, index, native); |
| attachPatchData(native, context); |
| mpValue = context; |
| break; |
| } |
| } |
| } |
| } |
| return mpValue || null; |
| } |
| /** |
| * Creates an empty instance of a `LContext` context |
| */ |
| function createLContext(lView, nodeIndex, native) { |
| return { |
| lView: lView, |
| nodeIndex: nodeIndex, |
| native: native, |
| component: undefined, |
| directives: undefined, |
| localRefs: undefined, |
| }; |
| } |
| /** |
| * Takes a component instance and returns the view for that component. |
| * |
| * @param componentInstance |
| * @returns The component's view |
| */ |
| function getComponentViewByInstance(componentInstance) { |
| var lView = readPatchedData(componentInstance); |
| var view; |
| if (Array.isArray(lView)) { |
| var nodeIndex = findViaComponent(lView, componentInstance); |
| view = getComponentViewByIndex(nodeIndex, lView); |
| var context = createLContext(lView, nodeIndex, view[HOST]); |
| context.component = componentInstance; |
| attachPatchData(componentInstance, context); |
| attachPatchData(context.native, context); |
| } |
| else { |
| var context = lView; |
| view = getComponentViewByIndex(context.nodeIndex, context.lView); |
| } |
| return view; |
| } |
| /** |
| * Assigns the given data to the given target (which could be a component, |
| * directive or DOM node instance) using monkey-patching. |
| */ |
| function attachPatchData(target, data) { |
| target[MONKEY_PATCH_KEY_NAME] = data; |
| } |
| function isComponentInstance(instance) { |
| return instance && instance.constructor && instance.constructor.ngComponentDef; |
| } |
| function isDirectiveInstance(instance) { |
| return instance && instance.constructor && instance.constructor.ngDirectiveDef; |
| } |
| /** |
| * Locates the element within the given LView and returns the matching index |
| */ |
| function findViaNativeElement(lView, target) { |
| var tNode = lView[TVIEW].firstChild; |
| while (tNode) { |
| var native = getNativeByTNode(tNode, lView); |
| if (native === target) { |
| return tNode.index; |
| } |
| tNode = traverseNextElement(tNode); |
| } |
| return -1; |
| } |
| /** |
| * Locates the next tNode (child, sibling or parent). |
| */ |
| function traverseNextElement(tNode) { |
| if (tNode.child) { |
| return tNode.child; |
| } |
| else if (tNode.next) { |
| return tNode.next; |
| } |
| else { |
| // Let's take the following template: <div><span>text</span></div><component/> |
| // After checking the text node, we need to find the next parent that has a "next" TNode, |
| // in this case the parent `div`, so that we can find the component. |
| while (tNode.parent && !tNode.parent.next) { |
| tNode = tNode.parent; |
| } |
| return tNode.parent && tNode.parent.next; |
| } |
| } |
| /** |
| * Locates the component within the given LView and returns the matching index |
| */ |
| function findViaComponent(lView, componentInstance) { |
| var componentIndices = lView[TVIEW].components; |
| if (componentIndices) { |
| for (var i = 0; i < componentIndices.length; i++) { |
| var elementComponentIndex = componentIndices[i]; |
| var componentView = getComponentViewByIndex(elementComponentIndex, lView); |
| if (componentView[CONTEXT] === componentInstance) { |
| return elementComponentIndex; |
| } |
| } |
| } |
| else { |
| var rootComponentView = getComponentViewByIndex(HEADER_OFFSET, lView); |
| var rootComponent = rootComponentView[CONTEXT]; |
| if (rootComponent === componentInstance) { |
| // we are dealing with the root element here therefore we know that the |
| // element is the very first element after the HEADER data in the lView |
| return HEADER_OFFSET; |
| } |
| } |
| return -1; |
| } |
| /** |
| * Locates the directive within the given LView and returns the matching index |
| */ |
| function findViaDirective(lView, directiveInstance) { |
| // if a directive is monkey patched then it will (by default) |
| // have a reference to the LView of the current view. The |
| // element bound to the directive being search lives somewhere |
| // in the view data. We loop through the nodes and check their |
| // list of directives for the instance. |
| var tNode = lView[TVIEW].firstChild; |
| while (tNode) { |
| var directiveIndexStart = tNode.directiveStart; |
| var directiveIndexEnd = tNode.directiveEnd; |
| for (var i = directiveIndexStart; i < directiveIndexEnd; i++) { |
| if (lView[i] === directiveInstance) { |
| return tNode.index; |
| } |
| } |
| tNode = traverseNextElement(tNode); |
| } |
| return -1; |
| } |
| /** |
| * Returns a list of directives extracted from the given view based on the |
| * provided list of directive index values. |
| * |
| * @param nodeIndex The node index |
| * @param lView The target view data |
| * @param includeComponents Whether or not to include components in returned directives |
| */ |
| function getDirectivesAtNodeIndex(nodeIndex, lView, includeComponents) { |
| var tNode = lView[TVIEW].data[nodeIndex]; |
| var directiveStartIndex = tNode.directiveStart; |
| if (directiveStartIndex == 0) |
| return EMPTY_ARRAY$2; |
| var directiveEndIndex = tNode.directiveEnd; |
| if (!includeComponents && tNode.flags & 1 /* isComponent */) |
| directiveStartIndex++; |
| return lView.slice(directiveStartIndex, directiveEndIndex); |
| } |
| function getComponentAtNodeIndex(nodeIndex, lView) { |
| var tNode = lView[TVIEW].data[nodeIndex]; |
| var directiveStartIndex = tNode.directiveStart; |
| return tNode.flags & 1 /* isComponent */ ? lView[directiveStartIndex] : null; |
| } |
| /** |
| * Returns a map of local references (local reference name => element or directive instance) that |
| * exist on a given element. |
| */ |
| function discoverLocalRefs(lView, nodeIndex) { |
| var tNode = lView[TVIEW].data[nodeIndex]; |
| if (tNode && tNode.localNames) { |
| var result = {}; |
| var localIndex = tNode.index + 1; |
| for (var i = 0; i < tNode.localNames.length; i += 2) { |
| result[tNode.localNames[i]] = lView[localIndex]; |
| localIndex++; |
| } |
| return result; |
| } |
| return null; |
| } |
| |
| var CorePlayerHandler = /** @class */ (function () { |
| function CorePlayerHandler() { |
| this._players = []; |
| } |
| CorePlayerHandler.prototype.flushPlayers = function () { |
| for (var i = 0; i < this._players.length; i++) { |
| var player = this._players[i]; |
| if (!player.parent && player.state === 0 /* Pending */) { |
| player.play(); |
| } |
| } |
| this._players.length = 0; |
| }; |
| CorePlayerHandler.prototype.queuePlayer = function (player) { this._players.push(player); }; |
| return CorePlayerHandler; |
| }()); |
| |
| /** |
| * @license |
| * Copyright Google Inc. All Rights Reserved. |
| * |
| * Use of this source code is governed by an MIT-style license that can be |
| * found in the LICENSE file at https://angular.io/license |
| */ |
| /** |
| * The default directive styling index value for template-based bindings. |
| * |
| * All host-level bindings (e.g. `hostStyleProp` and `hostStyleMap`) are |
| * assigned a directive styling index value based on the current directive |
| * uniqueId and the directive super-class inheritance depth. But for template |
| * bindings they always have the same directive styling index value. |
| */ |
| var DEFAULT_TEMPLATE_DIRECTIVE_INDEX = 0; |
| |
| /** |
| * @license |
| * Copyright Google Inc. All Rights Reserved. |
| * |
| * Use of this source code is governed by an MIT-style license that can be |
| * found in the LICENSE file at https://angular.io/license |
| */ |
| var ANIMATION_PROP_PREFIX = '@'; |
| function createEmptyStylingContext(wrappedElement, sanitizer, initialStyles, initialClasses) { |
| var context = [ |
| wrappedElement || null, |
| 0, |
| [], |
| initialStyles || [null, null], |
| initialClasses || [null, null], |
| [0, 0], |
| [0], |
| [0], |
| null, |
| null, |
| ]; |
| // whenever a context is created there is always a `null` directive |
| // that is registered (which is a placeholder for the "template"). |
| allocateOrUpdateDirectiveIntoContext(context, DEFAULT_TEMPLATE_DIRECTIVE_INDEX); |
| return context; |
| } |
| /** |
| * Allocates (registers) a directive into the directive registry within the provided styling |
| * context. |
| * |
| * For each and every `[style]`, `[style.prop]`, `[class]`, `[class.name]` binding |
| * (as well as static style and class attributes) a directive, component or template |
| * is marked as the owner. When an owner is determined (this happens when the template |
| * is first passed over) the directive owner is allocated into the styling context. When |
| * this happens, each owner gets its own index value. This then ensures that once any |
| * style and/or class binding are assigned into the context then they are marked to |
| * that directive's index value. |
| * |
| * @param context the target StylingContext |
| * @param directiveRef the directive that will be allocated into the context |
| * @returns the index where the directive was inserted into |
| */ |
| function allocateOrUpdateDirectiveIntoContext(context, directiveIndex, singlePropValuesIndex, styleSanitizer) { |
| if (singlePropValuesIndex === void 0) { singlePropValuesIndex = -1; } |
| var directiveRegistry = context[2 /* DirectiveRegistryPosition */]; |
| var index = directiveIndex * 2 /* Size */; |
| // we preemptively make space into the directives array and then |
| // assign values slot-by-slot to ensure that if the directive ordering |
| // changes then it will still function |
| var limit = index + 2 /* Size */; |
| for (var i = directiveRegistry.length; i < limit; i += 2 /* Size */) { |
| // -1 is used to signal that the directive has been allocated, but |
| // no actual style or class bindings have been registered yet... |
| directiveRegistry.push(-1, null); |
| } |
| var propValuesStartPosition = index + 0 /* SinglePropValuesIndexOffset */; |
| if (singlePropValuesIndex >= 0 && directiveRegistry[propValuesStartPosition] === -1) { |
| directiveRegistry[propValuesStartPosition] = singlePropValuesIndex; |
| directiveRegistry[index + 1 /* StyleSanitizerOffset */] = |
| styleSanitizer || null; |
| } |
| } |
| /** |
| * Used clone a copy of a pre-computed template of a styling context. |
| * |
| * A pre-computed template is designed to be computed once for a given element |
| * (instructions.ts has logic for caching this). |
| */ |
| function allocStylingContext(element, templateStyleContext) { |
| // each instance gets a copy |
| var context = templateStyleContext.slice(); |
| // the HEADER values contain arrays which also need |
| // to be copied over into the new context |
| for (var i = 0; i < 10 /* SingleStylesStartPosition */; i++) { |
| var value = templateStyleContext[i]; |
| if (Array.isArray(value)) { |
| context[i] = value.slice(); |
| } |
| } |
| context[0 /* ElementPosition */] = element; |
| // this will prevent any other directives from extending the context |
| context[1 /* MasterFlagPosition */] |= 16 /* BindingAllocationLocked */; |
| return context; |
| } |
| /** |
| * Retrieve the `StylingContext` at a given index. |
| * |
| * This method lazily creates the `StylingContext`. This is because in most cases |
| * we have styling without any bindings. Creating `StylingContext` eagerly would mean that |
| * every style declaration such as `<div style="color: red">` would result `StyleContext` |
| * which would create unnecessary memory pressure. |
| * |
| * @param index Index of the style allocation. See: `styling`. |
| * @param viewData The view to search for the styling context |
| */ |
| function getStylingContextFromLView(index, viewData) { |
| var storageIndex = index; |
| var slotValue = viewData[storageIndex]; |
| var wrapper = viewData; |
| while (Array.isArray(slotValue)) { |
| wrapper = slotValue; |
| slotValue = slotValue[HOST]; |
| } |
| if (isStylingContext(wrapper)) { |
| return wrapper; |
| } |
| else { |
| // This is an LView or an LContainer |
| var stylingTemplate = getTNode(index - HEADER_OFFSET, viewData).stylingTemplate; |
| if (wrapper !== viewData) { |
| storageIndex = HOST; |
| } |
| return wrapper[storageIndex] = stylingTemplate ? |
| allocStylingContext(slotValue, stylingTemplate) : |
| createEmptyStylingContext(slotValue); |
| } |
| } |
| function isAnimationProp(name) { |
| return name[0] === ANIMATION_PROP_PREFIX; |
| } |
| function hasClassInput(tNode) { |
| return (tNode.flags & 8 /* hasClassInput */) !== 0; |
| } |
| function hasStyleInput(tNode) { |
| return (tNode.flags & 16 /* hasStyleInput */) !== 0; |
| } |
| function forceClassesAsString(classes) { |
| if (classes && typeof classes !== 'string') { |
| classes = Object.keys(classes).join(' '); |
| } |
| return classes || ''; |
| } |
| function forceStylesAsString(styles) { |
| var str = ''; |
| if (styles) { |
| var props = Object.keys(styles); |
| for (var i = 0; i < props.length; i++) { |
| var prop = props[i]; |
| str += (i ? ';' : '') + (prop + ":" + styles[prop]); |
| } |
| } |
| return str; |
| } |
| function addPlayerInternal(playerContext, rootContext, element, player, playerContextIndex, ref) { |
| ref = ref || element; |
| if (playerContextIndex) { |
| playerContext[playerContextIndex] = player; |
| } |
| else { |
| playerContext.push(player); |
| } |
| if (player) { |
| player.addEventListener(200 /* Destroyed */, function () { |
| var index = playerContext.indexOf(player); |
| var nonFactoryPlayerIndex = playerContext[0 /* NonBuilderPlayersStart */]; |
| // if the player is being removed from the factory side of the context |
| // (which is where the [style] and [class] bindings do their thing) then |
| // that side of the array cannot be resized since the respective bindings |
| // have pointer index values that point to the associated factory instance |
| if (index) { |
| if (index < nonFactoryPlayerIndex) { |
| playerContext[index] = null; |
| } |
| else { |
| playerContext.splice(index, 1); |
| } |
| } |
| player.destroy(); |
| }); |
| var playerHandler = rootContext.playerHandler || (rootContext.playerHandler = new CorePlayerHandler()); |
| playerHandler.queuePlayer(player, ref); |
| return true; |
| } |
| return false; |
| } |
| function getPlayersInternal(playerContext) { |
| var players = []; |
| var nonFactoryPlayersStart = playerContext[0 /* NonBuilderPlayersStart */]; |
| // add all factory-based players (which are apart of [style] and [class] bindings) |
| for (var i = 1 /* PlayerBuildersStartPosition */ + 1 /* PlayerOffsetPosition */; i < nonFactoryPlayersStart; i += 2 /* PlayerAndPlayerBuildersTupleSize */) { |
| var player = playerContext[i]; |
| if (player) { |
| players.push(player); |
| } |
| } |
| // add all custom players (not apart of [style] and [class] bindings) |
| for (var i = nonFactoryPlayersStart; i < playerContext.length; i++) { |
| players.push(playerContext[i]); |
| } |
| return players; |
| } |
| function getOrCreatePlayerContext(target, context) { |
| context = context || getLContext(target); |
| if (!context) { |
| ngDevMode && throwInvalidRefError(); |
| return null; |
| } |
| var lView = context.lView, nodeIndex = context.nodeIndex; |
| var stylingContext = getStylingContextFromLView(nodeIndex, lView); |
| return getPlayerContext(stylingContext) || allocPlayerContext(stylingContext); |
| } |
| function getPlayerContext(stylingContext) { |
| return stylingContext[9 /* PlayerContext */]; |
| } |
| function allocPlayerContext(data) { |
| return data[9 /* PlayerContext */] = |
| [5 /* SinglePlayerBuildersStartPosition */, null, null, null, null]; |
| } |
| function throwInvalidRefError() { |
| throw new Error('Only elements that exist in an Angular application can be used for animations'); |
| } |
| |
| /** |
| * Assigns all attribute values to the provided element via the inferred renderer. |
| * |
| * This function accepts two forms of attribute entries: |
| * |
| * default: (key, value): |
| * attrs = [key1, value1, key2, value2] |
| * |
| * namespaced: (NAMESPACE_MARKER, uri, name, value) |
| * attrs = [NAMESPACE_MARKER, uri, name, value, NAMESPACE_MARKER, uri, name, value] |
| * |
| * The `attrs` array can contain a mix of both the default and namespaced entries. |
| * The "default" values are set without a marker, but if the function comes across |
| * a marker value then it will attempt to set a namespaced value. If the marker is |
| * not of a namespaced value then the function will quit and return the index value |
| * where it stopped during the iteration of the attrs array. |
| * |
| * See [AttributeMarker] to understand what the namespace marker value is. |
| * |
| * Note that this instruction does not support assigning style and class values to |
| * an element. See `elementStart` and `elementHostAttrs` to learn how styling values |
| * are applied to an element. |
| * |
| * @param native The element that the attributes will be assigned to |
| * @param attrs The attribute array of values that will be assigned to the element |
| * @returns the index value that was last accessed in the attributes array |
| */ |
| function setUpAttributes(native, attrs) { |
| var renderer = getLView()[RENDERER]; |
| var isProc = isProceduralRenderer(renderer); |
| var i = 0; |
| while (i < attrs.length) { |
| var value = attrs[i]; |
| if (typeof value === 'number') { |
| // only namespaces are supported. Other value types (such as style/class |
| // entries) are not supported in this function. |
| if (value !== 0 /* NamespaceURI */) { |
| break; |
| } |
| // we just landed on the marker value ... therefore |
| // we should skip to the next entry |
| i++; |
| var namespaceURI = attrs[i++]; |
| var attrName = attrs[i++]; |
| var attrVal = attrs[i++]; |
| ngDevMode && ngDevMode.rendererSetAttribute++; |
| isProc ? |
| renderer.setAttribute(native, attrName, attrVal, namespaceURI) : |
| native.setAttributeNS(namespaceURI, attrName, attrVal); |
| } |
| else { |
| // attrName is string; |
| var attrName = value; |
| var attrVal = attrs[++i]; |
| // Standard attributes |
| ngDevMode && ngDevMode.rendererSetAttribute++; |
| if (isAnimationProp(attrName)) { |
| if (isProc) { |
| renderer.setProperty(native, attrName, attrVal); |
| } |
| } |
| else { |
| isProc ? |
| renderer |
| .setAttribute(native, attrName, attrVal) : |
| native.setAttribute(attrName, attrVal); |
| } |
| i++; |
| } |
| } |
| // another piece of code may iterate over the same attributes array. Therefore |
| // it may be helpful to return the exact spot where the attributes array exited |
| // whether by running into an unsupported marker or if all the static values were |
| // iterated over. |
| return i; |
| } |
| function attrsStylingIndexOf(attrs, startIndex) { |
| for (var i = startIndex; i < attrs.length; i++) { |
| var val = attrs[i]; |
| if (val === 1 /* Classes */ || val === 2 /* Styles */) { |
| return i; |
| } |
| } |
| return -1; |
| } |
| /** |
| * Test whether the given value is a marker that indicates that the following |
| * attribute values in a `TAttributes` array are only the names of attributes, |
| * and not name-value pairs. |
| * @param marker The attribute marker to test. |
| * @returns true if the marker is a "name-only" marker (e.g. `Bindings`, `Template` or `I18n`). |
| */ |
| function isNameOnlyAttributeMarker(marker) { |
| return marker === 3 /* Bindings */ || marker === 4 /* Template */ || |
| marker === 6 /* I18n */; |
| } |
| |
| /** |
| * @license |
| * Copyright Google Inc. All Rights Reserved. |
| * |
| * Use of this source code is governed by an MIT-style license that can be |
| * found in the LICENSE file at https://angular.io/license |
| */ |
| /// Parent Injector Utils /////////////////////////////////////////////////////////////// |
| function hasParentInjector(parentLocation) { |
| return parentLocation !== NO_PARENT_INJECTOR; |
| } |
| function getParentInjectorIndex(parentLocation) { |
| return parentLocation & 32767 /* InjectorIndexMask */; |
| } |
| function getParentInjectorViewOffset(parentLocation) { |
| return parentLocation >> 16 /* ViewOffsetShift */; |
| } |
| /** |
| * Unwraps a parent injector location number to find the view offset from the current injector, |
| * then walks up the declaration view tree until the view is found that contains the parent |
| * injector. |
| * |
| * @param location The location of the parent injector, which contains the view offset |
| * @param startView The LView instance from which to start walking up the view tree |
| * @returns The LView instance that contains the parent injector |
| */ |
| function getParentInjectorView(location, startView) { |
| var viewOffset = getParentInjectorViewOffset(location); |
| var parentView = startView; |
| // For most cases, the parent injector can be found on the host node (e.g. for component |
| // or container), but we must keep the loop here to support the rarer case of deeply nested |
| // <ng-template> tags or inline views, where the parent injector might live many views |
| // above the child injector. |
| while (viewOffset > 0) { |
| parentView = parentView[DECLARATION_VIEW]; |
| viewOffset--; |
| } |
| return parentView; |
| } |
| |
| /** |
| * @license |
| * Copyright Google Inc. All Rights Reserved. |
| * |
| * Use of this source code is governed by an MIT-style license that can be |
| * found in the LICENSE file at https://angular.io/license |
| */ |
| /** |
| * Gets the parent LView of the passed LView, if the PARENT is an LContainer, will get the parent of |
| * that LContainer, which is an LView |
| * @param lView the lView whose parent to get |
| */ |
| function getLViewParent(lView) { |
| ngDevMode && assertLView(lView); |
| var parent = lView[PARENT]; |
| return isLContainer(parent) ? parent[PARENT] : parent; |
| } |
| /** |
| * Retrieve the root view from any component or `LView` by walking the parent `LView` until |
| * reaching the root `LView`. |
| * |
| * @param componentOrLView any component or `LView` |
| */ |
| function getRootView(componentOrLView) { |
| ngDevMode && assertDefined(componentOrLView, 'component'); |
| var lView = isLView(componentOrLView) ? componentOrLView : readPatchedLView(componentOrLView); |
| while (lView && !(lView[FLAGS] & 512 /* IsRoot */)) { |
| lView = getLViewParent(lView); |
| } |
| ngDevMode && assertLView(lView); |
| return lView; |
| } |
| /** |
| * Given an `LView`, find the closest declaration view which is not an embedded view. |
| * |
| * This method searches for the `LView` associated with the component which declared the `LView`. |
| * |
| * This function may return itself if the `LView` passed in is not an embedded `LView`. Otherwise |
| * it walks the declaration parents until it finds a component view (non-embedded-view.) |
| * |
| * @param lView LView for which we want a host element node |
| * @returns The host node |
| */ |
| function findComponentView(lView) { |
| var rootTNode = lView[T_HOST]; |
| while (rootTNode !== null && rootTNode.type === 2 /* View */) { |
| ngDevMode && assertDefined(lView[DECLARATION_VIEW], 'lView[DECLARATION_VIEW]'); |
| lView = lView[DECLARATION_VIEW]; |
| rootTNode = lView[T_HOST]; |
| } |
| ngDevMode && assertLView(lView); |
| return lView; |
| } |
| /** |
| * Returns the `RootContext` instance that is associated with |
| * the application where the target is situated. It does this by walking the parent views until it |
| * gets to the root view, then getting the context off of that. |
| * |
| * @param viewOrComponent the `LView` or component to get the root context for. |
| */ |
| function getRootContext(viewOrComponent) { |
| var rootView = getRootView(viewOrComponent); |
| ngDevMode && |
| assertDefined(rootView[CONTEXT], 'RootView has no context. Perhaps it is disconnected?'); |
| return rootView[CONTEXT]; |
| } |
| |
| /** |
| * @license |
| * Copyright Google Inc. All Rights Reserved. |
| * |
| * Use of this source code is governed by an MIT-style license that can be |
| * found in the LICENSE file at https://angular.io/license |
| */ |
| /** |
| * Defines if the call to `inject` should include `viewProviders` in its resolution. |
| * |
| * This is set to true when we try to instantiate a component. This value is reset in |
| * `getNodeInjectable` to a value which matches the declaration location of the token about to be |
| * instantiated. This is done so that if we are injecting a token which was declared outside of |
| * `viewProviders` we don't accidentally pull `viewProviders` in. |
| * |
| * Example: |
| * |
| * ``` |
| * @Injectable() |
| * class MyService { |
| * constructor(public value: String) {} |
| * } |
| * |
| * @Component({ |
| * providers: [ |
| * MyService, |
| * {provide: String, value: 'providers' } |
| * ] |
| * viewProviders: [ |
| * {provide: String, value: 'viewProviders'} |
| * ] |
| * }) |
| * class MyComponent { |
| * constructor(myService: MyService, value: String) { |
| * // We expect that Component can see into `viewProviders`. |
| * expect(value).toEqual('viewProviders'); |
| * // `MyService` was not declared in `viewProviders` hence it can't see it. |
| * expect(myService.value).toEqual('providers'); |
| * } |
| * } |
| * |
| * ``` |
| */ |
| var includeViewProviders = true; |
| function setIncludeViewProviders(v) { |
| var oldValue = includeViewProviders; |
| includeViewProviders = v; |
| return oldValue; |
| } |
| /** |
| * The number of slots in each bloom filter (used by DI). The larger this number, the fewer |
| * directives that will share slots, and thus, the fewer false positives when checking for |
| * the existence of a directive. |
| */ |
| var BLOOM_SIZE = 256; |
| var BLOOM_MASK = BLOOM_SIZE - 1; |
| /** Counter used to generate unique IDs for directives. */ |
| var nextNgElementId = 0; |
| /** |
| * Registers this directive as present in its node's injector by flipping the directive's |
| * corresponding bit in the injector's bloom filter. |
| * |
| * @param injectorIndex The index of the node injector where this token should be registered |
| * @param tView The TView for the injector's bloom filters |
| * @param type The directive token to register |
| */ |
| function bloomAdd(injectorIndex, tView, type) { |
| ngDevMode && assertEqual(tView.firstTemplatePass, true, 'expected firstTemplatePass to be true'); |
| var id = typeof type !== 'string' ? type[NG_ELEMENT_ID] : type.charCodeAt(0) || 0; |
| // Set a unique ID on the directive type, so if something tries to inject the directive, |
| // we can easily retrieve the ID and hash it into the bloom bit that should be checked. |
| if (id == null) { |
| id = type[NG_ELEMENT_ID] = nextNgElementId++; |
| } |
| // We only have BLOOM_SIZE (256) slots in our bloom filter (8 buckets * 32 bits each), |
| // so all unique IDs must be modulo-ed into a number from 0 - 255 to fit into the filter. |
| var bloomBit = id & BLOOM_MASK; |
| // Create a mask that targets the specific bit associated with the directive. |
| // JS bit operations are 32 bits, so this will be a number between 2^0 and 2^31, corresponding |
| // to bit positions 0 - 31 in a 32 bit integer. |
| var mask = 1 << bloomBit; |
| // Use the raw bloomBit number to determine which bloom filter bucket we should check |
| // e.g: bf0 = [0 - 31], bf1 = [32 - 63], bf2 = [64 - 95], bf3 = [96 - 127], etc |
| var b7 = bloomBit & 0x80; |
| var b6 = bloomBit & 0x40; |
| var b5 = bloomBit & 0x20; |
| var tData = tView.data; |
| if (b7) { |
| b6 ? (b5 ? (tData[injectorIndex + 7] |= mask) : (tData[injectorIndex + 6] |= mask)) : |
| (b5 ? (tData[injectorIndex + 5] |= mask) : (tData[injectorIndex + 4] |= mask)); |
| } |
| else { |
| b6 ? (b5 ? (tData[injectorIndex + 3] |= mask) : (tData[injectorIndex + 2] |= mask)) : |
| (b5 ? (tData[injectorIndex + 1] |= mask) : (tData[injectorIndex] |= mask)); |
| } |
| } |
| /** |
| * Creates (or gets an existing) injector for a given element or container. |
| * |
| * @param tNode for which an injector should be retrieved / created. |
| * @param hostView View where the node is stored |
| * @returns Node injector |
| */ |
| function getOrCreateNodeInjectorForNode(tNode, hostView) { |
| var existingInjectorIndex = getInjectorIndex(tNode, hostView); |
| if (existingInjectorIndex !== -1) { |
| return existingInjectorIndex; |
| } |
| var tView = hostView[TVIEW]; |
| if (tView.firstTemplatePass) { |
| tNode.injectorIndex = hostView.length; |
| insertBloom(tView.data, tNode); // foundation for node bloom |
| insertBloom(hostView, null); // foundation for cumulative bloom |
| insertBloom(tView.blueprint, null); |
| ngDevMode && assertEqual(tNode.flags === 0 || tNode.flags === 1 /* isComponent */, true, 'expected tNode.flags to not be initialized'); |
| } |
| var parentLoc = getParentInjectorLocation(tNode, hostView); |
| var parentIndex = getParentInjectorIndex(parentLoc); |
| var parentLView = getParentInjectorView(parentLoc, hostView); |
| var injectorIndex = tNode.injectorIndex; |
| // If a parent injector can't be found, its location is set to -1. |
| // In that case, we don't need to set up a cumulative bloom |
| if (hasParentInjector(parentLoc)) { |
| var parentData = parentLView[TVIEW].data; |
| // Creates a cumulative bloom filter that merges the parent's bloom filter |
| // and its own cumulative bloom (which contains tokens for all ancestors) |
| for (var i = 0; i < 8; i++) { |
| hostView[injectorIndex + i] = parentLView[parentIndex + i] | parentData[parentIndex + i]; |
| } |
| } |
| hostView[injectorIndex + PARENT_INJECTOR] = parentLoc; |
| return injectorIndex; |
| } |
| function insertBloom(arr, footer) { |
| arr.push(0, 0, 0, 0, 0, 0, 0, 0, footer); |
| } |
| function getInjectorIndex(tNode, hostView) { |
| if (tNode.injectorIndex === -1 || |
| // If the injector index is the same as its parent's injector index, then the index has been |
| // copied down from the parent node. No injector has been created yet on this node. |
| (tNode.parent && tNode.parent.injectorIndex === tNode.injectorIndex) || |
| // After the first template pass, the injector index might exist but the parent values |
| // might not have been calculated yet for this instance |
| hostView[tNode.injectorIndex + PARENT_INJECTOR] == null) { |
| return -1; |
| } |
| else { |
| return tNode.injectorIndex; |
| } |
| } |
| /** |
| * Finds the index of the parent injector, with a view offset if applicable. Used to set the |
| * parent injector initially. |
| * |
| * Returns a combination of number of `ViewData` we have to go up and index in that `Viewdata` |
| */ |
| function getParentInjectorLocation(tNode, view) { |
| if (tNode.parent && tNode.parent.injectorIndex !== -1) { |
| return tNode.parent.injectorIndex; // ViewOffset is 0 |
| } |
| // For most cases, the parent injector index can be found on the host node (e.g. for component |
| // or container), so this loop will be skipped, but we must keep the loop here to support |
| // the rarer case of deeply nested <ng-template> tags or inline views. |
| var hostTNode = view[T_HOST]; |
| var viewOffset = 1; |
| while (hostTNode && hostTNode.injectorIndex === -1) { |
| view = view[DECLARATION_VIEW]; |
| hostTNode = view ? view[T_HOST] : null; |
| viewOffset++; |
| } |
| return hostTNode ? |
| hostTNode.injectorIndex | (viewOffset << 16 /* ViewOffsetShift */) : |
| -1; |
| } |
| /** |
| * Makes a type or an injection token public to the DI system by adding it to an |
| * injector's bloom filter. |
| * |
| * @param di The node injector in which a directive will be added |
| * @param token The type or the injection token to be made public |
| */ |
| function diPublicInInjector(injectorIndex, view, token) { |
| bloomAdd(injectorIndex, view[TVIEW], token); |
| } |
| /** |
| * Inject static attribute value into directive constructor. |
| * |
| * This method is used with `factory` functions which are generated as part of |
| * `defineDirective` or `defineComponent`. The method retrieves the static value |
| * of an attribute. (Dynamic attributes are not supported since they are not resolved |
| * at the time of injection and can change over time.) |
| * |
| * # Example |
| * Given: |
| * ``` |
| * @Component(...) |
| * class MyComponent { |
| * constructor(@Attribute('title') title: string) { ... } |
| * } |
| * ``` |
| * When instantiated with |
| * ``` |
| * <my-component title="Hello"></my-component> |
| * ``` |
| * |
| * Then factory method generated is: |
| * ``` |
| * MyComponent.ngComponentDef = defineComponent({ |
| * factory: () => new MyComponent(injectAttribute('title')) |
| * ... |
| * }) |
| * ``` |
| * |
| * @publicApi |
| */ |
| function injectAttributeImpl(tNode, attrNameToInject) { |
| ngDevMode && assertNodeOfPossibleTypes(tNode, 0 /* Container */, 3 /* Element */, 4 /* ElementContainer */); |
| ngDevMode && assertDefined(tNode, 'expecting tNode'); |
| var attrs = tNode.attrs; |
| if (attrs) { |
| var attrsLength = attrs.length; |
| var i = 0; |
| while (i < attrsLength) { |
| var value = attrs[i]; |
| // If we hit a `Bindings` or `Template` marker then we are done. |
| if (isNameOnlyAttributeMarker(value)) |
| break; |
| // Skip namespaced attributes |
| if (value === 0 /* NamespaceURI */) { |
| // we skip the next two values |
| // as namespaced attributes looks like |
| // [..., AttributeMarker.NamespaceURI, 'http://someuri.com/test', 'test:exist', |
| // 'existValue', ...] |
| i = i + 2; |
| } |
| else if (typeof value === 'number') { |
| // Skip to the first value of the marked attribute. |
| i++; |
| if (value === 1 /* Classes */ && attrNameToInject === 'class') { |
| var accumulatedClasses = ''; |
| while (i < attrsLength && typeof attrs[i] === 'string') { |
| accumulatedClasses += ' ' + attrs[i++]; |
| } |
| return accumulatedClasses.trim(); |
| } |
| else if (value === 2 /* Styles */ && attrNameToInject === 'style') { |
| var accumulatedStyles = ''; |
| while (i < attrsLength && typeof attrs[i] === 'string') { |
| accumulatedStyles += attrs[i++] + ": " + attrs[i++] + "; "; |
| } |
| return accumulatedStyles.trim(); |
| } |
| else { |
| while (i < attrsLength && typeof attrs[i] === 'string') { |
| i++; |
| } |
| } |
| } |
| else if (value === attrNameToInject) { |
| return attrs[i + 1]; |
| } |
| else { |
| i = i + 2; |
| } |
| } |
| } |
| return null; |
| } |
| /** |
| * Returns the value associated to the given token from the NodeInjectors => ModuleInjector. |
| * |
| * Look for the injector providing the token by walking up the node injector tree and then |
| * the module injector tree. |
| * |
| * This function patches `token` with `__NG_ELEMENT_ID__` which contains the id for the bloom |
| * filter. Negative values are reserved for special objects. |
| * - `-1` is reserved for injecting `Injector` (implemented by `NodeInjector`) |
| * |
| * @param tNode The Node where the search for the injector should start |
| * @param lView The `LView` that contains the `tNode` |
| * @param token The token to look for |
| * @param flags Injection flags |
| * @param notFoundValue The value to return when the injection flags is `InjectFlags.Optional` |
| * @returns the value from the injector, `null` when not found, or `notFoundValue` if provided |
| */ |
| function getOrCreateInjectable(tNode, lView, token, flags, notFoundValue) { |
| if (flags === void 0) { flags = exports.InjectFlags.Default; } |
| if (tNode) { |
| var bloomHash = bloomHashBitOrFactory(token); |
| // If the ID stored here is a function, this is a special object like ElementRef or TemplateRef |
| // so just call the factory function to create it. |
| if (typeof bloomHash === 'function') { |
| var savePreviousOrParentTNode = getPreviousOrParentTNode(); |
| var saveLView = getLView(); |
| setTNodeAndViewData(tNode, lView); |
| try { |
| var value = bloomHash(); |
| if (value == null && !(flags & exports.InjectFlags.Optional)) { |
| throw new Error("No provider for " + stringifyForError(token) + "!"); |
| } |
| else { |
| return value; |
| } |
| } |
| finally { |
| setTNodeAndViewData(savePreviousOrParentTNode, saveLView); |
| } |
| } |
| else if (typeof bloomHash == 'number') { |
| if (bloomHash === -1) { |
| // `-1` is a special value used to identify `Injector` types. |
| return new NodeInjector(tNode, lView); |
| } |
| // If the token has a bloom hash, then it is a token which could be in NodeInjector. |
| // A reference to the previous injector TView that was found while climbing the element |
| // injector tree. This is used to know if viewProviders can be accessed on the current |
| // injector. |
| var previousTView = null; |
| var injectorIndex = getInjectorIndex(tNode, lView); |
| var parentLocation = NO_PARENT_INJECTOR; |
| var hostTElementNode = flags & exports.InjectFlags.Host ? findComponentView(lView)[T_HOST] : null; |
| // If we should skip this injector, or if there is no injector on this node, start by |
| // searching |
| // the parent injector. |
| if (injectorIndex === -1 || flags & exports.InjectFlags.SkipSelf) { |
| parentLocation = injectorIndex === -1 ? getParentInjectorLocation(tNode, lView) : |
| lView[injectorIndex + PARENT_INJECTOR]; |
| if (!shouldSearchParent(flags, false)) { |
| injectorIndex = -1; |
| } |
| else { |
| previousTView = lView[TVIEW]; |
| injectorIndex = getParentInjectorIndex(parentLocation); |
| lView = getParentInjectorView(parentLocation, lView); |
| } |
| } |
| // Traverse up the injector tree until we find a potential match or until we know there |
| // *isn't* a match. |
| while (injectorIndex !== -1) { |
| parentLocation = lView[injectorIndex + PARENT_INJECTOR]; |
| // Check the current injector. If it matches, see if it contains token. |
| var tView = lView[TVIEW]; |
| if (bloomHasToken(bloomHash, injectorIndex, tView.data)) { |
| // At this point, we have an injector which *may* contain the token, so we step through |
| // the providers and directives associated with the injector's corresponding node to get |
| // the instance. |
| var instance = searchTokensOnInjector(injectorIndex, lView, token, previousTView, flags, hostTElementNode); |
| if (instance !== NOT_FOUND) { |
| return instance; |
| } |
| } |
| if (shouldSearchParent(flags, lView[TVIEW].data[injectorIndex + TNODE] === hostTElementNode) && |
| bloomHasToken(bloomHash, injectorIndex, lView)) { |
| // The def wasn't found anywhere on this node, so it was a false positive. |
| // Traverse up the tree and continue searching. |
| previousTView = tView; |
| injectorIndex = getParentInjectorIndex(parentLocation); |
| lView = getParentInjectorView(parentLocation, lView); |
| } |
| else { |
| // If we should not search parent OR If the ancestor bloom filter value does not have the |
| // bit corresponding to the directive we can give up on traversing up to find the specific |
| // injector. |
| injectorIndex = -1; |
| } |
| } |
| } |
| } |
| if (flags & exports.InjectFlags.Optional && notFoundValue === undefined) { |
| // This must be set or the NullInjector will throw for optional deps |
| notFoundValue = null; |
| } |
| if ((flags & (exports.InjectFlags.Self | exports.InjectFlags.Host)) === 0) { |
| var moduleInjector = lView[INJECTOR$1]; |
| // switch to `injectInjectorOnly` implementation for module injector, since module injector |
| // should not have access to Component/Directive DI scope (that may happen through |
| // `directiveInject` implementation) |
| var previousInjectImplementation = setInjectImplementation(undefined); |
| try { |
| if (moduleInjector) { |
| return moduleInjector.get(token, notFoundValue, flags & exports.InjectFlags.Optional); |
| } |
| else { |
| return injectRootLimpMode(token, notFoundValue, flags & exports.InjectFlags.Optional); |
| } |
| } |
| finally { |
| setInjectImplementation(previousInjectImplementation); |
| } |
| } |
| if (flags & exports.InjectFlags.Optional) { |
| return notFoundValue; |
| } |
| else { |
| throw new Error("NodeInjector: NOT_FOUND [" + stringifyForError(token) + "]"); |
| } |
| } |
| var NOT_FOUND = {}; |
| function searchTokensOnInjector(injectorIndex, lView, token, previousTView, flags, hostTElementNode) { |
| var currentTView = lView[TVIEW]; |
| var tNode = currentTView.data[injectorIndex + TNODE]; |
| // First, we need to determine if view providers can be accessed by the starting element. |
| // There are two possibities |
| var canAccessViewProviders = previousTView == null ? |
| // 1) This is the first invocation `previousTView == null` which means that we are at the |
| // `TNode` of where injector is starting to look. In such a case the only time we are allowed |
| // to look into the ViewProviders is if: |
| // - we are on a component |
| // - AND the injector set `includeViewProviders` to true (implying that the token can see |
| // ViewProviders because it is the Component or a Service which itself was declared in |
| // ViewProviders) |
| (isComponent(tNode) && includeViewProviders) : |
| // 2) `previousTView != null` which means that we are now walking across the parent nodes. |
| // In such a case we are only allowed to look into the ViewProviders if: |
| // - We just crossed from child View to Parent View `previousTView != currentTView` |
| // - AND the parent TNode is an Element. |
| // This means that we just came from the Component's View and therefore are allowed to see |
| // into the ViewProviders. |
| (previousTView != currentTView && (tNode.type === 3 /* Element */)); |
| // This special case happens when there is a @host on the inject and when we are searching |
| // on the host element node. |
| var isHostSpecialCase = (flags & exports.InjectFlags.Host) && hostTElementNode === tNode; |
| var injectableIdx = locateDirectiveOrProvider(tNode, currentTView, token, canAccessViewProviders, isHostSpecialCase); |
| if (injectableIdx !== null) { |
| return getNodeInjectable(currentTView.data, lView, injectableIdx, tNode); |
| } |
| else { |
| return NOT_FOUND; |
| } |
| } |
| /** |
| * Searches for the given token among the node's directives and providers. |
| * |
| * @param tNode TNode on which directives are present. |
| * @param tView The tView we are currently processing |
| * @param token Provider token or type of a directive to look for. |
| * @param canAccessViewProviders Whether view providers should be considered. |
| * @param isHostSpecialCase Whether the host special case applies. |
| * @returns Index of a found directive or provider, or null when none found. |
| */ |
| function locateDirectiveOrProvider(tNode, tView, token, canAccessViewProviders, isHostSpecialCase) { |
| var nodeProviderIndexes = tNode.providerIndexes; |
| var tInjectables = tView.data; |
| var injectablesStart = nodeProviderIndexes & 65535 /* ProvidersStartIndexMask */; |
| var directivesStart = tNode.directiveStart; |
| var directiveEnd = tNode.directiveEnd; |
| var cptViewProvidersCount = nodeProviderIndexes >> 16 /* CptViewProvidersCountShift */; |
| var startingIndex = canAccessViewProviders ? injectablesStart : injectablesStart + cptViewProvidersCount; |
| // When the host special case applies, only the viewProviders and the component are visible |
| var endIndex = isHostSpecialCase ? injectablesStart + cptViewProvidersCount : directiveEnd; |
| for (var i = startingIndex; i < endIndex; i++) { |
| var providerTokenOrDef = tInjectables[i]; |
| if (i < directivesStart && token === providerTokenOrDef || |
| i >= directivesStart && providerTokenOrDef.type === token) { |
| return i; |
| } |
| } |
| if (isHostSpecialCase) { |
| var dirDef = tInjectables[directivesStart]; |
| if (dirDef && isComponentDef(dirDef) && dirDef.type === token) { |
| return directivesStart; |
| } |
| } |
| return null; |
| } |
| /** |
| * Retrieve or instantiate the injectable from the `lData` at particular `index`. |
| * |
| * This function checks to see if the value has already been instantiated and if so returns the |
| * cached `injectable`. Otherwise if it detects that the value is still a factory it |
| * instantiates the `injectable` and caches the value. |
| */ |
| function getNodeInjectable(tData, lData, index, tNode) { |
| var value = lData[index]; |
| if (isFactory(value)) { |
| var factory = value; |
| if (factory.resolving) { |
| throw new Error("Circular dep for " + stringifyForError(tData[index])); |
| } |
| var previousIncludeViewProviders = setIncludeViewProviders(factory.canSeeViewProviders); |
| factory.resolving = true; |
| var previousInjectImplementation = void 0; |
| if (factory.injectImpl) { |
| previousInjectImplementation = setInjectImplementation(factory.injectImpl); |
| } |
| var savePreviousOrParentTNode = getPreviousOrParentTNode(); |
| var saveLView = getLView(); |
| setTNodeAndViewData(tNode, lData); |
| try { |
| value = lData[index] = factory.factory(null, tData, lData, tNode); |
| } |
| finally { |
| if (factory.injectImpl) |
| setInjectImplementation(previousInjectImplementation); |
| setIncludeViewProviders(previousIncludeViewProviders); |
| factory.resolving = false; |
| setTNodeAndViewData(savePreviousOrParentTNode, saveLView); |
| } |
| } |
| return value; |
| } |
| /** |
| * Returns the bit in an injector's bloom filter that should be used to determine whether or not |
| * the directive might be provided by the injector. |
| * |
| * When a directive is public, it is added to the bloom filter and given a unique ID that can be |
| * retrieved on the Type. When the directive isn't public or the token is not a directive `null` |
| * is returned as the node injector can not possibly provide that token. |
| * |
| * @param token the injection token |
| * @returns the matching bit to check in the bloom filter or `null` if the token is not known. |
| * When the returned value is negative then it represents special values such as `Injector`. |
| */ |
| function bloomHashBitOrFactory(token) { |
| ngDevMode && assertDefined(token, 'token must be defined'); |
| if (typeof token === 'string') { |
| return token.charCodeAt(0) || 0; |
| } |
| var tokenId = token[NG_ELEMENT_ID]; |
| // Negative token IDs are used for special objects such as `Injector` |
| return (typeof tokenId === 'number' && tokenId > 0) ? tokenId & BLOOM_MASK : tokenId; |
| } |
| function bloomHasToken(bloomHash, injectorIndex, injectorView) { |
| // Create a mask that targets the specific bit associated with the directive we're looking for. |
| // JS bit operations are 32 bits, so this will be a number between 2^0 and 2^31, corresponding |
| // to bit positions 0 - 31 in a 32 bit integer. |
| var mask = 1 << bloomHash; |
| var b7 = bloomHash & 0x80; |
| var b6 = bloomHash & 0x40; |
| var b5 = bloomHash & 0x20; |
| // Our bloom filter size is 256 bits, which is eight 32-bit bloom filter buckets: |
| // bf0 = [0 - 31], bf1 = [32 - 63], bf2 = [64 - 95], bf3 = [96 - 127], etc. |
| // Get the bloom filter value from the appropriate bucket based on the directive's bloomBit. |
| var value; |
| if (b7) { |
| value = b6 ? (b5 ? injectorView[injectorIndex + 7] : injectorView[injectorIndex + 6]) : |
| (b5 ? injectorView[injectorIndex + 5] : injectorView[injectorIndex + 4]); |
| } |
| else { |
| value = b6 ? (b5 ? injectorView[injectorIndex + 3] : injectorView[injectorIndex + 2]) : |
| (b5 ? injectorView[injectorIndex + 1] : injectorView[injectorIndex]); |
| } |
| // If the bloom filter value has the bit corresponding to the directive's bloomBit flipped on, |
| // this injector is a potential match. |
| return !!(value & mask); |
| } |
| /** Returns true if flags prevent parent injector from being searched for tokens */ |
| function shouldSearchParent(flags, isFirstHostTNode) { |
| return !(flags & exports.InjectFlags.Self) && !(flags & exports.InjectFlags.Host && isFirstHostTNode); |
| } |
| var NodeInjector = /** @class */ (function () { |
| function NodeInjector(_tNode, _lView) { |
| this._tNode = _tNode; |
| this._lView = _lView; |
| } |
| NodeInjector.prototype.get = function (token, notFoundValue) { |
| return getOrCreateInjectable(this._tNode, this._lView, token, undefined, notFoundValue); |
| }; |
| return NodeInjector; |
| }()); |
| /** |
| * @codeGenApi |
| */ |
| function ɵɵgetFactoryOf(type) { |
| var typeAny = type; |
| var def = getComponentDef(typeAny) || getDirectiveDef(typeAny) || |
| getPipeDef(typeAny) || getInjectableDef(typeAny) || getInjectorDef(typeAny); |
| if (!def || def.factory === undefined) { |
| return null; |
| } |
| return def.factory; |
| } |
| /** |
| * @codeGenApi |
| */ |
| function ɵɵgetInheritedFactory(type) { |
| var proto = Object.getPrototypeOf(type.prototype).constructor; |
| var factory = ɵɵgetFactoryOf(proto); |
| if (factory !== null) { |
| return factory; |
| } |
| else { |
| // There is no factory defined. Either this was improper usage of inheritance |
| // (no Angular decorator on the superclass) or there is no constructor at all |
| // in the inheritance chain. Since the two cases cannot be distinguished, the |
| // latter has to be assumed. |
| return function (t) { return new t(); }; |
| } |
| } |
| |
| /** |
| * @license |
| * Copyright Google Inc. All Rights Reserved. |
| * |
| * Use of this source code is governed by an MIT-style license that can be |
| * found in the LICENSE file at https://angular.io/license |
| */ |
| function getDebugContext(error) { |
| return error[ERROR_DEBUG_CONTEXT]; |
| } |
| function getOriginalError(error) { |
| return error[ERROR_ORIGINAL_ERROR]; |
| } |
| function getErrorLogger(error) { |
| return error[ERROR_LOGGER] || defaultErrorLogger; |
| } |
| function defaultErrorLogger(console) { |
| var values = []; |
| for (var _i = 1; _i < arguments.length; _i++) { |
| values[_i - 1] = arguments[_i]; |
| } |
| console.error.apply(console, __spread(values)); |
| } |
| |
| /** |
| * @license |
| * Copyright Google Inc. All Rights Reserved. |
| * |
| * Use of this source code is governed by an MIT-style license that can be |
| * found in the LICENSE file at https://angular.io/license |
| */ |
| /** |
| * Provides a hook for centralized exception handling. |
| * |
| * The default implementation of `ErrorHandler` prints error messages to the `console`. To |
| * intercept error handling, write a custom exception handler that replaces this default as |
| * appropriate for your app. |
| * |
| * @usageNotes |
| * ### Example |
| * |
| * ``` |
| * class MyErrorHandler implements ErrorHandler { |
| * handleError(error) { |
| * // do something with the exception |
| * } |
| * } |
| * |
| * @NgModule({ |
| * providers: [{provide: ErrorHandler, useClass: MyErrorHandler}] |
| * }) |
| * class MyModule {} |
| * ``` |
| * |
| * @publicApi |
| */ |
| var ErrorHandler = /** @class */ (function () { |
| function ErrorHandler() { |
| /** |
| * @internal |
| */ |
| this._console = console; |
| } |
| ErrorHandler.prototype.handleError = function (error) { |
| var originalError = this._findOriginalError(error); |
| var context = this._findContext(error); |
| // Note: Browser consoles show the place from where console.error was called. |
| // We can use this to give users additional information about the error. |
| var errorLogger = getErrorLogger(error); |
| errorLogger(this._console, "ERROR", error); |
| if (originalError) { |
| errorLogger(this._console, "ORIGINAL ERROR", originalError); |
| } |
| if (context) { |
| errorLogger(this._console, 'ERROR CONTEXT', context); |
| } |
| }; |
| /** @internal */ |
| ErrorHandler.prototype._findContext = function (error) { |
| if (error) { |
| return getDebugContext(error) ? getDebugContext(error) : |
| this._findContext(getOriginalError(error)); |
| } |
| return null; |
| }; |
| /** @internal */ |
| ErrorHandler.prototype._findOriginalError = function (error) { |
| var e = getOriginalError(error); |
| while (e && getOriginalError(e)) { |
| e = getOriginalError(e); |
| } |
| return e; |
| }; |
| return ErrorHandler; |
| }()); |
| |
| /** |
| * @license |
| * Copyright Google Inc. All Rights Reserved. |
| * |
| * Use of this source code is governed by an MIT-style license that can be |
| * found in the LICENSE file at https://angular.io/license |
| */ |
| /** |
| * Defines a schema that allows an NgModule to contain the following: |
| * - Non-Angular elements named with dash case (`-`). |
| * - Element properties named with dash case (`-`). |
| * Dash case is the naming convention for custom elements. |
| * |
| * @publicApi |
| */ |
| var CUSTOM_ELEMENTS_SCHEMA = { |
| name: 'custom-elements' |
| }; |
| /** |
| * Defines a schema that allows any property on any element. |
| * |
| * @publicApi |
| */ |
| var NO_ERRORS_SCHEMA = { |
| name: 'no-errors-schema' |
| }; |
| |
| /** |
| * @license |
| * Copyright Google Inc. All Rights Reserved. |
| * |
| * Use of this source code is governed by an MIT-style license that can be |
| * found in the LICENSE file at https://angular.io/license |
| */ |
| /** |
| * THIS FILE CONTAINS CODE WHICH SHOULD BE TREE SHAKEN AND NEVER CALLED FROM PRODUCTION CODE!!! |
| */ |
| /** |
| * Creates an `Array` construction with a given name. This is useful when |
| * looking for memory consumption to see what time of array it is. |
| * |
| * |
| * @param name Name to give to the constructor |
| * @returns A subclass of `Array` if possible. This can only be done in |
| * environments which support `class` construct. |
| */ |
| function createNamedArrayType(name) { |
| // This should never be called in prod mode, so let's verify that is the case. |
| if (ngDevMode) { |
| try { |
| // We need to do it this way so that TypeScript does not down-level the below code. |
| var FunctionConstructor = createNamedArrayType.constructor; |
| return (new FunctionConstructor('Array', "return class ABC extends Array{}"))(Array); |
| } |
| catch (e) { |
| // If it does not work just give up and fall back to regular Array. |
| return Array; |
| } |
| } |
| else { |
| throw new Error('Looks like we are in \'prod mode\', but we are creating a named Array type, which is wrong! Check your code'); |
| } |
| } |
| |
| /** |
| * @license |
| * Copyright Google Inc. All Rights Reserved. |
| * |
| * Use of this source code is governed by an MIT-style license that can be |
| * found in the LICENSE file at https://angular.io/license |
| */ |
| function normalizeDebugBindingName(name) { |
| // Attribute names with `$` (eg `x-y$`) are valid per spec, but unsupported by some browsers |
| name = camelCaseToDashCase(name.replace(/[$@]/g, '_')); |
| return "ng-reflect-" + name; |
| } |
| var CAMEL_CASE_REGEXP = /([A-Z])/g; |
| function camelCaseToDashCase(input) { |
| return input.replace(CAMEL_CASE_REGEXP, function () { |
| var m = []; |
| for (var _i = 0; _i < arguments.length; _i++) { |
| m[_i] = arguments[_i]; |
| } |
| return '-' + m[1].toLowerCase(); |
| }); |
| } |
| function normalizeDebugBindingValue(value) { |
| try { |
| // Limit the size of the value as otherwise the DOM just gets polluted. |
| return value != null ? value.toString().slice(0, 30) : value; |
| } |
| catch (e) { |
| return '[ERROR] Exception while trying to serialize the value'; |
| } |
| } |
| |
| // Note: This hack is necessary so we don't erroneously get a circular dependency |
| |
| /** |
| * @license |
| * Copyright Google Inc. All Rights Reserved. |
| * |
| * Use of this source code is governed by an MIT-style license that can be |
| * found in the LICENSE file at https://angular.io/license |
| */ |
| |
| /** |
| * @license |
| * Copyright Google Inc. All Rights Reserved. |
| * |
| * Use of this source code is governed by an MIT-style license that can be |
| * found in the LICENSE file at https://angular.io/license |
| */ |
| /** A special value which designates that a value has not changed. */ |
| var NO_CHANGE = {}; |
| |
| /* |
| * This file contains the logic to defer all hostBindings-related styling code to run |
| * at a later point, instead of immediately (as is the case with how template-level |
| * styling instructions are run). |
| * |
| * Certain styling instructions, present within directives, components and sub-classed |
| * directives, are evaluated at different points (depending on priority) and will therefore |
| * not be applied to the styling context of an element immediately. They are instead |
| * designed to be applied just before styling is applied to an element. |
| * |
| * (The priority for when certain host-related styling operations are executed is discussed |
| * more within `interfaces/styling.ts`.) |
| */ |
| function registerHostDirective(context, directiveIndex) { |
| var buffer = context[8 /* HostInstructionsQueue */]; |
| if (!buffer) { |
| buffer = context[8 /* HostInstructionsQueue */] = [DEFAULT_TEMPLATE_DIRECTIVE_INDEX]; |
| } |
| buffer[0 /* LastRegisteredDirectiveIndexPosition */] = directiveIndex; |
| } |
| /** |
| * Queues a styling instruction to be run just before `renderStyling()` is executed. |
| */ |
| function enqueueHostInstruction(context, priority, instructionFn, instructionFnArgs) { |
| var buffer = context[8 /* HostInstructionsQueue */]; |
| // Buffer may be null if host element is a template node. In this case, just ignore the style. |
| if (buffer != null) { |
| var index = findNextInsertionIndex(buffer, priority); |
| buffer.splice(index, 0, priority, instructionFn, instructionFnArgs); |
| } |
| } |
| /** |
| * Figures out where exactly to to insert the next host instruction queue entry. |
| */ |
| function findNextInsertionIndex(buffer, priority) { |
| for (var i = 1 /* ValuesStartPosition */; i < buffer.length; i += 3 /* Size */) { |
| var p = buffer[i + 0 /* DirectiveIndexOffset */]; |
| if (p > priority) { |
| return i; |
| } |
| } |
| return buffer.length; |
| } |
| /** |
| * Iterates through the host instructions queue (if present within the provided |
| * context) and executes each queued instruction entry. |
| */ |
| function flushQueue(context) { |
| var buffer = context[8 /* HostInstructionsQueue */]; |
| if (buffer) { |
| for (var i = 1 /* ValuesStartPosition */; i < buffer.length; i += 3 /* Size */) { |
| var fn = buffer[i + 1 /* InstructionFnOffset */]; |
| var args = buffer[i + 2 /* ParamsOffset */]; |
| fn.apply(this, args); |
| } |
| buffer.length = 1 /* ValuesStartPosition */; |
| } |
| } |
| /** |
| * Determines whether or not to allow the host instructions queue to be flushed or not. |
| * |
| * Because the hostBindings function code is unaware of the presence of other host bindings |
| * (as well as the template function) then styling is evaluated multiple times per element. |
| * To prevent style and class values from being applied to the element multiple times, a |
| * flush is only allowed when the last directive (the directive that was registered into |
| * the styling context) attempts to render its styling. |
| */ |
| function allowFlush(context, directiveIndex) { |
| var buffer = context[8 /* HostInstructionsQueue */]; |
| if (buffer) { |
| return buffer[0 /* LastRegisteredDirectiveIndexPosition */] === |
| directiveIndex; |
| } |
| return true; |
| } |
| |
| /** |
| * Combines the binding value and a factory for an animation player. |
| * |
| * Used to bind a player to an element template binding (currently only |
| * `[style]`, `[style.prop]`, `[class]` and `[class.name]` bindings |
| * supported). The provided `factoryFn` function will be run once all |
| * the associated bindings have been evaluated on the element and is |
| * designed to return a player which will then be placed on the element. |
| * |
| * @param factoryFn The function that is used to create a player |
| * once all the rendering-related (styling values) have been |
| * processed for the element binding. |
| * @param value The raw value that will be exposed to the binding |
| * so that the binding can update its internal values when |
| * any changes are evaluated. |
| */ |
| function bindPlayerFactory(factoryFn, value) { |
| return new BoundPlayerFactory(factoryFn, value); |
| } |
| var BoundPlayerFactory = /** @class */ (function () { |
| function BoundPlayerFactory(fn, value) { |
| this.fn = fn; |
| this.value = value; |
| } |
| return BoundPlayerFactory; |
| }()); |
| |
| /** |
| * This file includes the code to power all styling-binding operations in Angular. |
| * |
| * These include: |
| * [style]="myStyleObj" |
| * [class]="myClassObj" |
| * [style.prop]="myPropValue" |
| * [class.name]="myClassValue" |
| * |
| * It also includes code that will allow style binding code to operate within host |
| * bindings for components/directives. |
| * |
| * There are many different ways in which these functions below are called. Please see |
| * `render3/interfaces/styling.ts` to get a better idea of how the styling algorithm works. |
| */ |
| /** |
| * Creates a new StylingContext an fills it with the provided static styling attribute values. |
| */ |
| function initializeStaticContext(attrs, stylingStartIndex, directiveIndex) { |
| if (directiveIndex === void 0) { directiveIndex = 0; } |
| var context = createEmptyStylingContext(); |
| patchContextWithStaticAttrs(context, attrs, stylingStartIndex, directiveIndex); |
| return context; |
| } |
| /** |
| * Designed to update an existing styling context with new static styling |
| * data (classes and styles). |
| * |
| * @param context the existing styling context |
| * @param attrs an array of new static styling attributes that will be |
| * assigned to the context |
| * @param attrsStylingStartIndex what index to start iterating within the |
| * provided `attrs` array to start reading style and class values |
| */ |
| function patchContextWithStaticAttrs(context, attrs, attrsStylingStartIndex, directiveIndex) { |
| // this means the context has already been set and instantiated |
| if (context[1 /* MasterFlagPosition */] & 16 /* BindingAllocationLocked */) |
| return; |
| allocateOrUpdateDirectiveIntoContext(context, directiveIndex); |
| var initialClasses = null; |
| var initialStyles = null; |
| var mode = -1; |
| for (var i = attrsStylingStartIndex; i < attrs.length; i++) { |
| var attr = attrs[i]; |
| if (typeof attr == 'number') { |
| mode = attr; |
| } |
| else if (mode == 1 /* Classes */) { |
| initialClasses = initialClasses || context[4 /* InitialClassValuesPosition */]; |
| patchInitialStylingValue(initialClasses, attr, true, directiveIndex); |
| } |
| else if (mode == 2 /* Styles */) { |
| initialStyles = initialStyles || context[3 /* InitialStyleValuesPosition */]; |
| patchInitialStylingValue(initialStyles, attr, attrs[++i], directiveIndex); |
| } |
| } |
| } |
| /** |
| * Designed to add a style or class value into the existing set of initial styles. |
| * |
| * The function will search and figure out if a style/class value is already present |
| * within the provided initial styling array. If and when a style/class value is |
| * present (allocated) then the code below will set the new value depending on the |
| * following cases: |
| * |
| * 1) if the existing value is falsy (this happens because a `[class.prop]` or |
| * `[style.prop]` binding was set, but there wasn't a matching static style |
| * or class present on the context) |
| * 2) if the value was set already by the template, component or directive, but the |
| * new value is set on a higher level (i.e. a sub component which extends a parent |
| * component sets its value after the parent has already set the same one) |
| * 3) if the same directive provides a new set of styling values to set |
| * |
| * @param initialStyling the initial styling array where the new styling entry will be added to |
| * @param prop the property value of the new entry (e.g. `width` (styles) or `foo` (classes)) |
| * @param value the styling value of the new entry (e.g. `absolute` (styles) or `true` (classes)) |
| * @param directiveOwnerIndex the directive owner index value of the styling source responsible |
| * for these styles (see `interfaces/styling.ts#directives` for more info) |
| */ |
| function patchInitialStylingValue(initialStyling, prop, value, directiveOwnerIndex) { |
| for (var i = 2 /* KeyValueStartPosition */; i < initialStyling.length; i += 3 /* Size */) { |
| var key = initialStyling[i + 0 /* PropOffset */]; |
| if (key === prop) { |
| var existingValue = initialStyling[i + 1 /* ValueOffset */]; |
| var existingOwner = initialStyling[i + 2 /* DirectiveOwnerOffset */]; |
| if (allowValueChange(existingValue, value, existingOwner, directiveOwnerIndex)) { |
| addOrUpdateStaticStyle(i, initialStyling, prop, value, directiveOwnerIndex); |
| } |
| return; |
| } |
| } |
| // We did not find existing key, add a new one. |
| addOrUpdateStaticStyle(null, initialStyling, prop, value, directiveOwnerIndex); |
| } |
| /** |
| * Runs through the initial class values present in the provided |
| * context and renders them via the provided renderer on the element. |
| * |
| * @param element the element the styling will be applied to |
| * @param context the source styling context which contains the initial class values |
| * @param renderer the renderer instance that will be used to apply the class |
| * @returns the index that the classes were applied up until |
| */ |
| function renderInitialClasses(element, context, renderer, startIndex) { |
| var initialClasses = context[4 /* InitialClassValuesPosition */]; |
| var i = startIndex || 2 /* KeyValueStartPosition */; |
| while (i < initialClasses.length) { |
| var value = initialClasses[i + 1 /* ValueOffset */]; |
| if (value) { |
| setClass(element, initialClasses[i + 0 /* PropOffset */], true, renderer, null); |
| } |
| i += 3 /* Size */; |
| } |
| return i; |
| } |
| /** |
| * Runs through the initial styles values present in the provided |
| * context and renders them via the provided renderer on the element. |
| * |
| * @param element the element the styling will be applied to |
| * @param context the source styling context which contains the initial class values |
| * @param renderer the renderer instance that will be used to apply the class |
| * @returns the index that the styles were applied up until |
| */ |
| function renderInitialStyles(element, context, renderer, startIndex) { |
| var initialStyles = context[3 /* InitialStyleValuesPosition */]; |
| var i = startIndex || 2 /* KeyValueStartPosition */; |
| while (i < initialStyles.length) { |
| var value = initialStyles[i + 1 /* ValueOffset */]; |
| if (value) { |
| setStyle(element, initialStyles[i + 0 /* PropOffset */], value, renderer, null); |
| } |
| i += 3 /* Size */; |
| } |
| return i; |
| } |
| /** |
| * Adds in new binding values to a styling context. |
| * |
| * If a directive value is provided then all provided class/style binding names will |
| * reference the provided directive. |
| * |
| * @param context the existing styling context |
| * @param classBindingNames an array of class binding names that will be added to the context |
| * @param styleBindingNames an array of style binding names that will be added to the context |
| * @param styleSanitizer an optional sanitizer that handle all sanitization on for each of |
| * the bindings added to the context. Note that if a directive is provided then the sanitizer |
| * instance will only be active if and when the directive updates the bindings that it owns. |
| */ |
| function updateContextWithBindings(context, directiveIndex, classBindingNames, styleBindingNames, styleSanitizer) { |
| if (context[1 /* MasterFlagPosition */] & 16 /* BindingAllocationLocked */) |
| return; |
| // this means the context has already been patched with the directive's bindings |
| var isNewDirective = findOrPatchDirectiveIntoRegistry(context, directiveIndex, false, styleSanitizer); |
| if (!isNewDirective) { |
| // this means the directive has already been patched in ... No point in doing anything |
| return; |
| } |
| if (styleBindingNames) { |
| styleBindingNames = hyphenateEntries(styleBindingNames); |
| } |
| // there are alot of variables being used below to track where in the context the new |
| // binding values will be placed. Because the context consists of multiple types of |
| // entries (single classes/styles and multi classes/styles) alot of the index positions |
| // need to be computed ahead of time and the context needs to be extended before the values |
| // are inserted in. |
| var singlePropOffsetValues = context[5 /* SinglePropOffsetPositions */]; |
| var totalCurrentClassBindings = singlePropOffsetValues[1 /* ClassesCountPosition */]; |
| var totalCurrentStyleBindings = singlePropOffsetValues[0 /* StylesCountPosition */]; |
| var cachedClassMapValues = context[6 /* CachedMultiClasses */]; |
| var cachedStyleMapValues = context[7 /* CachedMultiStyles */]; |
| var classesOffset = totalCurrentClassBindings * 4 /* Size */; |
| var stylesOffset = totalCurrentStyleBindings * 4 /* Size */; |
| var singleStylesStartIndex = 10 /* SingleStylesStartPosition */; |
| var singleClassesStartIndex = singleStylesStartIndex + stylesOffset; |
| var multiStylesStartIndex = singleClassesStartIndex + classesOffset; |
| var multiClassesStartIndex = multiStylesStartIndex + stylesOffset; |
| // because we're inserting more bindings into the context, this means that the |
| // binding values need to be referenced the singlePropOffsetValues array so that |
| // the template/directive can easily find them inside of the `styleProp` |
| // and the `classProp` functions without iterating through the entire context. |
| // The first step to setting up these reference points is to mark how many bindings |
| // are being added. Even if these bindings already exist in the context, the directive |
| // or template code will still call them unknowingly. Therefore the total values need |
| // to be registered so that we know how many bindings are assigned to each directive. |
| var currentSinglePropsLength = singlePropOffsetValues.length; |
| singlePropOffsetValues.push(styleBindingNames ? styleBindingNames.length : 0, classBindingNames ? classBindingNames.length : 0); |
| // the code below will check to see if a new style binding already exists in the context |
| // if so then there is no point in inserting it into the context again. Whether or not it |
| // exists the styling offset code will now know exactly where it is |
| var insertionOffset = 0; |
| var filteredStyleBindingNames = []; |
| if (styleBindingNames && styleBindingNames.length) { |
| for (var i_1 = 0; i_1 < styleBindingNames.length; i_1++) { |
| var name_1 = styleBindingNames[i_1]; |
| var singlePropIndex = getMatchingBindingIndex(context, name_1, singleStylesStartIndex, singleClassesStartIndex); |
| if (singlePropIndex == -1) { |
| singlePropIndex = singleClassesStartIndex + insertionOffset; |
| insertionOffset += 4 /* Size */; |
| filteredStyleBindingNames.push(name_1); |
| } |
| singlePropOffsetValues.push(singlePropIndex); |
| } |
| } |
| // just like with the style binding loop above, the new class bindings get the same treatment... |
| var filteredClassBindingNames = []; |
| if (classBindingNames && classBindingNames.length) { |
| for (var i_2 = 0; i_2 < classBindingNames.length; i_2++) { |
| var name_2 = classBindingNames[i_2]; |
| var singlePropIndex = getMatchingBindingIndex(context, name_2, singleClassesStartIndex, multiStylesStartIndex); |
| if (singlePropIndex == -1) { |
| singlePropIndex = multiStylesStartIndex + insertionOffset; |
| insertionOffset += 4 /* Size */; |
| filteredClassBindingNames.push(name_2); |
| } |
| else { |
| singlePropIndex += filteredStyleBindingNames.length * 4 /* Size */; |
| } |
| singlePropOffsetValues.push(singlePropIndex); |
| } |
| } |
| // because new styles are being inserted, this means the existing collection of style offset |
| // index values are incorrect (they point to the wrong values). The code below will run through |
| // the entire offset array and update the existing set of index values to point to their new |
| // locations while taking the new binding values into consideration. |
| var i = 2 /* ValueStartPosition */; |
| if (filteredStyleBindingNames.length) { |
| while (i < currentSinglePropsLength) { |
| var totalStyles = singlePropOffsetValues[i + 0 /* StylesCountPosition */]; |
| var totalClasses = singlePropOffsetValues[i + 1 /* ClassesCountPosition */]; |
| if (totalClasses) { |
| var start = i + 2 /* ValueStartPosition */ + totalStyles; |
| for (var j = start; j < start + totalClasses; j++) { |
| singlePropOffsetValues[j] += filteredStyleBindingNames.length * 4 /* Size */; |
| } |
| } |
| var total = totalStyles + totalClasses; |
| i += 2 /* ValueStartPosition */ + total; |
| } |
| } |
| var totalNewEntries = filteredClassBindingNames.length + filteredStyleBindingNames.length; |
| // in the event that there are new style values being inserted, all existing class and style |
| // bindings need to have their pointer values offsetted with the new amount of space that is |
| // used for the new style/class bindings. |
| for (var i_3 = singleStylesStartIndex; i_3 < context.length; i_3 += 4 /* Size */) { |
| var isMultiBased = i_3 >= multiStylesStartIndex; |
| var isClassBased = i_3 >= (isMultiBased ? multiClassesStartIndex : singleClassesStartIndex); |
| var flag = getPointers(context, i_3); |
| var staticIndex = getInitialIndex(flag); |
| var singleOrMultiIndex = getMultiOrSingleIndex(flag); |
| if (isMultiBased) { |
| singleOrMultiIndex += |
| isClassBased ? (filteredStyleBindingNames.length * 4 /* Size */) : 0; |
| } |
| else { |
| singleOrMultiIndex += (totalNewEntries * 4 /* Size */) + |
| ((isClassBased ? filteredStyleBindingNames.length : 0) * 4 /* Size */); |
| } |
| setFlag(context, i_3, pointers(flag, staticIndex, singleOrMultiIndex)); |
| } |
| // this is where we make space in the context for the new style bindings |
| for (var i_4 = 0; i_4 < filteredStyleBindingNames.length * 4 /* Size */; i_4++) { |
| context.splice(multiClassesStartIndex, 0, null); |
| context.splice(singleClassesStartIndex, 0, null); |
| singleClassesStartIndex++; |
| multiStylesStartIndex++; |
| multiClassesStartIndex += 2; // both single + multi slots were inserted |
| } |
| // this is where we make space in the context for the new class bindings |
| for (var i_5 = 0; i_5 < filteredClassBindingNames.length * 4 /* Size */; i_5++) { |
| context.splice(multiStylesStartIndex, 0, null); |
| context.push(null); |
| multiStylesStartIndex++; |
| multiClassesStartIndex++; |
| } |
| var initialClasses = context[4 /* InitialClassValuesPosition */]; |
| var initialStyles = context[3 /* InitialStyleValuesPosition */]; |
| // the code below will insert each new entry into the context and assign the appropriate |
| // flags and index values to them. It's important this runs at the end of this function |
| // because the context, property offset and index values have all been computed just before. |
| for (var i_6 = 0; i_6 < totalNewEntries; i_6++) { |
| var entryIsClassBased = i_6 >= filteredStyleBindingNames.length; |
| var adjustedIndex = entryIsClassBased ? (i_6 - filteredStyleBindingNames.length) : i_6; |
| var propName = entryIsClassBased ? filteredClassBindingNames[adjustedIndex] : |
| filteredStyleBindingNames[adjustedIndex]; |
| var multiIndex = void 0, singleIndex = void 0; |
| if (entryIsClassBased) { |
| multiIndex = multiClassesStartIndex + |
| ((totalCurrentClassBindings + adjustedIndex) * 4 /* Size */); |
| singleIndex = singleClassesStartIndex + |
| ((totalCurrentClassBindings + adjustedIndex) * 4 /* Size */); |
| } |
| else { |
| multiIndex = |
| multiStylesStartIndex + ((totalCurrentStyleBindings + adjustedIndex) * 4 /* Size */); |
| singleIndex = singleStylesStartIndex + |
| ((totalCurrentStyleBindings + adjustedIndex) * 4 /* Size */); |
| } |
| // if a property is not found in the initial style values list then it |
| // is ALWAYS added in case a follow-up directive introduces the same initial |
| // style/class value later on. |
| var initialValuesToLookup = entryIsClassBased ? initialClasses : initialStyles; |
| var indexForInitial = getInitialStylingValuesIndexOf(initialValuesToLookup, propName); |
| if (indexForInitial === -1) { |
| indexForInitial = addOrUpdateStaticStyle(null, initialValuesToLookup, propName, entryIsClassBased ? false : null, directiveIndex) + |
| 1 /* ValueOffset */; |
| } |
| else { |
| indexForInitial += 1 /* ValueOffset */; |
| } |
| var initialFlag = prepareInitialFlag(context, propName, entryIsClassBased, styleSanitizer || null); |
| setFlag(context, singleIndex, pointers(initialFlag, indexForInitial, multiIndex)); |
| setProp(context, singleIndex, propName); |
| setValue(context, singleIndex, null); |
| setPlayerBuilderIndex(context, singleIndex, 0, directiveIndex); |
| setFlag(context, multiIndex, pointers(initialFlag, indexForInitial, singleIndex)); |
| setProp(context, multiIndex, propName); |
| setValue(context, multiIndex, null); |
| setPlayerBuilderIndex(context, multiIndex, 0, directiveIndex); |
| } |
| // the total classes/style values are updated so the next time the context is patched |
| // additional style/class bindings from another directive then it knows exactly where |
| // to insert them in the context |
| singlePropOffsetValues[1 /* ClassesCountPosition */] = |
| totalCurrentClassBindings + filteredClassBindingNames.length; |
| singlePropOffsetValues[0 /* StylesCountPosition */] = |
| totalCurrentStyleBindings + filteredStyleBindingNames.length; |
| // the map-based values also need to know how many entries got inserted |
| cachedClassMapValues[0 /* EntriesCountPosition */] += |
| filteredClassBindingNames.length; |
| cachedStyleMapValues[0 /* EntriesCountPosition */] += |
| filteredStyleBindingNames.length; |
| var newStylesSpaceAllocationSize = filteredStyleBindingNames.length * 4 /* Size */; |
| var newClassesSpaceAllocationSize = filteredClassBindingNames.length * 4 /* Size */; |
| // update the multi styles cache with a reference for the directive that was just inserted |
| var directiveMultiStylesStartIndex = multiStylesStartIndex + totalCurrentStyleBindings * 4 /* Size */; |
| var cachedStyleMapIndex = cachedStyleMapValues.length; |
| registerMultiMapEntry(context, directiveIndex, false, directiveMultiStylesStartIndex, filteredStyleBindingNames.length); |
| for (var i_7 = 1 /* ValuesStartPosition */; i_7 < cachedStyleMapIndex; i_7 += 4 /* Size */) { |
| // multi values start after all the single values (which is also where classes are) in the |
| // context therefore the new class allocation size should be taken into account |
| cachedStyleMapValues[i_7 + 1 /* PositionStartOffset */] += |
| newClassesSpaceAllocationSize + newStylesSpaceAllocationSize; |
| } |
| // update the multi classes cache with a reference for the directive that was just inserted |
| var directiveMultiClassesStartIndex = multiClassesStartIndex + totalCurrentClassBindings * 4 /* Size */; |
| var cachedClassMapIndex = cachedClassMapValues.length; |
| registerMultiMapEntry(context, directiveIndex, true, directiveMultiClassesStartIndex, filteredClassBindingNames.length); |
| for (var i_8 = 1 /* ValuesStartPosition */; i_8 < cachedClassMapIndex; i_8 += 4 /* Size */) { |
| // the reason why both the styles + classes space is allocated to the existing offsets is |
| // because the styles show up before the classes in the context and any new inserted |
| // styles will offset any existing class entries in the context (even if there are no |
| // new class entries added) also the reason why it's *2 is because both single + multi |
| // entries for each new style have been added in the context before the multi class values |
| // actually start |
| cachedClassMapValues[i_8 + 1 /* PositionStartOffset */] += |
| (newStylesSpaceAllocationSize * 2) + newClassesSpaceAllocationSize; |
| } |
| // there is no initial value flag for the master index since it doesn't |
| // reference an initial style value |
| var masterFlag = pointers(0, 0, multiStylesStartIndex); |
| setFlag(context, 1 /* MasterFlagPosition */, masterFlag); |
| } |
| /** |
| * Searches through the existing registry of directives |
| */ |
| function findOrPatchDirectiveIntoRegistry(context, directiveIndex, staticModeOnly, styleSanitizer) { |
| var directiveRegistry = context[2 /* DirectiveRegistryPosition */]; |
| var index = directiveIndex * 2 /* Size */; |
| var singlePropStartPosition = index + 0 /* SinglePropValuesIndexOffset */; |
| // this means that the directive has already been registered into the registry |
| if (index < directiveRegistry.length && |
| directiveRegistry[singlePropStartPosition] >= 0) |
| return false; |
| var singlePropsStartIndex = staticModeOnly ? -1 : context[5 /* SinglePropOffsetPositions */].length; |
| allocateOrUpdateDirectiveIntoContext(context, directiveIndex, singlePropsStartIndex, styleSanitizer); |
| return true; |
| } |
| function getMatchingBindingIndex(context, bindingName, start, end) { |
| for (var j = start; j < end; j += 4 /* Size */) { |
| if (getProp(context, j) === bindingName) |
| return j; |
| } |
| return -1; |
| } |
| /** |
| * Registers the provided multi class values to the context. |
| * |
| * This function will iterate over the provided `classesInput` values and |
| * insert/update or remove them from the context at exactly the right spot. |
| * |
| * This function also takes in a directive which implies that the styling values will |
| * be evaluated for that directive with respect to any other styling that already exists |
| * on the context. When there are styles that conflict (e.g. say `ngClass` and `[class]` |
| * both update the `foo` className value at the same time) then the styling algorithm code below |
| * will decide which one wins based on the directive styling prioritization mechanism. (This |
| * mechanism is better explained in render3/interfaces/styling.ts#directives). |
| * |
| * This function will not render any styling values on screen, but is rather designed to |
| * prepare the context for that. `renderStyling` must be called afterwards to render any |
| * styling data that was set in this function (note that `updateClassProp` and |
| * `updateStyleProp` are designed to be run after this function is run). |
| * |
| * @param context The styling context that will be updated with the |
| * newly provided style values. |
| * @param classesInput The key/value map of CSS class names that will be used for the update. |
| * @param stylesInput The key/value map of CSS styles that will be used for the update. |
| */ |
| function updateClassMap(context, classesInput, directiveIndex) { |
| if (directiveIndex === void 0) { directiveIndex = 0; } |
| updateStylingMap(context, classesInput, true, directiveIndex); |
| } |
| /** |
| * Registers the provided multi style values to the context. |
| * |
| * This function will iterate over the provided `stylesInput` values and |
| * insert/update or remove them from the context at exactly the right spot. |
| * |
| * This function also takes in a directive which implies that the styling values will |
| * be evaluated for that directive with respect to any other styling that already exists |
| * on the context. When there are styles that conflict (e.g. say `ngStyle` and `[style]` |
| * both update the `width` property at the same time) then the styling algorithm code below |
| * will decide which one wins based on the directive styling prioritization mechanism. (This |
| * mechanism is better explained in render3/interfaces/styling.ts#directives). |
| * |
| * This function will not render any styling values on screen, but is rather designed to |
| * prepare the context for that. `renderStyling` must be called afterwards to render any |
| * styling data that was set in this function (note that `updateClassProp` and |
| * `updateStyleProp` are designed to be run after this function is run). |
| * |
| * @param context The styling context that will be updated with the |
| * newly provided style values. |
| * @param stylesInput The key/value map of CSS styles that will be used for the update. |
| */ |
| function updateStyleMap(context, stylesInput, directiveIndex) { |
| if (directiveIndex === void 0) { directiveIndex = 0; } |
| updateStylingMap(context, stylesInput, false, directiveIndex); |
| } |
| function updateStylingMap(context, input, entryIsClassBased, directiveIndex) { |
| if (directiveIndex === void 0) { directiveIndex = 0; } |
| ngDevMode && (entryIsClassBased ? ngDevMode.classMap++ : ngDevMode.styleMap++); |
| ngDevMode && assertValidDirectiveIndex(context, directiveIndex); |
| // early exit (this is what's done to avoid using ctx.bind() to cache the value) |
| if (isMultiValueCacheHit(context, entryIsClassBased, directiveIndex, input)) |
| return; |
| input = |
| input === NO_CHANGE ? readCachedMapValue(context, entryIsClassBased, directiveIndex) : input; |
| var element = context[0 /* ElementPosition */]; |
| var playerBuilder = input instanceof BoundPlayerFactory ? |
| new ClassAndStylePlayerBuilder(input, element, entryIsClassBased ? 1 /* Class */ : 2 /* Style */) : |
| null; |
| var rawValue = playerBuilder ? input.value : input; |
| // the position is always the same, but whether the player builder gets set |
| // at all (depending if its set) will be reflected in the index value below... |
| var playerBuilderPosition = entryIsClassBased ? 1 /* ClassMapPlayerBuilderPosition */ : |
| 3 /* StyleMapPlayerBuilderPosition */; |
| var playerBuilderIndex = playerBuilder ? playerBuilderPosition : 0; |
| var playerBuildersAreDirty = false; |
| if (hasPlayerBuilderChanged(context, playerBuilder, playerBuilderPosition)) { |
| setPlayerBuilder(context, playerBuilder, playerBuilderPosition); |
| playerBuildersAreDirty = true; |
| } |
| // each time a string-based value pops up then it shouldn't require a deep |
| // check of what's changed. |
| var startIndex; |
| var endIndex; |
| var propNames; |
| var applyAll = false; |
| if (entryIsClassBased) { |
| if (typeof rawValue == 'string') { |
| propNames = rawValue.split(/\s+/); |
| // this boolean is used to avoid having to create a key/value map of `true` values |
| // since a className string implies that all those classes are added |
| applyAll = true; |
| } |
| else { |
| propNames = rawValue ? Object.keys(rawValue) : EMPTY_ARRAY$2; |
| } |
| startIndex = getMultiClassesStartIndex(context); |
| endIndex = context.length; |
| } |
| else { |
| startIndex = getMultiStylesStartIndex(context); |
| endIndex = getMultiClassesStartIndex(context); |
| propNames = rawValue ? Object.keys(rawValue) : EMPTY_ARRAY$2; |
| } |
| var values = (rawValue || EMPTY_OBJ); |
| patchStylingMapIntoContext(context, directiveIndex, playerBuilderIndex, startIndex, endIndex, propNames, applyAll || values, input, entryIsClassBased); |
| if (playerBuildersAreDirty) { |
| setContextPlayersDirty(context, true); |
| } |
| ngDevMode && (entryIsClassBased ? ngDevMode.classMapCacheMiss++ : ngDevMode.styleMapCacheMiss++); |
| } |
| /** |
| * Applies the given multi styling (styles or classes) values to the context. |
| * |
| * The styling algorithm code that applies multi-level styling (things like `[style]` and `[class]` |
| * values) resides here. |
| * |
| * Because this function understands that multiple directives may all write to the `[style]` and |
| * `[class]` bindings (through host bindings), it relies of each directive applying its binding |
| * value in order. This means that a directive like `classADirective` will always fire before |
| * `classBDirective` and therefore its styling values (classes and styles) will always be evaluated |
| * in the same order. Because of this consistent ordering, the first directive has a higher priority |
| * than the second one. It is with this prioritzation mechanism that the styling algorithm knows how |
| * to merge and apply redudant styling properties. |
| * |
| * The function itself applies the key/value entries (or an array of keys) to |
| * the context in the following steps. |
| * |
| * STEP 1: |
| * First check to see what properties are already set and in use by another directive in the |
| * context (e.g. `ngClass` set the `width` value and `[style.width]="w"` in a directive is |
| * attempting to set it as well). |
| * |
| * STEP 2: |
| * All remaining properties (that were not set prior to this directive) are now updated in |
| * the context. Any new properties are inserted exactly at their spot in the context and any |
| * previously set properties are shifted to exactly where the cursor sits while iterating over |
| * the context. The end result is a balanced context that includes the exact ordering of the |
| * styling properties/values for the provided input from the directive. |
| * |
| * STEP 3: |
| * Any unmatched properties in the context that belong to the directive are set to null |
| * |
| * Once the updating phase is done, then the algorithm will decide whether or not to flag the |
| * follow-up directives (the directives that will pass in their styling values) depending on if |
| * the "shape" of the multi-value map has changed (either if any keys are removed or added or |
| * if there are any new `null` values). If any follow-up directives are flagged as dirty then the |
| * algorithm will run again for them. Otherwise if the shape did not change then any follow-up |
| * directives will not run (so long as their binding values stay the same). |
| * |
| * @returns the total amount of new slots that were allocated into the context due to new styling |
| * properties that were detected. |
| */ |
| function patchStylingMapIntoContext(context, directiveIndex, playerBuilderIndex, ctxStart, ctxEnd, props, values, cacheValue, entryIsClassBased) { |
| var dirty = false; |
| var cacheIndex = 1 /* ValuesStartPosition */ + |
| directiveIndex * 4 /* Size */; |
| // the cachedValues array is the registry of all multi style values (map values). Each |
| // value is stored (cached) each time is updated. |
| var cachedValues = context[entryIsClassBased ? 6 /* CachedMultiClasses */ : 7 /* CachedMultiStyles */]; |
| // this is the index in which this directive has ownership access to write to this |
| // value (anything before is owned by a previous directive that is more important) |
| var ownershipValuesStartIndex = cachedValues[cacheIndex + 1 /* PositionStartOffset */]; |
| var existingCachedValue = cachedValues[cacheIndex + 2 /* ValueOffset */]; |
| var existingCachedValueCount = cachedValues[cacheIndex + 3 /* ValueCountOffset */]; |
| var existingCachedValueIsDirty = cachedValues[cacheIndex + 0 /* DirtyFlagOffset */] === 1; |
| // A shape change means the provided map value has either removed or added new properties |
| // compared to what were in the last time. If a shape change occurs then it means that all |
| // follow-up multi-styling entries are obsolete and will be examined again when CD runs |
| // them. If a shape change has not occurred then there is no reason to check any other |
| // directive values if their identity has not changed. If a previous directive set this |
| // value as dirty (because its own shape changed) then this means that the object has been |
| // offset to a different area in the context. Because its value has been offset then it |
| // can't write to a region that it wrote to before (which may have been apart of another |
| // directive) and therefore its shape changes too. |
| var valuesEntryShapeChange = existingCachedValueIsDirty || ((!existingCachedValue && cacheValue) ? true : false); |
| var totalUniqueValues = 0; |
| var totalNewAllocatedSlots = 0; |
| // this is a trick to avoid building {key:value} map where all the values |
| // are `true` (this happens when a className string is provided instead of a |
| // map as an input value to this styling algorithm) |
| var applyAllProps = values === true; |
| // STEP 1: |
| // loop through the earlier directives and figure out if any properties here will be placed |
| // in their area (this happens when the value is null because the earlier directive erased it). |
| var ctxIndex = ctxStart; |
| var totalRemainingProperties = props.length; |
| while (ctxIndex < ownershipValuesStartIndex) { |
| var currentProp = getProp(context, ctxIndex); |
| if (totalRemainingProperties) { |
| for (var i = 0; i < props.length; i++) { |
| var mapProp = props[i]; |
| var normalizedProp = mapProp ? (entryIsClassBased ? mapProp : hyphenate(mapProp)) : null; |
| if (normalizedProp && currentProp === normalizedProp) { |
| var currentValue = getValue(context, ctxIndex); |
| var currentDirectiveIndex = getDirectiveIndexFromEntry(context, ctxIndex); |
| var value = applyAllProps ? true : values[normalizedProp]; |
| var currentFlag = getPointers(context, ctxIndex); |
| if (hasValueChanged(currentFlag, currentValue, value) && |
| allowValueChange(currentValue, value, currentDirectiveIndex, directiveIndex)) { |
| setValue(context, ctxIndex, value); |
| setPlayerBuilderIndex(context, ctxIndex, playerBuilderIndex, directiveIndex); |
| if (hasInitialValueChanged(context, currentFlag, value)) { |
| setDirty(context, ctxIndex, true); |
| dirty = true; |
| } |
| } |
| props[i] = null; |
| totalRemainingProperties--; |
| break; |
| } |
| } |
| } |
| ctxIndex += 4 /* Size */; |
| } |
| // STEP 2: |
| // apply the left over properties to the context in the correct order. |
| if (totalRemainingProperties) { |
| var sanitizer = entryIsClassBased ? null : getStyleSanitizer(context, directiveIndex); |
| propertiesLoop: for (var i = 0; i < props.length; i++) { |
| var mapProp = props[i]; |
| if (!mapProp) { |
| // this is an early exit in case a value was already encountered above in the |
| // previous loop (which means that the property was applied or rejected) |
| continue; |
| } |
| var value = applyAllProps ? true : values[mapProp]; |
| var normalizedProp = entryIsClassBased ? mapProp : hyphenate(mapProp); |
| var isInsideOwnershipArea = ctxIndex >= ownershipValuesStartIndex; |
| for (var j = ctxIndex; j < ctxEnd; j += 4 /* Size */) { |
| var distantCtxProp = getProp(context, j); |
| if (distantCtxProp === normalizedProp) { |
| var distantCtxDirectiveIndex = getDirectiveIndexFromEntry(context, j); |
| var distantCtxPlayerBuilderIndex = getPlayerBuilderIndex(context, j); |
| var distantCtxValue = getValue(context, j); |
| var distantCtxFlag = getPointers(context, j); |
| if (allowValueChange(distantCtxValue, value, distantCtxDirectiveIndex, directiveIndex)) { |
| // even if the entry isn't updated (by value or directiveIndex) then |
| // it should still be moved over to the correct spot in the array so |
| // the iteration loop is tighter. |
| if (isInsideOwnershipArea) { |
| swapMultiContextEntries(context, ctxIndex, j); |
| totalUniqueValues++; |
| } |
| if (hasValueChanged(distantCtxFlag, distantCtxValue, value)) { |
| if (value === null || value === undefined && value !== distantCtxValue) { |
| valuesEntryShapeChange = true; |
| } |
| setValue(context, ctxIndex, value); |
| // SKIP IF INITIAL CHECK |
| // If the former `value` is `null` then it means that an initial value |
| // could be being rendered on screen. If that is the case then there is |
| // no point in updating the value in case it matches. In other words if the |
| // new value is the exact same as the previously rendered value (which |
| // happens to be the initial value) then do nothing. |
| if (distantCtxValue !== null || |
| hasInitialValueChanged(context, distantCtxFlag, value)) { |
| setDirty(context, ctxIndex, true); |
| dirty = true; |
| } |
| } |
| if (distantCtxDirectiveIndex !== directiveIndex || |
| playerBuilderIndex !== distantCtxPlayerBuilderIndex) { |
| setPlayerBuilderIndex(context, ctxIndex, playerBuilderIndex, directiveIndex); |
| } |
| } |
| ctxIndex += 4 /* Size */; |
| continue propertiesLoop; |
| } |
| } |
| // fallback case ... value not found at all in the context |
| if (value != null) { |
| valuesEntryShapeChange = true; |
| totalUniqueValues++; |
| var flag = prepareInitialFlag(context, normalizedProp, entryIsClassBased, sanitizer) | |
| 1 /* Dirty */; |
| var insertionIndex = isInsideOwnershipArea ? |
| ctxIndex : |
| (ownershipValuesStartIndex + totalNewAllocatedSlots * 4 /* Size */); |
| insertNewMultiProperty(context, insertionIndex, entryIsClassBased, normalizedProp, flag, value, directiveIndex, playerBuilderIndex); |
| totalNewAllocatedSlots++; |
| ctxEnd += 4 /* Size */; |
| ctxIndex += 4 /* Size */; |
| dirty = true; |
| } |
| } |
| } |
| // STEP 3: |
| // Remove (nullify) any existing entries in the context that were not apart of the |
| // map input value that was passed into this algorithm for this directive. |
| while (ctxIndex < ctxEnd) { |
| valuesEntryShapeChange = true; // some values are missing |
| var ctxValue = getValue(context, ctxIndex); |
| var ctxFlag = getPointers(context, ctxIndex); |
| var ctxDirective = getDirectiveIndexFromEntry(context, ctxIndex); |
| if (ctxValue != null) { |
| valuesEntryShapeChange = true; |
| } |
| if (hasValueChanged(ctxFlag, ctxValue, null)) { |
| setValue(context, ctxIndex, null); |
| // only if the initial value is falsy then |
| if (hasInitialValueChanged(context, ctxFlag, ctxValue)) { |
| setDirty(context, ctxIndex, true); |
| dirty = true; |
| } |
| setPlayerBuilderIndex(context, ctxIndex, playerBuilderIndex, directiveIndex); |
| } |
| ctxIndex += 4 /* Size */; |
| } |
| // Because the object shape has changed, this means that all follow-up directives will need to |
| // reapply their values into the object. For this to happen, the cached array needs to be updated |
| // with dirty flags so that follow-up calls to `updateStylingMap` will reapply their styling code. |
| // the reapplication of styling code within the context will reshape it and update the offset |
| // values (also follow-up directives can write new values in case earlier directives set anything |
| // to null due to removals or falsy values). |
| valuesEntryShapeChange = valuesEntryShapeChange || existingCachedValueCount !== totalUniqueValues; |
| updateCachedMapValue(context, directiveIndex, entryIsClassBased, cacheValue, ownershipValuesStartIndex, ctxEnd, totalUniqueValues, valuesEntryShapeChange); |
| if (dirty) { |
| setContextDirty(context, true); |
| } |
| return totalNewAllocatedSlots; |
| } |
| /** |
| * Sets and resolves a single class value on the provided `StylingContext` so |
| * that they can be applied to the element once `renderStyling` is called. |
| * |
| * @param context The styling context that will be updated with the |
| * newly provided class value. |
| * @param offset The index of the CSS class which is being updated. |
| * @param addOrRemove Whether or not to add or remove the CSS class |
| * @param forceOverride whether or not to skip all directive prioritization |
| * and just apply the value regardless. |
| */ |
| function updateClassProp(context, offset, input, directiveIndex, forceOverride) { |
| if (directiveIndex === void 0) { directiveIndex = 0; } |
| updateSingleStylingValue(context, offset, input, true, directiveIndex, forceOverride); |
| } |
| /** |
| * Sets and resolves a single style value on the provided `StylingContext` so |
| * that they can be applied to the element once `renderStyling` is called. |
| * |
| * Note that prop-level styling values are considered higher priority than any styling that |
| * has been applied using `updateStylingMap`, therefore, when styling values are rendered |
| * then any styles/classes that have been applied using this function will be considered first |
| * (then multi values second and then initial values as a backup). |
| * |
| * @param context The styling context that will be updated with the |
| * newly provided style value. |
| * @param offset The index of the property which is being updated. |
| * @param value The CSS style value that will be assigned |
| * @param forceOverride whether or not to skip all directive prioritization |
| * and just apply the value regardless. |
| */ |
| function updateStyleProp(context, offset, input, directiveIndex, forceOverride) { |
| if (directiveIndex === void 0) { directiveIndex = 0; } |
| updateSingleStylingValue(context, offset, input, false, directiveIndex, forceOverride); |
| } |
| function updateSingleStylingValue(context, offset, input, isClassBased, directiveIndex, forceOverride) { |
| ngDevMode && assertValidDirectiveIndex(context, directiveIndex); |
| var singleIndex = getSinglePropIndexValue(context, directiveIndex, offset, isClassBased); |
| var currValue = getValue(context, singleIndex); |
| var currFlag = getPointers(context, singleIndex); |
| var currDirective = getDirectiveIndexFromEntry(context, singleIndex); |
| var value = (input instanceof BoundPlayerFactory) ? input.value : input; |
| ngDevMode && ngDevMode.stylingProp++; |
| if (hasValueChanged(currFlag, currValue, value) && |
| (forceOverride || allowValueChange(currValue, value, currDirective, directiveIndex))) { |
| var isClassBased_1 = (currFlag & 2 /* Class */) === 2 /* Class */; |
| var element = context[0 /* ElementPosition */]; |
| var playerBuilder = input instanceof BoundPlayerFactory ? |
| new ClassAndStylePlayerBuilder(input, element, isClassBased_1 ? 1 /* Class */ : 2 /* Style */) : |
| null; |
| var value_1 = (playerBuilder ? input.value : input); |
| var currPlayerIndex = getPlayerBuilderIndex(context, singleIndex); |
| var playerBuildersAreDirty = false; |
| var playerBuilderIndex = playerBuilder ? currPlayerIndex : 0; |
| if (hasPlayerBuilderChanged(context, playerBuilder, currPlayerIndex)) { |
| var newIndex = setPlayerBuilder(context, playerBuilder, currPlayerIndex); |
| playerBuilderIndex = playerBuilder ? newIndex : 0; |
| playerBuildersAreDirty = true; |
| } |
| if (playerBuildersAreDirty || currDirective !== directiveIndex) { |
| setPlayerBuilderIndex(context, singleIndex, playerBuilderIndex, directiveIndex); |
| } |
| if (currDirective !== directiveIndex) { |
| var prop = getProp(context, singleIndex); |
| var sanitizer = getStyleSanitizer(context, directiveIndex); |
| setSanitizeFlag(context, singleIndex, (sanitizer && sanitizer(prop, null, 1 /* ValidateProperty */)) ? true : false); |
| } |
| // the value will always get updated (even if the dirty flag is skipped) |
| setValue(context, singleIndex, value_1); |
| var indexForMulti = getMultiOrSingleIndex(currFlag); |
| // if the value is the same in the multi-area then there's no point in re-assembling |
| var valueForMulti = getValue(context, indexForMulti); |
| if (!valueForMulti || hasValueChanged(currFlag, valueForMulti, value_1)) { |
| var multiDirty = false; |
| var singleDirty = true; |
| // only when the value is set to `null` should the multi-value get flagged |
| if (!valueExists(value_1, isClassBased_1) && valueExists(valueForMulti, isClassBased_1)) { |
| multiDirty = true; |
| singleDirty = false; |
| } |
| setDirty(context, indexForMulti, multiDirty); |
| setDirty(context, singleIndex, singleDirty); |
| setContextDirty(context, true); |
| } |
| if (playerBuildersAreDirty) { |
| setContextPlayersDirty(context, true); |
| } |
| ngDevMode && ngDevMode.stylingPropCacheMiss++; |
| } |
| } |
| /** |
| * Renders all queued styling using a renderer onto the given element. |
| * |
| * This function works by rendering any styles (that have been applied |
| * using `updateStylingMap`) and any classes (that have been applied using |
| * `updateStyleProp`) onto the provided element using the provided renderer. |
| * Just before the styles/classes are rendered a final key/value style map |
| * will be assembled (if `styleStore` or `classStore` are provided). |
| * |
| * @param lElement the element that the styles will be rendered on |
| * @param context The styling context that will be used to determine |
| * what styles will be rendered |
| * @param renderer the renderer that will be used to apply the styling |
| * @param classesStore if provided, the updated class values will be applied |
| * to this key/value map instead of being renderered via the renderer. |
| * @param stylesStore if provided, the updated style values will be applied |
| * to this key/value map instead of being renderered via the renderer. |
| * @returns number the total amount of players that got queued for animation (if any) |
| */ |
| function renderStyling(context, renderer, rootOrView, isFirstRender, classesStore, stylesStore, directiveIndex) { |
| if (directiveIndex === void 0) { directiveIndex = 0; } |
| var totalPlayersQueued = 0; |
| ngDevMode && ngDevMode.stylingApply++; |
| // this prevents multiple attempts to render style/class values on |
| // the same element... |
| if (allowFlush(context, directiveIndex)) { |
| // all styling instructions present within any hostBindings functions |
| // do not update the context immediately when called. They are instead |
| // queued up and applied to the context right at this point. Why? This |
| // is because Angular evaluates component/directive and directive |
| // sub-class code at different points and it's important that the |
| // styling values are applied to the context in the right order |
| // (see `interfaces/styling.ts` for more information). |
| flushQueue(context); |
| if (isContextDirty(context)) { |
| ngDevMode && ngDevMode.stylingApplyCacheMiss++; |
| // this is here to prevent things like <ng-container [style] [class]>...</ng-container> |
| // or if there are any host style or class bindings present in a directive set on |
| // a container node |
| var native = context[0 /* ElementPosition */]; |
| var flushPlayerBuilders = context[1 /* MasterFlagPosition */] & 8 /* PlayerBuildersDirty */; |
| var multiStartIndex = getMultiStylesStartIndex(context); |
| for (var i = 10 /* SingleStylesStartPosition */; i < context.length; i += 4 /* Size */) { |
| // there is no point in rendering styles that have not changed on screen |
| if (isDirty(context, i)) { |
| var flag = getPointers(context, i); |
| var directiveIndex_1 = getDirectiveIndexFromEntry(context, i); |
| var prop = getProp(context, i); |
| var value = getValue(context, i); |
| var styleSanitizer = (flag & 4 /* Sanitize */) ? getStyleSanitizer(context, directiveIndex_1) : null; |
| var playerBuilder = getPlayerBuilder(context, i); |
| var isClassBased = flag & 2 /* Class */ ? true : false; |
| var isInSingleRegion = i < multiStartIndex; |
| var valueToApply = value; |
| // VALUE DEFER CASE 1: Use a multi value instead of a null single value |
| // this check implies that a single value was removed and we |
| // should now defer to a multi value and use that (if set). |
| if (isInSingleRegion && !valueExists(valueToApply, isClassBased)) { |
| // single values ALWAYS have a reference to a multi index |
| var multiIndex = getMultiOrSingleIndex(flag); |
| valueToApply = getValue(context, multiIndex); |
| } |
| // VALUE DEFER CASE 2: Use the initial value if all else fails (is falsy) |
| // the initial value will always be a string or null, |
| // therefore we can safely adopt it in case there's nothing else |
| // note that this should always be a falsy check since `false` is used |
| // for both class and style comparisons (styles can't be false and false |
| // classes are turned off and should therefore defer to their initial values) |
| // Note that we ignore class-based deferals because otherwise a class can never |
| // be removed in the case that it exists as true in the initial classes list... |
| if (!valueExists(valueToApply, isClassBased)) { |
| valueToApply = getInitialValue(context, flag); |
| } |
| // if the first render is true then we do not want to start applying falsy |
| // values to the DOM element's styling. Otherwise then we know there has |
| // been a change and even if it's falsy then it's removing something that |
| // was truthy before. |
| var doApplyValue = renderer && (isFirstRender ? valueToApply : true); |
| if (doApplyValue) { |
| if (isClassBased) { |
| setClass(native, prop, valueToApply ? true : false, renderer, classesStore, playerBuilder); |
| } |
| else { |
| setStyle(native, prop, valueToApply, renderer, styleSanitizer, stylesStore, playerBuilder); |
| } |
| } |
| setDirty(context, i, false); |
| } |
| } |
| if (flushPlayerBuilders) { |
| var rootContext = Array.isArray(rootOrView) ? getRootContext(rootOrView) : rootOrView; |
| var playerContext = getPlayerContext(context); |
| var playersStartIndex = playerContext[0 /* NonBuilderPlayersStart */]; |
| for (var i = 1 /* PlayerBuildersStartPosition */; i < playersStartIndex; i += 2 /* PlayerAndPlayerBuildersTupleSize */) { |
| var builder = playerContext[i]; |
| var playerInsertionIndex = i + 1 /* PlayerOffsetPosition */; |
| var oldPlayer = playerContext[playerInsertionIndex]; |
| if (builder) { |
| var player = builder.buildPlayer(oldPlayer, isFirstRender); |
| if (player !== undefined) { |
| if (player != null) { |
| var wasQueued = addPlayerInternal(playerContext, rootContext, native, player, playerInsertionIndex); |
| wasQueued && totalPlayersQueued++; |
| } |
| if (oldPlayer) { |
| oldPlayer.destroy(); |
| } |
| } |
| } |
| else if (oldPlayer) { |
| // the player builder has been removed ... therefore we should delete the associated |
| // player |
| oldPlayer.destroy(); |
| } |
| } |
| setContextPlayersDirty(context, false); |
| } |
| setContextDirty(context, false); |
| } |
| } |
| return totalPlayersQueued; |
| } |
| /** |
| * Assigns a style value to a style property for the given element. |
| * |
| * This function renders a given CSS prop/value entry using the |
| * provided renderer. If a `store` value is provided then |
| * that will be used a render context instead of the provided |
| * renderer. |
| * |
| * @param native the DOM Element |
| * @param prop the CSS style property that will be rendered |
| * @param value the CSS style value that will be rendered |
| * @param renderer |
| * @param store an optional key/value map that will be used as a context to render styles on |
| */ |
| function setStyle(native, prop, value, renderer, sanitizer, store, playerBuilder) { |
| value = |
| sanitizer && value ? sanitizer(prop, value, 3 /* ValidateAndSanitize */) : value; |
| if (store || playerBuilder) { |
| if (store) { |
| store.setValue(prop, value); |
| } |
| if (playerBuilder) { |
| playerBuilder.setValue(prop, value); |
| } |
| } |
| else if (value) { |
| value = value.toString(); // opacity, z-index and flexbox all have number values which may not |
| // assign as numbers |
| ngDevMode && ngDevMode.rendererSetStyle++; |
| isProceduralRenderer(renderer) ? |
| renderer.setStyle(native, prop, value, RendererStyleFlags3.DashCase) : |
| native.style.setProperty(prop, value); |
| } |
| else { |
| ngDevMode && ngDevMode.rendererRemoveStyle++; |
| isProceduralRenderer(renderer) ? |
| renderer.removeStyle(native, prop, RendererStyleFlags3.DashCase) : |
| native.style.removeProperty(prop); |
| } |
| } |
| /** |
| * Adds/removes the provided className value to the provided element. |
| * |
| * This function renders a given CSS class value using the provided |
| * renderer (by adding or removing it from the provided element). |
| * If a `store` value is provided then that will be used a render |
| * context instead of the provided renderer. |
| * |
| * @param native the DOM Element |
| * @param prop the CSS style property that will be rendered |
| * @param value the CSS style value that will be rendered |
| * @param renderer |
| * @param store an optional key/value map that will be used as a context to render styles on |
| */ |
| function setClass(native, className, add, renderer, store, playerBuilder) { |
| if (store || playerBuilder) { |
| if (store) { |
| store.setValue(className, add); |
| } |
| if (playerBuilder) { |
| playerBuilder.setValue(className, add); |
| } |
| // DOMTokenList will throw if we try to add or remove an empty string. |
| } |
| else if (className !== '') { |
| if (add) { |
| ngDevMode && ngDevMode.rendererAddClass++; |
| isProceduralRenderer(renderer) ? renderer.addClass(native, className) : |
| native['classList'].add(className); |
| } |
| else { |
| ngDevMode && ngDevMode.rendererRemoveClass++; |
| isProceduralRenderer(renderer) ? renderer.removeClass(native, className) : |
| native['classList'].remove(className); |
| } |
| } |
| } |
| function setSanitizeFlag(context, index, sanitizeYes) { |
| if (sanitizeYes) { |
| context[index] |= 4 /* Sanitize */; |
| } |
| else { |
| context[index] &= ~4 /* Sanitize */; |
| } |
| } |
| function setDirty(context, index, isDirtyYes) { |
| var adjustedIndex = index >= 10 /* SingleStylesStartPosition */ ? (index + 0 /* FlagsOffset */) : index; |
| if (isDirtyYes) { |
| context[adjustedIndex] |= 1 /* Dirty */; |
| } |
| else { |
| context[adjustedIndex] &= ~1 /* Dirty */; |
| } |
| } |
| function isDirty(context, index) { |
| var adjustedIndex = index >= 10 /* SingleStylesStartPosition */ ? (index + 0 /* FlagsOffset */) : index; |
| return (context[adjustedIndex] & 1 /* Dirty */) == 1 /* Dirty */; |
| } |
| function isClassBasedValue(context, index) { |
| var adjustedIndex = index >= 10 /* SingleStylesStartPosition */ ? (index + 0 /* FlagsOffset */) : index; |
| return (context[adjustedIndex] & 2 /* Class */) == 2 /* Class */; |
| } |
| function isSanitizable(context, index) { |
| var adjustedIndex = index >= 10 /* SingleStylesStartPosition */ ? (index + 0 /* FlagsOffset */) : index; |
| return (context[adjustedIndex] & 4 /* Sanitize */) == 4 /* Sanitize */; |
| } |
| function pointers(configFlag, staticIndex, dynamicIndex) { |
| return (configFlag & 31 /* BitMask */) | (staticIndex << 5 /* BitCountSize */) | |
| (dynamicIndex << (14 /* BitCountSize */ + 5 /* BitCountSize */)); |
| } |
| function getInitialValue(context, flag) { |
| var index = getInitialIndex(flag); |
| var entryIsClassBased = flag & 2 /* Class */; |
| var initialValues = entryIsClassBased ? context[4 /* InitialClassValuesPosition */] : |
| context[3 /* InitialStyleValuesPosition */]; |
| return initialValues[index]; |
| } |
| function getInitialIndex(flag) { |
| return (flag >> 5 /* BitCountSize */) & 16383 /* BitMask */; |
| } |
| function getMultiOrSingleIndex(flag) { |
| var index = (flag >> (14 /* BitCountSize */ + 5 /* BitCountSize */)) & 16383 /* BitMask */; |
| return index >= 10 /* SingleStylesStartPosition */ ? index : -1; |
| } |
| function getMultiClassesStartIndex(context) { |
| var classCache = context[6 /* CachedMultiClasses */]; |
| return classCache[1 /* ValuesStartPosition */ + |
| 1 /* PositionStartOffset */]; |
| } |
| function getMultiStylesStartIndex(context) { |
| var stylesCache = context[7 /* CachedMultiStyles */]; |
| return stylesCache[1 /* ValuesStartPosition */ + |
| 1 /* PositionStartOffset */]; |
| } |
| function setProp(context, index, prop) { |
| context[index + 1 /* PropertyOffset */] = prop; |
| } |
| function setValue(context, index, value) { |
| context[index + 2 /* ValueOffset */] = value; |
| } |
| function hasPlayerBuilderChanged(context, builder, index) { |
| var playerContext = context[9 /* PlayerContext */]; |
| if (builder) { |
| if (!playerContext || index === 0) { |
| return true; |
| } |
| } |
| else if (!playerContext) { |
| return false; |
| } |
| return playerContext[index] !== builder; |
| } |
| function setPlayerBuilder(context, builder, insertionIndex) { |
| var playerContext = context[9 /* PlayerContext */] || allocPlayerContext(context); |
| if (insertionIndex > 0) { |
| playerContext[insertionIndex] = builder; |
| } |
| else { |
| insertionIndex = playerContext[0 /* NonBuilderPlayersStart */]; |
| playerContext.splice(insertionIndex, 0, builder, null); |
| playerContext[0 /* NonBuilderPlayersStart */] += |
| 2 /* PlayerAndPlayerBuildersTupleSize */; |
| } |
| return insertionIndex; |
| } |
| function directiveOwnerPointers(directiveIndex, playerIndex) { |
| return (playerIndex << 16 /* BitCountSize */) | directiveIndex; |
| } |
| function setPlayerBuilderIndex(context, index, playerBuilderIndex, directiveIndex) { |
| var value = directiveOwnerPointers(directiveIndex, playerBuilderIndex); |
| context[index + 3 /* PlayerBuilderIndexOffset */] = value; |
| } |
| function getPlayerBuilderIndex(context, index) { |
| var flag = context[index + 3 /* PlayerBuilderIndexOffset */]; |
| var playerBuilderIndex = (flag >> 16 /* BitCountSize */) & |
| 65535 /* BitMask */; |
| return playerBuilderIndex; |
| } |
| function getPlayerBuilder(context, index) { |
| var playerBuilderIndex = getPlayerBuilderIndex(context, index); |
| if (playerBuilderIndex) { |
| var playerContext = context[9 /* PlayerContext */]; |
| if (playerContext) { |
| return playerContext[playerBuilderIndex]; |
| } |
| } |
| return null; |
| } |
| function setFlag(context, index, flag) { |
| var adjustedIndex = index === 1 /* MasterFlagPosition */ ? index : (index + 0 /* FlagsOffset */); |
| context[adjustedIndex] = flag; |
| } |
| function getPointers(context, index) { |
| var adjustedIndex = index === 1 /* MasterFlagPosition */ ? index : (index + 0 /* FlagsOffset */); |
| return context[adjustedIndex]; |
| } |
| function getValue(context, index) { |
| return context[index + 2 /* ValueOffset */]; |
| } |
| function getProp(context, index) { |
| return context[index + 1 /* PropertyOffset */]; |
| } |
| function isContextDirty(context) { |
| return isDirty(context, 1 /* MasterFlagPosition */); |
| } |
| function setContextDirty(context, isDirtyYes) { |
| setDirty(context, 1 /* MasterFlagPosition */, isDirtyYes); |
| } |
| function setContextPlayersDirty(context, isDirtyYes) { |
| if (isDirtyYes) { |
| context[1 /* MasterFlagPosition */] |= 8 /* PlayerBuildersDirty */; |
| } |
| else { |
| context[1 /* MasterFlagPosition */] &= ~8 /* PlayerBuildersDirty */; |
| } |
| } |
| function swapMultiContextEntries(context, indexA, indexB) { |
| if (indexA === indexB) |
| return; |
| var tmpValue = getValue(context, indexA); |
| var tmpProp = getProp(context, indexA); |
| var tmpFlag = getPointers(context, indexA); |
| var tmpPlayerBuilderIndex = getPlayerBuilderIndex(context, indexA); |
| var tmpDirectiveIndex = getDirectiveIndexFromEntry(context, indexA); |
| var flagA = tmpFlag; |
| var flagB = getPointers(context, indexB); |
| var singleIndexA = getMultiOrSingleIndex(flagA); |
| if (singleIndexA >= 0) { |
| var _flag = getPointers(context, singleIndexA); |
| var _initial = getInitialIndex(_flag); |
| setFlag(context, singleIndexA, pointers(_flag, _initial, indexB)); |
| } |
| var singleIndexB = getMultiOrSingleIndex(flagB); |
| if (singleIndexB >= 0) { |
| var _flag = getPointers(context, singleIndexB); |
| var _initial = getInitialIndex(_flag); |
| setFlag(context, singleIndexB, pointers(_flag, _initial, indexA)); |
| } |
| setValue(context, indexA, getValue(context, indexB)); |
| setProp(context, indexA, getProp(context, indexB)); |
| setFlag(context, indexA, getPointers(context, indexB)); |
| var playerIndexA = getPlayerBuilderIndex(context, indexB); |
| var directiveIndexA = getDirectiveIndexFromEntry(context, indexB); |
| setPlayerBuilderIndex(context, indexA, playerIndexA, directiveIndexA); |
| setValue(context, indexB, tmpValue); |
| setProp(context, indexB, tmpProp); |
| setFlag(context, indexB, tmpFlag); |
| setPlayerBuilderIndex(context, indexB, tmpPlayerBuilderIndex, tmpDirectiveIndex); |
| } |
| function updateSinglePointerValues(context, indexStartPosition) { |
| for (var i = indexStartPosition; i < context.length; i += 4 /* Size */) { |
| var multiFlag = getPointers(context, i); |
| var singleIndex = getMultiOrSingleIndex(multiFlag); |
| if (singleIndex > 0) { |
| var singleFlag = getPointers(context, singleIndex); |
| var initialIndexForSingle = getInitialIndex(singleFlag); |
| var flagValue = (isDirty(context, singleIndex) ? 1 /* Dirty */ : 0 /* None */) | |
| (isClassBasedValue(context, singleIndex) ? 2 /* Class */ : 0 /* None */) | |
| (isSanitizable(context, singleIndex) ? 4 /* Sanitize */ : 0 /* None */); |
| var updatedFlag = pointers(flagValue, initialIndexForSingle, i); |
| setFlag(context, singleIndex, updatedFlag); |
| } |
| } |
| } |
| function insertNewMultiProperty(context, index, classBased, name, flag, value, directiveIndex, playerIndex) { |
| var doShift = index < context.length; |
| // prop does not exist in the list, add it in |
| context.splice(index, 0, flag | 1 /* Dirty */ | (classBased ? 2 /* Class */ : 0 /* None */), name, value, 0); |
| setPlayerBuilderIndex(context, index, playerIndex, directiveIndex); |
| if (doShift) { |
| // because the value was inserted midway into the array then we |
| // need to update all the shifted multi values' single value |
| // pointers to point to the newly shifted location |
| updateSinglePointerValues(context, index + 4 /* Size */); |
| } |
| } |
| function valueExists(value, isClassBased) { |
| return value !== null; |
| } |
| function prepareInitialFlag(context, prop, entryIsClassBased, sanitizer) { |
| var flag = (sanitizer && sanitizer(prop, null, 1 /* ValidateProperty */)) ? |
| 4 /* Sanitize */ : |
| 0 /* None */; |
| var initialIndex; |
| if (entryIsClassBased) { |
| flag |= 2 /* Class */; |
| initialIndex = |
| getInitialStylingValuesIndexOf(context[4 /* InitialClassValuesPosition */], prop); |
| } |
| else { |
| initialIndex = |
| getInitialStylingValuesIndexOf(context[3 /* InitialStyleValuesPosition */], prop); |
| } |
| initialIndex = initialIndex > 0 ? (initialIndex + 1 /* ValueOffset */) : 0; |
| return pointers(flag, initialIndex, 0); |
| } |
| function hasInitialValueChanged(context, flag, newValue) { |
| var initialValue = getInitialValue(context, flag); |
| return !initialValue || hasValueChanged(flag, initialValue, newValue); |
| } |
| function hasValueChanged(flag, a, b) { |
| var isClassBased = flag & 2 /* Class */; |
| var hasValues = a && b; |
| var usesSanitizer = flag & 4 /* Sanitize */; |
| // the toString() comparison ensures that a value is checked |
| // ... otherwise (during sanitization bypassing) the === comparsion |
| // would fail since a new String() instance is created |
| if (!isClassBased && hasValues && usesSanitizer) { |
| // we know for sure we're dealing with strings at this point |
| return a.toString() !== b.toString(); |
| } |
| // everything else is safe to check with a normal equality check |
| return a !== b; |
| } |
| var ClassAndStylePlayerBuilder = /** @class */ (function () { |
| function ClassAndStylePlayerBuilder(factory, _element, _type) { |
| this._element = _element; |
| this._type = _type; |
| this._values = {}; |
| this._dirty = false; |
| this._factory = factory; |
| } |
| ClassAndStylePlayerBuilder.prototype.setValue = function (prop, value) { |
| if (this._values[prop] !== value) { |
| this._values[prop] = value; |
| this._dirty = true; |
| } |
| }; |
| ClassAndStylePlayerBuilder.prototype.buildPlayer = function (currentPlayer, isFirstRender) { |
| // if no values have been set here then this means the binding didn't |
| // change and therefore the binding values were not updated through |
| // `setValue` which means no new player will be provided. |
| if (this._dirty) { |
| var player = this._factory.fn(this._element, this._type, this._values, isFirstRender, currentPlayer || null); |
| this._values = {}; |
| this._dirty = false; |
| return player; |
| } |
| return undefined; |
| }; |
| return ClassAndStylePlayerBuilder; |
| }()); |
| function getDirectiveIndexFromEntry(context, index) { |
| var value = context[index + 3 /* PlayerBuilderIndexOffset */]; |
| return value & 65535 /* BitMask */; |
| } |
| function getInitialStylingValuesIndexOf(keyValues, key) { |
| for (var i = 2 /* KeyValueStartPosition */; i < keyValues.length; i += 3 /* Size */) { |
| if (keyValues[i] === key) |
| return i; |
| } |
| return -1; |
| } |
| function getSinglePropIndexValue(context, directiveIndex, offset, isClassBased) { |
| var singlePropOffsetRegistryIndex = context[2 /* DirectiveRegistryPosition */][(directiveIndex * 2 /* Size */) + |
| 0 /* SinglePropValuesIndexOffset */]; |
| var offsets = context[5 /* SinglePropOffsetPositions */]; |
| var indexForOffset = singlePropOffsetRegistryIndex + |
| 2 /* ValueStartPosition */ + |
| (isClassBased ? |
| offsets[singlePropOffsetRegistryIndex + 0 /* StylesCountPosition */] : |
| 0) + |
| offset; |
| return offsets[indexForOffset]; |
| } |
| function getStyleSanitizer(context, directiveIndex) { |
| var dirs = context[2 /* DirectiveRegistryPosition */]; |
| var value = dirs[directiveIndex * 2 /* Size */ + |
| 1 /* StyleSanitizerOffset */] || |
| dirs[1 /* StyleSanitizerOffset */] || null; |
| return value; |
| } |
| function allowValueChange(currentValue, newValue, currentDirectiveOwner, newDirectiveOwner) { |
| // the code below relies the importance of directive's being tied to their |
| // index value. The index values for each directive are derived from being |
| // registered into the styling context directive registry. The most important |
| // directive is the parent component directive (the template) and each directive |
| // that is added after is considered less important than the previous entry. This |
| // prioritization of directives enables the styling algorithm to decide if a style |
| // or class should be allowed to be updated/replaced in case an earlier directive |
| // already wrote to the exact same style-property or className value. In other words |
| // this decides what to do if and when there is a collision. |
| if (currentValue != null) { |
| if (newValue != null) { |
| // if a directive index is lower than it always has priority over the |
| // previous directive's value... |
| return newDirectiveOwner <= currentDirectiveOwner; |
| } |
| else { |
| // only write a null value in case it's the same owner writing it. |
| // this avoids having a higher-priority directive write to null |
| // only to have a lesser-priority directive change right to a |
| // non-null value immediately afterwards. |
| return currentDirectiveOwner === newDirectiveOwner; |
| } |
| } |
| return true; |
| } |
| /** |
| * Returns the className string of all the initial classes for the element. |
| * |
| * This function is designed to populate and cache all the static class |
| * values into a className string. The caching mechanism works by placing |
| * the completed className string into the initial values array into a |
| * dedicated slot. This will prevent the function from having to populate |
| * the string each time an element is created or matched. |
| * |
| * @returns the className string (e.g. `on active red`) |
| */ |
| function getInitialClassNameValue(context) { |
| var initialClassValues = context[4 /* InitialClassValuesPosition */]; |
| var className = initialClassValues[1 /* CachedStringValuePosition */]; |
| if (className === null) { |
| className = ''; |
| for (var i = 2 /* KeyValueStartPosition */; i < initialClassValues.length; i += 3 /* Size */) { |
| var isPresent = initialClassValues[i + 1]; |
| if (isPresent) { |
| className += (className.length ? ' ' : '') + initialClassValues[i]; |
| } |
| } |
| initialClassValues[1 /* CachedStringValuePosition */] = className; |
| } |
| return className; |
| } |
| /** |
| * Returns the style string of all the initial styles for the element. |
| * |
| * This function is designed to populate and cache all the static style |
| * values into a style string. The caching mechanism works by placing |
| * the completed style string into the initial values array into a |
| * dedicated slot. This will prevent the function from having to populate |
| * the string each time an element is created or matched. |
| * |
| * @returns the style string (e.g. `width:100px;height:200px`) |
| */ |
| function getInitialStyleStringValue(context) { |
| var initialStyleValues = context[3 /* InitialStyleValuesPosition */]; |
| var styleString = initialStyleValues[1 /* CachedStringValuePosition */]; |
| if (styleString === null) { |
| styleString = ''; |
| for (var i = 2 /* KeyValueStartPosition */; i < initialStyleValues.length; i += 3 /* Size */) { |
| var value = initialStyleValues[i + 1]; |
| if (value !== null) { |
| styleString += (styleString.length ? ';' : '') + (initialStyleValues[i] + ":" + value); |
| } |
| } |
| initialStyleValues[1 /* CachedStringValuePosition */] = styleString; |
| } |
| return styleString; |
| } |
| /** |
| * Returns the current cached multi-value for a given directiveIndex within the provided context. |
| */ |
| function readCachedMapValue(context, entryIsClassBased, directiveIndex) { |
| var values = context[entryIsClassBased ? 6 /* CachedMultiClasses */ : 7 /* CachedMultiStyles */]; |
| var index = 1 /* ValuesStartPosition */ + |
| directiveIndex * 4 /* Size */; |
| return values[index + 2 /* ValueOffset */] || null; |
| } |
| /** |
| * Determines whether the provided multi styling value should be updated or not. |
| * |
| * Because `[style]` and `[class]` bindings rely on an identity change to occur before |
| * applying new values, the styling algorithm may not update an existing entry into |
| * the context if a previous directive's entry changed shape. |
| * |
| * This function will decide whether or not a value should be applied (if there is a |
| * cache miss) to the context based on the following rules: |
| * |
| * - If there is an identity change between the existing value and new value |
| * - If there is no existing value cached (first write) |
| * - If a previous directive flagged the existing cached value as dirty |
| */ |
| function isMultiValueCacheHit(context, entryIsClassBased, directiveIndex, newValue) { |
| var indexOfCachedValues = entryIsClassBased ? 6 /* CachedMultiClasses */ : 7 /* CachedMultiStyles */; |
| var cachedValues = context[indexOfCachedValues]; |
| var index = 1 /* ValuesStartPosition */ + |
| directiveIndex * 4 /* Size */; |
| if (cachedValues[index + 0 /* DirtyFlagOffset */]) |
| return false; |
| return newValue === NO_CHANGE || |
| readCachedMapValue(context, entryIsClassBased, directiveIndex) === newValue; |
| } |
| /** |
| * Updates the cached status of a multi-styling value in the context. |
| * |
| * The cached map array (which exists in the context) contains a manifest of |
| * each multi-styling entry (`[style]` and `[class]` entries) for the template |
| * as well as all directives. |
| * |
| * This function will update the cached status of the provided multi-style |
| * entry within the cache. |
| * |
| * When called, this function will update the following information: |
| * - The actual cached value (the raw value that was passed into `[style]` or `[class]`) |
| * - The total amount of unique styling entries that this value has written into the context |
| * - The exact position of where the multi styling entries start in the context for this binding |
| * - The dirty flag will be set to true |
| * |
| * If the `dirtyFutureValues` param is provided then it will update all future entries (binding |
| * entries that exist as apart of other directives) to be dirty as well. This will force the |
| * styling algorithm to reapply those values once change detection checks them (which will in |
| * turn cause the styling context to update itself and the correct styling values will be |
| * rendered on screen). |
| */ |
| function updateCachedMapValue(context, directiveIndex, entryIsClassBased, cacheValue, startPosition, endPosition, totalValues, dirtyFutureValues) { |
| var values = context[entryIsClassBased ? 6 /* CachedMultiClasses */ : 7 /* CachedMultiStyles */]; |
| var index = 1 /* ValuesStartPosition */ + |
| directiveIndex * 4 /* Size */; |
| // in the event that this is true we assume that future values are dirty and therefore |
| // will be checked again in the next CD cycle |
| if (dirtyFutureValues) { |
| var nextStartPosition = startPosition + totalValues * 4 /* Size */; |
| for (var i = index + 4 /* Size */; i < values.length; i += 4 /* Size */) { |
| values[i + 1 /* PositionStartOffset */] = nextStartPosition; |
| values[i + 0 /* DirtyFlagOffset */] = 1; |
| } |
| } |
| values[index + 0 /* DirtyFlagOffset */] = 0; |
| values[index + 1 /* PositionStartOffset */] = startPosition; |
| values[index + 2 /* ValueOffset */] = cacheValue; |
| values[index + 3 /* ValueCountOffset */] = totalValues; |
| // the code below counts the total amount of styling values that exist in |
| // the context up until this directive. This value will be later used to |
| // update the cached value map's total counter value. |
| var totalStylingEntries = totalValues; |
| for (var i = 1 /* ValuesStartPosition */; i < index; i += 4 /* Size */) { |
| totalStylingEntries += values[i + 3 /* ValueCountOffset */]; |
| } |
| // because style values come before class values in the context this means |
| // that if any new values were inserted then the cache values array for |
| // classes is out of sync. The code below will update the offsets to point |
| // to their new values. |
| if (!entryIsClassBased) { |
| var classCache = context[6 /* CachedMultiClasses */]; |
| var classesStartPosition = classCache[1 /* ValuesStartPosition */ + |
| 1 /* PositionStartOffset */]; |
| var diffInStartPosition = endPosition - classesStartPosition; |
| for (var i = 1 /* ValuesStartPosition */; i < classCache.length; i += 4 /* Size */) { |
| classCache[i + 1 /* PositionStartOffset */] += diffInStartPosition; |
| } |
| } |
| values[0 /* EntriesCountPosition */] = totalStylingEntries; |
| } |
| function hyphenateEntries(entries) { |
| var newEntries = []; |
| for (var i = 0; i < entries.length; i++) { |
| newEntries.push(hyphenate(entries[i])); |
| } |
| return newEntries; |
| } |
| function hyphenate(value) { |
| return value.replace(/[a-z][A-Z]/g, function (match) { return match.charAt(0) + "-" + match.charAt(1).toLowerCase(); }); |
| } |
| function registerMultiMapEntry(context, directiveIndex, entryIsClassBased, startPosition, count) { |
| if (count === void 0) { count = 0; } |
| var cachedValues = context[entryIsClassBased ? 6 /* CachedMultiClasses */ : 7 /* CachedMultiStyles */]; |
| if (directiveIndex > 0) { |
| var limit = 1 /* ValuesStartPosition */ + |
| (directiveIndex * 4 /* Size */); |
| while (cachedValues.length < limit) { |
| // this means that ONLY directive class styling (like ngClass) was used |
| // therefore the root directive will still need to be filled in as well |
| // as any other directive spaces in case they only used static values |
| cachedValues.push(0, startPosition, null, 0); |
| } |
| } |
| cachedValues.push(0, startPosition, null, count); |
| } |
| /** |
| * Inserts or updates an existing entry in the provided `staticStyles` collection. |
| * |
| * @param index the index representing an existing styling entry in the collection: |
| * if provided (numeric): then it will update the existing entry at the given position |
| * if null: then it will insert a new entry within the collection |
| * @param staticStyles a collection of style or class entries where the value will |
| * be inserted or patched |
| * @param prop the property value of the entry (e.g. `width` (styles) or `foo` (classes)) |
| * @param value the styling value of the entry (e.g. `absolute` (styles) or `true` (classes)) |
| * @param directiveOwnerIndex the directive owner index value of the styling source responsible |
| * for these styles (see `interfaces/styling.ts#directives` for more info) |
| * @returns the index of the updated or new entry within the collection |
| */ |
| function addOrUpdateStaticStyle(index, staticStyles, prop, value, directiveOwnerIndex) { |
| if (index === null) { |
| index = staticStyles.length; |
| staticStyles.push(null, null, null); |
| staticStyles[index + 0 /* PropOffset */] = prop; |
| } |
| staticStyles[index + 1 /* ValueOffset */] = value; |
| staticStyles[index + 2 /* DirectiveOwnerOffset */] = directiveOwnerIndex; |
| return index; |
| } |
| function assertValidDirectiveIndex(context, directiveIndex) { |
| var dirs = context[2 /* DirectiveRegistryPosition */]; |
| var index = directiveIndex * 2 /* Size */; |
| if (index >= dirs.length || |
| dirs[index + 0 /* SinglePropValuesIndexOffset */] === -1) { |
| throw new Error('The provided directive is not registered with the styling context'); |
| } |
| } |
| |
| /** |
| * @license |
| * Copyright Google Inc. All Rights Reserved. |
| * |
| * Use of this source code is governed by an MIT-style license that can be |
| * found in the LICENSE file at https://angular.io/license |
| */ |
| var NG_TEMPLATE_SELECTOR = 'ng-template'; |
| function isCssClassMatching(nodeClassAttrVal, cssClassToMatch) { |
| var nodeClassesLen = nodeClassAttrVal.length; |
| var matchIndex = nodeClassAttrVal.indexOf(cssClassToMatch); |
| var matchEndIdx = matchIndex + cssClassToMatch.length; |
| if (matchIndex === -1 // no match |
| || (matchIndex > 0 && nodeClassAttrVal[matchIndex - 1] !== ' ') // no space before |
| || |
| (matchEndIdx < nodeClassesLen && nodeClassAttrVal[matchEndIdx] !== ' ')) // no space after |
| { |
| return false; |
| } |
| return true; |
| } |
| /** |
| * Function that checks whether a given tNode matches tag-based selector and has a valid type. |
| * |
| * Matching can be performed in 2 modes: projection mode (when we project nodes) and regular |
| * directive matching mode: |
| * - in the "directive matching" mode we do _not_ take TContainer's tagName into account if it is |
| * different from NG_TEMPLATE_SELECTOR (value different from NG_TEMPLATE_SELECTOR indicates that a |
| * tag name was extracted from * syntax so we would match the same directive twice); |
| * - in the "projection" mode, we use a tag name potentially extracted from the * syntax processing |
| * (applicable to TNodeType.Container only). |
| */ |
| function hasTagAndTypeMatch(tNode, currentSelector, isProjectionMode) { |
| var tagNameToCompare = tNode.type === 0 /* Container */ && !isProjectionMode ? |
| NG_TEMPLATE_SELECTOR : |
| tNode.tagName; |
| return currentSelector === tagNameToCompare; |
| } |
| /** |
| * A utility function to match an Ivy node static data against a simple CSS selector |
| * |
| * @param node static data of the node to match |
| * @param selector The selector to try matching against the node. |
| * @param isProjectionMode if `true` we are matching for content projection, otherwise we are doing |
| * directive matching. |
| * @returns true if node matches the selector. |
| */ |
| function isNodeMatchingSelector(tNode, selector, isProjectionMode) { |
| ngDevMode && assertDefined(selector[0], 'Selector should have a tag name'); |
| var mode = 4 /* ELEMENT */; |
| var nodeAttrs = tNode.attrs || []; |
| // Find the index of first attribute that has no value, only a name. |
| var nameOnlyMarkerIdx = getNameOnlyMarkerIndex(nodeAttrs); |
| // When processing ":not" selectors, we skip to the next ":not" if the |
| // current one doesn't match |
| var skipToNextSelector = false; |
| for (var i = 0; i < selector.length; i++) { |
| var current = selector[i]; |
| if (typeof current === 'number') { |
| // If we finish processing a :not selector and it hasn't failed, return false |
| if (!skipToNextSelector && !isPositive(mode) && !isPositive(current)) { |
| return false; |
| } |
| // If we are skipping to the next :not() and this mode flag is positive, |
| // it's a part of the current :not() selector, and we should keep skipping |
| if (skipToNextSelector && isPositive(current)) |
| continue; |
| skipToNextSelector = false; |
| mode = current | (mode & 1 /* NOT */); |
| continue; |
| } |
| if (skipToNextSelector) |
| continue; |
| if (mode & 4 /* ELEMENT */) { |
| mode = 2 /* ATTRIBUTE */ | mode & 1 /* NOT */; |
| if (current !== '' && !hasTagAndTypeMatch(tNode, current, isProjectionMode) || |
| current === '' && selector.length === 1) { |
| if (isPositive(mode)) |
| return false; |
| skipToNextSelector = true; |
| } |
| } |
| else { |
| var selectorAttrValue = mode & 8 /* CLASS */ ? current : selector[++i]; |
| // special case for matching against classes when a tNode has been instantiated with |
| // class and style values as separate attribute values (e.g. ['title', CLASS, 'foo']) |
| if ((mode & 8 /* CLASS */) && tNode.stylingTemplate) { |
| if (!isCssClassMatching(readClassValueFromTNode(tNode), selectorAttrValue)) { |
| if (isPositive(mode)) |
| return false; |
| skipToNextSelector = true; |
| } |
| continue; |
| } |
| var isInlineTemplate = tNode.type == 0 /* Container */ && tNode.tagName !== NG_TEMPLATE_SELECTOR; |
| var attrName = (mode & 8 /* CLASS */) ? 'class' : current; |
| var attrIndexInNode = findAttrIndexInNode(attrName, nodeAttrs, isInlineTemplate, isProjectionMode); |
| if (attrIndexInNode === -1) { |
| if (isPositive(mode)) |
| return false; |
| skipToNextSelector = true; |
| continue; |
| } |
| if (selectorAttrValue !== '') { |
| var nodeAttrValue = void 0; |
| if (attrIndexInNode > nameOnlyMarkerIdx) { |
| nodeAttrValue = ''; |
| } |
| else { |
| ngDevMode && assertNotEqual(nodeAttrs[attrIndexInNode], 0 /* NamespaceURI */, 'We do not match directives on namespaced attributes'); |
| nodeAttrValue = nodeAttrs[attrIndexInNode + 1]; |
| } |
| var compareAgainstClassName = mode & 8 /* CLASS */ ? nodeAttrValue : null; |
| if (compareAgainstClassName && |
| !isCssClassMatching(compareAgainstClassName, selectorAttrValue) || |
| mode & 2 /* ATTRIBUTE */ && selectorAttrValue !== nodeAttrValue) { |
| if (isPositive(mode)) |
| return false; |
| skipToNextSelector = true; |
| } |
| } |
| } |
| } |
| return isPositive(mode) || skipToNextSelector; |
| } |
| function isPositive(mode) { |
| return (mode & 1 /* NOT */) === 0; |
| } |
| function readClassValueFromTNode(tNode) { |
| // comparing against CSS class values is complex because the compiler doesn't place them as |
| // regular attributes when an element is created. Instead, the classes (and styles for |
| // that matter) are placed in a special styling context that is used for resolving all |
| // class/style values across static attributes, [style]/[class] and [style.prop]/[class.name] |
| // bindings. Therefore if and when the styling context exists then the class values are to be |
| // extracted by the context helper code below... |
| return tNode.stylingTemplate ? getInitialClassNameValue(tNode.stylingTemplate) : ''; |
| } |
| /** |
| * Examines the attribute's definition array for a node to find the index of the |
| * attribute that matches the given `name`. |
| * |
| * NOTE: This will not match namespaced attributes. |
| * |
| * Attribute matching depends upon `isInlineTemplate` and `isProjectionMode`. |
| * The following table summarizes which types of attributes we attempt to match: |
| * |
| * =========================================================================================================== |
| * Modes | Normal Attributes | Bindings Attributes | Template Attributes | I18n |
| * Attributes |
| * =========================================================================================================== |
| * Inline + Projection | YES | YES | NO | YES |
| * ----------------------------------------------------------------------------------------------------------- |
| * Inline + Directive | NO | NO | YES | NO |
| * ----------------------------------------------------------------------------------------------------------- |
| * Non-inline + Projection | YES | YES | NO | YES |
| * ----------------------------------------------------------------------------------------------------------- |
| * Non-inline + Directive | YES | YES | NO | YES |
| * =========================================================================================================== |
| * |
| * @param name the name of the attribute to find |
| * @param attrs the attribute array to examine |
| * @param isInlineTemplate true if the node being matched is an inline template (e.g. `*ngFor`) |
| * rather than a manually expanded template node (e.g `<ng-template>`). |
| * @param isProjectionMode true if we are matching against content projection otherwise we are |
| * matching against directives. |
| */ |
| function findAttrIndexInNode(name, attrs, isInlineTemplate, isProjectionMode) { |
| if (attrs === null) |
| return -1; |
| var i = 0; |
| if (isProjectionMode || !isInlineTemplate) { |
| var bindingsMode = false; |
| while (i < attrs.length) { |
| var maybeAttrName = attrs[i]; |
| if (maybeAttrName === name) { |
| return i; |
| } |
| else if (maybeAttrName === 3 /* Bindings */ || maybeAttrName === 6 /* I18n */) { |
| bindingsMode = true; |
| } |
| else if (maybeAttrName === 1 /* Classes */) { |
| var value = attrs[++i]; |
| // We should skip classes here because we have a separate mechanism for |
| // matching classes in projection mode. |
| while (typeof value === 'string') { |
| value = attrs[++i]; |
| } |
| continue; |
| } |
| else if (maybeAttrName === 4 /* Template */) { |
| // We do not care about Template attributes in this scenario. |
| break; |
| } |
| else if (maybeAttrName === 0 /* NamespaceURI */) { |
| // Skip the whole namespaced attribute and value. This is by design. |
| i += 4; |
| continue; |
| } |
| // In binding mode there are only names, rather than name-value pairs. |
| i += bindingsMode ? 1 : 2; |
| } |
| // We did not match the attribute |
| return -1; |
| } |
| else { |
| return matchTemplateAttribute(attrs, name); |
| } |
| } |
| function isNodeMatchingSelectorList(tNode, selector, isProjectionMode) { |
| if (isProjectionMode === void 0) { isProjectionMode = false; } |
| for (var i = 0; i < selector.length; i++) { |
| if (isNodeMatchingSelector(tNode, selector[i], isProjectionMode)) { |
| return true; |
| } |
| } |
| return false; |
| } |
| function getProjectAsAttrValue(tNode) { |
| var nodeAttrs = tNode.attrs; |
| if (nodeAttrs != null) { |
| var ngProjectAsAttrIdx = nodeAttrs.indexOf(5 /* ProjectAs */); |
| // only check for ngProjectAs in attribute names, don't accidentally match attribute's value |
| // (attribute names are stored at even indexes) |
| if ((ngProjectAsAttrIdx & 1) === 0) { |
| return nodeAttrs[ngProjectAsAttrIdx + 1]; |
| } |
| } |
| return null; |
| } |
| function getNameOnlyMarkerIndex(nodeAttrs) { |
| for (var i = 0; i < nodeAttrs.length; i++) { |
| var nodeAttr = nodeAttrs[i]; |
| if (isNameOnlyAttributeMarker(nodeAttr)) { |
| return i; |
| } |
| } |
| return nodeAttrs.length; |
| } |
| function matchTemplateAttribute(attrs, name) { |
| var i = attrs.indexOf(4 /* Template */); |
| if (i > -1) { |
| i++; |
| while (i < attrs.length) { |
| if (attrs[i] === name) |
| return i; |
| i++; |
| } |
| } |
| return -1; |
| } |
| /** |
| * Checks whether a selector is inside a CssSelectorList |
| * @param selector Selector to be checked. |
| * @param list List in which to look for the selector. |
| */ |
| function isSelectorInSelectorList(selector, list) { |
| selectorListLoop: for (var i = 0; i < list.length; i++) { |
| var currentSelectorInList = list[i]; |
| if (selector.length !== currentSelectorInList.length) { |
| continue; |
| } |
| for (var j = 0; j < selector.length; j++) { |
| if (selector[j] !== currentSelectorInList[j]) { |
| continue selectorListLoop; |
| } |
| } |
| return true; |
| } |
| return false; |
| } |
| |
| /** |
| * @license |
| * Copyright Google Inc. All Rights Reserved. |
| * |
| * Use of this source code is governed by an MIT-style license that can be |
| * found in the LICENSE file at https://angular.io/license |
| */ |
| /** |
| * Marks that the next string is for element. |
| * |
| * See `I18nMutateOpCodes` documentation. |
| */ |
| var ELEMENT_MARKER = { |
| marker: 'element' |
| }; |
| /** |
| * Marks that the next string is for comment. |
| * |
| * See `I18nMutateOpCodes` documentation. |
| */ |
| var COMMENT_MARKER = { |
| marker: 'comment' |
| }; |
| |
| var _stylingMode = 0; |
| function runtimeIsNewStylingInUse() { |
| return _stylingMode > 0 /* UseOld */; |
| } |
| function runtimeAllowOldStyling() { |
| return _stylingMode < 2 /* UseNew */; |
| } |
| var _currentSanitizer; |
| function setCurrentStyleSanitizer(sanitizer) { |
| _currentSanitizer = sanitizer; |
| } |
| function getCurrentStyleSanitizer() { |
| return _currentSanitizer; |
| } |
| |
| /** |
| * @license |
| * Copyright Google Inc. All Rights Reserved. |
| * |
| * Use of this source code is governed by an MIT-style license that can be |
| * found in the LICENSE file at https://angular.io/license |
| */ |
| function attachDebugObject(obj, debug) { |
| Object.defineProperty(obj, 'debug', { value: debug, enumerable: false }); |
| } |
| |
| /** |
| * @license |
| * Copyright Google Inc. All Rights Reserved. |
| * |
| * Use of this source code is governed by an MIT-style license that can be |
| * found in the LICENSE file at https://angular.io/license |
| */ |
| var MAP_BASED_ENTRY_PROP_NAME = '--MAP--'; |
| /** |
| * Creates a new instance of the `TStylingContext`. |
| * |
| * This function will also pre-fill the context with data |
| * for map-based bindings. |
| */ |
| function allocTStylingContext() { |
| // because map-based bindings deal with a dynamic set of values, there |
| // is no way to know ahead of time whether or not sanitization is required. |
| // For this reason the configuration will always mark sanitization as active |
| // (this means that when map-based values are applied then sanitization will |
| // be checked against each property). |
| var mapBasedConfig = 1 /* SanitizationRequired */; |
| return [0 /* Initial */, 0, mapBasedConfig, 0, MAP_BASED_ENTRY_PROP_NAME]; |
| } |
| /** |
| * Temporary function that allows for a string-based property name to be |
| * obtained from an index-based property identifier. |
| * |
| * This function will be removed once the new styling refactor code (which |
| * lives inside of `render3/styling_next/`) replaces the existing styling |
| * implementation. |
| */ |
| function getBindingNameFromIndex(stylingContext, offset, directiveIndex, isClassBased) { |
| var singleIndex = getSinglePropIndexValue(stylingContext, directiveIndex, offset, isClassBased); |
| return getProp(stylingContext, singleIndex); |
| } |
| function updateContextDirectiveIndex(context, index) { |
| context[1 /* MaxDirectiveIndexPosition */] = index; |
| } |
| function getConfig(context) { |
| return context[0 /* ConfigPosition */]; |
| } |
| function setConfig(context, value) { |
| context[0 /* ConfigPosition */] = value; |
| } |
| function getProp$1(context, index) { |
| return context[index + 2 /* PropOffset */]; |
| } |
| function getPropConfig(context, index) { |
| return context[index + 0 /* ConfigAndGuardOffset */] & |
| 1 /* Mask */; |
| } |
| function isSanitizationRequired(context, index) { |
| return (getPropConfig(context, index) & 1 /* SanitizationRequired */) > 0; |
| } |
| function getGuardMask(context, index) { |
| var configGuardValue = context[index + 0 /* ConfigAndGuardOffset */]; |
| return configGuardValue >> 1 /* TotalBits */; |
| } |
| function setGuardMask(context, index, maskValue) { |
| var config = getPropConfig(context, index); |
| var guardMask = maskValue << 1 /* TotalBits */; |
| context[index + 0 /* ConfigAndGuardOffset */] = config | guardMask; |
| } |
| function getValuesCount(context, index) { |
| return context[index + 1 /* ValuesCountOffset */]; |
| } |
| function getBindingValue(context, index, offset) { |
| return context[index + 3 /* BindingsStartOffset */ + offset]; |
| } |
| function getDefaultValue(context, index) { |
| var valuesCount = getValuesCount(context, index); |
| return context[index + 3 /* BindingsStartOffset */ + valuesCount - 1]; |
| } |
| /** |
| * Temporary function which determines whether or not a context is |
| * allowed to be flushed based on the provided directive index. |
| */ |
| function allowStylingFlush(context, index) { |
| return index === context[1 /* MaxDirectiveIndexPosition */]; |
| } |
| function lockContext(context) { |
| setConfig(context, getConfig(context) | 1 /* Locked */); |
| } |
| function isContextLocked(context) { |
| return (getConfig(context) & 1 /* Locked */) > 0; |
| } |
| function getPropValuesStartPosition(context) { |
| return 5 /* MapBindingsBindingsStartPosition */ + |
| context[3 /* MapBindingsValuesCountPosition */]; |
| } |
| function hasValueChanged$1(a, b) { |
| var compareValueA = Array.isArray(a) ? a[0 /* RawValuePosition */] : a; |
| var compareValueB = Array.isArray(b) ? b[0 /* RawValuePosition */] : b; |
| return compareValueA !== compareValueB; |
| } |
| /** |
| * Determines whether the provided styling value is truthy or falsy. |
| */ |
| function isStylingValueDefined(value) { |
| // the reason why null is compared against is because |
| // a CSS class value that is set to `false` must be |
| // respected (otherwise it would be treated as falsy). |
| // Empty string values are because developers usually |
| // set a value to an empty string to remove it. |
| return value != null && value !== ''; |
| } |
| /** |
| * Returns the current style sanitizer function for the given view. |
| * |
| * The default style sanitizer (which lives inside of `LView`) will |
| * be returned depending on whether the `styleSanitizer` instruction |
| * was called or not prior to any styling instructions running. |
| */ |
| function getCurrentOrLViewSanitizer(lView) { |
| var sanitizer = (getCurrentStyleSanitizer() || lView[SANITIZER]); |
| if (sanitizer && typeof sanitizer !== 'function') { |
| setCurrentStyleSanitizer(sanitizer); |
| return sanitizeUsingSanitizerObject; |
| } |
| return sanitizer; |
| } |
| /** |
| * Style sanitization function that internally uses a `Sanitizer` instance to handle style |
| * sanitization. |
| */ |
| var sanitizeUsingSanitizerObject = function (prop, value, mode) { |
| var sanitizer = getCurrentStyleSanitizer(); |
| if (sanitizer) { |
| if (mode & 2 /* SanitizeOnly */) { |
| return sanitizer.sanitize(exports.SecurityContext.STYLE, value); |
| } |
| else { |
| return true; |
| } |
| } |
| return value; |
| }; |
| |
| /** |
| * -------- |
| * |
| * This file contains the core logic for styling in Angular. |
| * |
| * All styling bindings (i.e. `[style]`, `[style.prop]`, `[class]` and `[class.name]`) |
| * will have their values be applied through the logic in this file. |
| * |
| * When a binding is encountered (e.g. `<div [style.width]="w">`) then |
| * the binding data will be populated into a `TStylingContext` data-structure. |
| * There is only one `TStylingContext` per `TNode` and each element instance |
| * will update its style/class binding values in concert with the styling |
| * context. |
| * |
| * To learn more about the algorithm see `TStylingContext`. |
| * |
| * -------- |
| */ |
| var DEFAULT_BINDING_VALUE = null; |
| var DEFAULT_SIZE_VALUE = 1; |
| // The first bit value reflects a map-based binding value's bit. |
| // The reason why it's always activated for every entry in the map |
| // is so that if any map-binding values update then all other prop |
| // based bindings will pass the guard check automatically without |
| // any extra code or flags. |
| var DEFAULT_GUARD_MASK_VALUE = 1; |
| var STYLING_INDEX_FOR_MAP_BINDING = 0; |
| var STYLING_INDEX_START_VALUE = 1; |
| // the values below are global to all styling code below. Each value |
| // will either increment or mutate each time a styling instruction is |
| // executed. Do not modify the values below. |
| var currentStyleIndex = STYLING_INDEX_START_VALUE; |
| var currentClassIndex = STYLING_INDEX_START_VALUE; |
| var stylesBitMask = 0; |
| var classesBitMask = 0; |
| var deferredBindingQueue = []; |
| /** |
| * Visits a class-based binding and updates the new value (if changed). |
| * |
| * This function is called each time a class-based styling instruction |
| * is executed. It's important that it's always called (even if the value |
| * has not changed) so that the inner counter index value is incremented. |
| * This way, each instruction is always guaranteed to get the same counter |
| * state each time it's called (which then allows the `TStylingContext` |
| * and the bit mask values to be in sync). |
| */ |
| function updateClassBinding(context, data, prop, bindingIndex, value, deferRegistration, forceUpdate) { |
| var isMapBased = !prop; |
| var index = isMapBased ? STYLING_INDEX_FOR_MAP_BINDING : currentClassIndex++; |
| var updated = updateBindingData(context, data, index, prop, bindingIndex, value, deferRegistration, forceUpdate, false); |
| if (updated || forceUpdate) { |
| classesBitMask |= 1 << index; |
| } |
| } |
| /** |
| * Visits a style-based binding and updates the new value (if changed). |
| * |
| * This function is called each time a style-based styling instruction |
| * is executed. It's important that it's always called (even if the value |
| * has not changed) so that the inner counter index value is incremented. |
| * This way, each instruction is always guaranteed to get the same counter |
| * state each time it's called (which then allows the `TStylingContext` |
| * and the bit mask values to be in sync). |
| */ |
| function updateStyleBinding(context, data, prop, bindingIndex, value, sanitizer, deferRegistration, forceUpdate) { |
| var isMapBased = !prop; |
| var index = isMapBased ? STYLING_INDEX_FOR_MAP_BINDING : currentStyleIndex++; |
| var sanitizationRequired = isMapBased ? |
| true : |
| (sanitizer ? sanitizer(prop, null, 1 /* ValidateProperty */) : false); |
| var updated = updateBindingData(context, data, index, prop, bindingIndex, value, deferRegistration, forceUpdate, sanitizationRequired); |
| if (updated || forceUpdate) { |
| stylesBitMask |= 1 << index; |
| } |
| } |
| /** |
| * Called each time a binding value has changed within the provided `TStylingContext`. |
| * |
| * This function is designed to be called from `updateStyleBinding` and `updateClassBinding`. |
| * If called during the first update pass, the binding will be registered in the context. |
| * If the binding does get registered and the `deferRegistration` flag is true then the |
| * binding data will be queued up until the context is later flushed in `applyStyling`. |
| * |
| * This function will also update binding slot in the provided `LStylingData` with the |
| * new binding entry (if it has changed). |
| * |
| * @returns whether or not the binding value was updated in the `LStylingData`. |
| */ |
| function updateBindingData(context, data, counterIndex, prop, bindingIndex, value, deferRegistration, forceUpdate, sanitizationRequired) { |
| if (!isContextLocked(context)) { |
| if (deferRegistration) { |
| deferBindingRegistration(context, counterIndex, prop, bindingIndex, sanitizationRequired); |
| } |
| else { |
| deferredBindingQueue.length && flushDeferredBindings(); |
| // this will only happen during the first update pass of the |
| // context. The reason why we can't use `tNode.firstTemplatePass` |
| // here is because its not guaranteed to be true when the first |
| // update pass is executed (remember that all styling instructions |
| // are run in the update phase, and, as a result, are no more |
| // styling instructions that are run in the creation phase). |
| registerBinding(context, counterIndex, prop, bindingIndex, sanitizationRequired); |
| } |
| } |
| var changed = forceUpdate || hasValueChanged$1(data[bindingIndex], value); |
| if (changed) { |
| data[bindingIndex] = value; |
| } |
| return changed; |
| } |
| /** |
| * Schedules a binding registration to be run at a later point. |
| * |
| * The reasoning for this feature is to ensure that styling |
| * bindings are registered in the correct order for when |
| * directives/components have a super/sub class inheritance |
| * chains. Each directive's styling bindings must be |
| * registered into the context in reverse order. Therefore all |
| * bindings will be buffered in reverse order and then applied |
| * after the inheritance chain exits. |
| */ |
| function deferBindingRegistration(context, counterIndex, prop, bindingIndex, sanitizationRequired) { |
| deferredBindingQueue.unshift(context, counterIndex, prop, bindingIndex, sanitizationRequired); |
| } |
| /** |
| * Flushes the collection of deferred bindings and causes each entry |
| * to be registered into the context. |
| */ |
| function flushDeferredBindings() { |
| var i = 0; |
| while (i < deferredBindingQueue.length) { |
| var context = deferredBindingQueue[i++]; |
| var count = deferredBindingQueue[i++]; |
| var prop = deferredBindingQueue[i++]; |
| var bindingIndex = deferredBindingQueue[i++]; |
| var sanitizationRequired = deferredBindingQueue[i++]; |
| registerBinding(context, count, prop, bindingIndex, sanitizationRequired); |
| } |
| deferredBindingQueue.length = 0; |
| } |
| /** |
| * Registers the provided binding (prop + bindingIndex) into the context. |
| * |
| * This function is shared between bindings that are assigned immediately |
| * (via `updateBindingData`) and at a deferred stage. When called, it will |
| * figure out exactly where to place the binding data in the context. |
| * |
| * It is needed because it will either update or insert a styling property |
| * into the context at the correct spot. |
| * |
| * When called, one of two things will happen: |
| * |
| * 1) If the property already exists in the context then it will just add |
| * the provided `bindingValue` to the end of the binding sources region |
| * for that particular property. |
| * |
| * - If the binding value is a number then it will be added as a new |
| * binding index source next to the other binding sources for the property. |
| * |
| * - Otherwise, if the binding value is a string/boolean/null type then it will |
| * replace the default value for the property if the default value is `null`. |
| * |
| * 2) If the property does not exist then it will be inserted into the context. |
| * The styling context relies on all properties being stored in alphabetical |
| * order, so it knows exactly where to store it. |
| * |
| * When inserted, a default `null` value is created for the property which exists |
| * as the default value for the binding. If the bindingValue property is inserted |
| * and it is either a string, number or null value then that will replace the default |
| * value. |
| * |
| * Note that this function is also used for map-based styling bindings. They are treated |
| * much the same as prop-based bindings, but, because they do not have a property value |
| * (since it's a map), all map-based entries are stored in an already populated area of |
| * the context at the top (which is reserved for map-based entries). |
| */ |
| function registerBinding(context, countId, prop, bindingValue, sanitizationRequired) { |
| // prop-based bindings (e.g `<div [style.width]="w" [class.foo]="f">`) |
| if (prop) { |
| var found = false; |
| var i = getPropValuesStartPosition(context); |
| while (i < context.length) { |
| var valuesCount = getValuesCount(context, i); |
| var p = getProp$1(context, i); |
| found = prop <= p; |
| if (found) { |
| // all style/class bindings are sorted by property name |
| if (prop < p) { |
| allocateNewContextEntry(context, i, prop, sanitizationRequired); |
| } |
| addBindingIntoContext(context, false, i, bindingValue, countId); |
| break; |
| } |
| i += 3 /* BindingsStartOffset */ + valuesCount; |
| } |
| if (!found) { |
| allocateNewContextEntry(context, context.length, prop, sanitizationRequired); |
| addBindingIntoContext(context, false, i, bindingValue, countId); |
| } |
| } |
| else { |
| // map-based bindings (e.g `<div [style]="s" [class]="{className:true}">`) |
| // there is no need to allocate the map-based binding region into the context |
| // since it is already there when the context is first created. |
| addBindingIntoContext(context, true, 2 /* MapBindingsPosition */, bindingValue, countId); |
| } |
| } |
| function allocateNewContextEntry(context, index, prop, sanitizationRequired) { |
| // 1,2: splice index locations |
| // 3: each entry gets a config value (guard mask + flags) |
| // 4. each entry gets a size value (which is always one because there is always a default binding |
| // value) |
| // 5. the property that is getting allocated into the context |
| // 6. the default binding value (usually `null`) |
| var config = sanitizationRequired ? 1 /* SanitizationRequired */ : |
| 0 /* Default */; |
| context.splice(index, 0, config, DEFAULT_SIZE_VALUE, prop, DEFAULT_BINDING_VALUE); |
| setGuardMask(context, index, DEFAULT_GUARD_MASK_VALUE); |
| } |
| /** |
| * Inserts a new binding value into a styling property tuple in the `TStylingContext`. |
| * |
| * A bindingValue is inserted into a context during the first update pass |
| * of a template or host bindings function. When this occurs, two things |
| * happen: |
| * |
| * - If the bindingValue value is a number then it is treated as a bindingIndex |
| * value (a index in the `LView`) and it will be inserted next to the other |
| * binding index entries. |
| * |
| * - Otherwise the binding value will update the default value for the property |
| * and this will only happen if the default value is `null`. |
| * |
| * Note that this function also handles map-based bindings and will insert them |
| * at the top of the context. |
| */ |
| function addBindingIntoContext(context, isMapBased, index, bindingValue, countId) { |
| var valuesCount = getValuesCount(context, index); |
| var lastValueIndex = index + 3 /* BindingsStartOffset */ + valuesCount; |
| if (!isMapBased) { |
| // prop-based values all have default values, but map-based entries do not. |
| // we want to access the index for the default value in this case and not just |
| // the bindings... |
| lastValueIndex--; |
| } |
| if (typeof bindingValue === 'number') { |
| context.splice(lastValueIndex, 0, bindingValue); |
| context[index + 1 /* ValuesCountOffset */]++; |
| // now that a new binding index has been added to the property |
| // the guard mask bit value (at the `countId` position) needs |
| // to be included into the existing mask value. |
| var guardMask = getGuardMask(context, index) | (1 << countId); |
| setGuardMask(context, index, guardMask); |
| } |
| else if (typeof bindingValue === 'string' && context[lastValueIndex] == null) { |
| context[lastValueIndex] = bindingValue; |
| } |
| } |
| /** |
| * Applies all class entries in the provided context to the provided element and resets |
| * any counter and/or bitMask values associated with class bindings. |
| * |
| * @returns whether or not the classes were flushed to the element. |
| */ |
| function applyClasses(renderer, data, context, element, directiveIndex) { |
| var classesFlushed = false; |
| if (allowStylingFlush(context, directiveIndex)) { |
| var isFirstPass = !isContextLocked(context); |
| isFirstPass && lockContext(context); |
| if (classesBitMask) { |
| // there is no way to sanitize a class value therefore `sanitizer=null` |
| applyStyling(context, renderer, element, data, classesBitMask, setClass$1, null); |
| classesBitMask = 0; |
| classesFlushed = true; |
| } |
| currentClassIndex = STYLING_INDEX_START_VALUE; |
| } |
| return classesFlushed; |
| } |
| /** |
| * Applies all style entries in the provided context to the provided element and resets |
| * any counter and/or bitMask values associated with style bindings. |
| * |
| * @returns whether or not the styles were flushed to the element. |
| */ |
| function applyStyles(renderer, data, context, element, directiveIndex, sanitizer) { |
| var stylesFlushed = false; |
| if (allowStylingFlush(context, directiveIndex)) { |
| var isFirstPass = !isContextLocked(context); |
| isFirstPass && lockContext(context); |
| if (stylesBitMask) { |
| applyStyling(context, renderer, element, data, stylesBitMask, setStyle$1, sanitizer); |
| stylesBitMask = 0; |
| stylesFlushed = true; |
| } |
| currentStyleIndex = STYLING_INDEX_START_VALUE; |
| return true; |
| } |
| return stylesFlushed; |
| } |
| /** |
| * Runs through the provided styling context and applies each value to |
| * the provided element (via the renderer) if one or more values are present. |
| * |
| * This function will iterate over all entries present in the provided |
| * `TStylingContext` array (both prop-based and map-based bindings).- |
| * |
| * Each entry, within the `TStylingContext` array, is stored alphabetically |
| * and this means that each prop/value entry will be applied in order |
| * (so long as it is marked dirty in the provided `bitMask` value). |
| * |
| * If there are any map-based entries present (which are applied to the |
| * element via the `[style]` and `[class]` bindings) then those entries |
| * will be applied as well. However, the code for that is not apart of |
| * this function. Instead, each time a property is visited, then the |
| * code below will call an external function called `stylingMapsSyncFn` |
| * and, if present, it will keep the application of styling values in |
| * map-based bindings up to sync with the application of prop-based |
| * bindings. |
| * |
| * Visit `styling_next/map_based_bindings.ts` to learn more about how the |
| * algorithm works for map-based styling bindings. |
| * |
| * Note that this function is not designed to be called in isolation (use |
| * `applyClasses` and `applyStyles` to actually apply styling values). |
| */ |
| function applyStyling(context, renderer, element, bindingData, bitMaskValue, applyStylingFn, sanitizer) { |
| deferredBindingQueue.length && flushDeferredBindings(); |
| var bitMask = normalizeBitMaskValue(bitMaskValue); |
| var stylingMapsSyncFn = getStylingMapsSyncFn(); |
| var mapsGuardMask = getGuardMask(context, 2 /* MapBindingsPosition */); |
| var applyAllValues = (bitMask & mapsGuardMask) > 0; |
| var mapsMode = applyAllValues ? 1 /* ApplyAllValues */ : 0 /* TraverseValues */; |
| var i = getPropValuesStartPosition(context); |
| while (i < context.length) { |
| var valuesCount = getValuesCount(context, i); |
| var guardMask = getGuardMask(context, i); |
| if (bitMask & guardMask) { |
| var valueApplied = false; |
| var prop = getProp$1(context, i); |
| var valuesCountUpToDefault = valuesCount - 1; |
| var defaultValue = getBindingValue(context, i, valuesCountUpToDefault); |
| // case 1: apply prop-based values |
| // try to apply the binding values and see if a non-null |
| // value gets set for the styling binding |
| for (var j = 0; j < valuesCountUpToDefault; j++) { |
| var bindingIndex = getBindingValue(context, i, j); |
| var value = bindingData[bindingIndex]; |
| if (isStylingValueDefined(value)) { |
| var finalValue = sanitizer && isSanitizationRequired(context, i) ? |
| sanitizer(prop, value, 2 /* SanitizeOnly */) : |
| value; |
| applyStylingFn(renderer, element, prop, finalValue, bindingIndex); |
| valueApplied = true; |
| break; |
| } |
| } |
| // case 2: apply map-based values |
| // traverse through each map-based styling binding and update all values up to |
| // the provided `prop` value. If the property was not applied in the loop above |
| // then it will be attempted to be applied in the maps sync code below. |
| if (stylingMapsSyncFn) { |
| // determine whether or not to apply the target property or to skip it |
| var mode = mapsMode | (valueApplied ? 4 /* SkipTargetProp */ : |
| 2 /* ApplyTargetProp */); |
| var valueAppliedWithinMap = stylingMapsSyncFn(context, renderer, element, bindingData, applyStylingFn, sanitizer, mode, prop, defaultValue); |
| valueApplied = valueApplied || valueAppliedWithinMap; |
| } |
| // case 3: apply the default value |
| // if the value has not yet been applied then a truthy value does not exist in the |
| // prop-based or map-based bindings code. If and when this happens, just apply the |
| // default value (even if the default value is `null`). |
| if (!valueApplied) { |
| applyStylingFn(renderer, element, prop, defaultValue); |
| } |
| } |
| i += 3 /* BindingsStartOffset */ + valuesCount; |
| } |
| // the map-based styling entries may have not applied all their |
| // values. For this reason, one more call to the sync function |
| // needs to be issued at the end. |
| if (stylingMapsSyncFn) { |
| stylingMapsSyncFn(context, renderer, element, bindingData, applyStylingFn, sanitizer, mapsMode); |
| } |
| } |
| function normalizeBitMaskValue(value) { |
| // if pass => apply all values (-1 implies that all bits are flipped to true) |
| if (value === true) |
| return -1; |
| // if pass => skip all values |
| if (value === false) |
| return 0; |
| // return the bit mask value as is |
| return value; |
| } |
| var _activeStylingMapApplyFn = null; |
| function getStylingMapsSyncFn() { |
| return _activeStylingMapApplyFn; |
| } |
| function setStylingMapsSyncFn(fn) { |
| _activeStylingMapApplyFn = fn; |
| } |
| /** |
| * Assigns a style value to a style property for the given element. |
| */ |
| var setStyle$1 = function (renderer, native, prop, value) { |
| if (value) { |
| // opacity, z-index and flexbox all have number values |
| // and these need to be converted into strings so that |
| // they can be assigned properly. |
| value = value.toString(); |
| ngDevMode && ngDevMode.rendererSetStyle++; |
| renderer && isProceduralRenderer(renderer) ? |
| renderer.setStyle(native, prop, value, RendererStyleFlags3.DashCase) : |
| native.style.setProperty(prop, value); |
| } |
| else { |
| ngDevMode && ngDevMode.rendererRemoveStyle++; |
| renderer && isProceduralRenderer(renderer) ? |
| renderer.removeStyle(native, prop, RendererStyleFlags3.DashCase) : |
| native.style.removeProperty(prop); |
| } |
| }; |
| /** |
| * Adds/removes the provided className value to the provided element. |
| */ |
| var setClass$1 = function (renderer, native, className, value) { |
| if (className !== '') { |
| if (value) { |
| ngDevMode && ngDevMode.rendererAddClass++; |
| renderer && isProceduralRenderer(renderer) ? renderer.addClass(native, className) : |
| native.classList.add(className); |
| } |
| else { |
| ngDevMode && ngDevMode.rendererRemoveClass++; |
| renderer && isProceduralRenderer(renderer) ? renderer.removeClass(native, className) : |
| native.classList.remove(className); |
| } |
| } |
| }; |
| |
| /** |
| * -------- |
| * |
| * This file contains the algorithm logic for applying map-based bindings |
| * such as `[style]` and `[class]`. |
| * |
| * -------- |
| */ |
| /** |
| * Used to apply styling values presently within any map-based bindings on an element. |
| * |
| * Angular supports map-based styling bindings which can be applied via the |
| * `[style]` and `[class]` bindings which can be placed on any HTML element. |
| * These bindings can work independently, together or alongside prop-based |
| * styling bindings (e.g. `<div [style]="x" [style.width]="w">`). |
| * |
| * If a map-based styling binding is detected by the compiler, the following |
| * AOT code is produced: |
| * |
| * ```typescript |
| * styleMap(ctx.styles); // styles = {key:value} |
| * classMap(ctx.classes); // classes = {key:value}|string |
| * ``` |
| * |
| * If and when either of the instructions above are evaluated, then the code |
| * present in this file is included into the bundle. The mechanism used, to |
| * activate support for map-based bindings at runtime is possible via the |
| * `activeStylingMapFeature` function (which is also present in this file). |
| * |
| * # The Algorithm |
| * Whenever a map-based binding updates (which is when the identity of the |
| * map-value changes) then the map is iterated over and a `LStylingMap` array |
| * is produced. The `LStylingMap` instance is stored in the binding location |
| * where the `BINDING_INDEX` is situated when the `styleMap()` or `classMap()` |
| * instruction were called. Once the binding changes, then the internal `bitMask` |
| * value is marked as dirty. |
| * |
| * Styling values are applied once CD exits the element (which happens when |
| * the `select(n)` instruction is called or the template function exits). When |
| * this occurs, all prop-based bindings are applied. If a map-based binding is |
| * present then a special flushing function (called a sync function) is made |
| * available and it will be called each time a styling property is flushed. |
| * |
| * The flushing algorithm is designed to apply styling for a property (which is |
| * a CSS property or a className value) one by one. If map-based bindings |
| * are present, then the flushing algorithm will keep calling the maps styling |
| * sync function each time a property is visited. This way, the flushing |
| * behavior of map-based bindings will always be at the same property level |
| * as the current prop-based property being iterated over (because everything |
| * is alphabetically sorted). |
| * |
| * Let's imagine we have the following HTML template code: |
| * |
| * ```html |
| * <div [style]="{width:'100px', height:'200px', 'z-index':'10'}" |
| * [style.width.px]="200">...</div> |
| * ``` |
| * |
| * When CD occurs, both the `[style]` and `[style.width]` bindings |
| * are evaluated. Then when the styles are flushed on screen, the |
| * following operations happen: |
| * |
| * 1. `[style.width]` is attempted to be written to the element. |
| * |
| * 2. Once that happens, the algorithm instructs the map-based |
| * entries (`[style]` in this case) to "catch up" and apply |
| * all values up to the `width` value. When this happens the |
| * `height` value is applied to the element (since it is |
| * alphabetically situated before the `width` property). |
| * |
| * 3. Since there are no more prop-based entries anymore, the |
| * loop exits and then, just before the flushing ends, it |
| * instructs all map-based bindings to "finish up" applying |
| * their values. |
| * |
| * 4. The only remaining value within the map-based entries is |
| * the `z-index` value (`width` got skipped because it was |
| * successfully applied via the prop-based `[style.width]` |
| * binding). Since all map-based entries are told to "finish up", |
| * the `z-index` value is iterated over and it is then applied |
| * to the element. |
| * |
| * The most important thing to take note of here is that prop-based |
| * bindings are evaluated in order alongside map-based bindings. |
| * This allows all styling across an element to be applied in O(n) |
| * time (a similar algorithm is that of the array merge algorithm |
| * in merge sort). |
| */ |
| var syncStylingMap = function (context, renderer, element, data, applyStylingFn, sanitizer, mode, targetProp, defaultValue) { |
| var targetPropValueWasApplied = false; |
| // once the map-based styling code is activate it is never deactivated. For this reason a |
| // check to see if the current styling context has any map based bindings is required. |
| var totalMaps = getValuesCount(context, 2 /* MapBindingsPosition */); |
| if (totalMaps) { |
| var runTheSyncAlgorithm = true; |
| var loopUntilEnd = !targetProp; |
| // If the code is told to finish up (run until the end), but the mode |
| // hasn't been flagged to apply values (it only traverses values) then |
| // there is no point in iterating over the array because nothing will |
| // be applied to the element. |
| if (loopUntilEnd && (mode & ~1 /* ApplyAllValues */)) { |
| runTheSyncAlgorithm = false; |
| targetPropValueWasApplied = true; |
| } |
| if (runTheSyncAlgorithm) { |
| targetPropValueWasApplied = innerSyncStylingMap(context, renderer, element, data, applyStylingFn, sanitizer, mode, targetProp || null, 0, defaultValue || null); |
| } |
| if (loopUntilEnd) { |
| resetSyncCursors(); |
| } |
| } |
| return targetPropValueWasApplied; |
| }; |
| /** |
| * Recursive function designed to apply map-based styling to an element one map at a time. |
| * |
| * This function is designed to be called from the `syncStylingMap` function and will |
| * apply map-based styling data one map at a time to the provided `element`. |
| * |
| * This function is recursive and it will call itself if a follow-up map value is to be |
| * processed. To learn more about how the algorithm works, see `syncStylingMap`. |
| */ |
| function innerSyncStylingMap(context, renderer, element, data, applyStylingFn, sanitizer, mode, targetProp, currentMapIndex, defaultValue) { |
| var targetPropValueWasApplied = false; |
| var totalMaps = getValuesCount(context, 2 /* MapBindingsPosition */); |
| if (currentMapIndex < totalMaps) { |
| var bindingIndex = getBindingValue(context, 2 /* MapBindingsPosition */, currentMapIndex); |
| var lStylingMap = data[bindingIndex]; |
| var cursor = getCurrentSyncCursor(currentMapIndex); |
| while (cursor < lStylingMap.length) { |
| var prop = getMapProp(lStylingMap, cursor); |
| var iteratedTooFar = targetProp && prop > targetProp; |
| var isTargetPropMatched = !iteratedTooFar && prop === targetProp; |
| var value = getMapValue(lStylingMap, cursor); |
| var valueIsDefined = isStylingValueDefined(value); |
| // the recursive code is designed to keep applying until |
| // it reaches or goes past the target prop. If and when |
| // this happens then it will stop processing values, but |
| // all other map values must also catch up to the same |
| // point. This is why a recursive call is still issued |
| // even if the code has iterated too far. |
| var innerMode = iteratedTooFar ? mode : resolveInnerMapMode(mode, valueIsDefined, isTargetPropMatched); |
| var innerProp = iteratedTooFar ? targetProp : prop; |
| var valueApplied = innerSyncStylingMap(context, renderer, element, data, applyStylingFn, sanitizer, innerMode, innerProp, currentMapIndex + 1, defaultValue); |
| if (iteratedTooFar) { |
| break; |
| } |
| if (!valueApplied && isValueAllowedToBeApplied(mode, isTargetPropMatched)) { |
| var useDefault = isTargetPropMatched && !valueIsDefined; |
| var valueToApply = useDefault ? defaultValue : value; |
| var bindingIndexToApply = useDefault ? bindingIndex : null; |
| var finalValue = sanitizer ? |
| sanitizer(prop, valueToApply, 3 /* ValidateAndSanitize */) : |
| valueToApply; |
| applyStylingFn(renderer, element, prop, finalValue, bindingIndexToApply); |
| valueApplied = true; |
| } |
| targetPropValueWasApplied = valueApplied && isTargetPropMatched; |
| cursor += 2 /* TupleSize */; |
| } |
| setCurrentSyncCursor(currentMapIndex, cursor); |
| } |
| return targetPropValueWasApplied; |
| } |
| /** |
| * Enables support for map-based styling bindings (e.g. `[style]` and `[class]` bindings). |
| */ |
| function activeStylingMapFeature() { |
| setStylingMapsSyncFn(syncStylingMap); |
| } |
| /** |
| * Used to determine the mode for the inner recursive call. |
| * |
| * If an inner map is iterated on then this is done so for one |
| * of two reasons: |
| * |
| * - The target property was detected and the inner map |
| * must now "catch up" (pointer-wise) up to where the current |
| * map's cursor is situated. |
| * |
| * - The target property was not detected in the current map |
| * and must be found in an inner map. This can only be allowed |
| * if the current map iteration is not set to skip the target |
| * property. |
| */ |
| function resolveInnerMapMode(currentMode, valueIsDefined, isExactMatch) { |
| var innerMode = currentMode; |
| if (!valueIsDefined && isExactMatch && !(currentMode & 4 /* SkipTargetProp */)) { |
| // case 1: set the mode to apply the targeted prop value if it |
| // ends up being encountered in another map value |
| innerMode |= 2 /* ApplyTargetProp */; |
| innerMode &= ~4 /* SkipTargetProp */; |
| } |
| else { |
| // case 2: set the mode to skip the targeted prop value if it |
| // ends up being encountered in another map value |
| innerMode |= 4 /* SkipTargetProp */; |
| innerMode &= ~2 /* ApplyTargetProp */; |
| } |
| return innerMode; |
| } |
| /** |
| * Decides whether or not a prop/value entry will be applied to an element. |
| * |
| * To determine whether or not a value is to be applied, |
| * the following procedure is evaluated: |
| * |
| * First check to see the current `mode` status: |
| * 1. If the mode value permits all props to be applied then allow. |
| * - But do not allow if the current prop is set to be skipped. |
| * 2. Otherwise if the current prop is permitted then allow. |
| */ |
| function isValueAllowedToBeApplied(mode, isTargetPropMatched) { |
| var doApplyValue = (mode & 1 /* ApplyAllValues */) > 0; |
| if (!doApplyValue) { |
| if (mode & 2 /* ApplyTargetProp */) { |
| doApplyValue = isTargetPropMatched; |
| } |
| } |
| else if ((mode & 4 /* SkipTargetProp */) && isTargetPropMatched) { |
| doApplyValue = false; |
| } |
| return doApplyValue; |
| } |
| /** |
| * Used to keep track of concurrent cursor values for multiple map-based styling bindings present on |
| * an element. |
| */ |
| var MAP_CURSORS = []; |
| /** |
| * Used to reset the state of each cursor value being used to iterate over map-based styling |
| * bindings. |
| */ |
| function resetSyncCursors() { |
| for (var i = 0; i < MAP_CURSORS.length; i++) { |
| MAP_CURSORS[i] = 1 /* ValuesStartPosition */; |
| } |
| } |
| /** |
| * Returns an active cursor value at a given mapIndex location. |
| */ |
| function getCurrentSyncCursor(mapIndex) { |
| if (mapIndex >= MAP_CURSORS.length) { |
| MAP_CURSORS.push(1 /* ValuesStartPosition */); |
| } |
| return MAP_CURSORS[mapIndex]; |
| } |
| /** |
| * Sets a cursor value at a given mapIndex location. |
| */ |
| function setCurrentSyncCursor(mapIndex, indexValue) { |
| MAP_CURSORS[mapIndex] = indexValue; |
| } |
| /** |
| * Used to convert a {key:value} map into a `LStylingMap` array. |
| * |
| * This function will either generate a new `LStylingMap` instance |
| * or it will patch the provided `newValues` map value into an |
| * existing `LStylingMap` value (this only happens if `bindingValue` |
| * is an instance of `LStylingMap`). |
| * |
| * If a new key/value map is provided with an old `LStylingMap` |
| * value then all properties will be overwritten with their new |
| * values or with `null`. This means that the array will never |
| * shrink in size (but it will also not be created and thrown |
| * away whenever the {key:value} map entries change). |
| */ |
| function normalizeIntoStylingMap(bindingValue, newValues) { |
| var lStylingMap = Array.isArray(bindingValue) ? bindingValue : [null]; |
| lStylingMap[0 /* RawValuePosition */] = newValues || null; |
| // because the new values may not include all the properties |
| // that the old ones had, all values are set to `null` before |
| // the new values are applied. This way, when flushed, the |
| // styling algorithm knows exactly what style/class values |
| // to remove from the element (since they are `null`). |
| for (var j = 1 /* ValuesStartPosition */; j < lStylingMap.length; j += 2 /* TupleSize */) { |
| setMapValue(lStylingMap, j, null); |
| } |
| var props = null; |
| var map; |
| var allValuesTrue = false; |
| if (typeof newValues === 'string') { // [class] bindings allow string values |
| if (newValues.length) { |
| props = newValues.split(/\s+/); |
| allValuesTrue = true; |
| } |
| } |
| else { |
| props = newValues ? Object.keys(newValues) : null; |
| map = newValues; |
| } |
| if (props) { |
| outer: for (var i = 0; i < props.length; i++) { |
| var prop = props[i]; |
| var value = allValuesTrue ? true : map[prop]; |
| for (var j = 1 /* ValuesStartPosition */; j < lStylingMap.length; j += 2 /* TupleSize */) { |
| var propAtIndex = getMapProp(lStylingMap, j); |
| if (prop <= propAtIndex) { |
| if (propAtIndex === prop) { |
| setMapValue(lStylingMap, j, value); |
| } |
| else { |
| lStylingMap.splice(j, 0, prop, value); |
| } |
| continue outer; |
| } |
| } |
| lStylingMap.push(prop, value); |
| } |
| } |
| return lStylingMap; |
| } |
| function getMapProp(map, index) { |
| return map[index + 0 /* PropOffset */]; |
| } |
| function setMapValue(map, index, value) { |
| map[index + 1 /* ValueOffset */] = value; |
| } |
| function getMapValue(map, index) { |
| return map[index + 1 /* ValueOffset */]; |
| } |
| |
| /** |
| * Instantiates and attaches an instance of `TStylingContextDebug` to the provided context. |
| */ |
| function attachStylingDebugObject(context) { |
| var debug = new TStylingContextDebug(context); |
| attachDebugObject(context, debug); |
| return debug; |
| } |
| /** |
| * A human-readable debug summary of the styling data present within `TStylingContext`. |
| * |
| * This class is designed to be used within testing code or when an |
| * application has `ngDevMode` activated. |
| */ |
| var TStylingContextDebug = /** @class */ (function () { |
| function TStylingContextDebug(context) { |
| this.context = context; |
| } |
| Object.defineProperty(TStylingContextDebug.prototype, "isLocked", { |
| get: function () { return isContextLocked(this.context); }, |
| enumerable: true, |
| configurable: true |
| }); |
| Object.defineProperty(TStylingContextDebug.prototype, "entries", { |
| /** |
| * Returns a detailed summary of each styling entry in the context. |
| * |
| * See `TStylingTupleSummary`. |
| */ |
| get: function () { |
| var context = this.context; |
| var entries = {}; |
| var start = 2 /* MapBindingsPosition */; |
| var i = start; |
| while (i < context.length) { |
| var valuesCount = getValuesCount(context, i); |
| // the context may contain placeholder values which are populated ahead of time, |
| // but contain no actual binding values. In this situation there is no point in |
| // classifying this as an "entry" since no real data is stored here yet. |
| if (valuesCount) { |
| var prop = getProp$1(context, i); |
| var guardMask = getGuardMask(context, i); |
| var defaultValue = getDefaultValue(context, i); |
| var sanitizationRequired = isSanitizationRequired(context, i); |
| var bindingsStartPosition = i + 3 /* BindingsStartOffset */; |
| var sources = []; |
| for (var j = 0; j < valuesCount; j++) { |
| sources.push(context[bindingsStartPosition + j]); |
| } |
| entries[prop] = { prop: prop, guardMask: guardMask, sanitizationRequired: sanitizationRequired, valuesCount: valuesCount, defaultValue: defaultValue, sources: sources }; |
| } |
| i += 3 /* BindingsStartOffset */ + valuesCount; |
| } |
| return entries; |
| }, |
| enumerable: true, |
| configurable: true |
| }); |
| return TStylingContextDebug; |
| }()); |
| /** |
| * A human-readable debug summary of the styling data present for a `DebugNode` instance. |
| * |
| * This class is designed to be used within testing code or when an |
| * application has `ngDevMode` activated. |
| */ |
| var NodeStylingDebug = /** @class */ (function () { |
| function NodeStylingDebug(context, _data, _isClassBased) { |
| this.context = context; |
| this._data = _data; |
| this._isClassBased = _isClassBased; |
| this._sanitizer = null; |
| } |
| /** |
| * Overrides the sanitizer used to process styles. |
| */ |
| NodeStylingDebug.prototype.overrideSanitizer = function (sanitizer) { this._sanitizer = sanitizer; }; |
| Object.defineProperty(NodeStylingDebug.prototype, "summary", { |
| /** |
| * Returns a detailed summary of each styling entry in the context and |
| * what their runtime representation is. |
| * |
| * See `LStylingSummary`. |
| */ |
| get: function () { |
| var entries = {}; |
| this._mapValues(function (prop, value, bindingIndex) { |
| entries[prop] = { prop: prop, value: value, bindingIndex: bindingIndex }; |
| }); |
| return entries; |
| }, |
| enumerable: true, |
| configurable: true |
| }); |
| Object.defineProperty(NodeStylingDebug.prototype, "values", { |
| /** |
| * Returns a key/value map of all the styles/classes that were last applied to the element. |
| */ |
| get: function () { |
| var entries = {}; |
| this._mapValues(function (prop, value) { entries[prop] = value; }); |
| return entries; |
| }, |
| enumerable: true, |
| configurable: true |
| }); |
| NodeStylingDebug.prototype._mapValues = function (fn) { |
| // there is no need to store/track an element instance. The |
| // element is only used when the styling algorithm attempts to |
| // style the value (and we mock out the stylingApplyFn anyway). |
| var mockElement = {}; |
| var hasMaps = getValuesCount(this.context, 2 /* MapBindingsPosition */) > 0; |
| if (hasMaps) { |
| activeStylingMapFeature(); |
| } |
| var mapFn = function (renderer, element, prop, value, bindingIndex) { |
| fn(prop, value, bindingIndex || null); |
| }; |
| var sanitizer = this._isClassBased ? null : (this._sanitizer || |
| getCurrentOrLViewSanitizer(this._data)); |
| applyStyling(this.context, null, mockElement, this._data, true, mapFn, sanitizer); |
| }; |
| return NodeStylingDebug; |
| }()); |
| |
| /** |
| * @license |
| * Copyright Google Inc. All Rights Reserved. |
| * |
| * Use of this source code is governed by an MIT-style license that can be |
| * found in the LICENSE file at https://angular.io/license |
| */ |
| /* |
| * This file contains conditionally attached classes which provide human readable (debug) level |
| * information for `LView`, `LContainer` and other internal data structures. These data structures |
| * are stored internally as array which makes it very difficult during debugging to reason about the |
| * current state of the system. |
| * |
| * Patching the array with extra property does change the array's hidden class' but it does not |
| * change the cost of access, therefore this patching should not have significant if any impact in |
| * `ngDevMode` mode. (see: https://jsperf.com/array-vs-monkey-patch-array) |
| * |
| * So instead of seeing: |
| * ``` |
| * Array(30) [Object, 659, null, …] |
| * ``` |
| * |
| * You get to see: |
| * ``` |
| * LViewDebug { |
| * views: [...], |
| * flags: {attached: true, ...} |
| * nodes: [ |
| * {html: '<div id="123">', ..., nodes: [ |
| * {html: '<span>', ..., nodes: null} |
| * ]} |
| * ] |
| * } |
| * ``` |
| */ |
| var LViewArray = ngDevMode && createNamedArrayType('LView'); |
| var LVIEW_EMPTY; // can't initialize here or it will not be tree shaken, because `LView` |
| // constructor could have side-effects. |
| /** |
| * This function clones a blueprint and creates LView. |
| * |
| * Simple slice will keep the same type, and we need it to be LView |
| */ |
| function cloneToLView(list) { |
| if (LVIEW_EMPTY === undefined) |
| LVIEW_EMPTY = new LViewArray(); |
| return LVIEW_EMPTY.concat(list); |
| } |
| /** |
| * This class is a debug version of Object literal so that we can have constructor name show up in |
| * debug tools in ngDevMode. |
| */ |
| var TViewConstructor = /** @class */ (function () { |
| function TView(id, // |
| blueprint, // |
| template, // |
| viewQuery, // |
| node, // |
| data, // |
| bindingStartIndex, // |
| viewQueryStartIndex, // |
| expandoStartIndex, // |
| expandoInstructions, // |
| firstTemplatePass, // |
| staticViewQueries, // |
| staticContentQueries, // |
| preOrderHooks, // |
| preOrderCheckHooks, // |
| contentHooks, // |
| contentCheckHooks, // |
| viewHooks, // |
| viewCheckHooks, // |
| destroyHooks, // |
| cleanup, // |
| contentQueries, // |
| components, // |
| directiveRegistry, // |
| pipeRegistry, // |
| firstChild, // |
| schemas) { |
| this.id = id; |
| this.blueprint = blueprint; |
| this.template = template; |
| this.viewQuery = viewQuery; |
| this.node = node; |
| this.data = data; |
| this.bindingStartIndex = bindingStartIndex; |
| this.viewQueryStartIndex = viewQueryStartIndex; |
| this.expandoStartIndex = expandoStartIndex; |
| this.expandoInstructions = expandoInstructions; |
| this.firstTemplatePass = firstTemplatePass; |
| this.staticViewQueries = staticViewQueries; |
| this.staticContentQueries = staticContentQueries; |
| this.preOrderHooks = preOrderHooks; |
| this.preOrderCheckHooks = preOrderCheckHooks; |
| this.contentHooks = contentHooks; |
| this.contentCheckHooks = contentCheckHooks; |
| this.viewHooks = viewHooks; |
| this.viewCheckHooks = viewCheckHooks; |
| this.destroyHooks = destroyHooks; |
| this.cleanup = cleanup; |
| this.contentQueries = contentQueries; |
| this.components = components; |
| this.directiveRegistry = directiveRegistry; |
| this.pipeRegistry = pipeRegistry; |
| this.firstChild = firstChild; |
| this.schemas = schemas; |
| } |
| return TView; |
| }()); |
| var TViewData = ngDevMode && createNamedArrayType('TViewData'); |
| var TVIEWDATA_EMPTY; // can't initialize here or it will not be tree shaken, because `LView` |
| // constructor could have side-effects. |
| /** |
| * This function clones a blueprint and creates TData. |
| * |
| * Simple slice will keep the same type, and we need it to be TData |
| */ |
| function cloneToTViewData(list) { |
| if (TVIEWDATA_EMPTY === undefined) |
| TVIEWDATA_EMPTY = new TViewData(); |
| return TVIEWDATA_EMPTY.concat(list); |
| } |
| var LViewBlueprint = ngDevMode && createNamedArrayType('LViewBlueprint'); |
| var MatchesArray = ngDevMode && createNamedArrayType('MatchesArray'); |
| var TViewComponents = ngDevMode && createNamedArrayType('TViewComponents'); |
| var TNodeLocalNames = ngDevMode && createNamedArrayType('TNodeLocalNames'); |
| var TNodeInitialInputs = ngDevMode && createNamedArrayType('TNodeInitialInputs'); |
| var TNodeInitialData = ngDevMode && createNamedArrayType('TNodeInitialData'); |
| var LCleanup = ngDevMode && createNamedArrayType('LCleanup'); |
| var TCleanup = ngDevMode && createNamedArrayType('TCleanup'); |
| function attachLViewDebug(lView) { |
| attachDebugObject(lView, new LViewDebug(lView)); |
| } |
| function attachLContainerDebug(lContainer) { |
| attachDebugObject(lContainer, new LContainerDebug(lContainer)); |
| } |
| function toDebug(obj) { |
| if (obj) { |
| var debug = obj.debug; |
| assertDefined(debug, 'Object does not have a debug representation.'); |
| return debug; |
| } |
| else { |
| return obj; |
| } |
| } |
| /** |
| * Use this method to unwrap a native element in `LView` and convert it into HTML for easier |
| * reading. |
| * |
| * @param value possibly wrapped native DOM node. |
| * @param includeChildren If `true` then the serialized HTML form will include child elements (same |
| * as `outerHTML`). If `false` then the serialized HTML form will only contain the element itself |
| * (will not serialize child elements). |
| */ |
| function toHtml(value, includeChildren) { |
| if (includeChildren === void 0) { includeChildren = false; } |
| var node = unwrapRNode(value); |
| if (node) { |
| var isTextNode = node.nodeType === Node.TEXT_NODE; |
| var outerHTML = (isTextNode ? node.textContent : node.outerHTML) || ''; |
| if (includeChildren || isTextNode) { |
| return outerHTML; |
| } |
| else { |
| var innerHTML = node.innerHTML; |
| return outerHTML.split(innerHTML)[0] || null; |
| } |
| } |
| else { |
| return null; |
| } |
| } |
| var LViewDebug = /** @class */ (function () { |
| function LViewDebug(_raw_lView) { |
| this._raw_lView = _raw_lView; |
| } |
| Object.defineProperty(LViewDebug.prototype, "flags", { |
| /** |
| * Flags associated with the `LView` unpacked into a more readable state. |
| */ |
| get: function () { |
| var flags = this._raw_lView[FLAGS]; |
| return { |
| __raw__flags__: flags, |
| initPhaseState: flags & 3 /* InitPhaseStateMask */, |
| creationMode: !!(flags & 4 /* CreationMode */), |
| firstViewPass: !!(flags & 8 /* FirstLViewPass */), |
| checkAlways: !!(flags & 16 /* CheckAlways */), |
| dirty: !!(flags & 64 /* Dirty */), |
| attached: !!(flags & 128 /* Attached */), |
| destroyed: !!(flags & 256 /* Destroyed */), |
| isRoot: !!(flags & 512 /* IsRoot */), |
| indexWithinInitPhase: flags >> 10 /* IndexWithinInitPhaseShift */, |
| }; |
| }, |
| enumerable: true, |
| configurable: true |
| }); |
| Object.defineProperty(LViewDebug.prototype, "parent", { |
| get: function () { return toDebug(this._raw_lView[PARENT]); }, |
| enumerable: true, |
| configurable: true |
| }); |
| Object.defineProperty(LViewDebug.prototype, "host", { |
| get: function () { return toHtml(this._raw_lView[HOST], true); }, |
| enumerable: true, |
| configurable: true |
| }); |
| Object.defineProperty(LViewDebug.prototype, "context", { |
| get: function () { return this._raw_lView[CONTEXT]; }, |
| enumerable: true, |
| configurable: true |
| }); |
| Object.defineProperty(LViewDebug.prototype, "nodes", { |
| /** |
| * The tree of nodes associated with the current `LView`. The nodes have been normalized into a |
| * tree structure with relevant details pulled out for readability. |
| */ |
| get: function () { |
| var lView = this._raw_lView; |
| var tNode = lView[TVIEW].firstChild; |
| return toDebugNodes(tNode, lView); |
| }, |
| enumerable: true, |
| configurable: true |
| }); |
| Object.defineProperty(LViewDebug.prototype, "__other__", { |
| /** |
| * Additional information which is hidden behind a property. The extra level of indirection is |
| * done so that the debug view would not be cluttered with properties which are only rarely |
| * relevant to the developer. |
| */ |
| get: function () { |
| return { |
| tView: this._raw_lView[TVIEW], |
| cleanup: this._raw_lView[CLEANUP], |
| injector: this._raw_lView[INJECTOR$1], |
| rendererFactory: this._raw_lView[RENDERER_FACTORY], |
| renderer: this._raw_lView[RENDERER], |
| sanitizer: this._raw_lView[SANITIZER], |
| childHead: toDebug(this._raw_lView[CHILD_HEAD]), |
| next: toDebug(this._raw_lView[NEXT]), |
| childTail: toDebug(this._raw_lView[CHILD_TAIL]), |
| declarationView: toDebug(this._raw_lView[DECLARATION_VIEW]), |
| contentQueries: this._raw_lView[CONTENT_QUERIES], |
| queries: this._raw_lView[QUERIES], |
| tHost: this._raw_lView[T_HOST], |
| bindingIndex: this._raw_lView[BINDING_INDEX], |
| }; |
| }, |
| enumerable: true, |
| configurable: true |
| }); |
| Object.defineProperty(LViewDebug.prototype, "childViews", { |
| /** |
| * Normalized view of child views (and containers) attached at this location. |
| */ |
| get: function () { |
| var childViews = []; |
| var child = this.__other__.childHead; |
| while (child) { |
| childViews.push(child); |
| child = child.__other__.next; |
| } |
| return childViews; |
| }, |
| enumerable: true, |
| configurable: true |
| }); |
| return LViewDebug; |
| }()); |
| /** |
| * Turns a flat list of nodes into a tree by walking the associated `TNode` tree. |
| * |
| * @param tNode |
| * @param lView |
| */ |
| function toDebugNodes(tNode, lView) { |
| if (tNode) { |
| var debugNodes = []; |
| var tNodeCursor = tNode; |
| while (tNodeCursor) { |
| var rawValue = lView[tNode.index]; |
| var native = unwrapRNode(rawValue); |
| var componentLViewDebug = isStylingContext(rawValue) ? null : toDebug(readLViewValue(rawValue)); |
| var styles = null; |
| var classes = null; |
| if (runtimeIsNewStylingInUse()) { |
| styles = tNode.newStyles ? new NodeStylingDebug(tNode.newStyles, lView, false) : null; |
| classes = tNode.newClasses ? new NodeStylingDebug(tNode.newClasses, lView, true) : null; |
| } |
| debugNodes.push({ |
| html: toHtml(native), |
| native: native, styles: styles, classes: classes, |
| nodes: toDebugNodes(tNode.child, lView), |
| component: componentLViewDebug, |
| }); |
| tNodeCursor = tNodeCursor.next; |
| } |
| return debugNodes; |
| } |
| else { |
| return null; |
| } |
| } |
| var LContainerDebug = /** @class */ (function () { |
| function LContainerDebug(_raw_lContainer) { |
| this._raw_lContainer = _raw_lContainer; |
| } |
| Object.defineProperty(LContainerDebug.prototype, "activeIndex", { |
| get: function () { return this._raw_lContainer[ACTIVE_INDEX]; }, |
| enumerable: true, |
| configurable: true |
| }); |
| Object.defineProperty(LContainerDebug.prototype, "views", { |
| get: function () { |
| return this._raw_lContainer.slice(CONTAINER_HEADER_OFFSET) |
| .map(toDebug); |
| }, |
| enumerable: true, |
| configurable: true |
| }); |
| Object.defineProperty(LContainerDebug.prototype, "parent", { |
| get: function () { return toDebug(this._raw_lContainer[PARENT]); }, |
| enumerable: true, |
| configurable: true |
| }); |
| Object.defineProperty(LContainerDebug.prototype, "queries", { |
| get: function () { return this._raw_lContainer[QUERIES]; }, |
| enumerable: true, |
| configurable: true |
| }); |
| Object.defineProperty(LContainerDebug.prototype, "host", { |
| get: function () { return this._raw_lContainer[HOST]; }, |
| enumerable: true, |
| configurable: true |
| }); |
| Object.defineProperty(LContainerDebug.prototype, "native", { |
| get: function () { return this._raw_lContainer[NATIVE]; }, |
| enumerable: true, |
| configurable: true |
| }); |
| Object.defineProperty(LContainerDebug.prototype, "__other__", { |
| get: function () { |
| return { |
| next: toDebug(this._raw_lContainer[NEXT]), |
| }; |
| }, |
| enumerable: true, |
| configurable: true |
| }); |
| return LContainerDebug; |
| }()); |
| /** |
| * Return an `LView` value if found. |
| * |
| * @param value `LView` if any |
| */ |
| function readLViewValue(value) { |
| while (Array.isArray(value)) { |
| // This check is not quite right, as it does not take into account `StylingContext` |
| // This is why it is in debug, not in util.ts |
| if (value.length >= HEADER_OFFSET - 1) |
| return value; |
| value = value[HOST]; |
| } |
| return null; |
| } |
| var I18NDebugItem = /** @class */ (function () { |
| function I18NDebugItem(__raw_opCode, _lView, nodeIndex, type) { |
| this.__raw_opCode = __raw_opCode; |
| this._lView = _lView; |
| this.nodeIndex = nodeIndex; |
| this.type = type; |
| } |
| Object.defineProperty(I18NDebugItem.prototype, "tNode", { |
| get: function () { return getTNode(this.nodeIndex, this._lView); }, |
| enumerable: true, |
| configurable: true |
| }); |
| return I18NDebugItem; |
| }()); |
| /** |
| * Turns a list of "Create" & "Update" OpCodes into a human-readable list of operations for |
| * debugging purposes. |
| * @param mutateOpCodes mutation opCodes to read |
| * @param updateOpCodes update opCodes to read |
| * @param icus list of ICU expressions |
| * @param lView The view the opCodes are acting on |
| */ |
| function attachI18nOpCodesDebug(mutateOpCodes, updateOpCodes, icus, lView) { |
| attachDebugObject(mutateOpCodes, new I18nMutateOpCodesDebug(mutateOpCodes, lView)); |
| attachDebugObject(updateOpCodes, new I18nUpdateOpCodesDebug(updateOpCodes, icus, lView)); |
| if (icus) { |
| icus.forEach(function (icu) { |
| icu.create.forEach(function (icuCase) { attachDebugObject(icuCase, new I18nMutateOpCodesDebug(icuCase, lView)); }); |
| icu.update.forEach(function (icuCase) { |
| attachDebugObject(icuCase, new I18nUpdateOpCodesDebug(icuCase, icus, lView)); |
| }); |
| }); |
| } |
| } |
| var I18nMutateOpCodesDebug = /** @class */ (function () { |
| function I18nMutateOpCodesDebug(__raw_opCodes, __lView) { |
| this.__raw_opCodes = __raw_opCodes; |
| this.__lView = __lView; |
| } |
| Object.defineProperty(I18nMutateOpCodesDebug.prototype, "operations", { |
| /** |
| * A list of operation information about how the OpCodes will act on the view. |
| */ |
| get: function () { |
| var _a = this, __lView = _a.__lView, __raw_opCodes = _a.__raw_opCodes; |
| var results = []; |
| for (var i = 0; i < __raw_opCodes.length; i++) { |
| var opCode = __raw_opCodes[i]; |
| var result = void 0; |
| if (typeof opCode === 'string') { |
| result = { |
| __raw_opCode: opCode, |
| type: 'Create Text Node', |
| nodeIndex: __raw_opCodes[++i], |
| text: opCode, |
| }; |
| } |
| if (typeof opCode === 'number') { |
| switch (opCode & 7 /* MASK_OPCODE */) { |
| case 1 /* AppendChild */: |
| var destinationNodeIndex = opCode >>> 17 /* SHIFT_PARENT */; |
| result = new I18NDebugItem(opCode, __lView, destinationNodeIndex, 'AppendChild'); |
| break; |
| case 0 /* Select */: |
| var nodeIndex = opCode >>> 3 /* SHIFT_REF */; |
| result = new I18NDebugItem(opCode, __lView, nodeIndex, 'Select'); |
| break; |
| case 5 /* ElementEnd */: |
| var elementIndex = opCode >>> 3 /* SHIFT_REF */; |
| result = new I18NDebugItem(opCode, __lView, elementIndex, 'ElementEnd'); |
| break; |
| case 4 /* Attr */: |
| elementIndex = opCode >>> 3 /* SHIFT_REF */; |
| result = new I18NDebugItem(opCode, __lView, elementIndex, 'Attr'); |
| result['attrName'] = __raw_opCodes[++i]; |
| result['attrValue'] = __raw_opCodes[++i]; |
| break; |
| } |
| } |
| if (!result) { |
| switch (opCode) { |
| case COMMENT_MARKER: |
| result = { |
| __raw_opCode: opCode, |
| type: 'COMMENT_MARKER', |
| commentValue: __raw_opCodes[++i], |
| nodeIndex: __raw_opCodes[++i], |
| }; |
| break; |
| case ELEMENT_MARKER: |
| result = { |
| __raw_opCode: opCode, |
| type: 'ELEMENT_MARKER', |
| }; |
| break; |
| } |
| } |
| if (!result) { |
| result = { |
| __raw_opCode: opCode, |
| type: 'Unknown Op Code', |
| code: opCode, |
| }; |
| } |
| results.push(result); |
| } |
| return results; |
| }, |
| enumerable: true, |
| configurable: true |
| }); |
| return I18nMutateOpCodesDebug; |
| }()); |
| var I18nUpdateOpCodesDebug = /** @class */ (function () { |
| function I18nUpdateOpCodesDebug(__raw_opCodes, icus, __lView) { |
| this.__raw_opCodes = __raw_opCodes; |
| this.icus = icus; |
| this.__lView = __lView; |
| } |
| Object.defineProperty(I18nUpdateOpCodesDebug.prototype, "operations", { |
| /** |
| * A list of operation information about how the OpCodes will act on the view. |
| */ |
| get: function () { |
| var _a = this, __lView = _a.__lView, __raw_opCodes = _a.__raw_opCodes, icus = _a.icus; |
| var results = []; |
| for (var i = 0; i < __raw_opCodes.length; i++) { |
| // bit code to check if we should apply the next update |
| var checkBit = __raw_opCodes[i]; |
| // Number of opCodes to skip until next set of update codes |
| var skipCodes = __raw_opCodes[++i]; |
| var value = ''; |
| for (var j = i + 1; j <= (i + skipCodes); j++) { |
| var opCode = __raw_opCodes[j]; |
| if (typeof opCode === 'string') { |
| value += opCode; |
| } |
| else if (typeof opCode == 'number') { |
| if (opCode < 0) { |
| // It's a binding index whose value is negative |
| // We cannot know the value of the binding so we only show the index |
| value += "\uFFFD" + (-opCode - 1) + "\uFFFD"; |
| } |
| else { |
| var nodeIndex = opCode >>> 2 /* SHIFT_REF */; |
| var tIcuIndex = void 0; |
| var tIcu = void 0; |
| switch (opCode & 3 /* MASK_OPCODE */) { |
| case 1 /* Attr */: |
| var attrName = __raw_opCodes[++j]; |
| var sanitizeFn = __raw_opCodes[++j]; |
| results.push({ |
| __raw_opCode: opCode, |
| checkBit: checkBit, |
| type: 'Attr', |
| attrValue: value, attrName: attrName, sanitizeFn: sanitizeFn, |
| }); |
| break; |
| case 0 /* Text */: |
| results.push({ |
| __raw_opCode: opCode, |
| checkBit: checkBit, |
| type: 'Text', nodeIndex: nodeIndex, |
| text: value, |
| }); |
| break; |
| case 2 /* IcuSwitch */: |
| tIcuIndex = __raw_opCodes[++j]; |
| tIcu = icus[tIcuIndex]; |
| var result = new I18NDebugItem(opCode, __lView, nodeIndex, 'IcuSwitch'); |
| result['tIcuIndex'] = tIcuIndex; |
| result['checkBit'] = checkBit; |
| result['mainBinding'] = value; |
| result['tIcu'] = tIcu; |
| results.push(result); |
| break; |
| case 3 /* IcuUpdate */: |
| tIcuIndex = __raw_opCodes[++j]; |
| tIcu = icus[tIcuIndex]; |
| result = new I18NDebugItem(opCode, __lView, nodeIndex, 'IcuUpdate'); |
| result['tIcuIndex'] = tIcuIndex; |
| result['checkBit'] = checkBit; |
| result['tIcu'] = tIcu; |
| results.push(result); |
| break; |
| } |
| } |
| } |
| } |
| i += skipCodes; |
| } |
| return results; |
| }, |
| enumerable: true, |
| configurable: true |
| }); |
| return I18nUpdateOpCodesDebug; |
| }()); |
| |
| /** |
| * @license |
| * Copyright Google Inc. All Rights Reserved. |
| * |
| * Use of this source code is governed by an MIT-style license that can be |
| * found in the LICENSE file at https://angular.io/license |
| */ |
| /** |
| * Selects an element for later binding instructions. |
| * |
| * Used in conjunction with instructions like {@link property} to act on elements with specified |
| * indices, for example those created with {@link element} or {@link elementStart}. |
| * |
| * ```ts |
| * (rf: RenderFlags, ctx: any) => { |
| * if (rf & 1) { |
| * element(0, 'div'); |
| * } |
| * if (rf & 2) { |
| * select(0); // Select the <div/> created above. |
| * property('title', 'test'); |
| * } |
| * } |
| * ``` |
| * @param index the index of the item to act on with the following instructions |
| * |
| * @codeGenApi |
| */ |
| function ɵɵselect(index) { |
| ngDevMode && assertGreaterThan(index, -1, 'Invalid index'); |
| ngDevMode && |
| assertLessThan(index, getLView().length - HEADER_OFFSET, 'Should be within range for the view data'); |
| var lView = getLView(); |
| selectInternal(lView, index); |
| } |
| function selectInternal(lView, index) { |
| // Flush the initial hooks for elements in the view that have been added up to this point. |
| executePreOrderHooks(lView, lView[TVIEW], getCheckNoChangesMode(), index); |
| // We must set the selected index *after* running the hooks, because hooks may have side-effects |
| // that cause other template functions to run, thus updating the selected index, which is global |
| // state. If we run `setSelectedIndex` *before* we run the hooks, in some cases the selected index |
| // will be altered by the time we leave the `ɵɵselect` instruction. |
| setSelectedIndex(index); |
| } |
| |
| var ɵ0$8 = function () { return Promise.resolve(null); }; |
| /** |
| * A permanent marker promise which signifies that the current CD tree is |
| * clean. |
| */ |
| var _CLEAN_PROMISE = (ɵ0$8)(); |
| /** |
| * Refreshes the view, executing the following steps in that order: |
| * triggers init hooks, refreshes dynamic embedded views, triggers content hooks, sets host |
| * bindings, refreshes child components. |
| * Note: view hooks are triggered later when leaving the view. |
| */ |
| function refreshDescendantViews(lView) { |
| var tView = lView[TVIEW]; |
| var creationMode = isCreationMode(lView); |
| // This needs to be set before children are processed to support recursive components |
| tView.firstTemplatePass = false; |
| // Resetting the bindingIndex of the current LView as the next steps may trigger change detection. |
| lView[BINDING_INDEX] = tView.bindingStartIndex; |
| // If this is a creation pass, we should not call lifecycle hooks or evaluate bindings. |
| // This will be done in the update pass. |
| if (!creationMode) { |
| var checkNoChangesMode = getCheckNoChangesMode(); |
| executePreOrderHooks(lView, tView, checkNoChangesMode, undefined); |
| refreshDynamicEmbeddedViews(lView); |
| // Content query results must be refreshed before content hooks are called. |
| refreshContentQueries(tView, lView); |
| resetPreOrderHookFlags(lView); |
| executeHooks(lView, tView.contentHooks, tView.contentCheckHooks, checkNoChangesMode, 1 /* AfterContentInitHooksToBeRun */, undefined); |
| setHostBindings(tView, lView); |
| } |
| // We resolve content queries specifically marked as `static` in creation mode. Dynamic |
| // content queries are resolved during change detection (i.e. update mode), after embedded |
| // views are refreshed (see block above). |
| if (creationMode && tView.staticContentQueries) { |
| refreshContentQueries(tView, lView); |
| } |
| refreshChildComponents(tView.components); |
| } |
| /** Sets the host bindings for the current view. */ |
| function setHostBindings(tView, viewData) { |
| var selectedIndex = getSelectedIndex(); |
| try { |
| if (tView.expandoInstructions) { |
| var bindingRootIndex = viewData[BINDING_INDEX] = tView.expandoStartIndex; |
| setBindingRoot(bindingRootIndex); |
| var currentDirectiveIndex = -1; |
| var currentElementIndex = -1; |
| for (var i = 0; i < tView.expandoInstructions.length; i++) { |
| var instruction = tView.expandoInstructions[i]; |
| if (typeof instruction === 'number') { |
| if (instruction <= 0) { |
| // Negative numbers mean that we are starting new EXPANDO block and need to update |
| // the current element and directive index. |
| currentElementIndex = -instruction; |
| setActiveHostElement(currentElementIndex); |
| // Injector block and providers are taken into account. |
| var providerCount = tView.expandoInstructions[++i]; |
| bindingRootIndex += INJECTOR_BLOOM_PARENT_SIZE + providerCount; |
| currentDirectiveIndex = bindingRootIndex; |
| } |
| else { |
| // This is either the injector size (so the binding root can skip over directives |
| // and get to the first set of host bindings on this node) or the host var count |
| // (to get to the next set of host bindings on this node). |
| bindingRootIndex += instruction; |
| } |
| setBindingRoot(bindingRootIndex); |
| } |
| else { |
| // If it's not a number, it's a host binding function that needs to be executed. |
| if (instruction !== null) { |
| viewData[BINDING_INDEX] = bindingRootIndex; |
| var hostCtx = unwrapRNode(viewData[currentDirectiveIndex]); |
| instruction(2 /* Update */, hostCtx, currentElementIndex); |
| // Each directive gets a uniqueId value that is the same for both |
| // create and update calls when the hostBindings function is called. The |
| // directive uniqueId is not set anywhere--it is just incremented between |
| // each hostBindings call and is useful for helping instruction code |
| // uniquely determine which directive is currently active when executed. |
| incrementActiveDirectiveId(); |
| } |
| currentDirectiveIndex++; |
| } |
| } |
| } |
| } |
| finally { |
| setActiveHostElement(selectedIndex); |
| } |
| } |
| /** Refreshes content queries for all directives in the given view. */ |
| function refreshContentQueries(tView, lView) { |
| if (tView.contentQueries != null) { |
| setCurrentQueryIndex(0); |
| for (var i = 0; i < tView.contentQueries.length; i++) { |
| var directiveDefIdx = tView.contentQueries[i]; |
| var directiveDef = tView.data[directiveDefIdx]; |
| ngDevMode && |
| assertDefined(directiveDef.contentQueries, 'contentQueries function should be defined'); |
| directiveDef.contentQueries(2 /* Update */, lView[directiveDefIdx], directiveDefIdx); |
| } |
| } |
| } |
| /** Refreshes child components in the current view. */ |
| function refreshChildComponents(components) { |
| if (components != null) { |
| for (var i = 0; i < components.length; i++) { |
| componentRefresh(components[i]); |
| } |
| } |
| } |
| /** |
| * Creates a native element from a tag name, using a renderer. |
| * @param name the tag name |
| * @param overriddenRenderer Optional A renderer to override the default one |
| * @returns the element created |
| */ |
| function elementCreate(name, overriddenRenderer) { |
| var native; |
| var rendererToUse = overriddenRenderer || getLView()[RENDERER]; |
| var namespace = getNamespace(); |
| if (isProceduralRenderer(rendererToUse)) { |
| native = rendererToUse.createElement(name, namespace); |
| } |
| else { |
| if (namespace === null) { |
| native = rendererToUse.createElement(name); |
| } |
| else { |
| native = rendererToUse.createElementNS(namespace, name); |
| } |
| } |
| return native; |
| } |
| function createLView(parentLView, tView, context, flags, host, tHostNode, rendererFactory, renderer, sanitizer, injector) { |
| var lView = ngDevMode ? cloneToLView(tView.blueprint) : tView.blueprint.slice(); |
| lView[HOST] = host; |
| lView[FLAGS] = flags | 4 /* CreationMode */ | 128 /* Attached */ | 8 /* FirstLViewPass */; |
| resetPreOrderHookFlags(lView); |
| lView[PARENT] = lView[DECLARATION_VIEW] = parentLView; |
| lView[CONTEXT] = context; |
| lView[RENDERER_FACTORY] = (rendererFactory || parentLView && parentLView[RENDERER_FACTORY]); |
| ngDevMode && assertDefined(lView[RENDERER_FACTORY], 'RendererFactory is required'); |
| lView[RENDERER] = (renderer || parentLView && parentLView[RENDERER]); |
| ngDevMode && assertDefined(lView[RENDERER], 'Renderer is required'); |
| lView[SANITIZER] = sanitizer || parentLView && parentLView[SANITIZER] || null; |
| lView[INJECTOR$1] = injector || parentLView && parentLView[INJECTOR$1] || null; |
| lView[T_HOST] = tHostNode; |
| ngDevMode && attachLViewDebug(lView); |
| return lView; |
| } |
| function getOrCreateTNode(tView, tHostNode, index, type, name, attrs) { |
| // Keep this function short, so that the VM will inline it. |
| var adjustedIndex = index + HEADER_OFFSET; |
| var tNode = tView.data[adjustedIndex] || |
| createTNodeAtIndex(tView, tHostNode, adjustedIndex, type, name, attrs, index); |
| setPreviousOrParentTNode(tNode, true); |
| return tNode; |
| } |
| function createTNodeAtIndex(tView, tHostNode, adjustedIndex, type, name, attrs, index) { |
| var previousOrParentTNode = getPreviousOrParentTNode(); |
| var isParent = getIsParent(); |
| var parent = isParent ? previousOrParentTNode : previousOrParentTNode && previousOrParentTNode.parent; |
| // Parents cannot cross component boundaries because components will be used in multiple places, |
| // so it's only set if the view is the same. |
| var parentInSameView = parent && parent !== tHostNode; |
| var tParentNode = parentInSameView ? parent : null; |
| var tNode = tView.data[adjustedIndex] = |
| createTNode(tParentNode, type, adjustedIndex, name, attrs); |
| // The first node is not always the one at index 0, in case of i18n, index 0 can be the |
| // instruction `i18nStart` and the first node has the index 1 or more |
| if (index === 0 || !tView.firstChild) { |
| tView.firstChild = tNode; |
| } |
| // Now link ourselves into the tree. |
| if (previousOrParentTNode) { |
| if (isParent && previousOrParentTNode.child == null && |
| (tNode.parent !== null || previousOrParentTNode.type === 2 /* View */)) { |
| // We are in the same view, which means we are adding content node to the parent view. |
| previousOrParentTNode.child = tNode; |
| } |
| else if (!isParent) { |
| previousOrParentTNode.next = tNode; |
| } |
| } |
| return tNode; |
| } |
| function assignTViewNodeToLView(tView, tParentNode, index, lView) { |
| // View nodes are not stored in data because they can be added / removed at runtime (which |
| // would cause indices to change). Their TNodes are instead stored in tView.node. |
| var tNode = tView.node; |
| if (tNode == null) { |
| ngDevMode && tParentNode && |
| assertNodeOfPossibleTypes(tParentNode, 3 /* Element */, 0 /* Container */); |
| tView.node = tNode = createTNode(tParentNode, // |
| 2 /* View */, index, null, null); |
| } |
| return lView[T_HOST] = tNode; |
| } |
| /** |
| * When elements are created dynamically after a view blueprint is created (e.g. through |
| * i18nApply() or ComponentFactory.create), we need to adjust the blueprint for future |
| * template passes. |
| */ |
| function allocExpando(view, numSlotsToAlloc) { |
| var tView = view[TVIEW]; |
| if (tView.firstTemplatePass) { |
| for (var i = 0; i < numSlotsToAlloc; i++) { |
| tView.blueprint.push(null); |
| tView.data.push(null); |
| view.push(null); |
| } |
| // We should only increment the expando start index if there aren't already directives |
| // and injectors saved in the "expando" section |
| if (!tView.expandoInstructions) { |
| tView.expandoStartIndex += numSlotsToAlloc; |
| } |
| else { |
| // Since we're adding the dynamic nodes into the expando section, we need to let the host |
| // bindings know that they should skip x slots |
| tView.expandoInstructions.push(numSlotsToAlloc); |
| } |
| } |
| } |
| ////////////////////////// |
| //// Render |
| ////////////////////////// |
| /** |
| * Used for creating the LViewNode of a dynamic embedded view, |
| * either through ViewContainerRef.createEmbeddedView() or TemplateRef.createEmbeddedView(). |
| * Such lViewNode will then be renderer with renderEmbeddedTemplate() (see below). |
| */ |
| function createEmbeddedViewAndNode(tView, context, declarationView, queries, injectorIndex) { |
| var _isParent = getIsParent(); |
| var _previousOrParentTNode = getPreviousOrParentTNode(); |
| setPreviousOrParentTNode(null, true); |
| var lView = createLView(declarationView, tView, context, 16 /* CheckAlways */, null, null); |
| lView[DECLARATION_VIEW] = declarationView; |
| if (queries) { |
| lView[QUERIES] = queries.createView(); |
| } |
| assignTViewNodeToLView(tView, null, -1, lView); |
| if (tView.firstTemplatePass) { |
| tView.node.injectorIndex = injectorIndex; |
| } |
| setPreviousOrParentTNode(_previousOrParentTNode, _isParent); |
| return lView; |
| } |
| /** |
| * Used for rendering embedded views (e.g. dynamically created views) |
| * |
| * Dynamically created views must store/retrieve their TViews differently from component views |
| * because their template functions are nested in the template functions of their hosts, creating |
| * closures. If their host template happens to be an embedded template in a loop (e.g. ngFor |
| * inside |
| * an ngFor), the nesting would mean we'd have multiple instances of the template function, so we |
| * can't store TViews in the template function itself (as we do for comps). Instead, we store the |
| * TView for dynamically created views on their host TNode, which only has one instance. |
| */ |
| function renderEmbeddedTemplate(viewToRender, tView, context) { |
| var _isParent = getIsParent(); |
| var _previousOrParentTNode = getPreviousOrParentTNode(); |
| var oldView; |
| if (viewToRender[FLAGS] & 512 /* IsRoot */) { |
| // This is a root view inside the view tree |
| tickRootContext(getRootContext(viewToRender)); |
| } |
| else { |
| // Will become true if the `try` block executes with no errors. |
| var safeToRunHooks = false; |
| try { |
| setPreviousOrParentTNode(null, true); |
| oldView = enterView(viewToRender, viewToRender[T_HOST]); |
| resetPreOrderHookFlags(viewToRender); |
| executeTemplate(viewToRender, tView.template, getRenderFlags(viewToRender), context); |
| // This must be set to false immediately after the first creation run because in an |
| // ngFor loop, all the views will be created together before update mode runs and turns |
| // off firstTemplatePass. If we don't set it here, instances will perform directive |
| // matching, etc again and again. |
| viewToRender[TVIEW].firstTemplatePass = false; |
| refreshDescendantViews(viewToRender); |
| safeToRunHooks = true; |
| } |
| finally { |
| leaveView(oldView, safeToRunHooks); |
| setPreviousOrParentTNode(_previousOrParentTNode, _isParent); |
| } |
| } |
| } |
| function renderComponentOrTemplate(hostView, context, templateFn) { |
| var rendererFactory = hostView[RENDERER_FACTORY]; |
| var oldView = enterView(hostView, hostView[T_HOST]); |
| var normalExecutionPath = !getCheckNoChangesMode(); |
| var creationModeIsActive = isCreationMode(hostView); |
| // Will become true if the `try` block executes with no errors. |
| var safeToRunHooks = false; |
| try { |
| if (normalExecutionPath && !creationModeIsActive && rendererFactory.begin) { |
| rendererFactory.begin(); |
| } |
| if (creationModeIsActive) { |
| // creation mode pass |
| templateFn && executeTemplate(hostView, templateFn, 1 /* Create */, context); |
| refreshDescendantViews(hostView); |
| hostView[FLAGS] &= ~4 /* CreationMode */; |
| } |
| // update mode pass |
| resetPreOrderHookFlags(hostView); |
| templateFn && executeTemplate(hostView, templateFn, 2 /* Update */, context); |
| refreshDescendantViews(hostView); |
| safeToRunHooks = true; |
| } |
| finally { |
| if (normalExecutionPath && !creationModeIsActive && rendererFactory.end) { |
| rendererFactory.end(); |
| } |
| leaveView(oldView, safeToRunHooks); |
| } |
| } |
| function executeTemplate(lView, templateFn, rf, context) { |
| ɵɵnamespaceHTML(); |
| var prevSelectedIndex = getSelectedIndex(); |
| try { |
| setActiveHostElement(null); |
| if (rf & 2 /* Update */) { |
| // When we're updating, have an inherent ɵɵselect(0) so we don't have to generate that |
| // instruction for most update blocks |
| selectInternal(lView, 0); |
| } |
| templateFn(rf, context); |
| } |
| finally { |
| setSelectedIndex(prevSelectedIndex); |
| } |
| } |
| /** |
| * This function returns the default configuration of rendering flags depending on when the |
| * template is in creation mode or update mode. Update block and create block are |
| * always run separately. |
| */ |
| function getRenderFlags(view) { |
| return isCreationMode(view) ? 1 /* Create */ : 2 /* Update */; |
| } |
| ////////////////////////// |
| //// Element |
| ////////////////////////// |
| /** |
| * Appropriately sets `stylingTemplate` on a TNode |
| * |
| * Does not apply styles to DOM nodes |
| * |
| * @param tNode The node whose `stylingTemplate` to set |
| * @param attrs The attribute array source to set the attributes from |
| * @param attrsStartIndex Optional start index to start processing the `attrs` from |
| */ |
| function setNodeStylingTemplate(tView, tNode, attrs, attrsStartIndex) { |
| if (tView.firstTemplatePass && !tNode.stylingTemplate) { |
| var stylingAttrsStartIndex = attrsStylingIndexOf(attrs, attrsStartIndex); |
| if (stylingAttrsStartIndex >= 0) { |
| tNode.stylingTemplate = initializeStaticContext(attrs, stylingAttrsStartIndex); |
| } |
| } |
| } |
| function executeContentQueries(tView, tNode, lView) { |
| if (isContentQueryHost(tNode)) { |
| var start = tNode.directiveStart; |
| var end = tNode.directiveEnd; |
| for (var directiveIndex = start; directiveIndex < end; directiveIndex++) { |
| var def = tView.data[directiveIndex]; |
| if (def.contentQueries) { |
| def.contentQueries(1 /* Create */, lView[directiveIndex], directiveIndex); |
| } |
| } |
| } |
| } |
| /** |
| * Creates directive instances and populates local refs. |
| * |
| * @param localRefs Local refs of the node in question |
| * @param localRefExtractor mapping function that extracts local ref value from TNode |
| */ |
| function createDirectivesAndLocals(tView, lView, localRefs, localRefExtractor) { |
| if (localRefExtractor === void 0) { localRefExtractor = getNativeByTNode; } |
| if (!getBindingsEnabled()) |
| return; |
| var previousOrParentTNode = getPreviousOrParentTNode(); |
| if (tView.firstTemplatePass) { |
| ngDevMode && ngDevMode.firstTemplatePass++; |
| resolveDirectives(tView, lView, findDirectiveMatches(tView, lView, previousOrParentTNode), previousOrParentTNode, localRefs || null); |
| } |
| instantiateAllDirectives(tView, lView, previousOrParentTNode); |
| invokeDirectivesHostBindings(tView, lView, previousOrParentTNode); |
| saveResolvedLocalsInData(lView, previousOrParentTNode, localRefExtractor); |
| setActiveHostElement(null); |
| } |
| /** |
| * Takes a list of local names and indices and pushes the resolved local variable values |
| * to LView in the same order as they are loaded in the template with load(). |
| */ |
| function saveResolvedLocalsInData(viewData, tNode, localRefExtractor) { |
| var localNames = tNode.localNames; |
| if (localNames) { |
| var localIndex = tNode.index + 1; |
| for (var i = 0; i < localNames.length; i += 2) { |
| var index = localNames[i + 1]; |
| var value = index === -1 ? |
| localRefExtractor(tNode, viewData) : |
| viewData[index]; |
| viewData[localIndex++] = value; |
| } |
| } |
| } |
| /** |
| * Gets TView from a template function or creates a new TView |
| * if it doesn't already exist. |
| * |
| * @param def ComponentDef |
| * @returns TView |
| */ |
| function getOrCreateTView(def) { |
| return def.tView || (def.tView = createTView(-1, def.template, def.consts, def.vars, def.directiveDefs, def.pipeDefs, def.viewQuery, def.schemas)); |
| } |
| /** |
| * Creates a TView instance |
| * |
| * @param viewIndex The viewBlockId for inline views, or -1 if it's a component/dynamic |
| * @param templateFn Template function |
| * @param consts The number of nodes, local refs, and pipes in this template |
| * @param directives Registry of directives for this view |
| * @param pipes Registry of pipes for this view |
| * @param viewQuery View queries for this view |
| * @param schemas Schemas for this view |
| */ |
| function createTView(viewIndex, templateFn, consts, vars, directives, pipes, viewQuery, schemas) { |
| ngDevMode && ngDevMode.tView++; |
| var bindingStartIndex = HEADER_OFFSET + consts; |
| // This length does not yet contain host bindings from child directives because at this point, |
| // we don't know which directives are active on this template. As soon as a directive is matched |
| // that has a host binding, we will update the blueprint with that def's hostVars count. |
| var initialViewLength = bindingStartIndex + vars; |
| var blueprint = createViewBlueprint(bindingStartIndex, initialViewLength); |
| return blueprint[TVIEW] = ngDevMode ? |
| new TViewConstructor(viewIndex, // id: number, |
| blueprint, // blueprint: LView, |
| templateFn, // template: ComponentTemplate<{}>|null, |
| viewQuery, // viewQuery: ViewQueriesFunction<{}>|null, |
| null, // node: TViewNode|TElementNode|null, |
| cloneToTViewData(blueprint).fill(null, bindingStartIndex), // data: TData, |
| bindingStartIndex, // bindingStartIndex: number, |
| initialViewLength, // viewQueryStartIndex: number, |
| initialViewLength, // expandoStartIndex: number, |
| null, // expandoInstructions: ExpandoInstructions|null, |
| true, // firstTemplatePass: boolean, |
| false, // staticViewQueries: boolean, |
| false, // staticContentQueries: boolean, |
| null, // preOrderHooks: HookData|null, |
| null, // preOrderCheckHooks: HookData|null, |
| null, // contentHooks: HookData|null, |
| null, // contentCheckHooks: HookData|null, |
| null, // viewHooks: HookData|null, |
| null, // viewCheckHooks: HookData|null, |
| null, // destroyHooks: HookData|null, |
| null, // cleanup: any[]|null, |
| null, // contentQueries: number[]|null, |
| null, // components: number[]|null, |
| typeof directives === 'function' ? |
| directives() : |
| directives, // directiveRegistry: DirectiveDefList|null, |
| typeof pipes === 'function' ? pipes() : pipes, // pipeRegistry: PipeDefList|null, |
| null, // firstChild: TNode|null, |
| schemas) : |
| { |
| id: viewIndex, |
| blueprint: blueprint, |
| template: templateFn, |
| viewQuery: viewQuery, |
| node: null, |
| data: blueprint.slice().fill(null, bindingStartIndex), |
| bindingStartIndex: bindingStartIndex, |
| viewQueryStartIndex: initialViewLength, |
| expandoStartIndex: initialViewLength, |
| expandoInstructions: null, |
| firstTemplatePass: true, |
| staticViewQueries: false, |
| staticContentQueries: false, |
| preOrderHooks: null, |
| preOrderCheckHooks: null, |
| contentHooks: null, |
| contentCheckHooks: null, |
| viewHooks: null, |
| viewCheckHooks: null, |
| destroyHooks: null, |
| cleanup: null, |
| contentQueries: null, |
| components: null, |
| directiveRegistry: typeof directives === 'function' ? directives() : directives, |
| pipeRegistry: typeof pipes === 'function' ? pipes() : pipes, |
| firstChild: null, |
| schemas: schemas, |
| }; |
| } |
| function createViewBlueprint(bindingStartIndex, initialViewLength) { |
| var blueprint = new (ngDevMode ? LViewBlueprint : Array)(initialViewLength) |
| .fill(null, 0, bindingStartIndex) |
| .fill(NO_CHANGE, bindingStartIndex); |
| blueprint[BINDING_INDEX] = bindingStartIndex; |
| return blueprint; |
| } |
| function createError(text, token) { |
| return new Error("Renderer: " + text + " [" + stringifyForError(token) + "]"); |
| } |
| /** |
| * Locates the host native element, used for bootstrapping existing nodes into rendering pipeline. |
| * |
| * @param elementOrSelector Render element or CSS selector to locate the element. |
| */ |
| function locateHostElement(factory, elementOrSelector) { |
| var defaultRenderer = factory.createRenderer(null, null); |
| var rNode = typeof elementOrSelector === 'string' ? |
| (isProceduralRenderer(defaultRenderer) ? |
| defaultRenderer.selectRootElement(elementOrSelector) : |
| defaultRenderer.querySelector(elementOrSelector)) : |
| elementOrSelector; |
| if (ngDevMode && !rNode) { |
| if (typeof elementOrSelector === 'string') { |
| throw createError('Host node with selector not found:', elementOrSelector); |
| } |
| else { |
| throw createError('Host node is required:', elementOrSelector); |
| } |
| } |
| return rNode; |
| } |
| /** |
| * Saves context for this cleanup function in LView.cleanupInstances. |
| * |
| * On the first template pass, saves in TView: |
| * - Cleanup function |
| * - Index of context we just saved in LView.cleanupInstances |
| */ |
| function storeCleanupWithContext(lView, context, cleanupFn) { |
| var lCleanup = getCleanup(lView); |
| lCleanup.push(context); |
| if (lView[TVIEW].firstTemplatePass) { |
| getTViewCleanup(lView).push(cleanupFn, lCleanup.length - 1); |
| } |
| } |
| /** |
| * Saves the cleanup function itself in LView.cleanupInstances. |
| * |
| * This is necessary for functions that are wrapped with their contexts, like in renderer2 |
| * listeners. |
| * |
| * On the first template pass, the index of the cleanup function is saved in TView. |
| */ |
| function storeCleanupFn(view, cleanupFn) { |
| getCleanup(view).push(cleanupFn); |
| if (view[TVIEW].firstTemplatePass) { |
| getTViewCleanup(view).push(view[CLEANUP].length - 1, null); |
| } |
| } |
| /** |
| * Constructs a TNode object from the arguments. |
| * |
| * @param type The type of the node |
| * @param adjustedIndex The index of the TNode in TView.data, adjusted for HEADER_OFFSET |
| * @param tagName The tag name of the node |
| * @param attrs The attributes defined on this node |
| * @param tViews Any TViews attached to this node |
| * @returns the TNode object |
| */ |
| function createTNode(tParent, type, adjustedIndex, tagName, attrs) { |
| ngDevMode && ngDevMode.tNode++; |
| return { |
| type: type, |
| index: adjustedIndex, |
| injectorIndex: tParent ? tParent.injectorIndex : -1, |
| directiveStart: -1, |
| directiveEnd: -1, |
| propertyMetadataStartIndex: -1, |
| propertyMetadataEndIndex: -1, |
| flags: 0, |
| providerIndexes: 0, |
| tagName: tagName, |
| attrs: attrs, |
| localNames: null, |
| initialInputs: undefined, |
| inputs: undefined, |
| outputs: undefined, |
| tViews: null, |
| next: null, |
| projectionNext: null, |
| child: null, |
| parent: tParent, |
| stylingTemplate: null, |
| projection: null, |
| onElementCreationFns: null, |
| // TODO (matsko): rename this to `styles` once the old styling impl is gone |
| newStyles: null, |
| // TODO (matsko): rename this to `classes` once the old styling impl is gone |
| newClasses: null, |
| }; |
| } |
| /** |
| * Consolidates all inputs or outputs of all directives on this logical node. |
| * |
| * @param tNode |
| * @param direction whether to consider inputs or outputs |
| * @returns PropertyAliases|null aggregate of all properties if any, `null` otherwise |
| */ |
| function generatePropertyAliases(tNode, direction) { |
| var tView = getLView()[TVIEW]; |
| var propStore = null; |
| var start = tNode.directiveStart; |
| var end = tNode.directiveEnd; |
| if (end > start) { |
| var isInput = direction === 0 /* Input */; |
| var defs = tView.data; |
| for (var i = start; i < end; i++) { |
| var directiveDef = defs[i]; |
| var propertyAliasMap = isInput ? directiveDef.inputs : directiveDef.outputs; |
| for (var publicName in propertyAliasMap) { |
| if (propertyAliasMap.hasOwnProperty(publicName)) { |
| propStore = propStore || {}; |
| var internalName = propertyAliasMap[publicName]; |
| var hasProperty = propStore.hasOwnProperty(publicName); |
| hasProperty ? propStore[publicName].push(i, publicName, internalName) : |
| (propStore[publicName] = [i, publicName, internalName]); |
| } |
| } |
| } |
| } |
| return propStore; |
| } |
| /** |
| * Mapping between attributes names that don't correspond to their element property names. |
| * Note: this mapping has to be kept in sync with the equally named mapping in the template |
| * type-checking machinery of ngtsc. |
| */ |
| var ATTR_TO_PROP = { |
| 'class': 'className', |
| 'for': 'htmlFor', |
| 'formaction': 'formAction', |
| 'innerHtml': 'innerHTML', |
| 'readonly': 'readOnly', |
| 'tabindex': 'tabIndex', |
| }; |
| function elementPropertyInternal(index, propName, value, sanitizer, nativeOnly, loadRendererFn) { |
| ngDevMode && assertNotSame(value, NO_CHANGE, 'Incoming value should never be NO_CHANGE.'); |
| var lView = getLView(); |
| var element = getNativeByIndex(index, lView); |
| var tNode = getTNode(index, lView); |
| var inputData; |
| var dataValue; |
| if (!nativeOnly && (inputData = initializeTNodeInputs(tNode)) && |
| (dataValue = inputData[propName])) { |
| setInputsForProperty(lView, dataValue, value); |
| if (isComponent(tNode)) |
| markDirtyIfOnPush(lView, index + HEADER_OFFSET); |
| if (ngDevMode) { |
| if (tNode.type === 3 /* Element */ || tNode.type === 0 /* Container */) { |
| /** |
| * dataValue is an array containing runtime input or output names for the directives: |
| * i+0: directive instance index |
| * i+1: publicName |
| * i+2: privateName |
| * |
| * e.g. [0, 'change', 'change-minified'] |
| * we want to set the reflected property with the privateName: dataValue[i+2] |
| */ |
| for (var i = 0; i < dataValue.length; i += 3) { |
| setNgReflectProperty(lView, element, tNode.type, dataValue[i + 2], value); |
| } |
| } |
| } |
| } |
| else if (tNode.type === 3 /* Element */) { |
| propName = ATTR_TO_PROP[propName] || propName; |
| if (ngDevMode) { |
| validateAgainstEventProperties(propName); |
| validateAgainstUnknownProperties(lView, element, propName, tNode); |
| ngDevMode.rendererSetProperty++; |
| } |
| savePropertyDebugData(tNode, lView, propName, lView[TVIEW].data, nativeOnly); |
| var renderer = loadRendererFn ? loadRendererFn(tNode, lView) : lView[RENDERER]; |
| // It is assumed that the sanitizer is only added when the compiler determines that the |
| // property |
| // is risky, so sanitization can be done without further checks. |
| value = sanitizer != null ? sanitizer(value, tNode.tagName || '', propName) : value; |
| if (isProceduralRenderer(renderer)) { |
| renderer.setProperty(element, propName, value); |
| } |
| else if (!isAnimationProp(propName)) { |
| element.setProperty ? element.setProperty(propName, value) : |
| element[propName] = value; |
| } |
| } |
| else if (tNode.type === 0 /* Container */) { |
| // If the node is a container and the property didn't |
| // match any of the inputs or schemas we should throw. |
| if (ngDevMode && !matchingSchemas(lView, tNode.tagName)) { |
| throw createUnknownPropertyError(propName, tNode); |
| } |
| } |
| } |
| /** If node is an OnPush component, marks its LView dirty. */ |
| function markDirtyIfOnPush(lView, viewIndex) { |
| ngDevMode && assertLView(lView); |
| var childComponentLView = getComponentViewByIndex(viewIndex, lView); |
| if (!(childComponentLView[FLAGS] & 16 /* CheckAlways */)) { |
| childComponentLView[FLAGS] |= 64 /* Dirty */; |
| } |
| } |
| function setNgReflectProperty(lView, element, type, attrName, value) { |
| var _a; |
| var renderer = lView[RENDERER]; |
| attrName = normalizeDebugBindingName(attrName); |
| var debugValue = normalizeDebugBindingValue(value); |
| if (type === 3 /* Element */) { |
| if (value == null) { |
| isProceduralRenderer(renderer) ? renderer.removeAttribute(element, attrName) : |
| element.removeAttribute(attrName); |
| } |
| else { |
| isProceduralRenderer(renderer) ? |
| renderer.setAttribute(element, attrName, debugValue) : |
| element.setAttribute(attrName, debugValue); |
| } |
| } |
| else { |
| var textContent = "bindings=" + JSON.stringify((_a = {}, _a[attrName] = debugValue, _a), null, 2); |
| if (isProceduralRenderer(renderer)) { |
| renderer.setValue(element, textContent); |
| } |
| else { |
| element.textContent = textContent; |
| } |
| } |
| } |
| function validateAgainstUnknownProperties(hostView, element, propName, tNode) { |
| // If the tag matches any of the schemas we shouldn't throw. |
| if (matchingSchemas(hostView, tNode.tagName)) { |
| return; |
| } |
| // If prop is not a known property of the HTML element... |
| if (!(propName in element) && |
| // and we are in a browser context... (web worker nodes should be skipped) |
| typeof Node === 'function' && element instanceof Node && |
| // and isn't a synthetic animation property... |
| propName[0] !== ANIMATION_PROP_PREFIX) { |
| // ... it is probably a user error and we should throw. |
| throw createUnknownPropertyError(propName, tNode); |
| } |
| } |
| function matchingSchemas(hostView, tagName) { |
| var schemas = hostView[TVIEW].schemas; |
| if (schemas !== null) { |
| for (var i = 0; i < schemas.length; i++) { |
| var schema = schemas[i]; |
| if (schema === NO_ERRORS_SCHEMA || |
| schema === CUSTOM_ELEMENTS_SCHEMA && tagName && tagName.indexOf('-') > -1) { |
| return true; |
| } |
| } |
| } |
| return false; |
| } |
| /** |
| * Stores debugging data for this property binding on first template pass. |
| * This enables features like DebugElement.properties. |
| */ |
| function savePropertyDebugData(tNode, lView, propName, tData, nativeOnly) { |
| var lastBindingIndex = lView[BINDING_INDEX] - 1; |
| // Bind/interpolation functions save binding metadata in the last binding index, |
| // but leave the property name blank. If the interpolation delimiter is at the 0 |
| // index, we know that this is our first pass and the property name still needs to |
| // be set. |
| var bindingMetadata = tData[lastBindingIndex]; |
| if (bindingMetadata[0] == INTERPOLATION_DELIMITER) { |
| tData[lastBindingIndex] = propName + bindingMetadata; |
| // We don't want to store indices for host bindings because they are stored in a |
| // different part of LView (the expando section). |
| if (!nativeOnly) { |
| if (tNode.propertyMetadataStartIndex == -1) { |
| tNode.propertyMetadataStartIndex = lastBindingIndex; |
| } |
| tNode.propertyMetadataEndIndex = lastBindingIndex + 1; |
| } |
| } |
| } |
| /** |
| * Creates an error that should be thrown when encountering an unknown property on an element. |
| * @param propName Name of the invalid property. |
| * @param tNode Node on which we encountered the error. |
| */ |
| function createUnknownPropertyError(propName, tNode) { |
| return new Error("Template error: Can't bind to '" + propName + "' since it isn't a known property of '" + tNode.tagName + "'."); |
| } |
| /** |
| * Instantiate a root component. |
| */ |
| function instantiateRootComponent(tView, viewData, def) { |
| var rootTNode = getPreviousOrParentTNode(); |
| if (tView.firstTemplatePass) { |
| if (def.providersResolver) |
| def.providersResolver(def); |
| generateExpandoInstructionBlock(tView, rootTNode, 1); |
| baseResolveDirective(tView, viewData, def, def.factory); |
| } |
| var directive = getNodeInjectable(tView.data, viewData, viewData.length - 1, rootTNode); |
| postProcessBaseDirective(viewData, rootTNode, directive); |
| return directive; |
| } |
| /** |
| * Resolve the matched directives on a node. |
| */ |
| function resolveDirectives(tView, viewData, directives, tNode, localRefs) { |
| // Please make sure to have explicit type for `exportsMap`. Inferred type triggers bug in |
| // tsickle. |
| ngDevMode && assertEqual(tView.firstTemplatePass, true, 'should run on first template pass only'); |
| var exportsMap = localRefs ? { '': -1 } : null; |
| if (directives) { |
| initNodeFlags(tNode, tView.data.length, directives.length); |
| // When the same token is provided by several directives on the same node, some rules apply in |
| // the viewEngine: |
| // - viewProviders have priority over providers |
| // - the last directive in NgModule.declarations has priority over the previous one |
| // So to match these rules, the order in which providers are added in the arrays is very |
| // important. |
| for (var i = 0; i < directives.length; i++) { |
| var def = directives[i]; |
| if (def.providersResolver) |
| def.providersResolver(def); |
| } |
| generateExpandoInstructionBlock(tView, tNode, directives.length); |
| var initialPreOrderHooksLength = (tView.preOrderHooks && tView.preOrderHooks.length) || 0; |
| var initialPreOrderCheckHooksLength = (tView.preOrderCheckHooks && tView.preOrderCheckHooks.length) || 0; |
| var nodeIndex = tNode.index - HEADER_OFFSET; |
| for (var i = 0; i < directives.length; i++) { |
| var def = directives[i]; |
| var directiveDefIdx = tView.data.length; |
| baseResolveDirective(tView, viewData, def, def.factory); |
| saveNameToExportMap(tView.data.length - 1, def, exportsMap); |
| // Init hooks are queued now so ngOnInit is called in host components before |
| // any projected components. |
| registerPreOrderHooks(directiveDefIdx, def, tView, nodeIndex, initialPreOrderHooksLength, initialPreOrderCheckHooksLength); |
| } |
| } |
| if (exportsMap) |
| cacheMatchingLocalNames(tNode, localRefs, exportsMap); |
| } |
| /** |
| * Instantiate all the directives that were previously resolved on the current node. |
| */ |
| function instantiateAllDirectives(tView, lView, tNode) { |
| var start = tNode.directiveStart; |
| var end = tNode.directiveEnd; |
| if (!tView.firstTemplatePass && start < end) { |
| getOrCreateNodeInjectorForNode(tNode, lView); |
| } |
| for (var i = start; i < end; i++) { |
| var def = tView.data[i]; |
| if (isComponentDef(def)) { |
| addComponentLogic(lView, tNode, def); |
| } |
| var directive = getNodeInjectable(tView.data, lView, i, tNode); |
| postProcessDirective(lView, directive, def, i); |
| } |
| } |
| function invokeDirectivesHostBindings(tView, viewData, tNode) { |
| var start = tNode.directiveStart; |
| var end = tNode.directiveEnd; |
| var expando = tView.expandoInstructions; |
| var firstTemplatePass = tView.firstTemplatePass; |
| var elementIndex = tNode.index - HEADER_OFFSET; |
| var selectedIndex = getSelectedIndex(); |
| try { |
| setActiveHostElement(elementIndex); |
| for (var i = start; i < end; i++) { |
| var def = tView.data[i]; |
| var directive = viewData[i]; |
| if (def.hostBindings) { |
| invokeHostBindingsInCreationMode(def, expando, directive, tNode, firstTemplatePass); |
| // Each directive gets a uniqueId value that is the same for both |
| // create and update calls when the hostBindings function is called. The |
| // directive uniqueId is not set anywhere--it is just incremented between |
| // each hostBindings call and is useful for helping instruction code |
| // uniquely determine which directive is currently active when executed. |
| incrementActiveDirectiveId(); |
| } |
| else if (firstTemplatePass) { |
| expando.push(null); |
| } |
| } |
| } |
| finally { |
| setActiveHostElement(selectedIndex); |
| } |
| } |
| function invokeHostBindingsInCreationMode(def, expando, directive, tNode, firstTemplatePass) { |
| var previousExpandoLength = expando.length; |
| setCurrentDirectiveDef(def); |
| var elementIndex = tNode.index - HEADER_OFFSET; |
| def.hostBindings(1 /* Create */, directive, elementIndex); |
| setCurrentDirectiveDef(null); |
| // `hostBindings` function may or may not contain `allocHostVars` call |
| // (e.g. it may not if it only contains host listeners), so we need to check whether |
| // `expandoInstructions` has changed and if not - we still push `hostBindings` to |
| // expando block, to make sure we execute it for DI cycle |
| if (previousExpandoLength === expando.length && firstTemplatePass) { |
| expando.push(def.hostBindings); |
| } |
| } |
| /** |
| * Generates a new block in TView.expandoInstructions for this node. |
| * |
| * Each expando block starts with the element index (turned negative so we can distinguish |
| * it from the hostVar count) and the directive count. See more in VIEW_DATA.md. |
| */ |
| function generateExpandoInstructionBlock(tView, tNode, directiveCount) { |
| ngDevMode && assertEqual(tView.firstTemplatePass, true, 'Expando block should only be generated on first template pass.'); |
| var elementIndex = -(tNode.index - HEADER_OFFSET); |
| var providerStartIndex = tNode.providerIndexes & 65535 /* ProvidersStartIndexMask */; |
| var providerCount = tView.data.length - providerStartIndex; |
| (tView.expandoInstructions || (tView.expandoInstructions = [])).push(elementIndex, providerCount, directiveCount); |
| } |
| /** |
| * Process a directive on the current node after its creation. |
| */ |
| function postProcessDirective(viewData, directive, def, directiveDefIdx) { |
| var previousOrParentTNode = getPreviousOrParentTNode(); |
| postProcessBaseDirective(viewData, previousOrParentTNode, directive); |
| ngDevMode && assertDefined(previousOrParentTNode, 'previousOrParentTNode'); |
| if (previousOrParentTNode && previousOrParentTNode.attrs) { |
| setInputsFromAttrs(directiveDefIdx, directive, def, previousOrParentTNode); |
| } |
| if (viewData[TVIEW].firstTemplatePass && def.contentQueries) { |
| previousOrParentTNode.flags |= 4 /* hasContentQuery */; |
| } |
| if (isComponentDef(def)) { |
| var componentView = getComponentViewByIndex(previousOrParentTNode.index, viewData); |
| componentView[CONTEXT] = directive; |
| } |
| } |
| /** |
| * A lighter version of postProcessDirective() that is used for the root component. |
| */ |
| function postProcessBaseDirective(lView, previousOrParentTNode, directive) { |
| var native = getNativeByTNode(previousOrParentTNode, lView); |
| ngDevMode && assertEqual(lView[BINDING_INDEX], lView[TVIEW].bindingStartIndex, 'directives should be created before any bindings'); |
| ngDevMode && assertPreviousIsParent(getIsParent()); |
| attachPatchData(directive, lView); |
| if (native) { |
| attachPatchData(native, lView); |
| } |
| } |
| /** |
| * Matches the current node against all available selectors. |
| * If a component is matched (at most one), it is returned in first position in the array. |
| */ |
| function findDirectiveMatches(tView, viewData, tNode) { |
| ngDevMode && assertEqual(tView.firstTemplatePass, true, 'should run on first template pass only'); |
| var registry = tView.directiveRegistry; |
| var matches = null; |
| if (registry) { |
| for (var i = 0; i < registry.length; i++) { |
| var def = registry[i]; |
| if (isNodeMatchingSelectorList(tNode, def.selectors, /* isProjectionMode */ false)) { |
| matches || (matches = ngDevMode ? new MatchesArray() : []); |
| diPublicInInjector(getOrCreateNodeInjectorForNode(getPreviousOrParentTNode(), viewData), viewData, def.type); |
| if (isComponentDef(def)) { |
| if (tNode.flags & 1 /* isComponent */) |
| throwMultipleComponentError(tNode); |
| tNode.flags = 1 /* isComponent */; |
| // The component is always stored first with directives after. |
| matches.unshift(def); |
| } |
| else { |
| matches.push(def); |
| } |
| } |
| } |
| } |
| return matches; |
| } |
| /** Stores index of component's host element so it will be queued for view refresh during CD. */ |
| function queueComponentIndexForCheck(previousOrParentTNode) { |
| var tView = getLView()[TVIEW]; |
| ngDevMode && |
| assertEqual(tView.firstTemplatePass, true, 'Should only be called in first template pass.'); |
| (tView.components || (tView.components = ngDevMode ? new TViewComponents() : [])).push(previousOrParentTNode.index); |
| } |
| /** Caches local names and their matching directive indices for query and template lookups. */ |
| function cacheMatchingLocalNames(tNode, localRefs, exportsMap) { |
| if (localRefs) { |
| var localNames = tNode.localNames = |
| ngDevMode ? new TNodeLocalNames() : []; |
| // Local names must be stored in tNode in the same order that localRefs are defined |
| // in the template to ensure the data is loaded in the same slots as their refs |
| // in the template (for template queries). |
| for (var i = 0; i < localRefs.length; i += 2) { |
| var index = exportsMap[localRefs[i + 1]]; |
| if (index == null) |
| throw new Error("Export of name '" + localRefs[i + 1] + "' not found!"); |
| localNames.push(localRefs[i], index); |
| } |
| } |
| } |
| /** |
| * Builds up an export map as directives are created, so local refs can be quickly mapped |
| * to their directive instances. |
| */ |
| function saveNameToExportMap(index, def, exportsMap) { |
| if (exportsMap) { |
| if (def.exportAs) { |
| for (var i = 0; i < def.exportAs.length; i++) { |
| exportsMap[def.exportAs[i]] = index; |
| } |
| } |
| if (def.template) |
| exportsMap[''] = index; |
| } |
| } |
| /** |
| * Initializes the flags on the current node, setting all indices to the initial index, |
| * the directive count to 0, and adding the isComponent flag. |
| * @param index the initial index |
| */ |
| function initNodeFlags(tNode, index, numberOfDirectives) { |
| var flags = tNode.flags; |
| ngDevMode && assertEqual(flags === 0 || flags === 1 /* isComponent */, true, 'expected node flags to not be initialized'); |
| ngDevMode && assertNotEqual(numberOfDirectives, tNode.directiveEnd - tNode.directiveStart, 'Reached the max number of directives'); |
| // When the first directive is created on a node, save the index |
| tNode.flags = flags & 1 /* isComponent */; |
| tNode.directiveStart = index; |
| tNode.directiveEnd = index + numberOfDirectives; |
| tNode.providerIndexes = index; |
| } |
| function baseResolveDirective(tView, viewData, def, directiveFactory) { |
| tView.data.push(def); |
| var nodeInjectorFactory = new NodeInjectorFactory(directiveFactory, isComponentDef(def), null); |
| tView.blueprint.push(nodeInjectorFactory); |
| viewData.push(nodeInjectorFactory); |
| } |
| function addComponentLogic(lView, previousOrParentTNode, def) { |
| var native = getNativeByTNode(previousOrParentTNode, lView); |
| var tView = getOrCreateTView(def); |
| // Only component views should be added to the view tree directly. Embedded views are |
| // accessed through their containers because they may be removed / re-added later. |
| var rendererFactory = lView[RENDERER_FACTORY]; |
| var componentView = addToViewTree(lView, createLView(lView, tView, null, def.onPush ? 64 /* Dirty */ : 16 /* CheckAlways */, lView[previousOrParentTNode.index], previousOrParentTNode, rendererFactory, rendererFactory.createRenderer(native, def))); |
| componentView[T_HOST] = previousOrParentTNode; |
| // Component view will always be created before any injected LContainers, |
| // so this is a regular element, wrap it with the component view |
| lView[previousOrParentTNode.index] = componentView; |
| if (lView[TVIEW].firstTemplatePass) { |
| queueComponentIndexForCheck(previousOrParentTNode); |
| } |
| } |
| function elementAttributeInternal(index, name, value, lView, sanitizer, namespace) { |
| ngDevMode && assertNotSame(value, NO_CHANGE, 'Incoming value should never be NO_CHANGE.'); |
| ngDevMode && validateAgainstEventAttributes(name); |
| var element = getNativeByIndex(index, lView); |
| var renderer = lView[RENDERER]; |
| if (value == null) { |
| ngDevMode && ngDevMode.rendererRemoveAttribute++; |
| isProceduralRenderer(renderer) ? renderer.removeAttribute(element, name, namespace) : |
| element.removeAttribute(name); |
| } |
| else { |
| ngDevMode && ngDevMode.rendererSetAttribute++; |
| var tNode = getTNode(index, lView); |
| var strValue = sanitizer == null ? renderStringify(value) : sanitizer(value, tNode.tagName || '', name); |
| if (isProceduralRenderer(renderer)) { |
| renderer.setAttribute(element, name, strValue, namespace); |
| } |
| else { |
| namespace ? element.setAttributeNS(namespace, name, strValue) : |
| element.setAttribute(name, strValue); |
| } |
| } |
| } |
| /** |
| * Sets initial input properties on directive instances from attribute data |
| * |
| * @param directiveIndex Index of the directive in directives array |
| * @param instance Instance of the directive on which to set the initial inputs |
| * @param def The directive def that contains the list of inputs |
| * @param tNode The static data for this node |
| */ |
| function setInputsFromAttrs(directiveIndex, instance, def, tNode) { |
| var initialInputData = tNode.initialInputs; |
| if (initialInputData === undefined || directiveIndex >= initialInputData.length) { |
| initialInputData = generateInitialInputs(directiveIndex, def.inputs, tNode); |
| } |
| var initialInputs = initialInputData[directiveIndex]; |
| if (initialInputs) { |
| var setInput = def.setInput; |
| for (var i = 0; i < initialInputs.length;) { |
| var publicName = initialInputs[i++]; |
| var privateName = initialInputs[i++]; |
| var value = initialInputs[i++]; |
| if (setInput) { |
| def.setInput(instance, value, publicName, privateName); |
| } |
| else { |
| instance[privateName] = value; |
| } |
| if (ngDevMode) { |
| var lView = getLView(); |
| var nativeElement = getNativeByTNode(tNode, lView); |
| setNgReflectProperty(lView, nativeElement, tNode.type, privateName, value); |
| } |
| } |
| } |
| } |
| /** |
| * Generates initialInputData for a node and stores it in the template's static storage |
| * so subsequent template invocations don't have to recalculate it. |
| * |
| * initialInputData is an array containing values that need to be set as input properties |
| * for directives on this node, but only once on creation. We need this array to support |
| * the case where you set an @Input property of a directive using attribute-like syntax. |
| * e.g. if you have a `name` @Input, you can set it once like this: |
| * |
| * <my-component name="Bess"></my-component> |
| * |
| * @param directiveIndex Index to store the initial input data |
| * @param inputs The list of inputs from the directive def |
| * @param tNode The static data on this node |
| */ |
| function generateInitialInputs(directiveIndex, inputs, tNode) { |
| var initialInputData = tNode.initialInputs || (tNode.initialInputs = ngDevMode ? new TNodeInitialInputs() : []); |
| // Ensure that we don't create sparse arrays |
| for (var i_1 = initialInputData.length; i_1 <= directiveIndex; i_1++) { |
| initialInputData.push(null); |
| } |
| var attrs = tNode.attrs; |
| var i = 0; |
| while (i < attrs.length) { |
| var attrName = attrs[i]; |
| if (attrName === 0 /* NamespaceURI */) { |
| // We do not allow inputs on namespaced attributes. |
| i += 4; |
| continue; |
| } |
| else if (attrName === 5 /* ProjectAs */) { |
| // Skip over the `ngProjectAs` value. |
| i += 2; |
| continue; |
| } |
| // If we hit any other attribute markers, we're done anyway. None of those are valid inputs. |
| if (typeof attrName === 'number') |
| break; |
| var minifiedInputName = inputs[attrName]; |
| var attrValue = attrs[i + 1]; |
| if (minifiedInputName !== undefined) { |
| var inputsToStore = initialInputData[directiveIndex] || |
| (initialInputData[directiveIndex] = ngDevMode ? new TNodeInitialData() : []); |
| inputsToStore.push(attrName, minifiedInputName, attrValue); |
| } |
| i += 2; |
| } |
| return initialInputData; |
| } |
| ////////////////////////// |
| //// ViewContainer & View |
| ////////////////////////// |
| // Not sure why I need to do `any` here but TS complains later. |
| var LContainerArray = ngDevMode && createNamedArrayType('LContainer'); |
| /** |
| * Creates a LContainer, either from a container instruction, or for a ViewContainerRef. |
| * |
| * @param hostNative The host element for the LContainer |
| * @param hostTNode The host TNode for the LContainer |
| * @param currentView The parent view of the LContainer |
| * @param native The native comment element |
| * @param isForViewContainerRef Optional a flag indicating the ViewContainerRef case |
| * @returns LContainer |
| */ |
| function createLContainer(hostNative, currentView, native, tNode, isForViewContainerRef) { |
| ngDevMode && assertDomNode(native); |
| ngDevMode && assertLView(currentView); |
| // https://jsperf.com/array-literal-vs-new-array-really |
| var lContainer = new (ngDevMode ? LContainerArray : Array)(hostNative, // host native |
| true, // Boolean `true` in this position signifies that this is an `LContainer` |
| isForViewContainerRef ? -1 : 0, // active index |
| currentView, // parent |
| null, // next |
| null, // queries |
| tNode, // t_host |
| native, // native, |
| null); |
| ngDevMode && attachLContainerDebug(lContainer); |
| return lContainer; |
| } |
| /** |
| * Goes over dynamic embedded views (ones created through ViewContainerRef APIs) and refreshes |
| * them |
| * by executing an associated template function. |
| */ |
| function refreshDynamicEmbeddedViews(lView) { |
| for (var current = lView[CHILD_HEAD]; current !== null; current = current[NEXT]) { |
| // Note: current can be an LView or an LContainer instance, but here we are only interested |
| // in LContainer. We can tell it's an LContainer because its length is less than the LView |
| // header. |
| if (current[ACTIVE_INDEX] === -1 && isLContainer(current)) { |
| for (var i = CONTAINER_HEADER_OFFSET; i < current.length; i++) { |
| var dynamicViewData = current[i]; |
| // The directives and pipes are not needed here as an existing view is only being |
| // refreshed. |
| ngDevMode && assertDefined(dynamicViewData[TVIEW], 'TView must be allocated'); |
| renderEmbeddedTemplate(dynamicViewData, dynamicViewData[TVIEW], dynamicViewData[CONTEXT]); |
| } |
| } |
| } |
| } |
| ///////////// |
| /** |
| * Refreshes components by entering the component view and processing its bindings, queries, etc. |
| * |
| * @param adjustedElementIndex Element index in LView[] (adjusted for HEADER_OFFSET) |
| */ |
| function componentRefresh(adjustedElementIndex) { |
| var lView = getLView(); |
| ngDevMode && assertDataInRange(lView, adjustedElementIndex); |
| var hostView = getComponentViewByIndex(adjustedElementIndex, lView); |
| ngDevMode && assertNodeType(lView[TVIEW].data[adjustedElementIndex], 3 /* Element */); |
| // Only components in creation mode, attached CheckAlways |
| // components or attached, dirty OnPush components should be checked |
| if ((viewAttachedToChangeDetector(hostView) || isCreationMode(lView)) && |
| hostView[FLAGS] & (16 /* CheckAlways */ | 64 /* Dirty */)) { |
| syncViewWithBlueprint(hostView); |
| checkView(hostView, hostView[CONTEXT]); |
| } |
| } |
| /** |
| * Syncs an LView instance with its blueprint if they have gotten out of sync. |
| * |
| * Typically, blueprints and their view instances should always be in sync, so the loop here |
| * will be skipped. However, consider this case of two components side-by-side: |
| * |
| * App template: |
| * ``` |
| * <comp></comp> |
| * <comp></comp> |
| * ``` |
| * |
| * The following will happen: |
| * 1. App template begins processing. |
| * 2. First <comp> is matched as a component and its LView is created. |
| * 3. Second <comp> is matched as a component and its LView is created. |
| * 4. App template completes processing, so it's time to check child templates. |
| * 5. First <comp> template is checked. It has a directive, so its def is pushed to blueprint. |
| * 6. Second <comp> template is checked. Its blueprint has been updated by the first |
| * <comp> template, but its LView was created before this update, so it is out of sync. |
| * |
| * Note that embedded views inside ngFor loops will never be out of sync because these views |
| * are processed as soon as they are created. |
| * |
| * @param componentView The view to sync |
| */ |
| function syncViewWithBlueprint(componentView) { |
| var componentTView = componentView[TVIEW]; |
| for (var i = componentView.length; i < componentTView.blueprint.length; i++) { |
| componentView[i] = componentTView.blueprint[i]; |
| } |
| } |
| /** |
| * Adds LView or LContainer to the end of the current view tree. |
| * |
| * This structure will be used to traverse through nested views to remove listeners |
| * and call onDestroy callbacks. |
| * |
| * @param lView The view where LView or LContainer should be added |
| * @param adjustedHostIndex Index of the view's host node in LView[], adjusted for header |
| * @param lViewOrLContainer The LView or LContainer to add to the view tree |
| * @returns The state passed in |
| */ |
| function addToViewTree(lView, lViewOrLContainer) { |
| // TODO(benlesh/misko): This implementation is incorrect, because it always adds the LContainer |
| // to |
| // the end of the queue, which means if the developer retrieves the LContainers from RNodes out |
| // of |
| // order, the change detection will run out of order, as the act of retrieving the the |
| // LContainer |
| // from the RNode is what adds it to the queue. |
| if (lView[CHILD_HEAD]) { |
| lView[CHILD_TAIL][NEXT] = lViewOrLContainer; |
| } |
| else { |
| lView[CHILD_HEAD] = lViewOrLContainer; |
| } |
| lView[CHILD_TAIL] = lViewOrLContainer; |
| return lViewOrLContainer; |
| } |
| /////////////////////////////// |
| //// Change detection |
| /////////////////////////////// |
| /** |
| * Marks current view and all ancestors dirty. |
| * |
| * Returns the root view because it is found as a byproduct of marking the view tree |
| * dirty, and can be used by methods that consume markViewDirty() to easily schedule |
| * change detection. Otherwise, such methods would need to traverse up the view tree |
| * an additional time to get the root view and schedule a tick on it. |
| * |
| * @param lView The starting LView to mark dirty |
| * @returns the root LView |
| */ |
| function markViewDirty(lView) { |
| while (lView) { |
| lView[FLAGS] |= 64 /* Dirty */; |
| var parent_1 = getLViewParent(lView); |
| // Stop traversing up as soon as you find a root view that wasn't attached to any container |
| if (isRootView(lView) && !parent_1) { |
| return lView; |
| } |
| // continue otherwise |
| lView = parent_1; |
| } |
| return null; |
| } |
| /** |
| * Used to schedule change detection on the whole application. |
| * |
| * Unlike `tick`, `scheduleTick` coalesces multiple calls into one change detection run. |
| * It is usually called indirectly by calling `markDirty` when the view needs to be |
| * re-rendered. |
| * |
| * Typically `scheduleTick` uses `requestAnimationFrame` to coalesce multiple |
| * `scheduleTick` requests. The scheduling function can be overridden in |
| * `renderComponent`'s `scheduler` option. |
| */ |
| function scheduleTick(rootContext, flags) { |
| var nothingScheduled = rootContext.flags === 0 /* Empty */; |
| rootContext.flags |= flags; |
| if (nothingScheduled && rootContext.clean == _CLEAN_PROMISE) { |
| var res_1; |
| rootContext.clean = new Promise(function (r) { return res_1 = r; }); |
| rootContext.scheduler(function () { |
| if (rootContext.flags & 1 /* DetectChanges */) { |
| rootContext.flags &= ~1 /* DetectChanges */; |
| tickRootContext(rootContext); |
| } |
| if (rootContext.flags & 2 /* FlushPlayers */) { |
| rootContext.flags &= ~2 /* FlushPlayers */; |
| var playerHandler = rootContext.playerHandler; |
| if (playerHandler) { |
| playerHandler.flushPlayers(); |
| } |
| } |
| rootContext.clean = _CLEAN_PROMISE; |
| res_1(null); |
| }); |
| } |
| } |
| function tickRootContext(rootContext) { |
| for (var i = 0; i < rootContext.components.length; i++) { |
| var rootComponent = rootContext.components[i]; |
| renderComponentOrTemplate(readPatchedLView(rootComponent), rootComponent); |
| } |
| } |
| function detectChangesInternal(view, context) { |
| var rendererFactory = view[RENDERER_FACTORY]; |
| if (rendererFactory.begin) |
| rendererFactory.begin(); |
| try { |
| if (isCreationMode(view)) { |
| checkView(view, context); // creation mode pass |
| } |
| checkView(view, context); // update mode pass |
| } |
| catch (error) { |
| handleError(view, error); |
| throw error; |
| } |
| finally { |
| if (rendererFactory.end) |
| rendererFactory.end(); |
| } |
| } |
| /** |
| * Synchronously perform change detection on a root view and its components. |
| * |
| * @param lView The view which the change detection should be performed on. |
| */ |
| function detectChangesInRootView(lView) { |
| tickRootContext(lView[CONTEXT]); |
| } |
| function checkNoChangesInternal(view, context) { |
| setCheckNoChangesMode(true); |
| try { |
| detectChangesInternal(view, context); |
| } |
| finally { |
| setCheckNoChangesMode(false); |
| } |
| } |
| /** |
| * Checks the change detector on a root view and its components, and throws if any changes are |
| * detected. |
| * |
| * This is used in development mode to verify that running change detection doesn't |
| * introduce other changes. |
| * |
| * @param lView The view which the change detection should be checked on. |
| */ |
| function checkNoChangesInRootView(lView) { |
| setCheckNoChangesMode(true); |
| try { |
| detectChangesInRootView(lView); |
| } |
| finally { |
| setCheckNoChangesMode(false); |
| } |
| } |
| /** Checks the view of the component provided. Does not gate on dirty checks or execute doCheck. |
| */ |
| function checkView(hostView, component) { |
| var hostTView = hostView[TVIEW]; |
| var oldView = enterView(hostView, hostView[T_HOST]); |
| var templateFn = hostTView.template; |
| var creationMode = isCreationMode(hostView); |
| // Will become true if the `try` block executes with no errors. |
| var safeToRunHooks = false; |
| try { |
| resetPreOrderHookFlags(hostView); |
| creationMode && executeViewQueryFn(1 /* Create */, hostTView, component); |
| executeTemplate(hostView, templateFn, getRenderFlags(hostView), component); |
| refreshDescendantViews(hostView); |
| // Only check view queries again in creation mode if there are static view queries |
| if (!creationMode || hostTView.staticViewQueries) { |
| executeViewQueryFn(2 /* Update */, hostTView, component); |
| } |
| safeToRunHooks = true; |
| } |
| finally { |
| leaveView(oldView, safeToRunHooks); |
| } |
| } |
| function executeViewQueryFn(flags, tView, component) { |
| var viewQuery = tView.viewQuery; |
| if (viewQuery) { |
| setCurrentQueryIndex(tView.viewQueryStartIndex); |
| viewQuery(flags, component); |
| } |
| } |
| /////////////////////////////// |
| //// Bindings & interpolations |
| /////////////////////////////// |
| /** |
| * Creates binding metadata for a particular binding and stores it in |
| * TView.data. These are generated in order to support DebugElement.properties. |
| * |
| * Each binding / interpolation will have one (including attribute bindings) |
| * because at the time of binding, we don't know to which instruction the binding |
| * belongs. It is always stored in TView.data at the index of the last binding |
| * value in LView (e.g. for interpolation8, it would be stored at the index of |
| * the 8th value). |
| * |
| * @param lView The LView that contains the current binding index. |
| * @param prefix The static prefix string |
| * @param suffix The static suffix string |
| * |
| * @returns Newly created binding metadata string for this binding or null |
| */ |
| function storeBindingMetadata(lView, prefix, suffix) { |
| if (prefix === void 0) { prefix = ''; } |
| if (suffix === void 0) { suffix = ''; } |
| var tData = lView[TVIEW].data; |
| var lastBindingIndex = lView[BINDING_INDEX] - 1; |
| var value = INTERPOLATION_DELIMITER + prefix + INTERPOLATION_DELIMITER + suffix; |
| return tData[lastBindingIndex] == null ? (tData[lastBindingIndex] = value) : null; |
| } |
| var CLEAN_PROMISE = _CLEAN_PROMISE; |
| function initializeTNodeInputs(tNode) { |
| // If tNode.inputs is undefined, a listener has created outputs, but inputs haven't |
| // yet been checked. |
| if (tNode.inputs === undefined) { |
| // mark inputs as checked |
| tNode.inputs = generatePropertyAliases(tNode, 0 /* Input */); |
| } |
| return tNode.inputs; |
| } |
| function getCleanup(view) { |
| // top level variables should not be exported for performance reasons (PERF_NOTES.md) |
| return view[CLEANUP] || (view[CLEANUP] = ngDevMode ? new LCleanup() : []); |
| } |
| function getTViewCleanup(view) { |
| return view[TVIEW].cleanup || (view[TVIEW].cleanup = ngDevMode ? new TCleanup() : []); |
| } |
| /** |
| * There are cases where the sub component's renderer needs to be included |
| * instead of the current renderer (see the componentSyntheticHost* instructions). |
| */ |
| function loadComponentRenderer(tNode, lView) { |
| var componentLView = lView[tNode.index]; |
| return componentLView[RENDERER]; |
| } |
| /** Handles an error thrown in an LView. */ |
| function handleError(lView, error) { |
| var injector = lView[INJECTOR$1]; |
| var errorHandler = injector ? injector.get(ErrorHandler, null) : null; |
| errorHandler && errorHandler.handleError(error); |
| } |
| /** |
| * Set the inputs of directives at the current node to corresponding value. |
| * |
| * @param lView the `LView` which contains the directives. |
| * @param inputs mapping between the public "input" name and privately-known, |
| * possibly minified, property names to write to. |
| * @param value Value to set. |
| */ |
| function setInputsForProperty(lView, inputs, value) { |
| var tView = lView[TVIEW]; |
| for (var i = 0; i < inputs.length;) { |
| var index = inputs[i++]; |
| var publicName = inputs[i++]; |
| var privateName = inputs[i++]; |
| var instance = lView[index]; |
| ngDevMode && assertDataInRange(lView, index); |
| var def = tView.data[index]; |
| var setInput = def.setInput; |
| if (setInput) { |
| def.setInput(instance, value, publicName, privateName); |
| } |
| else { |
| instance[privateName] = value; |
| } |
| } |
| } |
| /** |
| * Updates a text binding at a given index in a given LView. |
| */ |
| function textBindingInternal(lView, index, value) { |
| ngDevMode && assertNotSame(value, NO_CHANGE, 'value should not be NO_CHANGE'); |
| ngDevMode && assertDataInRange(lView, index + HEADER_OFFSET); |
| var element = getNativeByIndex(index, lView); |
| ngDevMode && assertDefined(element, 'native element should exist'); |
| ngDevMode && ngDevMode.rendererSetText++; |
| var renderer = lView[RENDERER]; |
| isProceduralRenderer(renderer) ? renderer.setValue(element, value) : element.textContent = value; |
| } |
| |
| /** |
| * @license |
| * Copyright Google Inc. All Rights Reserved. |
| * |
| * Use of this source code is governed by an MIT-style license that can be |
| * found in the LICENSE file at https://angular.io/license |
| */ |
| function applyOnCreateInstructions(tNode) { |
| // there may be some instructions that need to run in a specific |
| // order because the CREATE block in a directive runs before the |
| // CREATE block in a template. To work around this instructions |
| // can get access to the function array below and defer any code |
| // to run after the element is created. |
| var fns; |
| if (fns = tNode.onElementCreationFns) { |
| for (var i = 0; i < fns.length; i++) { |
| fns[i](); |
| } |
| tNode.onElementCreationFns = null; |
| } |
| } |
| /** |
| * Unwraps a parent injector location number to find the view offset from the current injector, |
| * then walks up the declaration view tree until the TNode of the parent injector is found. |
| * |
| * @param location The location of the parent injector, which contains the view offset |
| * @param startView The LView instance from which to start walking up the view tree |
| * @param startTNode The TNode instance of the starting element |
| * @returns The TNode of the parent injector |
| */ |
| function getParentInjectorTNode(location, startView, startTNode) { |
| if (startTNode.parent && startTNode.parent.injectorIndex !== -1) { |
| // view offset is 0 |
| var injectorIndex = startTNode.parent.injectorIndex; |
| var parentTNode_1 = startTNode.parent; |
| while (parentTNode_1.parent != null && injectorIndex == parentTNode_1.injectorIndex) { |
| parentTNode_1 = parentTNode_1.parent; |
| } |
| return parentTNode_1; |
| } |
| var viewOffset = getParentInjectorViewOffset(location); |
| // view offset is 1 |
| var parentView = startView; |
| var parentTNode = startView[T_HOST]; |
| // view offset is superior to 1 |
| while (viewOffset > 1) { |
| parentView = parentView[DECLARATION_VIEW]; |
| parentTNode = parentView[T_HOST]; |
| viewOffset--; |
| } |
| return parentTNode; |
| } |
| |
| /** |
| * @license |
| * Copyright Google Inc. All Rights Reserved. |
| * |
| * Use of this source code is governed by an MIT-style license that can be |
| * found in the LICENSE file at https://angular.io/license |
| */ |
| /** |
| * Allocates the necessary amount of slots for host vars. |
| * |
| * @param count Amount of vars to be allocated |
| * |
| * @codeGenApi |
| */ |
| function ɵɵallocHostVars(count) { |
| var lView = getLView(); |
| var tView = lView[TVIEW]; |
| if (!tView.firstTemplatePass) |
| return; |
| queueHostBindingForCheck(tView, getCurrentDirectiveDef(), count); |
| prefillHostVars(tView, lView, count); |
| } |
| /** |
| * Stores host binding fn and number of host vars so it will be queued for binding refresh during |
| * CD. |
| */ |
| function queueHostBindingForCheck(tView, def, hostVars) { |
| ngDevMode && |
| assertEqual(tView.firstTemplatePass, true, 'Should only be called in first template pass.'); |
| var expando = tView.expandoInstructions; |
| var length = expando.length; |
| // Check whether a given `hostBindings` function already exists in expandoInstructions, |
| // which can happen in case directive definition was extended from base definition (as a part of |
| // the `InheritDefinitionFeature` logic). If we found the same `hostBindings` function in the |
| // list, we just increase the number of host vars associated with that function, but do not add it |
| // into the list again. |
| if (length >= 2 && expando[length - 2] === def.hostBindings) { |
| expando[length - 1] = expando[length - 1] + hostVars; |
| } |
| else { |
| expando.push(def.hostBindings, hostVars); |
| } |
| } |
| /** |
| * On the first template pass, we need to reserve space for host binding values |
| * after directives are matched (so all directives are saved, then bindings). |
| * Because we are updating the blueprint, we only need to do this once. |
| */ |
| function prefillHostVars(tView, lView, totalHostVars) { |
| ngDevMode && |
| assertEqual(tView.firstTemplatePass, true, 'Should only be called in first template pass.'); |
| for (var i = 0; i < totalHostVars; i++) { |
| lView.push(NO_CHANGE); |
| tView.blueprint.push(NO_CHANGE); |
| tView.data.push(null); |
| } |
| } |
| |
| /** |
| * @license |
| * Copyright Google Inc. All Rights Reserved. |
| * |
| * Use of this source code is governed by an MIT-style license that can be |
| * found in the LICENSE file at https://angular.io/license |
| */ |
| var _symbolIterator = null; |
| function getSymbolIterator() { |
| if (!_symbolIterator) { |
| var Symbol_1 = _global['Symbol']; |
| if (Symbol_1 && Symbol_1.iterator) { |
| _symbolIterator = Symbol_1.iterator; |
| } |
| else { |
| // es6-shim specific logic |
| var keys = Object.getOwnPropertyNames(Map.prototype); |
| for (var i = 0; i < keys.length; ++i) { |
| var key = keys[i]; |
| if (key !== 'entries' && key !== 'size' && |
| Map.prototype[key] === Map.prototype['entries']) { |
| _symbolIterator = key; |
| } |
| } |
| } |
| } |
| return _symbolIterator; |
| } |
| |
| /** |
| * @license |
| * Copyright Google Inc. All Rights Reserved. |
| * |
| * Use of this source code is governed by an MIT-style license that can be |
| * found in the LICENSE file at https://angular.io/license |
| */ |
| |
| /** |
| * @license |
| * Copyright Google Inc. All Rights Reserved. |
| * |
| * Use of this source code is governed by an MIT-style license that can be |
| * found in the LICENSE file at https://angular.io/license |
| */ |
| // JS has NaN !== NaN |
| function looseIdentical(a, b) { |
| return a === b || typeof a === 'number' && typeof b === 'number' && isNaN(a) && isNaN(b); |
| } |
| |
| /** |
| * @license |
| * Copyright Google Inc. All Rights Reserved. |
| * |
| * Use of this source code is governed by an MIT-style license that can be |
| * found in the LICENSE file at https://angular.io/license |
| */ |
| function devModeEqual(a, b) { |
| var isListLikeIterableA = isListLikeIterable(a); |
| var isListLikeIterableB = isListLikeIterable(b); |
| if (isListLikeIterableA && isListLikeIterableB) { |
| return areIterablesEqual(a, b, devModeEqual); |
| } |
| else { |
| var isAObject = a && (typeof a === 'object' || typeof a === 'function'); |
| var isBObject = b && (typeof b === 'object' || typeof b === 'function'); |
| if (!isListLikeIterableA && isAObject && !isListLikeIterableB && isBObject) { |
| return true; |
| } |
| else { |
| return looseIdentical(a, b); |
| } |
| } |
| } |
| /** |
| * Indicates that the result of a {@link Pipe} transformation has changed even though the |
| * reference has not changed. |
| * |
| * Wrapped values are unwrapped automatically during the change detection, and the unwrapped value |
| * is stored. |
| * |
| * Example: |
| * |
| * ``` |
| * if (this._latestValue === this._latestReturnedValue) { |
| * return this._latestReturnedValue; |
| * } else { |
| * this._latestReturnedValue = this._latestValue; |
| * return WrappedValue.wrap(this._latestValue); // this will force update |
| * } |
| * ``` |
| * |
| * @publicApi |
| */ |
| var WrappedValue = /** @class */ (function () { |
| function WrappedValue(value) { |
| this.wrapped = value; |
| } |
| /** Creates a wrapped value. */ |
| WrappedValue.wrap = function (value) { return new WrappedValue(value); }; |
| /** |
| * Returns the underlying value of a wrapped value. |
| * Returns the given `value` when it is not wrapped. |
| **/ |
| WrappedValue.unwrap = function (value) { return WrappedValue.isWrapped(value) ? value.wrapped : value; }; |
| /** Returns true if `value` is a wrapped value. */ |
| WrappedValue.isWrapped = function (value) { return value instanceof WrappedValue; }; |
| return WrappedValue; |
| }()); |
| function isListLikeIterable(obj) { |
| if (!isJsObject(obj)) |
| return false; |
| return Array.isArray(obj) || |
| (!(obj instanceof Map) && // JS Map are iterables but return entries as [k, v] |
| getSymbolIterator() in obj); // JS Iterable have a Symbol.iterator prop |
| } |
| function areIterablesEqual(a, b, comparator) { |
| var iterator1 = a[getSymbolIterator()](); |
| var iterator2 = b[getSymbolIterator()](); |
| while (true) { |
| var item1 = iterator1.next(); |
| var item2 = iterator2.next(); |
| if (item1.done && item2.done) |
| return true; |
| if (item1.done || item2.done) |
| return false; |
| if (!comparator(item1.value, item2.value)) |
| return false; |
| } |
| } |
| function iterateListLike(obj, fn) { |
| if (Array.isArray(obj)) { |
| for (var i = 0; i < obj.length; i++) { |
| fn(obj[i]); |
| } |
| } |
| else { |
| var iterator = obj[getSymbolIterator()](); |
| var item = void 0; |
| while (!((item = iterator.next()).done)) { |
| fn(item.value); |
| } |
| } |
| } |
| function isJsObject(o) { |
| return o !== null && (typeof o === 'function' || typeof o === 'object'); |
| } |
| |
| /** |
| * @license |
| * Copyright Google Inc. All Rights Reserved. |
| * |
| * Use of this source code is governed by an MIT-style license that can be |
| * found in the LICENSE file at https://angular.io/license |
| */ |
| // TODO(misko): consider inlining |
| /** Updates binding and returns the value. */ |
| function updateBinding(lView, bindingIndex, value) { |
| return lView[bindingIndex] = value; |
| } |
| /** Gets the current binding value. */ |
| function getBinding(lView, bindingIndex) { |
| ngDevMode && assertDataInRange(lView, bindingIndex); |
| ngDevMode && |
| assertNotSame(lView[bindingIndex], NO_CHANGE, 'Stored value should never be NO_CHANGE.'); |
| return lView[bindingIndex]; |
| } |
| /** Updates binding if changed, then returns whether it was updated. */ |
| function bindingUpdated(lView, bindingIndex, value) { |
| ngDevMode && assertNotSame(value, NO_CHANGE, 'Incoming value should never be NO_CHANGE.'); |
| ngDevMode && |
| assertLessThan(bindingIndex, lView.length, "Slot should have been initialized to NO_CHANGE"); |
| var oldValue = lView[bindingIndex]; |
| if (isDifferent(oldValue, value)) { |
| if (ngDevMode && getCheckNoChangesMode()) { |
| // View engine didn't report undefined values as changed on the first checkNoChanges pass |
| // (before the change detection was run). |
| var oldValueToCompare = oldValue !== NO_CHANGE ? oldValue : undefined; |
| if (!devModeEqual(oldValueToCompare, value)) { |
| throwErrorIfNoChangesMode(oldValue === NO_CHANGE, oldValueToCompare, value); |
| } |
| } |
| lView[bindingIndex] = value; |
| return true; |
| } |
| return false; |
| } |
| /** Updates 2 bindings if changed, then returns whether either was updated. */ |
| function bindingUpdated2(lView, bindingIndex, exp1, exp2) { |
| var different = bindingUpdated(lView, bindingIndex, exp1); |
| return bindingUpdated(lView, bindingIndex + 1, exp2) || different; |
| } |
| /** Updates 3 bindings if changed, then returns whether any was updated. */ |
| function bindingUpdated3(lView, bindingIndex, exp1, exp2, exp3) { |
| var different = bindingUpdated2(lView, bindingIndex, exp1, exp2); |
| return bindingUpdated(lView, bindingIndex + 2, exp3) || different; |
| } |
| /** Updates 4 bindings if changed, then returns whether any was updated. */ |
| function bindingUpdated4(lView, bindingIndex, exp1, exp2, exp3, exp4) { |
| var different = bindingUpdated2(lView, bindingIndex, exp1, exp2); |
| return bindingUpdated2(lView, bindingIndex + 2, exp3, exp4) || different; |
| } |
| |
| /** |
| * @license |
| * Copyright Google Inc. All Rights Reserved. |
| * |
| * Use of this source code is governed by an MIT-style license that can be |
| * found in the LICENSE file at https://angular.io/license |
| */ |
| /** |
| * Update a property on a selected element. |
| * |
| * Operates on the element selected by index via the {@link select} instruction. |
| * |
| * If the property name also exists as an input property on one of the element's directives, |
| * the component property will be set instead of the element property. This check must |
| * be conducted at runtime so child components that add new `@Inputs` don't have to be re-compiled |
| * |
| * @param propName Name of property. Because it is going to DOM, this is not subject to |
| * renaming as part of minification. |
| * @param value New value to write. |
| * @param sanitizer An optional function used to sanitize the value. |
| * @param nativeOnly Whether or not we should only set native properties and skip input check |
| * (this is necessary for host property bindings) |
| * @returns This function returns itself so that it may be chained |
| * (e.g. `property('name', ctx.name)('title', ctx.title)`) |
| * |
| * @codeGenApi |
| */ |
| function ɵɵproperty(propName, value, sanitizer, nativeOnly) { |
| var index = getSelectedIndex(); |
| ngDevMode && assertNotEqual(index, -1, 'selected index cannot be -1'); |
| var lView = getLView(); |
| var bindReconciledValue = bind(lView, value); |
| if (bindReconciledValue !== NO_CHANGE) { |
| elementPropertyInternal(index, propName, bindReconciledValue, sanitizer, nativeOnly); |
| } |
| return ɵɵproperty; |
| } |
| /** |
| * Creates a single value binding. |
| * |
| * @param lView Current view |
| * @param value Value to diff |
| */ |
| function bind(lView, value) { |
| var bindingIndex = lView[BINDING_INDEX]++; |
| storeBindingMetadata(lView); |
| return bindingUpdated(lView, bindingIndex, value) ? value : NO_CHANGE; |
| } |
| /** |
| * Updates a synthetic host binding (e.g. `[@foo]`) on a component. |
| * |
| * This instruction is for compatibility purposes and is designed to ensure that a |
| * synthetic host binding (e.g. `@HostBinding('@foo')`) properly gets rendered in |
| * the component's renderer. Normally all host bindings are evaluated with the parent |
| * component's renderer, but, in the case of animation @triggers, they need to be |
| * evaluated with the sub component's renderer (because that's where the animation |
| * triggers are defined). |
| * |
| * Do not use this instruction as a replacement for `elementProperty`. This instruction |
| * only exists to ensure compatibility with the ViewEngine's host binding behavior. |
| * |
| * @param index The index of the element to update in the data array |
| * @param propName Name of property. Because it is going to DOM, this is not subject to |
| * renaming as part of minification. |
| * @param value New value to write. |
| * @param sanitizer An optional function used to sanitize the value. |
| * @param nativeOnly Whether or not we should only set native properties and skip input check |
| * (this is necessary for host property bindings) |
| * |
| * @codeGenApi |
| */ |
| function ɵɵupdateSyntheticHostBinding(propName, value, sanitizer, nativeOnly) { |
| var index = getSelectedIndex(); |
| var lView = getLView(); |
| // TODO(benlesh): remove bind call here. |
| var bound = bind(lView, value); |
| if (bound !== NO_CHANGE) { |
| elementPropertyInternal(index, propName, bound, sanitizer, nativeOnly, loadComponentRenderer); |
| } |
| } |
| |
| /** |
| * Updates the value of or removes a bound attribute on an Element. |
| * |
| * Used in the case of `[attr.title]="value"` |
| * |
| * @param name name The name of the attribute. |
| * @param value value The attribute is removed when value is `null` or `undefined`. |
| * Otherwise the attribute value is set to the stringified value. |
| * @param sanitizer An optional function used to sanitize the value. |
| * @param namespace Optional namespace to use when setting the attribute. |
| * |
| * @codeGenApi |
| */ |
| function ɵɵattribute(name, value, sanitizer, namespace) { |
| var index = getSelectedIndex(); |
| var lView = getLView(); |
| // TODO(FW-1340): Refactor to remove the use of other instructions here. |
| var bound = bind(lView, value); |
| if (bound !== NO_CHANGE) { |
| elementAttributeInternal(index, name, bound, lView, sanitizer, namespace); |
| } |
| return ɵɵattribute; |
| } |
| |
| /** |
| * @license |
| * Copyright Google Inc. All Rights Reserved. |
| * |
| * Use of this source code is governed by an MIT-style license that can be |
| * found in the LICENSE file at https://angular.io/license |
| */ |
| /** |
| * Create interpolation bindings with a variable number of expressions. |
| * |
| * If there are 1 to 8 expressions `interpolation1()` to `interpolation8()` should be used instead. |
| * Those are faster because there is no need to create an array of expressions and iterate over it. |
| * |
| * `values`: |
| * - has static text at even indexes, |
| * - has evaluated expressions at odd indexes. |
| * |
| * Returns the concatenated string when any of the arguments changes, `NO_CHANGE` otherwise. |
| * |
| * @codeGenApi |
| */ |
| function ɵɵinterpolationV(values) { |
| ngDevMode && assertLessThan(2, values.length, 'should have at least 3 values'); |
| ngDevMode && assertEqual(values.length % 2, 1, 'should have an odd number of values'); |
| var isBindingUpdated = false; |
| var lView = getLView(); |
| var tData = lView[TVIEW].data; |
| var bindingIndex = lView[BINDING_INDEX]; |
| if (tData[bindingIndex] == null) { |
| // 2 is the index of the first static interstitial value (ie. not prefix) |
| for (var i = 2; i < values.length; i += 2) { |
| tData[bindingIndex++] = values[i]; |
| } |
| bindingIndex = lView[BINDING_INDEX]; |
| } |
| for (var i = 1; i < values.length; i += 2) { |
| // Check if bindings (odd indexes) have changed |
| isBindingUpdated = bindingUpdated(lView, bindingIndex++, values[i]) || isBindingUpdated; |
| } |
| lView[BINDING_INDEX] = bindingIndex; |
| storeBindingMetadata(lView, values[0], values[values.length - 1]); |
| if (!isBindingUpdated) { |
| return NO_CHANGE; |
| } |
| // Build the updated content |
| var content = values[0]; |
| for (var i = 1; i < values.length; i += 2) { |
| content += renderStringify(values[i]) + values[i + 1]; |
| } |
| return content; |
| } |
| /** |
| * Creates an interpolation binding with 1 expression. |
| * |
| * @param prefix static value used for concatenation only. |
| * @param v0 value checked for change. |
| * @param suffix static value used for concatenation only. |
| * |
| * @codeGenApi |
| */ |
| function ɵɵinterpolation1(prefix, v0, suffix) { |
| var lView = getLView(); |
| var different = bindingUpdated(lView, lView[BINDING_INDEX]++, v0); |
| storeBindingMetadata(lView, prefix, suffix); |
| return different ? prefix + renderStringify(v0) + suffix : NO_CHANGE; |
| } |
| /** |
| * Creates an interpolation binding with 2 expressions. |
| * |
| * @codeGenApi |
| */ |
| function ɵɵinterpolation2(prefix, v0, i0, v1, suffix) { |
| var lView = getLView(); |
| var bindingIndex = lView[BINDING_INDEX]; |
| var different = bindingUpdated2(lView, bindingIndex, v0, v1); |
| lView[BINDING_INDEX] += 2; |
| // Only set static strings the first time (data will be null subsequent runs). |
| var data = storeBindingMetadata(lView, prefix, suffix); |
| if (data) { |
| lView[TVIEW].data[bindingIndex] = i0; |
| } |
| return different ? prefix + renderStringify(v0) + i0 + renderStringify(v1) + suffix : NO_CHANGE; |
| } |
| /** |
| * Creates an interpolation binding with 3 expressions. |
| * |
| * @codeGenApi |
| */ |
| function ɵɵinterpolation3(prefix, v0, i0, v1, i1, v2, suffix) { |
| var lView = getLView(); |
| var bindingIndex = lView[BINDING_INDEX]; |
| var different = bindingUpdated3(lView, bindingIndex, v0, v1, v2); |
| lView[BINDING_INDEX] += 3; |
| // Only set static strings the first time (data will be null subsequent runs). |
| var data = storeBindingMetadata(lView, prefix, suffix); |
| if (data) { |
| var tData = lView[TVIEW].data; |
| tData[bindingIndex] = i0; |
| tData[bindingIndex + 1] = i1; |
| } |
| return different ? |
| prefix + renderStringify(v0) + i0 + renderStringify(v1) + i1 + renderStringify(v2) + suffix : |
| NO_CHANGE; |
| } |
| /** |
| * Create an interpolation binding with 4 expressions. |
| * |
| * @codeGenApi |
| */ |
| function ɵɵinterpolation4(prefix, v0, i0, v1, i1, v2, i2, v3, suffix) { |
| var lView = getLView(); |
| var bindingIndex = lView[BINDING_INDEX]; |
| var different = bindingUpdated4(lView, bindingIndex, v0, v1, v2, v3); |
| lView[BINDING_INDEX] += 4; |
| // Only set static strings the first time (data will be null subsequent runs). |
| var data = storeBindingMetadata(lView, prefix, suffix); |
| if (data) { |
| var tData = lView[TVIEW].data; |
| tData[bindingIndex] = i0; |
| tData[bindingIndex + 1] = i1; |
| tData[bindingIndex + 2] = i2; |
| } |
| return different ? |
| prefix + renderStringify(v0) + i0 + renderStringify(v1) + i1 + renderStringify(v2) + i2 + |
| renderStringify(v3) + suffix : |
| NO_CHANGE; |
| } |
| /** |
| * Creates an interpolation binding with 5 expressions. |
| * |
| * @codeGenApi |
| */ |
| function ɵɵinterpolation5(prefix, v0, i0, v1, i1, v2, i2, v3, i3, v4, suffix) { |
| var lView = getLView(); |
| var bindingIndex = lView[BINDING_INDEX]; |
| var different = bindingUpdated4(lView, bindingIndex, v0, v1, v2, v3); |
| different = bindingUpdated(lView, bindingIndex + 4, v4) || different; |
| lView[BINDING_INDEX] += 5; |
| // Only set static strings the first time (data will be null subsequent runs). |
| var data = storeBindingMetadata(lView, prefix, suffix); |
| if (data) { |
| var tData = lView[TVIEW].data; |
| tData[bindingIndex] = i0; |
| tData[bindingIndex + 1] = i1; |
| tData[bindingIndex + 2] = i2; |
| tData[bindingIndex + 3] = i3; |
| } |
| return different ? |
| prefix + renderStringify(v0) + i0 + renderStringify(v1) + i1 + renderStringify(v2) + i2 + |
| renderStringify(v3) + i3 + renderStringify(v4) + suffix : |
| NO_CHANGE; |
| } |
| /** |
| * Creates an interpolation binding with 6 expressions. |
| * |
| * @codeGenApi |
| */ |
| function ɵɵinterpolation6(prefix, v0, i0, v1, i1, v2, i2, v3, i3, v4, i4, v5, suffix) { |
| var lView = getLView(); |
| var bindingIndex = lView[BINDING_INDEX]; |
| var different = bindingUpdated4(lView, bindingIndex, v0, v1, v2, v3); |
| different = bindingUpdated2(lView, bindingIndex + 4, v4, v5) || different; |
| lView[BINDING_INDEX] += 6; |
| // Only set static strings the first time (data will be null subsequent runs). |
| var data = storeBindingMetadata(lView, prefix, suffix); |
| if (data) { |
| var tData = lView[TVIEW].data; |
| tData[bindingIndex] = i0; |
| tData[bindingIndex + 1] = i1; |
| tData[bindingIndex + 2] = i2; |
| tData[bindingIndex + 3] = i3; |
| tData[bindingIndex + 4] = i4; |
| } |
| return different ? |
| prefix + renderStringify(v0) + i0 + renderStringify(v1) + i1 + renderStringify(v2) + i2 + |
| renderStringify(v3) + i3 + renderStringify(v4) + i4 + renderStringify(v5) + suffix : |
| NO_CHANGE; |
| } |
| /** |
| * Creates an interpolation binding with 7 expressions. |
| * |
| * @codeGenApi |
| */ |
| function ɵɵinterpolation7(prefix, v0, i0, v1, i1, v2, i2, v3, i3, v4, i4, v5, i5, v6, suffix) { |
| var lView = getLView(); |
| var bindingIndex = lView[BINDING_INDEX]; |
| var different = bindingUpdated4(lView, bindingIndex, v0, v1, v2, v3); |
| different = bindingUpdated3(lView, bindingIndex + 4, v4, v5, v6) || different; |
| lView[BINDING_INDEX] += 7; |
| // Only set static strings the first time (data will be null subsequent runs). |
| var data = storeBindingMetadata(lView, prefix, suffix); |
| if (data) { |
| var tData = lView[TVIEW].data; |
| tData[bindingIndex] = i0; |
| tData[bindingIndex + 1] = i1; |
| tData[bindingIndex + 2] = i2; |
| tData[bindingIndex + 3] = i3; |
| tData[bindingIndex + 4] = i4; |
| tData[bindingIndex + 5] = i5; |
| } |
| return different ? |
| prefix + renderStringify(v0) + i0 + renderStringify(v1) + i1 + renderStringify(v2) + i2 + |
| renderStringify(v3) + i3 + renderStringify(v4) + i4 + renderStringify(v5) + i5 + |
| renderStringify(v6) + suffix : |
| NO_CHANGE; |
| } |
| /** |
| * Creates an interpolation binding with 8 expressions. |
| * |
| * @codeGenApi |
| */ |
| function ɵɵinterpolation8(prefix, v0, i0, v1, i1, v2, i2, v3, i3, v4, i4, v5, i5, v6, i6, v7, suffix) { |
| var lView = getLView(); |
| var bindingIndex = lView[BINDING_INDEX]; |
| var different = bindingUpdated4(lView, bindingIndex, v0, v1, v2, v3); |
| different = bindingUpdated4(lView, bindingIndex + 4, v4, v5, v6, v7) || different; |
| lView[BINDING_INDEX] += 8; |
| // Only set static strings the first time (data will be null subsequent runs). |
| var data = storeBindingMetadata(lView, prefix, suffix); |
| if (data) { |
| var tData = lView[TVIEW].data; |
| tData[bindingIndex] = i0; |
| tData[bindingIndex + 1] = i1; |
| tData[bindingIndex + 2] = i2; |
| tData[bindingIndex + 3] = i3; |
| tData[bindingIndex + 4] = i4; |
| tData[bindingIndex + 5] = i5; |
| tData[bindingIndex + 6] = i6; |
| } |
| return different ? |
| prefix + renderStringify(v0) + i0 + renderStringify(v1) + i1 + renderStringify(v2) + i2 + |
| renderStringify(v3) + i3 + renderStringify(v4) + i4 + renderStringify(v5) + i5 + |
| renderStringify(v6) + i6 + renderStringify(v7) + suffix : |
| NO_CHANGE; |
| } |
| |
| /** |
| * |
| * Update an interpolated attribute on an element with single bound value surrounded by text. |
| * |
| * Used when the value passed to a property has 1 interpolated value in it: |
| * |
| * ```html |
| * <div attr.title="prefix{{v0}}suffix"></div> |
| * ``` |
| * |
| * Its compiled representation is:: |
| * |
| * ```ts |
| * ɵɵattributeInterpolate1('title', 'prefix', v0, 'suffix'); |
| * ``` |
| * |
| * @param attrName The name of the attribute to update |
| * @param prefix Static value used for concatenation only. |
| * @param v0 Value checked for change. |
| * @param suffix Static value used for concatenation only. |
| * @param sanitizer An optional sanitizer function |
| * @returns itself, so that it may be chained. |
| * @codeGenApi |
| */ |
| function ɵɵattributeInterpolate1(attrName, prefix, v0, suffix, sanitizer, namespace) { |
| var index = getSelectedIndex(); |
| var lView = getLView(); |
| // TODO(FW-1340): Refactor to remove the use of other instructions here. |
| var interpolatedValue = ɵɵinterpolation1(prefix, v0, suffix); |
| if (interpolatedValue !== NO_CHANGE) { |
| elementAttributeInternal(index, attrName, interpolatedValue, lView, sanitizer, namespace); |
| } |
| return ɵɵattributeInterpolate1; |
| } |
| /** |
| * |
| * Update an interpolated attribute on an element with 2 bound values surrounded by text. |
| * |
| * Used when the value passed to a property has 2 interpolated values in it: |
| * |
| * ```html |
| * <div attr.title="prefix{{v0}}-{{v1}}suffix"></div> |
| * ``` |
| * |
| * Its compiled representation is:: |
| * |
| * ```ts |
| * ɵɵattributeInterpolate2('title', 'prefix', v0, '-', v1, 'suffix'); |
| * ``` |
| * |
| * @param attrName The name of the attribute to update |
| * @param prefix Static value used for concatenation only. |
| * @param v0 Value checked for change. |
| * @param i0 Static value used for concatenation only. |
| * @param v1 Value checked for change. |
| * @param suffix Static value used for concatenation only. |
| * @param sanitizer An optional sanitizer function |
| * @returns itself, so that it may be chained. |
| * @codeGenApi |
| */ |
| function ɵɵattributeInterpolate2(attrName, prefix, v0, i0, v1, suffix, sanitizer, namespace) { |
| var index = getSelectedIndex(); |
| var lView = getLView(); |
| // TODO(FW-1340): Refactor to remove the use of other instructions here. |
| var interpolatedValue = ɵɵinterpolation2(prefix, v0, i0, v1, suffix); |
| if (interpolatedValue !== NO_CHANGE) { |
| elementAttributeInternal(index, attrName, interpolatedValue, lView, sanitizer, namespace); |
| } |
| return ɵɵattributeInterpolate2; |
| } |
| /** |
| * |
| * Update an interpolated attribute on an element with 3 bound values surrounded by text. |
| * |
| * Used when the value passed to a property has 3 interpolated values in it: |
| * |
| * ```html |
| * <div attr.title="prefix{{v0}}-{{v1}}-{{v2}}suffix"></div> |
| * ``` |
| * |
| * Its compiled representation is:: |
| * |
| * ```ts |
| * ɵɵattributeInterpolate3( |
| * 'title', 'prefix', v0, '-', v1, '-', v2, 'suffix'); |
| * ``` |
| * |
| * @param attrName The name of the attribute to update |
| * @param prefix Static value used for concatenation only. |
| * @param v0 Value checked for change. |
| * @param i0 Static value used for concatenation only. |
| * @param v1 Value checked for change. |
| * @param i1 Static value used for concatenation only. |
| * @param v2 Value checked for change. |
| * @param suffix Static value used for concatenation only. |
| * @param sanitizer An optional sanitizer function |
| * @returns itself, so that it may be chained. |
| * @codeGenApi |
| */ |
| function ɵɵattributeInterpolate3(attrName, prefix, v0, i0, v1, i1, v2, suffix, sanitizer, namespace) { |
| var index = getSelectedIndex(); |
| var lView = getLView(); |
| // TODO(FW-1340): Refactor to remove the use of other instructions here. |
| var interpolatedValue = ɵɵinterpolation3(prefix, v0, i0, v1, i1, v2, suffix); |
| if (interpolatedValue !== NO_CHANGE) { |
| elementAttributeInternal(index, attrName, interpolatedValue, lView, sanitizer, namespace); |
| } |
| return ɵɵattributeInterpolate3; |
| } |
| /** |
| * |
| * Update an interpolated attribute on an element with 4 bound values surrounded by text. |
| * |
| * Used when the value passed to a property has 4 interpolated values in it: |
| * |
| * ```html |
| * <div attr.title="prefix{{v0}}-{{v1}}-{{v2}}-{{v3}}suffix"></div> |
| * ``` |
| * |
| * Its compiled representation is:: |
| * |
| * ```ts |
| * ɵɵattributeInterpolate4( |
| * 'title', 'prefix', v0, '-', v1, '-', v2, '-', v3, 'suffix'); |
| * ``` |
| * |
| * @param attrName The name of the attribute to update |
| * @param prefix Static value used for concatenation only. |
| * @param v0 Value checked for change. |
| * @param i0 Static value used for concatenation only. |
| * @param v1 Value checked for change. |
| * @param i1 Static value used for concatenation only. |
| * @param v2 Value checked for change. |
| * @param i2 Static value used for concatenation only. |
| * @param v3 Value checked for change. |
| * @param suffix Static value used for concatenation only. |
| * @param sanitizer An optional sanitizer function |
| * @returns itself, so that it may be chained. |
| * @codeGenApi |
| */ |
| function ɵɵattributeInterpolate4(attrName, prefix, v0, i0, v1, i1, v2, i2, v3, suffix, sanitizer, namespace) { |
| var index = getSelectedIndex(); |
| var lView = getLView(); |
| // TODO(FW-1340): Refactor to remove the use of other instructions here. |
| var interpolatedValue = ɵɵinterpolation4(prefix, v0, i0, v1, i1, v2, i2, v3, suffix); |
| if (interpolatedValue !== NO_CHANGE) { |
| elementAttributeInternal(index, attrName, interpolatedValue, lView, sanitizer, namespace); |
| } |
| return ɵɵattributeInterpolate4; |
| } |
| /** |
| * |
| * Update an interpolated attribute on an element with 5 bound values surrounded by text. |
| * |
| * Used when the value passed to a property has 5 interpolated values in it: |
| * |
| * ```html |
| * <div attr.title="prefix{{v0}}-{{v1}}-{{v2}}-{{v3}}-{{v4}}suffix"></div> |
| * ``` |
| * |
| * Its compiled representation is:: |
| * |
| * ```ts |
| * ɵɵattributeInterpolate5( |
| * 'title', 'prefix', v0, '-', v1, '-', v2, '-', v3, '-', v4, 'suffix'); |
| * ``` |
| * |
| * @param attrName The name of the attribute to update |
| * @param prefix Static value used for concatenation only. |
| * @param v0 Value checked for change. |
| * @param i0 Static value used for concatenation only. |
| * @param v1 Value checked for change. |
| * @param i1 Static value used for concatenation only. |
| * @param v2 Value checked for change. |
| * @param i2 Static value used for concatenation only. |
| * @param v3 Value checked for change. |
| * @param i3 Static value used for concatenation only. |
| * @param v4 Value checked for change. |
| * @param suffix Static value used for concatenation only. |
| * @param sanitizer An optional sanitizer function |
| * @returns itself, so that it may be chained. |
| * @codeGenApi |
| */ |
| function ɵɵattributeInterpolate5(attrName, prefix, v0, i0, v1, i1, v2, i2, v3, i3, v4, suffix, sanitizer, namespace) { |
| var index = getSelectedIndex(); |
| var lView = getLView(); |
| // TODO(FW-1340): Refactor to remove the use of other instructions here. |
| var interpolatedValue = ɵɵinterpolation5(prefix, v0, i0, v1, i1, v2, i2, v3, i3, v4, suffix); |
| if (interpolatedValue !== NO_CHANGE) { |
| elementAttributeInternal(index, attrName, interpolatedValue, lView, sanitizer, namespace); |
| } |
| return ɵɵattributeInterpolate5; |
| } |
| /** |
| * |
| * Update an interpolated attribute on an element with 6 bound values surrounded by text. |
| * |
| * Used when the value passed to a property has 6 interpolated values in it: |
| * |
| * ```html |
| * <div attr.title="prefix{{v0}}-{{v1}}-{{v2}}-{{v3}}-{{v4}}-{{v5}}suffix"></div> |
| * ``` |
| * |
| * Its compiled representation is:: |
| * |
| * ```ts |
| * ɵɵattributeInterpolate6( |
| * 'title', 'prefix', v0, '-', v1, '-', v2, '-', v3, '-', v4, '-', v5, 'suffix'); |
| * ``` |
| * |
| * @param attrName The name of the attribute to update |
| * @param prefix Static value used for concatenation only. |
| * @param v0 Value checked for change. |
| * @param i0 Static value used for concatenation only. |
| * @param v1 Value checked for change. |
| * @param i1 Static value used for concatenation only. |
| * @param v2 Value checked for change. |
| * @param i2 Static value used for concatenation only. |
| * @param v3 Value checked for change. |
| * @param i3 Static value used for concatenation only. |
| * @param v4 Value checked for change. |
| * @param i4 Static value used for concatenation only. |
| * @param v5 Value checked for change. |
| * @param suffix Static value used for concatenation only. |
| * @param sanitizer An optional sanitizer function |
| * @returns itself, so that it may be chained. |
| * @codeGenApi |
| */ |
| function ɵɵattributeInterpolate6(attrName, prefix, v0, i0, v1, i1, v2, i2, v3, i3, v4, i4, v5, suffix, sanitizer, namespace) { |
| var index = getSelectedIndex(); |
| var lView = getLView(); |
| // TODO(FW-1340): Refactor to remove the use of other instructions here. |
| var interpolatedValue = ɵɵinterpolation6(prefix, v0, i0, v1, i1, v2, i2, v3, i3, v4, i4, v5, suffix); |
| if (interpolatedValue !== NO_CHANGE) { |
| elementAttributeInternal(index, attrName, interpolatedValue, lView, sanitizer, namespace); |
| } |
| return ɵɵattributeInterpolate6; |
| } |
| /** |
| * |
| * Update an interpolated attribute on an element with 7 bound values surrounded by text. |
| * |
| * Used when the value passed to a property has 7 interpolated values in it: |
| * |
| * ```html |
| * <div attr.title="prefix{{v0}}-{{v1}}-{{v2}}-{{v3}}-{{v4}}-{{v5}}-{{v6}}suffix"></div> |
| * ``` |
| * |
| * Its compiled representation is:: |
| * |
| * ```ts |
| * ɵɵattributeInterpolate7( |
| * 'title', 'prefix', v0, '-', v1, '-', v2, '-', v3, '-', v4, '-', v5, '-', v6, 'suffix'); |
| * ``` |
| * |
| * @param attrName The name of the attribute to update |
| * @param prefix Static value used for concatenation only. |
| * @param v0 Value checked for change. |
| * @param i0 Static value used for concatenation only. |
| * @param v1 Value checked for change. |
| * @param i1 Static value used for concatenation only. |
| * @param v2 Value checked for change. |
| * @param i2 Static value used for concatenation only. |
| * @param v3 Value checked for change. |
| * @param i3 Static value used for concatenation only. |
| * @param v4 Value checked for change. |
| * @param i4 Static value used for concatenation only. |
| * @param v5 Value checked for change. |
| * @param i5 Static value used for concatenation only. |
| * @param v6 Value checked for change. |
| * @param suffix Static value used for concatenation only. |
| * @param sanitizer An optional sanitizer function |
| * @returns itself, so that it may be chained. |
| * @codeGenApi |
| */ |
| function ɵɵattributeInterpolate7(attrName, prefix, v0, i0, v1, i1, v2, i2, v3, i3, v4, i4, v5, i5, v6, suffix, sanitizer, namespace) { |
| var index = getSelectedIndex(); |
| var lView = getLView(); |
| // TODO(FW-1340): Refactor to remove the use of other instructions here. |
| var interpolatedValue = ɵɵinterpolation7(prefix, v0, i0, v1, i1, v2, i2, v3, i3, v4, i4, v5, i5, v6, suffix); |
| if (interpolatedValue !== NO_CHANGE) { |
| elementAttributeInternal(index, attrName, interpolatedValue, lView, sanitizer, namespace); |
| } |
| return ɵɵattributeInterpolate7; |
| } |
| /** |
| * |
| * Update an interpolated attribute on an element with 8 bound values surrounded by text. |
| * |
| * Used when the value passed to a property has 8 interpolated values in it: |
| * |
| * ```html |
| * <div attr.title="prefix{{v0}}-{{v1}}-{{v2}}-{{v3}}-{{v4}}-{{v5}}-{{v6}}-{{v7}}suffix"></div> |
| * ``` |
| * |
| * Its compiled representation is:: |
| * |
| * ```ts |
| * ɵɵattributeInterpolate8( |
| * 'title', 'prefix', v0, '-', v1, '-', v2, '-', v3, '-', v4, '-', v5, '-', v6, '-', v7, 'suffix'); |
| * ``` |
| * |
| * @param attrName The name of the attribute to update |
| * @param prefix Static value used for concatenation only. |
| * @param v0 Value checked for change. |
| * @param i0 Static value used for concatenation only. |
| * @param v1 Value checked for change. |
| * @param i1 Static value used for concatenation only. |
| * @param v2 Value checked for change. |
| * @param i2 Static value used for concatenation only. |
| * @param v3 Value checked for change. |
| * @param i3 Static value used for concatenation only. |
| * @param v4 Value checked for change. |
| * @param i4 Static value used for concatenation only. |
| * @param v5 Value checked for change. |
| * @param i5 Static value used for concatenation only. |
| * @param v6 Value checked for change. |
| * @param i6 Static value used for concatenation only. |
| * @param v7 Value checked for change. |
| * @param suffix Static value used for concatenation only. |
| * @param sanitizer An optional sanitizer function |
| * @returns itself, so that it may be chained. |
| * @codeGenApi |
| */ |
| function ɵɵattributeInterpolate8(attrName, prefix, v0, i0, v1, i1, v2, i2, v3, i3, v4, i4, v5, i5, v6, i6, v7, suffix, sanitizer, namespace) { |
| var index = getSelectedIndex(); |
| var lView = getLView(); |
| // TODO(FW-1340): Refactor to remove the use of other instructions here. |
| var interpolatedValue = ɵɵinterpolation8(prefix, v0, i0, v1, i1, v2, i2, v3, i3, v4, i4, v5, i5, v6, i6, v7, suffix); |
| if (interpolatedValue !== NO_CHANGE) { |
| elementAttributeInternal(index, attrName, interpolatedValue, lView, sanitizer, namespace); |
| } |
| return ɵɵattributeInterpolate8; |
| } |
| /** |
| * Update an interpolated attribute on an element with 8 or more bound values surrounded by text. |
| * |
| * Used when the number of interpolated values exceeds 7. |
| * |
| * ```html |
| * <div |
| * title="prefix{{v0}}-{{v1}}-{{v2}}-{{v3}}-{{v4}}-{{v5}}-{{v6}}-{{v7}}-{{v8}}-{{v9}}suffix"></div> |
| * ``` |
| * |
| * Its compiled representation is:: |
| * |
| * ```ts |
| * ɵɵattributeInterpolateV( |
| * 'title', ['prefix', v0, '-', v1, '-', v2, '-', v3, '-', v4, '-', v5, '-', v6, '-', v7, '-', v9, |
| * 'suffix']); |
| * ``` |
| * |
| * @param attrName The name of the attribute to update. |
| * @param values The a collection of values and the strings in-between those values, beginning with |
| * a string prefix and ending with a string suffix. |
| * (e.g. `['prefix', value0, '-', value1, '-', value2, ..., value99, 'suffix']`) |
| * @param sanitizer An optional sanitizer function |
| * @returns itself, so that it may be chained. |
| * @codeGenApi |
| */ |
| function ɵɵattributeInterpolateV(attrName, values, sanitizer, namespace) { |
| var index = getSelectedIndex(); |
| var lView = getLView(); |
| // TODO(FW-1340): Refactor to remove the use of other instructions here. |
| var interpolated = ɵɵinterpolationV(values); |
| if (interpolated !== NO_CHANGE) { |
| elementAttributeInternal(index, attrName, interpolated, lView, sanitizer, namespace); |
| } |
| return ɵɵattributeInterpolateV; |
| } |
| |
| /** |
| * @license |
| * Copyright Google Inc. All Rights Reserved. |
| * |
| * Use of this source code is governed by an MIT-style license that can be |
| * found in the LICENSE file at https://angular.io/license |
| */ |
| /** |
| * Synchronously perform change detection on a component (and possibly its sub-components). |
| * |
| * This function triggers change detection in a synchronous way on a component. There should |
| * be very little reason to call this function directly since a preferred way to do change |
| * detection is to {@link markDirty} the component and wait for the scheduler to call this method |
| * at some future point in time. This is because a single user action often results in many |
| * components being invalidated and calling change detection on each component synchronously |
| * would be inefficient. It is better to wait until all components are marked as dirty and |
| * then perform single change detection across all of the components |
| * |
| * @param component The component which the change detection should be performed on. |
| */ |
| function detectChanges(component) { |
| var view = getComponentViewByInstance(component); |
| detectChangesInternal(view, component); |
| } |
| /** |
| * Mark the component as dirty (needing change detection). |
| * |
| * Marking a component dirty will schedule a change detection on this |
| * component at some point in the future. Marking an already dirty |
| * component as dirty is a noop. Only one outstanding change detection |
| * can be scheduled per component tree. (Two components bootstrapped with |
| * separate `renderComponent` will have separate schedulers) |
| * |
| * When the root component is bootstrapped with `renderComponent`, a scheduler |
| * can be provided. |
| * |
| * @param component Component to mark as dirty. |
| * |
| * @publicApi |
| */ |
| function markDirty(component) { |
| ngDevMode && assertDefined(component, 'component'); |
| var rootView = markViewDirty(getComponentViewByInstance(component)); |
| ngDevMode && assertDefined(rootView[CONTEXT], 'rootContext should be defined'); |
| scheduleTick(rootView[CONTEXT], 1 /* DetectChanges */); |
| } |
| |
| /** |
| * @license |
| * Copyright Google Inc. All Rights Reserved. |
| * |
| * Use of this source code is governed by an MIT-style license that can be |
| * found in the LICENSE file at https://angular.io/license |
| */ |
| function getLContainer(tNode, embeddedView) { |
| ngDevMode && assertLView(embeddedView); |
| var container = embeddedView[PARENT]; |
| if (tNode.index === -1) { |
| // This is a dynamically created view inside a dynamic container. |
| // The parent isn't an LContainer if the embedded view hasn't been attached yet. |
| return isLContainer(container) ? container : null; |
| } |
| else { |
| ngDevMode && assertLContainer(container); |
| // This is a inline view node (e.g. embeddedViewStart) |
| return container; |
| } |
| } |
| /** |
| * Retrieves render parent for a given view. |
| * Might be null if a view is not yet attached to any container. |
| */ |
| function getContainerRenderParent(tViewNode, view) { |
| var container = getLContainer(tViewNode, view); |
| return container ? nativeParentNode(view[RENDERER], container[NATIVE]) : null; |
| } |
| /** |
| * NOTE: for performance reasons, the possible actions are inlined within the function instead of |
| * being passed as an argument. |
| */ |
| function executeActionOnElementOrContainer(action, renderer, parent, lNodeToHandle, beforeNode) { |
| ngDevMode && assertDefined(lNodeToHandle, '\'lNodeToHandle\' is undefined'); |
| var lContainer; |
| var isComponent = false; |
| // We are expecting an RNode, but in the case of a component or LContainer the `RNode` is wrapped |
| // in an array which needs to be unwrapped. We need to know if it is a component and if |
| // it has LContainer so that we can process all of those cases appropriately. |
| if (isLContainer(lNodeToHandle)) { |
| lContainer = lNodeToHandle; |
| } |
| else if (isLView(lNodeToHandle)) { |
| isComponent = true; |
| ngDevMode && assertDefined(lNodeToHandle[HOST], 'HOST must be defined for a component LView'); |
| lNodeToHandle = lNodeToHandle[HOST]; |
| } |
| var rNode = unwrapRNode(lNodeToHandle); |
| ngDevMode && assertDomNode(rNode); |
| if (action === 0 /* Insert */) { |
| nativeInsertBefore(renderer, parent, rNode, beforeNode || null); |
| } |
| else if (action === 1 /* Detach */) { |
| nativeRemoveNode(renderer, rNode, isComponent); |
| } |
| else if (action === 2 /* Destroy */) { |
| ngDevMode && ngDevMode.rendererDestroyNode++; |
| renderer.destroyNode(rNode); |
| } |
| if (lContainer != null) { |
| executeActionOnContainer(renderer, action, lContainer, parent, beforeNode); |
| } |
| } |
| function createTextNode(value, renderer) { |
| return isProceduralRenderer(renderer) ? renderer.createText(renderStringify(value)) : |
| renderer.createTextNode(renderStringify(value)); |
| } |
| function addRemoveViewFromContainer(lView, insertMode, beforeNode) { |
| var renderParent = getContainerRenderParent(lView[TVIEW].node, lView); |
| ngDevMode && assertNodeType(lView[TVIEW].node, 2 /* View */); |
| if (renderParent) { |
| var renderer = lView[RENDERER]; |
| var action = insertMode ? 0 /* Insert */ : 1 /* Detach */; |
| executeActionOnView(renderer, action, lView, renderParent, beforeNode); |
| } |
| } |
| /** |
| * Detach a `LView` from the DOM by detaching its nodes. |
| * |
| * @param lView the `LView` to be detached. |
| */ |
| function renderDetachView(lView) { |
| executeActionOnView(lView[RENDERER], 1 /* Detach */, lView, null, null); |
| } |
| /** |
| * Traverses down and up the tree of views and containers to remove listeners and |
| * call onDestroy callbacks. |
| * |
| * Notes: |
| * - Because it's used for onDestroy calls, it needs to be bottom-up. |
| * - Must process containers instead of their views to avoid splicing |
| * when views are destroyed and re-added. |
| * - Using a while loop because it's faster than recursion |
| * - Destroy only called on movement to sibling or movement to parent (laterally or up) |
| * |
| * @param rootView The view to destroy |
| */ |
| function destroyViewTree(rootView) { |
| // If the view has no children, we can clean it up and return early. |
| var lViewOrLContainer = rootView[CHILD_HEAD]; |
| if (!lViewOrLContainer) { |
| return cleanUpView(rootView); |
| } |
| while (lViewOrLContainer) { |
| var next = null; |
| if (isLView(lViewOrLContainer)) { |
| // If LView, traverse down to child. |
| next = lViewOrLContainer[CHILD_HEAD]; |
| } |
| else { |
| ngDevMode && assertLContainer(lViewOrLContainer); |
| // If container, traverse down to its first LView. |
| var firstView = lViewOrLContainer[CONTAINER_HEADER_OFFSET]; |
| if (firstView) |
| next = firstView; |
| } |
| if (!next) { |
| // Only clean up view when moving to the side or up, as destroy hooks |
| // should be called in order from the bottom up. |
| while (lViewOrLContainer && !lViewOrLContainer[NEXT] && lViewOrLContainer !== rootView) { |
| cleanUpView(lViewOrLContainer); |
| lViewOrLContainer = getParentState(lViewOrLContainer, rootView); |
| } |
| cleanUpView(lViewOrLContainer || rootView); |
| next = lViewOrLContainer && lViewOrLContainer[NEXT]; |
| } |
| lViewOrLContainer = next; |
| } |
| } |
| /** |
| * Inserts a view into a container. |
| * |
| * This adds the view to the container's array of active views in the correct |
| * position. It also adds the view's elements to the DOM if the container isn't a |
| * root node of another view (in that case, the view's elements will be added when |
| * the container's parent view is added later). |
| * |
| * @param lView The view to insert |
| * @param lContainer The container into which the view should be inserted |
| * @param index Which index in the container to insert the child view into |
| */ |
| function insertView(lView, lContainer, index) { |
| ngDevMode && assertLView(lView); |
| ngDevMode && assertLContainer(lContainer); |
| var indexInContainer = CONTAINER_HEADER_OFFSET + index; |
| var containerLength = lContainer.length; |
| if (index > 0) { |
| // This is a new view, we need to add it to the children. |
| lContainer[indexInContainer - 1][NEXT] = lView; |
| } |
| if (index < containerLength - CONTAINER_HEADER_OFFSET) { |
| lView[NEXT] = lContainer[indexInContainer]; |
| lContainer.splice(CONTAINER_HEADER_OFFSET + index, 0, lView); |
| } |
| else { |
| lContainer.push(lView); |
| lView[NEXT] = null; |
| } |
| lView[PARENT] = lContainer; |
| // Notify query that a new view has been added |
| if (lView[QUERIES]) { |
| lView[QUERIES].insertView(index); |
| } |
| // Sets the attached flag |
| lView[FLAGS] |= 128 /* Attached */; |
| } |
| /** |
| * Detaches a view from a container. |
| * |
| * This method splices the view from the container's array of active views. It also |
| * removes the view's elements from the DOM. |
| * |
| * @param lContainer The container from which to detach a view |
| * @param removeIndex The index of the view to detach |
| * @returns Detached LView instance. |
| */ |
| function detachView(lContainer, removeIndex) { |
| if (lContainer.length <= CONTAINER_HEADER_OFFSET) |
| return; |
| var indexInContainer = CONTAINER_HEADER_OFFSET + removeIndex; |
| var viewToDetach = lContainer[indexInContainer]; |
| if (viewToDetach) { |
| if (removeIndex > 0) { |
| lContainer[indexInContainer - 1][NEXT] = viewToDetach[NEXT]; |
| } |
| lContainer.splice(CONTAINER_HEADER_OFFSET + removeIndex, 1); |
| addRemoveViewFromContainer(viewToDetach, false); |
| if ((viewToDetach[FLAGS] & 128 /* Attached */) && |
| !(viewToDetach[FLAGS] & 256 /* Destroyed */) && viewToDetach[QUERIES]) { |
| viewToDetach[QUERIES].removeView(); |
| } |
| viewToDetach[PARENT] = null; |
| viewToDetach[NEXT] = null; |
| // Unsets the attached flag |
| viewToDetach[FLAGS] &= ~128 /* Attached */; |
| } |
| return viewToDetach; |
| } |
| /** |
| * Removes a view from a container, i.e. detaches it and then destroys the underlying LView. |
| * |
| * @param lContainer The container from which to remove a view |
| * @param removeIndex The index of the view to remove |
| */ |
| function removeView(lContainer, removeIndex) { |
| var detachedView = detachView(lContainer, removeIndex); |
| detachedView && destroyLView(detachedView); |
| } |
| /** |
| * A standalone function which destroys an LView, |
| * conducting cleanup (e.g. removing listeners, calling onDestroys). |
| * |
| * @param lView The view to be destroyed. |
| */ |
| function destroyLView(lView) { |
| if (!(lView[FLAGS] & 256 /* Destroyed */)) { |
| var renderer = lView[RENDERER]; |
| if (isProceduralRenderer(renderer) && renderer.destroyNode) { |
| executeActionOnView(renderer, 2 /* Destroy */, lView, null, null); |
| } |
| destroyViewTree(lView); |
| } |
| } |
| /** |
| * Determines which LViewOrLContainer to jump to when traversing back up the |
| * tree in destroyViewTree. |
| * |
| * Normally, the view's parent LView should be checked, but in the case of |
| * embedded views, the container (which is the view node's parent, but not the |
| * LView's parent) needs to be checked for a possible next property. |
| * |
| * @param lViewOrLContainer The LViewOrLContainer for which we need a parent state |
| * @param rootView The rootView, so we don't propagate too far up the view tree |
| * @returns The correct parent LViewOrLContainer |
| */ |
| function getParentState(lViewOrLContainer, rootView) { |
| var tNode; |
| if (isLView(lViewOrLContainer) && (tNode = lViewOrLContainer[T_HOST]) && |
| tNode.type === 2 /* View */) { |
| // if it's an embedded view, the state needs to go up to the container, in case the |
| // container has a next |
| return getLContainer(tNode, lViewOrLContainer); |
| } |
| else { |
| // otherwise, use parent view for containers or component views |
| return lViewOrLContainer[PARENT] === rootView ? null : lViewOrLContainer[PARENT]; |
| } |
| } |
| /** |
| * Calls onDestroys hooks for all directives and pipes in a given view and then removes all |
| * listeners. Listeners are removed as the last step so events delivered in the onDestroys hooks |
| * can be propagated to @Output listeners. |
| * |
| * @param view The LView to clean up |
| */ |
| function cleanUpView(view) { |
| if (isLView(view) && !(view[FLAGS] & 256 /* Destroyed */)) { |
| // Usually the Attached flag is removed when the view is detached from its parent, however |
| // if it's a root view, the flag won't be unset hence why we're also removing on destroy. |
| view[FLAGS] &= ~128 /* Attached */; |
| // Mark the LView as destroyed *before* executing the onDestroy hooks. An onDestroy hook |
| // runs arbitrary user code, which could include its own `viewRef.destroy()` (or similar). If |
| // We don't flag the view as destroyed before the hooks, this could lead to an infinite loop. |
| // This also aligns with the ViewEngine behavior. It also means that the onDestroy hook is |
| // really more of an "afterDestroy" hook if you think about it. |
| view[FLAGS] |= 256 /* Destroyed */; |
| executeOnDestroys(view); |
| removeListeners(view); |
| var hostTNode = view[T_HOST]; |
| // For component views only, the local renderer is destroyed as clean up time. |
| if (hostTNode && hostTNode.type === 3 /* Element */ && isProceduralRenderer(view[RENDERER])) { |
| ngDevMode && ngDevMode.rendererDestroy++; |
| view[RENDERER].destroy(); |
| } |
| // For embedded views still attached to a container: remove query result from this view. |
| if (viewAttachedToContainer(view) && view[QUERIES]) { |
| view[QUERIES].removeView(); |
| } |
| } |
| } |
| /** Removes listeners and unsubscribes from output subscriptions */ |
| function removeListeners(lView) { |
| var tCleanup = lView[TVIEW].cleanup; |
| if (tCleanup !== null) { |
| var lCleanup = lView[CLEANUP]; |
| for (var i = 0; i < tCleanup.length - 1; i += 2) { |
| if (typeof tCleanup[i] === 'string') { |
| // This is a native DOM listener |
| var idxOrTargetGetter = tCleanup[i + 1]; |
| var target = typeof idxOrTargetGetter === 'function' ? |
| idxOrTargetGetter(lView) : |
| unwrapRNode(lView[idxOrTargetGetter]); |
| var listener = lCleanup[tCleanup[i + 2]]; |
| var useCaptureOrSubIdx = tCleanup[i + 3]; |
| if (typeof useCaptureOrSubIdx === 'boolean') { |
| // native DOM listener registered with Renderer3 |
| target.removeEventListener(tCleanup[i], listener, useCaptureOrSubIdx); |
| } |
| else { |
| if (useCaptureOrSubIdx >= 0) { |
| // unregister |
| lCleanup[useCaptureOrSubIdx](); |
| } |
| else { |
| // Subscription |
| lCleanup[-useCaptureOrSubIdx].unsubscribe(); |
| } |
| } |
| i += 2; |
| } |
| else { |
| // This is a cleanup function that is grouped with the index of its context |
| var context = lCleanup[tCleanup[i + 1]]; |
| tCleanup[i].call(context); |
| } |
| } |
| lView[CLEANUP] = null; |
| } |
| } |
| /** Calls onDestroy hooks for this view */ |
| function executeOnDestroys(view) { |
| var tView = view[TVIEW]; |
| var destroyHooks; |
| if (tView != null && (destroyHooks = tView.destroyHooks) != null) { |
| for (var i = 0; i < destroyHooks.length; i += 2) { |
| var context = view[destroyHooks[i]]; |
| // Only call the destroy hook if the context has been requested. |
| if (!(context instanceof NodeInjectorFactory)) { |
| destroyHooks[i + 1].call(context); |
| } |
| } |
| } |
| } |
| /** |
| * Returns a native element if a node can be inserted into the given parent. |
| * |
| * There are two reasons why we may not be able to insert a element immediately. |
| * - Projection: When creating a child content element of a component, we have to skip the |
| * insertion because the content of a component will be projected. |
| * `<component><content>delayed due to projection</content></component>` |
| * - Parent container is disconnected: This can happen when we are inserting a view into |
| * parent container, which itself is disconnected. For example the parent container is part |
| * of a View which has not be inserted or is made for projection but has not been inserted |
| * into destination. |
| */ |
| function getRenderParent(tNode, currentView) { |
| // Nodes of the top-most view can be inserted eagerly. |
| if (isRootView(currentView)) { |
| return nativeParentNode(currentView[RENDERER], getNativeByTNode(tNode, currentView)); |
| } |
| // Skip over element and ICU containers as those are represented by a comment node and |
| // can't be used as a render parent. |
| var parent = getHighestElementOrICUContainer(tNode); |
| var renderParent = parent.parent; |
| // If the parent is null, then we are inserting across views: either into an embedded view or a |
| // component view. |
| if (renderParent == null) { |
| var hostTNode = currentView[T_HOST]; |
| if (hostTNode.type === 2 /* View */) { |
| // We are inserting a root element of an embedded view We might delay insertion of children |
| // for a given view if it is disconnected. This might happen for 2 main reasons: |
| // - view is not inserted into any container(view was created but not inserted yet) |
| // - view is inserted into a container but the container itself is not inserted into the DOM |
| // (container might be part of projection or child of a view that is not inserted yet). |
| // In other words we can insert children of a given view if this view was inserted into a |
| // container and the container itself has its render parent determined. |
| return getContainerRenderParent(hostTNode, currentView); |
| } |
| else { |
| // We are inserting a root element of the component view into the component host element and |
| // it should always be eager. |
| return getHostNative(currentView); |
| } |
| } |
| else { |
| var isIcuCase = parent && parent.type === 5 /* IcuContainer */; |
| // If the parent of this node is an ICU container, then it is represented by comment node and we |
| // need to use it as an anchor. If it is projected then its direct parent node is the renderer. |
| if (isIcuCase && parent.flags & 2 /* isProjected */) { |
| return getNativeByTNode(parent, currentView).parentNode; |
| } |
| ngDevMode && assertNodeType(renderParent, 3 /* Element */); |
| if (renderParent.flags & 1 /* isComponent */ && !isIcuCase) { |
| var tData = currentView[TVIEW].data; |
| var tNode_1 = tData[renderParent.index]; |
| var encapsulation = tData[tNode_1.directiveStart].encapsulation; |
| // We've got a parent which is an element in the current view. We just need to verify if the |
| // parent element is not a component. Component's content nodes are not inserted immediately |
| // because they will be projected, and so doing insert at this point would be wasteful. |
| // Since the projection would then move it to its final destination. Note that we can't |
| // make this assumption when using the Shadow DOM, because the native projection placeholders |
| // (<content> or <slot>) have to be in place as elements are being inserted. |
| if (encapsulation !== exports.ViewEncapsulation.ShadowDom && |
| encapsulation !== exports.ViewEncapsulation.Native) { |
| return null; |
| } |
| } |
| return getNativeByTNode(renderParent, currentView); |
| } |
| } |
| /** |
| * Gets the native host element for a given view. Will return null if the current view does not have |
| * a host element. |
| */ |
| function getHostNative(currentView) { |
| ngDevMode && assertLView(currentView); |
| var hostTNode = currentView[T_HOST]; |
| return hostTNode && hostTNode.type === 3 /* Element */ ? |
| getNativeByTNode(hostTNode, getLViewParent(currentView)) : |
| null; |
| } |
| /** |
| * Inserts a native node before another native node for a given parent using {@link Renderer3}. |
| * This is a utility function that can be used when native nodes were determined - it abstracts an |
| * actual renderer being used. |
| */ |
| function nativeInsertBefore(renderer, parent, child, beforeNode) { |
| ngDevMode && ngDevMode.rendererInsertBefore++; |
| if (isProceduralRenderer(renderer)) { |
| renderer.insertBefore(parent, child, beforeNode); |
| } |
| else { |
| parent.insertBefore(child, beforeNode, true); |
| } |
| } |
| function nativeAppendChild(renderer, parent, child) { |
| ngDevMode && ngDevMode.rendererAppendChild++; |
| if (isProceduralRenderer(renderer)) { |
| renderer.appendChild(parent, child); |
| } |
| else { |
| parent.appendChild(child); |
| } |
| } |
| function nativeAppendOrInsertBefore(renderer, parent, child, beforeNode) { |
| if (beforeNode !== null) { |
| nativeInsertBefore(renderer, parent, child, beforeNode); |
| } |
| else { |
| nativeAppendChild(renderer, parent, child); |
| } |
| } |
| /** Removes a node from the DOM given its native parent. */ |
| function nativeRemoveChild(renderer, parent, child, isHostElement) { |
| if (isProceduralRenderer(renderer)) { |
| renderer.removeChild(parent, child, isHostElement); |
| } |
| else { |
| parent.removeChild(child); |
| } |
| } |
| /** |
| * Returns a native parent of a given native node. |
| */ |
| function nativeParentNode(renderer, node) { |
| return (isProceduralRenderer(renderer) ? renderer.parentNode(node) : node.parentNode); |
| } |
| /** |
| * Returns a native sibling of a given native node. |
| */ |
| function nativeNextSibling(renderer, node) { |
| return isProceduralRenderer(renderer) ? renderer.nextSibling(node) : node.nextSibling; |
| } |
| /** |
| * Finds a native "anchor" node for cases where we can't append a native child directly |
| * (`appendChild`) and need to use a reference (anchor) node for the `insertBefore` operation. |
| * @param parentTNode |
| * @param lView |
| */ |
| function getNativeAnchorNode(parentTNode, lView) { |
| if (parentTNode.type === 2 /* View */) { |
| var lContainer = getLContainer(parentTNode, lView); |
| var index = lContainer.indexOf(lView, CONTAINER_HEADER_OFFSET) - CONTAINER_HEADER_OFFSET; |
| return getBeforeNodeForView(index, lContainer); |
| } |
| else if (parentTNode.type === 4 /* ElementContainer */ || |
| parentTNode.type === 5 /* IcuContainer */) { |
| return getNativeByTNode(parentTNode, lView); |
| } |
| return null; |
| } |
| /** |
| * Appends the `child` native node (or a collection of nodes) to the `parent`. |
| * |
| * The element insertion might be delayed {@link canInsertNativeNode}. |
| * |
| * @param childEl The native child (or children) that should be appended |
| * @param childTNode The TNode of the child element |
| * @param currentView The current LView |
| * @returns Whether or not the child was appended |
| */ |
| function appendChild(childEl, childTNode, currentView) { |
| var e_1, _a; |
| var renderParent = getRenderParent(childTNode, currentView); |
| if (renderParent != null) { |
| var renderer = currentView[RENDERER]; |
| var parentTNode = childTNode.parent || currentView[T_HOST]; |
| var anchorNode = getNativeAnchorNode(parentTNode, currentView); |
| if (Array.isArray(childEl)) { |
| try { |
| for (var childEl_1 = __values(childEl), childEl_1_1 = childEl_1.next(); !childEl_1_1.done; childEl_1_1 = childEl_1.next()) { |
| var nativeNode = childEl_1_1.value; |
| nativeAppendOrInsertBefore(renderer, renderParent, nativeNode, anchorNode); |
| } |
| } |
| catch (e_1_1) { e_1 = { error: e_1_1 }; } |
| finally { |
| try { |
| if (childEl_1_1 && !childEl_1_1.done && (_a = childEl_1.return)) _a.call(childEl_1); |
| } |
| finally { if (e_1) throw e_1.error; } |
| } |
| } |
| else { |
| nativeAppendOrInsertBefore(renderer, renderParent, childEl, anchorNode); |
| } |
| } |
| } |
| /** |
| * Gets the top-level element or an ICU container if those containers are nested. |
| * |
| * @param tNode The starting TNode for which we should skip element and ICU containers |
| * @returns The TNode of the highest level ICU container or element container |
| */ |
| function getHighestElementOrICUContainer(tNode) { |
| while (tNode.parent != null && (tNode.parent.type === 4 /* ElementContainer */ || |
| tNode.parent.type === 5 /* IcuContainer */)) { |
| tNode = tNode.parent; |
| } |
| return tNode; |
| } |
| function getBeforeNodeForView(viewIndexInContainer, lContainer) { |
| var nextViewIndex = CONTAINER_HEADER_OFFSET + viewIndexInContainer + 1; |
| if (nextViewIndex < lContainer.length) { |
| var lView = lContainer[nextViewIndex]; |
| ngDevMode && assertDefined(lView[T_HOST], 'Missing Host TNode'); |
| var tViewNodeChild = lView[T_HOST].child; |
| return tViewNodeChild !== null ? getNativeByTNode(tViewNodeChild, lView) : lContainer[NATIVE]; |
| } |
| else { |
| return lContainer[NATIVE]; |
| } |
| } |
| /** |
| * Removes a native node itself using a given renderer. To remove the node we are looking up its |
| * parent from the native tree as not all platforms / browsers support the equivalent of |
| * node.remove(). |
| * |
| * @param renderer A renderer to be used |
| * @param rNode The native node that should be removed |
| * @param isHostElement A flag indicating if a node to be removed is a host of a component. |
| */ |
| function nativeRemoveNode(renderer, rNode, isHostElement) { |
| var nativeParent = nativeParentNode(renderer, rNode); |
| if (nativeParent) { |
| nativeRemoveChild(renderer, nativeParent, rNode, isHostElement); |
| } |
| } |
| /** |
| * Appends nodes to a target projection place. Nodes to insert were previously re-distribution and |
| * stored on a component host level. |
| * @param lView A LView where nodes are inserted (target LView) |
| * @param tProjectionNode A projection node where previously re-distribution should be appended |
| * (target insertion place) |
| * @param selectorIndex A bucket from where nodes to project should be taken |
| * @param componentView A where projectable nodes were initially created (source view) |
| */ |
| function appendProjectedNodes(lView, tProjectionNode, selectorIndex, componentView) { |
| var projectedView = componentView[PARENT]; |
| var componentNode = componentView[T_HOST]; |
| var nodeToProject = componentNode.projection[selectorIndex]; |
| if (Array.isArray(nodeToProject)) { |
| appendChild(nodeToProject, tProjectionNode, lView); |
| } |
| else { |
| while (nodeToProject) { |
| if (!(nodeToProject.flags & 32 /* isDetached */)) { |
| if (nodeToProject.type === 1 /* Projection */) { |
| appendProjectedNodes(lView, tProjectionNode, nodeToProject.projection, findComponentView(projectedView)); |
| } |
| else { |
| // This flag must be set now or we won't know that this node is projected |
| // if the nodes are inserted into a container later. |
| nodeToProject.flags |= 2 /* isProjected */; |
| appendProjectedNode(nodeToProject, tProjectionNode, lView, projectedView); |
| } |
| } |
| nodeToProject = nodeToProject.projectionNext; |
| } |
| } |
| } |
| /** |
| * Loops over all children of a TNode container and appends them to the DOM |
| * |
| * @param ngContainerChildTNode The first child of the TNode container |
| * @param tProjectionNode The projection (ng-content) TNode |
| * @param currentView Current LView |
| * @param projectionView Projection view (view above current) |
| */ |
| function appendProjectedChildren(ngContainerChildTNode, tProjectionNode, currentView, projectionView) { |
| while (ngContainerChildTNode) { |
| appendProjectedNode(ngContainerChildTNode, tProjectionNode, currentView, projectionView); |
| ngContainerChildTNode = ngContainerChildTNode.next; |
| } |
| } |
| /** |
| * Appends a projected node to the DOM, or in the case of a projected container, |
| * appends the nodes from all of the container's active views to the DOM. |
| * |
| * @param projectedTNode The TNode to be projected |
| * @param tProjectionNode The projection (ng-content) TNode |
| * @param currentView Current LView |
| * @param projectionView Projection view (view above current) |
| */ |
| function appendProjectedNode(projectedTNode, tProjectionNode, currentView, projectionView) { |
| var native = getNativeByTNode(projectedTNode, projectionView); |
| appendChild(native, tProjectionNode, currentView); |
| // the projected contents are processed while in the shadow view (which is the currentView) |
| // therefore we need to extract the view where the host element lives since it's the |
| // logical container of the content projected views |
| attachPatchData(native, projectionView); |
| var nodeOrContainer = projectionView[projectedTNode.index]; |
| if (projectedTNode.type === 0 /* Container */) { |
| // The node we are adding is a container and we are adding it to an element which |
| // is not a component (no more re-projection). |
| // Alternatively a container is projected at the root of a component's template |
| // and can't be re-projected (as not content of any component). |
| // Assign the final projection location in those cases. |
| for (var i = CONTAINER_HEADER_OFFSET; i < nodeOrContainer.length; i++) { |
| addRemoveViewFromContainer(nodeOrContainer[i], true, nodeOrContainer[NATIVE]); |
| } |
| } |
| else if (projectedTNode.type === 5 /* IcuContainer */) { |
| // The node we are adding is an ICU container which is why we also need to project all the |
| // children nodes that might have been created previously and are linked to this anchor |
| var ngContainerChildTNode = projectedTNode.child; |
| appendProjectedChildren(ngContainerChildTNode, ngContainerChildTNode, projectionView, projectionView); |
| } |
| else { |
| if (projectedTNode.type === 4 /* ElementContainer */) { |
| appendProjectedChildren(projectedTNode.child, tProjectionNode, currentView, projectionView); |
| } |
| if (isLContainer(nodeOrContainer)) { |
| appendChild(nodeOrContainer[NATIVE], tProjectionNode, currentView); |
| } |
| } |
| } |
| /** |
| * `executeActionOnView` performs an operation on the view as specified in `action` (insert, detach, |
| * destroy) |
| * |
| * Inserting a view without projection or containers at top level is simple. Just iterate over the |
| * root nodes of the View, and for each node perform the `action`. |
| * |
| * Things get more complicated with containers and projections. That is because coming across: |
| * - Container: implies that we have to insert/remove/destroy the views of that container as well |
| * which in turn can have their own Containers at the View roots. |
| * - Projection: implies that we have to insert/remove/destroy the nodes of the projection. The |
| * complication is that the nodes we are projecting can themselves have Containers |
| * or other Projections. |
| * |
| * As you can see this is a very recursive problem. While the recursive implementation is not the |
| * most efficient one, trying to unroll the nodes non-recursively results in very complex code that |
| * is very hard (to maintain). We are sacrificing a bit of performance for readability using a |
| * recursive implementation. |
| * |
| * @param renderer Renderer to use |
| * @param action action to perform (insert, detach, destroy) |
| * @param lView The LView which needs to be inserted, detached, destroyed. |
| * @param renderParent parent DOM element for insertion/removal. |
| * @param beforeNode Before which node the insertions should happen. |
| */ |
| function executeActionOnView(renderer, action, lView, renderParent, beforeNode) { |
| var tView = lView[TVIEW]; |
| ngDevMode && assertNodeType(tView.node, 2 /* View */); |
| var viewRootTNode = tView.node.child; |
| while (viewRootTNode !== null) { |
| executeActionOnNode(renderer, action, lView, viewRootTNode, renderParent, beforeNode); |
| viewRootTNode = viewRootTNode.next; |
| } |
| } |
| /** |
| * `executeActionOnProjection` performs an operation on the projection specified by `action` |
| * (insert, detach, destroy). |
| * |
| * Inserting a projection requires us to locate the projected nodes from the parent component. The |
| * complication is that those nodes themselves could be re-projected from their parent component. |
| * |
| * @param renderer Renderer to use |
| * @param action action to perform (insert, detach, destroy) |
| * @param lView The LView which needs to be inserted, detached, destroyed. |
| * @param renderParent parent DOM element for insertion/removal. |
| * @param beforeNode Before which node the insertions should happen. |
| */ |
| function executeActionOnProjection(renderer, action, lView, tProjectionNode, renderParent, beforeNode) { |
| var componentLView = findComponentView(lView); |
| var componentNode = componentLView[T_HOST]; |
| var nodeToProject = componentNode.projection[tProjectionNode.projection]; |
| if (Array.isArray(nodeToProject)) { |
| for (var i = 0; i < nodeToProject.length; i++) { |
| var rNode = nodeToProject[i]; |
| ngDevMode && assertDomNode(rNode); |
| executeActionOnElementOrContainer(action, renderer, renderParent, rNode, beforeNode); |
| } |
| } |
| else { |
| var projectionTNode = nodeToProject; |
| var projectedComponentLView = componentLView[PARENT]; |
| while (projectionTNode !== null) { |
| executeActionOnNode(renderer, action, projectedComponentLView, projectionTNode, renderParent, beforeNode); |
| projectionTNode = projectionTNode.projectionNext; |
| } |
| } |
| } |
| /** |
| * `executeActionOnContainer` performs an operation on the container and its views as specified by |
| * `action` (insert, detach, destroy) |
| * |
| * Inserting a Container is complicated by the fact that the container may have Views which |
| * themselves have containers or projections. |
| * |
| * @param renderer Renderer to use |
| * @param action action to perform (insert, detach, destroy) |
| * @param lContainer The LContainer which needs to be inserted, detached, destroyed. |
| * @param renderParent parent DOM element for insertion/removal. |
| * @param beforeNode Before which node the insertions should happen. |
| */ |
| function executeActionOnContainer(renderer, action, lContainer, renderParent, beforeNode) { |
| ngDevMode && assertLContainer(lContainer); |
| var anchor = lContainer[NATIVE]; // LContainer has its own before node. |
| var native = unwrapRNode(lContainer); |
| // An LContainer can be created dynamically on any node by injecting ViewContainerRef. |
| // Asking for a ViewContainerRef on an element will result in a creation of a separate anchor node |
| // (comment in the DOM) that will be different from the LContainer's host node. In this particular |
| // case we need to execute action on 2 nodes: |
| // - container's host node (this is done in the executeNodeAction) |
| // - container's host node (this is done here) |
| if (anchor !== native) { |
| executeActionOnElementOrContainer(action, renderer, renderParent, anchor, beforeNode); |
| } |
| for (var i = CONTAINER_HEADER_OFFSET; i < lContainer.length; i++) { |
| var lView = lContainer[i]; |
| executeActionOnView(renderer, action, lView, renderParent, anchor); |
| } |
| } |
| /** |
| * `executeActionOnElementContainer` performs an operation on the ng-container node and its child |
| * nodes as specified by the `action` (insert, detach, destroy). |
| * |
| * @param renderer Renderer to use |
| * @param action action to perform (insert, detach, destroy) |
| * @param lView The LView which needs to be inserted, detached, destroyed. |
| * @param tElementContainerNode The TNode associated with the ElementContainer. |
| * @param renderParent parent DOM element for insertion/removal. |
| * @param beforeNode Before which node the insertions should happen. |
| */ |
| function executeActionOnElementContainer(renderer, action, lView, tElementContainerNode, renderParent, beforeNode) { |
| var node = lView[tElementContainerNode.index]; |
| executeActionOnElementOrContainer(action, renderer, renderParent, node, beforeNode); |
| var childTNode = tElementContainerNode.child; |
| while (childTNode) { |
| executeActionOnNode(renderer, action, lView, childTNode, renderParent, beforeNode); |
| childTNode = childTNode.next; |
| } |
| } |
| function executeActionOnNode(renderer, action, lView, tNode, renderParent, beforeNode) { |
| var elementContainerRootTNodeType = tNode.type; |
| if (elementContainerRootTNodeType === 4 /* ElementContainer */) { |
| executeActionOnElementContainer(renderer, action, lView, tNode, renderParent, beforeNode); |
| } |
| else if (elementContainerRootTNodeType === 1 /* Projection */) { |
| executeActionOnProjection(renderer, action, lView, tNode, renderParent, beforeNode); |
| } |
| else { |
| ngDevMode && assertNodeOfPossibleTypes(tNode, 3 /* Element */, 0 /* Container */); |
| executeActionOnElementOrContainer(action, renderer, renderParent, lView[tNode.index], beforeNode); |
| } |
| } |
| |
| /** |
| * @license |
| * Copyright Google Inc. All Rights Reserved. |
| * |
| * Use of this source code is governed by an MIT-style license that can be |
| * found in the LICENSE file at https://angular.io/license |
| */ |
| /** |
| * Creates an LContainer for inline views, e.g. |
| * |
| * % if (showing) { |
| * <div></div> |
| * % } |
| * |
| * @param index The index of the container in the data array |
| * |
| * @codeGenApi |
| */ |
| function ɵɵcontainer(index) { |
| var tNode = containerInternal(index, null, null); |
| var lView = getLView(); |
| if (lView[TVIEW].firstTemplatePass) { |
| tNode.tViews = []; |
| } |
| addTContainerToQueries(lView, tNode); |
| setIsNotParent(); |
| } |
| /** |
| * Creates an LContainer for an ng-template (dynamically-inserted view), e.g. |
| * |
| * <ng-template #foo> |
| * <div></div> |
| * </ng-template> |
| * |
| * @param index The index of the container in the data array |
| * @param templateFn Inline template |
| * @param consts The number of nodes, local refs, and pipes for this template |
| * @param vars The number of bindings for this template |
| * @param tagName The name of the container element, if applicable |
| * @param attrs The attrs attached to the container, if applicable |
| * @param localRefs A set of local reference bindings on the element. |
| * @param localRefExtractor A function which extracts local-refs values from the template. |
| * Defaults to the current element associated with the local-ref. |
| * |
| * @codeGenApi |
| */ |
| function ɵɵtemplate(index, templateFn, consts, vars, tagName, attrs, localRefs, localRefExtractor) { |
| var lView = getLView(); |
| var tView = lView[TVIEW]; |
| // TODO: consider a separate node type for templates |
| var tContainerNode = containerInternal(index, tagName || null, attrs || null); |
| if (tView.firstTemplatePass) { |
| tContainerNode.tViews = createTView(-1, templateFn, consts, vars, tView.directiveRegistry, tView.pipeRegistry, null, null); |
| } |
| createDirectivesAndLocals(tView, lView, localRefs, localRefExtractor); |
| addTContainerToQueries(lView, tContainerNode); |
| attachPatchData(getNativeByTNode(tContainerNode, lView), lView); |
| registerPostOrderHooks(tView, tContainerNode); |
| setIsNotParent(); |
| } |
| /** |
| * Sets a container up to receive views. |
| * |
| * @param index The index of the container in the data array |
| * |
| * @codeGenApi |
| */ |
| function ɵɵcontainerRefreshStart(index) { |
| var lView = getLView(); |
| var tView = lView[TVIEW]; |
| var previousOrParentTNode = loadInternal(tView.data, index); |
| ngDevMode && assertNodeType(previousOrParentTNode, 0 /* Container */); |
| setPreviousOrParentTNode(previousOrParentTNode, true); |
| lView[index + HEADER_OFFSET][ACTIVE_INDEX] = 0; |
| // We need to execute init hooks here so ngOnInit hooks are called in top level views |
| // before they are called in embedded views (for backwards compatibility). |
| executePreOrderHooks(lView, tView, getCheckNoChangesMode(), undefined); |
| } |
| /** |
| * Marks the end of the LContainer. |
| * |
| * Marking the end of LContainer is the time when to child views get inserted or removed. |
| * |
| * @codeGenApi |
| */ |
| function ɵɵcontainerRefreshEnd() { |
| var previousOrParentTNode = getPreviousOrParentTNode(); |
| if (getIsParent()) { |
| setIsNotParent(); |
| } |
| else { |
| ngDevMode && assertNodeType(previousOrParentTNode, 2 /* View */); |
| ngDevMode && assertHasParent(previousOrParentTNode); |
| previousOrParentTNode = previousOrParentTNode.parent; |
| setPreviousOrParentTNode(previousOrParentTNode, false); |
| } |
| ngDevMode && assertNodeType(previousOrParentTNode, 0 /* Container */); |
| var lContainer = getLView()[previousOrParentTNode.index]; |
| var nextIndex = lContainer[ACTIVE_INDEX]; |
| // remove extra views at the end of the container |
| while (nextIndex < lContainer.length - CONTAINER_HEADER_OFFSET) { |
| removeView(lContainer, nextIndex); |
| } |
| } |
| /** |
| * Reporting a TContainer node queries is a 2-step process as we need to: |
| * - check if the container node itself is matching (query might match a <ng-template> node); |
| * - prepare room for nodes from views that might be created based on the TemplateRef linked to this |
| * container. |
| * |
| * Those 2 operations need to happen in the specific order (match the container node itself, then |
| * prepare space for nodes from views). |
| */ |
| function addTContainerToQueries(lView, tContainerNode) { |
| var queries = lView[QUERIES]; |
| if (queries) { |
| var lContainer = lView[tContainerNode.index]; |
| if (lContainer[QUERIES]) { |
| // Query container should only exist if it was created through a dynamic view |
| // in a directive constructor. In this case, we must splice the template |
| // matches in before the view matches to ensure query results in embedded views |
| // don't clobber query results on the template node itself. |
| queries.insertNodeBeforeViews(tContainerNode); |
| } |
| else { |
| queries.addNode(tContainerNode); |
| lContainer[QUERIES] = queries.container(); |
| } |
| } |
| } |
| function containerInternal(index, tagName, attrs) { |
| var lView = getLView(); |
| ngDevMode && assertEqual(lView[BINDING_INDEX], lView[TVIEW].bindingStartIndex, 'container nodes should be created before any bindings'); |
| var adjustedIndex = index + HEADER_OFFSET; |
| ngDevMode && assertDataInRange(lView, index + HEADER_OFFSET); |
| ngDevMode && ngDevMode.rendererCreateComment++; |
| var comment = lView[index + HEADER_OFFSET] = |
| lView[RENDERER].createComment(ngDevMode ? 'container' : ''); |
| var tNode = getOrCreateTNode(lView[TVIEW], lView[T_HOST], index, 0 /* Container */, tagName, attrs); |
| var lContainer = lView[adjustedIndex] = |
| createLContainer(lView[adjustedIndex], lView, comment, tNode); |
| appendChild(comment, tNode, lView); |
| // Containers are added to the current view tree instead of their embedded views |
| // because views can be removed and re-inserted. |
| addToViewTree(lView, lContainer); |
| ngDevMode && assertNodeType(getPreviousOrParentTNode(), 0 /* Container */); |
| return tNode; |
| } |
| |
| /** |
| * @license |
| * Copyright Google Inc. All Rights Reserved. |
| * |
| * Use of this source code is governed by an MIT-style license that can be |
| * found in the LICENSE file at https://angular.io/license |
| */ |
| /** Store a value in the `data` at a given `index`. */ |
| function store(index, value) { |
| var lView = getLView(); |
| var tView = lView[TVIEW]; |
| // We don't store any static data for local variables, so the first time |
| // we see the template, we should store as null to avoid a sparse array |
| var adjustedIndex = index + HEADER_OFFSET; |
| if (adjustedIndex >= tView.data.length) { |
| tView.data[adjustedIndex] = null; |
| tView.blueprint[adjustedIndex] = null; |
| } |
| lView[adjustedIndex] = value; |
| } |
| /** |
| * Retrieves a local reference from the current contextViewData. |
| * |
| * If the reference to retrieve is in a parent view, this instruction is used in conjunction |
| * with a nextContext() call, which walks up the tree and updates the contextViewData instance. |
| * |
| * @param index The index of the local ref in contextViewData. |
| * |
| * @codeGenApi |
| */ |
| function ɵɵreference(index) { |
| var contextLView = getContextLView(); |
| return loadInternal(contextLView, index); |
| } |
| /** |
| * Retrieves a value from current `viewData`. |
| * |
| * @codeGenApi |
| */ |
| function ɵɵload(index) { |
| return loadInternal(getLView(), index); |
| } |
| |
| /** |
| * @license |
| * Copyright Google Inc. All Rights Reserved. |
| * |
| * Use of this source code is governed by an MIT-style license that can be |
| * found in the LICENSE file at https://angular.io/license |
| */ |
| function ɵɵdirectiveInject(token, flags) { |
| if (flags === void 0) { flags = exports.InjectFlags.Default; } |
| token = resolveForwardRef(token); |
| var lView = getLView(); |
| // Fall back to inject() if view hasn't been created. This situation can happen in tests |
| // if inject utilities are used before bootstrapping. |
| if (lView == null) |
| return ɵɵinject(token, flags); |
| return getOrCreateInjectable(getPreviousOrParentTNode(), lView, token, flags); |
| } |
| /** |
| * Facade for the attribute injection from DI. |
| * |
| * @codeGenApi |
| */ |
| function ɵɵinjectAttribute(attrNameToInject) { |
| return injectAttributeImpl(getPreviousOrParentTNode(), attrNameToInject); |
| } |
| |
| /** |
| * -------- |
| * |
| * This file contains the core logic for how styling instructions are processed in Angular. |
| * |
| * To learn more about the algorithm see `TStylingContext`. |
| * |
| * -------- |
| */ |
| /** |
| * Temporary function to bridge styling functionality between this new |
| * refactor (which is here inside of `styling_next/`) and the old |
| * implementation (which lives inside of `styling/`). |
| * |
| * This function is executed during the creation block of an element. |
| * Because the existing styling implementation issues a call to the |
| * `styling()` instruction, this instruction will also get run. The |
| * central idea here is that the directive index values are bound |
| * into the context. The directive index is temporary and is only |
| * required until the `select(n)` instruction is fully functional. |
| */ |
| function stylingInit() { |
| var lView = getLView(); |
| var index = getSelectedIndex(); |
| var tNode = getTNode(index, lView); |
| updateLastDirectiveIndex(tNode, getActiveDirectiveStylingIndex()); |
| } |
| /** |
| * Sets the current style sanitizer function which will then be used |
| * within all follow-up prop and map-based style binding instructions |
| * for the given element. |
| * |
| * Note that once styling has been applied to the element (i.e. once |
| * `select(n)` is executed or the hostBindings/template function exits) |
| * then the active `sanitizerFn` will be set to `null`. This means that |
| * once styling is applied to another element then a another call to |
| * `styleSanitizer` will need to be made. |
| * |
| * @param sanitizerFn The sanitization function that will be used to |
| * process style prop/value entries. |
| * |
| * @codeGenApi |
| */ |
| function styleSanitizer(sanitizer) { |
| setCurrentStyleSanitizer(sanitizer); |
| } |
| /** |
| * Mirror implementation of the `styleProp()` instruction (found in `instructions/styling.ts`). |
| */ |
| function styleProp(prop, value, suffix) { |
| _stylingProp(prop, resolveStylePropValue(value, suffix), false); |
| } |
| /** |
| * Mirror implementation of the `classProp()` instruction (found in `instructions/styling.ts`). |
| */ |
| function classProp(className, value) { |
| _stylingProp(className, value, true); |
| } |
| /** |
| * Shared function used to update a prop-based styling binding for an element. |
| */ |
| function _stylingProp(prop, value, isClassBased) { |
| var index = getSelectedIndex(); |
| var lView = getLView(); |
| var bindingIndex = lView[BINDING_INDEX]++; |
| var tNode = getTNode(index, lView); |
| var defer = getActiveDirectiveSuperClassHeight() > 0; |
| if (isClassBased) { |
| updateClassBinding(getClassesContext(tNode), lView, prop, bindingIndex, value, defer, false); |
| } |
| else { |
| var sanitizer = getCurrentOrLViewSanitizer(lView); |
| updateStyleBinding(getStylesContext(tNode), lView, prop, bindingIndex, value, sanitizer, defer, false); |
| } |
| } |
| /** |
| * Mirror implementation of the `styleMap()` instruction (found in `instructions/styling.ts`). |
| */ |
| function styleMap(styles) { |
| _stylingMap(styles, false); |
| } |
| /** |
| * Mirror implementation of the `classMap()` instruction (found in `instructions/styling.ts`). |
| */ |
| function classMap(classes) { |
| _stylingMap(classes, true); |
| } |
| /** |
| * Shared function used to update a map-based styling binding for an element. |
| * |
| * When this function is called it will activate support for `[style]` and |
| * `[class]` bindings in Angular. |
| */ |
| function _stylingMap(value, isClassBased) { |
| activeStylingMapFeature(); |
| var index = getSelectedIndex(); |
| var lView = getLView(); |
| var bindingIndex = lView[BINDING_INDEX]++; |
| if (value !== NO_CHANGE) { |
| var tNode = getTNode(index, lView); |
| var defer = getActiveDirectiveSuperClassHeight() > 0; |
| var oldValue = lView[bindingIndex]; |
| var valueHasChanged = hasValueChanged$1(oldValue, value); |
| var lStylingMap = normalizeIntoStylingMap(oldValue, value); |
| if (isClassBased) { |
| updateClassBinding(getClassesContext(tNode), lView, null, bindingIndex, lStylingMap, defer, valueHasChanged); |
| } |
| else { |
| var sanitizer = getCurrentOrLViewSanitizer(lView); |
| updateStyleBinding(getStylesContext(tNode), lView, null, bindingIndex, lStylingMap, sanitizer, defer, valueHasChanged); |
| } |
| } |
| } |
| /** |
| * Temporary function to bridge styling functionality between this new |
| * refactor (which is here inside of `styling_next/`) and the old |
| * implementation (which lives inside of `styling/`). |
| * |
| * The new styling refactor ensures that styling flushing is called |
| * automatically when a template function exits or a follow-up element |
| * is visited (i.e. when `select(n)` is called). Because the `select(n)` |
| * instruction is not fully implemented yet (it doesn't actually execute |
| * host binding instruction code at the right time), this means that a |
| * styling apply function is still needed. |
| * |
| * This function is a mirror implementation of the `stylingApply()` |
| * instruction (found in `instructions/styling.ts`). |
| */ |
| function stylingApply() { |
| var index = getSelectedIndex(); |
| var lView = getLView(); |
| var tNode = getTNode(index, lView); |
| var renderer = getRenderer(tNode, lView); |
| var native = getNativeFromLView(index, lView); |
| var directiveIndex = getActiveDirectiveStylingIndex(); |
| applyClasses(renderer, lView, getClassesContext(tNode), native, directiveIndex); |
| var sanitizer = getCurrentOrLViewSanitizer(lView); |
| applyStyles(renderer, lView, getStylesContext(tNode), native, directiveIndex, sanitizer); |
| setCurrentStyleSanitizer(null); |
| } |
| /** |
| * Temporary function to bridge styling functionality between this new |
| * refactor (which is here inside of `styling_next/`) and the old |
| * implementation (which lives inside of `styling/`). |
| * |
| * The purpose of this function is to traverse through the LView data |
| * for a specific element index and return the native node. Because the |
| * current implementation relies on there being a styling context array, |
| * the code below will need to loop through these array values until it |
| * gets a native element node. |
| * |
| * Note that this code is temporary and will disappear once the new |
| * styling refactor lands in its entirety. |
| */ |
| function getNativeFromLView(index, viewData) { |
| var storageIndex = index + HEADER_OFFSET; |
| var slotValue = viewData[storageIndex]; |
| var wrapper = viewData; |
| while (Array.isArray(slotValue)) { |
| wrapper = slotValue; |
| slotValue = slotValue[HOST]; |
| } |
| if (isStylingContext(wrapper)) { |
| return wrapper[0 /* ElementPosition */]; |
| } |
| else { |
| return slotValue; |
| } |
| } |
| function getRenderer(tNode, lView) { |
| return tNode.type === 3 /* Element */ ? lView[RENDERER] : null; |
| } |
| /** |
| * Searches and assigns provided all static style/class entries (found in the `attrs` value) |
| * and registers them in their respective styling contexts. |
| */ |
| function registerInitialStylingIntoContext(tNode, attrs, startIndex) { |
| var classesContext; |
| var stylesContext; |
| var mode = -1; |
| for (var i = startIndex; i < attrs.length; i++) { |
| var attr = attrs[i]; |
| if (typeof attr == 'number') { |
| mode = attr; |
| } |
| else if (mode == 1 /* Classes */) { |
| classesContext = classesContext || getClassesContext(tNode); |
| registerBinding(classesContext, -1, attr, true, false); |
| } |
| else if (mode == 2 /* Styles */) { |
| stylesContext = stylesContext || getStylesContext(tNode); |
| registerBinding(stylesContext, -1, attr, attrs[++i], false); |
| } |
| } |
| } |
| /** |
| * Mirror implementation of the same function found in `instructions/styling.ts`. |
| */ |
| function getActiveDirectiveStylingIndex() { |
| // whenever a directive's hostBindings function is called a uniqueId value |
| // is assigned. Normally this is enough to help distinguish one directive |
| // from another for the styling context, but there are situations where a |
| // sub-class directive could inherit and assign styling in concert with a |
| // parent directive. To help the styling code distinguish between a parent |
| // sub-classed directive the inheritance depth is taken into account as well. |
| return getActiveDirectiveId() + getActiveDirectiveSuperClassDepth(); |
| } |
| /** |
| * Temporary function that will update the max directive index value in |
| * both the classes and styles contexts present on the provided `tNode`. |
| * |
| * This code is only used because the `select(n)` code functionality is not |
| * yet 100% functional. The `select(n)` instruction cannot yet evaluate host |
| * bindings function code in sync with the associated template function code. |
| * For this reason the styling algorithm needs to track the last directive index |
| * value so that it knows exactly when to render styling to the element since |
| * `stylingApply()` is called multiple times per CD (`stylingApply` will be |
| * removed once `select(n)` is fixed). |
| */ |
| function updateLastDirectiveIndex(tNode, directiveIndex) { |
| updateContextDirectiveIndex(getClassesContext(tNode), directiveIndex); |
| updateContextDirectiveIndex(getStylesContext(tNode), directiveIndex); |
| } |
| function getStylesContext(tNode) { |
| return getContext(tNode, false); |
| } |
| function getClassesContext(tNode) { |
| return getContext(tNode, true); |
| } |
| /** |
| * Returns/instantiates a styling context from/to a `tNode` instance. |
| */ |
| function getContext(tNode, isClassBased) { |
| var context = isClassBased ? tNode.newClasses : tNode.newStyles; |
| if (!context) { |
| context = allocTStylingContext(); |
| if (ngDevMode) { |
| attachStylingDebugObject(context); |
| } |
| if (isClassBased) { |
| tNode.newClasses = context; |
| } |
| else { |
| tNode.newStyles = context; |
| } |
| } |
| return context; |
| } |
| function resolveStylePropValue(value, suffix) { |
| var resolvedValue = null; |
| if (value !== null) { |
| if (suffix) { |
| // when a suffix is applied then it will bypass |
| // sanitization entirely (b/c a new string is created) |
| resolvedValue = renderStringify(value) + suffix; |
| } |
| else { |
| // sanitization happens by dealing with a String value |
| // this means that the string value will be passed through |
| // into the style rendering later (which is where the value |
| // will be sanitized before it is applied) |
| resolvedValue = value; |
| } |
| } |
| return resolvedValue; |
| } |
| |
| /* |
| * The contents of this file include the instructions for all styling-related |
| * operations in Angular. |
| * |
| * The instructions present in this file are: |
| * |
| * Template level styling instructions: |
| * - styling |
| * - styleMap |
| * - classMap |
| * - styleProp |
| * - classProp |
| * - stylingApply |
| */ |
| /** |
| * Allocates style and class binding properties on the element during creation mode. |
| * |
| * This instruction is meant to be called during creation mode to register all |
| * dynamic style and class bindings on the element. Note that this is only used |
| * for binding values (see `elementStart` to learn how to assign static styling |
| * values to an element). |
| * |
| * @param classBindingNames An array containing bindable class names. |
| * The `classProp` instruction refers to the class name by index in |
| * this array (i.e. `['foo', 'bar']` means `foo=0` and `bar=1`). |
| * @param styleBindingNames An array containing bindable style properties. |
| * The `styleProp` instruction refers to the class name by index in |
| * this array (i.e. `['width', 'height']` means `width=0` and `height=1`). |
| * @param styleSanitizer An optional sanitizer function that will be used to sanitize any CSS |
| * style values that are applied to the element (during rendering). |
| * |
| * Note that this will allocate the provided style/class bindings to the host element if |
| * this function is called within a host binding. |
| * |
| * @codeGenApi |
| */ |
| function ɵɵstyling(classBindingNames, styleBindingNames, styleSanitizer) { |
| var tNode = getPreviousOrParentTNode(); |
| if (!tNode.stylingTemplate) { |
| tNode.stylingTemplate = createEmptyStylingContext(); |
| } |
| var directiveStylingIndex = getActiveDirectiveStylingIndex$1(); |
| if (directiveStylingIndex) { |
| // this is temporary hack to get the existing styling instructions to |
| // play ball with the new refactored implementation. |
| // TODO (matsko): remove this once the old implementation is not needed. |
| if (runtimeIsNewStylingInUse()) { |
| stylingInit(); |
| } |
| // despite the binding being applied in a queue (below), the allocation |
| // of the directive into the context happens right away. The reason for |
| // this is to retain the ordering of the directives (which is important |
| // for the prioritization of bindings). |
| allocateOrUpdateDirectiveIntoContext(tNode.stylingTemplate, directiveStylingIndex); |
| var fns = tNode.onElementCreationFns = tNode.onElementCreationFns || []; |
| fns.push(function () { |
| initStyling(tNode, classBindingNames, styleBindingNames, styleSanitizer, directiveStylingIndex); |
| registerHostDirective(tNode.stylingTemplate, directiveStylingIndex); |
| }); |
| } |
| else { |
| // calling the function below ensures that the template's binding values |
| // are applied as the first set of bindings into the context. If any other |
| // styling bindings are set on the same element (by directives and/or |
| // components) then they will be applied at the end of the `elementEnd` |
| // instruction (because directives are created first before styling is |
| // executed for a new element). |
| initStyling(tNode, classBindingNames, styleBindingNames, styleSanitizer, DEFAULT_TEMPLATE_DIRECTIVE_INDEX); |
| } |
| } |
| function initStyling(tNode, classBindingNames, styleBindingNames, styleSanitizer, directiveStylingIndex) { |
| updateContextWithBindings(tNode.stylingTemplate, directiveStylingIndex, classBindingNames, styleBindingNames, styleSanitizer); |
| } |
| /** |
| * Update a style binding on an element with the provided value. |
| * |
| * If the style value is falsy then it will be removed from the element |
| * (or assigned a different value depending if there are any styles placed |
| * on the element with `styleMap` or any static styles that are |
| * present from when the element was created with `styling`). |
| * |
| * Note that the styling element is updated as part of `stylingApply`. |
| * |
| * @param styleIndex Index of style to update. This index value refers to the |
| * index of the style in the style bindings array that was passed into |
| * `styling`. |
| * @param value New value to write (falsy to remove). |
| * @param suffix Optional suffix. Used with scalar values to add unit such as `px`. |
| * Note that when a suffix is provided then the underlying sanitizer will |
| * be ignored. |
| * @param forceOverride Whether or not to update the styling value immediately |
| * (despite the other bindings possibly having priority) |
| * |
| * Note that this will apply the provided style value to the host element if this function is called |
| * within a host binding. |
| * |
| * @codeGenApi |
| */ |
| function ɵɵstyleProp(styleIndex, value, suffix, forceOverride) { |
| var index = getSelectedIndex(); |
| var valueToAdd = resolveStylePropValue$1(value, suffix); |
| var stylingContext = getStylingContext(index, getLView()); |
| var directiveStylingIndex = getActiveDirectiveStylingIndex$1(); |
| if (directiveStylingIndex) { |
| var args = [stylingContext, styleIndex, valueToAdd, directiveStylingIndex, forceOverride]; |
| enqueueHostInstruction(stylingContext, directiveStylingIndex, updateStyleProp, args); |
| } |
| else { |
| updateStyleProp(stylingContext, styleIndex, valueToAdd, DEFAULT_TEMPLATE_DIRECTIVE_INDEX, forceOverride); |
| } |
| if (runtimeIsNewStylingInUse()) { |
| var prop = getBindingNameFromIndex(stylingContext, styleIndex, directiveStylingIndex, false); |
| // the reason why we cast the value as `boolean` is |
| // because the new styling refactor does not yet support |
| // sanitization or animation players. |
| styleProp(prop, value, suffix); |
| } |
| } |
| function resolveStylePropValue$1(value, suffix) { |
| var valueToAdd = null; |
| if (value !== null) { |
| if (suffix) { |
| // when a suffix is applied then it will bypass |
| // sanitization entirely (b/c a new string is created) |
| valueToAdd = renderStringify(value) + suffix; |
| } |
| else { |
| // sanitization happens by dealing with a String value |
| // this means that the string value will be passed through |
| // into the style rendering later (which is where the value |
| // will be sanitized before it is applied) |
| valueToAdd = value; |
| } |
| } |
| return valueToAdd; |
| } |
| /** |
| * Update a class binding on an element with the provided value. |
| * |
| * This instruction is meant to handle the `[class.foo]="exp"` case and, |
| * therefore, the class binding itself must already be allocated using |
| * `styling` within the creation block. |
| * |
| * @param classIndex Index of class to toggle. This index value refers to the |
| * index of the class in the class bindings array that was passed into |
| * `styling` (which is meant to be called before this |
| * function is). |
| * @param value A true/false value which will turn the class on or off. |
| * @param forceOverride Whether or not this value will be applied regardless |
| * of where it is being set within the styling priority structure. |
| * |
| * Note that this will apply the provided class value to the host element if this function |
| * is called within a host binding. |
| * |
| * @codeGenApi |
| */ |
| function ɵɵclassProp(classIndex, value, forceOverride) { |
| var index = getSelectedIndex(); |
| var input = (value instanceof BoundPlayerFactory) ? |
| value : |
| booleanOrNull(value); |
| var directiveStylingIndex = getActiveDirectiveStylingIndex$1(); |
| var stylingContext = getStylingContext(index, getLView()); |
| if (directiveStylingIndex) { |
| var args = [stylingContext, classIndex, input, directiveStylingIndex, forceOverride]; |
| enqueueHostInstruction(stylingContext, directiveStylingIndex, updateClassProp, args); |
| } |
| else { |
| updateClassProp(stylingContext, classIndex, input, DEFAULT_TEMPLATE_DIRECTIVE_INDEX, forceOverride); |
| } |
| if (runtimeIsNewStylingInUse()) { |
| var prop = getBindingNameFromIndex(stylingContext, classIndex, directiveStylingIndex, true); |
| // the reason why we cast the value as `boolean` is |
| // because the new styling refactor does not yet support |
| // sanitization or animation players. |
| classProp(prop, input); |
| } |
| } |
| function booleanOrNull(value) { |
| if (typeof value === 'boolean') |
| return value; |
| return value ? true : null; |
| } |
| /** |
| * Update style bindings using an object literal on an element. |
| * |
| * This instruction is meant to apply styling via the `[style]="exp"` template bindings. |
| * When styles are applied to the element they will then be updated with respect to |
| * any styles/classes set via `styleProp`. If any styles are set to falsy |
| * then they will be removed from the element. |
| * |
| * Note that the styling instruction will not be applied until `stylingApply` is called. |
| * |
| * @param styles A key/value style map of the styles that will be applied to the given element. |
| * Any missing styles (that have already been applied to the element beforehand) will be |
| * removed (unset) from the element's styling. |
| * |
| * Note that this will apply the provided styleMap value to the host element if this function |
| * is called within a host binding. |
| * |
| * @codeGenApi |
| */ |
| function ɵɵstyleMap(styles) { |
| var index = getSelectedIndex(); |
| var lView = getLView(); |
| var stylingContext = getStylingContext(index, lView); |
| var directiveStylingIndex = getActiveDirectiveStylingIndex$1(); |
| if (directiveStylingIndex) { |
| var args = [stylingContext, styles, directiveStylingIndex]; |
| enqueueHostInstruction(stylingContext, directiveStylingIndex, updateStyleMap, args); |
| } |
| else { |
| var tNode = getTNode(index, lView); |
| // inputs are only evaluated from a template binding into a directive, therefore, |
| // there should not be a situation where a directive host bindings function |
| // evaluates the inputs (this should only happen in the template function) |
| if (hasStyleInput(tNode) && styles !== NO_CHANGE) { |
| var initialStyles = getInitialClassNameValue(stylingContext); |
| var styleInputVal = (initialStyles.length ? (initialStyles + ' ') : '') + forceStylesAsString(styles); |
| setInputsForProperty(lView, tNode.inputs['style'], styleInputVal); |
| styles = NO_CHANGE; |
| } |
| updateStyleMap(stylingContext, styles); |
| } |
| if (runtimeIsNewStylingInUse()) { |
| styleMap(styles); |
| } |
| } |
| /** |
| * Update class bindings using an object literal or class-string on an element. |
| * |
| * This instruction is meant to apply styling via the `[class]="exp"` template bindings. |
| * When classes are applied to the element they will then be updated with |
| * respect to any styles/classes set via `classProp`. If any |
| * classes are set to falsy then they will be removed from the element. |
| * |
| * Note that the styling instruction will not be applied until `stylingApply` is called. |
| * Note that this will the provided classMap value to the host element if this function is called |
| * within a host binding. |
| * |
| * @param classes A key/value map or string of CSS classes that will be added to the |
| * given element. Any missing classes (that have already been applied to the element |
| * beforehand) will be removed (unset) from the element's list of CSS classes. |
| * |
| * @codeGenApi |
| */ |
| function ɵɵclassMap(classes) { |
| var index = getSelectedIndex(); |
| var lView = getLView(); |
| var stylingContext = getStylingContext(index, lView); |
| var directiveStylingIndex = getActiveDirectiveStylingIndex$1(); |
| if (directiveStylingIndex) { |
| var args = [stylingContext, classes, directiveStylingIndex]; |
| enqueueHostInstruction(stylingContext, directiveStylingIndex, updateClassMap, args); |
| } |
| else { |
| var tNode = getTNode(index, lView); |
| // inputs are only evaluated from a template binding into a directive, therefore, |
| // there should not be a situation where a directive host bindings function |
| // evaluates the inputs (this should only happen in the template function) |
| if (hasClassInput(tNode) && classes !== NO_CHANGE) { |
| var initialClasses = getInitialClassNameValue(stylingContext); |
| var classInputVal = (initialClasses.length ? (initialClasses + ' ') : '') + forceClassesAsString(classes); |
| setInputsForProperty(lView, tNode.inputs['class'], classInputVal); |
| classes = NO_CHANGE; |
| } |
| updateClassMap(stylingContext, classes); |
| } |
| if (runtimeIsNewStylingInUse()) { |
| classMap(classes); |
| } |
| } |
| /** |
| * Apply all style and class binding values to the element. |
| * |
| * This instruction is meant to be run after `styleMap`, `classMap`, |
| * `styleProp` or `classProp` instructions have been run and will |
| * only apply styling to the element if any styling bindings have been updated. |
| * |
| * @codeGenApi |
| */ |
| function ɵɵstylingApply() { |
| var index = getSelectedIndex(); |
| var directiveStylingIndex = getActiveDirectiveStylingIndex$1() || DEFAULT_TEMPLATE_DIRECTIVE_INDEX; |
| var lView = getLView(); |
| var tNode = getTNode(index, lView); |
| // if a non-element value is being processed then we can't render values |
| // on the element at all therefore by setting the renderer to null then |
| // the styling apply code knows not to actually apply the values... |
| var renderer = tNode.type === 3 /* Element */ ? lView[RENDERER] : null; |
| var isFirstRender = (lView[FLAGS] & 8 /* FirstLViewPass */) !== 0; |
| var stylingContext = getStylingContext(index, lView); |
| if (runtimeAllowOldStyling()) { |
| var totalPlayersQueued = renderStyling(stylingContext, renderer, lView, isFirstRender, null, null, directiveStylingIndex); |
| if (totalPlayersQueued > 0) { |
| var rootContext = getRootContext(lView); |
| scheduleTick(rootContext, 2 /* FlushPlayers */); |
| } |
| } |
| // because select(n) may not run between every instruction, the cached styling |
| // context may not get cleared between elements. The reason for this is because |
| // styling bindings (like `[style]` and `[class]`) are not recognized as property |
| // bindings by default so a select(n) instruction is not generated. To ensure the |
| // context is loaded correctly for the next element the cache below is pre-emptively |
| // cleared because there is no code in Angular that applies more styling code after a |
| // styling flush has occurred. Note that this will be fixed once FW-1254 lands. |
| setCachedStylingContext(null); |
| if (runtimeIsNewStylingInUse()) { |
| stylingApply(); |
| } |
| } |
| function getActiveDirectiveStylingIndex$1() { |
| // whenever a directive's hostBindings function is called a uniqueId value |
| // is assigned. Normally this is enough to help distinguish one directive |
| // from another for the styling context, but there are situations where a |
| // sub-class directive could inherit and assign styling in concert with a |
| // parent directive. To help the styling code distinguish between a parent |
| // sub-classed directive the inheritance depth is taken into account as well. |
| return getActiveDirectiveId() + getActiveDirectiveSuperClassDepth(); |
| } |
| function getStylingContext(index, lView) { |
| var context = getCachedStylingContext(); |
| if (!context) { |
| context = getStylingContextFromLView(index + HEADER_OFFSET, lView); |
| setCachedStylingContext(context); |
| } |
| else if (ngDevMode) { |
| var actualContext = getStylingContextFromLView(index + HEADER_OFFSET, lView); |
| assertEqual(context, actualContext, 'The cached styling context is invalid'); |
| } |
| return context; |
| } |
| |
| /** |
| * @license |
| * Copyright Google Inc. All Rights Reserved. |
| * |
| * Use of this source code is governed by an MIT-style license that can be |
| * found in the LICENSE file at https://angular.io/license |
| */ |
| /** |
| * Create DOM element. The instruction must later be followed by `elementEnd()` call. |
| * |
| * @param index Index of the element in the LView array |
| * @param name Name of the DOM Node |
| * @param attrs Statically bound set of attributes, classes, and styles to be written into the DOM |
| * element on creation. Use [AttributeMarker] to denote the meaning of this array. |
| * @param localRefs A set of local reference bindings on the element. |
| * |
| * Attributes and localRefs are passed as an array of strings where elements with an even index |
| * hold an attribute name and elements with an odd index hold an attribute value, ex.: |
| * ['id', 'warning5', 'class', 'alert'] |
| * |
| * @codeGenApi |
| */ |
| function ɵɵelementStart(index, name, attrs, localRefs) { |
| var lView = getLView(); |
| var tView = lView[TVIEW]; |
| ngDevMode && assertEqual(lView[BINDING_INDEX], tView.bindingStartIndex, 'elements should be created before any bindings '); |
| ngDevMode && ngDevMode.rendererCreateElement++; |
| ngDevMode && assertDataInRange(lView, index + HEADER_OFFSET); |
| var native = lView[index + HEADER_OFFSET] = elementCreate(name); |
| var renderer = lView[RENDERER]; |
| var tNode = getOrCreateTNode(tView, lView[T_HOST], index, 3 /* Element */, name, attrs || null); |
| var initialStylesIndex = 0; |
| var initialClassesIndex = 0; |
| var lastAttrIndex = -1; |
| if (attrs) { |
| lastAttrIndex = setUpAttributes(native, attrs); |
| // it's important to only prepare styling-related datastructures once for a given |
| // tNode and not each time an element is created. Also, the styling code is designed |
| // to be patched and constructed at various points, but only up until the styling |
| // template is first allocated (which happens when the very first style/class binding |
| // value is evaluated). When the template is allocated (when it turns into a context) |
| // then the styling template is locked and cannot be further extended (it can only be |
| // instantiated into a context per element) |
| setNodeStylingTemplate(tView, tNode, attrs, lastAttrIndex); |
| var stylingTemplate = tNode.stylingTemplate; |
| if (stylingTemplate) { |
| // the initial style/class values are rendered immediately after having been |
| // initialized into the context so the element styling is ready when directives |
| // are initialized (since they may read style/class values in their constructor) |
| initialStylesIndex = renderInitialStyles(native, stylingTemplate, renderer); |
| initialClassesIndex = renderInitialClasses(native, stylingTemplate, renderer); |
| } |
| } |
| appendChild(native, tNode, lView); |
| createDirectivesAndLocals(tView, lView, localRefs); |
| // any immediate children of a component or template container must be pre-emptively |
| // monkey-patched with the component view data so that the element can be inspected |
| // later on using any element discovery utility methods (see `element_discovery.ts`) |
| if (getElementDepthCount() === 0) { |
| attachPatchData(native, lView); |
| } |
| increaseElementDepthCount(); |
| // if a directive contains a host binding for "class" then all class-based data will |
| // flow through that (except for `[class.prop]` bindings). This also includes initial |
| // static class values as well. (Note that this will be fixed once map-based `[style]` |
| // and `[class]` bindings work for multiple directives.) |
| if (tView.firstTemplatePass) { |
| var inputData = initializeTNodeInputs(tNode); |
| if (inputData && inputData.hasOwnProperty('class')) { |
| tNode.flags |= 8 /* hasClassInput */; |
| } |
| if (inputData && inputData.hasOwnProperty('style')) { |
| tNode.flags |= 16 /* hasStyleInput */; |
| } |
| } |
| // we render the styling again below in case any directives have set any `style` and/or |
| // `class` host attribute values... |
| if (tNode.stylingTemplate) { |
| renderInitialClasses(native, tNode.stylingTemplate, renderer, initialClassesIndex); |
| renderInitialStyles(native, tNode.stylingTemplate, renderer, initialStylesIndex); |
| } |
| if (runtimeIsNewStylingInUse() && lastAttrIndex >= 0) { |
| registerInitialStylingIntoContext(tNode, attrs, lastAttrIndex); |
| } |
| var currentQueries = lView[QUERIES]; |
| if (currentQueries) { |
| currentQueries.addNode(tNode); |
| lView[QUERIES] = currentQueries.clone(tNode); |
| } |
| executeContentQueries(tView, tNode, lView); |
| } |
| /** |
| * Mark the end of the element. |
| * |
| * @codeGenApi |
| */ |
| function ɵɵelementEnd() { |
| var previousOrParentTNode = getPreviousOrParentTNode(); |
| ngDevMode && assertDefined(previousOrParentTNode, 'No parent node to close.'); |
| if (getIsParent()) { |
| setIsNotParent(); |
| } |
| else { |
| ngDevMode && assertHasParent(getPreviousOrParentTNode()); |
| previousOrParentTNode = previousOrParentTNode.parent; |
| setPreviousOrParentTNode(previousOrParentTNode, false); |
| } |
| // this is required for all host-level styling-related instructions to run |
| // in the correct order |
| previousOrParentTNode.onElementCreationFns && applyOnCreateInstructions(previousOrParentTNode); |
| ngDevMode && assertNodeType(previousOrParentTNode, 3 /* Element */); |
| var lView = getLView(); |
| var currentQueries = lView[QUERIES]; |
| // Go back up to parent queries only if queries have been cloned on this element. |
| if (currentQueries && previousOrParentTNode.index === currentQueries.nodeIndex) { |
| lView[QUERIES] = currentQueries.parent; |
| } |
| registerPostOrderHooks(lView[TVIEW], previousOrParentTNode); |
| decreaseElementDepthCount(); |
| // this is fired at the end of elementEnd because ALL of the stylingBindings code |
| // (for directives and the template) have now executed which means the styling |
| // context can be instantiated properly. |
| var stylingContext = null; |
| if (hasClassInput(previousOrParentTNode)) { |
| stylingContext = getStylingContextFromLView(previousOrParentTNode.index, lView); |
| setInputsForProperty(lView, previousOrParentTNode.inputs['class'], getInitialClassNameValue(stylingContext)); |
| } |
| if (hasStyleInput(previousOrParentTNode)) { |
| stylingContext = |
| stylingContext || getStylingContextFromLView(previousOrParentTNode.index, lView); |
| setInputsForProperty(lView, previousOrParentTNode.inputs['style'], getInitialStyleStringValue(stylingContext)); |
| } |
| } |
| /** |
| * Creates an empty element using {@link elementStart} and {@link elementEnd} |
| * |
| * @param index Index of the element in the data array |
| * @param name Name of the DOM Node |
| * @param attrs Statically bound set of attributes, classes, and styles to be written into the DOM |
| * element on creation. Use [AttributeMarker] to denote the meaning of this array. |
| * @param localRefs A set of local reference bindings on the element. |
| * |
| * @codeGenApi |
| */ |
| function ɵɵelement(index, name, attrs, localRefs) { |
| ɵɵelementStart(index, name, attrs, localRefs); |
| ɵɵelementEnd(); |
| } |
| /** |
| * Assign static attribute values to a host element. |
| * |
| * This instruction will assign static attribute values as well as class and style |
| * values to an element within the host bindings function. Since attribute values |
| * can consist of different types of values, the `attrs` array must include the values in |
| * the following format: |
| * |
| * attrs = [ |
| * // static attributes (like `title`, `name`, `id`...) |
| * attr1, value1, attr2, value, |
| * |
| * // a single namespace value (like `x:id`) |
| * NAMESPACE_MARKER, namespaceUri1, name1, value1, |
| * |
| * // another single namespace value (like `x:name`) |
| * NAMESPACE_MARKER, namespaceUri2, name2, value2, |
| * |
| * // a series of CSS classes that will be applied to the element (no spaces) |
| * CLASSES_MARKER, class1, class2, class3, |
| * |
| * // a series of CSS styles (property + value) that will be applied to the element |
| * STYLES_MARKER, prop1, value1, prop2, value2 |
| * ] |
| * |
| * All non-class and non-style attributes must be defined at the start of the list |
| * first before all class and style values are set. When there is a change in value |
| * type (like when classes and styles are introduced) a marker must be used to separate |
| * the entries. The marker values themselves are set via entries found in the |
| * [AttributeMarker] enum. |
| * |
| * NOTE: This instruction is meant to used from `hostBindings` function only. |
| * |
| * @param directive A directive instance the styling is associated with. |
| * @param attrs An array of static values (attributes, classes and styles) with the correct marker |
| * values. |
| * |
| * @codeGenApi |
| */ |
| function ɵɵelementHostAttrs(attrs) { |
| var hostElementIndex = getSelectedIndex(); |
| var lView = getLView(); |
| var tNode = getTNode(hostElementIndex, lView); |
| // non-element nodes (e.g. `<ng-container>`) are not rendered as actual |
| // element nodes and adding styles/classes on to them will cause runtime |
| // errors... |
| if (tNode.type === 3 /* Element */) { |
| var native = getNativeByTNode(tNode, lView); |
| var lastAttrIndex = setUpAttributes(native, attrs); |
| var stylingAttrsStartIndex = attrsStylingIndexOf(attrs, lastAttrIndex); |
| if (stylingAttrsStartIndex >= 0) { |
| var directiveStylingIndex = getActiveDirectiveStylingIndex$1(); |
| if (tNode.stylingTemplate) { |
| patchContextWithStaticAttrs(tNode.stylingTemplate, attrs, stylingAttrsStartIndex, directiveStylingIndex); |
| } |
| else { |
| tNode.stylingTemplate = |
| initializeStaticContext(attrs, stylingAttrsStartIndex, directiveStylingIndex); |
| } |
| } |
| } |
| } |
| |
| /** |
| * @license |
| * Copyright Google Inc. All Rights Reserved. |
| * |
| * Use of this source code is governed by an MIT-style license that can be |
| * found in the LICENSE file at https://angular.io/license |
| */ |
| /** |
| * Creates a logical container for other nodes (<ng-container>) backed by a comment node in the DOM. |
| * The instruction must later be followed by `elementContainerEnd()` call. |
| * |
| * @param index Index of the element in the LView array |
| * @param attrs Set of attributes to be used when matching directives. |
| * @param localRefs A set of local reference bindings on the element. |
| * |
| * Even if this instruction accepts a set of attributes no actual attribute values are propagated to |
| * the DOM (as a comment node can't have attributes). Attributes are here only for directive |
| * matching purposes and setting initial inputs of directives. |
| * |
| * @codeGenApi |
| */ |
| function ɵɵelementContainerStart(index, attrs, localRefs) { |
| var lView = getLView(); |
| var tView = lView[TVIEW]; |
| var renderer = lView[RENDERER]; |
| var tagName = 'ng-container'; |
| ngDevMode && assertEqual(lView[BINDING_INDEX], tView.bindingStartIndex, 'element containers should be created before any bindings'); |
| ngDevMode && ngDevMode.rendererCreateComment++; |
| ngDevMode && assertDataInRange(lView, index + HEADER_OFFSET); |
| var native = lView[index + HEADER_OFFSET] = renderer.createComment(ngDevMode ? tagName : ''); |
| ngDevMode && assertDataInRange(lView, index - 1); |
| var tNode = getOrCreateTNode(tView, lView[T_HOST], index, 4 /* ElementContainer */, tagName, attrs || null); |
| if (attrs) { |
| // While ng-container doesn't necessarily support styling, we use the style context to identify |
| // and execute directives on the ng-container. |
| setNodeStylingTemplate(tView, tNode, attrs, 0); |
| } |
| appendChild(native, tNode, lView); |
| createDirectivesAndLocals(tView, lView, localRefs); |
| attachPatchData(native, lView); |
| var currentQueries = lView[QUERIES]; |
| if (currentQueries) { |
| currentQueries.addNode(tNode); |
| lView[QUERIES] = currentQueries.clone(tNode); |
| } |
| executeContentQueries(tView, tNode, lView); |
| } |
| /** |
| * Mark the end of the <ng-container>. |
| * |
| * @codeGenApi |
| */ |
| function ɵɵelementContainerEnd() { |
| var previousOrParentTNode = getPreviousOrParentTNode(); |
| var lView = getLView(); |
| var tView = lView[TVIEW]; |
| if (getIsParent()) { |
| setIsNotParent(); |
| } |
| else { |
| ngDevMode && assertHasParent(previousOrParentTNode); |
| previousOrParentTNode = previousOrParentTNode.parent; |
| setPreviousOrParentTNode(previousOrParentTNode, false); |
| } |
| ngDevMode && assertNodeType(previousOrParentTNode, 4 /* ElementContainer */); |
| var currentQueries = lView[QUERIES]; |
| // Go back up to parent queries only if queries have been cloned on this element. |
| if (currentQueries && previousOrParentTNode.index === currentQueries.nodeIndex) { |
| lView[QUERIES] = currentQueries.parent; |
| } |
| // this is required for all host-level styling-related instructions to run |
| // in the correct order |
| previousOrParentTNode.onElementCreationFns && applyOnCreateInstructions(previousOrParentTNode); |
| registerPostOrderHooks(tView, previousOrParentTNode); |
| } |
| |
| /** |
| * @license |
| * Copyright Google Inc. All Rights Reserved. |
| * |
| * Use of this source code is governed by an MIT-style license that can be |
| * found in the LICENSE file at https://angular.io/license |
| */ |
| /** |
| * Marks the start of an embedded view. |
| * |
| * @param viewBlockId The ID of this view |
| * @return boolean Whether or not this view is in creation mode |
| * |
| * @codeGenApi |
| */ |
| function ɵɵembeddedViewStart(viewBlockId, consts, vars) { |
| var lView = getLView(); |
| var previousOrParentTNode = getPreviousOrParentTNode(); |
| // The previous node can be a view node if we are processing an inline for loop |
| var containerTNode = previousOrParentTNode.type === 2 /* View */ ? |
| previousOrParentTNode.parent : |
| previousOrParentTNode; |
| var lContainer = lView[containerTNode.index]; |
| ngDevMode && assertNodeType(containerTNode, 0 /* Container */); |
| var viewToRender = scanForView(lContainer, lContainer[ACTIVE_INDEX], viewBlockId); |
| if (viewToRender) { |
| setIsParent(); |
| enterView(viewToRender, viewToRender[TVIEW].node); |
| } |
| else { |
| // When we create a new LView, we always reset the state of the instructions. |
| viewToRender = createLView(lView, getOrCreateEmbeddedTView(viewBlockId, consts, vars, containerTNode), null, 16 /* CheckAlways */, null, null); |
| if (lContainer[QUERIES]) { |
| viewToRender[QUERIES] = lContainer[QUERIES].createView(); |
| } |
| var tParentNode = getIsParent() ? previousOrParentTNode : |
| previousOrParentTNode && previousOrParentTNode.parent; |
| assignTViewNodeToLView(viewToRender[TVIEW], tParentNode, viewBlockId, viewToRender); |
| enterView(viewToRender, viewToRender[TVIEW].node); |
| } |
| if (lContainer) { |
| if (isCreationMode(viewToRender)) { |
| // it is a new view, insert it into collection of views for a given container |
| insertView(viewToRender, lContainer, lContainer[ACTIVE_INDEX]); |
| } |
| lContainer[ACTIVE_INDEX]++; |
| } |
| return isCreationMode(viewToRender) ? 1 /* Create */ | 2 /* Update */ : |
| 2 /* Update */; |
| } |
| /** |
| * Initialize the TView (e.g. static data) for the active embedded view. |
| * |
| * Each embedded view block must create or retrieve its own TView. Otherwise, the embedded view's |
| * static data for a particular node would overwrite the static data for a node in the view above |
| * it with the same index (since it's in the same template). |
| * |
| * @param viewIndex The index of the TView in TNode.tViews |
| * @param consts The number of nodes, local refs, and pipes in this template |
| * @param vars The number of bindings and pure function bindings in this template |
| * @param container The parent container in which to look for the view's static data |
| * @returns TView |
| */ |
| function getOrCreateEmbeddedTView(viewIndex, consts, vars, parent) { |
| var tView = getLView()[TVIEW]; |
| ngDevMode && assertNodeType(parent, 0 /* Container */); |
| var containerTViews = parent.tViews; |
| ngDevMode && assertDefined(containerTViews, 'TView expected'); |
| ngDevMode && assertEqual(Array.isArray(containerTViews), true, 'TViews should be in an array'); |
| if (viewIndex >= containerTViews.length || containerTViews[viewIndex] == null) { |
| containerTViews[viewIndex] = createTView(viewIndex, null, consts, vars, tView.directiveRegistry, tView.pipeRegistry, null, null); |
| } |
| return containerTViews[viewIndex]; |
| } |
| /** |
| * Looks for a view with a given view block id inside a provided LContainer. |
| * Removes views that need to be deleted in the process. |
| * |
| * @param lContainer to search for views |
| * @param startIdx starting index in the views array to search from |
| * @param viewBlockId exact view block id to look for |
| */ |
| function scanForView(lContainer, startIdx, viewBlockId) { |
| for (var i = startIdx + CONTAINER_HEADER_OFFSET; i < lContainer.length; i++) { |
| var viewAtPositionId = lContainer[i][TVIEW].id; |
| if (viewAtPositionId === viewBlockId) { |
| return lContainer[i]; |
| } |
| else if (viewAtPositionId < viewBlockId) { |
| // found a view that should not be at this position - remove |
| removeView(lContainer, i - CONTAINER_HEADER_OFFSET); |
| } |
| else { |
| // found a view with id greater than the one we are searching for |
| // which means that required view doesn't exist and can't be found at |
| // later positions in the views array - stop the searchdef.cont here |
| break; |
| } |
| } |
| return null; |
| } |
| /** |
| * Marks the end of an embedded view. |
| * |
| * @codeGenApi |
| */ |
| function ɵɵembeddedViewEnd() { |
| var lView = getLView(); |
| var viewHost = lView[T_HOST]; |
| if (isCreationMode(lView)) { |
| refreshDescendantViews(lView); // creation mode pass |
| lView[FLAGS] &= ~4 /* CreationMode */; |
| } |
| resetPreOrderHookFlags(lView); |
| refreshDescendantViews(lView); // update mode pass |
| var lContainer = lView[PARENT]; |
| ngDevMode && assertLContainerOrUndefined(lContainer); |
| // It's always safe to run hooks here, as `leaveView` is not called during the 'finally' block |
| // of a try-catch-finally statement, so it can never be reached while unwinding the stack due to |
| // an error being thrown. |
| leaveView(lContainer[PARENT], /* safeToRunHooks */ true); |
| setPreviousOrParentTNode(viewHost, false); |
| } |
| |
| /** |
| * Returns the current OpaqueViewState instance. |
| * |
| * Used in conjunction with the restoreView() instruction to save a snapshot |
| * of the current view and restore it when listeners are invoked. This allows |
| * walking the declaration view tree in listeners to get vars from parent views. |
| * |
| * @codeGenApi |
| */ |
| function ɵɵgetCurrentView() { |
| return getLView(); |
| } |
| |
| /** |
| * @license |
| * Copyright Google Inc. All Rights Reserved. |
| * |
| * Use of this source code is governed by an MIT-style license that can be |
| * found in the LICENSE file at https://angular.io/license |
| */ |
| /** |
| * Determine if the argument is shaped like a Promise |
| */ |
| function isPromise(obj) { |
| // allow any Promise/A+ compliant thenable. |
| // It's up to the caller to ensure that obj.then conforms to the spec |
| return !!obj && typeof obj.then === 'function'; |
| } |
| /** |
| * Determine if the argument is an Observable |
| */ |
| function isObservable(obj) { |
| // TODO: use isObservable once we update pass rxjs 6.1 |
| // https://github.com/ReactiveX/rxjs/blob/master/CHANGELOG.md#610-2018-05-03 |
| return !!obj && typeof obj.subscribe === 'function'; |
| } |
| |
| /** |
| * @license |
| * Copyright Google Inc. All Rights Reserved. |
| * |
| * Use of this source code is governed by an MIT-style license that can be |
| * found in the LICENSE file at https://angular.io/license |
| */ |
| /** |
| * Adds an event listener to the current node. |
| * |
| * If an output exists on one of the node's directives, it also subscribes to the output |
| * and saves the subscription for later cleanup. |
| * |
| * @param eventName Name of the event |
| * @param listenerFn The function to be called when event emits |
| * @param useCapture Whether or not to use capture in event listener |
| * @param eventTargetResolver Function that returns global target information in case this listener |
| * should be attached to a global object like window, document or body |
| * |
| * @codeGenApi |
| */ |
| function ɵɵlistener(eventName, listenerFn, useCapture, eventTargetResolver) { |
| if (useCapture === void 0) { useCapture = false; } |
| listenerInternal(eventName, listenerFn, useCapture, eventTargetResolver); |
| } |
| /** |
| * Registers a synthetic host listener (e.g. `(@foo.start)`) on a component. |
| * |
| * This instruction is for compatibility purposes and is designed to ensure that a |
| * synthetic host listener (e.g. `@HostListener('@foo.start')`) properly gets rendered |
| * in the component's renderer. Normally all host listeners are evaluated with the |
| * parent component's renderer, but, in the case of animation @triggers, they need |
| * to be evaluated with the sub component's renderer (because that's where the |
| * animation triggers are defined). |
| * |
| * Do not use this instruction as a replacement for `listener`. This instruction |
| * only exists to ensure compatibility with the ViewEngine's host binding behavior. |
| * |
| * @param eventName Name of the event |
| * @param listenerFn The function to be called when event emits |
| * @param useCapture Whether or not to use capture in event listener |
| * @param eventTargetResolver Function that returns global target information in case this listener |
| * should be attached to a global object like window, document or body |
| * |
| * @codeGenApi |
| */ |
| function ɵɵcomponentHostSyntheticListener(eventName, listenerFn, useCapture, eventTargetResolver) { |
| if (useCapture === void 0) { useCapture = false; } |
| listenerInternal(eventName, listenerFn, useCapture, eventTargetResolver, loadComponentRenderer); |
| } |
| /** |
| * A utility function that checks if a given element has already an event handler registered for an |
| * event with a specified name. The TView.cleanup data structure is used to find out which events |
| * are registered for a given element. |
| */ |
| function findExistingListener(lView, eventName, tNodeIdx) { |
| var tView = lView[TVIEW]; |
| var tCleanup = tView.cleanup; |
| if (tCleanup != null) { |
| for (var i = 0; i < tCleanup.length - 1; i += 2) { |
| var cleanupEventName = tCleanup[i]; |
| if (cleanupEventName === eventName && tCleanup[i + 1] === tNodeIdx) { |
| // We have found a matching event name on the same node but it might not have been |
| // registered yet, so we must explicitly verify entries in the LView cleanup data |
| // structures. |
| var lCleanup = lView[CLEANUP]; |
| var listenerIdxInLCleanup = tCleanup[i + 2]; |
| return lCleanup.length > listenerIdxInLCleanup ? lCleanup[listenerIdxInLCleanup] : null; |
| } |
| // TView.cleanup can have a mix of 4-elements entries (for event handler cleanups) or |
| // 2-element entries (for directive and queries destroy hooks). As such we can encounter |
| // blocks of 4 or 2 items in the tView.cleanup and this is why we iterate over 2 elements |
| // first and jump another 2 elements if we detect listeners cleanup (4 elements). Also check |
| // documentation of TView.cleanup for more details of this data structure layout. |
| if (typeof cleanupEventName === 'string') { |
| i += 2; |
| } |
| } |
| } |
| return null; |
| } |
| function listenerInternal(eventName, listenerFn, useCapture, eventTargetResolver, loadRendererFn) { |
| if (useCapture === void 0) { useCapture = false; } |
| var lView = getLView(); |
| var tNode = getPreviousOrParentTNode(); |
| var tView = lView[TVIEW]; |
| var firstTemplatePass = tView.firstTemplatePass; |
| var tCleanup = firstTemplatePass && (tView.cleanup || (tView.cleanup = [])); |
| ngDevMode && assertNodeOfPossibleTypes(tNode, 3 /* Element */, 0 /* Container */, 4 /* ElementContainer */); |
| var processOutputs = true; |
| // add native event listener - applicable to elements only |
| if (tNode.type === 3 /* Element */) { |
| var native = getNativeByTNode(tNode, lView); |
| var resolved = eventTargetResolver ? eventTargetResolver(native) : EMPTY_OBJ; |
| var target = resolved.target || native; |
| var renderer = loadRendererFn ? loadRendererFn(tNode, lView) : lView[RENDERER]; |
| var lCleanup = getCleanup(lView); |
| var lCleanupIndex = lCleanup.length; |
| var idxOrTargetGetter = eventTargetResolver ? |
| function (_lView) { return eventTargetResolver(unwrapRNode(_lView[tNode.index])).target; } : |
| tNode.index; |
| // In order to match current behavior, native DOM event listeners must be added for all |
| // events (including outputs). |
| if (isProceduralRenderer(renderer)) { |
| // There might be cases where multiple directives on the same element try to register an event |
| // handler function for the same event. In this situation we want to avoid registration of |
| // several native listeners as each registration would be intercepted by NgZone and |
| // trigger change detection. This would mean that a single user action would result in several |
| // change detections being invoked. To avoid this situation we want to have only one call to |
| // native handler registration (for the same element and same type of event). |
| // |
| // In order to have just one native event handler in presence of multiple handler functions, |
| // we just register a first handler function as a native event listener and then chain |
| // (coalesce) other handler functions on top of the first native handler function. |
| var existingListener = null; |
| // Please note that the coalescing described here doesn't happen for events specifying an |
| // alternative target (ex. (document:click)) - this is to keep backward compatibility with the |
| // view engine. |
| // Also, we don't have to search for existing listeners is there are no directives |
| // matching on a given node as we can't register multiple event handlers for the same event in |
| // a template (this would mean having duplicate attributes). |
| if (!eventTargetResolver && hasDirectives(tNode)) { |
| existingListener = findExistingListener(lView, eventName, tNode.index); |
| } |
| if (existingListener !== null) { |
| // Attach a new listener at the head of the coalesced listeners list. |
| listenerFn.__ngNextListenerFn__ = existingListener.__ngNextListenerFn__; |
| existingListener.__ngNextListenerFn__ = listenerFn; |
| processOutputs = false; |
| } |
| else { |
| // The first argument of `listen` function in Procedural Renderer is: |
| // - either a target name (as a string) in case of global target (window, document, body) |
| // - or element reference (in all other cases) |
| listenerFn = wrapListener(tNode, lView, listenerFn, false /** preventDefault */); |
| var cleanupFn = renderer.listen(resolved.name || target, eventName, listenerFn); |
| ngDevMode && ngDevMode.rendererAddEventListener++; |
| lCleanup.push(listenerFn, cleanupFn); |
| tCleanup && tCleanup.push(eventName, idxOrTargetGetter, lCleanupIndex, lCleanupIndex + 1); |
| } |
| } |
| else { |
| listenerFn = wrapListener(tNode, lView, listenerFn, true /** preventDefault */); |
| target.addEventListener(eventName, listenerFn, useCapture); |
| ngDevMode && ngDevMode.rendererAddEventListener++; |
| lCleanup.push(listenerFn); |
| tCleanup && tCleanup.push(eventName, idxOrTargetGetter, lCleanupIndex, useCapture); |
| } |
| } |
| // subscribe to directive outputs |
| if (tNode.outputs === undefined) { |
| // if we create TNode here, inputs must be undefined so we know they still need to be |
| // checked |
| tNode.outputs = generatePropertyAliases(tNode, 1 /* Output */); |
| } |
| var outputs = tNode.outputs; |
| var props; |
| if (processOutputs && outputs && (props = outputs[eventName])) { |
| var propsLength = props.length; |
| if (propsLength) { |
| var lCleanup = getCleanup(lView); |
| for (var i = 0; i < propsLength; i += 3) { |
| var index = props[i]; |
| ngDevMode && assertDataInRange(lView, index); |
| var minifiedName = props[i + 2]; |
| var directiveInstance = lView[index]; |
| var output = directiveInstance[minifiedName]; |
| if (ngDevMode && !isObservable(output)) { |
| throw new Error("@Output " + minifiedName + " not initialized in '" + directiveInstance.constructor.name + "'."); |
| } |
| var subscription = output.subscribe(listenerFn); |
| var idx = lCleanup.length; |
| lCleanup.push(listenerFn, subscription); |
| tCleanup && tCleanup.push(eventName, tNode.index, idx, -(idx + 1)); |
| } |
| } |
| } |
| } |
| function executeListenerWithErrorHandling(lView, listenerFn, e) { |
| try { |
| // Only explicitly returning false from a listener should preventDefault |
| return listenerFn(e) !== false; |
| } |
| catch (error) { |
| handleError(lView, error); |
| return false; |
| } |
| } |
| /** |
| * Wraps an event listener with a function that marks ancestors dirty and prevents default behavior, |
| * if applicable. |
| * |
| * @param tNode The TNode associated with this listener |
| * @param lView The LView that contains this listener |
| * @param listenerFn The listener function to call |
| * @param wrapWithPreventDefault Whether or not to prevent default behavior |
| * (the procedural renderer does this already, so in those cases, we should skip) |
| */ |
| function wrapListener(tNode, lView, listenerFn, wrapWithPreventDefault) { |
| // Note: we are performing most of the work in the listener function itself |
| // to optimize listener registration. |
| return function wrapListenerIn_markDirtyAndPreventDefault(e) { |
| // In order to be backwards compatible with View Engine, events on component host nodes |
| // must also mark the component view itself dirty (i.e. the view that it owns). |
| var startView = tNode.flags & 1 /* isComponent */ ? getComponentViewByIndex(tNode.index, lView) : lView; |
| // See interfaces/view.ts for more on LViewFlags.ManualOnPush |
| if ((lView[FLAGS] & 32 /* ManualOnPush */) === 0) { |
| markViewDirty(startView); |
| } |
| var result = executeListenerWithErrorHandling(lView, listenerFn, e); |
| // A just-invoked listener function might have coalesced listeners so we need to check for |
| // their presence and invoke as needed. |
| var nextListenerFn = wrapListenerIn_markDirtyAndPreventDefault.__ngNextListenerFn__; |
| while (nextListenerFn) { |
| // We should prevent default if any of the listeners explicitly return false |
| result = executeListenerWithErrorHandling(lView, nextListenerFn, e) && result; |
| nextListenerFn = nextListenerFn.__ngNextListenerFn__; |
| } |
| if (wrapWithPreventDefault && result === false) { |
| e.preventDefault(); |
| // Necessary for legacy browsers that don't support preventDefault (e.g. IE) |
| e.returnValue = false; |
| } |
| return result; |
| }; |
| } |
| |
| /** |
| * @license |
| * Copyright Google Inc. All Rights Reserved. |
| * |
| * Use of this source code is governed by an MIT-style license that can be |
| * found in the LICENSE file at https://angular.io/license |
| */ |
| |
| /** |
| * @license |
| * Copyright Google Inc. All Rights Reserved. |
| * |
| * Use of this source code is governed by an MIT-style license that can be |
| * found in the LICENSE file at https://angular.io/license |
| */ |
| /** |
| * Retrieves a context at the level specified and saves it as the global, contextViewData. |
| * Will get the next level up if level is not specified. |
| * |
| * This is used to save contexts of parent views so they can be bound in embedded views, or |
| * in conjunction with reference() to bind a ref from a parent view. |
| * |
| * @param level The relative level of the view from which to grab context compared to contextVewData |
| * @returns context |
| * |
| * @codeGenApi |
| */ |
| function ɵɵnextContext(level) { |
| if (level === void 0) { level = 1; } |
| return nextContextImpl(level); |
| } |
| |
| /** |
| * Checks a given node against matching projection slots and returns the |
| * determined slot index. Returns "null" if no slot matched the given node. |
| * |
| * This function takes into account the parsed ngProjectAs selector from the |
| * node's attributes. If present, it will check whether the ngProjectAs selector |
| * matches any of the projection slot selectors. |
| */ |
| function matchingProjectionSlotIndex(tNode, projectionSlots) { |
| var wildcardNgContentIndex = null; |
| var ngProjectAsAttrVal = getProjectAsAttrValue(tNode); |
| for (var i = 0; i < projectionSlots.length; i++) { |
| var slotValue = projectionSlots[i]; |
| // The last wildcard projection slot should match all nodes which aren't matching |
| // any selector. This is necessary to be backwards compatible with view engine. |
| if (slotValue === '*') { |
| wildcardNgContentIndex = i; |
| continue; |
| } |
| // If we ran into an `ngProjectAs` attribute, we should match its parsed selector |
| // to the list of selectors, otherwise we fall back to matching against the node. |
| if (ngProjectAsAttrVal === null ? |
| isNodeMatchingSelectorList(tNode, slotValue, /* isProjectionMode */ true) : |
| isSelectorInSelectorList(ngProjectAsAttrVal, slotValue)) { |
| return i; // first matching selector "captures" a given node |
| } |
| } |
| return wildcardNgContentIndex; |
| } |
| /** |
| * Instruction to distribute projectable nodes among <ng-content> occurrences in a given template. |
| * It takes all the selectors from the entire component's template and decides where |
| * each projected node belongs (it re-distributes nodes among "buckets" where each "bucket" is |
| * backed by a selector). |
| * |
| * This function requires CSS selectors to be provided in 2 forms: parsed (by a compiler) and text, |
| * un-parsed form. |
| * |
| * The parsed form is needed for efficient matching of a node against a given CSS selector. |
| * The un-parsed, textual form is needed for support of the ngProjectAs attribute. |
| * |
| * Having a CSS selector in 2 different formats is not ideal, but alternatives have even more |
| * drawbacks: |
| * - having only a textual form would require runtime parsing of CSS selectors; |
| * - we can't have only a parsed as we can't re-construct textual form from it (as entered by a |
| * template author). |
| * |
| * @param projectionSlots? A collection of projection slots. A projection slot can be based |
| * on a parsed CSS selectors or set to the wildcard selector ("*") in order to match |
| * all nodes which do not match any selector. If not specified, a single wildcard |
| * selector projection slot will be defined. |
| * |
| * @codeGenApi |
| */ |
| function ɵɵprojectionDef(projectionSlots) { |
| var componentNode = findComponentView(getLView())[T_HOST]; |
| if (!componentNode.projection) { |
| // If no explicit projection slots are defined, fall back to a single |
| // projection slot with the wildcard selector. |
| var numProjectionSlots = projectionSlots ? projectionSlots.length : 1; |
| var projectionHeads = componentNode.projection = |
| new Array(numProjectionSlots).fill(null); |
| var tails = projectionHeads.slice(); |
| var componentChild = componentNode.child; |
| while (componentChild !== null) { |
| var slotIndex = projectionSlots ? matchingProjectionSlotIndex(componentChild, projectionSlots) : 0; |
| if (slotIndex !== null) { |
| if (tails[slotIndex]) { |
| tails[slotIndex].projectionNext = componentChild; |
| } |
| else { |
| projectionHeads[slotIndex] = componentChild; |
| } |
| tails[slotIndex] = componentChild; |
| } |
| componentChild = componentChild.next; |
| } |
| } |
| } |
| var delayProjection = false; |
| function setDelayProjection(value) { |
| delayProjection = value; |
| } |
| /** |
| * Inserts previously re-distributed projected nodes. This instruction must be preceded by a call |
| * to the projectionDef instruction. |
| * |
| * @param nodeIndex |
| * @param selectorIndex: |
| * - 0 when the selector is `*` (or unspecified as this is the default value), |
| * - 1 based index of the selector from the {@link projectionDef} |
| * |
| * @codeGenApi |
| */ |
| function ɵɵprojection(nodeIndex, selectorIndex, attrs) { |
| if (selectorIndex === void 0) { selectorIndex = 0; } |
| var lView = getLView(); |
| var tProjectionNode = getOrCreateTNode(lView[TVIEW], lView[T_HOST], nodeIndex, 1 /* Projection */, null, attrs || null); |
| // We can't use viewData[HOST_NODE] because projection nodes can be nested in embedded views. |
| if (tProjectionNode.projection === null) |
| tProjectionNode.projection = selectorIndex; |
| // `<ng-content>` has no content |
| setIsNotParent(); |
| // We might need to delay the projection of nodes if they are in the middle of an i18n block |
| if (!delayProjection) { |
| // re-distribution of projectable nodes is stored on a component's view level |
| appendProjectedNodes(lView, tProjectionNode, selectorIndex, findComponentView(lView)); |
| } |
| } |
| |
| /** |
| * |
| * Update an interpolated property on an element with a lone bound value |
| * |
| * Used when the value passed to a property has 1 interpolated value in it, an no additional text |
| * surrounds that interpolated value: |
| * |
| * ```html |
| * <div title="{{v0}}"></div> |
| * ``` |
| * |
| * Its compiled representation is:: |
| * |
| * ```ts |
| * ɵɵpropertyInterpolate('title', v0); |
| * ``` |
| * |
| * If the property name also exists as an input property on one of the element's directives, |
| * the component property will be set instead of the element property. This check must |
| * be conducted at runtime so child components that add new `@Inputs` don't have to be re-compiled. |
| * |
| * @param propName The name of the property to update |
| * @param prefix Static value used for concatenation only. |
| * @param v0 Value checked for change. |
| * @param suffix Static value used for concatenation only. |
| * @param sanitizer An optional sanitizer function |
| * @returns itself, so that it may be chained. |
| * @codeGenApi |
| */ |
| function ɵɵpropertyInterpolate(propName, v0, sanitizer) { |
| ɵɵpropertyInterpolate1(propName, '', v0, '', sanitizer); |
| return ɵɵpropertyInterpolate; |
| } |
| /** |
| * |
| * Update an interpolated property on an element with single bound value surrounded by text. |
| * |
| * Used when the value passed to a property has 1 interpolated value in it: |
| * |
| * ```html |
| * <div title="prefix{{v0}}suffix"></div> |
| * ``` |
| * |
| * Its compiled representation is:: |
| * |
| * ```ts |
| * ɵɵpropertyInterpolate1('title', 'prefix', v0, 'suffix'); |
| * ``` |
| * |
| * If the property name also exists as an input property on one of the element's directives, |
| * the component property will be set instead of the element property. This check must |
| * be conducted at runtime so child components that add new `@Inputs` don't have to be re-compiled. |
| * |
| * @param propName The name of the property to update |
| * @param prefix Static value used for concatenation only. |
| * @param v0 Value checked for change. |
| * @param suffix Static value used for concatenation only. |
| * @param sanitizer An optional sanitizer function |
| * @returns itself, so that it may be chained. |
| * @codeGenApi |
| */ |
| function ɵɵpropertyInterpolate1(propName, prefix, v0, suffix, sanitizer) { |
| var index = getSelectedIndex(); |
| var interpolatedValue = ɵɵinterpolation1(prefix, v0, suffix); |
| if (interpolatedValue !== NO_CHANGE) { |
| elementPropertyInternal(index, propName, interpolatedValue, sanitizer); |
| } |
| return ɵɵpropertyInterpolate1; |
| } |
| /** |
| * |
| * Update an interpolated property on an element with 2 bound values surrounded by text. |
| * |
| * Used when the value passed to a property has 2 interpolated values in it: |
| * |
| * ```html |
| * <div title="prefix{{v0}}-{{v1}}suffix"></div> |
| * ``` |
| * |
| * Its compiled representation is:: |
| * |
| * ```ts |
| * ɵɵpropertyInterpolate2('title', 'prefix', v0, '-', v1, 'suffix'); |
| * ``` |
| * |
| * If the property name also exists as an input property on one of the element's directives, |
| * the component property will be set instead of the element property. This check must |
| * be conducted at runtime so child components that add new `@Inputs` don't have to be re-compiled. |
| * |
| * @param propName The name of the property to update |
| * @param prefix Static value used for concatenation only. |
| * @param v0 Value checked for change. |
| * @param i0 Static value used for concatenation only. |
| * @param v1 Value checked for change. |
| * @param suffix Static value used for concatenation only. |
| * @param sanitizer An optional sanitizer function |
| * @returns itself, so that it may be chained. |
| * @codeGenApi |
| */ |
| function ɵɵpropertyInterpolate2(propName, prefix, v0, i0, v1, suffix, sanitizer) { |
| var index = getSelectedIndex(); |
| var interpolatedValue = ɵɵinterpolation2(prefix, v0, i0, v1, suffix); |
| if (interpolatedValue !== NO_CHANGE) { |
| elementPropertyInternal(index, propName, interpolatedValue, sanitizer); |
| } |
| return ɵɵpropertyInterpolate2; |
| } |
| /** |
| * |
| * Update an interpolated property on an element with 3 bound values surrounded by text. |
| * |
| * Used when the value passed to a property has 3 interpolated values in it: |
| * |
| * ```html |
| * <div title="prefix{{v0}}-{{v1}}-{{v2}}suffix"></div> |
| * ``` |
| * |
| * Its compiled representation is:: |
| * |
| * ```ts |
| * ɵɵpropertyInterpolate3( |
| * 'title', 'prefix', v0, '-', v1, '-', v2, 'suffix'); |
| * ``` |
| * |
| * If the property name also exists as an input property on one of the element's directives, |
| * the component property will be set instead of the element property. This check must |
| * be conducted at runtime so child components that add new `@Inputs` don't have to be re-compiled. |
| * |
| * @param propName The name of the property to update |
| * @param prefix Static value used for concatenation only. |
| * @param v0 Value checked for change. |
| * @param i0 Static value used for concatenation only. |
| * @param v1 Value checked for change. |
| * @param i1 Static value used for concatenation only. |
| * @param v2 Value checked for change. |
| * @param suffix Static value used for concatenation only. |
| * @param sanitizer An optional sanitizer function |
| * @returns itself, so that it may be chained. |
| * @codeGenApi |
| */ |
| function ɵɵpropertyInterpolate3(propName, prefix, v0, i0, v1, i1, v2, suffix, sanitizer) { |
| var index = getSelectedIndex(); |
| var interpolatedValue = ɵɵinterpolation3(prefix, v0, i0, v1, i1, v2, suffix); |
| if (interpolatedValue !== NO_CHANGE) { |
| elementPropertyInternal(index, propName, interpolatedValue, sanitizer); |
| } |
| return ɵɵpropertyInterpolate3; |
| } |
| /** |
| * |
| * Update an interpolated property on an element with 4 bound values surrounded by text. |
| * |
| * Used when the value passed to a property has 4 interpolated values in it: |
| * |
| * ```html |
| * <div title="prefix{{v0}}-{{v1}}-{{v2}}-{{v3}}suffix"></div> |
| * ``` |
| * |
| * Its compiled representation is:: |
| * |
| * ```ts |
| * ɵɵpropertyInterpolate4( |
| * 'title', 'prefix', v0, '-', v1, '-', v2, '-', v3, 'suffix'); |
| * ``` |
| * |
| * If the property name also exists as an input property on one of the element's directives, |
| * the component property will be set instead of the element property. This check must |
| * be conducted at runtime so child components that add new `@Inputs` don't have to be re-compiled. |
| * |
| * @param propName The name of the property to update |
| * @param prefix Static value used for concatenation only. |
| * @param v0 Value checked for change. |
| * @param i0 Static value used for concatenation only. |
| * @param v1 Value checked for change. |
| * @param i1 Static value used for concatenation only. |
| * @param v2 Value checked for change. |
| * @param i2 Static value used for concatenation only. |
| * @param v3 Value checked for change. |
| * @param suffix Static value used for concatenation only. |
| * @param sanitizer An optional sanitizer function |
| * @returns itself, so that it may be chained. |
| * @codeGenApi |
| */ |
| function ɵɵpropertyInterpolate4(propName, prefix, v0, i0, v1, i1, v2, i2, v3, suffix, sanitizer) { |
| var index = getSelectedIndex(); |
| var interpolatedValue = ɵɵinterpolation4(prefix, v0, i0, v1, i1, v2, i2, v3, suffix); |
| if (interpolatedValue !== NO_CHANGE) { |
| elementPropertyInternal(index, propName, interpolatedValue, sanitizer); |
| } |
| return ɵɵpropertyInterpolate4; |
| } |
| /** |
| * |
| * Update an interpolated property on an element with 5 bound values surrounded by text. |
| * |
| * Used when the value passed to a property has 5 interpolated values in it: |
| * |
| * ```html |
| * <div title="prefix{{v0}}-{{v1}}-{{v2}}-{{v3}}-{{v4}}suffix"></div> |
| * ``` |
| * |
| * Its compiled representation is:: |
| * |
| * ```ts |
| * ɵɵpropertyInterpolate5( |
| * 'title', 'prefix', v0, '-', v1, '-', v2, '-', v3, '-', v4, 'suffix'); |
| * ``` |
| * |
| * If the property name also exists as an input property on one of the element's directives, |
| * the component property will be set instead of the element property. This check must |
| * be conducted at runtime so child components that add new `@Inputs` don't have to be re-compiled. |
| * |
| * @param propName The name of the property to update |
| * @param prefix Static value used for concatenation only. |
| * @param v0 Value checked for change. |
| * @param i0 Static value used for concatenation only. |
| * @param v1 Value checked for change. |
| * @param i1 Static value used for concatenation only. |
| * @param v2 Value checked for change. |
| * @param i2 Static value used for concatenation only. |
| * @param v3 Value checked for change. |
| * @param i3 Static value used for concatenation only. |
| * @param v4 Value checked for change. |
| * @param suffix Static value used for concatenation only. |
| * @param sanitizer An optional sanitizer function |
| * @returns itself, so that it may be chained. |
| * @codeGenApi |
| */ |
| function ɵɵpropertyInterpolate5(propName, prefix, v0, i0, v1, i1, v2, i2, v3, i3, v4, suffix, sanitizer) { |
| var index = getSelectedIndex(); |
| var interpolatedValue = ɵɵinterpolation5(prefix, v0, i0, v1, i1, v2, i2, v3, i3, v4, suffix); |
| if (interpolatedValue !== NO_CHANGE) { |
| elementPropertyInternal(index, propName, interpolatedValue, sanitizer); |
| } |
| return ɵɵpropertyInterpolate5; |
| } |
| /** |
| * |
| * Update an interpolated property on an element with 6 bound values surrounded by text. |
| * |
| * Used when the value passed to a property has 6 interpolated values in it: |
| * |
| * ```html |
| * <div title="prefix{{v0}}-{{v1}}-{{v2}}-{{v3}}-{{v4}}-{{v5}}suffix"></div> |
| * ``` |
| * |
| * Its compiled representation is:: |
| * |
| * ```ts |
| * ɵɵpropertyInterpolate6( |
| * 'title', 'prefix', v0, '-', v1, '-', v2, '-', v3, '-', v4, '-', v5, 'suffix'); |
| * ``` |
| * |
| * If the property name also exists as an input property on one of the element's directives, |
| * the component property will be set instead of the element property. This check must |
| * be conducted at runtime so child components that add new `@Inputs` don't have to be re-compiled. |
| * |
| * @param propName The name of the property to update |
| * @param prefix Static value used for concatenation only. |
| * @param v0 Value checked for change. |
| * @param i0 Static value used for concatenation only. |
| * @param v1 Value checked for change. |
| * @param i1 Static value used for concatenation only. |
| * @param v2 Value checked for change. |
| * @param i2 Static value used for concatenation only. |
| * @param v3 Value checked for change. |
| * @param i3 Static value used for concatenation only. |
| * @param v4 Value checked for change. |
| * @param i4 Static value used for concatenation only. |
| * @param v5 Value checked for change. |
| * @param suffix Static value used for concatenation only. |
| * @param sanitizer An optional sanitizer function |
| * @returns itself, so that it may be chained. |
| * @codeGenApi |
| */ |
| function ɵɵpropertyInterpolate6(propName, prefix, v0, i0, v1, i1, v2, i2, v3, i3, v4, i4, v5, suffix, sanitizer) { |
| var index = getSelectedIndex(); |
| var interpolatedValue = ɵɵinterpolation6(prefix, v0, i0, v1, i1, v2, i2, v3, i3, v4, i4, v5, suffix); |
| if (interpolatedValue !== NO_CHANGE) { |
| elementPropertyInternal(index, propName, interpolatedValue, sanitizer); |
| } |
| return ɵɵpropertyInterpolate6; |
| } |
| /** |
| * |
| * Update an interpolated property on an element with 7 bound values surrounded by text. |
| * |
| * Used when the value passed to a property has 7 interpolated values in it: |
| * |
| * ```html |
| * <div title="prefix{{v0}}-{{v1}}-{{v2}}-{{v3}}-{{v4}}-{{v5}}-{{v6}}suffix"></div> |
| * ``` |
| * |
| * Its compiled representation is:: |
| * |
| * ```ts |
| * ɵɵpropertyInterpolate7( |
| * 'title', 'prefix', v0, '-', v1, '-', v2, '-', v3, '-', v4, '-', v5, '-', v6, 'suffix'); |
| * ``` |
| * |
| * If the property name also exists as an input property on one of the element's directives, |
| * the component property will be set instead of the element property. This check must |
| * be conducted at runtime so child components that add new `@Inputs` don't have to be re-compiled. |
| * |
| * @param propName The name of the property to update |
| * @param prefix Static value used for concatenation only. |
| * @param v0 Value checked for change. |
| * @param i0 Static value used for concatenation only. |
| * @param v1 Value checked for change. |
| * @param i1 Static value used for concatenation only. |
| * @param v2 Value checked for change. |
| * @param i2 Static value used for concatenation only. |
| * @param v3 Value checked for change. |
| * @param i3 Static value used for concatenation only. |
| * @param v4 Value checked for change. |
| * @param i4 Static value used for concatenation only. |
| * @param v5 Value checked for change. |
| * @param i5 Static value used for concatenation only. |
| * @param v6 Value checked for change. |
| * @param suffix Static value used for concatenation only. |
| * @param sanitizer An optional sanitizer function |
| * @returns itself, so that it may be chained. |
| * @codeGenApi |
| */ |
| function ɵɵpropertyInterpolate7(propName, prefix, v0, i0, v1, i1, v2, i2, v3, i3, v4, i4, v5, i5, v6, suffix, sanitizer) { |
| var index = getSelectedIndex(); |
| var interpolatedValue = ɵɵinterpolation7(prefix, v0, i0, v1, i1, v2, i2, v3, i3, v4, i4, v5, i5, v6, suffix); |
| if (interpolatedValue !== NO_CHANGE) { |
| elementPropertyInternal(index, propName, interpolatedValue, sanitizer); |
| } |
| return ɵɵpropertyInterpolate7; |
| } |
| /** |
| * |
| * Update an interpolated property on an element with 8 bound values surrounded by text. |
| * |
| * Used when the value passed to a property has 8 interpolated values in it: |
| * |
| * ```html |
| * <div title="prefix{{v0}}-{{v1}}-{{v2}}-{{v3}}-{{v4}}-{{v5}}-{{v6}}-{{v7}}suffix"></div> |
| * ``` |
| * |
| * Its compiled representation is:: |
| * |
| * ```ts |
| * ɵɵpropertyInterpolate8( |
| * 'title', 'prefix', v0, '-', v1, '-', v2, '-', v3, '-', v4, '-', v5, '-', v6, '-', v7, 'suffix'); |
| * ``` |
| * |
| * If the property name also exists as an input property on one of the element's directives, |
| * the component property will be set instead of the element property. This check must |
| * be conducted at runtime so child components that add new `@Inputs` don't have to be re-compiled. |
| * |
| * @param propName The name of the property to update |
| * @param prefix Static value used for concatenation only. |
| * @param v0 Value checked for change. |
| * @param i0 Static value used for concatenation only. |
| * @param v1 Value checked for change. |
| * @param i1 Static value used for concatenation only. |
| * @param v2 Value checked for change. |
| * @param i2 Static value used for concatenation only. |
| * @param v3 Value checked for change. |
| * @param i3 Static value used for concatenation only. |
| * @param v4 Value checked for change. |
| * @param i4 Static value used for concatenation only. |
| * @param v5 Value checked for change. |
| * @param i5 Static value used for concatenation only. |
| * @param v6 Value checked for change. |
| * @param i6 Static value used for concatenation only. |
| * @param v7 Value checked for change. |
| * @param suffix Static value used for concatenation only. |
| * @param sanitizer An optional sanitizer function |
| * @returns itself, so that it may be chained. |
| * @codeGenApi |
| */ |
| function ɵɵpropertyInterpolate8(propName, prefix, v0, i0, v1, i1, v2, i2, v3, i3, v4, i4, v5, i5, v6, i6, v7, suffix, sanitizer) { |
| var index = getSelectedIndex(); |
| var interpolatedValue = ɵɵinterpolation8(prefix, v0, i0, v1, i1, v2, i2, v3, i3, v4, i4, v5, i5, v6, i6, v7, suffix); |
| if (interpolatedValue !== NO_CHANGE) { |
| elementPropertyInternal(index, propName, interpolatedValue, sanitizer); |
| } |
| return ɵɵpropertyInterpolate8; |
| } |
| /** |
| * Update an interpolated property on an element with 8 or more bound values surrounded by text. |
| * |
| * Used when the number of interpolated values exceeds 7. |
| * |
| * ```html |
| * <div |
| * title="prefix{{v0}}-{{v1}}-{{v2}}-{{v3}}-{{v4}}-{{v5}}-{{v6}}-{{v7}}-{{v8}}-{{v9}}suffix"></div> |
| * ``` |
| * |
| * Its compiled representation is:: |
| * |
| * ```ts |
| * ɵɵpropertyInterpolateV( |
| * 'title', ['prefix', v0, '-', v1, '-', v2, '-', v3, '-', v4, '-', v5, '-', v6, '-', v7, '-', v9, |
| * 'suffix']); |
| * ``` |
| * |
| * If the property name also exists as an input property on one of the element's directives, |
| * the component property will be set instead of the element property. This check must |
| * be conducted at runtime so child components that add new `@Inputs` don't have to be re-compiled. |
| * |
| * @param propName The name of the property to update. |
| * @param values The a collection of values and the strings inbetween those values, beginning with a |
| * string prefix and ending with a string suffix. |
| * (e.g. `['prefix', value0, '-', value1, '-', value2, ..., value99, 'suffix']`) |
| * @param sanitizer An optional sanitizer function |
| * @returns itself, so that it may be chained. |
| * @codeGenApi |
| */ |
| function ɵɵpropertyInterpolateV(propName, values, sanitizer) { |
| var index = getSelectedIndex(); |
| var interpolatedValue = ɵɵinterpolationV(values); |
| if (interpolatedValue !== NO_CHANGE) { |
| elementPropertyInternal(index, propName, interpolatedValue, sanitizer); |
| } |
| return ɵɵpropertyInterpolateV; |
| } |
| |
| /** |
| * @license |
| * Copyright Google Inc. All Rights Reserved. |
| * |
| * Use of this source code is governed by an MIT-style license that can be |
| * found in the LICENSE file at https://angular.io/license |
| */ |
| /** |
| * Create static text node |
| * |
| * @param index Index of the node in the data array |
| * @param value Value to write. This value will be stringified. |
| * |
| * @codeGenApi |
| */ |
| function ɵɵtext(index, value) { |
| var lView = getLView(); |
| ngDevMode && assertEqual(lView[BINDING_INDEX], lView[TVIEW].bindingStartIndex, 'text nodes should be created before any bindings'); |
| ngDevMode && ngDevMode.rendererCreateTextNode++; |
| ngDevMode && assertDataInRange(lView, index + HEADER_OFFSET); |
| var textNative = lView[index + HEADER_OFFSET] = createTextNode(value, lView[RENDERER]); |
| ngDevMode && ngDevMode.rendererSetText++; |
| var tNode = getOrCreateTNode(lView[TVIEW], lView[T_HOST], index, 3 /* Element */, null, null); |
| // Text nodes are self closing. |
| setIsNotParent(); |
| appendChild(textNative, tNode, lView); |
| } |
| /** |
| * Create text node with binding |
| * Bindings should be handled externally with the proper interpolation(1-8) method |
| * |
| * @param value Stringified value to write. |
| * |
| * @codeGenApi |
| */ |
| function ɵɵtextBinding(value) { |
| var lView = getLView(); |
| var index = getSelectedIndex(); |
| var bound = bind(lView, value); |
| if (bound !== NO_CHANGE) { |
| textBindingInternal(lView, index, renderStringify(bound)); |
| } |
| } |
| |
| /** |
| * @license |
| * Copyright Google Inc. All Rights Reserved. |
| * |
| * Use of this source code is governed by an MIT-style license that can be |
| * found in the LICENSE file at https://angular.io/license |
| */ |
| /** |
| * |
| * Update text content with a lone bound value |
| * |
| * Used when a text node has 1 interpolated value in it, an no additional text |
| * surrounds that interpolated value: |
| * |
| * ```html |
| * <div>{{v0}}</div> |
| * ``` |
| * |
| * Its compiled representation is: |
| * |
| * ```ts |
| * ɵɵtextInterpolate(v0); |
| * ``` |
| * @returns itself, so that it may be chained. |
| * @see textInterpolateV |
| * @codeGenApi |
| */ |
| function ɵɵtextInterpolate(v0) { |
| ɵɵtextInterpolate1('', v0, ''); |
| return ɵɵtextInterpolate; |
| } |
| /** |
| * |
| * Update text content with single bound value surrounded by other text. |
| * |
| * Used when a text node has 1 interpolated value in it: |
| * |
| * ```html |
| * <div>prefix{{v0}}suffix</div> |
| * ``` |
| * |
| * Its compiled representation is: |
| * |
| * ```ts |
| * ɵɵtextInterpolate1('prefix', v0, 'suffix'); |
| * ``` |
| * @returns itself, so that it may be chained. |
| * @see textInterpolateV |
| * @codeGenApi |
| */ |
| function ɵɵtextInterpolate1(prefix, v0, suffix) { |
| var index = getSelectedIndex(); |
| var lView = getLView(); |
| var interpolated = ɵɵinterpolation1(prefix, v0, suffix); |
| if (interpolated !== NO_CHANGE) { |
| textBindingInternal(lView, index, interpolated); |
| } |
| return ɵɵtextInterpolate1; |
| } |
| /** |
| * |
| * Update text content with 2 bound values surrounded by other text. |
| * |
| * Used when a text node has 2 interpolated values in it: |
| * |
| * ```html |
| * <div>prefix{{v0}}-{{v1}}suffix</div> |
| * ``` |
| * |
| * Its compiled representation is: |
| * |
| * ```ts |
| * ɵɵtextInterpolate2('prefix', v0, '-', v1, 'suffix'); |
| * ``` |
| * @returns itself, so that it may be chained. |
| * @see textInterpolateV |
| * @codeGenApi |
| */ |
| function ɵɵtextInterpolate2(prefix, v0, i0, v1, suffix) { |
| var index = getSelectedIndex(); |
| var lView = getLView(); |
| var interpolated = ɵɵinterpolation2(prefix, v0, i0, v1, suffix); |
| if (interpolated !== NO_CHANGE) { |
| textBindingInternal(lView, index, interpolated); |
| } |
| return ɵɵtextInterpolate2; |
| } |
| /** |
| * |
| * Update text content with 3 bound values surrounded by other text. |
| * |
| * Used when a text node has 3 interpolated values in it: |
| * |
| * ```html |
| * <div>prefix{{v0}}-{{v1}}-{{v2}}suffix</div> |
| * ``` |
| * |
| * Its compiled representation is: |
| * |
| * ```ts |
| * ɵɵtextInterpolate3( |
| * 'prefix', v0, '-', v1, '-', v2, 'suffix'); |
| * ``` |
| * @returns itself, so that it may be chained. |
| * @see textInterpolateV |
| * @codeGenApi |
| */ |
| function ɵɵtextInterpolate3(prefix, v0, i0, v1, i1, v2, suffix) { |
| var index = getSelectedIndex(); |
| var lView = getLView(); |
| var interpolated = ɵɵinterpolation3(prefix, v0, i0, v1, i1, v2, suffix); |
| if (interpolated !== NO_CHANGE) { |
| textBindingInternal(lView, index, interpolated); |
| } |
| return ɵɵtextInterpolate3; |
| } |
| /** |
| * |
| * Update text content with 4 bound values surrounded by other text. |
| * |
| * Used when a text node has 4 interpolated values in it: |
| * |
| * ```html |
| * <div>prefix{{v0}}-{{v1}}-{{v2}}-{{v3}}suffix</div> |
| * ``` |
| * |
| * Its compiled representation is: |
| * |
| * ```ts |
| * ɵɵtextInterpolate4( |
| * 'prefix', v0, '-', v1, '-', v2, '-', v3, 'suffix'); |
| * ``` |
| * @returns itself, so that it may be chained. |
| * @see ɵɵtextInterpolateV |
| * @codeGenApi |
| */ |
| function ɵɵtextInterpolate4(prefix, v0, i0, v1, i1, v2, i2, v3, suffix) { |
| var index = getSelectedIndex(); |
| var lView = getLView(); |
| var interpolated = ɵɵinterpolation4(prefix, v0, i0, v1, i1, v2, i2, v3, suffix); |
| if (interpolated !== NO_CHANGE) { |
| textBindingInternal(lView, index, interpolated); |
| } |
| return ɵɵtextInterpolate4; |
| } |
| /** |
| * |
| * Update text content with 5 bound values surrounded by other text. |
| * |
| * Used when a text node has 5 interpolated values in it: |
| * |
| * ```html |
| * <div>prefix{{v0}}-{{v1}}-{{v2}}-{{v3}}-{{v4}}suffix</div> |
| * ``` |
| * |
| * Its compiled representation is: |
| * |
| * ```ts |
| * ɵɵtextInterpolate5( |
| * 'prefix', v0, '-', v1, '-', v2, '-', v3, '-', v4, 'suffix'); |
| * ``` |
| * @returns itself, so that it may be chained. |
| * @see textInterpolateV |
| * @codeGenApi |
| */ |
| function ɵɵtextInterpolate5(prefix, v0, i0, v1, i1, v2, i2, v3, i3, v4, suffix) { |
| var index = getSelectedIndex(); |
| var lView = getLView(); |
| var interpolated = ɵɵinterpolation5(prefix, v0, i0, v1, i1, v2, i2, v3, i3, v4, suffix); |
| if (interpolated !== NO_CHANGE) { |
| textBindingInternal(lView, index, interpolated); |
| } |
| return ɵɵtextInterpolate5; |
| } |
| /** |
| * |
| * Update text content with 6 bound values surrounded by other text. |
| * |
| * Used when a text node has 6 interpolated values in it: |
| * |
| * ```html |
| * <div>prefix{{v0}}-{{v1}}-{{v2}}-{{v3}}-{{v4}}-{{v5}}suffix</div> |
| * ``` |
| * |
| * Its compiled representation is: |
| * |
| * ```ts |
| * ɵɵtextInterpolate6( |
| * 'prefix', v0, '-', v1, '-', v2, '-', v3, '-', v4, '-', v5, 'suffix'); |
| * ``` |
| * |
| * @param i4 Static value used for concatenation only. |
| * @param v5 Value checked for change. @returns itself, so that it may be chained. |
| * @see textInterpolateV |
| * @codeGenApi |
| */ |
| function ɵɵtextInterpolate6(prefix, v0, i0, v1, i1, v2, i2, v3, i3, v4, i4, v5, suffix) { |
| var index = getSelectedIndex(); |
| var lView = getLView(); |
| var interpolated = ɵɵinterpolation6(prefix, v0, i0, v1, i1, v2, i2, v3, i3, v4, i4, v5, suffix); |
| if (interpolated !== NO_CHANGE) { |
| textBindingInternal(lView, index, interpolated); |
| } |
| return ɵɵtextInterpolate6; |
| } |
| /** |
| * |
| * Update text content with 7 bound values surrounded by other text. |
| * |
| * Used when a text node has 7 interpolated values in it: |
| * |
| * ```html |
| * <div>prefix{{v0}}-{{v1}}-{{v2}}-{{v3}}-{{v4}}-{{v5}}-{{v6}}suffix</div> |
| * ``` |
| * |
| * Its compiled representation is: |
| * |
| * ```ts |
| * ɵɵtextInterpolate7( |
| * 'prefix', v0, '-', v1, '-', v2, '-', v3, '-', v4, '-', v5, '-', v6, 'suffix'); |
| * ``` |
| * @returns itself, so that it may be chained. |
| * @see textInterpolateV |
| * @codeGenApi |
| */ |
| function ɵɵtextInterpolate7(prefix, v0, i0, v1, i1, v2, i2, v3, i3, v4, i4, v5, i5, v6, suffix) { |
| var index = getSelectedIndex(); |
| var lView = getLView(); |
| var interpolated = ɵɵinterpolation7(prefix, v0, i0, v1, i1, v2, i2, v3, i3, v4, i4, v5, i5, v6, suffix); |
| if (interpolated !== NO_CHANGE) { |
| textBindingInternal(lView, index, interpolated); |
| } |
| return ɵɵtextInterpolate7; |
| } |
| /** |
| * |
| * Update text content with 8 bound values surrounded by other text. |
| * |
| * Used when a text node has 8 interpolated values in it: |
| * |
| * ```html |
| * <div>prefix{{v0}}-{{v1}}-{{v2}}-{{v3}}-{{v4}}-{{v5}}-{{v6}}-{{v7}}suffix</div> |
| * ``` |
| * |
| * Its compiled representation is: |
| * |
| * ```ts |
| * ɵɵtextInterpolate8( |
| * 'prefix', v0, '-', v1, '-', v2, '-', v3, '-', v4, '-', v5, '-', v6, '-', v7, 'suffix'); |
| * ``` |
| * @returns itself, so that it may be chained. |
| * @see textInterpolateV |
| * @codeGenApi |
| */ |
| function ɵɵtextInterpolate8(prefix, v0, i0, v1, i1, v2, i2, v3, i3, v4, i4, v5, i5, v6, i6, v7, suffix) { |
| var index = getSelectedIndex(); |
| var lView = getLView(); |
| var interpolated = ɵɵinterpolation8(prefix, v0, i0, v1, i1, v2, i2, v3, i3, v4, i4, v5, i5, v6, i6, v7, suffix); |
| if (interpolated !== NO_CHANGE) { |
| textBindingInternal(lView, index, interpolated); |
| } |
| return ɵɵtextInterpolate8; |
| } |
| /** |
| * Update text content with 9 or more bound values other surrounded by text. |
| * |
| * Used when the number of interpolated values exceeds 8. |
| * |
| * ```html |
| * <div>prefix{{v0}}-{{v1}}-{{v2}}-{{v3}}-{{v4}}-{{v5}}-{{v6}}-{{v7}}-{{v8}}-{{v9}}suffix</div> |
| * ``` |
| * |
| * Its compiled representation is: |
| * |
| * ```ts |
| * ɵɵtextInterpolateV( |
| * ['prefix', v0, '-', v1, '-', v2, '-', v3, '-', v4, '-', v5, '-', v6, '-', v7, '-', v9, |
| * 'suffix']); |
| * ``` |
| *. |
| * @param values The a collection of values and the strings in between those values, beginning with |
| * a string prefix and ending with a string suffix. |
| * (e.g. `['prefix', value0, '-', value1, '-', value2, ..., value99, 'suffix']`) |
| * |
| * @returns itself, so that it may be chained. |
| * @codeGenApi |
| */ |
| function ɵɵtextInterpolateV(values) { |
| var index = getSelectedIndex(); |
| var lView = getLView(); |
| var interpolated = ɵɵinterpolationV(values); |
| if (interpolated !== NO_CHANGE) { |
| textBindingInternal(lView, index, interpolated); |
| } |
| return ɵɵtextInterpolateV; |
| } |
| |
| /** |
| * @license |
| * Copyright Google Inc. All Rights Reserved. |
| * |
| * Use of this source code is governed by an MIT-style license that can be |
| * found in the LICENSE file at https://angular.io/license |
| */ |
| |
| /** |
| * @license |
| * Copyright Google Inc. All Rights Reserved. |
| * |
| * Use of this source code is governed by an MIT-style license that can be |
| * found in the LICENSE file at https://angular.io/license |
| */ |
| /** |
| * Adds a player to an element, directive or component instance that will later be |
| * animated once change detection has passed. |
| * |
| * When a player is added to a reference it will stay active until `player.destroy()` |
| * is called. Once called then the player will be removed from the active players |
| * present on the associated ref instance. |
| * |
| * To get a list of all the active players on an element see [getPlayers]. |
| * |
| * @param ref The element, directive or component that the player will be placed on. |
| * @param player The player that will be triggered to play once change detection has run. |
| */ |
| function addPlayer(ref, player) { |
| var context = getLContext(ref); |
| if (!context) { |
| ngDevMode && throwInvalidRefError(); |
| return; |
| } |
| var element = context.native; |
| var lView = context.lView; |
| var playerContext = getOrCreatePlayerContext(element, context); |
| var rootContext = getRootContext(lView); |
| addPlayerInternal(playerContext, rootContext, element, player, 0, ref); |
| scheduleTick(rootContext, 2 /* FlushPlayers */); |
| } |
| /** |
| * Returns a list of all the active players present on the provided ref instance (which can |
| * be an instance of a directive, component or element). |
| * |
| * This function will only return players that have been added to the ref instance using |
| * `addPlayer` or any players that are active through any template styling bindings |
| * (`[style]`, `[style.prop]`, `[class]` and `[class.name]`). |
| * |
| * @publicApi |
| */ |
| function getPlayers(ref) { |
| var context = getLContext(ref); |
| if (!context) { |
| ngDevMode && throwInvalidRefError(); |
| return []; |
| } |
| var stylingContext = getStylingContextFromLView(context.nodeIndex, context.lView); |
| var playerContext = stylingContext ? getPlayerContext(stylingContext) : null; |
| return playerContext ? getPlayersInternal(playerContext) : []; |
| } |
| |
| /** |
| * @license |
| * Copyright Google Inc. All Rights Reserved. |
| * |
| * Use of this source code is governed by an MIT-style license that can be |
| * found in the LICENSE file at https://angular.io/license |
| */ |
| /** |
| * Returns the component instance associated with a given DOM host element. |
| * Elements which don't represent components return `null`. |
| * |
| * @param element Host DOM element from which the component should be retrieved. |
| * |
| * ``` |
| * <my-app> |
| * #VIEW |
| * <div> |
| * <child-comp></child-comp> |
| * </div> |
| * </mp-app> |
| * |
| * expect(getComponent(<child-comp>) instanceof ChildComponent).toBeTruthy(); |
| * expect(getComponent(<my-app>) instanceof MyApp).toBeTruthy(); |
| * ``` |
| * |
| * @publicApi |
| */ |
| function getComponent(element) { |
| var context = loadLContextFromNode(element); |
| if (context.component === undefined) { |
| context.component = getComponentAtNodeIndex(context.nodeIndex, context.lView); |
| } |
| return context.component; |
| } |
| /** |
| * Returns the component instance associated with a given DOM host element. |
| * Elements which don't represent components return `null`. |
| * |
| * @param element Host DOM element from which the component should be retrieved. |
| * |
| * ``` |
| * <my-app> |
| * #VIEW |
| * <div> |
| * <child-comp></child-comp> |
| * </div> |
| * </mp-app> |
| * |
| * expect(getComponent(<child-comp>) instanceof ChildComponent).toBeTruthy(); |
| * expect(getComponent(<my-app>) instanceof MyApp).toBeTruthy(); |
| * ``` |
| * |
| * @publicApi |
| */ |
| function getContext$1(element) { |
| var context = loadLContextFromNode(element); |
| return context.lView[CONTEXT]; |
| } |
| /** |
| * Returns the component instance associated with view which owns the DOM element (`null` |
| * otherwise). |
| * |
| * @param element DOM element which is owned by an existing component's view. |
| * |
| * ``` |
| * <my-app> |
| * #VIEW |
| * <div> |
| * <child-comp></child-comp> |
| * </div> |
| * </mp-app> |
| * |
| * expect(getViewComponent(<child-comp>) instanceof MyApp).toBeTruthy(); |
| * expect(getViewComponent(<my-app>)).toEqual(null); |
| * ``` |
| * |
| * @publicApi |
| */ |
| function getViewComponent(element) { |
| var context = loadLContext(element); |
| var lView = context.lView; |
| var parent; |
| ngDevMode && assertLView(lView); |
| while (lView[HOST] === null && (parent = getLViewParent(lView))) { |
| // As long as lView[HOST] is null we know we are part of sub-template such as `*ngIf` |
| lView = parent; |
| } |
| return lView[FLAGS] & 512 /* IsRoot */ ? null : lView[CONTEXT]; |
| } |
| /** |
| * Retrieve all root components. |
| * |
| * Root components are those which have been bootstrapped by Angular. |
| * |
| * @param target A DOM element, component or directive instance. |
| * |
| * @publicApi |
| */ |
| function getRootComponents(target) { |
| return __spread(getRootContext(target).components); |
| } |
| /** |
| * Retrieves an `Injector` associated with the element, component or directive. |
| * |
| * @param target A DOM element, component or directive instance. |
| * |
| * @publicApi |
| */ |
| function getInjector(target) { |
| var context = loadLContext(target); |
| var tNode = context.lView[TVIEW].data[context.nodeIndex]; |
| return new NodeInjector(tNode, context.lView); |
| } |
| /** |
| * Retrieve a set of injection tokens at a given DOM node. |
| * |
| * @param element Element for which the injection tokens should be retrieved. |
| * @publicApi |
| */ |
| function getInjectionTokens(element) { |
| var context = loadLContext(element, false); |
| if (!context) |
| return []; |
| var lView = context.lView; |
| var tView = lView[TVIEW]; |
| var tNode = tView.data[context.nodeIndex]; |
| var providerTokens = []; |
| var startIndex = tNode.providerIndexes & 65535 /* ProvidersStartIndexMask */; |
| var endIndex = tNode.directiveEnd; |
| for (var i = startIndex; i < endIndex; i++) { |
| var value = tView.data[i]; |
| if (isDirectiveDefHack(value)) { |
| // The fact that we sometimes store Type and sometimes DirectiveDef in this location is a |
| // design flaw. We should always store same type so that we can be monomorphic. The issue |
| // is that for Components/Directives we store the def instead the type. The correct behavior |
| // is that we should always be storing injectable type in this location. |
| value = value.type; |
| } |
| providerTokens.push(value); |
| } |
| return providerTokens; |
| } |
| /** |
| * Retrieves directives associated with a given DOM host element. |
| * |
| * @param target A DOM element, component or directive instance. |
| * |
| * @publicApi |
| */ |
| function getDirectives(target) { |
| var context = loadLContext(target); |
| if (context.directives === undefined) { |
| context.directives = getDirectivesAtNodeIndex(context.nodeIndex, context.lView, false); |
| } |
| return context.directives || []; |
| } |
| function loadLContext(target, throwOnNotFound) { |
| if (throwOnNotFound === void 0) { throwOnNotFound = true; } |
| var context = getLContext(target); |
| if (!context && throwOnNotFound) { |
| throw new Error(ngDevMode ? "Unable to find context associated with " + stringifyForError(target) : |
| 'Invalid ng target'); |
| } |
| return context; |
| } |
| /** |
| * Retrieve map of local references. |
| * |
| * The references are retrieved as a map of local reference name to element or directive instance. |
| * |
| * @param target A DOM element, component or directive instance. |
| * |
| * @publicApi |
| */ |
| function getLocalRefs(target) { |
| var context = loadLContext(target); |
| if (context.localRefs === undefined) { |
| context.localRefs = discoverLocalRefs(context.lView, context.nodeIndex); |
| } |
| return context.localRefs || {}; |
| } |
| /** |
| * Retrieve the host element of the component. |
| * |
| * Use this function to retrieve the host element of the component. The host |
| * element is the element which the component is associated with. |
| * |
| * @param directive Component or Directive for which the host element should be retrieved. |
| * |
| * @publicApi |
| */ |
| function getHostElement(directive) { |
| return getLContext(directive).native; |
| } |
| function loadLContextFromNode(node) { |
| if (!(node instanceof Node)) |
| throw new Error('Expecting instance of DOM Node'); |
| return loadLContext(node); |
| } |
| function isBrowserEvents(listener) { |
| // Browser events are those which don't have `useCapture` as boolean. |
| return typeof listener.useCapture === 'boolean'; |
| } |
| /** |
| * Retrieves a list of DOM listeners. |
| * |
| * ``` |
| * <my-app> |
| * #VIEW |
| * <div (click)="doSomething()"> |
| * </div> |
| * </mp-app> |
| * |
| * expect(getListeners(<div>)).toEqual({ |
| * name: 'click', |
| * element: <div>, |
| * callback: () => doSomething(), |
| * useCapture: false |
| * }); |
| * ``` |
| * |
| * @param element Element for which the DOM listeners should be retrieved. |
| * @publicApi |
| */ |
| function getListeners(element) { |
| var lContext = loadLContextFromNode(element); |
| var lView = lContext.lView; |
| var tView = lView[TVIEW]; |
| var lCleanup = lView[CLEANUP]; |
| var tCleanup = tView.cleanup; |
| var listeners = []; |
| if (tCleanup && lCleanup) { |
| for (var i = 0; i < tCleanup.length;) { |
| var firstParam = tCleanup[i++]; |
| var secondParam = tCleanup[i++]; |
| if (typeof firstParam === 'string') { |
| var name_1 = firstParam; |
| var listenerElement = unwrapRNode(lView[secondParam]); |
| var callback = lCleanup[tCleanup[i++]]; |
| var useCaptureOrIndx = tCleanup[i++]; |
| // if useCaptureOrIndx is boolean then report it as is. |
| // if useCaptureOrIndx is positive number then it in unsubscribe method |
| // if useCaptureOrIndx is negative number then it is a Subscription |
| var useCapture = typeof useCaptureOrIndx === 'boolean' ? |
| useCaptureOrIndx : |
| (useCaptureOrIndx >= 0 ? false : null); |
| if (element == listenerElement) { |
| listeners.push({ element: element, name: name_1, callback: callback, useCapture: useCapture }); |
| } |
| } |
| } |
| } |
| listeners.sort(sortListeners); |
| return listeners; |
| } |
| function sortListeners(a, b) { |
| if (a.name == b.name) |
| return 0; |
| return a.name < b.name ? -1 : 1; |
| } |
| /** |
| * This function should not exist because it is megamorphic and only mostly correct. |
| * |
| * See call site for more info. |
| */ |
| function isDirectiveDefHack(obj) { |
| return obj.type !== undefined && obj.template !== undefined && obj.declaredInputs !== undefined; |
| } |
| |
| /** |
| * @license |
| * Copyright Google Inc. All Rights Reserved. |
| * |
| * Use of this source code is governed by an MIT-style license that can be |
| * found in the LICENSE file at https://angular.io/license |
| */ |
| |
| /** |
| * @license |
| * Copyright Google Inc. All Rights Reserved. |
| * |
| * Use of this source code is governed by an MIT-style license that can be |
| * found in the LICENSE file at https://angular.io/license |
| */ |
| /** |
| * This file introduces series of globally accessible debug tools |
| * to allow for the Angular debugging story to function. |
| * |
| * To see this in action run the following command: |
| * |
| * bazel run --define=compile=aot |
| * //packages/core/test/bundling/todo:devserver |
| * |
| * Then load `localhost:5432` and start using the console tools. |
| */ |
| /** |
| * This value reflects the property on the window where the dev |
| * tools are patched (window.ng). |
| * */ |
| var GLOBAL_PUBLISH_EXPANDO_KEY = 'ng'; |
| var _published = false; |
| /** |
| * Publishes a collection of default debug tools onto`window.ng`. |
| * |
| * These functions are available globally when Angular is in development |
| * mode and are automatically stripped away from prod mode is on. |
| */ |
| function publishDefaultGlobalUtils() { |
| if (!_published) { |
| _published = true; |
| publishGlobalUtil('getComponent', getComponent); |
| publishGlobalUtil('getContext', getContext$1); |
| publishGlobalUtil('getListeners', getListeners); |
| publishGlobalUtil('getViewComponent', getViewComponent); |
| publishGlobalUtil('getHostElement', getHostElement); |
| publishGlobalUtil('getInjector', getInjector); |
| publishGlobalUtil('getRootComponents', getRootComponents); |
| publishGlobalUtil('getDirectives', getDirectives); |
| publishGlobalUtil('getPlayers', getPlayers); |
| publishGlobalUtil('markDirty', markDirty); |
| } |
| } |
| /** |
| * Publishes the given function to `window.ng` so that it can be |
| * used from the browser console when an application is not in production. |
| */ |
| function publishGlobalUtil(name, fn) { |
| var w = _global; |
| ngDevMode && assertDefined(fn, 'function not defined'); |
| if (w) { |
| var container = w[GLOBAL_PUBLISH_EXPANDO_KEY]; |
| if (!container) { |
| container = w[GLOBAL_PUBLISH_EXPANDO_KEY] = {}; |
| } |
| container[name] = fn; |
| } |
| } |
| |
| /** |
| * @license |
| * Copyright Google Inc. All Rights Reserved. |
| * |
| * Use of this source code is governed by an MIT-style license that can be |
| * found in the LICENSE file at https://angular.io/license |
| */ |
| /** |
| * Bootstraps a Component into an existing host element and returns an instance |
| * of the component. |
| * |
| * Use this function to bootstrap a component into the DOM tree. Each invocation |
| * of this function will create a separate tree of components, injectors and |
| * change detection cycles and lifetimes. To dynamically insert a new component |
| * into an existing tree such that it shares the same injection, change detection |
| * and object lifetime, use {@link ViewContainer#createComponent}. |
| * |
| * @param componentType Component to bootstrap |
| * @param options Optional parameters which control bootstrapping |
| */ |
| function renderComponent(componentType /* Type as workaround for: Microsoft/TypeScript/issues/4881 */, opts) { |
| if (opts === void 0) { opts = {}; } |
| ngDevMode && publishDefaultGlobalUtils(); |
| ngDevMode && assertComponentType(componentType); |
| // this is preemptively set to avoid having test and debug code accidentally |
| // read data from a previous application state... |
| setActiveHostElement(null); |
| var rendererFactory = opts.rendererFactory || domRendererFactory3; |
| var sanitizer = opts.sanitizer || null; |
| var componentDef = getComponentDef(componentType); |
| if (componentDef.type != componentType) |
| componentDef.type = componentType; |
| // The first index of the first selector is the tag name. |
| var componentTag = componentDef.selectors[0][0]; |
| var hostRNode = locateHostElement(rendererFactory, opts.host || componentTag); |
| var rootFlags = componentDef.onPush ? 64 /* Dirty */ | 512 /* IsRoot */ : |
| 16 /* CheckAlways */ | 512 /* IsRoot */; |
| var rootContext = createRootContext(opts.scheduler, opts.playerHandler); |
| var renderer = rendererFactory.createRenderer(hostRNode, componentDef); |
| var rootView = createLView(null, createTView(-1, null, 1, 0, null, null, null, null), rootContext, rootFlags, null, null, rendererFactory, renderer, undefined, opts.injector || null); |
| var oldView = enterView(rootView, null); |
| var component; |
| // Will become true if the `try` block executes with no errors. |
| var safeToRunHooks = false; |
| try { |
| if (rendererFactory.begin) |
| rendererFactory.begin(); |
| var componentView = createRootComponentView(hostRNode, componentDef, rootView, rendererFactory, renderer, sanitizer); |
| component = createRootComponent(componentView, componentDef, rootView, rootContext, opts.hostFeatures || null); |
| addToViewTree(rootView, componentView); |
| refreshDescendantViews(rootView); // creation mode pass |
| rootView[FLAGS] &= ~4 /* CreationMode */; |
| resetPreOrderHookFlags(rootView); |
| refreshDescendantViews(rootView); // update mode pass |
| safeToRunHooks = true; |
| } |
| finally { |
| leaveView(oldView, safeToRunHooks); |
| if (rendererFactory.end) |
| rendererFactory.end(); |
| } |
| return component; |
| } |
| /** |
| * Creates the root component view and the root component node. |
| * |
| * @param rNode Render host element. |
| * @param def ComponentDef |
| * @param rootView The parent view where the host node is stored |
| * @param renderer The current renderer |
| * @param sanitizer The sanitizer, if provided |
| * |
| * @returns Component view created |
| */ |
| function createRootComponentView(rNode, def, rootView, rendererFactory, renderer, sanitizer) { |
| resetComponentState(); |
| var tView = rootView[TVIEW]; |
| ngDevMode && assertDataInRange(rootView, 0 + HEADER_OFFSET); |
| rootView[0 + HEADER_OFFSET] = rNode; |
| var tNode = getOrCreateTNode(tView, null, 0, 3 /* Element */, null, null); |
| var componentView = createLView(rootView, getOrCreateTView(def), null, def.onPush ? 64 /* Dirty */ : 16 /* CheckAlways */, rootView[HEADER_OFFSET], tNode, rendererFactory, renderer, sanitizer); |
| if (tView.firstTemplatePass) { |
| diPublicInInjector(getOrCreateNodeInjectorForNode(tNode, rootView), rootView, def.type); |
| tNode.flags = 1 /* isComponent */; |
| initNodeFlags(tNode, rootView.length, 1); |
| queueComponentIndexForCheck(tNode); |
| } |
| // Store component view at node index, with node as the HOST |
| return rootView[HEADER_OFFSET] = componentView; |
| } |
| /** |
| * Creates a root component and sets it up with features and host bindings. Shared by |
| * renderComponent() and ViewContainerRef.createComponent(). |
| */ |
| function createRootComponent(componentView, componentDef, rootView, rootContext, hostFeatures) { |
| var tView = rootView[TVIEW]; |
| // Create directive instance with factory() and store at next index in viewData |
| var component = instantiateRootComponent(tView, rootView, componentDef); |
| rootContext.components.push(component); |
| componentView[CONTEXT] = component; |
| hostFeatures && hostFeatures.forEach(function (feature) { return feature(component, componentDef); }); |
| // We want to generate an empty QueryList for root content queries for backwards |
| // compatibility with ViewEngine. |
| if (componentDef.contentQueries) { |
| componentDef.contentQueries(1 /* Create */, component, rootView.length - 1); |
| } |
| var rootTNode = getPreviousOrParentTNode(); |
| if (tView.firstTemplatePass && componentDef.hostBindings) { |
| var elementIndex = rootTNode.index - HEADER_OFFSET; |
| setActiveHostElement(elementIndex); |
| var expando = tView.expandoInstructions; |
| invokeHostBindingsInCreationMode(componentDef, expando, component, rootTNode, tView.firstTemplatePass); |
| rootTNode.onElementCreationFns && applyOnCreateInstructions(rootTNode); |
| setActiveHostElement(null); |
| } |
| if (rootTNode.stylingTemplate) { |
| var native = componentView[HOST]; |
| renderInitialClasses(native, rootTNode.stylingTemplate, componentView[RENDERER]); |
| renderInitialStyles(native, rootTNode.stylingTemplate, componentView[RENDERER]); |
| } |
| return component; |
| } |
| function createRootContext(scheduler, playerHandler) { |
| return { |
| components: [], |
| scheduler: scheduler || defaultScheduler, |
| clean: CLEAN_PROMISE, |
| playerHandler: playerHandler || null, |
| flags: 0 /* Empty */ |
| }; |
| } |
| /** |
| * Used to enable lifecycle hooks on the root component. |
| * |
| * Include this feature when calling `renderComponent` if the root component |
| * you are rendering has lifecycle hooks defined. Otherwise, the hooks won't |
| * be called properly. |
| * |
| * Example: |
| * |
| * ``` |
| * renderComponent(AppComponent, {features: [RootLifecycleHooks]}); |
| * ``` |
| */ |
| function LifecycleHooksFeature(component, def) { |
| var rootTView = readPatchedLView(component)[TVIEW]; |
| var dirIndex = rootTView.data.length - 1; |
| registerPreOrderHooks(dirIndex, def, rootTView, -1, -1, -1); |
| // TODO(misko): replace `as TNode` with createTNode call. (needs refactoring to lose dep on |
| // LNode). |
| registerPostOrderHooks(rootTView, { directiveStart: dirIndex, directiveEnd: dirIndex + 1 }); |
| } |
| /** |
| * Wait on component until it is rendered. |
| * |
| * This function returns a `Promise` which is resolved when the component's |
| * change detection is executed. This is determined by finding the scheduler |
| * associated with the `component`'s render tree and waiting until the scheduler |
| * flushes. If nothing is scheduled, the function returns a resolved promise. |
| * |
| * Example: |
| * ``` |
| * await whenRendered(myComponent); |
| * ``` |
| * |
| * @param component Component to wait upon |
| * @returns Promise which resolves when the component is rendered. |
| */ |
| function whenRendered(component) { |
| return getRootContext(component).clean; |
| } |
| |
| /** |
| * @license |
| * Copyright Google Inc. All Rights Reserved. |
| * |
| * Use of this source code is governed by an MIT-style license that can be |
| * found in the LICENSE file at https://angular.io/license |
| */ |
| /** |
| * Represents a basic change from a previous to a new value for a single |
| * property on a directive instance. Passed as a value in a |
| * {@link SimpleChanges} object to the `ngOnChanges` hook. |
| * |
| * @see `OnChanges` |
| * |
| * @publicApi |
| */ |
| var SimpleChange = /** @class */ (function () { |
| function SimpleChange(previousValue, currentValue, firstChange) { |
| this.previousValue = previousValue; |
| this.currentValue = currentValue; |
| this.firstChange = firstChange; |
| } |
| /** |
| * Check whether the new value is the first value assigned. |
| */ |
| SimpleChange.prototype.isFirstChange = function () { return this.firstChange; }; |
| return SimpleChange; |
| }()); |
| |
| /** |
| * @license |
| * Copyright Google Inc. All Rights Reserved. |
| * |
| * Use of this source code is governed by an MIT-style license that can be |
| * found in the LICENSE file at https://angular.io/license |
| */ |
| /** |
| * The NgOnChangesFeature decorates a component with support for the ngOnChanges |
| * lifecycle hook, so it should be included in any component that implements |
| * that hook. |
| * |
| * If the component or directive uses inheritance, the NgOnChangesFeature MUST |
| * be included as a feature AFTER {@link InheritDefinitionFeature}, otherwise |
| * inherited properties will not be propagated to the ngOnChanges lifecycle |
| * hook. |
| * |
| * Example usage: |
| * |
| * ``` |
| * static ngComponentDef = defineComponent({ |
| * ... |
| * inputs: {name: 'publicName'}, |
| * features: [NgOnChangesFeature()] |
| * }); |
| * ``` |
| * |
| * @codeGenApi |
| */ |
| function ɵɵNgOnChangesFeature() { |
| // This option ensures that the ngOnChanges lifecycle hook will be inherited |
| // from superclasses (in InheritDefinitionFeature). |
| NgOnChangesFeatureImpl.ngInherit = true; |
| return NgOnChangesFeatureImpl; |
| } |
| function NgOnChangesFeatureImpl(definition) { |
| if (definition.type.prototype.ngOnChanges) { |
| definition.setInput = ngOnChangesSetInput; |
| definition.onChanges = wrapOnChanges(); |
| } |
| } |
| function wrapOnChanges() { |
| return function wrapOnChangesHook_inPreviousChangesStorage() { |
| var simpleChangesStore = getSimpleChangesStore(this); |
| var current = simpleChangesStore && simpleChangesStore.current; |
| if (current) { |
| var previous = simpleChangesStore.previous; |
| if (previous === EMPTY_OBJ) { |
| simpleChangesStore.previous = current; |
| } |
| else { |
| // New changes are copied to the previous store, so that we don't lose history for inputs |
| // which were not changed this time |
| for (var key in current) { |
| previous[key] = current[key]; |
| } |
| } |
| simpleChangesStore.current = null; |
| this.ngOnChanges(current); |
| } |
| }; |
| } |
| function ngOnChangesSetInput(instance, value, publicName, privateName) { |
| var simpleChangesStore = getSimpleChangesStore(instance) || |
| setSimpleChangesStore(instance, { previous: EMPTY_OBJ, current: null }); |
| var current = simpleChangesStore.current || (simpleChangesStore.current = {}); |
| var previous = simpleChangesStore.previous; |
| var declaredName = this.declaredInputs[publicName]; |
| var previousChange = previous[declaredName]; |
| current[declaredName] = new SimpleChange(previousChange && previousChange.currentValue, value, previous === EMPTY_OBJ); |
| instance[privateName] = value; |
| } |
| var SIMPLE_CHANGES_STORE = '__ngSimpleChanges__'; |
| function getSimpleChangesStore(instance) { |
| return instance[SIMPLE_CHANGES_STORE] || null; |
| } |
| function setSimpleChangesStore(instance, store) { |
| return instance[SIMPLE_CHANGES_STORE] = store; |
| } |
| |
| /** |
| * @license |
| * Copyright Google Inc. All Rights Reserved. |
| * |
| * Use of this source code is governed by an MIT-style license that can be |
| * found in the LICENSE file at https://angular.io/license |
| */ |
| function getSuperType(type) { |
| return Object.getPrototypeOf(type.prototype).constructor; |
| } |
| /** |
| * Merges the definition from a super class to a sub class. |
| * @param definition The definition that is a SubClass of another directive of component |
| * |
| * @codeGenApi |
| */ |
| function ɵɵInheritDefinitionFeature(definition) { |
| var e_1, _a; |
| var superType = getSuperType(definition.type); |
| while (superType) { |
| var superDef = undefined; |
| if (isComponentDef(definition)) { |
| // Don't use getComponentDef/getDirectiveDef. This logic relies on inheritance. |
| superDef = superType.ngComponentDef || superType.ngDirectiveDef; |
| } |
| else { |
| if (superType.ngComponentDef) { |
| throw new Error('Directives cannot inherit Components'); |
| } |
| // Don't use getComponentDef/getDirectiveDef. This logic relies on inheritance. |
| superDef = superType.ngDirectiveDef; |
| } |
| var baseDef = superType.ngBaseDef; |
| // Some fields in the definition may be empty, if there were no values to put in them that |
| // would've justified object creation. Unwrap them if necessary. |
| if (baseDef || superDef) { |
| var writeableDef = definition; |
| writeableDef.inputs = maybeUnwrapEmpty(definition.inputs); |
| writeableDef.declaredInputs = maybeUnwrapEmpty(definition.declaredInputs); |
| writeableDef.outputs = maybeUnwrapEmpty(definition.outputs); |
| } |
| if (baseDef) { |
| var baseViewQuery = baseDef.viewQuery; |
| var baseContentQueries = baseDef.contentQueries; |
| var baseHostBindings = baseDef.hostBindings; |
| baseHostBindings && inheritHostBindings(definition, baseHostBindings); |
| baseViewQuery && inheritViewQuery(definition, baseViewQuery); |
| baseContentQueries && inheritContentQueries(definition, baseContentQueries); |
| fillProperties(definition.inputs, baseDef.inputs); |
| fillProperties(definition.declaredInputs, baseDef.declaredInputs); |
| fillProperties(definition.outputs, baseDef.outputs); |
| } |
| if (superDef) { |
| // Merge hostBindings |
| var superHostBindings = superDef.hostBindings; |
| superHostBindings && inheritHostBindings(definition, superHostBindings); |
| // Merge queries |
| var superViewQuery = superDef.viewQuery; |
| var superContentQueries = superDef.contentQueries; |
| superViewQuery && inheritViewQuery(definition, superViewQuery); |
| superContentQueries && inheritContentQueries(definition, superContentQueries); |
| // Merge inputs and outputs |
| fillProperties(definition.inputs, superDef.inputs); |
| fillProperties(definition.declaredInputs, superDef.declaredInputs); |
| fillProperties(definition.outputs, superDef.outputs); |
| // Inherit hooks |
| // Assume super class inheritance feature has already run. |
| definition.afterContentChecked = |
| definition.afterContentChecked || superDef.afterContentChecked; |
| definition.afterContentInit = definition.afterContentInit || superDef.afterContentInit; |
| definition.afterViewChecked = definition.afterViewChecked || superDef.afterViewChecked; |
| definition.afterViewInit = definition.afterViewInit || superDef.afterViewInit; |
| definition.doCheck = definition.doCheck || superDef.doCheck; |
| definition.onDestroy = definition.onDestroy || superDef.onDestroy; |
| definition.onInit = definition.onInit || superDef.onInit; |
| // Run parent features |
| var features = superDef.features; |
| if (features) { |
| try { |
| for (var features_1 = __values(features), features_1_1 = features_1.next(); !features_1_1.done; features_1_1 = features_1.next()) { |
| var feature = features_1_1.value; |
| if (feature && feature.ngInherit) { |
| feature(definition); |
| } |
| } |
| } |
| catch (e_1_1) { e_1 = { error: e_1_1 }; } |
| finally { |
| try { |
| if (features_1_1 && !features_1_1.done && (_a = features_1.return)) _a.call(features_1); |
| } |
| finally { if (e_1) throw e_1.error; } |
| } |
| } |
| } |
| else { |
| // Even if we don't have a definition, check the type for the hooks and use those if need be |
| var superPrototype = superType.prototype; |
| if (superPrototype) { |
| definition.afterContentChecked = |
| definition.afterContentChecked || superPrototype.ngAfterContentChecked; |
| definition.afterContentInit = |
| definition.afterContentInit || superPrototype.ngAfterContentInit; |
| definition.afterViewChecked = |
| definition.afterViewChecked || superPrototype.ngAfterViewChecked; |
| definition.afterViewInit = definition.afterViewInit || superPrototype.ngAfterViewInit; |
| definition.doCheck = definition.doCheck || superPrototype.ngDoCheck; |
| definition.onDestroy = definition.onDestroy || superPrototype.ngOnDestroy; |
| definition.onInit = definition.onInit || superPrototype.ngOnInit; |
| if (superPrototype.ngOnChanges) { |
| ɵɵNgOnChangesFeature()(definition); |
| } |
| } |
| } |
| superType = Object.getPrototypeOf(superType); |
| } |
| } |
| function maybeUnwrapEmpty(value) { |
| if (value === EMPTY_OBJ) { |
| return {}; |
| } |
| else if (value === EMPTY_ARRAY$2) { |
| return []; |
| } |
| else { |
| return value; |
| } |
| } |
| function inheritViewQuery(definition, superViewQuery) { |
| var prevViewQuery = definition.viewQuery; |
| if (prevViewQuery) { |
| definition.viewQuery = function (rf, ctx) { |
| superViewQuery(rf, ctx); |
| prevViewQuery(rf, ctx); |
| }; |
| } |
| else { |
| definition.viewQuery = superViewQuery; |
| } |
| } |
| function inheritContentQueries(definition, superContentQueries) { |
| var prevContentQueries = definition.contentQueries; |
| if (prevContentQueries) { |
| definition.contentQueries = function (rf, ctx, directiveIndex) { |
| superContentQueries(rf, ctx, directiveIndex); |
| prevContentQueries(rf, ctx, directiveIndex); |
| }; |
| } |
| else { |
| definition.contentQueries = superContentQueries; |
| } |
| } |
| function inheritHostBindings(definition, superHostBindings) { |
| var prevHostBindings = definition.hostBindings; |
| // If the subclass does not have a host bindings function, we set the subclass host binding |
| // function to be the superclass's (in this feature). We should check if they're the same here |
| // to ensure we don't inherit it twice. |
| if (superHostBindings !== prevHostBindings) { |
| if (prevHostBindings) { |
| // because inheritance is unknown during compile time, the runtime code |
| // needs to be informed of the super-class depth so that instruction code |
| // can distinguish one host bindings function from another. The reason why |
| // relying on the directive uniqueId exclusively is not enough is because the |
| // uniqueId value and the directive instance stay the same between hostBindings |
| // calls throughout the directive inheritance chain. This means that without |
| // a super-class depth value, there is no way to know whether a parent or |
| // sub-class host bindings function is currently being executed. |
| definition.hostBindings = function (rf, ctx, elementIndex) { |
| // The reason why we increment first and then decrement is so that parent |
| // hostBindings calls have a higher id value compared to sub-class hostBindings |
| // calls (this way the leaf directive is always at a super-class depth of 0). |
| adjustActiveDirectiveSuperClassDepthPosition(1); |
| try { |
| superHostBindings(rf, ctx, elementIndex); |
| } |
| finally { |
| adjustActiveDirectiveSuperClassDepthPosition(-1); |
| } |
| prevHostBindings(rf, ctx, elementIndex); |
| }; |
| } |
| else { |
| definition.hostBindings = superHostBindings; |
| } |
| } |
| } |
| |
| /** |
| * @license |
| * Copyright Google Inc. All Rights Reserved. |
| * |
| * Use of this source code is governed by an MIT-style license that can be |
| * found in the LICENSE file at https://angular.io/license |
| */ |
| /** |
| * Resolves the providers which are defined in the DirectiveDef. |
| * |
| * When inserting the tokens and the factories in their respective arrays, we can assume that |
| * this method is called first for the component (if any), and then for other directives on the same |
| * node. |
| * As a consequence,the providers are always processed in that order: |
| * 1) The view providers of the component |
| * 2) The providers of the component |
| * 3) The providers of the other directives |
| * This matches the structure of the injectables arrays of a view (for each node). |
| * So the tokens and the factories can be pushed at the end of the arrays, except |
| * in one case for multi providers. |
| * |
| * @param def the directive definition |
| * @param providers: Array of `providers`. |
| * @param viewProviders: Array of `viewProviders`. |
| */ |
| function providersResolver(def, providers, viewProviders) { |
| var lView = getLView(); |
| var tView = lView[TVIEW]; |
| if (tView.firstTemplatePass) { |
| var isComponent = isComponentDef(def); |
| // The list of view providers is processed first, and the flags are updated |
| resolveProvider$1(viewProviders, tView.data, tView.blueprint, isComponent, true); |
| // Then, the list of providers is processed, and the flags are updated |
| resolveProvider$1(providers, tView.data, tView.blueprint, isComponent, false); |
| } |
| } |
| /** |
| * Resolves a provider and publishes it to the DI system. |
| */ |
| function resolveProvider$1(provider, tInjectables, lInjectablesBlueprint, isComponent, isViewProvider) { |
| provider = resolveForwardRef(provider); |
| if (Array.isArray(provider)) { |
| // Recursively call `resolveProvider` |
| // Recursion is OK in this case because this code will not be in hot-path once we implement |
| // cloning of the initial state. |
| for (var i = 0; i < provider.length; i++) { |
| resolveProvider$1(provider[i], tInjectables, lInjectablesBlueprint, isComponent, isViewProvider); |
| } |
| } |
| else { |
| var lView = getLView(); |
| var token = isTypeProvider(provider) ? provider : resolveForwardRef(provider.provide); |
| var providerFactory = providerToFactory(provider); |
| var tNode = getPreviousOrParentTNode(); |
| var beginIndex = tNode.providerIndexes & 65535 /* ProvidersStartIndexMask */; |
| var endIndex = tNode.directiveStart; |
| var cptViewProvidersCount = tNode.providerIndexes >> 16 /* CptViewProvidersCountShift */; |
| if (isClassProvider(provider) || isTypeProvider(provider)) { |
| var prototype = (provider.useClass || provider).prototype; |
| var ngOnDestroy = prototype.ngOnDestroy; |
| if (ngOnDestroy) { |
| var tView = lView[TVIEW]; |
| (tView.destroyHooks || (tView.destroyHooks = [])).push(tInjectables.length, ngOnDestroy); |
| } |
| } |
| if (isTypeProvider(provider) || !provider.multi) { |
| // Single provider case: the factory is created and pushed immediately |
| var factory = new NodeInjectorFactory(providerFactory, isViewProvider, ɵɵdirectiveInject); |
| var existingFactoryIndex = indexOf(token, tInjectables, isViewProvider ? beginIndex : beginIndex + cptViewProvidersCount, endIndex); |
| if (existingFactoryIndex == -1) { |
| diPublicInInjector(getOrCreateNodeInjectorForNode(tNode, lView), lView, token); |
| tInjectables.push(token); |
| tNode.directiveStart++; |
| tNode.directiveEnd++; |
| if (isViewProvider) { |
| tNode.providerIndexes += 65536 /* CptViewProvidersCountShifter */; |
| } |
| lInjectablesBlueprint.push(factory); |
| lView.push(factory); |
| } |
| else { |
| lInjectablesBlueprint[existingFactoryIndex] = factory; |
| lView[existingFactoryIndex] = factory; |
| } |
| } |
| else { |
| // Multi provider case: |
| // We create a multi factory which is going to aggregate all the values. |
| // Since the output of such a factory depends on content or view injection, |
| // we create two of them, which are linked together. |
| // |
| // The first one (for view providers) is always in the first block of the injectables array, |
| // and the second one (for providers) is always in the second block. |
| // This is important because view providers have higher priority. When a multi token |
| // is being looked up, the view providers should be found first. |
| // Note that it is not possible to have a multi factory in the third block (directive block). |
| // |
| // The algorithm to process multi providers is as follows: |
| // 1) If the multi provider comes from the `viewProviders` of the component: |
| // a) If the special view providers factory doesn't exist, it is created and pushed. |
| // b) Else, the multi provider is added to the existing multi factory. |
| // 2) If the multi provider comes from the `providers` of the component or of another |
| // directive: |
| // a) If the multi factory doesn't exist, it is created and provider pushed into it. |
| // It is also linked to the multi factory for view providers, if it exists. |
| // b) Else, the multi provider is added to the existing multi factory. |
| var existingProvidersFactoryIndex = indexOf(token, tInjectables, beginIndex + cptViewProvidersCount, endIndex); |
| var existingViewProvidersFactoryIndex = indexOf(token, tInjectables, beginIndex, beginIndex + cptViewProvidersCount); |
| var doesProvidersFactoryExist = existingProvidersFactoryIndex >= 0 && |
| lInjectablesBlueprint[existingProvidersFactoryIndex]; |
| var doesViewProvidersFactoryExist = existingViewProvidersFactoryIndex >= 0 && |
| lInjectablesBlueprint[existingViewProvidersFactoryIndex]; |
| if (isViewProvider && !doesViewProvidersFactoryExist || |
| !isViewProvider && !doesProvidersFactoryExist) { |
| // Cases 1.a and 2.a |
| diPublicInInjector(getOrCreateNodeInjectorForNode(tNode, lView), lView, token); |
| var factory = multiFactory(isViewProvider ? multiViewProvidersFactoryResolver : multiProvidersFactoryResolver, lInjectablesBlueprint.length, isViewProvider, isComponent, providerFactory); |
| if (!isViewProvider && doesViewProvidersFactoryExist) { |
| lInjectablesBlueprint[existingViewProvidersFactoryIndex].providerFactory = factory; |
| } |
| tInjectables.push(token); |
| tNode.directiveStart++; |
| tNode.directiveEnd++; |
| if (isViewProvider) { |
| tNode.providerIndexes += 65536 /* CptViewProvidersCountShifter */; |
| } |
| lInjectablesBlueprint.push(factory); |
| lView.push(factory); |
| } |
| else { |
| // Cases 1.b and 2.b |
| multiFactoryAdd(lInjectablesBlueprint[isViewProvider ? existingViewProvidersFactoryIndex : existingProvidersFactoryIndex], providerFactory, !isViewProvider && isComponent); |
| } |
| if (!isViewProvider && isComponent && doesViewProvidersFactoryExist) { |
| lInjectablesBlueprint[existingViewProvidersFactoryIndex].componentProviders++; |
| } |
| } |
| } |
| } |
| /** |
| * Add a factory in a multi factory. |
| */ |
| function multiFactoryAdd(multiFactory, factory, isComponentProvider) { |
| multiFactory.multi.push(factory); |
| if (isComponentProvider) { |
| multiFactory.componentProviders++; |
| } |
| } |
| /** |
| * Returns the index of item in the array, but only in the begin to end range. |
| */ |
| function indexOf(item, arr, begin, end) { |
| for (var i = begin; i < end; i++) { |
| if (arr[i] === item) |
| return i; |
| } |
| return -1; |
| } |
| /** |
| * Use this with `multi` `providers`. |
| */ |
| function multiProvidersFactoryResolver(_, tData, lData, tNode) { |
| return multiResolve(this.multi, []); |
| } |
| /** |
| * Use this with `multi` `viewProviders`. |
| * |
| * This factory knows how to concatenate itself with the existing `multi` `providers`. |
| */ |
| function multiViewProvidersFactoryResolver(_, tData, lData, tNode) { |
| var factories = this.multi; |
| var result; |
| if (this.providerFactory) { |
| var componentCount = this.providerFactory.componentProviders; |
| var multiProviders = getNodeInjectable(tData, lData, this.providerFactory.index, tNode); |
| // Copy the section of the array which contains `multi` `providers` from the component |
| result = multiProviders.slice(0, componentCount); |
| // Insert the `viewProvider` instances. |
| multiResolve(factories, result); |
| // Copy the section of the array which contains `multi` `providers` from other directives |
| for (var i = componentCount; i < multiProviders.length; i++) { |
| result.push(multiProviders[i]); |
| } |
| } |
| else { |
| result = []; |
| // Insert the `viewProvider` instances. |
| multiResolve(factories, result); |
| } |
| return result; |
| } |
| /** |
| * Maps an array of factories into an array of values. |
| */ |
| function multiResolve(factories, result) { |
| for (var i = 0; i < factories.length; i++) { |
| var factory = factories[i]; |
| result.push(factory()); |
| } |
| return result; |
| } |
| /** |
| * Creates a multi factory. |
| */ |
| function multiFactory(factoryFn, index, isViewProvider, isComponent, f) { |
| var factory = new NodeInjectorFactory(factoryFn, isViewProvider, ɵɵdirectiveInject); |
| factory.multi = []; |
| factory.index = index; |
| factory.componentProviders = 0; |
| multiFactoryAdd(factory, f, isComponent && !isViewProvider); |
| return factory; |
| } |
| |
| /** |
| * This feature resolves the providers of a directive (or component), |
| * and publish them into the DI system, making it visible to others for injection. |
| * |
| * For example: |
| * ```ts |
| * class ComponentWithProviders { |
| * constructor(private greeter: GreeterDE) {} |
| * |
| * static ngComponentDef = defineComponent({ |
| * type: ComponentWithProviders, |
| * selectors: [['component-with-providers']], |
| * factory: () => new ComponentWithProviders(directiveInject(GreeterDE as any)), |
| * consts: 1, |
| * vars: 1, |
| * template: function(fs: RenderFlags, ctx: ComponentWithProviders) { |
| * if (fs & RenderFlags.Create) { |
| * ɵɵtext(0); |
| * } |
| * if (fs & RenderFlags.Update) { |
| * ɵɵselect(0); |
| * ɵɵtextBinding(ctx.greeter.greet()); |
| * } |
| * }, |
| * features: [ProvidersFeature([GreeterDE])] |
| * }); |
| * } |
| * ``` |
| * |
| * @param definition |
| * |
| * @codeGenApi |
| */ |
| function ɵɵProvidersFeature(providers, viewProviders) { |
| if (viewProviders === void 0) { viewProviders = []; } |
| return function (definition) { |
| definition.providersResolver = |
| function (def, processProvidersFn) { |
| return providersResolver(def, // |
| processProvidersFn ? processProvidersFn(providers) : providers, // |
| viewProviders); |
| }; |
| }; |
| } |
| |
| /** |
| * @license |
| * Copyright Google Inc. All Rights Reserved. |
| * |
| * Use of this source code is governed by an MIT-style license that can be |
| * found in the LICENSE file at https://angular.io/license |
| */ |
| /** |
| * Represents a component created by a `ComponentFactory`. |
| * Provides access to the component instance and related objects, |
| * and provides the means of destroying the instance. |
| * |
| * @publicApi |
| */ |
| var ComponentRef = /** @class */ (function () { |
| function ComponentRef() { |
| } |
| return ComponentRef; |
| }()); |
| /** |
| * Base class for a factory that can create a component dynamically. |
| * Instantiate a factory for a given type of component with `resolveComponentFactory()`. |
| * Use the resulting `ComponentFactory.create()` method to create a component of that type. |
| * |
| * @see [Dynamic Components](guide/dynamic-component-loader) |
| * |
| * @publicApi |
| */ |
| var ComponentFactory = /** @class */ (function () { |
| function ComponentFactory() { |
| } |
| return ComponentFactory; |
| }()); |
| |
| /** |
| * @license |
| * Copyright Google Inc. All Rights Reserved. |
| * |
| * Use of this source code is governed by an MIT-style license that can be |
| * found in the LICENSE file at https://angular.io/license |
| */ |
| function noComponentFactoryError(component) { |
| var error = Error("No component factory found for " + stringify(component) + ". Did you add it to @NgModule.entryComponents?"); |
| error[ERROR_COMPONENT] = component; |
| return error; |
| } |
| var ERROR_COMPONENT = 'ngComponent'; |
| var _NullComponentFactoryResolver = /** @class */ (function () { |
| function _NullComponentFactoryResolver() { |
| } |
| _NullComponentFactoryResolver.prototype.resolveComponentFactory = function (component) { |
| throw noComponentFactoryError(component); |
| }; |
| return _NullComponentFactoryResolver; |
| }()); |
| /** |
| * A simple registry that maps `Components` to generated `ComponentFactory` classes |
| * that can be used to create instances of components. |
| * Use to obtain the factory for a given component type, |
| * then use the factory's `create()` method to create a component of that type. |
| * |
| * @see [Dynamic Components](guide/dynamic-component-loader) |
| * @publicApi |
| */ |
| var ComponentFactoryResolver = /** @class */ (function () { |
| function ComponentFactoryResolver() { |
| } |
| ComponentFactoryResolver.NULL = new _NullComponentFactoryResolver(); |
| return ComponentFactoryResolver; |
| }()); |
| var CodegenComponentFactoryResolver = /** @class */ (function () { |
| function CodegenComponentFactoryResolver(factories, _parent, _ngModule) { |
| this._parent = _parent; |
| this._ngModule = _ngModule; |
| this._factories = new Map(); |
| for (var i = 0; i < factories.length; i++) { |
| var factory = factories[i]; |
| this._factories.set(factory.componentType, factory); |
| } |
| } |
| CodegenComponentFactoryResolver.prototype.resolveComponentFactory = function (component) { |
| var factory = this._factories.get(component); |
| if (!factory && this._parent) { |
| factory = this._parent.resolveComponentFactory(component); |
| } |
| if (!factory) { |
| throw noComponentFactoryError(component); |
| } |
| return new ComponentFactoryBoundToModule(factory, this._ngModule); |
| }; |
| return CodegenComponentFactoryResolver; |
| }()); |
| var ComponentFactoryBoundToModule = /** @class */ (function (_super) { |
| __extends(ComponentFactoryBoundToModule, _super); |
| function ComponentFactoryBoundToModule(factory, ngModule) { |
| var _this = _super.call(this) || this; |
| _this.factory = factory; |
| _this.ngModule = ngModule; |
| _this.selector = factory.selector; |
| _this.componentType = factory.componentType; |
| _this.ngContentSelectors = factory.ngContentSelectors; |
| _this.inputs = factory.inputs; |
| _this.outputs = factory.outputs; |
| return _this; |
| } |
| ComponentFactoryBoundToModule.prototype.create = function (injector, projectableNodes, rootSelectorOrNode, ngModule) { |
| return this.factory.create(injector, projectableNodes, rootSelectorOrNode, ngModule || this.ngModule); |
| }; |
| return ComponentFactoryBoundToModule; |
| }(ComponentFactory)); |
| |
| /** |
| * @license |
| * Copyright Google Inc. All Rights Reserved. |
| * |
| * Use of this source code is governed by an MIT-style license that can be |
| * found in the LICENSE file at https://angular.io/license |
| */ |
| /** |
| * Represents an instance of an NgModule created via a {@link NgModuleFactory}. |
| * |
| * `NgModuleRef` provides access to the NgModule Instance as well other objects related to this |
| * NgModule Instance. |
| * |
| * @publicApi |
| */ |
| var NgModuleRef = /** @class */ (function () { |
| function NgModuleRef() { |
| } |
| return NgModuleRef; |
| }()); |
| /** |
| * @publicApi |
| */ |
| var NgModuleFactory = /** @class */ (function () { |
| function NgModuleFactory() { |
| } |
| return NgModuleFactory; |
| }()); |
| |
| /** |
| * @license |
| * Copyright Google Inc. All Rights Reserved. |
| * |
| * Use of this source code is governed by an MIT-style license that can be |
| * found in the LICENSE file at https://angular.io/license |
| */ |
| var ViewRef = /** @class */ (function () { |
| function ViewRef(_lView, _context, _componentIndex) { |
| this._context = _context; |
| this._componentIndex = _componentIndex; |
| this._appRef = null; |
| this._viewContainerRef = null; |
| /** |
| * @internal |
| */ |
| this._tViewNode = null; |
| this._lView = _lView; |
| } |
| Object.defineProperty(ViewRef.prototype, "rootNodes", { |
| get: function () { |
| if (this._lView[HOST] == null) { |
| var tView = this._lView[T_HOST]; |
| return collectNativeNodes(this._lView, tView, []); |
| } |
| return []; |
| }, |
| enumerable: true, |
| configurable: true |
| }); |
| Object.defineProperty(ViewRef.prototype, "context", { |
| get: function () { return this._context ? this._context : this._lookUpContext(); }, |
| enumerable: true, |
| configurable: true |
| }); |
| Object.defineProperty(ViewRef.prototype, "destroyed", { |
| get: function () { |
| return (this._lView[FLAGS] & 256 /* Destroyed */) === 256 /* Destroyed */; |
| }, |
| enumerable: true, |
| configurable: true |
| }); |
| ViewRef.prototype.destroy = function () { |
| if (this._appRef) { |
| this._appRef.detachView(this); |
| } |
| else if (this._viewContainerRef) { |
| var index = this._viewContainerRef.indexOf(this); |
| if (index > -1) { |
| this._viewContainerRef.detach(index); |
| } |
| this._viewContainerRef = null; |
| } |
| destroyLView(this._lView); |
| }; |
| ViewRef.prototype.onDestroy = function (callback) { storeCleanupFn(this._lView, callback); }; |
| /** |
| * Marks a view and all of its ancestors dirty. |
| * |
| * It also triggers change detection by calling `scheduleTick` internally, which coalesces |
| * multiple `markForCheck` calls to into one change detection run. |
| * |
| * This can be used to ensure an {@link ChangeDetectionStrategy#OnPush OnPush} component is |
| * checked when it needs to be re-rendered but the two normal triggers haven't marked it |
| * dirty (i.e. inputs haven't changed and events haven't fired in the view). |
| * |
| * <!-- TODO: Add a link to a chapter on OnPush components --> |
| * |
| * @usageNotes |
| * ### Example |
| * |
| * ```typescript |
| * @Component({ |
| * selector: 'my-app', |
| * template: `Number of ticks: {{numberOfTicks}}` |
| * changeDetection: ChangeDetectionStrategy.OnPush, |
| * }) |
| * class AppComponent { |
| * numberOfTicks = 0; |
| * |
| * constructor(private ref: ChangeDetectorRef) { |
| * setInterval(() => { |
| * this.numberOfTicks++; |
| * // the following is required, otherwise the view will not be updated |
| * this.ref.markForCheck(); |
| * }, 1000); |
| * } |
| * } |
| * ``` |
| */ |
| ViewRef.prototype.markForCheck = function () { markViewDirty(this._lView); }; |
| /** |
| * Detaches the view from the change detection tree. |
| * |
| * Detached views will not be checked during change detection runs until they are |
| * re-attached, even if they are dirty. `detach` can be used in combination with |
| * {@link ChangeDetectorRef#detectChanges detectChanges} to implement local change |
| * detection checks. |
| * |
| * <!-- TODO: Add a link to a chapter on detach/reattach/local digest --> |
| * <!-- TODO: Add a live demo once ref.detectChanges is merged into master --> |
| * |
| * @usageNotes |
| * ### Example |
| * |
| * The following example defines a component with a large list of readonly data. |
| * Imagine the data changes constantly, many times per second. For performance reasons, |
| * we want to check and update the list every five seconds. We can do that by detaching |
| * the component's change detector and doing a local check every five seconds. |
| * |
| * ```typescript |
| * class DataProvider { |
| * // in a real application the returned data will be different every time |
| * get data() { |
| * return [1,2,3,4,5]; |
| * } |
| * } |
| * |
| * @Component({ |
| * selector: 'giant-list', |
| * template: ` |
| * <li *ngFor="let d of dataProvider.data">Data {{d}}</li> |
| * `, |
| * }) |
| * class GiantList { |
| * constructor(private ref: ChangeDetectorRef, private dataProvider: DataProvider) { |
| * ref.detach(); |
| * setInterval(() => { |
| * this.ref.detectChanges(); |
| * }, 5000); |
| * } |
| * } |
| * |
| * @Component({ |
| * selector: 'app', |
| * providers: [DataProvider], |
| * template: ` |
| * <giant-list><giant-list> |
| * `, |
| * }) |
| * class App { |
| * } |
| * ``` |
| */ |
| ViewRef.prototype.detach = function () { this._lView[FLAGS] &= ~128 /* Attached */; }; |
| /** |
| * Re-attaches a view to the change detection tree. |
| * |
| * This can be used to re-attach views that were previously detached from the tree |
| * using {@link ChangeDetectorRef#detach detach}. Views are attached to the tree by default. |
| * |
| * <!-- TODO: Add a link to a chapter on detach/reattach/local digest --> |
| * |
| * @usageNotes |
| * ### Example |
| * |
| * The following example creates a component displaying `live` data. The component will detach |
| * its change detector from the main change detector tree when the component's live property |
| * is set to false. |
| * |
| * ```typescript |
| * class DataProvider { |
| * data = 1; |
| * |
| * constructor() { |
| * setInterval(() => { |
| * this.data = this.data * 2; |
| * }, 500); |
| * } |
| * } |
| * |
| * @Component({ |
| * selector: 'live-data', |
| * inputs: ['live'], |
| * template: 'Data: {{dataProvider.data}}' |
| * }) |
| * class LiveData { |
| * constructor(private ref: ChangeDetectorRef, private dataProvider: DataProvider) {} |
| * |
| * set live(value) { |
| * if (value) { |
| * this.ref.reattach(); |
| * } else { |
| * this.ref.detach(); |
| * } |
| * } |
| * } |
| * |
| * @Component({ |
| * selector: 'my-app', |
| * providers: [DataProvider], |
| * template: ` |
| * Live Update: <input type="checkbox" [(ngModel)]="live"> |
| * <live-data [live]="live"><live-data> |
| * `, |
| * }) |
| * class AppComponent { |
| * live = true; |
| * } |
| * ``` |
| */ |
| ViewRef.prototype.reattach = function () { this._lView[FLAGS] |= 128 /* Attached */; }; |
| /** |
| * Checks the view and its children. |
| * |
| * This can also be used in combination with {@link ChangeDetectorRef#detach detach} to implement |
| * local change detection checks. |
| * |
| * <!-- TODO: Add a link to a chapter on detach/reattach/local digest --> |
| * <!-- TODO: Add a live demo once ref.detectChanges is merged into master --> |
| * |
| * @usageNotes |
| * ### Example |
| * |
| * The following example defines a component with a large list of readonly data. |
| * Imagine, the data changes constantly, many times per second. For performance reasons, |
| * we want to check and update the list every five seconds. |
| * |
| * We can do that by detaching the component's change detector and doing a local change detection |
| * check every five seconds. |
| * |
| * See {@link ChangeDetectorRef#detach detach} for more information. |
| */ |
| ViewRef.prototype.detectChanges = function () { detectChangesInternal(this._lView, this.context); }; |
| /** |
| * Checks the change detector and its children, and throws if any changes are detected. |
| * |
| * This is used in development mode to verify that running change detection doesn't |
| * introduce other changes. |
| */ |
| ViewRef.prototype.checkNoChanges = function () { checkNoChangesInternal(this._lView, this.context); }; |
| ViewRef.prototype.attachToViewContainerRef = function (vcRef) { |
| if (this._appRef) { |
| throw new Error('This view is already attached directly to the ApplicationRef!'); |
| } |
| this._viewContainerRef = vcRef; |
| }; |
| ViewRef.prototype.detachFromAppRef = function () { |
| this._appRef = null; |
| renderDetachView(this._lView); |
| }; |
| ViewRef.prototype.attachToAppRef = function (appRef) { |
| if (this._viewContainerRef) { |
| throw new Error('This view is already attached to a ViewContainer!'); |
| } |
| this._appRef = appRef; |
| }; |
| ViewRef.prototype._lookUpContext = function () { |
| return this._context = getLViewParent(this._lView)[this._componentIndex]; |
| }; |
| return ViewRef; |
| }()); |
| /** @internal */ |
| var RootViewRef = /** @class */ (function (_super) { |
| __extends(RootViewRef, _super); |
| function RootViewRef(_view) { |
| var _this = _super.call(this, _view, null, -1) || this; |
| _this._view = _view; |
| return _this; |
| } |
| RootViewRef.prototype.detectChanges = function () { detectChangesInRootView(this._view); }; |
| RootViewRef.prototype.checkNoChanges = function () { checkNoChangesInRootView(this._view); }; |
| Object.defineProperty(RootViewRef.prototype, "context", { |
| get: function () { return null; }, |
| enumerable: true, |
| configurable: true |
| }); |
| return RootViewRef; |
| }(ViewRef)); |
| function collectNativeNodes(lView, parentTNode, result) { |
| var tNodeChild = parentTNode.child; |
| while (tNodeChild) { |
| var nativeNode = getNativeByTNode(tNodeChild, lView); |
| nativeNode && result.push(nativeNode); |
| if (tNodeChild.type === 4 /* ElementContainer */) { |
| collectNativeNodes(lView, tNodeChild, result); |
| } |
| else if (tNodeChild.type === 1 /* Projection */) { |
| var componentView = findComponentView(lView); |
| var componentHost = componentView[T_HOST]; |
| var parentView = getLViewParent(componentView); |
| var currentProjectedNode = componentHost.projection[tNodeChild.projection]; |
| while (currentProjectedNode && parentView) { |
| result.push(getNativeByTNode(currentProjectedNode, parentView)); |
| currentProjectedNode = currentProjectedNode.next; |
| } |
| } |
| tNodeChild = tNodeChild.next; |
| } |
| return result; |
| } |
| |
| /** |
| * @license |
| * Copyright Google Inc. All Rights Reserved. |
| * |
| * Use of this source code is governed by an MIT-style license that can be |
| * found in the LICENSE file at https://angular.io/license |
| */ |
| /** |
| * Creates an ElementRef from the most recent node. |
| * |
| * @returns The ElementRef instance to use |
| */ |
| function injectElementRef(ElementRefToken) { |
| return createElementRef(ElementRefToken, getPreviousOrParentTNode(), getLView()); |
| } |
| var R3ElementRef; |
| /** |
| * Creates an ElementRef given a node. |
| * |
| * @param ElementRefToken The ElementRef type |
| * @param tNode The node for which you'd like an ElementRef |
| * @param view The view to which the node belongs |
| * @returns The ElementRef instance to use |
| */ |
| function createElementRef(ElementRefToken, tNode, view) { |
| if (!R3ElementRef) { |
| // TODO: Fix class name, should be ElementRef, but there appears to be a rollup bug |
| R3ElementRef = /** @class */ (function (_super) { |
| __extends(ElementRef_, _super); |
| function ElementRef_() { |
| return _super !== null && _super.apply(this, arguments) || this; |
| } |
| return ElementRef_; |
| }(ElementRefToken)); |
| } |
| return new R3ElementRef(getNativeByTNode(tNode, view)); |
| } |
| var R3TemplateRef; |
| /** |
| * Creates a TemplateRef given a node. |
| * |
| * @returns The TemplateRef instance to use |
| */ |
| function injectTemplateRef(TemplateRefToken, ElementRefToken) { |
| return createTemplateRef(TemplateRefToken, ElementRefToken, getPreviousOrParentTNode(), getLView()); |
| } |
| /** |
| * Creates a TemplateRef and stores it on the injector. |
| * |
| * @param TemplateRefToken The TemplateRef type |
| * @param ElementRefToken The ElementRef type |
| * @param hostTNode The node that is requesting a TemplateRef |
| * @param hostView The view to which the node belongs |
| * @returns The TemplateRef instance to use |
| */ |
| function createTemplateRef(TemplateRefToken, ElementRefToken, hostTNode, hostView) { |
| if (!R3TemplateRef) { |
| // TODO: Fix class name, should be TemplateRef, but there appears to be a rollup bug |
| R3TemplateRef = /** @class */ (function (_super) { |
| __extends(TemplateRef_, _super); |
| function TemplateRef_(_declarationParentView, elementRef, _tView, _hostLContainer, _injectorIndex) { |
| var _this = _super.call(this) || this; |
| _this._declarationParentView = _declarationParentView; |
| _this.elementRef = elementRef; |
| _this._tView = _tView; |
| _this._hostLContainer = _hostLContainer; |
| _this._injectorIndex = _injectorIndex; |
| return _this; |
| } |
| TemplateRef_.prototype.createEmbeddedView = function (context, container, index) { |
| var currentQueries = this._declarationParentView[QUERIES]; |
| // Query container may be missing if this view was created in a directive |
| // constructor. Create it now to avoid losing results in embedded views. |
| if (currentQueries && this._hostLContainer[QUERIES] == null) { |
| this._hostLContainer[QUERIES] = currentQueries.container(); |
| } |
| var lView = createEmbeddedViewAndNode(this._tView, context, this._declarationParentView, this._hostLContainer[QUERIES], this._injectorIndex); |
| if (container) { |
| insertView(lView, container, index); |
| } |
| renderEmbeddedTemplate(lView, this._tView, context); |
| var viewRef = new ViewRef(lView, context, -1); |
| viewRef._tViewNode = lView[T_HOST]; |
| return viewRef; |
| }; |
| return TemplateRef_; |
| }(TemplateRefToken)); |
| } |
| if (hostTNode.type === 0 /* Container */) { |
| var hostContainer = hostView[hostTNode.index]; |
| ngDevMode && assertDefined(hostTNode.tViews, 'TView must be allocated'); |
| return new R3TemplateRef(hostView, createElementRef(ElementRefToken, hostTNode, hostView), hostTNode.tViews, hostContainer, hostTNode.injectorIndex); |
| } |
| else { |
| return null; |
| } |
| } |
| var R3ViewContainerRef; |
| /** |
| * Creates a ViewContainerRef and stores it on the injector. Or, if the ViewContainerRef |
| * already exists, retrieves the existing ViewContainerRef. |
| * |
| * @returns The ViewContainerRef instance to use |
| */ |
| function injectViewContainerRef(ViewContainerRefToken, ElementRefToken) { |
| var previousTNode = getPreviousOrParentTNode(); |
| return createContainerRef(ViewContainerRefToken, ElementRefToken, previousTNode, getLView()); |
| } |
| /** |
| * Creates a ViewContainerRef and stores it on the injector. |
| * |
| * @param ViewContainerRefToken The ViewContainerRef type |
| * @param ElementRefToken The ElementRef type |
| * @param hostTNode The node that is requesting a ViewContainerRef |
| * @param hostView The view to which the node belongs |
| * @returns The ViewContainerRef instance to use |
| */ |
| function createContainerRef(ViewContainerRefToken, ElementRefToken, hostTNode, hostView) { |
| if (!R3ViewContainerRef) { |
| // TODO: Fix class name, should be ViewContainerRef, but there appears to be a rollup bug |
| R3ViewContainerRef = /** @class */ (function (_super) { |
| __extends(ViewContainerRef_, _super); |
| function ViewContainerRef_(_lContainer, _hostTNode, _hostView) { |
| var _this = _super.call(this) || this; |
| _this._lContainer = _lContainer; |
| _this._hostTNode = _hostTNode; |
| _this._hostView = _hostView; |
| return _this; |
| } |
| Object.defineProperty(ViewContainerRef_.prototype, "element", { |
| get: function () { |
| return createElementRef(ElementRefToken, this._hostTNode, this._hostView); |
| }, |
| enumerable: true, |
| configurable: true |
| }); |
| Object.defineProperty(ViewContainerRef_.prototype, "injector", { |
| get: function () { return new NodeInjector(this._hostTNode, this._hostView); }, |
| enumerable: true, |
| configurable: true |
| }); |
| Object.defineProperty(ViewContainerRef_.prototype, "parentInjector", { |
| /** @deprecated No replacement */ |
| get: function () { |
| var parentLocation = getParentInjectorLocation(this._hostTNode, this._hostView); |
| var parentView = getParentInjectorView(parentLocation, this._hostView); |
| var parentTNode = getParentInjectorTNode(parentLocation, this._hostView, this._hostTNode); |
| return !hasParentInjector(parentLocation) || parentTNode == null ? |
| new NodeInjector(null, this._hostView) : |
| new NodeInjector(parentTNode, parentView); |
| }, |
| enumerable: true, |
| configurable: true |
| }); |
| ViewContainerRef_.prototype.clear = function () { |
| while (this.length) { |
| this.remove(0); |
| } |
| }; |
| ViewContainerRef_.prototype.get = function (index) { |
| return this._lContainer[VIEW_REFS] !== null && this._lContainer[VIEW_REFS][index] || null; |
| }; |
| Object.defineProperty(ViewContainerRef_.prototype, "length", { |
| get: function () { |
| // Note that if there are no views, the container |
| // length will be smaller than the header offset. |
| var viewAmount = this._lContainer.length - CONTAINER_HEADER_OFFSET; |
| return viewAmount > 0 ? viewAmount : 0; |
| }, |
| enumerable: true, |
| configurable: true |
| }); |
| ViewContainerRef_.prototype.createEmbeddedView = function (templateRef, context, index) { |
| this.allocateContainerIfNeeded(); |
| var adjustedIdx = this._adjustIndex(index); |
| var viewRef = templateRef |
| .createEmbeddedView(context || {}, this._lContainer, adjustedIdx); |
| viewRef.attachToViewContainerRef(this); |
| this._lContainer[VIEW_REFS].splice(adjustedIdx, 0, viewRef); |
| return viewRef; |
| }; |
| ViewContainerRef_.prototype.createComponent = function (componentFactory, index, injector, projectableNodes, ngModuleRef) { |
| var contextInjector = injector || this.parentInjector; |
| if (!ngModuleRef && componentFactory.ngModule == null && contextInjector) { |
| ngModuleRef = contextInjector.get(NgModuleRef, null); |
| } |
| var componentRef = componentFactory.create(contextInjector, projectableNodes, undefined, ngModuleRef); |
| this.insert(componentRef.hostView, index); |
| return componentRef; |
| }; |
| ViewContainerRef_.prototype.insert = function (viewRef, index) { |
| if (viewRef.destroyed) { |
| throw new Error('Cannot insert a destroyed View in a ViewContainer!'); |
| } |
| this.allocateContainerIfNeeded(); |
| var lView = viewRef._lView; |
| var adjustedIdx = this._adjustIndex(index); |
| if (viewAttachedToContainer(lView)) { |
| // If view is already attached, fall back to move() so we clean up |
| // references appropriately. |
| return this.move(viewRef, adjustedIdx); |
| } |
| insertView(lView, this._lContainer, adjustedIdx); |
| var beforeNode = getBeforeNodeForView(adjustedIdx, this._lContainer); |
| addRemoveViewFromContainer(lView, true, beforeNode); |
| viewRef.attachToViewContainerRef(this); |
| this._lContainer[VIEW_REFS].splice(adjustedIdx, 0, viewRef); |
| return viewRef; |
| }; |
| ViewContainerRef_.prototype.move = function (viewRef, newIndex) { |
| if (viewRef.destroyed) { |
| throw new Error('Cannot move a destroyed View in a ViewContainer!'); |
| } |
| var index = this.indexOf(viewRef); |
| if (index !== -1) |
| this.detach(index); |
| this.insert(viewRef, newIndex); |
| return viewRef; |
| }; |
| ViewContainerRef_.prototype.indexOf = function (viewRef) { |
| return this._lContainer[VIEW_REFS] !== null ? |
| this._lContainer[VIEW_REFS].indexOf(viewRef) : |
| 0; |
| }; |
| ViewContainerRef_.prototype.remove = function (index) { |
| this.allocateContainerIfNeeded(); |
| var adjustedIdx = this._adjustIndex(index, -1); |
| removeView(this._lContainer, adjustedIdx); |
| this._lContainer[VIEW_REFS].splice(adjustedIdx, 1); |
| }; |
| ViewContainerRef_.prototype.detach = function (index) { |
| this.allocateContainerIfNeeded(); |
| var adjustedIdx = this._adjustIndex(index, -1); |
| var view = detachView(this._lContainer, adjustedIdx); |
| var wasDetached = view && this._lContainer[VIEW_REFS].splice(adjustedIdx, 1)[0] != null; |
| return wasDetached ? new ViewRef(view, view[CONTEXT], -1) : null; |
| }; |
| ViewContainerRef_.prototype._adjustIndex = function (index, shift) { |
| if (shift === void 0) { shift = 0; } |
| if (index == null) { |
| return this.length + shift; |
| } |
| if (ngDevMode) { |
| assertGreaterThan(index, -1, 'index must be positive'); |
| // +1 because it's legal to insert at the end. |
| assertLessThan(index, this.length + 1 + shift, 'index'); |
| } |
| return index; |
| }; |
| ViewContainerRef_.prototype.allocateContainerIfNeeded = function () { |
| if (this._lContainer[VIEW_REFS] === null) { |
| this._lContainer[VIEW_REFS] = []; |
| } |
| }; |
| return ViewContainerRef_; |
| }(ViewContainerRefToken)); |
| } |
| ngDevMode && assertNodeOfPossibleTypes(hostTNode, 0 /* Container */, 3 /* Element */, 4 /* ElementContainer */); |
| var lContainer; |
| var slotValue = hostView[hostTNode.index]; |
| if (isLContainer(slotValue)) { |
| // If the host is a container, we don't need to create a new LContainer |
| lContainer = slotValue; |
| lContainer[ACTIVE_INDEX] = -1; |
| } |
| else { |
| var commentNode = void 0; |
| // If the host is an element container, the native host element is guaranteed to be a |
| // comment and we can reuse that comment as anchor element for the new LContainer. |
| if (hostTNode.type === 4 /* ElementContainer */) { |
| commentNode = unwrapRNode(slotValue); |
| } |
| else { |
| ngDevMode && ngDevMode.rendererCreateComment++; |
| commentNode = hostView[RENDERER].createComment(ngDevMode ? 'container' : ''); |
| } |
| // A container can be created on the root (topmost / bootstrapped) component and in this case we |
| // can't use LTree to insert container's marker node (both parent of a comment node and the |
| // commend node itself is located outside of elements hold by LTree). In this specific case we |
| // use low-level DOM manipulation to insert container's marker (comment) node. |
| if (isRootView(hostView)) { |
| var renderer = hostView[RENDERER]; |
| var hostNative = getNativeByTNode(hostTNode, hostView); |
| var parentOfHostNative = nativeParentNode(renderer, hostNative); |
| nativeInsertBefore(renderer, parentOfHostNative, commentNode, nativeNextSibling(renderer, hostNative)); |
| } |
| else { |
| appendChild(commentNode, hostTNode, hostView); |
| } |
| hostView[hostTNode.index] = lContainer = |
| createLContainer(slotValue, hostView, commentNode, hostTNode, true); |
| addToViewTree(hostView, lContainer); |
| } |
| return new R3ViewContainerRef(lContainer, hostTNode, hostView); |
| } |
| /** Returns a ChangeDetectorRef (a.k.a. a ViewRef) */ |
| function injectChangeDetectorRef() { |
| return createViewRef(getPreviousOrParentTNode(), getLView(), null); |
| } |
| /** |
| * Creates a ViewRef and stores it on the injector as ChangeDetectorRef (public alias). |
| * |
| * @param hostTNode The node that is requesting a ChangeDetectorRef |
| * @param hostView The view to which the node belongs |
| * @param context The context for this change detector ref |
| * @returns The ChangeDetectorRef to use |
| */ |
| function createViewRef(hostTNode, hostView, context) { |
| if (isComponent(hostTNode)) { |
| var componentIndex = hostTNode.directiveStart; |
| var componentView = getComponentViewByIndex(hostTNode.index, hostView); |
| return new ViewRef(componentView, context, componentIndex); |
| } |
| else if (hostTNode.type === 3 /* Element */ || hostTNode.type === 0 /* Container */ || |
| hostTNode.type === 4 /* ElementContainer */) { |
| var hostComponentView = findComponentView(hostView); |
| return new ViewRef(hostComponentView, hostComponentView[CONTEXT], -1); |
| } |
| return null; |
| } |
| /** Returns a Renderer2 (or throws when application was bootstrapped with Renderer3) */ |
| function getOrCreateRenderer2(view) { |
| var renderer = view[RENDERER]; |
| if (isProceduralRenderer(renderer)) { |
| return renderer; |
| } |
| else { |
| throw new Error('Cannot inject Renderer2 when the application uses Renderer3!'); |
| } |
| } |
| /** Injects a Renderer2 for the current component. */ |
| function injectRenderer2() { |
| // We need the Renderer to be based on the component that it's being injected into, however since |
| // DI happens before we've entered its view, `getLView` will return the parent view instead. |
| var lView = getLView(); |
| var tNode = getPreviousOrParentTNode(); |
| var nodeAtIndex = getComponentViewByIndex(tNode.index, lView); |
| return getOrCreateRenderer2(isLView(nodeAtIndex) ? nodeAtIndex : lView); |
| } |
| |
| /** |
| * @license |
| * Copyright Google Inc. All Rights Reserved. |
| * |
| * Use of this source code is governed by an MIT-style license that can be |
| * found in the LICENSE file at https://angular.io/license |
| */ |
| function noop() { |
| var args = []; |
| for (var _i = 0; _i < arguments.length; _i++) { |
| args[_i] = arguments[_i]; |
| } |
| // Do nothing. |
| } |
| |
| /** |
| * @license |
| * Copyright Google Inc. All Rights Reserved. |
| * |
| * Use of this source code is governed by an MIT-style license that can be |
| * found in the LICENSE file at https://angular.io/license |
| */ |
| /** |
| * A wrapper around a native element inside of a View. |
| * |
| * An `ElementRef` is backed by a render-specific element. In the browser, this is usually a DOM |
| * element. |
| * |
| * @security Permitting direct access to the DOM can make your application more vulnerable to |
| * XSS attacks. Carefully review any use of `ElementRef` in your code. For more detail, see the |
| * [Security Guide](http://g.co/ng/security). |
| * |
| * @publicApi |
| */ |
| // Note: We don't expose things like `Injector`, `ViewContainer`, ... here, |
| // i.e. users have to ask for what they need. With that, we can build better analysis tools |
| // and could do better codegen in the future. |
| var ElementRef = /** @class */ (function () { |
| function ElementRef(nativeElement) { |
| this.nativeElement = nativeElement; |
| } |
| /** |
| * @internal |
| * @nocollapse |
| */ |
| ElementRef.__NG_ELEMENT_ID__ = function () { return SWITCH_ELEMENT_REF_FACTORY(ElementRef); }; |
| return ElementRef; |
| }()); |
| var SWITCH_ELEMENT_REF_FACTORY__POST_R3__ = injectElementRef; |
| var SWITCH_ELEMENT_REF_FACTORY__PRE_R3__ = noop; |
| var SWITCH_ELEMENT_REF_FACTORY = SWITCH_ELEMENT_REF_FACTORY__PRE_R3__; |
| |
| /** |
| * @license |
| * Copyright Google Inc. All Rights Reserved. |
| * |
| * Use of this source code is governed by an MIT-style license that can be |
| * found in the LICENSE file at https://angular.io/license |
| */ |
| /** |
| * @deprecated Use `RendererType2` (and `Renderer2`) instead. |
| * @publicApi |
| */ |
| var RenderComponentType = /** @class */ (function () { |
| function RenderComponentType(id, templateUrl, slotCount, encapsulation, styles, animations) { |
| this.id = id; |
| this.templateUrl = templateUrl; |
| this.slotCount = slotCount; |
| this.encapsulation = encapsulation; |
| this.styles = styles; |
| this.animations = animations; |
| } |
| return RenderComponentType; |
| }()); |
| /** |
| * @deprecated Debug info is handled internally in the view engine now. |
| */ |
| var RenderDebugInfo = /** @class */ (function () { |
| function RenderDebugInfo() { |
| } |
| return RenderDebugInfo; |
| }()); |
| /** |
| * @deprecated Use the `Renderer2` instead. |
| * @publicApi |
| */ |
| var Renderer = /** @class */ (function () { |
| function Renderer() { |
| } |
| return Renderer; |
| }()); |
| var Renderer2Interceptor = new InjectionToken('Renderer2Interceptor'); |
| /** |
| * Injectable service that provides a low-level interface for modifying the UI. |
| * |
| * Use this service to bypass Angular's templating and make custom UI changes that can't be |
| * expressed declaratively. For example if you need to set a property or an attribute whose name is |
| * not statically known, use {@link Renderer#setElementProperty setElementProperty} or |
| * {@link Renderer#setElementAttribute setElementAttribute} respectively. |
| * |
| * If you are implementing a custom renderer, you must implement this interface. |
| * |
| * The default Renderer implementation is `DomRenderer`. Also available is `WebWorkerRenderer`. |
| * |
| * @deprecated Use `RendererFactory2` instead. |
| * @publicApi |
| */ |
| var RootRenderer = /** @class */ (function () { |
| function RootRenderer() { |
| } |
| return RootRenderer; |
| }()); |
| /** |
| * Creates and initializes a custom renderer that implements the `Renderer2` base class. |
| * |
| * @publicApi |
| */ |
| var RendererFactory2 = /** @class */ (function () { |
| function RendererFactory2() { |
| } |
| return RendererFactory2; |
| }()); |
| (function (RendererStyleFlags2) { |
| /** |
| * Marks a style as important. |
| */ |
| RendererStyleFlags2[RendererStyleFlags2["Important"] = 1] = "Important"; |
| /** |
| * Marks a style as using dash case naming (this-is-dash-case). |
| */ |
| RendererStyleFlags2[RendererStyleFlags2["DashCase"] = 2] = "DashCase"; |
| })(exports.RendererStyleFlags2 || (exports.RendererStyleFlags2 = {})); |
| /** |
| * Extend this base class to implement custom rendering. By default, Angular |
| * renders a template into DOM. You can use custom rendering to intercept |
| * rendering calls, or to render to something other than DOM. |
| * |
| * Create your custom renderer using `RendererFactory2`. |
| * |
| * Use a custom renderer to bypass Angular's templating and |
| * make custom UI changes that can't be expressed declaratively. |
| * For example if you need to set a property or an attribute whose name is |
| * not statically known, use the `setProperty()` or |
| * `setAttribute()` method. |
| * |
| * @publicApi |
| */ |
| var Renderer2 = /** @class */ (function () { |
| function Renderer2() { |
| } |
| /** |
| * @internal |
| * @nocollapse |
| */ |
| Renderer2.__NG_ELEMENT_ID__ = function () { return SWITCH_RENDERER2_FACTORY(); }; |
| return Renderer2; |
| }()); |
| var SWITCH_RENDERER2_FACTORY__POST_R3__ = injectRenderer2; |
| var SWITCH_RENDERER2_FACTORY__PRE_R3__ = noop; |
| var SWITCH_RENDERER2_FACTORY = SWITCH_RENDERER2_FACTORY__PRE_R3__; |
| |
| /** |
| * @license |
| * Copyright Google Inc. All Rights Reserved. |
| * |
| * Use of this source code is governed by an MIT-style license that can be |
| * found in the LICENSE file at https://angular.io/license |
| */ |
| /** |
| * @description Represents the version of Angular |
| * |
| * @publicApi |
| */ |
| var Version = /** @class */ (function () { |
| function Version(full) { |
| this.full = full; |
| this.major = full.split('.')[0]; |
| this.minor = full.split('.')[1]; |
| this.patch = full.split('.').slice(2).join('.'); |
| } |
| return Version; |
| }()); |
| /** |
| * @publicApi |
| */ |
| var VERSION = new Version('8.1.1'); |
| |
| /** |
| * @license |
| * Copyright Google Inc. All Rights Reserved. |
| * |
| * Use of this source code is governed by an MIT-style license that can be |
| * found in the LICENSE file at https://angular.io/license |
| */ |
| var DefaultIterableDifferFactory = /** @class */ (function () { |
| function DefaultIterableDifferFactory() { |
| } |
| DefaultIterableDifferFactory.prototype.supports = function (obj) { return isListLikeIterable(obj); }; |
| DefaultIterableDifferFactory.prototype.create = function (trackByFn) { |
| return new DefaultIterableDiffer(trackByFn); |
| }; |
| return DefaultIterableDifferFactory; |
| }()); |
| var trackByIdentity = function (index, item) { return item; }; |
| /** |
| * @deprecated v4.0.0 - Should not be part of public API. |
| * @publicApi |
| */ |
| var DefaultIterableDiffer = /** @class */ (function () { |
| function DefaultIterableDiffer(trackByFn) { |
| this.length = 0; |
| // Keeps track of the used records at any point in time (during & across `_check()` calls) |
| this._linkedRecords = null; |
| // Keeps track of the removed records at any point in time during `_check()` calls. |
| this._unlinkedRecords = null; |
| this._previousItHead = null; |
| this._itHead = null; |
| this._itTail = null; |
| this._additionsHead = null; |
| this._additionsTail = null; |
| this._movesHead = null; |
| this._movesTail = null; |
| this._removalsHead = null; |
| this._removalsTail = null; |
| // Keeps track of records where custom track by is the same, but item identity has changed |
| this._identityChangesHead = null; |
| this._identityChangesTail = null; |
| this._trackByFn = trackByFn || trackByIdentity; |
| } |
| DefaultIterableDiffer.prototype.forEachItem = function (fn) { |
| var record; |
| for (record = this._itHead; record !== null; record = record._next) { |
| fn(record); |
| } |
| }; |
| DefaultIterableDiffer.prototype.forEachOperation = function (fn) { |
| var nextIt = this._itHead; |
| var nextRemove = this._removalsHead; |
| var addRemoveOffset = 0; |
| var moveOffsets = null; |
| while (nextIt || nextRemove) { |
| // Figure out which is the next record to process |
| // Order: remove, add, move |
| var record = !nextRemove || |
| nextIt && |
| nextIt.currentIndex < |
| getPreviousIndex(nextRemove, addRemoveOffset, moveOffsets) ? |
| nextIt : |
| nextRemove; |
| var adjPreviousIndex = getPreviousIndex(record, addRemoveOffset, moveOffsets); |
| var currentIndex = record.currentIndex; |
| // consume the item, and adjust the addRemoveOffset and update moveDistance if necessary |
| if (record === nextRemove) { |
| addRemoveOffset--; |
| nextRemove = nextRemove._nextRemoved; |
| } |
| else { |
| nextIt = nextIt._next; |
| if (record.previousIndex == null) { |
| addRemoveOffset++; |
| } |
| else { |
| // INVARIANT: currentIndex < previousIndex |
| if (!moveOffsets) |
| moveOffsets = []; |
| var localMovePreviousIndex = adjPreviousIndex - addRemoveOffset; |
| var localCurrentIndex = currentIndex - addRemoveOffset; |
| if (localMovePreviousIndex != localCurrentIndex) { |
| for (var i = 0; i < localMovePreviousIndex; i++) { |
| var offset = i < moveOffsets.length ? moveOffsets[i] : (moveOffsets[i] = 0); |
| var index = offset + i; |
| if (localCurrentIndex <= index && index < localMovePreviousIndex) { |
| moveOffsets[i] = offset + 1; |
| } |
| } |
| var previousIndex = record.previousIndex; |
| moveOffsets[previousIndex] = localCurrentIndex - localMovePreviousIndex; |
| } |
| } |
| } |
| if (adjPreviousIndex !== currentIndex) { |
| fn(record, adjPreviousIndex, currentIndex); |
| } |
| } |
| }; |
| DefaultIterableDiffer.prototype.forEachPreviousItem = function (fn) { |
| var record; |
| for (record = this._previousItHead; record !== null; record = record._nextPrevious) { |
| fn(record); |
| } |
| }; |
| DefaultIterableDiffer.prototype.forEachAddedItem = function (fn) { |
| var record; |
| for (record = this._additionsHead; record !== null; record = record._nextAdded) { |
| fn(record); |
| } |
| }; |
| DefaultIterableDiffer.prototype.forEachMovedItem = function (fn) { |
| var record; |
| for (record = this._movesHead; record !== null; record = record._nextMoved) { |
| fn(record); |
| } |
| }; |
| DefaultIterableDiffer.prototype.forEachRemovedItem = function (fn) { |
| var record; |
| for (record = this._removalsHead; record !== null; record = record._nextRemoved) { |
| fn(record); |
| } |
| }; |
| DefaultIterableDiffer.prototype.forEachIdentityChange = function (fn) { |
| var record; |
| for (record = this._identityChangesHead; record !== null; record = record._nextIdentityChange) { |
| fn(record); |
| } |
| }; |
| DefaultIterableDiffer.prototype.diff = function (collection) { |
| if (collection == null) |
| collection = []; |
| if (!isListLikeIterable(collection)) { |
| throw new Error("Error trying to diff '" + stringify(collection) + "'. Only arrays and iterables are allowed"); |
| } |
| if (this.check(collection)) { |
| return this; |
| } |
| else { |
| return null; |
| } |
| }; |
| DefaultIterableDiffer.prototype.onDestroy = function () { }; |
| DefaultIterableDiffer.prototype.check = function (collection) { |
| var _this = this; |
| this._reset(); |
| var record = this._itHead; |
| var mayBeDirty = false; |
| var index; |
| var item; |
| var itemTrackBy; |
| if (Array.isArray(collection)) { |
| this.length = collection.length; |
| for (var index_1 = 0; index_1 < this.length; index_1++) { |
| item = collection[index_1]; |
| itemTrackBy = this._trackByFn(index_1, item); |
| if (record === null || !looseIdentical(record.trackById, itemTrackBy)) { |
| record = this._mismatch(record, item, itemTrackBy, index_1); |
| mayBeDirty = true; |
| } |
| else { |
| if (mayBeDirty) { |
| // TODO(misko): can we limit this to duplicates only? |
| record = this._verifyReinsertion(record, item, itemTrackBy, index_1); |
| } |
| if (!looseIdentical(record.item, item)) |
| this._addIdentityChange(record, item); |
| } |
| record = record._next; |
| } |
| } |
| else { |
| index = 0; |
| iterateListLike(collection, function (item) { |
| itemTrackBy = _this._trackByFn(index, item); |
| if (record === null || !looseIdentical(record.trackById, itemTrackBy)) { |
| record = _this._mismatch(record, item, itemTrackBy, index); |
| mayBeDirty = true; |
| } |
| else { |
| if (mayBeDirty) { |
| // TODO(misko): can we limit this to duplicates only? |
| record = _this._verifyReinsertion(record, item, itemTrackBy, index); |
| } |
| if (!looseIdentical(record.item, item)) |
| _this._addIdentityChange(record, item); |
| } |
| record = record._next; |
| index++; |
| }); |
| this.length = index; |
| } |
| this._truncate(record); |
| this.collection = collection; |
| return this.isDirty; |
| }; |
| Object.defineProperty(DefaultIterableDiffer.prototype, "isDirty", { |
| /* CollectionChanges is considered dirty if it has any additions, moves, removals, or identity |
| * changes. |
| */ |
| get: function () { |
| return this._additionsHead !== null || this._movesHead !== null || |
| this._removalsHead !== null || this._identityChangesHead !== null; |
| }, |
| enumerable: true, |
| configurable: true |
| }); |
| /** |
| * Reset the state of the change objects to show no changes. This means set previousKey to |
| * currentKey, and clear all of the queues (additions, moves, removals). |
| * Set the previousIndexes of moved and added items to their currentIndexes |
| * Reset the list of additions, moves and removals |
| * |
| * @internal |
| */ |
| DefaultIterableDiffer.prototype._reset = function () { |
| if (this.isDirty) { |
| var record = void 0; |
| var nextRecord = void 0; |
| for (record = this._previousItHead = this._itHead; record !== null; record = record._next) { |
| record._nextPrevious = record._next; |
| } |
| for (record = this._additionsHead; record !== null; record = record._nextAdded) { |
| record.previousIndex = record.currentIndex; |
| } |
| this._additionsHead = this._additionsTail = null; |
| for (record = this._movesHead; record !== null; record = nextRecord) { |
| record.previousIndex = record.currentIndex; |
| nextRecord = record._nextMoved; |
| } |
| this._movesHead = this._movesTail = null; |
| this._removalsHead = this._removalsTail = null; |
| this._identityChangesHead = this._identityChangesTail = null; |
| // TODO(vicb): when assert gets supported |
| // assert(!this.isDirty); |
| } |
| }; |
| /** |
| * This is the core function which handles differences between collections. |
| * |
| * - `record` is the record which we saw at this position last time. If null then it is a new |
| * item. |
| * - `item` is the current item in the collection |
| * - `index` is the position of the item in the collection |
| * |
| * @internal |
| */ |
| DefaultIterableDiffer.prototype._mismatch = function (record, item, itemTrackBy, index) { |
| // The previous record after which we will append the current one. |
| var previousRecord; |
| if (record === null) { |
| previousRecord = this._itTail; |
| } |
| else { |
| previousRecord = record._prev; |
| // Remove the record from the collection since we know it does not match the item. |
| this._remove(record); |
| } |
| // Attempt to see if we have seen the item before. |
| record = this._linkedRecords === null ? null : this._linkedRecords.get(itemTrackBy, index); |
| if (record !== null) { |
| // We have seen this before, we need to move it forward in the collection. |
| // But first we need to check if identity changed, so we can update in view if necessary |
| if (!looseIdentical(record.item, item)) |
| this._addIdentityChange(record, item); |
| this._moveAfter(record, previousRecord, index); |
| } |
| else { |
| // Never seen it, check evicted list. |
| record = this._unlinkedRecords === null ? null : this._unlinkedRecords.get(itemTrackBy, null); |
| if (record !== null) { |
| // It is an item which we have evicted earlier: reinsert it back into the list. |
| // But first we need to check if identity changed, so we can update in view if necessary |
| if (!looseIdentical(record.item, item)) |
| this._addIdentityChange(record, item); |
| this._reinsertAfter(record, previousRecord, index); |
| } |
| else { |
| // It is a new item: add it. |
| record = |
| this._addAfter(new IterableChangeRecord_(item, itemTrackBy), previousRecord, index); |
| } |
| } |
| return record; |
| }; |
| /** |
| * This check is only needed if an array contains duplicates. (Short circuit of nothing dirty) |
| * |
| * Use case: `[a, a]` => `[b, a, a]` |
| * |
| * If we did not have this check then the insertion of `b` would: |
| * 1) evict first `a` |
| * 2) insert `b` at `0` index. |
| * 3) leave `a` at index `1` as is. <-- this is wrong! |
| * 3) reinsert `a` at index 2. <-- this is wrong! |
| * |
| * The correct behavior is: |
| * 1) evict first `a` |
| * 2) insert `b` at `0` index. |
| * 3) reinsert `a` at index 1. |
| * 3) move `a` at from `1` to `2`. |
| * |
| * |
| * Double check that we have not evicted a duplicate item. We need to check if the item type may |
| * have already been removed: |
| * The insertion of b will evict the first 'a'. If we don't reinsert it now it will be reinserted |
| * at the end. Which will show up as the two 'a's switching position. This is incorrect, since a |
| * better way to think of it is as insert of 'b' rather then switch 'a' with 'b' and then add 'a' |
| * at the end. |
| * |
| * @internal |
| */ |
| DefaultIterableDiffer.prototype._verifyReinsertion = function (record, item, itemTrackBy, index) { |
| var reinsertRecord = this._unlinkedRecords === null ? null : this._unlinkedRecords.get(itemTrackBy, null); |
| if (reinsertRecord !== null) { |
| record = this._reinsertAfter(reinsertRecord, record._prev, index); |
| } |
| else if (record.currentIndex != index) { |
| record.currentIndex = index; |
| this._addToMoves(record, index); |
| } |
| return record; |
| }; |
| /** |
| * Get rid of any excess {@link IterableChangeRecord_}s from the previous collection |
| * |
| * - `record` The first excess {@link IterableChangeRecord_}. |
| * |
| * @internal |
| */ |
| DefaultIterableDiffer.prototype._truncate = function (record) { |
| // Anything after that needs to be removed; |
| while (record !== null) { |
| var nextRecord = record._next; |
| this._addToRemovals(this._unlink(record)); |
| record = nextRecord; |
| } |
| if (this._unlinkedRecords !== null) { |
| this._unlinkedRecords.clear(); |
| } |
| if (this._additionsTail !== null) { |
| this._additionsTail._nextAdded = null; |
| } |
| if (this._movesTail !== null) { |
| this._movesTail._nextMoved = null; |
| } |
| if (this._itTail !== null) { |
| this._itTail._next = null; |
| } |
| if (this._removalsTail !== null) { |
| this._removalsTail._nextRemoved = null; |
| } |
| if (this._identityChangesTail !== null) { |
| this._identityChangesTail._nextIdentityChange = null; |
| } |
| }; |
| /** @internal */ |
| DefaultIterableDiffer.prototype._reinsertAfter = function (record, prevRecord, index) { |
| if (this._unlinkedRecords !== null) { |
| this._unlinkedRecords.remove(record); |
| } |
| var prev = record._prevRemoved; |
| var next = record._nextRemoved; |
| if (prev === null) { |
| this._removalsHead = next; |
| } |
| else { |
| prev._nextRemoved = next; |
| } |
| if (next === null) { |
| this._removalsTail = prev; |
| } |
| else { |
| next._prevRemoved = prev; |
| } |
| this._insertAfter(record, prevRecord, index); |
| this._addToMoves(record, index); |
| return record; |
| }; |
| /** @internal */ |
| DefaultIterableDiffer.prototype._moveAfter = function (record, prevRecord, index) { |
| this._unlink(record); |
| this._insertAfter(record, prevRecord, index); |
| this._addToMoves(record, index); |
| return record; |
| }; |
| /** @internal */ |
| DefaultIterableDiffer.prototype._addAfter = function (record, prevRecord, index) { |
| this._insertAfter(record, prevRecord, index); |
| if (this._additionsTail === null) { |
| // TODO(vicb): |
| // assert(this._additionsHead === null); |
| this._additionsTail = this._additionsHead = record; |
| } |
| else { |
| // TODO(vicb): |
| // assert(_additionsTail._nextAdded === null); |
| // assert(record._nextAdded === null); |
| this._additionsTail = this._additionsTail._nextAdded = record; |
| } |
| return record; |
| }; |
| /** @internal */ |
| DefaultIterableDiffer.prototype._insertAfter = function (record, prevRecord, index) { |
| // TODO(vicb): |
| // assert(record != prevRecord); |
| // assert(record._next === null); |
| // assert(record._prev === null); |
| var next = prevRecord === null ? this._itHead : prevRecord._next; |
| // TODO(vicb): |
| // assert(next != record); |
| // assert(prevRecord != record); |
| record._next = next; |
| record._prev = prevRecord; |
| if (next === null) { |
| this._itTail = record; |
| } |
| else { |
| next._prev = record; |
| } |
| if (prevRecord === null) { |
| this._itHead = record; |
| } |
| else { |
| prevRecord._next = record; |
| } |
| if (this._linkedRecords === null) { |
| this._linkedRecords = new _DuplicateMap(); |
| } |
| this._linkedRecords.put(record); |
| record.currentIndex = index; |
| return record; |
| }; |
| /** @internal */ |
| DefaultIterableDiffer.prototype._remove = function (record) { |
| return this._addToRemovals(this._unlink(record)); |
| }; |
| /** @internal */ |
| DefaultIterableDiffer.prototype._unlink = function (record) { |
| if (this._linkedRecords !== null) { |
| this._linkedRecords.remove(record); |
| } |
| var prev = record._prev; |
| var next = record._next; |
| // TODO(vicb): |
| // assert((record._prev = null) === null); |
| // assert((record._next = null) === null); |
| if (prev === null) { |
| this._itHead = next; |
| } |
| else { |
| prev._next = next; |
| } |
| if (next === null) { |
| this._itTail = prev; |
| } |
| else { |
| next._prev = prev; |
| } |
| return record; |
| }; |
| /** @internal */ |
| DefaultIterableDiffer.prototype._addToMoves = function (record, toIndex) { |
| // TODO(vicb): |
| // assert(record._nextMoved === null); |
| if (record.previousIndex === toIndex) { |
| return record; |
| } |
| if (this._movesTail === null) { |
| // TODO(vicb): |
| // assert(_movesHead === null); |
| this._movesTail = this._movesHead = record; |
| } |
| else { |
| // TODO(vicb): |
| // assert(_movesTail._nextMoved === null); |
| this._movesTail = this._movesTail._nextMoved = record; |
| } |
| return record; |
| }; |
| DefaultIterableDiffer.prototype._addToRemovals = function (record) { |
| if (this._unlinkedRecords === null) { |
| this._unlinkedRecords = new _DuplicateMap(); |
| } |
| this._unlinkedRecords.put(record); |
| record.currentIndex = null; |
| record._nextRemoved = null; |
| if (this._removalsTail === null) { |
| // TODO(vicb): |
| // assert(_removalsHead === null); |
| this._removalsTail = this._removalsHead = record; |
| record._prevRemoved = null; |
| } |
| else { |
| // TODO(vicb): |
| // assert(_removalsTail._nextRemoved === null); |
| // assert(record._nextRemoved === null); |
| record._prevRemoved = this._removalsTail; |
| this._removalsTail = this._removalsTail._nextRemoved = record; |
| } |
| return record; |
| }; |
| /** @internal */ |
| DefaultIterableDiffer.prototype._addIdentityChange = function (record, item) { |
| record.item = item; |
| if (this._identityChangesTail === null) { |
| this._identityChangesTail = this._identityChangesHead = record; |
| } |
| else { |
| this._identityChangesTail = this._identityChangesTail._nextIdentityChange = record; |
| } |
| return record; |
| }; |
| return DefaultIterableDiffer; |
| }()); |
| var IterableChangeRecord_ = /** @class */ (function () { |
| function IterableChangeRecord_(item, trackById) { |
| this.item = item; |
| this.trackById = trackById; |
| this.currentIndex = null; |
| this.previousIndex = null; |
| /** @internal */ |
| this._nextPrevious = null; |
| /** @internal */ |
| this._prev = null; |
| /** @internal */ |
| this._next = null; |
| /** @internal */ |
| this._prevDup = null; |
| /** @internal */ |
| this._nextDup = null; |
| /** @internal */ |
| this._prevRemoved = null; |
| /** @internal */ |
| this._nextRemoved = null; |
| /** @internal */ |
| this._nextAdded = null; |
| /** @internal */ |
| this._nextMoved = null; |
| /** @internal */ |
| this._nextIdentityChange = null; |
| } |
| return IterableChangeRecord_; |
| }()); |
| // A linked list of CollectionChangeRecords with the same IterableChangeRecord_.item |
| var _DuplicateItemRecordList = /** @class */ (function () { |
| function _DuplicateItemRecordList() { |
| /** @internal */ |
| this._head = null; |
| /** @internal */ |
| this._tail = null; |
| } |
| /** |
| * Append the record to the list of duplicates. |
| * |
| * Note: by design all records in the list of duplicates hold the same value in record.item. |
| */ |
| _DuplicateItemRecordList.prototype.add = function (record) { |
| if (this._head === null) { |
| this._head = this._tail = record; |
| record._nextDup = null; |
| record._prevDup = null; |
| } |
| else { |
| // TODO(vicb): |
| // assert(record.item == _head.item || |
| // record.item is num && record.item.isNaN && _head.item is num && _head.item.isNaN); |
| this._tail._nextDup = record; |
| record._prevDup = this._tail; |
| record._nextDup = null; |
| this._tail = record; |
| } |
| }; |
| // Returns a IterableChangeRecord_ having IterableChangeRecord_.trackById == trackById and |
| // IterableChangeRecord_.currentIndex >= atOrAfterIndex |
| _DuplicateItemRecordList.prototype.get = function (trackById, atOrAfterIndex) { |
| var record; |
| for (record = this._head; record !== null; record = record._nextDup) { |
| if ((atOrAfterIndex === null || atOrAfterIndex <= record.currentIndex) && |
| looseIdentical(record.trackById, trackById)) { |
| return record; |
| } |
| } |
| return null; |
| }; |
| /** |
| * Remove one {@link IterableChangeRecord_} from the list of duplicates. |
| * |
| * Returns whether the list of duplicates is empty. |
| */ |
| _DuplicateItemRecordList.prototype.remove = function (record) { |
| // TODO(vicb): |
| // assert(() { |
| // // verify that the record being removed is in the list. |
| // for (IterableChangeRecord_ cursor = _head; cursor != null; cursor = cursor._nextDup) { |
| // if (identical(cursor, record)) return true; |
| // } |
| // return false; |
| //}); |
| var prev = record._prevDup; |
| var next = record._nextDup; |
| if (prev === null) { |
| this._head = next; |
| } |
| else { |
| prev._nextDup = next; |
| } |
| if (next === null) { |
| this._tail = prev; |
| } |
| else { |
| next._prevDup = prev; |
| } |
| return this._head === null; |
| }; |
| return _DuplicateItemRecordList; |
| }()); |
| var _DuplicateMap = /** @class */ (function () { |
| function _DuplicateMap() { |
| this.map = new Map(); |
| } |
| _DuplicateMap.prototype.put = function (record) { |
| var key = record.trackById; |
| var duplicates = this.map.get(key); |
| if (!duplicates) { |
| duplicates = new _DuplicateItemRecordList(); |
| this.map.set(key, duplicates); |
| } |
| duplicates.add(record); |
| }; |
| /** |
| * Retrieve the `value` using key. Because the IterableChangeRecord_ value may be one which we |
| * have already iterated over, we use the `atOrAfterIndex` to pretend it is not there. |
| * |
| * Use case: `[a, b, c, a, a]` if we are at index `3` which is the second `a` then asking if we |
| * have any more `a`s needs to return the second `a`. |
| */ |
| _DuplicateMap.prototype.get = function (trackById, atOrAfterIndex) { |
| var key = trackById; |
| var recordList = this.map.get(key); |
| return recordList ? recordList.get(trackById, atOrAfterIndex) : null; |
| }; |
| /** |
| * Removes a {@link IterableChangeRecord_} from the list of duplicates. |
| * |
| * The list of duplicates also is removed from the map if it gets empty. |
| */ |
| _DuplicateMap.prototype.remove = function (record) { |
| var key = record.trackById; |
| var recordList = this.map.get(key); |
| // Remove the list of duplicates when it gets empty |
| if (recordList.remove(record)) { |
| this.map.delete(key); |
| } |
| return record; |
| }; |
| Object.defineProperty(_DuplicateMap.prototype, "isEmpty", { |
| get: function () { return this.map.size === 0; }, |
| enumerable: true, |
| configurable: true |
| }); |
| _DuplicateMap.prototype.clear = function () { this.map.clear(); }; |
| return _DuplicateMap; |
| }()); |
| function getPreviousIndex(item, addRemoveOffset, moveOffsets) { |
| var previousIndex = item.previousIndex; |
| if (previousIndex === null) |
| return previousIndex; |
| var moveOffset = 0; |
| if (moveOffsets && previousIndex < moveOffsets.length) { |
| moveOffset = moveOffsets[previousIndex]; |
| } |
| return previousIndex + addRemoveOffset + moveOffset; |
| } |
| |
| /** |
| * @license |
| * Copyright Google Inc. All Rights Reserved. |
| * |
| * Use of this source code is governed by an MIT-style license that can be |
| * found in the LICENSE file at https://angular.io/license |
| */ |
| var DefaultKeyValueDifferFactory = /** @class */ (function () { |
| function DefaultKeyValueDifferFactory() { |
| } |
| DefaultKeyValueDifferFactory.prototype.supports = function (obj) { return obj instanceof Map || isJsObject(obj); }; |
| DefaultKeyValueDifferFactory.prototype.create = function () { return new DefaultKeyValueDiffer(); }; |
| return DefaultKeyValueDifferFactory; |
| }()); |
| var DefaultKeyValueDiffer = /** @class */ (function () { |
| function DefaultKeyValueDiffer() { |
| this._records = new Map(); |
| this._mapHead = null; |
| // _appendAfter is used in the check loop |
| this._appendAfter = null; |
| this._previousMapHead = null; |
| this._changesHead = null; |
| this._changesTail = null; |
| this._additionsHead = null; |
| this._additionsTail = null; |
| this._removalsHead = null; |
| this._removalsTail = null; |
| } |
| Object.defineProperty(DefaultKeyValueDiffer.prototype, "isDirty", { |
| get: function () { |
| return this._additionsHead !== null || this._changesHead !== null || |
| this._removalsHead !== null; |
| }, |
| enumerable: true, |
| configurable: true |
| }); |
| DefaultKeyValueDiffer.prototype.forEachItem = function (fn) { |
| var record; |
| for (record = this._mapHead; record !== null; record = record._next) { |
| fn(record); |
| } |
| }; |
| DefaultKeyValueDiffer.prototype.forEachPreviousItem = function (fn) { |
| var record; |
| for (record = this._previousMapHead; record !== null; record = record._nextPrevious) { |
| fn(record); |
| } |
| }; |
| DefaultKeyValueDiffer.prototype.forEachChangedItem = function (fn) { |
| var record; |
| for (record = this._changesHead; record !== null; record = record._nextChanged) { |
| fn(record); |
| } |
| }; |
| DefaultKeyValueDiffer.prototype.forEachAddedItem = function (fn) { |
| var record; |
| for (record = this._additionsHead; record !== null; record = record._nextAdded) { |
| fn(record); |
| } |
| }; |
| DefaultKeyValueDiffer.prototype.forEachRemovedItem = function (fn) { |
| var record; |
| for (record = this._removalsHead; record !== null; record = record._nextRemoved) { |
| fn(record); |
| } |
| }; |
| DefaultKeyValueDiffer.prototype.diff = function (map) { |
| if (!map) { |
| map = new Map(); |
| } |
| else if (!(map instanceof Map || isJsObject(map))) { |
| throw new Error("Error trying to diff '" + stringify(map) + "'. Only maps and objects are allowed"); |
| } |
| return this.check(map) ? this : null; |
| }; |
| DefaultKeyValueDiffer.prototype.onDestroy = function () { }; |
| /** |
| * Check the current state of the map vs the previous. |
| * The algorithm is optimised for when the keys do no change. |
| */ |
| DefaultKeyValueDiffer.prototype.check = function (map) { |
| var _this = this; |
| this._reset(); |
| var insertBefore = this._mapHead; |
| this._appendAfter = null; |
| this._forEach(map, function (value, key) { |
| if (insertBefore && insertBefore.key === key) { |
| _this._maybeAddToChanges(insertBefore, value); |
| _this._appendAfter = insertBefore; |
| insertBefore = insertBefore._next; |
| } |
| else { |
| var record = _this._getOrCreateRecordForKey(key, value); |
| insertBefore = _this._insertBeforeOrAppend(insertBefore, record); |
| } |
| }); |
| // Items remaining at the end of the list have been deleted |
| if (insertBefore) { |
| if (insertBefore._prev) { |
| insertBefore._prev._next = null; |
| } |
| this._removalsHead = insertBefore; |
| for (var record = insertBefore; record !== null; record = record._nextRemoved) { |
| if (record === this._mapHead) { |
| this._mapHead = null; |
| } |
| this._records.delete(record.key); |
| record._nextRemoved = record._next; |
| record.previousValue = record.currentValue; |
| record.currentValue = null; |
| record._prev = null; |
| record._next = null; |
| } |
| } |
| // Make sure tails have no next records from previous runs |
| if (this._changesTail) |
| this._changesTail._nextChanged = null; |
| if (this._additionsTail) |
| this._additionsTail._nextAdded = null; |
| return this.isDirty; |
| }; |
| /** |
| * Inserts a record before `before` or append at the end of the list when `before` is null. |
| * |
| * Notes: |
| * - This method appends at `this._appendAfter`, |
| * - This method updates `this._appendAfter`, |
| * - The return value is the new value for the insertion pointer. |
| */ |
| DefaultKeyValueDiffer.prototype._insertBeforeOrAppend = function (before, record) { |
| if (before) { |
| var prev = before._prev; |
| record._next = before; |
| record._prev = prev; |
| before._prev = record; |
| if (prev) { |
| prev._next = record; |
| } |
| if (before === this._mapHead) { |
| this._mapHead = record; |
| } |
| this._appendAfter = before; |
| return before; |
| } |
| if (this._appendAfter) { |
| this._appendAfter._next = record; |
| record._prev = this._appendAfter; |
| } |
| else { |
| this._mapHead = record; |
| } |
| this._appendAfter = record; |
| return null; |
| }; |
| DefaultKeyValueDiffer.prototype._getOrCreateRecordForKey = function (key, value) { |
| if (this._records.has(key)) { |
| var record_1 = this._records.get(key); |
| this._maybeAddToChanges(record_1, value); |
| var prev = record_1._prev; |
| var next = record_1._next; |
| if (prev) { |
| prev._next = next; |
| } |
| if (next) { |
| next._prev = prev; |
| } |
| record_1._next = null; |
| record_1._prev = null; |
| return record_1; |
| } |
| var record = new KeyValueChangeRecord_(key); |
| this._records.set(key, record); |
| record.currentValue = value; |
| this._addToAdditions(record); |
| return record; |
| }; |
| /** @internal */ |
| DefaultKeyValueDiffer.prototype._reset = function () { |
| if (this.isDirty) { |
| var record = void 0; |
| // let `_previousMapHead` contain the state of the map before the changes |
| this._previousMapHead = this._mapHead; |
| for (record = this._previousMapHead; record !== null; record = record._next) { |
| record._nextPrevious = record._next; |
| } |
| // Update `record.previousValue` with the value of the item before the changes |
| // We need to update all changed items (that's those which have been added and changed) |
| for (record = this._changesHead; record !== null; record = record._nextChanged) { |
| record.previousValue = record.currentValue; |
| } |
| for (record = this._additionsHead; record != null; record = record._nextAdded) { |
| record.previousValue = record.currentValue; |
| } |
| this._changesHead = this._changesTail = null; |
| this._additionsHead = this._additionsTail = null; |
| this._removalsHead = null; |
| } |
| }; |
| // Add the record or a given key to the list of changes only when the value has actually changed |
| DefaultKeyValueDiffer.prototype._maybeAddToChanges = function (record, newValue) { |
| if (!looseIdentical(newValue, record.currentValue)) { |
| record.previousValue = record.currentValue; |
| record.currentValue = newValue; |
| this._addToChanges(record); |
| } |
| }; |
| DefaultKeyValueDiffer.prototype._addToAdditions = function (record) { |
| if (this._additionsHead === null) { |
| this._additionsHead = this._additionsTail = record; |
| } |
| else { |
| this._additionsTail._nextAdded = record; |
| this._additionsTail = record; |
| } |
| }; |
| DefaultKeyValueDiffer.prototype._addToChanges = function (record) { |
| if (this._changesHead === null) { |
| this._changesHead = this._changesTail = record; |
| } |
| else { |
| this._changesTail._nextChanged = record; |
| this._changesTail = record; |
| } |
| }; |
| /** @internal */ |
| DefaultKeyValueDiffer.prototype._forEach = function (obj, fn) { |
| if (obj instanceof Map) { |
| obj.forEach(fn); |
| } |
| else { |
| Object.keys(obj).forEach(function (k) { return fn(obj[k], k); }); |
| } |
| }; |
| return DefaultKeyValueDiffer; |
| }()); |
| var KeyValueChangeRecord_ = /** @class */ (function () { |
| function KeyValueChangeRecord_(key) { |
| this.key = key; |
| this.previousValue = null; |
| this.currentValue = null; |
| /** @internal */ |
| this._nextPrevious = null; |
| /** @internal */ |
| this._next = null; |
| /** @internal */ |
| this._prev = null; |
| /** @internal */ |
| this._nextAdded = null; |
| /** @internal */ |
| this._nextRemoved = null; |
| /** @internal */ |
| this._nextChanged = null; |
| } |
| return KeyValueChangeRecord_; |
| }()); |
| |
| /** |
| * @license |
| * Copyright Google Inc. All Rights Reserved. |
| * |
| * Use of this source code is governed by an MIT-style license that can be |
| * found in the LICENSE file at https://angular.io/license |
| */ |
| /** |
| * A repository of different iterable diffing strategies used by NgFor, NgClass, and others. |
| * |
| * @publicApi |
| */ |
| var IterableDiffers = /** @class */ (function () { |
| function IterableDiffers(factories) { |
| this.factories = factories; |
| } |
| IterableDiffers.create = function (factories, parent) { |
| if (parent != null) { |
| var copied = parent.factories.slice(); |
| factories = factories.concat(copied); |
| } |
| return new IterableDiffers(factories); |
| }; |
| /** |
| * Takes an array of {@link IterableDifferFactory} and returns a provider used to extend the |
| * inherited {@link IterableDiffers} instance with the provided factories and return a new |
| * {@link IterableDiffers} instance. |
| * |
| * @usageNotes |
| * ### Example |
| * |
| * The following example shows how to extend an existing list of factories, |
| * which will only be applied to the injector for this component and its children. |
| * This step is all that's required to make a new {@link IterableDiffer} available. |
| * |
| * ``` |
| * @Component({ |
| * viewProviders: [ |
| * IterableDiffers.extend([new ImmutableListDiffer()]) |
| * ] |
| * }) |
| * ``` |
| */ |
| IterableDiffers.extend = function (factories) { |
| return { |
| provide: IterableDiffers, |
| useFactory: function (parent) { |
| if (!parent) { |
| // Typically would occur when calling IterableDiffers.extend inside of dependencies passed |
| // to |
| // bootstrap(), which would override default pipes instead of extending them. |
| throw new Error('Cannot extend IterableDiffers without a parent injector'); |
| } |
| return IterableDiffers.create(factories, parent); |
| }, |
| // Dependency technically isn't optional, but we can provide a better error message this way. |
| deps: [[IterableDiffers, new SkipSelf(), new Optional()]] |
| }; |
| }; |
| IterableDiffers.prototype.find = function (iterable) { |
| var factory = this.factories.find(function (f) { return f.supports(iterable); }); |
| if (factory != null) { |
| return factory; |
| } |
| else { |
| throw new Error("Cannot find a differ supporting object '" + iterable + "' of type '" + getTypeNameForDebugging(iterable) + "'"); |
| } |
| }; |
| /** @nocollapse */ |
| IterableDiffers.ngInjectableDef = ɵɵdefineInjectable({ |
| token: IterableDiffers, |
| providedIn: 'root', |
| factory: function () { return new IterableDiffers([new DefaultIterableDifferFactory()]); } |
| }); |
| return IterableDiffers; |
| }()); |
| function getTypeNameForDebugging(type) { |
| return type['name'] || typeof type; |
| } |
| |
| /** |
| * @license |
| * Copyright Google Inc. All Rights Reserved. |
| * |
| * Use of this source code is governed by an MIT-style license that can be |
| * found in the LICENSE file at https://angular.io/license |
| */ |
| /** |
| * A repository of different Map diffing strategies used by NgClass, NgStyle, and others. |
| * |
| * @publicApi |
| */ |
| var KeyValueDiffers = /** @class */ (function () { |
| function KeyValueDiffers(factories) { |
| this.factories = factories; |
| } |
| KeyValueDiffers.create = function (factories, parent) { |
| if (parent) { |
| var copied = parent.factories.slice(); |
| factories = factories.concat(copied); |
| } |
| return new KeyValueDiffers(factories); |
| }; |
| /** |
| * Takes an array of {@link KeyValueDifferFactory} and returns a provider used to extend the |
| * inherited {@link KeyValueDiffers} instance with the provided factories and return a new |
| * {@link KeyValueDiffers} instance. |
| * |
| * @usageNotes |
| * ### Example |
| * |
| * The following example shows how to extend an existing list of factories, |
| * which will only be applied to the injector for this component and its children. |
| * This step is all that's required to make a new {@link KeyValueDiffer} available. |
| * |
| * ``` |
| * @Component({ |
| * viewProviders: [ |
| * KeyValueDiffers.extend([new ImmutableMapDiffer()]) |
| * ] |
| * }) |
| * ``` |
| */ |
| KeyValueDiffers.extend = function (factories) { |
| return { |
| provide: KeyValueDiffers, |
| useFactory: function (parent) { |
| if (!parent) { |
| // Typically would occur when calling KeyValueDiffers.extend inside of dependencies passed |
| // to bootstrap(), which would override default pipes instead of extending them. |
| throw new Error('Cannot extend KeyValueDiffers without a parent injector'); |
| } |
| return KeyValueDiffers.create(factories, parent); |
| }, |
| // Dependency technically isn't optional, but we can provide a better error message this way. |
| deps: [[KeyValueDiffers, new SkipSelf(), new Optional()]] |
| }; |
| }; |
| KeyValueDiffers.prototype.find = function (kv) { |
| var factory = this.factories.find(function (f) { return f.supports(kv); }); |
| if (factory) { |
| return factory; |
| } |
| throw new Error("Cannot find a differ supporting object '" + kv + "'"); |
| }; |
| /** @nocollapse */ |
| KeyValueDiffers.ngInjectableDef = ɵɵdefineInjectable({ |
| token: KeyValueDiffers, |
| providedIn: 'root', |
| factory: function () { return new KeyValueDiffers([new DefaultKeyValueDifferFactory()]); } |
| }); |
| return KeyValueDiffers; |
| }()); |
| |
| /** |
| * @license |
| * Copyright Google Inc. All Rights Reserved. |
| * |
| * Use of this source code is governed by an MIT-style license that can be |
| * found in the LICENSE file at https://angular.io/license |
| */ |
| /** |
| * Base class for Angular Views, provides change detection functionality. |
| * A change-detection tree collects all views that are to be checked for changes. |
| * Use the methods to add and remove views from the tree, initiate change-detection, |
| * and explicitly mark views as _dirty_, meaning that they have changed and need to be rerendered. |
| * |
| * @usageNotes |
| * |
| * The following examples demonstrate how to modify default change-detection behavior |
| * to perform explicit detection when needed. |
| * |
| * ### Use `markForCheck()` with `CheckOnce` strategy |
| * |
| * The following example sets the `OnPush` change-detection strategy for a component |
| * (`CheckOnce`, rather than the default `CheckAlways`), then forces a second check |
| * after an interval. See [live demo](http://plnkr.co/edit/GC512b?p=preview). |
| * |
| * <code-example path="core/ts/change_detect/change-detection.ts" |
| * region="mark-for-check"></code-example> |
| * |
| * ### Detach change detector to limit how often check occurs |
| * |
| * The following example defines a component with a large list of read-only data |
| * that is expected to change constantly, many times per second. |
| * To improve performance, we want to check and update the list |
| * less often than the changes actually occur. To do that, we detach |
| * the component's change detector and perform an explicit local check every five seconds. |
| * |
| * <code-example path="core/ts/change_detect/change-detection.ts" region="detach"></code-example> |
| * |
| * |
| * ### Reattaching a detached component |
| * |
| * The following example creates a component displaying live data. |
| * The component detaches its change detector from the main change detector tree |
| * when the `live` property is set to false, and reattaches it when the property |
| * becomes true. |
| * |
| * <code-example path="core/ts/change_detect/change-detection.ts" region="reattach"></code-example> |
| * |
| * @publicApi |
| */ |
| var ChangeDetectorRef = /** @class */ (function () { |
| function ChangeDetectorRef() { |
| } |
| /** |
| * @internal |
| * @nocollapse |
| */ |
| ChangeDetectorRef.__NG_ELEMENT_ID__ = function () { return SWITCH_CHANGE_DETECTOR_REF_FACTORY(); }; |
| return ChangeDetectorRef; |
| }()); |
| var SWITCH_CHANGE_DETECTOR_REF_FACTORY__POST_R3__ = injectChangeDetectorRef; |
| var SWITCH_CHANGE_DETECTOR_REF_FACTORY__PRE_R3__ = function () { |
| var args = []; |
| for (var _i = 0; _i < arguments.length; _i++) { |
| args[_i] = arguments[_i]; |
| } |
| }; |
| var SWITCH_CHANGE_DETECTOR_REF_FACTORY = SWITCH_CHANGE_DETECTOR_REF_FACTORY__PRE_R3__; |
| |
| /** |
| * @license |
| * Copyright Google Inc. All Rights Reserved. |
| * |
| * Use of this source code is governed by an MIT-style license that can be |
| * found in the LICENSE file at https://angular.io/license |
| */ |
| /** |
| * Structural diffing for `Object`s and `Map`s. |
| */ |
| var keyValDiff = [new DefaultKeyValueDifferFactory()]; |
| /** |
| * Structural diffing for `Iterable` types such as `Array`s. |
| */ |
| var iterableDiff = [new DefaultIterableDifferFactory()]; |
| var defaultIterableDiffers = new IterableDiffers(iterableDiff); |
| var defaultKeyValueDiffers = new KeyValueDiffers(keyValDiff); |
| |
| /** |
| * @license |
| * Copyright Google Inc. All Rights Reserved. |
| * |
| * Use of this source code is governed by an MIT-style license that can be |
| * found in the LICENSE file at https://angular.io/license |
| */ |
| /** |
| * Represents an embedded template that can be used to instantiate embedded views. |
| * To instantiate embedded views based on a template, use the `ViewContainerRef` |
| * method `createEmbeddedView()`. |
| * |
| * Access a `TemplateRef` instance by placing a directive on an `<ng-template>` |
| * element (or directive prefixed with `*`). The `TemplateRef` for the embedded view |
| * is injected into the constructor of the directive, |
| * using the `TemplateRef` token. |
| * |
| * You can also use a `Query` to find a `TemplateRef` associated with |
| * a component or a directive. |
| * |
| * @see `ViewContainerRef` |
| * @see [Navigate the Component Tree with DI](guide/dependency-injection-navtree) |
| * |
| * @publicApi |
| */ |
| var TemplateRef = /** @class */ (function () { |
| function TemplateRef() { |
| } |
| /** |
| * @internal |
| * @nocollapse |
| */ |
| TemplateRef.__NG_ELEMENT_ID__ = function () { return SWITCH_TEMPLATE_REF_FACTORY(TemplateRef, ElementRef); }; |
| return TemplateRef; |
| }()); |
| var SWITCH_TEMPLATE_REF_FACTORY__POST_R3__ = injectTemplateRef; |
| var SWITCH_TEMPLATE_REF_FACTORY__PRE_R3__ = noop; |
| var SWITCH_TEMPLATE_REF_FACTORY = SWITCH_TEMPLATE_REF_FACTORY__PRE_R3__; |
| |
| /** |
| * @license |
| * Copyright Google Inc. All Rights Reserved. |
| * |
| * Use of this source code is governed by an MIT-style license that can be |
| * found in the LICENSE file at https://angular.io/license |
| */ |
| /** |
| * Represents a container where one or more views can be attached to a component. |
| * |
| * Can contain *host views* (created by instantiating a |
| * component with the `createComponent()` method), and *embedded views* |
| * (created by instantiating a `TemplateRef` with the `createEmbeddedView()` method). |
| * |
| * A view container instance can contain other view containers, |
| * creating a [view hierarchy](guide/glossary#view-tree). |
| * |
| * @see `ComponentRef` |
| * @see `EmbeddedViewRef` |
| * |
| * @publicApi |
| */ |
| var ViewContainerRef = /** @class */ (function () { |
| function ViewContainerRef() { |
| } |
| /** |
| * @internal |
| * @nocollapse |
| */ |
| ViewContainerRef.__NG_ELEMENT_ID__ = function () { return SWITCH_VIEW_CONTAINER_REF_FACTORY(ViewContainerRef, ElementRef); }; |
| return ViewContainerRef; |
| }()); |
| var SWITCH_VIEW_CONTAINER_REF_FACTORY__POST_R3__ = injectViewContainerRef; |
| var SWITCH_VIEW_CONTAINER_REF_FACTORY__PRE_R3__ = noop; |
| var SWITCH_VIEW_CONTAINER_REF_FACTORY = SWITCH_VIEW_CONTAINER_REF_FACTORY__PRE_R3__; |
| |
| /** |
| * @license |
| * Copyright Google Inc. All Rights Reserved. |
| * |
| * Use of this source code is governed by an MIT-style license that can be |
| * found in the LICENSE file at https://angular.io/license |
| */ |
| function expressionChangedAfterItHasBeenCheckedError(context, oldValue, currValue, isFirstCheck) { |
| var msg = "ExpressionChangedAfterItHasBeenCheckedError: Expression has changed after it was checked. Previous value: '" + oldValue + "'. Current value: '" + currValue + "'."; |
| if (isFirstCheck) { |
| msg += |
| " It seems like the view has been created after its parent and its children have been dirty checked." + |
| " Has it been created in a change detection hook ?"; |
| } |
| return viewDebugError(msg, context); |
| } |
| function viewWrappedDebugError(err, context) { |
| if (!(err instanceof Error)) { |
| // errors that are not Error instances don't have a stack, |
| // so it is ok to wrap them into a new Error object... |
| err = new Error(err.toString()); |
| } |
| _addDebugContext(err, context); |
| return err; |
| } |
| function viewDebugError(msg, context) { |
| var err = new Error(msg); |
| _addDebugContext(err, context); |
| return err; |
| } |
| function _addDebugContext(err, context) { |
| err[ERROR_DEBUG_CONTEXT] = context; |
| err[ERROR_LOGGER] = context.logError.bind(context); |
| } |
| function isViewDebugError(err) { |
| return !!getDebugContext(err); |
| } |
| function viewDestroyedError(action) { |
| return new Error("ViewDestroyedError: Attempt to use a destroyed view: " + action); |
| } |
| |
| /** |
| * @license |
| * Copyright Google Inc. All Rights Reserved. |
| * |
| * Use of this source code is governed by an MIT-style license that can be |
| * found in the LICENSE file at https://angular.io/license |
| */ |
| // Called before each cycle of a view's check to detect whether this is in the |
| // initState for which we need to call ngOnInit, ngAfterContentInit or ngAfterViewInit |
| // lifecycle methods. Returns true if this check cycle should call lifecycle |
| // methods. |
| function shiftInitState(view, priorInitState, newInitState) { |
| // Only update the InitState if we are currently in the prior state. |
| // For example, only move into CallingInit if we are in BeforeInit. Only |
| // move into CallingContentInit if we are in CallingInit. Normally this will |
| // always be true because of how checkCycle is called in checkAndUpdateView. |
| // However, if checkAndUpdateView is called recursively or if an exception is |
| // thrown while checkAndUpdateView is running, checkAndUpdateView starts over |
| // from the beginning. This ensures the state is monotonically increasing, |
| // terminating in the AfterInit state, which ensures the Init methods are called |
| // at least once and only once. |
| var state = view.state; |
| var initState = state & 1792 /* InitState_Mask */; |
| if (initState === priorInitState) { |
| view.state = (state & ~1792 /* InitState_Mask */) | newInitState; |
| view.initIndex = -1; |
| return true; |
| } |
| return initState === newInitState; |
| } |
| // Returns true if the lifecycle init method should be called for the node with |
| // the given init index. |
| function shouldCallLifecycleInitHook(view, initState, index) { |
| if ((view.state & 1792 /* InitState_Mask */) === initState && view.initIndex <= index) { |
| view.initIndex = index + 1; |
| return true; |
| } |
| return false; |
| } |
| /** |
| * Accessor for view.nodes, enforcing that every usage site stays monomorphic. |
| */ |
| function asTextData(view, index) { |
| return view.nodes[index]; |
| } |
| /** |
| * Accessor for view.nodes, enforcing that every usage site stays monomorphic. |
| */ |
| function asElementData(view, index) { |
| return view.nodes[index]; |
| } |
| /** |
| * Accessor for view.nodes, enforcing that every usage site stays monomorphic. |
| */ |
| function asProviderData(view, index) { |
| return view.nodes[index]; |
| } |
| /** |
| * Accessor for view.nodes, enforcing that every usage site stays monomorphic. |
| */ |
| function asPureExpressionData(view, index) { |
| return view.nodes[index]; |
| } |
| /** |
| * Accessor for view.nodes, enforcing that every usage site stays monomorphic. |
| */ |
| function asQueryList(view, index) { |
| return view.nodes[index]; |
| } |
| var DebugContext = /** @class */ (function () { |
| function DebugContext() { |
| } |
| return DebugContext; |
| }()); |
| /** |
| * This object is used to prevent cycles in the source files and to have a place where |
| * debug mode can hook it. It is lazily filled when `isDevMode` is known. |
| */ |
| var Services = { |
| setCurrentNode: undefined, |
| createRootView: undefined, |
| createEmbeddedView: undefined, |
| createComponentView: undefined, |
| createNgModuleRef: undefined, |
| overrideProvider: undefined, |
| overrideComponentView: undefined, |
| clearOverrides: undefined, |
| checkAndUpdateView: undefined, |
| checkNoChangesView: undefined, |
| destroyView: undefined, |
| resolveDep: undefined, |
| createDebugContext: undefined, |
| handleEvent: undefined, |
| updateDirectives: undefined, |
| updateRenderer: undefined, |
| dirtyParentQueries: undefined, |
| }; |
| |
| /** |
| * @license |
| * Copyright Google Inc. All Rights Reserved. |
| * |
| * Use of this source code is governed by an MIT-style license that can be |
| * found in the LICENSE file at https://angular.io/license |
| */ |
| var NOOP = function () { }; |
| var _tokenKeyCache = new Map(); |
| function tokenKey(token) { |
| var key = _tokenKeyCache.get(token); |
| if (!key) { |
| key = stringify(token) + '_' + _tokenKeyCache.size; |
| _tokenKeyCache.set(token, key); |
| } |
| return key; |
| } |
| function unwrapValue(view, nodeIdx, bindingIdx, value) { |
| if (WrappedValue.isWrapped(value)) { |
| value = WrappedValue.unwrap(value); |
| var globalBindingIdx = view.def.nodes[nodeIdx].bindingIndex + bindingIdx; |
| var oldValue = WrappedValue.unwrap(view.oldValues[globalBindingIdx]); |
| view.oldValues[globalBindingIdx] = new WrappedValue(oldValue); |
| } |
| return value; |
| } |
| var UNDEFINED_RENDERER_TYPE_ID = '$$undefined'; |
| var EMPTY_RENDERER_TYPE_ID = '$$empty'; |
| // Attention: this function is called as top level function. |
| // Putting any logic in here will destroy closure tree shaking! |
| function createRendererType2(values) { |
| return { |
| id: UNDEFINED_RENDERER_TYPE_ID, |
| styles: values.styles, |
| encapsulation: values.encapsulation, |
| data: values.data |
| }; |
| } |
| var _renderCompCount$1 = 0; |
| function resolveRendererType2(type) { |
| if (type && type.id === UNDEFINED_RENDERER_TYPE_ID) { |
| // first time we see this RendererType2. Initialize it... |
| var isFilled = ((type.encapsulation != null && type.encapsulation !== exports.ViewEncapsulation.None) || |
| type.styles.length || Object.keys(type.data).length); |
| if (isFilled) { |
| type.id = "c" + _renderCompCount$1++; |
| } |
| else { |
| type.id = EMPTY_RENDERER_TYPE_ID; |
| } |
| } |
| if (type && type.id === EMPTY_RENDERER_TYPE_ID) { |
| type = null; |
| } |
| return type || null; |
| } |
| function checkBinding(view, def, bindingIdx, value) { |
| var oldValues = view.oldValues; |
| if ((view.state & 2 /* FirstCheck */) || |
| !looseIdentical(oldValues[def.bindingIndex + bindingIdx], value)) { |
| return true; |
| } |
| return false; |
| } |
| function checkAndUpdateBinding(view, def, bindingIdx, value) { |
| if (checkBinding(view, def, bindingIdx, value)) { |
| view.oldValues[def.bindingIndex + bindingIdx] = value; |
| return true; |
| } |
| return false; |
| } |
| function checkBindingNoChanges(view, def, bindingIdx, value) { |
| var oldValue = view.oldValues[def.bindingIndex + bindingIdx]; |
| if ((view.state & 1 /* BeforeFirstCheck */) || !devModeEqual(oldValue, value)) { |
| var bindingName = def.bindings[bindingIdx].name; |
| throw expressionChangedAfterItHasBeenCheckedError(Services.createDebugContext(view, def.nodeIndex), bindingName + ": " + oldValue, bindingName + ": " + value, (view.state & 1 /* BeforeFirstCheck */) !== 0); |
| } |
| } |
| function markParentViewsForCheck(view) { |
| var currView = view; |
| while (currView) { |
| if (currView.def.flags & 2 /* OnPush */) { |
| currView.state |= 8 /* ChecksEnabled */; |
| } |
| currView = currView.viewContainerParent || currView.parent; |
| } |
| } |
| function markParentViewsForCheckProjectedViews(view, endView) { |
| var currView = view; |
| while (currView && currView !== endView) { |
| currView.state |= 64 /* CheckProjectedViews */; |
| currView = currView.viewContainerParent || currView.parent; |
| } |
| } |
| function dispatchEvent(view, nodeIndex, eventName, event) { |
| try { |
| var nodeDef = view.def.nodes[nodeIndex]; |
| var startView = nodeDef.flags & 33554432 /* ComponentView */ ? |
| asElementData(view, nodeIndex).componentView : |
| view; |
| markParentViewsForCheck(startView); |
| return Services.handleEvent(view, nodeIndex, eventName, event); |
| } |
| catch (e) { |
| // Attention: Don't rethrow, as it would cancel Observable subscriptions! |
| view.root.errorHandler.handleError(e); |
| } |
| } |
| function declaredViewContainer(view) { |
| if (view.parent) { |
| var parentView = view.parent; |
| return asElementData(parentView, view.parentNodeDef.nodeIndex); |
| } |
| return null; |
| } |
| /** |
| * for component views, this is the host element. |
| * for embedded views, this is the index of the parent node |
| * that contains the view container. |
| */ |
| function viewParentEl(view) { |
| var parentView = view.parent; |
| if (parentView) { |
| return view.parentNodeDef.parent; |
| } |
| else { |
| return null; |
| } |
| } |
| function renderNode(view, def) { |
| switch (def.flags & 201347067 /* Types */) { |
| case 1 /* TypeElement */: |
| return asElementData(view, def.nodeIndex).renderElement; |
| case 2 /* TypeText */: |
| return asTextData(view, def.nodeIndex).renderText; |
| } |
| } |
| function elementEventFullName(target, name) { |
| return target ? target + ":" + name : name; |
| } |
| function isComponentView(view) { |
| return !!view.parent && !!(view.parentNodeDef.flags & 32768 /* Component */); |
| } |
| function isEmbeddedView(view) { |
| return !!view.parent && !(view.parentNodeDef.flags & 32768 /* Component */); |
| } |
| function filterQueryId(queryId) { |
| return 1 << (queryId % 32); |
| } |
| function splitMatchedQueriesDsl(matchedQueriesDsl) { |
| var matchedQueries = {}; |
| var matchedQueryIds = 0; |
| var references = {}; |
| if (matchedQueriesDsl) { |
| matchedQueriesDsl.forEach(function (_a) { |
| var _b = __read(_a, 2), queryId = _b[0], valueType = _b[1]; |
| if (typeof queryId === 'number') { |
| matchedQueries[queryId] = valueType; |
| matchedQueryIds |= filterQueryId(queryId); |
| } |
| else { |
| references[queryId] = valueType; |
| } |
| }); |
| } |
| return { matchedQueries: matchedQueries, references: references, matchedQueryIds: matchedQueryIds }; |
| } |
| function splitDepsDsl(deps, sourceName) { |
| return deps.map(function (value) { |
| var _a; |
| var token; |
| var flags; |
| if (Array.isArray(value)) { |
| _a = __read(value, 2), flags = _a[0], token = _a[1]; |
| } |
| else { |
| flags = 0 /* None */; |
| token = value; |
| } |
| if (token && (typeof token === 'function' || typeof token === 'object') && sourceName) { |
| Object.defineProperty(token, SOURCE, { value: sourceName, configurable: true }); |
| } |
| return { flags: flags, token: token, tokenKey: tokenKey(token) }; |
| }); |
| } |
| function getParentRenderElement(view, renderHost, def) { |
| var renderParent = def.renderParent; |
| if (renderParent) { |
| if ((renderParent.flags & 1 /* TypeElement */) === 0 || |
| (renderParent.flags & 33554432 /* ComponentView */) === 0 || |
| (renderParent.element.componentRendererType && |
| renderParent.element.componentRendererType.encapsulation === |
| exports.ViewEncapsulation.Native)) { |
| // only children of non components, or children of components with native encapsulation should |
| // be attached. |
| return asElementData(view, def.renderParent.nodeIndex).renderElement; |
| } |
| } |
| else { |
| return renderHost; |
| } |
| } |
| var DEFINITION_CACHE = new WeakMap(); |
| function resolveDefinition(factory) { |
| var value = DEFINITION_CACHE.get(factory); |
| if (!value) { |
| value = factory(function () { return NOOP; }); |
| value.factory = factory; |
| DEFINITION_CACHE.set(factory, value); |
| } |
| return value; |
| } |
| function rootRenderNodes(view) { |
| var renderNodes = []; |
| visitRootRenderNodes(view, 0 /* Collect */, undefined, undefined, renderNodes); |
| return renderNodes; |
| } |
| function visitRootRenderNodes(view, action, parentNode, nextSibling, target) { |
| // We need to re-compute the parent node in case the nodes have been moved around manually |
| if (action === 3 /* RemoveChild */) { |
| parentNode = view.renderer.parentNode(renderNode(view, view.def.lastRenderRootNode)); |
| } |
| visitSiblingRenderNodes(view, action, 0, view.def.nodes.length - 1, parentNode, nextSibling, target); |
| } |
| function visitSiblingRenderNodes(view, action, startIndex, endIndex, parentNode, nextSibling, target) { |
| for (var i = startIndex; i <= endIndex; i++) { |
| var nodeDef = view.def.nodes[i]; |
| if (nodeDef.flags & (1 /* TypeElement */ | 2 /* TypeText */ | 8 /* TypeNgContent */)) { |
| visitRenderNode(view, nodeDef, action, parentNode, nextSibling, target); |
| } |
| // jump to next sibling |
| i += nodeDef.childCount; |
| } |
| } |
| function visitProjectedRenderNodes(view, ngContentIndex, action, parentNode, nextSibling, target) { |
| var compView = view; |
| while (compView && !isComponentView(compView)) { |
| compView = compView.parent; |
| } |
| var hostView = compView.parent; |
| var hostElDef = viewParentEl(compView); |
| var startIndex = hostElDef.nodeIndex + 1; |
| var endIndex = hostElDef.nodeIndex + hostElDef.childCount; |
| for (var i = startIndex; i <= endIndex; i++) { |
| var nodeDef = hostView.def.nodes[i]; |
| if (nodeDef.ngContentIndex === ngContentIndex) { |
| visitRenderNode(hostView, nodeDef, action, parentNode, nextSibling, target); |
| } |
| // jump to next sibling |
| i += nodeDef.childCount; |
| } |
| if (!hostView.parent) { |
| // a root view |
| var projectedNodes = view.root.projectableNodes[ngContentIndex]; |
| if (projectedNodes) { |
| for (var i = 0; i < projectedNodes.length; i++) { |
| execRenderNodeAction(view, projectedNodes[i], action, parentNode, nextSibling, target); |
| } |
| } |
| } |
| } |
| function visitRenderNode(view, nodeDef, action, parentNode, nextSibling, target) { |
| if (nodeDef.flags & 8 /* TypeNgContent */) { |
| visitProjectedRenderNodes(view, nodeDef.ngContent.index, action, parentNode, nextSibling, target); |
| } |
| else { |
| var rn = renderNode(view, nodeDef); |
| if (action === 3 /* RemoveChild */ && (nodeDef.flags & 33554432 /* ComponentView */) && |
| (nodeDef.bindingFlags & 48 /* CatSyntheticProperty */)) { |
| // Note: we might need to do both actions. |
| if (nodeDef.bindingFlags & (16 /* SyntheticProperty */)) { |
| execRenderNodeAction(view, rn, action, parentNode, nextSibling, target); |
| } |
| if (nodeDef.bindingFlags & (32 /* SyntheticHostProperty */)) { |
| var compView = asElementData(view, nodeDef.nodeIndex).componentView; |
| execRenderNodeAction(compView, rn, action, parentNode, nextSibling, target); |
| } |
| } |
| else { |
| execRenderNodeAction(view, rn, action, parentNode, nextSibling, target); |
| } |
| if (nodeDef.flags & 16777216 /* EmbeddedViews */) { |
| var embeddedViews = asElementData(view, nodeDef.nodeIndex).viewContainer._embeddedViews; |
| for (var k = 0; k < embeddedViews.length; k++) { |
| visitRootRenderNodes(embeddedViews[k], action, parentNode, nextSibling, target); |
| } |
| } |
| if (nodeDef.flags & 1 /* TypeElement */ && !nodeDef.element.name) { |
| visitSiblingRenderNodes(view, action, nodeDef.nodeIndex + 1, nodeDef.nodeIndex + nodeDef.childCount, parentNode, nextSibling, target); |
| } |
| } |
| } |
| function execRenderNodeAction(view, renderNode, action, parentNode, nextSibling, target) { |
| var renderer = view.renderer; |
| switch (action) { |
| case 1 /* AppendChild */: |
| renderer.appendChild(parentNode, renderNode); |
| break; |
| case 2 /* InsertBefore */: |
| renderer.insertBefore(parentNode, renderNode, nextSibling); |
| break; |
| case 3 /* RemoveChild */: |
| renderer.removeChild(parentNode, renderNode); |
| break; |
| case 0 /* Collect */: |
| target.push(renderNode); |
| break; |
| } |
| } |
| var NS_PREFIX_RE = /^:([^:]+):(.+)$/; |
| function splitNamespace(name) { |
| if (name[0] === ':') { |
| var match = name.match(NS_PREFIX_RE); |
| return [match[1], match[2]]; |
| } |
| return ['', name]; |
| } |
| function calcBindingFlags(bindings) { |
| var flags = 0; |
| for (var i = 0; i < bindings.length; i++) { |
| flags |= bindings[i].flags; |
| } |
| return flags; |
| } |
| function interpolate(valueCount, constAndInterp) { |
| var result = ''; |
| for (var i = 0; i < valueCount * 2; i = i + 2) { |
| result = result + constAndInterp[i] + _toStringWithNull(constAndInterp[i + 1]); |
| } |
| return result + constAndInterp[valueCount * 2]; |
| } |
| function inlineInterpolate(valueCount, c0, a1, c1, a2, c2, a3, c3, a4, c4, a5, c5, a6, c6, a7, c7, a8, c8, a9, c9) { |
| switch (valueCount) { |
| case 1: |
| return c0 + _toStringWithNull(a1) + c1; |
| case 2: |
| return c0 + _toStringWithNull(a1) + c1 + _toStringWithNull(a2) + c2; |
| case 3: |
| return c0 + _toStringWithNull(a1) + c1 + _toStringWithNull(a2) + c2 + _toStringWithNull(a3) + |
| c3; |
| case 4: |
| return c0 + _toStringWithNull(a1) + c1 + _toStringWithNull(a2) + c2 + _toStringWithNull(a3) + |
| c3 + _toStringWithNull(a4) + c4; |
| case 5: |
| return c0 + _toStringWithNull(a1) + c1 + _toStringWithNull(a2) + c2 + _toStringWithNull(a3) + |
| c3 + _toStringWithNull(a4) + c4 + _toStringWithNull(a5) + c5; |
| case 6: |
| return c0 + _toStringWithNull(a1) + c1 + _toStringWithNull(a2) + c2 + _toStringWithNull(a3) + |
| c3 + _toStringWithNull(a4) + c4 + _toStringWithNull(a5) + c5 + _toStringWithNull(a6) + c6; |
| case 7: |
| return c0 + _toStringWithNull(a1) + c1 + _toStringWithNull(a2) + c2 + _toStringWithNull(a3) + |
| c3 + _toStringWithNull(a4) + c4 + _toStringWithNull(a5) + c5 + _toStringWithNull(a6) + |
| c6 + _toStringWithNull(a7) + c7; |
| case 8: |
| return c0 + _toStringWithNull(a1) + c1 + _toStringWithNull(a2) + c2 + _toStringWithNull(a3) + |
| c3 + _toStringWithNull(a4) + c4 + _toStringWithNull(a5) + c5 + _toStringWithNull(a6) + |
| c6 + _toStringWithNull(a7) + c7 + _toStringWithNull(a8) + c8; |
| case 9: |
| return c0 + _toStringWithNull(a1) + c1 + _toStringWithNull(a2) + c2 + _toStringWithNull(a3) + |
| c3 + _toStringWithNull(a4) + c4 + _toStringWithNull(a5) + c5 + _toStringWithNull(a6) + |
| c6 + _toStringWithNull(a7) + c7 + _toStringWithNull(a8) + c8 + _toStringWithNull(a9) + c9; |
| default: |
| throw new Error("Does not support more than 9 expressions"); |
| } |
| } |
| function _toStringWithNull(v) { |
| return v != null ? v.toString() : ''; |
| } |
| var EMPTY_ARRAY$3 = []; |
| var EMPTY_MAP = {}; |
| |
| /** |
| * @license |
| * Copyright Google Inc. All Rights Reserved. |
| * |
| * Use of this source code is governed by an MIT-style license that can be |
| * found in the LICENSE file at https://angular.io/license |
| */ |
| var UNDEFINED_VALUE = new Object(); |
| var InjectorRefTokenKey = tokenKey(Injector); |
| var INJECTORRefTokenKey = tokenKey(INJECTOR); |
| var NgModuleRefTokenKey = tokenKey(NgModuleRef); |
| function moduleProvideDef(flags, token, value, deps) { |
| // Need to resolve forwardRefs as e.g. for `useValue` we |
| // lowered the expression and then stopped evaluating it, |
| // i.e. also didn't unwrap it. |
| value = resolveForwardRef(value); |
| var depDefs = splitDepsDsl(deps, stringify(token)); |
| return { |
| // will bet set by the module definition |
| index: -1, |
| deps: depDefs, flags: flags, token: token, value: value |
| }; |
| } |
| function moduleDef(providers) { |
| var providersByKey = {}; |
| var modules = []; |
| var isRoot = false; |
| for (var i = 0; i < providers.length; i++) { |
| var provider = providers[i]; |
| if (provider.token === APP_ROOT && provider.value === true) { |
| isRoot = true; |
| } |
| if (provider.flags & 1073741824 /* TypeNgModule */) { |
| modules.push(provider.token); |
| } |
| provider.index = i; |
| providersByKey[tokenKey(provider.token)] = provider; |
| } |
| return { |
| // Will be filled later... |
| factory: null, |
| providersByKey: providersByKey, |
| providers: providers, |
| modules: modules, |
| isRoot: isRoot, |
| }; |
| } |
| function initNgModule(data) { |
| var def = data._def; |
| var providers = data._providers = new Array(def.providers.length); |
| for (var i = 0; i < def.providers.length; i++) { |
| var provDef = def.providers[i]; |
| if (!(provDef.flags & 4096 /* LazyProvider */)) { |
| // Make sure the provider has not been already initialized outside this loop. |
| if (providers[i] === undefined) { |
| providers[i] = _createProviderInstance(data, provDef); |
| } |
| } |
| } |
| } |
| function resolveNgModuleDep(data, depDef, notFoundValue) { |
| if (notFoundValue === void 0) { notFoundValue = Injector.THROW_IF_NOT_FOUND; } |
| var former = setCurrentInjector(data); |
| try { |
| if (depDef.flags & 8 /* Value */) { |
| return depDef.token; |
| } |
| if (depDef.flags & 2 /* Optional */) { |
| notFoundValue = null; |
| } |
| if (depDef.flags & 1 /* SkipSelf */) { |
| return data._parent.get(depDef.token, notFoundValue); |
| } |
| var tokenKey_1 = depDef.tokenKey; |
| switch (tokenKey_1) { |
| case InjectorRefTokenKey: |
| case INJECTORRefTokenKey: |
| case NgModuleRefTokenKey: |
| return data; |
| } |
| var providerDef = data._def.providersByKey[tokenKey_1]; |
| var injectableDef = void 0; |
| if (providerDef) { |
| var providerInstance = data._providers[providerDef.index]; |
| if (providerInstance === undefined) { |
| providerInstance = data._providers[providerDef.index] = |
| _createProviderInstance(data, providerDef); |
| } |
| return providerInstance === UNDEFINED_VALUE ? undefined : providerInstance; |
| } |
| else if ((injectableDef = getInjectableDef(depDef.token)) && targetsModule(data, injectableDef)) { |
| var index = data._providers.length; |
| data._def.providers[index] = data._def.providersByKey[depDef.tokenKey] = { |
| flags: 1024 /* TypeFactoryProvider */ | 4096 /* LazyProvider */, |
| value: injectableDef.factory, |
| deps: [], index: index, |
| token: depDef.token, |
| }; |
| data._providers[index] = UNDEFINED_VALUE; |
| return (data._providers[index] = |
| _createProviderInstance(data, data._def.providersByKey[depDef.tokenKey])); |
| } |
| else if (depDef.flags & 4 /* Self */) { |
| return notFoundValue; |
| } |
| return data._parent.get(depDef.token, notFoundValue); |
| } |
| finally { |
| setCurrentInjector(former); |
| } |
| } |
| function moduleTransitivelyPresent(ngModule, scope) { |
| return ngModule._def.modules.indexOf(scope) > -1; |
| } |
| function targetsModule(ngModule, def) { |
| return def.providedIn != null && (moduleTransitivelyPresent(ngModule, def.providedIn) || |
| def.providedIn === 'root' && ngModule._def.isRoot); |
| } |
| function _createProviderInstance(ngModule, providerDef) { |
| var injectable; |
| switch (providerDef.flags & 201347067 /* Types */) { |
| case 512 /* TypeClassProvider */: |
| injectable = _createClass(ngModule, providerDef.value, providerDef.deps); |
| break; |
| case 1024 /* TypeFactoryProvider */: |
| injectable = _callFactory(ngModule, providerDef.value, providerDef.deps); |
| break; |
| case 2048 /* TypeUseExistingProvider */: |
| injectable = resolveNgModuleDep(ngModule, providerDef.deps[0]); |
| break; |
| case 256 /* TypeValueProvider */: |
| injectable = providerDef.value; |
| break; |
| } |
| // The read of `ngOnDestroy` here is slightly expensive as it's megamorphic, so it should be |
| // avoided if possible. The sequence of checks here determines whether ngOnDestroy needs to be |
| // checked. It might not if the `injectable` isn't an object or if NodeFlags.OnDestroy is already |
| // set (ngOnDestroy was detected statically). |
| if (injectable !== UNDEFINED_VALUE && injectable !== null && typeof injectable === 'object' && |
| !(providerDef.flags & 131072 /* OnDestroy */) && typeof injectable.ngOnDestroy === 'function') { |
| providerDef.flags |= 131072 /* OnDestroy */; |
| } |
| return injectable === undefined ? UNDEFINED_VALUE : injectable; |
| } |
| function _createClass(ngModule, ctor, deps) { |
| var len = deps.length; |
| switch (len) { |
| case 0: |
| return new ctor(); |
| case 1: |
| return new ctor(resolveNgModuleDep(ngModule, deps[0])); |
| case 2: |
| return new ctor(resolveNgModuleDep(ngModule, deps[0]), resolveNgModuleDep(ngModule, deps[1])); |
| case 3: |
| return new ctor(resolveNgModuleDep(ngModule, deps[0]), resolveNgModuleDep(ngModule, deps[1]), resolveNgModuleDep(ngModule, deps[2])); |
| default: |
| var depValues = new Array(len); |
| for (var i = 0; i < len; i++) { |
| depValues[i] = resolveNgModuleDep(ngModule, deps[i]); |
| } |
| return new (ctor.bind.apply(ctor, __spread([void 0], depValues)))(); |
| } |
| } |
| function _callFactory(ngModule, factory, deps) { |
| var len = deps.length; |
| switch (len) { |
| case 0: |
| return factory(); |
| case 1: |
| return factory(resolveNgModuleDep(ngModule, deps[0])); |
| case 2: |
| return factory(resolveNgModuleDep(ngModule, deps[0]), resolveNgModuleDep(ngModule, deps[1])); |
| case 3: |
| return factory(resolveNgModuleDep(ngModule, deps[0]), resolveNgModuleDep(ngModule, deps[1]), resolveNgModuleDep(ngModule, deps[2])); |
| default: |
| var depValues = Array(len); |
| for (var i = 0; i < len; i++) { |
| depValues[i] = resolveNgModuleDep(ngModule, deps[i]); |
| } |
| return factory.apply(void 0, __spread(depValues)); |
| } |
| } |
| function callNgModuleLifecycle(ngModule, lifecycles) { |
| var def = ngModule._def; |
| var destroyed = new Set(); |
| for (var i = 0; i < def.providers.length; i++) { |
| var provDef = def.providers[i]; |
| if (provDef.flags & 131072 /* OnDestroy */) { |
| var instance = ngModule._providers[i]; |
| if (instance && instance !== UNDEFINED_VALUE) { |
| var onDestroy = instance.ngOnDestroy; |
| if (typeof onDestroy === 'function' && !destroyed.has(instance)) { |
| onDestroy.apply(instance); |
| destroyed.add(instance); |
| } |
| } |
| } |
| } |
| } |
| |
| /** |
| * @license |
| * Copyright Google Inc. All Rights Reserved. |
| * |
| * Use of this source code is governed by an MIT-style license that can be |
| * found in the LICENSE file at https://angular.io/license |
| */ |
| function attachEmbeddedView(parentView, elementData, viewIndex, view) { |
| var embeddedViews = elementData.viewContainer._embeddedViews; |
| if (viewIndex === null || viewIndex === undefined) { |
| viewIndex = embeddedViews.length; |
| } |
| view.viewContainerParent = parentView; |
| addToArray(embeddedViews, viewIndex, view); |
| attachProjectedView(elementData, view); |
| Services.dirtyParentQueries(view); |
| var prevView = viewIndex > 0 ? embeddedViews[viewIndex - 1] : null; |
| renderAttachEmbeddedView(elementData, prevView, view); |
| } |
| function attachProjectedView(vcElementData, view) { |
| var dvcElementData = declaredViewContainer(view); |
| if (!dvcElementData || dvcElementData === vcElementData || |
| view.state & 16 /* IsProjectedView */) { |
| return; |
| } |
| // Note: For performance reasons, we |
| // - add a view to template._projectedViews only 1x throughout its lifetime, |
| // and remove it not until the view is destroyed. |
| // (hard, as when a parent view is attached/detached we would need to attach/detach all |
| // nested projected views as well, even across component boundaries). |
| // - don't track the insertion order of views in the projected views array |
| // (hard, as when the views of the same template are inserted different view containers) |
| view.state |= 16 /* IsProjectedView */; |
| var projectedViews = dvcElementData.template._projectedViews; |
| if (!projectedViews) { |
| projectedViews = dvcElementData.template._projectedViews = []; |
| } |
| projectedViews.push(view); |
| // Note: we are changing the NodeDef here as we cannot calculate |
| // the fact whether a template is used for projection during compilation. |
| markNodeAsProjectedTemplate(view.parent.def, view.parentNodeDef); |
| } |
| function markNodeAsProjectedTemplate(viewDef, nodeDef) { |
| if (nodeDef.flags & 4 /* ProjectedTemplate */) { |
| return; |
| } |
| viewDef.nodeFlags |= 4 /* ProjectedTemplate */; |
| nodeDef.flags |= 4 /* ProjectedTemplate */; |
| var parentNodeDef = nodeDef.parent; |
| while (parentNodeDef) { |
| parentNodeDef.childFlags |= 4 /* ProjectedTemplate */; |
| parentNodeDef = parentNodeDef.parent; |
| } |
| } |
| function detachEmbeddedView(elementData, viewIndex) { |
| var embeddedViews = elementData.viewContainer._embeddedViews; |
| if (viewIndex == null || viewIndex >= embeddedViews.length) { |
| viewIndex = embeddedViews.length - 1; |
| } |
| if (viewIndex < 0) { |
| return null; |
| } |
| var view = embeddedViews[viewIndex]; |
| view.viewContainerParent = null; |
| removeFromArray(embeddedViews, viewIndex); |
| // See attachProjectedView for why we don't update projectedViews here. |
| Services.dirtyParentQueries(view); |
| renderDetachView$1(view); |
| return view; |
| } |
| function detachProjectedView(view) { |
| if (!(view.state & 16 /* IsProjectedView */)) { |
| return; |
| } |
| var dvcElementData = declaredViewContainer(view); |
| if (dvcElementData) { |
| var projectedViews = dvcElementData.template._projectedViews; |
| if (projectedViews) { |
| removeFromArray(projectedViews, projectedViews.indexOf(view)); |
| Services.dirtyParentQueries(view); |
| } |
| } |
| } |
| function moveEmbeddedView(elementData, oldViewIndex, newViewIndex) { |
| var embeddedViews = elementData.viewContainer._embeddedViews; |
| var view = embeddedViews[oldViewIndex]; |
| removeFromArray(embeddedViews, oldViewIndex); |
| if (newViewIndex == null) { |
| newViewIndex = embeddedViews.length; |
| } |
| addToArray(embeddedViews, newViewIndex, view); |
| // Note: Don't need to change projectedViews as the order in there |
| // as always invalid... |
| Services.dirtyParentQueries(view); |
| renderDetachView$1(view); |
| var prevView = newViewIndex > 0 ? embeddedViews[newViewIndex - 1] : null; |
| renderAttachEmbeddedView(elementData, prevView, view); |
| return view; |
| } |
| function renderAttachEmbeddedView(elementData, prevView, view) { |
| var prevRenderNode = prevView ? renderNode(prevView, prevView.def.lastRenderRootNode) : |
| elementData.renderElement; |
| var parentNode = view.renderer.parentNode(prevRenderNode); |
| var nextSibling = view.renderer.nextSibling(prevRenderNode); |
| // Note: We can't check if `nextSibling` is present, as on WebWorkers it will always be! |
| // However, browsers automatically do `appendChild` when there is no `nextSibling`. |
| visitRootRenderNodes(view, 2 /* InsertBefore */, parentNode, nextSibling, undefined); |
| } |
| function renderDetachView$1(view) { |
| visitRootRenderNodes(view, 3 /* RemoveChild */, null, null, undefined); |
| } |
| function addToArray(arr, index, value) { |
| // perf: array.push is faster than array.splice! |
| if (index >= arr.length) { |
| arr.push(value); |
| } |
| else { |
| arr.splice(index, 0, value); |
| } |
| } |
| function removeFromArray(arr, index) { |
| // perf: array.pop is faster than array.splice! |
| if (index >= arr.length - 1) { |
| arr.pop(); |
| } |
| else { |
| arr.splice(index, 1); |
| } |
| } |
| |
| /** |
| * @license |
| * Copyright Google Inc. All Rights Reserved. |
| * |
| * Use of this source code is governed by an MIT-style license that can be |
| * found in the LICENSE file at https://angular.io/license |
| */ |
| var EMPTY_CONTEXT = new Object(); |
| // Attention: this function is called as top level function. |
| // Putting any logic in here will destroy closure tree shaking! |
| function createComponentFactory(selector, componentType, viewDefFactory, inputs, outputs, ngContentSelectors) { |
| return new ComponentFactory_(selector, componentType, viewDefFactory, inputs, outputs, ngContentSelectors); |
| } |
| function getComponentViewDefinitionFactory(componentFactory) { |
| return componentFactory.viewDefFactory; |
| } |
| var ComponentFactory_ = /** @class */ (function (_super) { |
| __extends(ComponentFactory_, _super); |
| function ComponentFactory_(selector, componentType, viewDefFactory, _inputs, _outputs, ngContentSelectors) { |
| var _this = |
| // Attention: this ctor is called as top level function. |
| // Putting any logic in here will destroy closure tree shaking! |
| _super.call(this) || this; |
| _this.selector = selector; |
| _this.componentType = componentType; |
| _this._inputs = _inputs; |
| _this._outputs = _outputs; |
| _this.ngContentSelectors = ngContentSelectors; |
| _this.viewDefFactory = viewDefFactory; |
| return _this; |
| } |
| Object.defineProperty(ComponentFactory_.prototype, "inputs", { |
| get: function () { |
| var inputsArr = []; |
| var inputs = this._inputs; |
| for (var propName in inputs) { |
| var templateName = inputs[propName]; |
| inputsArr.push({ propName: propName, templateName: templateName }); |
| } |
| return inputsArr; |
| }, |
| enumerable: true, |
| configurable: true |
| }); |
| Object.defineProperty(ComponentFactory_.prototype, "outputs", { |
| get: function () { |
| var outputsArr = []; |
| for (var propName in this._outputs) { |
| var templateName = this._outputs[propName]; |
| outputsArr.push({ propName: propName, templateName: templateName }); |
| } |
| return outputsArr; |
| }, |
| enumerable: true, |
| configurable: true |
| }); |
| /** |
| * Creates a new component. |
| */ |
| ComponentFactory_.prototype.create = function (injector, projectableNodes, rootSelectorOrNode, ngModule) { |
| if (!ngModule) { |
| throw new Error('ngModule should be provided'); |
| } |
| var viewDef = resolveDefinition(this.viewDefFactory); |
| var componentNodeIndex = viewDef.nodes[0].element.componentProvider.nodeIndex; |
| var view = Services.createRootView(injector, projectableNodes || [], rootSelectorOrNode, viewDef, ngModule, EMPTY_CONTEXT); |
| var component = asProviderData(view, componentNodeIndex).instance; |
| if (rootSelectorOrNode) { |
| view.renderer.setAttribute(asElementData(view, 0).renderElement, 'ng-version', VERSION.full); |
| } |
| return new ComponentRef_(view, new ViewRef_(view), component); |
| }; |
| return ComponentFactory_; |
| }(ComponentFactory)); |
| var ComponentRef_ = /** @class */ (function (_super) { |
| __extends(ComponentRef_, _super); |
| function ComponentRef_(_view, _viewRef, _component) { |
| var _this = _super.call(this) || this; |
| _this._view = _view; |
| _this._viewRef = _viewRef; |
| _this._component = _component; |
| _this._elDef = _this._view.def.nodes[0]; |
| _this.hostView = _viewRef; |
| _this.changeDetectorRef = _viewRef; |
| _this.instance = _component; |
| return _this; |
| } |
| Object.defineProperty(ComponentRef_.prototype, "location", { |
| get: function () { |
| return new ElementRef(asElementData(this._view, this._elDef.nodeIndex).renderElement); |
| }, |
| enumerable: true, |
| configurable: true |
| }); |
| Object.defineProperty(ComponentRef_.prototype, "injector", { |
| get: function () { return new Injector_(this._view, this._elDef); }, |
| enumerable: true, |
| configurable: true |
| }); |
| Object.defineProperty(ComponentRef_.prototype, "componentType", { |
| get: function () { return this._component.constructor; }, |
| enumerable: true, |
| configurable: true |
| }); |
| ComponentRef_.prototype.destroy = function () { this._viewRef.destroy(); }; |
| ComponentRef_.prototype.onDestroy = function (callback) { this._viewRef.onDestroy(callback); }; |
| return ComponentRef_; |
| }(ComponentRef)); |
| function createViewContainerData(view, elDef, elData) { |
| return new ViewContainerRef_(view, elDef, elData); |
| } |
| var ViewContainerRef_ = /** @class */ (function () { |
| function ViewContainerRef_(_view, _elDef, _data) { |
| this._view = _view; |
| this._elDef = _elDef; |
| this._data = _data; |
| /** |
| * @internal |
| */ |
| this._embeddedViews = []; |
| } |
| Object.defineProperty(ViewContainerRef_.prototype, "element", { |
| get: function () { return new ElementRef(this._data.renderElement); }, |
| enumerable: true, |
| configurable: true |
| }); |
| Object.defineProperty(ViewContainerRef_.prototype, "injector", { |
| get: function () { return new Injector_(this._view, this._elDef); }, |
| enumerable: true, |
| configurable: true |
| }); |
| Object.defineProperty(ViewContainerRef_.prototype, "parentInjector", { |
| /** @deprecated No replacement */ |
| get: function () { |
| var view = this._view; |
| var elDef = this._elDef.parent; |
| while (!elDef && view) { |
| elDef = viewParentEl(view); |
| view = view.parent; |
| } |
| return view ? new Injector_(view, elDef) : new Injector_(this._view, null); |
| }, |
| enumerable: true, |
| configurable: true |
| }); |
| ViewContainerRef_.prototype.clear = function () { |
| var len = this._embeddedViews.length; |
| for (var i = len - 1; i >= 0; i--) { |
| var view = detachEmbeddedView(this._data, i); |
| Services.destroyView(view); |
| } |
| }; |
| ViewContainerRef_.prototype.get = function (index) { |
| var view = this._embeddedViews[index]; |
| if (view) { |
| var ref = new ViewRef_(view); |
| ref.attachToViewContainerRef(this); |
| return ref; |
| } |
| return null; |
| }; |
| Object.defineProperty(ViewContainerRef_.prototype, "length", { |
| get: function () { return this._embeddedViews.length; }, |
| enumerable: true, |
| configurable: true |
| }); |
| ViewContainerRef_.prototype.createEmbeddedView = function (templateRef, context, index) { |
| var viewRef = templateRef.createEmbeddedView(context || {}); |
| this.insert(viewRef, index); |
| return viewRef; |
| }; |
| ViewContainerRef_.prototype.createComponent = function (componentFactory, index, injector, projectableNodes, ngModuleRef) { |
| var contextInjector = injector || this.parentInjector; |
| if (!ngModuleRef && !(componentFactory instanceof ComponentFactoryBoundToModule)) { |
| ngModuleRef = contextInjector.get(NgModuleRef); |
| } |
| var componentRef = componentFactory.create(contextInjector, projectableNodes, undefined, ngModuleRef); |
| this.insert(componentRef.hostView, index); |
| return componentRef; |
| }; |
| ViewContainerRef_.prototype.insert = function (viewRef, index) { |
| if (viewRef.destroyed) { |
| throw new Error('Cannot insert a destroyed View in a ViewContainer!'); |
| } |
| var viewRef_ = viewRef; |
| var viewData = viewRef_._view; |
| attachEmbeddedView(this._view, this._data, index, viewData); |
| viewRef_.attachToViewContainerRef(this); |
| return viewRef; |
| }; |
| ViewContainerRef_.prototype.move = function (viewRef, currentIndex) { |
| if (viewRef.destroyed) { |
| throw new Error('Cannot move a destroyed View in a ViewContainer!'); |
| } |
| var previousIndex = this._embeddedViews.indexOf(viewRef._view); |
| moveEmbeddedView(this._data, previousIndex, currentIndex); |
| return viewRef; |
| }; |
| ViewContainerRef_.prototype.indexOf = function (viewRef) { |
| return this._embeddedViews.indexOf(viewRef._view); |
| }; |
| ViewContainerRef_.prototype.remove = function (index) { |
| var viewData = detachEmbeddedView(this._data, index); |
| if (viewData) { |
| Services.destroyView(viewData); |
| } |
| }; |
| ViewContainerRef_.prototype.detach = function (index) { |
| var view = detachEmbeddedView(this._data, index); |
| return view ? new ViewRef_(view) : null; |
| }; |
| return ViewContainerRef_; |
| }()); |
| function createChangeDetectorRef(view) { |
| return new ViewRef_(view); |
| } |
| var ViewRef_ = /** @class */ (function () { |
| function ViewRef_(_view) { |
| this._view = _view; |
| this._viewContainerRef = null; |
| this._appRef = null; |
| } |
| Object.defineProperty(ViewRef_.prototype, "rootNodes", { |
| get: function () { return rootRenderNodes(this._view); }, |
| enumerable: true, |
| configurable: true |
| }); |
| Object.defineProperty(ViewRef_.prototype, "context", { |
| get: function () { return this._view.context; }, |
| enumerable: true, |
| configurable: true |
| }); |
| Object.defineProperty(ViewRef_.prototype, "destroyed", { |
| get: function () { return (this._view.state & 128 /* Destroyed */) !== 0; }, |
| enumerable: true, |
| configurable: true |
| }); |
| ViewRef_.prototype.markForCheck = function () { markParentViewsForCheck(this._view); }; |
| ViewRef_.prototype.detach = function () { this._view.state &= ~4 /* Attached */; }; |
| ViewRef_.prototype.detectChanges = function () { |
| var fs = this._view.root.rendererFactory; |
| if (fs.begin) { |
| fs.begin(); |
| } |
| try { |
| Services.checkAndUpdateView(this._view); |
| } |
| finally { |
| if (fs.end) { |
| fs.end(); |
| } |
| } |
| }; |
| ViewRef_.prototype.checkNoChanges = function () { Services.checkNoChangesView(this._view); }; |
| ViewRef_.prototype.reattach = function () { this._view.state |= 4 /* Attached */; }; |
| ViewRef_.prototype.onDestroy = function (callback) { |
| if (!this._view.disposables) { |
| this._view.disposables = []; |
| } |
| this._view.disposables.push(callback); |
| }; |
| ViewRef_.prototype.destroy = function () { |
| if (this._appRef) { |
| this._appRef.detachView(this); |
| } |
| else if (this._viewContainerRef) { |
| this._viewContainerRef.detach(this._viewContainerRef.indexOf(this)); |
| } |
| Services.destroyView(this._view); |
| }; |
| ViewRef_.prototype.detachFromAppRef = function () { |
| this._appRef = null; |
| renderDetachView$1(this._view); |
| Services.dirtyParentQueries(this._view); |
| }; |
| ViewRef_.prototype.attachToAppRef = function (appRef) { |
| if (this._viewContainerRef) { |
| throw new Error('This view is already attached to a ViewContainer!'); |
| } |
| this._appRef = appRef; |
| }; |
| ViewRef_.prototype.attachToViewContainerRef = function (vcRef) { |
| if (this._appRef) { |
| throw new Error('This view is already attached directly to the ApplicationRef!'); |
| } |
| this._viewContainerRef = vcRef; |
| }; |
| return ViewRef_; |
| }()); |
| function createTemplateData(view, def) { |
| return new TemplateRef_(view, def); |
| } |
| var TemplateRef_ = /** @class */ (function (_super) { |
| __extends(TemplateRef_, _super); |
| function TemplateRef_(_parentView, _def) { |
| var _this = _super.call(this) || this; |
| _this._parentView = _parentView; |
| _this._def = _def; |
| return _this; |
| } |
| TemplateRef_.prototype.createEmbeddedView = function (context) { |
| return new ViewRef_(Services.createEmbeddedView(this._parentView, this._def, this._def.element.template, context)); |
| }; |
| Object.defineProperty(TemplateRef_.prototype, "elementRef", { |
| get: function () { |
| return new ElementRef(asElementData(this._parentView, this._def.nodeIndex).renderElement); |
| }, |
| enumerable: true, |
| configurable: true |
| }); |
| return TemplateRef_; |
| }(TemplateRef)); |
| function createInjector$1(view, elDef) { |
| return new Injector_(view, elDef); |
| } |
| var Injector_ = /** @class */ (function () { |
| function Injector_(view, elDef) { |
| this.view = view; |
| this.elDef = elDef; |
| } |
| Injector_.prototype.get = function (token, notFoundValue) { |
| if (notFoundValue === void 0) { notFoundValue = Injector.THROW_IF_NOT_FOUND; } |
| var allowPrivateServices = this.elDef ? (this.elDef.flags & 33554432 /* ComponentView */) !== 0 : false; |
| return Services.resolveDep(this.view, this.elDef, allowPrivateServices, { flags: 0 /* None */, token: token, tokenKey: tokenKey(token) }, notFoundValue); |
| }; |
| return Injector_; |
| }()); |
| function nodeValue(view, index) { |
| var def = view.def.nodes[index]; |
| if (def.flags & 1 /* TypeElement */) { |
| var elData = asElementData(view, def.nodeIndex); |
| return def.element.template ? elData.template : elData.renderElement; |
| } |
| else if (def.flags & 2 /* TypeText */) { |
| return asTextData(view, def.nodeIndex).renderText; |
| } |
| else if (def.flags & (20224 /* CatProvider */ | 16 /* TypePipe */)) { |
| return asProviderData(view, def.nodeIndex).instance; |
| } |
| throw new Error("Illegal state: read nodeValue for node index " + index); |
| } |
| function createRendererV1(view) { |
| return new RendererAdapter(view.renderer); |
| } |
| var RendererAdapter = /** @class */ (function () { |
| function RendererAdapter(delegate) { |
| this.delegate = delegate; |
| } |
| RendererAdapter.prototype.selectRootElement = function (selectorOrNode) { |
| return this.delegate.selectRootElement(selectorOrNode); |
| }; |
| RendererAdapter.prototype.createElement = function (parent, namespaceAndName) { |
| var _a = __read(splitNamespace(namespaceAndName), 2), ns = _a[0], name = _a[1]; |
| var el = this.delegate.createElement(name, ns); |
| if (parent) { |
| this.delegate.appendChild(parent, el); |
| } |
| return el; |
| }; |
| RendererAdapter.prototype.createViewRoot = function (hostElement) { return hostElement; }; |
| RendererAdapter.prototype.createTemplateAnchor = function (parentElement) { |
| var comment = this.delegate.createComment(''); |
| if (parentElement) { |
| this.delegate.appendChild(parentElement, comment); |
| } |
| return comment; |
| }; |
| RendererAdapter.prototype.createText = function (parentElement, value) { |
| var node = this.delegate.createText(value); |
| if (parentElement) { |
| this.delegate.appendChild(parentElement, node); |
| } |
| return node; |
| }; |
| RendererAdapter.prototype.projectNodes = function (parentElement, nodes) { |
| for (var i = 0; i < nodes.length; i++) { |
| this.delegate.appendChild(parentElement, nodes[i]); |
| } |
| }; |
| RendererAdapter.prototype.attachViewAfter = function (node, viewRootNodes) { |
| var parentElement = this.delegate.parentNode(node); |
| var nextSibling = this.delegate.nextSibling(node); |
| for (var i = 0; i < viewRootNodes.length; i++) { |
| this.delegate.insertBefore(parentElement, viewRootNodes[i], nextSibling); |
| } |
| }; |
| RendererAdapter.prototype.detachView = function (viewRootNodes) { |
| for (var i = 0; i < viewRootNodes.length; i++) { |
| var node = viewRootNodes[i]; |
| var parentElement = this.delegate.parentNode(node); |
| this.delegate.removeChild(parentElement, node); |
| } |
| }; |
| RendererAdapter.prototype.destroyView = function (hostElement, viewAllNodes) { |
| for (var i = 0; i < viewAllNodes.length; i++) { |
| this.delegate.destroyNode(viewAllNodes[i]); |
| } |
| }; |
| RendererAdapter.prototype.listen = function (renderElement, name, callback) { |
| return this.delegate.listen(renderElement, name, callback); |
| }; |
| RendererAdapter.prototype.listenGlobal = function (target, name, callback) { |
| return this.delegate.listen(target, name, callback); |
| }; |
| RendererAdapter.prototype.setElementProperty = function (renderElement, propertyName, propertyValue) { |
| this.delegate.setProperty(renderElement, propertyName, propertyValue); |
| }; |
| RendererAdapter.prototype.setElementAttribute = function (renderElement, namespaceAndName, attributeValue) { |
| var _a = __read(splitNamespace(namespaceAndName), 2), ns = _a[0], name = _a[1]; |
| if (attributeValue != null) { |
| this.delegate.setAttribute(renderElement, name, attributeValue, ns); |
| } |
| else { |
| this.delegate.removeAttribute(renderElement, name, ns); |
| } |
| }; |
| RendererAdapter.prototype.setBindingDebugInfo = function (renderElement, propertyName, propertyValue) { }; |
| RendererAdapter.prototype.setElementClass = function (renderElement, className, isAdd) { |
| if (isAdd) { |
| this.delegate.addClass(renderElement, className); |
| } |
| else { |
| this.delegate.removeClass(renderElement, className); |
| } |
| }; |
| RendererAdapter.prototype.setElementStyle = function (renderElement, styleName, styleValue) { |
| if (styleValue != null) { |
| this.delegate.setStyle(renderElement, styleName, styleValue); |
| } |
| else { |
| this.delegate.removeStyle(renderElement, styleName); |
| } |
| }; |
| RendererAdapter.prototype.invokeElementMethod = function (renderElement, methodName, args) { |
| renderElement[methodName].apply(renderElement, args); |
| }; |
| RendererAdapter.prototype.setText = function (renderNode, text) { this.delegate.setValue(renderNode, text); }; |
| RendererAdapter.prototype.animate = function () { throw new Error('Renderer.animate is no longer supported!'); }; |
| return RendererAdapter; |
| }()); |
| function createNgModuleRef(moduleType, parent, bootstrapComponents, def) { |
| return new NgModuleRef_(moduleType, parent, bootstrapComponents, def); |
| } |
| var NgModuleRef_ = /** @class */ (function () { |
| function NgModuleRef_(_moduleType, _parent, _bootstrapComponents, _def) { |
| this._moduleType = _moduleType; |
| this._parent = _parent; |
| this._bootstrapComponents = _bootstrapComponents; |
| this._def = _def; |
| this._destroyListeners = []; |
| this._destroyed = false; |
| this.injector = this; |
| initNgModule(this); |
| } |
| NgModuleRef_.prototype.get = function (token, notFoundValue, injectFlags) { |
| if (notFoundValue === void 0) { notFoundValue = Injector.THROW_IF_NOT_FOUND; } |
| if (injectFlags === void 0) { injectFlags = exports.InjectFlags.Default; } |
| var flags = 0 /* None */; |
| if (injectFlags & exports.InjectFlags.SkipSelf) { |
| flags |= 1 /* SkipSelf */; |
| } |
| else if (injectFlags & exports.InjectFlags.Self) { |
| flags |= 4 /* Self */; |
| } |
| return resolveNgModuleDep(this, { token: token, tokenKey: tokenKey(token), flags: flags }, notFoundValue); |
| }; |
| Object.defineProperty(NgModuleRef_.prototype, "instance", { |
| get: function () { return this.get(this._moduleType); }, |
| enumerable: true, |
| configurable: true |
| }); |
| Object.defineProperty(NgModuleRef_.prototype, "componentFactoryResolver", { |
| get: function () { return this.get(ComponentFactoryResolver); }, |
| enumerable: true, |
| configurable: true |
| }); |
| NgModuleRef_.prototype.destroy = function () { |
| if (this._destroyed) { |
| throw new Error("The ng module " + stringify(this.instance.constructor) + " has already been destroyed."); |
| } |
| this._destroyed = true; |
| callNgModuleLifecycle(this, 131072 /* OnDestroy */); |
| this._destroyListeners.forEach(function (listener) { return listener(); }); |
| }; |
| NgModuleRef_.prototype.onDestroy = function (callback) { this._destroyListeners.push(callback); }; |
| return NgModuleRef_; |
| }()); |
| |
| /** |
| * @license |
| * Copyright Google Inc. All Rights Reserved. |
| * |
| * Use of this source code is governed by an MIT-style license that can be |
| * found in the LICENSE file at https://angular.io/license |
| */ |
| var RendererV1TokenKey = tokenKey(Renderer); |
| var Renderer2TokenKey = tokenKey(Renderer2); |
| var ElementRefTokenKey = tokenKey(ElementRef); |
| var ViewContainerRefTokenKey = tokenKey(ViewContainerRef); |
| var TemplateRefTokenKey = tokenKey(TemplateRef); |
| var ChangeDetectorRefTokenKey = tokenKey(ChangeDetectorRef); |
| var InjectorRefTokenKey$1 = tokenKey(Injector); |
| var INJECTORRefTokenKey$1 = tokenKey(INJECTOR); |
| function directiveDef(checkIndex, flags, matchedQueries, childCount, ctor, deps, props, outputs) { |
| var bindings = []; |
| if (props) { |
| for (var prop in props) { |
| var _a = __read(props[prop], 2), bindingIndex = _a[0], nonMinifiedName = _a[1]; |
| bindings[bindingIndex] = { |
| flags: 8 /* TypeProperty */, |
| name: prop, nonMinifiedName: nonMinifiedName, |
| ns: null, |
| securityContext: null, |
| suffix: null |
| }; |
| } |
| } |
| var outputDefs = []; |
| if (outputs) { |
| for (var propName in outputs) { |
| outputDefs.push({ type: 1 /* DirectiveOutput */, propName: propName, target: null, eventName: outputs[propName] }); |
| } |
| } |
| flags |= 16384 /* TypeDirective */; |
| return _def(checkIndex, flags, matchedQueries, childCount, ctor, ctor, deps, bindings, outputDefs); |
| } |
| function pipeDef(flags, ctor, deps) { |
| flags |= 16 /* TypePipe */; |
| return _def(-1, flags, null, 0, ctor, ctor, deps); |
| } |
| function providerDef(flags, matchedQueries, token, value, deps) { |
| return _def(-1, flags, matchedQueries, 0, token, value, deps); |
| } |
| function _def(checkIndex, flags, matchedQueriesDsl, childCount, token, value, deps, bindings, outputs) { |
| var _a = splitMatchedQueriesDsl(matchedQueriesDsl), matchedQueries = _a.matchedQueries, references = _a.references, matchedQueryIds = _a.matchedQueryIds; |
| if (!outputs) { |
| outputs = []; |
| } |
| if (!bindings) { |
| bindings = []; |
| } |
| // Need to resolve forwardRefs as e.g. for `useValue` we |
| // lowered the expression and then stopped evaluating it, |
| // i.e. also didn't unwrap it. |
| value = resolveForwardRef(value); |
| var depDefs = splitDepsDsl(deps, stringify(token)); |
| return { |
| // will bet set by the view definition |
| nodeIndex: -1, |
| parent: null, |
| renderParent: null, |
| bindingIndex: -1, |
| outputIndex: -1, |
| // regular values |
| checkIndex: checkIndex, |
| flags: flags, |
| childFlags: 0, |
| directChildFlags: 0, |
| childMatchedQueries: 0, matchedQueries: matchedQueries, matchedQueryIds: matchedQueryIds, references: references, |
| ngContentIndex: -1, childCount: childCount, bindings: bindings, |
| bindingFlags: calcBindingFlags(bindings), outputs: outputs, |
| element: null, |
| provider: { token: token, value: value, deps: depDefs }, |
| text: null, |
| query: null, |
| ngContent: null |
| }; |
| } |
| function createProviderInstance(view, def) { |
| return _createProviderInstance$1(view, def); |
| } |
| function createPipeInstance(view, def) { |
| // deps are looked up from component. |
| var compView = view; |
| while (compView.parent && !isComponentView(compView)) { |
| compView = compView.parent; |
| } |
| // pipes can see the private services of the component |
| var allowPrivateServices = true; |
| // pipes are always eager and classes! |
| return createClass(compView.parent, viewParentEl(compView), allowPrivateServices, def.provider.value, def.provider.deps); |
| } |
| function createDirectiveInstance(view, def) { |
| // components can see other private services, other directives can't. |
| var allowPrivateServices = (def.flags & 32768 /* Component */) > 0; |
| // directives are always eager and classes! |
| var instance = createClass(view, def.parent, allowPrivateServices, def.provider.value, def.provider.deps); |
| if (def.outputs.length) { |
| for (var i = 0; i < def.outputs.length; i++) { |
| var output = def.outputs[i]; |
| var outputObservable = instance[output.propName]; |
| if (isObservable(outputObservable)) { |
| var subscription = outputObservable.subscribe(eventHandlerClosure(view, def.parent.nodeIndex, output.eventName)); |
| view.disposables[def.outputIndex + i] = subscription.unsubscribe.bind(subscription); |
| } |
| else { |
| throw new Error("@Output " + output.propName + " not initialized in '" + instance.constructor.name + "'."); |
| } |
| } |
| } |
| return instance; |
| } |
| function eventHandlerClosure(view, index, eventName) { |
| return function (event) { return dispatchEvent(view, index, eventName, event); }; |
| } |
| function checkAndUpdateDirectiveInline(view, def, v0, v1, v2, v3, v4, v5, v6, v7, v8, v9) { |
| var providerData = asProviderData(view, def.nodeIndex); |
| var directive = providerData.instance; |
| var changed = false; |
| var changes = undefined; |
| var bindLen = def.bindings.length; |
| if (bindLen > 0 && checkBinding(view, def, 0, v0)) { |
| changed = true; |
| changes = updateProp(view, providerData, def, 0, v0, changes); |
| } |
| if (bindLen > 1 && checkBinding(view, def, 1, v1)) { |
| changed = true; |
| changes = updateProp(view, providerData, def, 1, v1, changes); |
| } |
| if (bindLen > 2 && checkBinding(view, def, 2, v2)) { |
| changed = true; |
| changes = updateProp(view, providerData, def, 2, v2, changes); |
| } |
| if (bindLen > 3 && checkBinding(view, def, 3, v3)) { |
| changed = true; |
| changes = updateProp(view, providerData, def, 3, v3, changes); |
| } |
| if (bindLen > 4 && checkBinding(view, def, 4, v4)) { |
| changed = true; |
| changes = updateProp(view, providerData, def, 4, v4, changes); |
| } |
| if (bindLen > 5 && checkBinding(view, def, 5, v5)) { |
| changed = true; |
| changes = updateProp(view, providerData, def, 5, v5, changes); |
| } |
| if (bindLen > 6 && checkBinding(view, def, 6, v6)) { |
| changed = true; |
| changes = updateProp(view, providerData, def, 6, v6, changes); |
| } |
| if (bindLen > 7 && checkBinding(view, def, 7, v7)) { |
| changed = true; |
| changes = updateProp(view, providerData, def, 7, v7, changes); |
| } |
| if (bindLen > 8 && checkBinding(view, def, 8, v8)) { |
| changed = true; |
| changes = updateProp(view, providerData, def, 8, v8, changes); |
| } |
| if (bindLen > 9 && checkBinding(view, def, 9, v9)) { |
| changed = true; |
| changes = updateProp(view, providerData, def, 9, v9, changes); |
| } |
| if (changes) { |
| directive.ngOnChanges(changes); |
| } |
| if ((def.flags & 65536 /* OnInit */) && |
| shouldCallLifecycleInitHook(view, 256 /* InitState_CallingOnInit */, def.nodeIndex)) { |
| directive.ngOnInit(); |
| } |
| if (def.flags & 262144 /* DoCheck */) { |
| directive.ngDoCheck(); |
| } |
| return changed; |
| } |
| function checkAndUpdateDirectiveDynamic(view, def, values) { |
| var providerData = asProviderData(view, def.nodeIndex); |
| var directive = providerData.instance; |
| var changed = false; |
| var changes = undefined; |
| for (var i = 0; i < values.length; i++) { |
| if (checkBinding(view, def, i, values[i])) { |
| changed = true; |
| changes = updateProp(view, providerData, def, i, values[i], changes); |
| } |
| } |
| if (changes) { |
| directive.ngOnChanges(changes); |
| } |
| if ((def.flags & 65536 /* OnInit */) && |
| shouldCallLifecycleInitHook(view, 256 /* InitState_CallingOnInit */, def.nodeIndex)) { |
| directive.ngOnInit(); |
| } |
| if (def.flags & 262144 /* DoCheck */) { |
| directive.ngDoCheck(); |
| } |
| return changed; |
| } |
| function _createProviderInstance$1(view, def) { |
| // private services can see other private services |
| var allowPrivateServices = (def.flags & 8192 /* PrivateProvider */) > 0; |
| var providerDef = def.provider; |
| switch (def.flags & 201347067 /* Types */) { |
| case 512 /* TypeClassProvider */: |
| return createClass(view, def.parent, allowPrivateServices, providerDef.value, providerDef.deps); |
| case 1024 /* TypeFactoryProvider */: |
| return callFactory(view, def.parent, allowPrivateServices, providerDef.value, providerDef.deps); |
| case 2048 /* TypeUseExistingProvider */: |
| return resolveDep(view, def.parent, allowPrivateServices, providerDef.deps[0]); |
| case 256 /* TypeValueProvider */: |
| return providerDef.value; |
| } |
| } |
| function createClass(view, elDef, allowPrivateServices, ctor, deps) { |
| var len = deps.length; |
| switch (len) { |
| case 0: |
| return new ctor(); |
| case 1: |
| return new ctor(resolveDep(view, elDef, allowPrivateServices, deps[0])); |
| case 2: |
| return new ctor(resolveDep(view, elDef, allowPrivateServices, deps[0]), resolveDep(view, elDef, allowPrivateServices, deps[1])); |
| case 3: |
| return new ctor(resolveDep(view, elDef, allowPrivateServices, deps[0]), resolveDep(view, elDef, allowPrivateServices, deps[1]), resolveDep(view, elDef, allowPrivateServices, deps[2])); |
| default: |
| var depValues = new Array(len); |
| for (var i = 0; i < len; i++) { |
| depValues[i] = resolveDep(view, elDef, allowPrivateServices, deps[i]); |
| } |
| return new (ctor.bind.apply(ctor, __spread([void 0], depValues)))(); |
| } |
| } |
| function callFactory(view, elDef, allowPrivateServices, factory, deps) { |
| var len = deps.length; |
| switch (len) { |
| case 0: |
| return factory(); |
| case 1: |
| return factory(resolveDep(view, elDef, allowPrivateServices, deps[0])); |
| case 2: |
| return factory(resolveDep(view, elDef, allowPrivateServices, deps[0]), resolveDep(view, elDef, allowPrivateServices, deps[1])); |
| case 3: |
| return factory(resolveDep(view, elDef, allowPrivateServices, deps[0]), resolveDep(view, elDef, allowPrivateServices, deps[1]), resolveDep(view, elDef, allowPrivateServices, deps[2])); |
| default: |
| var depValues = Array(len); |
| for (var i = 0; i < len; i++) { |
| depValues[i] = resolveDep(view, elDef, allowPrivateServices, deps[i]); |
| } |
| return factory.apply(void 0, __spread(depValues)); |
| } |
| } |
| // This default value is when checking the hierarchy for a token. |
| // |
| // It means both: |
| // - the token is not provided by the current injector, |
| // - only the element injectors should be checked (ie do not check module injectors |
| // |
| // mod1 |
| // / |
| // el1 mod2 |
| // \ / |
| // el2 |
| // |
| // When requesting el2.injector.get(token), we should check in the following order and return the |
| // first found value: |
| // - el2.injector.get(token, default) |
| // - el1.injector.get(token, NOT_FOUND_CHECK_ONLY_ELEMENT_INJECTOR) -> do not check the module |
| // - mod2.injector.get(token, default) |
| var NOT_FOUND_CHECK_ONLY_ELEMENT_INJECTOR = {}; |
| function resolveDep(view, elDef, allowPrivateServices, depDef, notFoundValue) { |
| if (notFoundValue === void 0) { notFoundValue = Injector.THROW_IF_NOT_FOUND; } |
| if (depDef.flags & 8 /* Value */) { |
| return depDef.token; |
| } |
| var startView = view; |
| if (depDef.flags & 2 /* Optional */) { |
| notFoundValue = null; |
| } |
| var tokenKey = depDef.tokenKey; |
| if (tokenKey === ChangeDetectorRefTokenKey) { |
| // directives on the same element as a component should be able to control the change detector |
| // of that component as well. |
| allowPrivateServices = !!(elDef && elDef.element.componentView); |
| } |
| if (elDef && (depDef.flags & 1 /* SkipSelf */)) { |
| allowPrivateServices = false; |
| elDef = elDef.parent; |
| } |
| var searchView = view; |
| while (searchView) { |
| if (elDef) { |
| switch (tokenKey) { |
| case RendererV1TokenKey: { |
| var compView = findCompView(searchView, elDef, allowPrivateServices); |
| return createRendererV1(compView); |
| } |
| case Renderer2TokenKey: { |
| var compView = findCompView(searchView, elDef, allowPrivateServices); |
| return compView.renderer; |
| } |
| case ElementRefTokenKey: |
| return new ElementRef(asElementData(searchView, elDef.nodeIndex).renderElement); |
| case ViewContainerRefTokenKey: |
| return asElementData(searchView, elDef.nodeIndex).viewContainer; |
| case TemplateRefTokenKey: { |
| if (elDef.element.template) { |
| return asElementData(searchView, elDef.nodeIndex).template; |
| } |
| break; |
| } |
| case ChangeDetectorRefTokenKey: { |
| var cdView = findCompView(searchView, elDef, allowPrivateServices); |
| return createChangeDetectorRef(cdView); |
| } |
| case InjectorRefTokenKey$1: |
| case INJECTORRefTokenKey$1: |
| return createInjector$1(searchView, elDef); |
| default: |
| var providerDef_1 = (allowPrivateServices ? elDef.element.allProviders : |
| elDef.element.publicProviders)[tokenKey]; |
| if (providerDef_1) { |
| var providerData = asProviderData(searchView, providerDef_1.nodeIndex); |
| if (!providerData) { |
| providerData = { instance: _createProviderInstance$1(searchView, providerDef_1) }; |
| searchView.nodes[providerDef_1.nodeIndex] = providerData; |
| } |
| return providerData.instance; |
| } |
| } |
| } |
| allowPrivateServices = isComponentView(searchView); |
| elDef = viewParentEl(searchView); |
| searchView = searchView.parent; |
| if (depDef.flags & 4 /* Self */) { |
| searchView = null; |
| } |
| } |
| var value = startView.root.injector.get(depDef.token, NOT_FOUND_CHECK_ONLY_ELEMENT_INJECTOR); |
| if (value !== NOT_FOUND_CHECK_ONLY_ELEMENT_INJECTOR || |
| notFoundValue === NOT_FOUND_CHECK_ONLY_ELEMENT_INJECTOR) { |
| // Return the value from the root element injector when |
| // - it provides it |
| // (value !== NOT_FOUND_CHECK_ONLY_ELEMENT_INJECTOR) |
| // - the module injector should not be checked |
| // (notFoundValue === NOT_FOUND_CHECK_ONLY_ELEMENT_INJECTOR) |
| return value; |
| } |
| return startView.root.ngModule.injector.get(depDef.token, notFoundValue); |
| } |
| function findCompView(view, elDef, allowPrivateServices) { |
| var compView; |
| if (allowPrivateServices) { |
| compView = asElementData(view, elDef.nodeIndex).componentView; |
| } |
| else { |
| compView = view; |
| while (compView.parent && !isComponentView(compView)) { |
| compView = compView.parent; |
| } |
| } |
| return compView; |
| } |
| function updateProp(view, providerData, def, bindingIdx, value, changes) { |
| if (def.flags & 32768 /* Component */) { |
| var compView = asElementData(view, def.parent.nodeIndex).componentView; |
| if (compView.def.flags & 2 /* OnPush */) { |
| compView.state |= 8 /* ChecksEnabled */; |
| } |
| } |
| var binding = def.bindings[bindingIdx]; |
| var propName = binding.name; |
| // Note: This is still safe with Closure Compiler as |
| // the user passed in the property name as an object has to `providerDef`, |
| // so Closure Compiler will have renamed the property correctly already. |
| providerData.instance[propName] = value; |
| if (def.flags & 524288 /* OnChanges */) { |
| changes = changes || {}; |
| var oldValue = WrappedValue.unwrap(view.oldValues[def.bindingIndex + bindingIdx]); |
| var binding_1 = def.bindings[bindingIdx]; |
| changes[binding_1.nonMinifiedName] = |
| new SimpleChange(oldValue, value, (view.state & 2 /* FirstCheck */) !== 0); |
| } |
| view.oldValues[def.bindingIndex + bindingIdx] = value; |
| return changes; |
| } |
| // This function calls the ngAfterContentCheck, ngAfterContentInit, |
| // ngAfterViewCheck, and ngAfterViewInit lifecycle hooks (depending on the node |
| // flags in lifecycle). Unlike ngDoCheck, ngOnChanges and ngOnInit, which are |
| // called during a pre-order traversal of the view tree (that is calling the |
| // parent hooks before the child hooks) these events are sent in using a |
| // post-order traversal of the tree (children before parents). This changes the |
| // meaning of initIndex in the view state. For ngOnInit, initIndex tracks the |
| // expected nodeIndex which a ngOnInit should be called. When sending |
| // ngAfterContentInit and ngAfterViewInit it is the expected count of |
| // ngAfterContentInit or ngAfterViewInit methods that have been called. This |
| // ensure that despite being called recursively or after picking up after an |
| // exception, the ngAfterContentInit or ngAfterViewInit will be called on the |
| // correct nodes. Consider for example, the following (where E is an element |
| // and D is a directive) |
| // Tree: pre-order index post-order index |
| // E1 0 6 |
| // E2 1 1 |
| // D3 2 0 |
| // E4 3 5 |
| // E5 4 4 |
| // E6 5 2 |
| // E7 6 3 |
| // As can be seen, the post-order index has an unclear relationship to the |
| // pre-order index (postOrderIndex === preOrderIndex - parentCount + |
| // childCount). Since number of calls to ngAfterContentInit and ngAfterViewInit |
| // are stable (will be the same for the same view regardless of exceptions or |
| // recursion) we just need to count them which will roughly correspond to the |
| // post-order index (it skips elements and directives that do not have |
| // lifecycle hooks). |
| // |
| // For example, if an exception is raised in the E6.onAfterViewInit() the |
| // initIndex is left at 3 (by shouldCallLifecycleInitHook() which set it to |
| // initIndex + 1). When checkAndUpdateView() is called again D3, E2 and E6 will |
| // not have their ngAfterViewInit() called but, starting with E7, the rest of |
| // the view will begin getting ngAfterViewInit() called until a check and |
| // pass is complete. |
| // |
| // This algorthim also handles recursion. Consider if E4's ngAfterViewInit() |
| // indirectly calls E1's ChangeDetectorRef.detectChanges(). The expected |
| // initIndex is set to 6, the recusive checkAndUpdateView() starts walk again. |
| // D3, E2, E6, E7, E5 and E4 are skipped, ngAfterViewInit() is called on E1. |
| // When the recursion returns the initIndex will be 7 so E1 is skipped as it |
| // has already been called in the recursively called checkAnUpdateView(). |
| function callLifecycleHooksChildrenFirst(view, lifecycles) { |
| if (!(view.def.nodeFlags & lifecycles)) { |
| return; |
| } |
| var nodes = view.def.nodes; |
| var initIndex = 0; |
| for (var i = 0; i < nodes.length; i++) { |
| var nodeDef = nodes[i]; |
| var parent_1 = nodeDef.parent; |
| if (!parent_1 && nodeDef.flags & lifecycles) { |
| // matching root node (e.g. a pipe) |
| callProviderLifecycles(view, i, nodeDef.flags & lifecycles, initIndex++); |
| } |
| if ((nodeDef.childFlags & lifecycles) === 0) { |
| // no child matches one of the lifecycles |
| i += nodeDef.childCount; |
| } |
| while (parent_1 && (parent_1.flags & 1 /* TypeElement */) && |
| i === parent_1.nodeIndex + parent_1.childCount) { |
| // last child of an element |
| if (parent_1.directChildFlags & lifecycles) { |
| initIndex = callElementProvidersLifecycles(view, parent_1, lifecycles, initIndex); |
| } |
| parent_1 = parent_1.parent; |
| } |
| } |
| } |
| function callElementProvidersLifecycles(view, elDef, lifecycles, initIndex) { |
| for (var i = elDef.nodeIndex + 1; i <= elDef.nodeIndex + elDef.childCount; i++) { |
| var nodeDef = view.def.nodes[i]; |
| if (nodeDef.flags & lifecycles) { |
| callProviderLifecycles(view, i, nodeDef.flags & lifecycles, initIndex++); |
| } |
| // only visit direct children |
| i += nodeDef.childCount; |
| } |
| return initIndex; |
| } |
| function callProviderLifecycles(view, index, lifecycles, initIndex) { |
| var providerData = asProviderData(view, index); |
| if (!providerData) { |
| return; |
| } |
| var provider = providerData.instance; |
| if (!provider) { |
| return; |
| } |
| Services.setCurrentNode(view, index); |
| if (lifecycles & 1048576 /* AfterContentInit */ && |
| shouldCallLifecycleInitHook(view, 512 /* InitState_CallingAfterContentInit */, initIndex)) { |
| provider.ngAfterContentInit(); |
| } |
| if (lifecycles & 2097152 /* AfterContentChecked */) { |
| provider.ngAfterContentChecked(); |
| } |
| if (lifecycles & 4194304 /* AfterViewInit */ && |
| shouldCallLifecycleInitHook(view, 768 /* InitState_CallingAfterViewInit */, initIndex)) { |
| provider.ngAfterViewInit(); |
| } |
| if (lifecycles & 8388608 /* AfterViewChecked */) { |
| provider.ngAfterViewChecked(); |
| } |
| if (lifecycles & 131072 /* OnDestroy */) { |
| provider.ngOnDestroy(); |
| } |
| } |
| |
| /** |
| * @license |
| * Copyright Google Inc. All Rights Reserved. |
| * |
| * Use of this source code is governed by an MIT-style license that can be |
| * found in the LICENSE file at https://angular.io/license |
| */ |
| var ComponentFactoryResolver$1 = /** @class */ (function (_super) { |
| __extends(ComponentFactoryResolver, _super); |
| /** |
| * @param ngModule The NgModuleRef to which all resolved factories are bound. |
| */ |
| function ComponentFactoryResolver(ngModule) { |
| var _this = _super.call(this) || this; |
| _this.ngModule = ngModule; |
| return _this; |
| } |
| ComponentFactoryResolver.prototype.resolveComponentFactory = function (component) { |
| ngDevMode && assertComponentType(component); |
| var componentDef = getComponentDef(component); |
| return new ComponentFactory$1(componentDef, this.ngModule); |
| }; |
| return ComponentFactoryResolver; |
| }(ComponentFactoryResolver)); |
| function toRefArray(map) { |
| var array = []; |
| for (var nonMinified in map) { |
| if (map.hasOwnProperty(nonMinified)) { |
| var minified = map[nonMinified]; |
| array.push({ propName: minified, templateName: nonMinified }); |
| } |
| } |
| return array; |
| } |
| /** |
| * Default {@link RootContext} for all components rendered with {@link renderComponent}. |
| */ |
| var ROOT_CONTEXT = new InjectionToken('ROOT_CONTEXT_TOKEN', { providedIn: 'root', factory: function () { return createRootContext(ɵɵinject(SCHEDULER)); } }); |
| /** |
| * A change detection scheduler token for {@link RootContext}. This token is the default value used |
| * for the default `RootContext` found in the {@link ROOT_CONTEXT} token. |
| */ |
| var SCHEDULER = new InjectionToken('SCHEDULER_TOKEN', { |
| providedIn: 'root', |
| factory: function () { return defaultScheduler; }, |
| }); |
| function createChainedInjector(rootViewInjector, moduleInjector) { |
| return { |
| get: function (token, notFoundValue, flags) { |
| var value = rootViewInjector.get(token, NOT_FOUND_CHECK_ONLY_ELEMENT_INJECTOR, flags); |
| if (value !== NOT_FOUND_CHECK_ONLY_ELEMENT_INJECTOR || |
| notFoundValue === NOT_FOUND_CHECK_ONLY_ELEMENT_INJECTOR) { |
| // Return the value from the root element injector when |
| // - it provides it |
| // (value !== NOT_FOUND_CHECK_ONLY_ELEMENT_INJECTOR) |
| // - the module injector should not be checked |
| // (notFoundValue === NOT_FOUND_CHECK_ONLY_ELEMENT_INJECTOR) |
| return value; |
| } |
| return moduleInjector.get(token, notFoundValue, flags); |
| } |
| }; |
| } |
| /** |
| * Render3 implementation of {@link viewEngine_ComponentFactory}. |
| */ |
| var ComponentFactory$1 = /** @class */ (function (_super) { |
| __extends(ComponentFactory, _super); |
| /** |
| * @param componentDef The component definition. |
| * @param ngModule The NgModuleRef to which the factory is bound. |
| */ |
| function ComponentFactory(componentDef, ngModule) { |
| var _this = _super.call(this) || this; |
| _this.componentDef = componentDef; |
| _this.ngModule = ngModule; |
| _this.componentType = componentDef.type; |
| _this.selector = componentDef.selectors[0][0]; |
| _this.ngContentSelectors = |
| componentDef.ngContentSelectors ? componentDef.ngContentSelectors : []; |
| _this.isBoundToModule = !!ngModule; |
| return _this; |
| } |
| Object.defineProperty(ComponentFactory.prototype, "inputs", { |
| get: function () { |
| return toRefArray(this.componentDef.inputs); |
| }, |
| enumerable: true, |
| configurable: true |
| }); |
| Object.defineProperty(ComponentFactory.prototype, "outputs", { |
| get: function () { |
| return toRefArray(this.componentDef.outputs); |
| }, |
| enumerable: true, |
| configurable: true |
| }); |
| ComponentFactory.prototype.create = function (injector, projectableNodes, rootSelectorOrNode, ngModule) { |
| var isInternalRootView = rootSelectorOrNode === undefined; |
| ngModule = ngModule || this.ngModule; |
| var rootViewInjector = ngModule ? createChainedInjector(injector, ngModule.injector) : injector; |
| var rendererFactory = rootViewInjector.get(RendererFactory2, domRendererFactory3); |
| var sanitizer = rootViewInjector.get(Sanitizer, null); |
| var hostRNode = isInternalRootView ? |
| elementCreate(this.selector, rendererFactory.createRenderer(null, this.componentDef)) : |
| locateHostElement(rendererFactory, rootSelectorOrNode); |
| var rootFlags = this.componentDef.onPush ? 64 /* Dirty */ | 512 /* IsRoot */ : |
| 16 /* CheckAlways */ | 512 /* IsRoot */; |
| // Check whether this Component needs to be isolated from other components, i.e. whether it |
| // should be placed into its own (empty) root context or existing root context should be used. |
| // Note: this is internal-only convention and might change in the future, so it should not be |
| // relied upon externally. |
| var isIsolated = typeof rootSelectorOrNode === 'string' && |
| /^#root-ng-internal-isolated-\d+/.test(rootSelectorOrNode); |
| var rootContext = (isInternalRootView || isIsolated) ? |
| createRootContext() : |
| rootViewInjector.get(ROOT_CONTEXT); |
| var renderer = rendererFactory.createRenderer(hostRNode, this.componentDef); |
| if (rootSelectorOrNode && hostRNode) { |
| ngDevMode && ngDevMode.rendererSetAttribute++; |
| isProceduralRenderer(renderer) ? |
| renderer.setAttribute(hostRNode, 'ng-version', VERSION.full) : |
| hostRNode.setAttribute('ng-version', VERSION.full); |
| } |
| // Create the root view. Uses empty TView and ContentTemplate. |
| var rootLView = createLView(null, createTView(-1, null, 1, 0, null, null, null, null), rootContext, rootFlags, null, null, rendererFactory, renderer, sanitizer, rootViewInjector); |
| // rootView is the parent when bootstrapping |
| var oldLView = enterView(rootLView, null); |
| var component; |
| var tElementNode; |
| // Will become true if the `try` block executes with no errors. |
| var safeToRunHooks = false; |
| try { |
| var componentView = createRootComponentView(hostRNode, this.componentDef, rootLView, rendererFactory, renderer); |
| tElementNode = getTNode(0, rootLView); |
| if (projectableNodes) { |
| // projectable nodes can be passed as array of arrays or an array of iterables (ngUpgrade |
| // case). Here we do normalize passed data structure to be an array of arrays to avoid |
| // complex checks down the line. |
| tElementNode.projection = |
| projectableNodes.map(function (nodesforSlot) { return Array.from(nodesforSlot); }); |
| } |
| // TODO: should LifecycleHooksFeature and other host features be generated by the compiler and |
| // executed here? |
| // Angular 5 reference: https://stackblitz.com/edit/lifecycle-hooks-vcref |
| component = createRootComponent(componentView, this.componentDef, rootLView, rootContext, [LifecycleHooksFeature]); |
| addToViewTree(rootLView, componentView); |
| refreshDescendantViews(rootLView); |
| safeToRunHooks = true; |
| } |
| finally { |
| leaveView(oldLView, safeToRunHooks); |
| } |
| var componentRef = new ComponentRef$1(this.componentType, component, createElementRef(ElementRef, tElementNode, rootLView), rootLView, tElementNode); |
| if (isInternalRootView) { |
| // The host element of the internal root view is attached to the component's host view node |
| componentRef.hostView._tViewNode.child = tElementNode; |
| } |
| return componentRef; |
| }; |
| return ComponentFactory; |
| }(ComponentFactory)); |
| var componentFactoryResolver = new ComponentFactoryResolver$1(); |
| /** |
| * Represents an instance of a Component created via a {@link ComponentFactory}. |
| * |
| * `ComponentRef` provides access to the Component Instance as well other objects related to this |
| * Component Instance and allows you to destroy the Component Instance via the {@link #destroy} |
| * method. |
| * |
| */ |
| var ComponentRef$1 = /** @class */ (function (_super) { |
| __extends(ComponentRef, _super); |
| function ComponentRef(componentType, instance, location, _rootLView, _tNode) { |
| var _this = _super.call(this) || this; |
| _this.location = location; |
| _this._rootLView = _rootLView; |
| _this._tNode = _tNode; |
| _this.destroyCbs = []; |
| _this.instance = instance; |
| _this.hostView = _this.changeDetectorRef = new RootViewRef(_rootLView); |
| _this.hostView._tViewNode = assignTViewNodeToLView(_rootLView[TVIEW], null, -1, _rootLView); |
| _this.componentType = componentType; |
| return _this; |
| } |
| Object.defineProperty(ComponentRef.prototype, "injector", { |
| get: function () { return new NodeInjector(this._tNode, this._rootLView); }, |
| enumerable: true, |
| configurable: true |
| }); |
| ComponentRef.prototype.destroy = function () { |
| if (this.destroyCbs) { |
| this.destroyCbs.forEach(function (fn) { return fn(); }); |
| this.destroyCbs = null; |
| !this.hostView.destroyed && this.hostView.destroy(); |
| } |
| }; |
| ComponentRef.prototype.onDestroy = function (callback) { |
| if (this.destroyCbs) { |
| this.destroyCbs.push(callback); |
| } |
| }; |
| return ComponentRef; |
| }(ComponentRef)); |
| |
| /** |
| * @license |
| * Copyright Google Inc. All Rights Reserved. |
| * |
| * Use of this source code is governed by an MIT-style license that can be |
| * found in the LICENSE file at https://angular.io/license |
| */ |
| /** |
| * NOTE: changes to the `ngI18nClosureMode` name must be synced with `compiler-cli/src/tooling.ts`. |
| */ |
| if (typeof ngI18nClosureMode === 'undefined') { |
| // These property accesses can be ignored because ngI18nClosureMode will be set to false |
| // when optimizing code and the whole if statement will be dropped. |
| // Make sure to refer to ngI18nClosureMode as ['ngI18nClosureMode'] for closure. |
| // NOTE: we need to have it in IIFE so that the tree-shaker is happy. |
| (function () { |
| // tslint:disable-next-line:no-toplevel-property-access |
| _global['ngI18nClosureMode'] = |
| // TODO(FW-1250): validate that this actually, you know, works. |
| // tslint:disable-next-line:no-toplevel-property-access |
| typeof goog !== 'undefined' && typeof goog.getMsg === 'function'; |
| })(); |
| } |
| |
| /** |
| * @license |
| * Copyright Google Inc. All Rights Reserved. |
| * |
| * Use of this source code is governed by an MIT-style license that can be |
| * found in the LICENSE file at https://angular.io/license |
| */ |
| /** |
| * This const is used to store the locale data registered with `registerLocaleData` |
| */ |
| var LOCALE_DATA = {}; |
| (function (LocaleDataIndex) { |
| LocaleDataIndex[LocaleDataIndex["LocaleId"] = 0] = "LocaleId"; |
| LocaleDataIndex[LocaleDataIndex["DayPeriodsFormat"] = 1] = "DayPeriodsFormat"; |
| LocaleDataIndex[LocaleDataIndex["DayPeriodsStandalone"] = 2] = "DayPeriodsStandalone"; |
| LocaleDataIndex[LocaleDataIndex["DaysFormat"] = 3] = "DaysFormat"; |
| LocaleDataIndex[LocaleDataIndex["DaysStandalone"] = 4] = "DaysStandalone"; |
| LocaleDataIndex[LocaleDataIndex["MonthsFormat"] = 5] = "MonthsFormat"; |
| LocaleDataIndex[LocaleDataIndex["MonthsStandalone"] = 6] = "MonthsStandalone"; |
| LocaleDataIndex[LocaleDataIndex["Eras"] = 7] = "Eras"; |
| LocaleDataIndex[LocaleDataIndex["FirstDayOfWeek"] = 8] = "FirstDayOfWeek"; |
| LocaleDataIndex[LocaleDataIndex["WeekendRange"] = 9] = "WeekendRange"; |
| LocaleDataIndex[LocaleDataIndex["DateFormat"] = 10] = "DateFormat"; |
| LocaleDataIndex[LocaleDataIndex["TimeFormat"] = 11] = "TimeFormat"; |
| LocaleDataIndex[LocaleDataIndex["DateTimeFormat"] = 12] = "DateTimeFormat"; |
| LocaleDataIndex[LocaleDataIndex["NumberSymbols"] = 13] = "NumberSymbols"; |
| LocaleDataIndex[LocaleDataIndex["NumberFormats"] = 14] = "NumberFormats"; |
| LocaleDataIndex[LocaleDataIndex["CurrencySymbol"] = 15] = "CurrencySymbol"; |
| LocaleDataIndex[LocaleDataIndex["CurrencyName"] = 16] = "CurrencyName"; |
| LocaleDataIndex[LocaleDataIndex["Currencies"] = 17] = "Currencies"; |
| LocaleDataIndex[LocaleDataIndex["PluralCase"] = 18] = "PluralCase"; |
| LocaleDataIndex[LocaleDataIndex["ExtraData"] = 19] = "ExtraData"; |
| })(exports.ɵLocaleDataIndex || (exports.ɵLocaleDataIndex = {})); |
| |
| /** |
| * @license |
| * Copyright Google Inc. All Rights Reserved. |
| * |
| * Use of this source code is governed by an MIT-style license that can be |
| * found in the LICENSE file at https://angular.io/license |
| */ |
| // THIS CODE IS GENERATED - DO NOT MODIFY |
| // See angular/tools/gulp-tasks/cldr/extract.js |
| var u = undefined; |
| function plural(n) { |
| var i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; |
| if (i === 1 && v === 0) |
| return 1; |
| return 5; |
| } |
| var localeEn = [ |
| 'en', [['a', 'p'], ['AM', 'PM'], u], [['AM', 'PM'], u, u], |
| [ |
| ['S', 'M', 'T', 'W', 'T', 'F', 'S'], ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'], |
| ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'], |
| ['Su', 'Mo', 'Tu', 'We', 'Th', 'Fr', 'Sa'] |
| ], |
| u, |
| [ |
| ['J', 'F', 'M', 'A', 'M', 'J', 'J', 'A', 'S', 'O', 'N', 'D'], |
| ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'], |
| [ |
| 'January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', |
| 'October', 'November', 'December' |
| ] |
| ], |
| u, [['B', 'A'], ['BC', 'AD'], ['Before Christ', 'Anno Domini']], 0, [6, 0], |
| ['M/d/yy', 'MMM d, y', 'MMMM d, y', 'EEEE, MMMM d, y'], |
| ['h:mm a', 'h:mm:ss a', 'h:mm:ss a z', 'h:mm:ss a zzzz'], ['{1}, {0}', u, '{1} \'at\' {0}', u], |
| ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], |
| ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], '$', 'US Dollar', {}, plural |
| ]; |
| |
| /** |
| * @license |
| * Copyright Google Inc. All Rights Reserved. |
| * |
| * Use of this source code is governed by an MIT-style license that can be |
| * found in the LICENSE file at https://angular.io/license |
| */ |
| /** |
| * Retrieves the plural function used by ICU expressions to determine the plural case to use |
| * for a given locale. |
| * @param locale A locale code for the locale format rules to use. |
| * @returns The plural function for the locale. |
| * @see `NgPlural` |
| * @see [Internationalization (i18n) Guide](https://angular.io/guide/i18n) |
| */ |
| function getLocalePluralCase(locale) { |
| var data = findLocaleData(locale); |
| return data[exports.ɵLocaleDataIndex.PluralCase]; |
| } |
| /** |
| * Finds the locale data for a given locale. |
| * |
| * @param locale The locale code. |
| * @returns The locale data. |
| * @see [Internationalization (i18n) Guide](https://angular.io/guide/i18n) |
| */ |
| function findLocaleData(locale) { |
| var normalizedLocale = locale.toLowerCase().replace(/_/g, '-'); |
| var match = LOCALE_DATA[normalizedLocale]; |
| if (match) { |
| return match; |
| } |
| // let's try to find a parent locale |
| var parentLocale = normalizedLocale.split('-')[0]; |
| match = LOCALE_DATA[parentLocale]; |
| if (match) { |
| return match; |
| } |
| if (parentLocale === 'en') { |
| return localeEn; |
| } |
| throw new Error("Missing locale data for the locale \"" + locale + "\"."); |
| } |
| |
| /** |
| * @license |
| * Copyright Google Inc. All Rights Reserved. |
| * |
| * Use of this source code is governed by an MIT-style license that can be |
| * found in the LICENSE file at https://angular.io/license |
| */ |
| /** |
| * Returns the plural case based on the locale |
| */ |
| function getPluralCase(value, locale) { |
| var plural = getLocalePluralCase(locale)(value); |
| switch (plural) { |
| case 0: |
| return 'zero'; |
| case 1: |
| return 'one'; |
| case 2: |
| return 'two'; |
| case 3: |
| return 'few'; |
| case 4: |
| return 'many'; |
| default: |
| return 'other'; |
| } |
| } |
| |
| /** |
| * @license |
| * Copyright Google Inc. All Rights Reserved. |
| * |
| * Use of this source code is governed by an MIT-style license that can be |
| * found in the LICENSE file at https://angular.io/license |
| */ |
| /** |
| * Equivalent to ES6 spread, add each item to an array. |
| * |
| * @param items The items to add |
| * @param arr The array to which you want to add the items |
| */ |
| function addAllToArray(items, arr) { |
| for (var i = 0; i < items.length; i++) { |
| arr.push(items[i]); |
| } |
| } |
| /** |
| * Flattens an array. |
| */ |
| function flatten(list, dst) { |
| if (dst === undefined) |
| dst = list; |
| for (var i = 0; i < list.length; i++) { |
| var item = list[i]; |
| if (Array.isArray(item)) { |
| // we need to inline it. |
| if (dst === list) { |
| // Our assumption that the list was already flat was wrong and |
| // we need to clone flat since we need to write to it. |
| dst = list.slice(0, i); |
| } |
| flatten(item, dst); |
| } |
| else if (dst !== list) { |
| dst.push(item); |
| } |
| } |
| return dst; |
| } |
| |
| /** |
| * @license |
| * Copyright Google Inc. All Rights Reserved. |
| * |
| * Use of this source code is governed by an MIT-style license that can be |
| * found in the LICENSE file at https://angular.io/license |
| */ |
| var MARKER = "\uFFFD"; |
| var ICU_BLOCK_REGEXP = /^\s*(�\d+:?\d*�)\s*,\s*(select|plural)\s*,/; |
| var SUBTEMPLATE_REGEXP = /�\/?\*(\d+:\d+)�/gi; |
| var PH_REGEXP = /�(\/?[#*!]\d+):?\d*�/gi; |
| var BINDING_REGEXP = /�(\d+):?\d*�/gi; |
| var ICU_REGEXP = /({\s*�\d+:?\d*�\s*,\s*\S{6}\s*,[\s\S]*})/gi; |
| // i18nPostprocess consts |
| var ROOT_TEMPLATE_ID = 0; |
| var PP_MULTI_VALUE_PLACEHOLDERS_REGEXP = /\[(�.+?�?)\]/; |
| var PP_PLACEHOLDERS_REGEXP = /\[(�.+?�?)\]|(�\/?\*\d+:\d+�)/g; |
| var PP_ICU_VARS_REGEXP = /({\s*)(VAR_(PLURAL|SELECT)(_\d+)?)(\s*,)/g; |
| var PP_ICUS_REGEXP = /�I18N_EXP_(ICU(_\d+)?)�/g; |
| var PP_CLOSE_TEMPLATE_REGEXP = /\/\*/; |
| var PP_TEMPLATE_ID_REGEXP = /\d+\:(\d+)/; |
| /** |
| * Breaks pattern into strings and top level {...} blocks. |
| * Can be used to break a message into text and ICU expressions, or to break an ICU expression into |
| * keys and cases. |
| * Original code from closure library, modified for Angular. |
| * |
| * @param pattern (sub)Pattern to be broken. |
| * |
| */ |
| function extractParts(pattern) { |
| if (!pattern) { |
| return []; |
| } |
| var prevPos = 0; |
| var braceStack = []; |
| var results = []; |
| var braces = /[{}]/g; |
| // lastIndex doesn't get set to 0 so we have to. |
| braces.lastIndex = 0; |
| var match; |
| while (match = braces.exec(pattern)) { |
| var pos = match.index; |
| if (match[0] == '}') { |
| braceStack.pop(); |
| if (braceStack.length == 0) { |
| // End of the block. |
| var block = pattern.substring(prevPos, pos); |
| if (ICU_BLOCK_REGEXP.test(block)) { |
| results.push(parseICUBlock(block)); |
| } |
| else { |
| results.push(block); |
| } |
| prevPos = pos + 1; |
| } |
| } |
| else { |
| if (braceStack.length == 0) { |
| var substring_1 = pattern.substring(prevPos, pos); |
| results.push(substring_1); |
| prevPos = pos + 1; |
| } |
| braceStack.push('{'); |
| } |
| } |
| var substring = pattern.substring(prevPos); |
| results.push(substring); |
| return results; |
| } |
| /** |
| * Parses text containing an ICU expression and produces a JSON object for it. |
| * Original code from closure library, modified for Angular. |
| * |
| * @param pattern Text containing an ICU expression that needs to be parsed. |
| * |
| */ |
| function parseICUBlock(pattern) { |
| var cases = []; |
| var values = []; |
| var icuType = 1 /* plural */; |
| var mainBinding = 0; |
| pattern = pattern.replace(ICU_BLOCK_REGEXP, function (str, binding, type) { |
| if (type === 'select') { |
| icuType = 0 /* select */; |
| } |
| else { |
| icuType = 1 /* plural */; |
| } |
| mainBinding = parseInt(binding.substr(1), 10); |
| return ''; |
| }); |
| var parts = extractParts(pattern); |
| // Looking for (key block)+ sequence. One of the keys has to be "other". |
| for (var pos = 0; pos < parts.length;) { |
| var key = parts[pos++].trim(); |
| if (icuType === 1 /* plural */) { |
| // Key can be "=x", we just want "x" |
| key = key.replace(/\s*(?:=)?(\w+)\s*/, '$1'); |
| } |
| if (key.length) { |
| cases.push(key); |
| } |
| var blocks = extractParts(parts[pos++]); |
| if (cases.length > values.length) { |
| values.push(blocks); |
| } |
| } |
| assertGreaterThan(cases.indexOf('other'), -1, 'Missing key "other" in ICU statement.'); |
| // TODO(ocombe): support ICU expressions in attributes, see #21615 |
| return { type: icuType, mainBinding: mainBinding, cases: cases, values: values }; |
| } |
| /** |
| * Removes everything inside the sub-templates of a message. |
| */ |
| function removeInnerTemplateTranslation(message) { |
| var match; |
| var res = ''; |
| var index = 0; |
| var inTemplate = false; |
| var tagMatched; |
| while ((match = SUBTEMPLATE_REGEXP.exec(message)) !== null) { |
| if (!inTemplate) { |
| res += message.substring(index, match.index + match[0].length); |
| tagMatched = match[1]; |
| inTemplate = true; |
| } |
| else { |
| if (match[0] === MARKER + "/*" + tagMatched + MARKER) { |
| index = match.index; |
| inTemplate = false; |
| } |
| } |
| } |
| ngDevMode && |
| assertEqual(inTemplate, false, "Tag mismatch: unable to find the end of the sub-template in the translation \"" + message + "\""); |
| res += message.substr(index); |
| return res; |
| } |
| /** |
| * Extracts a part of a message and removes the rest. |
| * |
| * This method is used for extracting a part of the message associated with a template. A translated |
| * message can span multiple templates. |
| * |
| * Example: |
| * ``` |
| * <div i18n>Translate <span *ngIf>me</span>!</div> |
| * ``` |
| * |
| * @param message The message to crop |
| * @param subTemplateIndex Index of the sub-template to extract. If undefined it returns the |
| * external template and removes all sub-templates. |
| */ |
| function getTranslationForTemplate(message, subTemplateIndex) { |
| if (typeof subTemplateIndex !== 'number') { |
| // We want the root template message, ignore all sub-templates |
| return removeInnerTemplateTranslation(message); |
| } |
| else { |
| // We want a specific sub-template |
| var start = message.indexOf(":" + subTemplateIndex + MARKER) + 2 + subTemplateIndex.toString().length; |
| var end = message.search(new RegExp(MARKER + "\\/\\*\\d+:" + subTemplateIndex + MARKER)); |
| return removeInnerTemplateTranslation(message.substring(start, end)); |
| } |
| } |
| /** |
| * Generate the OpCodes to update the bindings of a string. |
| * |
| * @param str The string containing the bindings. |
| * @param destinationNode Index of the destination node which will receive the binding. |
| * @param attrName Name of the attribute, if the string belongs to an attribute. |
| * @param sanitizeFn Sanitization function used to sanitize the string after update, if necessary. |
| */ |
| function generateBindingUpdateOpCodes(str, destinationNode, attrName, sanitizeFn) { |
| if (sanitizeFn === void 0) { sanitizeFn = null; } |
| var updateOpCodes = [null, null]; // Alloc space for mask and size |
| var textParts = str.split(BINDING_REGEXP); |
| var mask = 0; |
| for (var j = 0; j < textParts.length; j++) { |
| var textValue = textParts[j]; |
| if (j & 1) { |
| // Odd indexes are bindings |
| var bindingIndex = parseInt(textValue, 10); |
| updateOpCodes.push(-1 - bindingIndex); |
| mask = mask | toMaskBit(bindingIndex); |
| } |
| else if (textValue !== '') { |
| // Even indexes are text |
| updateOpCodes.push(textValue); |
| } |
| } |
| updateOpCodes.push(destinationNode << 2 /* SHIFT_REF */ | |
| (attrName ? 1 /* Attr */ : 0 /* Text */)); |
| if (attrName) { |
| updateOpCodes.push(attrName, sanitizeFn); |
| } |
| updateOpCodes[0] = mask; |
| updateOpCodes[1] = updateOpCodes.length - 2; |
| return updateOpCodes; |
| } |
| function getBindingMask(icuExpression, mask) { |
| if (mask === void 0) { mask = 0; } |
| mask = mask | toMaskBit(icuExpression.mainBinding); |
| var match; |
| for (var i = 0; i < icuExpression.values.length; i++) { |
| var valueArr = icuExpression.values[i]; |
| for (var j = 0; j < valueArr.length; j++) { |
| var value = valueArr[j]; |
| if (typeof value === 'string') { |
| while (match = BINDING_REGEXP.exec(value)) { |
| mask = mask | toMaskBit(parseInt(match[1], 10)); |
| } |
| } |
| else { |
| mask = getBindingMask(value, mask); |
| } |
| } |
| } |
| return mask; |
| } |
| var i18nIndexStack = []; |
| var i18nIndexStackPointer = -1; |
| /** |
| * Convert binding index to mask bit. |
| * |
| * Each index represents a single bit on the bit-mask. Because bit-mask only has 32 bits, we make |
| * the 32nd bit share all masks for all bindings higher than 32. Since it is extremely rare to have |
| * more than 32 bindings this will be hit very rarely. The downside of hitting this corner case is |
| * that we will execute binding code more often than necessary. (penalty of performance) |
| */ |
| function toMaskBit(bindingIndex) { |
| return 1 << Math.min(bindingIndex, 31); |
| } |
| var parentIndexStack = []; |
| /** |
| * Marks a block of text as translatable. |
| * |
| * The instructions `i18nStart` and `i18nEnd` mark the translation block in the template. |
| * The translation `message` is the value which is locale specific. The translation string may |
| * contain placeholders which associate inner elements and sub-templates within the translation. |
| * |
| * The translation `message` placeholders are: |
| * - `�{index}(:{block})�`: *Binding Placeholder*: Marks a location where an expression will be |
| * interpolated into. The placeholder `index` points to the expression binding index. An optional |
| * `block` that matches the sub-template in which it was declared. |
| * - `�#{index}(:{block})�`/`�/#{index}(:{block})�`: *Element Placeholder*: Marks the beginning |
| * and end of DOM element that were embedded in the original translation block. The placeholder |
| * `index` points to the element index in the template instructions set. An optional `block` that |
| * matches the sub-template in which it was declared. |
| * - `�!{index}(:{block})�`/`�/!{index}(:{block})�`: *Projection Placeholder*: Marks the |
| * beginning and end of <ng-content> that was embedded in the original translation block. |
| * The placeholder `index` points to the element index in the template instructions set. |
| * An optional `block` that matches the sub-template in which it was declared. |
| * - `�*{index}:{block}�`/`�/*{index}:{block}�`: *Sub-template Placeholder*: Sub-templates must be |
| * split up and translated separately in each angular template function. The `index` points to the |
| * `template` instruction index. A `block` that matches the sub-template in which it was declared. |
| * |
| * @param index A unique index of the translation in the static block. |
| * @param message The translation message. |
| * @param subTemplateIndex Optional sub-template index in the `message`. |
| * |
| * @codeGenApi |
| */ |
| function ɵɵi18nStart(index, message, subTemplateIndex) { |
| var tView = getLView()[TVIEW]; |
| ngDevMode && assertDefined(tView, "tView should be defined"); |
| i18nIndexStack[++i18nIndexStackPointer] = index; |
| // We need to delay projections until `i18nEnd` |
| setDelayProjection(true); |
| if (tView.firstTemplatePass && tView.data[index + HEADER_OFFSET] === null) { |
| i18nStartFirstPass(tView, index, message, subTemplateIndex); |
| } |
| } |
| // Count for the number of vars that will be allocated for each i18n block. |
| // It is global because this is used in multiple functions that include loops and recursive calls. |
| // This is reset to 0 when `i18nStartFirstPass` is called. |
| var i18nVarsCount; |
| /** |
| * See `i18nStart` above. |
| */ |
| function i18nStartFirstPass(tView, index, message, subTemplateIndex) { |
| var viewData = getLView(); |
| var startIndex = tView.blueprint.length - HEADER_OFFSET; |
| i18nVarsCount = 0; |
| var previousOrParentTNode = getPreviousOrParentTNode(); |
| var parentTNode = getIsParent() ? getPreviousOrParentTNode() : |
| previousOrParentTNode && previousOrParentTNode.parent; |
| var parentIndex = parentTNode && parentTNode !== viewData[T_HOST] ? parentTNode.index - HEADER_OFFSET : index; |
| var parentIndexPointer = 0; |
| parentIndexStack[parentIndexPointer] = parentIndex; |
| var createOpCodes = []; |
| // If the previous node wasn't the direct parent then we have a translation without top level |
| // element and we need to keep a reference of the previous element if there is one |
| if (index > 0 && previousOrParentTNode !== parentTNode) { |
| // Create an OpCode to select the previous TNode |
| createOpCodes.push(previousOrParentTNode.index << 3 /* SHIFT_REF */ | 0 /* Select */); |
| } |
| var updateOpCodes = []; |
| var icuExpressions = []; |
| var templateTranslation = getTranslationForTemplate(message, subTemplateIndex); |
| var msgParts = templateTranslation.split(PH_REGEXP); |
| for (var i = 0; i < msgParts.length; i++) { |
| var value = msgParts[i]; |
| if (i & 1) { |
| // Odd indexes are placeholders (elements and sub-templates) |
| if (value.charAt(0) === '/') { |
| // It is a closing tag |
| if (value.charAt(1) === "#" /* ELEMENT */) { |
| var phIndex = parseInt(value.substr(2), 10); |
| parentIndex = parentIndexStack[--parentIndexPointer]; |
| createOpCodes.push(phIndex << 3 /* SHIFT_REF */ | 5 /* ElementEnd */); |
| } |
| } |
| else { |
| var phIndex = parseInt(value.substr(1), 10); |
| // The value represents a placeholder that we move to the designated index |
| createOpCodes.push(phIndex << 3 /* SHIFT_REF */ | 0 /* Select */, parentIndex << 17 /* SHIFT_PARENT */ | 1 /* AppendChild */); |
| if (value.charAt(0) === "#" /* ELEMENT */) { |
| parentIndexStack[++parentIndexPointer] = parentIndex = phIndex; |
| } |
| } |
| } |
| else { |
| // Even indexes are text (including bindings & ICU expressions) |
| var parts = extractParts(value); |
| for (var j = 0; j < parts.length; j++) { |
| if (j & 1) { |
| // Odd indexes are ICU expressions |
| // Create the comment node that will anchor the ICU expression |
| var icuNodeIndex = startIndex + i18nVarsCount++; |
| createOpCodes.push(COMMENT_MARKER, ngDevMode ? "ICU " + icuNodeIndex : '', icuNodeIndex, parentIndex << 17 /* SHIFT_PARENT */ | 1 /* AppendChild */); |
| // Update codes for the ICU expression |
| var icuExpression = parts[j]; |
| var mask = getBindingMask(icuExpression); |
| icuStart(icuExpressions, icuExpression, icuNodeIndex, icuNodeIndex); |
| // Since this is recursive, the last TIcu that was pushed is the one we want |
| var tIcuIndex = icuExpressions.length - 1; |
| updateOpCodes.push(toMaskBit(icuExpression.mainBinding), // mask of the main binding |
| 3, // skip 3 opCodes if not changed |
| -1 - icuExpression.mainBinding, icuNodeIndex << 2 /* SHIFT_REF */ | 2 /* IcuSwitch */, tIcuIndex, mask, // mask of all the bindings of this ICU expression |
| 2, // skip 2 opCodes if not changed |
| icuNodeIndex << 2 /* SHIFT_REF */ | 3 /* IcuUpdate */, tIcuIndex); |
| } |
| else if (parts[j] !== '') { |
| var text = parts[j]; |
| // Even indexes are text (including bindings) |
| var hasBinding = text.match(BINDING_REGEXP); |
| // Create text nodes |
| var textNodeIndex = startIndex + i18nVarsCount++; |
| createOpCodes.push( |
| // If there is a binding, the value will be set during update |
| hasBinding ? '' : text, textNodeIndex, parentIndex << 17 /* SHIFT_PARENT */ | 1 /* AppendChild */); |
| if (hasBinding) { |
| addAllToArray(generateBindingUpdateOpCodes(text, textNodeIndex), updateOpCodes); |
| } |
| } |
| } |
| } |
| } |
| allocExpando(viewData, i18nVarsCount); |
| ngDevMode && |
| attachI18nOpCodesDebug(createOpCodes, updateOpCodes, icuExpressions.length ? icuExpressions : null, viewData); |
| // NOTE: local var needed to properly assert the type of `TI18n`. |
| var tI18n = { |
| vars: i18nVarsCount, |
| create: createOpCodes, |
| update: updateOpCodes, |
| icus: icuExpressions.length ? icuExpressions : null, |
| }; |
| tView.data[index + HEADER_OFFSET] = tI18n; |
| } |
| function appendI18nNode(tNode, parentTNode, previousTNode, viewData) { |
| ngDevMode && ngDevMode.rendererMoveNode++; |
| var nextNode = tNode.next; |
| if (!previousTNode) { |
| previousTNode = parentTNode; |
| } |
| // Re-organize node tree to put this node in the correct position. |
| if (previousTNode === parentTNode && tNode !== parentTNode.child) { |
| tNode.next = parentTNode.child; |
| parentTNode.child = tNode; |
| } |
| else if (previousTNode !== parentTNode && tNode !== previousTNode.next) { |
| tNode.next = previousTNode.next; |
| previousTNode.next = tNode; |
| } |
| else { |
| tNode.next = null; |
| } |
| if (parentTNode !== viewData[T_HOST]) { |
| tNode.parent = parentTNode; |
| } |
| // If tNode was moved around, we might need to fix a broken link. |
| var cursor = tNode.next; |
| while (cursor) { |
| if (cursor.next === tNode) { |
| cursor.next = nextNode; |
| } |
| cursor = cursor.next; |
| } |
| // If the placeholder to append is a projection, we need to move the projected nodes instead |
| if (tNode.type === 1 /* Projection */) { |
| var tProjectionNode = tNode; |
| appendProjectedNodes(viewData, tProjectionNode, tProjectionNode.projection, findComponentView(viewData)); |
| return tNode; |
| } |
| appendChild(getNativeByTNode(tNode, viewData), tNode, viewData); |
| var slotValue = viewData[tNode.index]; |
| if (tNode.type !== 0 /* Container */ && isLContainer(slotValue)) { |
| // Nodes that inject ViewContainerRef also have a comment node that should be moved |
| appendChild(slotValue[NATIVE], tNode, viewData); |
| } |
| return tNode; |
| } |
| /** |
| * Handles message string post-processing for internationalization. |
| * |
| * Handles message string post-processing by transforming it from intermediate |
| * format (that might contain some markers that we need to replace) to the final |
| * form, consumable by i18nStart instruction. Post processing steps include: |
| * |
| * 1. Resolve all multi-value cases (like [�*1:1��#2:1�|�#4:1�|�5�]) |
| * 2. Replace all ICU vars (like "VAR_PLURAL") |
| * 3. Replace all ICU references with corresponding values (like �ICU_EXP_ICU_1�) |
| * in case multiple ICUs have the same placeholder name |
| * |
| * @param message Raw translation string for post processing |
| * @param replacements Set of replacements that should be applied |
| * |
| * @returns Transformed string that can be consumed by i18nStart instruction |
| * |
| * @codeGenApi |
| */ |
| function ɵɵi18nPostprocess(message, replacements) { |
| if (replacements === void 0) { replacements = {}; } |
| /** |
| * Step 1: resolve all multi-value placeholders like [�#5�|�*1:1��#2:1�|�#4:1�] |
| * |
| * Note: due to the way we process nested templates (BFS), multi-value placeholders are typically |
| * grouped by templates, for example: [�#5�|�#6�|�#1:1�|�#3:2�] where �#5� and �#6� belong to root |
| * template, �#1:1� belong to nested template with index 1 and �#1:2� - nested template with index |
| * 3. However in real templates the order might be different: i.e. �#1:1� and/or �#3:2� may go in |
| * front of �#6�. The post processing step restores the right order by keeping track of the |
| * template id stack and looks for placeholders that belong to the currently active template. |
| */ |
| var result = message; |
| if (PP_MULTI_VALUE_PLACEHOLDERS_REGEXP.test(message)) { |
| var matches_1 = {}; |
| var templateIdsStack_1 = [ROOT_TEMPLATE_ID]; |
| result = result.replace(PP_PLACEHOLDERS_REGEXP, function (m, phs, tmpl) { |
| var content = phs || tmpl; |
| var placeholders = matches_1[content] || []; |
| if (!placeholders.length) { |
| content.split('|').forEach(function (placeholder) { |
| var match = placeholder.match(PP_TEMPLATE_ID_REGEXP); |
| var templateId = match ? parseInt(match[1], 10) : ROOT_TEMPLATE_ID; |
| var isCloseTemplateTag = PP_CLOSE_TEMPLATE_REGEXP.test(placeholder); |
| placeholders.push([templateId, isCloseTemplateTag, placeholder]); |
| }); |
| matches_1[content] = placeholders; |
| } |
| if (!placeholders.length) { |
| throw new Error("i18n postprocess: unmatched placeholder - " + content); |
| } |
| var currentTemplateId = templateIdsStack_1[templateIdsStack_1.length - 1]; |
| var idx = 0; |
| // find placeholder index that matches current template id |
| for (var i = 0; i < placeholders.length; i++) { |
| if (placeholders[i][0] === currentTemplateId) { |
| idx = i; |
| break; |
| } |
| } |
| // update template id stack based on the current tag extracted |
| var _a = __read(placeholders[idx], 3), templateId = _a[0], isCloseTemplateTag = _a[1], placeholder = _a[2]; |
| if (isCloseTemplateTag) { |
| templateIdsStack_1.pop(); |
| } |
| else if (currentTemplateId !== templateId) { |
| templateIdsStack_1.push(templateId); |
| } |
| // remove processed tag from the list |
| placeholders.splice(idx, 1); |
| return placeholder; |
| }); |
| } |
| // return current result if no replacements specified |
| if (!Object.keys(replacements).length) { |
| return result; |
| } |
| /** |
| * Step 2: replace all ICU vars (like "VAR_PLURAL") |
| */ |
| result = result.replace(PP_ICU_VARS_REGEXP, function (match, start, key, _type, _idx, end) { |
| return replacements.hasOwnProperty(key) ? "" + start + replacements[key] + end : match; |
| }); |
| /** |
| * Step 3: replace all ICU references with corresponding values (like �ICU_EXP_ICU_1�) in case |
| * multiple ICUs have the same placeholder name |
| */ |
| result = result.replace(PP_ICUS_REGEXP, function (match, key) { |
| if (replacements.hasOwnProperty(key)) { |
| var list = replacements[key]; |
| if (!list.length) { |
| throw new Error("i18n postprocess: unmatched ICU - " + match + " with key: " + key); |
| } |
| return list.shift(); |
| } |
| return match; |
| }); |
| return result; |
| } |
| /** |
| * Translates a translation block marked by `i18nStart` and `i18nEnd`. It inserts the text/ICU nodes |
| * into the render tree, moves the placeholder nodes and removes the deleted nodes. |
| * |
| * @codeGenApi |
| */ |
| function ɵɵi18nEnd() { |
| var tView = getLView()[TVIEW]; |
| ngDevMode && assertDefined(tView, "tView should be defined"); |
| i18nEndFirstPass(tView); |
| // Stop delaying projections |
| setDelayProjection(false); |
| } |
| /** |
| * See `i18nEnd` above. |
| */ |
| function i18nEndFirstPass(tView) { |
| var viewData = getLView(); |
| ngDevMode && assertEqual(viewData[BINDING_INDEX], viewData[TVIEW].bindingStartIndex, 'i18nEnd should be called before any binding'); |
| var rootIndex = i18nIndexStack[i18nIndexStackPointer--]; |
| var tI18n = tView.data[rootIndex + HEADER_OFFSET]; |
| ngDevMode && assertDefined(tI18n, "You should call i18nStart before i18nEnd"); |
| // Find the last node that was added before `i18nEnd` |
| var lastCreatedNode = getPreviousOrParentTNode(); |
| // Read the instructions to insert/move/remove DOM elements |
| var visitedNodes = readCreateOpCodes(rootIndex, tI18n.create, tI18n.icus, viewData); |
| // Remove deleted nodes |
| for (var i = rootIndex + 1; i <= lastCreatedNode.index - HEADER_OFFSET; i++) { |
| if (visitedNodes.indexOf(i) === -1) { |
| removeNode(i, viewData); |
| } |
| } |
| } |
| /** |
| * Creates and stores the dynamic TNode, and unhooks it from the tree for now. |
| */ |
| function createDynamicNodeAtIndex(lView, index, type, native, name) { |
| var previousOrParentTNode = getPreviousOrParentTNode(); |
| ngDevMode && assertDataInRange(lView, index + HEADER_OFFSET); |
| lView[index + HEADER_OFFSET] = native; |
| var tNode = getOrCreateTNode(lView[TVIEW], lView[T_HOST], index, type, name, null); |
| // We are creating a dynamic node, the previous tNode might not be pointing at this node. |
| // We will link ourselves into the tree later with `appendI18nNode`. |
| if (previousOrParentTNode.next === tNode) { |
| previousOrParentTNode.next = null; |
| } |
| return tNode; |
| } |
| function readCreateOpCodes(index, createOpCodes, icus, viewData) { |
| var renderer = getLView()[RENDERER]; |
| var currentTNode = null; |
| var previousTNode = null; |
| var visitedNodes = []; |
| for (var i = 0; i < createOpCodes.length; i++) { |
| var opCode = createOpCodes[i]; |
| if (typeof opCode == 'string') { |
| var textRNode = createTextNode(opCode, renderer); |
| var textNodeIndex = createOpCodes[++i]; |
| ngDevMode && ngDevMode.rendererCreateTextNode++; |
| previousTNode = currentTNode; |
| currentTNode = |
| createDynamicNodeAtIndex(viewData, textNodeIndex, 3 /* Element */, textRNode, null); |
| visitedNodes.push(textNodeIndex); |
| setIsNotParent(); |
| } |
| else if (typeof opCode == 'number') { |
| switch (opCode & 7 /* MASK_OPCODE */) { |
| case 1 /* AppendChild */: |
| var destinationNodeIndex = opCode >>> 17 /* SHIFT_PARENT */; |
| var destinationTNode = void 0; |
| if (destinationNodeIndex === index) { |
| // If the destination node is `i18nStart`, we don't have a |
| // top-level node and we should use the host node instead |
| destinationTNode = viewData[T_HOST]; |
| } |
| else { |
| destinationTNode = getTNode(destinationNodeIndex, viewData); |
| } |
| ngDevMode && |
| assertDefined(currentTNode, "You need to create or select a node before you can insert it into the DOM"); |
| previousTNode = appendI18nNode(currentTNode, destinationTNode, previousTNode, viewData); |
| break; |
| case 0 /* Select */: |
| var nodeIndex = opCode >>> 3 /* SHIFT_REF */; |
| visitedNodes.push(nodeIndex); |
| previousTNode = currentTNode; |
| currentTNode = getTNode(nodeIndex, viewData); |
| if (currentTNode) { |
| setPreviousOrParentTNode(currentTNode, currentTNode.type === 3 /* Element */); |
| } |
| break; |
| case 5 /* ElementEnd */: |
| var elementIndex = opCode >>> 3 /* SHIFT_REF */; |
| previousTNode = currentTNode = getTNode(elementIndex, viewData); |
| setPreviousOrParentTNode(currentTNode, false); |
| break; |
| case 4 /* Attr */: |
| var elementNodeIndex = opCode >>> 3 /* SHIFT_REF */; |
| var attrName = createOpCodes[++i]; |
| var attrValue = createOpCodes[++i]; |
| // This code is used for ICU expressions only, since we don't support |
| // directives/components in ICUs, we don't need to worry about inputs here |
| elementAttributeInternal(elementNodeIndex, attrName, attrValue, viewData); |
| break; |
| default: |
| throw new Error("Unable to determine the type of mutate operation for \"" + opCode + "\""); |
| } |
| } |
| else { |
| switch (opCode) { |
| case COMMENT_MARKER: |
| var commentValue = createOpCodes[++i]; |
| var commentNodeIndex = createOpCodes[++i]; |
| ngDevMode && assertEqual(typeof commentValue, 'string', "Expected \"" + commentValue + "\" to be a comment node value"); |
| var commentRNode = renderer.createComment(commentValue); |
| ngDevMode && ngDevMode.rendererCreateComment++; |
| previousTNode = currentTNode; |
| currentTNode = createDynamicNodeAtIndex(viewData, commentNodeIndex, 5 /* IcuContainer */, commentRNode, null); |
| visitedNodes.push(commentNodeIndex); |
| attachPatchData(commentRNode, viewData); |
| currentTNode.activeCaseIndex = null; |
| // We will add the case nodes later, during the update phase |
| setIsNotParent(); |
| break; |
| case ELEMENT_MARKER: |
| var tagNameValue = createOpCodes[++i]; |
| var elementNodeIndex = createOpCodes[++i]; |
| ngDevMode && assertEqual(typeof tagNameValue, 'string', "Expected \"" + tagNameValue + "\" to be an element node tag name"); |
| var elementRNode = renderer.createElement(tagNameValue); |
| ngDevMode && ngDevMode.rendererCreateElement++; |
| previousTNode = currentTNode; |
| currentTNode = createDynamicNodeAtIndex(viewData, elementNodeIndex, 3 /* Element */, elementRNode, tagNameValue); |
| visitedNodes.push(elementNodeIndex); |
| break; |
| default: |
| throw new Error("Unable to determine the type of mutate operation for \"" + opCode + "\""); |
| } |
| } |
| } |
| setIsNotParent(); |
| return visitedNodes; |
| } |
| function readUpdateOpCodes(updateOpCodes, icus, bindingsStartIndex, changeMask, viewData, bypassCheckBit) { |
| if (bypassCheckBit === void 0) { bypassCheckBit = false; } |
| var caseCreated = false; |
| for (var i = 0; i < updateOpCodes.length; i++) { |
| // bit code to check if we should apply the next update |
| var checkBit = updateOpCodes[i]; |
| // Number of opCodes to skip until next set of update codes |
| var skipCodes = updateOpCodes[++i]; |
| if (bypassCheckBit || (checkBit & changeMask)) { |
| // The value has been updated since last checked |
| var value = ''; |
| for (var j = i + 1; j <= (i + skipCodes); j++) { |
| var opCode = updateOpCodes[j]; |
| if (typeof opCode == 'string') { |
| value += opCode; |
| } |
| else if (typeof opCode == 'number') { |
| if (opCode < 0) { |
| // It's a binding index whose value is negative |
| value += renderStringify(viewData[bindingsStartIndex - opCode]); |
| } |
| else { |
| var nodeIndex = opCode >>> 2 /* SHIFT_REF */; |
| var tIcuIndex = void 0; |
| var tIcu = void 0; |
| var icuTNode = void 0; |
| switch (opCode & 3 /* MASK_OPCODE */) { |
| case 1 /* Attr */: |
| var propName = updateOpCodes[++j]; |
| var sanitizeFn = updateOpCodes[++j]; |
| elementPropertyInternal(nodeIndex, propName, value, sanitizeFn); |
| break; |
| case 0 /* Text */: |
| textBindingInternal(viewData, nodeIndex, value); |
| break; |
| case 2 /* IcuSwitch */: |
| tIcuIndex = updateOpCodes[++j]; |
| tIcu = icus[tIcuIndex]; |
| icuTNode = getTNode(nodeIndex, viewData); |
| // If there is an active case, delete the old nodes |
| if (icuTNode.activeCaseIndex !== null) { |
| var removeCodes = tIcu.remove[icuTNode.activeCaseIndex]; |
| for (var k = 0; k < removeCodes.length; k++) { |
| var removeOpCode = removeCodes[k]; |
| switch (removeOpCode & 7 /* MASK_OPCODE */) { |
| case 3 /* Remove */: |
| var nodeIndex_1 = removeOpCode >>> 3 /* SHIFT_REF */; |
| removeNode(nodeIndex_1, viewData); |
| break; |
| case 6 /* RemoveNestedIcu */: |
| var nestedIcuNodeIndex = removeCodes[k + 1] >>> 3 /* SHIFT_REF */; |
| var nestedIcuTNode = getTNode(nestedIcuNodeIndex, viewData); |
| var activeIndex = nestedIcuTNode.activeCaseIndex; |
| if (activeIndex !== null) { |
| var nestedIcuTIndex = removeOpCode >>> 3 /* SHIFT_REF */; |
| var nestedTIcu = icus[nestedIcuTIndex]; |
| addAllToArray(nestedTIcu.remove[activeIndex], removeCodes); |
| } |
| break; |
| } |
| } |
| } |
| // Update the active caseIndex |
| var caseIndex = getCaseIndex(tIcu, value); |
| icuTNode.activeCaseIndex = caseIndex !== -1 ? caseIndex : null; |
| // Add the nodes for the new case |
| readCreateOpCodes(-1, tIcu.create[caseIndex], icus, viewData); |
| caseCreated = true; |
| break; |
| case 3 /* IcuUpdate */: |
| tIcuIndex = updateOpCodes[++j]; |
| tIcu = icus[tIcuIndex]; |
| icuTNode = getTNode(nodeIndex, viewData); |
| readUpdateOpCodes(tIcu.update[icuTNode.activeCaseIndex], icus, bindingsStartIndex, changeMask, viewData, caseCreated); |
| break; |
| } |
| } |
| } |
| } |
| } |
| i += skipCodes; |
| } |
| } |
| function removeNode(index, viewData) { |
| var removedPhTNode = getTNode(index, viewData); |
| var removedPhRNode = getNativeByIndex(index, viewData); |
| if (removedPhRNode) { |
| nativeRemoveNode(viewData[RENDERER], removedPhRNode); |
| } |
| var slotValue = ɵɵload(index); |
| if (isLContainer(slotValue)) { |
| var lContainer = slotValue; |
| if (removedPhTNode.type !== 0 /* Container */) { |
| nativeRemoveNode(viewData[RENDERER], lContainer[NATIVE]); |
| } |
| } |
| // Define this node as detached so that we don't risk projecting it |
| removedPhTNode.flags |= 32 /* isDetached */; |
| ngDevMode && ngDevMode.rendererRemoveNode++; |
| } |
| /** |
| * |
| * Use this instruction to create a translation block that doesn't contain any placeholder. |
| * It calls both {@link i18nStart} and {@link i18nEnd} in one instruction. |
| * |
| * The translation `message` is the value which is locale specific. The translation string may |
| * contain placeholders which associate inner elements and sub-templates within the translation. |
| * |
| * The translation `message` placeholders are: |
| * - `�{index}(:{block})�`: *Binding Placeholder*: Marks a location where an expression will be |
| * interpolated into. The placeholder `index` points to the expression binding index. An optional |
| * `block` that matches the sub-template in which it was declared. |
| * - `�#{index}(:{block})�`/`�/#{index}(:{block})�`: *Element Placeholder*: Marks the beginning |
| * and end of DOM element that were embedded in the original translation block. The placeholder |
| * `index` points to the element index in the template instructions set. An optional `block` that |
| * matches the sub-template in which it was declared. |
| * - `�*{index}:{block}�`/`�/*{index}:{block}�`: *Sub-template Placeholder*: Sub-templates must be |
| * split up and translated separately in each angular template function. The `index` points to the |
| * `template` instruction index. A `block` that matches the sub-template in which it was declared. |
| * |
| * @param index A unique index of the translation in the static block. |
| * @param message The translation message. |
| * @param subTemplateIndex Optional sub-template index in the `message`. |
| * |
| * @codeGenApi |
| */ |
| function ɵɵi18n(index, message, subTemplateIndex) { |
| ɵɵi18nStart(index, message, subTemplateIndex); |
| ɵɵi18nEnd(); |
| } |
| /** |
| * Marks a list of attributes as translatable. |
| * |
| * @param index A unique index in the static block |
| * @param values |
| * |
| * @codeGenApi |
| */ |
| function ɵɵi18nAttributes(index, values) { |
| var tView = getLView()[TVIEW]; |
| ngDevMode && assertDefined(tView, "tView should be defined"); |
| i18nAttributesFirstPass(tView, index, values); |
| } |
| /** |
| * See `i18nAttributes` above. |
| */ |
| function i18nAttributesFirstPass(tView, index, values) { |
| var previousElement = getPreviousOrParentTNode(); |
| var previousElementIndex = previousElement.index - HEADER_OFFSET; |
| var updateOpCodes = []; |
| for (var i = 0; i < values.length; i += 2) { |
| var attrName = values[i]; |
| var message = values[i + 1]; |
| var parts = message.split(ICU_REGEXP); |
| for (var j = 0; j < parts.length; j++) { |
| var value = parts[j]; |
| if (j & 1) { |
| // Odd indexes are ICU expressions |
| // TODO(ocombe): support ICU expressions in attributes |
| throw new Error('ICU expressions are not yet supported in attributes'); |
| } |
| else if (value !== '') { |
| // Even indexes are text (including bindings) |
| var hasBinding = !!value.match(BINDING_REGEXP); |
| if (hasBinding) { |
| if (tView.firstTemplatePass && tView.data[index + HEADER_OFFSET] === null) { |
| addAllToArray(generateBindingUpdateOpCodes(value, previousElementIndex, attrName), updateOpCodes); |
| } |
| } |
| else { |
| var lView = getLView(); |
| elementAttributeInternal(previousElementIndex, attrName, value, lView); |
| // Check if that attribute is a directive input |
| var tNode = getTNode(previousElementIndex, lView); |
| var dataValue = tNode.inputs && tNode.inputs[attrName]; |
| if (dataValue) { |
| setInputsForProperty(lView, dataValue, value); |
| } |
| } |
| } |
| } |
| } |
| if (tView.firstTemplatePass && tView.data[index + HEADER_OFFSET] === null) { |
| tView.data[index + HEADER_OFFSET] = updateOpCodes; |
| } |
| } |
| var changeMask = 0; |
| var shiftsCounter = 0; |
| /** |
| * Stores the values of the bindings during each update cycle in order to determine if we need to |
| * update the translated nodes. |
| * |
| * @param value The binding's value |
| * @returns This function returns itself so that it may be chained |
| * (e.g. `i18nExp(ctx.name)(ctx.title)`) |
| * |
| * @codeGenApi |
| */ |
| function ɵɵi18nExp(value) { |
| var lView = getLView(); |
| var expression = bind(lView, value); |
| if (expression !== NO_CHANGE) { |
| changeMask = changeMask | (1 << shiftsCounter); |
| } |
| shiftsCounter++; |
| return ɵɵi18nExp; |
| } |
| /** |
| * Updates a translation block or an i18n attribute when the bindings have changed. |
| * |
| * @param index Index of either {@link i18nStart} (translation block) or {@link i18nAttributes} |
| * (i18n attribute) on which it should update the content. |
| * |
| * @codeGenApi |
| */ |
| function ɵɵi18nApply(index) { |
| if (shiftsCounter) { |
| var lView = getLView(); |
| var tView = lView[TVIEW]; |
| ngDevMode && assertDefined(tView, "tView should be defined"); |
| var tI18n = tView.data[index + HEADER_OFFSET]; |
| var updateOpCodes = void 0; |
| var icus = null; |
| if (Array.isArray(tI18n)) { |
| updateOpCodes = tI18n; |
| } |
| else { |
| updateOpCodes = tI18n.update; |
| icus = tI18n.icus; |
| } |
| var bindingsStartIndex = lView[BINDING_INDEX] - shiftsCounter - 1; |
| readUpdateOpCodes(updateOpCodes, icus, bindingsStartIndex, changeMask, lView); |
| // Reset changeMask & maskBit to default for the next update cycle |
| changeMask = 0; |
| shiftsCounter = 0; |
| } |
| } |
| /** |
| * Returns the index of the current case of an ICU expression depending on the main binding value |
| * |
| * @param icuExpression |
| * @param bindingValue The value of the main binding used by this ICU expression |
| */ |
| function getCaseIndex(icuExpression, bindingValue) { |
| var index = icuExpression.cases.indexOf(bindingValue); |
| if (index === -1) { |
| switch (icuExpression.type) { |
| case 1 /* plural */: { |
| var resolvedCase = getPluralCase(bindingValue, getLocaleId()); |
| index = icuExpression.cases.indexOf(resolvedCase); |
| if (index === -1 && resolvedCase !== 'other') { |
| index = icuExpression.cases.indexOf('other'); |
| } |
| break; |
| } |
| case 0 /* select */: { |
| index = icuExpression.cases.indexOf('other'); |
| break; |
| } |
| } |
| } |
| return index; |
| } |
| /** |
| * Generate the OpCodes for ICU expressions. |
| * |
| * @param tIcus |
| * @param icuExpression |
| * @param startIndex |
| * @param expandoStartIndex |
| */ |
| function icuStart(tIcus, icuExpression, startIndex, expandoStartIndex) { |
| var createCodes = []; |
| var removeCodes = []; |
| var updateCodes = []; |
| var vars = []; |
| var childIcus = []; |
| for (var i = 0; i < icuExpression.values.length; i++) { |
| // Each value is an array of strings & other ICU expressions |
| var valueArr = icuExpression.values[i]; |
| var nestedIcus = []; |
| for (var j = 0; j < valueArr.length; j++) { |
| var value = valueArr[j]; |
| if (typeof value !== 'string') { |
| // It is an nested ICU expression |
| var icuIndex = nestedIcus.push(value) - 1; |
| // Replace nested ICU expression by a comment node |
| valueArr[j] = "<!--\uFFFD" + icuIndex + "\uFFFD-->"; |
| } |
| } |
| var icuCase = parseIcuCase(valueArr.join(''), startIndex, nestedIcus, tIcus, expandoStartIndex); |
| createCodes.push(icuCase.create); |
| removeCodes.push(icuCase.remove); |
| updateCodes.push(icuCase.update); |
| vars.push(icuCase.vars); |
| childIcus.push(icuCase.childIcus); |
| } |
| var tIcu = { |
| type: icuExpression.type, |
| vars: vars, |
| childIcus: childIcus, |
| cases: icuExpression.cases, |
| create: createCodes, |
| remove: removeCodes, |
| update: updateCodes |
| }; |
| tIcus.push(tIcu); |
| // Adding the maximum possible of vars needed (based on the cases with the most vars) |
| i18nVarsCount += Math.max.apply(Math, __spread(vars)); |
| } |
| /** |
| * Transforms a string template into an HTML template and a list of instructions used to update |
| * attributes or nodes that contain bindings. |
| * |
| * @param unsafeHtml The string to parse |
| * @param parentIndex |
| * @param nestedIcus |
| * @param tIcus |
| * @param expandoStartIndex |
| */ |
| function parseIcuCase(unsafeHtml, parentIndex, nestedIcus, tIcus, expandoStartIndex) { |
| var inertBodyHelper = new InertBodyHelper(document); |
| var inertBodyElement = inertBodyHelper.getInertBodyElement(unsafeHtml); |
| if (!inertBodyElement) { |
| throw new Error('Unable to generate inert body element'); |
| } |
| var wrapper = getTemplateContent(inertBodyElement) || inertBodyElement; |
| var opCodes = { vars: 0, childIcus: [], create: [], remove: [], update: [] }; |
| parseNodes(wrapper.firstChild, opCodes, parentIndex, nestedIcus, tIcus, expandoStartIndex); |
| return opCodes; |
| } |
| var NESTED_ICU = /�(\d+)�/; |
| /** |
| * Parses a node, its children and its siblings, and generates the mutate & update OpCodes. |
| * |
| * @param currentNode The first node to parse |
| * @param icuCase The data for the ICU expression case that contains those nodes |
| * @param parentIndex Index of the current node's parent |
| * @param nestedIcus Data for the nested ICU expressions that this case contains |
| * @param tIcus Data for all ICU expressions of the current message |
| * @param expandoStartIndex Expando start index for the current ICU expression |
| */ |
| function parseNodes(currentNode, icuCase, parentIndex, nestedIcus, tIcus, expandoStartIndex) { |
| if (currentNode) { |
| var nestedIcusToCreate = []; |
| while (currentNode) { |
| var nextNode = currentNode.nextSibling; |
| var newIndex = expandoStartIndex + ++icuCase.vars; |
| switch (currentNode.nodeType) { |
| case Node.ELEMENT_NODE: |
| var element = currentNode; |
| var tagName = element.tagName.toLowerCase(); |
| if (!VALID_ELEMENTS.hasOwnProperty(tagName)) { |
| // This isn't a valid element, we won't create an element for it |
| icuCase.vars--; |
| } |
| else { |
| icuCase.create.push(ELEMENT_MARKER, tagName, newIndex, parentIndex << 17 /* SHIFT_PARENT */ | 1 /* AppendChild */); |
| var elAttrs = element.attributes; |
| for (var i = 0; i < elAttrs.length; i++) { |
| var attr = elAttrs.item(i); |
| var lowerAttrName = attr.name.toLowerCase(); |
| var hasBinding_1 = !!attr.value.match(BINDING_REGEXP); |
| // we assume the input string is safe, unless it's using a binding |
| if (hasBinding_1) { |
| if (VALID_ATTRS.hasOwnProperty(lowerAttrName)) { |
| if (URI_ATTRS[lowerAttrName]) { |
| addAllToArray(generateBindingUpdateOpCodes(attr.value, newIndex, attr.name, _sanitizeUrl), icuCase.update); |
| } |
| else if (SRCSET_ATTRS[lowerAttrName]) { |
| addAllToArray(generateBindingUpdateOpCodes(attr.value, newIndex, attr.name, sanitizeSrcset), icuCase.update); |
| } |
| else { |
| addAllToArray(generateBindingUpdateOpCodes(attr.value, newIndex, attr.name), icuCase.update); |
| } |
| } |
| else { |
| ngDevMode && |
| console.warn("WARNING: ignoring unsafe attribute value " + lowerAttrName + " on element " + tagName + " (see http://g.co/ng/security#xss)"); |
| } |
| } |
| else { |
| icuCase.create.push(newIndex << 3 /* SHIFT_REF */ | 4 /* Attr */, attr.name, attr.value); |
| } |
| } |
| // Parse the children of this node (if any) |
| parseNodes(currentNode.firstChild, icuCase, newIndex, nestedIcus, tIcus, expandoStartIndex); |
| // Remove the parent node after the children |
| icuCase.remove.push(newIndex << 3 /* SHIFT_REF */ | 3 /* Remove */); |
| } |
| break; |
| case Node.TEXT_NODE: |
| var value = currentNode.textContent || ''; |
| var hasBinding = value.match(BINDING_REGEXP); |
| icuCase.create.push(hasBinding ? '' : value, newIndex, parentIndex << 17 /* SHIFT_PARENT */ | 1 /* AppendChild */); |
| icuCase.remove.push(newIndex << 3 /* SHIFT_REF */ | 3 /* Remove */); |
| if (hasBinding) { |
| addAllToArray(generateBindingUpdateOpCodes(value, newIndex), icuCase.update); |
| } |
| break; |
| case Node.COMMENT_NODE: |
| // Check if the comment node is a placeholder for a nested ICU |
| var match = NESTED_ICU.exec(currentNode.textContent || ''); |
| if (match) { |
| var nestedIcuIndex = parseInt(match[1], 10); |
| var newLocal = ngDevMode ? "nested ICU " + nestedIcuIndex : ''; |
| // Create the comment node that will anchor the ICU expression |
| icuCase.create.push(COMMENT_MARKER, newLocal, newIndex, parentIndex << 17 /* SHIFT_PARENT */ | 1 /* AppendChild */); |
| var nestedIcu = nestedIcus[nestedIcuIndex]; |
| nestedIcusToCreate.push([nestedIcu, newIndex]); |
| } |
| else { |
| // We do not handle any other type of comment |
| icuCase.vars--; |
| } |
| break; |
| default: |
| // We do not handle any other type of element |
| icuCase.vars--; |
| } |
| currentNode = nextNode; |
| } |
| for (var i = 0; i < nestedIcusToCreate.length; i++) { |
| var nestedIcu = nestedIcusToCreate[i][0]; |
| var nestedIcuNodeIndex = nestedIcusToCreate[i][1]; |
| icuStart(tIcus, nestedIcu, nestedIcuNodeIndex, expandoStartIndex + icuCase.vars); |
| // Since this is recursive, the last TIcu that was pushed is the one we want |
| var nestTIcuIndex = tIcus.length - 1; |
| icuCase.vars += Math.max.apply(Math, __spread(tIcus[nestTIcuIndex].vars)); |
| icuCase.childIcus.push(nestTIcuIndex); |
| var mask = getBindingMask(nestedIcu); |
| icuCase.update.push(toMaskBit(nestedIcu.mainBinding), // mask of the main binding |
| 3, // skip 3 opCodes if not changed |
| -1 - nestedIcu.mainBinding, nestedIcuNodeIndex << 2 /* SHIFT_REF */ | 2 /* IcuSwitch */, nestTIcuIndex, mask, // mask of all the bindings of this ICU expression |
| 2, // skip 2 opCodes if not changed |
| nestedIcuNodeIndex << 2 /* SHIFT_REF */ | 3 /* IcuUpdate */, nestTIcuIndex); |
| icuCase.remove.push(nestTIcuIndex << 3 /* SHIFT_REF */ | 6 /* RemoveNestedIcu */, nestedIcuNodeIndex << 3 /* SHIFT_REF */ | 3 /* Remove */); |
| } |
| } |
| } |
| var TRANSLATIONS = {}; |
| /** |
| * Set the configuration for `i18nLocalize`. |
| * |
| * @deprecated this method is temporary & should not be used as it will be removed soon |
| */ |
| function i18nConfigureLocalize(options) { |
| if (options === void 0) { options = { |
| translations: {} |
| }; } |
| TRANSLATIONS = options.translations; |
| } |
| var LOCALIZE_PH_REGEXP = /\{\$(.*?)\}/g; |
| /** |
| * A goog.getMsg-like function for users that do not use Closure. |
| * |
| * This method is required as a *temporary* measure to prevent i18n tests from being blocked while |
| * running outside of Closure Compiler. This method will not be needed once runtime translation |
| * service support is introduced. |
| * |
| * @codeGenApi |
| * @deprecated this method is temporary & should not be used as it will be removed soon |
| */ |
| function ɵɵi18nLocalize(input, placeholders) { |
| if (typeof TRANSLATIONS[input] !== 'undefined') { // to account for empty string |
| input = TRANSLATIONS[input]; |
| } |
| if (placeholders !== undefined && Object.keys(placeholders).length) { |
| return input.replace(LOCALIZE_PH_REGEXP, function (_, key) { return placeholders[key] || ''; }); |
| } |
| return input; |
| } |
| /** |
| * The locale id that the application is currently using (for translations and ICU expressions). |
| * This is the ivy version of `LOCALE_ID` that was defined as an injection token for the view engine |
| * but is now defined as a global value. |
| */ |
| var DEFAULT_LOCALE_ID = 'en-US'; |
| var LOCALE_ID = DEFAULT_LOCALE_ID; |
| /** |
| * Sets the locale id that will be used for translations and ICU expressions. |
| * This is the ivy version of `LOCALE_ID` that was defined as an injection token for the view engine |
| * but is now defined as a global value. |
| * |
| * @param localeId |
| */ |
| function setLocaleId(localeId) { |
| LOCALE_ID = localeId.toLowerCase().replace(/_/g, '-'); |
| } |
| /** |
| * Gets the locale id that will be used for translations and ICU expressions. |
| * This is the ivy version of `LOCALE_ID` that was defined as an injection token for the view engine |
| * but is now defined as a global value. |
| */ |
| function getLocaleId() { |
| return LOCALE_ID; |
| } |
| |
| /** |
| * @license |
| * Copyright Google Inc. All Rights Reserved. |
| * |
| * Use of this source code is governed by an MIT-style license that can be |
| * found in the LICENSE file at https://angular.io/license |
| */ |
| /** |
| * Map of module-id to the corresponding NgModule. |
| * - In pre Ivy we track NgModuleFactory, |
| * - In post Ivy we track the NgModuleType |
| */ |
| var modules = new Map(); |
| /** |
| * Registers a loaded module. Should only be called from generated NgModuleFactory code. |
| * @publicApi |
| */ |
| function registerModuleFactory(id, factory) { |
| var existing = modules.get(id); |
| assertSameOrNotExisting(id, existing && existing.moduleType, factory.moduleType); |
| modules.set(id, factory); |
| } |
| function assertSameOrNotExisting(id, type, incoming) { |
| if (type && type !== incoming) { |
| throw new Error("Duplicate module registered for " + id + " - " + stringify(type) + " vs " + stringify(type.name)); |
| } |
| } |
| function registerNgModuleType(ngModuleType) { |
| if (ngModuleType.ngModuleDef.id !== null) { |
| var id = ngModuleType.ngModuleDef.id; |
| var existing = modules.get(id); |
| assertSameOrNotExisting(id, existing, ngModuleType); |
| modules.set(id, ngModuleType); |
| } |
| var imports = ngModuleType.ngModuleDef.imports; |
| if (imports instanceof Function) { |
| imports = imports(); |
| } |
| if (imports) { |
| imports.forEach(function (i) { return registerNgModuleType(i); }); |
| } |
| } |
| function getRegisteredNgModuleType(id) { |
| return modules.get(id); |
| } |
| |
| /** |
| * @license |
| * Copyright Google Inc. All Rights Reserved. |
| * |
| * Use of this source code is governed by an MIT-style license that can be |
| * found in the LICENSE file at https://angular.io/license |
| */ |
| var COMPONENT_FACTORY_RESOLVER = { |
| provide: ComponentFactoryResolver, |
| useClass: ComponentFactoryResolver$1, |
| deps: [NgModuleRef], |
| }; |
| var NgModuleRef$1 = /** @class */ (function (_super) { |
| __extends(NgModuleRef$1, _super); |
| function NgModuleRef$1(ngModuleType, _parent) { |
| var _this = _super.call(this) || this; |
| _this._parent = _parent; |
| // tslint:disable-next-line:require-internal-with-underscore |
| _this._bootstrapComponents = []; |
| _this.injector = _this; |
| _this.destroyCbs = []; |
| var ngModuleDef = getNgModuleDef(ngModuleType); |
| ngDevMode && assertDefined(ngModuleDef, "NgModule '" + stringify(ngModuleType) + "' is not a subtype of 'NgModuleType'."); |
| var ngLocaleIdDef = getNgLocaleIdDef(ngModuleType); |
| if (ngLocaleIdDef) { |
| setLocaleId(ngLocaleIdDef); |
| } |
| _this._bootstrapComponents = maybeUnwrapFn(ngModuleDef.bootstrap); |
| var additionalProviders = [ |
| { |
| provide: NgModuleRef, |
| useValue: _this, |
| }, |
| COMPONENT_FACTORY_RESOLVER |
| ]; |
| _this._r3Injector = createInjector(ngModuleType, _parent, additionalProviders, stringify(ngModuleType)); |
| _this.instance = _this.get(ngModuleType); |
| return _this; |
| } |
| NgModuleRef$1.prototype.get = function (token, notFoundValue, injectFlags) { |
| if (notFoundValue === void 0) { notFoundValue = Injector.THROW_IF_NOT_FOUND; } |
| if (injectFlags === void 0) { injectFlags = exports.InjectFlags.Default; } |
| if (token === Injector || token === NgModuleRef || token === INJECTOR) { |
| return this; |
| } |
| return this._r3Injector.get(token, notFoundValue, injectFlags); |
| }; |
| Object.defineProperty(NgModuleRef$1.prototype, "componentFactoryResolver", { |
| get: function () { |
| return this.get(ComponentFactoryResolver); |
| }, |
| enumerable: true, |
| configurable: true |
| }); |
| NgModuleRef$1.prototype.destroy = function () { |
| ngDevMode && assertDefined(this.destroyCbs, 'NgModule already destroyed'); |
| var injector = this._r3Injector; |
| !injector.destroyed && injector.destroy(); |
| this.destroyCbs.forEach(function (fn) { return fn(); }); |
| this.destroyCbs = null; |
| }; |
| NgModuleRef$1.prototype.onDestroy = function (callback) { |
| ngDevMode && assertDefined(this.destroyCbs, 'NgModule already destroyed'); |
| this.destroyCbs.push(callback); |
| }; |
| return NgModuleRef$1; |
| }(NgModuleRef)); |
| var NgModuleFactory$1 = /** @class */ (function (_super) { |
| __extends(NgModuleFactory, _super); |
| function NgModuleFactory(moduleType) { |
| var _this = _super.call(this) || this; |
| _this.moduleType = moduleType; |
| var ngModuleDef = getNgModuleDef(moduleType); |
| if (ngModuleDef !== null) { |
| // Register the NgModule with Angular's module registry. The location (and hence timing) of |
| // this call is critical to ensure this works correctly (modules get registered when expected) |
| // without bloating bundles (modules are registered when otherwise not referenced). |
| // |
| // In View Engine, registration occurs in the .ngfactory.js file as a side effect. This has |
| // several practical consequences: |
| // |
| // - If an .ngfactory file is not imported from, the module won't be registered (and can be |
| // tree shaken). |
| // - If an .ngfactory file is imported from, the module will be registered even if an instance |
| // is not actually created (via `create` below). |
| // - Since an .ngfactory file in View Engine references the .ngfactory files of the NgModule's |
| // imports, |
| // |
| // In Ivy, things are a bit different. .ngfactory files still exist for compatibility, but are |
| // not a required API to use - there are other ways to obtain an NgModuleFactory for a given |
| // NgModule. Thus, relying on a side effect in the .ngfactory file is not sufficient. Instead, |
| // the side effect of registration is added here, in the constructor of NgModuleFactory, |
| // ensuring no matter how a factory is created, the module is registered correctly. |
| // |
| // An alternative would be to include the registration side effect inline following the actual |
| // NgModule definition. This also has the correct timing, but breaks tree-shaking - modules |
| // will be registered and retained even if they're otherwise never referenced. |
| registerNgModuleType(moduleType); |
| } |
| return _this; |
| } |
| NgModuleFactory.prototype.create = function (parentInjector) { |
| return new NgModuleRef$1(this.moduleType, parentInjector); |
| }; |
| return NgModuleFactory; |
| }(NgModuleFactory)); |
| |
| /** |
| * @license |
| * Copyright Google Inc. All Rights Reserved. |
| * |
| * Use of this source code is governed by an MIT-style license that can be |
| * found in the LICENSE file at https://angular.io/license |
| */ |
| /** |
| * Adds decorator, constructor, and property metadata to a given type via static metadata fields |
| * on the type. |
| * |
| * These metadata fields can later be read with Angular's `ReflectionCapabilities` API. |
| * |
| * Calls to `setClassMetadata` can be marked as pure, resulting in the metadata assignments being |
| * tree-shaken away during production builds. |
| */ |
| function setClassMetadata(type, decorators, ctorParameters, propDecorators) { |
| return noSideEffects(function () { |
| var _a; |
| var clazz = type; |
| // We determine whether a class has its own metadata by taking the metadata from the parent |
| // constructor and checking whether it's the same as the subclass metadata below. We can't use |
| // `hasOwnProperty` here because it doesn't work correctly in IE10 for static fields that are |
| // defined by TS. See https://github.com/angular/angular/pull/28439#issuecomment-459349218. |
| var parentPrototype = clazz.prototype ? Object.getPrototypeOf(clazz.prototype) : null; |
| var parentConstructor = parentPrototype && parentPrototype.constructor; |
| if (decorators !== null) { |
| if (clazz.decorators !== undefined && |
| (!parentConstructor || parentConstructor.decorators !== clazz.decorators)) { |
| (_a = clazz.decorators).push.apply(_a, __spread(decorators)); |
| } |
| else { |
| clazz.decorators = decorators; |
| } |
| } |
| if (ctorParameters !== null) { |
| // Rather than merging, clobber the existing parameters. If other projects exist which use |
| // tsickle-style annotations and reflect over them in the same way, this could cause issues, |
| // but that is vanishingly unlikely. |
| clazz.ctorParameters = ctorParameters; |
| } |
| if (propDecorators !== null) { |
| // The property decorator objects are merged as it is possible different fields have different |
| // decorator types. Decorators on individual fields are not merged, as it's also incredibly |
| // unlikely that a field will be decorated both with an Angular decorator and a non-Angular |
| // decorator that's also been downleveled. |
| if (clazz.propDecorators !== undefined && |
| (!parentConstructor || parentConstructor.propDecorators !== clazz.propDecorators)) { |
| clazz.propDecorators = __assign({}, clazz.propDecorators, propDecorators); |
| } |
| else { |
| clazz.propDecorators = propDecorators; |
| } |
| } |
| }); |
| } |
| |
| /** |
| * @license |
| * Copyright Google Inc. All Rights Reserved. |
| * |
| * Use of this source code is governed by an MIT-style license that can be |
| * found in the LICENSE file at https://angular.io/license |
| */ |
| /** |
| * Bindings for pure functions are stored after regular bindings. |
| * |
| * |------consts------|---------vars---------| |----- hostVars (dir1) ------| |
| * ------------------------------------------------------------------------------------------ |
| * | nodes/refs/pipes | bindings | fn slots | injector | dir1 | host bindings | host slots | |
| * ------------------------------------------------------------------------------------------ |
| * ^ ^ |
| * TView.bindingStartIndex TView.expandoStartIndex |
| * |
| * Pure function instructions are given an offset from the binding root. Adding the offset to the |
| * binding root gives the first index where the bindings are stored. In component views, the binding |
| * root is the bindingStartIndex. In host bindings, the binding root is the expandoStartIndex + |
| * any directive instances + any hostVars in directives evaluated before it. |
| * |
| * See VIEW_DATA.md for more information about host binding resolution. |
| */ |
| /** |
| * If the value hasn't been saved, calls the pure function to store and return the |
| * value. If it has been saved, returns the saved value. |
| * |
| * @param slotOffset the offset from binding root to the reserved slot |
| * @param pureFn Function that returns a value |
| * @param thisArg Optional calling context of pureFn |
| * @returns value |
| * |
| * @codeGenApi |
| */ |
| function ɵɵpureFunction0(slotOffset, pureFn, thisArg) { |
| // TODO(kara): use bindingRoot instead of bindingStartIndex when implementing host bindings |
| var bindingIndex = getBindingRoot() + slotOffset; |
| var lView = getLView(); |
| return isCreationMode() ? |
| updateBinding(lView, bindingIndex, thisArg ? pureFn.call(thisArg) : pureFn()) : |
| getBinding(lView, bindingIndex); |
| } |
| /** |
| * If the value of the provided exp has changed, calls the pure function to return |
| * an updated value. Or if the value has not changed, returns cached value. |
| * |
| * @param slotOffset the offset from binding root to the reserved slot |
| * @param pureFn Function that returns an updated value |
| * @param exp Updated expression value |
| * @param thisArg Optional calling context of pureFn |
| * @returns Updated or cached value |
| * |
| * @codeGenApi |
| */ |
| function ɵɵpureFunction1(slotOffset, pureFn, exp, thisArg) { |
| // TODO(kara): use bindingRoot instead of bindingStartIndex when implementing host bindings |
| var lView = getLView(); |
| var bindingIndex = getBindingRoot() + slotOffset; |
| return bindingUpdated(lView, bindingIndex, exp) ? |
| updateBinding(lView, bindingIndex + 1, thisArg ? pureFn.call(thisArg, exp) : pureFn(exp)) : |
| getBinding(lView, bindingIndex + 1); |
| } |
| /** |
| * If the value of any provided exp has changed, calls the pure function to return |
| * an updated value. Or if no values have changed, returns cached value. |
| * |
| * @param slotOffset the offset from binding root to the reserved slot |
| * @param pureFn |
| * @param exp1 |
| * @param exp2 |
| * @param thisArg Optional calling context of pureFn |
| * @returns Updated or cached value |
| * |
| * @codeGenApi |
| */ |
| function ɵɵpureFunction2(slotOffset, pureFn, exp1, exp2, thisArg) { |
| // TODO(kara): use bindingRoot instead of bindingStartIndex when implementing host bindings |
| var bindingIndex = getBindingRoot() + slotOffset; |
| var lView = getLView(); |
| return bindingUpdated2(lView, bindingIndex, exp1, exp2) ? |
| updateBinding(lView, bindingIndex + 2, thisArg ? pureFn.call(thisArg, exp1, exp2) : pureFn(exp1, exp2)) : |
| getBinding(lView, bindingIndex + 2); |
| } |
| /** |
| * If the value of any provided exp has changed, calls the pure function to return |
| * an updated value. Or if no values have changed, returns cached value. |
| * |
| * @param slotOffset the offset from binding root to the reserved slot |
| * @param pureFn |
| * @param exp1 |
| * @param exp2 |
| * @param exp3 |
| * @param thisArg Optional calling context of pureFn |
| * @returns Updated or cached value |
| * |
| * @codeGenApi |
| */ |
| function ɵɵpureFunction3(slotOffset, pureFn, exp1, exp2, exp3, thisArg) { |
| // TODO(kara): use bindingRoot instead of bindingStartIndex when implementing host bindings |
| var bindingIndex = getBindingRoot() + slotOffset; |
| var lView = getLView(); |
| return bindingUpdated3(lView, bindingIndex, exp1, exp2, exp3) ? |
| updateBinding(lView, bindingIndex + 3, thisArg ? pureFn.call(thisArg, exp1, exp2, exp3) : pureFn(exp1, exp2, exp3)) : |
| getBinding(lView, bindingIndex + 3); |
| } |
| /** |
| * If the value of any provided exp has changed, calls the pure function to return |
| * an updated value. Or if no values have changed, returns cached value. |
| * |
| * @param slotOffset the offset from binding root to the reserved slot |
| * @param pureFn |
| * @param exp1 |
| * @param exp2 |
| * @param exp3 |
| * @param exp4 |
| * @param thisArg Optional calling context of pureFn |
| * @returns Updated or cached value |
| * |
| * @codeGenApi |
| */ |
| function ɵɵpureFunction4(slotOffset, pureFn, exp1, exp2, exp3, exp4, thisArg) { |
| // TODO(kara): use bindingRoot instead of bindingStartIndex when implementing host bindings |
| var bindingIndex = getBindingRoot() + slotOffset; |
| var lView = getLView(); |
| return bindingUpdated4(lView, bindingIndex, exp1, exp2, exp3, exp4) ? |
| updateBinding(lView, bindingIndex + 4, thisArg ? pureFn.call(thisArg, exp1, exp2, exp3, exp4) : pureFn(exp1, exp2, exp3, exp4)) : |
| getBinding(lView, bindingIndex + 4); |
| } |
| /** |
| * If the value of any provided exp has changed, calls the pure function to return |
| * an updated value. Or if no values have changed, returns cached value. |
| * |
| * @param slotOffset the offset from binding root to the reserved slot |
| * @param pureFn |
| * @param exp1 |
| * @param exp2 |
| * @param exp3 |
| * @param exp4 |
| * @param exp5 |
| * @param thisArg Optional calling context of pureFn |
| * @returns Updated or cached value |
| * |
| * @codeGenApi |
| */ |
| function ɵɵpureFunction5(slotOffset, pureFn, exp1, exp2, exp3, exp4, exp5, thisArg) { |
| // TODO(kara): use bindingRoot instead of bindingStartIndex when implementing host bindings |
| var bindingIndex = getBindingRoot() + slotOffset; |
| var lView = getLView(); |
| var different = bindingUpdated4(lView, bindingIndex, exp1, exp2, exp3, exp4); |
| return bindingUpdated(lView, bindingIndex + 4, exp5) || different ? |
| updateBinding(lView, bindingIndex + 5, thisArg ? pureFn.call(thisArg, exp1, exp2, exp3, exp4, exp5) : |
| pureFn(exp1, exp2, exp3, exp4, exp5)) : |
| getBinding(lView, bindingIndex + 5); |
| } |
| /** |
| * If the value of any provided exp has changed, calls the pure function to return |
| * an updated value. Or if no values have changed, returns cached value. |
| * |
| * @param slotOffset the offset from binding root to the reserved slot |
| * @param pureFn |
| * @param exp1 |
| * @param exp2 |
| * @param exp3 |
| * @param exp4 |
| * @param exp5 |
| * @param exp6 |
| * @param thisArg Optional calling context of pureFn |
| * @returns Updated or cached value |
| * |
| * @codeGenApi |
| */ |
| function ɵɵpureFunction6(slotOffset, pureFn, exp1, exp2, exp3, exp4, exp5, exp6, thisArg) { |
| // TODO(kara): use bindingRoot instead of bindingStartIndex when implementing host bindings |
| var bindingIndex = getBindingRoot() + slotOffset; |
| var lView = getLView(); |
| var different = bindingUpdated4(lView, bindingIndex, exp1, exp2, exp3, exp4); |
| return bindingUpdated2(lView, bindingIndex + 4, exp5, exp6) || different ? |
| updateBinding(lView, bindingIndex + 6, thisArg ? |
| pureFn.call(thisArg, exp1, exp2, exp3, exp4, exp5, exp6) : |
| pureFn(exp1, exp2, exp3, exp4, exp5, exp6)) : |
| getBinding(lView, bindingIndex + 6); |
| } |
| /** |
| * If the value of any provided exp has changed, calls the pure function to return |
| * an updated value. Or if no values have changed, returns cached value. |
| * |
| * @param slotOffset the offset from binding root to the reserved slot |
| * @param pureFn |
| * @param exp1 |
| * @param exp2 |
| * @param exp3 |
| * @param exp4 |
| * @param exp5 |
| * @param exp6 |
| * @param exp7 |
| * @param thisArg Optional calling context of pureFn |
| * @returns Updated or cached value |
| * |
| * @codeGenApi |
| */ |
| function ɵɵpureFunction7(slotOffset, pureFn, exp1, exp2, exp3, exp4, exp5, exp6, exp7, thisArg) { |
| // TODO(kara): use bindingRoot instead of bindingStartIndex when implementing host bindings |
| var bindingIndex = getBindingRoot() + slotOffset; |
| var lView = getLView(); |
| var different = bindingUpdated4(lView, bindingIndex, exp1, exp2, exp3, exp4); |
| return bindingUpdated3(lView, bindingIndex + 4, exp5, exp6, exp7) || different ? |
| updateBinding(lView, bindingIndex + 7, thisArg ? |
| pureFn.call(thisArg, exp1, exp2, exp3, exp4, exp5, exp6, exp7) : |
| pureFn(exp1, exp2, exp3, exp4, exp5, exp6, exp7)) : |
| getBinding(lView, bindingIndex + 7); |
| } |
| /** |
| * If the value of any provided exp has changed, calls the pure function to return |
| * an updated value. Or if no values have changed, returns cached value. |
| * |
| * @param slotOffset the offset from binding root to the reserved slot |
| * @param pureFn |
| * @param exp1 |
| * @param exp2 |
| * @param exp3 |
| * @param exp4 |
| * @param exp5 |
| * @param exp6 |
| * @param exp7 |
| * @param exp8 |
| * @param thisArg Optional calling context of pureFn |
| * @returns Updated or cached value |
| * |
| * @codeGenApi |
| */ |
| function ɵɵpureFunction8(slotOffset, pureFn, exp1, exp2, exp3, exp4, exp5, exp6, exp7, exp8, thisArg) { |
| // TODO(kara): use bindingRoot instead of bindingStartIndex when implementing host bindings |
| var bindingIndex = getBindingRoot() + slotOffset; |
| var lView = getLView(); |
| var different = bindingUpdated4(lView, bindingIndex, exp1, exp2, exp3, exp4); |
| return bindingUpdated4(lView, bindingIndex + 4, exp5, exp6, exp7, exp8) || different ? |
| updateBinding(lView, bindingIndex + 8, thisArg ? |
| pureFn.call(thisArg, exp1, exp2, exp3, exp4, exp5, exp6, exp7, exp8) : |
| pureFn(exp1, exp2, exp3, exp4, exp5, exp6, exp7, exp8)) : |
| getBinding(lView, bindingIndex + 8); |
| } |
| /** |
| * pureFunction instruction that can support any number of bindings. |
| * |
| * If the value of any provided exp has changed, calls the pure function to return |
| * an updated value. Or if no values have changed, returns cached value. |
| * |
| * @param slotOffset the offset from binding root to the reserved slot |
| * @param pureFn A pure function that takes binding values and builds an object or array |
| * containing those values. |
| * @param exps An array of binding values |
| * @param thisArg Optional calling context of pureFn |
| * @returns Updated or cached value |
| * |
| * @codeGenApi |
| */ |
| function ɵɵpureFunctionV(slotOffset, pureFn, exps, thisArg) { |
| // TODO(kara): use bindingRoot instead of bindingStartIndex when implementing host bindings |
| var bindingIndex = getBindingRoot() + slotOffset; |
| var different = false; |
| var lView = getLView(); |
| for (var i = 0; i < exps.length; i++) { |
| bindingUpdated(lView, bindingIndex++, exps[i]) && (different = true); |
| } |
| return different ? updateBinding(lView, bindingIndex, pureFn.apply(thisArg, exps)) : |
| getBinding(lView, bindingIndex); |
| } |
| |
| /** |
| * @license |
| * Copyright Google Inc. All Rights Reserved. |
| * |
| * Use of this source code is governed by an MIT-style license that can be |
| * found in the LICENSE file at https://angular.io/license |
| */ |
| /** |
| * Create a pipe. |
| * |
| * @param index Pipe index where the pipe will be stored. |
| * @param pipeName The name of the pipe |
| * @returns T the instance of the pipe. |
| * |
| * @codeGenApi |
| */ |
| function ɵɵpipe(index, pipeName) { |
| var tView = getLView()[TVIEW]; |
| var pipeDef; |
| var adjustedIndex = index + HEADER_OFFSET; |
| if (tView.firstTemplatePass) { |
| pipeDef = getPipeDef$1(pipeName, tView.pipeRegistry); |
| tView.data[adjustedIndex] = pipeDef; |
| if (pipeDef.onDestroy) { |
| (tView.destroyHooks || (tView.destroyHooks = [])).push(adjustedIndex, pipeDef.onDestroy); |
| } |
| } |
| else { |
| pipeDef = tView.data[adjustedIndex]; |
| } |
| var pipeInstance = pipeDef.factory(); |
| store(index, pipeInstance); |
| return pipeInstance; |
| } |
| /** |
| * Searches the pipe registry for a pipe with the given name. If one is found, |
| * returns the pipe. Otherwise, an error is thrown because the pipe cannot be resolved. |
| * |
| * @param name Name of pipe to resolve |
| * @param registry Full list of available pipes |
| * @returns Matching PipeDef |
| * |
| * @publicApi |
| */ |
| function getPipeDef$1(name, registry) { |
| if (registry) { |
| for (var i = registry.length - 1; i >= 0; i--) { |
| var pipeDef = registry[i]; |
| if (name === pipeDef.name) { |
| return pipeDef; |
| } |
| } |
| } |
| throw new Error("The pipe '" + name + "' could not be found!"); |
| } |
| /** |
| * Invokes a pipe with 1 arguments. |
| * |
| * This instruction acts as a guard to {@link PipeTransform#transform} invoking |
| * the pipe only when an input to the pipe changes. |
| * |
| * @param index Pipe index where the pipe was stored on creation. |
| * @param slotOffset the offset in the reserved slot space |
| * @param v1 1st argument to {@link PipeTransform#transform}. |
| * |
| * @codeGenApi |
| */ |
| function ɵɵpipeBind1(index, slotOffset, v1) { |
| var pipeInstance = ɵɵload(index); |
| return unwrapValue$1(isPure(index) ? ɵɵpureFunction1(slotOffset, pipeInstance.transform, v1, pipeInstance) : |
| pipeInstance.transform(v1)); |
| } |
| /** |
| * Invokes a pipe with 2 arguments. |
| * |
| * This instruction acts as a guard to {@link PipeTransform#transform} invoking |
| * the pipe only when an input to the pipe changes. |
| * |
| * @param index Pipe index where the pipe was stored on creation. |
| * @param slotOffset the offset in the reserved slot space |
| * @param v1 1st argument to {@link PipeTransform#transform}. |
| * @param v2 2nd argument to {@link PipeTransform#transform}. |
| * |
| * @codeGenApi |
| */ |
| function ɵɵpipeBind2(index, slotOffset, v1, v2) { |
| var pipeInstance = ɵɵload(index); |
| return unwrapValue$1(isPure(index) ? ɵɵpureFunction2(slotOffset, pipeInstance.transform, v1, v2, pipeInstance) : |
| pipeInstance.transform(v1, v2)); |
| } |
| /** |
| * Invokes a pipe with 3 arguments. |
| * |
| * This instruction acts as a guard to {@link PipeTransform#transform} invoking |
| * the pipe only when an input to the pipe changes. |
| * |
| * @param index Pipe index where the pipe was stored on creation. |
| * @param slotOffset the offset in the reserved slot space |
| * @param v1 1st argument to {@link PipeTransform#transform}. |
| * @param v2 2nd argument to {@link PipeTransform#transform}. |
| * @param v3 4rd argument to {@link PipeTransform#transform}. |
| * |
| * @codeGenApi |
| */ |
| function ɵɵpipeBind3(index, slotOffset, v1, v2, v3) { |
| var pipeInstance = ɵɵload(index); |
| return unwrapValue$1(isPure(index) ? |
| ɵɵpureFunction3(slotOffset, pipeInstance.transform, v1, v2, v3, pipeInstance) : |
| pipeInstance.transform(v1, v2, v3)); |
| } |
| /** |
| * Invokes a pipe with 4 arguments. |
| * |
| * This instruction acts as a guard to {@link PipeTransform#transform} invoking |
| * the pipe only when an input to the pipe changes. |
| * |
| * @param index Pipe index where the pipe was stored on creation. |
| * @param slotOffset the offset in the reserved slot space |
| * @param v1 1st argument to {@link PipeTransform#transform}. |
| * @param v2 2nd argument to {@link PipeTransform#transform}. |
| * @param v3 3rd argument to {@link PipeTransform#transform}. |
| * @param v4 4th argument to {@link PipeTransform#transform}. |
| * |
| * @codeGenApi |
| */ |
| function ɵɵpipeBind4(index, slotOffset, v1, v2, v3, v4) { |
| var pipeInstance = ɵɵload(index); |
| return unwrapValue$1(isPure(index) ? |
| ɵɵpureFunction4(slotOffset, pipeInstance.transform, v1, v2, v3, v4, pipeInstance) : |
| pipeInstance.transform(v1, v2, v3, v4)); |
| } |
| /** |
| * Invokes a pipe with variable number of arguments. |
| * |
| * This instruction acts as a guard to {@link PipeTransform#transform} invoking |
| * the pipe only when an input to the pipe changes. |
| * |
| * @param index Pipe index where the pipe was stored on creation. |
| * @param slotOffset the offset in the reserved slot space |
| * @param values Array of arguments to pass to {@link PipeTransform#transform} method. |
| * |
| * @codeGenApi |
| */ |
| function ɵɵpipeBindV(index, slotOffset, values) { |
| var pipeInstance = ɵɵload(index); |
| return unwrapValue$1(isPure(index) ? ɵɵpureFunctionV(slotOffset, pipeInstance.transform, values, pipeInstance) : |
| pipeInstance.transform.apply(pipeInstance, values)); |
| } |
| function isPure(index) { |
| return getLView()[TVIEW].data[index + HEADER_OFFSET].pure; |
| } |
| /** |
| * Unwrap the output of a pipe transformation. |
| * In order to trick change detection into considering that the new value is always different from |
| * the old one, the old value is overwritten by NO_CHANGE. |
| * |
| * @param newValue the pipe transformation output. |
| */ |
| function unwrapValue$1(newValue) { |
| if (WrappedValue.isWrapped(newValue)) { |
| newValue = WrappedValue.unwrap(newValue); |
| var lView = getLView(); |
| // The NO_CHANGE value needs to be written at the index where the impacted binding value is |
| // stored |
| var bindingToInvalidateIdx = lView[BINDING_INDEX]; |
| lView[bindingToInvalidateIdx] = NO_CHANGE; |
| } |
| return newValue; |
| } |
| |
| /** |
| * @license |
| * Copyright Google Inc. All Rights Reserved. |
| * |
| * Use of this source code is governed by an MIT-style license that can be |
| * found in the LICENSE file at https://angular.io/license |
| */ |
| /** |
| * Use in directives and components to emit custom events synchronously |
| * or asynchronously, and register handlers for those events by subscribing |
| * to an instance. |
| * |
| * @usageNotes |
| * |
| * In the following example, a component defines two output properties |
| * that create event emitters. When the title is clicked, the emitter |
| * emits an open or close event to toggle the current visibility state. |
| * |
| * ```html |
| * @Component({ |
| * selector: 'zippy', |
| * template: ` |
| * <div class="zippy"> |
| * <div (click)="toggle()">Toggle</div> |
| * <div [hidden]="!visible"> |
| * <ng-content></ng-content> |
| * </div> |
| * </div>`}) |
| * export class Zippy { |
| * visible: boolean = true; |
| * @Output() open: EventEmitter<any> = new EventEmitter(); |
| * @Output() close: EventEmitter<any> = new EventEmitter(); |
| * |
| * toggle() { |
| * this.visible = !this.visible; |
| * if (this.visible) { |
| * this.open.emit(null); |
| * } else { |
| * this.close.emit(null); |
| * } |
| * } |
| * } |
| * ``` |
| * |
| * Access the event object with the `$event` argument passed to the output event |
| * handler: |
| * |
| * ```html |
| * <zippy (open)="onOpen($event)" (close)="onClose($event)"></zippy> |
| * ``` |
| * |
| * @publicApi |
| */ |
| var EventEmitter = /** @class */ (function (_super) { |
| __extends(EventEmitter, _super); |
| /** |
| * Creates an instance of this class that can |
| * deliver events synchronously or asynchronously. |
| * |
| * @param isAsync When true, deliver events asynchronously. |
| * |
| */ |
| function EventEmitter(isAsync) { |
| if (isAsync === void 0) { isAsync = false; } |
| var _this = _super.call(this) || this; |
| _this.__isAsync = isAsync; |
| return _this; |
| } |
| /** |
| * Emits an event containing a given value. |
| * @param value The value to emit. |
| */ |
| EventEmitter.prototype.emit = function (value) { _super.prototype.next.call(this, value); }; |
| /** |
| * Registers handlers for events emitted by this instance. |
| * @param generatorOrNext When supplied, a custom handler for emitted events. |
| * @param error When supplied, a custom handler for an error notification |
| * from this emitter. |
| * @param complete When supplied, a custom handler for a completion |
| * notification from this emitter. |
| */ |
| EventEmitter.prototype.subscribe = function (generatorOrNext, error, complete) { |
| var schedulerFn; |
| var errorFn = function (err) { return null; }; |
| var completeFn = function () { return null; }; |
| if (generatorOrNext && typeof generatorOrNext === 'object') { |
| schedulerFn = this.__isAsync ? function (value) { |
| setTimeout(function () { return generatorOrNext.next(value); }); |
| } : function (value) { generatorOrNext.next(value); }; |
| if (generatorOrNext.error) { |
| errorFn = this.__isAsync ? function (err) { setTimeout(function () { return generatorOrNext.error(err); }); } : |
| function (err) { generatorOrNext.error(err); }; |
| } |
| if (generatorOrNext.complete) { |
| completeFn = this.__isAsync ? function () { setTimeout(function () { return generatorOrNext.complete(); }); } : |
| function () { generatorOrNext.complete(); }; |
| } |
| } |
| else { |
| schedulerFn = this.__isAsync ? function (value) { setTimeout(function () { return generatorOrNext(value); }); } : |
| function (value) { generatorOrNext(value); }; |
| if (error) { |
| errorFn = |
| this.__isAsync ? function (err) { setTimeout(function () { return error(err); }); } : function (err) { error(err); }; |
| } |
| if (complete) { |
| completeFn = |
| this.__isAsync ? function () { setTimeout(function () { return complete(); }); } : function () { complete(); }; |
| } |
| } |
| var sink = _super.prototype.subscribe.call(this, schedulerFn, errorFn, completeFn); |
| if (generatorOrNext instanceof rxjs.Subscription) { |
| generatorOrNext.add(sink); |
| } |
| return sink; |
| }; |
| return EventEmitter; |
| }(rxjs.Subject)); |
| |
| /** |
| * @license |
| * Copyright Google Inc. All Rights Reserved. |
| * |
| * Use of this source code is governed by an MIT-style license that can be |
| * found in the LICENSE file at https://angular.io/license |
| */ |
| function symbolIterator() { |
| return this._results[getSymbolIterator()](); |
| } |
| /** |
| * An unmodifiable list of items that Angular keeps up to date when the state |
| * of the application changes. |
| * |
| * The type of object that {@link ViewChildren}, {@link ContentChildren}, and {@link QueryList} |
| * provide. |
| * |
| * Implements an iterable interface, therefore it can be used in both ES6 |
| * javascript `for (var i of items)` loops as well as in Angular templates with |
| * `*ngFor="let i of myList"`. |
| * |
| * Changes can be observed by subscribing to the changes `Observable`. |
| * |
| * NOTE: In the future this class will implement an `Observable` interface. |
| * |
| * @usageNotes |
| * ### Example |
| * ```typescript |
| * @Component({...}) |
| * class Container { |
| * @ViewChildren(Item) items:QueryList<Item>; |
| * } |
| * ``` |
| * |
| * @publicApi |
| */ |
| var QueryList = /** @class */ (function () { |
| function QueryList() { |
| this.dirty = true; |
| this._results = []; |
| this.changes = new EventEmitter(); |
| this.length = 0; |
| // This function should be declared on the prototype, but doing so there will cause the class |
| // declaration to have side-effects and become not tree-shakable. For this reason we do it in |
| // the constructor. |
| // [getSymbolIterator()](): Iterator<T> { ... } |
| var symbol = getSymbolIterator(); |
| var proto = QueryList.prototype; |
| if (!proto[symbol]) |
| proto[symbol] = symbolIterator; |
| } |
| /** |
| * See |
| * [Array.map](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map) |
| */ |
| QueryList.prototype.map = function (fn) { return this._results.map(fn); }; |
| /** |
| * See |
| * [Array.filter](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/filter) |
| */ |
| QueryList.prototype.filter = function (fn) { |
| return this._results.filter(fn); |
| }; |
| /** |
| * See |
| * [Array.find](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/find) |
| */ |
| QueryList.prototype.find = function (fn) { |
| return this._results.find(fn); |
| }; |
| /** |
| * See |
| * [Array.reduce](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/reduce) |
| */ |
| QueryList.prototype.reduce = function (fn, init) { |
| return this._results.reduce(fn, init); |
| }; |
| /** |
| * See |
| * [Array.forEach](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/forEach) |
| */ |
| QueryList.prototype.forEach = function (fn) { this._results.forEach(fn); }; |
| /** |
| * See |
| * [Array.some](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/some) |
| */ |
| QueryList.prototype.some = function (fn) { |
| return this._results.some(fn); |
| }; |
| /** |
| * Returns a copy of the internal results list as an Array. |
| */ |
| QueryList.prototype.toArray = function () { return this._results.slice(); }; |
| QueryList.prototype.toString = function () { return this._results.toString(); }; |
| /** |
| * Updates the stored data of the query list, and resets the `dirty` flag to `false`, so that |
| * on change detection, it will not notify of changes to the queries, unless a new change |
| * occurs. |
| * |
| * @param resultsTree The results tree to store |
| */ |
| QueryList.prototype.reset = function (resultsTree) { |
| this._results = flatten(resultsTree); |
| this.dirty = false; |
| this.length = this._results.length; |
| this.last = this._results[this.length - 1]; |
| this.first = this._results[0]; |
| }; |
| /** |
| * Triggers a change event by emitting on the `changes` {@link EventEmitter}. |
| */ |
| QueryList.prototype.notifyOnChanges = function () { this.changes.emit(this); }; |
| /** internal */ |
| QueryList.prototype.setDirty = function () { this.dirty = true; }; |
| /** internal */ |
| QueryList.prototype.destroy = function () { |
| this.changes.complete(); |
| this.changes.unsubscribe(); |
| }; |
| return QueryList; |
| }()); |
| |
| /** |
| * @license |
| * Copyright Google Inc. All Rights Reserved. |
| * |
| * Use of this source code is governed by an MIT-style license that can be |
| * found in the LICENSE file at https://angular.io/license |
| */ |
| |
| /** |
| * @license |
| * Copyright Google Inc. All Rights Reserved. |
| * |
| * Use of this source code is governed by an MIT-style license that can be |
| * found in the LICENSE file at https://angular.io/license |
| */ |
| |
| /** |
| * @license |
| * Copyright Google Inc. All Rights Reserved. |
| * |
| * Use of this source code is governed by an MIT-style license that can be |
| * found in the LICENSE file at https://angular.io/license |
| */ |
| /** |
| * An object representing a query, which is a combination of: |
| * - query predicate to determines if a given element/directive should be included in the query |
| * - values collected based on a predicate |
| * - `QueryList` to which collected values should be reported |
| */ |
| var LQuery = /** @class */ (function () { |
| function LQuery( |
| /** |
| * Next query. Used when queries are stored as a linked list in `LQueries`. |
| */ |
| next, |
| /** |
| * Destination to which the value should be added. |
| */ |
| list, |
| /** |
| * A predicate which determines if a given element/directive should be included in the query |
| * results. |
| */ |
| predicate, |
| /** |
| * Values which have been located. |
| * This is what builds up the `QueryList._valuesTree`. |
| */ |
| values, |
| /** |
| * A pointer to an array that stores collected values from views. This is necessary so we |
| * know a container into which to insert nodes collected from views. |
| */ |
| containerValues) { |
| this.next = next; |
| this.list = list; |
| this.predicate = predicate; |
| this.values = values; |
| this.containerValues = containerValues; |
| } |
| return LQuery; |
| }()); |
| var LQueries_ = /** @class */ (function () { |
| function LQueries_(parent, shallow, deep, nodeIndex) { |
| if (nodeIndex === void 0) { nodeIndex = -1; } |
| this.parent = parent; |
| this.shallow = shallow; |
| this.deep = deep; |
| this.nodeIndex = nodeIndex; |
| } |
| LQueries_.prototype.track = function (queryList, predicate, descend, read) { |
| if (descend) { |
| this.deep = createLQuery(this.deep, queryList, predicate, read != null ? read : null); |
| } |
| else { |
| this.shallow = createLQuery(this.shallow, queryList, predicate, read != null ? read : null); |
| } |
| }; |
| LQueries_.prototype.clone = function (tNode) { |
| return this.shallow !== null || isContentQueryHost(tNode) ? |
| new LQueries_(this, null, this.deep, tNode.index) : |
| this; |
| }; |
| LQueries_.prototype.container = function () { |
| var shallowResults = copyQueriesToContainer(this.shallow); |
| var deepResults = copyQueriesToContainer(this.deep); |
| return shallowResults || deepResults ? new LQueries_(this, shallowResults, deepResults) : null; |
| }; |
| LQueries_.prototype.createView = function () { |
| var shallowResults = copyQueriesToView(this.shallow); |
| var deepResults = copyQueriesToView(this.deep); |
| return shallowResults || deepResults ? new LQueries_(this, shallowResults, deepResults) : null; |
| }; |
| LQueries_.prototype.insertView = function (index) { |
| insertView$1(index, this.shallow); |
| insertView$1(index, this.deep); |
| }; |
| LQueries_.prototype.addNode = function (tNode) { |
| add(this.deep, tNode, false); |
| add(this.shallow, tNode, false); |
| }; |
| LQueries_.prototype.insertNodeBeforeViews = function (tNode) { |
| add(this.deep, tNode, true); |
| add(this.shallow, tNode, true); |
| }; |
| LQueries_.prototype.removeView = function () { |
| removeView$1(this.shallow); |
| removeView$1(this.deep); |
| }; |
| return LQueries_; |
| }()); |
| function copyQueriesToContainer(query) { |
| var result = null; |
| while (query) { |
| var containerValues = []; // prepare room for views |
| query.values.push(containerValues); |
| result = new LQuery(result, query.list, query.predicate, containerValues, null); |
| query = query.next; |
| } |
| return result; |
| } |
| function copyQueriesToView(query) { |
| var result = null; |
| while (query) { |
| result = new LQuery(result, query.list, query.predicate, [], query.values); |
| query = query.next; |
| } |
| return result; |
| } |
| function insertView$1(index, query) { |
| while (query) { |
| ngDevMode && assertViewQueryhasPointerToDeclarationContainer(query); |
| query.containerValues.splice(index, 0, query.values); |
| // mark a query as dirty only when inserted view had matching modes |
| if (query.values.length) { |
| query.list.setDirty(); |
| } |
| query = query.next; |
| } |
| } |
| function removeView$1(query) { |
| while (query) { |
| ngDevMode && assertViewQueryhasPointerToDeclarationContainer(query); |
| var containerValues = query.containerValues; |
| var viewValuesIdx = containerValues.indexOf(query.values); |
| var removed = containerValues.splice(viewValuesIdx, 1); |
| // mark a query as dirty only when removed view had matching modes |
| ngDevMode && assertEqual(removed.length, 1, 'removed.length'); |
| if (removed[0].length) { |
| query.list.setDirty(); |
| } |
| query = query.next; |
| } |
| } |
| function assertViewQueryhasPointerToDeclarationContainer(query) { |
| assertDefined(query.containerValues, 'View queries need to have a pointer to container values.'); |
| } |
| /** |
| * Iterates over local names for a given node and returns directive index |
| * (or -1 if a local name points to an element). |
| * |
| * @param tNode static data of a node to check |
| * @param selector selector to match |
| * @returns directive index, -1 or null if a selector didn't match any of the local names |
| */ |
| function getIdxOfMatchingSelector(tNode, selector) { |
| var localNames = tNode.localNames; |
| if (localNames) { |
| for (var i = 0; i < localNames.length; i += 2) { |
| if (localNames[i] === selector) { |
| return localNames[i + 1]; |
| } |
| } |
| } |
| return null; |
| } |
| // TODO: "read" should be an AbstractType (FW-486) |
| function queryByReadToken(read, tNode, currentView) { |
| var factoryFn = read[NG_ELEMENT_ID]; |
| if (typeof factoryFn === 'function') { |
| return factoryFn(); |
| } |
| else { |
| var tView = currentView[TVIEW]; |
| var matchingIdx = locateDirectiveOrProvider(tNode, tView, read, false, false); |
| if (matchingIdx !== null) { |
| return getNodeInjectable(tView.data, currentView, matchingIdx, tNode); |
| } |
| } |
| return null; |
| } |
| function queryByTNodeType(tNode, currentView) { |
| if (tNode.type === 3 /* Element */ || tNode.type === 4 /* ElementContainer */) { |
| return createElementRef(ElementRef, tNode, currentView); |
| } |
| if (tNode.type === 0 /* Container */) { |
| return createTemplateRef(TemplateRef, ElementRef, tNode, currentView); |
| } |
| return null; |
| } |
| function queryByTemplateRef(templateRefToken, tNode, currentView, read) { |
| var templateRefResult = templateRefToken[NG_ELEMENT_ID](); |
| if (read) { |
| return templateRefResult ? queryByReadToken(read, tNode, currentView) : null; |
| } |
| return templateRefResult; |
| } |
| function queryRead(tNode, currentView, read, matchingIdx) { |
| if (read) { |
| return queryByReadToken(read, tNode, currentView); |
| } |
| if (matchingIdx > -1) { |
| return getNodeInjectable(currentView[TVIEW].data, currentView, matchingIdx, tNode); |
| } |
| // if read token and / or strategy is not specified, |
| // detect it using appropriate tNode type |
| return queryByTNodeType(tNode, currentView); |
| } |
| /** |
| * Add query matches for a given node. |
| * |
| * @param query The first query in the linked list |
| * @param tNode The TNode to match against queries |
| * @param insertBeforeContainer Whether or not we should add matches before the last |
| * container array. This mode is necessary if the query container had to be created |
| * out of order (e.g. a view was created in a constructor) |
| */ |
| function add(query, tNode, insertBeforeContainer) { |
| var lView = getLView(); |
| var tView = lView[TVIEW]; |
| while (query) { |
| var predicate = query.predicate; |
| var type = predicate.type; |
| if (type) { |
| var result = null; |
| if (type === TemplateRef) { |
| result = queryByTemplateRef(type, tNode, lView, predicate.read); |
| } |
| else { |
| var matchingIdx = locateDirectiveOrProvider(tNode, tView, type, false, false); |
| if (matchingIdx !== null) { |
| result = queryRead(tNode, lView, predicate.read, matchingIdx); |
| } |
| } |
| if (result !== null) { |
| addMatch(query, result, insertBeforeContainer); |
| } |
| } |
| else { |
| var selector = predicate.selector; |
| for (var i = 0; i < selector.length; i++) { |
| var matchingIdx = getIdxOfMatchingSelector(tNode, selector[i]); |
| if (matchingIdx !== null) { |
| var result = queryRead(tNode, lView, predicate.read, matchingIdx); |
| if (result !== null) { |
| addMatch(query, result, insertBeforeContainer); |
| } |
| } |
| } |
| } |
| query = query.next; |
| } |
| } |
| function addMatch(query, matchingValue, insertBeforeViewMatches) { |
| // Views created in constructors may have their container values created too early. In this case, |
| // ensure template node results are unshifted before container results. Otherwise, results inside |
| // embedded views will appear before results on parent template nodes when flattened. |
| insertBeforeViewMatches ? query.values.unshift(matchingValue) : query.values.push(matchingValue); |
| query.list.setDirty(); |
| } |
| function createPredicate(predicate, read) { |
| var isArray = Array.isArray(predicate); |
| return { |
| type: isArray ? null : predicate, |
| selector: isArray ? predicate : null, |
| read: read |
| }; |
| } |
| function createLQuery(previous, queryList, predicate, read) { |
| return new LQuery(previous, queryList, createPredicate(predicate, read), queryList._valuesTree, null); |
| } |
| /** |
| * Creates a QueryList and stores it in LView's collection of active queries (LQueries). |
| * |
| * @param predicate The type for which the query will search |
| * @param descend Whether or not to descend into children |
| * @param read What to save in the query |
| * @returns QueryList<T> |
| */ |
| function createQueryListInLView( |
| // TODO: "read" should be an AbstractType (FW-486) |
| lView, predicate, descend, read, isStatic, nodeIndex) { |
| ngDevMode && assertPreviousIsParent(getIsParent()); |
| var queryList = new QueryList(); |
| var queries = lView[QUERIES] || (lView[QUERIES] = new LQueries_(null, null, null, nodeIndex)); |
| queryList._valuesTree = []; |
| queryList._static = isStatic; |
| queries.track(queryList, predicate, descend, read); |
| storeCleanupWithContext(lView, queryList, queryList.destroy); |
| return queryList; |
| } |
| /** |
| * Refreshes a query by combining matches from all active views and removing matches from deleted |
| * views. |
| * |
| * @returns `true` if a query got dirty during change detection or if this is a static query |
| * resolving in creation mode, `false` otherwise. |
| * |
| * @codeGenApi |
| */ |
| function ɵɵqueryRefresh(queryList) { |
| var queryListImpl = queryList; |
| var creationMode = isCreationMode(); |
| // if creation mode and static or update mode and not static |
| if (queryList.dirty && creationMode === queryListImpl._static) { |
| queryList.reset(queryListImpl._valuesTree || []); |
| queryList.notifyOnChanges(); |
| return true; |
| } |
| return false; |
| } |
| /** |
| * Creates new QueryList for a static view query. |
| * |
| * @param predicate The type for which the query will search |
| * @param descend Whether or not to descend into children |
| * @param read What to save in the query |
| * |
| * @codeGenApi |
| */ |
| function ɵɵstaticViewQuery( |
| // TODO(FW-486): "read" should be an AbstractType |
| predicate, descend, read) { |
| var lView = getLView(); |
| var tView = lView[TVIEW]; |
| viewQueryInternal(lView, tView, predicate, descend, read, true); |
| tView.staticViewQueries = true; |
| } |
| /** |
| * Creates new QueryList, stores the reference in LView and returns QueryList. |
| * |
| * @param predicate The type for which the query will search |
| * @param descend Whether or not to descend into children |
| * @param read What to save in the query |
| * @returns QueryList<T> |
| * |
| * @codeGenApi |
| */ |
| function ɵɵviewQuery( |
| // TODO(FW-486): "read" should be an AbstractType |
| predicate, descend, read) { |
| var lView = getLView(); |
| var tView = lView[TVIEW]; |
| return viewQueryInternal(lView, tView, predicate, descend, read, false); |
| } |
| function viewQueryInternal(lView, tView, predicate, descend, read, isStatic) { |
| if (tView.firstTemplatePass) { |
| tView.expandoStartIndex++; |
| } |
| var index = getCurrentQueryIndex(); |
| var queryList = createQueryListInLView(lView, predicate, descend, read, isStatic, -1); |
| store(index - HEADER_OFFSET, queryList); |
| setCurrentQueryIndex(index + 1); |
| return queryList; |
| } |
| /** |
| * Loads current View Query and moves the pointer/index to the next View Query in LView. |
| * |
| * @codeGenApi |
| */ |
| function ɵɵloadViewQuery() { |
| var index = getCurrentQueryIndex(); |
| setCurrentQueryIndex(index + 1); |
| return loadInternal(getLView(), index - HEADER_OFFSET); |
| } |
| /** |
| * Registers a QueryList, associated with a content query, for later refresh (part of a view |
| * refresh). |
| * |
| * @param directiveIndex Current directive index |
| * @param predicate The type for which the query will search |
| * @param descend Whether or not to descend into children |
| * @param read What to save in the query |
| * @returns QueryList<T> |
| * |
| * @codeGenApi |
| */ |
| function ɵɵcontentQuery(directiveIndex, predicate, descend, |
| // TODO(FW-486): "read" should be an AbstractType |
| read) { |
| var lView = getLView(); |
| var tView = lView[TVIEW]; |
| var tNode = getPreviousOrParentTNode(); |
| return contentQueryInternal(lView, tView, directiveIndex, predicate, descend, read, false, tNode.index); |
| } |
| function contentQueryInternal(lView, tView, directiveIndex, predicate, descend, |
| // TODO(FW-486): "read" should be an AbstractType |
| read, isStatic, nodeIndex) { |
| var contentQuery = createQueryListInLView(lView, predicate, descend, read, isStatic, nodeIndex); |
| (lView[CONTENT_QUERIES] || (lView[CONTENT_QUERIES] = [])).push(contentQuery); |
| if (tView.firstTemplatePass) { |
| var tViewContentQueries = tView.contentQueries || (tView.contentQueries = []); |
| var lastSavedDirectiveIndex = tView.contentQueries.length ? tView.contentQueries[tView.contentQueries.length - 1] : -1; |
| if (directiveIndex !== lastSavedDirectiveIndex) { |
| tViewContentQueries.push(directiveIndex); |
| } |
| } |
| return contentQuery; |
| } |
| /** |
| * Registers a QueryList, associated with a static content query, for later refresh |
| * (part of a view refresh). |
| * |
| * @param directiveIndex Current directive index |
| * @param predicate The type for which the query will search |
| * @param descend Whether or not to descend into children |
| * @param read What to save in the query |
| * @returns QueryList<T> |
| * |
| * @codeGenApi |
| */ |
| function ɵɵstaticContentQuery(directiveIndex, predicate, descend, |
| // TODO(FW-486): "read" should be an AbstractType |
| read) { |
| var lView = getLView(); |
| var tView = lView[TVIEW]; |
| var tNode = getPreviousOrParentTNode(); |
| contentQueryInternal(lView, tView, directiveIndex, predicate, descend, read, true, tNode.index); |
| tView.staticContentQueries = true; |
| } |
| /** |
| * |
| * @codeGenApi |
| */ |
| function ɵɵloadContentQuery() { |
| var lView = getLView(); |
| ngDevMode && |
| assertDefined(lView[CONTENT_QUERIES], 'Content QueryList array should be defined if reading a query.'); |
| var index = getCurrentQueryIndex(); |
| ngDevMode && assertDataInRange(lView[CONTENT_QUERIES], index); |
| setCurrentQueryIndex(index + 1); |
| return lView[CONTENT_QUERIES][index]; |
| } |
| |
| /** |
| * @license |
| * Copyright Google Inc. All Rights Reserved. |
| * |
| * Use of this source code is governed by an MIT-style license that can be |
| * found in the LICENSE file at https://angular.io/license |
| */ |
| /** |
| * Retrieves `TemplateRef` instance from `Injector` when a local reference is placed on the |
| * `<ng-template>` element. |
| * |
| * @codeGenApi |
| */ |
| function ɵɵtemplateRefExtractor(tNode, currentView) { |
| return createTemplateRef(TemplateRef, ElementRef, tNode, currentView); |
| } |
| |
| /** |
| * @license |
| * Copyright Google Inc. All Rights Reserved. |
| * |
| * Use of this source code is governed by an MIT-style license that can be |
| * found in the LICENSE file at https://angular.io/license |
| */ |
| |
| /** |
| * @license |
| * Copyright Google Inc. All Rights Reserved. |
| * |
| * Use of this source code is governed by an MIT-style license that can be |
| * found in the LICENSE file at https://angular.io/license |
| */ |
| var ɵ0$9 = function () { return ({ |
| 'ɵɵattribute': ɵɵattribute, |
| 'ɵɵattributeInterpolate1': ɵɵattributeInterpolate1, |
| 'ɵɵattributeInterpolate2': ɵɵattributeInterpolate2, |
| 'ɵɵattributeInterpolate3': ɵɵattributeInterpolate3, |
| 'ɵɵattributeInterpolate4': ɵɵattributeInterpolate4, |
| 'ɵɵattributeInterpolate5': ɵɵattributeInterpolate5, |
| 'ɵɵattributeInterpolate6': ɵɵattributeInterpolate6, |
| 'ɵɵattributeInterpolate7': ɵɵattributeInterpolate7, |
| 'ɵɵattributeInterpolate8': ɵɵattributeInterpolate8, |
| 'ɵɵattributeInterpolateV': ɵɵattributeInterpolateV, |
| 'ɵɵdefineBase': ɵɵdefineBase, |
| 'ɵɵdefineComponent': ɵɵdefineComponent, |
| 'ɵɵdefineDirective': ɵɵdefineDirective, |
| 'ɵɵdefineInjectable': ɵɵdefineInjectable, |
| 'ɵɵdefineInjector': ɵɵdefineInjector, |
| 'ɵɵdefineNgModule': ɵɵdefineNgModule, |
| 'ɵɵdefinePipe': ɵɵdefinePipe, |
| 'ɵɵdirectiveInject': ɵɵdirectiveInject, |
| 'ɵɵgetFactoryOf': ɵɵgetFactoryOf, |
| 'ɵɵgetInheritedFactory': ɵɵgetInheritedFactory, |
| 'ɵɵinject': ɵɵinject, |
| 'ɵɵinjectAttribute': ɵɵinjectAttribute, |
| 'ɵɵtemplateRefExtractor': ɵɵtemplateRefExtractor, |
| 'ɵɵNgOnChangesFeature': ɵɵNgOnChangesFeature, |
| 'ɵɵProvidersFeature': ɵɵProvidersFeature, |
| 'ɵɵInheritDefinitionFeature': ɵɵInheritDefinitionFeature, |
| 'ɵɵcontainer': ɵɵcontainer, |
| 'ɵɵnextContext': ɵɵnextContext, |
| 'ɵɵcontainerRefreshStart': ɵɵcontainerRefreshStart, |
| 'ɵɵcontainerRefreshEnd': ɵɵcontainerRefreshEnd, |
| 'ɵɵnamespaceHTML': ɵɵnamespaceHTML, |
| 'ɵɵnamespaceMathML': ɵɵnamespaceMathML, |
| 'ɵɵnamespaceSVG': ɵɵnamespaceSVG, |
| 'ɵɵenableBindings': ɵɵenableBindings, |
| 'ɵɵdisableBindings': ɵɵdisableBindings, |
| 'ɵɵallocHostVars': ɵɵallocHostVars, |
| 'ɵɵelementStart': ɵɵelementStart, |
| 'ɵɵelementEnd': ɵɵelementEnd, |
| 'ɵɵelement': ɵɵelement, |
| 'ɵɵelementContainerStart': ɵɵelementContainerStart, |
| 'ɵɵelementContainerEnd': ɵɵelementContainerEnd, |
| 'ɵɵpureFunction0': ɵɵpureFunction0, |
| 'ɵɵpureFunction1': ɵɵpureFunction1, |
| 'ɵɵpureFunction2': ɵɵpureFunction2, |
| 'ɵɵpureFunction3': ɵɵpureFunction3, |
| 'ɵɵpureFunction4': ɵɵpureFunction4, |
| 'ɵɵpureFunction5': ɵɵpureFunction5, |
| 'ɵɵpureFunction6': ɵɵpureFunction6, |
| 'ɵɵpureFunction7': ɵɵpureFunction7, |
| 'ɵɵpureFunction8': ɵɵpureFunction8, |
| 'ɵɵpureFunctionV': ɵɵpureFunctionV, |
| 'ɵɵgetCurrentView': ɵɵgetCurrentView, |
| 'ɵɵrestoreView': ɵɵrestoreView, |
| 'ɵɵinterpolation1': ɵɵinterpolation1, |
| 'ɵɵinterpolation2': ɵɵinterpolation2, |
| 'ɵɵinterpolation3': ɵɵinterpolation3, |
| 'ɵɵinterpolation4': ɵɵinterpolation4, |
| 'ɵɵinterpolation5': ɵɵinterpolation5, |
| 'ɵɵinterpolation6': ɵɵinterpolation6, |
| 'ɵɵinterpolation7': ɵɵinterpolation7, |
| 'ɵɵinterpolation8': ɵɵinterpolation8, |
| 'ɵɵinterpolationV': ɵɵinterpolationV, |
| 'ɵɵlistener': ɵɵlistener, |
| 'ɵɵload': ɵɵload, |
| 'ɵɵprojection': ɵɵprojection, |
| 'ɵɵupdateSyntheticHostBinding': ɵɵupdateSyntheticHostBinding, |
| 'ɵɵcomponentHostSyntheticListener': ɵɵcomponentHostSyntheticListener, |
| 'ɵɵpipeBind1': ɵɵpipeBind1, |
| 'ɵɵpipeBind2': ɵɵpipeBind2, |
| 'ɵɵpipeBind3': ɵɵpipeBind3, |
| 'ɵɵpipeBind4': ɵɵpipeBind4, |
| 'ɵɵpipeBindV': ɵɵpipeBindV, |
| 'ɵɵprojectionDef': ɵɵprojectionDef, |
| 'ɵɵproperty': ɵɵproperty, |
| 'ɵɵpropertyInterpolate': ɵɵpropertyInterpolate, |
| 'ɵɵpropertyInterpolate1': ɵɵpropertyInterpolate1, |
| 'ɵɵpropertyInterpolate2': ɵɵpropertyInterpolate2, |
| 'ɵɵpropertyInterpolate3': ɵɵpropertyInterpolate3, |
| 'ɵɵpropertyInterpolate4': ɵɵpropertyInterpolate4, |
| 'ɵɵpropertyInterpolate5': ɵɵpropertyInterpolate5, |
| 'ɵɵpropertyInterpolate6': ɵɵpropertyInterpolate6, |
| 'ɵɵpropertyInterpolate7': ɵɵpropertyInterpolate7, |
| 'ɵɵpropertyInterpolate8': ɵɵpropertyInterpolate8, |
| 'ɵɵpropertyInterpolateV': ɵɵpropertyInterpolateV, |
| 'ɵɵpipe': ɵɵpipe, |
| 'ɵɵqueryRefresh': ɵɵqueryRefresh, |
| 'ɵɵviewQuery': ɵɵviewQuery, |
| 'ɵɵstaticViewQuery': ɵɵstaticViewQuery, |
| 'ɵɵstaticContentQuery': ɵɵstaticContentQuery, |
| 'ɵɵloadViewQuery': ɵɵloadViewQuery, |
| 'ɵɵcontentQuery': ɵɵcontentQuery, |
| 'ɵɵloadContentQuery': ɵɵloadContentQuery, |
| 'ɵɵreference': ɵɵreference, |
| 'ɵɵelementHostAttrs': ɵɵelementHostAttrs, |
| 'ɵɵclassMap': ɵɵclassMap, |
| 'ɵɵstyling': ɵɵstyling, |
| 'ɵɵstyleMap': ɵɵstyleMap, |
| 'ɵɵstyleProp': ɵɵstyleProp, |
| 'ɵɵstyleSanitizer': styleSanitizer, |
| 'ɵɵstylingApply': ɵɵstylingApply, |
| 'ɵɵclassProp': ɵɵclassProp, |
| 'ɵɵselect': ɵɵselect, |
| 'ɵɵtemplate': ɵɵtemplate, |
| 'ɵɵtext': ɵɵtext, |
| 'ɵɵtextBinding': ɵɵtextBinding, |
| 'ɵɵtextInterpolate': ɵɵtextInterpolate, |
| 'ɵɵtextInterpolate1': ɵɵtextInterpolate1, |
| 'ɵɵtextInterpolate2': ɵɵtextInterpolate2, |
| 'ɵɵtextInterpolate3': ɵɵtextInterpolate3, |
| 'ɵɵtextInterpolate4': ɵɵtextInterpolate4, |
| 'ɵɵtextInterpolate5': ɵɵtextInterpolate5, |
| 'ɵɵtextInterpolate6': ɵɵtextInterpolate6, |
| 'ɵɵtextInterpolate7': ɵɵtextInterpolate7, |
| 'ɵɵtextInterpolate8': ɵɵtextInterpolate8, |
| 'ɵɵtextInterpolateV': ɵɵtextInterpolateV, |
| 'ɵɵembeddedViewStart': ɵɵembeddedViewStart, |
| 'ɵɵembeddedViewEnd': ɵɵembeddedViewEnd, |
| 'ɵɵi18n': ɵɵi18n, |
| 'ɵɵi18nAttributes': ɵɵi18nAttributes, |
| 'ɵɵi18nExp': ɵɵi18nExp, |
| 'ɵɵi18nStart': ɵɵi18nStart, |
| 'ɵɵi18nEnd': ɵɵi18nEnd, |
| 'ɵɵi18nApply': ɵɵi18nApply, |
| 'ɵɵi18nPostprocess': ɵɵi18nPostprocess, |
| 'ɵɵi18nLocalize': ɵɵi18nLocalize, |
| 'ɵɵresolveWindow': ɵɵresolveWindow, |
| 'ɵɵresolveDocument': ɵɵresolveDocument, |
| 'ɵɵresolveBody': ɵɵresolveBody, |
| 'ɵɵsetComponentScope': ɵɵsetComponentScope, |
| 'ɵɵsetNgModuleScope': ɵɵsetNgModuleScope, |
| 'ɵɵsanitizeHtml': ɵɵsanitizeHtml, |
| 'ɵɵsanitizeStyle': ɵɵsanitizeStyle, |
| 'ɵɵdefaultStyleSanitizer': ɵɵdefaultStyleSanitizer, |
| 'ɵɵsanitizeResourceUrl': ɵɵsanitizeResourceUrl, |
| 'ɵɵsanitizeScript': ɵɵsanitizeScript, |
| 'ɵɵsanitizeUrl': ɵɵsanitizeUrl, |
| 'ɵɵsanitizeUrlOrResourceUrl': ɵɵsanitizeUrlOrResourceUrl, |
| }); }; |
| /** |
| * A mapping of the @angular/core API surface used in generated expressions to the actual symbols. |
| * |
| * This should be kept up to date with the public exports of @angular/core. |
| */ |
| var angularCoreEnv = (ɵ0$9)(); |
| |
| /** |
| * @license |
| * Copyright Google Inc. All Rights Reserved. |
| * |
| * Use of this source code is governed by an MIT-style license that can be |
| * found in the LICENSE file at https://angular.io/license |
| */ |
| var EMPTY_ARRAY$4 = []; |
| var moduleQueue = []; |
| /** |
| * Enqueues moduleDef to be checked later to see if scope can be set on its |
| * component declarations. |
| */ |
| function enqueueModuleForDelayedScoping(moduleType, ngModule) { |
| moduleQueue.push({ moduleType: moduleType, ngModule: ngModule }); |
| } |
| var flushingModuleQueue = false; |
| /** |
| * Loops over queued module definitions, if a given module definition has all of its |
| * declarations resolved, it dequeues that module definition and sets the scope on |
| * its declarations. |
| */ |
| function flushModuleScopingQueueAsMuchAsPossible() { |
| if (!flushingModuleQueue) { |
| flushingModuleQueue = true; |
| try { |
| for (var i = moduleQueue.length - 1; i >= 0; i--) { |
| var _a = moduleQueue[i], moduleType = _a.moduleType, ngModule = _a.ngModule; |
| if (ngModule.declarations && ngModule.declarations.every(isResolvedDeclaration)) { |
| // dequeue |
| moduleQueue.splice(i, 1); |
| setScopeOnDeclaredComponents(moduleType, ngModule); |
| } |
| } |
| } |
| finally { |
| flushingModuleQueue = false; |
| } |
| } |
| } |
| /** |
| * Returns truthy if a declaration has resolved. If the declaration happens to be |
| * an array of declarations, it will recurse to check each declaration in that array |
| * (which may also be arrays). |
| */ |
| function isResolvedDeclaration(declaration) { |
| if (Array.isArray(declaration)) { |
| return declaration.every(isResolvedDeclaration); |
| } |
| return !!resolveForwardRef(declaration); |
| } |
| /** |
| * Compiles a module in JIT mode. |
| * |
| * This function automatically gets called when a class has a `@NgModule` decorator. |
| */ |
| function compileNgModule(moduleType, ngModule) { |
| if (ngModule === void 0) { ngModule = {}; } |
| compileNgModuleDefs(moduleType, ngModule); |
| // Because we don't know if all declarations have resolved yet at the moment the |
| // NgModule decorator is executing, we're enqueueing the setting of module scope |
| // on its declarations to be run at a later time when all declarations for the module, |
| // including forward refs, have resolved. |
| enqueueModuleForDelayedScoping(moduleType, ngModule); |
| } |
| /** |
| * Compiles and adds the `ngModuleDef` and `ngInjectorDef` properties to the module class. |
| * |
| * It's possible to compile a module via this API which will allow duplicate declarations in its |
| * root. |
| */ |
| function compileNgModuleDefs(moduleType, ngModule, allowDuplicateDeclarationsInRoot) { |
| if (allowDuplicateDeclarationsInRoot === void 0) { allowDuplicateDeclarationsInRoot = false; } |
| ngDevMode && assertDefined(moduleType, 'Required value moduleType'); |
| ngDevMode && assertDefined(ngModule, 'Required value ngModule'); |
| var declarations = flatten(ngModule.declarations || EMPTY_ARRAY$4); |
| var ngModuleDef = null; |
| Object.defineProperty(moduleType, NG_MODULE_DEF, { |
| configurable: true, |
| get: function () { |
| if (ngModuleDef === null) { |
| ngModuleDef = getCompilerFacade().compileNgModule(angularCoreEnv, "ng:///" + moduleType.name + "/ngModuleDef.js", { |
| type: moduleType, |
| bootstrap: flatten(ngModule.bootstrap || EMPTY_ARRAY$4).map(resolveForwardRef), |
| declarations: declarations.map(resolveForwardRef), |
| imports: flatten(ngModule.imports || EMPTY_ARRAY$4) |
| .map(resolveForwardRef) |
| .map(expandModuleWithProviders), |
| exports: flatten(ngModule.exports || EMPTY_ARRAY$4) |
| .map(resolveForwardRef) |
| .map(expandModuleWithProviders), |
| emitInline: true, |
| schemas: ngModule.schemas ? flatten(ngModule.schemas) : null, |
| id: ngModule.id || null, |
| }); |
| } |
| return ngModuleDef; |
| } |
| }); |
| var ngInjectorDef = null; |
| Object.defineProperty(moduleType, NG_INJECTOR_DEF, { |
| get: function () { |
| if (ngInjectorDef === null) { |
| ngDevMode && verifySemanticsOfNgModuleDef(moduleType, allowDuplicateDeclarationsInRoot); |
| var meta = { |
| name: moduleType.name, |
| type: moduleType, |
| deps: reflectDependencies(moduleType), |
| providers: ngModule.providers || EMPTY_ARRAY$4, |
| imports: [ |
| (ngModule.imports || EMPTY_ARRAY$4).map(resolveForwardRef), |
| (ngModule.exports || EMPTY_ARRAY$4).map(resolveForwardRef), |
| ], |
| }; |
| ngInjectorDef = getCompilerFacade().compileInjector(angularCoreEnv, "ng:///" + moduleType.name + "/ngInjectorDef.js", meta); |
| } |
| return ngInjectorDef; |
| }, |
| // Make the property configurable in dev mode to allow overriding in tests |
| configurable: !!ngDevMode, |
| }); |
| } |
| function verifySemanticsOfNgModuleDef(moduleType, allowDuplicateDeclarationsInRoot) { |
| if (verifiedNgModule.get(moduleType)) |
| return; |
| verifiedNgModule.set(moduleType, true); |
| moduleType = resolveForwardRef(moduleType); |
| var ngModuleDef = getNgModuleDef(moduleType, true); |
| var errors = []; |
| var declarations = maybeUnwrapFn(ngModuleDef.declarations); |
| var imports = maybeUnwrapFn(ngModuleDef.imports); |
| flatten(imports) |
| .map(unwrapModuleWithProvidersImports) |
| .forEach(function (mod) { return verifySemanticsOfNgModuleDef(mod, false); }); |
| var exports = maybeUnwrapFn(ngModuleDef.exports); |
| declarations.forEach(verifyDeclarationsHaveDefinitions); |
| var combinedDeclarations = __spread(declarations.map(resolveForwardRef), flatten(imports.map(computeCombinedExports)).map(resolveForwardRef)); |
| exports.forEach(verifyExportsAreDeclaredOrReExported); |
| declarations.forEach(function (decl) { return verifyDeclarationIsUnique(decl, allowDuplicateDeclarationsInRoot); }); |
| declarations.forEach(verifyComponentEntryComponentsIsPartOfNgModule); |
| var ngModule = getAnnotation(moduleType, 'NgModule'); |
| if (ngModule) { |
| ngModule.imports && |
| flatten(ngModule.imports) |
| .map(unwrapModuleWithProvidersImports) |
| .forEach(function (mod) { return verifySemanticsOfNgModuleDef(mod, false); }); |
| ngModule.bootstrap && ngModule.bootstrap.forEach(verifyCorrectBootstrapType); |
| ngModule.bootstrap && ngModule.bootstrap.forEach(verifyComponentIsPartOfNgModule); |
| ngModule.entryComponents && ngModule.entryComponents.forEach(verifyComponentIsPartOfNgModule); |
| } |
| // Throw Error if any errors were detected. |
| if (errors.length) { |
| throw new Error(errors.join('\n')); |
| } |
| //////////////////////////////////////////////////////////////////////////////////////////////// |
| function verifyDeclarationsHaveDefinitions(type) { |
| type = resolveForwardRef(type); |
| var def = getComponentDef(type) || getDirectiveDef(type) || getPipeDef(type); |
| if (!def) { |
| errors.push("Unexpected value '" + stringifyForError(type) + "' declared by the module '" + stringifyForError(moduleType) + "'. Please add a @Pipe/@Directive/@Component annotation."); |
| } |
| } |
| function verifyExportsAreDeclaredOrReExported(type) { |
| type = resolveForwardRef(type); |
| var kind = getComponentDef(type) && 'component' || getDirectiveDef(type) && 'directive' || |
| getPipeDef(type) && 'pipe'; |
| if (kind) { |
| // only checked if we are declared as Component, Directive, or Pipe |
| // Modules don't need to be declared or imported. |
| if (combinedDeclarations.lastIndexOf(type) === -1) { |
| // We are exporting something which we don't explicitly declare or import. |
| errors.push("Can't export " + kind + " " + stringifyForError(type) + " from " + stringifyForError(moduleType) + " as it was neither declared nor imported!"); |
| } |
| } |
| } |
| function verifyDeclarationIsUnique(type, suppressErrors) { |
| type = resolveForwardRef(type); |
| var existingModule = ownerNgModule.get(type); |
| if (existingModule && existingModule !== moduleType) { |
| if (!suppressErrors) { |
| var modules = [existingModule, moduleType].map(stringifyForError).sort(); |
| errors.push("Type " + stringifyForError(type) + " is part of the declarations of 2 modules: " + modules[0] + " and " + modules[1] + "! " + |
| ("Please consider moving " + stringifyForError(type) + " to a higher module that imports " + modules[0] + " and " + modules[1] + ". ") + |
| ("You can also create a new NgModule that exports and includes " + stringifyForError(type) + " then import that NgModule in " + modules[0] + " and " + modules[1] + ".")); |
| } |
| } |
| else { |
| // Mark type as having owner. |
| ownerNgModule.set(type, moduleType); |
| } |
| } |
| function verifyComponentIsPartOfNgModule(type) { |
| type = resolveForwardRef(type); |
| var existingModule = ownerNgModule.get(type); |
| if (!existingModule) { |
| errors.push("Component " + stringifyForError(type) + " is not part of any NgModule or the module has not been imported into your module."); |
| } |
| } |
| function verifyCorrectBootstrapType(type) { |
| type = resolveForwardRef(type); |
| if (!getComponentDef(type)) { |
| errors.push(stringifyForError(type) + " cannot be used as an entry component."); |
| } |
| } |
| function verifyComponentEntryComponentsIsPartOfNgModule(type) { |
| type = resolveForwardRef(type); |
| if (getComponentDef(type)) { |
| // We know we are component |
| var component = getAnnotation(type, 'Component'); |
| if (component && component.entryComponents) { |
| component.entryComponents.forEach(verifyComponentIsPartOfNgModule); |
| } |
| } |
| } |
| } |
| function unwrapModuleWithProvidersImports(typeOrWithProviders) { |
| typeOrWithProviders = resolveForwardRef(typeOrWithProviders); |
| return typeOrWithProviders.ngModule || typeOrWithProviders; |
| } |
| function getAnnotation(type, name) { |
| var annotation = null; |
| collect(type.__annotations__); |
| collect(type.decorators); |
| return annotation; |
| function collect(annotations) { |
| if (annotations) { |
| annotations.forEach(readAnnotation); |
| } |
| } |
| function readAnnotation(decorator) { |
| if (!annotation) { |
| var proto = Object.getPrototypeOf(decorator); |
| if (proto.ngMetadataName == name) { |
| annotation = decorator; |
| } |
| else if (decorator.type) { |
| var proto_1 = Object.getPrototypeOf(decorator.type); |
| if (proto_1.ngMetadataName == name) { |
| annotation = decorator.args[0]; |
| } |
| } |
| } |
| } |
| } |
| /** |
| * Keep track of compiled components. This is needed because in tests we often want to compile the |
| * same component with more than one NgModule. This would cause an error unless we reset which |
| * NgModule the component belongs to. We keep the list of compiled components here so that the |
| * TestBed can reset it later. |
| */ |
| var ownerNgModule = new Map(); |
| var verifiedNgModule = new Map(); |
| function resetCompiledComponents() { |
| ownerNgModule = new Map(); |
| verifiedNgModule = new Map(); |
| moduleQueue.length = 0; |
| } |
| /** |
| * Computes the combined declarations of explicit declarations, as well as declarations inherited by |
| * traversing the exports of imported modules. |
| * @param type |
| */ |
| function computeCombinedExports(type) { |
| type = resolveForwardRef(type); |
| var ngModuleDef = getNgModuleDef(type, true); |
| return __spread(flatten(maybeUnwrapFn(ngModuleDef.exports).map(function (type) { |
| var ngModuleDef = getNgModuleDef(type); |
| if (ngModuleDef) { |
| verifySemanticsOfNgModuleDef(type, false); |
| return computeCombinedExports(type); |
| } |
| else { |
| return type; |
| } |
| }))); |
| } |
| /** |
| * Some declared components may be compiled asynchronously, and thus may not have their |
| * ngComponentDef set yet. If this is the case, then a reference to the module is written into |
| * the `ngSelectorScope` property of the declared type. |
| */ |
| function setScopeOnDeclaredComponents(moduleType, ngModule) { |
| var declarations = flatten(ngModule.declarations || EMPTY_ARRAY$4); |
| var transitiveScopes = transitiveScopesFor(moduleType); |
| declarations.forEach(function (declaration) { |
| if (declaration.hasOwnProperty(NG_COMPONENT_DEF)) { |
| // An `ngComponentDef` field exists - go ahead and patch the component directly. |
| var component = declaration; |
| var componentDef = getComponentDef(component); |
| patchComponentDefWithScope(componentDef, transitiveScopes); |
| } |
| else if (!declaration.hasOwnProperty(NG_DIRECTIVE_DEF) && !declaration.hasOwnProperty(NG_PIPE_DEF)) { |
| // Set `ngSelectorScope` for future reference when the component compilation finishes. |
| declaration.ngSelectorScope = moduleType; |
| } |
| }); |
| } |
| /** |
| * Patch the definition of a component with directives and pipes from the compilation scope of |
| * a given module. |
| */ |
| function patchComponentDefWithScope(componentDef, transitiveScopes) { |
| componentDef.directiveDefs = function () { |
| return Array.from(transitiveScopes.compilation.directives) |
| .map(function (dir) { return dir.hasOwnProperty(NG_COMPONENT_DEF) ? getComponentDef(dir) : |
| getDirectiveDef(dir); }) |
| .filter(function (def) { return !!def; }); |
| }; |
| componentDef.pipeDefs = function () { |
| return Array.from(transitiveScopes.compilation.pipes).map(function (pipe) { return getPipeDef(pipe); }); |
| }; |
| componentDef.schemas = transitiveScopes.schemas; |
| // Since we avoid Components/Directives/Pipes recompiling in case there are no overrides, we |
| // may face a problem where previously compiled defs available to a given Component/Directive |
| // are cached in TView and may become stale (in case any of these defs gets recompiled). In |
| // order to avoid this problem, we force fresh TView to be created. |
| componentDef.tView = null; |
| } |
| /** |
| * Compute the pair of transitive scopes (compilation scope and exported scope) for a given module. |
| * |
| * This operation is memoized and the result is cached on the module's definition. It can be called |
| * on modules with components that have not fully compiled yet, but the result should not be used |
| * until they have. |
| */ |
| function transitiveScopesFor(moduleType, processNgModuleFn) { |
| if (!isNgModule(moduleType)) { |
| throw new Error(moduleType.name + " does not have an ngModuleDef"); |
| } |
| var def = getNgModuleDef(moduleType); |
| if (def.transitiveCompileScopes !== null) { |
| return def.transitiveCompileScopes; |
| } |
| var scopes = { |
| schemas: def.schemas || null, |
| compilation: { |
| directives: new Set(), |
| pipes: new Set(), |
| }, |
| exported: { |
| directives: new Set(), |
| pipes: new Set(), |
| }, |
| }; |
| maybeUnwrapFn(def.declarations).forEach(function (declared) { |
| var declaredWithDefs = declared; |
| if (getPipeDef(declaredWithDefs)) { |
| scopes.compilation.pipes.add(declared); |
| } |
| else { |
| // Either declared has an ngComponentDef or ngDirectiveDef, or it's a component which hasn't |
| // had its template compiled yet. In either case, it gets added to the compilation's |
| // directives. |
| scopes.compilation.directives.add(declared); |
| } |
| }); |
| maybeUnwrapFn(def.imports).forEach(function (imported) { |
| var importedType = imported; |
| if (!isNgModule(importedType)) { |
| throw new Error("Importing " + importedType.name + " which does not have an ngModuleDef"); |
| } |
| if (processNgModuleFn) { |
| processNgModuleFn(importedType); |
| } |
| // When this module imports another, the imported module's exported directives and pipes are |
| // added to the compilation scope of this module. |
| var importedScope = transitiveScopesFor(importedType, processNgModuleFn); |
| importedScope.exported.directives.forEach(function (entry) { return scopes.compilation.directives.add(entry); }); |
| importedScope.exported.pipes.forEach(function (entry) { return scopes.compilation.pipes.add(entry); }); |
| }); |
| maybeUnwrapFn(def.exports).forEach(function (exported) { |
| var exportedType = exported; |
| // Either the type is a module, a pipe, or a component/directive (which may not have an |
| // ngComponentDef as it might be compiled asynchronously). |
| if (isNgModule(exportedType)) { |
| // When this module exports another, the exported module's exported directives and pipes are |
| // added to both the compilation and exported scopes of this module. |
| var exportedScope = transitiveScopesFor(exportedType, processNgModuleFn); |
| exportedScope.exported.directives.forEach(function (entry) { |
| scopes.compilation.directives.add(entry); |
| scopes.exported.directives.add(entry); |
| }); |
| exportedScope.exported.pipes.forEach(function (entry) { |
| scopes.compilation.pipes.add(entry); |
| scopes.exported.pipes.add(entry); |
| }); |
| } |
| else if (getPipeDef(exportedType)) { |
| scopes.exported.pipes.add(exportedType); |
| } |
| else { |
| scopes.exported.directives.add(exportedType); |
| } |
| }); |
| def.transitiveCompileScopes = scopes; |
| return scopes; |
| } |
| function expandModuleWithProviders(value) { |
| if (isModuleWithProviders(value)) { |
| return value.ngModule; |
| } |
| return value; |
| } |
| function isModuleWithProviders(value) { |
| return value.ngModule !== undefined; |
| } |
| function isNgModule(value) { |
| return !!getNgModuleDef(value); |
| } |
| |
| /** |
| * @license |
| * Copyright Google Inc. All Rights Reserved. |
| * |
| * Use of this source code is governed by an MIT-style license that can be |
| * found in the LICENSE file at https://angular.io/license |
| */ |
| /** |
| * Compile an Angular component according to its decorator metadata, and patch the resulting |
| * ngComponentDef onto the component type. |
| * |
| * Compilation may be asynchronous (due to the need to resolve URLs for the component template or |
| * other resources, for example). In the event that compilation is not immediate, `compileComponent` |
| * will enqueue resource resolution into a global queue and will fail to return the `ngComponentDef` |
| * until the global queue has been resolved with a call to `resolveComponentResources`. |
| */ |
| function compileComponent(type, metadata) { |
| var ngComponentDef = null; |
| // Metadata may have resources which need to be resolved. |
| maybeQueueResolutionOfComponentResources(type, metadata); |
| Object.defineProperty(type, NG_COMPONENT_DEF, { |
| get: function () { |
| var compiler = getCompilerFacade(); |
| if (ngComponentDef === null) { |
| if (componentNeedsResolution(metadata)) { |
| var error = ["Component '" + type.name + "' is not resolved:"]; |
| if (metadata.templateUrl) { |
| error.push(" - templateUrl: " + metadata.templateUrl); |
| } |
| if (metadata.styleUrls && metadata.styleUrls.length) { |
| error.push(" - styleUrls: " + JSON.stringify(metadata.styleUrls)); |
| } |
| error.push("Did you run and wait for 'resolveComponentResources()'?"); |
| throw new Error(error.join('\n')); |
| } |
| var templateUrl = metadata.templateUrl || "ng:///" + type.name + "/template.html"; |
| var meta = __assign({}, directiveMetadata(type, metadata), { typeSourceSpan: compiler.createParseSourceSpan('Component', type.name, templateUrl), template: metadata.template || '', preserveWhitespaces: metadata.preserveWhitespaces || false, styles: metadata.styles || EMPTY_ARRAY$2, animations: metadata.animations, directives: [], changeDetection: metadata.changeDetection, pipes: new Map(), encapsulation: metadata.encapsulation || exports.ViewEncapsulation.Emulated, interpolation: metadata.interpolation, viewProviders: metadata.viewProviders || null }); |
| if (meta.usesInheritance) { |
| addBaseDefToUndecoratedParents(type); |
| } |
| ngComponentDef = compiler.compileComponent(angularCoreEnv, templateUrl, meta); |
| // When NgModule decorator executed, we enqueued the module definition such that |
| // it would only dequeue and add itself as module scope to all of its declarations, |
| // but only if if all of its declarations had resolved. This call runs the check |
| // to see if any modules that are in the queue can be dequeued and add scope to |
| // their declarations. |
| flushModuleScopingQueueAsMuchAsPossible(); |
| // If component compilation is async, then the @NgModule annotation which declares the |
| // component may execute and set an ngSelectorScope property on the component type. This |
| // allows the component to patch itself with directiveDefs from the module after it |
| // finishes compiling. |
| if (hasSelectorScope(type)) { |
| var scopes = transitiveScopesFor(type.ngSelectorScope); |
| patchComponentDefWithScope(ngComponentDef, scopes); |
| } |
| } |
| return ngComponentDef; |
| }, |
| // Make the property configurable in dev mode to allow overriding in tests |
| configurable: !!ngDevMode, |
| }); |
| // Add ngInjectableDef so components are reachable through the module injector by default |
| // This is mostly to support injecting components in tests. In real application code, |
| // components should be retrieved through the node injector, so this isn't a problem. |
| compileInjectable(type); |
| } |
| function hasSelectorScope(component) { |
| return component.ngSelectorScope !== undefined; |
| } |
| /** |
| * Compile an Angular directive according to its decorator metadata, and patch the resulting |
| * ngDirectiveDef onto the component type. |
| * |
| * In the event that compilation is not immediate, `compileDirective` will return a `Promise` which |
| * will resolve when compilation completes and the directive becomes usable. |
| */ |
| function compileDirective(type, directive) { |
| var ngDirectiveDef = null; |
| Object.defineProperty(type, NG_DIRECTIVE_DEF, { |
| get: function () { |
| if (ngDirectiveDef === null) { |
| var name_1 = type && type.name; |
| var sourceMapUrl = "ng:///" + name_1 + "/ngDirectiveDef.js"; |
| var compiler = getCompilerFacade(); |
| var facade = directiveMetadata(type, directive); |
| facade.typeSourceSpan = compiler.createParseSourceSpan('Directive', name_1, sourceMapUrl); |
| if (facade.usesInheritance) { |
| addBaseDefToUndecoratedParents(type); |
| } |
| ngDirectiveDef = compiler.compileDirective(angularCoreEnv, sourceMapUrl, facade); |
| } |
| return ngDirectiveDef; |
| }, |
| // Make the property configurable in dev mode to allow overriding in tests |
| configurable: !!ngDevMode, |
| }); |
| // Add ngInjectableDef so directives are reachable through the module injector by default |
| // This is mostly to support injecting directives in tests. In real application code, |
| // directives should be retrieved through the node injector, so this isn't a problem. |
| compileInjectable(type); |
| } |
| function extendsDirectlyFromObject(type) { |
| return Object.getPrototypeOf(type.prototype) === Object.prototype; |
| } |
| /** |
| * Extract the `R3DirectiveMetadata` for a particular directive (either a `Directive` or a |
| * `Component`). |
| */ |
| function directiveMetadata(type, metadata) { |
| // Reflect inputs and outputs. |
| var propMetadata = getReflect().ownPropMetadata(type); |
| return { |
| name: type.name, |
| type: type, |
| typeArgumentCount: 0, |
| selector: metadata.selector, |
| deps: reflectDependencies(type), |
| host: metadata.host || EMPTY_OBJ, |
| propMetadata: propMetadata, |
| inputs: metadata.inputs || EMPTY_ARRAY$2, |
| outputs: metadata.outputs || EMPTY_ARRAY$2, |
| queries: extractQueriesMetadata(type, propMetadata, isContentQuery), |
| lifecycle: { usesOnChanges: type.prototype.hasOwnProperty('ngOnChanges') }, |
| typeSourceSpan: null, |
| usesInheritance: !extendsDirectlyFromObject(type), |
| exportAs: extractExportAs(metadata.exportAs), |
| providers: metadata.providers || null, |
| viewQueries: extractQueriesMetadata(type, propMetadata, isViewQuery), |
| }; |
| } |
| /** |
| * Adds an `ngBaseDef` to all parent classes of a type that don't have an Angular decorator. |
| */ |
| function addBaseDefToUndecoratedParents(type) { |
| var objPrototype = Object.prototype; |
| var parent = Object.getPrototypeOf(type); |
| // Go up the prototype until we hit `Object`. |
| while (parent && parent !== objPrototype) { |
| // Since inheritance works if the class was annotated already, we only need to add |
| // the base def if there are no annotations and the base def hasn't been created already. |
| if (!getDirectiveDef(parent) && !getComponentDef(parent) && !getBaseDef(parent)) { |
| var facade = extractBaseDefMetadata(parent); |
| facade && compileBase(parent, facade); |
| } |
| parent = Object.getPrototypeOf(parent); |
| } |
| } |
| /** Compiles the base metadata into a base definition. */ |
| function compileBase(type, facade) { |
| var ngBaseDef = null; |
| Object.defineProperty(type, NG_BASE_DEF, { |
| get: function () { |
| if (ngBaseDef === null) { |
| var name_2 = type && type.name; |
| var sourceMapUrl = "ng://" + name_2 + "/ngBaseDef.js"; |
| var compiler = getCompilerFacade(); |
| ngBaseDef = compiler.compileBase(angularCoreEnv, sourceMapUrl, facade); |
| } |
| return ngBaseDef; |
| }, |
| // Make the property configurable in dev mode to allow overriding in tests |
| configurable: !!ngDevMode, |
| }); |
| } |
| /** Extracts the metadata necessary to construct an `ngBaseDef` from a class. */ |
| function extractBaseDefMetadata(type) { |
| var propMetadata = getReflect().ownPropMetadata(type); |
| var viewQueries = extractQueriesMetadata(type, propMetadata, isViewQuery); |
| var queries = extractQueriesMetadata(type, propMetadata, isContentQuery); |
| var inputs; |
| var outputs; |
| // We only need to know whether there are any HostListener or HostBinding |
| // decorators present, the parsing logic is in the compiler already. |
| var hasHostDecorators = false; |
| var _loop_1 = function (field) { |
| propMetadata[field].forEach(function (ann) { |
| var metadataName = ann.ngMetadataName; |
| if (metadataName === 'Input') { |
| inputs = inputs || {}; |
| inputs[field] = ann.bindingPropertyName ? [ann.bindingPropertyName, field] : field; |
| } |
| else if (metadataName === 'Output') { |
| outputs = outputs || {}; |
| outputs[field] = ann.bindingPropertyName || field; |
| } |
| else if (metadataName === 'HostBinding' || metadataName === 'HostListener') { |
| hasHostDecorators = true; |
| } |
| }); |
| }; |
| for (var field in propMetadata) { |
| _loop_1(field); |
| } |
| // Only generate the base def if there's any info inside it. |
| if (inputs || outputs || viewQueries.length || queries.length || hasHostDecorators) { |
| return { name: type.name, inputs: inputs, outputs: outputs, viewQueries: viewQueries, queries: queries, propMetadata: propMetadata }; |
| } |
| return null; |
| } |
| function convertToR3QueryPredicate(selector) { |
| return typeof selector === 'string' ? splitByComma(selector) : resolveForwardRef(selector); |
| } |
| function convertToR3QueryMetadata(propertyName, ann) { |
| return { |
| propertyName: propertyName, |
| predicate: convertToR3QueryPredicate(ann.selector), |
| descendants: ann.descendants, |
| first: ann.first, |
| read: ann.read ? ann.read : null, |
| static: !!ann.static |
| }; |
| } |
| function extractQueriesMetadata(type, propMetadata, isQueryAnn) { |
| var queriesMeta = []; |
| var _loop_2 = function (field) { |
| if (propMetadata.hasOwnProperty(field)) { |
| var annotations_1 = propMetadata[field]; |
| annotations_1.forEach(function (ann) { |
| if (isQueryAnn(ann)) { |
| if (!ann.selector) { |
| throw new Error("Can't construct a query for the property \"" + field + "\" of " + |
| ("\"" + stringifyForError(type) + "\" since the query selector wasn't defined.")); |
| } |
| if (annotations_1.some(isInputAnn)) { |
| throw new Error("Cannot combine @Input decorators with query decorators"); |
| } |
| queriesMeta.push(convertToR3QueryMetadata(field, ann)); |
| } |
| }); |
| } |
| }; |
| for (var field in propMetadata) { |
| _loop_2(field); |
| } |
| return queriesMeta; |
| } |
| function extractExportAs(exportAs) { |
| if (exportAs === undefined) { |
| return null; |
| } |
| return exportAs.split(',').map(function (part) { return part.trim(); }); |
| } |
| function isContentQuery(value) { |
| var name = value.ngMetadataName; |
| return name === 'ContentChild' || name === 'ContentChildren'; |
| } |
| function isViewQuery(value) { |
| var name = value.ngMetadataName; |
| return name === 'ViewChild' || name === 'ViewChildren'; |
| } |
| function isInputAnn(value) { |
| return value.ngMetadataName === 'Input'; |
| } |
| function splitByComma(value) { |
| return value.split(',').map(function (piece) { return piece.trim(); }); |
| } |
| |
| /** |
| * @license |
| * Copyright Google Inc. All Rights Reserved. |
| * |
| * Use of this source code is governed by an MIT-style license that can be |
| * found in the LICENSE file at https://angular.io/license |
| */ |
| function compilePipe(type, meta) { |
| var ngPipeDef = null; |
| Object.defineProperty(type, NG_PIPE_DEF, { |
| get: function () { |
| if (ngPipeDef === null) { |
| var typeName = type.name; |
| ngPipeDef = |
| getCompilerFacade().compilePipe(angularCoreEnv, "ng:///" + typeName + "/ngPipeDef.js", { |
| type: type, |
| typeArgumentCount: 0, |
| name: typeName, |
| deps: reflectDependencies(type), |
| pipeName: meta.name, |
| pure: meta.pure !== undefined ? meta.pure : true |
| }); |
| } |
| return ngPipeDef; |
| }, |
| // Make the property configurable in dev mode to allow overriding in tests |
| configurable: !!ngDevMode, |
| }); |
| } |
| |
| /** |
| * @license |
| * Copyright Google Inc. All Rights Reserved. |
| * |
| * Use of this source code is governed by an MIT-style license that can be |
| * found in the LICENSE file at https://angular.io/license |
| */ |
| var ɵ0$a = function (dir) { |
| if (dir === void 0) { dir = {}; } |
| return dir; |
| }, ɵ1$2 = function (type, meta) { return SWITCH_COMPILE_DIRECTIVE(type, meta); }; |
| /** |
| * Type of the Directive metadata. |
| * |
| * @publicApi |
| */ |
| var Directive = makeDecorator('Directive', ɵ0$a, undefined, undefined, ɵ1$2); |
| var ɵ2$1 = function (c) { |
| if (c === void 0) { c = {}; } |
| return (__assign({ changeDetection: exports.ChangeDetectionStrategy.Default }, c)); |
| }, ɵ3$1 = function (type, meta) { return SWITCH_COMPILE_COMPONENT(type, meta); }; |
| /** |
| * Component decorator and metadata. |
| * |
| * @Annotation |
| * @publicApi |
| */ |
| var Component = makeDecorator('Component', ɵ2$1, Directive, undefined, ɵ3$1); |
| var ɵ4 = function (p) { return (__assign({ pure: true }, p)); }, ɵ5 = function (type, meta) { return SWITCH_COMPILE_PIPE(type, meta); }; |
| /** |
| * @Annotation |
| * @publicApi |
| */ |
| var Pipe = makeDecorator('Pipe', ɵ4, undefined, undefined, ɵ5); |
| var ɵ6 = function (bindingPropertyName) { return ({ bindingPropertyName: bindingPropertyName }); }; |
| /** |
| * @Annotation |
| * @publicApi |
| */ |
| var Input = makePropDecorator('Input', ɵ6); |
| var ɵ7 = function (bindingPropertyName) { return ({ bindingPropertyName: bindingPropertyName }); }; |
| /** |
| * @Annotation |
| * @publicApi |
| */ |
| var Output = makePropDecorator('Output', ɵ7); |
| var ɵ8 = function (hostPropertyName) { return ({ hostPropertyName: hostPropertyName }); }; |
| /** |
| * @Annotation |
| * @publicApi |
| */ |
| var HostBinding = makePropDecorator('HostBinding', ɵ8); |
| var ɵ9 = function (eventName, args) { return ({ eventName: eventName, args: args }); }; |
| /** |
| * Decorator that binds a DOM event to a host listener and supplies configuration metadata. |
| * Angular invokes the supplied handler method when the host element emits the specified event, |
| * and updates the bound element with the result. |
| * |
| * If the handler method returns false, applies `preventDefault` on the bound element. |
| * |
| * @usageNotes |
| * |
| * The following example declares a directive |
| * that attaches a click listener to a button and counts clicks. |
| * |
| * ```ts |
| * @Directive({selector: 'button[counting]'}) |
| * class CountClicks { |
| * numberOfClicks = 0; |
| * |
| * @HostListener('click', ['$event.target']) |
| * onClick(btn) { |
| * console.log('button', btn, 'number of clicks:', this.numberOfClicks++); |
| * } |
| * } |
| * |
| * @Component({ |
| * selector: 'app', |
| * template: '<button counting>Increment</button>', |
| * }) |
| * class App {} |
| * ``` |
| * |
| * @Annotation |
| * @publicApi |
| */ |
| var HostListener = makePropDecorator('HostListener', ɵ9); |
| var SWITCH_COMPILE_COMPONENT__POST_R3__ = compileComponent; |
| var SWITCH_COMPILE_DIRECTIVE__POST_R3__ = compileDirective; |
| var SWITCH_COMPILE_PIPE__POST_R3__ = compilePipe; |
| var SWITCH_COMPILE_COMPONENT__PRE_R3__ = noop; |
| var SWITCH_COMPILE_DIRECTIVE__PRE_R3__ = noop; |
| var SWITCH_COMPILE_PIPE__PRE_R3__ = noop; |
| var SWITCH_COMPILE_COMPONENT = SWITCH_COMPILE_COMPONENT__PRE_R3__; |
| var SWITCH_COMPILE_DIRECTIVE = SWITCH_COMPILE_DIRECTIVE__PRE_R3__; |
| var SWITCH_COMPILE_PIPE = SWITCH_COMPILE_PIPE__PRE_R3__; |
| |
| /** |
| * @license |
| * Copyright Google Inc. All Rights Reserved. |
| * |
| * Use of this source code is governed by an MIT-style license that can be |
| * found in the LICENSE file at https://angular.io/license |
| */ |
| var ɵ0$b = function (ngModule) { return ngModule; }, ɵ1$3 = |
| /** |
| * Decorator that marks the following class as an NgModule, and supplies |
| * configuration metadata for it. |
| * |
| * * The `declarations` and `entryComponents` options configure the compiler |
| * with information about what belongs to the NgModule. |
| * * The `providers` options configures the NgModule's injector to provide |
| * dependencies the NgModule members. |
| * * The `imports` and `exports` options bring in members from other modules, and make |
| * this module's members available to others. |
| */ |
| function (type, meta) { return SWITCH_COMPILE_NGMODULE(type, meta); }; |
| /** |
| * @Annotation |
| * @publicApi |
| */ |
| var NgModule = makeDecorator('NgModule', ɵ0$b, undefined, undefined, ɵ1$3); |
| function preR3NgModuleCompile(moduleType, metadata) { |
| var imports = (metadata && metadata.imports) || []; |
| if (metadata && metadata.exports) { |
| imports = __spread(imports, [metadata.exports]); |
| } |
| moduleType.ngInjectorDef = ɵɵdefineInjector({ |
| factory: convertInjectableProviderToFactory(moduleType, { useClass: moduleType }), |
| providers: metadata && metadata.providers, |
| imports: imports, |
| }); |
| } |
| var SWITCH_COMPILE_NGMODULE__POST_R3__ = compileNgModule; |
| var SWITCH_COMPILE_NGMODULE__PRE_R3__ = preR3NgModuleCompile; |
| var SWITCH_COMPILE_NGMODULE = SWITCH_COMPILE_NGMODULE__PRE_R3__; |
| |
| /** |
| * @license |
| * Copyright Google Inc. All Rights Reserved. |
| * |
| * Use of this source code is governed by an MIT-style license that can be |
| * found in the LICENSE file at https://angular.io/license |
| */ |
| |
| /** |
| * @license |
| * Copyright Google Inc. All Rights Reserved. |
| * |
| * Use of this source code is governed by an MIT-style license that can be |
| * found in the LICENSE file at https://angular.io/license |
| */ |
| /** |
| * A function that will be executed when an application is initialized. |
| * |
| * @publicApi |
| */ |
| var APP_INITIALIZER = new InjectionToken('Application Initializer'); |
| /** |
| * A class that reflects the state of running {@link APP_INITIALIZER}s. |
| * |
| * @publicApi |
| */ |
| var ApplicationInitStatus = /** @class */ (function () { |
| function ApplicationInitStatus(appInits) { |
| var _this = this; |
| this.appInits = appInits; |
| this.initialized = false; |
| this.done = false; |
| this.donePromise = new Promise(function (res, rej) { |
| _this.resolve = res; |
| _this.reject = rej; |
| }); |
| } |
| /** @internal */ |
| ApplicationInitStatus.prototype.runInitializers = function () { |
| var _this = this; |
| if (this.initialized) { |
| return; |
| } |
| var asyncInitPromises = []; |
| var complete = function () { |
| _this.done = true; |
| _this.resolve(); |
| }; |
| if (this.appInits) { |
| for (var i = 0; i < this.appInits.length; i++) { |
| var initResult = this.appInits[i](); |
| if (isPromise(initResult)) { |
| asyncInitPromises.push(initResult); |
| } |
| } |
| } |
| Promise.all(asyncInitPromises).then(function () { complete(); }).catch(function (e) { _this.reject(e); }); |
| if (asyncInitPromises.length === 0) { |
| complete(); |
| } |
| this.initialized = true; |
| }; |
| ApplicationInitStatus = __decorate([ |
| Injectable(), |
| __param(0, Inject(APP_INITIALIZER)), __param(0, Optional()), |
| __metadata("design:paramtypes", [Array]) |
| ], ApplicationInitStatus); |
| return ApplicationInitStatus; |
| }()); |
| |
| /** |
| * @license |
| * Copyright Google Inc. All Rights Reserved. |
| * |
| * Use of this source code is governed by an MIT-style license that can be |
| * found in the LICENSE file at https://angular.io/license |
| */ |
| /** |
| * A DI Token representing a unique string id assigned to the application by Angular and used |
| * primarily for prefixing application attributes and CSS styles when |
| * {@link ViewEncapsulation#Emulated ViewEncapsulation.Emulated} is being used. |
| * |
| * If you need to avoid randomly generated value to be used as an application id, you can provide |
| * a custom value via a DI provider <!-- TODO: provider --> configuring the root {@link Injector} |
| * using this token. |
| * @publicApi |
| */ |
| var APP_ID = new InjectionToken('AppId'); |
| function _appIdRandomProviderFactory() { |
| return "" + _randomChar() + _randomChar() + _randomChar(); |
| } |
| /** |
| * Providers that will generate a random APP_ID_TOKEN. |
| * @publicApi |
| */ |
| var APP_ID_RANDOM_PROVIDER = { |
| provide: APP_ID, |
| useFactory: _appIdRandomProviderFactory, |
| deps: [], |
| }; |
| function _randomChar() { |
| return String.fromCharCode(97 + Math.floor(Math.random() * 25)); |
| } |
| /** |
| * A function that will be executed when a platform is initialized. |
| * @publicApi |
| */ |
| var PLATFORM_INITIALIZER = new InjectionToken('Platform Initializer'); |
| /** |
| * A token that indicates an opaque platform id. |
| * @publicApi |
| */ |
| var PLATFORM_ID = new InjectionToken('Platform ID'); |
| /** |
| * All callbacks provided via this token will be called for every component that is bootstrapped. |
| * Signature of the callback: |
| * |
| * `(componentRef: ComponentRef) => void`. |
| * |
| * @publicApi |
| */ |
| var APP_BOOTSTRAP_LISTENER = new InjectionToken('appBootstrapListener'); |
| /** |
| * A token which indicates the root directory of the application |
| * @publicApi |
| */ |
| var PACKAGE_ROOT_URL = new InjectionToken('Application Packages Root URL'); |
| |
| /** |
| * @license |
| * Copyright Google Inc. All Rights Reserved. |
| * |
| * Use of this source code is governed by an MIT-style license that can be |
| * found in the LICENSE file at https://angular.io/license |
| */ |
| var Console = /** @class */ (function () { |
| function Console() { |
| } |
| Console.prototype.log = function (message) { |
| // tslint:disable-next-line:no-console |
| console.log(message); |
| }; |
| // Note: for reporting errors use `DOM.logError()` as it is platform specific |
| Console.prototype.warn = function (message) { |
| // tslint:disable-next-line:no-console |
| console.warn(message); |
| }; |
| Console = __decorate([ |
| Injectable() |
| ], Console); |
| return Console; |
| }()); |
| |
| /** |
| * @license |
| * Copyright Google Inc. All Rights Reserved. |
| * |
| * Use of this source code is governed by an MIT-style license that can be |
| * found in the LICENSE file at https://angular.io/license |
| */ |
| /** |
| * Provide this token to set the locale of your application. |
| * It is used for i18n extraction, by i18n pipes (DatePipe, I18nPluralPipe, CurrencyPipe, |
| * DecimalPipe and PercentPipe) and by ICU expressions. |
| * |
| * See the [i18n guide](guide/i18n#setting-up-locale) for more information. |
| * |
| * @usageNotes |
| * ### Example |
| * |
| * ```typescript |
| * import { LOCALE_ID } from '@angular/core'; |
| * import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; |
| * import { AppModule } from './app/app.module'; |
| * |
| * platformBrowserDynamic().bootstrapModule(AppModule, { |
| * providers: [{provide: LOCALE_ID, useValue: 'en-US' }] |
| * }); |
| * ``` |
| * |
| * @publicApi |
| */ |
| var LOCALE_ID$1 = new InjectionToken('LocaleId'); |
| /** |
| * Use this token at bootstrap to provide the content of your translation file (`xtb`, |
| * `xlf` or `xlf2`) when you want to translate your application in another language. |
| * |
| * See the [i18n guide](guide/i18n#merge) for more information. |
| * |
| * @usageNotes |
| * ### Example |
| * |
| * ```typescript |
| * import { TRANSLATIONS } from '@angular/core'; |
| * import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; |
| * import { AppModule } from './app/app.module'; |
| * |
| * // content of your translation file |
| * const translations = '....'; |
| * |
| * platformBrowserDynamic().bootstrapModule(AppModule, { |
| * providers: [{provide: TRANSLATIONS, useValue: translations }] |
| * }); |
| * ``` |
| * |
| * @publicApi |
| */ |
| var TRANSLATIONS$1 = new InjectionToken('Translations'); |
| /** |
| * Provide this token at bootstrap to set the format of your {@link TRANSLATIONS}: `xtb`, |
| * `xlf` or `xlf2`. |
| * |
| * See the [i18n guide](guide/i18n#merge) for more information. |
| * |
| * @usageNotes |
| * ### Example |
| * |
| * ```typescript |
| * import { TRANSLATIONS_FORMAT } from '@angular/core'; |
| * import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; |
| * import { AppModule } from './app/app.module'; |
| * |
| * platformBrowserDynamic().bootstrapModule(AppModule, { |
| * providers: [{provide: TRANSLATIONS_FORMAT, useValue: 'xlf' }] |
| * }); |
| * ``` |
| * |
| * @publicApi |
| */ |
| var TRANSLATIONS_FORMAT = new InjectionToken('TranslationsFormat'); |
| (function (MissingTranslationStrategy) { |
| MissingTranslationStrategy[MissingTranslationStrategy["Error"] = 0] = "Error"; |
| MissingTranslationStrategy[MissingTranslationStrategy["Warning"] = 1] = "Warning"; |
| MissingTranslationStrategy[MissingTranslationStrategy["Ignore"] = 2] = "Ignore"; |
| })(exports.MissingTranslationStrategy || (exports.MissingTranslationStrategy = {})); |
| |
| /** |
| * @license |
| * Copyright Google Inc. All Rights Reserved. |
| * |
| * Use of this source code is governed by an MIT-style license that can be |
| * found in the LICENSE file at https://angular.io/license |
| */ |
| /** |
| * Combination of NgModuleFactory and ComponentFactorys. |
| * |
| * @publicApi |
| */ |
| var ModuleWithComponentFactories = /** @class */ (function () { |
| function ModuleWithComponentFactories(ngModuleFactory, componentFactories) { |
| this.ngModuleFactory = ngModuleFactory; |
| this.componentFactories = componentFactories; |
| } |
| return ModuleWithComponentFactories; |
| }()); |
| function _throwError() { |
| throw new Error("Runtime compiler is not loaded"); |
| } |
| var Compiler_compileModuleSync__PRE_R3__ = _throwError; |
| var Compiler_compileModuleSync__POST_R3__ = function (moduleType) { |
| return new NgModuleFactory$1(moduleType); |
| }; |
| var Compiler_compileModuleSync = Compiler_compileModuleSync__PRE_R3__; |
| var Compiler_compileModuleAsync__PRE_R3__ = _throwError; |
| var Compiler_compileModuleAsync__POST_R3__ = function (moduleType) { |
| return Promise.resolve(Compiler_compileModuleSync__POST_R3__(moduleType)); |
| }; |
| var Compiler_compileModuleAsync = Compiler_compileModuleAsync__PRE_R3__; |
| var Compiler_compileModuleAndAllComponentsSync__PRE_R3__ = _throwError; |
| var Compiler_compileModuleAndAllComponentsSync__POST_R3__ = function (moduleType) { |
| var ngModuleFactory = Compiler_compileModuleSync__POST_R3__(moduleType); |
| var moduleDef = getNgModuleDef(moduleType); |
| var componentFactories = maybeUnwrapFn(moduleDef.declarations) |
| .reduce(function (factories, declaration) { |
| var componentDef = getComponentDef(declaration); |
| componentDef && factories.push(new ComponentFactory$1(componentDef)); |
| return factories; |
| }, []); |
| return new ModuleWithComponentFactories(ngModuleFactory, componentFactories); |
| }; |
| var Compiler_compileModuleAndAllComponentsSync = Compiler_compileModuleAndAllComponentsSync__PRE_R3__; |
| var Compiler_compileModuleAndAllComponentsAsync__PRE_R3__ = _throwError; |
| var Compiler_compileModuleAndAllComponentsAsync__POST_R3__ = function (moduleType) { |
| return Promise.resolve(Compiler_compileModuleAndAllComponentsSync__POST_R3__(moduleType)); |
| }; |
| var Compiler_compileModuleAndAllComponentsAsync = Compiler_compileModuleAndAllComponentsAsync__PRE_R3__; |
| /** |
| * Low-level service for running the angular compiler during runtime |
| * to create {@link ComponentFactory}s, which |
| * can later be used to create and render a Component instance. |
| * |
| * Each `@NgModule` provides an own `Compiler` to its injector, |
| * that will use the directives/pipes of the ng module for compilation |
| * of components. |
| * |
| * @publicApi |
| */ |
| var Compiler = /** @class */ (function () { |
| function Compiler() { |
| /** |
| * Compiles the given NgModule and all of its components. All templates of the components listed |
| * in `entryComponents` have to be inlined. |
| */ |
| this.compileModuleSync = Compiler_compileModuleSync; |
| /** |
| * Compiles the given NgModule and all of its components |
| */ |
| this.compileModuleAsync = Compiler_compileModuleAsync; |
| /** |
| * Same as {@link #compileModuleSync} but also creates ComponentFactories for all components. |
| */ |
| this.compileModuleAndAllComponentsSync = Compiler_compileModuleAndAllComponentsSync; |
| /** |
| * Same as {@link #compileModuleAsync} but also creates ComponentFactories for all components. |
| */ |
| this.compileModuleAndAllComponentsAsync = Compiler_compileModuleAndAllComponentsAsync; |
| } |
| /** |
| * Clears all caches. |
| */ |
| Compiler.prototype.clearCache = function () { }; |
| /** |
| * Clears the cache for the given component/ngModule. |
| */ |
| Compiler.prototype.clearCacheFor = function (type) { }; |
| /** |
| * Returns the id for a given NgModule, if one is defined and known to the compiler. |
| */ |
| Compiler.prototype.getModuleId = function (moduleType) { return undefined; }; |
| Compiler = __decorate([ |
| Injectable() |
| ], Compiler); |
| return Compiler; |
| }()); |
| /** |
| * Token to provide CompilerOptions in the platform injector. |
| * |
| * @publicApi |
| */ |
| var COMPILER_OPTIONS = new InjectionToken('compilerOptions'); |
| /** |
| * A factory for creating a Compiler |
| * |
| * @publicApi |
| */ |
| var CompilerFactory = /** @class */ (function () { |
| function CompilerFactory() { |
| } |
| return CompilerFactory; |
| }()); |
| |
| /** |
| * @license |
| * Copyright Google Inc. All Rights Reserved. |
| * |
| * Use of this source code is governed by an MIT-style license that can be |
| * found in the LICENSE file at https://angular.io/license |
| */ |
| var trace; |
| var events; |
| function detectWTF() { |
| var wtf = _global /** TODO #9100 */['wtf']; |
| if (wtf) { |
| trace = wtf['trace']; |
| if (trace) { |
| events = trace['events']; |
| return true; |
| } |
| } |
| return false; |
| } |
| function createScope(signature, flags) { |
| if (flags === void 0) { flags = null; } |
| return events.createScope(signature, flags); |
| } |
| function leave(scope, returnValue) { |
| trace.leaveScope(scope, returnValue); |
| return returnValue; |
| } |
| function startTimeRange(rangeType, action) { |
| return trace.beginTimeRange(rangeType, action); |
| } |
| function endTimeRange(range) { |
| trace.endTimeRange(range); |
| } |
| |
| /** |
| * @license |
| * Copyright Google Inc. All Rights Reserved. |
| * |
| * Use of this source code is governed by an MIT-style license that can be |
| * found in the LICENSE file at https://angular.io/license |
| */ |
| /** |
| * True if WTF is enabled. |
| */ |
| var wtfEnabled = detectWTF(); |
| function noopScope(arg0, arg1) { |
| return null; |
| } |
| /** |
| * Create trace scope. |
| * |
| * Scopes must be strictly nested and are analogous to stack frames, but |
| * do not have to follow the stack frames. Instead it is recommended that they follow logical |
| * nesting. You may want to use |
| * [Event |
| * Signatures](http://google.github.io/tracing-framework/instrumenting-code.html#custom-events) |
| * as they are defined in WTF. |
| * |
| * Used to mark scope entry. The return value is used to leave the scope. |
| * |
| * var myScope = wtfCreateScope('MyClass#myMethod(ascii someVal)'); |
| * |
| * someMethod() { |
| * var s = myScope('Foo'); // 'Foo' gets stored in tracing UI |
| * // DO SOME WORK HERE |
| * return wtfLeave(s, 123); // Return value 123 |
| * } |
| * |
| * Note, adding try-finally block around the work to ensure that `wtfLeave` gets called can |
| * negatively impact the performance of your application. For this reason we recommend that |
| * you don't add them to ensure that `wtfLeave` gets called. In production `wtfLeave` is a noop and |
| * so try-finally block has no value. When debugging perf issues, skipping `wtfLeave`, do to |
| * exception, will produce incorrect trace, but presence of exception signifies logic error which |
| * needs to be fixed before the app should be profiled. Add try-finally only when you expect that |
| * an exception is expected during normal execution while profiling. |
| * |
| * @publicApi |
| * @deprecated the Web Tracing Framework is no longer supported in Angular |
| */ |
| var wtfCreateScope = wtfEnabled ? createScope : function (signature, flags) { return noopScope; }; |
| /** |
| * Used to mark end of Scope. |
| * |
| * - `scope` to end. |
| * - `returnValue` (optional) to be passed to the WTF. |
| * |
| * Returns the `returnValue for easy chaining. |
| * @publicApi |
| * @deprecated the Web Tracing Framework is no longer supported in Angular |
| */ |
| var wtfLeave = wtfEnabled ? leave : function (s, r) { return r; }; |
| /** |
| * Used to mark Async start. Async are similar to scope but they don't have to be strictly nested. |
| * The return value is used in the call to [endAsync]. Async ranges only work if WTF has been |
| * enabled. |
| * |
| * someMethod() { |
| * var s = wtfStartTimeRange('HTTP:GET', 'some.url'); |
| * var future = new Future.delay(5).then((_) { |
| * wtfEndTimeRange(s); |
| * }); |
| * } |
| * @publicApi |
| * @deprecated the Web Tracing Framework is no longer supported in Angular |
| */ |
| var wtfStartTimeRange = wtfEnabled ? startTimeRange : function (rangeType, action) { return null; }; |
| /** |
| * Ends a async time range operation. |
| * [range] is the return value from [wtfStartTimeRange] Async ranges only work if WTF has been |
| * enabled. |
| * @publicApi |
| * @deprecated the Web Tracing Framework is no longer supported in Angular |
| */ |
| var wtfEndTimeRange = wtfEnabled ? endTimeRange : function (r) { return null; }; |
| |
| /** |
| * @license |
| * Copyright Google Inc. All Rights Reserved. |
| * |
| * Use of this source code is governed by an MIT-style license that can be |
| * found in the LICENSE file at https://angular.io/license |
| */ |
| var promise = (function () { return Promise.resolve(0); })(); |
| function scheduleMicroTask(fn) { |
| if (typeof Zone === 'undefined') { |
| // use promise to schedule microTask instead of use Zone |
| promise.then(function () { fn && fn.apply(null, null); }); |
| } |
| else { |
| Zone.current.scheduleMicroTask('scheduleMicrotask', fn); |
| } |
| } |
| |
| /** |
| * @license |
| * Copyright Google Inc. All Rights Reserved. |
| * |
| * Use of this source code is governed by an MIT-style license that can be |
| * found in the LICENSE file at https://angular.io/license |
| */ |
| /** |
| * An injectable service for executing work inside or outside of the Angular zone. |
| * |
| * The most common use of this service is to optimize performance when starting a work consisting of |
| * one or more asynchronous tasks that don't require UI updates or error handling to be handled by |
| * Angular. Such tasks can be kicked off via {@link #runOutsideAngular} and if needed, these tasks |
| * can reenter the Angular zone via {@link #run}. |
| * |
| * <!-- TODO: add/fix links to: |
| * - docs explaining zones and the use of zones in Angular and change-detection |
| * - link to runOutsideAngular/run (throughout this file!) |
| * --> |
| * |
| * @usageNotes |
| * ### Example |
| * |
| * ``` |
| * import {Component, NgZone} from '@angular/core'; |
| * import {NgIf} from '@angular/common'; |
| * |
| * @Component({ |
| * selector: 'ng-zone-demo', |
| * template: ` |
| * <h2>Demo: NgZone</h2> |
| * |
| * <p>Progress: {{progress}}%</p> |
| * <p *ngIf="progress >= 100">Done processing {{label}} of Angular zone!</p> |
| * |
| * <button (click)="processWithinAngularZone()">Process within Angular zone</button> |
| * <button (click)="processOutsideOfAngularZone()">Process outside of Angular zone</button> |
| * `, |
| * }) |
| * export class NgZoneDemo { |
| * progress: number = 0; |
| * label: string; |
| * |
| * constructor(private _ngZone: NgZone) {} |
| * |
| * // Loop inside the Angular zone |
| * // so the UI DOES refresh after each setTimeout cycle |
| * processWithinAngularZone() { |
| * this.label = 'inside'; |
| * this.progress = 0; |
| * this._increaseProgress(() => console.log('Inside Done!')); |
| * } |
| * |
| * // Loop outside of the Angular zone |
| * // so the UI DOES NOT refresh after each setTimeout cycle |
| * processOutsideOfAngularZone() { |
| * this.label = 'outside'; |
| * this.progress = 0; |
| * this._ngZone.runOutsideAngular(() => { |
| * this._increaseProgress(() => { |
| * // reenter the Angular zone and display done |
| * this._ngZone.run(() => { console.log('Outside Done!'); }); |
| * }); |
| * }); |
| * } |
| * |
| * _increaseProgress(doneCallback: () => void) { |
| * this.progress += 1; |
| * console.log(`Current progress: ${this.progress}%`); |
| * |
| * if (this.progress < 100) { |
| * window.setTimeout(() => this._increaseProgress(doneCallback), 10); |
| * } else { |
| * doneCallback(); |
| * } |
| * } |
| * } |
| * ``` |
| * |
| * @publicApi |
| */ |
| var NgZone = /** @class */ (function () { |
| function NgZone(_a) { |
| var _b = _a.enableLongStackTrace, enableLongStackTrace = _b === void 0 ? false : _b; |
| this.hasPendingMicrotasks = false; |
| this.hasPendingMacrotasks = false; |
| /** |
| * Whether there are no outstanding microtasks or macrotasks. |
| */ |
| this.isStable = true; |
| /** |
| * Notifies when code enters Angular Zone. This gets fired first on VM Turn. |
| */ |
| this.onUnstable = new EventEmitter(false); |
| /** |
| * Notifies when there is no more microtasks enqueued in the current VM Turn. |
| * This is a hint for Angular to do change detection, which may enqueue more microtasks. |
| * For this reason this event can fire multiple times per VM Turn. |
| */ |
| this.onMicrotaskEmpty = new EventEmitter(false); |
| /** |
| * Notifies when the last `onMicrotaskEmpty` has run and there are no more microtasks, which |
| * implies we are about to relinquish VM turn. |
| * This event gets called just once. |
| */ |
| this.onStable = new EventEmitter(false); |
| /** |
| * Notifies that an error has been delivered. |
| */ |
| this.onError = new EventEmitter(false); |
| if (typeof Zone == 'undefined') { |
| throw new Error("In this configuration Angular requires Zone.js"); |
| } |
| Zone.assertZonePatched(); |
| var self = this; |
| self._nesting = 0; |
| self._outer = self._inner = Zone.current; |
| if (Zone['wtfZoneSpec']) { |
| self._inner = self._inner.fork(Zone['wtfZoneSpec']); |
| } |
| if (Zone['TaskTrackingZoneSpec']) { |
| self._inner = self._inner.fork(new Zone['TaskTrackingZoneSpec']); |
| } |
| if (enableLongStackTrace && Zone['longStackTraceZoneSpec']) { |
| self._inner = self._inner.fork(Zone['longStackTraceZoneSpec']); |
| } |
| forkInnerZoneWithAngularBehavior(self); |
| } |
| NgZone.isInAngularZone = function () { return Zone.current.get('isAngularZone') === true; }; |
| NgZone.assertInAngularZone = function () { |
| if (!NgZone.isInAngularZone()) { |
| throw new Error('Expected to be in Angular Zone, but it is not!'); |
| } |
| }; |
| NgZone.assertNotInAngularZone = function () { |
| if (NgZone.isInAngularZone()) { |
| throw new Error('Expected to not be in Angular Zone, but it is!'); |
| } |
| }; |
| /** |
| * Executes the `fn` function synchronously within the Angular zone and returns value returned by |
| * the function. |
| * |
| * Running functions via `run` allows you to reenter Angular zone from a task that was executed |
| * outside of the Angular zone (typically started via {@link #runOutsideAngular}). |
| * |
| * Any future tasks or microtasks scheduled from within this function will continue executing from |
| * within the Angular zone. |
| * |
| * If a synchronous error happens it will be rethrown and not reported via `onError`. |
| */ |
| NgZone.prototype.run = function (fn, applyThis, applyArgs) { |
| return this._inner.run(fn, applyThis, applyArgs); |
| }; |
| /** |
| * Executes the `fn` function synchronously within the Angular zone as a task and returns value |
| * returned by the function. |
| * |
| * Running functions via `run` allows you to reenter Angular zone from a task that was executed |
| * outside of the Angular zone (typically started via {@link #runOutsideAngular}). |
| * |
| * Any future tasks or microtasks scheduled from within this function will continue executing from |
| * within the Angular zone. |
| * |
| * If a synchronous error happens it will be rethrown and not reported via `onError`. |
| */ |
| NgZone.prototype.runTask = function (fn, applyThis, applyArgs, name) { |
| var zone = this._inner; |
| var task = zone.scheduleEventTask('NgZoneEvent: ' + name, fn, EMPTY_PAYLOAD, noop$1, noop$1); |
| try { |
| return zone.runTask(task, applyThis, applyArgs); |
| } |
| finally { |
| zone.cancelTask(task); |
| } |
| }; |
| /** |
| * Same as `run`, except that synchronous errors are caught and forwarded via `onError` and not |
| * rethrown. |
| */ |
| NgZone.prototype.runGuarded = function (fn, applyThis, applyArgs) { |
| return this._inner.runGuarded(fn, applyThis, applyArgs); |
| }; |
| /** |
| * Executes the `fn` function synchronously in Angular's parent zone and returns value returned by |
| * the function. |
| * |
| * Running functions via {@link #runOutsideAngular} allows you to escape Angular's zone and do |
| * work that |
| * doesn't trigger Angular change-detection or is subject to Angular's error handling. |
| * |
| * Any future tasks or microtasks scheduled from within this function will continue executing from |
| * outside of the Angular zone. |
| * |
| * Use {@link #run} to reenter the Angular zone and do work that updates the application model. |
| */ |
| NgZone.prototype.runOutsideAngular = function (fn) { |
| return this._outer.run(fn); |
| }; |
| return NgZone; |
| }()); |
| function noop$1() { } |
| var EMPTY_PAYLOAD = {}; |
| function checkStable(zone) { |
| if (zone._nesting == 0 && !zone.hasPendingMicrotasks && !zone.isStable) { |
| try { |
| zone._nesting++; |
| zone.onMicrotaskEmpty.emit(null); |
| } |
| finally { |
| zone._nesting--; |
| if (!zone.hasPendingMicrotasks) { |
| try { |
| zone.runOutsideAngular(function () { return zone.onStable.emit(null); }); |
| } |
| finally { |
| zone.isStable = true; |
| } |
| } |
| } |
| } |
| } |
| function forkInnerZoneWithAngularBehavior(zone) { |
| zone._inner = zone._inner.fork({ |
| name: 'angular', |
| properties: { 'isAngularZone': true }, |
| onInvokeTask: function (delegate, current, target, task, applyThis, applyArgs) { |
| try { |
| onEnter(zone); |
| return delegate.invokeTask(target, task, applyThis, applyArgs); |
| } |
| finally { |
| onLeave(zone); |
| } |
| }, |
| onInvoke: function (delegate, current, target, callback, applyThis, applyArgs, source) { |
| try { |
| onEnter(zone); |
| return delegate.invoke(target, callback, applyThis, applyArgs, source); |
| } |
| finally { |
| onLeave(zone); |
| } |
| }, |
| onHasTask: function (delegate, current, target, hasTaskState) { |
| delegate.hasTask(target, hasTaskState); |
| if (current === target) { |
| // We are only interested in hasTask events which originate from our zone |
| // (A child hasTask event is not interesting to us) |
| if (hasTaskState.change == 'microTask') { |
| zone.hasPendingMicrotasks = hasTaskState.microTask; |
| checkStable(zone); |
| } |
| else if (hasTaskState.change == 'macroTask') { |
| zone.hasPendingMacrotasks = hasTaskState.macroTask; |
| } |
| } |
| }, |
| onHandleError: function (delegate, current, target, error) { |
| delegate.handleError(target, error); |
| zone.runOutsideAngular(function () { return zone.onError.emit(error); }); |
| return false; |
| } |
| }); |
| } |
| function onEnter(zone) { |
| zone._nesting++; |
| if (zone.isStable) { |
| zone.isStable = false; |
| zone.onUnstable.emit(null); |
| } |
| } |
| function onLeave(zone) { |
| zone._nesting--; |
| checkStable(zone); |
| } |
| /** |
| * Provides a noop implementation of `NgZone` which does nothing. This zone requires explicit calls |
| * to framework to perform rendering. |
| */ |
| var NoopNgZone = /** @class */ (function () { |
| function NoopNgZone() { |
| this.hasPendingMicrotasks = false; |
| this.hasPendingMacrotasks = false; |
| this.isStable = true; |
| this.onUnstable = new EventEmitter(); |
| this.onMicrotaskEmpty = new EventEmitter(); |
| this.onStable = new EventEmitter(); |
| this.onError = new EventEmitter(); |
| } |
| NoopNgZone.prototype.run = function (fn) { return fn(); }; |
| NoopNgZone.prototype.runGuarded = function (fn) { return fn(); }; |
| NoopNgZone.prototype.runOutsideAngular = function (fn) { return fn(); }; |
| NoopNgZone.prototype.runTask = function (fn) { return fn(); }; |
| return NoopNgZone; |
| }()); |
| |
| /** |
| * @license |
| * Copyright Google Inc. All Rights Reserved. |
| * |
| * Use of this source code is governed by an MIT-style license that can be |
| * found in the LICENSE file at https://angular.io/license |
| */ |
| /** |
| * The Testability service provides testing hooks that can be accessed from |
| * the browser and by services such as Protractor. Each bootstrapped Angular |
| * application on the page will have an instance of Testability. |
| * @publicApi |
| */ |
| var Testability = /** @class */ (function () { |
| function Testability(_ngZone) { |
| var _this = this; |
| this._ngZone = _ngZone; |
| this._pendingCount = 0; |
| this._isZoneStable = true; |
| /** |
| * Whether any work was done since the last 'whenStable' callback. This is |
| * useful to detect if this could have potentially destabilized another |
| * component while it is stabilizing. |
| * @internal |
| */ |
| this._didWork = false; |
| this._callbacks = []; |
| this.taskTrackingZone = null; |
| this._watchAngularEvents(); |
| _ngZone.run(function () { |
| _this.taskTrackingZone = |
| typeof Zone == 'undefined' ? null : Zone.current.get('TaskTrackingZone'); |
| }); |
| } |
| Testability.prototype._watchAngularEvents = function () { |
| var _this = this; |
| this._ngZone.onUnstable.subscribe({ |
| next: function () { |
| _this._didWork = true; |
| _this._isZoneStable = false; |
| } |
| }); |
| this._ngZone.runOutsideAngular(function () { |
| _this._ngZone.onStable.subscribe({ |
| next: function () { |
| NgZone.assertNotInAngularZone(); |
| scheduleMicroTask(function () { |
| _this._isZoneStable = true; |
| _this._runCallbacksIfReady(); |
| }); |
| } |
| }); |
| }); |
| }; |
| /** |
| * Increases the number of pending request |
| * @deprecated pending requests are now tracked with zones. |
| */ |
| Testability.prototype.increasePendingRequestCount = function () { |
| this._pendingCount += 1; |
| this._didWork = true; |
| return this._pendingCount; |
| }; |
| /** |
| * Decreases the number of pending request |
| * @deprecated pending requests are now tracked with zones |
| */ |
| Testability.prototype.decreasePendingRequestCount = function () { |
| this._pendingCount -= 1; |
| if (this._pendingCount < 0) { |
| throw new Error('pending async requests below zero'); |
| } |
| this._runCallbacksIfReady(); |
| return this._pendingCount; |
| }; |
| /** |
| * Whether an associated application is stable |
| */ |
| Testability.prototype.isStable = function () { |
| return this._isZoneStable && this._pendingCount === 0 && !this._ngZone.hasPendingMacrotasks; |
| }; |
| Testability.prototype._runCallbacksIfReady = function () { |
| var _this = this; |
| if (this.isStable()) { |
| // Schedules the call backs in a new frame so that it is always async. |
| scheduleMicroTask(function () { |
| while (_this._callbacks.length !== 0) { |
| var cb = _this._callbacks.pop(); |
| clearTimeout(cb.timeoutId); |
| cb.doneCb(_this._didWork); |
| } |
| _this._didWork = false; |
| }); |
| } |
| else { |
| // Still not stable, send updates. |
| var pending_1 = this.getPendingTasks(); |
| this._callbacks = this._callbacks.filter(function (cb) { |
| if (cb.updateCb && cb.updateCb(pending_1)) { |
| clearTimeout(cb.timeoutId); |
| return false; |
| } |
| return true; |
| }); |
| this._didWork = true; |
| } |
| }; |
| Testability.prototype.getPendingTasks = function () { |
| if (!this.taskTrackingZone) { |
| return []; |
| } |
| // Copy the tasks data so that we don't leak tasks. |
| return this.taskTrackingZone.macroTasks.map(function (t) { |
| return { |
| source: t.source, |
| // From TaskTrackingZone: |
| // https://github.com/angular/zone.js/blob/master/lib/zone-spec/task-tracking.ts#L40 |
| creationLocation: t.creationLocation, |
| data: t.data |
| }; |
| }); |
| }; |
| Testability.prototype.addCallback = function (cb, timeout, updateCb) { |
| var _this = this; |
| var timeoutId = -1; |
| if (timeout && timeout > 0) { |
| timeoutId = setTimeout(function () { |
| _this._callbacks = _this._callbacks.filter(function (cb) { return cb.timeoutId !== timeoutId; }); |
| cb(_this._didWork, _this.getPendingTasks()); |
| }, timeout); |
| } |
| this._callbacks.push({ doneCb: cb, timeoutId: timeoutId, updateCb: updateCb }); |
| }; |
| /** |
| * Wait for the application to be stable with a timeout. If the timeout is reached before that |
| * happens, the callback receives a list of the macro tasks that were pending, otherwise null. |
| * |
| * @param doneCb The callback to invoke when Angular is stable or the timeout expires |
| * whichever comes first. |
| * @param timeout Optional. The maximum time to wait for Angular to become stable. If not |
| * specified, whenStable() will wait forever. |
| * @param updateCb Optional. If specified, this callback will be invoked whenever the set of |
| * pending macrotasks changes. If this callback returns true doneCb will not be invoked |
| * and no further updates will be issued. |
| */ |
| Testability.prototype.whenStable = function (doneCb, timeout, updateCb) { |
| if (updateCb && !this.taskTrackingZone) { |
| throw new Error('Task tracking zone is required when passing an update callback to ' + |
| 'whenStable(). Is "zone.js/dist/task-tracking.js" loaded?'); |
| } |
| // These arguments are 'Function' above to keep the public API simple. |
| this.addCallback(doneCb, timeout, updateCb); |
| this._runCallbacksIfReady(); |
| }; |
| /** |
| * Get the number of pending requests |
| * @deprecated pending requests are now tracked with zones |
| */ |
| Testability.prototype.getPendingRequestCount = function () { return this._pendingCount; }; |
| /** |
| * Find providers by name |
| * @param using The root element to search from |
| * @param provider The name of binding variable |
| * @param exactMatch Whether using exactMatch |
| */ |
| Testability.prototype.findProviders = function (using, provider, exactMatch) { |
| // TODO(juliemr): implement. |
| return []; |
| }; |
| Testability = __decorate([ |
| Injectable(), |
| __metadata("design:paramtypes", [NgZone]) |
| ], Testability); |
| return Testability; |
| }()); |
| /** |
| * A global registry of {@link Testability} instances for specific elements. |
| * @publicApi |
| */ |
| var TestabilityRegistry = /** @class */ (function () { |
| function TestabilityRegistry() { |
| /** @internal */ |
| this._applications = new Map(); |
| _testabilityGetter.addToWindow(this); |
| } |
| /** |
| * Registers an application with a testability hook so that it can be tracked |
| * @param token token of application, root element |
| * @param testability Testability hook |
| */ |
| TestabilityRegistry.prototype.registerApplication = function (token, testability) { |
| this._applications.set(token, testability); |
| }; |
| /** |
| * Unregisters an application. |
| * @param token token of application, root element |
| */ |
| TestabilityRegistry.prototype.unregisterApplication = function (token) { this._applications.delete(token); }; |
| /** |
| * Unregisters all applications |
| */ |
| TestabilityRegistry.prototype.unregisterAllApplications = function () { this._applications.clear(); }; |
| /** |
| * Get a testability hook associated with the application |
| * @param elem root element |
| */ |
| TestabilityRegistry.prototype.getTestability = function (elem) { return this._applications.get(elem) || null; }; |
| /** |
| * Get all registered testabilities |
| */ |
| TestabilityRegistry.prototype.getAllTestabilities = function () { return Array.from(this._applications.values()); }; |
| /** |
| * Get all registered applications(root elements) |
| */ |
| TestabilityRegistry.prototype.getAllRootElements = function () { return Array.from(this._applications.keys()); }; |
| /** |
| * Find testability of a node in the Tree |
| * @param elem node |
| * @param findInAncestors whether finding testability in ancestors if testability was not found in |
| * current node |
| */ |
| TestabilityRegistry.prototype.findTestabilityInTree = function (elem, findInAncestors) { |
| if (findInAncestors === void 0) { findInAncestors = true; } |
| return _testabilityGetter.findTestabilityInTree(this, elem, findInAncestors); |
| }; |
| TestabilityRegistry = __decorate([ |
| Injectable(), |
| __metadata("design:paramtypes", []) |
| ], TestabilityRegistry); |
| return TestabilityRegistry; |
| }()); |
| var _NoopGetTestability = /** @class */ (function () { |
| function _NoopGetTestability() { |
| } |
| _NoopGetTestability.prototype.addToWindow = function (registry) { }; |
| _NoopGetTestability.prototype.findTestabilityInTree = function (registry, elem, findInAncestors) { |
| return null; |
| }; |
| return _NoopGetTestability; |
| }()); |
| /** |
| * Set the {@link GetTestability} implementation used by the Angular testing framework. |
| * @publicApi |
| */ |
| function setTestabilityGetter(getter) { |
| _testabilityGetter = getter; |
| } |
| var _testabilityGetter = new _NoopGetTestability(); |
| |
| /** |
| * @license |
| * Copyright Google Inc. All Rights Reserved. |
| * |
| * Use of this source code is governed by an MIT-style license that can be |
| * found in the LICENSE file at https://angular.io/license |
| */ |
| var _platform; |
| var compileNgModuleFactory = compileNgModuleFactory__PRE_R3__; |
| function compileNgModuleFactory__PRE_R3__(injector, options, moduleType) { |
| var compilerFactory = injector.get(CompilerFactory); |
| var compiler = compilerFactory.createCompiler([options]); |
| return compiler.compileModuleAsync(moduleType); |
| } |
| function compileNgModuleFactory__POST_R3__(injector, options, moduleType) { |
| ngDevMode && assertNgModuleType(moduleType); |
| var moduleFactory = new NgModuleFactory$1(moduleType); |
| if (isComponentResourceResolutionQueueEmpty()) { |
| return Promise.resolve(moduleFactory); |
| } |
| var compilerOptions = injector.get(COMPILER_OPTIONS, []).concat(options); |
| var compilerProviders = _mergeArrays(compilerOptions.map(function (o) { return o.providers; })); |
| // In case there are no compiler providers, we just return the module factory as |
| // there won't be any resource loader. This can happen with Ivy, because AOT compiled |
| // modules can be still passed through "bootstrapModule". In that case we shouldn't |
| // unnecessarily require the JIT compiler. |
| if (compilerProviders.length === 0) { |
| return Promise.resolve(moduleFactory); |
| } |
| var compiler = getCompilerFacade(); |
| var compilerInjector = Injector.create({ providers: compilerProviders }); |
| var resourceLoader = compilerInjector.get(compiler.ResourceLoader); |
| // The resource loader can also return a string while the "resolveComponentResources" |
| // always expects a promise. Therefore we need to wrap the returned value in a promise. |
| return resolveComponentResources(function (url) { return Promise.resolve(resourceLoader.get(url)); }) |
| .then(function () { return moduleFactory; }); |
| } |
| var isBoundToModule = isBoundToModule__PRE_R3__; |
| function isBoundToModule__PRE_R3__(cf) { |
| return cf instanceof ComponentFactoryBoundToModule; |
| } |
| function isBoundToModule__POST_R3__(cf) { |
| return cf.isBoundToModule; |
| } |
| var ALLOW_MULTIPLE_PLATFORMS = new InjectionToken('AllowMultipleToken'); |
| /** |
| * A token for third-party components that can register themselves with NgProbe. |
| * |
| * @publicApi |
| */ |
| var NgProbeToken = /** @class */ (function () { |
| function NgProbeToken(name, token) { |
| this.name = name; |
| this.token = token; |
| } |
| return NgProbeToken; |
| }()); |
| /** |
| * Creates a platform. |
| * Platforms have to be eagerly created via this function. |
| * |
| * @publicApi |
| */ |
| function createPlatform(injector) { |
| if (_platform && !_platform.destroyed && |
| !_platform.injector.get(ALLOW_MULTIPLE_PLATFORMS, false)) { |
| throw new Error('There can be only one platform. Destroy the previous one to create a new one.'); |
| } |
| _platform = injector.get(PlatformRef); |
| var inits = injector.get(PLATFORM_INITIALIZER, null); |
| if (inits) |
| inits.forEach(function (init) { return init(); }); |
| return _platform; |
| } |
| /** |
| * Creates a factory for a platform |
| * |
| * @publicApi |
| */ |
| function createPlatformFactory(parentPlatformFactory, name, providers) { |
| if (providers === void 0) { providers = []; } |
| var desc = "Platform: " + name; |
| var marker = new InjectionToken(desc); |
| return function (extraProviders) { |
| if (extraProviders === void 0) { extraProviders = []; } |
| var platform = getPlatform(); |
| if (!platform || platform.injector.get(ALLOW_MULTIPLE_PLATFORMS, false)) { |
| if (parentPlatformFactory) { |
| parentPlatformFactory(providers.concat(extraProviders).concat({ provide: marker, useValue: true })); |
| } |
| else { |
| var injectedProviders = providers.concat(extraProviders).concat({ provide: marker, useValue: true }); |
| createPlatform(Injector.create({ providers: injectedProviders, name: desc })); |
| } |
| } |
| return assertPlatform(marker); |
| }; |
| } |
| /** |
| * Checks that there currently is a platform which contains the given token as a provider. |
| * |
| * @publicApi |
| */ |
| function assertPlatform(requiredToken) { |
| var platform = getPlatform(); |
| if (!platform) { |
| throw new Error('No platform exists!'); |
| } |
| if (!platform.injector.get(requiredToken, null)) { |
| throw new Error('A platform with a different configuration has been created. Please destroy it first.'); |
| } |
| return platform; |
| } |
| /** |
| * Destroy the existing platform. |
| * |
| * @publicApi |
| */ |
| function destroyPlatform() { |
| if (_platform && !_platform.destroyed) { |
| _platform.destroy(); |
| } |
| } |
| /** |
| * Returns the current platform. |
| * |
| * @publicApi |
| */ |
| function getPlatform() { |
| return _platform && !_platform.destroyed ? _platform : null; |
| } |
| /** |
| * The Angular platform is the entry point for Angular on a web page. Each page |
| * has exactly one platform, and services (such as reflection) which are common |
| * to every Angular application running on the page are bound in its scope. |
| * |
| * A page's platform is initialized implicitly when a platform is created via a platform factory |
| * (e.g. {@link platformBrowser}), or explicitly by calling the {@link createPlatform} function. |
| * |
| * @publicApi |
| */ |
| var PlatformRef = /** @class */ (function () { |
| /** @internal */ |
| function PlatformRef(_injector) { |
| this._injector = _injector; |
| this._modules = []; |
| this._destroyListeners = []; |
| this._destroyed = false; |
| } |
| /** |
| * Creates an instance of an `@NgModule` for the given platform |
| * for offline compilation. |
| * |
| * @usageNotes |
| * ### Simple Example |
| * |
| * ```typescript |
| * my_module.ts: |
| * |
| * @NgModule({ |
| * imports: [BrowserModule] |
| * }) |
| * class MyModule {} |
| * |
| * main.ts: |
| * import {MyModuleNgFactory} from './my_module.ngfactory'; |
| * import {platformBrowser} from '@angular/platform-browser'; |
| * |
| * let moduleRef = platformBrowser().bootstrapModuleFactory(MyModuleNgFactory); |
| * ``` |
| */ |
| PlatformRef.prototype.bootstrapModuleFactory = function (moduleFactory, options) { |
| var _this = this; |
| // Note: We need to create the NgZone _before_ we instantiate the module, |
| // as instantiating the module creates some providers eagerly. |
| // So we create a mini parent injector that just contains the new NgZone and |
| // pass that as parent to the NgModuleFactory. |
| var ngZoneOption = options ? options.ngZone : undefined; |
| var ngZone = getNgZone(ngZoneOption); |
| var providers = [{ provide: NgZone, useValue: ngZone }]; |
| // Attention: Don't use ApplicationRef.run here, |
| // as we want to be sure that all possible constructor calls are inside `ngZone.run`! |
| return ngZone.run(function () { |
| var ngZoneInjector = Injector.create({ providers: providers, parent: _this.injector, name: moduleFactory.moduleType.name }); |
| var moduleRef = moduleFactory.create(ngZoneInjector); |
| var exceptionHandler = moduleRef.injector.get(ErrorHandler, null); |
| if (!exceptionHandler) { |
| throw new Error('No ErrorHandler. Is platform module (BrowserModule) included?'); |
| } |
| // If the `LOCALE_ID` provider is defined at bootstrap we set the value for runtime i18n (ivy) |
| var localeId = moduleRef.injector.get(LOCALE_ID$1, DEFAULT_LOCALE_ID); |
| setLocaleId(localeId); |
| moduleRef.onDestroy(function () { return remove(_this._modules, moduleRef); }); |
| ngZone.runOutsideAngular(function () { return ngZone.onError.subscribe({ next: function (error) { exceptionHandler.handleError(error); } }); }); |
| return _callAndReportToErrorHandler(exceptionHandler, ngZone, function () { |
| var initStatus = moduleRef.injector.get(ApplicationInitStatus); |
| initStatus.runInitializers(); |
| return initStatus.donePromise.then(function () { |
| _this._moduleDoBootstrap(moduleRef); |
| return moduleRef; |
| }); |
| }); |
| }); |
| }; |
| /** |
| * Creates an instance of an `@NgModule` for a given platform using the given runtime compiler. |
| * |
| * @usageNotes |
| * ### Simple Example |
| * |
| * ```typescript |
| * @NgModule({ |
| * imports: [BrowserModule] |
| * }) |
| * class MyModule {} |
| * |
| * let moduleRef = platformBrowser().bootstrapModule(MyModule); |
| * ``` |
| * |
| */ |
| PlatformRef.prototype.bootstrapModule = function (moduleType, compilerOptions) { |
| var _this = this; |
| if (compilerOptions === void 0) { compilerOptions = []; } |
| var options = optionsReducer({}, compilerOptions); |
| return compileNgModuleFactory(this.injector, options, moduleType) |
| .then(function (moduleFactory) { return _this.bootstrapModuleFactory(moduleFactory, options); }); |
| }; |
| PlatformRef.prototype._moduleDoBootstrap = function (moduleRef) { |
| var appRef = moduleRef.injector.get(ApplicationRef); |
| if (moduleRef._bootstrapComponents.length > 0) { |
| moduleRef._bootstrapComponents.forEach(function (f) { return appRef.bootstrap(f); }); |
| } |
| else if (moduleRef.instance.ngDoBootstrap) { |
| moduleRef.instance.ngDoBootstrap(appRef); |
| } |
| else { |
| throw new Error("The module " + stringify(moduleRef.instance.constructor) + " was bootstrapped, but it does not declare \"@NgModule.bootstrap\" components nor a \"ngDoBootstrap\" method. " + |
| "Please define one of these."); |
| } |
| this._modules.push(moduleRef); |
| }; |
| /** |
| * Register a listener to be called when the platform is disposed. |
| */ |
| PlatformRef.prototype.onDestroy = function (callback) { this._destroyListeners.push(callback); }; |
| Object.defineProperty(PlatformRef.prototype, "injector", { |
| /** |
| * Retrieve the platform {@link Injector}, which is the parent injector for |
| * every Angular application on the page and provides singleton providers. |
| */ |
| get: function () { return this._injector; }, |
| enumerable: true, |
| configurable: true |
| }); |
| /** |
| * Destroy the Angular platform and all Angular applications on the page. |
| */ |
| PlatformRef.prototype.destroy = function () { |
| if (this._destroyed) { |
| throw new Error('The platform has already been destroyed!'); |
| } |
| this._modules.slice().forEach(function (module) { return module.destroy(); }); |
| this._destroyListeners.forEach(function (listener) { return listener(); }); |
| this._destroyed = true; |
| }; |
| Object.defineProperty(PlatformRef.prototype, "destroyed", { |
| get: function () { return this._destroyed; }, |
| enumerable: true, |
| configurable: true |
| }); |
| PlatformRef = __decorate([ |
| Injectable(), |
| __metadata("design:paramtypes", [Injector]) |
| ], PlatformRef); |
| return PlatformRef; |
| }()); |
| function getNgZone(ngZoneOption) { |
| var ngZone; |
| if (ngZoneOption === 'noop') { |
| ngZone = new NoopNgZone(); |
| } |
| else { |
| ngZone = (ngZoneOption === 'zone.js' ? undefined : ngZoneOption) || |
| new NgZone({ enableLongStackTrace: isDevMode() }); |
| } |
| return ngZone; |
| } |
| function _callAndReportToErrorHandler(errorHandler, ngZone, callback) { |
| try { |
| var result = callback(); |
| if (isPromise(result)) { |
| return result.catch(function (e) { |
| ngZone.runOutsideAngular(function () { return errorHandler.handleError(e); }); |
| // rethrow as the exception handler might not do it |
| throw e; |
| }); |
| } |
| return result; |
| } |
| catch (e) { |
| ngZone.runOutsideAngular(function () { return errorHandler.handleError(e); }); |
| // rethrow as the exception handler might not do it |
| throw e; |
| } |
| } |
| function optionsReducer(dst, objs) { |
| if (Array.isArray(objs)) { |
| dst = objs.reduce(optionsReducer, dst); |
| } |
| else { |
| dst = __assign({}, dst, objs); |
| } |
| return dst; |
| } |
| /** |
| * A reference to an Angular application running on a page. |
| * |
| * @usageNotes |
| * |
| * {@a is-stable-examples} |
| * ### isStable examples and caveats |
| * |
| * Note two important points about `isStable`, demonstrated in the examples below: |
| * - the application will never be stable if you start any kind |
| * of recurrent asynchronous task when the application starts |
| * (for example for a polling process, started with a `setInterval`, a `setTimeout` |
| * or using RxJS operators like `interval`); |
| * - the `isStable` Observable runs outside of the Angular zone. |
| * |
| * Let's imagine that you start a recurrent task |
| * (here incrementing a counter, using RxJS `interval`), |
| * and at the same time subscribe to `isStable`. |
| * |
| * ``` |
| * constructor(appRef: ApplicationRef) { |
| * appRef.isStable.pipe( |
| * filter(stable => stable) |
| * ).subscribe(() => console.log('App is stable now'); |
| * interval(1000).subscribe(counter => console.log(counter)); |
| * } |
| * ``` |
| * In this example, `isStable` will never emit `true`, |
| * and the trace "App is stable now" will never get logged. |
| * |
| * If you want to execute something when the app is stable, |
| * you have to wait for the application to be stable |
| * before starting your polling process. |
| * |
| * ``` |
| * constructor(appRef: ApplicationRef) { |
| * appRef.isStable.pipe( |
| * first(stable => stable), |
| * tap(stable => console.log('App is stable now')), |
| * switchMap(() => interval(1000)) |
| * ).subscribe(counter => console.log(counter)); |
| * } |
| * ``` |
| * In this example, the trace "App is stable now" will be logged |
| * and then the counter starts incrementing every second. |
| * |
| * Note also that this Observable runs outside of the Angular zone, |
| * which means that the code in the subscription |
| * to this Observable will not trigger the change detection. |
| * |
| * Let's imagine that instead of logging the counter value, |
| * you update a field of your component |
| * and display it in its template. |
| * |
| * ``` |
| * constructor(appRef: ApplicationRef) { |
| * appRef.isStable.pipe( |
| * first(stable => stable), |
| * switchMap(() => interval(1000)) |
| * ).subscribe(counter => this.value = counter); |
| * } |
| * ``` |
| * As the `isStable` Observable runs outside the zone, |
| * the `value` field will be updated properly, |
| * but the template will not be refreshed! |
| * |
| * You'll have to manually trigger the change detection to update the template. |
| * |
| * ``` |
| * constructor(appRef: ApplicationRef, cd: ChangeDetectorRef) { |
| * appRef.isStable.pipe( |
| * first(stable => stable), |
| * switchMap(() => interval(1000)) |
| * ).subscribe(counter => { |
| * this.value = counter; |
| * cd.detectChanges(); |
| * }); |
| * } |
| * ``` |
| * |
| * Or make the subscription callback run inside the zone. |
| * |
| * ``` |
| * constructor(appRef: ApplicationRef, zone: NgZone) { |
| * appRef.isStable.pipe( |
| * first(stable => stable), |
| * switchMap(() => interval(1000)) |
| * ).subscribe(counter => zone.run(() => this.value = counter)); |
| * } |
| * ``` |
| * |
| * @publicApi |
| */ |
| var ApplicationRef = /** @class */ (function () { |
| /** @internal */ |
| function ApplicationRef(_zone, _console, _injector, _exceptionHandler, _componentFactoryResolver, _initStatus) { |
| var _this = this; |
| this._zone = _zone; |
| this._console = _console; |
| this._injector = _injector; |
| this._exceptionHandler = _exceptionHandler; |
| this._componentFactoryResolver = _componentFactoryResolver; |
| this._initStatus = _initStatus; |
| this._bootstrapListeners = []; |
| this._views = []; |
| this._runningTick = false; |
| this._enforceNoNewChanges = false; |
| this._stable = true; |
| /** |
| * Get a list of component types registered to this application. |
| * This list is populated even before the component is created. |
| */ |
| this.componentTypes = []; |
| /** |
| * Get a list of components registered to this application. |
| */ |
| this.components = []; |
| this._enforceNoNewChanges = isDevMode(); |
| this._zone.onMicrotaskEmpty.subscribe({ next: function () { _this._zone.run(function () { _this.tick(); }); } }); |
| var isCurrentlyStable = new rxjs.Observable(function (observer) { |
| _this._stable = _this._zone.isStable && !_this._zone.hasPendingMacrotasks && |
| !_this._zone.hasPendingMicrotasks; |
| _this._zone.runOutsideAngular(function () { |
| observer.next(_this._stable); |
| observer.complete(); |
| }); |
| }); |
| var isStable = new rxjs.Observable(function (observer) { |
| // Create the subscription to onStable outside the Angular Zone so that |
| // the callback is run outside the Angular Zone. |
| var stableSub; |
| _this._zone.runOutsideAngular(function () { |
| stableSub = _this._zone.onStable.subscribe(function () { |
| NgZone.assertNotInAngularZone(); |
| // Check whether there are no pending macro/micro tasks in the next tick |
| // to allow for NgZone to update the state. |
| scheduleMicroTask(function () { |
| if (!_this._stable && !_this._zone.hasPendingMacrotasks && |
| !_this._zone.hasPendingMicrotasks) { |
| _this._stable = true; |
| observer.next(true); |
| } |
| }); |
| }); |
| }); |
| var unstableSub = _this._zone.onUnstable.subscribe(function () { |
| NgZone.assertInAngularZone(); |
| if (_this._stable) { |
| _this._stable = false; |
| _this._zone.runOutsideAngular(function () { observer.next(false); }); |
| } |
| }); |
| return function () { |
| stableSub.unsubscribe(); |
| unstableSub.unsubscribe(); |
| }; |
| }); |
| this.isStable = |
| rxjs.merge(isCurrentlyStable, isStable.pipe(operators.share())); |
| } |
| ApplicationRef_1 = ApplicationRef; |
| /** |
| * Bootstrap a new component at the root level of the application. |
| * |
| * @usageNotes |
| * ### Bootstrap process |
| * |
| * When bootstrapping a new root component into an application, Angular mounts the |
| * specified application component onto DOM elements identified by the componentType's |
| * selector and kicks off automatic change detection to finish initializing the component. |
| * |
| * Optionally, a component can be mounted onto a DOM element that does not match the |
| * componentType's selector. |
| * |
| * ### Example |
| * {@example core/ts/platform/platform.ts region='longform'} |
| */ |
| ApplicationRef.prototype.bootstrap = function (componentOrFactory, rootSelectorOrNode) { |
| var _this = this; |
| if (!this._initStatus.done) { |
| throw new Error('Cannot bootstrap as there are still asynchronous initializers running. Bootstrap components in the `ngDoBootstrap` method of the root module.'); |
| } |
| var componentFactory; |
| if (componentOrFactory instanceof ComponentFactory) { |
| componentFactory = componentOrFactory; |
| } |
| else { |
| componentFactory = |
| this._componentFactoryResolver.resolveComponentFactory(componentOrFactory); |
| } |
| this.componentTypes.push(componentFactory.componentType); |
| // Create a factory associated with the current module if it's not bound to some other |
| var ngModule = isBoundToModule(componentFactory) ? null : this._injector.get(NgModuleRef); |
| var selectorOrNode = rootSelectorOrNode || componentFactory.selector; |
| var compRef = componentFactory.create(Injector.NULL, [], selectorOrNode, ngModule); |
| compRef.onDestroy(function () { _this._unloadComponent(compRef); }); |
| var testability = compRef.injector.get(Testability, null); |
| if (testability) { |
| compRef.injector.get(TestabilityRegistry) |
| .registerApplication(compRef.location.nativeElement, testability); |
| } |
| this._loadComponent(compRef); |
| if (isDevMode()) { |
| this._console.log("Angular is running in the development mode. Call enableProdMode() to enable the production mode."); |
| } |
| return compRef; |
| }; |
| /** |
| * Invoke this method to explicitly process change detection and its side-effects. |
| * |
| * In development mode, `tick()` also performs a second change detection cycle to ensure that no |
| * further changes are detected. If additional changes are picked up during this second cycle, |
| * bindings in the app have side-effects that cannot be resolved in a single change detection |
| * pass. |
| * In this case, Angular throws an error, since an Angular application can only have one change |
| * detection pass during which all change detection must complete. |
| */ |
| ApplicationRef.prototype.tick = function () { |
| var _this = this; |
| var e_1, _a, e_2, _b; |
| if (this._runningTick) { |
| throw new Error('ApplicationRef.tick is called recursively'); |
| } |
| var scope = ApplicationRef_1._tickScope(); |
| try { |
| this._runningTick = true; |
| try { |
| for (var _c = __values(this._views), _d = _c.next(); !_d.done; _d = _c.next()) { |
| var view = _d.value; |
| view.detectChanges(); |
| } |
| } |
| catch (e_1_1) { e_1 = { error: e_1_1 }; } |
| finally { |
| try { |
| if (_d && !_d.done && (_a = _c.return)) _a.call(_c); |
| } |
| finally { if (e_1) throw e_1.error; } |
| } |
| if (this._enforceNoNewChanges) { |
| try { |
| for (var _e = __values(this._views), _f = _e.next(); !_f.done; _f = _e.next()) { |
| var view = _f.value; |
| view.checkNoChanges(); |
| } |
| } |
| catch (e_2_1) { e_2 = { error: e_2_1 }; } |
| finally { |
| try { |
| if (_f && !_f.done && (_b = _e.return)) _b.call(_e); |
| } |
| finally { if (e_2) throw e_2.error; } |
| } |
| } |
| } |
| catch (e) { |
| // Attention: Don't rethrow as it could cancel subscriptions to Observables! |
| this._zone.runOutsideAngular(function () { return _this._exceptionHandler.handleError(e); }); |
| } |
| finally { |
| this._runningTick = false; |
| wtfLeave(scope); |
| } |
| }; |
| /** |
| * Attaches a view so that it will be dirty checked. |
| * The view will be automatically detached when it is destroyed. |
| * This will throw if the view is already attached to a ViewContainer. |
| */ |
| ApplicationRef.prototype.attachView = function (viewRef) { |
| var view = viewRef; |
| this._views.push(view); |
| view.attachToAppRef(this); |
| }; |
| /** |
| * Detaches a view from dirty checking again. |
| */ |
| ApplicationRef.prototype.detachView = function (viewRef) { |
| var view = viewRef; |
| remove(this._views, view); |
| view.detachFromAppRef(); |
| }; |
| ApplicationRef.prototype._loadComponent = function (componentRef) { |
| this.attachView(componentRef.hostView); |
| this.tick(); |
| this.components.push(componentRef); |
| // Get the listeners lazily to prevent DI cycles. |
| var listeners = this._injector.get(APP_BOOTSTRAP_LISTENER, []).concat(this._bootstrapListeners); |
| listeners.forEach(function (listener) { return listener(componentRef); }); |
| }; |
| ApplicationRef.prototype._unloadComponent = function (componentRef) { |
| this.detachView(componentRef.hostView); |
| remove(this.components, componentRef); |
| }; |
| /** @internal */ |
| ApplicationRef.prototype.ngOnDestroy = function () { |
| // TODO(alxhub): Dispose of the NgZone. |
| this._views.slice().forEach(function (view) { return view.destroy(); }); |
| }; |
| Object.defineProperty(ApplicationRef.prototype, "viewCount", { |
| /** |
| * Returns the number of attached views. |
| */ |
| get: function () { return this._views.length; }, |
| enumerable: true, |
| configurable: true |
| }); |
| var ApplicationRef_1; |
| /** @internal */ |
| ApplicationRef._tickScope = wtfCreateScope('ApplicationRef#tick()'); |
| ApplicationRef = ApplicationRef_1 = __decorate([ |
| Injectable(), |
| __metadata("design:paramtypes", [NgZone, Console, Injector, |
| ErrorHandler, |
| ComponentFactoryResolver, |
| ApplicationInitStatus]) |
| ], ApplicationRef); |
| return ApplicationRef; |
| }()); |
| function remove(list, el) { |
| var index = list.indexOf(el); |
| if (index > -1) { |
| list.splice(index, 1); |
| } |
| } |
| function _mergeArrays(parts) { |
| var result = []; |
| parts.forEach(function (part) { return part && result.push.apply(result, __spread(part)); }); |
| return result; |
| } |
| |
| /** |
| * @license |
| * Copyright Google Inc. All Rights Reserved. |
| * |
| * Use of this source code is governed by an MIT-style license that can be |
| * found in the LICENSE file at https://angular.io/license |
| */ |
| |
| /** |
| * @license |
| * Copyright Google Inc. All Rights Reserved. |
| * |
| * Use of this source code is governed by an MIT-style license that can be |
| * found in the LICENSE file at https://angular.io/license |
| */ |
| |
| /** |
| * @license |
| * Copyright Google Inc. All Rights Reserved. |
| * |
| * Use of this source code is governed by an MIT-style license that can be |
| * found in the LICENSE file at https://angular.io/license |
| */ |
| /** |
| * Used to load ng module factories. |
| * |
| * @publicApi |
| * @deprecated the `string` form of `loadChildren` is deprecated, and `NgModuleFactoryLoader` is |
| * part of its implementation. See `LoadChildren` for more details. |
| */ |
| var NgModuleFactoryLoader = /** @class */ (function () { |
| function NgModuleFactoryLoader() { |
| } |
| return NgModuleFactoryLoader; |
| }()); |
| function getModuleFactory__PRE_R3__(id) { |
| var factory = getRegisteredNgModuleType(id); |
| if (!factory) |
| throw noModuleError(id); |
| return factory; |
| } |
| function getModuleFactory__POST_R3__(id) { |
| var type = getRegisteredNgModuleType(id); |
| if (!type) |
| throw noModuleError(id); |
| return new NgModuleFactory$1(type); |
| } |
| /** |
| * Returns the NgModuleFactory with the given id, if it exists and has been loaded. |
| * Factories for modules that do not specify an `id` cannot be retrieved. Throws if the module |
| * cannot be found. |
| * @publicApi |
| */ |
| var getModuleFactory = getModuleFactory__PRE_R3__; |
| function noModuleError(id) { |
| return new Error("No module with ID " + id + " loaded"); |
| } |
| |
| /** |
| * @license |
| * Copyright Google Inc. All Rights Reserved. |
| * |
| * Use of this source code is governed by an MIT-style license that can be |
| * found in the LICENSE file at https://angular.io/license |
| */ |
| var SWITCH_IVY_ENABLED__POST_R3__ = true; |
| var SWITCH_IVY_ENABLED__PRE_R3__ = false; |
| var ivyEnabled = SWITCH_IVY_ENABLED__PRE_R3__; |
| |
| /** |
| * @license |
| * Copyright Google Inc. All Rights Reserved. |
| * |
| * Use of this source code is governed by an MIT-style license that can be |
| * found in the LICENSE file at https://angular.io/license |
| */ |
| var _SEPARATOR = '#'; |
| var FACTORY_CLASS_SUFFIX = 'NgFactory'; |
| /** |
| * Configuration for SystemJsNgModuleLoader. |
| * token. |
| * |
| * @publicApi |
| * @deprecated the `string` form of `loadChildren` is deprecated, and `SystemJsNgModuleLoaderConfig` |
| * is part of its implementation. See `LoadChildren` for more details. |
| */ |
| var SystemJsNgModuleLoaderConfig = /** @class */ (function () { |
| function SystemJsNgModuleLoaderConfig() { |
| } |
| return SystemJsNgModuleLoaderConfig; |
| }()); |
| var DEFAULT_CONFIG = { |
| factoryPathPrefix: '', |
| factoryPathSuffix: '.ngfactory', |
| }; |
| /** |
| * NgModuleFactoryLoader that uses SystemJS to load NgModuleFactory |
| * @publicApi |
| * @deprecated the `string` form of `loadChildren` is deprecated, and `SystemJsNgModuleLoader` is |
| * part of its implementation. See `LoadChildren` for more details. |
| */ |
| var SystemJsNgModuleLoader = /** @class */ (function () { |
| function SystemJsNgModuleLoader(_compiler, config) { |
| this._compiler = _compiler; |
| this._config = config || DEFAULT_CONFIG; |
| } |
| SystemJsNgModuleLoader.prototype.load = function (path) { |
| var legacyOfflineMode = !ivyEnabled && this._compiler instanceof Compiler; |
| return legacyOfflineMode ? this.loadFactory(path) : this.loadAndCompile(path); |
| }; |
| SystemJsNgModuleLoader.prototype.loadAndCompile = function (path) { |
| var _this = this; |
| var _a = __read(path.split(_SEPARATOR), 2), module = _a[0], exportName = _a[1]; |
| if (exportName === undefined) { |
| exportName = 'default'; |
| } |
| return System.import(module) |
| .then(function (module) { return module[exportName]; }) |
| .then(function (type) { return checkNotEmpty(type, module, exportName); }) |
| .then(function (type) { return _this._compiler.compileModuleAsync(type); }); |
| }; |
| SystemJsNgModuleLoader.prototype.loadFactory = function (path) { |
| var _a = __read(path.split(_SEPARATOR), 2), module = _a[0], exportName = _a[1]; |
| var factoryClassSuffix = FACTORY_CLASS_SUFFIX; |
| if (exportName === undefined) { |
| exportName = 'default'; |
| factoryClassSuffix = ''; |
| } |
| return System.import(this._config.factoryPathPrefix + module + this._config.factoryPathSuffix) |
| .then(function (module) { return module[exportName + factoryClassSuffix]; }) |
| .then(function (factory) { return checkNotEmpty(factory, module, exportName); }); |
| }; |
| SystemJsNgModuleLoader = __decorate([ |
| Injectable(), |
| __param(1, Optional()), |
| __metadata("design:paramtypes", [Compiler, SystemJsNgModuleLoaderConfig]) |
| ], SystemJsNgModuleLoader); |
| return SystemJsNgModuleLoader; |
| }()); |
| function checkNotEmpty(value, modulePath, exportName) { |
| if (!value) { |
| throw new Error("Cannot find '" + exportName + "' in '" + modulePath + "'"); |
| } |
| return value; |
| } |
| |
| /** |
| * @license |
| * Copyright Google Inc. All Rights Reserved. |
| * |
| * Use of this source code is governed by an MIT-style license that can be |
| * found in the LICENSE file at https://angular.io/license |
| */ |
| /** |
| * Represents an Angular [view](guide/glossary#view), |
| * specifically the [host view](guide/glossary#view-tree) that is defined by a component. |
| * Also serves as the base class |
| * that adds destroy methods for [embedded views](guide/glossary#view-tree). |
| * |
| * @see `EmbeddedViewRef` |
| * |
| * @publicApi |
| */ |
| var ViewRef$1 = /** @class */ (function (_super) { |
| __extends(ViewRef, _super); |
| function ViewRef() { |
| return _super !== null && _super.apply(this, arguments) || this; |
| } |
| return ViewRef; |
| }(ChangeDetectorRef)); |
| /** |
| * Represents an Angular [view](guide/glossary#view) in a view container. |
| * An [embedded view](guide/glossary#view-tree) can be referenced from a component |
| * other than the hosting component whose template defines it, or it can be defined |
| * independently by a `TemplateRef`. |
| * |
| * Properties of elements in a view can change, but the structure (number and order) of elements in |
| * a view cannot. Change the structure of elements by inserting, moving, or |
| * removing nested views in a view container. |
| * |
| * @see `ViewContainerRef` |
| * |
| * @usageNotes |
| * |
| * The following template breaks down into two separate `TemplateRef` instances, |
| * an outer one and an inner one. |
| * |
| * ``` |
| * Count: {{items.length}} |
| * <ul> |
| * <li *ngFor="let item of items">{{item}}</li> |
| * </ul> |
| * ``` |
| * |
| * This is the outer `TemplateRef`: |
| * |
| * ``` |
| * Count: {{items.length}} |
| * <ul> |
| * <ng-template ngFor let-item [ngForOf]="items"></ng-template> |
| * </ul> |
| * ``` |
| * |
| * This is the inner `TemplateRef`: |
| * |
| * ``` |
| * <li>{{item}}</li> |
| * ``` |
| * |
| * The outer and inner `TemplateRef` instances are assembled into views as follows: |
| * |
| * ``` |
| * <!-- ViewRef: outer-0 --> |
| * Count: 2 |
| * <ul> |
| * <ng-template view-container-ref></ng-template> |
| * <!-- ViewRef: inner-1 --><li>first</li><!-- /ViewRef: inner-1 --> |
| * <!-- ViewRef: inner-2 --><li>second</li><!-- /ViewRef: inner-2 --> |
| * </ul> |
| * <!-- /ViewRef: outer-0 --> |
| * ``` |
| * @publicApi |
| */ |
| var EmbeddedViewRef = /** @class */ (function (_super) { |
| __extends(EmbeddedViewRef, _super); |
| function EmbeddedViewRef() { |
| return _super !== null && _super.apply(this, arguments) || this; |
| } |
| return EmbeddedViewRef; |
| }(ViewRef$1)); |
| |
| /** |
| * @license |
| * Copyright Google Inc. All Rights Reserved. |
| * |
| * Use of this source code is governed by an MIT-style license that can be |
| * found in the LICENSE file at https://angular.io/license |
| */ |
| |
| /** |
| * @license |
| * Copyright Google Inc. All Rights Reserved. |
| * |
| * Use of this source code is governed by an MIT-style license that can be |
| * found in the LICENSE file at https://angular.io/license |
| */ |
| /** |
| * @publicApi |
| */ |
| var DebugEventListener = /** @class */ (function () { |
| function DebugEventListener(name, callback) { |
| this.name = name; |
| this.callback = callback; |
| } |
| return DebugEventListener; |
| }()); |
| var DebugNode__PRE_R3__ = /** @class */ (function () { |
| function DebugNode__PRE_R3__(nativeNode, parent, _debugContext) { |
| this.listeners = []; |
| this.parent = null; |
| this._debugContext = _debugContext; |
| this.nativeNode = nativeNode; |
| if (parent && parent instanceof DebugElement__PRE_R3__) { |
| parent.addChild(this); |
| } |
| } |
| Object.defineProperty(DebugNode__PRE_R3__.prototype, "injector", { |
| get: function () { return this._debugContext.injector; }, |
| enumerable: true, |
| configurable: true |
| }); |
| Object.defineProperty(DebugNode__PRE_R3__.prototype, "componentInstance", { |
| get: function () { return this._debugContext.component; }, |
| enumerable: true, |
| configurable: true |
| }); |
| Object.defineProperty(DebugNode__PRE_R3__.prototype, "context", { |
| get: function () { return this._debugContext.context; }, |
| enumerable: true, |
| configurable: true |
| }); |
| Object.defineProperty(DebugNode__PRE_R3__.prototype, "references", { |
| get: function () { return this._debugContext.references; }, |
| enumerable: true, |
| configurable: true |
| }); |
| Object.defineProperty(DebugNode__PRE_R3__.prototype, "providerTokens", { |
| get: function () { return this._debugContext.providerTokens; }, |
| enumerable: true, |
| configurable: true |
| }); |
| return DebugNode__PRE_R3__; |
| }()); |
| var DebugElement__PRE_R3__ = /** @class */ (function (_super) { |
| __extends(DebugElement__PRE_R3__, _super); |
| function DebugElement__PRE_R3__(nativeNode, parent, _debugContext) { |
| var _this = _super.call(this, nativeNode, parent, _debugContext) || this; |
| _this.properties = {}; |
| _this.attributes = {}; |
| _this.classes = {}; |
| _this.styles = {}; |
| _this.childNodes = []; |
| _this.nativeElement = nativeNode; |
| return _this; |
| } |
| DebugElement__PRE_R3__.prototype.addChild = function (child) { |
| if (child) { |
| this.childNodes.push(child); |
| child.parent = this; |
| } |
| }; |
| DebugElement__PRE_R3__.prototype.removeChild = function (child) { |
| var childIndex = this.childNodes.indexOf(child); |
| if (childIndex !== -1) { |
| child.parent = null; |
| this.childNodes.splice(childIndex, 1); |
| } |
| }; |
| DebugElement__PRE_R3__.prototype.insertChildrenAfter = function (child, newChildren) { |
| var _this = this; |
| var _a; |
| var siblingIndex = this.childNodes.indexOf(child); |
| if (siblingIndex !== -1) { |
| (_a = this.childNodes).splice.apply(_a, __spread([siblingIndex + 1, 0], newChildren)); |
| newChildren.forEach(function (c) { |
| if (c.parent) { |
| c.parent.removeChild(c); |
| } |
| child.parent = _this; |
| }); |
| } |
| }; |
| DebugElement__PRE_R3__.prototype.insertBefore = function (refChild, newChild) { |
| var refIndex = this.childNodes.indexOf(refChild); |
| if (refIndex === -1) { |
| this.addChild(newChild); |
| } |
| else { |
| if (newChild.parent) { |
| newChild.parent.removeChild(newChild); |
| } |
| newChild.parent = this; |
| this.childNodes.splice(refIndex, 0, newChild); |
| } |
| }; |
| DebugElement__PRE_R3__.prototype.query = function (predicate) { |
| var results = this.queryAll(predicate); |
| return results[0] || null; |
| }; |
| DebugElement__PRE_R3__.prototype.queryAll = function (predicate) { |
| var matches = []; |
| _queryElementChildren(this, predicate, matches); |
| return matches; |
| }; |
| DebugElement__PRE_R3__.prototype.queryAllNodes = function (predicate) { |
| var matches = []; |
| _queryNodeChildren(this, predicate, matches); |
| return matches; |
| }; |
| Object.defineProperty(DebugElement__PRE_R3__.prototype, "children", { |
| get: function () { |
| return this |
| .childNodes // |
| .filter(function (node) { return node instanceof DebugElement__PRE_R3__; }); |
| }, |
| enumerable: true, |
| configurable: true |
| }); |
| DebugElement__PRE_R3__.prototype.triggerEventHandler = function (eventName, eventObj) { |
| this.listeners.forEach(function (listener) { |
| if (listener.name == eventName) { |
| listener.callback(eventObj); |
| } |
| }); |
| }; |
| return DebugElement__PRE_R3__; |
| }(DebugNode__PRE_R3__)); |
| /** |
| * @publicApi |
| */ |
| function asNativeElements(debugEls) { |
| return debugEls.map(function (el) { return el.nativeElement; }); |
| } |
| function _queryElementChildren(element, predicate, matches) { |
| element.childNodes.forEach(function (node) { |
| if (node instanceof DebugElement__PRE_R3__) { |
| if (predicate(node)) { |
| matches.push(node); |
| } |
| _queryElementChildren(node, predicate, matches); |
| } |
| }); |
| } |
| function _queryNodeChildren(parentNode, predicate, matches) { |
| if (parentNode instanceof DebugElement__PRE_R3__) { |
| parentNode.childNodes.forEach(function (node) { |
| if (predicate(node)) { |
| matches.push(node); |
| } |
| if (node instanceof DebugElement__PRE_R3__) { |
| _queryNodeChildren(node, predicate, matches); |
| } |
| }); |
| } |
| } |
| var DebugNode__POST_R3__ = /** @class */ (function () { |
| function DebugNode__POST_R3__(nativeNode) { |
| this.nativeNode = nativeNode; |
| } |
| Object.defineProperty(DebugNode__POST_R3__.prototype, "parent", { |
| get: function () { |
| var parent = this.nativeNode.parentNode; |
| return parent ? new DebugElement__POST_R3__(parent) : null; |
| }, |
| enumerable: true, |
| configurable: true |
| }); |
| Object.defineProperty(DebugNode__POST_R3__.prototype, "injector", { |
| get: function () { return getInjector(this.nativeNode); }, |
| enumerable: true, |
| configurable: true |
| }); |
| Object.defineProperty(DebugNode__POST_R3__.prototype, "componentInstance", { |
| get: function () { |
| var nativeElement = this.nativeNode; |
| return nativeElement && |
| (getComponent(nativeElement) || getViewComponent(nativeElement)); |
| }, |
| enumerable: true, |
| configurable: true |
| }); |
| Object.defineProperty(DebugNode__POST_R3__.prototype, "context", { |
| get: function () { return getContext$1(this.nativeNode); }, |
| enumerable: true, |
| configurable: true |
| }); |
| Object.defineProperty(DebugNode__POST_R3__.prototype, "listeners", { |
| get: function () { |
| return getListeners(this.nativeNode).filter(isBrowserEvents); |
| }, |
| enumerable: true, |
| configurable: true |
| }); |
| Object.defineProperty(DebugNode__POST_R3__.prototype, "references", { |
| get: function () { return getLocalRefs(this.nativeNode); }, |
| enumerable: true, |
| configurable: true |
| }); |
| Object.defineProperty(DebugNode__POST_R3__.prototype, "providerTokens", { |
| get: function () { return getInjectionTokens(this.nativeNode); }, |
| enumerable: true, |
| configurable: true |
| }); |
| return DebugNode__POST_R3__; |
| }()); |
| var DebugElement__POST_R3__ = /** @class */ (function (_super) { |
| __extends(DebugElement__POST_R3__, _super); |
| function DebugElement__POST_R3__(nativeNode) { |
| var _this = this; |
| ngDevMode && assertDomNode(nativeNode); |
| _this = _super.call(this, nativeNode) || this; |
| return _this; |
| } |
| Object.defineProperty(DebugElement__POST_R3__.prototype, "nativeElement", { |
| get: function () { |
| return this.nativeNode.nodeType == Node.ELEMENT_NODE ? this.nativeNode : null; |
| }, |
| enumerable: true, |
| configurable: true |
| }); |
| Object.defineProperty(DebugElement__POST_R3__.prototype, "name", { |
| get: function () { return this.nativeElement.nodeName; }, |
| enumerable: true, |
| configurable: true |
| }); |
| Object.defineProperty(DebugElement__POST_R3__.prototype, "properties", { |
| /** |
| * Gets a map of property names to property values for an element. |
| * |
| * This map includes: |
| * - Regular property bindings (e.g. `[id]="id"`) |
| * - Host property bindings (e.g. `host: { '[id]': "id" }`) |
| * - Interpolated property bindings (e.g. `id="{{ value }}") |
| * |
| * It does not include: |
| * - input property bindings (e.g. `[myCustomInput]="value"`) |
| * - attribute bindings (e.g. `[attr.role]="menu"`) |
| */ |
| get: function () { |
| var context = loadLContext(this.nativeNode); |
| var lView = context.lView; |
| var tData = lView[TVIEW].data; |
| var tNode = tData[context.nodeIndex]; |
| var properties = collectPropertyBindings(tNode, lView, tData); |
| var hostProperties = collectHostPropertyBindings(tNode, lView, tData); |
| var className = collectClassNames(this); |
| var output = __assign({}, properties, hostProperties); |
| if (className) { |
| output['className'] = output['className'] ? output['className'] + (" " + className) : className; |
| } |
| return output; |
| }, |
| enumerable: true, |
| configurable: true |
| }); |
| Object.defineProperty(DebugElement__POST_R3__.prototype, "attributes", { |
| get: function () { |
| var attributes = {}; |
| var element = this.nativeElement; |
| if (!element) { |
| return attributes; |
| } |
| var context = loadLContext(element); |
| var lView = context.lView; |
| var tNodeAttrs = lView[TVIEW].data[context.nodeIndex].attrs; |
| var lowercaseTNodeAttrs = []; |
| // For debug nodes we take the element's attribute directly from the DOM since it allows us |
| // to account for ones that weren't set via bindings (e.g. ViewEngine keeps track of the ones |
| // that are set through `Renderer2`). The problem is that the browser will lowercase all names, |
| // however since we have the attributes already on the TNode, we can preserve the case by going |
| // through them once, adding them to the `attributes` map and putting their lower-cased name |
| // into an array. Afterwards when we're going through the native DOM attributes, we can check |
| // whether we haven't run into an attribute already through the TNode. |
| if (tNodeAttrs) { |
| var i = 0; |
| while (i < tNodeAttrs.length) { |
| var attrName = tNodeAttrs[i]; |
| // Stop as soon as we hit a marker. We only care about the regular attributes. Everything |
| // else will be handled below when we read the final attributes off the DOM. |
| if (typeof attrName !== 'string') |
| break; |
| var attrValue = tNodeAttrs[i + 1]; |
| attributes[attrName] = attrValue; |
| lowercaseTNodeAttrs.push(attrName.toLowerCase()); |
| i += 2; |
| } |
| } |
| var eAttrs = element.attributes; |
| for (var i = 0; i < eAttrs.length; i++) { |
| var attr = eAttrs[i]; |
| // Make sure that we don't assign the same attribute both in its |
| // case-sensitive form and the lower-cased one from the browser. |
| if (lowercaseTNodeAttrs.indexOf(attr.name) === -1) { |
| attributes[attr.name] = attr.value; |
| } |
| } |
| return attributes; |
| }, |
| enumerable: true, |
| configurable: true |
| }); |
| Object.defineProperty(DebugElement__POST_R3__.prototype, "classes", { |
| get: function () { |
| var classes = {}; |
| var element = this.nativeElement; |
| if (element) { |
| var lContext = loadLContextFromNode(element); |
| var stylingContext = getStylingContextFromLView(lContext.nodeIndex, lContext.lView); |
| if (stylingContext) { |
| for (var i = 10 /* SingleStylesStartPosition */; i < stylingContext.length; i += 4 /* Size */) { |
| if (isClassBasedValue(stylingContext, i)) { |
| var className = getProp(stylingContext, i); |
| var value = getValue(stylingContext, i); |
| if (typeof value == 'boolean') { |
| // we want to ignore `null` since those don't overwrite the values. |
| classes[className] = value; |
| } |
| } |
| } |
| } |
| else { |
| // Fallback, just read DOM. |
| var eClasses = element.classList; |
| for (var i = 0; i < eClasses.length; i++) { |
| classes[eClasses[i]] = true; |
| } |
| } |
| } |
| return classes; |
| }, |
| enumerable: true, |
| configurable: true |
| }); |
| Object.defineProperty(DebugElement__POST_R3__.prototype, "styles", { |
| get: function () { |
| var styles = {}; |
| var element = this.nativeElement; |
| if (element) { |
| var lContext = loadLContextFromNode(element); |
| var stylingContext = getStylingContextFromLView(lContext.nodeIndex, lContext.lView); |
| if (stylingContext) { |
| for (var i = 10 /* SingleStylesStartPosition */; i < stylingContext.length; i += 4 /* Size */) { |
| if (!isClassBasedValue(stylingContext, i)) { |
| var styleName = getProp(stylingContext, i); |
| var value = getValue(stylingContext, i); |
| if (value !== null) { |
| // we want to ignore `null` since those don't overwrite the values. |
| styles[styleName] = value; |
| } |
| } |
| } |
| } |
| else { |
| // Fallback, just read DOM. |
| var eStyles = element.style; |
| for (var i = 0; i < eStyles.length; i++) { |
| var name_1 = eStyles.item(i); |
| styles[name_1] = eStyles.getPropertyValue(name_1); |
| } |
| } |
| } |
| return styles; |
| }, |
| enumerable: true, |
| configurable: true |
| }); |
| Object.defineProperty(DebugElement__POST_R3__.prototype, "childNodes", { |
| get: function () { |
| var childNodes = this.nativeNode.childNodes; |
| var children = []; |
| for (var i = 0; i < childNodes.length; i++) { |
| var element = childNodes[i]; |
| children.push(getDebugNode__POST_R3__(element)); |
| } |
| return children; |
| }, |
| enumerable: true, |
| configurable: true |
| }); |
| Object.defineProperty(DebugElement__POST_R3__.prototype, "children", { |
| get: function () { |
| var nativeElement = this.nativeElement; |
| if (!nativeElement) |
| return []; |
| var childNodes = nativeElement.children; |
| var children = []; |
| for (var i = 0; i < childNodes.length; i++) { |
| var element = childNodes[i]; |
| children.push(getDebugNode__POST_R3__(element)); |
| } |
| return children; |
| }, |
| enumerable: true, |
| configurable: true |
| }); |
| DebugElement__POST_R3__.prototype.query = function (predicate) { |
| var results = this.queryAll(predicate); |
| return results[0] || null; |
| }; |
| DebugElement__POST_R3__.prototype.queryAll = function (predicate) { |
| var matches = []; |
| _queryAllR3(this, predicate, matches, true); |
| return matches; |
| }; |
| DebugElement__POST_R3__.prototype.queryAllNodes = function (predicate) { |
| var matches = []; |
| _queryAllR3(this, predicate, matches, false); |
| return matches; |
| }; |
| DebugElement__POST_R3__.prototype.triggerEventHandler = function (eventName, eventObj) { |
| this.listeners.forEach(function (listener) { |
| if (listener.name === eventName) { |
| listener.callback(eventObj); |
| } |
| }); |
| }; |
| return DebugElement__POST_R3__; |
| }(DebugNode__POST_R3__)); |
| /** |
| * Walk the TNode tree to find matches for the predicate. |
| * |
| * @param parentElement the element from which the walk is started |
| * @param predicate the predicate to match |
| * @param matches the list of positive matches |
| * @param elementsOnly whether only elements should be searched |
| */ |
| function _queryAllR3(parentElement, predicate, matches, elementsOnly) { |
| var context = loadLContext(parentElement.nativeNode); |
| var parentTNode = context.lView[TVIEW].data[context.nodeIndex]; |
| _queryNodeChildrenR3(parentTNode, context.lView, predicate, matches, elementsOnly, parentElement.nativeNode); |
| } |
| /** |
| * Recursively match the current TNode against the predicate, and goes on with the next ones. |
| * |
| * @param tNode the current TNode |
| * @param lView the LView of this TNode |
| * @param predicate the predicate to match |
| * @param matches the list of positive matches |
| * @param elementsOnly whether only elements should be searched |
| * @param rootNativeNode the root native node on which prediccate shouold not be matched |
| */ |
| function _queryNodeChildrenR3(tNode, lView, predicate, matches, elementsOnly, rootNativeNode) { |
| var e_1, _a; |
| var nativeNode = getNativeByTNode(tNode, lView); |
| // For each type of TNode, specific logic is executed. |
| if (tNode.type === 3 /* Element */ || tNode.type === 4 /* ElementContainer */) { |
| // Case 1: the TNode is an element |
| // The native node has to be checked. |
| _addQueryMatchR3(nativeNode, predicate, matches, elementsOnly, rootNativeNode); |
| if (isComponent(tNode)) { |
| // If the element is the host of a component, then all nodes in its view have to be processed. |
| // Note: the component's content (tNode.child) will be processed from the insertion points. |
| var componentView = getComponentViewByIndex(tNode.index, lView); |
| if (componentView && componentView[TVIEW].firstChild) { |
| _queryNodeChildrenR3(componentView[TVIEW].firstChild, componentView, predicate, matches, elementsOnly, rootNativeNode); |
| } |
| } |
| else if (tNode.child) { |
| // Otherwise, its children have to be processed. |
| _queryNodeChildrenR3(tNode.child, lView, predicate, matches, elementsOnly, rootNativeNode); |
| } |
| // In all cases, if a dynamic container exists for this node, each view inside it has to be |
| // processed. |
| var nodeOrContainer = lView[tNode.index]; |
| if (isLContainer(nodeOrContainer)) { |
| _queryNodeChildrenInContainerR3(nodeOrContainer, predicate, matches, elementsOnly, rootNativeNode); |
| } |
| } |
| else if (tNode.type === 0 /* Container */) { |
| // Case 2: the TNode is a container |
| // The native node has to be checked. |
| var lContainer = lView[tNode.index]; |
| _addQueryMatchR3(lContainer[NATIVE], predicate, matches, elementsOnly, rootNativeNode); |
| // Each view inside the container has to be processed. |
| _queryNodeChildrenInContainerR3(lContainer, predicate, matches, elementsOnly, rootNativeNode); |
| } |
| else if (tNode.type === 1 /* Projection */) { |
| // Case 3: the TNode is a projection insertion point (i.e. a <ng-content>). |
| // The nodes projected at this location all need to be processed. |
| var componentView = findComponentView(lView); |
| var componentHost = componentView[T_HOST]; |
| var head = componentHost.projection[tNode.projection]; |
| if (Array.isArray(head)) { |
| try { |
| for (var head_1 = __values(head), head_1_1 = head_1.next(); !head_1_1.done; head_1_1 = head_1.next()) { |
| var nativeNode_1 = head_1_1.value; |
| _addQueryMatchR3(nativeNode_1, predicate, matches, elementsOnly, rootNativeNode); |
| } |
| } |
| catch (e_1_1) { e_1 = { error: e_1_1 }; } |
| finally { |
| try { |
| if (head_1_1 && !head_1_1.done && (_a = head_1.return)) _a.call(head_1); |
| } |
| finally { if (e_1) throw e_1.error; } |
| } |
| } |
| else if (head) { |
| var nextLView = componentView[PARENT]; |
| var nextTNode = nextLView[TVIEW].data[head.index]; |
| _queryNodeChildrenR3(nextTNode, nextLView, predicate, matches, elementsOnly, rootNativeNode); |
| } |
| } |
| else if (tNode.child) { |
| // Case 4: the TNode is a view. |
| _queryNodeChildrenR3(tNode.child, lView, predicate, matches, elementsOnly, rootNativeNode); |
| } |
| // We don't want to go to the next sibling of the root node. |
| if (rootNativeNode !== nativeNode) { |
| // To determine the next node to be processed, we need to use the next or the projectionNext |
| // link, depending on whether the current node has been projected. |
| var nextTNode = (tNode.flags & 2 /* isProjected */) ? tNode.projectionNext : tNode.next; |
| if (nextTNode) { |
| _queryNodeChildrenR3(nextTNode, lView, predicate, matches, elementsOnly, rootNativeNode); |
| } |
| } |
| } |
| /** |
| * Process all TNodes in a given container. |
| * |
| * @param lContainer the container to be processed |
| * @param predicate the predicate to match |
| * @param matches the list of positive matches |
| * @param elementsOnly whether only elements should be searched |
| * @param rootNativeNode the root native node on which prediccate shouold not be matched |
| */ |
| function _queryNodeChildrenInContainerR3(lContainer, predicate, matches, elementsOnly, rootNativeNode) { |
| for (var i = CONTAINER_HEADER_OFFSET; i < lContainer.length; i++) { |
| var childView = lContainer[i]; |
| _queryNodeChildrenR3(childView[TVIEW].node, childView, predicate, matches, elementsOnly, rootNativeNode); |
| } |
| } |
| /** |
| * Match the current native node against the predicate. |
| * |
| * @param nativeNode the current native node |
| * @param predicate the predicate to match |
| * @param matches the list of positive matches |
| * @param elementsOnly whether only elements should be searched |
| * @param rootNativeNode the root native node on which prediccate shouold not be matched |
| */ |
| function _addQueryMatchR3(nativeNode, predicate, matches, elementsOnly, rootNativeNode) { |
| if (rootNativeNode !== nativeNode) { |
| var debugNode = getDebugNode(nativeNode); |
| if (debugNode && (elementsOnly ? debugNode instanceof DebugElement__POST_R3__ : true) && |
| predicate(debugNode)) { |
| matches.push(debugNode); |
| } |
| } |
| } |
| /** |
| * Iterates through the property bindings for a given node and generates |
| * a map of property names to values. This map only contains property bindings |
| * defined in templates, not in host bindings. |
| */ |
| function collectPropertyBindings(tNode, lView, tData) { |
| var properties = {}; |
| var bindingIndex = getFirstBindingIndex(tNode.propertyMetadataStartIndex, tData); |
| while (bindingIndex < tNode.propertyMetadataEndIndex) { |
| var value = void 0; |
| var propMetadata = tData[bindingIndex]; |
| while (!isPropMetadataString(propMetadata)) { |
| // This is the first value for an interpolation. We need to build up |
| // the full interpolation by combining runtime values in LView with |
| // the static interstitial values stored in TData. |
| value = (value || '') + renderStringify(lView[bindingIndex]) + tData[bindingIndex]; |
| propMetadata = tData[++bindingIndex]; |
| } |
| value = value === undefined ? lView[bindingIndex] : value += lView[bindingIndex]; |
| // Property metadata string has 3 parts: property name, prefix, and suffix |
| var metadataParts = propMetadata.split(INTERPOLATION_DELIMITER); |
| var propertyName = metadataParts[0]; |
| // Attr bindings don't have property names and should be skipped |
| if (propertyName) { |
| // Wrap value with prefix and suffix (will be '' for normal bindings), if they're defined. |
| // Avoid wrapping for normal bindings so that the value doesn't get cast to a string. |
| properties[propertyName] = (metadataParts[1] && metadataParts[2]) ? |
| metadataParts[1] + value + metadataParts[2] : |
| value; |
| } |
| bindingIndex++; |
| } |
| return properties; |
| } |
| /** |
| * Retrieves the first binding index that holds values for this property |
| * binding. |
| * |
| * For normal bindings (e.g. `[id]="id"`), the binding index is the |
| * same as the metadata index. For interpolations (e.g. `id="{{id}}-{{name}}"`), |
| * there can be multiple binding values, so we might have to loop backwards |
| * from the metadata index until we find the first one. |
| * |
| * @param metadataIndex The index of the first property metadata string for |
| * this node. |
| * @param tData The data array for the current TView |
| * @returns The first binding index for this binding |
| */ |
| function getFirstBindingIndex(metadataIndex, tData) { |
| var currentBindingIndex = metadataIndex - 1; |
| // If the slot before the metadata holds a string, we know that this |
| // metadata applies to an interpolation with at least 2 bindings, and |
| // we need to search further to access the first binding value. |
| var currentValue = tData[currentBindingIndex]; |
| // We need to iterate until we hit either a: |
| // - TNode (it is an element slot marking the end of `consts` section), OR a |
| // - metadata string (slot is attribute metadata or a previous node's property metadata) |
| while (typeof currentValue === 'string' && !isPropMetadataString(currentValue)) { |
| currentValue = tData[--currentBindingIndex]; |
| } |
| return currentBindingIndex + 1; |
| } |
| function collectHostPropertyBindings(tNode, lView, tData) { |
| var properties = {}; |
| // Host binding values for a node are stored after directives on that node |
| var hostPropIndex = tNode.directiveEnd; |
| var propMetadata = tData[hostPropIndex]; |
| // When we reach a value in TView.data that is not a string, we know we've |
| // hit the next node's providers and directives and should stop copying data. |
| while (typeof propMetadata === 'string') { |
| var propertyName = propMetadata.split(INTERPOLATION_DELIMITER)[0]; |
| properties[propertyName] = lView[hostPropIndex]; |
| propMetadata = tData[++hostPropIndex]; |
| } |
| return properties; |
| } |
| function collectClassNames(debugElement) { |
| var e_2, _a; |
| var classes = debugElement.classes; |
| var output = ''; |
| try { |
| for (var _b = __values(Object.keys(classes)), _c = _b.next(); !_c.done; _c = _b.next()) { |
| var className = _c.value; |
| if (classes[className]) { |
| output = output ? output + (" " + className) : className; |
| } |
| } |
| } |
| catch (e_2_1) { e_2 = { error: e_2_1 }; } |
| finally { |
| try { |
| if (_c && !_c.done && (_a = _b.return)) _a.call(_b); |
| } |
| finally { if (e_2) throw e_2.error; } |
| } |
| return output; |
| } |
| // Need to keep the nodes in a global Map so that multiple angular apps are supported. |
| var _nativeNodeToDebugNode = new Map(); |
| function getDebugNode__PRE_R3__(nativeNode) { |
| return _nativeNodeToDebugNode.get(nativeNode) || null; |
| } |
| var NG_DEBUG_PROPERTY = '__ng_debug__'; |
| function getDebugNode__POST_R3__(nativeNode) { |
| if (nativeNode instanceof Node) { |
| if (!(nativeNode.hasOwnProperty(NG_DEBUG_PROPERTY))) { |
| nativeNode[NG_DEBUG_PROPERTY] = nativeNode.nodeType == Node.ELEMENT_NODE ? |
| new DebugElement__POST_R3__(nativeNode) : |
| new DebugNode__POST_R3__(nativeNode); |
| } |
| return nativeNode[NG_DEBUG_PROPERTY]; |
| } |
| return null; |
| } |
| /** |
| * @publicApi |
| */ |
| var getDebugNode = getDebugNode__PRE_R3__; |
| function indexDebugNode(node) { |
| _nativeNodeToDebugNode.set(node.nativeNode, node); |
| } |
| function removeDebugNodeFromIndex(node) { |
| _nativeNodeToDebugNode.delete(node.nativeNode); |
| } |
| /** |
| * @publicApi |
| */ |
| var DebugNode = DebugNode__PRE_R3__; |
| /** |
| * @publicApi |
| */ |
| var DebugElement = DebugElement__PRE_R3__; |
| |
| /** |
| * @license |
| * Copyright Google Inc. All Rights Reserved. |
| * |
| * Use of this source code is governed by an MIT-style license that can be |
| * found in the LICENSE file at https://angular.io/license |
| */ |
| |
| /** |
| * @license |
| * Copyright Google Inc. All Rights Reserved. |
| * |
| * Use of this source code is governed by an MIT-style license that can be |
| * found in the LICENSE file at https://angular.io/license |
| */ |
| var _CORE_PLATFORM_PROVIDERS = [ |
| // Set a default platform name for platforms that don't set it explicitly. |
| { provide: PLATFORM_ID, useValue: 'unknown' }, |
| { provide: PlatformRef, deps: [Injector] }, |
| { provide: TestabilityRegistry, deps: [] }, |
| { provide: Console, deps: [] }, |
| ]; |
| /** |
| * This platform has to be included in any other platform |
| * |
| * @publicApi |
| */ |
| var platformCore = createPlatformFactory(null, 'core', _CORE_PLATFORM_PROVIDERS); |
| |
| /** |
| * @license |
| * Copyright Google Inc. All Rights Reserved. |
| * |
| * Use of this source code is governed by an MIT-style license that can be |
| * found in the LICENSE file at https://angular.io/license |
| */ |
| function _iterableDiffersFactory() { |
| return defaultIterableDiffers; |
| } |
| function _keyValueDiffersFactory() { |
| return defaultKeyValueDiffers; |
| } |
| function _localeFactory(locale) { |
| return locale || 'en-US'; |
| } |
| /** |
| * A built-in [dependency injection token](guide/glossary#di-token) |
| * that is used to configure the root injector for bootstrapping. |
| */ |
| var APPLICATION_MODULE_PROVIDERS = [ |
| { |
| provide: ApplicationRef, |
| useClass: ApplicationRef, |
| deps: [NgZone, Console, Injector, ErrorHandler, ComponentFactoryResolver, ApplicationInitStatus] |
| }, |
| { provide: SCHEDULER, deps: [NgZone], useFactory: zoneSchedulerFactory }, |
| { |
| provide: ApplicationInitStatus, |
| useClass: ApplicationInitStatus, |
| deps: [[new Optional(), APP_INITIALIZER]] |
| }, |
| { provide: Compiler, useClass: Compiler, deps: [] }, |
| APP_ID_RANDOM_PROVIDER, |
| { provide: IterableDiffers, useFactory: _iterableDiffersFactory, deps: [] }, |
| { provide: KeyValueDiffers, useFactory: _keyValueDiffersFactory, deps: [] }, |
| { |
| provide: LOCALE_ID$1, |
| useFactory: _localeFactory, |
| deps: [[new Inject(LOCALE_ID$1), new Optional(), new SkipSelf()]] |
| }, |
| ]; |
| /** |
| * Schedule work at next available slot. |
| * |
| * In Ivy this is just `requestAnimationFrame`. For compatibility reasons when bootstrapped |
| * using `platformRef.bootstrap` we need to use `NgZone.onStable` as the scheduling mechanism. |
| * This overrides the scheduling mechanism in Ivy to `NgZone.onStable`. |
| * |
| * @param ngZone NgZone to use for scheduling. |
| */ |
| function zoneSchedulerFactory(ngZone) { |
| var queue = []; |
| ngZone.onStable.subscribe(function () { |
| while (queue.length) { |
| queue.pop()(); |
| } |
| }); |
| return function (fn) { queue.push(fn); }; |
| } |
| /** |
| * Configures the root injector for an app with |
| * providers of `@angular/core` dependencies that `ApplicationRef` needs |
| * to bootstrap components. |
| * |
| * Re-exported by `BrowserModule`, which is included automatically in the root |
| * `AppModule` when you create a new app with the CLI `new` command. |
| * |
| * @publicApi |
| */ |
| var ApplicationModule = /** @class */ (function () { |
| // Inject ApplicationRef to make it eager... |
| function ApplicationModule(appRef) { |
| } |
| ApplicationModule = __decorate([ |
| NgModule({ providers: APPLICATION_MODULE_PROVIDERS }), |
| __metadata("design:paramtypes", [ApplicationRef]) |
| ], ApplicationModule); |
| return ApplicationModule; |
| }()); |
| |
| /** |
| * @license |
| * Copyright Google Inc. All Rights Reserved. |
| * |
| * Use of this source code is governed by an MIT-style license that can be |
| * found in the LICENSE file at https://angular.io/license |
| */ |
| function anchorDef(flags, matchedQueriesDsl, ngContentIndex, childCount, handleEvent, templateFactory) { |
| flags |= 1 /* TypeElement */; |
| var _a = splitMatchedQueriesDsl(matchedQueriesDsl), matchedQueries = _a.matchedQueries, references = _a.references, matchedQueryIds = _a.matchedQueryIds; |
| var template = templateFactory ? resolveDefinition(templateFactory) : null; |
| return { |
| // will bet set by the view definition |
| nodeIndex: -1, |
| parent: null, |
| renderParent: null, |
| bindingIndex: -1, |
| outputIndex: -1, |
| // regular values |
| flags: flags, |
| checkIndex: -1, |
| childFlags: 0, |
| directChildFlags: 0, |
| childMatchedQueries: 0, matchedQueries: matchedQueries, matchedQueryIds: matchedQueryIds, references: references, ngContentIndex: ngContentIndex, childCount: childCount, |
| bindings: [], |
| bindingFlags: 0, |
| outputs: [], |
| element: { |
| ns: null, |
| name: null, |
| attrs: null, template: template, |
| componentProvider: null, |
| componentView: null, |
| componentRendererType: null, |
| publicProviders: null, |
| allProviders: null, |
| handleEvent: handleEvent || NOOP |
| }, |
| provider: null, |
| text: null, |
| query: null, |
| ngContent: null |
| }; |
| } |
| function elementDef(checkIndex, flags, matchedQueriesDsl, ngContentIndex, childCount, namespaceAndName, fixedAttrs, bindings, outputs, handleEvent, componentView, componentRendererType) { |
| var _a; |
| if (fixedAttrs === void 0) { fixedAttrs = []; } |
| if (!handleEvent) { |
| handleEvent = NOOP; |
| } |
| var _b = splitMatchedQueriesDsl(matchedQueriesDsl), matchedQueries = _b.matchedQueries, references = _b.references, matchedQueryIds = _b.matchedQueryIds; |
| var ns = null; |
| var name = null; |
| if (namespaceAndName) { |
| _a = __read(splitNamespace(namespaceAndName), 2), ns = _a[0], name = _a[1]; |
| } |
| bindings = bindings || []; |
| var bindingDefs = new Array(bindings.length); |
| for (var i = 0; i < bindings.length; i++) { |
| var _c = __read(bindings[i], 3), bindingFlags = _c[0], namespaceAndName_1 = _c[1], suffixOrSecurityContext = _c[2]; |
| var _d = __read(splitNamespace(namespaceAndName_1), 2), ns_1 = _d[0], name_1 = _d[1]; |
| var securityContext = undefined; |
| var suffix = undefined; |
| switch (bindingFlags & 15 /* Types */) { |
| case 4 /* TypeElementStyle */: |
| suffix = suffixOrSecurityContext; |
| break; |
| case 1 /* TypeElementAttribute */: |
| case 8 /* TypeProperty */: |
| securityContext = suffixOrSecurityContext; |
| break; |
| } |
| bindingDefs[i] = |
| { flags: bindingFlags, ns: ns_1, name: name_1, nonMinifiedName: name_1, securityContext: securityContext, suffix: suffix }; |
| } |
| outputs = outputs || []; |
| var outputDefs = new Array(outputs.length); |
| for (var i = 0; i < outputs.length; i++) { |
| var _e = __read(outputs[i], 2), target = _e[0], eventName = _e[1]; |
| outputDefs[i] = { |
| type: 0 /* ElementOutput */, |
| target: target, eventName: eventName, |
| propName: null |
| }; |
| } |
| fixedAttrs = fixedAttrs || []; |
| var attrs = fixedAttrs.map(function (_a) { |
| var _b = __read(_a, 2), namespaceAndName = _b[0], value = _b[1]; |
| var _c = __read(splitNamespace(namespaceAndName), 2), ns = _c[0], name = _c[1]; |
| return [ns, name, value]; |
| }); |
| componentRendererType = resolveRendererType2(componentRendererType); |
| if (componentView) { |
| flags |= 33554432 /* ComponentView */; |
| } |
| flags |= 1 /* TypeElement */; |
| return { |
| // will bet set by the view definition |
| nodeIndex: -1, |
| parent: null, |
| renderParent: null, |
| bindingIndex: -1, |
| outputIndex: -1, |
| // regular values |
| checkIndex: checkIndex, |
| flags: flags, |
| childFlags: 0, |
| directChildFlags: 0, |
| childMatchedQueries: 0, matchedQueries: matchedQueries, matchedQueryIds: matchedQueryIds, references: references, ngContentIndex: ngContentIndex, childCount: childCount, |
| bindings: bindingDefs, |
| bindingFlags: calcBindingFlags(bindingDefs), |
| outputs: outputDefs, |
| element: { |
| ns: ns, |
| name: name, |
| attrs: attrs, |
| template: null, |
| // will bet set by the view definition |
| componentProvider: null, |
| componentView: componentView || null, |
| componentRendererType: componentRendererType, |
| publicProviders: null, |
| allProviders: null, |
| handleEvent: handleEvent || NOOP, |
| }, |
| provider: null, |
| text: null, |
| query: null, |
| ngContent: null |
| }; |
| } |
| function createElement(view, renderHost, def) { |
| var elDef = def.element; |
| var rootSelectorOrNode = view.root.selectorOrNode; |
| var renderer = view.renderer; |
| var el; |
| if (view.parent || !rootSelectorOrNode) { |
| if (elDef.name) { |
| el = renderer.createElement(elDef.name, elDef.ns); |
| } |
| else { |
| el = renderer.createComment(''); |
| } |
| var parentEl = getParentRenderElement(view, renderHost, def); |
| if (parentEl) { |
| renderer.appendChild(parentEl, el); |
| } |
| } |
| else { |
| // when using native Shadow DOM, do not clear the root element contents to allow slot projection |
| var preserveContent = (!!elDef.componentRendererType && |
| elDef.componentRendererType.encapsulation === exports.ViewEncapsulation.ShadowDom); |
| el = renderer.selectRootElement(rootSelectorOrNode, preserveContent); |
| } |
| if (elDef.attrs) { |
| for (var i = 0; i < elDef.attrs.length; i++) { |
| var _a = __read(elDef.attrs[i], 3), ns = _a[0], name_2 = _a[1], value = _a[2]; |
| renderer.setAttribute(el, name_2, value, ns); |
| } |
| } |
| return el; |
| } |
| function listenToElementOutputs(view, compView, def, el) { |
| for (var i = 0; i < def.outputs.length; i++) { |
| var output = def.outputs[i]; |
| var handleEventClosure = renderEventHandlerClosure(view, def.nodeIndex, elementEventFullName(output.target, output.eventName)); |
| var listenTarget = output.target; |
| var listenerView = view; |
| if (output.target === 'component') { |
| listenTarget = null; |
| listenerView = compView; |
| } |
| var disposable = listenerView.renderer.listen(listenTarget || el, output.eventName, handleEventClosure); |
| view.disposables[def.outputIndex + i] = disposable; |
| } |
| } |
| function renderEventHandlerClosure(view, index, eventName) { |
| return function (event) { return dispatchEvent(view, index, eventName, event); }; |
| } |
| function checkAndUpdateElementInline(view, def, v0, v1, v2, v3, v4, v5, v6, v7, v8, v9) { |
| var bindLen = def.bindings.length; |
| var changed = false; |
| if (bindLen > 0 && checkAndUpdateElementValue(view, def, 0, v0)) |
| changed = true; |
| if (bindLen > 1 && checkAndUpdateElementValue(view, def, 1, v1)) |
| changed = true; |
| if (bindLen > 2 && checkAndUpdateElementValue(view, def, 2, v2)) |
| changed = true; |
| if (bindLen > 3 && checkAndUpdateElementValue(view, def, 3, v3)) |
| changed = true; |
| if (bindLen > 4 && checkAndUpdateElementValue(view, def, 4, v4)) |
| changed = true; |
| if (bindLen > 5 && checkAndUpdateElementValue(view, def, 5, v5)) |
| changed = true; |
| if (bindLen > 6 && checkAndUpdateElementValue(view, def, 6, v6)) |
| changed = true; |
| if (bindLen > 7 && checkAndUpdateElementValue(view, def, 7, v7)) |
| changed = true; |
| if (bindLen > 8 && checkAndUpdateElementValue(view, def, 8, v8)) |
| changed = true; |
| if (bindLen > 9 && checkAndUpdateElementValue(view, def, 9, v9)) |
| changed = true; |
| return changed; |
| } |
| function checkAndUpdateElementDynamic(view, def, values) { |
| var changed = false; |
| for (var i = 0; i < values.length; i++) { |
| if (checkAndUpdateElementValue(view, def, i, values[i])) |
| changed = true; |
| } |
| return changed; |
| } |
| function checkAndUpdateElementValue(view, def, bindingIdx, value) { |
| if (!checkAndUpdateBinding(view, def, bindingIdx, value)) { |
| return false; |
| } |
| var binding = def.bindings[bindingIdx]; |
| var elData = asElementData(view, def.nodeIndex); |
| var renderNode = elData.renderElement; |
| var name = binding.name; |
| switch (binding.flags & 15 /* Types */) { |
| case 1 /* TypeElementAttribute */: |
| setElementAttribute(view, binding, renderNode, binding.ns, name, value); |
| break; |
| case 2 /* TypeElementClass */: |
| setElementClass(view, renderNode, name, value); |
| break; |
| case 4 /* TypeElementStyle */: |
| setElementStyle(view, binding, renderNode, name, value); |
| break; |
| case 8 /* TypeProperty */: |
| var bindView = (def.flags & 33554432 /* ComponentView */ && |
| binding.flags & 32 /* SyntheticHostProperty */) ? |
| elData.componentView : |
| view; |
| setElementProperty(bindView, binding, renderNode, name, value); |
| break; |
| } |
| return true; |
| } |
| function setElementAttribute(view, binding, renderNode, ns, name, value) { |
| var securityContext = binding.securityContext; |
| var renderValue = securityContext ? view.root.sanitizer.sanitize(securityContext, value) : value; |
| renderValue = renderValue != null ? renderValue.toString() : null; |
| var renderer = view.renderer; |
| if (value != null) { |
| renderer.setAttribute(renderNode, name, renderValue, ns); |
| } |
| else { |
| renderer.removeAttribute(renderNode, name, ns); |
| } |
| } |
| function setElementClass(view, renderNode, name, value) { |
| var renderer = view.renderer; |
| if (value) { |
| renderer.addClass(renderNode, name); |
| } |
| else { |
| renderer.removeClass(renderNode, name); |
| } |
| } |
| function setElementStyle(view, binding, renderNode, name, value) { |
| var renderValue = view.root.sanitizer.sanitize(exports.SecurityContext.STYLE, value); |
| if (renderValue != null) { |
| renderValue = renderValue.toString(); |
| var unit = binding.suffix; |
| if (unit != null) { |
| renderValue = renderValue + unit; |
| } |
| } |
| else { |
| renderValue = null; |
| } |
| var renderer = view.renderer; |
| if (renderValue != null) { |
| renderer.setStyle(renderNode, name, renderValue); |
| } |
| else { |
| renderer.removeStyle(renderNode, name); |
| } |
| } |
| function setElementProperty(view, binding, renderNode, name, value) { |
| var securityContext = binding.securityContext; |
| var renderValue = securityContext ? view.root.sanitizer.sanitize(securityContext, value) : value; |
| view.renderer.setProperty(renderNode, name, renderValue); |
| } |
| |
| /** |
| * @license |
| * Copyright Google Inc. All Rights Reserved. |
| * |
| * Use of this source code is governed by an MIT-style license that can be |
| * found in the LICENSE file at https://angular.io/license |
| */ |
| function queryDef(flags, id, bindings) { |
| var bindingDefs = []; |
| for (var propName in bindings) { |
| var bindingType = bindings[propName]; |
| bindingDefs.push({ propName: propName, bindingType: bindingType }); |
| } |
| return { |
| // will bet set by the view definition |
| nodeIndex: -1, |
| parent: null, |
| renderParent: null, |
| bindingIndex: -1, |
| outputIndex: -1, |
| // regular values |
| // TODO(vicb): check |
| checkIndex: -1, flags: flags, |
| childFlags: 0, |
| directChildFlags: 0, |
| childMatchedQueries: 0, |
| ngContentIndex: -1, |
| matchedQueries: {}, |
| matchedQueryIds: 0, |
| references: {}, |
| childCount: 0, |
| bindings: [], |
| bindingFlags: 0, |
| outputs: [], |
| element: null, |
| provider: null, |
| text: null, |
| query: { id: id, filterId: filterQueryId(id), bindings: bindingDefs }, |
| ngContent: null |
| }; |
| } |
| function createQuery() { |
| return new QueryList(); |
| } |
| function dirtyParentQueries(view) { |
| var queryIds = view.def.nodeMatchedQueries; |
| while (view.parent && isEmbeddedView(view)) { |
| var tplDef = view.parentNodeDef; |
| view = view.parent; |
| // content queries |
| var end = tplDef.nodeIndex + tplDef.childCount; |
| for (var i = 0; i <= end; i++) { |
| var nodeDef = view.def.nodes[i]; |
| if ((nodeDef.flags & 67108864 /* TypeContentQuery */) && |
| (nodeDef.flags & 536870912 /* DynamicQuery */) && |
| (nodeDef.query.filterId & queryIds) === nodeDef.query.filterId) { |
| asQueryList(view, i).setDirty(); |
| } |
| if ((nodeDef.flags & 1 /* TypeElement */ && i + nodeDef.childCount < tplDef.nodeIndex) || |
| !(nodeDef.childFlags & 67108864 /* TypeContentQuery */) || |
| !(nodeDef.childFlags & 536870912 /* DynamicQuery */)) { |
| // skip elements that don't contain the template element or no query. |
| i += nodeDef.childCount; |
| } |
| } |
| } |
| // view queries |
| if (view.def.nodeFlags & 134217728 /* TypeViewQuery */) { |
| for (var i = 0; i < view.def.nodes.length; i++) { |
| var nodeDef = view.def.nodes[i]; |
| if ((nodeDef.flags & 134217728 /* TypeViewQuery */) && (nodeDef.flags & 536870912 /* DynamicQuery */)) { |
| asQueryList(view, i).setDirty(); |
| } |
| // only visit the root nodes |
| i += nodeDef.childCount; |
| } |
| } |
| } |
| function checkAndUpdateQuery(view, nodeDef) { |
| var queryList = asQueryList(view, nodeDef.nodeIndex); |
| if (!queryList.dirty) { |
| return; |
| } |
| var directiveInstance; |
| var newValues = undefined; |
| if (nodeDef.flags & 67108864 /* TypeContentQuery */) { |
| var elementDef = nodeDef.parent.parent; |
| newValues = calcQueryValues(view, elementDef.nodeIndex, elementDef.nodeIndex + elementDef.childCount, nodeDef.query, []); |
| directiveInstance = asProviderData(view, nodeDef.parent.nodeIndex).instance; |
| } |
| else if (nodeDef.flags & 134217728 /* TypeViewQuery */) { |
| newValues = calcQueryValues(view, 0, view.def.nodes.length - 1, nodeDef.query, []); |
| directiveInstance = view.component; |
| } |
| queryList.reset(newValues); |
| var bindings = nodeDef.query.bindings; |
| var notify = false; |
| for (var i = 0; i < bindings.length; i++) { |
| var binding = bindings[i]; |
| var boundValue = void 0; |
| switch (binding.bindingType) { |
| case 0 /* First */: |
| boundValue = queryList.first; |
| break; |
| case 1 /* All */: |
| boundValue = queryList; |
| notify = true; |
| break; |
| } |
| directiveInstance[binding.propName] = boundValue; |
| } |
| if (notify) { |
| queryList.notifyOnChanges(); |
| } |
| } |
| function calcQueryValues(view, startIndex, endIndex, queryDef, values) { |
| for (var i = startIndex; i <= endIndex; i++) { |
| var nodeDef = view.def.nodes[i]; |
| var valueType = nodeDef.matchedQueries[queryDef.id]; |
| if (valueType != null) { |
| values.push(getQueryValue(view, nodeDef, valueType)); |
| } |
| if (nodeDef.flags & 1 /* TypeElement */ && nodeDef.element.template && |
| (nodeDef.element.template.nodeMatchedQueries & queryDef.filterId) === |
| queryDef.filterId) { |
| var elementData = asElementData(view, i); |
| // check embedded views that were attached at the place of their template, |
| // but process child nodes first if some match the query (see issue #16568) |
| if ((nodeDef.childMatchedQueries & queryDef.filterId) === queryDef.filterId) { |
| calcQueryValues(view, i + 1, i + nodeDef.childCount, queryDef, values); |
| i += nodeDef.childCount; |
| } |
| if (nodeDef.flags & 16777216 /* EmbeddedViews */) { |
| var embeddedViews = elementData.viewContainer._embeddedViews; |
| for (var k = 0; k < embeddedViews.length; k++) { |
| var embeddedView = embeddedViews[k]; |
| var dvc = declaredViewContainer(embeddedView); |
| if (dvc && dvc === elementData) { |
| calcQueryValues(embeddedView, 0, embeddedView.def.nodes.length - 1, queryDef, values); |
| } |
| } |
| } |
| var projectedViews = elementData.template._projectedViews; |
| if (projectedViews) { |
| for (var k = 0; k < projectedViews.length; k++) { |
| var projectedView = projectedViews[k]; |
| calcQueryValues(projectedView, 0, projectedView.def.nodes.length - 1, queryDef, values); |
| } |
| } |
| } |
| if ((nodeDef.childMatchedQueries & queryDef.filterId) !== queryDef.filterId) { |
| // if no child matches the query, skip the children. |
| i += nodeDef.childCount; |
| } |
| } |
| return values; |
| } |
| function getQueryValue(view, nodeDef, queryValueType) { |
| if (queryValueType != null) { |
| // a match |
| switch (queryValueType) { |
| case 1 /* RenderElement */: |
| return asElementData(view, nodeDef.nodeIndex).renderElement; |
| case 0 /* ElementRef */: |
| return new ElementRef(asElementData(view, nodeDef.nodeIndex).renderElement); |
| case 2 /* TemplateRef */: |
| return asElementData(view, nodeDef.nodeIndex).template; |
| case 3 /* ViewContainerRef */: |
| return asElementData(view, nodeDef.nodeIndex).viewContainer; |
| case 4 /* Provider */: |
| return asProviderData(view, nodeDef.nodeIndex).instance; |
| } |
| } |
| } |
| |
| /** |
| * @license |
| * Copyright Google Inc. All Rights Reserved. |
| * |
| * Use of this source code is governed by an MIT-style license that can be |
| * found in the LICENSE file at https://angular.io/license |
| */ |
| function ngContentDef(ngContentIndex, index) { |
| return { |
| // will bet set by the view definition |
| nodeIndex: -1, |
| parent: null, |
| renderParent: null, |
| bindingIndex: -1, |
| outputIndex: -1, |
| // regular values |
| checkIndex: -1, |
| flags: 8 /* TypeNgContent */, |
| childFlags: 0, |
| directChildFlags: 0, |
| childMatchedQueries: 0, |
| matchedQueries: {}, |
| matchedQueryIds: 0, |
| references: {}, ngContentIndex: ngContentIndex, |
| childCount: 0, |
| bindings: [], |
| bindingFlags: 0, |
| outputs: [], |
| element: null, |
| provider: null, |
| text: null, |
| query: null, |
| ngContent: { index: index } |
| }; |
| } |
| function appendNgContent(view, renderHost, def) { |
| var parentEl = getParentRenderElement(view, renderHost, def); |
| if (!parentEl) { |
| // Nothing to do if there is no parent element. |
| return; |
| } |
| var ngContentIndex = def.ngContent.index; |
| visitProjectedRenderNodes(view, ngContentIndex, 1 /* AppendChild */, parentEl, null, undefined); |
| } |
| |
| /** |
| * @license |
| * Copyright Google Inc. All Rights Reserved. |
| * |
| * Use of this source code is governed by an MIT-style license that can be |
| * found in the LICENSE file at https://angular.io/license |
| */ |
| function purePipeDef(checkIndex, argCount) { |
| // argCount + 1 to include the pipe as first arg |
| return _pureExpressionDef(128 /* TypePurePipe */, checkIndex, new Array(argCount + 1)); |
| } |
| function pureArrayDef(checkIndex, argCount) { |
| return _pureExpressionDef(32 /* TypePureArray */, checkIndex, new Array(argCount)); |
| } |
| function pureObjectDef(checkIndex, propToIndex) { |
| var keys = Object.keys(propToIndex); |
| var nbKeys = keys.length; |
| var propertyNames = new Array(nbKeys); |
| for (var i = 0; i < nbKeys; i++) { |
| var key = keys[i]; |
| var index = propToIndex[key]; |
| propertyNames[index] = key; |
| } |
| return _pureExpressionDef(64 /* TypePureObject */, checkIndex, propertyNames); |
| } |
| function _pureExpressionDef(flags, checkIndex, propertyNames) { |
| var bindings = new Array(propertyNames.length); |
| for (var i = 0; i < propertyNames.length; i++) { |
| var prop = propertyNames[i]; |
| bindings[i] = { |
| flags: 8 /* TypeProperty */, |
| name: prop, |
| ns: null, |
| nonMinifiedName: prop, |
| securityContext: null, |
| suffix: null |
| }; |
| } |
| return { |
| // will bet set by the view definition |
| nodeIndex: -1, |
| parent: null, |
| renderParent: null, |
| bindingIndex: -1, |
| outputIndex: -1, |
| // regular values |
| checkIndex: checkIndex, |
| flags: flags, |
| childFlags: 0, |
| directChildFlags: 0, |
| childMatchedQueries: 0, |
| matchedQueries: {}, |
| matchedQueryIds: 0, |
| references: {}, |
| ngContentIndex: -1, |
| childCount: 0, bindings: bindings, |
| bindingFlags: calcBindingFlags(bindings), |
| outputs: [], |
| element: null, |
| provider: null, |
| text: null, |
| query: null, |
| ngContent: null |
| }; |
| } |
| function createPureExpression(view, def) { |
| return { value: undefined }; |
| } |
| function checkAndUpdatePureExpressionInline(view, def, v0, v1, v2, v3, v4, v5, v6, v7, v8, v9) { |
| var bindings = def.bindings; |
| var changed = false; |
| var bindLen = bindings.length; |
| if (bindLen > 0 && checkAndUpdateBinding(view, def, 0, v0)) |
| changed = true; |
| if (bindLen > 1 && checkAndUpdateBinding(view, def, 1, v1)) |
| changed = true; |
| if (bindLen > 2 && checkAndUpdateBinding(view, def, 2, v2)) |
| changed = true; |
| if (bindLen > 3 && checkAndUpdateBinding(view, def, 3, v3)) |
| changed = true; |
| if (bindLen > 4 && checkAndUpdateBinding(view, def, 4, v4)) |
| changed = true; |
| if (bindLen > 5 && checkAndUpdateBinding(view, def, 5, v5)) |
| changed = true; |
| if (bindLen > 6 && checkAndUpdateBinding(view, def, 6, v6)) |
| changed = true; |
| if (bindLen > 7 && checkAndUpdateBinding(view, def, 7, v7)) |
| changed = true; |
| if (bindLen > 8 && checkAndUpdateBinding(view, def, 8, v8)) |
| changed = true; |
| if (bindLen > 9 && checkAndUpdateBinding(view, def, 9, v9)) |
| changed = true; |
| if (changed) { |
| var data = asPureExpressionData(view, def.nodeIndex); |
| var value = void 0; |
| switch (def.flags & 201347067 /* Types */) { |
| case 32 /* TypePureArray */: |
| value = new Array(bindings.length); |
| if (bindLen > 0) |
| value[0] = v0; |
| if (bindLen > 1) |
| value[1] = v1; |
| if (bindLen > 2) |
| value[2] = v2; |
| if (bindLen > 3) |
| value[3] = v3; |
| if (bindLen > 4) |
| value[4] = v4; |
| if (bindLen > 5) |
| value[5] = v5; |
| if (bindLen > 6) |
| value[6] = v6; |
| if (bindLen > 7) |
| value[7] = v7; |
| if (bindLen > 8) |
| value[8] = v8; |
| if (bindLen > 9) |
| value[9] = v9; |
| break; |
| case 64 /* TypePureObject */: |
| value = {}; |
| if (bindLen > 0) |
| value[bindings[0].name] = v0; |
| if (bindLen > 1) |
| value[bindings[1].name] = v1; |
| if (bindLen > 2) |
| value[bindings[2].name] = v2; |
| if (bindLen > 3) |
| value[bindings[3].name] = v3; |
| if (bindLen > 4) |
| value[bindings[4].name] = v4; |
| if (bindLen > 5) |
| value[bindings[5].name] = v5; |
| if (bindLen > 6) |
| value[bindings[6].name] = v6; |
| if (bindLen > 7) |
| value[bindings[7].name] = v7; |
| if (bindLen > 8) |
| value[bindings[8].name] = v8; |
| if (bindLen > 9) |
| value[bindings[9].name] = v9; |
| break; |
| case 128 /* TypePurePipe */: |
| var pipe = v0; |
| switch (bindLen) { |
| case 1: |
| value = pipe.transform(v0); |
| break; |
| case 2: |
| value = pipe.transform(v1); |
| break; |
| case 3: |
| value = pipe.transform(v1, v2); |
| break; |
| case 4: |
| value = pipe.transform(v1, v2, v3); |
| break; |
| case 5: |
| value = pipe.transform(v1, v2, v3, v4); |
| break; |
| case 6: |
| value = pipe.transform(v1, v2, v3, v4, v5); |
| break; |
| case 7: |
| value = pipe.transform(v1, v2, v3, v4, v5, v6); |
| break; |
| case 8: |
| value = pipe.transform(v1, v2, v3, v4, v5, v6, v7); |
| break; |
| case 9: |
| value = pipe.transform(v1, v2, v3, v4, v5, v6, v7, v8); |
| break; |
| case 10: |
| value = pipe.transform(v1, v2, v3, v4, v5, v6, v7, v8, v9); |
| break; |
| } |
| break; |
| } |
| data.value = value; |
| } |
| return changed; |
| } |
| function checkAndUpdatePureExpressionDynamic(view, def, values) { |
| var bindings = def.bindings; |
| var changed = false; |
| for (var i = 0; i < values.length; i++) { |
| // Note: We need to loop over all values, so that |
| // the old values are updates as well! |
| if (checkAndUpdateBinding(view, def, i, values[i])) { |
| changed = true; |
| } |
| } |
| if (changed) { |
| var data = asPureExpressionData(view, def.nodeIndex); |
| var value = void 0; |
| switch (def.flags & 201347067 /* Types */) { |
| case 32 /* TypePureArray */: |
| value = values; |
| break; |
| case 64 /* TypePureObject */: |
| value = {}; |
| for (var i = 0; i < values.length; i++) { |
| value[bindings[i].name] = values[i]; |
| } |
| break; |
| case 128 /* TypePurePipe */: |
| var pipe = values[0]; |
| var params = values.slice(1); |
| value = pipe.transform.apply(pipe, __spread(params)); |
| break; |
| } |
| data.value = value; |
| } |
| return changed; |
| } |
| |
| /** |
| * @license |
| * Copyright Google Inc. All Rights Reserved. |
| * |
| * Use of this source code is governed by an MIT-style license that can be |
| * found in the LICENSE file at https://angular.io/license |
| */ |
| function textDef(checkIndex, ngContentIndex, staticText) { |
| var bindings = new Array(staticText.length - 1); |
| for (var i = 1; i < staticText.length; i++) { |
| bindings[i - 1] = { |
| flags: 8 /* TypeProperty */, |
| name: null, |
| ns: null, |
| nonMinifiedName: null, |
| securityContext: null, |
| suffix: staticText[i], |
| }; |
| } |
| return { |
| // will bet set by the view definition |
| nodeIndex: -1, |
| parent: null, |
| renderParent: null, |
| bindingIndex: -1, |
| outputIndex: -1, |
| // regular values |
| checkIndex: checkIndex, |
| flags: 2 /* TypeText */, |
| childFlags: 0, |
| directChildFlags: 0, |
| childMatchedQueries: 0, |
| matchedQueries: {}, |
| matchedQueryIds: 0, |
| references: {}, ngContentIndex: ngContentIndex, |
| childCount: 0, bindings: bindings, |
| bindingFlags: 8 /* TypeProperty */, |
| outputs: [], |
| element: null, |
| provider: null, |
| text: { prefix: staticText[0] }, |
| query: null, |
| ngContent: null, |
| }; |
| } |
| function createText(view, renderHost, def) { |
| var renderNode; |
| var renderer = view.renderer; |
| renderNode = renderer.createText(def.text.prefix); |
| var parentEl = getParentRenderElement(view, renderHost, def); |
| if (parentEl) { |
| renderer.appendChild(parentEl, renderNode); |
| } |
| return { renderText: renderNode }; |
| } |
| function checkAndUpdateTextInline(view, def, v0, v1, v2, v3, v4, v5, v6, v7, v8, v9) { |
| var changed = false; |
| var bindings = def.bindings; |
| var bindLen = bindings.length; |
| if (bindLen > 0 && checkAndUpdateBinding(view, def, 0, v0)) |
| changed = true; |
| if (bindLen > 1 && checkAndUpdateBinding(view, def, 1, v1)) |
| changed = true; |
| if (bindLen > 2 && checkAndUpdateBinding(view, def, 2, v2)) |
| changed = true; |
| if (bindLen > 3 && checkAndUpdateBinding(view, def, 3, v3)) |
| changed = true; |
| if (bindLen > 4 && checkAndUpdateBinding(view, def, 4, v4)) |
| changed = true; |
| if (bindLen > 5 && checkAndUpdateBinding(view, def, 5, v5)) |
| changed = true; |
| if (bindLen > 6 && checkAndUpdateBinding(view, def, 6, v6)) |
| changed = true; |
| if (bindLen > 7 && checkAndUpdateBinding(view, def, 7, v7)) |
| changed = true; |
| if (bindLen > 8 && checkAndUpdateBinding(view, def, 8, v8)) |
| changed = true; |
| if (bindLen > 9 && checkAndUpdateBinding(view, def, 9, v9)) |
| changed = true; |
| if (changed) { |
| var value = def.text.prefix; |
| if (bindLen > 0) |
| value += _addInterpolationPart(v0, bindings[0]); |
| if (bindLen > 1) |
| value += _addInterpolationPart(v1, bindings[1]); |
| if (bindLen > 2) |
| value += _addInterpolationPart(v2, bindings[2]); |
| if (bindLen > 3) |
| value += _addInterpolationPart(v3, bindings[3]); |
| if (bindLen > 4) |
| value += _addInterpolationPart(v4, bindings[4]); |
| if (bindLen > 5) |
| value += _addInterpolationPart(v5, bindings[5]); |
| if (bindLen > 6) |
| value += _addInterpolationPart(v6, bindings[6]); |
| if (bindLen > 7) |
| value += _addInterpolationPart(v7, bindings[7]); |
| if (bindLen > 8) |
| value += _addInterpolationPart(v8, bindings[8]); |
| if (bindLen > 9) |
| value += _addInterpolationPart(v9, bindings[9]); |
| var renderNode = asTextData(view, def.nodeIndex).renderText; |
| view.renderer.setValue(renderNode, value); |
| } |
| return changed; |
| } |
| function checkAndUpdateTextDynamic(view, def, values) { |
| var bindings = def.bindings; |
| var changed = false; |
| for (var i = 0; i < values.length; i++) { |
| // Note: We need to loop over all values, so that |
| // the old values are updates as well! |
| if (checkAndUpdateBinding(view, def, i, values[i])) { |
| changed = true; |
| } |
| } |
| if (changed) { |
| var value = ''; |
| for (var i = 0; i < values.length; i++) { |
| value = value + _addInterpolationPart(values[i], bindings[i]); |
| } |
| value = def.text.prefix + value; |
| var renderNode = asTextData(view, def.nodeIndex).renderText; |
| view.renderer.setValue(renderNode, value); |
| } |
| return changed; |
| } |
| function _addInterpolationPart(value, binding) { |
| var valueStr = value != null ? value.toString() : ''; |
| return valueStr + binding.suffix; |
| } |
| |
| /** |
| * @license |
| * Copyright Google Inc. All Rights Reserved. |
| * |
| * Use of this source code is governed by an MIT-style license that can be |
| * found in the LICENSE file at https://angular.io/license |
| */ |
| function viewDef(flags, nodes, updateDirectives, updateRenderer) { |
| // clone nodes and set auto calculated values |
| var viewBindingCount = 0; |
| var viewDisposableCount = 0; |
| var viewNodeFlags = 0; |
| var viewRootNodeFlags = 0; |
| var viewMatchedQueries = 0; |
| var currentParent = null; |
| var currentRenderParent = null; |
| var currentElementHasPublicProviders = false; |
| var currentElementHasPrivateProviders = false; |
| var lastRenderRootNode = null; |
| for (var i = 0; i < nodes.length; i++) { |
| var node = nodes[i]; |
| node.nodeIndex = i; |
| node.parent = currentParent; |
| node.bindingIndex = viewBindingCount; |
| node.outputIndex = viewDisposableCount; |
| node.renderParent = currentRenderParent; |
| viewNodeFlags |= node.flags; |
| viewMatchedQueries |= node.matchedQueryIds; |
| if (node.element) { |
| var elDef = node.element; |
| elDef.publicProviders = |
| currentParent ? currentParent.element.publicProviders : Object.create(null); |
| elDef.allProviders = elDef.publicProviders; |
| // Note: We assume that all providers of an element are before any child element! |
| currentElementHasPublicProviders = false; |
| currentElementHasPrivateProviders = false; |
| if (node.element.template) { |
| viewMatchedQueries |= node.element.template.nodeMatchedQueries; |
| } |
| } |
| validateNode(currentParent, node, nodes.length); |
| viewBindingCount += node.bindings.length; |
| viewDisposableCount += node.outputs.length; |
| if (!currentRenderParent && (node.flags & 3 /* CatRenderNode */)) { |
| lastRenderRootNode = node; |
| } |
| if (node.flags & 20224 /* CatProvider */) { |
| if (!currentElementHasPublicProviders) { |
| currentElementHasPublicProviders = true; |
| // Use prototypical inheritance to not get O(n^2) complexity... |
| currentParent.element.publicProviders = |
| Object.create(currentParent.element.publicProviders); |
| currentParent.element.allProviders = currentParent.element.publicProviders; |
| } |
| var isPrivateService = (node.flags & 8192 /* PrivateProvider */) !== 0; |
| var isComponent = (node.flags & 32768 /* Component */) !== 0; |
| if (!isPrivateService || isComponent) { |
| currentParent.element.publicProviders[tokenKey(node.provider.token)] = node; |
| } |
| else { |
| if (!currentElementHasPrivateProviders) { |
| currentElementHasPrivateProviders = true; |
| // Use prototypical inheritance to not get O(n^2) complexity... |
| currentParent.element.allProviders = |
| Object.create(currentParent.element.publicProviders); |
| } |
| currentParent.element.allProviders[tokenKey(node.provider.token)] = node; |
| } |
| if (isComponent) { |
| currentParent.element.componentProvider = node; |
| } |
| } |
| if (currentParent) { |
| currentParent.childFlags |= node.flags; |
| currentParent.directChildFlags |= node.flags; |
| currentParent.childMatchedQueries |= node.matchedQueryIds; |
| if (node.element && node.element.template) { |
| currentParent.childMatchedQueries |= node.element.template.nodeMatchedQueries; |
| } |
| } |
| else { |
| viewRootNodeFlags |= node.flags; |
| } |
| if (node.childCount > 0) { |
| currentParent = node; |
| if (!isNgContainer(node)) { |
| currentRenderParent = node; |
| } |
| } |
| else { |
| // When the current node has no children, check if it is the last children of its parent. |
| // When it is, propagate the flags up. |
| // The loop is required because an element could be the last transitive children of several |
| // elements. We loop to either the root or the highest opened element (= with remaining |
| // children) |
| while (currentParent && i === currentParent.nodeIndex + currentParent.childCount) { |
| var newParent = currentParent.parent; |
| if (newParent) { |
| newParent.childFlags |= currentParent.childFlags; |
| newParent.childMatchedQueries |= currentParent.childMatchedQueries; |
| } |
| currentParent = newParent; |
| // We also need to update the render parent & account for ng-container |
| if (currentParent && isNgContainer(currentParent)) { |
| currentRenderParent = currentParent.renderParent; |
| } |
| else { |
| currentRenderParent = currentParent; |
| } |
| } |
| } |
| } |
| var handleEvent = function (view, nodeIndex, eventName, event) { |
| return nodes[nodeIndex].element.handleEvent(view, eventName, event); |
| }; |
| return { |
| // Will be filled later... |
| factory: null, |
| nodeFlags: viewNodeFlags, |
| rootNodeFlags: viewRootNodeFlags, |
| nodeMatchedQueries: viewMatchedQueries, flags: flags, |
| nodes: nodes, |
| updateDirectives: updateDirectives || NOOP, |
| updateRenderer: updateRenderer || NOOP, handleEvent: handleEvent, |
| bindingCount: viewBindingCount, |
| outputCount: viewDisposableCount, lastRenderRootNode: lastRenderRootNode |
| }; |
| } |
| function isNgContainer(node) { |
| return (node.flags & 1 /* TypeElement */) !== 0 && node.element.name === null; |
| } |
| function validateNode(parent, node, nodeCount) { |
| var template = node.element && node.element.template; |
| if (template) { |
| if (!template.lastRenderRootNode) { |
| throw new Error("Illegal State: Embedded templates without nodes are not allowed!"); |
| } |
| if (template.lastRenderRootNode && |
| template.lastRenderRootNode.flags & 16777216 /* EmbeddedViews */) { |
| throw new Error("Illegal State: Last root node of a template can't have embedded views, at index " + node.nodeIndex + "!"); |
| } |
| } |
| if (node.flags & 20224 /* CatProvider */) { |
| var parentFlags = parent ? parent.flags : 0; |
| if ((parentFlags & 1 /* TypeElement */) === 0) { |
| throw new Error("Illegal State: StaticProvider/Directive nodes need to be children of elements or anchors, at index " + node.nodeIndex + "!"); |
| } |
| } |
| if (node.query) { |
| if (node.flags & 67108864 /* TypeContentQuery */ && |
| (!parent || (parent.flags & 16384 /* TypeDirective */) === 0)) { |
| throw new Error("Illegal State: Content Query nodes need to be children of directives, at index " + node.nodeIndex + "!"); |
| } |
| if (node.flags & 134217728 /* TypeViewQuery */ && parent) { |
| throw new Error("Illegal State: View Query nodes have to be top level nodes, at index " + node.nodeIndex + "!"); |
| } |
| } |
| if (node.childCount) { |
| var parentEnd = parent ? parent.nodeIndex + parent.childCount : nodeCount - 1; |
| if (node.nodeIndex <= parentEnd && node.nodeIndex + node.childCount > parentEnd) { |
| throw new Error("Illegal State: childCount of node leads outside of parent, at index " + node.nodeIndex + "!"); |
| } |
| } |
| } |
| function createEmbeddedView(parent, anchorDef, viewDef, context) { |
| // embedded views are seen as siblings to the anchor, so we need |
| // to get the parent of the anchor and use it as parentIndex. |
| var view = createView(parent.root, parent.renderer, parent, anchorDef, viewDef); |
| initView(view, parent.component, context); |
| createViewNodes(view); |
| return view; |
| } |
| function createRootView(root, def, context) { |
| var view = createView(root, root.renderer, null, null, def); |
| initView(view, context, context); |
| createViewNodes(view); |
| return view; |
| } |
| function createComponentView(parentView, nodeDef, viewDef, hostElement) { |
| var rendererType = nodeDef.element.componentRendererType; |
| var compRenderer; |
| if (!rendererType) { |
| compRenderer = parentView.root.renderer; |
| } |
| else { |
| compRenderer = parentView.root.rendererFactory.createRenderer(hostElement, rendererType); |
| } |
| return createView(parentView.root, compRenderer, parentView, nodeDef.element.componentProvider, viewDef); |
| } |
| function createView(root, renderer, parent, parentNodeDef, def) { |
| var nodes = new Array(def.nodes.length); |
| var disposables = def.outputCount ? new Array(def.outputCount) : null; |
| var view = { |
| def: def, |
| parent: parent, |
| viewContainerParent: null, parentNodeDef: parentNodeDef, |
| context: null, |
| component: null, nodes: nodes, |
| state: 13 /* CatInit */, root: root, renderer: renderer, |
| oldValues: new Array(def.bindingCount), disposables: disposables, |
| initIndex: -1 |
| }; |
| return view; |
| } |
| function initView(view, component, context) { |
| view.component = component; |
| view.context = context; |
| } |
| function createViewNodes(view) { |
| var renderHost; |
| if (isComponentView(view)) { |
| var hostDef = view.parentNodeDef; |
| renderHost = asElementData(view.parent, hostDef.parent.nodeIndex).renderElement; |
| } |
| var def = view.def; |
| var nodes = view.nodes; |
| for (var i = 0; i < def.nodes.length; i++) { |
| var nodeDef = def.nodes[i]; |
| Services.setCurrentNode(view, i); |
| var nodeData = void 0; |
| switch (nodeDef.flags & 201347067 /* Types */) { |
| case 1 /* TypeElement */: |
| var el = createElement(view, renderHost, nodeDef); |
| var componentView = undefined; |
| if (nodeDef.flags & 33554432 /* ComponentView */) { |
| var compViewDef = resolveDefinition(nodeDef.element.componentView); |
| componentView = Services.createComponentView(view, nodeDef, compViewDef, el); |
| } |
| listenToElementOutputs(view, componentView, nodeDef, el); |
| nodeData = { |
| renderElement: el, |
| componentView: componentView, |
| viewContainer: null, |
| template: nodeDef.element.template ? createTemplateData(view, nodeDef) : undefined |
| }; |
| if (nodeDef.flags & 16777216 /* EmbeddedViews */) { |
| nodeData.viewContainer = createViewContainerData(view, nodeDef, nodeData); |
| } |
| break; |
| case 2 /* TypeText */: |
| nodeData = createText(view, renderHost, nodeDef); |
| break; |
| case 512 /* TypeClassProvider */: |
| case 1024 /* TypeFactoryProvider */: |
| case 2048 /* TypeUseExistingProvider */: |
| case 256 /* TypeValueProvider */: { |
| nodeData = nodes[i]; |
| if (!nodeData && !(nodeDef.flags & 4096 /* LazyProvider */)) { |
| var instance = createProviderInstance(view, nodeDef); |
| nodeData = { instance: instance }; |
| } |
| break; |
| } |
| case 16 /* TypePipe */: { |
| var instance = createPipeInstance(view, nodeDef); |
| nodeData = { instance: instance }; |
| break; |
| } |
| case 16384 /* TypeDirective */: { |
| nodeData = nodes[i]; |
| if (!nodeData) { |
| var instance = createDirectiveInstance(view, nodeDef); |
| nodeData = { instance: instance }; |
| } |
| if (nodeDef.flags & 32768 /* Component */) { |
| var compView = asElementData(view, nodeDef.parent.nodeIndex).componentView; |
| initView(compView, nodeData.instance, nodeData.instance); |
| } |
| break; |
| } |
| case 32 /* TypePureArray */: |
| case 64 /* TypePureObject */: |
| case 128 /* TypePurePipe */: |
| nodeData = createPureExpression(view, nodeDef); |
| break; |
| case 67108864 /* TypeContentQuery */: |
| case 134217728 /* TypeViewQuery */: |
| nodeData = createQuery(); |
| break; |
| case 8 /* TypeNgContent */: |
| appendNgContent(view, renderHost, nodeDef); |
| // no runtime data needed for NgContent... |
| nodeData = undefined; |
| break; |
| } |
| nodes[i] = nodeData; |
| } |
| // Create the ViewData.nodes of component views after we created everything else, |
| // so that e.g. ng-content works |
| execComponentViewsAction(view, ViewAction.CreateViewNodes); |
| // fill static content and view queries |
| execQueriesAction(view, 67108864 /* TypeContentQuery */ | 134217728 /* TypeViewQuery */, 268435456 /* StaticQuery */, 0 /* CheckAndUpdate */); |
| } |
| function checkNoChangesView(view) { |
| markProjectedViewsForCheck(view); |
| Services.updateDirectives(view, 1 /* CheckNoChanges */); |
| execEmbeddedViewsAction(view, ViewAction.CheckNoChanges); |
| Services.updateRenderer(view, 1 /* CheckNoChanges */); |
| execComponentViewsAction(view, ViewAction.CheckNoChanges); |
| // Note: We don't check queries for changes as we didn't do this in v2.x. |
| // TODO(tbosch): investigate if we can enable the check again in v5.x with a nicer error message. |
| view.state &= ~(64 /* CheckProjectedViews */ | 32 /* CheckProjectedView */); |
| } |
| function checkAndUpdateView(view) { |
| if (view.state & 1 /* BeforeFirstCheck */) { |
| view.state &= ~1 /* BeforeFirstCheck */; |
| view.state |= 2 /* FirstCheck */; |
| } |
| else { |
| view.state &= ~2 /* FirstCheck */; |
| } |
| shiftInitState(view, 0 /* InitState_BeforeInit */, 256 /* InitState_CallingOnInit */); |
| markProjectedViewsForCheck(view); |
| Services.updateDirectives(view, 0 /* CheckAndUpdate */); |
| execEmbeddedViewsAction(view, ViewAction.CheckAndUpdate); |
| execQueriesAction(view, 67108864 /* TypeContentQuery */, 536870912 /* DynamicQuery */, 0 /* CheckAndUpdate */); |
| var callInit = shiftInitState(view, 256 /* InitState_CallingOnInit */, 512 /* InitState_CallingAfterContentInit */); |
| callLifecycleHooksChildrenFirst(view, 2097152 /* AfterContentChecked */ | (callInit ? 1048576 /* AfterContentInit */ : 0)); |
| Services.updateRenderer(view, 0 /* CheckAndUpdate */); |
| execComponentViewsAction(view, ViewAction.CheckAndUpdate); |
| execQueriesAction(view, 134217728 /* TypeViewQuery */, 536870912 /* DynamicQuery */, 0 /* CheckAndUpdate */); |
| callInit = shiftInitState(view, 512 /* InitState_CallingAfterContentInit */, 768 /* InitState_CallingAfterViewInit */); |
| callLifecycleHooksChildrenFirst(view, 8388608 /* AfterViewChecked */ | (callInit ? 4194304 /* AfterViewInit */ : 0)); |
| if (view.def.flags & 2 /* OnPush */) { |
| view.state &= ~8 /* ChecksEnabled */; |
| } |
| view.state &= ~(64 /* CheckProjectedViews */ | 32 /* CheckProjectedView */); |
| shiftInitState(view, 768 /* InitState_CallingAfterViewInit */, 1024 /* InitState_AfterInit */); |
| } |
| function checkAndUpdateNode(view, nodeDef, argStyle, v0, v1, v2, v3, v4, v5, v6, v7, v8, v9) { |
| if (argStyle === 0 /* Inline */) { |
| return checkAndUpdateNodeInline(view, nodeDef, v0, v1, v2, v3, v4, v5, v6, v7, v8, v9); |
| } |
| else { |
| return checkAndUpdateNodeDynamic(view, nodeDef, v0); |
| } |
| } |
| function markProjectedViewsForCheck(view) { |
| var def = view.def; |
| if (!(def.nodeFlags & 4 /* ProjectedTemplate */)) { |
| return; |
| } |
| for (var i = 0; i < def.nodes.length; i++) { |
| var nodeDef = def.nodes[i]; |
| if (nodeDef.flags & 4 /* ProjectedTemplate */) { |
| var projectedViews = asElementData(view, i).template._projectedViews; |
| if (projectedViews) { |
| for (var i_1 = 0; i_1 < projectedViews.length; i_1++) { |
| var projectedView = projectedViews[i_1]; |
| projectedView.state |= 32 /* CheckProjectedView */; |
| markParentViewsForCheckProjectedViews(projectedView, view); |
| } |
| } |
| } |
| else if ((nodeDef.childFlags & 4 /* ProjectedTemplate */) === 0) { |
| // a parent with leafs |
| // no child is a component, |
| // then skip the children |
| i += nodeDef.childCount; |
| } |
| } |
| } |
| function checkAndUpdateNodeInline(view, nodeDef, v0, v1, v2, v3, v4, v5, v6, v7, v8, v9) { |
| switch (nodeDef.flags & 201347067 /* Types */) { |
| case 1 /* TypeElement */: |
| return checkAndUpdateElementInline(view, nodeDef, v0, v1, v2, v3, v4, v5, v6, v7, v8, v9); |
| case 2 /* TypeText */: |
| return checkAndUpdateTextInline(view, nodeDef, v0, v1, v2, v3, v4, v5, v6, v7, v8, v9); |
| case 16384 /* TypeDirective */: |
| return checkAndUpdateDirectiveInline(view, nodeDef, v0, v1, v2, v3, v4, v5, v6, v7, v8, v9); |
| case 32 /* TypePureArray */: |
| case 64 /* TypePureObject */: |
| case 128 /* TypePurePipe */: |
| return checkAndUpdatePureExpressionInline(view, nodeDef, v0, v1, v2, v3, v4, v5, v6, v7, v8, v9); |
| default: |
| throw 'unreachable'; |
| } |
| } |
| function checkAndUpdateNodeDynamic(view, nodeDef, values) { |
| switch (nodeDef.flags & 201347067 /* Types */) { |
| case 1 /* TypeElement */: |
| return checkAndUpdateElementDynamic(view, nodeDef, values); |
| case 2 /* TypeText */: |
| return checkAndUpdateTextDynamic(view, nodeDef, values); |
| case 16384 /* TypeDirective */: |
| return checkAndUpdateDirectiveDynamic(view, nodeDef, values); |
| case 32 /* TypePureArray */: |
| case 64 /* TypePureObject */: |
| case 128 /* TypePurePipe */: |
| return checkAndUpdatePureExpressionDynamic(view, nodeDef, values); |
| default: |
| throw 'unreachable'; |
| } |
| } |
| function checkNoChangesNode(view, nodeDef, argStyle, v0, v1, v2, v3, v4, v5, v6, v7, v8, v9) { |
| if (argStyle === 0 /* Inline */) { |
| checkNoChangesNodeInline(view, nodeDef, v0, v1, v2, v3, v4, v5, v6, v7, v8, v9); |
| } |
| else { |
| checkNoChangesNodeDynamic(view, nodeDef, v0); |
| } |
| // Returning false is ok here as we would have thrown in case of a change. |
| return false; |
| } |
| function checkNoChangesNodeInline(view, nodeDef, v0, v1, v2, v3, v4, v5, v6, v7, v8, v9) { |
| var bindLen = nodeDef.bindings.length; |
| if (bindLen > 0) |
| checkBindingNoChanges(view, nodeDef, 0, v0); |
| if (bindLen > 1) |
| checkBindingNoChanges(view, nodeDef, 1, v1); |
| if (bindLen > 2) |
| checkBindingNoChanges(view, nodeDef, 2, v2); |
| if (bindLen > 3) |
| checkBindingNoChanges(view, nodeDef, 3, v3); |
| if (bindLen > 4) |
| checkBindingNoChanges(view, nodeDef, 4, v4); |
| if (bindLen > 5) |
| checkBindingNoChanges(view, nodeDef, 5, v5); |
| if (bindLen > 6) |
| checkBindingNoChanges(view, nodeDef, 6, v6); |
| if (bindLen > 7) |
| checkBindingNoChanges(view, nodeDef, 7, v7); |
| if (bindLen > 8) |
| checkBindingNoChanges(view, nodeDef, 8, v8); |
| if (bindLen > 9) |
| checkBindingNoChanges(view, nodeDef, 9, v9); |
| } |
| function checkNoChangesNodeDynamic(view, nodeDef, values) { |
| for (var i = 0; i < values.length; i++) { |
| checkBindingNoChanges(view, nodeDef, i, values[i]); |
| } |
| } |
| /** |
| * Workaround https://github.com/angular/tsickle/issues/497 |
| * @suppress {misplacedTypeAnnotation} |
| */ |
| function checkNoChangesQuery(view, nodeDef) { |
| var queryList = asQueryList(view, nodeDef.nodeIndex); |
| if (queryList.dirty) { |
| throw expressionChangedAfterItHasBeenCheckedError(Services.createDebugContext(view, nodeDef.nodeIndex), "Query " + nodeDef.query.id + " not dirty", "Query " + nodeDef.query.id + " dirty", (view.state & 1 /* BeforeFirstCheck */) !== 0); |
| } |
| } |
| function destroyView(view) { |
| if (view.state & 128 /* Destroyed */) { |
| return; |
| } |
| execEmbeddedViewsAction(view, ViewAction.Destroy); |
| execComponentViewsAction(view, ViewAction.Destroy); |
| callLifecycleHooksChildrenFirst(view, 131072 /* OnDestroy */); |
| if (view.disposables) { |
| for (var i = 0; i < view.disposables.length; i++) { |
| view.disposables[i](); |
| } |
| } |
| detachProjectedView(view); |
| if (view.renderer.destroyNode) { |
| destroyViewNodes(view); |
| } |
| if (isComponentView(view)) { |
| view.renderer.destroy(); |
| } |
| view.state |= 128 /* Destroyed */; |
| } |
| function destroyViewNodes(view) { |
| var len = view.def.nodes.length; |
| for (var i = 0; i < len; i++) { |
| var def = view.def.nodes[i]; |
| if (def.flags & 1 /* TypeElement */) { |
| view.renderer.destroyNode(asElementData(view, i).renderElement); |
| } |
| else if (def.flags & 2 /* TypeText */) { |
| view.renderer.destroyNode(asTextData(view, i).renderText); |
| } |
| else if (def.flags & 67108864 /* TypeContentQuery */ || def.flags & 134217728 /* TypeViewQuery */) { |
| asQueryList(view, i).destroy(); |
| } |
| } |
| } |
| var ViewAction; |
| (function (ViewAction) { |
| ViewAction[ViewAction["CreateViewNodes"] = 0] = "CreateViewNodes"; |
| ViewAction[ViewAction["CheckNoChanges"] = 1] = "CheckNoChanges"; |
| ViewAction[ViewAction["CheckNoChangesProjectedViews"] = 2] = "CheckNoChangesProjectedViews"; |
| ViewAction[ViewAction["CheckAndUpdate"] = 3] = "CheckAndUpdate"; |
| ViewAction[ViewAction["CheckAndUpdateProjectedViews"] = 4] = "CheckAndUpdateProjectedViews"; |
| ViewAction[ViewAction["Destroy"] = 5] = "Destroy"; |
| })(ViewAction || (ViewAction = {})); |
| function execComponentViewsAction(view, action) { |
| var def = view.def; |
| if (!(def.nodeFlags & 33554432 /* ComponentView */)) { |
| return; |
| } |
| for (var i = 0; i < def.nodes.length; i++) { |
| var nodeDef = def.nodes[i]; |
| if (nodeDef.flags & 33554432 /* ComponentView */) { |
| // a leaf |
| callViewAction(asElementData(view, i).componentView, action); |
| } |
| else if ((nodeDef.childFlags & 33554432 /* ComponentView */) === 0) { |
| // a parent with leafs |
| // no child is a component, |
| // then skip the children |
| i += nodeDef.childCount; |
| } |
| } |
| } |
| function execEmbeddedViewsAction(view, action) { |
| var def = view.def; |
| if (!(def.nodeFlags & 16777216 /* EmbeddedViews */)) { |
| return; |
| } |
| for (var i = 0; i < def.nodes.length; i++) { |
| var nodeDef = def.nodes[i]; |
| if (nodeDef.flags & 16777216 /* EmbeddedViews */) { |
| // a leaf |
| var embeddedViews = asElementData(view, i).viewContainer._embeddedViews; |
| for (var k = 0; k < embeddedViews.length; k++) { |
| callViewAction(embeddedViews[k], action); |
| } |
| } |
| else if ((nodeDef.childFlags & 16777216 /* EmbeddedViews */) === 0) { |
| // a parent with leafs |
| // no child is a component, |
| // then skip the children |
| i += nodeDef.childCount; |
| } |
| } |
| } |
| function callViewAction(view, action) { |
| var viewState = view.state; |
| switch (action) { |
| case ViewAction.CheckNoChanges: |
| if ((viewState & 128 /* Destroyed */) === 0) { |
| if ((viewState & 12 /* CatDetectChanges */) === 12 /* CatDetectChanges */) { |
| checkNoChangesView(view); |
| } |
| else if (viewState & 64 /* CheckProjectedViews */) { |
| execProjectedViewsAction(view, ViewAction.CheckNoChangesProjectedViews); |
| } |
| } |
| break; |
| case ViewAction.CheckNoChangesProjectedViews: |
| if ((viewState & 128 /* Destroyed */) === 0) { |
| if (viewState & 32 /* CheckProjectedView */) { |
| checkNoChangesView(view); |
| } |
| else if (viewState & 64 /* CheckProjectedViews */) { |
| execProjectedViewsAction(view, action); |
| } |
| } |
| break; |
| case ViewAction.CheckAndUpdate: |
| if ((viewState & 128 /* Destroyed */) === 0) { |
| if ((viewState & 12 /* CatDetectChanges */) === 12 /* CatDetectChanges */) { |
| checkAndUpdateView(view); |
| } |
| else if (viewState & 64 /* CheckProjectedViews */) { |
| execProjectedViewsAction(view, ViewAction.CheckAndUpdateProjectedViews); |
| } |
| } |
| break; |
| case ViewAction.CheckAndUpdateProjectedViews: |
| if ((viewState & 128 /* Destroyed */) === 0) { |
| if (viewState & 32 /* CheckProjectedView */) { |
| checkAndUpdateView(view); |
| } |
| else if (viewState & 64 /* CheckProjectedViews */) { |
| execProjectedViewsAction(view, action); |
| } |
| } |
| break; |
| case ViewAction.Destroy: |
| // Note: destroyView recurses over all views, |
| // so we don't need to special case projected views here. |
| destroyView(view); |
| break; |
| case ViewAction.CreateViewNodes: |
| createViewNodes(view); |
| break; |
| } |
| } |
| function execProjectedViewsAction(view, action) { |
| execEmbeddedViewsAction(view, action); |
| execComponentViewsAction(view, action); |
| } |
| function execQueriesAction(view, queryFlags, staticDynamicQueryFlag, checkType) { |
| if (!(view.def.nodeFlags & queryFlags) || !(view.def.nodeFlags & staticDynamicQueryFlag)) { |
| return; |
| } |
| var nodeCount = view.def.nodes.length; |
| for (var i = 0; i < nodeCount; i++) { |
| var nodeDef = view.def.nodes[i]; |
| if ((nodeDef.flags & queryFlags) && (nodeDef.flags & staticDynamicQueryFlag)) { |
| Services.setCurrentNode(view, nodeDef.nodeIndex); |
| switch (checkType) { |
| case 0 /* CheckAndUpdate */: |
| checkAndUpdateQuery(view, nodeDef); |
| break; |
| case 1 /* CheckNoChanges */: |
| checkNoChangesQuery(view, nodeDef); |
| break; |
| } |
| } |
| if (!(nodeDef.childFlags & queryFlags) || !(nodeDef.childFlags & staticDynamicQueryFlag)) { |
| // no child has a matching query |
| // then skip the children |
| i += nodeDef.childCount; |
| } |
| } |
| } |
| |
| /** |
| * @license |
| * Copyright Google Inc. All Rights Reserved. |
| * |
| * Use of this source code is governed by an MIT-style license that can be |
| * found in the LICENSE file at https://angular.io/license |
| */ |
| var initialized = false; |
| function initServicesIfNeeded() { |
| if (initialized) { |
| return; |
| } |
| initialized = true; |
| var services = isDevMode() ? createDebugServices() : createProdServices(); |
| Services.setCurrentNode = services.setCurrentNode; |
| Services.createRootView = services.createRootView; |
| Services.createEmbeddedView = services.createEmbeddedView; |
| Services.createComponentView = services.createComponentView; |
| Services.createNgModuleRef = services.createNgModuleRef; |
| Services.overrideProvider = services.overrideProvider; |
| Services.overrideComponentView = services.overrideComponentView; |
| Services.clearOverrides = services.clearOverrides; |
| Services.checkAndUpdateView = services.checkAndUpdateView; |
| Services.checkNoChangesView = services.checkNoChangesView; |
| Services.destroyView = services.destroyView; |
| Services.resolveDep = resolveDep; |
| Services.createDebugContext = services.createDebugContext; |
| Services.handleEvent = services.handleEvent; |
| Services.updateDirectives = services.updateDirectives; |
| Services.updateRenderer = services.updateRenderer; |
| Services.dirtyParentQueries = dirtyParentQueries; |
| } |
| function createProdServices() { |
| return { |
| setCurrentNode: function () { }, |
| createRootView: createProdRootView, |
| createEmbeddedView: createEmbeddedView, |
| createComponentView: createComponentView, |
| createNgModuleRef: createNgModuleRef, |
| overrideProvider: NOOP, |
| overrideComponentView: NOOP, |
| clearOverrides: NOOP, |
| checkAndUpdateView: checkAndUpdateView, |
| checkNoChangesView: checkNoChangesView, |
| destroyView: destroyView, |
| createDebugContext: function (view, nodeIndex) { return new DebugContext_(view, nodeIndex); }, |
| handleEvent: function (view, nodeIndex, eventName, event) { |
| return view.def.handleEvent(view, nodeIndex, eventName, event); |
| }, |
| updateDirectives: function (view, checkType) { return view.def.updateDirectives(checkType === 0 /* CheckAndUpdate */ ? prodCheckAndUpdateNode : |
| prodCheckNoChangesNode, view); }, |
| updateRenderer: function (view, checkType) { return view.def.updateRenderer(checkType === 0 /* CheckAndUpdate */ ? prodCheckAndUpdateNode : |
| prodCheckNoChangesNode, view); }, |
| }; |
| } |
| function createDebugServices() { |
| return { |
| setCurrentNode: debugSetCurrentNode, |
| createRootView: debugCreateRootView, |
| createEmbeddedView: debugCreateEmbeddedView, |
| createComponentView: debugCreateComponentView, |
| createNgModuleRef: debugCreateNgModuleRef, |
| overrideProvider: debugOverrideProvider, |
| overrideComponentView: debugOverrideComponentView, |
| clearOverrides: debugClearOverrides, |
| checkAndUpdateView: debugCheckAndUpdateView, |
| checkNoChangesView: debugCheckNoChangesView, |
| destroyView: debugDestroyView, |
| createDebugContext: function (view, nodeIndex) { return new DebugContext_(view, nodeIndex); }, |
| handleEvent: debugHandleEvent, |
| updateDirectives: debugUpdateDirectives, |
| updateRenderer: debugUpdateRenderer, |
| }; |
| } |
| function createProdRootView(elInjector, projectableNodes, rootSelectorOrNode, def, ngModule, context) { |
| var rendererFactory = ngModule.injector.get(RendererFactory2); |
| return createRootView(createRootData(elInjector, ngModule, rendererFactory, projectableNodes, rootSelectorOrNode), def, context); |
| } |
| function debugCreateRootView(elInjector, projectableNodes, rootSelectorOrNode, def, ngModule, context) { |
| var rendererFactory = ngModule.injector.get(RendererFactory2); |
| var root = createRootData(elInjector, ngModule, new DebugRendererFactory2(rendererFactory), projectableNodes, rootSelectorOrNode); |
| var defWithOverride = applyProviderOverridesToView(def); |
| return callWithDebugContext(DebugAction.create, createRootView, null, [root, defWithOverride, context]); |
| } |
| function createRootData(elInjector, ngModule, rendererFactory, projectableNodes, rootSelectorOrNode) { |
| var sanitizer = ngModule.injector.get(Sanitizer); |
| var errorHandler = ngModule.injector.get(ErrorHandler); |
| var renderer = rendererFactory.createRenderer(null, null); |
| return { |
| ngModule: ngModule, |
| injector: elInjector, projectableNodes: projectableNodes, |
| selectorOrNode: rootSelectorOrNode, sanitizer: sanitizer, rendererFactory: rendererFactory, renderer: renderer, errorHandler: errorHandler |
| }; |
| } |
| function debugCreateEmbeddedView(parentView, anchorDef, viewDef, context) { |
| var defWithOverride = applyProviderOverridesToView(viewDef); |
| return callWithDebugContext(DebugAction.create, createEmbeddedView, null, [parentView, anchorDef, defWithOverride, context]); |
| } |
| function debugCreateComponentView(parentView, nodeDef, viewDef, hostElement) { |
| var overrideComponentView = viewDefOverrides.get(nodeDef.element.componentProvider.provider.token); |
| if (overrideComponentView) { |
| viewDef = overrideComponentView; |
| } |
| else { |
| viewDef = applyProviderOverridesToView(viewDef); |
| } |
| return callWithDebugContext(DebugAction.create, createComponentView, null, [parentView, nodeDef, viewDef, hostElement]); |
| } |
| function debugCreateNgModuleRef(moduleType, parentInjector, bootstrapComponents, def) { |
| var defWithOverride = applyProviderOverridesToNgModule(def); |
| return createNgModuleRef(moduleType, parentInjector, bootstrapComponents, defWithOverride); |
| } |
| var providerOverrides = new Map(); |
| var providerOverridesWithScope = new Map(); |
| var viewDefOverrides = new Map(); |
| function debugOverrideProvider(override) { |
| providerOverrides.set(override.token, override); |
| var injectableDef; |
| if (typeof override.token === 'function' && (injectableDef = getInjectableDef(override.token)) && |
| typeof injectableDef.providedIn === 'function') { |
| providerOverridesWithScope.set(override.token, override); |
| } |
| } |
| function debugOverrideComponentView(comp, compFactory) { |
| var hostViewDef = resolveDefinition(getComponentViewDefinitionFactory(compFactory)); |
| var compViewDef = resolveDefinition(hostViewDef.nodes[0].element.componentView); |
| viewDefOverrides.set(comp, compViewDef); |
| } |
| function debugClearOverrides() { |
| providerOverrides.clear(); |
| providerOverridesWithScope.clear(); |
| viewDefOverrides.clear(); |
| } |
| // Notes about the algorithm: |
| // 1) Locate the providers of an element and check if one of them was overwritten |
| // 2) Change the providers of that element |
| // |
| // We only create new datastructures if we need to, to keep perf impact |
| // reasonable. |
| function applyProviderOverridesToView(def) { |
| if (providerOverrides.size === 0) { |
| return def; |
| } |
| var elementIndicesWithOverwrittenProviders = findElementIndicesWithOverwrittenProviders(def); |
| if (elementIndicesWithOverwrittenProviders.length === 0) { |
| return def; |
| } |
| // clone the whole view definition, |
| // as it maintains references between the nodes that are hard to update. |
| def = def.factory(function () { return NOOP; }); |
| for (var i = 0; i < elementIndicesWithOverwrittenProviders.length; i++) { |
| applyProviderOverridesToElement(def, elementIndicesWithOverwrittenProviders[i]); |
| } |
| return def; |
| function findElementIndicesWithOverwrittenProviders(def) { |
| var elIndicesWithOverwrittenProviders = []; |
| var lastElementDef = null; |
| for (var i = 0; i < def.nodes.length; i++) { |
| var nodeDef = def.nodes[i]; |
| if (nodeDef.flags & 1 /* TypeElement */) { |
| lastElementDef = nodeDef; |
| } |
| if (lastElementDef && nodeDef.flags & 3840 /* CatProviderNoDirective */ && |
| providerOverrides.has(nodeDef.provider.token)) { |
| elIndicesWithOverwrittenProviders.push(lastElementDef.nodeIndex); |
| lastElementDef = null; |
| } |
| } |
| return elIndicesWithOverwrittenProviders; |
| } |
| function applyProviderOverridesToElement(viewDef, elIndex) { |
| for (var i = elIndex + 1; i < viewDef.nodes.length; i++) { |
| var nodeDef = viewDef.nodes[i]; |
| if (nodeDef.flags & 1 /* TypeElement */) { |
| // stop at the next element |
| return; |
| } |
| if (nodeDef.flags & 3840 /* CatProviderNoDirective */) { |
| var provider = nodeDef.provider; |
| var override = providerOverrides.get(provider.token); |
| if (override) { |
| nodeDef.flags = (nodeDef.flags & ~3840 /* CatProviderNoDirective */) | override.flags; |
| provider.deps = splitDepsDsl(override.deps); |
| provider.value = override.value; |
| } |
| } |
| } |
| } |
| } |
| // Notes about the algorithm: |
| // We only create new datastructures if we need to, to keep perf impact |
| // reasonable. |
| function applyProviderOverridesToNgModule(def) { |
| var _a = calcHasOverrides(def), hasOverrides = _a.hasOverrides, hasDeprecatedOverrides = _a.hasDeprecatedOverrides; |
| if (!hasOverrides) { |
| return def; |
| } |
| // clone the whole view definition, |
| // as it maintains references between the nodes that are hard to update. |
| def = def.factory(function () { return NOOP; }); |
| applyProviderOverrides(def); |
| return def; |
| function calcHasOverrides(def) { |
| var hasOverrides = false; |
| var hasDeprecatedOverrides = false; |
| if (providerOverrides.size === 0) { |
| return { hasOverrides: hasOverrides, hasDeprecatedOverrides: hasDeprecatedOverrides }; |
| } |
| def.providers.forEach(function (node) { |
| var override = providerOverrides.get(node.token); |
| if ((node.flags & 3840 /* CatProviderNoDirective */) && override) { |
| hasOverrides = true; |
| hasDeprecatedOverrides = hasDeprecatedOverrides || override.deprecatedBehavior; |
| } |
| }); |
| def.modules.forEach(function (module) { |
| providerOverridesWithScope.forEach(function (override, token) { |
| if (getInjectableDef(token).providedIn === module) { |
| hasOverrides = true; |
| hasDeprecatedOverrides = hasDeprecatedOverrides || override.deprecatedBehavior; |
| } |
| }); |
| }); |
| return { hasOverrides: hasOverrides, hasDeprecatedOverrides: hasDeprecatedOverrides }; |
| } |
| function applyProviderOverrides(def) { |
| for (var i = 0; i < def.providers.length; i++) { |
| var provider = def.providers[i]; |
| if (hasDeprecatedOverrides) { |
| // We had a bug where me made |
| // all providers lazy. Keep this logic behind a flag |
| // for migrating existing users. |
| provider.flags |= 4096 /* LazyProvider */; |
| } |
| var override = providerOverrides.get(provider.token); |
| if (override) { |
| provider.flags = (provider.flags & ~3840 /* CatProviderNoDirective */) | override.flags; |
| provider.deps = splitDepsDsl(override.deps); |
| provider.value = override.value; |
| } |
| } |
| if (providerOverridesWithScope.size > 0) { |
| var moduleSet_1 = new Set(def.modules); |
| providerOverridesWithScope.forEach(function (override, token) { |
| if (moduleSet_1.has(getInjectableDef(token).providedIn)) { |
| var provider = { |
| token: token, |
| flags: override.flags | (hasDeprecatedOverrides ? 4096 /* LazyProvider */ : 0 /* None */), |
| deps: splitDepsDsl(override.deps), |
| value: override.value, |
| index: def.providers.length, |
| }; |
| def.providers.push(provider); |
| def.providersByKey[tokenKey(token)] = provider; |
| } |
| }); |
| } |
| } |
| } |
| function prodCheckAndUpdateNode(view, checkIndex, argStyle, v0, v1, v2, v3, v4, v5, v6, v7, v8, v9) { |
| var nodeDef = view.def.nodes[checkIndex]; |
| checkAndUpdateNode(view, nodeDef, argStyle, v0, v1, v2, v3, v4, v5, v6, v7, v8, v9); |
| return (nodeDef.flags & 224 /* CatPureExpression */) ? |
| asPureExpressionData(view, checkIndex).value : |
| undefined; |
| } |
| function prodCheckNoChangesNode(view, checkIndex, argStyle, v0, v1, v2, v3, v4, v5, v6, v7, v8, v9) { |
| var nodeDef = view.def.nodes[checkIndex]; |
| checkNoChangesNode(view, nodeDef, argStyle, v0, v1, v2, v3, v4, v5, v6, v7, v8, v9); |
| return (nodeDef.flags & 224 /* CatPureExpression */) ? |
| asPureExpressionData(view, checkIndex).value : |
| undefined; |
| } |
| function debugCheckAndUpdateView(view) { |
| return callWithDebugContext(DebugAction.detectChanges, checkAndUpdateView, null, [view]); |
| } |
| function debugCheckNoChangesView(view) { |
| return callWithDebugContext(DebugAction.checkNoChanges, checkNoChangesView, null, [view]); |
| } |
| function debugDestroyView(view) { |
| return callWithDebugContext(DebugAction.destroy, destroyView, null, [view]); |
| } |
| var DebugAction; |
| (function (DebugAction) { |
| DebugAction[DebugAction["create"] = 0] = "create"; |
| DebugAction[DebugAction["detectChanges"] = 1] = "detectChanges"; |
| DebugAction[DebugAction["checkNoChanges"] = 2] = "checkNoChanges"; |
| DebugAction[DebugAction["destroy"] = 3] = "destroy"; |
| DebugAction[DebugAction["handleEvent"] = 4] = "handleEvent"; |
| })(DebugAction || (DebugAction = {})); |
| var _currentAction; |
| var _currentView; |
| var _currentNodeIndex; |
| function debugSetCurrentNode(view, nodeIndex) { |
| _currentView = view; |
| _currentNodeIndex = nodeIndex; |
| } |
| function debugHandleEvent(view, nodeIndex, eventName, event) { |
| debugSetCurrentNode(view, nodeIndex); |
| return callWithDebugContext(DebugAction.handleEvent, view.def.handleEvent, null, [view, nodeIndex, eventName, event]); |
| } |
| function debugUpdateDirectives(view, checkType) { |
| if (view.state & 128 /* Destroyed */) { |
| throw viewDestroyedError(DebugAction[_currentAction]); |
| } |
| debugSetCurrentNode(view, nextDirectiveWithBinding(view, 0)); |
| return view.def.updateDirectives(debugCheckDirectivesFn, view); |
| function debugCheckDirectivesFn(view, nodeIndex, argStyle) { |
| var values = []; |
| for (var _i = 3; _i < arguments.length; _i++) { |
| values[_i - 3] = arguments[_i]; |
| } |
| var nodeDef = view.def.nodes[nodeIndex]; |
| if (checkType === 0 /* CheckAndUpdate */) { |
| debugCheckAndUpdateNode(view, nodeDef, argStyle, values); |
| } |
| else { |
| debugCheckNoChangesNode(view, nodeDef, argStyle, values); |
| } |
| if (nodeDef.flags & 16384 /* TypeDirective */) { |
| debugSetCurrentNode(view, nextDirectiveWithBinding(view, nodeIndex)); |
| } |
| return (nodeDef.flags & 224 /* CatPureExpression */) ? |
| asPureExpressionData(view, nodeDef.nodeIndex).value : |
| undefined; |
| } |
| } |
| function debugUpdateRenderer(view, checkType) { |
| if (view.state & 128 /* Destroyed */) { |
| throw viewDestroyedError(DebugAction[_currentAction]); |
| } |
| debugSetCurrentNode(view, nextRenderNodeWithBinding(view, 0)); |
| return view.def.updateRenderer(debugCheckRenderNodeFn, view); |
| function debugCheckRenderNodeFn(view, nodeIndex, argStyle) { |
| var values = []; |
| for (var _i = 3; _i < arguments.length; _i++) { |
| values[_i - 3] = arguments[_i]; |
| } |
| var nodeDef = view.def.nodes[nodeIndex]; |
| if (checkType === 0 /* CheckAndUpdate */) { |
| debugCheckAndUpdateNode(view, nodeDef, argStyle, values); |
| } |
| else { |
| debugCheckNoChangesNode(view, nodeDef, argStyle, values); |
| } |
| if (nodeDef.flags & 3 /* CatRenderNode */) { |
| debugSetCurrentNode(view, nextRenderNodeWithBinding(view, nodeIndex)); |
| } |
| return (nodeDef.flags & 224 /* CatPureExpression */) ? |
| asPureExpressionData(view, nodeDef.nodeIndex).value : |
| undefined; |
| } |
| } |
| function debugCheckAndUpdateNode(view, nodeDef, argStyle, givenValues) { |
| var changed = checkAndUpdateNode.apply(void 0, __spread([view, nodeDef, argStyle], givenValues)); |
| if (changed) { |
| var values = argStyle === 1 /* Dynamic */ ? givenValues[0] : givenValues; |
| if (nodeDef.flags & 16384 /* TypeDirective */) { |
| var bindingValues = {}; |
| for (var i = 0; i < nodeDef.bindings.length; i++) { |
| var binding = nodeDef.bindings[i]; |
| var value = values[i]; |
| if (binding.flags & 8 /* TypeProperty */) { |
| bindingValues[normalizeDebugBindingName(binding.nonMinifiedName)] = |
| normalizeDebugBindingValue(value); |
| } |
| } |
| var elDef = nodeDef.parent; |
| var el = asElementData(view, elDef.nodeIndex).renderElement; |
| if (!elDef.element.name) { |
| // a comment. |
| view.renderer.setValue(el, "bindings=" + JSON.stringify(bindingValues, null, 2)); |
| } |
| else { |
| // a regular element. |
| for (var attr in bindingValues) { |
| var value = bindingValues[attr]; |
| if (value != null) { |
| view.renderer.setAttribute(el, attr, value); |
| } |
| else { |
| view.renderer.removeAttribute(el, attr); |
| } |
| } |
| } |
| } |
| } |
| } |
| function debugCheckNoChangesNode(view, nodeDef, argStyle, values) { |
| checkNoChangesNode.apply(void 0, __spread([view, nodeDef, argStyle], values)); |
| } |
| function nextDirectiveWithBinding(view, nodeIndex) { |
| for (var i = nodeIndex; i < view.def.nodes.length; i++) { |
| var nodeDef = view.def.nodes[i]; |
| if (nodeDef.flags & 16384 /* TypeDirective */ && nodeDef.bindings && nodeDef.bindings.length) { |
| return i; |
| } |
| } |
| return null; |
| } |
| function nextRenderNodeWithBinding(view, nodeIndex) { |
| for (var i = nodeIndex; i < view.def.nodes.length; i++) { |
| var nodeDef = view.def.nodes[i]; |
| if ((nodeDef.flags & 3 /* CatRenderNode */) && nodeDef.bindings && nodeDef.bindings.length) { |
| return i; |
| } |
| } |
| return null; |
| } |
| var DebugContext_ = /** @class */ (function () { |
| function DebugContext_(view, nodeIndex) { |
| this.view = view; |
| this.nodeIndex = nodeIndex; |
| if (nodeIndex == null) { |
| this.nodeIndex = nodeIndex = 0; |
| } |
| this.nodeDef = view.def.nodes[nodeIndex]; |
| var elDef = this.nodeDef; |
| var elView = view; |
| while (elDef && (elDef.flags & 1 /* TypeElement */) === 0) { |
| elDef = elDef.parent; |
| } |
| if (!elDef) { |
| while (!elDef && elView) { |
| elDef = viewParentEl(elView); |
| elView = elView.parent; |
| } |
| } |
| this.elDef = elDef; |
| this.elView = elView; |
| } |
| Object.defineProperty(DebugContext_.prototype, "elOrCompView", { |
| get: function () { |
| // Has to be done lazily as we use the DebugContext also during creation of elements... |
| return asElementData(this.elView, this.elDef.nodeIndex).componentView || this.view; |
| }, |
| enumerable: true, |
| configurable: true |
| }); |
| Object.defineProperty(DebugContext_.prototype, "injector", { |
| get: function () { return createInjector$1(this.elView, this.elDef); }, |
| enumerable: true, |
| configurable: true |
| }); |
| Object.defineProperty(DebugContext_.prototype, "component", { |
| get: function () { return this.elOrCompView.component; }, |
| enumerable: true, |
| configurable: true |
| }); |
| Object.defineProperty(DebugContext_.prototype, "context", { |
| get: function () { return this.elOrCompView.context; }, |
| enumerable: true, |
| configurable: true |
| }); |
| Object.defineProperty(DebugContext_.prototype, "providerTokens", { |
| get: function () { |
| var tokens = []; |
| if (this.elDef) { |
| for (var i = this.elDef.nodeIndex + 1; i <= this.elDef.nodeIndex + this.elDef.childCount; i++) { |
| var childDef = this.elView.def.nodes[i]; |
| if (childDef.flags & 20224 /* CatProvider */) { |
| tokens.push(childDef.provider.token); |
| } |
| i += childDef.childCount; |
| } |
| } |
| return tokens; |
| }, |
| enumerable: true, |
| configurable: true |
| }); |
| Object.defineProperty(DebugContext_.prototype, "references", { |
| get: function () { |
| var references = {}; |
| if (this.elDef) { |
| collectReferences(this.elView, this.elDef, references); |
| for (var i = this.elDef.nodeIndex + 1; i <= this.elDef.nodeIndex + this.elDef.childCount; i++) { |
| var childDef = this.elView.def.nodes[i]; |
| if (childDef.flags & 20224 /* CatProvider */) { |
| collectReferences(this.elView, childDef, references); |
| } |
| i += childDef.childCount; |
| } |
| } |
| return references; |
| }, |
| enumerable: true, |
| configurable: true |
| }); |
| Object.defineProperty(DebugContext_.prototype, "componentRenderElement", { |
| get: function () { |
| var elData = findHostElement(this.elOrCompView); |
| return elData ? elData.renderElement : undefined; |
| }, |
| enumerable: true, |
| configurable: true |
| }); |
| Object.defineProperty(DebugContext_.prototype, "renderNode", { |
| get: function () { |
| return this.nodeDef.flags & 2 /* TypeText */ ? renderNode(this.view, this.nodeDef) : |
| renderNode(this.elView, this.elDef); |
| }, |
| enumerable: true, |
| configurable: true |
| }); |
| DebugContext_.prototype.logError = function (console) { |
| var values = []; |
| for (var _i = 1; _i < arguments.length; _i++) { |
| values[_i - 1] = arguments[_i]; |
| } |
| var logViewDef; |
| var logNodeIndex; |
| if (this.nodeDef.flags & 2 /* TypeText */) { |
| logViewDef = this.view.def; |
| logNodeIndex = this.nodeDef.nodeIndex; |
| } |
| else { |
| logViewDef = this.elView.def; |
| logNodeIndex = this.elDef.nodeIndex; |
| } |
| // Note: we only generate a log function for text and element nodes |
| // to make the generated code as small as possible. |
| var renderNodeIndex = getRenderNodeIndex(logViewDef, logNodeIndex); |
| var currRenderNodeIndex = -1; |
| var nodeLogger = function () { |
| var _a; |
| currRenderNodeIndex++; |
| if (currRenderNodeIndex === renderNodeIndex) { |
| return (_a = console.error).bind.apply(_a, __spread([console], values)); |
| } |
| else { |
| return NOOP; |
| } |
| }; |
| logViewDef.factory(nodeLogger); |
| if (currRenderNodeIndex < renderNodeIndex) { |
| console.error('Illegal state: the ViewDefinitionFactory did not call the logger!'); |
| console.error.apply(console, __spread(values)); |
| } |
| }; |
| return DebugContext_; |
| }()); |
| function getRenderNodeIndex(viewDef, nodeIndex) { |
| var renderNodeIndex = -1; |
| for (var i = 0; i <= nodeIndex; i++) { |
| var nodeDef = viewDef.nodes[i]; |
| if (nodeDef.flags & 3 /* CatRenderNode */) { |
| renderNodeIndex++; |
| } |
| } |
| return renderNodeIndex; |
| } |
| function findHostElement(view) { |
| while (view && !isComponentView(view)) { |
| view = view.parent; |
| } |
| if (view.parent) { |
| return asElementData(view.parent, viewParentEl(view).nodeIndex); |
| } |
| return null; |
| } |
| function collectReferences(view, nodeDef, references) { |
| for (var refName in nodeDef.references) { |
| references[refName] = getQueryValue(view, nodeDef, nodeDef.references[refName]); |
| } |
| } |
| function callWithDebugContext(action, fn, self, args) { |
| var oldAction = _currentAction; |
| var oldView = _currentView; |
| var oldNodeIndex = _currentNodeIndex; |
| try { |
| _currentAction = action; |
| var result = fn.apply(self, args); |
| _currentView = oldView; |
| _currentNodeIndex = oldNodeIndex; |
| _currentAction = oldAction; |
| return result; |
| } |
| catch (e) { |
| if (isViewDebugError(e) || !_currentView) { |
| throw e; |
| } |
| throw viewWrappedDebugError(e, getCurrentDebugContext()); |
| } |
| } |
| function getCurrentDebugContext() { |
| return _currentView ? new DebugContext_(_currentView, _currentNodeIndex) : null; |
| } |
| var DebugRendererFactory2 = /** @class */ (function () { |
| function DebugRendererFactory2(delegate) { |
| this.delegate = delegate; |
| } |
| DebugRendererFactory2.prototype.createRenderer = function (element, renderData) { |
| return new DebugRenderer2(this.delegate.createRenderer(element, renderData)); |
| }; |
| DebugRendererFactory2.prototype.begin = function () { |
| if (this.delegate.begin) { |
| this.delegate.begin(); |
| } |
| }; |
| DebugRendererFactory2.prototype.end = function () { |
| if (this.delegate.end) { |
| this.delegate.end(); |
| } |
| }; |
| DebugRendererFactory2.prototype.whenRenderingDone = function () { |
| if (this.delegate.whenRenderingDone) { |
| return this.delegate.whenRenderingDone(); |
| } |
| return Promise.resolve(null); |
| }; |
| return DebugRendererFactory2; |
| }()); |
| var DebugRenderer2 = /** @class */ (function () { |
| function DebugRenderer2(delegate) { |
| this.delegate = delegate; |
| /** |
| * Factory function used to create a `DebugContext` when a node is created. |
| * |
| * The `DebugContext` allows to retrieve information about the nodes that are useful in tests. |
| * |
| * The factory is configurable so that the `DebugRenderer2` could instantiate either a View Engine |
| * or a Render context. |
| */ |
| this.debugContextFactory = getCurrentDebugContext; |
| this.data = this.delegate.data; |
| } |
| DebugRenderer2.prototype.createDebugContext = function (nativeElement) { return this.debugContextFactory(nativeElement); }; |
| DebugRenderer2.prototype.destroyNode = function (node) { |
| removeDebugNodeFromIndex(getDebugNode(node)); |
| if (this.delegate.destroyNode) { |
| this.delegate.destroyNode(node); |
| } |
| }; |
| DebugRenderer2.prototype.destroy = function () { this.delegate.destroy(); }; |
| DebugRenderer2.prototype.createElement = function (name, namespace) { |
| var el = this.delegate.createElement(name, namespace); |
| var debugCtx = this.createDebugContext(el); |
| if (debugCtx) { |
| var debugEl = new DebugElement__PRE_R3__(el, null, debugCtx); |
| debugEl.name = name; |
| indexDebugNode(debugEl); |
| } |
| return el; |
| }; |
| DebugRenderer2.prototype.createComment = function (value) { |
| var comment = this.delegate.createComment(value); |
| var debugCtx = this.createDebugContext(comment); |
| if (debugCtx) { |
| indexDebugNode(new DebugNode__PRE_R3__(comment, null, debugCtx)); |
| } |
| return comment; |
| }; |
| DebugRenderer2.prototype.createText = function (value) { |
| var text = this.delegate.createText(value); |
| var debugCtx = this.createDebugContext(text); |
| if (debugCtx) { |
| indexDebugNode(new DebugNode__PRE_R3__(text, null, debugCtx)); |
| } |
| return text; |
| }; |
| DebugRenderer2.prototype.appendChild = function (parent, newChild) { |
| var debugEl = getDebugNode(parent); |
| var debugChildEl = getDebugNode(newChild); |
| if (debugEl && debugChildEl && debugEl instanceof DebugElement__PRE_R3__) { |
| debugEl.addChild(debugChildEl); |
| } |
| this.delegate.appendChild(parent, newChild); |
| }; |
| DebugRenderer2.prototype.insertBefore = function (parent, newChild, refChild) { |
| var debugEl = getDebugNode(parent); |
| var debugChildEl = getDebugNode(newChild); |
| var debugRefEl = getDebugNode(refChild); |
| if (debugEl && debugChildEl && debugEl instanceof DebugElement__PRE_R3__) { |
| debugEl.insertBefore(debugRefEl, debugChildEl); |
| } |
| this.delegate.insertBefore(parent, newChild, refChild); |
| }; |
| DebugRenderer2.prototype.removeChild = function (parent, oldChild) { |
| var debugEl = getDebugNode(parent); |
| var debugChildEl = getDebugNode(oldChild); |
| if (debugEl && debugChildEl && debugEl instanceof DebugElement__PRE_R3__) { |
| debugEl.removeChild(debugChildEl); |
| } |
| this.delegate.removeChild(parent, oldChild); |
| }; |
| DebugRenderer2.prototype.selectRootElement = function (selectorOrNode, preserveContent) { |
| var el = this.delegate.selectRootElement(selectorOrNode, preserveContent); |
| var debugCtx = getCurrentDebugContext(); |
| if (debugCtx) { |
| indexDebugNode(new DebugElement__PRE_R3__(el, null, debugCtx)); |
| } |
| return el; |
| }; |
| DebugRenderer2.prototype.setAttribute = function (el, name, value, namespace) { |
| var debugEl = getDebugNode(el); |
| if (debugEl && debugEl instanceof DebugElement__PRE_R3__) { |
| var fullName = namespace ? namespace + ':' + name : name; |
| debugEl.attributes[fullName] = value; |
| } |
| this.delegate.setAttribute(el, name, value, namespace); |
| }; |
| DebugRenderer2.prototype.removeAttribute = function (el, name, namespace) { |
| var debugEl = getDebugNode(el); |
| if (debugEl && debugEl instanceof DebugElement__PRE_R3__) { |
| var fullName = namespace ? namespace + ':' + name : name; |
| debugEl.attributes[fullName] = null; |
| } |
| this.delegate.removeAttribute(el, name, namespace); |
| }; |
| DebugRenderer2.prototype.addClass = function (el, name) { |
| var debugEl = getDebugNode(el); |
| if (debugEl && debugEl instanceof DebugElement__PRE_R3__) { |
| debugEl.classes[name] = true; |
| } |
| this.delegate.addClass(el, name); |
| }; |
| DebugRenderer2.prototype.removeClass = function (el, name) { |
| var debugEl = getDebugNode(el); |
| if (debugEl && debugEl instanceof DebugElement__PRE_R3__) { |
| debugEl.classes[name] = false; |
| } |
| this.delegate.removeClass(el, name); |
| }; |
| DebugRenderer2.prototype.setStyle = function (el, style, value, flags) { |
| var debugEl = getDebugNode(el); |
| if (debugEl && debugEl instanceof DebugElement__PRE_R3__) { |
| debugEl.styles[style] = value; |
| } |
| this.delegate.setStyle(el, style, value, flags); |
| }; |
| DebugRenderer2.prototype.removeStyle = function (el, style, flags) { |
| var debugEl = getDebugNode(el); |
| if (debugEl && debugEl instanceof DebugElement__PRE_R3__) { |
| debugEl.styles[style] = null; |
| } |
| this.delegate.removeStyle(el, style, flags); |
| }; |
| DebugRenderer2.prototype.setProperty = function (el, name, value) { |
| var debugEl = getDebugNode(el); |
| if (debugEl && debugEl instanceof DebugElement__PRE_R3__) { |
| debugEl.properties[name] = value; |
| } |
| this.delegate.setProperty(el, name, value); |
| }; |
| DebugRenderer2.prototype.listen = function (target, eventName, callback) { |
| if (typeof target !== 'string') { |
| var debugEl = getDebugNode(target); |
| if (debugEl) { |
| debugEl.listeners.push(new DebugEventListener(eventName, callback)); |
| } |
| } |
| return this.delegate.listen(target, eventName, callback); |
| }; |
| DebugRenderer2.prototype.parentNode = function (node) { return this.delegate.parentNode(node); }; |
| DebugRenderer2.prototype.nextSibling = function (node) { return this.delegate.nextSibling(node); }; |
| DebugRenderer2.prototype.setValue = function (node, value) { return this.delegate.setValue(node, value); }; |
| return DebugRenderer2; |
| }()); |
| |
| /** |
| * @license |
| * Copyright Google Inc. All Rights Reserved. |
| * |
| * Use of this source code is governed by an MIT-style license that can be |
| * found in the LICENSE file at https://angular.io/license |
| */ |
| function overrideProvider(override) { |
| initServicesIfNeeded(); |
| return Services.overrideProvider(override); |
| } |
| function overrideComponentView(comp, componentFactory) { |
| initServicesIfNeeded(); |
| return Services.overrideComponentView(comp, componentFactory); |
| } |
| function clearOverrides() { |
| initServicesIfNeeded(); |
| return Services.clearOverrides(); |
| } |
| // Attention: this function is called as top level function. |
| // Putting any logic in here will destroy closure tree shaking! |
| function createNgModuleFactory(ngModuleType, bootstrapComponents, defFactory) { |
| return new NgModuleFactory_(ngModuleType, bootstrapComponents, defFactory); |
| } |
| function cloneNgModuleDefinition(def) { |
| var providers = Array.from(def.providers); |
| var modules = Array.from(def.modules); |
| var providersByKey = {}; |
| for (var key in def.providersByKey) { |
| providersByKey[key] = def.providersByKey[key]; |
| } |
| return { |
| factory: def.factory, |
| isRoot: def.isRoot, providers: providers, modules: modules, providersByKey: providersByKey, |
| }; |
| } |
| var NgModuleFactory_ = /** @class */ (function (_super) { |
| __extends(NgModuleFactory_, _super); |
| function NgModuleFactory_(moduleType, _bootstrapComponents, _ngModuleDefFactory) { |
| var _this = |
| // Attention: this ctor is called as top level function. |
| // Putting any logic in here will destroy closure tree shaking! |
| _super.call(this) || this; |
| _this.moduleType = moduleType; |
| _this._bootstrapComponents = _bootstrapComponents; |
| _this._ngModuleDefFactory = _ngModuleDefFactory; |
| return _this; |
| } |
| NgModuleFactory_.prototype.create = function (parentInjector) { |
| initServicesIfNeeded(); |
| // Clone the NgModuleDefinition so that any tree shakeable provider definition |
| // added to this instance of the NgModuleRef doesn't affect the cached copy. |
| // See https://github.com/angular/angular/issues/25018. |
| var def = cloneNgModuleDefinition(resolveDefinition(this._ngModuleDefFactory)); |
| return Services.createNgModuleRef(this.moduleType, parentInjector || Injector.NULL, this._bootstrapComponents, def); |
| }; |
| return NgModuleFactory_; |
| }(NgModuleFactory)); |
| |
| /** |
| * @license |
| * Copyright Google Inc. All Rights Reserved. |
| * |
| * Use of this source code is governed by an MIT-style license that can be |
| * found in the LICENSE file at https://angular.io/license |
| */ |
| |
| /** |
| * @license |
| * Copyright Google Inc. All Rights Reserved. |
| * |
| * Use of this source code is governed by an MIT-style license that can be |
| * found in the LICENSE file at https://angular.io/license |
| */ |
| |
| /** |
| * @license |
| * Copyright Google Inc. All Rights Reserved. |
| * |
| * Use of this source code is governed by an MIT-style license that can be |
| * found in the LICENSE file at https://angular.io/license |
| */ |
| // clang-format on |
| |
| /** |
| * @license |
| * Copyright Google Inc. All Rights Reserved. |
| * |
| * Use of this source code is governed by an MIT-style license that can be |
| * found in the LICENSE file at https://angular.io/license |
| */ |
| |
| /** |
| * @license |
| * Copyright Google Inc. All Rights Reserved. |
| * |
| * Use of this source code is governed by an MIT-style license that can be |
| * found in the LICENSE file at https://angular.io/license |
| */ |
| |
| /** |
| * @license |
| * Copyright Google Inc. All Rights Reserved. |
| * |
| * Use of this source code is governed by an MIT-style license that can be |
| * found in the LICENSE file at https://angular.io/license |
| */ |
| // This file only reexports content of the `src` folder. Keep it that way. |
| |
| /** |
| * @license |
| * Copyright Google Inc. All Rights Reserved. |
| * |
| * Use of this source code is governed by an MIT-style license that can be |
| * found in the LICENSE file at https://angular.io/license |
| */ |
| |
| /** |
| * Generated bundle index. Do not edit. |
| */ |
| |
| exports.ɵangular_packages_core_core_r = APPLICATION_MODULE_PROVIDERS; |
| exports.ɵangular_packages_core_core_o = _iterableDiffersFactory; |
| exports.ɵangular_packages_core_core_p = _keyValueDiffersFactory; |
| exports.ɵangular_packages_core_core_q = _localeFactory; |
| exports.ɵangular_packages_core_core_s = zoneSchedulerFactory; |
| exports.ɵangular_packages_core_core_f = _appIdRandomProviderFactory; |
| exports.ɵangular_packages_core_core_m = DefaultIterableDifferFactory; |
| exports.ɵangular_packages_core_core_n = DefaultKeyValueDifferFactory; |
| exports.ɵangular_packages_core_core_l = DebugElement__PRE_R3__; |
| exports.ɵangular_packages_core_core_k = DebugNode__PRE_R3__; |
| exports.ɵangular_packages_core_core_b = NullInjector; |
| exports.ɵangular_packages_core_core_a = injectInjectorOnly; |
| exports.ɵangular_packages_core_core_c = ReflectiveInjector_; |
| exports.ɵangular_packages_core_core_d = ReflectiveDependency; |
| exports.ɵangular_packages_core_core_e = resolveReflectiveProviders; |
| exports.ɵangular_packages_core_core_j = getModuleFactory__PRE_R3__; |
| exports.ɵangular_packages_core_core_t = wtfEnabled; |
| exports.ɵangular_packages_core_core_v = createScope; |
| exports.ɵangular_packages_core_core_u = detectWTF; |
| exports.ɵangular_packages_core_core_y = endTimeRange; |
| exports.ɵangular_packages_core_core_w = leave; |
| exports.ɵangular_packages_core_core_x = startTimeRange; |
| exports.ɵangular_packages_core_core_bb = SCHEDULER; |
| exports.ɵangular_packages_core_core_bc = injectAttributeImpl; |
| exports.ɵangular_packages_core_core_bd = getLView; |
| exports.ɵangular_packages_core_core_be = getPreviousOrParentTNode; |
| exports.ɵangular_packages_core_core_bf = nextContextImpl; |
| exports.ɵangular_packages_core_core_bj = BoundPlayerFactory; |
| exports.ɵangular_packages_core_core_bp = getRootContext; |
| exports.ɵangular_packages_core_core_bo = loadInternal; |
| exports.ɵangular_packages_core_core_g = createElementRef; |
| exports.ɵangular_packages_core_core_h = createTemplateRef; |
| exports.ɵangular_packages_core_core_i = createViewRef; |
| exports.ɵangular_packages_core_core_bh = getUrlSanitizer; |
| exports.ɵangular_packages_core_core_bn = noSideEffects; |
| exports.ɵangular_packages_core_core_bk = makeParamDecorator; |
| exports.ɵangular_packages_core_core_bl = makePropDecorator; |
| exports.ɵangular_packages_core_core_bq = getClosureSafeProperty; |
| exports.ɵangular_packages_core_core_z = _def; |
| exports.ɵangular_packages_core_core_ba = DebugContext; |
| exports.createPlatform = createPlatform; |
| exports.assertPlatform = assertPlatform; |
| exports.destroyPlatform = destroyPlatform; |
| exports.getPlatform = getPlatform; |
| exports.PlatformRef = PlatformRef; |
| exports.ApplicationRef = ApplicationRef; |
| exports.createPlatformFactory = createPlatformFactory; |
| exports.NgProbeToken = NgProbeToken; |
| exports.enableProdMode = enableProdMode; |
| exports.isDevMode = isDevMode; |
| exports.APP_ID = APP_ID; |
| exports.PACKAGE_ROOT_URL = PACKAGE_ROOT_URL; |
| exports.PLATFORM_INITIALIZER = PLATFORM_INITIALIZER; |
| exports.PLATFORM_ID = PLATFORM_ID; |
| exports.APP_BOOTSTRAP_LISTENER = APP_BOOTSTRAP_LISTENER; |
| exports.APP_INITIALIZER = APP_INITIALIZER; |
| exports.ApplicationInitStatus = ApplicationInitStatus; |
| exports.DebugElement = DebugElement; |
| exports.DebugEventListener = DebugEventListener; |
| exports.DebugNode = DebugNode; |
| exports.asNativeElements = asNativeElements; |
| exports.getDebugNode = getDebugNode; |
| exports.Testability = Testability; |
| exports.TestabilityRegistry = TestabilityRegistry; |
| exports.setTestabilityGetter = setTestabilityGetter; |
| exports.TRANSLATIONS = TRANSLATIONS$1; |
| exports.TRANSLATIONS_FORMAT = TRANSLATIONS_FORMAT; |
| exports.LOCALE_ID = LOCALE_ID$1; |
| exports.ApplicationModule = ApplicationModule; |
| exports.wtfCreateScope = wtfCreateScope; |
| exports.wtfLeave = wtfLeave; |
| exports.wtfStartTimeRange = wtfStartTimeRange; |
| exports.wtfEndTimeRange = wtfEndTimeRange; |
| exports.Type = Type; |
| exports.EventEmitter = EventEmitter; |
| exports.ErrorHandler = ErrorHandler; |
| exports.Sanitizer = Sanitizer; |
| exports.Attribute = Attribute; |
| exports.ANALYZE_FOR_ENTRY_COMPONENTS = ANALYZE_FOR_ENTRY_COMPONENTS; |
| exports.ContentChild = ContentChild; |
| exports.ContentChildren = ContentChildren; |
| exports.Query = Query; |
| exports.ViewChild = ViewChild; |
| exports.ViewChildren = ViewChildren; |
| exports.Component = Component; |
| exports.Directive = Directive; |
| exports.HostBinding = HostBinding; |
| exports.HostListener = HostListener; |
| exports.Input = Input; |
| exports.Output = Output; |
| exports.Pipe = Pipe; |
| exports.NgModule = NgModule; |
| exports.CUSTOM_ELEMENTS_SCHEMA = CUSTOM_ELEMENTS_SCHEMA; |
| exports.NO_ERRORS_SCHEMA = NO_ERRORS_SCHEMA; |
| exports.Version = Version; |
| exports.VERSION = VERSION; |
| exports.ɵɵdefineInjectable = ɵɵdefineInjectable; |
| exports.defineInjectable = defineInjectable; |
| exports.ɵɵdefineInjector = ɵɵdefineInjector; |
| exports.forwardRef = forwardRef; |
| exports.resolveForwardRef = resolveForwardRef; |
| exports.Injectable = Injectable; |
| exports.Injector = Injector; |
| exports.ɵɵinject = ɵɵinject; |
| exports.inject = inject; |
| exports.INJECTOR = INJECTOR; |
| exports.ReflectiveInjector = ReflectiveInjector; |
| exports.ResolvedReflectiveFactory = ResolvedReflectiveFactory; |
| exports.ReflectiveKey = ReflectiveKey; |
| exports.InjectionToken = InjectionToken; |
| exports.Inject = Inject; |
| exports.Optional = Optional; |
| exports.Self = Self; |
| exports.SkipSelf = SkipSelf; |
| exports.Host = Host; |
| exports.ɵ0 = ɵ0; |
| exports.ɵ1 = ɵ1; |
| exports.NgZone = NgZone; |
| exports.ɵNoopNgZone = NoopNgZone; |
| exports.RenderComponentType = RenderComponentType; |
| exports.Renderer = Renderer; |
| exports.Renderer2 = Renderer2; |
| exports.RendererFactory2 = RendererFactory2; |
| exports.RootRenderer = RootRenderer; |
| exports.COMPILER_OPTIONS = COMPILER_OPTIONS; |
| exports.Compiler = Compiler; |
| exports.CompilerFactory = CompilerFactory; |
| exports.ModuleWithComponentFactories = ModuleWithComponentFactories; |
| exports.ComponentFactory = ComponentFactory; |
| exports.ɵComponentFactory = ComponentFactory; |
| exports.ComponentRef = ComponentRef; |
| exports.ComponentFactoryResolver = ComponentFactoryResolver; |
| exports.ElementRef = ElementRef; |
| exports.NgModuleFactory = NgModuleFactory; |
| exports.NgModuleRef = NgModuleRef; |
| exports.NgModuleFactoryLoader = NgModuleFactoryLoader; |
| exports.getModuleFactory = getModuleFactory; |
| exports.QueryList = QueryList; |
| exports.SystemJsNgModuleLoader = SystemJsNgModuleLoader; |
| exports.SystemJsNgModuleLoaderConfig = SystemJsNgModuleLoaderConfig; |
| exports.TemplateRef = TemplateRef; |
| exports.ViewContainerRef = ViewContainerRef; |
| exports.EmbeddedViewRef = EmbeddedViewRef; |
| exports.ViewRef = ViewRef$1; |
| exports.ChangeDetectorRef = ChangeDetectorRef; |
| exports.DefaultIterableDiffer = DefaultIterableDiffer; |
| exports.IterableDiffers = IterableDiffers; |
| exports.KeyValueDiffers = KeyValueDiffers; |
| exports.SimpleChange = SimpleChange; |
| exports.WrappedValue = WrappedValue; |
| exports.platformCore = platformCore; |
| exports.ɵALLOW_MULTIPLE_PLATFORMS = ALLOW_MULTIPLE_PLATFORMS; |
| exports.ɵAPP_ID_RANDOM_PROVIDER = APP_ID_RANDOM_PROVIDER; |
| exports.ɵdefaultIterableDiffers = defaultIterableDiffers; |
| exports.ɵdefaultKeyValueDiffers = defaultKeyValueDiffers; |
| exports.ɵdevModeEqual = devModeEqual; |
| exports.ɵisListLikeIterable = isListLikeIterable; |
| exports.ɵisDefaultChangeDetectionStrategy = isDefaultChangeDetectionStrategy; |
| exports.ɵConsole = Console; |
| exports.ɵsetCurrentInjector = setCurrentInjector; |
| exports.ɵgetInjectableDef = getInjectableDef; |
| exports.ɵAPP_ROOT = APP_ROOT; |
| exports.ɵivyEnabled = ivyEnabled; |
| exports.ɵCodegenComponentFactoryResolver = CodegenComponentFactoryResolver; |
| exports.ɵclearResolutionOfComponentResourcesQueue = clearResolutionOfComponentResourcesQueue; |
| exports.ɵresolveComponentResources = resolveComponentResources; |
| exports.ɵReflectionCapabilities = ReflectionCapabilities; |
| exports.ɵRenderDebugInfo = RenderDebugInfo; |
| exports.ɵ_sanitizeHtml = _sanitizeHtml; |
| exports.ɵ_sanitizeStyle = _sanitizeStyle; |
| exports.ɵ_sanitizeUrl = _sanitizeUrl; |
| exports.ɵglobal = _global; |
| exports.ɵlooseIdentical = looseIdentical; |
| exports.ɵstringify = stringify; |
| exports.ɵmakeDecorator = makeDecorator; |
| exports.ɵisObservable = isObservable; |
| exports.ɵisPromise = isPromise; |
| exports.ɵclearOverrides = clearOverrides; |
| exports.ɵinitServicesIfNeeded = initServicesIfNeeded; |
| exports.ɵoverrideComponentView = overrideComponentView; |
| exports.ɵoverrideProvider = overrideProvider; |
| exports.ɵNOT_FOUND_CHECK_ONLY_ELEMENT_INJECTOR = NOT_FOUND_CHECK_ONLY_ELEMENT_INJECTOR; |
| exports.ɵgetLocalePluralCase = getLocalePluralCase; |
| exports.ɵfindLocaleData = findLocaleData; |
| exports.ɵLOCALE_DATA = LOCALE_DATA; |
| exports.ɵɵattribute = ɵɵattribute; |
| exports.ɵɵattributeInterpolate1 = ɵɵattributeInterpolate1; |
| exports.ɵɵattributeInterpolate2 = ɵɵattributeInterpolate2; |
| exports.ɵɵattributeInterpolate3 = ɵɵattributeInterpolate3; |
| exports.ɵɵattributeInterpolate4 = ɵɵattributeInterpolate4; |
| exports.ɵɵattributeInterpolate5 = ɵɵattributeInterpolate5; |
| exports.ɵɵattributeInterpolate6 = ɵɵattributeInterpolate6; |
| exports.ɵɵattributeInterpolate7 = ɵɵattributeInterpolate7; |
| exports.ɵɵattributeInterpolate8 = ɵɵattributeInterpolate8; |
| exports.ɵɵattributeInterpolateV = ɵɵattributeInterpolateV; |
| exports.ɵɵdefineBase = ɵɵdefineBase; |
| exports.ɵɵdefineComponent = ɵɵdefineComponent; |
| exports.ɵɵdefineDirective = ɵɵdefineDirective; |
| exports.ɵɵdefinePipe = ɵɵdefinePipe; |
| exports.ɵɵdefineNgModule = ɵɵdefineNgModule; |
| exports.ɵdetectChanges = detectChanges; |
| exports.ɵrenderComponent = renderComponent; |
| exports.ɵRender3ComponentFactory = ComponentFactory$1; |
| exports.ɵRender3ComponentRef = ComponentRef$1; |
| exports.ɵɵdirectiveInject = ɵɵdirectiveInject; |
| exports.ɵɵinjectAttribute = ɵɵinjectAttribute; |
| exports.ɵɵgetFactoryOf = ɵɵgetFactoryOf; |
| exports.ɵɵgetInheritedFactory = ɵɵgetInheritedFactory; |
| exports.ɵɵsetComponentScope = ɵɵsetComponentScope; |
| exports.ɵɵsetNgModuleScope = ɵɵsetNgModuleScope; |
| exports.ɵɵtemplateRefExtractor = ɵɵtemplateRefExtractor; |
| exports.ɵɵProvidersFeature = ɵɵProvidersFeature; |
| exports.ɵɵInheritDefinitionFeature = ɵɵInheritDefinitionFeature; |
| exports.ɵɵNgOnChangesFeature = ɵɵNgOnChangesFeature; |
| exports.ɵLifecycleHooksFeature = LifecycleHooksFeature; |
| exports.ɵRender3NgModuleRef = NgModuleRef$1; |
| exports.ɵmarkDirty = markDirty; |
| exports.ɵNgModuleFactory = NgModuleFactory$1; |
| exports.ɵNO_CHANGE = NO_CHANGE; |
| exports.ɵɵcontainer = ɵɵcontainer; |
| exports.ɵɵnextContext = ɵɵnextContext; |
| exports.ɵɵelementStart = ɵɵelementStart; |
| exports.ɵɵnamespaceHTML = ɵɵnamespaceHTML; |
| exports.ɵɵnamespaceMathML = ɵɵnamespaceMathML; |
| exports.ɵɵnamespaceSVG = ɵɵnamespaceSVG; |
| exports.ɵɵelement = ɵɵelement; |
| exports.ɵɵlistener = ɵɵlistener; |
| exports.ɵɵtext = ɵɵtext; |
| exports.ɵɵtextInterpolate = ɵɵtextInterpolate; |
| exports.ɵɵtextInterpolate1 = ɵɵtextInterpolate1; |
| exports.ɵɵtextInterpolate2 = ɵɵtextInterpolate2; |
| exports.ɵɵtextInterpolate3 = ɵɵtextInterpolate3; |
| exports.ɵɵtextInterpolate4 = ɵɵtextInterpolate4; |
| exports.ɵɵtextInterpolate5 = ɵɵtextInterpolate5; |
| exports.ɵɵtextInterpolate6 = ɵɵtextInterpolate6; |
| exports.ɵɵtextInterpolate7 = ɵɵtextInterpolate7; |
| exports.ɵɵtextInterpolate8 = ɵɵtextInterpolate8; |
| exports.ɵɵtextInterpolateV = ɵɵtextInterpolateV; |
| exports.ɵɵembeddedViewStart = ɵɵembeddedViewStart; |
| exports.ɵɵprojection = ɵɵprojection; |
| exports.ɵɵinterpolation1 = ɵɵinterpolation1; |
| exports.ɵɵinterpolation2 = ɵɵinterpolation2; |
| exports.ɵɵinterpolation3 = ɵɵinterpolation3; |
| exports.ɵɵinterpolation4 = ɵɵinterpolation4; |
| exports.ɵɵinterpolation5 = ɵɵinterpolation5; |
| exports.ɵɵinterpolation6 = ɵɵinterpolation6; |
| exports.ɵɵinterpolation7 = ɵɵinterpolation7; |
| exports.ɵɵinterpolation8 = ɵɵinterpolation8; |
| exports.ɵɵinterpolationV = ɵɵinterpolationV; |
| exports.ɵɵpipeBind1 = ɵɵpipeBind1; |
| exports.ɵɵpipeBind2 = ɵɵpipeBind2; |
| exports.ɵɵpipeBind3 = ɵɵpipeBind3; |
| exports.ɵɵpipeBind4 = ɵɵpipeBind4; |
| exports.ɵɵpipeBindV = ɵɵpipeBindV; |
| exports.ɵɵpureFunction0 = ɵɵpureFunction0; |
| exports.ɵɵpureFunction1 = ɵɵpureFunction1; |
| exports.ɵɵpureFunction2 = ɵɵpureFunction2; |
| exports.ɵɵpureFunction3 = ɵɵpureFunction3; |
| exports.ɵɵpureFunction4 = ɵɵpureFunction4; |
| exports.ɵɵpureFunction5 = ɵɵpureFunction5; |
| exports.ɵɵpureFunction6 = ɵɵpureFunction6; |
| exports.ɵɵpureFunction7 = ɵɵpureFunction7; |
| exports.ɵɵpureFunction8 = ɵɵpureFunction8; |
| exports.ɵɵpureFunctionV = ɵɵpureFunctionV; |
| exports.ɵɵgetCurrentView = ɵɵgetCurrentView; |
| exports.ɵgetDirectives = getDirectives; |
| exports.ɵgetHostElement = getHostElement; |
| exports.ɵɵrestoreView = ɵɵrestoreView; |
| exports.ɵɵcontainerRefreshStart = ɵɵcontainerRefreshStart; |
| exports.ɵɵcontainerRefreshEnd = ɵɵcontainerRefreshEnd; |
| exports.ɵɵqueryRefresh = ɵɵqueryRefresh; |
| exports.ɵɵviewQuery = ɵɵviewQuery; |
| exports.ɵɵstaticViewQuery = ɵɵstaticViewQuery; |
| exports.ɵɵstaticContentQuery = ɵɵstaticContentQuery; |
| exports.ɵɵloadViewQuery = ɵɵloadViewQuery; |
| exports.ɵɵcontentQuery = ɵɵcontentQuery; |
| exports.ɵɵloadContentQuery = ɵɵloadContentQuery; |
| exports.ɵɵelementEnd = ɵɵelementEnd; |
| exports.ɵɵproperty = ɵɵproperty; |
| exports.ɵɵpropertyInterpolate = ɵɵpropertyInterpolate; |
| exports.ɵɵpropertyInterpolate1 = ɵɵpropertyInterpolate1; |
| exports.ɵɵpropertyInterpolate2 = ɵɵpropertyInterpolate2; |
| exports.ɵɵpropertyInterpolate3 = ɵɵpropertyInterpolate3; |
| exports.ɵɵpropertyInterpolate4 = ɵɵpropertyInterpolate4; |
| exports.ɵɵpropertyInterpolate5 = ɵɵpropertyInterpolate5; |
| exports.ɵɵpropertyInterpolate6 = ɵɵpropertyInterpolate6; |
| exports.ɵɵpropertyInterpolate7 = ɵɵpropertyInterpolate7; |
| exports.ɵɵpropertyInterpolate8 = ɵɵpropertyInterpolate8; |
| exports.ɵɵpropertyInterpolateV = ɵɵpropertyInterpolateV; |
| exports.ɵɵupdateSyntheticHostBinding = ɵɵupdateSyntheticHostBinding; |
| exports.ɵɵcomponentHostSyntheticListener = ɵɵcomponentHostSyntheticListener; |
| exports.ɵɵprojectionDef = ɵɵprojectionDef; |
| exports.ɵɵreference = ɵɵreference; |
| exports.ɵɵenableBindings = ɵɵenableBindings; |
| exports.ɵɵdisableBindings = ɵɵdisableBindings; |
| exports.ɵɵallocHostVars = ɵɵallocHostVars; |
| exports.ɵɵelementContainerStart = ɵɵelementContainerStart; |
| exports.ɵɵelementContainerEnd = ɵɵelementContainerEnd; |
| exports.ɵɵstyling = ɵɵstyling; |
| exports.ɵɵstyleMap = ɵɵstyleMap; |
| exports.ɵɵclassMap = ɵɵclassMap; |
| exports.ɵɵstyleProp = ɵɵstyleProp; |
| exports.ɵɵstylingApply = ɵɵstylingApply; |
| exports.ɵɵclassProp = ɵɵclassProp; |
| exports.ɵɵelementHostAttrs = ɵɵelementHostAttrs; |
| exports.ɵɵselect = ɵɵselect; |
| exports.ɵɵtextBinding = ɵɵtextBinding; |
| exports.ɵɵtemplate = ɵɵtemplate; |
| exports.ɵɵembeddedViewEnd = ɵɵembeddedViewEnd; |
| exports.ɵstore = store; |
| exports.ɵɵload = ɵɵload; |
| exports.ɵɵpipe = ɵɵpipe; |
| exports.ɵwhenRendered = whenRendered; |
| exports.ɵɵi18n = ɵɵi18n; |
| exports.ɵɵi18nAttributes = ɵɵi18nAttributes; |
| exports.ɵɵi18nExp = ɵɵi18nExp; |
| exports.ɵɵi18nStart = ɵɵi18nStart; |
| exports.ɵɵi18nEnd = ɵɵi18nEnd; |
| exports.ɵɵi18nApply = ɵɵi18nApply; |
| exports.ɵɵi18nPostprocess = ɵɵi18nPostprocess; |
| exports.ɵi18nConfigureLocalize = i18nConfigureLocalize; |
| exports.ɵɵi18nLocalize = ɵɵi18nLocalize; |
| exports.ɵsetLocaleId = setLocaleId; |
| exports.ɵDEFAULT_LOCALE_ID = DEFAULT_LOCALE_ID; |
| exports.ɵsetClassMetadata = setClassMetadata; |
| exports.ɵɵresolveWindow = ɵɵresolveWindow; |
| exports.ɵɵresolveDocument = ɵɵresolveDocument; |
| exports.ɵɵresolveBody = ɵɵresolveBody; |
| exports.ɵcompileComponent = compileComponent; |
| exports.ɵcompileDirective = compileDirective; |
| exports.ɵcompileNgModule = compileNgModule; |
| exports.ɵcompileNgModuleDefs = compileNgModuleDefs; |
| exports.ɵpatchComponentDefWithScope = patchComponentDefWithScope; |
| exports.ɵresetCompiledComponents = resetCompiledComponents; |
| exports.ɵflushModuleScopingQueueAsMuchAsPossible = flushModuleScopingQueueAsMuchAsPossible; |
| exports.ɵtransitiveScopesFor = transitiveScopesFor; |
| exports.ɵcompilePipe = compilePipe; |
| exports.ɵɵsanitizeHtml = ɵɵsanitizeHtml; |
| exports.ɵɵsanitizeStyle = ɵɵsanitizeStyle; |
| exports.ɵɵdefaultStyleSanitizer = ɵɵdefaultStyleSanitizer; |
| exports.ɵɵsanitizeScript = ɵɵsanitizeScript; |
| exports.ɵɵsanitizeUrl = ɵɵsanitizeUrl; |
| exports.ɵɵsanitizeResourceUrl = ɵɵsanitizeResourceUrl; |
| exports.ɵɵsanitizeUrlOrResourceUrl = ɵɵsanitizeUrlOrResourceUrl; |
| exports.ɵbypassSanitizationTrustHtml = bypassSanitizationTrustHtml; |
| exports.ɵbypassSanitizationTrustStyle = bypassSanitizationTrustStyle; |
| exports.ɵbypassSanitizationTrustScript = bypassSanitizationTrustScript; |
| exports.ɵbypassSanitizationTrustUrl = bypassSanitizationTrustUrl; |
| exports.ɵbypassSanitizationTrustResourceUrl = bypassSanitizationTrustResourceUrl; |
| exports.ɵgetLContext = getLContext; |
| exports.ɵNG_ELEMENT_ID = NG_ELEMENT_ID; |
| exports.ɵNG_COMPONENT_DEF = NG_COMPONENT_DEF; |
| exports.ɵNG_DIRECTIVE_DEF = NG_DIRECTIVE_DEF; |
| exports.ɵNG_PIPE_DEF = NG_PIPE_DEF; |
| exports.ɵNG_MODULE_DEF = NG_MODULE_DEF; |
| exports.ɵNG_BASE_DEF = NG_BASE_DEF; |
| exports.ɵNG_INJECTABLE_DEF = NG_INJECTABLE_DEF; |
| exports.ɵNG_INJECTOR_DEF = NG_INJECTOR_DEF; |
| exports.ɵbindPlayerFactory = bindPlayerFactory; |
| exports.ɵaddPlayer = addPlayer; |
| exports.ɵgetPlayers = getPlayers; |
| exports.ɵcompileNgModuleFactory__POST_R3__ = compileNgModuleFactory__POST_R3__; |
| exports.ɵisBoundToModule__POST_R3__ = isBoundToModule__POST_R3__; |
| exports.ɵSWITCH_COMPILE_COMPONENT__POST_R3__ = SWITCH_COMPILE_COMPONENT__POST_R3__; |
| exports.ɵSWITCH_COMPILE_DIRECTIVE__POST_R3__ = SWITCH_COMPILE_DIRECTIVE__POST_R3__; |
| exports.ɵSWITCH_COMPILE_PIPE__POST_R3__ = SWITCH_COMPILE_PIPE__POST_R3__; |
| exports.ɵSWITCH_COMPILE_NGMODULE__POST_R3__ = SWITCH_COMPILE_NGMODULE__POST_R3__; |
| exports.ɵgetDebugNode__POST_R3__ = getDebugNode__POST_R3__; |
| exports.ɵSWITCH_COMPILE_INJECTABLE__POST_R3__ = SWITCH_COMPILE_INJECTABLE__POST_R3__; |
| exports.ɵSWITCH_IVY_ENABLED__POST_R3__ = SWITCH_IVY_ENABLED__POST_R3__; |
| exports.ɵSWITCH_CHANGE_DETECTOR_REF_FACTORY__POST_R3__ = SWITCH_CHANGE_DETECTOR_REF_FACTORY__POST_R3__; |
| exports.ɵCompiler_compileModuleSync__POST_R3__ = Compiler_compileModuleSync__POST_R3__; |
| exports.ɵCompiler_compileModuleAsync__POST_R3__ = Compiler_compileModuleAsync__POST_R3__; |
| exports.ɵCompiler_compileModuleAndAllComponentsSync__POST_R3__ = Compiler_compileModuleAndAllComponentsSync__POST_R3__; |
| exports.ɵCompiler_compileModuleAndAllComponentsAsync__POST_R3__ = Compiler_compileModuleAndAllComponentsAsync__POST_R3__; |
| exports.ɵSWITCH_ELEMENT_REF_FACTORY__POST_R3__ = SWITCH_ELEMENT_REF_FACTORY__POST_R3__; |
| exports.ɵSWITCH_TEMPLATE_REF_FACTORY__POST_R3__ = SWITCH_TEMPLATE_REF_FACTORY__POST_R3__; |
| exports.ɵSWITCH_VIEW_CONTAINER_REF_FACTORY__POST_R3__ = SWITCH_VIEW_CONTAINER_REF_FACTORY__POST_R3__; |
| exports.ɵSWITCH_RENDERER2_FACTORY__POST_R3__ = SWITCH_RENDERER2_FACTORY__POST_R3__; |
| exports.ɵgetModuleFactory__POST_R3__ = getModuleFactory__POST_R3__; |
| exports.ɵregisterNgModuleType = registerNgModuleType; |
| exports.ɵpublishGlobalUtil = publishGlobalUtil; |
| exports.ɵpublishDefaultGlobalUtils = publishDefaultGlobalUtils; |
| exports.ɵcreateInjector = createInjector; |
| exports.ɵINJECTOR_IMPL__POST_R3__ = INJECTOR_IMPL__POST_R3__; |
| exports.ɵregisterModuleFactory = registerModuleFactory; |
| exports.ɵEMPTY_ARRAY = EMPTY_ARRAY$3; |
| exports.ɵEMPTY_MAP = EMPTY_MAP; |
| exports.ɵand = anchorDef; |
| exports.ɵccf = createComponentFactory; |
| exports.ɵcmf = createNgModuleFactory; |
| exports.ɵcrt = createRendererType2; |
| exports.ɵdid = directiveDef; |
| exports.ɵeld = elementDef; |
| exports.ɵgetComponentViewDefinitionFactory = getComponentViewDefinitionFactory; |
| exports.ɵinlineInterpolate = inlineInterpolate; |
| exports.ɵinterpolate = interpolate; |
| exports.ɵmod = moduleDef; |
| exports.ɵmpd = moduleProvideDef; |
| exports.ɵncd = ngContentDef; |
| exports.ɵnov = nodeValue; |
| exports.ɵpid = pipeDef; |
| exports.ɵprd = providerDef; |
| exports.ɵpad = pureArrayDef; |
| exports.ɵpod = pureObjectDef; |
| exports.ɵppd = purePipeDef; |
| exports.ɵqud = queryDef; |
| exports.ɵted = textDef; |
| exports.ɵunv = unwrapValue; |
| exports.ɵvid = viewDef; |
| |
| Object.defineProperty(exports, '__esModule', { value: true }); |
| |
| })); |
| //# sourceMappingURL=core.umd.js.map |