mirror of
https://github.com/ionic-team/ionic-framework.git
synced 2025-08-19 03:32:21 +08:00
Action Menu nice
This commit is contained in:
@ -1,3 +1,11 @@
|
|||||||
|
/**
|
||||||
|
* @ngdoc service
|
||||||
|
* @name ActionMenu
|
||||||
|
* @module ionic
|
||||||
|
* @description
|
||||||
|
* The ActionMenu is a modal menu with options to select based on an action.
|
||||||
|
*/
|
||||||
|
|
||||||
import {NgIf, NgFor, DynamicComponentLoader, ComponentLaoder, ElementRef, ComponentRef, onDestroy, DomRenderer} from 'angular2/angular2';
|
import {NgIf, NgFor, DynamicComponentLoader, ComponentLaoder, ElementRef, ComponentRef, onDestroy, DomRenderer} from 'angular2/angular2';
|
||||||
import {bind, Injector} from 'angular2/di';
|
import {bind, Injector} from 'angular2/di';
|
||||||
import {Promise} from 'angular2/src/facade/async';
|
import {Promise} from 'angular2/src/facade/async';
|
||||||
@ -10,12 +18,153 @@ import {Parent} from 'angular2/src/core/annotations_impl/visibility';
|
|||||||
import {Item, Icon} from 'ionic/ionic'
|
import {Item, Icon} from 'ionic/ionic'
|
||||||
import {Ionic} from 'ionic/components/app/app'
|
import {Ionic} from 'ionic/components/app/app'
|
||||||
import {IonicComponent} from 'ionic/config/component'
|
import {IonicComponent} from 'ionic/config/component'
|
||||||
import {raf, ready} from 'ionic/util/dom'
|
import {raf, rafPromise, ready} from 'ionic/util/dom'
|
||||||
import * as util from 'ionic/util'
|
import * as util from 'ionic/util'
|
||||||
|
|
||||||
import {Animation} from 'ionic/animations/animation';
|
import {Animation} from 'ionic/animations/animation';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'ion-action-menu'
|
||||||
|
})
|
||||||
|
@View({
|
||||||
|
template: `
|
||||||
|
<div class="action-menu-backdrop">
|
||||||
|
<div class="action-menu-wrapper">
|
||||||
|
<div class="action-menu-container">
|
||||||
|
<div class="action-menu-group action-menu-options">
|
||||||
|
<div class="action-menu-title" *ng-if="options.titleText">{{options.titleText}}</div>
|
||||||
|
<button (click)="_buttonClicked(index)" *ng-for="#b of options.buttons; #index = index" class="button action-menu-option">{{b.text}}</button>
|
||||||
|
<button *ng-if="options.destructiveText" (click)="_destructiveButtonClicked()" class="button destructive action-menu-destructive">{{options.destructiveText}}</button>
|
||||||
|
</div>
|
||||||
|
<div class="action-menu-group action-menu-cancel" *ng-if="options.cancelText">
|
||||||
|
<button class="button" (click)="_cancel()">{{options.cancelText}}</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>`,
|
||||||
|
directives: [Item,Icon, NgIf, NgFor]
|
||||||
|
})
|
||||||
|
export class ActionMenu {
|
||||||
|
constructor(elementRef: ElementRef) {
|
||||||
|
this.domElement = elementRef.domElement
|
||||||
|
this.config = ActionMenu.config.invoke(this)
|
||||||
|
|
||||||
|
this.wrapperEl = this.domElement.querySelector('.action-menu-wrapper');
|
||||||
|
|
||||||
|
this.options = {
|
||||||
|
destructiveButtonClicked: util.noop,
|
||||||
|
buttonClicked: util.noop,
|
||||||
|
cancel: util.noop
|
||||||
|
};
|
||||||
|
|
||||||
|
console.log('ActionMenu: Component Created', this.domElement);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Close the ActionMenu.
|
||||||
|
*
|
||||||
|
* @return Promise that resolves when the action menu is closed.
|
||||||
|
*/
|
||||||
|
close() {
|
||||||
|
return new Promise(resolve => {
|
||||||
|
raf(() => {
|
||||||
|
var backdrop = this.domElement.children[0].classList.remove('active');
|
||||||
|
var slideOut = Animation.create(this.wrapperEl, 'action-menu-slide-out');
|
||||||
|
|
||||||
|
slideOut.play().then(() => {
|
||||||
|
this.wrapperEl.classList.remove('action-menu-up');
|
||||||
|
this._clean();
|
||||||
|
resolve();
|
||||||
|
})
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Open the Action Menu
|
||||||
|
*
|
||||||
|
* @return Promise that resolves when the action menu is open.
|
||||||
|
*/
|
||||||
|
open() {
|
||||||
|
return new Promise(resolve => {
|
||||||
|
raf(() => {
|
||||||
|
var backdrop = this.domElement.children[0].classList.add('active');
|
||||||
|
var slideIn = Animation.create(this.wrapperEl, 'action-menu-slide-in');
|
||||||
|
|
||||||
|
slideIn.play().then(() => {
|
||||||
|
this.wrapperEl.classList.add('action-menu-up');
|
||||||
|
resolve();
|
||||||
|
})
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the options (as in show())
|
||||||
|
*
|
||||||
|
* @param opts the options to set
|
||||||
|
*/
|
||||||
|
setOptions(opts) {
|
||||||
|
util.extend(this.options, opts);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create and open a new Action Menu. This is the
|
||||||
|
* public API, and most often you will only use ActionMenu.open()
|
||||||
|
*
|
||||||
|
* @return Promise that resolves when the action menu is open.
|
||||||
|
*/
|
||||||
|
static open(opts) {
|
||||||
|
console.log('Opening menu', opts, Ionic);
|
||||||
|
|
||||||
|
var promise = new Promise(resolve => {
|
||||||
|
ActionMenu._inject().then((ref) => {
|
||||||
|
let actionMenu = ref.instance;
|
||||||
|
actionMenu.ref = ref;
|
||||||
|
actionMenu.setOptions(opts);
|
||||||
|
actionMenu.open();
|
||||||
|
resolve(actionMenu);
|
||||||
|
});
|
||||||
|
})
|
||||||
|
|
||||||
|
return promise;
|
||||||
|
}
|
||||||
|
|
||||||
|
static _inject() {
|
||||||
|
return Ionic.appendToRoot(ActionMenu);
|
||||||
|
}
|
||||||
|
|
||||||
|
_clean() {
|
||||||
|
this.ref.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
_cancel() {
|
||||||
|
this.options.cancel();
|
||||||
|
this.close().then(() => {
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
_destructiveButtonClicked() {
|
||||||
|
let shouldClose = this.options.destructiveButtonClicked();
|
||||||
|
if(shouldClose === true) {
|
||||||
|
return this.close()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_buttonClicked(index) {
|
||||||
|
let shouldClose = this.options.buttonClicked(index);
|
||||||
|
if(shouldClose === true) {
|
||||||
|
return this.close()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
new IonicComponent(ActionMenu, {})
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Animations for action sheet
|
||||||
|
*/
|
||||||
class ActionMenuSlideIn extends Animation {
|
class ActionMenuSlideIn extends Animation {
|
||||||
constructor(element) {
|
constructor(element) {
|
||||||
super(element);
|
super(element);
|
||||||
@ -38,90 +187,4 @@ class ActionMenuSlideOut extends Animation {
|
|||||||
.to('translateY', '100%');
|
.to('translateY', '100%');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Animation.register('action-menu-slide-out', ActionMenuSlideIn);
|
Animation.register('action-menu-slide-out', ActionMenuSlideOut);
|
||||||
|
|
||||||
@Component({
|
|
||||||
selector: 'ion-action-menu'
|
|
||||||
})
|
|
||||||
@View({
|
|
||||||
template: `
|
|
||||||
<div class="action-menu-backdrop">
|
|
||||||
<div class="action-menu-wrapper">
|
|
||||||
<div class="action-menu-container">
|
|
||||||
<div class="action-menu-group action-menu-options">
|
|
||||||
<div class="action-menu-title" *ng-if="titleText">{{titleText}}</div>
|
|
||||||
<button (click)="buttonClicked(index)" *ng-for="#b of buttons; #index = index" class="button action-menu-option">{{b.text}}</button>
|
|
||||||
<button *ng-if="destructiveText" (click)="destructiveButtonClicked()" class="button destructive action-menu-destructive">{{destructiveText}}</button>
|
|
||||||
</div>
|
|
||||||
<div class="action-menu-group action-menu-cancel" *ng-if="cancelText">
|
|
||||||
<button class="button" (click)="cancel()">{{cancelText}}</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>`,
|
|
||||||
directives: [Item,Icon, NgIf, NgFor]
|
|
||||||
})
|
|
||||||
export class ActionMenu {
|
|
||||||
constructor(elementRef: ElementRef) {
|
|
||||||
this.domElement = elementRef.domElement
|
|
||||||
this.config = ActionMenu.config.invoke(this)
|
|
||||||
|
|
||||||
this.wrapperEl = this.domElement.querySelector('.action-menu-wrapper');
|
|
||||||
|
|
||||||
console.log('ActionMenu: Component Created', this.domElement);
|
|
||||||
}
|
|
||||||
|
|
||||||
close() {
|
|
||||||
raf(() => {
|
|
||||||
var backdrop = this.domElement.children[0].classList.remove('active');
|
|
||||||
var slideOut = Animation.create(this.wrapperEl, 'action-menu-slide-out');
|
|
||||||
|
|
||||||
return slideOut.play().then(() => {
|
|
||||||
this.wrapperEl.classList.remove('action-menu-up');
|
|
||||||
})
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
open() {
|
|
||||||
raf(() => {
|
|
||||||
var backdrop = this.domElement.children[0].classList.add('active');
|
|
||||||
var slideIn = Animation.create(this.wrapperEl, 'action-menu-slide-in');
|
|
||||||
|
|
||||||
return slideIn.play().then(() => {
|
|
||||||
this.wrapperEl.classList.add('action-menu-up');
|
|
||||||
})
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
setOptions(opts) {
|
|
||||||
util.extend(this, opts);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Overridden by options
|
|
||||||
destructiveButtonClicked() {}
|
|
||||||
buttonClicked(index) {}
|
|
||||||
cancel() {}
|
|
||||||
|
|
||||||
static open(opts) {
|
|
||||||
console.log('Opening menu', opts, Ionic);
|
|
||||||
|
|
||||||
var promise = new Promise(resolve => {
|
|
||||||
ActionMenu._inject().then((actionMenu) => {
|
|
||||||
actionMenu.setOptions(opts);
|
|
||||||
setTimeout(() => {
|
|
||||||
actionMenu.open();
|
|
||||||
})
|
|
||||||
resolve(actionMenu);
|
|
||||||
});
|
|
||||||
})
|
|
||||||
|
|
||||||
return promise;
|
|
||||||
}
|
|
||||||
|
|
||||||
static _inject() {
|
|
||||||
return Ionic.appendToRoot(ActionMenu);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
new IonicComponent(ActionMenu, {})
|
|
||||||
|
@ -32,8 +32,12 @@ class IonicApp {
|
|||||||
// add cancel code..
|
// add cancel code..
|
||||||
console.log('Canceled');
|
console.log('Canceled');
|
||||||
},
|
},
|
||||||
|
destructiveButtonClicked: () => {
|
||||||
|
console.log('Destructive clicked');
|
||||||
|
},
|
||||||
buttonClicked: function(index) {
|
buttonClicked: function(index) {
|
||||||
console.log('Button clicked', index);
|
console.log('Button clicked', index);
|
||||||
|
if(index == 1) { return false; }
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}).then(actionMenu => {
|
}).then(actionMenu => {
|
||||||
|
@ -22,6 +22,13 @@ class IonicAppRoot {
|
|||||||
return this.rootElementRef;
|
return this.rootElementRef;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create and append the given component into the root
|
||||||
|
* element of the app.
|
||||||
|
*
|
||||||
|
* @param Component the ComponentClass to create and insert
|
||||||
|
* @return Promise that resolves with the ContainerRef created
|
||||||
|
*/
|
||||||
appendToRoot(Component: Type) {
|
appendToRoot(Component: Type) {
|
||||||
var appRef = Ionic.getAppRef();
|
var appRef = Ionic.getAppRef();
|
||||||
var injector = appRef.injector;
|
var injector = appRef.injector;
|
||||||
@ -39,7 +46,7 @@ class IonicAppRoot {
|
|||||||
|
|
||||||
console.log('Injected and created', containerRef);
|
console.log('Injected and created', containerRef);
|
||||||
|
|
||||||
resolve(containerRef.instance, containerRef.location);
|
resolve(containerRef);//containerRef.instance, containerRef.location);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
// Use Angular's promise which doesn't swallow exceptions
|
||||||
|
import {Promise} from 'angular2/src/facade/async';
|
||||||
|
|
||||||
const nativeRaf = window.requestAnimationFrame ||
|
const nativeRaf = window.requestAnimationFrame ||
|
||||||
window.webkitRequestAnimationFrame ||
|
window.webkitRequestAnimationFrame ||
|
||||||
|
Reference in New Issue
Block a user