update to latest ng

This commit is contained in:
Andrew
2015-03-24 19:22:09 -06:00
parent 1549876988
commit ce33a09be3
11 changed files with 156 additions and 490 deletions

View File

@ -88,9 +88,20 @@ gulp.task('ng2-rename', function(done) {
});
gulp.task('ng2', ['ng2-rename'], function() {
var builder = new SystemJsBuilder();
return builder.loadConfig('jspm-config.js')
.then(function() {
return builder.build('dist/lib/angular2/angular2', 'dist/lib/angular2.js');
builder.config({
traceurOptions: {
'sourceMaps': true,
'annotations': true,
'types': true,
'script': false,
'memberVariables': true,
'modules': 'instantiate'
},
baseURL: 'dist/lib',
map: {
rx: __dirname + '/node_modules/rx'
}
});
return builder.build('angular2/angular2', 'dist/lib/angular2.js');
});

View File

@ -1,26 +1,23 @@
System.config({
"paths": {
"*": "*.js",
"dist/*": "/dist",
"node_modules/*": "/node_modules/*",
'paths': {
'*': '*.js',
'angular2/*': '/dist/lib/angular2/*.js'
},
"traceurOptions": {
"sourceMaps": true,
"annotations": true,
"types": true,
"script": false,
"memberVariables": true,
"modules": "instantiate"
'traceurOptions': {
'sourceMaps': true,
'annotations': true,
'types': true,
'script': false,
'memberVariables': true,
'modules': 'instantiate'
}
});
System.config({
"map": {
"angular2": "dist/lib/angular2",
"hammer": "node_modules/hammerjs/hammer.js",
"rtts_assert": "dist/lib/rtts_assert",
"rx": "node_modules/rx",
"ionic2": "/src",
'map': {
'hammer': '/node_modules/hammerjs/hammer',
'rx': '/node_modules/rx',
'ionic2': '/src',
}
});

View File

@ -4,12 +4,6 @@ import {PrivateComponentLoader} from 'angular2/src/core/compiler/private_compone
import {PrivateComponentLocation} from 'angular2/src/core/compiler/private_component_location';
import {RedBgStyler, BlueTextStyler} from './components/stylers';
class Testy {
constructor(@Inject() element: NgElement) {
element.domElement.style.border = '3px solid pink;'
}
}
@DynamicComponent({
selector: 'dynamic-component',
services: [PrivateComponentLoader, PrivateComponentLocation]
@ -20,12 +14,8 @@ class MyDynamic {
loader:PrivateComponentLoader,
location:PrivateComponentLocation
) {
// loader.load(RedBgStyler, location);
// loader.load(BlueTextStyler, location);
Testy.annotations = [
new Component({ selector: 'testy' }),
new Template({ inline: 'testy-template' })
];
loader.load(RedBgStyler, location);
loader.load(BlueTextStyler, location);
}
}

View File

@ -1,10 +1,10 @@
import {Component, Template, Inject, Parent, NgElement} from 'angular2/angular2';
import {Ion} from '../ion';
import {IonConfig} from '../../config';
import {Config} from '../../core/config/config';
import {SlideEdgeGesture} from '../../core/gestures/slide-edge-gesture';
import * as util from '../../util';
export var asideConfig = new IonConfig('aside');
export var asideConfig = new Config('aside');
// TODO defaults or bindings?
asideConfig.set({
@ -12,6 +12,13 @@ asideConfig.set({
dragThreshold: 50
})
class AndroidAside {}
class IosAside {}
asideConfig.platform('android').component(AndroidAside);
asideConfig.platform('ios').component(IosAside);
// AsideParent is just a temporary directive
@Component({
selector: 'ion-aside-parent'
@ -49,7 +56,9 @@ export class Aside {
// TODO: remove this. setTimeout has to be done so the bindings can be applied
setTimeout(() => {
// asideConfig.invoke(this);
let Comp = asideConfig.invoke(this);
console.log('using', Comp);
let GestureConstructor = {
left: LeftAsideSlideGesture,
top: TopAsideSlideGesture,

View File

@ -1,4 +1,3 @@
import * as Platform from '../platform';
import * as util from '../util';
export class Ion {}

View File

@ -1,180 +0,0 @@
import * as Platform from './platform';
import * as util from './util';
// TODO stop hardcoding platforms and media sizes
/*
config
.set({ side: 'left' })
.set('threshold', 50)
.platform('ios')
.set('side', 'top')
.unset('threshold')
.media('lg')
.set('side', 'right')
config.platform('ios')
.behavior(function() {
do something
})
.defaults({
side: 'right'
})
config.platform('ios').media('tablet')
.defaults({
side: 'bottom'
});
*/
/*
User wants to remove the default behavior for sidemenu, but that's stuck under `.platform('ios').`
config.platform('ios').media('tablet') === config.media('tablet').platform('ios')
*/
var QUERIES = {
sm: true,
md: true,
lg: true
};
var PLATFORMS = {
ios: true,
android: true
};
function isPlatform(key = '') {
return key.toLowerCase() in PLATFORMS;
}
function isMedia(key = '') {
return key.toLowerCase() in QUERIES;
}
class ConfigCase {
constructor({ root, parent, path }) {
this._root = root;
this._parent = parent;
this._path = path || [];
this._values = {};
this.behaviors = [];
}
platform(key = '') {
if (isPlatform(key)) return this._root._addCase(key, this);
return this;
}
media(key = '') {
if (isMedia(key)) return this._root._addCase(key, this);
return this;
}
when(condition = '') {
if (isPlatform(condition) || isMedia(condition)) {
return this._root._addCase(condition, this);
}
return this;
}
behavior(fn) {
this.behaviors.push(fn);
return this;
}
set(a, b) {
if (util.isString(a)) {
this._values[a] = b;
} else {
util.extend(this._values, a || {});
}
return this;
}
unset(key) {
delete this._values[key];
return this;
}
get(key) {
return util.isDefined(this._values[key]) ?
this._values[key] :
(this._parent ? this._parent.get(key) : undefined);
}
}
export class IonConfig extends ConfigCase {
constructor() {
this._root = this;
this._cases = {};
super({
root: this,
parent: null,
path: ''
});
}
invoke(instance) {
return invokeConfig(this, instance);
}
_addCase(key, baseCase) {
var path = baseCase._path.slice();
path.push(key);
// Remove empties & duplicates
path = path
.filter((value, index) => {
return value && path.indexOf(value) === index;
})
.sort();
if (path.join(' ') === baseCase._path.join(' ')) {
return baseCase;
}
return this._createCase(path);
}
_createCase(path) {
if (!path.length) return this;
var pathStr = path.join(' ');
var configCase = this._cases[pathStr];
if (!configCase) {
var parentPath = path.slice(0, path.length - 1);
configCase = this._cases[pathStr] = new ConfigCase({
root: this,
parent: this._createCase(parentPath),
path: path
});
}
return configCase;
}
}
export function invokeConfig(config, object, opts = {}) {
util.defaults(opts, { media: 'lg', platform: 'ios' });
var { platform, media } = opts;
var passedCases = [config].concat(
Object.keys(config._cases)
.map(name => config._cases[name])
.filter(configCasePasses)
.sort(function(a,b) {
return a._path.length < b._path.length ? -1 : 1;
})
);
// Extend the given object with the values of all the passed cases, starting with the
// most specific.
var defaults = [object];
var behaviors = [];
for (let i = 0, ii = passedCases.length; i < ii; i++) {
defaults.push(passedCases[i]._values);
// Avoid allocating a new array for each passed case's array of behaviors
behaviors.push.apply(behaviors, passedCases[i].behaviors);
}
util.defaults.apply(null, defaults);
for (let i = 0, ii = behaviors.length; i < ii; i++) {
behaviors[i].call(object, object);
}
function configCasePasses(configCase) {
var path = configCase._path;
var key;
for (let i = 0, ii = path.length; i < ii; i++) {
if (!(media === path[i] || platform === path[i])) return false;
}
return true;
}
}

View File

@ -1,138 +0,0 @@
import {IonConfig} from './config';
// TODO stop hardcoding platforms and media sizes
export function main() {
var rootConfig;
beforeEach(() => {
rootConfig = new IonConfig();
});
it('should create a config one level down', () => {
var sub = rootConfig.platform('ios');
expect(sub._parent).toBe(rootConfig);
expect(sub._path).toEqual(['ios']);
expect(rootConfig._cases.ios).toBe(sub);
});
it('should create a config two levels down', () => {
var sub1 = rootConfig.platform('ios');
var sub2 = sub1.media('lg');
expect(sub2._parent).toBe(sub1);
expect(sub1._parent).toBe(rootConfig);
expect(rootConfig._cases['ios lg']).toBe(sub2);
expect(rootConfig._cases.ios).toBe(sub1);
});
it('set should be chainable', () => {
expect(rootConfig.set()).toBe(rootConfig);
});
it('should set values on the root', () => {
rootConfig.set({
letter: 'a'
});
expect(rootConfig.get('letter')).toBe('a');
});
it('should always return the same object for the same key', () => {
expect(rootConfig.platform('android')).toBe(rootConfig.platform('android'));
expect(rootConfig.platform('ios')).toBe(rootConfig.platform('ios'));
expect(rootConfig.media('lg')).toBe(rootConfig.media('lg'));
});
it('should return the same object when nesting in different order', () => {
var sub1 = rootConfig.platform('ios').media('sm');
var sub2 = rootConfig.media('sm').platform('ios');
expect(sub1).toBe(sub2);
});
it('should return the same object when nesting in different order for huge queries', () => {
var sub1 = rootConfig.platform('ios').media('sm').platform('android').media('lg');
var sub2 = rootConfig.media('sm').media('lg').platform('android').platform('ios');
expect(sub1).toBe(sub2);
});
it('should set values one level down and be chainable', () => {
rootConfig.set({ letter: 'a' });
var sub1 = rootConfig.platform('ios');
expect(sub1.get('letter')).toBe('a');
expect( sub1.set({ letter: 'b' }) ).toBe(sub1);
expect(sub1.get('letter')).toBe('b');
});
it('should set values two levels down and be chainable', () => {
rootConfig.set({ letter: 'a' });
var sub1 = rootConfig.platform('ios');
sub1.set({ letter: 'b' });
var sub2 = sub1.media('lg');
expect(sub2.get('letter')).toBe('b');
expect( sub2.set({ letter: 'c' }) ).toBe(sub2);
expect(sub2.get('letter')).toBe('c');
});
it('should use parent\'s value if its later set to undefined', () => {
rootConfig.set({ letter: 'a' });
var sub1 = rootConfig.platform('ios');
sub1.set({ letter: 'b' });
expect(sub1.get('letter')).toBe('b');
expect( sub1.unset('letter') ).toBe(sub1);
expect(sub1.get('letter')).toBe('a');
});
it('when() as alias for media()', () => {
expect(rootConfig.when('lg')).toBe(rootConfig.media('lg'));
expect(rootConfig.when('bad')).toBe(rootConfig);
expect(rootConfig.when('lg')).not.toBe(rootConfig.when('ios'));
});
it('when() as alias for platform()', () => {
expect(rootConfig.platform('ios')).toBe(rootConfig.when('ios'));
expect(rootConfig.when('bad')).toBe(rootConfig);
});
describe('invokeConfig', function() {
it('should invoke defaults', () => {
var obj = {};
rootConfig.set('foo', 'bar');
rootConfig.invoke(obj);
});
it('should invoke defaults in nested whens', () => {
var obj = {};
rootConfig.set({ a: 'root', b: 'root' });
rootConfig.when('ios').set({b: 'ios', c: 'ios'});
rootConfig.when('ios').when('lg').set({ c: 'ios-lg', d: 'ios-lg' });
rootConfig.invoke(obj);
expect(obj).toEqual({
a: 'root',
b: 'ios',
c: 'ios-lg',
d: 'ios-lg'
});
});
it('should run behaviors', () => {
var obj = {};
rootConfig.behavior(instance => {
instance.foo = 'bar';
});
rootConfig.invoke(obj);
expect(obj.foo).toBe('bar');
});
it('should invoke behaviors in nested whens', () => {
var obj = {};
rootConfig.when('ios')
.behavior(o => o.ios = true)
.when('lg')
.behavior(o => o.lg = true)
rootConfig.invoke(obj);
expect(obj).toEqual({
ios: true,
lg: true
});
});
});
}

View File

@ -0,0 +1,47 @@
import * as util from '../../util';
import {platform} from '../platform/platform';
function isPlatform(key = '') {
return platform.isRegistered(key.toLowerCase());
}
export class ConfigCase {
constructor({ root, parent, path }) {
this._root = root;
this._parent = parent;
this._path = path || [];
this._values = {};
this._component = null;
}
platform(key = '') {
if (isPlatform(key)) return this._root._addCase(key, this);
return this;
}
// media(key = '') {
// if (isMedia(key)) return this._root._addCase(key, this);
// return this;
// }
when(condition = '') {
if (isPlatform(condition)) {
return this._root._addCase(condition, this);
}
return this;
}
component(Class) {
this._component = Class;
return this;
}
set(obj) {
util.extend(this._values, obj);
return this;
}
unset(key) {
delete this._values[key];
return this;
}
get(key) {
return util.isDefined(this._values[key]) ?
this._values[key] :
(this._parent ? this._parent.get(key) : undefined);
}
}

View File

@ -1,100 +1,29 @@
import getPlatform from '../platform/platform';
import {platform} from '../platform/platform';
import {ConfigCase} from './config-case';
import * as util from '../../util';
// TODO stop hardcoding platforms and media sizes
/*
config
.set({ side: 'left' })
.set('threshold', 50)
.platform('ios')
.set('side', 'top')
.unset('threshold')
.media('lg')
.set('side', 'right')
config.platform('ios')
.behavior(function() {
do something
})
.defaults({
side: 'right'
@ConfigPlatform({
for: AsideBase
platform: 'android',
defaults: {
type: 'reveal'
}
})
class AndroidAside extends AsideBase {}
config.platform('ios').media('tablet')
.defaults({
side: 'bottom'
});
```@ConfigCase({
for: AsideBase,
condition: instance => instance.type === 'reveal'
})
class AsideReveal {
constructor(aside: AsideBase) {}
}
*/
/*
User wants to remove the default behavior for sidemenu, but that's stuck under `.platform('ios').`
config.platform('ios').media('tablet') === config.media('tablet').platform('ios')
*/
var QUERIES = {
sm: true,
md: true,
lg: true
};
var PLATFORMS = {
ios: true,
android: true
};
function isPlatform(key = '') {
return key.toLowerCase() in PLATFORMS;
}
function isMedia(key = '') {
return key.toLowerCase() in QUERIES;
}
class ConfigCase {
constructor({ root, parent, path }) {
this._root = root;
this._parent = parent;
this._path = path || [];
this._values = {};
this.behaviors = [];
}
platform(key = '') {
if (isPlatform(key)) return this._root._addCase(key, this);
return this;
}
media(key = '') {
if (isMedia(key)) return this._root._addCase(key, this);
return this;
}
when(condition = '') {
if (isPlatform(condition) || isMedia(condition)) {
return this._root._addCase(condition, this);
}
return this;
}
behavior(fn) {
this.behaviors.push(fn);
return this;
}
set(a, b) {
if (util.isString(a)) {
this._values[a] = b;
} else {
util.extend(this._values, a || {});
}
return this;
}
unset(key) {
delete this._values[key];
return this;
}
get(key) {
return util.isDefined(this._values[key]) ?
this._values[key] :
(this._parent ? this._parent.get(key) : undefined);
}
}
export class IonConfig extends ConfigCase {
export class Config extends ConfigCase {
constructor() {
this._root = this;
this._cases = {};
@ -108,7 +37,7 @@ export class IonConfig extends ConfigCase {
return invokeConfig(this, instance);
}
_addCase(key, baseCase) {
var path = baseCase._path.slice();
let path = baseCase._path.slice();
path.push(key);
// Remove empties & duplicates
@ -125,10 +54,10 @@ export class IonConfig extends ConfigCase {
}
_createCase(path) {
if (!path.length) return this;
var pathStr = path.join(' ');
var configCase = this._cases[pathStr];
let pathStr = path.join(' ');
let configCase = this._cases[pathStr];
if (!configCase) {
var parentPath = path.slice(0, path.length - 1);
let parentPath = path.slice(0, path.length - 1);
configCase = this._cases[pathStr] = new ConfigCase({
root: this,
parent: this._createCase(parentPath),
@ -139,11 +68,10 @@ export class IonConfig extends ConfigCase {
}
}
export function invokeConfig(config, object, opts = {}) {
util.defaults(opts, { media: 'lg', platform: 'ios' });
var { platform, media } = opts;
export function invokeConfig(config, object) {
let platformName = platform.get().name;
var passedCases = [config].concat(
let passedCases = [config].concat(
Object.keys(config._cases)
.map(name => config._cases[name])
.filter(configCasePasses)
@ -154,25 +82,25 @@ export function invokeConfig(config, object, opts = {}) {
// Extend the given object with the values of all the passed cases, starting with the
// most specific.
var defaults = [object];
var behaviors = [];
let defaults = [object];
// Also find the most specific case with a component that we should use.
let ComponentToUse;
for (let i = 0, ii = passedCases.length; i < ii; i++) {
defaults.push(passedCases[i]._values);
// Avoid allocating a new array for each passed case's array of behaviors
behaviors.push.apply(behaviors, passedCases[i].behaviors);
if (passedCases[i]._component) {
ComponentToUse = passedCases[i]._component;
}
}
util.defaults.apply(null, defaults);
for (let i = 0, ii = behaviors.length; i < ii; i++) {
behaviors[i].call(object, object);
}
return ComponentToUse;
function configCasePasses(configCase) {
var path = configCase._path;
var key;
let path = configCase._path;
let key;
for (let i = 0, ii = path.length; i < ii; i++) {
if (!(media === path[i] || platform === path[i])) return false;
if (platformName !== path[i]) return false;
}
return true;
}

View File

@ -1,19 +1,13 @@
var platforms = [];
// TODO(ajoslin): move this to a facade somewhere else?
var ua = window.navigator.userAgent;
import * as util from '../../util';
class Platform {
constructor({
name,
matcher
}) {
this.name = name;
this.matcher = matcher;
constructor(options) {
util.extend(this, options);
}
}
class PlatformController {
current: Platform;
constructor() {
this.registry = [];
}
@ -21,11 +15,19 @@ class PlatformController {
this.current = platform;
}
get() {
return platform;
return this.current;
}
register(platform) {
if (!platform instanceof Platform) {
platform = new Platform(platform);
}
this.registry.push(platform);
}
isRegistered(platformName) {
return this.registry.some(platform => {
return platform.name === platformName;
});
}
detect() {
for (let platform of this.registry) {
if (platform.matcher()) {
@ -37,18 +39,23 @@ class PlatformController {
export let platform = new PlatformController();
platform.register(new Platform({
name: 'android',
matcher: () => {
return /android/i.test(ua)
}
}));
platform.register(new Platform({
name: 'ios',
matcher: () => {
return /iPhone|iPad|iPod/.test(ua)
}
})
// TODO(ajoslin): move this to a facade somewhere else?
var ua = window.navigator.userAgent;
function detectPlatform() {
// TODO(ajoslin): move these to their own files
platform.register({
name: 'android',
matcher() {
return /android/i.test(ua);
}
});
platform.register({
name: 'ios',
// For now always default to ios
matcher() {
return true;
}
});
platform.set( platform.detect() );

View File

@ -1,4 +0,0 @@
export function getPlatform() {
return 'android';
}