Feature(generate): Merge generate with latest. Update tests for tims refactor

This commit is contained in:
jbavari
2015-11-02 12:58:13 -07:00
37 changed files with 443 additions and 273 deletions

View File

@@ -18,6 +18,62 @@ We are also building out a number of starter projects, including the Ionic 2 sta
[https://github.com/driftyco/ionic2-starter](https://github.com/driftyco/ionic2-starter)
### Distribution
## Distribution
- [npm: ionic-framework](https://www.npmjs.com/package/ionic-framework)
## Ionic Framework Package
The ionic-framework package comes with both frontend dependencies, located in 'dist', and a Node API, located in 'tooling'.
### Bundles:
- `css/`
- the Ionic CSS stylesheet
- `fonts/`
- Ionicons and Roboto fonts
- `js/`
- `ionic.js` the Ionic module, in System register format
- `ionic.bundle.js` the Ionic bundle, contains:
- es6-module-loader.js
- system.js
- angular2.dev.js
- router.dev.js (angular2 router)
- ionic.js
- web-animations.min.js
- `web-animations.min.js` web animations API polyfill
### Source files:
- `src/es5` - Ionic ES5 source files in both CommonJS and System module formats
- `src/es6` - Ionic ES6 source files
- `src/ts` - Ionic TypeScript source files (typings still missing)
- `scss` - Ionic Sass source files
---------
### Tooling
At the moment, ionic-framework exports one function, `generate`, that can be used to scaffold new pages in an Ionic app. It is used by the [Ionic CLI's](https://github.com/driftyco/ionic-cli) `generate` command.
#### Methods
`generate(config)`
Creates the js, html, and scss file for a new page, based on the supplied [Generator](#generators).
- **config** (Object) Config object, with the following options:
- `appDirectory` - root directory of the Ionic project
- `generator` - which [generator](#generators) to use, default is `page`.
- `name` -
Example:
```
var ionic = require('ionic-framework');
ionic.generate({ appDirectory: process.cwd(), generator: 'tabs', name: 'MyTabsPage' })
```
#### Generators
- `page`, a blank page
- `tabs`, a page with tab navigation
- `sidemenu`

View File

@@ -4,7 +4,7 @@
</ion-navbar>
<ion-content class="has-header demo-list-icons">
<ion-list>
<ion-list no-lines>
<ion-item>Pokémon Yellow</ion-item>
<ion-item>Super Metroid</ion-item>
<ion-item>Mega Man X</ion-item>

View File

@@ -497,47 +497,3 @@ gulp.task('demos:docs', ['sass.demos:docs', 'bundle.demos:docs'], function() {
gulp.task('demos', ['demos:all']);
gulp.task('publish', function(done) {
var version = flags.version;
var ngVersion = flags.ngVersion;
var dryRun = flags['dry-run'];
if (!version || !ngVersion) {
console.error("\nERR: You need to provide a version for Ionic as well as " +
"the version of Angular it depends on.\n\n" +
"gulp publish -v {version} -a {ngVersion}\n");
return
}
if (version.indexOf("alpha") + version.indexOf("-") > -2 ||
ngVersion.indexOf("alpha") + ngVersion.indexOf("-") > -2)
{
console.error("\n ERR: Just provide version number. Instead of 2.0.0-alpha.10, just enter 10\n");
return
}
var exec = require('child_process').exec;
var _ = require('lodash');
var fs = require('fs');
runSequence(
'clean',
['bundle', 'sass', 'fonts', 'copy.ts', 'copy.scss', 'copy.web-animations'],
'transpile.common',
function() {
var packageJSONTemplate = _.template(fs.readFileSync('scripts/npm/package.json'));
packageJSONContents = packageJSONTemplate({ 'version': version, 'ngVersion': ngVersion });
fs.writeFileSync('dist/package.json', packageJSONContents);
fs.writeFileSync('dist/README.md', fs.readFileSync('scripts/npm/README.md'));
// publish to npm
if (!dryRun) {
exec('cd dist && npm publish', function (err, stdout, stderr) {
console.log(stdout);
console.error(stderr);
done();
});
}
}
)
})

View File

@@ -1,3 +0,0 @@
module.exports = {
generate: require('./tooling/generate')
};

View File

@@ -76,6 +76,9 @@ import * as util from 'ionic/util';
'</div>' +
'</div>' +
'</action-sheet-wrapper>',
host: {
'[style.zIndex]': '_zIndex'
},
directives: [NgFor, NgIf, Icon]
})
class ActionSheetCmp {

View File

@@ -88,6 +88,7 @@ ion-tabs {
left: 0;
width: 100%;
height: 100%;
overflow: hidden;
}
ion-navbar-section {

View File

@@ -10,6 +10,23 @@ import * as util from 'ionic/util';
import {CSS, raf} from 'ionic/util/dom';
@Directive({
selector: 'ion-item-options > button,ion-item-options > [button]',
host: {
'(click)': 'clicked($event)'
}
})
export class ItemSlidingOptionButton {
constructor(elementRef: ElementRef) {
}
clicked(event) {
// Don't allow the click to propagate
event.preventDefault();
event.stopPropagation();
}
}
/**
* @name ionItem
* @description
@@ -41,8 +58,7 @@ import {CSS, raf} from 'ionic/util/dom';
'<ion-item-content>' +
'<ng-content></ng-content>'+
'</ion-item-content>' +
'</ion-item-sliding-content>',
directives: [NgIf]
'</ion-item-sliding-content>'
})
export class ItemSliding {
/**
@@ -165,6 +181,11 @@ class ItemSlideGesture extends DragGesture {
el.addEventListener('mousedown', touchStart);
let touchEnd = (e) => {
// If we have a touch end and the item is closing,
// prevent default to stop a click from triggering
if(this.item.didClose) {
e.preventDefault();
}
this.item.didClose = false;
};
el.addEventListener('touchend', touchEnd);

View File

@@ -1,4 +1,4 @@
import {Component, ElementRef, Renderer} from 'angular2/angular2';
import {Component} from 'angular2/angular2';
/**
@@ -24,10 +24,13 @@ import {Component, ElementRef, Renderer} from 'angular2/angular2';
'<ng-content select="[item-right]"></ng-content>' +
'<ion-item-content>' +
'<ng-content></ng-content>'+
'</ion-item-content>'
'</ion-item-content>',
host: {
'[class.item]': 'isItem'
}
})
export class Item {
constructor(elementRef: ElementRef, renderer: Renderer) {
renderer.setElementClass(elementRef, 'item', true);
constructor() {
this.isItem = true;
}
}

View File

@@ -16,4 +16,14 @@ class E2EApp {
return [0,1];
}
didClick(e) {
console.log('CLICK', e.defaultPrevented, e)
}
archive(e) {
console.log('Accept', e);
}
del(e) {
console.log('Delete', e);
}
}

View File

@@ -2,13 +2,14 @@
<ion-list>
<ion-item-sliding text-wrap detail-push>
<ion-item-sliding text-wrap detail-push (click)="didClick($event)">
<h3>Max Lynch</h3>
<p>
Hey do you want to go to the game tonight?
</p>
<ion-item-options>
<button primary>Archive</button>
<button primary (click)="archive($event)">Archive</button>
<button danger (click)="del($event)">Delete</button>
</ion-item-options>
</ion-item-sliding>

View File

@@ -17,7 +17,7 @@ class MenuContentGesture extends SlideEdgeGesture {
}
canStart(ev) {
return this.menu.isOpen ? true : super.canStart(ev);
return this.menu.isOpen && this.menu.isEnabled ? true : super.canStart(ev);
}
// Set CSS, then wait one frame for it to apply before sliding starts

View File

@@ -16,7 +16,8 @@ import {Navbar} from '../nav-bar/nav-bar';
],
host: {
'(click)': 'toggle()',
'[hidden]': 'isHidden'
'[hidden]': 'isHidden',
'menu-toggle': '' //ensures the attr is there for css when using [menu-toggle]
}
})
export class MenuToggle extends Ion {

View File

@@ -78,7 +78,8 @@ export class Menu extends Ion {
this.opening = new EventEmitter('opening');
this.isOpen = false;
this._disableTime = 0;
this._preventTime = 0;
this.isEnabled = true;
}
/**
@@ -107,9 +108,11 @@ export class Menu extends Ion {
let self = this;
this.onContentClick = function(ev) {
ev.preventDefault();
ev.stopPropagation();
self.close();
if (self.isEnabled) {
ev.preventDefault();
ev.stopPropagation();
self.close();
}
};
}
@@ -151,9 +154,9 @@ export class Menu extends Ion {
* @return {Promise} TODO
*/
setOpen(shouldOpen) {
// _isDisabled is used to prevent unwanted opening/closing after swiping open/close
// _isPrevented is used to prevent unwanted opening/closing after swiping open/close
// or swiping open the menu while pressing down on the menu-toggle button
if (shouldOpen === this.isOpen || this._isDisabled()) {
if (shouldOpen === this.isOpen || this._isPrevented()) {
return Promise.resolve();
}
@@ -166,7 +169,7 @@ export class Menu extends Ion {
setProgressStart() {
// user started swiping the menu open/close
if (this._isDisabled()) return;
if (this._isPrevented() || !this.isEnabled) return;
this._before();
@@ -175,58 +178,66 @@ export class Menu extends Ion {
setProgess(value) {
// user actively dragging the menu
this._disable();
this.app.setTransitioning(true);
this._type.setProgess(value);
if (this.isEnabled) {
this._prevent();
this.app.setTransitioning(true);
this._type.setProgess(value);
}
}
setProgressEnd(shouldComplete) {
// user has finished dragging the menu
this._disable();
this.app.setTransitioning(true);
this._type.setProgressEnd(shouldComplete).then(isOpen => {
this._after(isOpen);
});
if (this.isEnabled) {
this._prevent();
this.app.setTransitioning(true);
this._type.setProgressEnd(shouldComplete).then(isOpen => {
this._after(isOpen);
});
}
}
_before() {
// this places the menu into the correct location before it animates in
// this css class doesn't actually kick off any animations
this.getNativeElement().classList.add('show-menu');
this.getBackdropElement().classList.add('show-backdrop');
if (this.isEnabled) {
this.getNativeElement().classList.add('show-menu');
this.getBackdropElement().classList.add('show-backdrop');
this._disable();
this.app.setTransitioning(true);
this.keyboard.close();
this._prevent();
this.app.setTransitioning(true);
this.keyboard.close();
}
}
_after(isOpen) {
// keep opening/closing the menu disabled for a touch more yet
this._disable();
this.app.setTransitioning(false);
if (this.isEnabled) {
this._prevent();
this.app.setTransitioning(false);
this.isOpen = isOpen;
this.isOpen = isOpen;
this._cntEle.classList[isOpen ? 'add' : 'remove']('menu-content-open');
this._cntEle.classList[isOpen ? 'add' : 'remove']('menu-content-open');
this._cntEle.removeEventListener('click', this.onContentClick);
if (isOpen) {
this._cntEle.addEventListener('click', this.onContentClick);
this._cntEle.removeEventListener('click', this.onContentClick);
if (isOpen) {
this._cntEle.addEventListener('click', this.onContentClick);
} else {
this.getNativeElement().classList.remove('show-menu');
this.getBackdropElement().classList.remove('show-backdrop');
} else {
this.getNativeElement().classList.remove('show-menu');
this.getBackdropElement().classList.remove('show-backdrop');
}
}
}
_disable() {
_prevent() {
// used to prevent unwanted opening/closing after swiping open/close
// or swiping open the menu while pressing down on the menu-toggle
this._disableTime = Date.now() + 20;
this._preventTime = Date.now() + 20;
}
_isDisabled() {
return this._disableTime > Date.now();
_isPrevented() {
return this._preventTime > Date.now();
}
/**
@@ -253,6 +264,10 @@ export class Menu extends Ion {
return this.setOpen(!this.isOpen);
}
enable(shouldEnable) {
this.isEnabled = shouldEnable;
}
/**
* TODO
* @return {Element} The Menu element.

View File

@@ -0,0 +1,33 @@
import {App, IonicApp, Page, NavController} from 'ionic/ionic';
@Page({
templateUrl: 'page1.html'
})
class Page1 {
constructor(app: IonicApp) {
this.app = app;
this.menu1Active();
}
menu1Active() {
this.activeMenu = 'menu1';
this.app.getComponent('menu1').enable(true);
this.app.getComponent('menu2').enable(false);
}
menu2Active() {
this.activeMenu = 'menu2';
this.app.getComponent('menu1').enable(false);
this.app.getComponent('menu2').enable(true);
}
}
@App({
templateUrl: 'main.html'
})
class E2EApp {
constructor(app: IonicApp) {
this.app = app;
this.rootPage = Page1;
}
}

View File

@@ -0,0 +1,36 @@
<ion-menu [content]="content" id="menu1">
<ion-toolbar secondary>
<ion-title>Menu 1</ion-title>
</ion-toolbar>
<ion-content>
<ion-list>
<button ion-item menu-close="menu1" detail-none>
Close Menu 1
</button>
</ion-list>
</ion-content>
</ion-menu>
<ion-menu [content]="content" id="menu2">
<ion-toolbar danger>
<ion-title>Menu 2</ion-title>
</ion-toolbar>
<ion-content>
<ion-list>
<button ion-item menu-close="menu2" detail-none>
Close Menu 2
</button>
</ion-list>
</ion-content>
</ion-menu>
<ion-nav [root]="rootPage" #content swipe-back-enabled="false"></ion-nav>

View File

@@ -0,0 +1,30 @@
<ion-navbar *navbar>
<a [menu-toggle]="activeMenu">
<icon menu></icon>
</a>
<ion-title>
Multiple Menus
</ion-title>
</ion-navbar>
<ion-content padding>
<h4>Active Menu: {{ activeMenu }}</h4>
<p>
<button secondary (click)="menu1Active()">Make Menu 1 Active</button>
</p>
<p>
<button danger (click)="menu2Active()">Make Menu 2 Active</button>
</p>
<p>
<button [menu-toggle]="activeMenu">Toggle Menu</button>
</p>
<p>This page has two left menus, but only one is active at a time.</p>
</ion-content>

View File

@@ -193,9 +193,7 @@ export class NavController extends Ion {
}
// start the transition
this.transition(enteringView, leavingView, opts, () => {
resolve();
});
this._transition(enteringView, leavingView, opts, resolve);
return promise;
}
@@ -236,10 +234,7 @@ export class NavController extends Ion {
}
// start the transition
this.transition(enteringView, leavingView, opts, () => {
// transition completed, destroy the leaving view
resolve();
});
this._transition(enteringView, leavingView, opts, resolve);
} else {
this._transComplete();
@@ -256,20 +251,19 @@ export class NavController extends Ion {
* @param view {ViewController} to pop to
* @param opts {object} pop options
*/
_popTo(view, opts = {}) {
popTo(viewCtrl, opts = {}) {
// Get the target index of the view to pop to
let viewIndex = this._views.indexOf(view);
let viewIndex = this._views.indexOf(viewCtrl);
let targetIndex = viewIndex + 1;
let resolve;
let promise = new Promise(res => { resolve = res; });
// Don't pop to the view if it wasn't found, or the target is beyond the view list
if(viewIndex < 0 || targetIndex > this._views.length - 1) {
resolve();
return;
if (viewIndex < 0 || targetIndex > this._views.length - 1) {
return Promise.resolve();
}
let resolve;
let promise = new Promise(res => { resolve = res; });
opts.direction = opts.direction || 'back';
// get the views to auto remove without having to do a transiton for each
@@ -283,16 +277,13 @@ export class NavController extends Ion {
}
}
let leavingView = this._views[this._views.length - 1];
let enteringView = view;
let leavingView = this.getPrevious(viewCtrl);
if (this.router) {
this.router.stateChange('pop', enteringView);
this.router.stateChange('pop', viewCtrl);
}
this.transition(enteringView, leavingView, opts, () => {
resolve();
});
this._transition(viewCtrl, leavingView, opts, resolve);
return promise;
}
@@ -302,7 +293,7 @@ export class NavController extends Ion {
* @param opts extra animation options
*/
popToRoot(opts = {}) {
this._popTo(this.first());
return this._popTo(this.first(), opts);
}
/**
@@ -311,14 +302,14 @@ export class NavController extends Ion {
* @param {TODO} index TODO
* @returns {Promise} TODO
*/
insert(componentType, index) {
insert(componentType, index, params = {}, opts = {}) {
if (!componentType || index < 0) {
return Promise.reject();
}
// push it onto the end
if (index >= this._views.length) {
return this.push(componentType);
return this.push(componentType, params, opts);
}
// create new ViewController, but don't render yet
@@ -337,14 +328,14 @@ export class NavController extends Ion {
* @param {TODO} index TODO
* @returns {Promise} TODO
*/
remove(index) {
remove(index, opts = {}) {
if (index < 0 || index >= this._views.length) {
return Promise.reject("Index out of range");
}
let viewToRemove = this._views[index];
if (this.isActive(viewToRemove)){
return this.pop();
return this.pop(opts);
}
viewToRemove.shouldDestroy = true;
@@ -436,12 +427,12 @@ export class NavController extends Ion {
* @param {TODO} enteringView TODO
* @param {TODO} leavingView TODO
* @param {TODO} opts TODO
* @param {Function} callback TODO
* @param {Function} done TODO
* @returns {any} TODO
*/
transition(enteringView, leavingView, opts, callback) {
_transition(enteringView, leavingView, opts, done) {
if (!enteringView || enteringView === leavingView) {
return callback();
return done();
}
if (!opts.animation) {
@@ -452,13 +443,15 @@ export class NavController extends Ion {
}
// wait for the new view to complete setup
enteringView.stage(() => {
this._stage(enteringView, () => {
if (enteringView.shouldDestroy) {
// already marked as a view that will be destroyed, don't continue
return callback();
return done();
}
this._setZIndex(enteringView.instance, leavingView.instance, opts.direction);
this._zone.runOutsideAngular(() => {
enteringView.shouldDestroy = false;
@@ -503,7 +496,7 @@ export class NavController extends Ion {
// all done!
this._zone.run(() => {
this._transComplete();
callback();
done();
});
});
@@ -513,6 +506,30 @@ export class NavController extends Ion {
}
/**
* @private
*/
_stage(viewCtrl, done) {
if (viewCtrl.instance || viewCtrl.shouldDestroy) {
// already compiled this view
return done();
}
// get the pane the NavController wants to use
// the pane is where all this content will be placed into
this.loadPage(viewCtrl, null, () => {
// this ViewController instance has finished loading
try {
viewCtrl.loaded();
} catch (e) {
console.error(e);
}
done();
});
}
loadPage(viewCtrl, navbarContainerRef, done) {
let providers = this.providers.concat(Injector.resolve([
provide(ViewController, {useValue: viewCtrl}),
@@ -560,6 +577,20 @@ export class NavController extends Ion {
});
}
_setZIndex(enteringInstance, leavingInstance, direction) {
if (!leavingInstance) {
enteringInstance._zIndex = 0;
} else if (direction === 'back') {
// moving back
enteringInstance._zIndex = leavingInstance._zIndex - 1;
} else {
// moving forward
enteringInstance._zIndex = leavingInstance._zIndex + 1;
}
}
/**
* @private
* TODO
@@ -594,7 +625,7 @@ export class NavController extends Ion {
enteringView.willEnter();
// wait for the new view to complete setup
enteringView.stage(() => {
enteringView._stage(() => {
this._zone.runOutsideAngular(() => {
// set that the new view pushed on the stack is staged to be entering/leaving

View File

@@ -14,18 +14,24 @@ import {NavParams, NavController, ViewController} from 'ionic/ionic';
<button>S1</button>
</ion-nav-items>
</ion-navbar>
<ion-content padding>
<p>{{title}}</p>
<p><button class="e2eFrom1To2" (click)="pushFullPage()">Push to FullPage</button></p>
<p><button (click)="pushPrimaryHeaderPage()">Push to PrimaryHeaderPage</button></p>
<p><button (click)="pushAnother()">Push to AnotherPage</button></p>
<p><button [nav-push]="[pushPage, {id: 42}]">Push FullPage w/ [nav-push] array</button></p>
<p><button [nav-push]="pushPage" [nav-params]="{id:40}">Push w/ [nav-push] and [nav-params]</button></p>
<p><button [nav-push]="[\'FirstPage\', {id: 22}]">Push w/ [nav-push] array and string view name</button></p>
<p><button nav-push="FirstPage" [nav-params]="{id: 23}">Push w/ nav-push and [nav-params]</button></p>
<p><button (click)="setViews()">setViews() (Go to PrimaryHeaderPage)</button></p>
<p><button (click)="nav.pop()">Pop</button></p>
<f></f><f></f><f></f><f></f><f></f><f></f><f></f><f></f><f></f><f></f>
<ion-content>
<ion-list>
<ion-header>
{{title}}
</ion-header>
<button ion-item class="e2eFrom1To2" (click)="pushFullPage()">Push to FullPage</button>
<button ion-item (click)="pushPrimaryHeaderPage()">Push to PrimaryHeaderPage</button>
<button ion-item (click)="pushAnother()">Push to AnotherPage</button>
<button ion-item [nav-push]="[pushPage, {id: 42}]">Push FullPage w/ [nav-push] array</button>
<button ion-item [nav-push]="pushPage" [nav-params]="{id:40}">Push w/ [nav-push] and [nav-params]</button>
<button ion-item [nav-push]="[\'FirstPage\', {id: 22}]">Push w/ [nav-push] array and string view name</button>
<button ion-item nav-push="FirstPage" [nav-params]="{id: 23}">Push w/ nav-push and [nav-params]</button>
<button ion-item (click)="setViews()">setViews() (Go to PrimaryHeaderPage)</button>
<button ion-item (click)="nav.pop()">Pop</button>
<button *ng-for="#i of pages" ion-item (click)="pushPrimaryHeaderPage()">Page {{i}}</button>
</ion-list>
</ion-content>`
})
class FirstPage {
@@ -38,6 +44,11 @@ class FirstPage {
this.title = 'First Page';
this.pushPage = FullPage;
this.pages = [];
for (var i = 1; i <= 50; i++) {
this.pages.push(i);
}
}
setViews() {

View File

@@ -133,7 +133,7 @@ export function run() {
spyOn(nav, '_add').and.callThrough();
nav.transition = mockTransitionFn;
nav._transition = mockTransitionFn;
nav.push(FirstPage, {}, {}).then(() => {
expect(nav._add).toHaveBeenCalled();
expect(nav._views.length).toBe(1);
@@ -163,7 +163,7 @@ export function run() {
nav._views = [vc1, vc2, vc3];
let arr = [FirstPage, SecondPage, ThirdPage];
nav.transition = mockTransitionFn;
nav._transition = mockTransitionFn;
nav.setViews(arr);
//_views[0] will be transitioned out of
@@ -188,7 +188,7 @@ export function run() {
nav.insert(FirstPage, 2);
expect(nav.push).not.toHaveBeenCalled();
nav.transition = mockTransitionFn;
nav._transition = mockTransitionFn;
nav.insert(FirstPage, 4);
expect(nav._views[4].componentType).toBe(FirstPage);
expect(nav.push).toHaveBeenCalled();
@@ -208,7 +208,7 @@ export function run() {
nav._views = [vc1, vc2, vc3];
expect(nav._views.length).toBe(3);
nav.transition = mockTransitionFn;
nav._transition = mockTransitionFn;
nav.setRoot(FirstPage);
//_views[0] will be transitioned out of
expect(nav._views.length).toBe(2);
@@ -250,5 +250,27 @@ export function run() {
});
});
describe("_setZIndex", () => {
it('should set zIndex 0 on first entering view', () => {
let enteringInstance = {};
nav._setZIndex(enteringInstance, null, 'forward');
expect(enteringInstance._zIndex).toEqual(0);
});
it('should set zIndex 1 on second entering view', () => {
let leavingInstance = { _zIndex: 0 };
let enteringInstance = {};
nav._setZIndex(enteringInstance, leavingInstance, 'forward');
expect(enteringInstance._zIndex).toEqual(1);
});
it('should set zIndex 0 on entering view going back', () => {
let leavingInstance = { _zIndex: 1 };
let enteringInstance = {};
nav._setZIndex(enteringInstance, leavingInstance, 'back');
expect(enteringInstance._zIndex).toEqual(0);
});
});
});
}

View File

@@ -15,32 +15,6 @@ export class ViewController {
this._destroys = [];
}
/**
* @private
*/
stage(done) {
let navCtrl = this.navCtrl;
if (this.instance || !navCtrl || this.shouldDestroy) {
// already compiled this view
return done();
}
// get the pane the NavController wants to use
// the pane is where all this content will be placed into
navCtrl.loadPage(this, null, () => {
// this ViewController instance has finished loading
try {
this.loaded();
} catch (e) {
console.error(e);
}
done();
});
}
/**
* TODO
* @returns {boolean} TODO

View File

@@ -33,13 +33,12 @@ export class OverlayController {
return reject();
}
ref._z = ROOT_Z_INDEX;
instance._zIndex = ROOT_Z_INDEX;
for (let i = 0; i < this.refs.length; i++) {
if (this.refs[i]._z >= ref._z) {
ref._z = this.refs[i]._z + 1;
if (this.refs[i].instance._zIndex >= ref.instance._zIndex) {
ref.instance._zIndex = this.refs[i].instance._zIndex + 1;
}
}
this.renderer.setElementStyle(ref.location, 'zIndex', ref._z);
this.renderer.setElementAttribute(ref.location, 'role', 'dialog');
util.extend(instance, opts);

View File

@@ -283,6 +283,9 @@ const OVERLAY_TYPE = 'popup';
'<button *ng-for="#button of buttons" (click)="buttonTapped(button, $event)" [inner-html]="button.text"></button>' +
'</div>' +
'</popup-wrapper>',
host: {
'[style.zIndex]': '_zIndex'
},
directives: [FORM_DIRECTIVES, NgClass, NgIf, NgFor, Button]
})

View File

@@ -44,6 +44,9 @@ class Tab2 {
@Page({
template: `
<ion-navbar *navbar>
<a menu-toggle>
<icon menu></icon>
</a>
<ion-title>Stopwatch</ion-title>
</ion-navbar>
<ion-content padding>
@@ -59,12 +62,25 @@ class Tab3 {
@App({
template: `
<ion-tabs>
<ion-menu [content]="content">
<ion-toolbar secondary>
<ion-title>Menu</ion-title>
</ion-toolbar>
<ion-content>
<ion-list>
<button ion-item menu-close detail-none>
Close Menu
</button>
</ion-list>
</ion-content>
</ion-menu>
<ion-tabs #content>
<ion-tab tab-title="Heart" tab-icon="heart" [root]="root1"></ion-tab>
<ion-tab tab-title="Star" tab-icon="star" [root]="root2"></ion-tab>
<ion-tab tab-title="Stopwatch" tab-icon="stopwatch" [root]="root3"></ion-tab>
</ion-tabs>
`
`
})
export class TabsPage {
constructor() {

View File

@@ -70,6 +70,7 @@ export function Page(config={}) {
config.host = config.host || {};
config.host['[hidden]'] = '_hidden';
config.host['[class.tab-subpage]'] = '_tabSubPage';
config.host['[style.zIndex]'] = '_zIndex';
var annotations = Reflect.getMetadata('annotations', cls) || [];
annotations.push(new Component(config));
Reflect.defineMetadata('annotations', annotations, cls);

View File

@@ -15,7 +15,7 @@ import {Tab} from '../components/tabs/tab';
import {List, ListHeader} from '../components/list/list';
import {Item} from '../components/item/item';
import {ItemGroup, ItemGroupTitle} from '../components/item/item-group';
import {ItemSliding} from '../components/item/item-sliding';
import {ItemSliding, ItemSlidingOptionButton} from '../components/item/item-sliding';
import {Toolbar, ToolbarTitle, ToolbarItem} from '../components/toolbar/toolbar';
import {Icon} from '../components/icon/icon';
import {Checkbox} from '../components/checkbox/checkbox';
@@ -60,6 +60,7 @@ export const IONIC_DIRECTIVES = [
ItemGroup,
ItemGroupTitle,
ItemSliding,
ItemSlidingOptionButton,
// Slides
Slides,

View File

@@ -50,7 +50,7 @@ export class SqlStorage extends StorageEngine {
if(window.sqlitePlugin) {
let location = this._getBackupLocation(dbOptions);
let location = this._getBackupLocation(dbOptions.backupFlag);
this._db = window.sqlitePlugin.openDatabase(util.extend({
name: dbOptions.name,

View File

@@ -39,13 +39,14 @@ class MDTransition extends Animation {
.fadeIn();
}
let enteringBackButton = new Animation(enteringView.backBtnRef());
this.add(enteringBackButton);
if (enteringHasNavbar && enteringView.enableBack()) {
enteringBackButton.before.addClass(SHOW_BACK_BTN_CSS);
} else {
enteringBackButton.before.removeClass(SHOW_BACK_BTN_CSS);
if (enteringHasNavbar) {
let enteringBackButton = new Animation(enteringView.backBtnRef());
this.add(enteringBackButton);
if (enteringView.enableBack()) {
enteringBackButton.before.addClass(SHOW_BACK_BTN_CSS);
} else {
enteringBackButton.before.removeClass(SHOW_BACK_BTN_CSS);
}
}
// setup leaving view

View File

@@ -1,12 +1,12 @@
{
"name": "ionic2",
"version": "2.0.0-alpha.2",
"name": "ionic-framework",
"version": "2.0.0-alpha.31",
"license": "Apache-2.0",
"repository": {
"type": "git",
"url": "https://github.com/driftyco/ionic2.git"
},
"main": "index.js",
"main": "tooling/index.js",
"scripts": {
"test": "gulp karma",
"test:generators": "jasmine-node ./tooling/spec",
@@ -15,10 +15,13 @@
"dependencies": {
"@reactivex/rxjs": "5.0.0-alpha.4",
"angular2": "2.0.0-alpha.44",
"es6-shim": "^0.33.6",
"lodash": "^3.10.1",
"colors": "^1.1.2",
"es6-shim": "0.33.6",
"inquirer": "0.11.0",
"lodash": "3.10.1",
"q": "1.4.1",
"reflect-metadata": "0.1.1",
"shelljs": "^0.5.3",
"shelljs": "0.5.3",
"zone.js": "0.5.8"
},
"devDependencies": {
@@ -56,7 +59,6 @@
"minimist": "^1.1.3",
"node-html-encoder": "0.0.2",
"node-libs-browser": "^0.5.2",
"q": "^1.4.1",
"request": "2.53.0",
"run-sequence": "^1.1.0",
"semver": "^5.0.1",

View File

@@ -16,6 +16,13 @@
4. Run `gulp watch` in this directory
5. A browser should launch at `http://localhost:3000` at which point you can navigate to `http://localhost:3000/docs/v2/components/`
### Building API Docs
1. `gulp docs` to build the nightly version
2. `gulp docs --doc-version=2.0.0` to build a specific API version
### Running Snapshot
1. Install [Protractor](https://angular.github.io/protractor/#/): `npm install -g protractor`

View File

@@ -30,7 +30,6 @@
-webkit-transition-duration: 0ms !important;
transition-duration: 0ms !important;
}
.snapshot ion-loading-icon,
.snapshot md-ripple {
display: none !important;
}

View File

@@ -1,25 +0,0 @@
# Ionic Framework
### Bundles:
- `css/`
- the Ionic CSS stylesheet
- `fonts/`
- Ionicons and Roboto fonts
- `js/`
- `ionic.js` the Ionic module, in System register format
- `ionic.bundle.js` the Ionic bundle, contains:
- es6-module-loader.js
- system.js
- angular2.dev.js
- router.dev.js (angular2 router)
- ionic.js
- web-animations.min.js
- `web-animations.min.js` web animations API polyfill
### Source files:
- `src/es5` - Ionic ES5 source files in both CommonJS and System module formats
- `src/es6` - Ionic ES6 source files
- `src/ts` - Ionic TypeScript source files (typings still missing)
- `scss` - Ionic Sass source files

View File

@@ -1,22 +0,0 @@
{
"name": "ionic-framework",
"version": "2.0.0-alpha.<%= version %>",
"license": "Apache-2.0",
"repository": {
"type": "git",
"url": "https://github.com/driftyco/ionic2.git"
},
"files": [
"css",
"fonts",
"js",
"src"
],
"dependencies": {
"angular2": "2.0.0-alpha.<%= ngVersion %>",
"es6-shim": "^0.33.6",
"@reactivex/rxjs": "5.0.0-alpha.4",
"reflect-metadata": "0.1.1",
"zone.js": "0.5.8"
}
}

View File

@@ -11,7 +11,7 @@ exports.config = {
specs: 'dist/e2e/**/*e2e.js',
//specs: 'dist/e2e/search-bar/**/*e2e.js',
sleepBetweenSpecs: 250,
sleepBetweenSpecs: 300,
platformDefauls: {
browser: 'chrome',

View File

@@ -11,7 +11,7 @@ Generate.__defineGetter__('generators', function() {
if (!Generate._generators) {
Generate._generators = Generate.loadGenerators();
}
return Generate._generators;
});
@@ -26,21 +26,17 @@ Generate.generate = function generate(options) {
if (!options) {
throw new Error('No options passed to generator');
}
//add optional logger for CLI or other tools
if (options.log) {
Generate.log = options.log;
}
if (options.q) {
Generate.q = options.q;
}
if (!options.generatorName) {
options.generatorName = 'page';
}
var generateOptions = {
var generateOptions = {
appDirectory: options.appDirectory,
cssClassName: Generate.cssClassName(options.name),
fileName: Generate.fileName(options.name),
@@ -112,7 +108,7 @@ Generate.loadGenerator = function loadGenerator(file) {
}
return generateModule;
};
Generate.loadGenerators = function loadGenerators() {
var generators = {};
fs.readdirSync(path.join(__dirname, 'generators'))
@@ -126,7 +122,7 @@ Generate.loadGenerators = function loadGenerators() {
return generators;
};
/*
/*
Will take options to render an html, js, or scss template.
options:
they differ based on what is needed in template

View File

@@ -1,4 +1,8 @@
var fs = require('fs'),
var colors = require('colors'),
fs = require('fs'),
path = require('path'),
inquirer = require('inquirer'),
Q = require('q'),
Generator = module.exports,
Generate = require('../../generate'),
path = require('path'),
@@ -18,7 +22,7 @@ Generator.numberNames = ['first', 'second', 'third', 'fourth', 'fifth'];
Generator.promptForTabCount = function promptForTabCount() {
var q = Q.defer();
Generate.inquirer.prompt({choices: ['1', '2', '3', '4', '5'], message: 'How many tabs will you have?', name: 'count', type: 'list', validate: Generator.validate}, function(result) {
inquirer.prompt({choices: ['1', '2', '3', '4', '5'], message: 'How many tabs will you have?', name: 'count', type: 'list', validate: Generator.validate}, function(result) {
q.resolve(result.count);
});
@@ -28,7 +32,7 @@ Generator.promptForTabCount = function promptForTabCount() {
Generator.promptForTabName = function promptForTabName(tabIndex, options) {
var q = Q.defer();
Generate.inquirer.prompt({message: 'Enter the ' + Generator.numberNames[tabIndex] + ' tab name:', name: 'name', type: 'input'}, function(nameResult) {
inquirer.prompt({message: 'Enter the ' + Generator.numberNames[tabIndex] + ' tab name:', name: 'name', type: 'input'}, function(nameResult) {
Generator.tabs.push({ appDirectory: options.appDirectory, cssClassName: Generate.cssClassName(nameResult.name), fileName: Generate.fileName(nameResult.name), jsClassName: Generate.jsClassName(nameResult.name), name: nameResult.name });
q.resolve();
});
@@ -39,7 +43,6 @@ Generator.promptForTabName = function promptForTabName(tabIndex, options) {
Generator.run = function run(options) {
console.log('got options!', options);
// Generator.q = Q;
//Need to query user for tabs:
options.rootDirectory = options.rootDirectory || path.join('www', 'app');
var savePath = path.join(options.appDirectory, options.rootDirectory, options.fileName);
@@ -59,17 +62,12 @@ Generator.run = function run(options) {
}
return promise;
// .fin(function(result) {
// console.log('All done', result);
// console.log('Using tabs:', Generator.tabs);
// });
})
.then(function() {
.then(function() {
var templates = Generate.loadGeneratorTemplates(__dirname);
//Generate the tabs container page templates
templates.forEach(function(template) {
// var templatePath = path.join(__dirname, template.file);
options.templatePath = template.file;
options.tabs = Generator.tabs;
console.log('generating stuffs', options);
@@ -82,13 +80,10 @@ Generator.run = function run(options) {
//Now render the individual tab pages
Generator.tabs.forEach(function(tab) {
// Generate.createScaffoldDirectories({appDirectory: tab.appDirectory, fileName: tab.fileName});
console.log('Tab:', tab);
tab.generatorName = 'page';
tab.appDirectory = tab.appDirectory;
Generate.generate(tab);
// var pageGenerator = require('../page');
// pageGenerator.run(tab);
});
})
.catch(function(ex) {
@@ -99,10 +94,4 @@ Generator.run = function run(options) {
.fin(function() {
console.log('√ Done'.green);
});
// var tabsData = [];
// tabs.forEach(function(tab) {
// var tabObj = { name: tab, javascriptClassName: Generate.javascriptClassName(tab)};
// tabsData.push(tabObj);
// });
};

3
tooling/index.js Normal file
View File

@@ -0,0 +1,3 @@
module.exports = {
generate: require('./generate').generate
};

View File

@@ -1,5 +1,4 @@
var colors = require('colors'),
fs = require('fs'),
var fs = require('fs'),
path = require('path'),
Generate = require('../generate'),
_ = require('lodash'),
@@ -76,12 +75,12 @@ describe('#Generate', function() {
Generate.generate(generatorOptions);
expect(fs.writeFileSync.calls.length).toBe(3);
});
});
});
xdescribe('#page', function() {
xdescribe('#page', function() {
it('should generate a page at a directory', function() {
//ionic g page about
@@ -149,7 +148,7 @@ describe('#Generate', function() {
});
}); //#page
xdescribe('#directories', function() {
xdescribe('#directories', function() {
it('should create directories for scaffolding', function() {
// pwd = /ionic/app
// ionic g page about