Files
ionic-framework/src/config/bootstrap.ts
Dan Bucholtz b20647c16e refactor(click-block): reversing previous change, making getBoolean use fallback of true
reversing previous change, making getBoolean use fallback of true
2016-06-13 15:53:51 -05:00

244 lines
7.4 KiB
TypeScript

import {bootstrap} from '@angular/platform-browser-dynamic';
import {enableProdMode, provide, PLATFORM_DIRECTIVES, ComponentRef, NgZone} from '@angular/core';
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 {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 {ScrollView} from '../util/scroll-view';
import {TapClick} from '../components/tap-click/tap-click';
import {Translate} from '../translation/translate';
const _reflect: any = Reflect;
/**
* @name ionicBootstrap
* @description
* `ionicBootstrap` allows you to bootstrap your entire application. Similar to Angular's `bootstrap`, `ionicBootstrap`
* takes a root component in order to start the app. You can pass along any providers that you may want to inject into your
* app as an array for the second argument. You can also pass a config object as the third argument to configure your app's settings.
*
* @usage
*
* ```ts
* import {ionicBootstrap} from 'ionic-angular';
* import {Component} from '@angular/core';
*
* @Component({
* templateUrl: 'build/app.html',
* })
* export class MyClass{}
*
* ionicBootstrap(MyClass, null, {tabbarPlacement: 'bottom'})
* ```
*/
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);
});
}
/**
* @private
*/
export function ionicPostBootstrap(ngComponentRef: ComponentRef<any>): ComponentRef<any> {
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 PLATFORM_INITIALIZER
ngComponentRef.injector.get(TapClick);
// TODO: Use Renderer
ngComponentRef.location.nativeElement.classList.add('app-init');
return ngComponentRef;
}
/**
* @private
*/
export function ionicProviders(customProviders?: Array<any>, config?: any): any[] {
let directives = IONIC_DIRECTIVES;
// add custom providers to Ionic's app
customProviders = isPresent(customProviders) ? 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);
platform.load(config);
config.setPlatform(platform);
let clickBlock = new ClickBlock();
let events = new Events();
let featureDetect = new FeatureDetect();
let navRegistry = new NavRegistry();
setupDom(window, document, config, platform, clickBlock, featureDetect);
bindEvents(window, document, platform, events);
return [
App,
provide(ClickBlock, {useValue: clickBlock}),
provide(Config, {useValue: config}),
provide(Events, {useValue: events}),
provide(FeatureDetect, {useValue: featureDetect}),
Form,
Keyboard,
MenuController,
provide(NavRegistry, {useValue: navRegistry}),
provide(Platform, {useValue: platform}),
Translate,
TapClick,
provide(PLATFORM_DIRECTIVES, {useValue: [directives], multi: true}),
HTTP_PROVIDERS,
customProviders
];
}
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 = <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);
// language and direction
platform.setDir(document.documentElement.dir, false);
platform.setLang(document.documentElement.lang, false);
let versions = platform.versions();
platform.platforms().forEach(platformName => {
// platform-ios
let platformClass = 'platform-' + platformName;
bodyEle.classList.add(platformClass);
let platformVersion = versions[platformName];
if (platformVersion) {
// platform-ios9
platformClass += platformVersion.major;
bodyEle.classList.add(platformClass);
// platform-ios9_3
bodyEle.classList.add(platformClass + '_' + platformVersion.minor);
}
});
// touch devices should not use :hover CSS pseudo
// enable :hover CSS when the "hoverCSS" setting is not false
if (config.get('hoverCSS') !== false) {
bodyEle.classList.add('enable-hover');
}
if ( config.getBoolean('clickBlock', true) !== false ) {
clickBlock.enable();
}
// run feature detection tests
featureDetect.run(window, document);
}
/**
* Bind some global events and publish on the 'app' channel
*/
function bindEvents(window: Window, document: Document, platform: Platform, events: Events) {
window.addEventListener('online', (ev) => {
events.publish('app:online', ev);
}, false);
window.addEventListener('offline', (ev) => {
events.publish('app:offline', ev);
}, false);
window.addEventListener('orientationchange', (ev) => {
events.publish('app:rotated', ev);
});
// When that status taps, we respond
window.addEventListener('statusTap', (ev) => {
// TODO: Make this more better
let el = <HTMLElement>document.elementFromPoint(platform.width() / 2, platform.height() / 2);
if (!el) { return; }
let content = closest(el, 'scroll-content');
if (content) {
var scroll = new ScrollView(content);
scroll.scrollTo(0, 0, 300);
}
});
// start listening for resizes XXms after the app starts
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);
}
}
}