feat(prop): load controllers w/ prop connect and context

This commit is contained in:
Adam Bradley
2017-08-10 08:17:30 -05:00
parent 814268b31e
commit ccb63ee34f
28 changed files with 262 additions and 379 deletions

View File

@ -1,15 +0,0 @@
import { Component } from '@stencil/core';
import { Animator } from './animator';
import { Ionic } from '../../index';
@Component({
tag: 'ion-animation-controller'
})
export class AnimationController {
ionViewWillLoad() {
Ionic.registerController('animation', Animator);
}
}

View File

@ -0,0 +1,22 @@
import { Component, Method } from '@stencil/core';
import { Animation, AnimationBuilder } from './animation-interface';
import { Animator } from './animator';
@Component({
tag: 'ion-animation'
})
export class AnimationController {
@Method()
create(animationBuilder?: AnimationBuilder, baseElm?: any): Promise<Animation> {
return new Promise(resolve => {
if (animationBuilder) {
resolve(animationBuilder(Animator as any, baseElm));
} else {
resolve(new Animator() as any);
}
});
}
}

View File

@ -1,5 +1,5 @@
import { Component, Element, Prop } from '@stencil/core';
import { Ionic, Scroll, ScrollDetail } from '../../index';
import { Config, Scroll, ScrollDetail } from '../../index';
import { createThemedClasses } from '../../utils/theme';
import { getParentElement, getToolbarHeight } from '../../utils/helpers';
@ -16,6 +16,7 @@ export class Content {
private mode: string;
private color: string;
@Element() private el: HTMLElement;
@Prop({ context: 'config' }) config: Config;
$scroll: Scroll;
$scrollDetail: ScrollDetail = {};
@ -103,7 +104,7 @@ export class Content {
props['ionScrollEnd'] = this.ionScrollEnd.bind(this);
}
const themedClasses = createThemedClasses(this.mode, this.color, 'content');
themedClasses['statusbar-padding'] = Ionic.config.getBoolean('statusbarPadding');
themedClasses['statusbar-padding'] = this.config.getBoolean('statusbarPadding');
return (
<ion-scroll style={scrollStyle} props={props} class={themedClasses}>

View File

@ -1,6 +1,6 @@
import { Component, Element } from '@stencil/core';
import { Component, Element, Prop } from '@stencil/core';
import { getParentElement, getToolbarHeight } from '../../utils/helpers';
import { Ionic } from '../../index';
import { Config } from '../../index';
@Component({
@ -15,6 +15,7 @@ import { Ionic } from '../../index';
})
export class Fixed {
@Element() private el: HTMLElement;
@Prop({ context: 'config' }) config: Config;
mode: string;
hostData() {
@ -24,7 +25,7 @@ export class Fixed {
return {
class: {
'statusbar-padding': Ionic.config.getBoolean('statusbarPadding')
'statusbar-padding': this.config.getBoolean('statusbarPadding')
},
style: {
'margin-top': headerHeight,

View File

@ -1,5 +1,9 @@
import { Component } from '@stencil/core';
@Component({
tag: 'ion-gesture-ctrl'
})
export class GestureController {
private id: number = 0;
private requestedStart: { [eventId: number]: number } = {};

View File

@ -1,8 +1,6 @@
import { applyStyles, getElementReference, pointerCoordX, pointerCoordY } from '../../utils/helpers';
import { BlockerDelegate } from './gesture-controller';
import { BlockerDelegate, GestureController, GestureDelegate, BLOCK_ALL } from '../gesture-controller/gesture-controller';
import { Component, Element, Event, EventEmitter, Listen, Prop, PropDidChange } from '@stencil/core';
import { GestureController, GestureDelegate, BLOCK_ALL } from './gesture-controller';
import { Ionic } from '../../index';
import { PanRecognizer } from './recognizers';
@ -11,9 +9,9 @@ import { PanRecognizer } from './recognizers';
})
export class Gesture {
@Element() private el: HTMLElement;
private ctrl: GestureController;
private detail: GestureDetail = {};
private positions: number[] = [];
private ctrl: GestureController;
private gesture: GestureDelegate;
private lastTouch = 0;
private pan: PanRecognizer;
@ -53,8 +51,7 @@ export class Gesture {
// in this case, we already know the GestureController and Gesture are already
// apart of the same bundle, so it's safe to load it this way
// only create one instance of GestureController, and reuse the same one later
this.ctrl = Ionic.controllers.gesture = (Ionic.controllers.gesture || new GestureController());
this.ctrl = Context.gesture = Context.gesture || new GestureController;
this.gesture = this.ctrl.createGesture(this.gestureName, this.gesturePriority, this.disableScroll);
const types = this.type.replace(/\s/g, '').toLowerCase().split(',');
@ -66,10 +63,10 @@ export class Gesture {
this.hasPress = (types.indexOf('press') > -1);
if (this.pan || this.hasPress) {
Core.enableListener(this, 'touchstart', true, this.attachTo);
Core.enableListener(this, 'mousedown', true, this.attachTo);
Context.enableListener(this, 'touchstart', true, this.attachTo);
Context.enableListener(this, 'mousedown', true, this.attachTo);
Core.dom.write(() => {
Context.dom.write(() => {
applyStyles(getElementReference(this.el, this.attachTo), GESTURE_INLINE_STYLES);
});
}
@ -187,7 +184,7 @@ export class Gesture {
if (!this.isMoveQueued) {
this.isMoveQueued = true;
Core.dom.write(() => {
Context.dom.write(() => {
this.isMoveQueued = false;
detail.type = 'pan';
@ -357,17 +354,17 @@ export class Gesture {
private enableMouse(shouldEnable: boolean) {
if (this.requiresMove) {
Core.enableListener(this, 'document:mousemove', shouldEnable);
Context.enableListener(this, 'document:mousemove', shouldEnable);
}
Core.enableListener(this, 'document:mouseup', shouldEnable);
Context.enableListener(this, 'document:mouseup', shouldEnable);
}
private enableTouch(shouldEnable: boolean) {
if (this.requiresMove) {
Core.enableListener(this, 'touchmove', shouldEnable);
Context.enableListener(this, 'touchmove', shouldEnable);
}
Core.enableListener(this, 'touchend', shouldEnable);
Context.enableListener(this, 'touchend', shouldEnable);
}

View File

@ -1,32 +0,0 @@
@import "../../themes/ionic.globals";
// Loading Controller
// --------------------------------------------------
ion-loading-controller {
display: none;
}
// Loading Controller Backdrop
// --------------------------------------------------
/// @prop - Color of the backdrop
$loading-backdrop-color: #000 !default;
.loading-backdrop {
position: absolute;
top: 0;
left: 0;
z-index: $z-index-backdrop;
display: block;
width: 100%;
height: 100%;
background-color: $loading-backdrop-color;
opacity: .01;
transform: translateZ(0);
}

View File

@ -1,26 +1,17 @@
import { Component, Listen } from '@stencil/core';
import { Ionic } from '../../index';
import { LoadingEvent, LoadingOptions, Loading, IonicControllerApi } from '../../index';
import { Component, Listen, Method } from '@stencil/core';
import { LoadingEvent, LoadingOptions, Loading } from '../../index';
@Component({
tag: 'ion-loading-controller',
styleUrl: 'loading-controller.scss'
tag: 'ion-loading-ctrl'
})
export class LoadingController implements IonicControllerApi {
export class LoadingController {
private ids = 0;
private loadingResolves: {[loadingId: string]: Function} = {};
private loadings: Loading[] = [];
private appRoot: Element;
ionViewDidLoad() {
this.appRoot = document.querySelector('ion-app') || document.body;
Ionic.registerController('loading', this);
}
load(opts?: LoadingOptions) {
@Method()
create(opts?: LoadingOptions) {
// create ionic's wrapping ion-loading component
const loading = document.createElement('ion-loading');
@ -35,7 +26,8 @@ export class LoadingController implements IonicControllerApi {
Object.assign(loading, opts);
// append the loading element to the document body
this.appRoot.appendChild(loading as any);
const appRoot = document.querySelector('ion-app') || document.body;
appRoot.appendChild(loading as any);
// store the resolve function to be called later up when the loading loads
return new Promise<Loading>(resolve => {
@ -45,7 +37,7 @@ export class LoadingController implements IonicControllerApi {
@Listen('body:ionLoadingDidLoad')
viewDidLoad(ev: LoadingEvent) {
protected viewDidLoad(ev: LoadingEvent) {
const loading = ev.detail.loading;
const loadingResolve = this.loadingResolves[loading.id];
if (loadingResolve) {
@ -56,13 +48,13 @@ export class LoadingController implements IonicControllerApi {
@Listen('body:ionLoadingWillPresent')
willPresent(ev: LoadingEvent) {
protected willPresent(ev: LoadingEvent) {
this.loadings.push(ev.detail.loading);
}
@Listen('body:ionLoadingWillDismiss, body:ionLoadingDidUnload')
willDismiss(ev: LoadingEvent) {
protected willDismiss(ev: LoadingEvent) {
const index = this.loadings.indexOf(ev.detail.loading);
if (index > -1) {
this.loadings.splice(index, 1);
@ -71,7 +63,7 @@ export class LoadingController implements IonicControllerApi {
@Listen('body:keyup.escape')
escapeKeyUp() {
protected escapeKeyUp() {
const lastLoading = this.loadings[this.loadings.length - 1];
if (lastLoading) {
lastLoading.dismiss();

View File

@ -1,9 +1,13 @@
@import "../../themes/ionic.globals";
// Loading Indicator
// Loading
// --------------------------------------------------
/// @prop - Color of the backdrop
$loading-backdrop-color: #000 !default;
ion-loading {
@include position(0, 0, 0, 0);
@ -27,6 +31,25 @@ ion-loading ion-gesture {
visibility: inherit;
}
ion-loading-controller {
display: none;
}
.loading-backdrop {
position: absolute;
top: 0;
left: 0;
z-index: $z-index-backdrop;
display: block;
width: 100%;
height: 100%;
background-color: $loading-backdrop-color;
opacity: .01;
transform: translateZ(0);
}
.loading-wrapper {
z-index: $z-index-overlay-wrapper;
display: flex;

View File

@ -1,4 +1,4 @@
import { Animation, AnimationBuilder, Ionic } from '../../index';
import { Animation, AnimationBuilder, AnimationController, Config } from '../../index';
import { Component, Element, Event, EventEmitter, Listen, Prop, State } from '@stencil/core';
import iOSEnterAnimation from './animations/ios.enter';
@ -32,6 +32,8 @@ export class Loading {
@State() private showSpinner: boolean = null;
@State() private spinner: string;
@Prop({ connect: 'ion-animation' }) animationCtrl: AnimationController;
@Prop({ context: 'config' }) config: Config;
@Prop() cssClass: string;
@Prop() content: string;
@Prop() dismissOnPageChange: boolean = false;
@ -41,38 +43,6 @@ export class Loading {
@Prop() id: string;
@Prop() showBackdrop: boolean = true;
@Listen('ionDismiss')
onDismiss(ev: UIEvent) {
ev.stopPropagation();
ev.preventDefault();
this.dismiss();
}
ionViewDidLoad() {
if (!this.spinner) {
this.spinner = Ionic.config.get('loadingSpinner', Ionic.config.get('spinner', 'lines'));
}
if (this.showSpinner === null || this.showSpinner === undefined) {
this.showSpinner = !!(this.spinner && this.spinner !== 'hide');
}
this.ionLoadingDidLoad.emit({ loading: this });
}
ionViewDidEnter() {
// blur the currently active element
const activeElement: any = document.activeElement;
activeElement && activeElement.blur && activeElement.blur();
// If there is a duration, dismiss after that amount of time
if (typeof this.duration === 'number' && this.duration > 10) {
this.durationTimeout = setTimeout(() => this.dismiss(), this.duration);
}
this.ionLoadingDidPresent.emit({ loading: this });
}
present() {
return new Promise<void>(resolve => {
this._present(resolve);
@ -97,16 +67,15 @@ export class Loading {
}
// build the animation and kick it off
Ionic.controller('animation').then(Animation => {
this.animation = animationBuilder(Animation, this.el);
this.animationCtrl.create(animationBuilder, this.el).then(animation => {
this.animation = animation;
this.animation.onFinish((a: any) => {
animation.onFinish((a: any) => {
a.destroy();
this.ionViewDidEnter();
resolve();
}).play();
});
}
@ -118,26 +87,27 @@ export class Loading {
this.animation = null;
}
return Ionic.controller('animation').then(Animation => {
return new Promise(resolve => {
this.ionLoadingWillDismiss.emit({ loading: this });
return new Promise(resolve => {
this.ionLoadingWillDismiss.emit({ loading: this });
// get the user's animation fn if one was provided
let animationBuilder = this.exitAnimation;
// get the user's animation fn if one was provided
let animationBuilder = this.exitAnimation;
if (!animationBuilder) {
// user did not provide a custom animation fn
// decide from the config which animation to use
animationBuilder = iOSLeaveAnimation;
}
if (!animationBuilder) {
// user did not provide a custom animation fn
// decide from the config which animation to use
animationBuilder = iOSLeaveAnimation;
}
// build the animation and kick it off
this.animation = animationBuilder(Animation, this.el);
this.animation.onFinish((a: any) => {
// build the animation and kick it off
this.animationCtrl.create(animationBuilder, this.el).then(animation => {
this.animation = animation;
animation.onFinish((a: any) => {
a.destroy();
this.ionLoadingDidDismiss.emit({ loading: this });
Core.dom.write(() => {
Context.dom.write(() => {
this.el.parentNode.removeChild(this.el);
});
@ -148,11 +118,43 @@ export class Loading {
});
}
ionViewDidUnload() {
protected ionViewDidUnload() {
this.ionLoadingDidUnload.emit({ loading: this });
}
render() {
@Listen('ionDismiss')
protected onDismiss(ev: UIEvent) {
ev.stopPropagation();
ev.preventDefault();
this.dismiss();
}
protected ionViewDidLoad() {
if (!this.spinner) {
this.spinner = this.config.get('loadingSpinner', this.config.get('spinner', 'lines'));
}
if (this.showSpinner === null || this.showSpinner === undefined) {
this.showSpinner = !!(this.spinner && this.spinner !== 'hide');
}
this.ionLoadingDidLoad.emit({ loading: this });
}
protected ionViewDidEnter() {
// blur the currently active element
const activeElement: any = document.activeElement;
activeElement && activeElement.blur && activeElement.blur();
// If there is a duration, dismiss after that amount of time
if (typeof this.duration === 'number' && this.duration > 10) {
this.durationTimeout = setTimeout(() => this.dismiss(), this.duration);
}
this.ionLoadingDidPresent.emit({ loading: this });
}
protected render() {
let userCssClass = 'loading-content';
if (this.cssClass) {
userCssClass += ' ' + this.cssClass;

View File

@ -1,5 +1,5 @@
import { Component, Element, Event, EventEmitter, Prop, PropDidChange } from '@stencil/core';
import { Ionic } from '../../index';
import { Config } from '../../index';
import { MenuController } from './menu-controller';
import { MenuType } from './menu-types';
@ -35,6 +35,8 @@ export class Menu {
@Event() ionOpen: EventEmitter;
@Event() ionClose: EventEmitter;
@Prop({ context: 'config' }) config: Config;
/**
* @hidden
*/
@ -153,7 +155,7 @@ export class Menu {
render() {
// normalize the "type"
if (!this.type) {
this.type = Ionic.config.get('menuType', 'overlay');
this.type = this.config.get('menuType', 'overlay');
}
return [
@ -193,7 +195,7 @@ export class Menu {
if (!this._type) {
this._type = this._ctrl.create(this.type, this);
if (Ionic.config.getBoolean('animate') === false) {
if (this.config.getBoolean('animate') === false) {
this._type.ani.duration(0);
}
}
@ -309,7 +311,7 @@ export class Menu {
this._activeBlock = GESTURE_BLOCKER;
// add css class
Core.dom.write(() => {
Context.dom.write(() => {
this._cntElm.classList.add('menu-content-open');
});
@ -321,7 +323,7 @@ export class Menu {
this._activeBlock = null;
// remove css classes
Core.dom.write(() => {
Context.dom.write(() => {
this._cntElm.classList.remove('menu-content-open');
this._cntElm.classList.remove('show-menu');
this._backdropElm.classList.remove('show-menu');
@ -479,8 +481,8 @@ export class Menu {
const onBackdropClick = this.onBackdropClick.bind(this);
if (shouldAdd && !this._unregBdClick) {
this._unregBdClick = Core.addListener(this._cntElm, 'click', onBackdropClick, { capture: true });
this._unregCntClick = Core.addListener(this._cntElm, 'click', onBackdropClick, { capture: true });
this._unregBdClick = Context.addListener(this._cntElm, 'click', onBackdropClick, { capture: true });
this._unregCntClick = Context.addListener(this._cntElm, 'click', onBackdropClick, { capture: true });
} else if (!shouldAdd && this._unregBdClick) {
this._unregBdClick();

View File

@ -1,36 +0,0 @@
@import "../../themes/ionic.globals";
// Modal Controller
// --------------------------------------------------
ion-modal-controller {
display: none;
}
// Modal Controller Backdrop
// --------------------------------------------------
/// @prop - Color of the backdrop
$modal-backdrop-color: #000 !default;
.modal-backdrop {
position: absolute;
top: 0;
left: 0;
z-index: $z-index-backdrop;
display: block;
width: 100%;
height: 100%;
background-color: $modal-backdrop-color;
opacity: .01;
transform: translateZ(0);
}
.modal-backdrop.backdrop-no-tappable {
cursor: auto;
}

View File

@ -1,26 +1,18 @@
import { Component, Listen } from '@stencil/core';
import { Ionic } from '../../index';
import { ModalEvent, ModalOptions, Modal, IonicControllerApi } from '../../index';
import { Component, Listen, Method } from '@stencil/core';
import { Modal, ModalEvent, ModalOptions } from '../../index';
@Component({
tag: 'ion-modal-controller',
styleUrl: 'modal-controller.scss'
tag: 'ion-modal-ctrl'
})
export class ModalController implements IonicControllerApi {
export class ModalController {
private ids = 0;
private modalResolves: {[modalId: string]: Function} = {};
private modals: Modal[] = [];
private appRoot: Element;
ionViewDidLoad() {
this.appRoot = document.querySelector('ion-app') || document.body;
Ionic.registerController('modal', this);
}
load(opts?: ModalOptions) {
@Method()
create(opts?: ModalOptions) {
// create ionic's wrapping ion-modal component
const modal = document.createElement('ion-modal');
@ -35,7 +27,8 @@ export class ModalController implements IonicControllerApi {
Object.assign(modal, opts);
// append the modal element to the document body
this.appRoot.appendChild(modal as any);
const appRoot = document.querySelector('ion-app') || document.body;
appRoot.appendChild(modal as any);
// store the resolve function to be called later up when the modal loads
return new Promise<Modal>(resolve => {
@ -45,7 +38,7 @@ export class ModalController implements IonicControllerApi {
@Listen('body:ionModalDidLoad')
modalDidLoad(ev: ModalEvent) {
protected modalDidLoad(ev: ModalEvent) {
const modal = ev.detail.modal;
const modalResolve = this.modalResolves[modal.id];
if (modalResolve) {
@ -56,13 +49,13 @@ export class ModalController implements IonicControllerApi {
@Listen('body:ionModalWillPresent')
modalWillPresent(ev: ModalEvent) {
protected modalWillPresent(ev: ModalEvent) {
this.modals.push(ev.detail.modal);
}
@Listen('body:ionModalWillDismiss, body:ionModalDidUnload')
modalWillDismiss(ev: ModalEvent) {
protected modalWillDismiss(ev: ModalEvent) {
const index = this.modals.indexOf(ev.detail.modal);
if (index > -1) {
this.modals.splice(index, 1);
@ -71,7 +64,7 @@ export class ModalController implements IonicControllerApi {
@Listen('body:keyup.escape')
escapeKeyUp() {
protected escapeKeyUp() {
const lastModal = this.modals[this.modals.length - 1];
if (lastModal) {
lastModal.dismiss();

View File

@ -22,6 +22,9 @@ $modal-inset-height-small: 500px !default;
/// @prop - Height of the large modal inset
$modal-inset-height-large: 600px !default;
/// @prop - Color of the backdrop
$modal-backdrop-color: #000 !default;
ion-modal {
@include position(0, null, null, 0);
@ -36,6 +39,29 @@ ion-modal {
contain: strict;
}
ion-modal-controller {
display: none;
}
.modal-backdrop {
position: absolute;
top: 0;
left: 0;
z-index: $z-index-backdrop;
display: block;
width: 100%;
height: 100%;
background-color: $modal-backdrop-color;
opacity: .01;
transform: translateZ(0);
}
.modal-backdrop.backdrop-no-tappable {
cursor: auto;
}
.modal-backdrop {
@media not all and (min-width: $modal-inset-min-width) and (min-height: $modal-inset-min-height-small) {
visibility: hidden;

View File

@ -1,5 +1,5 @@
import { Component, Element, Event, EventEmitter, Listen, Prop } from '@stencil/core';
import { AnimationBuilder, Animation, Ionic } from '../../index';
import { AnimationBuilder, AnimationController, Animation } from '../../index';
import { createThemedClasses } from '../../utils/theme';
import iOSEnterAnimation from './animations/ios.enter';
@ -27,6 +27,7 @@ export class Modal {
@Event() ionModalDidDismiss: EventEmitter;
@Event() ionModalDidUnload: EventEmitter;
@Prop({ connect: 'ion-animation' }) animationCtrl: AnimationController;
@Prop() mode: string;
@Prop() color: string;
@Prop() component: string;
@ -38,20 +39,8 @@ export class Modal {
@Prop() id: string;
@Prop() showBackdrop: boolean = true;
private animation: Animation;
@Listen('ionDismiss')
onDismiss(ev: UIEvent) {
ev.stopPropagation();
ev.preventDefault();
this.dismiss();
}
ionViewDidLoad() {
this.ionModalDidLoad.emit({ modal: this });
}
present() {
return new Promise<void>(resolve => {
@ -77,11 +66,11 @@ export class Modal {
animationBuilder = iOSEnterAnimation;
}
Ionic.controller('animation').then(Animation => {
// build the animation and kick it off
this.animation = animationBuilder(Animation, this.el);
// build the animation and kick it off
this.animationCtrl.create(animationBuilder, this.el).then(animation => {
this.animation = animation;
this.animation.onFinish((a: any) => {
animation.onFinish((a: any) => {
a.destroy();
this.ionModalDidPresent.emit({ modal: this });
resolve();
@ -109,13 +98,14 @@ export class Modal {
}
// build the animation and kick it off
Ionic.controller('animation').then(Animation => {
this.animation = animationBuilder(Animation, this.el);
this.animation.onFinish((a: any) => {
this.animationCtrl.create(animationBuilder, this.el).then(animation => {
this.animation = animation;
animation.onFinish((a: any) => {
a.destroy();
this.ionModalDidDismiss.emit({ modal: this });
Core.dom.write(() => {
Context.dom.write(() => {
this.el.parentNode.removeChild(this.el);
});
resolve();
@ -124,11 +114,23 @@ export class Modal {
});
}
ionViewDidUnload() {
@Listen('ionDismiss')
protected onDismiss(ev: UIEvent) {
ev.stopPropagation();
ev.preventDefault();
this.dismiss();
}
protected ionViewDidLoad() {
this.ionModalDidLoad.emit({ modal: this });
}
protected ionViewDidUnload() {
this.ionModalDidUnload.emit({ modal: this });
}
backdropClick() {
protected backdropClick() {
if (this.enableBackdropDismiss) {
// const opts: NavOptions = {
// minClickBlockDuration: 400
@ -137,7 +139,7 @@ export class Modal {
}
}
render() {
protected render() {
const ThisComponent = this.component;
let userCssClasses = 'modal-content';

View File

@ -1,7 +1,6 @@
import { Component, Element, Listen, Prop } from '@stencil/core';
import { GestureDetail } from '../../index';
import { GestureController, GestureDelegate } from '../gesture/gesture-controller';
import { Ionic } from '../../index';
import { Config, GestureDetail } from '../../index';
import { GestureController, GestureDelegate } from '../gesture-controller/gesture-controller';
@Component({
@ -20,6 +19,7 @@ export class Scroll {
isScrolling: boolean = false;
detail: ScrollDetail = {};
@Prop({ context: 'config'}) config: Config;
@Prop() enabled: boolean = true;
@Prop() jsScroll: boolean = false;
@Prop() ionScrollStart: ScrollCallback;
@ -27,11 +27,10 @@ export class Scroll {
@Prop() ionScrollEnd: ScrollCallback;
ionViewDidLoad() {
if (Core.isServer) return;
if (Context.isServer) return;
const ctrl = Ionic.controllers.gesture = (Ionic.controllers.gesture || new GestureController());
this.gesture = ctrl.createGesture('scroll', 100, false);
const gestureCtrl = Context.gesture = Context.gesture || new GestureController;
this.gesture = gestureCtrl.createGesture('scroll', 100, false);
}
@ -44,7 +43,7 @@ export class Scroll {
if (!self.queued && self.enabled) {
self.queued = true;
Core.dom.read(function(timeStamp) {
Context.dom.read(function(timeStamp) {
self.queued = false;
self.onScroll(timeStamp || Date.now());
});
@ -125,7 +124,7 @@ export class Scroll {
// haven't scrolled in a while, so it's a scrollend
self.isScrolling = false;
Core.dom.read(function(timeStamp) {
Context.dom.read(function(timeStamp) {
if (!self.isScrolling) {
self.onEnd(timeStamp);
}
@ -155,9 +154,8 @@ export class Scroll {
enableJsScroll(contentTop: number, contentBottom: number) {
this.jsScroll = true;
Core.enableListener(this, 'scroll', false);
Core.enableListener(this, 'touchstart', true);
Context.enableListener(this, 'scroll', false);
Context.enableListener(this, 'touchstart', true);
contentTop; contentBottom;
}
@ -171,8 +169,8 @@ export class Scroll {
return;
}
Core.enableListener(this, 'touchmove', true);
Core.enableListener(this, 'touchend', true);
Context.enableListener(this, 'touchmove', true);
Context.enableListener(this, 'touchend', true);
throw 'jsScroll: TODO!';
}
@ -186,8 +184,8 @@ export class Scroll {
@Listen('touchend', { passive: true, enabled: false })
onTouchEnd() {
Core.enableListener(this, 'touchmove', false);
Core.enableListener(this, 'touchend', false);
Context.enableListener(this, 'touchmove', false);
Context.enableListener(this, 'touchend', false);
if (!this.enabled) {
return;
@ -308,7 +306,7 @@ export class Scroll {
if (easedT < 1) {
// do not use DomController here
// must use nativeRaf in order to fire in the next frame
Core.dom.raf(step);
Context.dom.raf(step);
} else {
stopScroll = true;
@ -322,8 +320,8 @@ export class Scroll {
self.isScrolling = true;
// chill out for a frame first
Core.dom.write(() => {
Core.dom.write(timeStamp => {
Context.dom.write(() => {
Context.dom.write(timeStamp => {
startTime = timeStamp;
step(timeStamp);
});

View File

@ -1,6 +1,6 @@
import { Component, Prop } from '@stencil/core';
import { createThemedClasses } from '../../utils/theme';
import { Ionic } from '../../index';
import { Config } from '../../index';
import { SPINNERS, SpinnerConfig } from './spinner-configs';
@ -19,6 +19,7 @@ export class Spinner {
mode: string;
color: string;
@Prop({ context: 'config' }) config: Config;
@Prop() duration: number = null;
@Prop() name: string;
@Prop() paused: boolean = false;
@ -45,7 +46,7 @@ export class Spinner {
}
render() {
let name = this.name || Ionic.config.get('spinner', 'lines');
let name = this.name || this.config.get('spinner', 'lines');
if (name === 'ios') {
name = this.name = 'lines';

View File

@ -1,6 +1,6 @@
import { Component, Element, Prop } from '@stencil/core';
import { createThemedClasses } from '../../utils/theme';
import { Ionic } from '../../index';
import { Config } from '../../index';
/**
@ -49,11 +49,11 @@ export class Navbar {
@Element() el: HTMLElement;
mode: string;
color: string;
sbPadding: boolean = Ionic.config.getBoolean('statusbarPadding');
@Prop({ context: 'config' }) config: Config;
@Prop() hideBackButton: boolean = false;
@Prop() backButtonText: string = Ionic.config.get('backButtonText', 'Back');
@Prop() backButtonIcon: string = Ionic.config.get('backButtonIcon');
@Prop() backButtonText: string;
@Prop() backButtonIcon: string;
@Prop() hidden: boolean = false;
backButtonClick(ev: UIEvent) {
@ -73,12 +73,15 @@ export class Navbar {
hostData() {
return {
class: {
'statusbar-padding': Ionic.config.getBoolean('statusbarPadding')
'statusbar-padding': this.config.getBoolean('statusbarPadding')
}
};
}
render() {
const backButtonIcon = this.backButtonIcon || this.config.get('backButtonText', 'Back');
const backButtonText = this.backButtonText || this.config.get('backButtonIcon', 'Back');
const backgroundCss = createThemedClasses(this.mode, this.color, 'toolbar-background');
const contentCss = createThemedClasses(this.mode, this.color, 'toolbar-content');
const backButtonCss = createThemedClasses(this.mode, this.color, 'back-button');
@ -88,8 +91,10 @@ export class Navbar {
return [
<div class={backgroundCss}></div>,
<button onClick={this.backButtonClick.bind(this)} class={backButtonCss} hidden={this.hideBackButton}>
<ion-icon class={backButtonIconCss} name={this.backButtonIcon}></ion-icon>
<span class={backButtonTextCss}>{this.backButtonText}</span>
if (backButtonIcon) {
<ion-icon class={backButtonIconCss} name={backButtonIcon}></ion-icon>
}
<span class={backButtonTextCss}>{backButtonText}</span>
</button>,
<slot name='start'></slot>,
<slot name='mode-start'></slot>,

View File

@ -1,7 +1,6 @@
import { Component, Element } from '@stencil/core';
import { Component, Element, Prop } from '@stencil/core';
import { createThemedClasses } from '../../utils/theme';
import { Ionic } from '../../index';
import { Config } from '../../index';
/**
* @name Toolbar
@ -104,6 +103,7 @@ import { Ionic } from '../../index';
})
export class Toolbar {
@Element() el: HTMLElement;
@Prop({ context: 'config' }) config: Config;
mode: string;
color: string;
@ -117,7 +117,7 @@ export class Toolbar {
hostData() {
return {
class: {
'statusbar-padding': Ionic.config.getBoolean('statusbarPadding')
'statusbar-padding': this.config.getBoolean('statusbarPadding')
}
};
}

View File

@ -1,8 +1,8 @@
import { ConfigApi } from '../index';
import { Config } from '../index';
import { PlatformConfig } from './platform-configs';
export function createConfigController(configObj: any, platforms: PlatformConfig[]): ConfigApi {
export function createConfigController(configObj: any, platforms: PlatformConfig[]): Config {
configObj = configObj || {};
function get(key: string, fallback?: any): any {

View File

@ -1,95 +1,13 @@
import { createConfigController } from './config-controller';
import { detectPlatforms, PLATFORM_CONFIGS } from './platform-configs';
import { IonicControllerApi, IonicGlobal } from '../index';
// create the Ionic global (if one doesn't exist)
const Ionic: IonicGlobal = (window as any).Ionic = (window as any).Ionic || {};
// used to store the queued controller promises to
// be resolved when the controller finishes loading
const queuedCtrlResolves: {[ctrlName: string]: any[]} = {};
// create a container for all of the controllers that get loaded
Ionic.controllers = {};
// create the public method to load controllers
Ionic.controller = (ctrlName: string, opts?: any) => {
// loading a controller is always async so return a promise
return new Promise<any>((resolve: Function) => {
// see if we already have the controller loaded
const ctrl = Ionic.controllers[ctrlName];
if (ctrl) {
// we've already loaded this controller
// resolve it immediately
resolveController(ctrl, resolve, opts);
} else {
// oh noz! we haven't already loaded this controller yet!
const ctrlResolveQueue = queuedCtrlResolves[ctrlName];
if (ctrlResolveQueue) {
// cool we've already "started" to load the controller
// but it hasn't finished loading yet, so let's add
// this one also to the queue of to-be resolved promises
ctrlResolveQueue.push(resolve, opts);
} else {
// looks like we haven't even started the request yet,
// let's add the component to the DOM and create
// a queue for this controller
queuedCtrlResolves[ctrlName] = [resolve, opts];
// create our controller element
// and append it to the body
document.body.appendChild(document.createElement(`ion-${ctrlName}-controller`));
}
}
});
};
// create the method controllers will call once their instance has loaded
Ionic.registerController = (ctrlName: string, ctrl: IonicControllerApi) => {
// this method is called when the singleton
// instance of our controller initially loads
// add this controller instance to our map of controller singletons
Ionic.controllers[ctrlName] = ctrl;
// check for to-be resolved controller promises
const pendingCtrlResolves = queuedCtrlResolves[ctrlName];
if (pendingCtrlResolves) {
for (var i = 0; i < pendingCtrlResolves.length; i += 2) {
// first arg is the original promise's resolve
// which still needs to be resolved
// second arg was the originally passed in options
resolveController(ctrl, pendingCtrlResolves[i], pendingCtrlResolves[i + 1]);
}
// all good, go ahead and remove from the queue
delete queuedCtrlResolves[ctrlName];
}
};
function resolveController(ctrl: IonicControllerApi, resolve: Function, opts: any) {
if (opts) {
// if the call had options passed in then
// it should run the controller's load() method
// and let the controller's load() do the resolve
// which then will resolve the user's promise
ctrl.load(opts).then(<any>resolve);
} else {
// no options passed in, so resolve with
// the actual controller instance
resolve(ctrl);
}
}
const Ionic = (window as any).Ionic = (window as any).Ionic || {};
// create the Ionic.config from raw config object (if it exists)
// and convert Ionic.config into a ConfigApi that has a get() fn
Ionic.config = createConfigController(
Context.config = createConfigController(
Ionic.config,
detectPlatforms(window.location.href, window.navigator.userAgent, PLATFORM_CONFIGS, 'core')
);
@ -97,4 +15,4 @@ Ionic.config = createConfigController(
// get the mode via config settings and set it to
// both Ionic and the Core global
Core.mode = Ionic.mode = Ionic.config.get('mode', 'md');
Context.mode = Context.config.get('mode', 'md');

View File

@ -1,5 +1,5 @@
import { AnimationController } from './components/animation-controller/animation-controller';
import { Animation, AnimationBuilder } from './components/animation-controller/animation-interface';
import { AnimationController } from './components/animation/animation';
import { Animation, AnimationBuilder } from './components/animation/animation-interface';
import { Loading, LoadingEvent, LoadingOptions } from './components/loading/loading';
import { LoadingController } from './components/loading-controller/loading-controller';
import { GestureDetail, GestureCallback } from './components/gesture/gesture';
@ -14,33 +14,7 @@ import { SegmentButton, SegmentButtonEvent } from './components/segment-button/s
import * as Stencil from '@stencil/core';
export const Ionic: IonicGlobal = (window as any).Ionic;
export interface IonicGlobal extends Stencil.AppGlobal {
controllers?: {[ctrlName: string]: any};
controller?: IonicController;
config: ConfigApi;
registerController?: (ctrlName: string, ctrl: any) => void;
mode: string;
}
export interface IonicController {
<AnimationController>(ctrlName: 'animation'): Promise<Animation>;
<LoadingController>(ctrlName: 'loading', opts: LoadingOptions): Promise<Loading>;
<MenuController>(ctrlName: 'menu'): Promise<MenuController>;
<ModalController>(ctrlName: 'modal', opts: ModalOptions): Promise<Modal>;
(ctrlName: string, opts?: any): Promise<IonicControllerApi>;
}
export interface IonicControllerApi {
load?: (opts?: any) => Promise<any>;
}
export interface ConfigApi {
export interface Config {
get: (key: string, fallback?: any) => any;
getBoolean: (key: string, fallback?: boolean) => boolean;
getNumber: (key: string, fallback?: number) => number;