diff --git a/src/components.ts b/src/components.ts deleted file mode 100644 index 18fd1ce1ba..0000000000 --- a/src/components.ts +++ /dev/null @@ -1,65 +0,0 @@ -export { ActionSheet, ActionSheetController } from './components/action-sheet/action-sheet'; -export { ActionSheetOptions } from './components/action-sheet/action-sheet-options'; -export { Alert, AlertController } from './components/alert/alert'; -export { AlertOptions, AlertInputOptions } from './components/alert/alert-options'; -export { App } from './components/app/app'; -export { Backdrop } from './components/backdrop/backdrop'; -export { Badge } from './components/badge/badge'; -export { Button } from './components/button/button'; -export { Checkbox } from './components/checkbox/checkbox'; -export { Chip } from './components/chip/chip'; -export { Content } from './components/content/content'; -export { DateTime } from './components/datetime/datetime'; -export { Icon } from './components/icon/icon'; -export { Img } from './components/img/img'; -export { InfiniteScroll } from './components/infinite-scroll/infinite-scroll'; -export { InfiniteScrollContent } from './components/infinite-scroll/infinite-scroll-content'; -export { TextArea, TextInput } from './components/input/input'; -export { Item } from './components/item/item'; -export { ItemReorder } from './components/item/item-reorder'; -export { ItemSliding, ItemOptions, ItemSideFlags } from './components/item/item-sliding'; -export { Label } from './components/label/label'; -export { List, ListHeader } from './components/list/list'; -export { Loading, LoadingController } from './components/loading/loading'; -export { LoadingOptions } from './components/loading/loading-options'; -export { Menu } from './components/menu/menu'; -export { MenuClose } from './components/menu/menu-close'; -export { MenuController } from './components/menu/menu-controller'; -export { MenuToggle } from './components/menu/menu-toggle'; -export { MenuType } from './components/menu/menu-types'; -export { Modal, ModalController } from './components/modal/modal'; -export { ModalOptions } from './components/modal/modal-options'; -export { Nav } from './components/nav/nav'; -export { NavController } from './components/nav/nav-controller'; -export { NavOptions } from './components/nav/nav-interfaces'; -export { NavParams } from './components/nav/nav-params'; -export { NavPop } from './components/nav/nav-pop'; -export { NavPush } from './components/nav/nav-push'; -export { ViewController } from './components/nav/view-controller'; -export { Navbar, NavbarTemplate } from './components/navbar/navbar'; -export { Option } from './components/option/option'; -export { Picker, PickerController } from './components/picker/picker'; -export { PickerOptions, PickerColumn, PickerColumnOption } from './components/picker/picker-options'; -export { Popover, PopoverController } from './components/popover/popover'; -export { PopoverOptions } from './components/popover/popover-options'; -export { RadioButton } from './components/radio/radio-button'; -export { RadioGroup } from './components/radio/radio-group'; -export { Range, RangeKnob, ClientRect } from './components/range/range'; -export { Refresher } from './components/refresher/refresher'; -export { RefresherContent } from './components/refresher/refresher-content'; -export { Scroll } from './components/scroll/scroll'; -export { Searchbar } from './components/searchbar/searchbar'; -export { Segment, SegmentButton } from './components/segment/segment'; -export { Select } from './components/select/select'; -export { ShowWhen, HideWhen, DisplayWhen } from './components/show-hide-when/show-hide-when'; -export { Slides, Slide, SlideLazy } from './components/slides/slides'; -export { Spinner } from './components/spinner/spinner'; -export { Tab } from './components/tabs/tab'; -export { Tabs } from './components/tabs/tabs'; -export { TapClick, isActivatable } from './components/tap-click/tap-click'; -export { Toast, ToastController } from './components/toast/toast'; -export { ToastOptions } from './components/toast/toast-options'; -export { Toggle } from './components/toggle/toggle'; -export { Toolbar, ToolbarBase, Header, Footer } from './components/toolbar/toolbar'; -export { Typography } from './components/typography/typography'; -export { VirtualScroll } from './components/virtual-scroll/virtual-scroll'; diff --git a/src/components/app/app-root.ts b/src/components/app/app-root.ts new file mode 100644 index 0000000000..06c155369d --- /dev/null +++ b/src/components/app/app-root.ts @@ -0,0 +1,113 @@ +import { Component, ComponentFactoryResolver, ElementRef, Inject, OnInit, OpaqueToken, Renderer, ViewChild, ViewContainerRef } from '@angular/core'; + +import { App } from './app'; +import { Config } from '../../config/config'; +import { FeatureDetect } from '../../util/feature-detect'; +import { Ion } from '../ion'; +import { OverlayPortal } from '../nav/overlay-portal'; +import { Platform } from '../../platform/platform'; + +export const UserRoot = new OpaqueToken('USERROOT'); + +/** + * @private + */ +@Component({ + selector: 'ion-app', + template: + '
' + + '
' + + '
' + + '
' + + '
' +}) +export class IonicApp extends Ion implements OnInit { + + @ViewChild('viewport', {read: ViewContainerRef}) _viewport: ViewContainerRef; + + @ViewChild('overlayPortal', { read: OverlayPortal }) _overlayPortal: OverlayPortal; + + @ViewChild('loadingPortal', { read: OverlayPortal }) _loadingPortal: OverlayPortal; + + @ViewChild('toastPortal', { read: OverlayPortal }) _toastPortal: OverlayPortal; + + constructor( + @Inject(UserRoot) private _userCmp: any, + private _cfr: ComponentFactoryResolver, + elementRef: ElementRef, + renderer: Renderer, + config: Config, + private _platform: Platform, + private _featureDetect: FeatureDetect, + app: App + ) { + super(config, elementRef, renderer); + // register with App that this is Ionic's appRoot component. tada! + app._appRoot = this; + } + + ngOnInit() { + // load the user root component + // into Ionic's root component + const factory = this._cfr.resolveComponentFactory(this._userCmp); + const componentRef = this._viewport.createComponent(factory); + this._renderer.setElementClass(componentRef.location.nativeElement, 'app-root', true); + componentRef.changeDetectorRef.detectChanges(); + + // set the mode class name + // ios/md/wp + this.setElementClass(this._config.get('mode'), true); + + const versions = this._platform.versions(); + this._platform.platforms().forEach(platformName => { + // platform-ios + let platformClass = 'platform-' + platformName; + this.setElementClass(platformClass, true); + + let platformVersion = versions[platformName]; + if (platformVersion) { + // platform-ios9 + platformClass += platformVersion.major; + this.setElementClass(platformClass, true); + + // platform-ios9_3 + this.setElementClass(platformClass + '_' + platformVersion.minor, true); + } + }); + + // touch devices should not use :hover CSS pseudo + // enable :hover CSS when the "hoverCSS" setting is not false + if (this._config.getBoolean('hoverCSS', true)) { + this.setElementClass('enable-hover', true); + } + + this._featureDetect.test(this); + } + + /** + * @private + */ + _getPortal(portal?: AppPortal): OverlayPortal { + if (portal === AppPortal.LOADING) { + return this._loadingPortal; + } + if (portal === AppPortal.TOAST) { + return this._toastPortal; + } + return this._overlayPortal; + } + + /** + * @private + */ + _disableScroll(shouldDisableScroll: boolean) { + this.setElementClass('disable-scroll', shouldDisableScroll); + } + +} + +export enum AppPortal { + DEFAULT, + LOADING, + TOAST +}; diff --git a/src/components/app/app.ts b/src/components/app/app.ts index 6d42cd39d5..17602ed0e4 100644 --- a/src/components/app/app.ts +++ b/src/components/app/app.ts @@ -1,22 +1,17 @@ -import { Component, ComponentResolver, EventEmitter, HostBinding, Injectable, Renderer, ViewChild, ViewContainerRef } from '@angular/core'; +import { EventEmitter, Injectable } from '@angular/core'; import { Title } from '@angular/platform-browser'; +import { AppPortal, IonicApp } from './app-root'; import { ClickBlock } from '../../util/click-block'; import { Config } from '../../config/config'; -import { NavController } from '../nav/nav-controller'; -import { isTabs, isNav } from '../nav/nav-controller-base'; -import { NavOptions } from '../nav/nav-interfaces'; -import { NavPortal } from '../nav/nav-portal'; +import { isNav, isTabs, NavOptions, DIRECTION_FORWARD, DIRECTION_BACK } from '../../navigation/nav-util'; +import { NavController } from '../../navigation/nav-controller'; import { Platform } from '../../platform/platform'; - -/** - * @private - */ -export abstract class UserComponent {} +import { ViewController } from '../../navigation/view-controller'; /** - * Ionic App utility service. + * Ionic App */ @Injectable() export class App { @@ -25,17 +20,16 @@ export class App { private _title: string = ''; private _titleSrv: Title = new Title(); private _rootNav: NavController = null; - private _portal: NavPortal; /** * @private */ - clickBlock: ClickBlock; + _clickBlock: ClickBlock; /** * @private */ - appRoot: AppRoot; + _appRoot: IonicApp; /** * @private @@ -67,11 +61,6 @@ export class App { */ viewWillUnload: EventEmitter = new EventEmitter(); - /** - * @private - */ - viewDidUnload: EventEmitter = new EventEmitter(); - constructor( private _config: Config, private _platform: Platform @@ -92,6 +81,13 @@ export class App { } } + /** + * @private + */ + setElementClass(className: string, isAdd: boolean) { + this._appRoot.setElementClass(className, isAdd); + } + /** * Sets if the app is currently enabled or not, meaning if it's * available to accept new user commands. For example, this is set to `false` @@ -106,14 +102,14 @@ export class App { setEnabled(isEnabled: boolean, duration: number = 700) { this._disTime = (isEnabled ? 0 : Date.now() + duration); - if (this.clickBlock) { + if (this._clickBlock) { if (isEnabled || duration <= 32) { // disable the click block if it's enabled, or the duration is tiny - this.clickBlock.activate(false, 0); + this._clickBlock.activate(false, 0); } else { // show the click block for duration + some number - this.clickBlock.activate(true, duration + CLICK_BLOCK_BUFFER_IN_MILLIS); + this._clickBlock.activate(true, duration + CLICK_BLOCK_BUFFER_IN_MILLIS); } } } @@ -124,15 +120,9 @@ export class App { * scrolling is enabled. When set to `true`, scrolling is disabled. */ setScrollDisabled(disableScroll: boolean) { - let enabled = this._config.get('canDisableScroll', true); - if (!enabled) { - return; + if (this._config.get('canDisableScroll', true)) { + this._appRoot._disableScroll(disableScroll); } - if (!this.appRoot) { - console.error('appRoot is missing, scrolling can not be enabled/disabled'); - return; - } - this.appRoot.disableScroll = disableScroll; } /** @@ -187,38 +177,33 @@ export class App { /** * @private */ - setRootNav(nav: any) { + _setRootNav(nav: any) { this._rootNav = nav; } /** * @private */ - setPortal(portal: NavPortal) { - this._portal = portal; - } + present(enteringView: ViewController, opts: NavOptions, appPortal?: AppPortal): Promise { + const portal = this._appRoot._getPortal(appPortal); - /** - * @private - */ - present(enteringView: any, opts: NavOptions = {}): Promise { - enteringView.setNav(this._portal); + enteringView._setNav(portal); opts.keyboardClose = false; - opts.direction = 'forward'; + opts.direction = DIRECTION_FORWARD; if (!opts.animation) { - opts.animation = enteringView.getTransitionName('forward'); + opts.animation = enteringView.getTransitionName(DIRECTION_FORWARD); } enteringView.setLeavingOpts({ keyboardClose: false, - direction: 'back', - animation: enteringView.getTransitionName('back'), + direction: DIRECTION_BACK, + animation: enteringView.getTransitionName(DIRECTION_BACK), ev: opts.ev }); - return this._portal.insertViews(-1, [enteringView], opts); + return portal.insertPages(-1, [enteringView], opts); } /** @@ -257,14 +242,15 @@ export class App { // app must be enabled and there must be a // root nav controller for go back to work if (this._rootNav && this.isEnabled()) { + const portal = this._appRoot._getPortal(); // first check if the root navigation has any overlays // opened in it's portal, like alert/actionsheet/popup - if (this._portal && this._portal.length() > 0) { + if (portal.length() > 0) { // there is an overlay view in the portal // let's pop this one off to go back console.debug('app, goBack pop overlay'); - return this._portal.pop(); + return portal.pop(); } // next get the active nav, check itself and climb up all @@ -285,72 +271,6 @@ export class App { return Promise.resolve(); } - /** - * @private - */ - private getRegisteredComponent(cls: any): any { - // deprecated warning: added 2016-04-28, beta7 - console.warn('Using app.getRegisteredComponent() to query components has been deprecated. ' + - 'Please use Angular\'s ViewChild annotation instead:\n\nhttp://learnangular2.com/viewChild/'); - } - - /** - * @private - */ - private getComponent(id: string): any { - // deprecated warning: added 2016-04-28, beta7 - console.warn('Using app.getComponent() to query components has been deprecated. ' + - 'Please use Angular\'s ViewChild annotation instead:\n\nhttp://learnangular2.com/viewChild/'); - } - - /** - * Get an instance of the global app injector that contains references to all of the instantiated providers - * @returns {Injector} - */ - private getAppInjector(): any { - // deprecated warning: added 2016-06-27, beta10 - console.warn('Recent Angular2 versions should no longer require App.getAppInjector()'); - } -} - - -/** - * @private - */ -@Component({ - selector: 'ion-app', - template: ` -
- - `, - directives: [NavPortal, ClickBlock] -}) -export class AppRoot { - - @ViewChild('anchor', {read: ViewContainerRef}) private _viewport: ViewContainerRef; - - constructor( - private _cmp: UserComponent, - private _cr: ComponentResolver, - private _renderer: Renderer, - app: App - ) { - app.appRoot = this; - } - - ngAfterViewInit() { - // load the user app's root component - this._cr.resolveComponent(this._cmp).then(componentFactory => { - let appEle: HTMLElement = this._renderer.createElement(null, componentFactory.selector || 'div', null); - appEle.setAttribute('class', 'app-root'); - - let componentRef = componentFactory.create(this._viewport.injector, null, appEle); - this._viewport.insert(componentRef.hostView, 0); - }); - } - - @HostBinding('class.disable-scroll') disableScroll: boolean = false; - } const CLICK_BLOCK_BUFFER_IN_MILLIS = 64; diff --git a/src/components/ion.ts b/src/components/ion.ts index 4f487ff8f5..227e03d631 100644 --- a/src/components/ion.ts +++ b/src/components/ion.ts @@ -1,7 +1,7 @@ -import { ElementRef } from '@angular/core'; -import { getDimensions, clearDimensions } from '../util/dom'; +import { ElementRef, Renderer } from '@angular/core'; -let ids: number = 0; +import { Config } from '../config/config'; +import { getDimensions, clearDimensions } from '../util/dom'; /** * Base class for all Ionic components. Exposes some common functionality @@ -9,36 +9,109 @@ let ids: number = 0; * sending/receiving app-level events. */ export class Ion { - private _id: string; + private _ionId: string; - constructor(protected elementRef: ElementRef) { - this._id = 'i' + ids++; + /** @private */ + _config: Config; + + /** @private */ + _elementRef: ElementRef; + + /** @private */ + _renderer: Renderer; + + /** @private */ + _color: string; + + /** @private */ + _mode: string; + + constructor(config: Config, elementRef: ElementRef, renderer: Renderer) { + this._config = config; + this._elementRef = elementRef; + this._renderer = renderer; } + /** @private */ + setElementClass(className: string, isAdd: boolean) { + this._renderer.setElementClass(this._elementRef.nativeElement, className, isAdd); + } + + /** @private */ + setElementAttribute(attributeName: string, attributeValue: any) { + this._renderer.setElementAttribute(this._elementRef.nativeElement, attributeName, attributeValue); + } + + /** @private */ + setElementStyle(property: string, value: string) { + this._renderer.setElementStyle(this._elementRef.nativeElement, property, value); + } + + /** @private */ + _setColor(componentName: string, newColor: string) { + if (this._color) { + this.setElementClass(`${componentName}-${this._mode}-${this._color}`, false); + } + if (newColor) { + this.setElementClass(`${componentName}-${this._mode}-${newColor}`, true); + this._color = newColor; + } + } + + /** @private */ + _setMode(componentName: string, newMode: string) { + if (this._mode) { + this.setElementClass(`${componentName}-${this._mode}`, false); + } + if (newMode) { + this.setElementClass(`${componentName}-${newMode}`, true); + + // Remove the color class associated with the previous mode, + // change the mode, then add the new color class + this._setColor(componentName, null); + this._mode = newMode; + this._setColor(componentName, this._color); + } + } + + /** @private */ getElementRef(): ElementRef { - return this.elementRef; + return this._elementRef; } + /** @private */ getNativeElement(): any { - return this.elementRef.nativeElement; + return this._elementRef.nativeElement; } - getDimensions(): { - width: number, height: number, left: number, top: number - } { - return getDimensions(this.elementRef.nativeElement, this._id); + /** @private */ + getDimensions(): { width: number, height: number, left: number, top: number} { + return getDimensions(this.getNativeElement(), this._getId()); } + /** @private */ width(): number { - return getDimensions(this.elementRef.nativeElement, this._id).width; + return getDimensions(this.getNativeElement(), this._getId()).width; } + /** @private */ height(): number { - return getDimensions(this.elementRef.nativeElement, this._id).height; + return getDimensions(this.getNativeElement(), this._getId()).height; } - ngOnDestroy() { - clearDimensions(this._id); + /** @private */ + destroy() { + clearDimensions(this._ionId); + } + + /** internal */ + _getId() { + if (!this._ionId) { + this._ionId = 'i' + ids++; + } + return this._ionId; } } + +let ids: number = 0; diff --git a/src/directives.ts b/src/directives.ts new file mode 100644 index 0000000000..b047ab2085 --- /dev/null +++ b/src/directives.ts @@ -0,0 +1,241 @@ + +/** + * Import Components + */ +import { Avatar } from './components/avatar/avatar'; +import { Backdrop } from './components/backdrop/backdrop'; +import { Badge } from './components/badge/badge'; +import { Button } from './components/button/button'; +import { Card, CardContent, CardHeader, CardTitle } from './components/card/card'; +import { Checkbox } from './components/checkbox/checkbox'; +import { Chip } from './components/chip/chip'; +import { Content } from './components/content/content'; +import { DateTime } from './components/datetime/datetime'; +import { Fixed } from './components/fixed/fixed'; +import { Grid, Row, Col } from './components/grid/grid'; +import { Icon } from './components/icon/icon'; +import { Img } from './components/img/img'; +import { InfiniteScroll } from './components/infinite-scroll/infinite-scroll'; +import { InfiniteScrollContent } from './components/infinite-scroll/infinite-scroll-content'; +import { IonicApp } from './components/app/app-root'; +import { Item, ItemContent, ItemGroup } from './components/item/item'; +import { ItemReorder, Reorder } from './components/item/item-reorder'; +import { ItemSliding, ItemOptions } from './components/item/item-sliding'; +import { Label } from './components/label/label'; +import { List } from './components/list/list'; +import { ListHeader } from './components/list/list-header'; +import { Menu } from './components/menu/menu'; +import { MenuClose } from './components/menu/menu-close'; +import { MenuToggle } from './components/menu/menu-toggle'; +import { NativeInput, NextInput } from './components/input/native-input'; +import { Nav } from './components/nav/nav'; +import { NavPop, NavPopAnchor } from './components/nav/nav-pop'; +import { NavPush, NavPushAnchor } from './components/nav/nav-push'; +import { Navbar } from './components/navbar/navbar'; +import { Note } from './components/note/note'; +import { Option } from './components/option/option'; +import { OverlayPortal } from './components/nav/overlay-portal'; +import { PickerColumnCmp } from './components/picker/picker-component'; +import { RadioButton } from './components/radio/radio-button'; +import { RadioGroup } from './components/radio/radio-group'; +import { Range, RangeKnob } from './components/range/range'; +import { Refresher } from './components/refresher/refresher'; +import { RefresherContent } from './components/refresher/refresher-content'; +import { Scroll } from './components/scroll/scroll'; +import { Searchbar } from './components/searchbar/searchbar'; +import { Segment, SegmentButton } from './components/segment/segment'; +import { Select } from './components/select/select'; +import { ShowWhen, HideWhen } from './components/show-hide-when/show-hide-when'; +import { Slides, Slide, SlideLazy } from './components/slides/slides'; +import { Spinner } from './components/spinner/spinner'; +import { Tab } from './components/tabs/tab'; +import { Tabs } from './components/tabs/tabs'; +import { TabButton } from './components/tabs/tab-button'; +import { TextInput, TextArea } from './components/input/input'; +import { Thumbnail } from './components/thumbnail/thumbnail'; +import { Toggle } from './components/toggle/toggle'; +import { Toolbar, Header, Footer } from './components/toolbar/toolbar'; +import { ToolbarItem } from './components/toolbar/toolbar-item'; +import { ToolbarTitle } from './components/toolbar/toolbar-title'; +import { Typography } from './components/typography/typography'; +import { VirtualScroll } from './components/virtual-scroll/virtual-scroll'; +import { VirtualItem, VirtualHeader, VirtualFooter } from './components/virtual-scroll/virtual-item'; + + +/** + * Export Components + */ +export { ActionSheet, ActionSheetController } from './components/action-sheet/action-sheet'; +export { ActionSheetOptions } from './components/action-sheet/action-sheet-options'; +export { Alert, AlertController } from './components/alert/alert'; +export { AlertOptions, AlertInputOptions } from './components/alert/alert-options'; +export { App } from './components/app/app'; +export { Avatar } from './components/avatar/avatar'; +export { Backdrop } from './components/backdrop/backdrop'; +export { Badge } from './components/badge/badge'; +export { Button } from './components/button/button'; +export { Card, CardContent, CardHeader, CardTitle } from './components/card/card'; +export { Checkbox } from './components/checkbox/checkbox'; +export { Chip } from './components/chip/chip'; +export { Content } from './components/content/content'; +export { DateTime } from './components/datetime/datetime'; +export { Fixed } from './components/fixed/fixed'; +export { Grid, Row, Col } from './components/grid/grid'; +export { Icon } from './components/icon/icon'; +export { Img } from './components/img/img'; +export { InfiniteScroll } from './components/infinite-scroll/infinite-scroll'; +export { InfiniteScrollContent } from './components/infinite-scroll/infinite-scroll-content'; +export { TextArea, TextInput } from './components/input/input'; +export { IonicApp } from './components/app/app-root'; +export { Item, ItemContent, ItemGroup } from './components/item/item'; +export { ItemReorder, Reorder } from './components/item/item-reorder'; +export { ItemSliding, ItemOptions, ItemSideFlags } from './components/item/item-sliding'; +export { Label } from './components/label/label'; +export { List } from './components/list/list'; +export { ListHeader } from './components/list/list-header'; +export { Loading, LoadingController } from './components/loading/loading'; +export { LoadingOptions } from './components/loading/loading-options'; +export { Menu } from './components/menu/menu'; +export { MenuClose } from './components/menu/menu-close'; +export { MenuController } from './components/menu/menu-controller'; +export { MenuToggle } from './components/menu/menu-toggle'; +export { MenuType } from './components/menu/menu-types'; +export { Modal, ModalController } from './components/modal/modal'; +export { ModalOptions } from './components/modal/modal-options'; +export { Nav } from './components/nav/nav'; +export { NavPop, NavPopAnchor } from './components/nav/nav-pop'; +export { NavPush, NavPushAnchor } from './components/nav/nav-push'; +export { Navbar } from './components/navbar/navbar'; +export { NativeInput, NextInput } from './components/input/native-input'; +export { Note } from './components/note/note'; +export { Option } from './components/option/option'; +export { OverlayPortal } from './components/nav/overlay-portal'; +export { Picker, PickerController } from './components/picker/picker'; +export { PickerOptions, PickerColumn, PickerColumnOption } from './components/picker/picker-options'; +export { Popover, PopoverController } from './components/popover/popover'; +export { PopoverOptions } from './components/popover/popover-options'; +export { RadioButton } from './components/radio/radio-button'; +export { RadioGroup } from './components/radio/radio-group'; +export { Range, RangeKnob, ClientRect } from './components/range/range'; +export { Refresher } from './components/refresher/refresher'; +export { RefresherContent } from './components/refresher/refresher-content'; +export { Scroll } from './components/scroll/scroll'; +export { Searchbar } from './components/searchbar/searchbar'; +export { Segment, SegmentButton } from './components/segment/segment'; +export { Select } from './components/select/select'; +export { ShowWhen, HideWhen, DisplayWhen } from './components/show-hide-when/show-hide-when'; +export { Slides, Slide, SlideLazy } from './components/slides/slides'; +export { Spinner } from './components/spinner/spinner'; +export { Tab } from './components/tabs/tab'; +export { Tabs } from './components/tabs/tabs'; +export { TabButton } from './components/tabs/tab-button'; +export { TabHighlight } from './components/tabs/tab-highlight'; +export { TapClick, isActivatable } from './components/tap-click/tap-click'; +export { Toast, ToastController } from './components/toast/toast'; +export { ToastOptions } from './components/toast/toast-options'; +export { Toggle } from './components/toggle/toggle'; +export { Toolbar, ToolbarBase, Header, Footer } from './components/toolbar/toolbar'; +export { ToolbarTitle } from'./components/toolbar/toolbar-title'; +export { Thumbnail } from './components/thumbnail/thumbnail'; +export { Typography } from './components/typography/typography'; +export { VirtualScroll } from './components/virtual-scroll/virtual-scroll'; + + +export { ActionSheetCmp } from './components/action-sheet/action-sheet-component'; +export { AlertCmp } from './components/alert/alert-component'; +export { LoadingCmp } from './components/loading/loading-component'; +export { ModalCmp } from './components/modal/modal-component'; +export { PickerCmp, PickerColumnCmp } from './components/picker/picker-component'; +export { PopoverCmp } from './components/popover/popover-component'; +export { ToastCmp } from './components/toast/toast-component'; + +/** + * @private + * @name IONIC_DIRECTIVES + * @description + * The core Ionic directives are automatically available when you bootstrap your app + * with the `IonicModule`. This means if you are using custom components you do not + * need to import `IONIC_DIRECTIVES` as they are part of the app's default directives. + */ +export const IONIC_DIRECTIVES: any[] = [ + Avatar, + Backdrop, + Badge, + Button, + Card, + CardContent, + CardHeader, + CardTitle, + Checkbox, + Chip, + Col, + Content, + DateTime, + Fixed, + Footer, + Grid, + Header, + HideWhen, + Icon, + Img, + InfiniteScroll, + InfiniteScrollContent, + IonicApp, + Item, + ItemContent, + ItemGroup, + ItemOptions, + ItemReorder, + ItemSliding, + Label, + List, + ListHeader, + Menu, + MenuClose, + MenuToggle, + NativeInput, + Nav, + Navbar, + NavPop, + NavPopAnchor, + NavPush, + NavPushAnchor, + NextInput, + Note, + Option, + OverlayPortal, + PickerColumnCmp, + RadioButton, + RadioGroup, + Range, + RangeKnob, + Refresher, + RefresherContent, + Reorder, + Row, + Scroll, + Searchbar, + Segment, + SegmentButton, + Select, + ShowWhen, + Slide, + Slides, + SlideLazy, + Spinner, + Tab, + Tabs, + TabButton, + TextArea, + TextInput, + Thumbnail, + Toggle, + Toolbar, + ToolbarItem, + ToolbarTitle, + Typography, + VirtualFooter, + VirtualHeader, + VirtualItem, + VirtualScroll, +]; diff --git a/src/index.ts b/src/index.ts index 5043478fb8..3dfbd3996a 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,12 +1,9 @@ -export { ionicBootstrap, ionicPostBootstrap } from './config/bootstrap'; export { Config } from './config/config'; -export { IONIC_DIRECTIVES } from './config/directives'; -export { ionicProviders } from './config/providers'; +export { IonicModule } from './module'; -export * from './decorators/page'; - -export * from './components'; +export * from './directives'; +export * from './providers'; export * from './gestures/drag-gesture'; export * from './gestures/gesture'; @@ -15,7 +12,9 @@ export * from './gestures/slide-gesture'; export * from './gestures/gesture-controller'; export * from './platform/platform'; -export * from './platform/storage'; +export * from './storage/storage'; +export * from './storage/sql'; +export * from './storage/local-storage'; export * from './util/click-block'; export * from './util/events'; @@ -29,11 +28,3 @@ export * from './transitions/transition'; export * from './translation/translate'; export * from './translation/translate_pipe'; - -// these modules don't export anything -import './config/modes'; -import './platform/registry'; -import './animations/builtins'; -import './transitions/transition-ios'; -import './transitions/transition-md'; -import './transitions/transition-wp'; diff --git a/src/module.ts b/src/module.ts new file mode 100644 index 0000000000..f78ce90810 --- /dev/null +++ b/src/module.ts @@ -0,0 +1,51 @@ +import { ModuleWithProviders, NgModule } from '@angular/core'; +import { BrowserModule } from '@angular/platform-browser'; +import { FormsModule, ReactiveFormsModule } from '@angular/forms'; +import { HttpModule } from '@angular/http'; + +import { ActionSheetCmp } from './components/action-sheet/action-sheet-component'; +import { AlertCmp } from './components/alert/alert-component'; +import { IONIC_DIRECTIVES } from './directives'; +import { IonicApp } from './components/app/app-root'; +import { ionicProviders } from './providers'; +import { LoadingCmp } from './components/loading/loading-component'; +import { ModalCmp } from './components/modal/modal-component'; +import { PickerCmp } from './components/picker/picker-component'; +import { PopoverCmp } from './components/popover/popover-component'; +import { ToastCmp } from './components/toast/toast-component'; + + +@NgModule({ + imports: [BrowserModule, HttpModule, FormsModule, ReactiveFormsModule], + exports: [BrowserModule, HttpModule, FormsModule, ReactiveFormsModule, IONIC_DIRECTIVES], + declarations: [ + ActionSheetCmp, + AlertCmp, + IONIC_DIRECTIVES, + LoadingCmp, + ModalCmp, + PickerCmp, + PopoverCmp, + ToastCmp + ], + entryComponents: [ + ActionSheetCmp, + AlertCmp, + IonicApp, + LoadingCmp, + ModalCmp, + PickerCmp, + PopoverCmp, + ToastCmp + ] +}) +export class IonicModule { + + static forRoot(userAppRoot: any, userConfig?: any, userDeepLinkConfig?: any): ModuleWithProviders { + return { + ngModule: IonicModule, + providers: ionicProviders(userAppRoot, userConfig, userDeepLinkConfig) + }; + } + +} diff --git a/src/providers.ts b/src/providers.ts new file mode 100644 index 0000000000..f5f81b96ae --- /dev/null +++ b/src/providers.ts @@ -0,0 +1,118 @@ +import { ANALYZE_FOR_ENTRY_COMPONENTS } from '@angular/core'; +import { HAMMER_GESTURE_CONFIG } from '@angular/platform-browser'; + + +/** + * Import Providers + */ +import { ActionSheetController } from './components/action-sheet/action-sheet'; +import { AlertController } from './components/alert/alert'; +import { App } from './components/app/app'; +import { provideConfig } from './config/config'; +import { provideEvents } from './util/events'; +import { FeatureDetect } from './util/feature-detect'; +import { Form } from './util/form'; +import { GestureController } from './gestures/gesture-controller'; +import { IonicGestureConfig } from './gestures/gesture-config'; +import { Keyboard } from './util/keyboard'; +import { LoadingController } from './components/loading/loading'; +import { MenuController } from './components/menu/menu-controller'; +import { ModalController } from './components/modal/modal'; +import { PickerController } from './components/picker/picker'; +import { providePlatform, UserAgent, UserNavigatorPlatform, UserDir, UserLang } from './platform/platform'; +import { PopoverController } from './components/popover/popover'; +import { provideDeepLinker } from './navigation/deep-linker'; +import { provideQueryParams, UserUrl } from './platform/query-params'; +import { TapClick, provideTapClick } from './components/tap-click/tap-click'; +import { ToastController } from './components/toast/toast'; +import { Translate } from './translation/translate'; +import { TransitionController } from './transitions/transition-controller'; +import { UserRoot } from './components/app/app-root'; + + +/** + * Export Providers + */ +export { DeepLinker, provideDeepLinker } from './navigation/deep-linker'; +export { NavController } from './navigation/nav-controller'; +export { NavParams } from './navigation/nav-params'; +export { NavLink, NavOptions, DeepLink, DeepLinkConfig } from './navigation/nav-util'; +export { ViewController } from './navigation/view-controller'; + + +/** + * @private + * ionicProviders used by IonicModule + */ +export function ionicProviders(userRoot: any, userConfig?: any, userDeepLinkConfig?: any): any[] { + return [ + { provide: ANALYZE_FOR_ENTRY_COMPONENTS, useValue: userRoot, multi: true }, + { provide: HAMMER_GESTURE_CONFIG, useClass: IonicGestureConfig }, + { provide: UserAgent, useFactory: getWindowUserAgent }, + { provide: UserDir, useFactory: getDocumentDir }, + { provide: UserLang, useFactory: getDocumentLang }, + { provide: UserNavigatorPlatform, useFactory: getWindowPlatform }, + { provide: UserRoot, useValue: userRoot }, + { provide: UserUrl, useFactory: getWindowLocation }, + + provideConfig(userConfig), + provideDeepLinker(userDeepLinkConfig), + provideEvents(), + providePlatform(), + provideQueryParams(), + provideTapClick(), + + ActionSheetController, + AlertController, + App, + Form, + FeatureDetect, + GestureController, + Keyboard, + LoadingController, + MenuController, + ModalController, + PickerController, + PopoverController, + TapClick, + ToastController, + Translate, + TransitionController + ]; +} + + +/** + * @private + */ +export function getWindowUserAgent() { + return window && window.navigator.userAgent; +} + +/** + * @private + */ +export function getWindowPlatform() { + return window && window.navigator.platform; +} + +/** + * @private + */ +export function getWindowLocation() { + return window && window.location.href; +} + +/** + * @private + */ +export function getDocumentDir() { + return document && document.documentElement.dir; +} + +/** + * @private + */ +export function getDocumentLang() { + return document && document.documentElement.lang; +} diff --git a/src/util/click-block.ts b/src/util/click-block.ts index 3c4b19ab89..632db61160 100644 --- a/src/util/click-block.ts +++ b/src/util/click-block.ts @@ -11,7 +11,7 @@ const DEFAULT_EXPIRE = 330; * @private */ @Directive({ - selector: 'click-block' + selector: '.click-block' }) export class ClickBlock { private _tmrId: number; @@ -24,7 +24,7 @@ export class ClickBlock { private elementRef: ElementRef, private renderer: Renderer ) { - app.clickBlock = this; + app._clickBlock = this; this.isEnabled = config.getBoolean('clickBlock', true); } diff --git a/src/util/feature-detect.ts b/src/util/feature-detect.ts index 7f6ee48887..d281a6a9ba 100644 --- a/src/util/feature-detect.ts +++ b/src/util/feature-detect.ts @@ -1,58 +1,51 @@ +import { IonicApp } from '../components/app/app-root'; + export class FeatureDetect { - private _results: {[featureName: string]: boolean} = {}; + private _r: {[featureName: string]: boolean} = {}; - run(window: Window, document: Document) { + test(appRoot: IonicApp) { for (let name in featureDetects) { - this._results[name] = featureDetects[name](window, document, document.body); + this._r[name] = !!featureDetects[name].test(); + if (this._r[name]) { + appRoot.setElementClass(name, true); + } } + featureDetects = null; } has(featureName: string): boolean { - return !!this._results[featureName]; + return !!this._r[featureName]; } - static add(name: string, fn: any) { - featureDetects[name] = fn; + static add(name: string, test: any) { + // feature detection tests should only run on client side + if ((this).window) { + featureDetects[name] = new test(); + } } } -let featureDetects: {[featureName: string]: Function} = {}; +let featureDetects: {[featureName: string]: FeatureDetectTest} = {}; -FeatureDetect.add('hairlines', function(window: Window, document: Document, body: HTMLBodyElement): boolean { - /** - * Hairline Shim - * Add the "hairline" CSS class name to the body tag - * if the browser supports subpixels. - */ - let canDo = false; - if (window.devicePixelRatio >= 2) { - var hairlineEle = document.createElement('div'); - hairlineEle.style.border = '.5px solid transparent'; - body.appendChild(hairlineEle); +export abstract class FeatureDetectTest { + abstract test(): boolean; +} - if (hairlineEle.offsetHeight === 1) { - body.classList.add('hairlines'); - canDo = true; - } - body.removeChild(hairlineEle); + +/** +* backdrop-filter Test +* Checks if css backdrop-filter is implemented by the browser. +*/ +export class BackdropFilterTest implements FeatureDetectTest { + + test() { + const styles = document.documentElement.style; + return !!(styles['backdrop-filter'] !== undefined || styles['-webkit-backdrop-filter'] !== undefined); } - return canDo; -}); -FeatureDetect.add('backdrop-filter', function(window: Window, document: Document, body: HTMLBodyElement): boolean { - /** - * backdrop-filter Shim - * Checks if css backdrop-filter is implemented by the browser. - */ - let styles = body.style; - let backdrop = styles['backdrop-filter'] !== undefined || - styles['-webkit-backdrop-filter'] !== undefined; - if (backdrop) { - body.classList.add('backdrop-filter'); - } - return backdrop; -}); +} +FeatureDetect.add('backdrop-filter', BackdropFilterTest);