mirror of
https://github.com/ionic-team/ionic-framework.git
synced 2025-08-20 12:29:55 +08:00
refactor(bootstrap): use ionicBootstrap() to bootstrap
BREAKING CHANGES: - Ionic's custom decorators have been removed. - `@App` and `@Page` should be replaced with `@Component`. - `IonicApp` has been renamed to `App`. - `ionicBootstrap` is required to bootstrap the app. - Config is now the 3rd parameter in `ionicBootstrap(rootComponent, providers, config)`. - Property `prodMode` is now a config option, enabling or disabling production mode.
This commit is contained in:
@ -7,16 +7,14 @@ import {Platform} from '../../platform/platform';
|
||||
|
||||
|
||||
/**
|
||||
* App utility service. Allows you to look up components that have been
|
||||
* registered using the [Id directive](../Id/).
|
||||
* Ionic App utility service.
|
||||
*/
|
||||
@Injectable()
|
||||
export class IonicApp {
|
||||
export class App {
|
||||
private _disTime: number = 0;
|
||||
private _scrollTime: number = 0;
|
||||
private _title: string = '';
|
||||
private _titleSrv: Title = new Title();
|
||||
private _isProd: boolean = false;
|
||||
private _rootNav: any = null;
|
||||
private _appInjector: Injector;
|
||||
|
||||
@ -48,23 +46,6 @@ export class IonicApp {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns if the app has been set to be in be in production mode or not.
|
||||
* Production mode can only be set within the config of `@App`. Defaults
|
||||
* to `false`.
|
||||
* @return {boolean}
|
||||
*/
|
||||
isProd(): boolean {
|
||||
return this._isProd;
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
setProd(val: boolean) {
|
||||
this._isProd = !!val;
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
* Sets if the app is currently enabled or not, meaning if it's
|
||||
@ -80,9 +61,14 @@ export class IonicApp {
|
||||
setEnabled(isEnabled: boolean, duration: number = 700) {
|
||||
this._disTime = (isEnabled ? 0 : Date.now() + duration);
|
||||
|
||||
if (duration > 32 || isEnabled) {
|
||||
// only do a click block if the duration is longer than XXms
|
||||
this._clickBlock.show(!isEnabled, duration + 64);
|
||||
if (this._clickBlock) {
|
||||
if (duration > 32) {
|
||||
// only do a click block if the duration is longer than XXms
|
||||
this._clickBlock.show(true, duration + 64);
|
||||
|
||||
} else {
|
||||
this._clickBlock.show(false, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -85,7 +85,7 @@ body {
|
||||
text-size-adjust: none;
|
||||
}
|
||||
|
||||
ion-app,
|
||||
ion-app.app-init,
|
||||
ion-nav,
|
||||
ion-tabs {
|
||||
position: absolute;
|
||||
|
@ -1,7 +1,7 @@
|
||||
import {Component, ElementRef, Optional, NgZone, ChangeDetectionStrategy, ViewEncapsulation} from '@angular/core';
|
||||
|
||||
import {Ion} from '../ion';
|
||||
import {IonicApp} from '../app/app';
|
||||
import {App} from '../app/app';
|
||||
import {Config} from '../../config/config';
|
||||
import {Keyboard} from '../../util/keyboard';
|
||||
import {nativeRaf, nativeTimeout, transitionEnd} from '../../util/dom';
|
||||
@ -28,10 +28,10 @@ import {ScrollView} from '../../util/scroll-view';
|
||||
* you can use Angular's `@ViewChild` annotation:
|
||||
*
|
||||
* ```ts
|
||||
* import {ViewChild} from '@angular/core';
|
||||
* import {Component, ViewChild} from '@angular/core';
|
||||
* import {Content} from 'ionic-angular';
|
||||
*
|
||||
* @Page({...}
|
||||
* @Component({...})
|
||||
* export class MyPage{
|
||||
* @ViewChild(Content) content: Content;
|
||||
*
|
||||
@ -67,7 +67,7 @@ export class Content extends Ion {
|
||||
constructor(
|
||||
private _elementRef: ElementRef,
|
||||
private _config: Config,
|
||||
private _app: IonicApp,
|
||||
private _app: App,
|
||||
private _keyboard: Keyboard,
|
||||
private _zone: NgZone,
|
||||
@Optional() viewCtrl: ViewController
|
||||
@ -217,10 +217,10 @@ export class Content extends Ion {
|
||||
* Scroll to the specified position.
|
||||
*
|
||||
* ```ts
|
||||
* import {ViewChild} from '@angular/core';
|
||||
* import {Component, ViewChild} from '@angular/core';
|
||||
* import {Content} from 'ionic-angular';
|
||||
*
|
||||
* @Page({
|
||||
* @Component({
|
||||
* template: `<ion-content>
|
||||
* <button (click)="scrollTo()">Down 500px</button>
|
||||
* </ion-content>`
|
||||
@ -248,10 +248,10 @@ export class Content extends Ion {
|
||||
* Scroll to the top of the content component.
|
||||
*
|
||||
* ```ts
|
||||
* import {ViewChild} from '@angular/core';
|
||||
* import {Component, ViewChild} from '@angular/core';
|
||||
* import {Content} from 'ionic-angular';
|
||||
*
|
||||
* @Page({
|
||||
* @Component({
|
||||
* template: `<ion-content>
|
||||
* <button (click)="scrollToTop()">Scroll to top</button>
|
||||
* </ion-content>`
|
||||
|
@ -5,7 +5,7 @@ import {Config} from '../../config/config';
|
||||
import {Content} from '../content/content';
|
||||
import {Form} from '../../util/form';
|
||||
import {Item} from '../item/item';
|
||||
import {IonicApp} from '../app/app';
|
||||
import {App} from '../app/app';
|
||||
import {isTrueProperty} from '../../util/util';
|
||||
import {Label} from '../label/label';
|
||||
import {pointerCoord, hasPointerMoved, closest, copyInputAttributes} from '../../util/dom';
|
||||
@ -41,7 +41,7 @@ export class InputBase {
|
||||
config: Config,
|
||||
protected _form: Form,
|
||||
protected _item: Item,
|
||||
protected _app: IonicApp,
|
||||
protected _app: App,
|
||||
protected _platform: Platform,
|
||||
protected _elementRef: ElementRef,
|
||||
protected _scrollView: Content,
|
||||
|
@ -5,7 +5,7 @@ import {Config} from '../../config/config';
|
||||
import {Content} from '../content/content';
|
||||
import {Form} from '../../util/form';
|
||||
import {InputBase} from './input-base';
|
||||
import {IonicApp} from '../app/app';
|
||||
import {App} from '../app/app';
|
||||
import {Item} from '../item/item';
|
||||
import {Label} from '../label/label';
|
||||
import {NativeInput, NextInput} from './native-input';
|
||||
@ -79,7 +79,7 @@ export class TextInput extends InputBase {
|
||||
config: Config,
|
||||
form: Form,
|
||||
@Optional() item: Item,
|
||||
app: IonicApp,
|
||||
app: App,
|
||||
platform: Platform,
|
||||
elementRef: ElementRef,
|
||||
@Optional() scrollView: Content,
|
||||
@ -170,7 +170,7 @@ export class TextArea extends InputBase {
|
||||
config: Config,
|
||||
form: Form,
|
||||
@Optional() item: Item,
|
||||
app: IonicApp,
|
||||
app: App,
|
||||
platform: Platform,
|
||||
elementRef: ElementRef,
|
||||
@Optional() scrollView: Content,
|
||||
|
@ -1,11 +1,12 @@
|
||||
import {Component, ComponentRef, DynamicComponentLoader, ElementRef, ViewChild, ViewContainerRef} from '@angular/core';
|
||||
import {Component, ComponentRef, DynamicComponentLoader, ViewChild, ViewContainerRef} from '@angular/core';
|
||||
|
||||
import {windowDimensions} from '../../util/dom';
|
||||
import {pascalCaseToDashCase} from '../../util/util';
|
||||
import {NavParams} from '../nav/nav-params';
|
||||
import {ViewController} from '../nav/view-controller';
|
||||
import {addSelector} from '../../config/bootstrap';
|
||||
import {Animation} from '../../animations/animation';
|
||||
import {NavParams} from '../nav/nav-params';
|
||||
import {pascalCaseToDashCase} from '../../util/util';
|
||||
import {Transition, TransitionOptions} from '../../transitions/transition';
|
||||
import {ViewController} from '../nav/view-controller';
|
||||
import {windowDimensions} from '../../util/dom';
|
||||
|
||||
/**
|
||||
* @name Modal
|
||||
@ -35,7 +36,7 @@ import {Transition, TransitionOptions} from '../../transitions/transition';
|
||||
* ```ts
|
||||
* import {Page, Modal, NavController, NavParams} from 'ionic-angular';
|
||||
*
|
||||
* @Page(...)
|
||||
* @Component(...)
|
||||
* class HomePage {
|
||||
*
|
||||
* constructor(nav: NavController) {
|
||||
@ -49,7 +50,7 @@ import {Transition, TransitionOptions} from '../../transitions/transition';
|
||||
*
|
||||
* }
|
||||
*
|
||||
* @Page(...)
|
||||
* @Component(...)
|
||||
* class Profile {
|
||||
*
|
||||
* constructor(params: NavParams) {
|
||||
@ -65,9 +66,10 @@ import {Transition, TransitionOptions} from '../../transitions/transition';
|
||||
* modal.
|
||||
*
|
||||
* ```ts
|
||||
* import {Page, Modal, NavController, ViewController} from 'ionic-angular';
|
||||
* import {Component} from '@angular/core';
|
||||
* import {Modal, NavController, ViewController} from 'ionic-angular';
|
||||
*
|
||||
* @Page(...)
|
||||
* @Component(...)
|
||||
* class HomePage {
|
||||
*
|
||||
* constructor(nav: NavController) {
|
||||
@ -89,7 +91,7 @@ import {Transition, TransitionOptions} from '../../transitions/transition';
|
||||
*
|
||||
* }
|
||||
*
|
||||
* @Page(...)
|
||||
* @Component(...)
|
||||
* class Profile {
|
||||
*
|
||||
* constructor(viewCtrl: ViewController) {
|
||||
@ -140,7 +142,7 @@ export class Modal extends ViewController {
|
||||
let originalNgAfterViewInit = this.instance.ngAfterViewInit;
|
||||
|
||||
this.instance.ngAfterViewInit = () => {
|
||||
if ( originalNgAfterViewInit ) {
|
||||
if (originalNgAfterViewInit) {
|
||||
originalNgAfterViewInit();
|
||||
}
|
||||
this.instance.loadComponent().then( (componentRef: ComponentRef<any>) => {
|
||||
@ -163,11 +165,13 @@ export class ModalCmp {
|
||||
|
||||
@ViewChild('viewport', {read: ViewContainerRef}) viewport: ViewContainerRef;
|
||||
|
||||
constructor(protected _eleRef: ElementRef, protected _loader: DynamicComponentLoader, protected _navParams: NavParams, protected _viewCtrl: ViewController) {
|
||||
}
|
||||
constructor(protected _loader: DynamicComponentLoader, protected _navParams: NavParams) {}
|
||||
|
||||
loadComponent(): Promise<ComponentRef<any>> {
|
||||
return this._loader.loadNextToLocation(this._navParams.data.componentType, this.viewport).then(componentRef => {
|
||||
let componentType = this._navParams.data.componentType;
|
||||
addSelector(componentType, 'ion-page');
|
||||
|
||||
return this._loader.loadNextToLocation(componentType, this.viewport).then(componentRef => {
|
||||
return componentRef;
|
||||
});
|
||||
}
|
||||
|
@ -1,4 +1,5 @@
|
||||
import {Modal, ModalCmp, Page, NavController, ViewController} from '../../../../src';
|
||||
import {Component} from '@angular/core';
|
||||
import {Modal, ModalCmp, NavController, ViewController} from '../../../../src';
|
||||
|
||||
export function run() {
|
||||
describe('Modal', () => {
|
||||
@ -51,19 +52,19 @@ export function run() {
|
||||
|
||||
it('should return a componentRef object after loading component', (done) => {
|
||||
// arrange
|
||||
let mockLoader = {
|
||||
let mockLoader: any = {
|
||||
loadNextToLocation: () => {}
|
||||
};
|
||||
let mockNavParams = {
|
||||
let mockNavParams: any = {
|
||||
data: {
|
||||
componentType: "myComponentType"
|
||||
componentType: function mockComponentType(){}
|
||||
}
|
||||
};
|
||||
let mockComponentRef = {};
|
||||
|
||||
spyOn(mockLoader, "loadNextToLocation").and.returnValue(Promise.resolve(mockComponentRef));
|
||||
let modalCmp = new ModalCmp(null, mockLoader, mockNavParams, null);
|
||||
modalCmp.viewport = "mockViewport";
|
||||
let modalCmp = new ModalCmp(mockLoader, mockNavParams);
|
||||
modalCmp.viewport = <any>"mockViewport";
|
||||
|
||||
// act
|
||||
modalCmp.loadComponent().then(loadedComponentRef => {
|
||||
@ -91,7 +92,7 @@ let componentToPresentSpy = {
|
||||
_ionicProjectContent: () => {},
|
||||
};
|
||||
|
||||
@Page({
|
||||
@Component({
|
||||
template: `<div class="myComponent"></div>`
|
||||
})
|
||||
class ComponentToPresent{
|
||||
|
@ -1,11 +1,12 @@
|
||||
import {ViewContainerRef, DynamicComponentLoader, provide, ReflectiveInjector, ResolvedReflectiveProvider, ElementRef, NgZone, Renderer, Type} from '@angular/core';
|
||||
import {ViewContainerRef, DynamicComponentLoader, provide, ReflectiveInjector, ResolvedReflectiveProvider, ElementRef, NgZone, Renderer, Type, EventEmitter} from '@angular/core';
|
||||
|
||||
import {addSelector} from '../../config/bootstrap';
|
||||
import {App} from '../app/app';
|
||||
import {Config} from '../../config/config';
|
||||
import {Ion} from '../ion';
|
||||
import {IonicApp} from '../app/app';
|
||||
import {isBlank, pascalCaseToDashCase} from '../../util/util';
|
||||
import {Keyboard} from '../../util/keyboard';
|
||||
import {NavParams} from './nav-params';
|
||||
import {pascalCaseToDashCase, isBlank} from '../../util/util';
|
||||
import {MenuController} from '../menu/menu-controller';
|
||||
import {NavPortal} from './nav-portal';
|
||||
import {SwipeBackGesture} from './swipe-back';
|
||||
@ -59,12 +60,9 @@ import {ViewController} from './view-controller';
|
||||
*
|
||||
*
|
||||
* ## Page creation
|
||||
* _For more information on the `@Page` decorator see the [@Page API
|
||||
* reference](../../../decorators/Page/)._
|
||||
*
|
||||
* Pages are created when they are added to the navigation stack. For methods
|
||||
* like [push()](#push), the NavController takes any component class that is
|
||||
* decorated with `@Page` as its first argument. The NavController then
|
||||
* decorated with `@Component` as its first argument. The NavController then
|
||||
* compiles that component, adds it to the app and animates it into view.
|
||||
*
|
||||
* By default, pages are cached and left in the DOM if they are navigated away
|
||||
@ -75,10 +73,12 @@ import {ViewController} from './view-controller';
|
||||
*
|
||||
* ## Lifecycle events
|
||||
* Lifecycle events are fired during various stages of navigation. They can be
|
||||
* defined in any `@Page` decorated component class.
|
||||
* defined in any component type which is pushed/popped from a `NavController`.
|
||||
*
|
||||
* ```ts
|
||||
* @Page({
|
||||
* import {Component} from '@angular/core';
|
||||
*
|
||||
* @Component({
|
||||
* template: 'Hello World'
|
||||
* })
|
||||
* class HelloWorld {
|
||||
@ -171,6 +171,14 @@ export class NavController extends Ion {
|
||||
protected _trnsTime: number = 0;
|
||||
protected _views: Array<ViewController> = [];
|
||||
|
||||
pageDidLoad: EventEmitter<any>;
|
||||
pageWillEnter: EventEmitter<any>;
|
||||
pageDidEnter: EventEmitter<any>;
|
||||
pageWillLeave: EventEmitter<any>;
|
||||
pageDidLeave: EventEmitter<any>;
|
||||
pageWillUnload: EventEmitter<any>;
|
||||
pageDidUnload: EventEmitter<any>;
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
@ -203,7 +211,7 @@ export class NavController extends Ion {
|
||||
|
||||
constructor(
|
||||
parent: any,
|
||||
protected _app: IonicApp,
|
||||
protected _app: App,
|
||||
config: Config,
|
||||
protected _keyboard: Keyboard,
|
||||
elementRef: ElementRef,
|
||||
@ -227,6 +235,14 @@ export class NavController extends Ion {
|
||||
this.providers = ReflectiveInjector.resolve([
|
||||
provide(NavController, {useValue: this})
|
||||
]);
|
||||
|
||||
this.pageDidLoad = new EventEmitter();
|
||||
this.pageWillEnter = new EventEmitter();
|
||||
this.pageDidEnter = new EventEmitter();
|
||||
this.pageWillLeave = new EventEmitter();
|
||||
this.pageDidLeave = new EventEmitter();
|
||||
this.pageWillUnload = new EventEmitter();
|
||||
this.pageDidUnload = new EventEmitter();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -508,6 +524,7 @@ export class NavController extends Ion {
|
||||
animation: enteringView.getTransitionName('back')
|
||||
});
|
||||
|
||||
// present() always uses the root nav
|
||||
// start the transition
|
||||
return rootNav._insertViews(-1, [enteringView], opts);
|
||||
}
|
||||
@ -819,9 +836,11 @@ export class NavController extends Ion {
|
||||
// Tabs can be a parent, but it is not a collection of views
|
||||
// only we're looking for an actual NavController w/ stack of views
|
||||
leavingView.fireWillLeave();
|
||||
this.pageWillLeave.emit(leavingView);
|
||||
|
||||
return parentNav.pop(opts).then((rtnVal: boolean) => {
|
||||
leavingView.fireDidLeave();
|
||||
this.pageDidLeave.emit(leavingView);
|
||||
return rtnVal;
|
||||
});
|
||||
}
|
||||
@ -919,6 +938,7 @@ export class NavController extends Ion {
|
||||
// the first view to be removed, it should init leave
|
||||
view.state = STATE_INIT_LEAVE;
|
||||
view.fireWillUnload();
|
||||
this.pageWillUnload.emit(view);
|
||||
|
||||
// from the index of the leaving view, go backwards and
|
||||
// find the first view that is inactive so it can be the entering
|
||||
@ -952,7 +972,9 @@ export class NavController extends Ion {
|
||||
// apart of any transitions that will eventually happen
|
||||
this._views.filter(v => v.state === STATE_REMOVE).forEach(view => {
|
||||
view.fireWillLeave();
|
||||
this.pageWillLeave.emit(view);
|
||||
view.fireDidLeave();
|
||||
this.pageDidLeave.emit(view);
|
||||
this._views.splice(this.indexOf(view), 1);
|
||||
view.destroy();
|
||||
});
|
||||
@ -987,6 +1009,7 @@ export class NavController extends Ion {
|
||||
// if no entering view then create a bogus one
|
||||
enteringView = new ViewController();
|
||||
enteringView.fireLoaded();
|
||||
this.pageDidLoad.emit(enteringView);
|
||||
}
|
||||
|
||||
/* Async steps to complete a transition
|
||||
@ -1043,6 +1066,7 @@ export class NavController extends Ion {
|
||||
|
||||
this.loadPage(enteringView, null, opts, () => {
|
||||
enteringView.fireLoaded();
|
||||
this.pageDidLoad.emit(enteringView);
|
||||
this._postRender(transId, enteringView, leavingView, isAlreadyTransitioning, opts, done);
|
||||
});
|
||||
}
|
||||
@ -1102,12 +1126,14 @@ export class NavController extends Ion {
|
||||
// only fire entering lifecycle if the leaving
|
||||
// view hasn't explicitly set not to
|
||||
enteringView.fireWillEnter();
|
||||
this.pageWillEnter.emit(enteringView);
|
||||
}
|
||||
|
||||
if (enteringView.fireOtherLifecycles) {
|
||||
// only fire leaving lifecycle if the entering
|
||||
// view hasn't explicitly set not to
|
||||
leavingView.fireWillLeave();
|
||||
this.pageWillLeave.emit(leavingView);
|
||||
}
|
||||
|
||||
} else {
|
||||
@ -1214,12 +1240,14 @@ export class NavController extends Ion {
|
||||
// only fire entering lifecycle if the leaving
|
||||
// view hasn't explicitly set not to
|
||||
enteringView.fireDidEnter();
|
||||
this.pageDidEnter.emit(enteringView);
|
||||
}
|
||||
|
||||
if (enteringView.fireOtherLifecycles) {
|
||||
// only fire leaving lifecycle if the entering
|
||||
// view hasn't explicitly set not to
|
||||
leavingView.fireDidLeave();
|
||||
this.pageDidLeave.emit(leavingView);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1422,21 +1450,25 @@ export class NavController extends Ion {
|
||||
return;
|
||||
}
|
||||
|
||||
// add more providers to just this page
|
||||
let providers = this.providers.concat(ReflectiveInjector.resolve([
|
||||
provide(ViewController, {useValue: view}),
|
||||
provide(NavParams, {useValue: view.getNavParams()})
|
||||
]));
|
||||
|
||||
// automatically set "ion-page" selector
|
||||
addSelector(view.componentType, 'ion-page');
|
||||
|
||||
// load the page component inside the nav
|
||||
this._loader.loadNextToLocation(view.componentType, this._viewport, providers).then(component => {
|
||||
|
||||
|
||||
// a new ComponentRef has been created
|
||||
// set the ComponentRef's instance to its ViewController
|
||||
view.setInstance(component.instance);
|
||||
|
||||
|
||||
// the component has been loaded, so call the view controller's loaded method to load any dependencies into the dom
|
||||
view.loaded( () => {
|
||||
|
||||
|
||||
// the ElementRef of the actual ion-page created
|
||||
let pageElementRef = component.location;
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
import {Directive, ElementRef, Optional, NgZone, Renderer, DynamicComponentLoader, ViewContainerRef} from '@angular/core';
|
||||
|
||||
import {IonicApp} from '../app/app';
|
||||
import {App} from '../app/app';
|
||||
import {Config} from '../../config/config';
|
||||
import {Keyboard} from '../../util/keyboard';
|
||||
import {NavController} from './nav-controller';
|
||||
@ -16,7 +16,7 @@ export class NavPortal extends NavController {
|
||||
constructor(
|
||||
@Optional() viewCtrl: ViewController,
|
||||
@Optional() parent: NavController,
|
||||
app: IonicApp,
|
||||
app: App,
|
||||
config: Config,
|
||||
keyboard: Keyboard,
|
||||
elementRef: ElementRef,
|
||||
|
@ -1,6 +1,6 @@
|
||||
import {Component, ElementRef, ViewContainerRef, DynamicComponentLoader, Input, Optional, NgZone, Renderer, Type, ViewChild, ViewEncapsulation, AfterViewInit} from '@angular/core';
|
||||
|
||||
import {IonicApp} from '../app/app';
|
||||
import {App} from '../app/app';
|
||||
import {Config} from '../../config/config';
|
||||
import {Keyboard} from '../../util/keyboard';
|
||||
import {isTrueProperty} from '../../util/util';
|
||||
@ -28,15 +28,18 @@ import {ViewController} from './view-controller';
|
||||
*
|
||||
* @usage
|
||||
* ```ts
|
||||
* import {GettingStartedPage} from 'getting-started';
|
||||
* @App({
|
||||
* template: `<ion-nav [root]="rootPage"></ion-nav>`
|
||||
* import {Component} from '@angular/core';
|
||||
* import {ionicBootstrap} from 'ionic-angular';
|
||||
* import {GettingStartedPage} from './getting-started';
|
||||
*
|
||||
* @Component({
|
||||
* template: `<ion-nav [root]="root"></ion-nav>`
|
||||
* })
|
||||
* class MyApp {
|
||||
* constructor(){
|
||||
* this.rootPage = GettingStartedPage;
|
||||
* }
|
||||
* root = GettingStartedPage;
|
||||
* }
|
||||
*
|
||||
* ionicBootstrap(MyApp);
|
||||
* ```
|
||||
*
|
||||
* ### Back Navigation
|
||||
@ -117,7 +120,7 @@ export class Nav extends NavController implements AfterViewInit {
|
||||
constructor(
|
||||
@Optional() viewCtrl: ViewController,
|
||||
@Optional() parent: NavController,
|
||||
app: IonicApp,
|
||||
app: App,
|
||||
config: Config,
|
||||
keyboard: Keyboard,
|
||||
elementRef: ElementRef,
|
||||
|
@ -4,7 +4,7 @@ import {Ion} from '../ion';
|
||||
import {Icon} from '../icon/icon';
|
||||
import {ToolbarBase} from '../toolbar/toolbar';
|
||||
import {Config} from '../../config/config';
|
||||
import {IonicApp} from '../app/app';
|
||||
import {App} from '../app/app';
|
||||
import {isTrueProperty} from '../../util/util';
|
||||
import {ViewController} from '../nav/view-controller';
|
||||
import {NavController} from '../nav/nav-controller';
|
||||
@ -134,7 +134,7 @@ export class Navbar extends ToolbarBase {
|
||||
}
|
||||
|
||||
constructor(
|
||||
private _app: IonicApp,
|
||||
private _app: App,
|
||||
@Optional() viewCtrl: ViewController,
|
||||
elementRef: ElementRef,
|
||||
config: Config,
|
||||
|
@ -1,6 +1,6 @@
|
||||
import {Component, Inject, forwardRef, ElementRef, NgZone, Renderer, DynamicComponentLoader, ViewContainerRef, ViewChild, Type, ViewEncapsulation, ChangeDetectorRef, EventEmitter, Input, Output} from '@angular/core';
|
||||
|
||||
import {IonicApp} from '../app/app';
|
||||
import {App} from '../app/app';
|
||||
import {Config} from '../../config/config';
|
||||
import {isTrueProperty} from '../../util/util';
|
||||
import {Keyboard} from '../../util/keyboard';
|
||||
@ -208,7 +208,7 @@ export class Tab extends NavController {
|
||||
|
||||
constructor(
|
||||
@Inject(forwardRef(() => Tabs)) parentTabs: Tabs,
|
||||
app: IonicApp,
|
||||
app: App,
|
||||
config: Config,
|
||||
keyboard: Keyboard,
|
||||
elementRef: ElementRef,
|
||||
|
@ -1,6 +1,6 @@
|
||||
import {Component, Directive, ElementRef, Optional, Host, forwardRef, ViewContainerRef, ViewChild, ViewChildren, EventEmitter, Output, Input, Renderer, ViewEncapsulation} from '@angular/core';
|
||||
|
||||
import {IonicApp} from '../app/app';
|
||||
import {App} from '../app/app';
|
||||
import {Config} from '../../config/config';
|
||||
import {Tab} from './tab';
|
||||
import {TabButton} from './tab-button';
|
||||
@ -49,7 +49,7 @@ import {isBlank, isTrueProperty} from '../../util/util';
|
||||
*
|
||||
* @usage
|
||||
*
|
||||
* You can add a basic tabs template to a `@Page` using the following
|
||||
* You can add a basic tabs template to a `@Component` using the following
|
||||
* template:
|
||||
*
|
||||
* ```html
|
||||
@ -63,7 +63,7 @@ import {isBlank, isTrueProperty} from '../../util/util';
|
||||
* Where `tab1Root`, `tab2Root`, and `tab3Root` are each a page:
|
||||
*
|
||||
*```ts
|
||||
* @Page({
|
||||
* @Component({
|
||||
* templateUrl: 'build/pages/tabs/tabs.html'
|
||||
* })
|
||||
* export class TabsPage {
|
||||
@ -223,7 +223,7 @@ export class Tabs extends Ion {
|
||||
constructor(
|
||||
@Optional() parent: NavController,
|
||||
@Optional() viewCtrl: ViewController,
|
||||
private _app: IonicApp,
|
||||
private _app: App,
|
||||
private _config: Config,
|
||||
private _elementRef: ElementRef,
|
||||
private _platform: Platform,
|
||||
|
@ -1,6 +1,6 @@
|
||||
import {Injectable, NgZone} from '@angular/core';
|
||||
|
||||
import {IonicApp} from '../app/app';
|
||||
import {App} from '../app/app';
|
||||
import {Config} from '../../config/config';
|
||||
import {pointerCoord, hasPointerMoved} from '../../util/dom';
|
||||
import {Activator} from './activator';
|
||||
@ -22,7 +22,7 @@ export class TapClick {
|
||||
|
||||
constructor(
|
||||
config: Config,
|
||||
private app: IonicApp,
|
||||
private app: App,
|
||||
private zone: NgZone
|
||||
) {
|
||||
let self = this;
|
||||
|
@ -1,36 +1,81 @@
|
||||
import {provide, Provider, ComponentRef, NgZone} from '@angular/core';
|
||||
import {bootstrap} from '@angular/platform-browser-dynamic';
|
||||
import {Directive, ReflectiveInjector, Renderer, enableProdMode, ViewContainerRef, provide, PLATFORM_DIRECTIVES, ComponentRef, NgZone, DynamicComponentLoader} from '@angular/core';
|
||||
import {ROUTER_PROVIDERS} from '@angular/router';
|
||||
import {LocationStrategy, HashLocationStrategy} from '@angular/common';
|
||||
import {HTTP_PROVIDERS} from '@angular/http';
|
||||
|
||||
import {App} from '../components/app/app';
|
||||
import {ClickBlock} from '../util/click-block';
|
||||
import {Config} from './config';
|
||||
import {Events} from '../util/events';
|
||||
import {FeatureDetect} from '../util/feature-detect';
|
||||
import {Form} from '../util/form';
|
||||
import {IonicApp} from '../components/app/app';
|
||||
import {IONIC_DIRECTIVES} from './directives';
|
||||
import {isPresent} from '../util/util';
|
||||
import {Keyboard} from '../util/keyboard';
|
||||
import {MenuController} from '../components/menu/menu-controller';
|
||||
import {nativeTimeout, closest} from '../util/dom';
|
||||
import {NavRegistry} from '../components/nav/nav-registry';
|
||||
import {Platform} from '../platform/platform';
|
||||
import {ready, closest} from '../util/dom';
|
||||
import {ScrollView} from '../util/scroll-view';
|
||||
import {TapClick} from '../components/tap-click/tap-click';
|
||||
import {Translate} from '../translation/translate';
|
||||
const _reflect: any = Reflect;
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
export function ionicProviders(args: any = {}) {
|
||||
let platform = new Platform();
|
||||
let navRegistry = new NavRegistry(args.pages);
|
||||
|
||||
var config = args.config;
|
||||
export function ionicBootstrap(appRootComponent: any, customProviders?: Array<any>, config?: any): Promise<ComponentRef<any>> {
|
||||
// get all Ionic Providers
|
||||
let providers = ionicProviders(customProviders, config);
|
||||
|
||||
// automatically set "ion-app" selector to users root component
|
||||
addSelector(appRootComponent, 'ion-app');
|
||||
|
||||
// call angular bootstrap
|
||||
return bootstrap(appRootComponent, providers).then(ngComponentRef => {
|
||||
// ionic app has finished bootstrapping
|
||||
return ionicPostBootstrap(ngComponentRef);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
export function ionicPostBootstrap(ngComponentRef: ComponentRef<any>): ComponentRef<any> {
|
||||
//ngComponentRef.injector.get(TapClick);
|
||||
let app: App = ngComponentRef.injector.get(App);
|
||||
app.setAppInjector(ngComponentRef.injector);
|
||||
|
||||
// prepare platform ready
|
||||
let platform: Platform = ngComponentRef.injector.get(Platform);
|
||||
platform.setZone(ngComponentRef.injector.get(NgZone));
|
||||
platform.prepareReady();
|
||||
|
||||
// TODO: Use Renderer
|
||||
ngComponentRef.location.nativeElement.classList.add('app-init');
|
||||
|
||||
return ngComponentRef;
|
||||
}
|
||||
|
||||
|
||||
export function ionicProviders(customProviders?: Array<any>, config?: any): any[] {
|
||||
// add custom providers to Ionic's dev
|
||||
let directives = IONIC_DIRECTIVES;
|
||||
if (customProviders) {
|
||||
directives.push(customProviders);
|
||||
}
|
||||
|
||||
// create an instance of Config
|
||||
if (!(config instanceof Config)) {
|
||||
config = new Config(config);
|
||||
}
|
||||
|
||||
// enable production mode if config set to true
|
||||
if (config.getBoolean('prodMode')) {
|
||||
enableProdMode();
|
||||
}
|
||||
|
||||
// create an instance of Platform
|
||||
let platform = new Platform();
|
||||
|
||||
// initialize platform
|
||||
platform.setUrl(window.location.href);
|
||||
platform.setUserAgent(window.navigator.userAgent);
|
||||
platform.setNavigatorPlatform(window.navigator.platform);
|
||||
@ -38,7 +83,6 @@ export function ionicProviders(args: any = {}) {
|
||||
config.setPlatform(platform);
|
||||
|
||||
let clickBlock = new ClickBlock();
|
||||
|
||||
let events = new Events();
|
||||
let featureDetect = new FeatureDetect();
|
||||
|
||||
@ -46,51 +90,43 @@ export function ionicProviders(args: any = {}) {
|
||||
bindEvents(window, document, platform, events);
|
||||
|
||||
return [
|
||||
IonicApp,
|
||||
App,
|
||||
provide(ClickBlock, {useValue: clickBlock}),
|
||||
provide(Config, {useValue: config}),
|
||||
provide(Platform, {useValue: platform}),
|
||||
provide(FeatureDetect, {useValue: featureDetect}),
|
||||
provide(Events, {useValue: events}),
|
||||
provide(NavRegistry, {useValue: navRegistry}),
|
||||
TapClick,
|
||||
provide(FeatureDetect, {useValue: featureDetect}),
|
||||
Form,
|
||||
Keyboard,
|
||||
MenuController,
|
||||
NavRegistry,
|
||||
provide(Platform, {useValue: platform}),
|
||||
Translate,
|
||||
TapClick,
|
||||
provide(PLATFORM_DIRECTIVES, {useValue: [directives], multi: true}),
|
||||
ROUTER_PROVIDERS,
|
||||
provide(LocationStrategy, {useClass: HashLocationStrategy}),
|
||||
HTTP_PROVIDERS,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
export function postBootstrap(appRef: ComponentRef<any>, prodMode: boolean) {
|
||||
appRef.injector.get(TapClick);
|
||||
let app: IonicApp = appRef.injector.get(IonicApp);
|
||||
let platform: Platform = appRef.injector.get(Platform);
|
||||
platform.setZone(appRef.injector.get(NgZone));
|
||||
platform.prepareReady();
|
||||
app.setProd(prodMode);
|
||||
app.setAppInjector(appRef.injector);
|
||||
}
|
||||
|
||||
|
||||
function setupDom(window, document, config, platform, clickBlock, featureDetect) {
|
||||
function setupDom(window: Window, document: Document, config: Config, platform: Platform, clickBlock: ClickBlock, featureDetect: FeatureDetect) {
|
||||
let bodyEle = document.body;
|
||||
let mode = config.get('mode');
|
||||
|
||||
// if dynamic mode links have been added the fire up the correct one
|
||||
let modeLinkAttr = mode + '-href';
|
||||
let linkEle = document.head.querySelector('link[' + modeLinkAttr + ']');
|
||||
let linkEle = <HTMLLinkElement>document.head.querySelector('link[' + modeLinkAttr + ']');
|
||||
if (linkEle) {
|
||||
let href = linkEle.getAttribute(modeLinkAttr);
|
||||
linkEle.removeAttribute(modeLinkAttr);
|
||||
linkEle.href = href;
|
||||
}
|
||||
|
||||
let headStyle = document.createElement('style');
|
||||
headStyle.innerHTML = 'ion-app{display:none}';
|
||||
document.head.appendChild(headStyle);
|
||||
|
||||
// set the mode class name
|
||||
// ios/md/wp
|
||||
bodyEle.classList.add(mode);
|
||||
@ -122,10 +158,6 @@ function setupDom(window, document, config, platform, clickBlock, featureDetect)
|
||||
bodyEle.classList.add('enable-hover');
|
||||
}
|
||||
|
||||
if (config.get('clickBlock')) {
|
||||
clickBlock.enable();
|
||||
}
|
||||
|
||||
// run feature detection tests
|
||||
featureDetect.run(window, document);
|
||||
}
|
||||
@ -134,7 +166,7 @@ function setupDom(window, document, config, platform, clickBlock, featureDetect)
|
||||
/**
|
||||
* Bind some global events and publish on the 'app' channel
|
||||
*/
|
||||
function bindEvents(window, document, platform, events) {
|
||||
function bindEvents(window: Window, document: Document, platform: Platform, events: Events) {
|
||||
window.addEventListener('online', (ev) => {
|
||||
events.publish('app:online', ev);
|
||||
}, false);
|
||||
@ -150,10 +182,10 @@ function bindEvents(window, document, platform, events) {
|
||||
// When that status taps, we respond
|
||||
window.addEventListener('statusTap', (ev) => {
|
||||
// TODO: Make this more better
|
||||
var el = document.elementFromPoint(platform.width() / 2, platform.height() / 2);
|
||||
let el = <HTMLElement>document.elementFromPoint(platform.width() / 2, platform.height() / 2);
|
||||
if (!el) { return; }
|
||||
|
||||
var content = closest(el, 'scroll-content');
|
||||
let content = closest(el, 'scroll-content');
|
||||
if (content) {
|
||||
var scroll = new ScrollView(content);
|
||||
scroll.scrollTo(0, 0, 300);
|
||||
@ -161,9 +193,22 @@ function bindEvents(window, document, platform, events) {
|
||||
});
|
||||
|
||||
// start listening for resizes XXms after the app starts
|
||||
setTimeout(function() {
|
||||
window.addEventListener('resize', function() {
|
||||
nativeTimeout(() => {
|
||||
window.addEventListener('resize', () => {
|
||||
platform.windowResize();
|
||||
});
|
||||
}, 2000);
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
export function addSelector(type: any, selector: string) {
|
||||
if (type) {
|
||||
let annotations = _reflect.getMetadata('annotations', type);
|
||||
if (annotations && !annotations[0].selector) {
|
||||
annotations[0].selector = selector;
|
||||
_reflect.defineMetadata('annotations', annotations, type);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -80,7 +80,7 @@ export function run() {
|
||||
let userConfig = new Config({
|
||||
mode: 'configInstance'
|
||||
})
|
||||
let providers = ionicProviders({config:userConfig});
|
||||
let providers = ionicProviders(null, userConfig);
|
||||
|
||||
let config = providers.find(provider => provider.useValue instanceof Config).useValue;
|
||||
|
||||
@ -88,9 +88,9 @@ export function run() {
|
||||
});
|
||||
|
||||
it('should create new Config instance from config object in ionicProviders', () => {
|
||||
let providers = ionicProviders({config: {
|
||||
let providers = ionicProviders(null, {
|
||||
mode: 'configObj'
|
||||
}});
|
||||
});
|
||||
|
||||
let config = providers.find(provider => provider.useValue instanceof Config).useValue;
|
||||
|
||||
|
@ -1,107 +0,0 @@
|
||||
import {Component, ChangeDetectionStrategy, ViewEncapsulation, enableProdMode, Type, provide, PLATFORM_DIRECTIVES} from '@angular/core';
|
||||
import {bootstrap} from '@angular/platform-browser-dynamic';
|
||||
import {ionicProviders, postBootstrap} from '../config/bootstrap';
|
||||
import {IONIC_DIRECTIVES} from '../config/directives';
|
||||
|
||||
const _reflect: any = Reflect;
|
||||
|
||||
export interface AppMetadata {
|
||||
prodMode?: boolean;
|
||||
selector?: string;
|
||||
inputs?: string[];
|
||||
outputs?: string[];
|
||||
properties?: string[];
|
||||
events?: string[];
|
||||
host?: {
|
||||
[key: string]: string;
|
||||
};
|
||||
providers?: any[];
|
||||
directives?: Array<Type | any[]>;
|
||||
pipes?: Array<Type | any[]>;
|
||||
exportAs?: string;
|
||||
queries?: {
|
||||
[key: string]: any;
|
||||
};
|
||||
template?: string;
|
||||
templateUrl?: string;
|
||||
moduleId?: string;
|
||||
styleUrls?: string[];
|
||||
styles?: string[];
|
||||
changeDetection?: ChangeDetectionStrategy;
|
||||
encapsulation?: ViewEncapsulation;
|
||||
config?: any;
|
||||
}
|
||||
|
||||
/**
|
||||
* @name App
|
||||
* @description
|
||||
* App is an Ionic decorator that bootstraps an application. It can be passed a
|
||||
* number of arguments that act as global config variables for the app.
|
||||
* `@App` is similar to Angular's `@Component` in which it can accept a `template`
|
||||
* property that has an inline template, or a `templateUrl` property that points
|
||||
* to an external html template. The `@App` decorator runs the Angular bootstrapping
|
||||
* process automatically, however you can bootstrap your app separately if you prefer.
|
||||
* Additionally, `@App` will automatically bootstrap with all of Ionic's
|
||||
* core components, meaning they won't all have to be individually imported and added
|
||||
* to each component's `directives` property.
|
||||
*
|
||||
* @usage
|
||||
* ```ts
|
||||
* import {App} from 'ionic-angular';
|
||||
*
|
||||
* @App({
|
||||
* templateUrl: 'app/app.html',
|
||||
* providers: [DataService]
|
||||
* })
|
||||
*
|
||||
* export class MyApp{
|
||||
* // Anything we would want to do at the root of our app
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* @property {object} [config] - the app's {@link /docs/v2/api/config/Config/ Config} object.
|
||||
* @property {boolean} [prodMode] - Enable Angular's production mode, which turns off assertions and other checks within the framework. Additionally, this config sets the return value of `isProd()` which is on the `IonicApp` instance. Defaults to `false`.
|
||||
* @property {array} [pipes] - any pipes for your app.
|
||||
* @property {array} [providers] - any providers for your app.
|
||||
* @property {string} [template] - the template to use for the app root.
|
||||
* @property {string} [templateUrl] - a relative URL pointing to the template to use for the app root.
|
||||
*/
|
||||
export function App(args: AppMetadata = {}) {
|
||||
|
||||
return function(cls) {
|
||||
// get current annotations
|
||||
let annotations = _reflect.getMetadata('annotations', cls) || [];
|
||||
|
||||
args.selector = 'ion-app';
|
||||
|
||||
// if no template was provided, default so it has a root <ion-nav>
|
||||
if (!args.templateUrl && !args.template) {
|
||||
args.template = '<ion-nav></ion-nav>';
|
||||
}
|
||||
|
||||
// create @Component
|
||||
annotations.push(new Component(args));
|
||||
|
||||
// redefine with added annotations
|
||||
_reflect.defineMetadata('annotations', annotations, cls);
|
||||
|
||||
// define array of bootstrap providers
|
||||
let providers = ionicProviders(args).concat(args.providers || []);
|
||||
|
||||
// auto add Ionic directives
|
||||
let directives = args.directives ? args.directives.concat(IONIC_DIRECTIVES) : IONIC_DIRECTIVES;
|
||||
|
||||
// automatically provide all of Ionic's directives to every component
|
||||
providers.push(provide(PLATFORM_DIRECTIVES, {useValue: [directives], multi: true}));
|
||||
|
||||
if (args.prodMode) {
|
||||
enableProdMode();
|
||||
}
|
||||
|
||||
bootstrap(cls, providers).then(appRef => {
|
||||
postBootstrap(appRef, args.prodMode);
|
||||
});
|
||||
|
||||
return cls;
|
||||
};
|
||||
}
|
@ -28,41 +28,13 @@ export interface PageMetadata {
|
||||
}
|
||||
|
||||
/**
|
||||
* @name Page
|
||||
* @description
|
||||
*
|
||||
* The Page decorator indicates that the decorated class is an Ionic
|
||||
* navigation component, meaning it can be navigated to using a
|
||||
* [NavController](../../nav/NavController).
|
||||
*
|
||||
* Since the app has already been bootstrapped with Ionic's core directives, it
|
||||
* is not needed to include `IONIC_DIRECTIVES` in the directives property. Additionally,
|
||||
* Angular's [CORE_DIRECTIVES](https://angular.io/docs/ts/latest/api/common/CORE_DIRECTIVES-let.html)
|
||||
* and [FORM_DIRECTIVES](https://angular.io/docs/ts/latest/api/common/FORM_DIRECTIVES-let.html),
|
||||
* are also already provided, so you only need to supply any custom components and directives
|
||||
* to your pages:
|
||||
*
|
||||
* @usage
|
||||
*
|
||||
* ```ts
|
||||
* @Page({
|
||||
* template: `
|
||||
* <ion-content>
|
||||
* I am a page!
|
||||
* </ion-content>
|
||||
* `
|
||||
* })
|
||||
* class MyPage {}
|
||||
* ```
|
||||
*
|
||||
* Pages have their content automatically wrapped in `<ion-page>`, so although
|
||||
* you may see these tags if you inspect your markup, you don't need to include
|
||||
* them in your templates.
|
||||
*
|
||||
* For more information on how pages are created, see the [NavController API Docs](../../components/nav/NavController/#creating_pages)
|
||||
* @private
|
||||
*/
|
||||
export function Page(config: PageMetadata) {
|
||||
return function(cls) {
|
||||
// deprecated warning: added beta.8 2016-05-27
|
||||
console.warn('@Page decorator has been deprecated. Please use Angular\'s @Component instead.\nimport {Component} from \'@angular/core\';');
|
||||
|
||||
config.selector = 'ion-page';
|
||||
config.host = config.host || {};
|
||||
config.host['[hidden]'] = '_hidden';
|
||||
|
@ -3,7 +3,6 @@ export * from './config/bootstrap';
|
||||
export * from './config/config';
|
||||
export * from './config/directives';
|
||||
|
||||
export * from './decorators/app';
|
||||
export * from './decorators/page';
|
||||
|
||||
export * from './components';
|
||||
|
Reference in New Issue
Block a user