UNPKG

88.5 kBJavaScriptView Raw
1/**
2 * @license Angular v14.0.3
3 * (c) 2010-2022 Google LLC. https://angular.io/
4 * License: MIT
5 */
6
7import * as i0 from '@angular/core';
8import { ɵNG_MOD_DEF, Injector, ChangeDetectorRef, Testability, TestabilityRegistry, ApplicationRef, SimpleChange, NgZone, ComponentFactoryResolver, Version, ɵNOT_FOUND_CHECK_ONLY_ELEMENT_INJECTOR, PlatformRef, EventEmitter, Directive, NgModule } from '@angular/core';
9import { platformBrowser } from '@angular/platform-browser';
10
11/**
12 * @license
13 * Copyright Google LLC All Rights Reserved.
14 *
15 * Use of this source code is governed by an MIT-style license that can be
16 * found in the LICENSE file at https://angular.io/license
17 */
18function noNg() {
19 throw new Error('AngularJS v1.x is not loaded!');
20}
21const noNgElement = (() => noNg());
22noNgElement.cleanData = noNg;
23let angular = {
24 bootstrap: noNg,
25 module: noNg,
26 element: noNgElement,
27 injector: noNg,
28 version: undefined,
29 resumeBootstrap: noNg,
30 getTestability: noNg
31};
32try {
33 if (window.hasOwnProperty('angular')) {
34 angular = window.angular;
35 }
36}
37catch (_a) {
38 // ignore in CJS mode.
39}
40/**
41 * @deprecated Use `setAngularJSGlobal` instead.
42 *
43 * @publicApi
44 */
45function setAngularLib(ng) {
46 setAngularJSGlobal(ng);
47}
48/**
49 * @deprecated Use `getAngularJSGlobal` instead.
50 *
51 * @publicApi
52 */
53function getAngularLib() {
54 return getAngularJSGlobal();
55}
56/**
57 * Resets the AngularJS global.
58 *
59 * Used when AngularJS is loaded lazily, and not available on `window`.
60 *
61 * @publicApi
62 */
63function setAngularJSGlobal(ng) {
64 angular = ng;
65}
66/**
67 * Returns the current AngularJS global.
68 *
69 * @publicApi
70 */
71function getAngularJSGlobal() {
72 return angular;
73}
74const bootstrap = (e, modules, config) => angular.bootstrap(e, modules, config);
75// Do not declare as `module` to avoid webpack bug
76// (see https://github.com/angular/angular/issues/30050).
77const module_ = (prefix, dependencies) => angular.module(prefix, dependencies);
78const element = (e => angular.element(e));
79element.cleanData = nodes => angular.element.cleanData(nodes);
80const injector = (modules, strictDi) => angular.injector(modules, strictDi);
81const resumeBootstrap = () => angular.resumeBootstrap();
82const getTestability = e => angular.getTestability(e);
83
84/**
85 * @license
86 * Copyright Google LLC All Rights Reserved.
87 *
88 * Use of this source code is governed by an MIT-style license that can be
89 * found in the LICENSE file at https://angular.io/license
90 */
91const $COMPILE = '$compile';
92const $CONTROLLER = '$controller';
93const $DELEGATE = '$delegate';
94const $EXCEPTION_HANDLER = '$exceptionHandler';
95const $HTTP_BACKEND = '$httpBackend';
96const $INJECTOR = '$injector';
97const $INTERVAL = '$interval';
98const $PARSE = '$parse';
99const $PROVIDE = '$provide';
100const $ROOT_ELEMENT = '$rootElement';
101const $ROOT_SCOPE = '$rootScope';
102const $SCOPE = '$scope';
103const $TEMPLATE_CACHE = '$templateCache';
104const $TEMPLATE_REQUEST = '$templateRequest';
105const $$TESTABILITY = '$$testability';
106const COMPILER_KEY = '$$angularCompiler';
107const DOWNGRADED_MODULE_COUNT_KEY = '$$angularDowngradedModuleCount';
108const GROUP_PROJECTABLE_NODES_KEY = '$$angularGroupProjectableNodes';
109const INJECTOR_KEY = '$$angularInjector';
110const LAZY_MODULE_REF = '$$angularLazyModuleRef';
111const NG_ZONE_KEY = '$$angularNgZone';
112const UPGRADE_APP_TYPE_KEY = '$$angularUpgradeAppType';
113const REQUIRE_INJECTOR = '?^^' + INJECTOR_KEY;
114const REQUIRE_NG_MODEL = '?ngModel';
115const UPGRADE_MODULE_NAME = '$$UpgradeModule';
116
117/**
118 * @license
119 * Copyright Google LLC All Rights Reserved.
120 *
121 * Use of this source code is governed by an MIT-style license that can be
122 * found in the LICENSE file at https://angular.io/license
123 */
124/**
125 * A `PropertyBinding` represents a mapping between a property name
126 * and an attribute name. It is parsed from a string of the form
127 * `"prop: attr"`; or simply `"propAndAttr" where the property
128 * and attribute have the same identifier.
129 */
130class PropertyBinding {
131 constructor(prop, attr) {
132 this.prop = prop;
133 this.attr = attr;
134 this.parseBinding();
135 }
136 parseBinding() {
137 this.bracketAttr = `[${this.attr}]`;
138 this.parenAttr = `(${this.attr})`;
139 this.bracketParenAttr = `[(${this.attr})]`;
140 const capitalAttr = this.attr.charAt(0).toUpperCase() + this.attr.slice(1);
141 this.onAttr = `on${capitalAttr}`;
142 this.bindAttr = `bind${capitalAttr}`;
143 this.bindonAttr = `bindon${capitalAttr}`;
144 }
145}
146
147/**
148 * @license
149 * Copyright Google LLC All Rights Reserved.
150 *
151 * Use of this source code is governed by an MIT-style license that can be
152 * found in the LICENSE file at https://angular.io/license
153 */
154const DIRECTIVE_PREFIX_REGEXP = /^(?:x|data)[:\-_]/i;
155const DIRECTIVE_SPECIAL_CHARS_REGEXP = /[:\-_]+(.)/g;
156function onError(e) {
157 // TODO: (misko): We seem to not have a stack trace here!
158 if (console.error) {
159 console.error(e, e.stack);
160 }
161 else {
162 // tslint:disable-next-line:no-console
163 console.log(e, e.stack);
164 }
165 throw e;
166}
167/**
168 * Clean the jqLite/jQuery data on the element and all its descendants.
169 * Equivalent to how jqLite/jQuery invoke `cleanData()` on an Element when removed:
170 * https://github.com/angular/angular.js/blob/2e72ea13fa98bebf6ed4b5e3c45eaf5f990ed16f/src/jqLite.js#L349-L355
171 * https://github.com/jquery/jquery/blob/6984d1747623dbc5e87fd6c261a5b6b1628c107c/src/manipulation.js#L182
172 *
173 * NOTE:
174 * `cleanData()` will also invoke the AngularJS `$destroy` DOM event on the element:
175 * https://github.com/angular/angular.js/blob/2e72ea13fa98bebf6ed4b5e3c45eaf5f990ed16f/src/Angular.js#L1932-L1945
176 *
177 * @param node The DOM node whose data needs to be cleaned.
178 */
179function cleanData(node) {
180 element.cleanData([node]);
181 if (isParentNode(node)) {
182 element.cleanData(node.querySelectorAll('*'));
183 }
184}
185function controllerKey(name) {
186 return '$' + name + 'Controller';
187}
188/**
189 * Destroy an AngularJS app given the app `$injector`.
190 *
191 * NOTE: Destroying an app is not officially supported by AngularJS, but try to do our best by
192 * destroying `$rootScope` and clean the jqLite/jQuery data on `$rootElement` and all
193 * descendants.
194 *
195 * @param $injector The `$injector` of the AngularJS app to destroy.
196 */
197function destroyApp($injector) {
198 const $rootElement = $injector.get($ROOT_ELEMENT);
199 const $rootScope = $injector.get($ROOT_SCOPE);
200 $rootScope.$destroy();
201 cleanData($rootElement[0]);
202}
203function directiveNormalize(name) {
204 return name.replace(DIRECTIVE_PREFIX_REGEXP, '')
205 .replace(DIRECTIVE_SPECIAL_CHARS_REGEXP, (_, letter) => letter.toUpperCase());
206}
207function getTypeName(type) {
208 // Return the name of the type or the first line of its stringified version.
209 return type.overriddenName || type.name || type.toString().split('\n')[0];
210}
211function getDowngradedModuleCount($injector) {
212 return $injector.has(DOWNGRADED_MODULE_COUNT_KEY) ? $injector.get(DOWNGRADED_MODULE_COUNT_KEY) :
213 0;
214}
215function getUpgradeAppType($injector) {
216 return $injector.has(UPGRADE_APP_TYPE_KEY) ? $injector.get(UPGRADE_APP_TYPE_KEY) :
217 0 /* UpgradeAppType.None */;
218}
219function isFunction(value) {
220 return typeof value === 'function';
221}
222function isNgModuleType(value) {
223 // NgModule class should have the `ɵmod` static property attached by AOT or JIT compiler.
224 return isFunction(value) && !!value[ɵNG_MOD_DEF];
225}
226function isParentNode(node) {
227 return isFunction(node.querySelectorAll);
228}
229function validateInjectionKey($injector, downgradedModule, injectionKey, attemptedAction) {
230 const upgradeAppType = getUpgradeAppType($injector);
231 const downgradedModuleCount = getDowngradedModuleCount($injector);
232 // Check for common errors.
233 switch (upgradeAppType) {
234 case 1 /* UpgradeAppType.Dynamic */:
235 case 2 /* UpgradeAppType.Static */:
236 if (downgradedModule) {
237 throw new Error(`Error while ${attemptedAction}: 'downgradedModule' unexpectedly specified.\n` +
238 'You should not specify a value for \'downgradedModule\', unless you are downgrading ' +
239 'more than one Angular module (via \'downgradeModule()\').');
240 }
241 break;
242 case 3 /* UpgradeAppType.Lite */:
243 if (!downgradedModule && (downgradedModuleCount >= 2)) {
244 throw new Error(`Error while ${attemptedAction}: 'downgradedModule' not specified.\n` +
245 'This application contains more than one downgraded Angular module, thus you need to ' +
246 'always specify \'downgradedModule\' when downgrading components and injectables.');
247 }
248 if (!$injector.has(injectionKey)) {
249 throw new Error(`Error while ${attemptedAction}: Unable to find the specified downgraded module.\n` +
250 'Did you forget to downgrade an Angular module or include it in the AngularJS ' +
251 'application?');
252 }
253 break;
254 default:
255 throw new Error(`Error while ${attemptedAction}: Not a valid '@angular/upgrade' application.\n` +
256 'Did you forget to downgrade an Angular module or include it in the AngularJS ' +
257 'application?');
258 }
259}
260class Deferred {
261 constructor() {
262 this.promise = new Promise((res, rej) => {
263 this.resolve = res;
264 this.reject = rej;
265 });
266 }
267}
268/**
269 * @return Whether the passed-in component implements the subset of the
270 * `ControlValueAccessor` interface needed for AngularJS `ng-model`
271 * compatibility.
272 */
273function supportsNgModel(component) {
274 return typeof component.writeValue === 'function' &&
275 typeof component.registerOnChange === 'function';
276}
277/**
278 * Glue the AngularJS `NgModelController` (if it exists) to the component
279 * (if it implements the needed subset of the `ControlValueAccessor` interface).
280 */
281function hookupNgModel(ngModel, component) {
282 if (ngModel && supportsNgModel(component)) {
283 ngModel.$render = () => {
284 component.writeValue(ngModel.$viewValue);
285 };
286 component.registerOnChange(ngModel.$setViewValue.bind(ngModel));
287 if (typeof component.registerOnTouched === 'function') {
288 component.registerOnTouched(ngModel.$setTouched.bind(ngModel));
289 }
290 }
291}
292/**
293 * Test two values for strict equality, accounting for the fact that `NaN !== NaN`.
294 */
295function strictEquals(val1, val2) {
296 return val1 === val2 || (val1 !== val1 && val2 !== val2);
297}
298
299/**
300 * @license
301 * Copyright Google LLC All Rights Reserved.
302 *
303 * Use of this source code is governed by an MIT-style license that can be
304 * found in the LICENSE file at https://angular.io/license
305 */
306const INITIAL_VALUE$1 = {
307 __UNINITIALIZED__: true
308};
309class DowngradeComponentAdapter {
310 constructor(element, attrs, scope, ngModel, parentInjector, $compile, $parse, componentFactory, wrapCallback) {
311 this.element = element;
312 this.attrs = attrs;
313 this.scope = scope;
314 this.ngModel = ngModel;
315 this.parentInjector = parentInjector;
316 this.$compile = $compile;
317 this.$parse = $parse;
318 this.componentFactory = componentFactory;
319 this.wrapCallback = wrapCallback;
320 this.implementsOnChanges = false;
321 this.inputChangeCount = 0;
322 this.inputChanges = {};
323 this.componentScope = scope.$new();
324 }
325 compileContents() {
326 const compiledProjectableNodes = [];
327 const projectableNodes = this.groupProjectableNodes();
328 const linkFns = projectableNodes.map(nodes => this.$compile(nodes));
329 this.element.empty();
330 linkFns.forEach(linkFn => {
331 linkFn(this.scope, (clone) => {
332 compiledProjectableNodes.push(clone);
333 this.element.append(clone);
334 });
335 });
336 return compiledProjectableNodes;
337 }
338 createComponent(projectableNodes) {
339 const providers = [{ provide: $SCOPE, useValue: this.componentScope }];
340 const childInjector = Injector.create({ providers: providers, parent: this.parentInjector, name: 'DowngradeComponentAdapter' });
341 this.componentRef =
342 this.componentFactory.create(childInjector, projectableNodes, this.element[0]);
343 this.viewChangeDetector = this.componentRef.injector.get(ChangeDetectorRef);
344 this.changeDetector = this.componentRef.changeDetectorRef;
345 this.component = this.componentRef.instance;
346 // testability hook is commonly added during component bootstrap in
347 // packages/core/src/application_ref.bootstrap()
348 // in downgraded application, component creation will take place here as well as adding the
349 // testability hook.
350 const testability = this.componentRef.injector.get(Testability, null);
351 if (testability) {
352 this.componentRef.injector.get(TestabilityRegistry)
353 .registerApplication(this.componentRef.location.nativeElement, testability);
354 }
355 hookupNgModel(this.ngModel, this.component);
356 }
357 setupInputs(manuallyAttachView, propagateDigest = true) {
358 const attrs = this.attrs;
359 const inputs = this.componentFactory.inputs || [];
360 for (let i = 0; i < inputs.length; i++) {
361 const input = new PropertyBinding(inputs[i].propName, inputs[i].templateName);
362 let expr = null;
363 if (attrs.hasOwnProperty(input.attr)) {
364 const observeFn = (prop => {
365 let prevValue = INITIAL_VALUE$1;
366 return (currValue) => {
367 // Initially, both `$observe()` and `$watch()` will call this function.
368 if (!strictEquals(prevValue, currValue)) {
369 if (prevValue === INITIAL_VALUE$1) {
370 prevValue = currValue;
371 }
372 this.updateInput(prop, prevValue, currValue);
373 prevValue = currValue;
374 }
375 };
376 })(input.prop);
377 attrs.$observe(input.attr, observeFn);
378 // Use `$watch()` (in addition to `$observe()`) in order to initialize the input in time
379 // for `ngOnChanges()`. This is necessary if we are already in a `$digest`, which means that
380 // `ngOnChanges()` (which is called by a watcher) will run before the `$observe()` callback.
381 let unwatch = this.componentScope.$watch(() => {
382 unwatch();
383 unwatch = null;
384 observeFn(attrs[input.attr]);
385 });
386 }
387 else if (attrs.hasOwnProperty(input.bindAttr)) {
388 expr = attrs[input.bindAttr];
389 }
390 else if (attrs.hasOwnProperty(input.bracketAttr)) {
391 expr = attrs[input.bracketAttr];
392 }
393 else if (attrs.hasOwnProperty(input.bindonAttr)) {
394 expr = attrs[input.bindonAttr];
395 }
396 else if (attrs.hasOwnProperty(input.bracketParenAttr)) {
397 expr = attrs[input.bracketParenAttr];
398 }
399 if (expr != null) {
400 const watchFn = (prop => (currValue, prevValue) => this.updateInput(prop, prevValue, currValue))(input.prop);
401 this.componentScope.$watch(expr, watchFn);
402 }
403 }
404 // Invoke `ngOnChanges()` and Change Detection (when necessary)
405 const detectChanges = () => this.changeDetector.detectChanges();
406 const prototype = this.componentFactory.componentType.prototype;
407 this.implementsOnChanges = !!(prototype && prototype.ngOnChanges);
408 this.componentScope.$watch(() => this.inputChangeCount, this.wrapCallback(() => {
409 // Invoke `ngOnChanges()`
410 if (this.implementsOnChanges) {
411 const inputChanges = this.inputChanges;
412 this.inputChanges = {};
413 this.component.ngOnChanges(inputChanges);
414 }
415 this.viewChangeDetector.markForCheck();
416 // If opted out of propagating digests, invoke change detection when inputs change.
417 if (!propagateDigest) {
418 detectChanges();
419 }
420 }));
421 // If not opted out of propagating digests, invoke change detection on every digest
422 if (propagateDigest) {
423 this.componentScope.$watch(this.wrapCallback(detectChanges));
424 }
425 // If necessary, attach the view so that it will be dirty-checked.
426 // (Allow time for the initial input values to be set and `ngOnChanges()` to be called.)
427 if (manuallyAttachView || !propagateDigest) {
428 let unwatch = this.componentScope.$watch(() => {
429 unwatch();
430 unwatch = null;
431 const appRef = this.parentInjector.get(ApplicationRef);
432 appRef.attachView(this.componentRef.hostView);
433 });
434 }
435 }
436 setupOutputs() {
437 const attrs = this.attrs;
438 const outputs = this.componentFactory.outputs || [];
439 for (let j = 0; j < outputs.length; j++) {
440 const output = new PropertyBinding(outputs[j].propName, outputs[j].templateName);
441 const bindonAttr = output.bindonAttr.substring(0, output.bindonAttr.length - 6);
442 const bracketParenAttr = `[(${output.bracketParenAttr.substring(2, output.bracketParenAttr.length - 8)})]`;
443 // order below is important - first update bindings then evaluate expressions
444 if (attrs.hasOwnProperty(bindonAttr)) {
445 this.subscribeToOutput(output, attrs[bindonAttr], true);
446 }
447 if (attrs.hasOwnProperty(bracketParenAttr)) {
448 this.subscribeToOutput(output, attrs[bracketParenAttr], true);
449 }
450 if (attrs.hasOwnProperty(output.onAttr)) {
451 this.subscribeToOutput(output, attrs[output.onAttr]);
452 }
453 if (attrs.hasOwnProperty(output.parenAttr)) {
454 this.subscribeToOutput(output, attrs[output.parenAttr]);
455 }
456 }
457 }
458 subscribeToOutput(output, expr, isAssignment = false) {
459 const getter = this.$parse(expr);
460 const setter = getter.assign;
461 if (isAssignment && !setter) {
462 throw new Error(`Expression '${expr}' is not assignable!`);
463 }
464 const emitter = this.component[output.prop];
465 if (emitter) {
466 emitter.subscribe({
467 next: isAssignment ? (v) => setter(this.scope, v) :
468 (v) => getter(this.scope, { '$event': v })
469 });
470 }
471 else {
472 throw new Error(`Missing emitter '${output.prop}' on component '${getTypeName(this.componentFactory.componentType)}'!`);
473 }
474 }
475 registerCleanup() {
476 const testabilityRegistry = this.componentRef.injector.get(TestabilityRegistry);
477 const destroyComponentRef = this.wrapCallback(() => this.componentRef.destroy());
478 let destroyed = false;
479 this.element.on('$destroy', () => {
480 // The `$destroy` event may have been triggered by the `cleanData()` call in the
481 // `componentScope` `$destroy` handler below. In that case, we don't want to call
482 // `componentScope.$destroy()` again.
483 if (!destroyed)
484 this.componentScope.$destroy();
485 });
486 this.componentScope.$on('$destroy', () => {
487 if (!destroyed) {
488 destroyed = true;
489 testabilityRegistry.unregisterApplication(this.componentRef.location.nativeElement);
490 // The `componentScope` might be getting destroyed, because an ancestor element is being
491 // removed/destroyed. If that is the case, jqLite/jQuery would normally invoke `cleanData()`
492 // on the removed element and all descendants.
493 // https://github.com/angular/angular.js/blob/2e72ea13fa98bebf6ed4b5e3c45eaf5f990ed16f/src/jqLite.js#L349-L355
494 // https://github.com/jquery/jquery/blob/6984d1747623dbc5e87fd6c261a5b6b1628c107c/src/manipulation.js#L182
495 //
496 // Here, however, `destroyComponentRef()` may under some circumstances remove the element
497 // from the DOM and therefore it will no longer be a descendant of the removed element when
498 // `cleanData()` is called. This would result in a memory leak, because the element's data
499 // and event handlers (and all objects directly or indirectly referenced by them) would be
500 // retained.
501 //
502 // To ensure the element is always properly cleaned up, we manually call `cleanData()` on
503 // this element and its descendants before destroying the `ComponentRef`.
504 cleanData(this.element[0]);
505 destroyComponentRef();
506 }
507 });
508 }
509 getInjector() {
510 return this.componentRef.injector;
511 }
512 updateInput(prop, prevValue, currValue) {
513 if (this.implementsOnChanges) {
514 this.inputChanges[prop] = new SimpleChange(prevValue, currValue, prevValue === currValue);
515 }
516 this.inputChangeCount++;
517 this.component[prop] = currValue;
518 }
519 groupProjectableNodes() {
520 let ngContentSelectors = this.componentFactory.ngContentSelectors;
521 return groupNodesBySelector(ngContentSelectors, this.element.contents());
522 }
523}
524/**
525 * Group a set of DOM nodes into `ngContent` groups, based on the given content selectors.
526 */
527function groupNodesBySelector(ngContentSelectors, nodes) {
528 const projectableNodes = [];
529 for (let i = 0, ii = ngContentSelectors.length; i < ii; ++i) {
530 projectableNodes[i] = [];
531 }
532 for (let j = 0, jj = nodes.length; j < jj; ++j) {
533 const node = nodes[j];
534 const ngContentIndex = findMatchingNgContentIndex(node, ngContentSelectors);
535 if (ngContentIndex != null) {
536 projectableNodes[ngContentIndex].push(node);
537 }
538 }
539 return projectableNodes;
540}
541function findMatchingNgContentIndex(element, ngContentSelectors) {
542 const ngContentIndices = [];
543 let wildcardNgContentIndex = -1;
544 for (let i = 0; i < ngContentSelectors.length; i++) {
545 const selector = ngContentSelectors[i];
546 if (selector === '*') {
547 wildcardNgContentIndex = i;
548 }
549 else {
550 if (matchesSelector(element, selector)) {
551 ngContentIndices.push(i);
552 }
553 }
554 }
555 ngContentIndices.sort();
556 if (wildcardNgContentIndex !== -1) {
557 ngContentIndices.push(wildcardNgContentIndex);
558 }
559 return ngContentIndices.length ? ngContentIndices[0] : null;
560}
561let _matches;
562function matchesSelector(el, selector) {
563 if (!_matches) {
564 const elProto = Element.prototype;
565 _matches = elProto.matches || elProto.matchesSelector || elProto.mozMatchesSelector ||
566 elProto.msMatchesSelector || elProto.oMatchesSelector || elProto.webkitMatchesSelector;
567 }
568 return el.nodeType === Node.ELEMENT_NODE ? _matches.call(el, selector) : false;
569}
570
571/**
572 * @license
573 * Copyright Google LLC All Rights Reserved.
574 *
575 * Use of this source code is governed by an MIT-style license that can be
576 * found in the LICENSE file at https://angular.io/license
577 */
578function isThenable(obj) {
579 return !!obj && isFunction(obj.then);
580}
581/**
582 * Synchronous, promise-like object.
583 */
584class SyncPromise {
585 constructor() {
586 this.resolved = false;
587 this.callbacks = [];
588 }
589 static all(valuesOrPromises) {
590 const aggrPromise = new SyncPromise();
591 let resolvedCount = 0;
592 const results = [];
593 const resolve = (idx, value) => {
594 results[idx] = value;
595 if (++resolvedCount === valuesOrPromises.length)
596 aggrPromise.resolve(results);
597 };
598 valuesOrPromises.forEach((p, idx) => {
599 if (isThenable(p)) {
600 p.then(v => resolve(idx, v));
601 }
602 else {
603 resolve(idx, p);
604 }
605 });
606 return aggrPromise;
607 }
608 resolve(value) {
609 // Do nothing, if already resolved.
610 if (this.resolved)
611 return;
612 this.value = value;
613 this.resolved = true;
614 // Run the queued callbacks.
615 this.callbacks.forEach(callback => callback(value));
616 this.callbacks.length = 0;
617 }
618 then(callback) {
619 if (this.resolved) {
620 callback(this.value);
621 }
622 else {
623 this.callbacks.push(callback);
624 }
625 }
626}
627
628/**
629 * @license
630 * Copyright Google LLC All Rights Reserved.
631 *
632 * Use of this source code is governed by an MIT-style license that can be
633 * found in the LICENSE file at https://angular.io/license
634 */
635/**
636 * @description
637 *
638 * A helper function that allows an Angular component to be used from AngularJS.
639 *
640 * *Part of the [upgrade/static](api?query=upgrade%2Fstatic)
641 * library for hybrid upgrade apps that support AOT compilation*
642 *
643 * This helper function returns a factory function to be used for registering
644 * an AngularJS wrapper directive for "downgrading" an Angular component.
645 *
646 * @usageNotes
647 * ### Examples
648 *
649 * Let's assume that you have an Angular component called `ng2Heroes` that needs
650 * to be made available in AngularJS templates.
651 *
652 * {@example upgrade/static/ts/full/module.ts region="ng2-heroes"}
653 *
654 * We must create an AngularJS [directive](https://docs.angularjs.org/guide/directive)
655 * that will make this Angular component available inside AngularJS templates.
656 * The `downgradeComponent()` function returns a factory function that we
657 * can use to define the AngularJS directive that wraps the "downgraded" component.
658 *
659 * {@example upgrade/static/ts/full/module.ts region="ng2-heroes-wrapper"}
660 *
661 * For more details and examples on downgrading Angular components to AngularJS components please
662 * visit the [Upgrade guide](guide/upgrade#using-angular-components-from-angularjs-code).
663 *
664 * @param info contains information about the Component that is being downgraded:
665 *
666 * - `component: Type<any>`: The type of the Component that will be downgraded
667 * - `downgradedModule?: string`: The name of the downgraded module (if any) that the component
668 * "belongs to", as returned by a call to `downgradeModule()`. It is the module, whose
669 * corresponding Angular module will be bootstrapped, when the component needs to be instantiated.
670 * <br />
671 * (This option is only necessary when using `downgradeModule()` to downgrade more than one
672 * Angular module.)
673 * - `propagateDigest?: boolean`: Whether to perform {@link ChangeDetectorRef#detectChanges
674 * change detection} on the component on every
675 * [$digest](https://docs.angularjs.org/api/ng/type/$rootScope.Scope#$digest). If set to `false`,
676 * change detection will still be performed when any of the component's inputs changes.
677 * (Default: true)
678 *
679 * @returns a factory function that can be used to register the component in an
680 * AngularJS module.
681 *
682 * @publicApi
683 */
684function downgradeComponent(info) {
685 const directiveFactory = function ($compile, $injector, $parse) {
686 // When using `downgradeModule()`, we need to handle certain things specially. For example:
687 // - We always need to attach the component view to the `ApplicationRef` for it to be
688 // dirty-checked.
689 // - We need to ensure callbacks to Angular APIs (e.g. change detection) are run inside the
690 // Angular zone.
691 // NOTE: This is not needed, when using `UpgradeModule`, because `$digest()` will be run
692 // inside the Angular zone (except if explicitly escaped, in which case we shouldn't
693 // force it back in).
694 const isNgUpgradeLite = getUpgradeAppType($injector) === 3 /* UpgradeAppType.Lite */;
695 const wrapCallback = !isNgUpgradeLite ? cb => cb : cb => () => NgZone.isInAngularZone() ? cb() : ngZone.run(cb);
696 let ngZone;
697 // When downgrading multiple modules, special handling is needed wrt injectors.
698 const hasMultipleDowngradedModules = isNgUpgradeLite && (getDowngradedModuleCount($injector) > 1);
699 return {
700 restrict: 'E',
701 terminal: true,
702 require: [REQUIRE_INJECTOR, REQUIRE_NG_MODEL],
703 link: (scope, element, attrs, required) => {
704 // We might have to compile the contents asynchronously, because this might have been
705 // triggered by `UpgradeNg1ComponentAdapterBuilder`, before the Angular templates have
706 // been compiled.
707 const ngModel = required[1];
708 const parentInjector = required[0];
709 let moduleInjector = undefined;
710 let ranAsync = false;
711 if (!parentInjector || hasMultipleDowngradedModules) {
712 const downgradedModule = info.downgradedModule || '';
713 const lazyModuleRefKey = `${LAZY_MODULE_REF}${downgradedModule}`;
714 const attemptedAction = `instantiating component '${getTypeName(info.component)}'`;
715 validateInjectionKey($injector, downgradedModule, lazyModuleRefKey, attemptedAction);
716 const lazyModuleRef = $injector.get(lazyModuleRefKey);
717 moduleInjector = lazyModuleRef.injector || lazyModuleRef.promise;
718 }
719 // Notes:
720 //
721 // There are two injectors: `finalModuleInjector` and `finalParentInjector` (they might be
722 // the same instance, but that is irrelevant):
723 // - `finalModuleInjector` is used to retrieve `ComponentFactoryResolver`, thus it must be
724 // on the same tree as the `NgModule` that declares this downgraded component.
725 // - `finalParentInjector` is used for all other injection purposes.
726 // (Note that Angular knows to only traverse the component-tree part of that injector,
727 // when looking for an injectable and then switch to the module injector.)
728 //
729 // There are basically three cases:
730 // - If there is no parent component (thus no `parentInjector`), we bootstrap the downgraded
731 // `NgModule` and use its injector as both `finalModuleInjector` and
732 // `finalParentInjector`.
733 // - If there is a parent component (and thus a `parentInjector`) and we are sure that it
734 // belongs to the same `NgModule` as this downgraded component (e.g. because there is only
735 // one downgraded module, we use that `parentInjector` as both `finalModuleInjector` and
736 // `finalParentInjector`.
737 // - If there is a parent component, but it may belong to a different `NgModule`, then we
738 // use the `parentInjector` as `finalParentInjector` and this downgraded component's
739 // declaring `NgModule`'s injector as `finalModuleInjector`.
740 // Note 1: If the `NgModule` is already bootstrapped, we just get its injector (we don't
741 // bootstrap again).
742 // Note 2: It is possible that (while there are multiple downgraded modules) this
743 // downgraded component and its parent component both belong to the same NgModule.
744 // In that case, we could have used the `parentInjector` as both
745 // `finalModuleInjector` and `finalParentInjector`, but (for simplicity) we are
746 // treating this case as if they belong to different `NgModule`s. That doesn't
747 // really affect anything, since `parentInjector` has `moduleInjector` as ancestor
748 // and trying to resolve `ComponentFactoryResolver` from either one will return
749 // the same instance.
750 // If there is a parent component, use its injector as parent injector.
751 // If this is a "top-level" Angular component, use the module injector.
752 const finalParentInjector = parentInjector || moduleInjector;
753 // If this is a "top-level" Angular component or the parent component may belong to a
754 // different `NgModule`, use the module injector for module-specific dependencies.
755 // If there is a parent component that belongs to the same `NgModule`, use its injector.
756 const finalModuleInjector = moduleInjector || parentInjector;
757 const doDowngrade = (injector, moduleInjector) => {
758 // Retrieve `ComponentFactoryResolver` from the injector tied to the `NgModule` this
759 // component belongs to.
760 const componentFactoryResolver = moduleInjector.get(ComponentFactoryResolver);
761 const componentFactory = componentFactoryResolver.resolveComponentFactory(info.component);
762 if (!componentFactory) {
763 throw new Error(`Expecting ComponentFactory for: ${getTypeName(info.component)}`);
764 }
765 const injectorPromise = new ParentInjectorPromise(element);
766 const facade = new DowngradeComponentAdapter(element, attrs, scope, ngModel, injector, $compile, $parse, componentFactory, wrapCallback);
767 const projectableNodes = facade.compileContents();
768 facade.createComponent(projectableNodes);
769 facade.setupInputs(isNgUpgradeLite, info.propagateDigest);
770 facade.setupOutputs();
771 facade.registerCleanup();
772 injectorPromise.resolve(facade.getInjector());
773 if (ranAsync) {
774 // If this is run async, it is possible that it is not run inside a
775 // digest and initial input values will not be detected.
776 scope.$evalAsync(() => { });
777 }
778 };
779 const downgradeFn = !isNgUpgradeLite ? doDowngrade : (pInjector, mInjector) => {
780 if (!ngZone) {
781 ngZone = pInjector.get(NgZone);
782 }
783 wrapCallback(() => doDowngrade(pInjector, mInjector))();
784 };
785 // NOTE:
786 // Not using `ParentInjectorPromise.all()` (which is inherited from `SyncPromise`), because
787 // Closure Compiler (or some related tool) complains:
788 // `TypeError: ...$src$downgrade_component_ParentInjectorPromise.all is not a function`
789 SyncPromise.all([finalParentInjector, finalModuleInjector])
790 .then(([pInjector, mInjector]) => downgradeFn(pInjector, mInjector));
791 ranAsync = true;
792 }
793 };
794 };
795 // bracket-notation because of closure - see #14441
796 directiveFactory['$inject'] = [$COMPILE, $INJECTOR, $PARSE];
797 return directiveFactory;
798}
799/**
800 * Synchronous promise-like object to wrap parent injectors,
801 * to preserve the synchronous nature of AngularJS's `$compile`.
802 */
803class ParentInjectorPromise extends SyncPromise {
804 constructor(element) {
805 super();
806 this.element = element;
807 this.injectorKey = controllerKey(INJECTOR_KEY);
808 // Store the promise on the element.
809 element.data(this.injectorKey, this);
810 }
811 resolve(injector) {
812 // Store the real injector on the element.
813 this.element.data(this.injectorKey, injector);
814 // Release the element to prevent memory leaks.
815 this.element = null;
816 // Resolve the promise.
817 super.resolve(injector);
818 }
819}
820
821/**
822 * @license
823 * Copyright Google LLC All Rights Reserved.
824 *
825 * Use of this source code is governed by an MIT-style license that can be
826 * found in the LICENSE file at https://angular.io/license
827 */
828/**
829 * @description
830 *
831 * A helper function to allow an Angular service to be accessible from AngularJS.
832 *
833 * *Part of the [upgrade/static](api?query=upgrade%2Fstatic)
834 * library for hybrid upgrade apps that support AOT compilation*
835 *
836 * This helper function returns a factory function that provides access to the Angular
837 * service identified by the `token` parameter.
838 *
839 * @usageNotes
840 * ### Examples
841 *
842 * First ensure that the service to be downgraded is provided in an `NgModule`
843 * that will be part of the upgrade application. For example, let's assume we have
844 * defined `HeroesService`
845 *
846 * {@example upgrade/static/ts/full/module.ts region="ng2-heroes-service"}
847 *
848 * and that we have included this in our upgrade app `NgModule`
849 *
850 * {@example upgrade/static/ts/full/module.ts region="ng2-module"}
851 *
852 * Now we can register the `downgradeInjectable` factory function for the service
853 * on an AngularJS module.
854 *
855 * {@example upgrade/static/ts/full/module.ts region="downgrade-ng2-heroes-service"}
856 *
857 * Inside an AngularJS component's controller we can get hold of the
858 * downgraded service via the name we gave when downgrading.
859 *
860 * {@example upgrade/static/ts/full/module.ts region="example-app"}
861 *
862 * <div class="alert is-important">
863 *
864 * When using `downgradeModule()`, downgraded injectables will not be available until the Angular
865 * module that provides them is instantiated. In order to be safe, you need to ensure that the
866 * downgraded injectables are not used anywhere _outside_ the part of the app where it is
867 * guaranteed that their module has been instantiated.
868 *
869 * For example, it is _OK_ to use a downgraded service in an upgraded component that is only used
870 * from a downgraded Angular component provided by the same Angular module as the injectable, but
871 * it is _not OK_ to use it in an AngularJS component that may be used independently of Angular or
872 * use it in a downgraded Angular component from a different module.
873 *
874 * </div>
875 *
876 * @param token an `InjectionToken` that identifies a service provided from Angular.
877 * @param downgradedModule the name of the downgraded module (if any) that the injectable
878 * "belongs to", as returned by a call to `downgradeModule()`. It is the module, whose injector will
879 * be used for instantiating the injectable.<br />
880 * (This option is only necessary when using `downgradeModule()` to downgrade more than one Angular
881 * module.)
882 *
883 * @returns a [factory function](https://docs.angularjs.org/guide/di) that can be
884 * used to register the service on an AngularJS module.
885 *
886 * @publicApi
887 */
888function downgradeInjectable(token, downgradedModule = '') {
889 const factory = function ($injector) {
890 const injectorKey = `${INJECTOR_KEY}${downgradedModule}`;
891 const injectableName = isFunction(token) ? getTypeName(token) : String(token);
892 const attemptedAction = `instantiating injectable '${injectableName}'`;
893 validateInjectionKey($injector, downgradedModule, injectorKey, attemptedAction);
894 try {
895 const injector = $injector.get(injectorKey);
896 return injector.get(token);
897 }
898 catch (err) {
899 throw new Error(`Error while ${attemptedAction}: ${err.message || err}`);
900 }
901 };
902 factory['$inject'] = [$INJECTOR];
903 return factory;
904}
905
906/**
907 * @license
908 * Copyright Google LLC All Rights Reserved.
909 *
910 * Use of this source code is governed by an MIT-style license that can be
911 * found in the LICENSE file at https://angular.io/license
912 */
913/**
914 * @publicApi
915 */
916const VERSION = new Version('14.0.3');
917
918/**
919 * @license
920 * Copyright Google LLC All Rights Reserved.
921 *
922 * Use of this source code is governed by an MIT-style license that can be
923 * found in the LICENSE file at https://angular.io/license
924 */
925// We have to do a little dance to get the ng1 injector into the module injector.
926// We store the ng1 injector so that the provider in the module injector can access it
927// Then we "get" the ng1 injector from the module injector, which triggers the provider to read
928// the stored injector and release the reference to it.
929let tempInjectorRef = null;
930function setTempInjectorRef(injector) {
931 tempInjectorRef = injector;
932}
933function injectorFactory() {
934 if (!tempInjectorRef) {
935 throw new Error('Trying to get the AngularJS injector before it being set.');
936 }
937 const injector = tempInjectorRef;
938 tempInjectorRef = null; // clear the value to prevent memory leaks
939 return injector;
940}
941function rootScopeFactory(i) {
942 return i.get('$rootScope');
943}
944function compileFactory(i) {
945 return i.get('$compile');
946}
947function parseFactory(i) {
948 return i.get('$parse');
949}
950const angular1Providers = [
951 // We must use exported named functions for the ng2 factories to keep the compiler happy:
952 // > Metadata collected contains an error that will be reported at runtime:
953 // > Function calls are not supported.
954 // > Consider replacing the function or lambda with a reference to an exported function
955 { provide: '$injector', useFactory: injectorFactory, deps: [] },
956 { provide: '$rootScope', useFactory: rootScopeFactory, deps: ['$injector'] },
957 { provide: '$compile', useFactory: compileFactory, deps: ['$injector'] },
958 { provide: '$parse', useFactory: parseFactory, deps: ['$injector'] }
959];
960
961/**
962 * @license
963 * Copyright Google LLC All Rights Reserved.
964 *
965 * Use of this source code is governed by an MIT-style license that can be
966 * found in the LICENSE file at https://angular.io/license
967 */
968class NgAdapterInjector {
969 constructor(modInjector) {
970 this.modInjector = modInjector;
971 }
972 // When Angular locate a service in the component injector tree, the not found value is set to
973 // `NOT_FOUND_CHECK_ONLY_ELEMENT_INJECTOR`. In such a case we should not walk up to the module
974 // injector.
975 // AngularJS only supports a single tree and should always check the module injector.
976 get(token, notFoundValue) {
977 if (notFoundValue === ɵNOT_FOUND_CHECK_ONLY_ELEMENT_INJECTOR) {
978 return notFoundValue;
979 }
980 return this.modInjector.get(token, notFoundValue);
981 }
982}
983
984/**
985 * @license
986 * Copyright Google LLC All Rights Reserved.
987 *
988 * Use of this source code is governed by an MIT-style license that can be
989 * found in the LICENSE file at https://angular.io/license
990 */
991let moduleUid = 0;
992/**
993 * @description
994 *
995 * A helper function for creating an AngularJS module that can bootstrap an Angular module
996 * "on-demand" (possibly lazily) when a {@link downgradeComponent downgraded component} needs to be
997 * instantiated.
998 *
999 * *Part of the [upgrade/static](api?query=upgrade/static) library for hybrid upgrade apps that
1000 * support AOT compilation.*
1001 *
1002 * It allows loading/bootstrapping the Angular part of a hybrid application lazily and not having to
1003 * pay the cost up-front. For example, you can have an AngularJS application that uses Angular for
1004 * specific routes and only instantiate the Angular modules if/when the user visits one of these
1005 * routes.
1006 *
1007 * The Angular module will be bootstrapped once (when requested for the first time) and the same
1008 * reference will be used from that point onwards.
1009 *
1010 * `downgradeModule()` requires either an `NgModuleFactory`, `NgModule` class or a function:
1011 * - `NgModuleFactory`: If you pass an `NgModuleFactory`, it will be used to instantiate a module
1012 * using `platformBrowser`'s {@link PlatformRef#bootstrapModuleFactory bootstrapModuleFactory()}.
1013 * NOTE: this type of the argument is deprecated. Please either provide an `NgModule` class or a
1014 * bootstrap function instead.
1015 * - `NgModule` class: If you pass an NgModule class, it will be used to instantiate a module
1016 * using `platformBrowser`'s {@link PlatformRef#bootstrapModule bootstrapModule()}.
1017 * - `Function`: If you pass a function, it is expected to return a promise resolving to an
1018 * `NgModuleRef`. The function is called with an array of extra {@link StaticProvider Providers}
1019 * that are expected to be available from the returned `NgModuleRef`'s `Injector`.
1020 *
1021 * `downgradeModule()` returns the name of the created AngularJS wrapper module. You can use it to
1022 * declare a dependency in your main AngularJS module.
1023 *
1024 * {@example upgrade/static/ts/lite/module.ts region="basic-how-to"}
1025 *
1026 * For more details on how to use `downgradeModule()` see
1027 * [Upgrading for Performance](guide/upgrade-performance).
1028 *
1029 * @usageNotes
1030 *
1031 * Apart from `UpgradeModule`, you can use the rest of the `upgrade/static` helpers as usual to
1032 * build a hybrid application. Note that the Angular pieces (e.g. downgraded services) will not be
1033 * available until the downgraded module has been bootstrapped, i.e. by instantiating a downgraded
1034 * component.
1035 *
1036 * <div class="alert is-important">
1037 *
1038 * You cannot use `downgradeModule()` and `UpgradeModule` in the same hybrid application.<br />
1039 * Use one or the other.
1040 *
1041 * </div>
1042 *
1043 * ### Differences with `UpgradeModule`
1044 *
1045 * Besides their different API, there are two important internal differences between
1046 * `downgradeModule()` and `UpgradeModule` that affect the behavior of hybrid applications:
1047 *
1048 * 1. Unlike `UpgradeModule`, `downgradeModule()` does not bootstrap the main AngularJS module
1049 * inside the {@link NgZone Angular zone}.
1050 * 2. Unlike `UpgradeModule`, `downgradeModule()` does not automatically run a
1051 * [$digest()](https://docs.angularjs.org/api/ng/type/$rootScope.Scope#$digest) when changes are
1052 * detected in the Angular part of the application.
1053 *
1054 * What this means is that applications using `UpgradeModule` will run change detection more
1055 * frequently in order to ensure that both frameworks are properly notified about possible changes.
1056 * This will inevitably result in more change detection runs than necessary.
1057 *
1058 * `downgradeModule()`, on the other side, does not try to tie the two change detection systems as
1059 * tightly, restricting the explicit change detection runs only to cases where it knows it is
1060 * necessary (e.g. when the inputs of a downgraded component change). This improves performance,
1061 * especially in change-detection-heavy applications, but leaves it up to the developer to manually
1062 * notify each framework as needed.
1063 *
1064 * For a more detailed discussion of the differences and their implications, see
1065 * [Upgrading for Performance](guide/upgrade-performance).
1066 *
1067 * <div class="alert is-helpful">
1068 *
1069 * You can manually trigger a change detection run in AngularJS using
1070 * [scope.$apply(...)](https://docs.angularjs.org/api/ng/type/$rootScope.Scope#$apply) or
1071 * [$rootScope.$digest()](https://docs.angularjs.org/api/ng/type/$rootScope.Scope#$digest).
1072 *
1073 * You can manually trigger a change detection run in Angular using {@link NgZone#run
1074 * ngZone.run(...)}.
1075 *
1076 * </div>
1077 *
1078 * ### Downgrading multiple modules
1079 *
1080 * It is possible to downgrade multiple modules and include them in an AngularJS application. In
1081 * that case, each downgraded module will be bootstrapped when an associated downgraded component or
1082 * injectable needs to be instantiated.
1083 *
1084 * Things to keep in mind, when downgrading multiple modules:
1085 *
1086 * - Each downgraded component/injectable needs to be explicitly associated with a downgraded
1087 * module. See `downgradeComponent()` and `downgradeInjectable()` for more details.
1088 *
1089 * - If you want some injectables to be shared among all downgraded modules, you can provide them as
1090 * `StaticProvider`s, when creating the `PlatformRef` (e.g. via `platformBrowser` or
1091 * `platformBrowserDynamic`).
1092 *
1093 * - When using {@link PlatformRef#bootstrapmodule `bootstrapModule()`} or
1094 * {@link PlatformRef#bootstrapmodulefactory `bootstrapModuleFactory()`} to bootstrap the
1095 * downgraded modules, each one is considered a "root" module. As a consequence, a new instance
1096 * will be created for every injectable provided in `"root"` (via
1097 * {@link Injectable#providedIn `providedIn`}).
1098 * If this is not your intention, you can have a shared module (that will act as act as the "root"
1099 * module) and create all downgraded modules using that module's injector:
1100 *
1101 * {@example upgrade/static/ts/lite-multi-shared/module.ts region="shared-root-module"}
1102 *
1103 * @publicApi
1104 */
1105function downgradeModule(moduleOrBootstrapFn) {
1106 const lazyModuleName = `${UPGRADE_MODULE_NAME}.lazy${++moduleUid}`;
1107 const lazyModuleRefKey = `${LAZY_MODULE_REF}${lazyModuleName}`;
1108 const lazyInjectorKey = `${INJECTOR_KEY}${lazyModuleName}`;
1109 let bootstrapFn;
1110 if (isNgModuleType(moduleOrBootstrapFn)) {
1111 // NgModule class
1112 bootstrapFn = (extraProviders) => platformBrowser(extraProviders).bootstrapModule(moduleOrBootstrapFn);
1113 }
1114 else if (!isFunction(moduleOrBootstrapFn)) {
1115 // NgModule factory
1116 bootstrapFn = (extraProviders) => platformBrowser(extraProviders).bootstrapModuleFactory(moduleOrBootstrapFn);
1117 }
1118 else {
1119 // bootstrap function
1120 bootstrapFn = moduleOrBootstrapFn;
1121 }
1122 let injector;
1123 // Create an ng1 module to bootstrap.
1124 module_(lazyModuleName, [])
1125 .constant(UPGRADE_APP_TYPE_KEY, 3 /* UpgradeAppType.Lite */)
1126 .factory(INJECTOR_KEY, [lazyInjectorKey, identity])
1127 .factory(lazyInjectorKey, () => {
1128 if (!injector) {
1129 throw new Error('Trying to get the Angular injector before bootstrapping the corresponding ' +
1130 'Angular module.');
1131 }
1132 return injector;
1133 })
1134 .factory(LAZY_MODULE_REF, [lazyModuleRefKey, identity])
1135 .factory(lazyModuleRefKey, [
1136 $INJECTOR,
1137 ($injector) => {
1138 setTempInjectorRef($injector);
1139 const result = {
1140 promise: bootstrapFn(angular1Providers).then(ref => {
1141 injector = result.injector = new NgAdapterInjector(ref.injector);
1142 injector.get($INJECTOR);
1143 // Destroy the AngularJS app once the Angular `PlatformRef` is destroyed.
1144 // This does not happen in a typical SPA scenario, but it might be useful for
1145 // other use-cases where disposing of an Angular/AngularJS app is necessary
1146 // (such as Hot Module Replacement (HMR)).
1147 // See https://github.com/angular/angular/issues/39935.
1148 injector.get(PlatformRef).onDestroy(() => destroyApp($injector));
1149 return injector;
1150 })
1151 };
1152 return result;
1153 }
1154 ])
1155 .config([
1156 $INJECTOR, $PROVIDE,
1157 ($injector, $provide) => {
1158 $provide.constant(DOWNGRADED_MODULE_COUNT_KEY, getDowngradedModuleCount($injector) + 1);
1159 }
1160 ]);
1161 return lazyModuleName;
1162}
1163function identity(x) {
1164 return x;
1165}
1166
1167/**
1168 * @license
1169 * Copyright Google LLC All Rights Reserved.
1170 *
1171 * Use of this source code is governed by an MIT-style license that can be
1172 * found in the LICENSE file at https://angular.io/license
1173 */
1174// Constants
1175const REQUIRE_PREFIX_RE = /^(\^\^?)?(\?)?(\^\^?)?/;
1176// Classes
1177class UpgradeHelper {
1178 constructor(injector, name, elementRef, directive) {
1179 this.name = name;
1180 this.$injector = injector.get($INJECTOR);
1181 this.$compile = this.$injector.get($COMPILE);
1182 this.$controller = this.$injector.get($CONTROLLER);
1183 this.element = elementRef.nativeElement;
1184 this.$element = element(this.element);
1185 this.directive = directive || UpgradeHelper.getDirective(this.$injector, name);
1186 }
1187 static getDirective($injector, name) {
1188 const directives = $injector.get(name + 'Directive');
1189 if (directives.length > 1) {
1190 throw new Error(`Only support single directive definition for: ${name}`);
1191 }
1192 const directive = directives[0];
1193 // AngularJS will transform `link: xyz` to `compile: () => xyz`. So we can only tell there was a
1194 // user-defined `compile` if there is no `link`. In other cases, we will just ignore `compile`.
1195 if (directive.compile && !directive.link)
1196 notSupported(name, 'compile');
1197 if (directive.replace)
1198 notSupported(name, 'replace');
1199 if (directive.terminal)
1200 notSupported(name, 'terminal');
1201 return directive;
1202 }
1203 static getTemplate($injector, directive, fetchRemoteTemplate = false, $element) {
1204 if (directive.template !== undefined) {
1205 return getOrCall(directive.template, $element);
1206 }
1207 else if (directive.templateUrl) {
1208 const $templateCache = $injector.get($TEMPLATE_CACHE);
1209 const url = getOrCall(directive.templateUrl, $element);
1210 const template = $templateCache.get(url);
1211 if (template !== undefined) {
1212 return template;
1213 }
1214 else if (!fetchRemoteTemplate) {
1215 throw new Error('loading directive templates asynchronously is not supported');
1216 }
1217 return new Promise((resolve, reject) => {
1218 const $httpBackend = $injector.get($HTTP_BACKEND);
1219 $httpBackend('GET', url, null, (status, response) => {
1220 if (status === 200) {
1221 resolve($templateCache.put(url, response));
1222 }
1223 else {
1224 reject(`GET component template from '${url}' returned '${status}: ${response}'`);
1225 }
1226 });
1227 });
1228 }
1229 else {
1230 throw new Error(`Directive '${directive.name}' is not a component, it is missing template.`);
1231 }
1232 }
1233 buildController(controllerType, $scope) {
1234 // TODO: Document that we do not pre-assign bindings on the controller instance.
1235 // Quoted properties below so that this code can be optimized with Closure Compiler.
1236 const locals = { '$scope': $scope, '$element': this.$element };
1237 const controller = this.$controller(controllerType, locals, null, this.directive.controllerAs);
1238 this.$element.data(controllerKey(this.directive.name), controller);
1239 return controller;
1240 }
1241 compileTemplate(template) {
1242 if (template === undefined) {
1243 template =
1244 UpgradeHelper.getTemplate(this.$injector, this.directive, false, this.$element);
1245 }
1246 return this.compileHtml(template);
1247 }
1248 onDestroy($scope, controllerInstance) {
1249 if (controllerInstance && isFunction(controllerInstance.$onDestroy)) {
1250 controllerInstance.$onDestroy();
1251 }
1252 $scope.$destroy();
1253 cleanData(this.element);
1254 }
1255 prepareTransclusion() {
1256 const transclude = this.directive.transclude;
1257 const contentChildNodes = this.extractChildNodes();
1258 const attachChildrenFn = (scope, cloneAttachFn) => {
1259 // Since AngularJS v1.5.8, `cloneAttachFn` will try to destroy the transclusion scope if
1260 // `$template` is empty. Since the transcluded content comes from Angular, not AngularJS,
1261 // there will be no transclusion scope here.
1262 // Provide a dummy `scope.$destroy()` method to prevent `cloneAttachFn` from throwing.
1263 scope = scope || { $destroy: () => undefined };
1264 return cloneAttachFn($template, scope);
1265 };
1266 let $template = contentChildNodes;
1267 if (transclude) {
1268 const slots = Object.create(null);
1269 if (typeof transclude === 'object') {
1270 $template = [];
1271 const slotMap = Object.create(null);
1272 const filledSlots = Object.create(null);
1273 // Parse the element selectors.
1274 Object.keys(transclude).forEach(slotName => {
1275 let selector = transclude[slotName];
1276 const optional = selector.charAt(0) === '?';
1277 selector = optional ? selector.substring(1) : selector;
1278 slotMap[selector] = slotName;
1279 slots[slotName] = null; // `null`: Defined but not yet filled.
1280 filledSlots[slotName] = optional; // Consider optional slots as filled.
1281 });
1282 // Add the matching elements into their slot.
1283 contentChildNodes.forEach(node => {
1284 const slotName = slotMap[directiveNormalize(node.nodeName.toLowerCase())];
1285 if (slotName) {
1286 filledSlots[slotName] = true;
1287 slots[slotName] = slots[slotName] || [];
1288 slots[slotName].push(node);
1289 }
1290 else {
1291 $template.push(node);
1292 }
1293 });
1294 // Check for required slots that were not filled.
1295 Object.keys(filledSlots).forEach(slotName => {
1296 if (!filledSlots[slotName]) {
1297 throw new Error(`Required transclusion slot '${slotName}' on directive: ${this.name}`);
1298 }
1299 });
1300 Object.keys(slots).filter(slotName => slots[slotName]).forEach(slotName => {
1301 const nodes = slots[slotName];
1302 slots[slotName] = (scope, cloneAttach) => {
1303 return cloneAttach(nodes, scope);
1304 };
1305 });
1306 }
1307 // Attach `$$slots` to default slot transclude fn.
1308 attachChildrenFn.$$slots = slots;
1309 // AngularJS v1.6+ ignores empty or whitespace-only transcluded text nodes. But Angular
1310 // removes all text content after the first interpolation and updates it later, after
1311 // evaluating the expressions. This would result in AngularJS failing to recognize text
1312 // nodes that start with an interpolation as transcluded content and use the fallback
1313 // content instead.
1314 // To avoid this issue, we add a
1315 // [zero-width non-joiner character](https://en.wikipedia.org/wiki/Zero-width_non-joiner)
1316 // to empty text nodes (which can only be a result of Angular removing their initial content).
1317 // NOTE: Transcluded text content that starts with whitespace followed by an interpolation
1318 // will still fail to be detected by AngularJS v1.6+
1319 $template.forEach(node => {
1320 if (node.nodeType === Node.TEXT_NODE && !node.nodeValue) {
1321 node.nodeValue = '\u200C';
1322 }
1323 });
1324 }
1325 return attachChildrenFn;
1326 }
1327 resolveAndBindRequiredControllers(controllerInstance) {
1328 const directiveRequire = this.getDirectiveRequire();
1329 const requiredControllers = this.resolveRequire(directiveRequire);
1330 if (controllerInstance && this.directive.bindToController && isMap(directiveRequire)) {
1331 const requiredControllersMap = requiredControllers;
1332 Object.keys(requiredControllersMap).forEach(key => {
1333 controllerInstance[key] = requiredControllersMap[key];
1334 });
1335 }
1336 return requiredControllers;
1337 }
1338 compileHtml(html) {
1339 this.element.innerHTML = html;
1340 return this.$compile(this.element.childNodes);
1341 }
1342 extractChildNodes() {
1343 const childNodes = [];
1344 let childNode;
1345 while (childNode = this.element.firstChild) {
1346 this.element.removeChild(childNode);
1347 childNodes.push(childNode);
1348 }
1349 return childNodes;
1350 }
1351 getDirectiveRequire() {
1352 const require = this.directive.require || (this.directive.controller && this.directive.name);
1353 if (isMap(require)) {
1354 Object.keys(require).forEach(key => {
1355 const value = require[key];
1356 const match = value.match(REQUIRE_PREFIX_RE);
1357 const name = value.substring(match[0].length);
1358 if (!name) {
1359 require[key] = match[0] + key;
1360 }
1361 });
1362 }
1363 return require;
1364 }
1365 resolveRequire(require, controllerInstance) {
1366 if (!require) {
1367 return null;
1368 }
1369 else if (Array.isArray(require)) {
1370 return require.map(req => this.resolveRequire(req));
1371 }
1372 else if (typeof require === 'object') {
1373 const value = {};
1374 Object.keys(require).forEach(key => value[key] = this.resolveRequire(require[key]));
1375 return value;
1376 }
1377 else if (typeof require === 'string') {
1378 const match = require.match(REQUIRE_PREFIX_RE);
1379 const inheritType = match[1] || match[3];
1380 const name = require.substring(match[0].length);
1381 const isOptional = !!match[2];
1382 const searchParents = !!inheritType;
1383 const startOnParent = inheritType === '^^';
1384 const ctrlKey = controllerKey(name);
1385 const elem = startOnParent ? this.$element.parent() : this.$element;
1386 const value = searchParents ? elem.inheritedData(ctrlKey) : elem.data(ctrlKey);
1387 if (!value && !isOptional) {
1388 throw new Error(`Unable to find required '${require}' in upgraded directive '${this.name}'.`);
1389 }
1390 return value;
1391 }
1392 else {
1393 throw new Error(`Unrecognized 'require' syntax on upgraded directive '${this.name}': ${require}`);
1394 }
1395 }
1396}
1397function getOrCall(property, ...args) {
1398 return isFunction(property) ? property(...args) : property;
1399}
1400// NOTE: Only works for `typeof T !== 'object'`.
1401function isMap(value) {
1402 return value && !Array.isArray(value) && typeof value === 'object';
1403}
1404function notSupported(name, feature) {
1405 throw new Error(`Upgraded directive '${name}' contains unsupported feature: '${feature}'.`);
1406}
1407
1408/**
1409 * @license
1410 * Copyright Google LLC All Rights Reserved.
1411 *
1412 * Use of this source code is governed by an MIT-style license that can be
1413 * found in the LICENSE file at https://angular.io/license
1414 */
1415const NOT_SUPPORTED = 'NOT_SUPPORTED';
1416const INITIAL_VALUE = {
1417 __UNINITIALIZED__: true
1418};
1419class Bindings {
1420 constructor() {
1421 this.twoWayBoundProperties = [];
1422 this.twoWayBoundLastValues = [];
1423 this.expressionBoundProperties = [];
1424 this.propertyToOutputMap = {};
1425 }
1426}
1427/**
1428 * @description
1429 *
1430 * A helper class that allows an AngularJS component to be used from Angular.
1431 *
1432 * *Part of the [upgrade/static](api?query=upgrade%2Fstatic)
1433 * library for hybrid upgrade apps that support AOT compilation.*
1434 *
1435 * This helper class should be used as a base class for creating Angular directives
1436 * that wrap AngularJS components that need to be "upgraded".
1437 *
1438 * @usageNotes
1439 * ### Examples
1440 *
1441 * Let's assume that you have an AngularJS component called `ng1Hero` that needs
1442 * to be made available in Angular templates.
1443 *
1444 * {@example upgrade/static/ts/full/module.ts region="ng1-hero"}
1445 *
1446 * We must create a `Directive` that will make this AngularJS component
1447 * available inside Angular templates.
1448 *
1449 * {@example upgrade/static/ts/full/module.ts region="ng1-hero-wrapper"}
1450 *
1451 * In this example you can see that we must derive from the `UpgradeComponent`
1452 * base class but also provide an {@link Directive `@Directive`} decorator. This is
1453 * because the AOT compiler requires that this information is statically available at
1454 * compile time.
1455 *
1456 * Note that we must do the following:
1457 * * specify the directive's selector (`ng1-hero`)
1458 * * specify all inputs and outputs that the AngularJS component expects
1459 * * derive from `UpgradeComponent`
1460 * * call the base class from the constructor, passing
1461 * * the AngularJS name of the component (`ng1Hero`)
1462 * * the `ElementRef` and `Injector` for the component wrapper
1463 *
1464 * @publicApi
1465 * @extensible
1466 */
1467class UpgradeComponent {
1468 /**
1469 * Create a new `UpgradeComponent` instance. You should not normally need to do this.
1470 * Instead you should derive a new class from this one and call the super constructor
1471 * from the base class.
1472 *
1473 * {@example upgrade/static/ts/full/module.ts region="ng1-hero-wrapper" }
1474 *
1475 * * The `name` parameter should be the name of the AngularJS directive.
1476 * * The `elementRef` and `injector` parameters should be acquired from Angular by dependency
1477 * injection into the base class constructor.
1478 */
1479 constructor(name, elementRef, injector) {
1480 this.name = name;
1481 this.elementRef = elementRef;
1482 this.injector = injector;
1483 this.helper = new UpgradeHelper(injector, name, elementRef);
1484 this.$injector = this.helper.$injector;
1485 this.element = this.helper.element;
1486 this.$element = this.helper.$element;
1487 this.directive = this.helper.directive;
1488 this.bindings = this.initializeBindings(this.directive);
1489 // We ask for the AngularJS scope from the Angular injector, since
1490 // we will put the new component scope onto the new injector for each component
1491 const $parentScope = injector.get($SCOPE);
1492 // QUESTION 1: Should we create an isolated scope if the scope is only true?
1493 // QUESTION 2: Should we make the scope accessible through `$element.scope()/isolateScope()`?
1494 this.$componentScope = $parentScope.$new(!!this.directive.scope);
1495 this.initializeOutputs();
1496 }
1497 ngOnInit() {
1498 // Collect contents, insert and compile template
1499 const attachChildNodes = this.helper.prepareTransclusion();
1500 const linkFn = this.helper.compileTemplate();
1501 // Instantiate controller
1502 const controllerType = this.directive.controller;
1503 const bindToController = this.directive.bindToController;
1504 if (controllerType) {
1505 this.controllerInstance = this.helper.buildController(controllerType, this.$componentScope);
1506 }
1507 else if (bindToController) {
1508 throw new Error(`Upgraded directive '${this.directive.name}' specifies 'bindToController' but no controller.`);
1509 }
1510 // Set up outputs
1511 this.bindingDestination = bindToController ? this.controllerInstance : this.$componentScope;
1512 this.bindOutputs();
1513 // Require other controllers
1514 const requiredControllers = this.helper.resolveAndBindRequiredControllers(this.controllerInstance);
1515 // Hook: $onChanges
1516 if (this.pendingChanges) {
1517 this.forwardChanges(this.pendingChanges);
1518 this.pendingChanges = null;
1519 }
1520 // Hook: $onInit
1521 if (this.controllerInstance && isFunction(this.controllerInstance.$onInit)) {
1522 this.controllerInstance.$onInit();
1523 }
1524 // Hook: $doCheck
1525 if (this.controllerInstance && isFunction(this.controllerInstance.$doCheck)) {
1526 const callDoCheck = () => this.controllerInstance.$doCheck();
1527 this.unregisterDoCheckWatcher = this.$componentScope.$parent.$watch(callDoCheck);
1528 callDoCheck();
1529 }
1530 // Linking
1531 const link = this.directive.link;
1532 const preLink = typeof link == 'object' && link.pre;
1533 const postLink = typeof link == 'object' ? link.post : link;
1534 const attrs = NOT_SUPPORTED;
1535 const transcludeFn = NOT_SUPPORTED;
1536 if (preLink) {
1537 preLink(this.$componentScope, this.$element, attrs, requiredControllers, transcludeFn);
1538 }
1539 linkFn(this.$componentScope, null, { parentBoundTranscludeFn: attachChildNodes });
1540 if (postLink) {
1541 postLink(this.$componentScope, this.$element, attrs, requiredControllers, transcludeFn);
1542 }
1543 // Hook: $postLink
1544 if (this.controllerInstance && isFunction(this.controllerInstance.$postLink)) {
1545 this.controllerInstance.$postLink();
1546 }
1547 }
1548 ngOnChanges(changes) {
1549 if (!this.bindingDestination) {
1550 this.pendingChanges = changes;
1551 }
1552 else {
1553 this.forwardChanges(changes);
1554 }
1555 }
1556 ngDoCheck() {
1557 const twoWayBoundProperties = this.bindings.twoWayBoundProperties;
1558 const twoWayBoundLastValues = this.bindings.twoWayBoundLastValues;
1559 const propertyToOutputMap = this.bindings.propertyToOutputMap;
1560 twoWayBoundProperties.forEach((propName, idx) => {
1561 const newValue = this.bindingDestination[propName];
1562 const oldValue = twoWayBoundLastValues[idx];
1563 if (!Object.is(newValue, oldValue)) {
1564 const outputName = propertyToOutputMap[propName];
1565 const eventEmitter = this[outputName];
1566 eventEmitter.emit(newValue);
1567 twoWayBoundLastValues[idx] = newValue;
1568 }
1569 });
1570 }
1571 ngOnDestroy() {
1572 if (isFunction(this.unregisterDoCheckWatcher)) {
1573 this.unregisterDoCheckWatcher();
1574 }
1575 this.helper.onDestroy(this.$componentScope, this.controllerInstance);
1576 }
1577 initializeBindings(directive) {
1578 const btcIsObject = typeof directive.bindToController === 'object';
1579 if (btcIsObject && Object.keys(directive.scope).length) {
1580 throw new Error(`Binding definitions on scope and controller at the same time is not supported.`);
1581 }
1582 const context = btcIsObject ? directive.bindToController : directive.scope;
1583 const bindings = new Bindings();
1584 if (typeof context == 'object') {
1585 Object.keys(context).forEach(propName => {
1586 const definition = context[propName];
1587 const bindingType = definition.charAt(0);
1588 // QUESTION: What about `=*`? Ignore? Throw? Support?
1589 switch (bindingType) {
1590 case '@':
1591 case '<':
1592 // We don't need to do anything special. They will be defined as inputs on the
1593 // upgraded component facade and the change propagation will be handled by
1594 // `ngOnChanges()`.
1595 break;
1596 case '=':
1597 bindings.twoWayBoundProperties.push(propName);
1598 bindings.twoWayBoundLastValues.push(INITIAL_VALUE);
1599 bindings.propertyToOutputMap[propName] = propName + 'Change';
1600 break;
1601 case '&':
1602 bindings.expressionBoundProperties.push(propName);
1603 bindings.propertyToOutputMap[propName] = propName;
1604 break;
1605 default:
1606 let json = JSON.stringify(context);
1607 throw new Error(`Unexpected mapping '${bindingType}' in '${json}' in '${this.name}' directive.`);
1608 }
1609 });
1610 }
1611 return bindings;
1612 }
1613 initializeOutputs() {
1614 // Initialize the outputs for `=` and `&` bindings
1615 this.bindings.twoWayBoundProperties.concat(this.bindings.expressionBoundProperties)
1616 .forEach(propName => {
1617 const outputName = this.bindings.propertyToOutputMap[propName];
1618 this[outputName] = new EventEmitter();
1619 });
1620 }
1621 bindOutputs() {
1622 // Bind `&` bindings to the corresponding outputs
1623 this.bindings.expressionBoundProperties.forEach(propName => {
1624 const outputName = this.bindings.propertyToOutputMap[propName];
1625 const emitter = this[outputName];
1626 this.bindingDestination[propName] = (value) => emitter.emit(value);
1627 });
1628 }
1629 forwardChanges(changes) {
1630 // Forward input changes to `bindingDestination`
1631 Object.keys(changes).forEach(propName => this.bindingDestination[propName] = changes[propName].currentValue);
1632 if (isFunction(this.bindingDestination.$onChanges)) {
1633 this.bindingDestination.$onChanges(changes);
1634 }
1635 }
1636}
1637UpgradeComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.0.3", ngImport: i0, type: UpgradeComponent, deps: "invalid", target: i0.ɵɵFactoryTarget.Directive });
1638UpgradeComponent.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "14.0.3", type: UpgradeComponent, usesOnChanges: true, ngImport: i0 });
1639i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.3", ngImport: i0, type: UpgradeComponent, decorators: [{
1640 type: Directive
1641 }], ctorParameters: function () { return [{ type: undefined }, { type: i0.ElementRef }, { type: i0.Injector }]; } });
1642
1643/**
1644 * @license
1645 * Copyright Google LLC All Rights Reserved.
1646 *
1647 * Use of this source code is governed by an MIT-style license that can be
1648 * found in the LICENSE file at https://angular.io/license
1649 */
1650/**
1651 * @description
1652 *
1653 * An `NgModule`, which you import to provide AngularJS core services,
1654 * and has an instance method used to bootstrap the hybrid upgrade application.
1655 *
1656 * *Part of the [upgrade/static](api?query=upgrade/static)
1657 * library for hybrid upgrade apps that support AOT compilation*
1658 *
1659 * The `upgrade/static` package contains helpers that allow AngularJS and Angular components
1660 * to be used together inside a hybrid upgrade application, which supports AOT compilation.
1661 *
1662 * Specifically, the classes and functions in the `upgrade/static` module allow the following:
1663 *
1664 * 1. Creation of an Angular directive that wraps and exposes an AngularJS component so
1665 * that it can be used in an Angular template. See `UpgradeComponent`.
1666 * 2. Creation of an AngularJS directive that wraps and exposes an Angular component so
1667 * that it can be used in an AngularJS template. See `downgradeComponent`.
1668 * 3. Creation of an Angular root injector provider that wraps and exposes an AngularJS
1669 * service so that it can be injected into an Angular context. See
1670 * {@link UpgradeModule#upgrading-an-angular-1-service Upgrading an AngularJS service} below.
1671 * 4. Creation of an AngularJS service that wraps and exposes an Angular injectable
1672 * so that it can be injected into an AngularJS context. See `downgradeInjectable`.
1673 * 3. Bootstrapping of a hybrid Angular application which contains both of the frameworks
1674 * coexisting in a single application.
1675 *
1676 * @usageNotes
1677 *
1678 * ```ts
1679 * import {UpgradeModule} from '@angular/upgrade/static';
1680 * ```
1681 *
1682 * See also the {@link UpgradeModule#examples examples} below.
1683 *
1684 * ### Mental Model
1685 *
1686 * When reasoning about how a hybrid application works it is useful to have a mental model which
1687 * describes what is happening and explains what is happening at the lowest level.
1688 *
1689 * 1. There are two independent frameworks running in a single application, each framework treats
1690 * the other as a black box.
1691 * 2. Each DOM element on the page is owned exactly by one framework. Whichever framework
1692 * instantiated the element is the owner. Each framework only updates/interacts with its own
1693 * DOM elements and ignores others.
1694 * 3. AngularJS directives always execute inside the AngularJS framework codebase regardless of
1695 * where they are instantiated.
1696 * 4. Angular components always execute inside the Angular framework codebase regardless of
1697 * where they are instantiated.
1698 * 5. An AngularJS component can be "upgraded"" to an Angular component. This is achieved by
1699 * defining an Angular directive, which bootstraps the AngularJS component at its location
1700 * in the DOM. See `UpgradeComponent`.
1701 * 6. An Angular component can be "downgraded" to an AngularJS component. This is achieved by
1702 * defining an AngularJS directive, which bootstraps the Angular component at its location
1703 * in the DOM. See `downgradeComponent`.
1704 * 7. Whenever an "upgraded"/"downgraded" component is instantiated the host element is owned by
1705 * the framework doing the instantiation. The other framework then instantiates and owns the
1706 * view for that component.
1707 * 1. This implies that the component bindings will always follow the semantics of the
1708 * instantiation framework.
1709 * 2. The DOM attributes are parsed by the framework that owns the current template. So
1710 * attributes in AngularJS templates must use kebab-case, while AngularJS templates must use
1711 * camelCase.
1712 * 3. However the template binding syntax will always use the Angular style, e.g. square
1713 * brackets (`[...]`) for property binding.
1714 * 8. Angular is bootstrapped first; AngularJS is bootstrapped second. AngularJS always owns the
1715 * root component of the application.
1716 * 9. The new application is running in an Angular zone, and therefore it no longer needs calls to
1717 * `$apply()`.
1718 *
1719 * ### The `UpgradeModule` class
1720 *
1721 * This class is an `NgModule`, which you import to provide AngularJS core services,
1722 * and has an instance method used to bootstrap the hybrid upgrade application.
1723 *
1724 * * Core AngularJS services
1725 * Importing this `NgModule` will add providers for the core
1726 * [AngularJS services](https://docs.angularjs.org/api/ng/service) to the root injector.
1727 *
1728 * * Bootstrap
1729 * The runtime instance of this class contains a {@link UpgradeModule#bootstrap `bootstrap()`}
1730 * method, which you use to bootstrap the top level AngularJS module onto an element in the
1731 * DOM for the hybrid upgrade app.
1732 *
1733 * It also contains properties to access the {@link UpgradeModule#injector root injector}, the
1734 * bootstrap `NgZone` and the
1735 * [AngularJS $injector](https://docs.angularjs.org/api/auto/service/$injector).
1736 *
1737 * ### Examples
1738 *
1739 * Import the `UpgradeModule` into your top level {@link NgModule Angular `NgModule`}.
1740 *
1741 * {@example upgrade/static/ts/full/module.ts region='ng2-module'}
1742 *
1743 * Then inject `UpgradeModule` into your Angular `NgModule` and use it to bootstrap the top level
1744 * [AngularJS module](https://docs.angularjs.org/api/ng/type/angular.Module) in the
1745 * `ngDoBootstrap()` method.
1746 *
1747 * {@example upgrade/static/ts/full/module.ts region='bootstrap-ng1'}
1748 *
1749 * Finally, kick off the whole process, by bootstrapping your top level Angular `NgModule`.
1750 *
1751 * {@example upgrade/static/ts/full/module.ts region='bootstrap-ng2'}
1752 *
1753 * {@a upgrading-an-angular-1-service}
1754 * ### Upgrading an AngularJS service
1755 *
1756 * There is no specific API for upgrading an AngularJS service. Instead you should just follow the
1757 * following recipe:
1758 *
1759 * Let's say you have an AngularJS service:
1760 *
1761 * {@example upgrade/static/ts/full/module.ts region="ng1-text-formatter-service"}
1762 *
1763 * Then you should define an Angular provider to be included in your `NgModule` `providers`
1764 * property.
1765 *
1766 * {@example upgrade/static/ts/full/module.ts region="upgrade-ng1-service"}
1767 *
1768 * Then you can use the "upgraded" AngularJS service by injecting it into an Angular component
1769 * or service.
1770 *
1771 * {@example upgrade/static/ts/full/module.ts region="use-ng1-upgraded-service"}
1772 *
1773 * @publicApi
1774 */
1775class UpgradeModule {
1776 constructor(
1777 /** The root `Injector` for the upgrade application. */
1778 injector,
1779 /** The bootstrap zone for the upgrade application */
1780 ngZone,
1781 /**
1782 * The owning `NgModuleRef`s `PlatformRef` instance.
1783 * This is used to tie the lifecycle of the bootstrapped AngularJS apps to that of the Angular
1784 * `PlatformRef`.
1785 */
1786 platformRef) {
1787 this.ngZone = ngZone;
1788 this.platformRef = platformRef;
1789 this.injector = new NgAdapterInjector(injector);
1790 }
1791 /**
1792 * Bootstrap an AngularJS application from this NgModule
1793 * @param element the element on which to bootstrap the AngularJS application
1794 * @param [modules] the AngularJS modules to bootstrap for this application
1795 * @param [config] optional extra AngularJS bootstrap configuration
1796 */
1797 bootstrap(element$1, modules = [], config /*angular.IAngularBootstrapConfig*/) {
1798 const INIT_MODULE_NAME = UPGRADE_MODULE_NAME + '.init';
1799 // Create an ng1 module to bootstrap
1800 module_(INIT_MODULE_NAME, [])
1801 .constant(UPGRADE_APP_TYPE_KEY, 2 /* UpgradeAppType.Static */)
1802 .value(INJECTOR_KEY, this.injector)
1803 .factory(LAZY_MODULE_REF, [INJECTOR_KEY, (injector) => ({ injector })])
1804 .config([
1805 $PROVIDE, $INJECTOR,
1806 ($provide, $injector) => {
1807 if ($injector.has($$TESTABILITY)) {
1808 $provide.decorator($$TESTABILITY, [
1809 $DELEGATE,
1810 (testabilityDelegate) => {
1811 const originalWhenStable = testabilityDelegate.whenStable;
1812 const injector = this.injector;
1813 // Cannot use arrow function below because we need the context
1814 const newWhenStable = function (callback) {
1815 originalWhenStable.call(testabilityDelegate, function () {
1816 const ng2Testability = injector.get(Testability);
1817 if (ng2Testability.isStable()) {
1818 callback();
1819 }
1820 else {
1821 ng2Testability.whenStable(newWhenStable.bind(testabilityDelegate, callback));
1822 }
1823 });
1824 };
1825 testabilityDelegate.whenStable = newWhenStable;
1826 return testabilityDelegate;
1827 }
1828 ]);
1829 }
1830 if ($injector.has($INTERVAL)) {
1831 $provide.decorator($INTERVAL, [
1832 $DELEGATE,
1833 (intervalDelegate) => {
1834 // Wrap the $interval service so that setInterval is called outside NgZone,
1835 // but the callback is still invoked within it. This is so that $interval
1836 // won't block stability, which preserves the behavior from AngularJS.
1837 let wrappedInterval = (fn, delay, count, invokeApply, ...pass) => {
1838 return this.ngZone.runOutsideAngular(() => {
1839 return intervalDelegate((...args) => {
1840 // Run callback in the next VM turn - $interval calls
1841 // $rootScope.$apply, and running the callback in NgZone will
1842 // cause a '$digest already in progress' error if it's in the
1843 // same vm turn.
1844 setTimeout(() => {
1845 this.ngZone.run(() => fn(...args));
1846 });
1847 }, delay, count, invokeApply, ...pass);
1848 });
1849 };
1850 Object.keys(intervalDelegate)
1851 .forEach(prop => wrappedInterval[prop] = intervalDelegate[prop]);
1852 // the `flush` method will be present when ngMocks is used
1853 if (intervalDelegate.hasOwnProperty('flush')) {
1854 wrappedInterval['flush'] = () => {
1855 intervalDelegate['flush']();
1856 return wrappedInterval;
1857 };
1858 }
1859 return wrappedInterval;
1860 }
1861 ]);
1862 }
1863 }
1864 ])
1865 .run([
1866 $INJECTOR,
1867 ($injector) => {
1868 this.$injector = $injector;
1869 const $rootScope = $injector.get('$rootScope');
1870 // Initialize the ng1 $injector provider
1871 setTempInjectorRef($injector);
1872 this.injector.get($INJECTOR);
1873 // Put the injector on the DOM, so that it can be "required"
1874 element(element$1).data(controllerKey(INJECTOR_KEY), this.injector);
1875 // Destroy the AngularJS app once the Angular `PlatformRef` is destroyed.
1876 // This does not happen in a typical SPA scenario, but it might be useful for
1877 // other use-cases where disposing of an Angular/AngularJS app is necessary
1878 // (such as Hot Module Replacement (HMR)).
1879 // See https://github.com/angular/angular/issues/39935.
1880 this.platformRef.onDestroy(() => destroyApp($injector));
1881 // Wire up the ng1 rootScope to run a digest cycle whenever the zone settles
1882 // We need to do this in the next tick so that we don't prevent the bootup stabilizing
1883 setTimeout(() => {
1884 const subscription = this.ngZone.onMicrotaskEmpty.subscribe(() => {
1885 if ($rootScope.$$phase) {
1886 if (typeof ngDevMode === 'undefined' || ngDevMode) {
1887 console.warn('A digest was triggered while one was already in progress. This may mean that something is triggering digests outside the Angular zone.');
1888 }
1889 return $rootScope.$evalAsync();
1890 }
1891 return $rootScope.$digest();
1892 });
1893 $rootScope.$on('$destroy', () => {
1894 subscription.unsubscribe();
1895 });
1896 }, 0);
1897 }
1898 ]);
1899 const upgradeModule = module_(UPGRADE_MODULE_NAME, [INIT_MODULE_NAME].concat(modules));
1900 // Make sure resumeBootstrap() only exists if the current bootstrap is deferred
1901 const windowAngular = window['angular'];
1902 windowAngular.resumeBootstrap = undefined;
1903 // Bootstrap the AngularJS application inside our zone
1904 this.ngZone.run(() => {
1905 bootstrap(element$1, [upgradeModule.name], config);
1906 });
1907 // Patch resumeBootstrap() to run inside the ngZone
1908 if (windowAngular.resumeBootstrap) {
1909 const originalResumeBootstrap = windowAngular.resumeBootstrap;
1910 const ngZone = this.ngZone;
1911 windowAngular.resumeBootstrap = function () {
1912 let args = arguments;
1913 windowAngular.resumeBootstrap = originalResumeBootstrap;
1914 return ngZone.run(() => windowAngular.resumeBootstrap.apply(this, args));
1915 };
1916 }
1917 }
1918}
1919UpgradeModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.0.3", ngImport: i0, type: UpgradeModule, deps: [{ token: i0.Injector }, { token: i0.NgZone }, { token: i0.PlatformRef }], target: i0.ɵɵFactoryTarget.NgModule });
1920UpgradeModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "14.0.3", ngImport: i0, type: UpgradeModule });
1921UpgradeModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "14.0.3", ngImport: i0, type: UpgradeModule, providers: [angular1Providers] });
1922i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.3", ngImport: i0, type: UpgradeModule, decorators: [{
1923 type: NgModule,
1924 args: [{ providers: [angular1Providers] }]
1925 }], ctorParameters: function () { return [{ type: i0.Injector }, { type: i0.NgZone }, { type: i0.PlatformRef }]; } });
1926
1927/**
1928 * @license
1929 * Copyright Google LLC All Rights Reserved.
1930 *
1931 * Use of this source code is governed by an MIT-style license that can be
1932 * found in the LICENSE file at https://angular.io/license
1933 */
1934// This file only re-exports items to appear in the public api. Keep it that way.
1935
1936/**
1937 * @license
1938 * Copyright Google LLC All Rights Reserved.
1939 *
1940 * Use of this source code is governed by an MIT-style license that can be
1941 * found in the LICENSE file at https://angular.io/license
1942 */
1943
1944/**
1945 * Generated bundle index. Do not edit.
1946 */
1947
1948export { UpgradeComponent, UpgradeModule, VERSION, downgradeComponent, downgradeInjectable, downgradeModule, getAngularJSGlobal, getAngularLib, setAngularJSGlobal, setAngularLib };
1949//# sourceMappingURL=static.mjs.map