From 5b0eda5be11ebd1409db7612695e58cc7774d108 Mon Sep 17 00:00:00 2001 From: Adam Bradley Date: Fri, 2 Oct 2015 15:23:08 -0500 Subject: [PATCH 01/11] refactor(config): get/set/settings and unit tests --- demos/modal/index.ts | 2 +- ionic/components/action-sheet/action-sheet.ts | 8 +- ionic/components/app/app.ts | 8 +- ionic/components/button/button.ts | 2 +- ionic/components/icon/icon.ts | 2 +- ionic/components/ion.ts | 2 +- ionic/components/modal/modal.ts | 4 +- ionic/components/modal/test/basic/index.ts | 2 +- ionic/components/nav-bar/nav-bar.ts | 4 +- ionic/components/nav/nav-controller.ts | 6 +- ionic/components/overlay/overlay.ts | 2 +- ionic/components/popup/popup.ts | 4 +- ionic/components/switch/switch.ts | 2 +- ionic/components/tabs/tabs.ts | 4 +- ionic/components/tap-click/activator.ts | 2 +- ionic/components/tap-click/tap-click.ts | 4 +- ionic/components/text-input/label.ts | 2 +- ionic/components/text-input/text-input.ts | 4 +- ionic/config/config.ts | 266 +++++++----------- ionic/config/test/config.spec.ts | 205 +++++++++++++- ionic/platform/platform.ts | 19 +- ionic/platform/test/platform.spec.ts | 49 ++-- ionic/transitions/ios-transition.ts | 22 +- ionic/transitions/md-transition.ts | 16 +- ionic/transitions/transition.ts | 52 ++-- 25 files changed, 414 insertions(+), 279 deletions(-) diff --git a/demos/modal/index.ts b/demos/modal/index.ts index 3b15c4ec16..54bee6fbe3 100644 --- a/demos/modal/index.ts +++ b/demos/modal/index.ts @@ -11,7 +11,7 @@ class MyAppCmp { this.modal = modal; console.log('platforms', platform.platforms()); - console.log('mode', config.setting('mode')); + console.log('mode', config.get('mode')); console.log('core', platform.is('core')) console.log('cordova', platform.is('cordova')) diff --git a/ionic/components/action-sheet/action-sheet.ts b/ionic/components/action-sheet/action-sheet.ts index ba0490303d..bfed358662 100644 --- a/ionic/components/action-sheet/action-sheet.ts +++ b/ionic/components/action-sheet/action-sheet.ts @@ -110,10 +110,10 @@ export class ActionSheet extends Overlay { open(opts={}) { let config = this.config; let defaults = { - enterAnimation: config.setting('actionSheetEnter'), - leaveAnimation: config.setting('actionSheetLeave'), - cancelIcon: config.setting('actionSheetCancelIcon'), - destructiveIcon: config.setting('actionSheetDestructiveIcon') + enterAnimation: config.get('actionSheetEnter'), + leaveAnimation: config.get('actionSheetLeave'), + cancelIcon: config.get('actionSheetCancelIcon'), + destructiveIcon: config.get('actionSheetDestructiveIcon') }; let context = util.extend(defaults, opts); diff --git a/ionic/components/app/app.ts b/ionic/components/app/app.ts index 90a30a0772..7a1deb80e3 100644 --- a/ionic/components/app/app.ts +++ b/ionic/components/app/app.ts @@ -281,7 +281,7 @@ function initApp(window, document, config, platform) { platform.url(window.location.href); platform.userAgent(window.navigator.userAgent); platform.navigatorPlatform(window.navigator.platform); - platform.load(config); + platform.load(); // copy default platform settings into the user config platform settings // user config platform settings should override default platform settings @@ -361,7 +361,7 @@ export function ionicBootstrap(rootComponentType, views, config) { let loader = injector.get(DynamicComponentLoader); loader.loadNextToLocation(RootAnchor, lastElementRef).then(() => { // append the focus holder if its needed - if (config.setting('keyboardScrollAssist')) { + if (config.get('keyboardScrollAssist')) { app.appendComponent(FocusHolder).then(ref => { app.focusHolder(ref.instance); }); @@ -409,11 +409,11 @@ function applyBodyCss(document, config, platform) { // set the mode class name // ios - bodyEle.classList.add(config.setting('mode')); + bodyEle.classList.add(config.get('mode')); // touch devices should not use :hover CSS pseudo // enable :hover CSS when the "hoverCSS" setting is not false - if (config.setting('hoverCSS') !== false) { + if (config.get('hoverCSS') !== false) { bodyEle.classList.add('enable-hover'); } diff --git a/ionic/components/button/button.ts b/ionic/components/button/button.ts index 1756a039cc..9151012bf9 100644 --- a/ionic/components/button/button.ts +++ b/ionic/components/button/button.ts @@ -17,7 +17,7 @@ export class Button { ) { let element = elementRef.nativeElement; - if (config.setting('hoverCSS') === false) { + if (config.get('hoverCSS') === false) { element.classList.add('disable-hover'); } diff --git a/ionic/components/icon/icon.ts b/ionic/components/icon/icon.ts index d76d3be9af..7f2c28d74b 100644 --- a/ionic/components/icon/icon.ts +++ b/ionic/components/icon/icon.ts @@ -34,7 +34,7 @@ export class Icon { this.eleRef = elementRef; this.config = config; - this.mode = config.setting('iconMode'); + this.mode = config.get('iconMode'); } /** diff --git a/ionic/components/ion.ts b/ionic/components/ion.ts index d6c0d375dc..6be3e4dd58 100644 --- a/ionic/components/ion.ts +++ b/ionic/components/ion.ts @@ -35,7 +35,7 @@ export class Ion { } // get the property values from a global user/platform config - let configVal = this.config.setting(prop); + let configVal = this.config.get(prop); if (configVal) { this[prop] = configVal; continue; diff --git a/ionic/components/modal/modal.ts b/ionic/components/modal/modal.ts index 791dc6869e..3764cecbcf 100644 --- a/ionic/components/modal/modal.ts +++ b/ionic/components/modal/modal.ts @@ -38,8 +38,8 @@ export class Modal extends Overlay { */ open(ComponentType: Type, opts={}) { let defaults = { - enterAnimation: this.config.setting('modalEnter') || 'modal-slide-in', - leaveAnimation: this.config.setting('modalLeave') || 'modal-slide-out', + enterAnimation: this.config.get('modalEnter') || 'modal-slide-in', + leaveAnimation: this.config.get('modalLeave') || 'modal-slide-out', }; return this.create(OVERLAY_TYPE, ComponentType, util.extend(defaults, opts)); diff --git a/ionic/components/modal/test/basic/index.ts b/ionic/components/modal/test/basic/index.ts index f21fab5ced..4d91f900ea 100644 --- a/ionic/components/modal/test/basic/index.ts +++ b/ionic/components/modal/test/basic/index.ts @@ -11,7 +11,7 @@ class MyAppCmp { this.modal = modal; console.log('platforms', platform.platforms()); - console.log('mode', config.setting('mode')); + console.log('mode', config.get('mode')); console.log('core', platform.is('core')) console.log('cordova', platform.is('cordova')) diff --git a/ionic/components/nav-bar/nav-bar.ts b/ionic/components/nav-bar/nav-bar.ts index 66d7ebed15..108dbee8b2 100644 --- a/ionic/components/nav-bar/nav-bar.ts +++ b/ionic/components/nav-bar/nav-bar.ts @@ -83,8 +83,8 @@ export class Navbar extends ToolbarBase { this.app = app; viewCtrl && viewCtrl.navbarView(this); - this.bbIcon = config.setting('backButtonIcon'); - this.bbDefault = config.setting('backButtonText'); + this.bbIcon = config.get('backButtonIcon'); + this.bbDefault = config.get('backButtonText'); } getBackButtonRef() { diff --git a/ionic/components/nav/nav-controller.ts b/ionic/components/nav/nav-controller.ts index 3eaeac525a..636f7d5e8e 100644 --- a/ionic/components/nav/nav-controller.ts +++ b/ionic/components/nav/nav-controller.ts @@ -46,8 +46,8 @@ export class NavController extends Ion { this.views = []; this._sbTrans = null; - this._sbEnabled = config.setting('swipeBackEnabled') || false; - this._sbThreshold = config.setting('swipeBackThreshold') || 40; + this._sbEnabled = config.get('swipeBackEnabled') || false; + this._sbThreshold = config.get('swipeBackThreshold') || 40; this.id = ++ctrlIds; this._ids = -1; @@ -333,7 +333,7 @@ export class NavController extends Ion { } if (!opts.animation) { - opts.animation = this.config.setting('viewTransition'); + opts.animation = this.config.get('viewTransition'); } // wait for the new view to complete setup diff --git a/ionic/components/overlay/overlay.ts b/ionic/components/overlay/overlay.ts index 3a8d9c299d..e6bf9ff0a6 100644 --- a/ionic/components/overlay/overlay.ts +++ b/ionic/components/overlay/overlay.ts @@ -11,7 +11,7 @@ export class Overlay { constructor(app: IonicApp, config: IonicConfig) { this.app = app; this.config = config; - this.mode = config.setting('mode'); + this.mode = config.get('mode'); } create(overlayType, componentType: Type, opts={}, context=null) { diff --git a/ionic/components/popup/popup.ts b/ionic/components/popup/popup.ts index 90bbd9f0af..e9b1c75b57 100644 --- a/ionic/components/popup/popup.ts +++ b/ionic/components/popup/popup.ts @@ -74,8 +74,8 @@ export class Popup extends Overlay { return new Promise((resolve, reject)=> { let config = this.config; let defaults = { - enterAnimation: config.setting('popupPopIn'), - leaveAnimation: config.setting('popupPopOut'), + enterAnimation: config.get('popupPopIn'), + leaveAnimation: config.get('popupPopOut'), }; opts.promiseResolve = resolve; diff --git a/ionic/components/switch/switch.ts b/ionic/components/switch/switch.ts index 16e3d28d40..e3fc3f6968 100644 --- a/ionic/components/switch/switch.ts +++ b/ionic/components/switch/switch.ts @@ -130,7 +130,7 @@ export class Switch extends Ion { self.id = IonInput.nextId(); self.tabIndex = 0; self.lastTouch = 0; - self.mode = config.setting('mode'); + self.mode = config.get('mode'); self.onChange = (_) => {}; self.onTouched = (_) => {}; diff --git a/ionic/components/tabs/tabs.ts b/ionic/components/tabs/tabs.ts index 3d5cb9c6a1..40fd909b4d 100644 --- a/ionic/components/tabs/tabs.ts +++ b/ionic/components/tabs/tabs.ts @@ -202,7 +202,7 @@ class TabButton extends Ion { super(elementRef, config); this.tabs = tabs; - if (config.setting('hoverCSS') === false) { + if (config.get('hoverCSS') === false) { elementRef.nativeElement.classList.add('disable-hover'); } } @@ -232,7 +232,7 @@ class TabButton extends Ion { }) class TabHighlight { constructor(@Host() tabs: Tabs, config: IonicConfig, elementRef: ElementRef) { - if (config.setting('mode') === 'md') { + if (config.get('mode') === 'md') { tabs.highlight = this; this.elementRef = elementRef; } diff --git a/ionic/components/tap-click/activator.ts b/ionic/components/tap-click/activator.ts index a919c4798c..7adcc819f8 100644 --- a/ionic/components/tap-click/activator.ts +++ b/ionic/components/tap-click/activator.ts @@ -9,7 +9,7 @@ export class Activator { this.active = []; this.clearStateTimeout = 180; this.clearAttempt = 0; - this.activatedClass = config.setting('activatedClass') || 'activated'; + this.activatedClass = config.get('activatedClass') || 'activated'; this.x = 0; this.y = 0; } diff --git a/ionic/components/tap-click/tap-click.ts b/ionic/components/tap-click/tap-click.ts index 9a0647a2d7..1a93c766b5 100644 --- a/ionic/components/tap-click/tap-click.ts +++ b/ionic/components/tap-click/tap-click.ts @@ -18,9 +18,9 @@ export class TapClick { self.disableClick = 0; self.disableClickLimit = 1000; - self.tapPolyfill = (config.setting('tapPolyfill') !== false); + self.tapPolyfill = (config.get('tapPolyfill') !== false); - if (config.setting('mdRipple')) { + if (config.get('mdRipple')) { self.activator = new RippleActivator(app, config); } else { self.activator = new Activator(app, config); diff --git a/ionic/components/text-input/label.ts b/ionic/components/text-input/label.ts index f038e0e35e..b4ff8a1e1d 100644 --- a/ionic/components/text-input/label.ts +++ b/ionic/components/text-input/label.ts @@ -26,7 +26,7 @@ export class Label { * @param {IonicConfig} config */ constructor(config: IonicConfig) { - this.scrollAssist = config.setting('keyboardScrollAssist'); + this.scrollAssist = config.get('keyboardScrollAssist'); } /** diff --git a/ionic/components/text-input/text-input.ts b/ionic/components/text-input/text-input.ts index 8b41724d12..16c76cf7b4 100644 --- a/ionic/components/text-input/text-input.ts +++ b/ionic/components/text-input/text-input.ts @@ -111,7 +111,7 @@ export class TextInput extends Ion { super(elementRef, config); this.scrollView = scrollView; - this.scrollAssist = config.setting('keyboardScrollAssist'); + this.scrollAssist = config.get('keyboardScrollAssist'); this.id = IonInput.nextId(); IonInput.registerInput(this); @@ -121,7 +121,7 @@ export class TextInput extends Ion { this.inputQry = inputQry; this.labelQry = labelQry; - this.keyboardHeight = this.config.setting('keyboardHeight'); + this.keyboardHeight = this.config.get('keyboardHeight'); } /** diff --git a/ionic/config/config.ts b/ionic/config/config.ts index 7be575d64b..96468c174e 100644 --- a/ionic/config/config.ts +++ b/ionic/config/config.ts @@ -1,4 +1,4 @@ - +import {IonicPlatform} from '../platform/platform'; import {isObject, isDefined, isFunction, extend} from '../util/util'; /** @@ -10,56 +10,129 @@ export class IonicConfig { * TODO * @param {Object} settings The settings for your app */ - constructor(settings) { + constructor(settings={}) { + this._s = settings; + this._c = {}; // cached values + } - // defaults - this._settings = {}; + /** + * For setting and getting multiple config values + */ + settings() { + const args = arguments; + + switch (args.length) { + + case 0: + return this._s; + + case 1: + // settings({...}) + this._s = args[0]; + this._c = {}; // clear cache + break; + + case 2: + // settings('ios', {...}) + this._s.platforms = this._s.platforms || {}; + this._s.platforms[args[0]] = args[1]; + this._c = {}; // clear cache + break; - // override defaults w/ user config - if (settings) { - extend(this._settings, settings); } } - get(key) { - let settings = this._settings; + /** + * For setting a single config values + */ + set() { + const args = arguments; + const arg0 = args[0]; + const arg1 = args[1]; - if (!isDefined(this._settings[key])) { + switch (args.length) { + case 2: + // set('key', 'value') = set key/value pair + // arg1 = value + this._s[arg0] = arg1; + delete this._c[arg0]; // clear cache + break; + + case 3: + // setting('ios', 'key', 'value') = set key/value pair for platform + // arg0 = platform + // arg1 = key + // arg2 = value + this._s.platforms = this._s.platforms || {}; + this._s.platforms[arg0] = this._s.platforms[arg0] || {}; + this._s.platforms[arg0][arg1] = args[2]; + delete this._c[arg1]; // clear cache + break; + + } + + return this; + } + + /** + * For getting a single config values + */ + get(key) { + + if (!isDefined(this._c[key])) { // if the value was already set this will all be skipped // if there was no user config then it'll check each of // the user config's platforms, which already contains // settings from default platform configs - this._settings[key] = null; + this._c[key] = null; - // check the platform settings object for this value - // loop though each of the active platforms - let activePlatformKeys = this._platforms; - let platformSettings = this._settings.platforms; - let platformObj = null; - if (platformSettings) { - let platformValue = undefined; + let userPlatformValue = undefined; + let platformValue = undefined; + let userDefaultValue = this._s[key]; + let modeValue = undefined; + + if (this._platform) { + // check the platform settings object for this value + // loop though each of the active platforms + let platformObj = null; + + // array of active platforms, which also knows the hierarchy, + // with the last one the most important + let activePlatformKeys = this._platform.platforms(); + + // loop through all of the active platforms we're on for (let i = 0; i < activePlatformKeys.length; i++) { - platformObj = platformSettings[ activePlatformKeys[i] ]; - if (platformObj) { - if (isDefined(platformObj[key])) { - // check assigned platform settings - platformValue = platformObj[key]; - - } else if (platformObj.mode) { - // check the platform default mode settings - platformObj = IonicConfig.modeConfig(platformObj.mode); - if (platformObj) { - platformValue = platformObj[key]; - } + // get user defined platform values + if (this._s.platforms) { + platformObj = this._s.platforms[ activePlatformKeys[i] ]; + if (platformObj && isDefined(platformObj[key])) { + userPlatformValue = platformObj[key]; } } - } - if (isDefined(platformValue)) { - this._settings[key] = platformValue; + // get default platform's setting + platformObj = IonicPlatform.get(activePlatformKeys[i]); + if (platformObj && platformObj.settings) { + + if (isDefined(platformObj.settings[key])) { + // found a setting for this platform + platformValue = platformObj.settings[key]; + } + + platformObj = IonicConfig.modeConfig(platformObj.settings.mode); + if (platformObj && isDefined(platformObj[key])) { + // found setting for this platform's mode + modeValue = platformObj[key]; + } + + } + } } + + // cache the value + this._c[key] = isDefined(userPlatformValue) ? userPlatformValue : isDefined(platformValue) ? platformValue : isDefined(userDefaultValue) ? userDefaultValue : isDefined(modeValue) ? modeValue : null; } // return key's value @@ -67,124 +140,11 @@ export class IonicConfig { // or it was from the users platform configs // or it was from the default platform configs // in that order - if (isFunction(this._settings[key])) { - this._settings[key] = settings[key](this._platform); - } - return this._settings[key]; - } - - /** - * TODO - */ - setting() { - const args = arguments; - const arg0 = args[0]; - const arg1 = args[1]; - - let settings = this._settings; - - switch (args.length) { - - case 0: - // setting() = get settings object - return settings; - - - case 1: - // setting({...}) = set settings object - // setting('key') = get value - - if (isObject(arg0)) { - // setting({...}) = set settings object - // arg0 = setting object - this._settings = arg0; - return this; - } - - // time for the big show, get the value - // setting('key') = get value - // arg0 = key - - if (!isDefined(settings[arg0])) { - // if the value was already set this will all be skipped - // if there was no user config then it'll check each of - // the user config's platforms, which already contains - // settings from default platform configs - settings[arg0] = null; - - // check the platform settings object for this value - // loop though each of the active platforms - let activePlatformKeys = this._platforms; - let platformSettings = settings.platforms; - let platformObj = null; - if (platformSettings) { - let platformValue = undefined; - for (let i = 0; i < activePlatformKeys.length; i++) { - platformObj = platformSettings[ activePlatformKeys[i] ]; - - if (platformObj) { - if (isDefined(platformObj[arg0])) { - // check assigned platform settings - platformValue = platformObj[arg0]; - - } else if (platformObj.mode) { - // check the platform default mode settings - platformObj = IonicConfig.modeConfig(platformObj.mode); - if (platformObj) { - platformValue = platformObj[arg0]; - } - } - } - - } - if (isDefined(platformValue)) { - settings[arg0] = platformValue; - } - } - } - - // return key's value - // either it came directly from the user config - // or it was from the users platform configs - // or it was from the default platform configs - // in that order - if (isFunction(settings[arg0])) { - settings[arg0] = settings[arg0](this._platform); - } - return settings[arg0]; - - - case 2: - // setting('ios', {...}) = set platform config object - // setting('key', 'value') = set key/value pair - if (isObject(arg1)) { - // setting('ios', {...}) = set platform config object - // arg0 = platform - // arg1 = platform config object - settings.platforms = settings.platforms || {}; - settings.platforms[arg0] = arg1; - - } else { - // setting('key', 'value') = set key/value pair - // arg0 = key - // arg1 = value - settings[arg0] = arg1; - } - return this; - - - case 3: - // setting('ios', 'key', 'value') = set key/value pair for platform - // arg0 = platform - // arg1 = key - // arg2 = value - settings.platforms = settings.platforms || {}; - settings.platforms[arg0] = settings.platforms[arg0] || {}; - settings.platforms[arg0][arg1] = args[2]; - return this; - + if (isFunction(this._c[key])) { + return this._c[key](this._platform); } + return this._c[key]; } /** @@ -193,14 +153,6 @@ export class IonicConfig { */ setPlatform(platform) { this._platform = platform; - - // get the array of active platforms, which also knows the hierarchy, - // with the last one the most important - this._platforms = platform.platforms(); - - // copy default platform settings into the user config platform settings - // user config platform settings should override default platform settings - this._settings.platforms = extend(platform.settings(), this._settings.platforms || {}); } static modeConfig(mode, config) { diff --git a/ionic/config/test/config.spec.ts b/ionic/config/test/config.spec.ts index 1d14153559..15b987b315 100644 --- a/ionic/config/test/config.spec.ts +++ b/ionic/config/test/config.spec.ts @@ -2,9 +2,206 @@ import {IonicConfig, IonicPlatform} from 'ionic/ionic'; export function run() { + it('should get ios mode for core platform', () => { + let config = new IonicConfig(); + let platform = new IonicPlatform(['core']); + config.setPlatform(platform); + + expect(config.get('mode')).toEqual('ios'); + }); + + it('should get ios mode for ipad platform', () => { + let config = new IonicConfig(); + let platform = new IonicPlatform(['mobile', 'ios', 'ipad', 'tablet']); + config.setPlatform(platform); + + expect(config.get('mode')).toEqual('ios'); + }); + + it('should get md mode for windowsphone platform', () => { + let config = new IonicConfig(); + let platform = new IonicPlatform(['mobile', 'windowsphone']); + config.setPlatform(platform); + + expect(config.get('mode')).toEqual('md'); + }); + + it('should get md mode for android platform', () => { + let config = new IonicConfig(); + let platform = new IonicPlatform(['mobile', 'android']); + config.setPlatform(platform); + + expect(config.get('mode')).toEqual('md'); + }); + + it('should override ios mode config with user platform setting', () => { + let config = new IonicConfig({ + tabBarPlacement: 'hide', + platforms: { + ios: { + tabBarPlacement: 'top' + } + } + }); + let platform = new IonicPlatform(['ios']); + config.setPlatform(platform); + + expect(config.get('tabBarPlacement')).toEqual('top'); + }); + + it('should override ios mode config with user setting', () => { + let config = new IonicConfig({ + tabBarPlacement: 'top' + }); + let platform = new IonicPlatform(['ios']); + config.setPlatform(platform); + + expect(config.get('tabBarPlacement')).toEqual('top'); + }); + + it('should get setting from md mode', () => { + let config = new IonicConfig(); + let platform = new IonicPlatform(['android']); + config.setPlatform(platform); + + expect(config.get('tabBarPlacement')).toEqual('top'); + }); + + it('should get setting from ios mode', () => { + let config = new IonicConfig(); + let platform = new IonicPlatform(['ios']); + config.setPlatform(platform); + + expect(config.get('tabBarPlacement')).toEqual('bottom'); + }); + + it('should set/get platform setting from set()', () => { + let config = new IonicConfig(); + let platform = new IonicPlatform(['ios']); + config.setPlatform(platform); + + config.set('tabBarPlacement', 'bottom'); + config.set('ios', 'tabBarPlacement', 'top'); + + expect(config.get('tabBarPlacement')).toEqual('top'); + }); + + it('should set/get setting from set()', () => { + let config = new IonicConfig(); + let platform = new IonicPlatform(['ios']); + config.setPlatform(platform); + + config.set('tabBarPlacement', 'top'); + + expect(config.get('tabBarPlacement')).toEqual('top'); + }); + + it('should set ios platform settings from settings()', () => { + let config = new IonicConfig(); + let platform = new IonicPlatform(['ios']); + config.setPlatform(platform); + + config.settings('ios', { + key: 'iosValue' + }); + + expect(config.get('key')).toEqual('iosValue'); + }); + + it('should set/get mobile setting even w/ higher priority ios', () => { + let config = new IonicConfig(); + let platform = new IonicPlatform(['mobile', 'ios']); + config.setPlatform(platform); + + config.settings({ + key: 'defaultValue', + platforms: { + mobile: { + key: 'mobileValue' + } + } + }); + + expect(config.get('key')).toEqual('mobileValue'); + }); + + it('should set/get mobile setting even w/ higher priority ios', () => { + let config = new IonicConfig(); + let platform = new IonicPlatform(['mobile', 'ios']); + config.setPlatform(platform); + + config.settings({ + key: 'defaultValue', + platforms: { + mobile: { + key: 'mobileValue' + } + } + }); + + expect(config.get('key')).toEqual('mobileValue'); + }); + + it('should set/get android setting w/ higher priority than mobile', () => { + let config = new IonicConfig(); + let platform = new IonicPlatform(['mobile', 'android']); + config.setPlatform(platform); + + config.settings({ + key: 'defaultValue', + platforms: { + mobile: { + key: 'mobileValue' + }, + android: { + key: 'androidValue' + } + } + }); + + expect(config.get('key')).toEqual('androidValue'); + }); + + it('should set/get ios setting w/ platforms set', () => { + let config = new IonicConfig(); + let platform = new IonicPlatform(['ios']); + config.setPlatform(platform); + + config.settings({ + key: 'defaultValue', + platforms: { + ios: { + key: 'iosValue' + }, + android: { + key: 'androidValue' + } + } + }); + + expect(config.get('key')).toEqual('iosValue'); + }); + + it('should set/get default setting w/ platforms set, but no platform match', () => { + let config = new IonicConfig(); + config.settings({ + key: 'defaultValue', + platforms: { + ios: { + key: 'iosValue' + }, + android: { + key: 'androidValue' + } + } + }); + + expect(config.get('key')).toEqual('defaultValue'); + }); + it('should set setting object', () => { let config = new IonicConfig(); - config.setting({ + config.settings({ name: 'Doc Brown', occupation: 'Weather Man' }); @@ -26,8 +223,8 @@ export function run() { it('should set/get single setting', () => { let config = new IonicConfig(); - config.setting('name', 'Doc Brown'); - config.setting('occupation', 'Weather Man'); + config.set('name', 'Doc Brown'); + config.set('occupation', 'Weather Man'); expect(config.get('name')).toEqual('Doc Brown'); expect(config.get('name')).toEqual('Doc Brown'); @@ -50,7 +247,7 @@ export function run() { occupation: 'Weather Man' }); - expect(config.setting()).toEqual({ + expect(config.settings()).toEqual({ name: 'Doc Brown', occupation: 'Weather Man' }); diff --git a/ionic/platform/platform.ts b/ionic/platform/platform.ts index ed1098d137..4311fa49da 100644 --- a/ionic/platform/platform.ts +++ b/ionic/platform/platform.ts @@ -7,9 +7,8 @@ import * as dom from '../util/dom'; */ export class IonicPlatform { - constructor() { - this._settings = {}; - this._platforms = []; + constructor(platforms=[]) { + this._platforms = platforms; this._versions = {}; this._onResizes = []; @@ -283,12 +282,12 @@ export class IonicPlatform { * TODO * @param {TODO} config TODO */ - load(config) { + load(platformOverride) { let rootPlatformNode = null; let engineNode = null; let self = this; - this.platformOverride = config.setting('platform'); + this.platformOverride = platformOverride; // figure out the most specific platform and active engine let tmpPlatform = null; @@ -359,9 +358,6 @@ export class IonicPlatform { // the last one in the array the most important this._platforms.push(platformNode.name()); - // copy default platform settings into this platform settings obj - this._settings[platformNode.name()] = util.extend({}, platformNode.settings()); - // get the platforms version if a version parser was provided this._versions[platformNode.name()] = platformNode.version(this); @@ -394,13 +390,6 @@ export class IonicPlatform { return rootNode; } - settings(val) { - if (arguments.length) { - this._settings = val; - } - return this._settings; - } - } function insertSuperset(platformNode) { diff --git a/ionic/platform/test/platform.spec.ts b/ionic/platform/test/platform.spec.ts index 784129e6b7..534cbf992e 100644 --- a/ionic/platform/test/platform.spec.ts +++ b/ionic/platform/test/platform.spec.ts @@ -1,13 +1,21 @@ -import {IonicConfig, IonicPlatform} from 'ionic/ionic'; +import {IonicPlatform} from 'ionic/ionic'; export function run() { + it('should set core as the fallback', () => { + let platform = new IonicPlatform(); + platform.userAgent('idk'); + platform.load(); + + expect(platform.is('android')).toEqual(false); + expect(platform.is('ios')).toEqual(false); + expect(platform.is('core')).toEqual(true); + }); + it('should set android via platformOverride, despite ios user agent', () => { let platform = new IonicPlatform(); - let config = new IonicConfig(); - config.setting('platform', 'android'); platform.userAgent(IPAD_UA); - platform.load(config); + platform.load('android'); expect(platform.is('android')).toEqual(true); expect(platform.is('ios')).toEqual(false); @@ -15,10 +23,8 @@ export function run() { it('should set ios via platformOverride, despite android querystring', () => { let platform = new IonicPlatform(); - let config = new IonicConfig(); - config.setting('platform', 'ios'); platform.url('/?ionicplatform=android'); - platform.load(config); + platform.load('ios'); expect(platform.is('android')).toEqual(false); expect(platform.is('ios')).toEqual(true); @@ -26,9 +32,7 @@ export function run() { it('should set ios via platformOverride', () => { let platform = new IonicPlatform(); - let config = new IonicConfig(); - config.setting('platform', 'ios'); - platform.load(config); + platform.load('ios'); expect(platform.is('android')).toEqual(false); expect(platform.is('ios')).toEqual(true); @@ -36,9 +40,7 @@ export function run() { it('should set android via platformOverride', () => { let platform = new IonicPlatform(); - let config = new IonicConfig(); - config.setting('platform', 'android'); - platform.load(config); + platform.load('android'); expect(platform.is('android')).toEqual(true); expect(platform.is('ios')).toEqual(false); @@ -46,9 +48,8 @@ export function run() { it('should set ios via querystring', () => { let platform = new IonicPlatform(); - let config = new IonicConfig(); platform.url('/?ionicplatform=ios'); - platform.load(config); + platform.load(); expect(platform.is('mobile')).toEqual(true); expect(platform.is('android')).toEqual(false); @@ -58,10 +59,9 @@ export function run() { it('should set ios via querystring, even with android user agent', () => { let platform = new IonicPlatform(); - let config = new IonicConfig(); platform.url('/?ionicplatform=ios'); platform.userAgent(ANDROID_UA); - platform.load(config); + platform.load(); expect(platform.is('android')).toEqual(false); expect(platform.is('ios')).toEqual(true); @@ -69,9 +69,8 @@ export function run() { it('should set android via querystring', () => { let platform = new IonicPlatform(); - let config = new IonicConfig(); platform.url('/?ionicplatform=android'); - platform.load(config); + platform.load(); expect(platform.is('android')).toEqual(true); expect(platform.is('ios')).toEqual(false); @@ -79,10 +78,9 @@ export function run() { it('should set android via querystring, even with ios user agent', () => { let platform = new IonicPlatform(); - let config = new IonicConfig(); platform.url('/?ionicplatform=android'); platform.userAgent(IPHONE_UA); - platform.load(config); + platform.load(); expect(platform.is('android')).toEqual(true); expect(platform.is('ios')).toEqual(false); @@ -90,9 +88,8 @@ export function run() { it('should set android via user agent', () => { let platform = new IonicPlatform(); - let config = new IonicConfig(); platform.userAgent(ANDROID_UA); - platform.load(config); + platform.load(); expect(platform.is('mobile')).toEqual(true); expect(platform.is('android')).toEqual(true); @@ -101,9 +98,8 @@ export function run() { it('should set iphone via user agent', () => { let platform = new IonicPlatform(); - let config = new IonicConfig(); platform.userAgent(IPHONE_UA); - platform.load(config); + platform.load(); expect(platform.is('mobile')).toEqual(true); expect(platform.is('android')).toEqual(false); @@ -114,9 +110,8 @@ export function run() { it('should set ipad via user agent', () => { let platform = new IonicPlatform(); - let config = new IonicConfig(); platform.userAgent(IPAD_UA); - platform.load(config); + platform.load(); expect(platform.is('mobile')).toEqual(true); expect(platform.is('android')).toEqual(false); diff --git a/ionic/transitions/ios-transition.ts b/ionic/transitions/ios-transition.ts index 6009cac757..87bc8b3f13 100644 --- a/ionic/transitions/ios-transition.ts +++ b/ionic/transitions/ios-transition.ts @@ -26,7 +26,7 @@ class IOSTransition extends Transition { this.enteringContent .to(TRANSLATEX, CENTER) .to(OPACITY, 1) - .before.setStyles({ zIndex: this.entering.index }); + .before.setStyles({ zIndex: this.enteringZ }); this.enteringTitle .fadeIn() @@ -36,16 +36,16 @@ class IOSTransition extends Transition { .to(TRANSLATEX, CENTER); // leaving view moves off screen - this.leavingContent && this.leavingContent + this.leavingContent .from(TRANSLATEX, CENTER) .from(OPACITY, 1) - .before.setStyles({ zIndex: this.leaving.index }); + .before.setStyles({ zIndex: this.leavingZ }); - this.leavingTitle && this.leavingTitle + this.leavingTitle .from(TRANSLATEX, CENTER) .from(OPACITY, 1); - this.leavingNavbarBg && this.leavingNavbarBg + this.leavingNavbarBg .from(TRANSLATEX, CENTER); // set properties depending on direction @@ -62,15 +62,15 @@ class IOSTransition extends Transition { this.enteringNavbarBg .from(TRANSLATEX, OFF_LEFT); - this.leavingContent && this.leavingContent + this.leavingContent .to(TRANSLATEX, '100%') .to(OPACITY, 1); - this.leavingTitle && this.leavingTitle + this.leavingTitle .to(TRANSLATEX, '100%') .to(OPACITY, 0); - this.leavingNavbarBg && this.leavingNavbarBg + this.leavingNavbarBg .to(TRANSLATEX, '100%'); if (this.leaving && this.leaving.enableBack() && this.viewWidth() > 200) { @@ -91,15 +91,15 @@ class IOSTransition extends Transition { this.enteringNavbarBg .from(TRANSLATEX, '99.5%'); - this.leavingContent && this.leavingContent + this.leavingContent .to(TRANSLATEX, OFF_LEFT) .to(OPACITY, OFF_OPACITY); - this.leavingTitle && this.leavingTitle + this.leavingTitle .to(TRANSLATEX, OFF_LEFT) .to(OPACITY, 0); - this.leavingNavbarBg && this.leavingNavbarBg + this.leavingNavbarBg .to(TRANSLATEX, OFF_LEFT); if (this.entering.enableBack() && this.viewWidth() > 200) { diff --git a/ionic/transitions/md-transition.ts b/ionic/transitions/md-transition.ts index d7c4521422..d7789970d5 100644 --- a/ionic/transitions/md-transition.ts +++ b/ionic/transitions/md-transition.ts @@ -15,19 +15,19 @@ class MaterialTransition extends Transition { // entering item moves in bottom to center this.enteringContent .to(TRANSLATEY, CENTER) - .before.setStyles({ zIndex: this.entering.index }); + .before.setStyles({ zIndex: this.enteringZ }); // entering item moves in bottom to center this.enteringNavbar .to(TRANSLATEY, CENTER) - .before.setStyles({ zIndex: this.entering.index + 10 }); + .before.setStyles({ zIndex: this.enteringZ + 10 }); // leaving view stays put - this.leavingContent && this.leavingContent - .before.setStyles({ zIndex: this.leaving.index }); + this.leavingContent + .before.setStyles({ zIndex: this.leavingZ }); - this.leavingNavbar && this.leavingNavbar - .before.setStyles({ zIndex: this.leaving.index + 10 }); + this.leavingNavbar + .before.setStyles({ zIndex: this.leavingZ + 10 }); // set properties depending on direction if (opts.direction === 'back') { @@ -41,11 +41,11 @@ class MaterialTransition extends Transition { .from(TRANSLATEY, CENTER); // leaving view goes center to bottom - this.leavingContent && this.leavingContent + this.leavingContent .fromTo(TRANSLATEY, CENTER, OFF_BOTTOM) .fadeOut(); - this.leavingNavbar && this.leavingNavbar + this.leavingNavbar .fromTo(TRANSLATEY, CENTER, OFF_BOTTOM) .fadeOut(); diff --git a/ionic/transitions/transition.ts b/ionic/transitions/transition.ts index 61067f6a26..b8e8c32a54 100644 --- a/ionic/transitions/transition.ts +++ b/ionic/transitions/transition.ts @@ -17,60 +17,62 @@ export class Transition extends Animation { let entering = this.entering = nav.getStagedEnteringView(); let leaving = this.leaving = nav.getStagedLeavingView(); + this.enteringZ = entering.index; + this.leavingZ = (leaving && leaving.index) || 0; // create animation for the entering view's content area this.enteringContent = new Animation(entering.viewElementRef()); this.enteringContent.before.addClass(SHOW_VIEW_CSS); this.add(this.enteringContent); + let enteringNavbar = this.enteringNavbar = new Animation(entering.navbarRef()); + this.enteringBackButton = new Animation(entering.backBtnRef()); + this.enteringTitle = new Animation(entering.titleRef()); + this.enteringNavbarItems = new Animation(entering.navbarItemRefs()); + this.enteringNavbarBg = new Animation(entering.navbarBgRef()); + if (opts.navbar !== false) { - let enteringNavbar = this.enteringNavbar = new Animation(entering.navbarRef()); enteringNavbar.before.addClass(SHOW_NAVBAR_CSS); if (entering.enableBack()) { // only animate in the back button if the entering view has it enabled - let enteringBackButton = this.enteringBackButton = new Animation(entering.backBtnRef()); - enteringBackButton + this.enteringBackButton .before.addClass(SHOW_BACK_BUTTON) .fadeIn(); - enteringNavbar.add(enteringBackButton); + enteringNavbar.add(this.enteringBackButton); } - this.enteringTitle = new Animation(entering.titleRef()); - enteringNavbar.add(this.enteringTitle); + enteringNavbar + .add(this.enteringTitle) + .add(this.enteringNavbarItems.fadeIn()) + .add(this.enteringNavbarBg); + this.add(enteringNavbar); - - this.enteringNavbarItems = new Animation(entering.navbarItemRefs()); - enteringNavbar.add(this.enteringNavbarItems.fadeIn()); - - this.enteringNavbarBg = new Animation(entering.navbarBgRef()); - enteringNavbar.add(this.enteringNavbarBg); } + this.leavingContent = new Animation(leaving && leaving.viewElementRef()); + let leavingNavbar = this.leavingNavbar = new Animation(leaving && leaving.navbarRef()); + this.leavingBackButton = new Animation(leaving && leaving.backBtnRef()); + this.leavingTitle = new Animation(leaving && leaving.titleRef()); + this.leavingNavbarItems = new Animation(leaving && leaving.navbarItemRefs()); + this.leavingNavbarBg = new Animation(leaving && leaving.navbarBgRef()); if (leaving) { // setup the leaving item if one exists (initial viewing wouldn't have a leaving item) - this.leavingContent = new Animation(leaving.viewElementRef()); this.leavingContent.after.removeClass(SHOW_VIEW_CSS); - let leavingNavbar = this.leavingNavbar = new Animation(leaving.navbarRef()); leavingNavbar.after.removeClass(SHOW_NAVBAR_CSS); - let leavingBackButton = this.leavingBackButton = new Animation(leaving.backBtnRef()); - leavingBackButton + this.leavingBackButton .after.removeClass(SHOW_BACK_BUTTON) .fadeOut(); - leavingNavbar.add(leavingBackButton); - this.leavingTitle = new Animation(leaving.titleRef()); - leavingNavbar.add(this.leavingTitle); - - this.leavingNavbarItems = new Animation(leaving.navbarItemRefs()); - leavingNavbar.add(this.leavingNavbarItems.fadeOut()); - - this.leavingNavbarBg = new Animation(leaving.navbarBgRef()); - leavingNavbar.add(this.leavingNavbarBg); + leavingNavbar + .add(this.leavingBackButton) + .add(this.leavingTitle) + .add(this.leavingNavbarItems.fadeOut()) + .add(this.leavingNavbarBg); this.add(this.leavingContent, leavingNavbar); } From 539edf8ebd4756dccd415c0f33d4ed386280d375 Mon Sep 17 00:00:00 2001 From: Tim Lancina Date: Fri, 2 Oct 2015 19:45:54 -0500 Subject: [PATCH 02/11] chore(nav): more nav docs --- ionic/components/nav/nav-controller.ts | 96 ++++++++++++++++++++++++-- ionic/components/nav/nav.ts | 15 +++- ionic/config/decorators.ts | 12 +++- 3 files changed, 114 insertions(+), 9 deletions(-) diff --git a/ionic/components/nav/nav-controller.ts b/ionic/components/nav/nav-controller.ts index 636f7d5e8e..e69e00a44e 100644 --- a/ionic/components/nav/nav-controller.ts +++ b/ionic/components/nav/nav-controller.ts @@ -15,12 +15,98 @@ import * as util from 'ionic/util'; * NavController is the base class for navigation controller components like * [`Nav`](../Nav/) and [`Tab`](../../Tabs/Tab/). At a basic level, it is an array of * [views](#creating_views) representing a particular history (of a Tab for example). - * This array can be manipulated to navigate throughout an app by pushing, - * popping, inserting and removing views. + * This array can be manipulated to navigate throughout an app by pushing and + * popping views or inserting and removing them at arbitrary indices. * - *

How do I create views?

- * Any class that is annotated with [@IonicView](../../../config/IonicView/) will - * create a view, that is, a component that can be navigated to. + * The current view is the last one in the array, or the top of the stack, if we think of it + * that way. Pushing a new [view](#creating_views) onto the top of + * the navigation stack causes the new view to be animated in, while popping the current + * view will navigate to the previous view in the stack. + * + * For examples on the basic usage of NavController, check out the [Navigation section](../../../../components/#navigation) + * of the Component docs. The following is a more in depth explanation of some + * of the features of NavController. + * + * Unless you are using a directive like [NavPush](../NavPush/), or need a + * specific NavController, most times you will inject and use a reference to the + * nearest NavController to manipulate the navigation stack. + * + *

Injecting NavController

+ * Injecting NavController will always get you an instance of the nearest NavController, + * regardless of whether it's a Tab or a Nav. + * + * Behind the scenes, when Ionic instantiates a new NavController, it creates an + * injector with NavController bound to that instance (usually either a Nav or Tab) + * and adds the injector to its own bindings. For more information on binding + * and dependency injection, see [Binding and DI](). + * + * ```ts + * // class NavController + * //"this" is either Nav or Tab, both extend NavController + * this.bindings = Injector.resolve([ + * bind(NavController).toValue(this) + * ]); + * ``` + * + * That way you don't need to worry about getting a hold of the proper NavController + * for [views](#creating_views) that may be used in either a Tab or a Nav: + * + * ```ts + * class MyPage { + * constructor(@Optional() tab: Tab, @Optional() nav: Nav) { + * // Unhhhhh so much typinggggg + * // What if we are in a nav that is in a tab, or vice versa, so these both resolve? + * } + * } + * ``` + * + * Instead, you can inject NavController and know that it is the correct + * navigation controller for most situations (for more advanced situations, see + * [Menu](../../Menu/Menu/) and [Tab](../../Tab/Tab/)). + * + * ```ts + * class MyComponent { + * constructor(nav: NavController) { + * this.nav = nav; + * } + * } + * ``` + * + *

View creation

+ * Views 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 [@IonicView](../../../config/IonicView/) as its first + * argument. The NavController then [compiles]() that component, loads it in + * a similar fashion to Angular's [DynamicComponentLoader](https://angular.io/docs/js/latest/api/core/DynamicComponentLoader-interface.html), + * and animates it into view. + * + * By default, views are cached and left in the DOM if they are navigated away from, but are + * still in the navigation stack (on a `push()` for example). They are + * destroyed when removed from the navigation stack (on [pop()](#pop) or [setRoot()](#setRoot)). + * + * + *

Lifecycle events

+ * Lifecycle events are fired during various stages of navigation. They can be + * defined in any `@IonicView` decorated component class. + * + * ```ts + * @IonicView({ + * template: 'Hello World' + * }) + * class HelloWorld { + * onViewLoaded() { + * console.log("I'm alive!"); + * } + * } + * ``` + * + * - `onViewLoaded` - Runs when the view has loaded. This event only happens once per view being created and added to the DOM. If a view leaves but is cached, then this event will not fire again on a subsequent viewing. The `onViewLoaded` event is good place to put your setup code for the view. + * - `onViewWillEnter` - Runs when the view is about to enter and become the active view. + * - `onViewDidEnter` - Runs when the view has fully entered and is now the active view. This event will fire, whether it was the first load or a cached view. + * - `onViewWillLeave` - Runs when the view is about to leave and no longer be the active view. + * - `onViewDidLeave` - Runs when the view has finished leaving and is no longer the active view. + * - `onViewWillUnload` - Runs when the view is about to be destroyed and have its elements removed. + * - `onViewDidUnload` - Runs after the view has been destroyed and its elements have been removed. * */ export class NavController extends Ion { diff --git a/ionic/components/nav/nav.ts b/ionic/components/nav/nav.ts index fb776d192a..a2effd7de3 100644 --- a/ionic/components/nav/nav.ts +++ b/ionic/components/nav/nav.ts @@ -12,6 +12,17 @@ import {NavController} from './nav-controller'; * For more information on using navigation controllers like Nav or [Tabs](../../Tabs/Tabs/), * please take a look at the [NavController API reference](../NavController/). * + *

Back navigation

+ * One feature of Nav is that if your [view](../NavController/#creating_views) has + * a [NavBar](../NavBar/), a back button will be added automatically when there + * view before it in the navigation stack. + * + * Additionally, specifying the `swipe-back-enabled` property will allow you to + * swipe to go back: + * ```ts + * + * ``` + * * Here is a diagram of how Nav animates smoothly between [views](../NavController/#creating_views): * *
@@ -66,8 +77,8 @@ import {NavController} from './nav-controller'; * * ### Panes * - * NOTE: You don't have to do anything with panes, it is all taken care of for you. - * This is just an explanation of how Nav works to accompany the diagram above. + * NOTE: You don't have to do anything with panes, Ionic takes care of animated + * transitions for you. This is an explanation of how Nav works to accompany the diagram above. * * When you push a new view onto the navigation stack using [NavController.push()](../NavController/#push) * or the [NavPush directive](../NavPush/), Nav animates the new view into the diff --git a/ionic/config/decorators.ts b/ionic/config/decorators.ts index b4619ea7e4..93a4c56fbe 100644 --- a/ionic/config/decorators.ts +++ b/ionic/config/decorators.ts @@ -26,7 +26,6 @@ import { * template. */ export const IONIC_DIRECTIVES = [ -// TODO: Why is forwardRef() required when they're already imported above???? // Angular CORE_DIRECTIVES, FORM_DIRECTIVES, @@ -94,6 +93,9 @@ export const IONIC_DIRECTIVES = [ forwardRef(() => HideWhen) ]; +/** + * @private + */ class IonicViewImpl extends View { constructor(args = {}) { args.directives = (args.directives || []).concat(IONIC_DIRECTIVES); @@ -102,7 +104,13 @@ class IonicViewImpl extends View { } /** - * TODO + * the IonicView decorator indicates that the decorated class is an Ionic + * navigation view, meaning it can be navigated to using a [NavController](../../Nav/NavController/) + * + * Ionic views are automatically wrapped in ``, so although you may + * see these tags if you inspect your markup, you don't need to include them in + * your templates. + * */ export function IonicView(args) { return function(cls) { From 8f75a27980d17e9619e78303ea3ca76429b41b39 Mon Sep 17 00:00:00 2001 From: Tim Lancina Date: Sat, 3 Oct 2015 08:40:29 -0500 Subject: [PATCH 03/11] chore(nav): improve doc wording --- ionic/components/nav/nav.ts | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/ionic/components/nav/nav.ts b/ionic/components/nav/nav.ts index a2effd7de3..a2c27e7224 100644 --- a/ionic/components/nav/nav.ts +++ b/ionic/components/nav/nav.ts @@ -5,17 +5,17 @@ import {IonicComponent} from '../../config/decorators'; import {NavController} from './nav-controller'; /** - * Nav is a basic navigation controller component. It handles animating between - * incoming and outgoing views, and as a subclass of [NavController](../NavController/) - * it also exposes the underlying navigation stack. + * Nav is a basic navigation controller component. As a subclass of [NavController](../NavController/) + * you use it to navigate to views in your app. Nav automatically animates + * transitions between views for you. * * For more information on using navigation controllers like Nav or [Tabs](../../Tabs/Tabs/), - * please take a look at the [NavController API reference](../NavController/). + * take a look at the [NavController API reference](../NavController/). * *

Back navigation

- * One feature of Nav is that if your [view](../NavController/#creating_views) has - * a [NavBar](../NavBar/), a back button will be added automatically when there - * view before it in the navigation stack. + * If a [view](../NavController/#creating_views) you navigate to has a [NavBar](../NavBar/), + * Nav will automatically add a back button to it if there is a view + * before the one you are navigating to in the navigation stack. * * Additionally, specifying the `swipe-back-enabled` property will allow you to * swipe to go back: From 0358d1b16208866c3c3089e419d68dd2d688b963 Mon Sep 17 00:00:00 2001 From: Tim Lancina Date: Sat, 3 Oct 2015 08:51:18 -0500 Subject: [PATCH 04/11] chore(navController): improve doc wording --- ionic/components/nav/nav-controller.ts | 28 ++++++++++++++------------ 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/ionic/components/nav/nav-controller.ts b/ionic/components/nav/nav-controller.ts index e69e00a44e..f86a1bf59f 100644 --- a/ionic/components/nav/nav-controller.ts +++ b/ionic/components/nav/nav-controller.ts @@ -13,14 +13,16 @@ import * as util from 'ionic/util'; /** * NavController is the base class for navigation controller components like - * [`Nav`](../Nav/) and [`Tab`](../../Tabs/Tab/). At a basic level, it is an array of - * [views](#creating_views) representing a particular history (of a Tab for example). - * This array can be manipulated to navigate throughout an app by pushing and - * popping views or inserting and removing them at arbitrary indices. + * [`Nav`](../Nav/) and [`Tab`](../../Tabs/Tab/). You use navigation controllers + * to navigate to [views](#creating_views) in your app. At a basic level, a + * navigation controller is an array of views representing a particular history + * (of a Tab for example). This array can be manipulated to navigate throughout + * an app by pushing and popping views or inserting and removing them at + * arbitrary locations in history. * - * The current view is the last one in the array, or the top of the stack, if we think of it - * that way. Pushing a new [view](#creating_views) onto the top of - * the navigation stack causes the new view to be animated in, while popping the current + * The current view is the last one in the array, or the top of the stack if we think of it + * that way. [Pushing](#push) a new view onto the top of + * the navigation stack causes the new view to be animated in, while [popping](#pop) the current * view will navigate to the previous view in the stack. * * For examples on the basic usage of NavController, check out the [Navigation section](../../../../components/#navigation) @@ -33,7 +35,7 @@ import * as util from 'ionic/util'; * *

Injecting NavController

* Injecting NavController will always get you an instance of the nearest NavController, - * regardless of whether it's a Tab or a Nav. + * regardless of whether it is a Tab or a Nav. * * Behind the scenes, when Ionic instantiates a new NavController, it creates an * injector with NavController bound to that instance (usually either a Nav or Tab) @@ -49,7 +51,7 @@ import * as util from 'ionic/util'; * ``` * * That way you don't need to worry about getting a hold of the proper NavController - * for [views](#creating_views) that may be used in either a Tab or a Nav: + * for views that may be used in either a Tab or a Nav: * * ```ts * class MyPage { @@ -76,12 +78,12 @@ import * as util from 'ionic/util'; * Views 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 [@IonicView](../../../config/IonicView/) as its first - * argument. The NavController then [compiles]() that component, loads it in - * a similar fashion to Angular's [DynamicComponentLoader](https://angular.io/docs/js/latest/api/core/DynamicComponentLoader-interface.html), + * argument. The NavController then [compiles]() that component, adds it to the + * DOM in a similar fashion to Angular's [DynamicComponentLoader](https://angular.io/docs/js/latest/api/core/DynamicComponentLoader-interface.html), * and animates it into view. * - * By default, views are cached and left in the DOM if they are navigated away from, but are - * still in the navigation stack (on a `push()` for example). They are + * By default, views are cached and left in the DOM if they are navigated away from but + * still in the navigation stack (the exiting view on a `push()` for example). They are * destroyed when removed from the navigation stack (on [pop()](#pop) or [setRoot()](#setRoot)). * * From 3d6dbe3c9adf4ef1a274c250f8fab2cdfac47403 Mon Sep 17 00:00:00 2001 From: Tim Lancina Date: Sun, 4 Oct 2015 14:11:09 -0500 Subject: [PATCH 05/11] tweak nav docs --- ionic/components/nav/nav.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ionic/components/nav/nav.ts b/ionic/components/nav/nav.ts index a2c27e7224..3e43b18597 100644 --- a/ionic/components/nav/nav.ts +++ b/ionic/components/nav/nav.ts @@ -6,8 +6,8 @@ import {NavController} from './nav-controller'; /** * Nav is a basic navigation controller component. As a subclass of [NavController](../NavController/) - * you use it to navigate to views in your app. Nav automatically animates - * transitions between views for you. + * you use it to navigate to views in your app and manipulate the navigation stack. + * Nav automatically animates transitions between views for you. * * For more information on using navigation controllers like Nav or [Tabs](../../Tabs/Tabs/), * take a look at the [NavController API reference](../NavController/). From 39c17ca5c5c50f4c5fa4c2ab1e9c422c45049d1a Mon Sep 17 00:00:00 2001 From: Tim Lancina Date: Sun, 4 Oct 2015 14:11:29 -0500 Subject: [PATCH 06/11] chore(tabs): tabs API docs --- ionic/components/tabs/tabs.ts | 43 +++++++++++++++++++++-------------- 1 file changed, 26 insertions(+), 17 deletions(-) diff --git a/ionic/components/tabs/tabs.ts b/ionic/components/tabs/tabs.ts index 40fd909b4d..299f0784d0 100644 --- a/ionic/components/tabs/tabs.ts +++ b/ionic/components/tabs/tabs.ts @@ -11,28 +11,29 @@ import * as dom from 'ionic/util/dom'; /** - * @name ionTabs - * @description - * Powers a multi-tabbed interface with a Tab Bar and a set of "pages" - * that can be tabbed through. + * The Tabs component is a container that contains a [TabBar]() and any number of + * individual [Tab]() components. On iOS, the TabBar is placed on the bottom of + * the screen, while on Android it is at the top. * - * Assign any tabs attribute to the element to define its look and feel. + * For basic Tabs usage, see the [Tabs section]() of the component docs. + * See the [Tab API reference]() for more details on individual Tab components. * - * For iOS, tabs will appear at the bottom of the screen. For Android, tabs - * will be at the top of the screen, below the nav-bar. This follows each platform's - * design specification, but can be configured with IonicConfig. + * You can override the platform specific TabBar placement, by using the + * `tab-bar-placement` property: * - * See the ionTab component's documentation for more details on individual tabs. - * - * @usage - * ```html - * - * - * - * + * ```ts + * + * * * ``` * + * To change the location of the icons in the TabBar, use the `tab-bar-icons` + * property: + * ```ts + * + * + * + * ``` */ @IonicComponent({ selector: 'ion-tabs', @@ -181,6 +182,7 @@ export class Tabs extends NavController { } /** + * @private * TODO */ @Directive({ @@ -226,7 +228,10 @@ class TabButton extends Ion { } } - +/** + * @private + * TODO + */ @Directive({ selector: 'tab-highlight' }) @@ -256,6 +261,10 @@ class TabHighlight { } +/** + * @private + * TODO + */ @Directive({selector: 'template[navbar-anchor]'}) class TabNavBarAnchor { constructor( From 7a954c3f1e8b39dbcc16d4e75d2e8949b92bfad2 Mon Sep 17 00:00:00 2001 From: Tim Lancina Date: Sun, 4 Oct 2015 14:12:26 -0500 Subject: [PATCH 07/11] container that contains lol --- ionic/components/tabs/tabs.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ionic/components/tabs/tabs.ts b/ionic/components/tabs/tabs.ts index 299f0784d0..5d1f972151 100644 --- a/ionic/components/tabs/tabs.ts +++ b/ionic/components/tabs/tabs.ts @@ -11,7 +11,7 @@ import * as dom from 'ionic/util/dom'; /** - * The Tabs component is a container that contains a [TabBar]() and any number of + * The Tabs component is a container with a [TabBar]() and any number of * individual [Tab]() components. On iOS, the TabBar is placed on the bottom of * the screen, while on Android it is at the top. * From 2483b1ee086219042c7693e35a4f48f1a26635c7 Mon Sep 17 00:00:00 2001 From: Tim Lancina Date: Sun, 4 Oct 2015 16:02:40 -0500 Subject: [PATCH 08/11] chore(nav): add [root] description to api doc --- ionic/components/nav/nav.ts | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/ionic/components/nav/nav.ts b/ionic/components/nav/nav.ts index 3e43b18597..2b05c37382 100644 --- a/ionic/components/nav/nav.ts +++ b/ionic/components/nav/nav.ts @@ -12,6 +12,21 @@ import {NavController} from './nav-controller'; * For more information on using navigation controllers like Nav or [Tabs](../../Tabs/Tabs/), * take a look at the [NavController API reference](../NavController/). * + * You must set a root view to be loaded initially for any Nav you create, using + * the 'root' property: + * + * ```ts + * import {GettingStartedPage} from 'getting-started'; + * @App({ + * template: `` + * }) + * class MyApp { + * constructor(){ + * this.rootPage = GettingStartedPage; + * } + * } + * ``` + * *

Back navigation

* If a [view](../NavController/#creating_views) you navigate to has a [NavBar](../NavBar/), * Nav will automatically add a back button to it if there is a view From 43a4a7162932873dad027afb8026522b1c104b2d Mon Sep 17 00:00:00 2001 From: Tim Lancina Date: Sun, 4 Oct 2015 16:03:03 -0500 Subject: [PATCH 09/11] chore(tab): tab api docs --- ionic/components/tabs/tab.ts | 35 +++++++++++++++++++++++++++++------ 1 file changed, 29 insertions(+), 6 deletions(-) diff --git a/ionic/components/tabs/tab.ts b/ionic/components/tabs/tab.ts index 24afe6c9a9..cf07a0afeb 100644 --- a/ionic/components/tabs/tab.ts +++ b/ionic/components/tabs/tab.ts @@ -7,14 +7,37 @@ import {Tabs} from './tabs'; /** - * @name ionTab - * @requires ionTabs - * @description - * Contains a tab's content. The content only exists while the given tab is selected. + * Tab components are basic navigation controllers used with [Tabs](). Much like + * [Nav](), they are a subclass of [NavController]() and are used to navigate to + * views and manipulate the navigation stack of a particular tab. * - * @usage + * For basic Tabs usage, see the [Tabs section]() of the component docs. + * + * Like Nav, you must set a root view to be loaded initially for each Tab with + * the 'root' property: + * ``` + * import {GettingStartedPage} from 'getting-started'; + * @App({ + * template: ` + * + * + * ` + * }) + * class MyApp { + * constructor(){ + * this.tabOneRoot = GettingStartedPage; + * this.tabTwoRoot = GettingStartedPage; + * } + * } + * ``` + * + * To change the title and icon for each tab, use the `tab-title` and `tab-icon` + * properties: * ```html - * + * + * + * + * * ``` */ @Component({ From 45329851f54e1a6bed5068eae75279a0ed06f33c Mon Sep 17 00:00:00 2001 From: Tim Lancina Date: Sun, 4 Oct 2015 16:03:36 -0500 Subject: [PATCH 10/11] chore(tabs): more tabs api docs --- ionic/components/tabs/tabs.ts | 35 ++++++++++++++++++++++++++++++++--- 1 file changed, 32 insertions(+), 3 deletions(-) diff --git a/ionic/components/tabs/tabs.ts b/ionic/components/tabs/tabs.ts index 5d1f972151..d0a5edd448 100644 --- a/ionic/components/tabs/tabs.ts +++ b/ionic/components/tabs/tabs.ts @@ -15,10 +15,10 @@ import * as dom from 'ionic/util/dom'; * individual [Tab]() components. On iOS, the TabBar is placed on the bottom of * the screen, while on Android it is at the top. * - * For basic Tabs usage, see the [Tabs section]() of the component docs. - * See the [Tab API reference]() for more details on individual Tab components. + * For basic Tabs usage, see the [Tabs section](../../../../components/#tabs) of the component docs. + * See the [Tab API reference](../Tab/) for more details on individual Tab components. * - * You can override the platform specific TabBar placement, by using the + * You can override the platform specific TabBar placement by using the * `tab-bar-placement` property: * * ```ts @@ -34,6 +34,26 @@ import * as dom from 'ionic/util/dom'; * * * ``` + * + * You can select tabs programatically by injecting Tabs into any child + * component, and using the [select()](#select) method: + * ```ts + * @IonicView({ + * template: `` + * }) + * class TabOne { + * constructor(tabs: Tabs){ + * this.tabs = tabs; + * } + * + * goToTabTwo() { + * this.tabs.select(this.tabs.tabs[1]); + * } + * } + * ``` + * The [tabs](#tabs) property is an array of all child [Tab](../Tab/) components + * of this Tabs component. + * */ @IonicComponent({ selector: 'ion-tabs', @@ -112,6 +132,10 @@ export class Tabs extends NavController { } + /** + * @private + * TODO + */ addTab(tab) { this.add(tab.viewCtrl); @@ -163,6 +187,7 @@ export class Tabs extends NavController { } /** + * @private * "Touch" the active tab, either going back to the root view of the tab * or scrolling the tab to the top */ @@ -175,6 +200,10 @@ export class Tabs extends NavController { } } + /** + * TODO + * @return TODO + */ get tabs() { return this.instances(); } From 13e146b3e50ca91425c815a453fb65710788af24 Mon Sep 17 00:00:00 2001 From: Tim Lancina Date: Sun, 4 Oct 2015 16:05:47 -0500 Subject: [PATCH 11/11] fix tab tabs --- ionic/components/tabs/tab.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ionic/components/tabs/tab.ts b/ionic/components/tabs/tab.ts index cf07a0afeb..fdd935e1be 100644 --- a/ionic/components/tabs/tab.ts +++ b/ionic/components/tabs/tab.ts @@ -19,9 +19,9 @@ import {Tabs} from './tabs'; * import {GettingStartedPage} from 'getting-started'; * @App({ * template: ` - * - * - * ` + * + * + * ` * }) * class MyApp { * constructor(){