Merge branch 'config-wip'

This commit is contained in:
Adam Bradley
2015-06-25 11:04:48 -05:00
8 changed files with 578 additions and 176 deletions

View File

@ -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(queryValue) {
let val = this.query('ionicplatform');
if (val) {
let valueSplit = val.toLowerCase().split(';');
for (let i = 0; i < valueSplit.length; i++) {
if (valueSplit[i] == queryValue) {
return true;
}
}
}
return false;
}
matchesUserAgent(userAgentExpression) {
let rx = new RegExp(userAgentExpression, 'i');
return rx.test(this._ua);
}
matchesPlatform(queryValue, userAgentExpression) {
if (!userAgentExpression) {
userAgentExpression = queryValue;
}
return this.matchesQuery(queryValue) ||
this.matchesUserAgent(userAgentExpression);
}
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,55 @@ 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.create(app);
bootstrap(ComponentType, componentInjectableBindings).then(appRef => {
app.ref(appRef);
resolve(app);
config = config || new IonicConfig();
}).catch(err => {
// copy default platform settings into the user config platform settings
// user config platform settings should override default platform settings
config.setPlatform(platform);
GlobalIonicConfig = config;
let injectableBindings = [
bind(IonicApp).toValue(app),
bind(Platform).toValue(platform),
bind(IonicConfig).toValue(config)
];
bootstrap(ComponentType, injectableBindings).then(appRef => {
app.ref(appRef);
platform.run();
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');

View File

@ -149,12 +149,27 @@ export class ModalSecondPage {
}
export function main(ionicBootstrap) {
// crazy config
let myConfig = new IonicConfig();
ionicBootstrap(MyApp, myConfig).then(app => {
// crazy run
console.log('ionicBootstrap', app);
//myConfig.setting('someKey', 'userConfig');
// myConfig.setting('ios', 'someKey', 'iosConfig');
// myConfig.setting('ipad', 'someKey', 'ipadConfig');
ionicBootstrap(MyApp, myConfig).then(root => {
console.log('someKey', myConfig.setting('someKey'));
console.log(myConfig.setting('mode'));
console.log('mobile', root.platform.is('mobile'))
console.log('ipad', root.platform.is('ipad'))
console.log('iphone', root.platform.is('iphone'))
console.log('phablet', root.platform.is('phablet'))
console.log('tablet', root.platform.is('tablet'))
console.log('ios', root.platform.is('ios'))
console.log('android', root.platform.is('android'))
console.log('windows phone', root.platform.is('windowsphone'))
});
}

View File

@ -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 {
constructor(ComponentType) {
@ -25,8 +24,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 || [];
@ -58,20 +55,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];
}
@ -94,8 +84,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;

View File

@ -1,9 +1,116 @@
import {isString, isObject, isDefined, extend} from '../util/util';
export class IonicConfig {
constructor() {
this.canWe = true;
constructor(settings) {
this.setting(settings || {});
}
setting() {
const args = arguments;
const arg0 = args[0];
const arg1 = args[1];
let s = this._settings;
switch (args.length) {
case 0:
// setting() = get settings object
return s;
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(s[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
s[arg0] = null;
// check the platform settings object for this value
// loop though each of the active platforms
let activePlatformKeys = this._platforms;
let platformSettings = s.platforms;
let platformObj = null;
if (platformSettings) {
let platformValue = undefined;
for (let i = 0; i < activePlatformKeys.length; i++) {
platformObj = platformSettings[ activePlatformKeys[i] ];
if (platformObj && isDefined(platformObj[arg0])) {
platformValue = platformObj[arg0];
}
}
if (isDefined(platformValue)) {
s[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
return s[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
s.platforms = s.platforms || {};
s.platforms[arg0] = arg1;
} else {
// setting('key', 'value') = set key/value pair
// arg0 = key
// arg1 = value
s[arg0] = arg1;
}
return this;
case 3:
// setting('ios', 'key', 'value') = set key/value pair for platform
// arg0 = platform
// arg1 = key
// arg2 = value
s.platforms = s.platforms || {};
s.platforms[arg0] = s.platforms[arg0] || {};
s.platforms[arg0][arg1] = args[2];
return this;
}
}
setPlatform(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 || {});
}
}

View File

@ -4,7 +4,10 @@ export * from 'ionic/config/component'
export * from 'ionic/config/ionic-view'
export * from 'ionic/components'
export * from 'ionic/platform/platform'
export * from 'ionic/platform/registry'
export * from 'ionic/routing/router'
export * from 'ionic/util/click-block'

View File

@ -1,144 +1,220 @@
import * as util from '../util/util';
import {Tap} from '../util/tap';
let registry = {};
let defaultPlatform;
let activePlatform;
class PlatformController {
export class Platform {
constructor(platformQuerystring, userAgent) {
this.pqs = platformQuerystring;
this.ua = userAgent;
constructor() {
this._settings = {};
this._platforms = [];
}
get() {
if (util.isUndefined(activePlatform)) {
this.set(this.detect());
is(platformName) {
return (this._platforms.indexOf(platformName) > -1);
}
settings(val) {
if (arguments.length) {
this._settings = val;
}
return activePlatform || defaultPlatform;
}
getName() {
return this.get().name;
}
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);
return this._settings;
}
run() {
activePlatform && activePlatform.run();
let config = null;
for (var i = 0; i < this._platforms.length; i++) {
config = Platform.get(this._platforms[i]);
config.run && config.run();
}
}
/**
* Check if the platform matches the provided one.
*/
is(platform) {
if(!activePlatform) { return false; }
return activePlatform.name === platform;
add(platformName) {
this._platforms.push(platformName);
}
/**
* Check if the loaded device matches the provided one.
*/
isDevice(device) {
if(!activePlatform) { return false; }
return activePlatform.getDevice() === device;
platforms() {
// get the array of active platforms, which also knows the hierarchy,
// with the last one the most important
return this._platforms;
}
/* Static Methods */
static create(app) {
let rootNode = null;
function matchPlatform(platformConfig) {
let platformNode = new PlatformNode();
platformNode.config(platformConfig);
let tmpPlatform = platformNode.getRoot(app, 0);
if (tmpPlatform) {
tmpPlatform.depth = 0;
let childPlatform = tmpPlatform.child();
while(childPlatform) {
tmpPlatform.depth++
childPlatform = childPlatform.child();
}
if (!rootNode || tmpPlatform.depth > rootNode.depth) {
rootNode = tmpPlatform;
}
}
}
function insertSuperset(platformNode) {
let supersetPlaformName = platformNode.superset();
if (supersetPlaformName) {
let supersetPlatform = new PlatformNode();
supersetPlatform.load(supersetPlaformName);
supersetPlatform.parent(platformNode.parent());
supersetPlatform.child(platformNode);
supersetPlatform.parent().child(supersetPlatform);
platformNode.parent(supersetPlatform);
}
}
for (let platformName in platformRegistry) {
matchPlatform( platformRegistry[platformName] );
}
let platform = new Platform();
if (rootNode) {
let platformNode = rootNode;
while (platformNode) {
insertSuperset(platformNode);
platformNode = platformNode.child();
}
platformNode = rootNode;
let settings = {};
while (platformNode) {
// set the array of active platforms with
// the last one in the array the most important
platform.add(platformNode.name());
// copy default platform settings into this platform settings obj
settings[platformNode.name()] = util.extend({}, platformNode.settings());
// go to the next child
platformNode = platformNode.child();
}
platform.settings(settings);
}
return platform;
}
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);
class PlatformNode {
Platform.register({
name: 'android',
mode: 'md',
isMatch(platformQuerystring, userAgent) {
if (platformQuerystring) {
return platformQuerystring == 'android';
}
return /android/i.test(userAgent);
},
getDevice: function() {
return 'android';
},
run() {
load(platformName) {
this._c = Platform.get(platformName);
}
});
Platform.register({
name: 'ios',
isMatch(platformQuerystring, userAgent) {
if (platformQuerystring) {
return platformQuerystring == 'ios';
}
return /ipad|iphone|ipod/i.test(userAgent);
},
getDevice: function() {
if(/ipad/i.test(userAgent)) {
return 'ipad';
}
if(/iphone/i.test(userAgent)) {
return 'iphone';
}
},
run() {
Tap.run();
config(val) {
this._c = val;
}
});
// 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() );
settings() {
return this._c.settings || {};
}
name() {
return this._c.name;
}
superset() {
return this._c.superset;
}
runAll() {
let platform = this;
while (platform) {
platform.run();
platform = platform.child();
}
return false;
}
parent(val) {
if (arguments.length) {
this._parent = val;
}
return this._parent;
}
child(val) {
if (arguments.length) {
this._child = val;
}
return this._child;
}
isMatch(app) {
if (typeof this._c._isMatched !== 'boolean') {
// only do the actual check once
if (!this._c.isMatch) {
this._c._isMatched = true;
} else {
this._c._isMatched = this._c.isMatch(app);
}
}
return this._c._isMatched;
}
getRoot(app) {
if (this.isMatch(app)) {
let parents = Platform.getSubsetParents(this.name());
if (!parents.length) {
return this;
}
let platform = null;
let rootPlatform = null;
for (let i = 0; i < parents.length; i++) {
platform = new PlatformNode();
platform.load(parents[i]);
platform.child(this);
rootPlatform = platform.getRoot(app);
if (rootPlatform) {
this.parent(platform);
return rootPlatform;
}
}
}
return null;
}
}
let platformRegistry = {};
// If the platform needs to do some initialization (like load a custom
// tap strategy), run it now
Platform.run();

116
ionic/platform/registry.js Normal file
View File

@ -0,0 +1,116 @@
import {Platform} from './platform';
import {Tap} from '../util/tap';
Platform.register({
name: 'core',
subsets: [
'android',
'ios',
'windowsphone'
],
settings: {
mode: 'core'
}
});
Platform.register({
name: 'mobile'
});
Platform.register({
name: 'phablet',
isMatch(app) {
let smallest = Math.min(app.width(), app.height());
let largest = Math.max(app.width(), app.height());
// http://www.mydevice.io/devices/
return (smallest > 390 && smallest < 520) &&
(largest > 620 && largest < 800);
}
});
Platform.register({
name: 'tablet',
isMatch(app) {
let smallest = Math.min(app.width(), app.height());
let largest = Math.max(app.width(), app.height());
// http://www.mydevice.io/devices/
return (smallest > 460 && smallest < 820) &&
(largest > 780 && largest < 1400);
}
});
Platform.register({
name: 'android',
superset: 'mobile',
subsets: [
'phablet',
'tablet'
],
settings: {
mode: 'md'
},
isMatch(app) {
return app.matchesPlatform('android');
}
});
Platform.register({
name: 'ios',
superset: 'mobile',
subsets: [
'ipad',
'iphone'
],
settings: {
mode: 'ios'
},
isMatch(app) {
return app.matchesPlatform('ios', 'iphone|ipad|ipod');
},
run() {
Tap.run();
}
});
Platform.register({
name: 'ipad',
superset: 'tablet',
isMatch(app) {
return app.matchesPlatform('ipad');
}
});
Platform.register({
name: 'iphone',
subsets: [
'phablet'
],
isMatch(app) {
return app.matchesPlatform('iphone');
}
});
Platform.register({
name: 'windowsphone',
superset: 'mobile',
subsets: [
'phablet',
'tablet'
],
settings: {
mode: 'wp'
},
isMatch(app) {
return app.matchesPlatform('windowsphone', 'windows phone');
}
});

View File

@ -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;
}