mirror of
https://github.com/ionic-team/ionic-framework.git
synced 2025-08-16 01:52:19 +08:00
feat(angular): build for angular 12.0 (#23970)
This commit is contained in:
@ -101,7 +101,7 @@ jobs:
|
||||
- attach_workspace:
|
||||
at: /tmp/workspace
|
||||
- run:
|
||||
command: npm install --legacy-peer-deps
|
||||
command: npm ci
|
||||
working_directory: /tmp/workspace/angular
|
||||
- run:
|
||||
command: sudo npm link
|
||||
@ -125,7 +125,7 @@ jobs:
|
||||
- attach_workspace:
|
||||
at: /tmp/workspace
|
||||
- run:
|
||||
command: npm install --legacy-peer-deps
|
||||
command: npm ci
|
||||
working_directory: /tmp/workspace/packages/angular-server
|
||||
- run:
|
||||
command: npm run build.prod
|
||||
@ -433,7 +433,7 @@ jobs:
|
||||
- attach_workspace:
|
||||
at: /tmp/workspace
|
||||
- run:
|
||||
command: npm install --legacy-peer-deps
|
||||
command: npm ci
|
||||
working_directory: /tmp/workspace/angular/test/test-app
|
||||
- run:
|
||||
command: npm run test
|
||||
|
4
angular/.eslintignore
Normal file
4
angular/.eslintignore
Normal file
@ -0,0 +1,4 @@
|
||||
dist
|
||||
virtual-scroll
|
||||
scripts
|
||||
proxies.ts
|
30
angular/.eslintrc.json
Normal file
30
angular/.eslintrc.json
Normal file
@ -0,0 +1,30 @@
|
||||
{
|
||||
"root": true,
|
||||
"ignorePatterns": ["test/**/*", "src/directives/virtual-scroll/**/*"],
|
||||
"overrides": [
|
||||
{
|
||||
"files": ["*.ts"],
|
||||
"parserOptions": {
|
||||
"project": ["tsconfig.json"],
|
||||
"createDefaultProgram": true
|
||||
},
|
||||
"extends": [
|
||||
"@ionic/eslint-config/recommended",
|
||||
"plugin:@angular-eslint/recommended",
|
||||
"plugin:@angular-eslint/template/process-inline-templates"
|
||||
],
|
||||
"rules": {
|
||||
"@typescript-eslint/consistent-type-imports": "off",
|
||||
"@angular-eslint/component-class-suffix": "off",
|
||||
"@angular-eslint/component-selector": [
|
||||
"error",
|
||||
{
|
||||
"type": "element",
|
||||
"prefix": "ion",
|
||||
"style": "kebab-case"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
6
angular/.prettierignore
Normal file
6
angular/.prettierignore
Normal file
@ -0,0 +1,6 @@
|
||||
dist
|
||||
virtual-scroll
|
||||
scripts
|
||||
test
|
||||
src/directives/proxies.ts
|
||||
src/directives/angular-component-lib/utils.ts
|
15834
angular/package-lock.json
generated
15834
angular/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -26,16 +26,14 @@
|
||||
"scripts": {
|
||||
"build": "npm run clean && npm run build.ng && npm run build.core && npm run clean-generated",
|
||||
"build.core": "node scripts/build-core.js",
|
||||
"build.fesm": "rollup --config ./scripts/rollup.config.js",
|
||||
"build.link": "npm run build && node scripts/link-copy.js",
|
||||
"build.ng": "ng-packagr -p package.json",
|
||||
"build.es2015": "ngc -p tsconfig.json && rollup --config ./scripts/rollup.config.js",
|
||||
"build.es5": "ngc -p tsconfig.legacy.json && rollup --config ./scripts/rollup.config.legacy.js",
|
||||
"build.ng": "ng-packagr -p package.json -c tsconfig.json",
|
||||
"clean": "node scripts/clean.js",
|
||||
"clean-generated": "node ./scripts/clean-generated.js",
|
||||
"lint": "npm run lint.ts",
|
||||
"lint.ts": "tslint --project .",
|
||||
"lint.fix": "tslint --project . --fix",
|
||||
"lint": "npm run eslint && npm run prettier -- --check",
|
||||
"fmt": "npm run eslint -- --fix && npm run prettier -- --write",
|
||||
"prettier": "prettier \"**/*.ts\"",
|
||||
"eslint": "eslint . --ext .ts",
|
||||
"prerelease": "npm run validate && np prerelease --yolo --any-branch --tag next",
|
||||
"test": "echo 'angular no tests yet'",
|
||||
"tsc": "tsc -p .",
|
||||
@ -43,44 +41,53 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@ionic/core": "6.0.0-rc.0",
|
||||
"tslib": "^1.9.3"
|
||||
"jsonc-parser": "^3.0.0",
|
||||
"tslib": "^2.0.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@angular/core": ">=8.2.7",
|
||||
"@angular/forms": ">=8.2.7",
|
||||
"@angular/router": ">=8.2.7",
|
||||
"rxjs": ">=6.2.0",
|
||||
"zone.js": ">=0.8.26"
|
||||
"@angular/core": ">=12.0.0",
|
||||
"@angular/forms": ">=12.0.0",
|
||||
"@angular/router": ">=12.0.0",
|
||||
"rxjs": ">=6.6.0",
|
||||
"zone.js": ">=0.11.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@angular-devkit/core": "8.3.17",
|
||||
"@angular-devkit/schematics": "8.3.17",
|
||||
"@angular/common": "8.2.13",
|
||||
"@angular/compiler": "8.2.13",
|
||||
"@angular/compiler-cli": "8.2.13",
|
||||
"@angular/core": "8.2.13",
|
||||
"@angular/forms": "8.2.13",
|
||||
"@angular/router": "8.2.13",
|
||||
"@angular-devkit/core": "^12.0.0",
|
||||
"@angular-devkit/schematics": "^12.0.0",
|
||||
"@angular-eslint/eslint-plugin": "^12.5.0",
|
||||
"@angular-eslint/eslint-plugin-template": "^12.5.0",
|
||||
"@angular-eslint/template-parser": "^12.5.0",
|
||||
"@angular/common": "^12.0.0",
|
||||
"@angular/compiler": "^12.0.0",
|
||||
"@angular/compiler-cli": "^12.0.0",
|
||||
"@angular/core": "^12.0.0",
|
||||
"@angular/forms": "^12.0.0",
|
||||
"@angular/router": "^12.0.0",
|
||||
"@ionic/eslint-config": "^0.3.0",
|
||||
"@ionic/prettier-config": "^2.0.0",
|
||||
"@schematics/angular": "^12.2.9",
|
||||
"@types/node": "12.12.5",
|
||||
"@typescript-eslint/eslint-plugin": "^4.32.0",
|
||||
"@typescript-eslint/parser": "^4.32.0",
|
||||
"eslint": "^7.32.0",
|
||||
"eslint-plugin-import": "^2.25.2",
|
||||
"fs-extra": "^7.0.0",
|
||||
"glob": "^7.1.4",
|
||||
"ng-packagr": "^9.1.5",
|
||||
"rollup": "~1.17.0",
|
||||
"rollup-plugin-node-resolve": "~5.2.0",
|
||||
"ng-packagr": "^12.0.0",
|
||||
"prettier": "^2.4.1",
|
||||
"rxjs": "^6.6.2",
|
||||
"tsickle": "^0.39.1",
|
||||
"tslint": "^5.12.1",
|
||||
"tslint-ionic-rules": "0.0.21",
|
||||
"typescript": "3.4.5",
|
||||
"zone.js": "^0.11.1"
|
||||
"typescript": "4.2.4",
|
||||
"typescript-eslint-language-service": "^4.1.5",
|
||||
"zone.js": "~0.11.4"
|
||||
},
|
||||
"prettier": "@ionic/prettier-config",
|
||||
"schematics": "./schematics/collection.json",
|
||||
"ngPackage": {
|
||||
"lib": {
|
||||
"entryFile": "src/index.ts"
|
||||
},
|
||||
"whitelistedNonPeerDependencies": [
|
||||
"@ionic/core"
|
||||
"allowedNonPeerDependencies": [
|
||||
"@ionic/core",
|
||||
"jsonc-parser"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
@ -10,15 +10,13 @@ export const appInitialize = (config: Config, doc: Document, zone: NgZone) => {
|
||||
return (): any => {
|
||||
const win: IonicWindow | undefined = doc.defaultView as any;
|
||||
if (win && typeof (window as any) !== 'undefined') {
|
||||
|
||||
setupConfig({
|
||||
...config,
|
||||
_zoneGate: (h: any) => zone.run(h)
|
||||
_zoneGate: (h: any) => zone.run(h),
|
||||
});
|
||||
|
||||
const aelFn = '__zone_symbol__addEventListener' in (doc.body as any)
|
||||
? '__zone_symbol__addEventListener'
|
||||
: 'addEventListener';
|
||||
const aelFn =
|
||||
'__zone_symbol__addEventListener' in (doc.body as any) ? '__zone_symbol__addEventListener' : 'addEventListener';
|
||||
|
||||
return applyPolyfills().then(() => {
|
||||
return defineCustomElements(win, {
|
||||
@ -31,7 +29,7 @@ export const appInitialize = (config: Config, doc: Document, zone: NgZone) => {
|
||||
},
|
||||
rel(elm, eventName, cb, opts) {
|
||||
elm.removeEventListener(eventName, cb, opts);
|
||||
}
|
||||
},
|
||||
});
|
||||
});
|
||||
}
|
||||
|
@ -1,32 +1,30 @@
|
||||
import { Directive, ElementRef, HostListener, Injector } from '@angular/core';
|
||||
import { Directive, HostListener, ElementRef, Injector } from '@angular/core';
|
||||
import { NG_VALUE_ACCESSOR } from '@angular/forms';
|
||||
|
||||
import { ValueAccessor, setIonicClasses } from './value-accessor';
|
||||
|
||||
@Directive({
|
||||
/* tslint:disable-next-line:directive-selector */
|
||||
selector: 'ion-checkbox,ion-toggle',
|
||||
providers: [
|
||||
{
|
||||
provide: NG_VALUE_ACCESSOR,
|
||||
useExisting: BooleanValueAccessor,
|
||||
multi: true
|
||||
}
|
||||
]
|
||||
useExisting: BooleanValueAccessorDirective,
|
||||
multi: true,
|
||||
},
|
||||
],
|
||||
})
|
||||
export class BooleanValueAccessor extends ValueAccessor {
|
||||
|
||||
export class BooleanValueAccessorDirective extends ValueAccessor {
|
||||
constructor(injector: Injector, el: ElementRef) {
|
||||
super(injector, el);
|
||||
}
|
||||
|
||||
writeValue(value: any) {
|
||||
writeValue(value: any): void {
|
||||
this.el.nativeElement.checked = this.lastValue = value == null ? false : value;
|
||||
setIonicClasses(this.el);
|
||||
}
|
||||
|
||||
@HostListener('ionChange', ['$event.target'])
|
||||
_handleIonChange(el: any) {
|
||||
_handleIonChange(el: any): void {
|
||||
this.handleChangeEvent(el, el.checked);
|
||||
}
|
||||
}
|
||||
|
@ -1,32 +1,30 @@
|
||||
import { Directive, ElementRef, HostListener, Injector } from '@angular/core';
|
||||
import { Directive, HostListener, ElementRef, Injector } from '@angular/core';
|
||||
import { NG_VALUE_ACCESSOR } from '@angular/forms';
|
||||
|
||||
import { ValueAccessor } from './value-accessor';
|
||||
|
||||
@Directive({
|
||||
/* tslint:disable-next-line:directive-selector */
|
||||
selector: 'ion-input[type=number]',
|
||||
providers: [
|
||||
{
|
||||
provide: NG_VALUE_ACCESSOR,
|
||||
useExisting: NumericValueAccessor,
|
||||
multi: true
|
||||
}
|
||||
]
|
||||
useExisting: NumericValueAccessorDirective,
|
||||
multi: true,
|
||||
},
|
||||
],
|
||||
})
|
||||
export class NumericValueAccessor extends ValueAccessor {
|
||||
|
||||
export class NumericValueAccessorDirective extends ValueAccessor {
|
||||
constructor(injector: Injector, el: ElementRef) {
|
||||
super(injector, el);
|
||||
}
|
||||
|
||||
@HostListener('ionChange', ['$event.target'])
|
||||
_handleIonChange(el: any) {
|
||||
_handleIonChange(el: any): void {
|
||||
this.handleChangeEvent(el, el.value);
|
||||
}
|
||||
|
||||
registerOnChange(fn: (_: number | null) => void) {
|
||||
super.registerOnChange(value => {
|
||||
registerOnChange(fn: (_: number | null) => void): void {
|
||||
super.registerOnChange((value) => {
|
||||
fn(value === '' ? null : parseFloat(value));
|
||||
});
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { Directive, ElementRef, HostListener, Injector } from '@angular/core';
|
||||
import { ElementRef, Injector, Directive, HostListener } from '@angular/core';
|
||||
import { NG_VALUE_ACCESSOR } from '@angular/forms';
|
||||
|
||||
import { ValueAccessor } from './value-accessor';
|
||||
@ -9,19 +9,18 @@ import { ValueAccessor } from './value-accessor';
|
||||
providers: [
|
||||
{
|
||||
provide: NG_VALUE_ACCESSOR,
|
||||
useExisting: RadioValueAccessor,
|
||||
multi: true
|
||||
}
|
||||
]
|
||||
useExisting: RadioValueAccessorDirective,
|
||||
multi: true,
|
||||
},
|
||||
],
|
||||
})
|
||||
export class RadioValueAccessor extends ValueAccessor {
|
||||
|
||||
export class RadioValueAccessorDirective extends ValueAccessor {
|
||||
constructor(injector: Injector, el: ElementRef) {
|
||||
super(injector, el);
|
||||
}
|
||||
|
||||
@HostListener('ionSelect', ['$event.target'])
|
||||
_handleIonSelect(el: any) {
|
||||
_handleIonSelect(el: any): void {
|
||||
this.handleChangeEvent(el, el.checked);
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { Directive, ElementRef, HostListener, Injector } from '@angular/core';
|
||||
import { ElementRef, Injector, Directive, HostListener } from '@angular/core';
|
||||
import { NG_VALUE_ACCESSOR } from '@angular/forms';
|
||||
|
||||
import { ValueAccessor } from './value-accessor';
|
||||
@ -9,19 +9,18 @@ import { ValueAccessor } from './value-accessor';
|
||||
providers: [
|
||||
{
|
||||
provide: NG_VALUE_ACCESSOR,
|
||||
useExisting: SelectValueAccessor,
|
||||
multi: true
|
||||
}
|
||||
]
|
||||
useExisting: SelectValueAccessorDirective,
|
||||
multi: true,
|
||||
},
|
||||
],
|
||||
})
|
||||
export class SelectValueAccessor extends ValueAccessor {
|
||||
|
||||
export class SelectValueAccessorDirective extends ValueAccessor {
|
||||
constructor(injector: Injector, el: ElementRef) {
|
||||
super(injector, el);
|
||||
}
|
||||
|
||||
@HostListener('ionChange', ['$event.target'])
|
||||
_handleChangeEvent(el: any) {
|
||||
_handleChangeEvent(el: any): void {
|
||||
this.handleChangeEvent(el, el.value);
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { Directive, ElementRef, HostListener, Injector } from '@angular/core';
|
||||
import { ElementRef, Injector, Directive, HostListener } from '@angular/core';
|
||||
import { NG_VALUE_ACCESSOR } from '@angular/forms';
|
||||
|
||||
import { ValueAccessor } from './value-accessor';
|
||||
@ -9,19 +9,18 @@ import { ValueAccessor } from './value-accessor';
|
||||
providers: [
|
||||
{
|
||||
provide: NG_VALUE_ACCESSOR,
|
||||
useExisting: TextValueAccessor,
|
||||
multi: true
|
||||
}
|
||||
]
|
||||
useExisting: TextValueAccessorDirective,
|
||||
multi: true,
|
||||
},
|
||||
],
|
||||
})
|
||||
export class TextValueAccessor extends ValueAccessor {
|
||||
|
||||
export class TextValueAccessorDirective extends ValueAccessor {
|
||||
constructor(injector: Injector, el: ElementRef) {
|
||||
super(injector, el);
|
||||
}
|
||||
|
||||
@HostListener('ionChange', ['$event.target'])
|
||||
_handleInputEvent(el: any) {
|
||||
_handleInputEvent(el: any): void {
|
||||
this.handleChangeEvent(el, el.value);
|
||||
}
|
||||
}
|
||||
|
@ -1,19 +1,23 @@
|
||||
import { AfterViewInit, ElementRef, HostListener, Injector, OnDestroy, Type } from '@angular/core';
|
||||
import { AfterViewInit, ElementRef, Injector, OnDestroy, Directive, HostListener } from '@angular/core';
|
||||
import { ControlValueAccessor, NgControl } from '@angular/forms';
|
||||
import { Subscription } from 'rxjs';
|
||||
|
||||
import { raf } from '../../util/util';
|
||||
|
||||
@Directive()
|
||||
export class ValueAccessor implements ControlValueAccessor, AfterViewInit, OnDestroy {
|
||||
|
||||
private onChange: (value: any) => void = () => {/**/};
|
||||
private onTouched: () => void = () => {/**/};
|
||||
private onChange: (value: any) => void = () => {
|
||||
/**/
|
||||
};
|
||||
private onTouched: () => void = () => {
|
||||
/**/
|
||||
};
|
||||
protected lastValue: any;
|
||||
private statusChanges?: Subscription;
|
||||
|
||||
constructor(protected injector: Injector, protected el: ElementRef) {}
|
||||
|
||||
writeValue(value: any) {
|
||||
writeValue(value: any): void {
|
||||
/**
|
||||
* TODO for Ionic 6:
|
||||
* Change `value == null ? '' : value;`
|
||||
@ -25,7 +29,7 @@ export class ValueAccessor implements ControlValueAccessor, AfterViewInit, OnDes
|
||||
setIonicClasses(this.el);
|
||||
}
|
||||
|
||||
handleChangeEvent(el: HTMLElement, value: any) {
|
||||
handleChangeEvent(el: HTMLElement, value: any): void {
|
||||
if (el === this.el.nativeElement) {
|
||||
if (value !== this.lastValue) {
|
||||
this.lastValue = value;
|
||||
@ -36,38 +40,42 @@ export class ValueAccessor implements ControlValueAccessor, AfterViewInit, OnDes
|
||||
}
|
||||
|
||||
@HostListener('ionBlur', ['$event.target'])
|
||||
_handleBlurEvent(el: any) {
|
||||
_handleBlurEvent(el: any): void {
|
||||
if (el === this.el.nativeElement) {
|
||||
this.onTouched();
|
||||
setIonicClasses(this.el);
|
||||
}
|
||||
}
|
||||
|
||||
registerOnChange(fn: (value: any) => void) {
|
||||
registerOnChange(fn: (value: any) => void): void {
|
||||
this.onChange = fn;
|
||||
}
|
||||
|
||||
registerOnTouched(fn: () => void) {
|
||||
registerOnTouched(fn: () => void): void {
|
||||
this.onTouched = fn;
|
||||
}
|
||||
|
||||
setDisabledState(isDisabled: boolean) {
|
||||
setDisabledState(isDisabled: boolean): void {
|
||||
this.el.nativeElement.disabled = isDisabled;
|
||||
}
|
||||
|
||||
ngOnDestroy() {
|
||||
ngOnDestroy(): void {
|
||||
if (this.statusChanges) {
|
||||
this.statusChanges.unsubscribe();
|
||||
}
|
||||
}
|
||||
|
||||
ngAfterViewInit() {
|
||||
ngAfterViewInit(): void {
|
||||
let ngControl;
|
||||
try {
|
||||
ngControl = this.injector.get<NgControl>(NgControl as Type<NgControl>);
|
||||
} catch { /* No FormControl or ngModel binding */ }
|
||||
ngControl = this.injector.get<NgControl>(NgControl);
|
||||
} catch {
|
||||
/* No FormControl or ngModel binding */
|
||||
}
|
||||
|
||||
if (!ngControl) { return; }
|
||||
if (!ngControl) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Listen for changes in validity, disabled, or pending states
|
||||
if (ngControl.statusChanges) {
|
||||
@ -84,13 +92,13 @@ export class ValueAccessor implements ControlValueAccessor, AfterViewInit, OnDes
|
||||
* This patches the methods to manually sync
|
||||
* the classes until this feature is implemented in Angular.
|
||||
*/
|
||||
const formControl = ngControl.control;
|
||||
const formControl = ngControl.control as any;
|
||||
if (formControl) {
|
||||
const methodsToPatch = ['markAsTouched', 'markAllAsTouched', 'markAsUntouched', 'markAsDirty', 'markAsPristine'];
|
||||
methodsToPatch.forEach(method => {
|
||||
if (formControl[method]) {
|
||||
methodsToPatch.forEach((method) => {
|
||||
if (formControl.get(method)) {
|
||||
const oldFn = formControl[method].bind(formControl);
|
||||
formControl[method] = (...params) => {
|
||||
formControl[method] = (...params: any[]) => {
|
||||
oldFn(...params);
|
||||
setIonicClasses(this.el);
|
||||
};
|
||||
@ -100,7 +108,7 @@ export class ValueAccessor implements ControlValueAccessor, AfterViewInit, OnDes
|
||||
}
|
||||
}
|
||||
|
||||
export const setIonicClasses = (element: ElementRef) => {
|
||||
export const setIonicClasses = (element: ElementRef): void => {
|
||||
raf(() => {
|
||||
const input = element.nativeElement as HTMLElement;
|
||||
const classes = getClasses(input);
|
||||
@ -127,16 +135,11 @@ const getClasses = (element: HTMLElement) => {
|
||||
|
||||
const setClasses = (element: HTMLElement, classes: string[]) => {
|
||||
const classList = element.classList;
|
||||
[
|
||||
'ion-valid',
|
||||
'ion-invalid',
|
||||
'ion-touched',
|
||||
'ion-untouched',
|
||||
'ion-dirty',
|
||||
'ion-pristine'
|
||||
].forEach(c => classList.remove(c));
|
||||
['ion-valid', 'ion-invalid', 'ion-touched', 'ion-untouched', 'ion-dirty', 'ion-pristine'].forEach((c) =>
|
||||
classList.remove(c)
|
||||
);
|
||||
|
||||
classes.forEach(c => classList.add(c));
|
||||
classes.forEach((c) => classList.add(c));
|
||||
};
|
||||
|
||||
const startsWith = (input: string, search: string): boolean => {
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { Directive, HostListener, Optional } from '@angular/core';
|
||||
import { Directive, HostListener, Input, Optional } from '@angular/core';
|
||||
import { AnimationBuilder } from '@ionic/core';
|
||||
|
||||
import { Config } from '../../providers/config';
|
||||
@ -8,11 +8,12 @@ import { IonRouterOutlet } from './ion-router-outlet';
|
||||
|
||||
@Directive({
|
||||
selector: 'ion-back-button',
|
||||
inputs: ['defaultHref', 'routerAnimation'],
|
||||
})
|
||||
export class IonBackButtonDelegate {
|
||||
|
||||
export class IonBackButtonDelegateDirective {
|
||||
@Input()
|
||||
defaultHref: string | undefined | null;
|
||||
|
||||
@Input()
|
||||
routerAnimation?: AnimationBuilder;
|
||||
|
||||
constructor(
|
||||
@ -25,10 +26,10 @@ export class IonBackButtonDelegate {
|
||||
* @internal
|
||||
*/
|
||||
@HostListener('click', ['$event'])
|
||||
onClick(ev: Event) {
|
||||
onClick(ev: Event): void {
|
||||
const defaultHref = this.defaultHref || this.config.get('backButtonDefaultHref');
|
||||
|
||||
if (this.routerOutlet && this.routerOutlet.canGoBack()) {
|
||||
if (this.routerOutlet?.canGoBack()) {
|
||||
this.navCtrl.setDirection('back', undefined, undefined, this.routerAnimation);
|
||||
this.routerOutlet.pop();
|
||||
ev.preventDefault();
|
||||
|
@ -1,11 +1,26 @@
|
||||
import { Location } from '@angular/common';
|
||||
import { Attribute, ComponentFactoryResolver, ComponentRef, Directive, ElementRef, EventEmitter, Injector, NgZone, OnDestroy, OnInit, Optional, Output, SkipSelf, ViewContainerRef } from '@angular/core';
|
||||
import { ActivatedRoute, ChildrenOutletContexts, OutletContext, PRIMARY_OUTLET, Router } from '@angular/router';
|
||||
import {
|
||||
ComponentFactoryResolver,
|
||||
ComponentRef,
|
||||
ElementRef,
|
||||
Injector,
|
||||
NgZone,
|
||||
OnDestroy,
|
||||
OnInit,
|
||||
ViewContainerRef,
|
||||
Attribute,
|
||||
Directive,
|
||||
EventEmitter,
|
||||
Optional,
|
||||
Output,
|
||||
SkipSelf,
|
||||
} from '@angular/core';
|
||||
import { OutletContext, Router, ActivatedRoute, ChildrenOutletContexts, PRIMARY_OUTLET } from '@angular/router';
|
||||
import { componentOnReady } from '@ionic/core';
|
||||
import { BehaviorSubject, Observable } from 'rxjs';
|
||||
import { Observable, BehaviorSubject } from 'rxjs';
|
||||
import { distinctUntilChanged, filter, switchMap } from 'rxjs/operators';
|
||||
|
||||
import { AnimationBuilder } from '../../';
|
||||
import { AnimationBuilder } from '../../ionic-core';
|
||||
import { Config } from '../../providers/config';
|
||||
import { NavController } from '../../providers/nav-controller';
|
||||
|
||||
@ -15,8 +30,10 @@ import { RouteView, getUrl } from './stack-utils';
|
||||
@Directive({
|
||||
selector: 'ion-router-outlet',
|
||||
exportAs: 'outlet',
|
||||
inputs: ['animated', 'animation', 'swipeGesture']
|
||||
// eslint-disable-next-line @angular-eslint/no-inputs-metadata-property
|
||||
inputs: ['animated', 'animation', 'swipeGesture'],
|
||||
})
|
||||
// eslint-disable-next-line @angular-eslint/directive-class-suffix
|
||||
export class IonRouterOutlet implements OnDestroy, OnInit {
|
||||
nativeEl: HTMLIonRouterOutletElement;
|
||||
|
||||
@ -37,7 +54,9 @@ export class IonRouterOutlet implements OnDestroy, OnInit {
|
||||
tabsPrefix: string | undefined;
|
||||
|
||||
@Output() stackEvents = new EventEmitter<any>();
|
||||
// eslint-disable-next-line @angular-eslint/no-output-rename
|
||||
@Output('activate') activateEvents = new EventEmitter<any>();
|
||||
// eslint-disable-next-line @angular-eslint/no-output-rename
|
||||
@Output('deactivate') deactivateEvents = new EventEmitter<any>();
|
||||
|
||||
set animation(animation: AnimationBuilder) {
|
||||
@ -51,11 +70,13 @@ export class IonRouterOutlet implements OnDestroy, OnInit {
|
||||
set swipeGesture(swipe: boolean) {
|
||||
this._swipeGesture = swipe;
|
||||
|
||||
this.nativeEl.swipeHandler = swipe ? {
|
||||
this.nativeEl.swipeHandler = swipe
|
||||
? {
|
||||
canStart: () => this.stackCtrl.canGoBack(1) && !this.stackCtrl.hasRunningTask(),
|
||||
onStart: () => this.stackCtrl.startBackTransition(),
|
||||
onEnd: shouldContinue => this.stackCtrl.endBackTransition(shouldContinue)
|
||||
} : undefined;
|
||||
onEnd: (shouldContinue) => this.stackCtrl.endBackTransition(shouldContinue),
|
||||
}
|
||||
: undefined;
|
||||
}
|
||||
|
||||
constructor(
|
||||
@ -93,12 +114,12 @@ export class IonRouterOutlet implements OnDestroy, OnInit {
|
||||
// If the outlet was not instantiated at the time the route got activated we need to populate
|
||||
// the outlet when it is initialized (ie inside a NgIf)
|
||||
const context = this.getContext();
|
||||
if (context && context.route) {
|
||||
if (context?.route) {
|
||||
this.activateWith(context.route, context.resolver || null);
|
||||
}
|
||||
}
|
||||
|
||||
new Promise(resolve => componentOnReady(this.nativeEl, resolve)).then(() => {
|
||||
new Promise((resolve) => componentOnReady(this.nativeEl, resolve)).then(() => {
|
||||
if (this._swipeGesture === undefined) {
|
||||
this.swipeGesture = this.config.getBoolean('swipeBackEnabled', (this.nativeEl as any).mode === 'ios');
|
||||
}
|
||||
@ -109,7 +130,7 @@ export class IonRouterOutlet implements OnDestroy, OnInit {
|
||||
return !!this.activated;
|
||||
}
|
||||
|
||||
get component(): object {
|
||||
get component(): Record<string, unknown> {
|
||||
if (!this.activated) {
|
||||
throw new Error('Outlet is not activated');
|
||||
}
|
||||
@ -140,13 +161,15 @@ export class IonRouterOutlet implements OnDestroy, OnInit {
|
||||
/**
|
||||
* Called when the `RouteReuseStrategy` instructs to re-attach a previously detached subtree
|
||||
*/
|
||||
attach(_ref: ComponentRef<any>, _activatedRoute: ActivatedRoute) {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
attach(_ref: ComponentRef<any>, _activatedRoute: ActivatedRoute): void {
|
||||
throw new Error('incompatible reuse strategy');
|
||||
}
|
||||
|
||||
deactivate(): void {
|
||||
if (this.activated) {
|
||||
if (this.activatedView) {
|
||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||
const context = this.getContext()!;
|
||||
this.activatedView.savedData = new Map(context.children['contexts']);
|
||||
|
||||
@ -172,7 +195,7 @@ export class IonRouterOutlet implements OnDestroy, OnInit {
|
||||
const contextSnapshot = context.route.snapshot;
|
||||
|
||||
this.activatedView.savedExtras.queryParams = contextSnapshot.queryParams;
|
||||
this.activatedView.savedExtras.fragment = contextSnapshot.fragment;
|
||||
(this.activatedView.savedExtras.fragment as string | null) = contextSnapshot.fragment;
|
||||
}
|
||||
}
|
||||
const c = this.component;
|
||||
@ -183,7 +206,7 @@ export class IonRouterOutlet implements OnDestroy, OnInit {
|
||||
}
|
||||
}
|
||||
|
||||
activateWith(activatedRoute: ActivatedRoute, resolver: ComponentFactoryResolver | null) {
|
||||
activateWith(activatedRoute: ActivatedRoute, resolver: ComponentFactoryResolver | null): void {
|
||||
if (this.isActivated) {
|
||||
throw new Error('Cannot activate an already activated outlet');
|
||||
}
|
||||
@ -196,6 +219,7 @@ export class IonRouterOutlet implements OnDestroy, OnInit {
|
||||
const saved = enteringView.savedData;
|
||||
if (saved) {
|
||||
// self-restore
|
||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||
const context = this.getContext()!;
|
||||
context.children['contexts'] = saved;
|
||||
}
|
||||
@ -203,6 +227,7 @@ export class IonRouterOutlet implements OnDestroy, OnInit {
|
||||
this.updateActivatedRouteProxy(cmpRef.instance, activatedRoute);
|
||||
} else {
|
||||
const snapshot = (activatedRoute as any)._futureSnapshot;
|
||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||
const component = snapshot.routeConfig!.component as any;
|
||||
resolver = resolver || this.resolver;
|
||||
|
||||
@ -230,7 +255,7 @@ export class IonRouterOutlet implements OnDestroy, OnInit {
|
||||
}
|
||||
|
||||
this.activatedView = enteringView;
|
||||
this.stackCtrl.setActive(enteringView).then(data => {
|
||||
this.stackCtrl.setActive(enteringView).then((data) => {
|
||||
this.navCtrl.setTopOutlet(this);
|
||||
this.activateEvents.emit(cmpRef.instance);
|
||||
this.stackEvents.emit(data);
|
||||
@ -313,11 +338,11 @@ export class IonRouterOutlet implements OnDestroy, OnInit {
|
||||
private proxyObservable(component$: Observable<any>, path: string): Observable<any> {
|
||||
return component$.pipe(
|
||||
// First wait until the component instance is pushed
|
||||
filter(component => !!component),
|
||||
switchMap(component =>
|
||||
filter((component) => !!component),
|
||||
switchMap((component) =>
|
||||
this.currentActivatedRoute$.pipe(
|
||||
filter(current => current !== null && current.component === component),
|
||||
switchMap(current => current && (current.activatedRoute as any)[path]),
|
||||
filter((current) => current !== null && current.component === component),
|
||||
switchMap((current) => current && (current.activatedRoute as any)[path]),
|
||||
distinctUntilChanged()
|
||||
)
|
||||
)
|
||||
@ -344,11 +369,7 @@ export class IonRouterOutlet implements OnDestroy, OnInit {
|
||||
}
|
||||
|
||||
class OutletInjector implements Injector {
|
||||
constructor(
|
||||
private route: ActivatedRoute,
|
||||
private childContexts: ChildrenOutletContexts,
|
||||
private parent: Injector
|
||||
) { }
|
||||
constructor(private route: ActivatedRoute, private childContexts: ChildrenOutletContexts, private parent: Injector) {}
|
||||
|
||||
get(token: any, notFoundValue?: any): any {
|
||||
if (token === ActivatedRoute) {
|
||||
@ -359,7 +380,6 @@ class OutletInjector implements Injector {
|
||||
return this.childContexts;
|
||||
}
|
||||
|
||||
// tslint:disable-next-line
|
||||
return this.parent.get(token, notFoundValue);
|
||||
}
|
||||
}
|
||||
|
@ -8,13 +8,13 @@ import { StackEvent } from './stack-utils';
|
||||
|
||||
@Component({
|
||||
selector: 'ion-tabs',
|
||||
template: `
|
||||
<ng-content select="[slot=top]"></ng-content>
|
||||
template: ` <ng-content select="[slot=top]"></ng-content>
|
||||
<div class="tabs-inner">
|
||||
<ion-router-outlet #outlet tabs="true" (stackEvents)="onPageSelected($event)"></ion-router-outlet>
|
||||
</div>
|
||||
<ng-content></ng-content>`,
|
||||
styles: [`
|
||||
styles: [
|
||||
`
|
||||
:host {
|
||||
display: flex;
|
||||
position: absolute;
|
||||
@ -37,25 +37,24 @@ import { StackEvent } from './stack-utils';
|
||||
flex: 1;
|
||||
|
||||
contain: layout size style;
|
||||
}`
|
||||
]
|
||||
}
|
||||
`,
|
||||
],
|
||||
})
|
||||
// eslint-disable-next-line @angular-eslint/component-class-suffix
|
||||
export class IonTabs {
|
||||
|
||||
@ViewChild('outlet', { read: IonRouterOutlet, static: false }) outlet: IonRouterOutlet;
|
||||
@ContentChild(IonTabBar, { static: false }) tabBar: IonTabBar | undefined;
|
||||
|
||||
@Output() ionTabsWillChange = new EventEmitter<{ tab: string }>();
|
||||
@Output() ionTabsDidChange = new EventEmitter<{ tab: string }>();
|
||||
|
||||
constructor(
|
||||
private navCtrl: NavController,
|
||||
) { }
|
||||
constructor(private navCtrl: NavController) {}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
onPageSelected(detail: StackEvent) {
|
||||
onPageSelected(detail: StackEvent): void {
|
||||
const stackId = detail.enteringView.stackId;
|
||||
if (detail.tabSwitch && stackId !== undefined) {
|
||||
if (this.tabBar) {
|
||||
@ -87,9 +86,9 @@ export class IonTabs {
|
||||
* to the default tabRootUrl
|
||||
*/
|
||||
@HostListener('ionTabButtonClick', ['$event'])
|
||||
select(tabOrEvent: string | CustomEvent) {
|
||||
select(tabOrEvent: string | CustomEvent): Promise<boolean> | undefined {
|
||||
const isTabString = typeof tabOrEvent === 'string';
|
||||
const tab = (isTabString) ? tabOrEvent : (tabOrEvent as CustomEvent).detail.tab;
|
||||
const tab = isTabString ? tabOrEvent : (tabOrEvent as CustomEvent).detail.tab;
|
||||
const alreadySelected = this.outlet.getActiveStackId() === tab;
|
||||
const tabRootUrl = `${this.outlet.tabsPrefix}/${tab}`;
|
||||
|
||||
@ -108,12 +107,14 @@ export class IonTabs {
|
||||
const activeView = this.outlet.getLastRouteView(activeStackId);
|
||||
|
||||
// If on root tab, do not navigate to root tab again
|
||||
if (activeView.url === tabRootUrl) { return; }
|
||||
if (activeView?.url === tabRootUrl) {
|
||||
return;
|
||||
}
|
||||
|
||||
const rootView = this.outlet.getRootView(tab);
|
||||
const navigationExtras = rootView && tabRootUrl === rootView.url && rootView.savedExtras;
|
||||
return this.navCtrl.navigateRoot(tabRootUrl, {
|
||||
...(navigationExtras),
|
||||
...navigationExtras,
|
||||
animated: true,
|
||||
animationDirection: 'back',
|
||||
});
|
||||
@ -123,11 +124,11 @@ export class IonTabs {
|
||||
* If there is a lastRoute, goto that, otherwise goto the fallback url of the
|
||||
* selected tab
|
||||
*/
|
||||
const url = lastRoute && lastRoute.url || tabRootUrl;
|
||||
const navigationExtras = lastRoute && lastRoute.savedExtras;
|
||||
const url = lastRoute?.url || tabRootUrl;
|
||||
const navigationExtras = lastRoute?.savedExtras;
|
||||
|
||||
return this.navCtrl.navigateRoot(url, {
|
||||
...(navigationExtras),
|
||||
...navigationExtras,
|
||||
animated: true,
|
||||
animationDirection: 'back',
|
||||
});
|
||||
|
@ -1,15 +1,30 @@
|
||||
import { ComponentFactoryResolver, Directive, ElementRef, Injector, ViewContainerRef } from '@angular/core';
|
||||
import { ComponentFactoryResolver, ElementRef, Injector, ViewContainerRef, Directive } from '@angular/core';
|
||||
|
||||
import { AngularDelegate } from '../../providers/angular-delegate';
|
||||
import { ProxyCmp, proxyOutputs } from '../angular-component-lib/utils';
|
||||
|
||||
@ProxyCmp({
|
||||
inputs: ['animated', 'animation', 'root', 'rootParams', 'swipeGesture'],
|
||||
methods: ['push', 'insert', 'insertPages', 'pop', 'popTo', 'popToRoot', 'removeIndex', 'setRoot', 'setPages', 'getActive', 'getByIndex', 'canGoBack', 'getPrevious']
|
||||
methods: [
|
||||
'push',
|
||||
'insert',
|
||||
'insertPages',
|
||||
'pop',
|
||||
'popTo',
|
||||
'popToRoot',
|
||||
'removeIndex',
|
||||
'setRoot',
|
||||
'setPages',
|
||||
'getActive',
|
||||
'getByIndex',
|
||||
'canGoBack',
|
||||
'getPrevious',
|
||||
],
|
||||
})
|
||||
@Directive({
|
||||
selector: 'ion-nav'
|
||||
selector: 'ion-nav',
|
||||
})
|
||||
// eslint-disable-next-line @angular-eslint/directive-class-suffix
|
||||
export class NavDelegate {
|
||||
protected el: HTMLElement;
|
||||
constructor(
|
||||
@ -21,6 +36,6 @@ export class NavDelegate {
|
||||
) {
|
||||
this.el = ref.nativeElement;
|
||||
ref.nativeElement.delegate = angularDelegate.create(resolver, injector, location);
|
||||
proxyOutputs(this, this.el, ['ionNavDidChange' , 'ionNavWillChange' ]);
|
||||
proxyOutputs(this, this.el, ['ionNavDidChange', 'ionNavWillChange']);
|
||||
}
|
||||
}
|
||||
|
@ -19,8 +19,7 @@
|
||||
* ```
|
||||
*/
|
||||
export class NavParams {
|
||||
|
||||
constructor(public data: {[key: string]: any} = {}) {}
|
||||
constructor(public data: { [key: string]: any } = {}) {}
|
||||
|
||||
/**
|
||||
* Get the value of a nav-parameter for the current view
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { LocationStrategy } from '@angular/common';
|
||||
import { Directive, ElementRef, HostListener, Optional } from '@angular/core';
|
||||
import { ElementRef, OnChanges, OnDestroy, OnInit, Directive, HostListener, Input, Optional } from '@angular/core';
|
||||
import { Router, RouterLink } from '@angular/router';
|
||||
import { AnimationBuilder, RouterDirection } from '@ionic/core';
|
||||
import { Subscription } from 'rxjs';
|
||||
@ -8,13 +8,14 @@ import { NavController } from '../../providers/nav-controller';
|
||||
|
||||
@Directive({
|
||||
selector: '[routerLink]',
|
||||
inputs: ['routerDirection', 'routerAnimation']
|
||||
})
|
||||
export class RouterLinkDelegate {
|
||||
|
||||
export class RouterLinkDelegateDirective implements OnInit, OnChanges, OnDestroy {
|
||||
private subscription?: Subscription;
|
||||
|
||||
@Input()
|
||||
routerDirection: RouterDirection = 'forward';
|
||||
|
||||
@Input()
|
||||
routerAnimation?: AnimationBuilder;
|
||||
|
||||
constructor(
|
||||
@ -22,18 +23,18 @@ export class RouterLinkDelegate {
|
||||
private navCtrl: NavController,
|
||||
private elementRef: ElementRef,
|
||||
private router: Router,
|
||||
@Optional() private routerLink?: RouterLink,
|
||||
) { }
|
||||
@Optional() private routerLink?: RouterLink
|
||||
) {}
|
||||
|
||||
ngOnInit() {
|
||||
ngOnInit(): void {
|
||||
this.updateTargetUrlAndHref();
|
||||
}
|
||||
|
||||
ngOnChanges(): any {
|
||||
ngOnChanges(): void {
|
||||
this.updateTargetUrlAndHref();
|
||||
}
|
||||
|
||||
ngOnDestroy(): any {
|
||||
ngOnDestroy(): void {
|
||||
if (this.subscription) {
|
||||
this.subscription.unsubscribe();
|
||||
}
|
||||
@ -50,7 +51,7 @@ export class RouterLinkDelegate {
|
||||
* @internal
|
||||
*/
|
||||
@HostListener('click', ['$event'])
|
||||
onClick(ev: UIEvent) {
|
||||
onClick(ev: UIEvent): void {
|
||||
this.navCtrl.setDirection(this.routerDirection, undefined, undefined, this.routerAnimation);
|
||||
ev.preventDefault();
|
||||
}
|
||||
|
@ -6,10 +6,18 @@ import { AnimationBuilder, RouterDirection } from '@ionic/core';
|
||||
import { bindLifecycleEvents } from '../../providers/angular-delegate';
|
||||
import { NavController } from '../../providers/nav-controller';
|
||||
|
||||
import { RouteView, StackEvent, computeStackId, destroyView, getUrl, insertView, isTabSwitch, toSegments } from './stack-utils';
|
||||
import {
|
||||
RouteView,
|
||||
StackEvent,
|
||||
computeStackId,
|
||||
destroyView,
|
||||
getUrl,
|
||||
insertView,
|
||||
isTabSwitch,
|
||||
toSegments,
|
||||
} from './stack-utils';
|
||||
|
||||
export class StackController {
|
||||
|
||||
private views: RouteView[] = [];
|
||||
private runningTask?: Promise<any>;
|
||||
private skipTransition = false;
|
||||
@ -30,7 +38,7 @@ export class StackController {
|
||||
|
||||
createView(ref: ComponentRef<any>, activatedRoute: ActivatedRoute): RouteView {
|
||||
const url = getUrl(this.router, activatedRoute);
|
||||
const element = (ref && ref.location && ref.location.nativeElement) as HTMLElement;
|
||||
const element = ref?.location?.nativeElement as HTMLElement;
|
||||
const unlistenEvents = bindLifecycleEvents(this.zone, ref.instance, element);
|
||||
return {
|
||||
id: this.nextId++,
|
||||
@ -44,7 +52,7 @@ export class StackController {
|
||||
|
||||
getExistingView(activatedRoute: ActivatedRoute): RouteView | undefined {
|
||||
const activatedUrlKey = getUrl(this.router, activatedRoute);
|
||||
const view = this.views.find(vw => vw.url === activatedUrlKey);
|
||||
const view = this.views.find((vw) => vw.url === activatedUrlKey);
|
||||
if (view) {
|
||||
view.ref.changeDetectorRef.reattach();
|
||||
}
|
||||
@ -65,17 +73,14 @@ export class StackController {
|
||||
|
||||
let currentNavigation;
|
||||
|
||||
const router = (this.router as any);
|
||||
const router = this.router as any;
|
||||
|
||||
// Angular >= 7.2.0
|
||||
if (router.getCurrentNavigation) {
|
||||
currentNavigation = router.getCurrentNavigation();
|
||||
|
||||
// Angular < 7.2.0
|
||||
} else if (
|
||||
router.navigations &&
|
||||
router.navigations.value
|
||||
) {
|
||||
} else if (router.navigations?.value) {
|
||||
currentNavigation = router.navigations.value;
|
||||
}
|
||||
|
||||
@ -86,11 +91,7 @@ export class StackController {
|
||||
* we remove the last item
|
||||
* from our views stack
|
||||
*/
|
||||
if (
|
||||
currentNavigation &&
|
||||
currentNavigation.extras &&
|
||||
currentNavigation.extras.replaceUrl
|
||||
) {
|
||||
if (currentNavigation?.extras?.replaceUrl) {
|
||||
if (this.views.length > 0) {
|
||||
this.views.splice(-1, 1);
|
||||
}
|
||||
@ -114,12 +115,7 @@ export class StackController {
|
||||
* provided another animation.
|
||||
*/
|
||||
const customAnimation = enteringView.animationBuilder;
|
||||
if (
|
||||
animationBuilder === undefined &&
|
||||
direction === 'back' &&
|
||||
!tabSwitch &&
|
||||
customAnimation !== undefined
|
||||
) {
|
||||
if (animationBuilder === undefined && direction === 'back' && !tabSwitch && customAnimation !== undefined) {
|
||||
animationBuilder = customAnimation;
|
||||
}
|
||||
|
||||
@ -148,7 +144,7 @@ export class StackController {
|
||||
enteringView,
|
||||
direction,
|
||||
animation,
|
||||
tabSwitch
|
||||
tabSwitch,
|
||||
}));
|
||||
});
|
||||
});
|
||||
@ -158,7 +154,7 @@ export class StackController {
|
||||
return this.getStack(stackId).length > deep;
|
||||
}
|
||||
|
||||
pop(deep: number, stackId = this.getActiveStackId()) {
|
||||
pop(deep: number, stackId = this.getActiveStackId()): Promise<boolean> {
|
||||
return this.zone.run(() => {
|
||||
const views = this.getStack(stackId);
|
||||
if (views.length <= deep) {
|
||||
@ -170,13 +166,7 @@ export class StackController {
|
||||
const viewSavedData = view.savedData;
|
||||
if (viewSavedData) {
|
||||
const primaryOutlet = viewSavedData.get('primary');
|
||||
if (
|
||||
primaryOutlet &&
|
||||
primaryOutlet.route &&
|
||||
primaryOutlet.route._routerState &&
|
||||
primaryOutlet.route._routerState.snapshot &&
|
||||
primaryOutlet.route._routerState.snapshot.url
|
||||
) {
|
||||
if (primaryOutlet?.route?._routerState?.snapshot.url) {
|
||||
url = primaryOutlet.route._routerState.snapshot.url;
|
||||
}
|
||||
}
|
||||
@ -185,7 +175,7 @@ export class StackController {
|
||||
});
|
||||
}
|
||||
|
||||
startBackTransition() {
|
||||
startBackTransition(): Promise<boolean> | Promise<void> {
|
||||
const leavingView = this.activeView;
|
||||
if (leavingView) {
|
||||
const views = this.getStack(leavingView.stackId);
|
||||
@ -206,7 +196,7 @@ export class StackController {
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
endBackTransition(shouldComplete: boolean) {
|
||||
endBackTransition(shouldComplete: boolean): void {
|
||||
if (shouldComplete) {
|
||||
this.skipTransition = true;
|
||||
this.pop(1);
|
||||
@ -215,7 +205,7 @@ export class StackController {
|
||||
}
|
||||
}
|
||||
|
||||
getLastUrl(stackId?: string) {
|
||||
getLastUrl(stackId?: string): RouteView | undefined {
|
||||
const views = this.getStack(stackId);
|
||||
return views.length > 0 ? views[views.length - 1] : undefined;
|
||||
}
|
||||
@ -223,7 +213,7 @@ export class StackController {
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
getRootUrl(stackId?: string) {
|
||||
getRootUrl(stackId?: string): RouteView | undefined {
|
||||
const views = this.getStack(stackId);
|
||||
return views.length > 0 ? views[0] : undefined;
|
||||
}
|
||||
@ -236,7 +226,8 @@ export class StackController {
|
||||
return this.runningTask !== undefined;
|
||||
}
|
||||
|
||||
destroy() {
|
||||
destroy(): void {
|
||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||
this.containerEl = undefined!;
|
||||
this.views.forEach(destroyView);
|
||||
this.activeView = undefined;
|
||||
@ -244,7 +235,7 @@ export class StackController {
|
||||
}
|
||||
|
||||
private getStack(stackId: string | undefined) {
|
||||
return this.views.filter(v => v.stackId === stackId);
|
||||
return this.views.filter((v) => v.stackId === stackId);
|
||||
}
|
||||
|
||||
private insertView(enteringView: RouteView, direction: RouterDirection) {
|
||||
@ -285,7 +276,7 @@ export class StackController {
|
||||
direction,
|
||||
showGoBack,
|
||||
progressAnimation,
|
||||
animationBuilder
|
||||
animationBuilder,
|
||||
});
|
||||
}
|
||||
}
|
||||
@ -297,15 +288,15 @@ export class StackController {
|
||||
await this.runningTask;
|
||||
this.runningTask = undefined;
|
||||
}
|
||||
const promise = this.runningTask = task();
|
||||
promise.finally(() => this.runningTask = undefined);
|
||||
const promise = (this.runningTask = task());
|
||||
promise.finally(() => (this.runningTask = undefined));
|
||||
return promise;
|
||||
}
|
||||
}
|
||||
|
||||
const cleanupAsync = (activeRoute: RouteView, views: RouteView[], viewsSnapshot: RouteView[], location: Location) => {
|
||||
if (typeof (requestAnimationFrame as any) === 'function') {
|
||||
return new Promise<any>(resolve => {
|
||||
return new Promise<void>((resolve) => {
|
||||
requestAnimationFrame(() => {
|
||||
cleanup(activeRoute, views, viewsSnapshot, location);
|
||||
resolve();
|
||||
@ -316,11 +307,9 @@ const cleanupAsync = (activeRoute: RouteView, views: RouteView[], viewsSnapshot:
|
||||
};
|
||||
|
||||
const cleanup = (activeRoute: RouteView, views: RouteView[], viewsSnapshot: RouteView[], location: Location) => {
|
||||
viewsSnapshot
|
||||
.filter(view => !views.includes(view))
|
||||
.forEach(destroyView);
|
||||
viewsSnapshot.filter((view) => !views.includes(view)).forEach(destroyView);
|
||||
|
||||
views.forEach(view => {
|
||||
views.forEach((view) => {
|
||||
/**
|
||||
* In the event that a user navigated multiple
|
||||
* times in rapid succession, we want to make sure
|
||||
|
@ -2,7 +2,7 @@ import { ComponentRef } from '@angular/core';
|
||||
import { ActivatedRoute, NavigationExtras, Router } from '@angular/router';
|
||||
import { AnimationBuilder, NavDirection, RouterDirection } from '@ionic/core';
|
||||
|
||||
export const insertView = (views: RouteView[], view: RouteView, direction: RouterDirection) => {
|
||||
export const insertView = (views: RouteView[], view: RouteView, direction: RouterDirection): RouteView[] => {
|
||||
if (direction === 'root') {
|
||||
return setRoot(views, view);
|
||||
} else if (direction === 'forward') {
|
||||
@ -13,7 +13,7 @@ export const insertView = (views: RouteView[], view: RouteView, direction: Route
|
||||
};
|
||||
|
||||
const setRoot = (views: RouteView[], view: RouteView) => {
|
||||
views = views.filter(v => v.stackId !== view.stackId);
|
||||
views = views.filter((v) => v.stackId !== view.stackId);
|
||||
views.push(view);
|
||||
return views;
|
||||
};
|
||||
@ -21,7 +21,7 @@ const setRoot = (views: RouteView[], view: RouteView) => {
|
||||
const setForward = (views: RouteView[], view: RouteView) => {
|
||||
const index = views.indexOf(view);
|
||||
if (index >= 0) {
|
||||
views = views.filter(v => v.stackId !== view.stackId || v.id <= view.id);
|
||||
views = views.filter((v) => v.stackId !== view.stackId || v.id <= view.id);
|
||||
} else {
|
||||
views.push(view);
|
||||
}
|
||||
@ -31,25 +31,25 @@ const setForward = (views: RouteView[], view: RouteView) => {
|
||||
const setBack = (views: RouteView[], view: RouteView) => {
|
||||
const index = views.indexOf(view);
|
||||
if (index >= 0) {
|
||||
return views.filter(v => v.stackId !== view.stackId || v.id <= view.id);
|
||||
return views.filter((v) => v.stackId !== view.stackId || v.id <= view.id);
|
||||
} else {
|
||||
return setRoot(views, view);
|
||||
}
|
||||
};
|
||||
|
||||
export const getUrl = (router: Router, activatedRoute: ActivatedRoute) => {
|
||||
export const getUrl = (router: Router, activatedRoute: ActivatedRoute): string => {
|
||||
const urlTree = router.createUrlTree(['.'], { relativeTo: activatedRoute });
|
||||
return router.serializeUrl(urlTree);
|
||||
};
|
||||
|
||||
export const isTabSwitch = (enteringView: RouteView, leavingView: RouteView | undefined) => {
|
||||
export const isTabSwitch = (enteringView: RouteView, leavingView: RouteView | undefined): boolean => {
|
||||
if (!leavingView) {
|
||||
return true;
|
||||
}
|
||||
return enteringView.stackId !== leavingView.stackId;
|
||||
};
|
||||
|
||||
export const computeStackId = (prefixUrl: string[] | undefined, url: string) => {
|
||||
export const computeStackId = (prefixUrl: string[] | undefined, url: string): string | undefined => {
|
||||
if (!prefixUrl) {
|
||||
return undefined;
|
||||
}
|
||||
@ -65,14 +65,14 @@ export const computeStackId = (prefixUrl: string[] | undefined, url: string) =>
|
||||
return undefined;
|
||||
};
|
||||
|
||||
export const toSegments = (path: string) => {
|
||||
export const toSegments = (path: string): string[] => {
|
||||
return path
|
||||
.split('/')
|
||||
.map(s => s.trim())
|
||||
.filter(s => s !== '');
|
||||
.map((s) => s.trim())
|
||||
.filter((s) => s !== '');
|
||||
};
|
||||
|
||||
export const destroyView = (view: RouteView | undefined) => {
|
||||
export const destroyView = (view: RouteView | undefined): void => {
|
||||
if (view) {
|
||||
// TODO lifecycle event
|
||||
view.ref.destroy();
|
||||
|
@ -1,12 +1,66 @@
|
||||
/* eslint-disable */
|
||||
/* tslint:disable */
|
||||
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, ContentChild, ElementRef, EventEmitter, NgZone, TemplateRef } from "@angular/core";
|
||||
import { ProxyCmp, proxyOutputs } from "../angular-component-lib/utils";
|
||||
import { Components } from "@ionic/core";
|
||||
export declare interface IonModal extends Components.IonModal {
|
||||
}
|
||||
@ProxyCmp({ inputs: ["animated", "backdropBreakpoint", "backdropDismiss", "breakpoints", "cssClass", "enterAnimation", "event", "handle", "initialBreakpoint", "isOpen", "keyboardClose", "leaveAnimation", "mode", "presentingElement", "showBackdrop", "swipeToClose", "translucent", "trigger"], "methods": ["present", "dismiss", "onDidDismiss", "onWillDismiss"] })
|
||||
@Component({ selector: "ion-modal", changeDetection: ChangeDetectionStrategy.OnPush, template: `<ng-container [ngTemplateOutlet]="template" *ngIf="isCmpOpen"></ng-container>`, inputs: ["animated", "backdropBreakpoint", "backdropDismiss", "breakpoints", "cssClass", "enterAnimation", "event", "handle", "initialBreakpoint", "isOpen", "keyboardClose", "leaveAnimation", "mode", "presentingElement", "showBackdrop", "swipeToClose", "translucent", "trigger"] })
|
||||
import {
|
||||
ChangeDetectionStrategy,
|
||||
ChangeDetectorRef,
|
||||
Component,
|
||||
ContentChild,
|
||||
ElementRef,
|
||||
EventEmitter,
|
||||
NgZone,
|
||||
TemplateRef,
|
||||
} from '@angular/core';
|
||||
import { ProxyCmp, proxyOutputs } from '../angular-component-lib/utils';
|
||||
import { Components } from '@ionic/core';
|
||||
export declare interface IonModal extends Components.IonModal {}
|
||||
@ProxyCmp({
|
||||
inputs: [
|
||||
'animated',
|
||||
'backdropBreakpoint',
|
||||
'backdropDismiss',
|
||||
'breakpoints',
|
||||
'cssClass',
|
||||
'enterAnimation',
|
||||
'event',
|
||||
'handle',
|
||||
'initialBreakpoint',
|
||||
'isOpen',
|
||||
'keyboardClose',
|
||||
'leaveAnimation',
|
||||
'mode',
|
||||
'presentingElement',
|
||||
'showBackdrop',
|
||||
'swipeToClose',
|
||||
'translucent',
|
||||
'trigger',
|
||||
],
|
||||
methods: ['present', 'dismiss', 'onDidDismiss', 'onWillDismiss'],
|
||||
})
|
||||
@Component({
|
||||
selector: 'ion-modal',
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
template: `<ng-container [ngTemplateOutlet]="template" *ngIf="isCmpOpen"></ng-container>`,
|
||||
inputs: [
|
||||
'animated',
|
||||
'backdropBreakpoint',
|
||||
'backdropDismiss',
|
||||
'breakpoints',
|
||||
'cssClass',
|
||||
'enterAnimation',
|
||||
'event',
|
||||
'handle',
|
||||
'initialBreakpoint',
|
||||
'isOpen',
|
||||
'keyboardClose',
|
||||
'leaveAnimation',
|
||||
'mode',
|
||||
'presentingElement',
|
||||
'showBackdrop',
|
||||
'swipeToClose',
|
||||
'translucent',
|
||||
'trigger',
|
||||
],
|
||||
})
|
||||
export class IonModal {
|
||||
@ContentChild(TemplateRef, { static: false }) template: TemplateRef<any>;
|
||||
|
||||
@ -34,6 +88,15 @@ export class IonModal {
|
||||
c.detectChanges();
|
||||
});
|
||||
|
||||
proxyOutputs(this, this.el, ["ionModalDidPresent", "ionModalWillPresent", "ionModalWillDismiss", "ionModalDidDismiss", "didPresent", "willPresent", "willDismiss", "didDismiss"]);
|
||||
proxyOutputs(this, this.el, [
|
||||
'ionModalDidPresent',
|
||||
'ionModalWillPresent',
|
||||
'ionModalWillDismiss',
|
||||
'ionModalDidDismiss',
|
||||
'didPresent',
|
||||
'willPresent',
|
||||
'willDismiss',
|
||||
'didDismiss',
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
@ -1,12 +1,66 @@
|
||||
/* eslint-disable */
|
||||
/* tslint:disable */
|
||||
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, ContentChild, ElementRef, EventEmitter, NgZone, TemplateRef } from "@angular/core";
|
||||
import { ProxyCmp, proxyOutputs } from "../angular-component-lib/utils";
|
||||
import { Components } from "@ionic/core";
|
||||
export declare interface IonPopover extends Components.IonPopover {
|
||||
}
|
||||
@ProxyCmp({ inputs: ["alignment", "animated", "arrow", "backdropDismiss", "cssClass", "dismissOnSelect", "enterAnimation", "event", "isOpen", "keyboardClose", "leaveAnimation", "mode", "showBackdrop", "translucent", "trigger", "triggerAction", "reference", "size"], "methods": ["present", "dismiss", "onDidDismiss", "onWillDismiss"] })
|
||||
@Component({ selector: "ion-popover", changeDetection: ChangeDetectionStrategy.OnPush, template: `<ng-container [ngTemplateOutlet]="template" *ngIf="isCmpOpen"></ng-container>`, inputs: ["alignment", "animated", "arrow", "backdropDismiss", "cssClass", "dismissOnSelect", "enterAnimation", "event", "isOpen", "keyboardClose", "leaveAnimation", "mode", "showBackdrop", "translucent", "trigger", "triggerAction", "reference", "size"] })
|
||||
import {
|
||||
ChangeDetectionStrategy,
|
||||
ChangeDetectorRef,
|
||||
Component,
|
||||
ContentChild,
|
||||
ElementRef,
|
||||
EventEmitter,
|
||||
NgZone,
|
||||
TemplateRef,
|
||||
} from '@angular/core';
|
||||
import { ProxyCmp, proxyOutputs } from '../angular-component-lib/utils';
|
||||
import { Components } from '@ionic/core';
|
||||
export declare interface IonPopover extends Components.IonPopover {}
|
||||
@ProxyCmp({
|
||||
inputs: [
|
||||
'alignment',
|
||||
'animated',
|
||||
'arrow',
|
||||
'backdropDismiss',
|
||||
'cssClass',
|
||||
'dismissOnSelect',
|
||||
'enterAnimation',
|
||||
'event',
|
||||
'isOpen',
|
||||
'keyboardClose',
|
||||
'leaveAnimation',
|
||||
'mode',
|
||||
'showBackdrop',
|
||||
'translucent',
|
||||
'trigger',
|
||||
'triggerAction',
|
||||
'reference',
|
||||
'size',
|
||||
],
|
||||
methods: ['present', 'dismiss', 'onDidDismiss', 'onWillDismiss'],
|
||||
})
|
||||
@Component({
|
||||
selector: 'ion-popover',
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
template: `<ng-container [ngTemplateOutlet]="template" *ngIf="isCmpOpen"></ng-container>`,
|
||||
inputs: [
|
||||
'alignment',
|
||||
'animated',
|
||||
'arrow',
|
||||
'backdropDismiss',
|
||||
'cssClass',
|
||||
'dismissOnSelect',
|
||||
'enterAnimation',
|
||||
'event',
|
||||
'isOpen',
|
||||
'keyboardClose',
|
||||
'leaveAnimation',
|
||||
'mode',
|
||||
'showBackdrop',
|
||||
'translucent',
|
||||
'trigger',
|
||||
'triggerAction',
|
||||
'reference',
|
||||
'size',
|
||||
],
|
||||
})
|
||||
export class IonPopover {
|
||||
@ContentChild(TemplateRef, { static: false }) template: TemplateRef<any>;
|
||||
|
||||
@ -34,6 +88,15 @@ export class IonPopover {
|
||||
c.detectChanges();
|
||||
});
|
||||
|
||||
proxyOutputs(this, this.el, ["ionPopoverDidPresent", "ionPopoverWillPresent", "ionPopoverWillDismiss", "ionPopoverDidDismiss", "didPresent", "willPresent", "willDismiss", "didDismiss"]);
|
||||
proxyOutputs(this, this.el, [
|
||||
'ionPopoverDidPresent',
|
||||
'ionPopoverWillPresent',
|
||||
'ionPopoverWillDismiss',
|
||||
'ionPopoverDidDismiss',
|
||||
'didPresent',
|
||||
'willPresent',
|
||||
'willDismiss',
|
||||
'didDismiss',
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
@ -205,8 +205,8 @@ export class IonVirtualScroll {
|
||||
case 'item': return this.itmTmp.templateRef;
|
||||
case 'header': return this.hdrTmp.templateRef;
|
||||
case 'footer': return this.ftrTmp.templateRef;
|
||||
default: throw new Error('template for virtual item was not provided');
|
||||
}
|
||||
throw new Error('template for virtual item was not provided');
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,14 +1,14 @@
|
||||
// DIRECTIVES
|
||||
export { BooleanValueAccessor } from './directives/control-value-accessors/boolean-value-accessor';
|
||||
export { NumericValueAccessor } from './directives/control-value-accessors/numeric-value-accesssor';
|
||||
export { RadioValueAccessor } from './directives/control-value-accessors/radio-value-accessor';
|
||||
export { SelectValueAccessor } from './directives/control-value-accessors/select-value-accessor';
|
||||
export { TextValueAccessor } from './directives/control-value-accessors/text-value-accessor';
|
||||
export { BooleanValueAccessorDirective as BooleanValueAccessor } from './directives/control-value-accessors/boolean-value-accessor';
|
||||
export { NumericValueAccessorDirective as NumericValueAccessor } from './directives/control-value-accessors/numeric-value-accesssor';
|
||||
export { RadioValueAccessorDirective as RadioValueAccessor } from './directives/control-value-accessors/radio-value-accessor';
|
||||
export { SelectValueAccessorDirective as SelectValueAccessor } from './directives/control-value-accessors/select-value-accessor';
|
||||
export { TextValueAccessorDirective as TextValueAccessor } from './directives/control-value-accessors/text-value-accessor';
|
||||
export { IonTabs } from './directives/navigation/ion-tabs';
|
||||
export { IonBackButtonDelegate } from './directives/navigation/ion-back-button';
|
||||
export { IonBackButtonDelegateDirective as IonBackButtonDelegate } from './directives/navigation/ion-back-button';
|
||||
export { NavDelegate } from './directives/navigation/nav-delegate';
|
||||
export { IonRouterOutlet } from './directives/navigation/ion-router-outlet';
|
||||
export { RouterLinkDelegate } from './directives/navigation/router-link-delegate';
|
||||
export { RouterLinkDelegateDirective as RouterLinkDelegate } from './directives/navigation/router-link-delegate';
|
||||
export { NavParams } from './directives/navigation/nav-params';
|
||||
export { IonVirtualScroll } from './directives/virtual-scroll/virtual-scroll';
|
||||
export { VirtualItem } from './directives/virtual-scroll/virtual-item';
|
||||
@ -55,7 +55,6 @@ export {
|
||||
getPlatforms,
|
||||
isPlatform,
|
||||
getTimeGivenProgression,
|
||||
|
||||
// TYPES
|
||||
Animation,
|
||||
AnimationBuilder,
|
||||
@ -68,92 +67,61 @@ export {
|
||||
GestureConfig,
|
||||
GestureDetail,
|
||||
NavComponentWithProps,
|
||||
|
||||
SpinnerTypes,
|
||||
|
||||
AccordionGroupCustomEvent,
|
||||
AccordionGroupChangeEventDetail,
|
||||
|
||||
BreadcrumbCustomEvent,
|
||||
BreadcrumbCollapsedClickEventDetail,
|
||||
|
||||
ActionSheetOptions,
|
||||
ActionSheetButton,
|
||||
|
||||
AlertOptions,
|
||||
AlertInput,
|
||||
AlertTextareaAttributes,
|
||||
AlertInputAttributes,
|
||||
AlertButton,
|
||||
|
||||
BackButtonEvent,
|
||||
|
||||
CheckboxCustomEvent,
|
||||
CheckboxChangeEventDetail,
|
||||
|
||||
DatetimeCustomEvent,
|
||||
DatetimeChangeEventDetail,
|
||||
|
||||
InfiniteScrollCustomEvent,
|
||||
|
||||
InputCustomEvent,
|
||||
InputChangeEventDetail,
|
||||
|
||||
ItemReorderEventDetail,
|
||||
ItemReorderCustomEvent,
|
||||
|
||||
ItemSlidingCustomEvent,
|
||||
|
||||
IonicSafeString,
|
||||
|
||||
LoadingOptions,
|
||||
|
||||
MenuCustomEvent,
|
||||
|
||||
ModalOptions,
|
||||
|
||||
NavCustomEvent,
|
||||
|
||||
PickerOptions,
|
||||
PickerButton,
|
||||
PickerColumn,
|
||||
PickerColumnOption,
|
||||
|
||||
PlatformConfig,
|
||||
|
||||
PopoverOptions,
|
||||
|
||||
RadioGroupCustomEvent,
|
||||
RadioGroupChangeEventDetail,
|
||||
|
||||
RefresherCustomEvent,
|
||||
RefresherEventDetail,
|
||||
|
||||
RouterEventDetail,
|
||||
RouterCustomEvent,
|
||||
|
||||
ScrollBaseCustomEvent,
|
||||
ScrollBaseDetail,
|
||||
ScrollDetail,
|
||||
ScrollCustomEvent,
|
||||
|
||||
SearchbarCustomEvent,
|
||||
SearchbarChangeEventDetail,
|
||||
|
||||
SegmentChangeEventDetail,
|
||||
SegmentCustomEvent,
|
||||
|
||||
SelectChangeEventDetail,
|
||||
SelectCustomEvent,
|
||||
|
||||
TabsCustomEvent,
|
||||
|
||||
TextareaChangeEventDetail,
|
||||
TextareaCustomEvent,
|
||||
|
||||
ToastOptions,
|
||||
ToastButton,
|
||||
|
||||
ToggleChangeEventDetail,
|
||||
ToggleCustomEvent,
|
||||
} from '@ionic/core';
|
||||
|
21
angular/src/ionic-core.ts
Normal file
21
angular/src/ionic-core.ts
Normal file
@ -0,0 +1,21 @@
|
||||
// Re-exports from ionic/core
|
||||
|
||||
// UTILS
|
||||
export { IonicSafeString, getPlatforms, isPlatform, createAnimation } from '@ionic/core';
|
||||
|
||||
// CORE TYPES
|
||||
export {
|
||||
Animation,
|
||||
AnimationBuilder,
|
||||
AnimationCallbackOptions,
|
||||
AnimationDirection,
|
||||
AnimationFill,
|
||||
AnimationKeyFrames,
|
||||
AnimationLifecycle,
|
||||
Gesture,
|
||||
GestureConfig,
|
||||
GestureDetail,
|
||||
mdTransitionAnimation,
|
||||
iosTransitionAnimation,
|
||||
NavComponentWithProps,
|
||||
} from '@ionic/core';
|
@ -1,21 +1,97 @@
|
||||
import { CommonModule, DOCUMENT } from '@angular/common';
|
||||
import { APP_INITIALIZER, ModuleWithProviders, NgModule, NgZone } from '@angular/core';
|
||||
import { ModuleWithProviders, APP_INITIALIZER, NgModule, NgZone } from '@angular/core';
|
||||
import { IonicConfig } from '@ionic/core';
|
||||
|
||||
import { appInitialize } from './app-initialize';
|
||||
import { BooleanValueAccessor } from './directives/control-value-accessors/boolean-value-accessor';
|
||||
import { NumericValueAccessor } from './directives/control-value-accessors/numeric-value-accesssor';
|
||||
import { RadioValueAccessor } from './directives/control-value-accessors/radio-value-accessor';
|
||||
import { SelectValueAccessor } from './directives/control-value-accessors/select-value-accessor';
|
||||
import { TextValueAccessor } from './directives/control-value-accessors/text-value-accessor';
|
||||
import { IonBackButtonDelegate } from './directives/navigation/ion-back-button';
|
||||
import { BooleanValueAccessorDirective } from './directives/control-value-accessors/boolean-value-accessor';
|
||||
import { NumericValueAccessorDirective } from './directives/control-value-accessors/numeric-value-accesssor';
|
||||
import { RadioValueAccessorDirective } from './directives/control-value-accessors/radio-value-accessor';
|
||||
import { SelectValueAccessorDirective } from './directives/control-value-accessors/select-value-accessor';
|
||||
import { TextValueAccessorDirective } from './directives/control-value-accessors/text-value-accessor';
|
||||
import { IonBackButtonDelegateDirective } from './directives/navigation/ion-back-button';
|
||||
import { IonRouterOutlet } from './directives/navigation/ion-router-outlet';
|
||||
import { IonTabs } from './directives/navigation/ion-tabs';
|
||||
import { NavDelegate } from './directives/navigation/nav-delegate';
|
||||
import { RouterLinkDelegate } from './directives/navigation/router-link-delegate';
|
||||
import { RouterLinkDelegateDirective } from './directives/navigation/router-link-delegate';
|
||||
import { IonModal } from './directives/overlays/modal';
|
||||
import { IonPopover } from './directives/overlays/popover';
|
||||
import { IonAccordion, IonAccordionGroup, IonApp, IonAvatar, IonBackButton, IonBackdrop, IonBadge, IonBreadcrumb, IonBreadcrumbs, IonButton, IonButtons, IonCard, IonCardContent, IonCardHeader, IonCardSubtitle, IonCardTitle, IonCheckbox, IonChip, IonCol, IonContent, IonDatetime, IonFab, IonFabButton, IonFabList, IonFooter, IonGrid, IonHeader, IonIcon, IonImg, IonInfiniteScroll, IonInfiniteScrollContent, IonInput, IonItem, IonItemDivider, IonItemGroup, IonItemOption, IonItemOptions, IonItemSliding, IonLabel, IonList, IonListHeader, IonMenu, IonMenuButton, IonMenuToggle, IonNav, IonNavLink, IonNote, IonProgressBar, IonRadio, IonRadioGroup, IonRange, IonRefresher, IonRefresherContent, IonReorder, IonReorderGroup, IonRippleEffect, IonRow, IonSearchbar, IonSegment, IonSegmentButton, IonSelect, IonSelectOption, IonSkeletonText, IonSlide, IonSlides, IonSpinner, IonSplitPane, IonTabBar, IonTabButton, IonText, IonTextarea, IonThumbnail, IonTitle, IonToggle, IonToolbar } from './directives/proxies';
|
||||
import {
|
||||
IonAccordion,
|
||||
IonAccordionGroup,
|
||||
IonApp,
|
||||
IonAvatar,
|
||||
IonBackButton,
|
||||
IonBackdrop,
|
||||
IonBadge,
|
||||
IonBreadcrumb,
|
||||
IonBreadcrumbs,
|
||||
IonButton,
|
||||
IonButtons,
|
||||
IonCard,
|
||||
IonCardContent,
|
||||
IonCardHeader,
|
||||
IonCardSubtitle,
|
||||
IonCardTitle,
|
||||
IonCheckbox,
|
||||
IonChip,
|
||||
IonCol,
|
||||
IonContent,
|
||||
IonDatetime,
|
||||
IonFab,
|
||||
IonFabButton,
|
||||
IonFabList,
|
||||
IonFooter,
|
||||
IonGrid,
|
||||
IonHeader,
|
||||
IonIcon,
|
||||
IonImg,
|
||||
IonInfiniteScroll,
|
||||
IonInfiniteScrollContent,
|
||||
IonInput,
|
||||
IonItem,
|
||||
IonItemDivider,
|
||||
IonItemGroup,
|
||||
IonItemOption,
|
||||
IonItemOptions,
|
||||
IonItemSliding,
|
||||
IonLabel,
|
||||
IonList,
|
||||
IonListHeader,
|
||||
IonMenu,
|
||||
IonMenuButton,
|
||||
IonMenuToggle,
|
||||
IonNav,
|
||||
IonNavLink,
|
||||
IonNote,
|
||||
IonProgressBar,
|
||||
IonRadio,
|
||||
IonRadioGroup,
|
||||
IonRange,
|
||||
IonRefresher,
|
||||
IonRefresherContent,
|
||||
IonReorder,
|
||||
IonReorderGroup,
|
||||
IonRippleEffect,
|
||||
IonRow,
|
||||
IonSearchbar,
|
||||
IonSegment,
|
||||
IonSegmentButton,
|
||||
IonSelect,
|
||||
IonSelectOption,
|
||||
IonSkeletonText,
|
||||
IonSlide,
|
||||
IonSlides,
|
||||
IonSpinner,
|
||||
IonSplitPane,
|
||||
IonTabBar,
|
||||
IonTabButton,
|
||||
IonText,
|
||||
IonTextarea,
|
||||
IonThumbnail,
|
||||
IonTitle,
|
||||
IonToggle,
|
||||
IonToolbar,
|
||||
} from './directives/proxies';
|
||||
import { VirtualFooter } from './directives/virtual-scroll/virtual-footer';
|
||||
import { VirtualHeader } from './directives/virtual-scroll/virtual-header';
|
||||
import { VirtualItem } from './directives/virtual-scroll/virtual-item';
|
||||
@ -108,30 +184,30 @@ const DECLARATIONS = [
|
||||
IonTabs,
|
||||
|
||||
// ngModel accessors
|
||||
BooleanValueAccessor,
|
||||
NumericValueAccessor,
|
||||
RadioValueAccessor,
|
||||
SelectValueAccessor,
|
||||
TextValueAccessor,
|
||||
BooleanValueAccessorDirective,
|
||||
NumericValueAccessorDirective,
|
||||
RadioValueAccessorDirective,
|
||||
SelectValueAccessorDirective,
|
||||
TextValueAccessorDirective,
|
||||
|
||||
// navigation
|
||||
IonRouterOutlet,
|
||||
IonBackButtonDelegate,
|
||||
IonBackButtonDelegateDirective,
|
||||
NavDelegate,
|
||||
RouterLinkDelegate,
|
||||
RouterLinkDelegateDirective,
|
||||
|
||||
// virtual scroll
|
||||
VirtualFooter,
|
||||
VirtualHeader,
|
||||
VirtualItem,
|
||||
IonVirtualScroll
|
||||
IonVirtualScroll,
|
||||
];
|
||||
|
||||
@NgModule({
|
||||
declarations: DECLARATIONS,
|
||||
exports: DECLARATIONS,
|
||||
providers: [AngularDelegate, ModalController, PopoverController],
|
||||
imports: [CommonModule]
|
||||
imports: [CommonModule],
|
||||
})
|
||||
export class IonicModule {
|
||||
static forRoot(config?: IonicConfig): ModuleWithProviders<IonicModule> {
|
||||
@ -140,19 +216,15 @@ export class IonicModule {
|
||||
providers: [
|
||||
{
|
||||
provide: ConfigToken,
|
||||
useValue: config
|
||||
useValue: config,
|
||||
},
|
||||
{
|
||||
provide: APP_INITIALIZER,
|
||||
useFactory: appInitialize,
|
||||
multi: true,
|
||||
deps: [
|
||||
ConfigToken,
|
||||
DOCUMENT,
|
||||
NgZone
|
||||
]
|
||||
}
|
||||
]
|
||||
deps: [ConfigToken, DOCUMENT, NgZone],
|
||||
},
|
||||
],
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -1,27 +1,37 @@
|
||||
import { ApplicationRef, ComponentFactoryResolver, Injectable, InjectionToken, Injector, NgZone, ViewContainerRef } from '@angular/core';
|
||||
import { FrameworkDelegate, LIFECYCLE_DID_ENTER, LIFECYCLE_DID_LEAVE, LIFECYCLE_WILL_ENTER, LIFECYCLE_WILL_LEAVE, LIFECYCLE_WILL_UNLOAD } from '@ionic/core';
|
||||
import {
|
||||
ApplicationRef,
|
||||
ComponentFactoryResolver,
|
||||
NgZone,
|
||||
ViewContainerRef,
|
||||
Injectable,
|
||||
InjectionToken,
|
||||
Injector,
|
||||
} from '@angular/core';
|
||||
import {
|
||||
FrameworkDelegate,
|
||||
LIFECYCLE_DID_ENTER,
|
||||
LIFECYCLE_DID_LEAVE,
|
||||
LIFECYCLE_WILL_ENTER,
|
||||
LIFECYCLE_WILL_LEAVE,
|
||||
LIFECYCLE_WILL_UNLOAD,
|
||||
} from '@ionic/core';
|
||||
|
||||
import { NavParams } from '../directives/navigation/nav-params';
|
||||
|
||||
@Injectable()
|
||||
export class AngularDelegate {
|
||||
|
||||
constructor(
|
||||
private zone: NgZone,
|
||||
private appRef: ApplicationRef
|
||||
) {}
|
||||
constructor(private zone: NgZone, private appRef: ApplicationRef) {}
|
||||
|
||||
create(
|
||||
resolver: ComponentFactoryResolver,
|
||||
injector: Injector,
|
||||
location?: ViewContainerRef,
|
||||
) {
|
||||
location?: ViewContainerRef
|
||||
): AngularFrameworkDelegate {
|
||||
return new AngularFrameworkDelegate(resolver, injector, location, this.appRef, this.zone);
|
||||
}
|
||||
}
|
||||
|
||||
export class AngularFrameworkDelegate implements FrameworkDelegate {
|
||||
|
||||
private elRefMap = new WeakMap<HTMLElement, any>();
|
||||
private elEventsMap = new WeakMap<HTMLElement, () => void>();
|
||||
|
||||
@ -30,16 +40,24 @@ export class AngularFrameworkDelegate implements FrameworkDelegate {
|
||||
private injector: Injector,
|
||||
private location: ViewContainerRef | undefined,
|
||||
private appRef: ApplicationRef,
|
||||
private zone: NgZone,
|
||||
private zone: NgZone
|
||||
) {}
|
||||
|
||||
attachViewToDom(container: any, component: any, params?: any, cssClasses?: string[]): Promise<any> {
|
||||
return this.zone.run(() => {
|
||||
return new Promise(resolve => {
|
||||
return new Promise((resolve) => {
|
||||
const el = attachView(
|
||||
this.zone, this.resolver, this.injector, this.location, this.appRef,
|
||||
this.elRefMap, this.elEventsMap,
|
||||
container, component, params, cssClasses
|
||||
this.zone,
|
||||
this.resolver,
|
||||
this.injector,
|
||||
this.location,
|
||||
this.appRef,
|
||||
this.elRefMap,
|
||||
this.elEventsMap,
|
||||
container,
|
||||
component,
|
||||
params,
|
||||
cssClasses
|
||||
);
|
||||
resolve(el);
|
||||
});
|
||||
@ -48,7 +66,7 @@ export class AngularFrameworkDelegate implements FrameworkDelegate {
|
||||
|
||||
removeViewFromDom(_container: any, component: any): Promise<void> {
|
||||
return this.zone.run(() => {
|
||||
return new Promise(resolve => {
|
||||
return new Promise((resolve) => {
|
||||
const componentRef = this.elRefMap.get(component);
|
||||
if (componentRef) {
|
||||
componentRef.destroy();
|
||||
@ -73,14 +91,17 @@ export const attachView = (
|
||||
appRef: ApplicationRef,
|
||||
elRefMap: WeakMap<HTMLElement, any>,
|
||||
elEventsMap: WeakMap<HTMLElement, () => void>,
|
||||
container: any, component: any, params: any, cssClasses: string[] | undefined
|
||||
) => {
|
||||
container: any,
|
||||
component: any,
|
||||
params: any,
|
||||
cssClasses: string[] | undefined
|
||||
): any => {
|
||||
const factory = resolver.resolveComponentFactory(component);
|
||||
const childInjector = Injector.create({
|
||||
providers: getProviders(params),
|
||||
parent: injector
|
||||
parent: injector,
|
||||
});
|
||||
const componentRef = (location)
|
||||
const componentRef = location
|
||||
? location.createComponent(factory, location.length, childInjector)
|
||||
: factory.create(childInjector);
|
||||
|
||||
@ -111,35 +132,36 @@ const LIFECYCLES = [
|
||||
LIFECYCLE_DID_ENTER,
|
||||
LIFECYCLE_WILL_LEAVE,
|
||||
LIFECYCLE_DID_LEAVE,
|
||||
LIFECYCLE_WILL_UNLOAD
|
||||
LIFECYCLE_WILL_UNLOAD,
|
||||
];
|
||||
|
||||
export const bindLifecycleEvents = (zone: NgZone, instance: any, element: HTMLElement) => {
|
||||
export const bindLifecycleEvents = (zone: NgZone, instance: any, element: HTMLElement): (() => void) => {
|
||||
return zone.run(() => {
|
||||
const unregisters = LIFECYCLES
|
||||
.filter(eventName => typeof instance[eventName] === 'function')
|
||||
.map(eventName => {
|
||||
const unregisters = LIFECYCLES.filter((eventName) => typeof instance[eventName] === 'function').map((eventName) => {
|
||||
const handler = (ev: any) => instance[eventName](ev.detail);
|
||||
element.addEventListener(eventName, handler);
|
||||
return () => element.removeEventListener(eventName, handler);
|
||||
});
|
||||
return () => unregisters.forEach(fn => fn());
|
||||
return () => unregisters.forEach((fn) => fn());
|
||||
});
|
||||
};
|
||||
|
||||
const NavParamsToken = new InjectionToken<any>('NavParamsToken');
|
||||
|
||||
const getProviders = (params: {[key: string]: any}) => {
|
||||
const getProviders = (params: { [key: string]: any }) => {
|
||||
return [
|
||||
{
|
||||
provide: NavParamsToken, useValue: params
|
||||
provide: NavParamsToken,
|
||||
useValue: params,
|
||||
},
|
||||
{
|
||||
provide: NavParams, useFactory: provideNavParamsInjectable, deps: [NavParamsToken]
|
||||
}
|
||||
provide: NavParams,
|
||||
useFactory: provideNavParamsInjectable,
|
||||
deps: [NavParamsToken],
|
||||
},
|
||||
];
|
||||
};
|
||||
|
||||
const provideNavParamsInjectable = (params: {[key: string]: any}) => {
|
||||
const provideNavParamsInjectable = (params: { [key: string]: any }) => {
|
||||
return new NavParams(params);
|
||||
};
|
||||
|
@ -4,10 +4,9 @@ import { Config as CoreConfig, IonicConfig } from '@ionic/core';
|
||||
import { IonicWindow } from '../types/interfaces';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
providedIn: 'root',
|
||||
})
|
||||
export class Config {
|
||||
|
||||
get(key: keyof IonicConfig, fallback?: any): any {
|
||||
const c = getConfig();
|
||||
if (c) {
|
||||
@ -38,7 +37,7 @@ export const ConfigToken = new InjectionToken<any>('USERCONFIG');
|
||||
const getConfig = (): CoreConfig | null => {
|
||||
if (typeof (window as any) !== 'undefined') {
|
||||
const Ionic = (window as any as IonicWindow).Ionic;
|
||||
if (Ionic && Ionic.config) {
|
||||
if (Ionic?.config) {
|
||||
return Ionic.config;
|
||||
}
|
||||
}
|
||||
|
@ -4,12 +4,11 @@ import { Injectable } from '@angular/core';
|
||||
providedIn: 'root',
|
||||
})
|
||||
export class DomController {
|
||||
|
||||
/**
|
||||
* Schedules a task to run during the READ phase of the next frame.
|
||||
* This task should only read the DOM, but never modify it.
|
||||
*/
|
||||
read(cb: RafCallback) {
|
||||
read(cb: RafCallback): void {
|
||||
getQueue().read(cb);
|
||||
}
|
||||
|
||||
@ -17,29 +16,29 @@ export class DomController {
|
||||
* Schedules a task to run during the WRITE phase of the next frame.
|
||||
* This task should write the DOM, but never READ it.
|
||||
*/
|
||||
write(cb: RafCallback) {
|
||||
write(cb: RafCallback): void {
|
||||
getQueue().write(cb);
|
||||
}
|
||||
}
|
||||
|
||||
const getQueue = () => {
|
||||
const win = typeof (window as any) !== 'undefined' ? window : null as any;
|
||||
const win = typeof (window as any) !== 'undefined' ? window : (null as any);
|
||||
|
||||
if (win != null) {
|
||||
const Ionic = win.Ionic;
|
||||
if (Ionic && Ionic.queue) {
|
||||
if (Ionic?.queue) {
|
||||
return Ionic.queue;
|
||||
}
|
||||
|
||||
return {
|
||||
read: (cb: any) => win.requestAnimationFrame(cb),
|
||||
write: (cb: any) => win.requestAnimationFrame(cb)
|
||||
write: (cb: any) => win.requestAnimationFrame(cb),
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
read: (cb: any) => cb(),
|
||||
write: (cb: any) => cb()
|
||||
write: (cb: any) => cb(),
|
||||
};
|
||||
};
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { Injectable, NgZone } from '@angular/core';
|
||||
import { NgZone, Injectable } from '@angular/core';
|
||||
import { Gesture, GestureConfig, createGesture } from '@ionic/core';
|
||||
|
||||
@Injectable({
|
||||
@ -11,10 +11,10 @@ export class GestureController {
|
||||
*/
|
||||
create(opts: GestureConfig, runInsideAngularZone = false): Gesture {
|
||||
if (runInsideAngularZone) {
|
||||
Object.getOwnPropertyNames(opts).forEach(key => {
|
||||
Object.getOwnPropertyNames(opts).forEach((key) => {
|
||||
if (typeof opts[key] === 'function') {
|
||||
const fn = opts[key];
|
||||
opts[key] = (...props) => this.zone.run(() => fn(...props));
|
||||
opts[key] = (...props: any[]) => this.zone.run(() => fn(...props));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -5,13 +5,12 @@ import { menuController } from '@ionic/core';
|
||||
providedIn: 'root',
|
||||
})
|
||||
export class MenuController {
|
||||
|
||||
/**
|
||||
* Programmatically open the Menu.
|
||||
* @param [menuId] Optionally get the menu by its id, or side.
|
||||
* @return returns a promise when the menu is fully opened
|
||||
*/
|
||||
open(menuId?: string) {
|
||||
open(menuId?: string): Promise<boolean> {
|
||||
return menuController.open(menuId);
|
||||
}
|
||||
|
||||
@ -22,7 +21,7 @@ export class MenuController {
|
||||
* @param [menuId] Optionally get the menu by its id, or side.
|
||||
* @return returns a promise when the menu is fully closed
|
||||
*/
|
||||
close(menuId?: string) {
|
||||
close(menuId?: string): Promise<boolean> {
|
||||
return menuController.close(menuId);
|
||||
}
|
||||
|
||||
@ -32,7 +31,7 @@ export class MenuController {
|
||||
* @param [menuId] Optionally get the menu by its id, or side.
|
||||
* @return returns a promise when the menu has been toggled
|
||||
*/
|
||||
toggle(menuId?: string) {
|
||||
toggle(menuId?: string): Promise<boolean> {
|
||||
return menuController.toggle(menuId);
|
||||
}
|
||||
|
||||
@ -44,7 +43,7 @@ export class MenuController {
|
||||
* @param [menuId] Optionally get the menu by its id, or side.
|
||||
* @return Returns the instance of the menu, which is useful for chaining.
|
||||
*/
|
||||
enable(shouldEnable: boolean, menuId?: string) {
|
||||
enable(shouldEnable: boolean, menuId?: string): Promise<HTMLIonMenuElement | undefined> {
|
||||
return menuController.enable(shouldEnable, menuId);
|
||||
}
|
||||
|
||||
@ -54,7 +53,7 @@ export class MenuController {
|
||||
* @param [menuId] Optionally get the menu by its id, or side.
|
||||
* @return Returns the instance of the menu, which is useful for chaining.
|
||||
*/
|
||||
swipeGesture(shouldEnable: boolean, menuId?: string) {
|
||||
swipeGesture(shouldEnable: boolean, menuId?: string): Promise<HTMLIonMenuElement | undefined> {
|
||||
return menuController.swipeGesture(shouldEnable, menuId);
|
||||
}
|
||||
|
||||
@ -63,7 +62,7 @@ export class MenuController {
|
||||
* @return Returns true if the specified menu is currently open, otherwise false.
|
||||
* If the menuId is not specified, it returns true if ANY menu is currenly open.
|
||||
*/
|
||||
isOpen(menuId?: string) {
|
||||
isOpen(menuId?: string): Promise<boolean> {
|
||||
return menuController.isOpen(menuId);
|
||||
}
|
||||
|
||||
@ -71,7 +70,7 @@ export class MenuController {
|
||||
* @param [menuId] Optionally get the menu by its id, or side.
|
||||
* @return Returns true if the menu is currently enabled, otherwise false.
|
||||
*/
|
||||
isEnabled(menuId?: string) {
|
||||
isEnabled(menuId?: string): Promise<boolean> {
|
||||
return menuController.isEnabled(menuId);
|
||||
}
|
||||
|
||||
@ -84,21 +83,21 @@ export class MenuController {
|
||||
* @param [menuId] Optionally get the menu by its id, or side.
|
||||
* @return Returns the instance of the menu if found, otherwise `null`.
|
||||
*/
|
||||
get(menuId?: string) {
|
||||
get(menuId?: string): Promise<HTMLIonMenuElement | undefined> {
|
||||
return menuController.get(menuId);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Returns the instance of the menu already opened, otherwise `null`.
|
||||
*/
|
||||
getOpen() {
|
||||
getOpen(): Promise<HTMLIonMenuElement | undefined> {
|
||||
return menuController.getOpen();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Returns an array of all menu instances.
|
||||
*/
|
||||
getMenus() {
|
||||
getMenus(): Promise<HTMLIonMenuElement[]> {
|
||||
return menuController.getMenus();
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { ComponentFactoryResolver, Injectable, Injector } from '@angular/core';
|
||||
import { ComponentFactoryResolver, Injector, Injectable } from '@angular/core';
|
||||
import { ModalOptions, modalController } from '@ionic/core';
|
||||
|
||||
import { OverlayBaseController } from '../util/overlay';
|
||||
@ -7,11 +7,10 @@ import { AngularDelegate } from './angular-delegate';
|
||||
|
||||
@Injectable()
|
||||
export class ModalController extends OverlayBaseController<ModalOptions, HTMLIonModalElement> {
|
||||
|
||||
constructor(
|
||||
private angularDelegate: AngularDelegate,
|
||||
private resolver: ComponentFactoryResolver,
|
||||
private injector: Injector,
|
||||
private injector: Injector
|
||||
) {
|
||||
super(modalController);
|
||||
}
|
||||
@ -19,7 +18,7 @@ export class ModalController extends OverlayBaseController<ModalOptions, HTMLIon
|
||||
create(opts: ModalOptions): Promise<HTMLIonModalElement> {
|
||||
return super.create({
|
||||
...opts,
|
||||
delegate: this.angularDelegate.create(this.resolver, this.injector)
|
||||
delegate: this.angularDelegate.create(this.resolver, this.injector),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { Location } from '@angular/common';
|
||||
import { Injectable, Optional } from '@angular/core';
|
||||
import { NavigationExtras, NavigationStart, Router, UrlSerializer, UrlTree } from '@angular/router';
|
||||
import { NavigationExtras, Router, UrlSerializer, UrlTree, NavigationStart } from '@angular/router';
|
||||
import { AnimationBuilder, NavDirection, RouterDirection } from '@ionic/core';
|
||||
|
||||
import { IonRouterOutlet } from '../directives/navigation/ion-router-outlet';
|
||||
@ -19,7 +19,6 @@ export interface NavigationOptions extends NavigationExtras, AnimationOptions {}
|
||||
providedIn: 'root',
|
||||
})
|
||||
export class NavController {
|
||||
|
||||
private topOutlet?: IonRouterOutlet;
|
||||
private direction: 'forward' | 'back' | 'root' | 'auto' = DEFAULT_DIRECTION;
|
||||
private animated?: NavDirection = DEFAULT_ANIMATED;
|
||||
@ -32,13 +31,13 @@ export class NavController {
|
||||
platform: Platform,
|
||||
private location: Location,
|
||||
private serializer: UrlSerializer,
|
||||
@Optional() private router?: Router,
|
||||
@Optional() private router?: Router
|
||||
) {
|
||||
// Subscribe to router events to detect direction
|
||||
if (router) {
|
||||
router.events.subscribe(ev => {
|
||||
router.events.subscribe((ev) => {
|
||||
if (ev instanceof NavigationStart) {
|
||||
const id = (ev.restoredState) ? ev.restoredState.navigationId : ev.id;
|
||||
const id = ev.restoredState ? ev.restoredState.navigationId : ev.id;
|
||||
this.guessDirection = id < this.lastNavId ? 'back' : 'forward';
|
||||
this.guessAnimation = !ev.restoredState ? this.guessDirection : undefined;
|
||||
this.lastNavId = this.guessDirection === 'forward' ? ev.id : id;
|
||||
@ -47,7 +46,7 @@ export class NavController {
|
||||
}
|
||||
|
||||
// Subscribe to backButton events
|
||||
platform.backButton.subscribeWithPriority(0, processNextHandler => {
|
||||
platform.backButton.subscribeWithPriority(0, (processNextHandler) => {
|
||||
this.pop();
|
||||
processNextHandler();
|
||||
});
|
||||
@ -122,7 +121,7 @@ export class NavController {
|
||||
* It will use the standard `window.history.back()` under the hood, but featuring a `back` animation
|
||||
* by default.
|
||||
*/
|
||||
back(options: AnimationOptions = { animated: true, animationDirection: 'back' }) {
|
||||
back(options: AnimationOptions = { animated: true, animationDirection: 'back' }): void {
|
||||
this.setDirection('back', options.animated, options.animationDirection, options.animation);
|
||||
return this.location.back();
|
||||
}
|
||||
@ -133,7 +132,7 @@ export class NavController {
|
||||
* It recursively finds the top active `ion-router-outlet` and calls `pop()`.
|
||||
* This is the recommended way to go back when you are using `ion-router-outlet`.
|
||||
*/
|
||||
async pop() {
|
||||
async pop(): Promise<void> {
|
||||
let outlet = this.topOutlet;
|
||||
|
||||
while (outlet) {
|
||||
@ -152,7 +151,12 @@ export class NavController {
|
||||
*
|
||||
* It's recommended to use `navigateForward()`, `navigateBack()` and `navigateRoot()` instead of `setDirection()`.
|
||||
*/
|
||||
setDirection(direction: RouterDirection, animated?: boolean, animationDirection?: 'forward' | 'back', animationBuilder?: AnimationBuilder) {
|
||||
setDirection(
|
||||
direction: RouterDirection,
|
||||
animated?: boolean,
|
||||
animationDirection?: 'forward' | 'back',
|
||||
animationBuilder?: AnimationBuilder
|
||||
): void {
|
||||
this.direction = direction;
|
||||
this.animated = getAnimation(direction, animated, animationDirection);
|
||||
this.animationBuilder = animationBuilder;
|
||||
@ -161,14 +165,18 @@ export class NavController {
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
setTopOutlet(outlet: IonRouterOutlet) {
|
||||
setTopOutlet(outlet: IonRouterOutlet): void {
|
||||
this.topOutlet = outlet;
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
consumeTransition() {
|
||||
consumeTransition(): {
|
||||
direction: RouterDirection;
|
||||
animation: NavDirection | undefined;
|
||||
animationBuilder: AnimationBuilder | undefined;
|
||||
} {
|
||||
let direction: RouterDirection = 'root';
|
||||
let animation: NavDirection | undefined;
|
||||
const animationBuilder = this.animationBuilder;
|
||||
@ -187,15 +195,15 @@ export class NavController {
|
||||
return {
|
||||
direction,
|
||||
animation,
|
||||
animationBuilder
|
||||
animationBuilder,
|
||||
};
|
||||
}
|
||||
|
||||
private navigate(url: string | UrlTree | any[], options: NavigationOptions) {
|
||||
if (Array.isArray(url)) {
|
||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||
return this.router!.navigate(url, options);
|
||||
} else {
|
||||
|
||||
/**
|
||||
* navigateByUrl ignores any properties that
|
||||
* would change the url, so things like queryParams
|
||||
@ -217,12 +225,17 @@ export class NavController {
|
||||
* that do not modify the url, such as `replaceUrl` which is why
|
||||
* `options` is passed in here.
|
||||
*/
|
||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||
return this.router!.navigateByUrl(urlTree, options);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const getAnimation = (direction: RouterDirection, animated: boolean | undefined, animationDirection: 'forward' | 'back' | undefined): NavDirection | undefined => {
|
||||
const getAnimation = (
|
||||
direction: RouterDirection,
|
||||
animated: boolean | undefined,
|
||||
animationDirection: 'forward' | 'back' | undefined
|
||||
): NavDirection | undefined => {
|
||||
if (animated === false) {
|
||||
return undefined;
|
||||
}
|
||||
|
@ -1,17 +1,19 @@
|
||||
import { DOCUMENT } from '@angular/common';
|
||||
import { Inject, Injectable, NgZone } from '@angular/core';
|
||||
import { NgZone, Inject, Injectable } from '@angular/core';
|
||||
import { BackButtonEventDetail, KeyboardEventDetail, Platforms, getPlatforms, isPlatform } from '@ionic/core';
|
||||
import { Subject, Subscription } from 'rxjs';
|
||||
import { Subscription, Subject } from 'rxjs';
|
||||
|
||||
export interface BackButtonEmitter extends Subject<BackButtonEventDetail> {
|
||||
subscribeWithPriority(priority: number, callback: (processNextHandler: () => void) => Promise<any> | void): Subscription;
|
||||
subscribeWithPriority(
|
||||
priority: number,
|
||||
callback: (processNextHandler: () => void) => Promise<any> | void
|
||||
): Subscription;
|
||||
}
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root',
|
||||
})
|
||||
export class Platform {
|
||||
|
||||
private _readyPromise: Promise<string>;
|
||||
private win: any;
|
||||
|
||||
@ -57,9 +59,9 @@ export class Platform {
|
||||
constructor(@Inject(DOCUMENT) private doc: any, zone: NgZone) {
|
||||
zone.run(() => {
|
||||
this.win = doc.defaultView;
|
||||
this.backButton.subscribeWithPriority = function(priority, callback) {
|
||||
return this.subscribe(ev => {
|
||||
return ev.register(priority, processNextHandler => zone.run(() => callback(processNextHandler)));
|
||||
this.backButton.subscribeWithPriority = function (priority, callback) {
|
||||
return this.subscribe((ev) => {
|
||||
return ev.register(priority, (processNextHandler) => zone.run(() => callback(processNextHandler)));
|
||||
});
|
||||
};
|
||||
|
||||
@ -71,12 +73,19 @@ export class Platform {
|
||||
proxyEvent(this.keyboardDidHide, this.win, 'ionKeyboardDidHide');
|
||||
|
||||
let readyResolve: (value: string) => void;
|
||||
this._readyPromise = new Promise(res => { readyResolve = res; });
|
||||
if (this.win && this.win['cordova']) {
|
||||
doc.addEventListener('deviceready', () => {
|
||||
this._readyPromise = new Promise((res) => {
|
||||
readyResolve = res;
|
||||
});
|
||||
if (this.win?.['cordova']) {
|
||||
doc.addEventListener(
|
||||
'deviceready',
|
||||
() => {
|
||||
readyResolve('cordova');
|
||||
}, { once: true });
|
||||
},
|
||||
{ once: true }
|
||||
);
|
||||
} else {
|
||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||
readyResolve!('dom');
|
||||
}
|
||||
});
|
||||
@ -213,25 +222,25 @@ export class Platform {
|
||||
* Returns `true` if the app is in portrait mode.
|
||||
*/
|
||||
isPortrait(): boolean {
|
||||
return this.win.matchMedia && this.win.matchMedia('(orientation: portrait)').matches;
|
||||
return this.win.matchMedia?.('(orientation: portrait)').matches;
|
||||
}
|
||||
|
||||
testUserAgent(expression: string): boolean {
|
||||
const nav = this.win.navigator;
|
||||
return !!(nav && nav.userAgent && nav.userAgent.indexOf(expression) >= 0);
|
||||
return !!(nav?.userAgent && nav.userAgent.indexOf(expression) >= 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current url.
|
||||
*/
|
||||
url() {
|
||||
url(): string {
|
||||
return this.win.location.href;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the width of the platform's viewport using `window.innerWidth`.
|
||||
*/
|
||||
width() {
|
||||
width(): number {
|
||||
return this.win.innerWidth;
|
||||
}
|
||||
|
||||
@ -244,17 +253,17 @@ export class Platform {
|
||||
}
|
||||
|
||||
const readQueryParam = (url: string, key: string) => {
|
||||
key = key.replace(/[\[]/, '\\[').replace(/[\]]/, '\\]');
|
||||
key = key.replace(/[[]/, '\\[').replace(/[\]]/, '\\]');
|
||||
const regex = new RegExp('[\\?&]' + key + '=([^&#]*)');
|
||||
const results = regex.exec(url);
|
||||
return results ? decodeURIComponent(results[1].replace(/\+/g, ' ')) : null;
|
||||
};
|
||||
|
||||
const proxyEvent = <T>(emitter: Subject<T>, el: EventTarget, eventName: string) => {
|
||||
if ((el as any)) {
|
||||
if (el as any) {
|
||||
el.addEventListener(eventName, (ev: Event | undefined | null) => {
|
||||
// ?? cordova might emit "null" events
|
||||
emitter.next(ev != null ? (ev as any).detail as T : undefined);
|
||||
emitter.next(ev != null ? ((ev as any).detail as T) : undefined);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { ComponentFactoryResolver, Injectable, Injector } from '@angular/core';
|
||||
import { ComponentFactoryResolver, Injector, Injectable } from '@angular/core';
|
||||
import { PopoverOptions, popoverController } from '@ionic/core';
|
||||
|
||||
import { OverlayBaseController } from '../util/overlay';
|
||||
@ -7,11 +7,10 @@ import { AngularDelegate } from './angular-delegate';
|
||||
|
||||
@Injectable()
|
||||
export class PopoverController extends OverlayBaseController<PopoverOptions, HTMLIonPopoverElement> {
|
||||
|
||||
constructor(
|
||||
private angularDelegate: AngularDelegate,
|
||||
private resolver: ComponentFactoryResolver,
|
||||
private injector: Injector,
|
||||
private injector: Injector
|
||||
) {
|
||||
super(popoverController);
|
||||
}
|
||||
@ -19,7 +18,7 @@ export class PopoverController extends OverlayBaseController<PopoverOptions, HTM
|
||||
create(opts: PopoverOptions): Promise<HTMLIonPopoverElement> {
|
||||
return super.create({
|
||||
...opts,
|
||||
delegate: this.angularDelegate.create(this.resolver, this.injector)
|
||||
delegate: this.angularDelegate.create(this.resolver, this.injector),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -1,8 +1,21 @@
|
||||
import { join, Path } from '@angular-devkit/core';
|
||||
import { apply, chain, mergeWith, move, Rule, SchematicContext, SchematicsException, template, Tree, url } from '@angular-devkit/schematics';
|
||||
import { Path, join } from '@angular-devkit/core';
|
||||
import {
|
||||
Rule,
|
||||
SchematicContext,
|
||||
Tree,
|
||||
apply,
|
||||
chain,
|
||||
mergeWith,
|
||||
move,
|
||||
SchematicsException,
|
||||
template,
|
||||
url,
|
||||
} from '@angular-devkit/schematics';
|
||||
import { NodePackageInstallTask } from '@angular-devkit/schematics/tasks';
|
||||
import { getWorkspace } from '@schematics/angular/utility/workspace';
|
||||
|
||||
import { addModuleImportToRootModule } from './../utils/ast';
|
||||
import { addArchitectBuilder, addAsset, addStyle, getDefaultAngularAppName, getWorkspace, WorkspaceProject, WorkspaceSchema } from './../utils/config';
|
||||
import { addArchitectBuilder, addAsset, addStyle, getDefaultAngularAppName } from './../utils/config';
|
||||
import { addPackageToPackageJson } from './../utils/package';
|
||||
import { Schema as IonAddOptions } from './schema';
|
||||
|
||||
@ -15,24 +28,14 @@ function addIonicAngularToPackageJson(): Rule {
|
||||
|
||||
function addIonicAngularToolkitToPackageJson(): Rule {
|
||||
return (host: Tree) => {
|
||||
addPackageToPackageJson(
|
||||
host,
|
||||
'devDependencies',
|
||||
'@ionic/angular-toolkit',
|
||||
'latest'
|
||||
);
|
||||
addPackageToPackageJson(host, 'devDependencies', '@ionic/angular-toolkit', 'latest');
|
||||
return host;
|
||||
};
|
||||
}
|
||||
|
||||
function addIonicAngularModuleToAppModule(projectSourceRoot: Path): Rule {
|
||||
return (host: Tree) => {
|
||||
addModuleImportToRootModule(
|
||||
host,
|
||||
projectSourceRoot,
|
||||
'IonicModule.forRoot()',
|
||||
'@ionic/angular'
|
||||
);
|
||||
addModuleImportToRootModule(host, projectSourceRoot, 'IonicModule.forRoot()', '@ionic/angular');
|
||||
return host;
|
||||
};
|
||||
}
|
||||
@ -50,10 +53,10 @@ function addIonicStyles(projectName: string, projectSourceRoot: Path): Rule {
|
||||
'node_modules/@ionic/angular/css/text-alignment.css',
|
||||
'node_modules/@ionic/angular/css/text-transformation.css',
|
||||
'node_modules/@ionic/angular/css/flex-utils.css',
|
||||
`${projectSourceRoot}/theme/variables.css`
|
||||
]
|
||||
`${projectSourceRoot}/theme/variables.css`,
|
||||
];
|
||||
|
||||
ionicStyles.forEach(entry => {
|
||||
ionicStyles.forEach((entry) => {
|
||||
addStyle(host, projectName, entry);
|
||||
});
|
||||
return host;
|
||||
@ -65,7 +68,7 @@ function addIonicons(projectName: string): Rule {
|
||||
const ioniconsGlob = {
|
||||
glob: '**/*.svg',
|
||||
input: 'node_modules/ionicons/dist/ionicons/svg',
|
||||
output: './svg'
|
||||
output: './svg',
|
||||
};
|
||||
addAsset(host, projectName, 'build', ioniconsGlob);
|
||||
addAsset(host, projectName, 'test', ioniconsGlob);
|
||||
@ -79,25 +82,25 @@ function addIonicBuilder(projectName: string): Rule {
|
||||
builder: '@ionic/angular-toolkit:cordova-serve',
|
||||
options: {
|
||||
cordovaBuildTarget: `${projectName}:ionic-cordova-build`,
|
||||
devServerTarget: `${projectName}:serve`
|
||||
devServerTarget: `${projectName}:serve`,
|
||||
},
|
||||
configurations: {
|
||||
production: {
|
||||
cordovaBuildTarget: `${projectName}:ionic-cordova-build:production`,
|
||||
devServerTarget: `${projectName}:serve:production`
|
||||
}
|
||||
}
|
||||
devServerTarget: `${projectName}:serve:production`,
|
||||
},
|
||||
},
|
||||
});
|
||||
addArchitectBuilder(host, projectName, 'ionic-cordova-build', {
|
||||
builder: '@ionic/angular-toolkit:cordova-build',
|
||||
options: {
|
||||
browserTarget: `${projectName}:build`
|
||||
browserTarget: `${projectName}:build`,
|
||||
},
|
||||
configurations: {
|
||||
production: {
|
||||
browserTarget: `${projectName}:build:production`
|
||||
}
|
||||
}
|
||||
browserTarget: `${projectName}:build:production`,
|
||||
},
|
||||
},
|
||||
});
|
||||
return host;
|
||||
};
|
||||
@ -110,22 +113,18 @@ function installNodeDeps() {
|
||||
}
|
||||
|
||||
export default function ngAdd(options: IonAddOptions): Rule {
|
||||
return (host: Tree) => {
|
||||
const workspace: WorkspaceSchema = getWorkspace(host);
|
||||
return async (host: Tree) => {
|
||||
const workspace = await getWorkspace(host);
|
||||
if (!options.project) {
|
||||
options.project = getDefaultAngularAppName(workspace);
|
||||
}
|
||||
const project: WorkspaceProject = workspace.projects[options.project];
|
||||
if (project.projectType !== 'application') {
|
||||
throw new SchematicsException(
|
||||
`Ionic Add requires a project type of "application".`
|
||||
);
|
||||
const project = workspace.projects.get(options.project);
|
||||
|
||||
if (!project || project.extensions.projectType !== 'application') {
|
||||
throw new SchematicsException(`Ionic Add requires a project type of "application".`);
|
||||
}
|
||||
const sourcePath: Path = join(project.sourceRoot as Path);
|
||||
const rootTemplateSource = apply(url('./files/root'), [
|
||||
template({ ...options }),
|
||||
move(sourcePath)
|
||||
]);
|
||||
const rootTemplateSource = apply(url('./files/root'), [template({ ...options }), move(sourcePath)]);
|
||||
return chain([
|
||||
// @ionic/angular
|
||||
addIonicAngularToPackageJson(),
|
||||
@ -136,7 +135,7 @@ export default function ngAdd(options: IonAddOptions): Rule {
|
||||
addIonicons(options.project),
|
||||
mergeWith(rootTemplateSource),
|
||||
// install freshly added dependencies
|
||||
installNodeDeps()
|
||||
installNodeDeps(),
|
||||
]);
|
||||
};
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"$schema": "http://json-schema.org/schema",
|
||||
"id": "ionicNgAdd",
|
||||
"$id": "ionicNgAdd",
|
||||
"title": "Ionic Add options",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
|
@ -1,6 +1,7 @@
|
||||
import { SchematicsException, Tree } from '@angular-devkit/schematics';
|
||||
import { normalize } from '@angular-devkit/core';
|
||||
import { Tree, SchematicsException } from '@angular-devkit/schematics';
|
||||
import * as ts from 'typescript';
|
||||
|
||||
import { addImportToModule } from './devkit-utils/ast-utils';
|
||||
import { InsertChange } from './devkit-utils/change';
|
||||
|
||||
@ -13,12 +14,7 @@ export function getSourceFile(host: Tree, path: string): ts.SourceFile {
|
||||
throw new SchematicsException(`Could not find file for path: ${path}`);
|
||||
}
|
||||
const content = buffer.toString();
|
||||
const source = ts.createSourceFile(
|
||||
path,
|
||||
content,
|
||||
ts.ScriptTarget.Latest,
|
||||
true
|
||||
);
|
||||
const source = ts.createSourceFile(path, content, ts.ScriptTarget.Latest, true);
|
||||
return source;
|
||||
}
|
||||
|
||||
@ -30,13 +26,8 @@ export function addModuleImportToRootModule(
|
||||
projectSourceRoot: string,
|
||||
moduleName: string,
|
||||
importSrc: string
|
||||
) {
|
||||
addModuleImportToModule(
|
||||
host,
|
||||
normalize(`${projectSourceRoot}/app/app.module.ts`),
|
||||
moduleName,
|
||||
importSrc
|
||||
);
|
||||
): void {
|
||||
addModuleImportToModule(host, normalize(`${projectSourceRoot}/app/app.module.ts`), moduleName, importSrc);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -46,17 +37,12 @@ export function addModuleImportToRootModule(
|
||||
* @param moduleName name of module to import
|
||||
* @param src src location to import
|
||||
*/
|
||||
export function addModuleImportToModule(
|
||||
host: Tree,
|
||||
modulePath: string,
|
||||
moduleName: string,
|
||||
src: string
|
||||
) {
|
||||
export function addModuleImportToModule(host: Tree, modulePath: string, moduleName: string, src: string): void {
|
||||
const moduleSource = getSourceFile(host, modulePath);
|
||||
const changes = addImportToModule(moduleSource, modulePath, moduleName, src);
|
||||
const recorder = host.beginUpdate(modulePath);
|
||||
|
||||
changes.forEach(change => {
|
||||
changes.forEach((change) => {
|
||||
if (change instanceof InsertChange) {
|
||||
recorder.insertLeft(change.pos, change.toAdd);
|
||||
}
|
||||
|
@ -1,18 +1,19 @@
|
||||
import { SchematicsException, Tree } from '@angular-devkit/schematics';
|
||||
import { experimental, parseJson, JsonParseMode } from '@angular-devkit/core';
|
||||
import { WorkspaceDefinition } from '@angular-devkit/core/src/workspace';
|
||||
import { Tree, SchematicsException } from '@angular-devkit/schematics';
|
||||
import { parse } from 'jsonc-parser';
|
||||
|
||||
const CONFIG_PATH = 'angular.json';
|
||||
|
||||
export function readConfig(host: Tree) {
|
||||
const sourceText = host.read(CONFIG_PATH)!.toString('utf-8');
|
||||
export function readConfig(host: Tree): any {
|
||||
const sourceText = host.read(CONFIG_PATH)?.toString('utf-8');
|
||||
return JSON.parse(sourceText);
|
||||
}
|
||||
|
||||
export function writeConfig(host: Tree, config: JSON) {
|
||||
export function writeConfig(host: Tree, config: JSON): void {
|
||||
host.overwrite(CONFIG_PATH, JSON.stringify(config, null, 2));
|
||||
}
|
||||
|
||||
function isAngularBrowserProject(projectConfig: any) {
|
||||
function isAngularBrowserProject(projectConfig: any): boolean {
|
||||
if (projectConfig.projectType === 'application') {
|
||||
const buildConfig = projectConfig.architect.build;
|
||||
return buildConfig.builder === '@angular-devkit/build-angular:browser';
|
||||
@ -36,6 +37,7 @@ export function getDefaultAngularAppName(config: any): string {
|
||||
}
|
||||
|
||||
export function getAngularAppConfig(config: any, projectName: string): any | never {
|
||||
// eslint-disable-next-line no-prototype-builtins
|
||||
if (!config.projects.hasOwnProperty(projectName)) {
|
||||
throw new SchematicsException(`Could not find project: ${projectName}`);
|
||||
}
|
||||
@ -53,40 +55,50 @@ export function getAngularAppConfig(config: any, projectName: string): any | nev
|
||||
}
|
||||
}
|
||||
|
||||
export function addStyle(host: Tree, projectName: string, stylePath: string) {
|
||||
export function addStyle(host: Tree, projectName: string, stylePath: string): void {
|
||||
const config = readConfig(host);
|
||||
const appConfig = getAngularAppConfig(config, projectName);
|
||||
appConfig.architect.build.options.styles.push({
|
||||
input: stylePath
|
||||
input: stylePath,
|
||||
});
|
||||
writeConfig(host, config);
|
||||
}
|
||||
|
||||
export function addAsset(host: Tree, projectName: string, architect: string, asset: string | {glob: string; input: string; output: string}) {
|
||||
export function addAsset(
|
||||
host: Tree,
|
||||
projectName: string,
|
||||
architect: string,
|
||||
asset: string | { glob: string; input: string; output: string }
|
||||
): void {
|
||||
const config = readConfig(host);
|
||||
const appConfig = getAngularAppConfig(config, projectName);
|
||||
appConfig.architect[architect].options.assets.push(asset);
|
||||
const target = appConfig.architect[architect];
|
||||
if (target) {
|
||||
target.options.assets.push(asset);
|
||||
writeConfig(host, config);
|
||||
}
|
||||
}
|
||||
|
||||
export function addArchitectBuilder(host: Tree, projectName: string, builderName: string, builderOpts: any): void | never {
|
||||
export function addArchitectBuilder(
|
||||
host: Tree,
|
||||
projectName: string,
|
||||
builderName: string,
|
||||
builderOpts: any
|
||||
): void | never {
|
||||
const config = readConfig(host);
|
||||
const appConfig = getAngularAppConfig(config, projectName);
|
||||
appConfig.architect[builderName] = builderOpts;
|
||||
writeConfig(host, config);
|
||||
}
|
||||
|
||||
export type WorkspaceSchema = experimental.workspace.WorkspaceSchema;
|
||||
export type WorkspaceProject = experimental.workspace.WorkspaceProject;
|
||||
|
||||
export function getWorkspacePath(host: Tree): string {
|
||||
const possibleFiles = ['/angular.json', '/.angular.json'];
|
||||
const path = possibleFiles.filter(path => host.exists(path))[0];
|
||||
const path = possibleFiles.filter((path) => host.exists(path))[0];
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
export function getWorkspace(host: Tree): WorkspaceSchema {
|
||||
export function getWorkspace(host: Tree): WorkspaceDefinition {
|
||||
const path = getWorkspacePath(host);
|
||||
const configBuffer = host.read(path);
|
||||
if (configBuffer === null) {
|
||||
@ -94,5 +106,5 @@ export function getWorkspace(host: Tree): WorkspaceSchema {
|
||||
}
|
||||
const content = configBuffer.toString();
|
||||
|
||||
return (parseJson(content, JsonParseMode.Loose) as {}) as WorkspaceSchema;
|
||||
return parse(content) as WorkspaceDefinition;
|
||||
}
|
||||
|
@ -6,8 +6,8 @@
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
import * as ts from 'typescript';
|
||||
import { Change, InsertChange, NoopChange } from './change';
|
||||
|
||||
import { Change, InsertChange, NoopChange } from './change';
|
||||
|
||||
/**
|
||||
* Add Import `import { symbolName } from fileName` if the import doesn't exit
|
||||
@ -18,26 +18,32 @@ import { Change, InsertChange, NoopChange } from './change';
|
||||
* @param isDefault (if true, import follows style for importing default exports)
|
||||
* @return Change
|
||||
*/
|
||||
export function insertImport(source: ts.SourceFile, fileToEdit: string, symbolName: string,
|
||||
fileName: string, isDefault = false): Change {
|
||||
export function insertImport(
|
||||
source: ts.SourceFile,
|
||||
fileToEdit: string,
|
||||
symbolName: string,
|
||||
fileName: string,
|
||||
isDefault = false
|
||||
): Change {
|
||||
const rootNode = source;
|
||||
const allImports = findNodes(rootNode, ts.SyntaxKind.ImportDeclaration);
|
||||
|
||||
// get nodes that map to import statements from the file fileName
|
||||
const relevantImports = allImports.filter(node => {
|
||||
const relevantImports = allImports.filter((node) => {
|
||||
// StringLiteral of the ImportDeclaration is the import file (fileName in this case).
|
||||
const importFiles = node.getChildren()
|
||||
.filter(child => child.kind === ts.SyntaxKind.StringLiteral)
|
||||
.map(n => (n as ts.StringLiteral).text);
|
||||
const importFiles = node
|
||||
.getChildren()
|
||||
.filter((child) => child.kind === ts.SyntaxKind.StringLiteral)
|
||||
.map((n) => (n as ts.StringLiteral).text);
|
||||
|
||||
return importFiles.filter(file => file === fileName).length === 1;
|
||||
return importFiles.filter((file) => file === fileName).length === 1;
|
||||
});
|
||||
|
||||
if (relevantImports.length > 0) {
|
||||
let importsAsterisk = false;
|
||||
// imports from import file
|
||||
const imports: ts.Node[] = [];
|
||||
relevantImports.forEach(n => {
|
||||
relevantImports.forEach((n) => {
|
||||
Array.prototype.push.apply(imports, findNodes(n, ts.SyntaxKind.Identifier));
|
||||
if (findNodes(n, ts.SyntaxKind.AsteriskToken).length > 0) {
|
||||
importsAsterisk = true;
|
||||
@ -49,7 +55,7 @@ export function insertImport(source: ts.SourceFile, fileToEdit: string, symbolNa
|
||||
return new NoopChange();
|
||||
}
|
||||
|
||||
const importTextNodes = imports.filter(n => (n as ts.Identifier).text === symbolName);
|
||||
const importTextNodes = imports.filter((n) => (n as ts.Identifier).text === symbolName);
|
||||
|
||||
// insert import if it's not there
|
||||
if (importTextNodes.length === 0) {
|
||||
@ -64,8 +70,9 @@ export function insertImport(source: ts.SourceFile, fileToEdit: string, symbolNa
|
||||
}
|
||||
|
||||
// no such import declaration exists
|
||||
const useStrict = findNodes(rootNode, ts.SyntaxKind.StringLiteral)
|
||||
.filter((n: ts.StringLiteral) => n.text === 'use strict');
|
||||
const useStrict = findNodes(rootNode, ts.SyntaxKind.StringLiteral).filter(
|
||||
(n: ts.StringLiteral) => n.text === 'use strict'
|
||||
);
|
||||
let fallbackPos = 0;
|
||||
if (useStrict.length > 0) {
|
||||
fallbackPos = useStrict[0].end;
|
||||
@ -75,19 +82,12 @@ export function insertImport(source: ts.SourceFile, fileToEdit: string, symbolNa
|
||||
// if there are no imports or 'use strict' statement, insert import at beginning of file
|
||||
const insertAtBeginning = allImports.length === 0 && useStrict.length === 0;
|
||||
const separator = insertAtBeginning ? '' : ';\n';
|
||||
const toInsert = `${separator}import ${open}${symbolName}${close}` +
|
||||
` from '${fileName}'${insertAtBeginning ? ';\n' : ''}`;
|
||||
const toInsert =
|
||||
`${separator}import ${open}${symbolName}${close}` + ` from '${fileName}'${insertAtBeginning ? ';\n' : ''}`;
|
||||
|
||||
return insertAfterLastOccurrence(
|
||||
allImports,
|
||||
toInsert,
|
||||
fileToEdit,
|
||||
fallbackPos,
|
||||
ts.SyntaxKind.StringLiteral,
|
||||
);
|
||||
return insertAfterLastOccurrence(allImports, toInsert, fileToEdit, fallbackPos, ts.SyntaxKind.StringLiteral);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Find all nodes from the AST in the subtree of node of SyntaxKind kind.
|
||||
* @param node
|
||||
@ -107,7 +107,7 @@ export function findNodes(node: ts.Node, kind: ts.SyntaxKind, max = Infinity): t
|
||||
}
|
||||
if (max > 0) {
|
||||
for (const child of node.getChildren()) {
|
||||
findNodes(child, kind, max).forEach(node => {
|
||||
findNodes(child, kind, max).forEach((node) => {
|
||||
if (max > 0) {
|
||||
arr.push(node);
|
||||
}
|
||||
@ -123,7 +123,6 @@ export function findNodes(node: ts.Node, kind: ts.SyntaxKind, max = Infinity): t
|
||||
return arr;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get all the nodes from a source.
|
||||
* @param sourceFile The source file object.
|
||||
@ -154,14 +153,13 @@ export function findNode(node: ts.Node, kind: ts.SyntaxKind, text: string): ts.N
|
||||
}
|
||||
|
||||
let foundNode: ts.Node | null = null;
|
||||
ts.forEachChild(node, childNode => {
|
||||
ts.forEachChild(node, (childNode) => {
|
||||
foundNode = foundNode || findNode(childNode, kind, text);
|
||||
});
|
||||
|
||||
return foundNode;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Helper for sorting nodes.
|
||||
* @return function to sort nodes in increasing order of position in sourceFile
|
||||
@ -170,7 +168,6 @@ function nodesByPosition(first: ts.Node, second: ts.Node): number {
|
||||
return first.getStart() - second.getStart();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Insert `toInsert` after the last occurence of `ts.SyntaxKind[nodes[i].kind]`
|
||||
* or after the last of occurence of `syntaxKind` if the last occurence is a sub child
|
||||
@ -184,11 +181,13 @@ function nodesByPosition(first: ts.Node, second: ts.Node): number {
|
||||
* @return Change instance
|
||||
* @throw Error if toInsert is first occurence but fall back is not set
|
||||
*/
|
||||
export function insertAfterLastOccurrence(nodes: ts.Node[],
|
||||
export function insertAfterLastOccurrence(
|
||||
nodes: ts.Node[],
|
||||
toInsert: string,
|
||||
file: string,
|
||||
fallbackPos: number,
|
||||
syntaxKind?: ts.SyntaxKind): Change {
|
||||
syntaxKind?: ts.SyntaxKind
|
||||
): Change {
|
||||
// sort() has a side effect, so make a copy so that we won't overwrite the parent's object.
|
||||
let lastItem = [...nodes].sort(nodesByPosition).pop();
|
||||
if (!lastItem) {
|
||||
@ -205,7 +204,6 @@ export function insertAfterLastOccurrence(nodes: ts.Node[],
|
||||
return new InsertChange(file, lastItemPosition, toInsert);
|
||||
}
|
||||
|
||||
|
||||
export function getContentOfKeyLiteral(_source: ts.SourceFile, node: ts.Node): string | null {
|
||||
if (node.kind == ts.SyntaxKind.Identifier) {
|
||||
return (node as ts.Identifier).text;
|
||||
@ -216,9 +214,11 @@ export function getContentOfKeyLiteral(_source: ts.SourceFile, node: ts.Node): s
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function _angularImportsFromNode(node: ts.ImportDeclaration,
|
||||
_sourceFile: ts.SourceFile): {[name: string]: string} {
|
||||
function _angularImportsFromNode(
|
||||
node: ts.ImportDeclaration,
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
_sourceFile: ts.SourceFile
|
||||
): { [name: string]: string } {
|
||||
const ms = node.moduleSpecifier;
|
||||
let modulePath: string;
|
||||
switch (ms.kind) {
|
||||
@ -249,8 +249,8 @@ function _angularImportsFromNode(node: ts.ImportDeclaration,
|
||||
const namedImports = nb as ts.NamedImports;
|
||||
|
||||
return namedImports.elements
|
||||
.map((is: ts.ImportSpecifier) => is.propertyName ? is.propertyName.text : is.name.text)
|
||||
.reduce((acc: {[name: string]: string}, curr: string) => {
|
||||
.map((is: ts.ImportSpecifier) => (is.propertyName ? is.propertyName.text : is.name.text))
|
||||
.reduce((acc: { [name: string]: string }, curr: string) => {
|
||||
acc[curr] = modulePath;
|
||||
|
||||
return acc;
|
||||
@ -265,13 +265,10 @@ function _angularImportsFromNode(node: ts.ImportDeclaration,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export function getDecoratorMetadata(source: ts.SourceFile, identifier: string,
|
||||
module: string): ts.Node[] {
|
||||
const angularImports: {[name: string]: string}
|
||||
= findNodes(source, ts.SyntaxKind.ImportDeclaration)
|
||||
export function getDecoratorMetadata(source: ts.SourceFile, identifier: string, module: string): ts.Node[] {
|
||||
const angularImports: { [name: string]: string } = findNodes(source, ts.SyntaxKind.ImportDeclaration)
|
||||
.map((node: ts.ImportDeclaration) => _angularImportsFromNode(node, source))
|
||||
.reduce((acc: {[name: string]: string}, current: {[name: string]: string}) => {
|
||||
.reduce((acc: { [name: string]: string }, current: { [name: string]: string }) => {
|
||||
for (const key of Object.keys(current)) {
|
||||
acc[key] = current[key];
|
||||
}
|
||||
@ -280,17 +277,17 @@ export function getDecoratorMetadata(source: ts.SourceFile, identifier: string,
|
||||
}, {});
|
||||
|
||||
return getSourceNodes(source)
|
||||
.filter(node => {
|
||||
return node.kind == ts.SyntaxKind.Decorator
|
||||
&& (node as ts.Decorator).expression.kind == ts.SyntaxKind.CallExpression;
|
||||
.filter((node) => {
|
||||
return (
|
||||
node.kind == ts.SyntaxKind.Decorator && (node as ts.Decorator).expression.kind == ts.SyntaxKind.CallExpression
|
||||
);
|
||||
})
|
||||
.map(node => (node as ts.Decorator).expression as ts.CallExpression)
|
||||
.filter(expr => {
|
||||
.map((node) => (node as ts.Decorator).expression as ts.CallExpression)
|
||||
.filter((expr) => {
|
||||
if (expr.expression.kind == ts.SyntaxKind.Identifier) {
|
||||
const id = expr.expression as ts.Identifier;
|
||||
|
||||
return id.getFullText(source) == identifier
|
||||
&& angularImports[id.getFullText(source)] === module;
|
||||
return id.getFullText(source) == identifier && angularImports[id.getFullText(source)] === module;
|
||||
} else if (expr.expression.kind == ts.SyntaxKind.PropertyAccessExpression) {
|
||||
// This covers foo.NgModule when importing * as foo.
|
||||
const paExpr = expr.expression as ts.PropertyAccessExpression;
|
||||
@ -302,17 +299,16 @@ export function getDecoratorMetadata(source: ts.SourceFile, identifier: string,
|
||||
const id = paExpr.name.text;
|
||||
const moduleId = (paExpr.expression as ts.Identifier).getText(source);
|
||||
|
||||
return id === identifier && (angularImports[moduleId + '.'] === module);
|
||||
return id === identifier && angularImports[moduleId + '.'] === module;
|
||||
}
|
||||
|
||||
return false;
|
||||
})
|
||||
.filter(expr => expr.arguments[0]
|
||||
&& expr.arguments[0].kind == ts.SyntaxKind.ObjectLiteralExpression)
|
||||
.map(expr => expr.arguments[0] as ts.ObjectLiteralExpression);
|
||||
.filter((expr) => expr.arguments[0] && expr.arguments[0].kind == ts.SyntaxKind.ObjectLiteralExpression)
|
||||
.map((expr) => expr.arguments[0] as ts.ObjectLiteralExpression);
|
||||
}
|
||||
|
||||
function findClassDeclarationParent(node: ts.Node): ts.ClassDeclaration|undefined {
|
||||
function findClassDeclarationParent(node: ts.Node): ts.ClassDeclaration | undefined {
|
||||
if (ts.isClassDeclaration(node)) {
|
||||
return node;
|
||||
}
|
||||
@ -326,7 +322,7 @@ function findClassDeclarationParent(node: ts.Node): ts.ClassDeclaration|undefine
|
||||
* @param source source file containing one or more @NgModule
|
||||
* @returns the name of the first @NgModule, or `undefined` if none is found
|
||||
*/
|
||||
export function getFirstNgModuleName(source: ts.SourceFile): string|undefined {
|
||||
export function getFirstNgModuleName(source: ts.SourceFile): string | undefined {
|
||||
// First, find the @NgModule decorators.
|
||||
const ngModulesMetadata = getDecoratorMetadata(source, 'NgModule', '@angular/core');
|
||||
if (ngModulesMetadata.length === 0) {
|
||||
@ -349,7 +345,7 @@ export function addSymbolToNgModuleMetadata(
|
||||
ngModulePath: string,
|
||||
metadataField: string,
|
||||
symbolName: string,
|
||||
importPath: string | null = null,
|
||||
importPath: string | null = null
|
||||
): Change[] {
|
||||
const nodes = getDecoratorMetadata(source, 'NgModule', '@angular/core');
|
||||
let node: any = nodes[0]; // tslint:disable-line:no-any
|
||||
@ -360,9 +356,8 @@ export function addSymbolToNgModuleMetadata(
|
||||
}
|
||||
|
||||
// Get all the children property assignment of object literals.
|
||||
const matchingProperties: ts.ObjectLiteralElement[] =
|
||||
(node as ts.ObjectLiteralExpression).properties
|
||||
.filter(prop => prop.kind == ts.SyntaxKind.PropertyAssignment)
|
||||
const matchingProperties: ts.ObjectLiteralElement[] = (node as ts.ObjectLiteralExpression).properties
|
||||
.filter((prop) => prop.kind == ts.SyntaxKind.PropertyAssignment)
|
||||
// Filter out every fields that's not "metadataField". Also handles string literals
|
||||
// (but not expressions).
|
||||
.filter((prop: ts.PropertyAssignment) => {
|
||||
@ -432,8 +427,9 @@ export function addSymbolToNgModuleMetadata(
|
||||
}
|
||||
|
||||
if (Array.isArray(node)) {
|
||||
const nodeArray = node as {} as Array<ts.Node>;
|
||||
const symbolsArray = nodeArray.map(node => node.getText());
|
||||
// eslint-disable-next-line @typescript-eslint/ban-types
|
||||
const nodeArray = node as {} as ts.Node[];
|
||||
const symbolsArray = nodeArray.map((node) => node.getText());
|
||||
if (symbolsArray.includes(symbolName)) {
|
||||
return [];
|
||||
}
|
||||
@ -488,81 +484,93 @@ export function addSymbolToNgModuleMetadata(
|
||||
* Custom function to insert a declaration (component, pipe, directive)
|
||||
* into NgModule declarations. It also imports the component.
|
||||
*/
|
||||
export function addDeclarationToModule(source: ts.SourceFile,
|
||||
modulePath: string, classifiedName: string,
|
||||
importPath: string): Change[] {
|
||||
return addSymbolToNgModuleMetadata(
|
||||
source, modulePath, 'declarations', classifiedName, importPath);
|
||||
export function addDeclarationToModule(
|
||||
source: ts.SourceFile,
|
||||
modulePath: string,
|
||||
classifiedName: string,
|
||||
importPath: string
|
||||
): Change[] {
|
||||
return addSymbolToNgModuleMetadata(source, modulePath, 'declarations', classifiedName, importPath);
|
||||
}
|
||||
|
||||
/**
|
||||
* Custom function to insert an NgModule into NgModule imports. It also imports the module.
|
||||
*/
|
||||
export function addImportToModule(source: ts.SourceFile,
|
||||
modulePath: string, classifiedName: string,
|
||||
importPath: string): Change[] {
|
||||
|
||||
export function addImportToModule(
|
||||
source: ts.SourceFile,
|
||||
modulePath: string,
|
||||
classifiedName: string,
|
||||
importPath: string
|
||||
): Change[] {
|
||||
return addSymbolToNgModuleMetadata(source, modulePath, 'imports', classifiedName, importPath);
|
||||
}
|
||||
|
||||
/**
|
||||
* Custom function to insert a provider into NgModule. It also imports it.
|
||||
*/
|
||||
export function addProviderToModule(source: ts.SourceFile,
|
||||
modulePath: string, classifiedName: string,
|
||||
importPath: string): Change[] {
|
||||
export function addProviderToModule(
|
||||
source: ts.SourceFile,
|
||||
modulePath: string,
|
||||
classifiedName: string,
|
||||
importPath: string
|
||||
): Change[] {
|
||||
return addSymbolToNgModuleMetadata(source, modulePath, 'providers', classifiedName, importPath);
|
||||
}
|
||||
|
||||
/**
|
||||
* Custom function to insert an export into NgModule. It also imports it.
|
||||
*/
|
||||
export function addExportToModule(source: ts.SourceFile,
|
||||
modulePath: string, classifiedName: string,
|
||||
importPath: string): Change[] {
|
||||
export function addExportToModule(
|
||||
source: ts.SourceFile,
|
||||
modulePath: string,
|
||||
classifiedName: string,
|
||||
importPath: string
|
||||
): Change[] {
|
||||
return addSymbolToNgModuleMetadata(source, modulePath, 'exports', classifiedName, importPath);
|
||||
}
|
||||
|
||||
/**
|
||||
* Custom function to insert an export into NgModule. It also imports it.
|
||||
*/
|
||||
export function addBootstrapToModule(source: ts.SourceFile,
|
||||
modulePath: string, classifiedName: string,
|
||||
importPath: string): Change[] {
|
||||
export function addBootstrapToModule(
|
||||
source: ts.SourceFile,
|
||||
modulePath: string,
|
||||
classifiedName: string,
|
||||
importPath: string
|
||||
): Change[] {
|
||||
return addSymbolToNgModuleMetadata(source, modulePath, 'bootstrap', classifiedName, importPath);
|
||||
}
|
||||
|
||||
/**
|
||||
* Custom function to insert an entryComponent into NgModule. It also imports it.
|
||||
*/
|
||||
export function addEntryComponentToModule(source: ts.SourceFile,
|
||||
modulePath: string, classifiedName: string,
|
||||
importPath: string): Change[] {
|
||||
return addSymbolToNgModuleMetadata(
|
||||
source, modulePath,
|
||||
'entryComponents', classifiedName, importPath,
|
||||
);
|
||||
export function addEntryComponentToModule(
|
||||
source: ts.SourceFile,
|
||||
modulePath: string,
|
||||
classifiedName: string,
|
||||
importPath: string
|
||||
): Change[] {
|
||||
return addSymbolToNgModuleMetadata(source, modulePath, 'entryComponents', classifiedName, importPath);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if an import already exists.
|
||||
*/
|
||||
export function isImported(source: ts.SourceFile,
|
||||
classifiedName: string,
|
||||
importPath: string): boolean {
|
||||
export function isImported(source: ts.SourceFile, classifiedName: string, importPath: string): boolean {
|
||||
const allNodes = getSourceNodes(source);
|
||||
const matchingNodes = allNodes
|
||||
.filter(node => node.kind === ts.SyntaxKind.ImportDeclaration)
|
||||
.filter((node) => node.kind === ts.SyntaxKind.ImportDeclaration)
|
||||
.filter((imp: ts.ImportDeclaration) => imp.moduleSpecifier.kind === ts.SyntaxKind.StringLiteral)
|
||||
.filter((imp: ts.ImportDeclaration) => {
|
||||
return (<ts.StringLiteral> imp.moduleSpecifier).text === importPath;
|
||||
return (imp.moduleSpecifier as ts.StringLiteral).text === importPath;
|
||||
})
|
||||
.filter((imp: ts.ImportDeclaration) => {
|
||||
if (!imp.importClause) {
|
||||
return false;
|
||||
}
|
||||
const nodes = findNodes(imp.importClause, ts.SyntaxKind.ImportSpecifier)
|
||||
.filter(n => n.getText() === classifiedName);
|
||||
const nodes = findNodes(imp.importClause, ts.SyntaxKind.ImportSpecifier).filter(
|
||||
(n) => n.getText() === classifiedName
|
||||
);
|
||||
|
||||
return nodes.length > 0;
|
||||
});
|
||||
|
@ -10,7 +10,6 @@ export interface Host {
|
||||
read(path: string): Promise<string>;
|
||||
}
|
||||
|
||||
|
||||
export interface Change {
|
||||
apply(host: Host): Promise<void>;
|
||||
|
||||
@ -26,7 +25,6 @@ export interface Change {
|
||||
readonly description: string;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* An operation that does nothing.
|
||||
*/
|
||||
@ -34,15 +32,15 @@ export class NoopChange implements Change {
|
||||
description = 'No operation.';
|
||||
order = Infinity;
|
||||
path = null;
|
||||
apply() { return Promise.resolve(); }
|
||||
apply(): Promise<void> {
|
||||
return Promise.resolve();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Will add text to the source code.
|
||||
*/
|
||||
export class InsertChange implements Change {
|
||||
|
||||
order: number;
|
||||
description: string;
|
||||
|
||||
@ -57,8 +55,8 @@ export class InsertChange implements Change {
|
||||
/**
|
||||
* This method does not insert spaces if there is none in the original string.
|
||||
*/
|
||||
apply(host: Host) {
|
||||
return host.read(this.path).then(content => {
|
||||
apply(host: Host): Promise<void> {
|
||||
return host.read(this.path).then((content) => {
|
||||
const prefix = content.substring(0, this.pos);
|
||||
const suffix = content.substring(this.pos);
|
||||
|
||||
@ -71,7 +69,6 @@ export class InsertChange implements Change {
|
||||
* Will remove text from the source code.
|
||||
*/
|
||||
export class RemoveChange implements Change {
|
||||
|
||||
order: number;
|
||||
description: string;
|
||||
|
||||
@ -84,7 +81,7 @@ export class RemoveChange implements Change {
|
||||
}
|
||||
|
||||
apply(host: Host): Promise<void> {
|
||||
return host.read(this.path).then(content => {
|
||||
return host.read(this.path).then((content) => {
|
||||
const prefix = content.substring(0, this.pos);
|
||||
const suffix = content.substring(this.pos + this.toRemove.length);
|
||||
|
||||
@ -101,8 +98,7 @@ export class ReplaceChange implements Change {
|
||||
order: number;
|
||||
description: string;
|
||||
|
||||
constructor(public path: string, private pos: number, private oldText: string,
|
||||
private newText: string) {
|
||||
constructor(public path: string, private pos: number, private oldText: string, private newText: string) {
|
||||
if (pos < 0) {
|
||||
throw new Error('Negative positions are invalid');
|
||||
}
|
||||
@ -111,7 +107,7 @@ export class ReplaceChange implements Change {
|
||||
}
|
||||
|
||||
apply(host: Host): Promise<void> {
|
||||
return host.read(this.path).then(content => {
|
||||
return host.read(this.path).then((content) => {
|
||||
const prefix = content.substring(0, this.pos);
|
||||
const suffix = content.substring(this.pos + this.oldText.length);
|
||||
const text = content.substring(this.pos, this.pos + this.oldText.length);
|
||||
|
@ -3,5 +3,3 @@
|
||||
These are utility files copied over from `@angular-devkit`.
|
||||
They are not exported so they need to be manually copied over.
|
||||
Please do not edit directly.
|
||||
|
||||
|
||||
|
@ -6,6 +6,7 @@
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
import * as ts from 'typescript';
|
||||
|
||||
import { findNodes, insertAfterLastOccurrence } from './ast-utils';
|
||||
import { Change, NoopChange } from './change';
|
||||
|
||||
@ -30,25 +31,22 @@ export function insertImport(
|
||||
const allImports = findNodes(rootNode, ts.SyntaxKind.ImportDeclaration);
|
||||
|
||||
// get nodes that map to import statements from the file fileName
|
||||
const relevantImports = allImports.filter(node => {
|
||||
const relevantImports = allImports.filter((node) => {
|
||||
// StringLiteral of the ImportDeclaration is the import file (fileName in this case).
|
||||
const importFiles = node
|
||||
.getChildren()
|
||||
.filter(child => child.kind === ts.SyntaxKind.StringLiteral)
|
||||
.map(n => (n as ts.StringLiteral).text);
|
||||
.filter((child) => child.kind === ts.SyntaxKind.StringLiteral)
|
||||
.map((n) => (n as ts.StringLiteral).text);
|
||||
|
||||
return importFiles.filter(file => file === fileName).length === 1;
|
||||
return importFiles.filter((file) => file === fileName).length === 1;
|
||||
});
|
||||
|
||||
if (relevantImports.length > 0) {
|
||||
let importsAsterisk = false;
|
||||
// imports from import file
|
||||
const imports: ts.Node[] = [];
|
||||
relevantImports.forEach(n => {
|
||||
Array.prototype.push.apply(
|
||||
imports,
|
||||
findNodes(n, ts.SyntaxKind.Identifier)
|
||||
);
|
||||
relevantImports.forEach((n) => {
|
||||
Array.prototype.push.apply(imports, findNodes(n, ts.SyntaxKind.Identifier));
|
||||
if (findNodes(n, ts.SyntaxKind.AsteriskToken).length > 0) {
|
||||
importsAsterisk = true;
|
||||
}
|
||||
@ -59,25 +57,15 @@ export function insertImport(
|
||||
return new NoopChange();
|
||||
}
|
||||
|
||||
const importTextNodes = imports.filter(
|
||||
n => (n as ts.Identifier).text === symbolName
|
||||
);
|
||||
const importTextNodes = imports.filter((n) => (n as ts.Identifier).text === symbolName);
|
||||
|
||||
// insert import if it's not there
|
||||
if (importTextNodes.length === 0) {
|
||||
const fallbackPos =
|
||||
findNodes(
|
||||
relevantImports[0],
|
||||
ts.SyntaxKind.CloseBraceToken
|
||||
)[0].getStart() ||
|
||||
findNodes(relevantImports[0], ts.SyntaxKind.CloseBraceToken)[0].getStart() ||
|
||||
findNodes(relevantImports[0], ts.SyntaxKind.FromKeyword)[0].getStart();
|
||||
|
||||
return insertAfterLastOccurrence(
|
||||
imports,
|
||||
`, ${symbolName}`,
|
||||
fileToEdit,
|
||||
fallbackPos
|
||||
);
|
||||
return insertAfterLastOccurrence(imports, `, ${symbolName}`, fileToEdit, fallbackPos);
|
||||
}
|
||||
|
||||
return new NoopChange();
|
||||
@ -97,14 +85,7 @@ export function insertImport(
|
||||
const insertAtBeginning = allImports.length === 0 && useStrict.length === 0;
|
||||
const separator = insertAtBeginning ? '' : ';\n';
|
||||
const toInsert =
|
||||
`${separator}import ${open}${symbolName}${close}` +
|
||||
` from '${fileName}'${insertAtBeginning ? ';\n' : ''}`;
|
||||
`${separator}import ${open}${symbolName}${close}` + ` from '${fileName}'${insertAtBeginning ? ';\n' : ''}`;
|
||||
|
||||
return insertAfterLastOccurrence(
|
||||
allImports,
|
||||
toInsert,
|
||||
fileToEdit,
|
||||
fallbackPos,
|
||||
ts.SyntaxKind.StringLiteral
|
||||
);
|
||||
return insertAfterLastOccurrence(allImports, toInsert, fileToEdit, fallbackPos, ts.SyntaxKind.StringLiteral);
|
||||
}
|
||||
|
@ -1,11 +1,11 @@
|
||||
import {Tree} from '@angular-devkit/schematics';
|
||||
import { Tree } from '@angular-devkit/schematics';
|
||||
|
||||
/**
|
||||
* Adds a package to the package.json
|
||||
*/
|
||||
export function addPackageToPackageJson(host: Tree, type: string, pkg: string, version: string) {
|
||||
export function addPackageToPackageJson(host: Tree, type: string, pkg: string, version: string): Tree {
|
||||
if (host.exists('package.json')) {
|
||||
const sourceText = host.read('package.json')!.toString('utf-8');
|
||||
const sourceText = host.read('package.json')?.toString('utf-8');
|
||||
const json = JSON.parse(sourceText);
|
||||
if (!json[type]) {
|
||||
json[type] = {};
|
||||
|
@ -1,4 +1,3 @@
|
||||
|
||||
export interface IonicGlobal {
|
||||
config?: any;
|
||||
asyncQueue?: boolean;
|
||||
|
@ -1,27 +1,31 @@
|
||||
import { ActivatedRouteSnapshot, DetachedRouteHandle, RouteReuseStrategy } from '@angular/router';
|
||||
|
||||
export class IonicRouteStrategy implements RouteReuseStrategy {
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
shouldDetach(_route: ActivatedRouteSnapshot): boolean {
|
||||
return false;
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
shouldAttach(_route: ActivatedRouteSnapshot): boolean {
|
||||
return false;
|
||||
}
|
||||
|
||||
store(_route: ActivatedRouteSnapshot, _detachedTree: DetachedRouteHandle): void {
|
||||
store(
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
_route: ActivatedRouteSnapshot,
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
_detachedTree: DetachedRouteHandle
|
||||
): void {
|
||||
return;
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
retrieve(_route: ActivatedRouteSnapshot): DetachedRouteHandle | null {
|
||||
return null;
|
||||
}
|
||||
|
||||
shouldReuseRoute(
|
||||
future: ActivatedRouteSnapshot,
|
||||
curr: ActivatedRouteSnapshot
|
||||
): boolean {
|
||||
shouldReuseRoute(future: ActivatedRouteSnapshot, curr: ActivatedRouteSnapshot): boolean {
|
||||
if (future.routeConfig !== curr.routeConfig) {
|
||||
return false;
|
||||
}
|
||||
|
@ -1,4 +1,3 @@
|
||||
|
||||
interface ControllerShape<Opts, HTMLElm> {
|
||||
create(options: Opts): Promise<HTMLElm>;
|
||||
dismiss(data?: any, role?: string, id?: string): Promise<boolean>;
|
||||
@ -11,7 +10,7 @@ export class OverlayBaseController<Opts, Overlay> implements ControllerShape<Opt
|
||||
/**
|
||||
* Creates a new overlay
|
||||
*/
|
||||
create(opts?: Opts) {
|
||||
create(opts?: Opts): Promise<Overlay> {
|
||||
// TODO: next major release opts is not optional
|
||||
return this.ctrl.create((opts || {}) as any);
|
||||
}
|
||||
@ -19,14 +18,14 @@ export class OverlayBaseController<Opts, Overlay> implements ControllerShape<Opt
|
||||
/**
|
||||
* When `id` is not provided, it dismisses the top overlay.
|
||||
*/
|
||||
dismiss(data?: any, role?: string, id?: string) {
|
||||
dismiss(data?: any, role?: string, id?: string): Promise<boolean> {
|
||||
return this.ctrl.dismiss(data, role, id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the top overlay.
|
||||
*/
|
||||
getTop() {
|
||||
getTop(): Promise<Overlay | undefined> {
|
||||
return this.ctrl.getTop();
|
||||
}
|
||||
}
|
||||
|
@ -1,8 +1,7 @@
|
||||
|
||||
declare const __zone_symbol__requestAnimationFrame: any;
|
||||
declare const requestAnimationFrame: any;
|
||||
|
||||
export const raf = (h: any) => {
|
||||
export const raf = (h: any): any => {
|
||||
if (typeof __zone_symbol__requestAnimationFrame === 'function') {
|
||||
return __zone_symbol__requestAnimationFrame(h);
|
||||
}
|
||||
|
51
angular/test/test-app/.eslintrc.json
Normal file
51
angular/test/test-app/.eslintrc.json
Normal file
@ -0,0 +1,51 @@
|
||||
{
|
||||
"root": true,
|
||||
"ignorePatterns": [
|
||||
"projects/**/*"
|
||||
],
|
||||
"overrides": [
|
||||
{
|
||||
"files": [
|
||||
"*.ts"
|
||||
],
|
||||
"parserOptions": {
|
||||
"project": [
|
||||
"tsconfig.json",
|
||||
"e2e/tsconfig.json"
|
||||
],
|
||||
"createDefaultProgram": true
|
||||
},
|
||||
"extends": [
|
||||
"plugin:@angular-eslint/recommended",
|
||||
"plugin:@angular-eslint/template/process-inline-templates"
|
||||
],
|
||||
"rules": {
|
||||
"@angular-eslint/component-selector": [
|
||||
"error",
|
||||
{
|
||||
"prefix": "app",
|
||||
"style": "kebab-case",
|
||||
"type": "element"
|
||||
}
|
||||
],
|
||||
"@angular-eslint/directive-selector": [
|
||||
"error",
|
||||
{
|
||||
"prefix": "app",
|
||||
"style": "camelCase",
|
||||
"type": "attribute"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"files": [
|
||||
"*.html"
|
||||
],
|
||||
"extends": [
|
||||
"plugin:@angular-eslint/template/recommended"
|
||||
],
|
||||
"rules": {}
|
||||
}
|
||||
]
|
||||
}
|
@ -33,7 +33,9 @@
|
||||
"output": "./svg"
|
||||
}
|
||||
],
|
||||
"styles": ["src/styles.css"],
|
||||
"styles": [
|
||||
"src/styles.css"
|
||||
],
|
||||
"scripts": []
|
||||
},
|
||||
"configurations": {
|
||||
@ -47,7 +49,6 @@
|
||||
"optimization": true,
|
||||
"outputHashing": "all",
|
||||
"sourceMap": false,
|
||||
"extractCss": true,
|
||||
"namedChunks": false,
|
||||
"aot": true,
|
||||
"progress": false,
|
||||
@ -86,10 +87,12 @@
|
||||
}
|
||||
},
|
||||
"lint": {
|
||||
"builder": "@angular-devkit/build-angular:tslint",
|
||||
"builder": "@angular-eslint/builder:lint",
|
||||
"options": {
|
||||
"tsConfig": ["tsconfig.app.json", "tsconfig.spec.json"],
|
||||
"exclude": ["**/node_modules/**"]
|
||||
"lintFilePatterns": [
|
||||
"src/**/*.ts",
|
||||
"src/**/*.html"
|
||||
]
|
||||
}
|
||||
},
|
||||
"server": {
|
||||
@ -137,5 +140,8 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"defaultProject": "test-app"
|
||||
"defaultProject": "test-app",
|
||||
"cli": {
|
||||
"defaultCollection": "@angular-eslint/schematics"
|
||||
}
|
||||
}
|
||||
|
31913
angular/test/test-app/package-lock.json
generated
31913
angular/test/test-app/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -7,7 +7,7 @@
|
||||
"start": "npm run sync && ng serve",
|
||||
"sync:build": "sh scripts/build-ionic.sh",
|
||||
"sync": "sh scripts/sync.sh",
|
||||
"build": "npm run sync && ng build --prod --no-progress",
|
||||
"build": "npm run sync && ng build --configuration production --no-progress",
|
||||
"lint": "ng lint",
|
||||
"postinstall": "npm run sync && ngcc",
|
||||
"serve:ssr": "node dist/test-app/server/main.js",
|
||||
@ -20,40 +20,47 @@
|
||||
"test.watch": "concurrently \"npm run start\" \"wait-on http-get://localhost:4200 && npm run cy.open\" --kill-others --success first"
|
||||
},
|
||||
"dependencies": {
|
||||
"@angular/animations": "^11.2.11",
|
||||
"@angular/common": "^11.2.11",
|
||||
"@angular/compiler": "^11.2.11",
|
||||
"@angular/core": "^11.2.11",
|
||||
"@angular/forms": "^11.2.11",
|
||||
"@angular/platform-browser": "^11.2.11",
|
||||
"@angular/platform-browser-dynamic": "^11.2.11",
|
||||
"@angular/platform-server": "^11.2.11",
|
||||
"@angular/router": "^11.2.11",
|
||||
"@angular/animations": "^12.2.8",
|
||||
"@angular/common": "^12.2.8",
|
||||
"@angular/compiler": "^12.2.8",
|
||||
"@angular/core": "^12.2.8",
|
||||
"@angular/forms": "^12.2.8",
|
||||
"@angular/platform-browser": "^12.2.8",
|
||||
"@angular/platform-browser-dynamic": "^12.2.8",
|
||||
"@angular/platform-server": "^12.2.8",
|
||||
"@angular/router": "^12.2.8",
|
||||
"@ionic/angular": "^5.3.1",
|
||||
"@ionic/angular-server": "^5.3.1",
|
||||
"@nguniversal/express-engine": "^11.2.1",
|
||||
"@nguniversal/express-engine": "^12.1.1",
|
||||
"angular-in-memory-web-api": "^0.11.0",
|
||||
"core-js": "^2.6.11",
|
||||
"express": "^4.15.2",
|
||||
"rxjs": "^6.5.5",
|
||||
"tslib": "^2.0.0",
|
||||
"zone.js": "^0.10.3"
|
||||
"typescript-eslint-language-service": "^4.1.5",
|
||||
"zone.js": "^0.11.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@angular-devkit/build-angular": "^0.1102.10",
|
||||
"@angular/cli": "^11.2.10",
|
||||
"@angular/compiler-cli": "^11.2.11",
|
||||
"@angular/language-service": "^11.2.11",
|
||||
"@nguniversal/builders": "^11.2.1",
|
||||
"@angular-devkit/build-angular": "^12.2.8",
|
||||
"@angular-eslint/builder": "12.5.0",
|
||||
"@angular-eslint/eslint-plugin": "12.5.0",
|
||||
"@angular-eslint/eslint-plugin-template": "12.5.0",
|
||||
"@angular-eslint/schematics": "12.5.0",
|
||||
"@angular-eslint/template-parser": "12.5.0",
|
||||
"@angular/cli": "^12.2.8",
|
||||
"@angular/compiler-cli": "^12.2.8",
|
||||
"@angular/language-service": "^12.2.8",
|
||||
"@nguniversal/builders": "^12.1.1",
|
||||
"@types/express": "^4.17.7",
|
||||
"@types/node": "^12.12.54",
|
||||
"codelyzer": "^6.0.1",
|
||||
"@typescript-eslint/eslint-plugin": "4.28.2",
|
||||
"@typescript-eslint/parser": "4.28.2",
|
||||
"concurrently": "^6.0.0",
|
||||
"cypress": "^6.7.1",
|
||||
"eslint": "^7.26.0",
|
||||
"ts-loader": "^6.2.2",
|
||||
"ts-node": "^8.3.0",
|
||||
"tslint": "~6.1.0",
|
||||
"typescript": "^4.0.7",
|
||||
"typescript": "^4.3.5",
|
||||
"wait-on": "^5.2.1",
|
||||
"webpack-cli": "^3.3.12"
|
||||
}
|
||||
|
@ -9,6 +9,7 @@ export class RouterLinkPage2Component implements OnInit {
|
||||
constructor() { }
|
||||
|
||||
ngOnInit() {
|
||||
console.log('ngOnInit')
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -9,6 +9,7 @@ export class RouterLinkPage3Component implements OnInit {
|
||||
constructor() { }
|
||||
|
||||
ngOnInit() {
|
||||
console.log('ngOnInit')
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,11 +1,11 @@
|
||||
import { ActivatedRoute } from '@angular/router';
|
||||
import { Component, Input } from '@angular/core';
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'app-tabs-tab1-nested',
|
||||
templateUrl: './tabs-tab1-nested.component.html',
|
||||
})
|
||||
export class TabsTab1NestedComponent {
|
||||
export class TabsTab1NestedComponent implements OnInit {
|
||||
id = '';
|
||||
constructor(
|
||||
private route: ActivatedRoute,
|
||||
|
@ -1,10 +1,10 @@
|
||||
import { Component, NgZone } from '@angular/core';
|
||||
import { Component, NgZone, OnInit } from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'app-tabs-tab2',
|
||||
templateUrl: './tabs-tab2.component.html',
|
||||
})
|
||||
export class TabsTab2Component {
|
||||
export class TabsTab2Component implements OnInit {
|
||||
title = 'ERROR';
|
||||
segment = 'two';
|
||||
changed = 'false';
|
||||
|
@ -16,6 +16,11 @@
|
||||
"lib": [
|
||||
"es2018",
|
||||
"dom"
|
||||
],
|
||||
"plugins": [
|
||||
{
|
||||
"name": "typescript-eslint-language-service"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
@ -1,133 +0,0 @@
|
||||
{
|
||||
"extends": "tslint:recommended",
|
||||
"rulesDirectory": ["codelyzer"],
|
||||
"rules": {
|
||||
"align": {
|
||||
"options": [
|
||||
"parameters",
|
||||
"statements"
|
||||
]
|
||||
},
|
||||
"array-type": false,
|
||||
"arrow-parens": false,
|
||||
"arrow-return-shorthand": true,
|
||||
"deprecation": {
|
||||
"severity": "warn"
|
||||
},
|
||||
"import-blacklist": [
|
||||
true,
|
||||
"rxjs/Rx"
|
||||
],
|
||||
"curly": true,
|
||||
"interface-name": false,
|
||||
"max-classes-per-file": false,
|
||||
"max-line-length": [
|
||||
true,
|
||||
140
|
||||
],
|
||||
"eofline": true,
|
||||
"member-access": false,
|
||||
"import-spacing": true,
|
||||
"indent": {
|
||||
"options": [
|
||||
"spaces"
|
||||
]
|
||||
},
|
||||
"member-ordering": [
|
||||
true,
|
||||
{
|
||||
"order": [
|
||||
"static-field",
|
||||
"instance-field",
|
||||
"static-method",
|
||||
"instance-method"
|
||||
]
|
||||
}
|
||||
],
|
||||
"no-consecutive-blank-lines": false,
|
||||
"no-console": [true, "debug", "info", "time", "timeEnd", "trace"],
|
||||
"no-empty": false,
|
||||
"no-inferrable-types": [true, "ignore-params"],
|
||||
"no-non-null-assertion": true,
|
||||
"no-redundant-jsdoc": true,
|
||||
"no-switch-case-fall-through": true,
|
||||
"no-var-requires": false,
|
||||
"object-literal-key-quotes": [true, "as-needed"],
|
||||
"object-literal-sort-keys": false,
|
||||
"ordered-imports": false,
|
||||
"quotemark": [true, "single"],
|
||||
"trailing-comma": false,
|
||||
"no-output-on-prefix": true,
|
||||
"no-inputs-metadata-property": true,
|
||||
"no-inputs-metadata-property": true,
|
||||
"no-host-metadata-property": true,
|
||||
"no-input-rename": true,
|
||||
"no-output-rename": true,
|
||||
"use-lifecycle-interface": true,
|
||||
"use-pipe-transform-interface": true,
|
||||
"one-variable-per-declaration": false,
|
||||
"component-class-suffix": [
|
||||
true,
|
||||
"Page",
|
||||
"Component"
|
||||
],
|
||||
"semicolon": {
|
||||
"options": [
|
||||
"always"
|
||||
]
|
||||
},
|
||||
"space-before-function-paren": {
|
||||
"options": {
|
||||
"anonymous": "never",
|
||||
"asyncArrow": "always",
|
||||
"constructor": "never",
|
||||
"method": "never",
|
||||
"named": "never"
|
||||
}
|
||||
},
|
||||
"directive-class-suffix": true,
|
||||
"typedef-whitespace": {
|
||||
"options": [
|
||||
{
|
||||
"call-signature": "nospace",
|
||||
"index-signature": "nospace",
|
||||
"parameter": "nospace",
|
||||
"property-declaration": "nospace",
|
||||
"variable-declaration": "nospace"
|
||||
},
|
||||
{
|
||||
"call-signature": "onespace",
|
||||
"index-signature": "onespace",
|
||||
"parameter": "onespace",
|
||||
"property-declaration": "onespace",
|
||||
"variable-declaration": "onespace"
|
||||
}
|
||||
]
|
||||
},
|
||||
"directive-selector": [true, "attribute", "app", "camelCase"],
|
||||
"component-selector": [
|
||||
true,
|
||||
"element",
|
||||
"app",
|
||||
"page",
|
||||
"kebab-case"
|
||||
],
|
||||
"variable-name": {
|
||||
"options": [
|
||||
"ban-keywords",
|
||||
"check-format",
|
||||
"allow-pascal-case"
|
||||
]
|
||||
},
|
||||
"whitespace": {
|
||||
"options": [
|
||||
"check-branch",
|
||||
"check-decl",
|
||||
"check-operator",
|
||||
"check-separator",
|
||||
"check-type",
|
||||
"check-typecast"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
@ -2,12 +2,10 @@
|
||||
"angularCompilerOptions": {
|
||||
"annotateForClosureCompiler": true,
|
||||
"strictMetadataEmit": true,
|
||||
"flatModuleOutFile": "core.js",
|
||||
"flatModuleId": "@ionic/angular",
|
||||
"skipTemplateCodegen": true,
|
||||
"fullTemplateTypeCheck": false,
|
||||
"enableResourceInlining": true,
|
||||
"enableIvy": false
|
||||
"compilationMode": "partial"
|
||||
},
|
||||
"compilerOptions": {
|
||||
"alwaysStrict": true,
|
||||
@ -36,7 +34,12 @@
|
||||
"paths": {
|
||||
"@ionic/core/hydrate": ["../core/hydrate"],
|
||||
"@ionic/core": ["../core"]
|
||||
},
|
||||
"plugins": [
|
||||
{
|
||||
"name": "typescript-eslint-language-service"
|
||||
}
|
||||
]
|
||||
},
|
||||
"exclude": ["node_modules", "src/schematics"],
|
||||
"files": ["src/index.ts"]
|
||||
|
@ -1,8 +0,0 @@
|
||||
{
|
||||
"extends": "./tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"target": "es5",
|
||||
"declarationDir": "build/es5",
|
||||
"outDir": "build/es5"
|
||||
}
|
||||
}
|
@ -1,10 +1,7 @@
|
||||
{
|
||||
"extends": ["tslint-ionic-rules/strict"],
|
||||
"linterOptions": {
|
||||
"exclude": [
|
||||
"**/*.spec.ts",
|
||||
"**/*.spec.tsx"
|
||||
]
|
||||
"exclude": ["**/*.spec.ts", "**/*.spec.tsx"]
|
||||
},
|
||||
"rules": {
|
||||
"no-conditional-assignment": false,
|
||||
|
6
core/package-lock.json
generated
6
core/package-lock.json
generated
@ -15037,7 +15037,8 @@
|
||||
"version": "0.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@stencil/react-output-target/-/react-output-target-0.1.0.tgz",
|
||||
"integrity": "sha512-NWeN2S43dwWDIousfojzGXIMkJJhfcdS1JxpwgE7IOqy4tZ+nqlDLPhM6tXvZ3eq4rJm8bkF+3/WbPJNR9xR7Q==",
|
||||
"dev": true
|
||||
"dev": true,
|
||||
"requires": {}
|
||||
},
|
||||
"@stencil/sass": {
|
||||
"version": "1.3.2",
|
||||
@ -15049,7 +15050,8 @@
|
||||
"version": "0.5.1",
|
||||
"resolved": "https://registry.npmjs.org/@stencil/vue-output-target/-/vue-output-target-0.5.1.tgz",
|
||||
"integrity": "sha512-E9HeuUf4DjHO8VFd+faR6T+/JwLtU/2kIA000YTTv0ARPUXuxr/3+U3YMBRPCVFPC5n2jsFxU3E9rTmVH1MGyg==",
|
||||
"dev": true
|
||||
"dev": true,
|
||||
"requires": {}
|
||||
},
|
||||
"@stylelint/postcss-css-in-js": {
|
||||
"version": "0.37.2",
|
||||
|
@ -308,6 +308,7 @@ export interface Gesture {
|
||||
}
|
||||
|
||||
export interface GestureConfig {
|
||||
[index: string]: any;
|
||||
el: Node;
|
||||
disableScroll?: boolean;
|
||||
|
||||
|
35580
packages/angular-server/package-lock.json
generated
35580
packages/angular-server/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -22,7 +22,7 @@
|
||||
"homepage": "https://ionicframework.com/",
|
||||
"scripts": {
|
||||
"test": "echo 'angular no tests yet'",
|
||||
"build": "ng-packagr -p package.json",
|
||||
"build": "ng-packagr -p package.json -c tsconfig.json",
|
||||
"build.prod": "npm run clean && npm run build",
|
||||
"clean": "rm -rf ./dist",
|
||||
"lint": "npm run lint.ts",
|
||||
@ -35,25 +35,23 @@
|
||||
}
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@angular/core": ">=8.2.7",
|
||||
"@angular/platform-server": ">=8.2.7",
|
||||
"@angular/core": ">=12.0.0",
|
||||
"@angular/platform-server": ">=12.0.0",
|
||||
"@ionic/angular": "*",
|
||||
"rxjs": ">=6.2.0",
|
||||
"zone.js": ">=0.8.26"
|
||||
"rxjs": ">=6.6.0",
|
||||
"zone.js": ">=0.11.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@angular/animations": "8.2.13",
|
||||
"@angular/common": "8.2.13",
|
||||
"@angular/compiler": "8.2.13",
|
||||
"@angular/compiler-cli": "8.2.13",
|
||||
"@angular/core": "8.2.13",
|
||||
"@angular/platform-browser": "8.2.13",
|
||||
"@angular/platform-server": "8.2.13",
|
||||
"@angular/animations": "^12.0.0",
|
||||
"@angular/common": "^12.0.0",
|
||||
"@angular/compiler": "^12.0.0",
|
||||
"@angular/compiler-cli": "^12.0.0",
|
||||
"@angular/core": "^12.0.0",
|
||||
"@angular/platform-browser": "^12.0.0",
|
||||
"@angular/platform-browser-dynamic": "^12.2.10",
|
||||
"@angular/platform-server": "^12.0.0",
|
||||
"@ionic/core": "6.0.0-rc.0",
|
||||
"ng-packagr": "5.7.1",
|
||||
"tslint": "^5.12.1",
|
||||
"tslint-ionic-rules": "0.0.21",
|
||||
"typescript": "3.4.5",
|
||||
"typescript-tslint-plugin": "^0.5.5"
|
||||
"ng-packagr": "^12.0.0",
|
||||
"typescript": "4.2.4"
|
||||
}
|
||||
}
|
||||
|
@ -3,20 +3,16 @@
|
||||
"compilerOptions": {
|
||||
"module": "commonjs",
|
||||
"rootDir": "src",
|
||||
"outDir": "dist",
|
||||
"plugins": [
|
||||
{ "name": "typescript-tslint-plugin" }
|
||||
]
|
||||
"outDir": "dist"
|
||||
},
|
||||
"files": [
|
||||
"src/ionic-server-module.ts"
|
||||
],
|
||||
"files": ["src/ionic-server-module.ts"],
|
||||
"angularCompilerOptions": {
|
||||
"annotateForClosureCompiler": true,
|
||||
"strictMetadataEmit" : true,
|
||||
"strictMetadataEmit": true,
|
||||
"flatModuleOutFile": "./index.js",
|
||||
"flatModuleId": "@ionic/angular-server",
|
||||
"skipTemplateCodegen": true,
|
||||
"fullTemplateTypeCheck": false
|
||||
"fullTemplateTypeCheck": false,
|
||||
"compilationMode": "partial"
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user