diff --git a/ionic/components/app/app.js b/ionic/components/app/app.js index 8b1b174528..89f45703a2 100644 --- a/ionic/components/app/app.js +++ b/ionic/components/app/app.js @@ -1,21 +1,13 @@ import {bootstrap} from 'angular2/angular2'; import {AppViewManager} from 'angular2/src/core/compiler/view_manager'; -import {Component, Directive, onInit} from 'angular2/src/core/annotations_impl/annotations'; -import {View} from 'angular2/src/core/annotations_impl/view'; -import {ComponentRef, onDestroy, DomRenderer, ApplicationRef} from 'angular2/angular2'; -import {Promise} from 'angular2/src/facade/async'; -import {isPresent, Type} from 'angular2/src/facade/lang'; import {Compiler} from 'angular2/angular2'; import {ElementRef} from 'angular2/src/core/compiler/element_ref'; -import {DynamicComponentLoader} from 'angular2/src/core/compiler/dynamic_component_loader'; -import {Injector} from 'angular2/di'; -import {Parent} from 'angular2/src/core/annotations_impl/visibility'; import {bind} from 'angular2/di'; -import {Injectable} from 'angular2/src/di/decorators'; import {ViewContainerRef} from 'angular2/src/core/compiler/view_container_ref'; import {IonicConfig} from '../../config/config'; -import {ViewController} from '../view/view-controller'; +import {Platform} from '../../platform/platform'; +import * as util from '../../util/util'; export class IonicApp { @@ -24,6 +16,72 @@ export class IonicApp { this.overlays = []; } + config(val) { + if (arguments.length) { + this._config = val; + } + return this._config; + } + + url(val) { + if (arguments.length) { + this._url = val; + this._qs = util.getQuerystring(val); + } + return this._url; + } + + query(key) { + return (this._qs || {})[key]; + } + + userAgent(val) { + if (arguments.length) { + this._ua = val; + } + return this._ua; + } + + matchesQuery(queryKey, queryValue) { + const val = this.query(queryKey); + return !!(val && val == queryValue); + } + + matchesUserAgent(userAgentExpression) { + const rx = new RegExp(userAgentExpression, 'i'); + return rx.test(this._ua); + } + + matchesPlatform(platformQueryValue, platformUserAgentExpression) { + if (!platformUserAgentExpression) { + platformUserAgentExpression = platformQueryValue; + } + return this.matchesQuery('ionicplatform', platformQueryValue) || + this.matchesUserAgent(platformUserAgentExpression); + } + + matchesDevice(deviceQueryValue, deviceUserAgentExpression) { + if (!deviceUserAgentExpression) { + deviceUserAgentExpression = deviceQueryValue; + } + return this.matchesQuery('ionicdevice', deviceQueryValue) || + this.matchesUserAgent(deviceUserAgentExpression); + } + + width(val) { + if (arguments.length) { + this._w = val; + } + return this._w || 0; + } + + height(val) { + if (arguments.length) { + this._h = val; + } + return this._h || 0; + } + /** * Create and append the given component into the root * element of the app. @@ -67,9 +125,9 @@ export class IonicApp { }); } - ref() { + ref(val) { if (arguments.length) { - this._ref = arguments[0]; + this._ref = val; } return this._ref; } @@ -78,26 +136,52 @@ export class IonicApp { export function ionicBootstrap(ComponentType, config) { return new Promise((resolve, reject) => { - let app = new IonicApp(); - config = config || new IonicConfig(); + try { + let app = new IonicApp(); + app.url(window.location.href); + app.userAgent(window.navigator.userAgent); + app.width(window.innerWidth); + app.height(window.innerHeight); - let componentInjectableBindings = [ - bind(IonicApp).toValue(app), - bind(IonicConfig).toValue(config) - ]; + let platform = Platform.getActivePlatform(app); - bootstrap(ComponentType, componentInjectableBindings).then(appRef => { - app.ref(appRef); - resolve(app); + config = config || new IonicConfig(); + config.platform(platform); - }).catch(err => { + GlobalIonicConfig = config; + + let injectableBindings = [ + bind(IonicApp).toValue(app), + bind(Platform).toValue(platform), + bind(IonicConfig).toValue(config) + ]; + + bootstrap(ComponentType, injectableBindings).then(appRef => { + app.ref(appRef); + + let rootPlatform = platform.root(); + rootPlatform.runAll(); + + resolve({ + app, + config, + platform + }); + + }).catch(err => { + console.error('ionicBootstrap', err); + reject(err); + }); + + } catch (err) { console.error('ionicBootstrap', err); reject(err); - }); - + } }); } +export let GlobalIonicConfig = null; + export function load(app) { if (!app) { console.error('Invalid app module'); diff --git a/ionic/components/modal/test/basic/index.js b/ionic/components/modal/test/basic/index.js index 384999342e..3274e1479c 100644 --- a/ionic/components/modal/test/basic/index.js +++ b/ionic/components/modal/test/basic/index.js @@ -149,12 +149,32 @@ export class ModalSecondPage { } export function main(ionicBootstrap) { - // crazy config - let myConfig = new IonicConfig(); - ionicBootstrap(MyApp, myConfig).then(app => { - // crazy run - console.log('ionicBootstrap', app); + let myConfig = new IonicConfig({ + 'adams': 'config', + 'tabBarPlacement': 'adam' + }); + + // myConfig.platform('ios', { + // 'tabBarPlacement': 'ios' + // }); + + // myConfig.device('ipad', { + // 'tabBarPlacement': 'ipad' + // }); + + // myConfig.platform('android', { + // 'tabBarPlacement': 'android' + // }); + + ionicBootstrap(MyApp, myConfig).then(root => { + + console.log('mobile', root.platform.is('mobile')) + console.log('ipad', root.platform.is('ipad')) + console.log('tablet', root.platform.is('tablet')) + console.log('ios', root.platform.is('ios')) + console.log('android', root.platform.is('android')) + }); } diff --git a/ionic/config/component.js b/ionic/config/component.js index 0c472ac3d8..e4c498e7f6 100644 --- a/ionic/config/component.js +++ b/ionic/config/component.js @@ -3,8 +3,7 @@ import {DirectiveMetadata} from 'angular2/src/render/api'; import * as util from 'ionic/util'; import {Platform} from 'ionic/platform/platform'; - -const platformMode = Platform.getMode(); +import {GlobalIonicConfig} from '../components/app/app'; export class IonicDirective extends Directive { @@ -23,8 +22,6 @@ function appendModeConfig(ComponentType) { let config = ComponentType.config; config.host = config.host || {}; -// let host = DirectiveMetadata.parseHostConfig(config.host); - const defaultProperties = config.defaultProperties; config.properties = config.properties || []; @@ -56,20 +53,13 @@ function appendModeConfig(ComponentType) { continue; } - // get the property values from a global user config - var globalPropertyValue = null; - if (globalPropertyValue) { + // get the property values from a global user/platform config + let configVal = GlobalIonicConfig.setting(prop); + if (configVal) { instance[prop] = globalPropertyValue; continue; } - // get the property values provided by this mode/platform - var modePropertyValue = null; - if (modePropertyValue) { - instance[prop] = modePropertyValue; - continue; - } - // wasn't set yet, so go with property's default value instance[prop] = defaultProperties[prop]; } @@ -92,8 +82,14 @@ function appendModeConfig(ComponentType) { }; } + if (!platformMode) { + platformMode = GlobalIonicConfig.setting('mode'); + } + let id = config.classId || (config.selector && config.selector.replace('ion-', '')); config.host['class'] = (id + ' ' + id + '-' + platformMode); return config; } + +let platformMode = null; diff --git a/ionic/config/config.js b/ionic/config/config.js index 05e4e4f19b..bfe4babe3e 100644 --- a/ionic/config/config.js +++ b/ionic/config/config.js @@ -1,9 +1,123 @@ +import {isString, isObject, isDefined} from '../util/util'; export class IonicConfig { - constructor() { - this.canWe = true; + constructor(settings={}) { + this._settings = settings; + this._settings.platforms = this._settings.platforms || {}; + } + + platform(val) { + if (arguments.length) { + this._platform = val; + } + return this._platform; + } + + setting() { + const args = arguments; + const arg0 = args[0]; + const arg1 = args[1]; + const arg2 = args[2]; + const arg3 = args[3]; + const argLength = args.length; + + let s = this._settings; + + if (argLength === 0) { + // setting() = get settings object + return s; + + } else if (argLength === 1) { + // setting({...}) = set settings object + // setting('key') = get value + + if (isObject(arg0)) { + // setting({...}) = set settings object + // arg0 = setting object + s = arg0; + + } else if (isString(arg0)) { + // setting('key') = get value + // arg0 = key + return s[arg0] + } + + } else if (argLength === 2) { + // setting('key', 'value') = set key/value pair + // arg0 = key + // arg1 = value + s[arg0] = arg1; + + } else if (argLength > 2) { + // create platform object and platformKey object if needed + // arg0 = key + // arg1 = platform key + s.platforms = s.platforms || {}; + s.platforms[arg1] = s.platforms[arg1] || {}; + + if (argLength === 3) { + // setting('key', 'ios', 'value') = set key/value pair for platform + // arg0 = key + // arg1 = platform key + // arg2 = value + s.platforms[arg1][arg0] = arg2; + + } else if (argLength === 4) { + // setting('key', 'ios', 'ipad', 'value') = set key/value pair for platform/device + // arg0 = key + // arg1 = platform key + // arg2 = device key + // arg3 = value + s.platforms[arg1] = s.platforms[arg1] || {}; + } + + } + + if (arguments.length > 1) { + this._settings[key] = val; + + } else { + // 1) user platform settings + // 2) user settings + // 3) platform settings + let tmp = null; + + if (this._platform) { + tmp = this.platformSetting( this._platform.name() ); + if (isDefined(tmp)) { + return tmp; + } + } + + tmp = this._settings[key]; + if (util.isDefined(tmp)) { + return tmp; + } + + if (this._platform) { + return this._platform.setting(key); + } + + return null; + } + } + + platformSettings(platformName, platformSettings) { + let settings = this._settings.platforms[platformName] = this._settings.platforms[platformName] || {}; + if (arguments.length > 1) { + settings = platformSettings || {}; + } + return settings; + } + + platformSetting(platformName, key, val) { + let settings = this._settings.platforms[platformName] = this._settings.platforms[platformName] || {}; + if (arguments.length > 2) { + settings[key] = val; + } + return settings[key]; } } diff --git a/ionic/ionic.js b/ionic/ionic.js index ba38509ba9..290e4320fc 100644 --- a/ionic/ionic.js +++ b/ionic/ionic.js @@ -1,10 +1,15 @@ export * from 'ionic/config/config' -export * from 'ionic/config/ionic-directive' +export * from 'ionic/config/component' export * from 'ionic/config/ionic-view' export * from 'ionic/components' + export * from 'ionic/platform/platform' +// export * from 'ionic/platform/core' +// export * from 'ionic/platform/android' +// export * from 'ionic/platform/ios' + export * from 'ionic/routing/router' export * from 'ionic/util/click-block' diff --git a/ionic/platform/platform.js b/ionic/platform/platform.js index 9a11f5e966..5fe00bb55c 100644 --- a/ionic/platform/platform.js +++ b/ionic/platform/platform.js @@ -1,144 +1,224 @@ import * as util from '../util/util'; import {Tap} from '../util/tap'; -let registry = {}; +let platformRegistry = {}; let defaultPlatform; let activePlatform; -class PlatformController { +export class Platform { - constructor(platformQuerystring, userAgent) { - this.pqs = platformQuerystring; - this.ua = userAgent; + load(platformName) { + this._c = Platform.get(platformName); } - get() { - if (util.isUndefined(activePlatform)) { - this.set(this.detect()); - } - return activePlatform || defaultPlatform; + name() { + return this._c.name; } - getName() { - return this.get().name; + settings() { + return this._c.settings || {}; } - getMode() { - let plt = this.get(); - return plt.mode || plt.name; - } - - register(platform) { - registry[platform.name] = platform; - } - - getPlatform(name) { - return registry[name]; - } - - set(platform) { - activePlatform = platform; - - this._applyBodyClasses(); - } - - setDefault(platform) { - defaultPlatform = platform; - } - - isRegistered(platformName) { - return registry.some(platform => { - return platform.name === platformName; - }) - } - - detect() { - for (let name in registry) { - if (registry[name].isMatch(this.pqs, this.ua)) { - return registry[name]; - } - } - return null; - } - - _applyBodyClasses() { - if(!activePlatform) { - return; - } - - document.body.classList.add('platform-' + activePlatform.name); + subsets() { + return this._c.subsets || []; } run() { - activePlatform && activePlatform.run(); + this._c.run && this._c.run(); } - /** - * Check if the platform matches the provided one. - */ - is(platform) { - if(!activePlatform) { return false; } - - return activePlatform.name === platform; + parent(val) { + if (arguments.length) { + this._parent = val; + } + return this._parent; } - /** - * Check if the loaded device matches the provided one. - */ - isDevice(device) { - if(!activePlatform) { return false; } - return activePlatform.getDevice() === device; + child(val) { + if (arguments.length) { + this._child = val; + } + return this._child; + } + + isMatch(app) { + if (!this._c.isMatch) { + return true; + } + return this._c.isMatch(app); + } + + getRoot(app, childPlatform) { + if (this.isMatch(app)) { + let parents = Platform.getSubsetParents(this.name()); + + if (!parents.length) { + platform = new Platform(); + platform.load(this.name()); + platform.child(childPlatform); + return platform; + } + + let platform = null; + let rootPlatform = null; + + for (let i = 0; i < parents.length; i++) { + platform = new Platform(); + platform.load(parents[i]); + platform.child(this); + + rootPlatform = platform.getRoot(app, this); + if (rootPlatform) { + this.parent(platform); + return rootPlatform; + } + } + } + + return null; + } + + + static getActivePlatform(app) { + let platform = new Platform(); + platform.load('tablet'); + + let root = platform.getRoot(app, null); + console.log(root) + } + + static register(platform) { + platformRegistry[platform.name] = platform; + } + + static get(platformName) { + return platformRegistry[platformName] || {}; + } + + static getSubsetParents(subsetPlatformName) { + let parentPlatformNames = []; + let platform = null; + + for (let platformName in platformRegistry) { + platform = platformRegistry[platformName]; + if (platform.subsets && platform.subsets.indexOf(subsetPlatformName) > -1) { + parentPlatformNames.push(platformName); + } + } + return parentPlatformNames; } } -export let Platform = new PlatformController((util.getQuerystring('ionicplatform')).toLowerCase(), window.navigator.userAgent); +let rootPlatform = null; + + +Platform.register({ + name: 'core', + subsets: [ + 'mobile' + ], + settings: { + mode: 'a' + }, + run() { + console.log('Core'); + } +}); + + +Platform.register({ + name: 'mobile', + subsets: [ + 'android', + 'ios' + ], + settings: { + mode: 'b' + }, + run() { + console.log('Mobile'); + } +}); Platform.register({ name: 'android', - mode: 'md', - isMatch(platformQuerystring, userAgent) { - if (platformQuerystring) { - return platformQuerystring == 'android'; - } - return /android/i.test(userAgent); + subsets: [ + 'tablet' + ], + settings: { + mode: 'c' }, - getDevice: function() { - return 'android'; + isMatch(app) { + return app.matchesPlatform('android'); }, run() { + console.log('Android'); } }); + Platform.register({ - name: 'ios', - isMatch(platformQuerystring, userAgent) { - if (platformQuerystring) { - return platformQuerystring == 'ios'; - } - return /ipad|iphone|ipod/i.test(userAgent); + name: 'tablet', + settings: { + mode: 'd' }, - getDevice: function() { - if(/ipad/i.test(userAgent)) { - return 'ipad'; - } - if(/iphone/i.test(userAgent)) { - return 'iphone'; - } + isMatch(app) { + return app.height() >= 800 || app.width() >= 800; }, run() { + console.log('Tablet'); + } +}); + + +Platform.register({ + name: 'ios', + subsets: [ + 'ipad', + 'iphone' + ], + settings: { + mode: 'e' + }, + isMatch(app) { + return app.matchesPlatform('ios'); + }, + run() { + console.log('iOS'); Tap.run(); } }); -// Last case is a catch-all -// TODO(mlynch): don't default to iOS, default to core, -// also make sure to remove getPlatform and set to detect() -Platform.setDefault({ - name: 'ios' -}); -Platform.set( Platform.getPlatform('ios') );//Platform.detect() ); -// If the platform needs to do some initialization (like load a custom -// tap strategy), run it now -Platform.run(); +Platform.register({ + name: 'ipad', + subsets: [ + 'tablet' + ], + settings: { + mode: 'f' + }, + isMatch(app) { + return app.matchesDevice('ipad'); + }, + run() { + console.log('iPad'); + } +}); + + +Platform.register({ + name: 'iphone', + settings: { + mode: 'g' + }, + isMatch(app) { + return app.matchesDevice('iphone'); + }, + run() { + console.log('iPhone'); + } +}); + + diff --git a/ionic/platform/platform_TWO.js b/ionic/platform/platform_TWO.js new file mode 100644 index 0000000000..e7f42563ac --- /dev/null +++ b/ionic/platform/platform_TWO.js @@ -0,0 +1,155 @@ +// import * as util from '../util/util'; +// import {IonicConfig} from '../config/config'; + + +// let platformRegistry = {}; + +// export class Platform extends IonicConfig { + +// constructor(settings={}) { +// super(settings); +// this._chld = {}; +// this._parent = null; +// } + +// parent(val) { +// if (arguments.length) { +// this._parent = val; +// } +// return this._parent; +// } + +// app(val) { +// if (arguments.length) { +// this._app = val; +// } +// return this._app; +// } + +// name(val) { +// if (arguments.length) { +// this._name = val; +// } +// return this._name; +// } + +// is(platformName, climbToRoot) { +// if (this._name == platformName) { +// return true; +// } + +// let platform = null; + +// if (climbToRoot !== false) { +// platform = this._parent +// while (platform) { +// if (platform.name() == platformName) { +// return true; +// } +// platform = platform._parent; +// } +// } + +// for (let childPlatform in this._chld) { +// platform = this._chld[childPlatform]; +// platform.app(this._app); +// if (platform.is(platformName, false) == platform.isMatch()) { +// return true; +// } +// } + +// return false; +// } + +// matchesQuery(queryKey, queryValue) { +// const qs = this._app.query()[queryKey]; +// return !!(qs && qs == queryValue); +// } + +// matchesUserAgent(userAgentExpression) { +// const rx = new RegExp(userAgentExpression, 'i'); +// return rx.test( this._app.userAgent() ); +// } + +// matchesPlatform(platformQueryValue, platformUserAgentExpression) { +// return this.matchesQuery('ionicplatform', platformQueryValue) || +// this.matchesUserAgent(platformUserAgentExpression); +// } + +// matchesDevice(deviceQueryValue, deviceUserAgentExpression) { +// return this.matchesQuery('ionicdevice', deviceQueryValue) || +// this.matchesUserAgent(deviceUserAgentExpression); +// } + +// registerChild(platformName, PlatformClass) { +// let platform = new PlatformClass(); +// platform.name(platformName); +// platform.parent(this); +// this._chld[platformName] = platform; +// } + +// root() { +// let rootPlatform = this; +// while (rootPlatform._parent) { +// rootPlatform = rootPlatform._parent; +// } +// return rootPlatform; +// } + +// runAll() { +// let platform = null; + +// if (this.isMatch()) { +// this.run(); + +// for (let childPlatform in this._chld) { +// this._chld[childPlatform].app(this._app); +// this._chld[childPlatform].runAll(); +// } +// } +// } + +// getActive() { +// let platform = null; + +// if (this.isMatch()) { +// for (let childPlatform in this._chld) { +// this._chld[childPlatform].app(this._app); +// platform = this._chld[childPlatform].getActive(); +// if (platform) { +// return platform; +// } +// } + +// return this; +// } + +// return null; +// } + + +// /* Methods to Override */ +// isMatch() { return true; } +// run() {} + + +// /* Static Methods */ +// static register(platformName, PlatformClass) { +// basePlatform.registerChild(platformName, PlatformClass); +// } + +// static getActivePlatform(app) { +// basePlatform.app(app); +// return basePlatform.getActive(app); +// } + +// static setBase(PlatformClass) { +// basePlatform = new PlatformClass(); +// } + +// } + +// let basePlatform = null; + + +console.log('') diff --git a/ionic/util/util.js b/ionic/util/util.js index 7b22ac5718..2f49ad864d 100644 --- a/ionic/util/util.js +++ b/ionic/util/util.js @@ -134,20 +134,22 @@ export const array = { * Grab the query string param value for the given key. * @param key the key to look for */ -export function getQuerystring(key) { +export function getQuerystring(url, key) { var queryParams = {}; - const startIndex = window.location.href.indexOf('?'); - if (startIndex !== -1) { - const queries = window.location.href.slice(startIndex + 1).split('&'); - if (queries.length) { - queries.forEach((param) => { - var split = param.split('='); - queryParams[split[0]] = split[1]; - }); + if (url) { + const startIndex = url.indexOf('?'); + if (startIndex !== -1) { + const queries = url.slice(startIndex + 1).split('&'); + if (queries.length) { + queries.forEach((param) => { + var split = param.split('='); + queryParams[split[0]] = split[1]; + }); + } + } + if (key) { + return queryParams[key] || ''; } - } - if (key) { - return queryParams[key] || ''; } return queryParams; }