mirror of
https://github.com/ionic-team/ionic-framework.git
synced 2026-03-13 10:22:08 +08:00
refactor(fab): restructure fab component to separate modules
restructure fab component to separate modules
This commit is contained in:
186
src/components/fab/fab-container.ts
Normal file
186
src/components/fab/fab-container.ts
Normal file
@@ -0,0 +1,186 @@
|
||||
import { Component, ContentChild, ContentChildren, QueryList, ElementRef } from '@angular/core';
|
||||
|
||||
import { Platform } from '../../platform/platform';
|
||||
import { UIEventManager } from '../../gestures/ui-event-manager';
|
||||
import { FabButton } from './fab';
|
||||
import { FabList } from './fab-list';
|
||||
|
||||
/**
|
||||
* @name FabContainer
|
||||
* @module ionic
|
||||
*
|
||||
* @description
|
||||
* `<ion-fab>` is not a FAB button by itself but a container that assist the fab button (`<button ion-fab>`) allowing it
|
||||
* to be placed in fixed position that does not scroll with the content. It is also used to implement "material design speed dial",
|
||||
* ie. a FAB buttons displays a small lists of related actions when clicked.
|
||||
*
|
||||
* @property [top] - Places the container on the top of the content
|
||||
* @property [bottom] - Places the container on the bottom of the content
|
||||
* @property [left] - Places the container on the left
|
||||
* @property [right] - Places the container on the right
|
||||
* @property [middle] - Places the container on the middle vertically
|
||||
* @property [center] - Places the container on the center horizontally
|
||||
* @property [edge] - Used to place the container between the content and the header/footer
|
||||
*
|
||||
* @usage
|
||||
*
|
||||
* ```html
|
||||
* <!-- this fab is placed at top right -->
|
||||
* <ion-content>
|
||||
* <ion-fab top right>
|
||||
* <button ion-fab>Button</button>
|
||||
* </ion-fab>
|
||||
*
|
||||
* <!-- this fab is placed at the center of the content viewport -->
|
||||
* <ion-fab center middle>
|
||||
* <button ion-fab>Button</button>
|
||||
* </ion-fab>
|
||||
* </ion-content>
|
||||
* ```
|
||||
*
|
||||
* Ionic's FAB also supports "material design's fab speed dial". It is a normal fab button
|
||||
* that shows a list of related actions when clicked.
|
||||
*
|
||||
* The same `ion-fab` container can contain several `ion-fab-list` with different side values:
|
||||
* `top`, `bottom`, `left` and `right`. For example, if you want to have a list of button that are
|
||||
* on the top of the main button, you should use `side="top"` and so on. By default, if side is ommited, `side="bottom"`.
|
||||
*
|
||||
* ```html
|
||||
* <ion-content>
|
||||
* <!-- this fab is placed at bottom right -->
|
||||
* <ion-fab bottom right >
|
||||
* <button ion-fab>Share</button>
|
||||
* <ion-fab-list side="top">
|
||||
* <button ion-fab>Facebook</button>
|
||||
* <button ion-fab>Twitter</button>
|
||||
* <button ion-fab>Youtube</button>
|
||||
* </ion-fab-list>
|
||||
* <ion-fab-list side="left">
|
||||
* <button ion-fab>Vimeo</button>
|
||||
* </ion-fab-list>
|
||||
* </ion-fab>
|
||||
* </ion-content>
|
||||
* ```
|
||||
*
|
||||
* A FAB speed dial can also be closed programatically.
|
||||
*
|
||||
* ```html
|
||||
* <ion-content>
|
||||
* <ion-fab bottom right #fab>
|
||||
* <button ion-fab>Share</button>
|
||||
* <ion-fab-list side="top">
|
||||
* <button ion-fab (click)="share('facebook', fab)">Facebook</button>
|
||||
* <button ion-fab (click)="share('twitter', fab)">Twitter</button>
|
||||
* </ion-fab-list>
|
||||
* </ion-fab>
|
||||
* </ion-content>
|
||||
* ```
|
||||
*
|
||||
* ```ts
|
||||
* share(socialNet: string, fab: FabContainer) {
|
||||
* fab.close();
|
||||
* console.log("Sharing in", socialNet);
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* @demo /docs/v2/demos/src/fab/
|
||||
* @see {@link /docs/v2/components#fabs FAB Component Docs}
|
||||
*/
|
||||
@Component({
|
||||
selector: 'ion-fab',
|
||||
template: '<ng-content></ng-content>'
|
||||
})
|
||||
export class FabContainer {
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
_events: UIEventManager;
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
_listsActive: boolean = false;
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
@ContentChild(FabButton) _mainButton: FabButton;
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
@ContentChildren(FabList) _fabLists: QueryList<FabList>;
|
||||
|
||||
constructor(private _elementRef: ElementRef, plt: Platform) {
|
||||
this._events = new UIEventManager(plt);
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
ngAfterContentInit() {
|
||||
const mainButton = this._mainButton;
|
||||
if (!mainButton || !mainButton.getNativeElement()) {
|
||||
console.error('FAB container needs a main <button ion-fab>');
|
||||
return;
|
||||
}
|
||||
this._events.listen(mainButton.getNativeElement(), 'click', this.clickHandler.bind(this), { zone: true });
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
clickHandler(ev: any) {
|
||||
if (this.canActivateList(ev)) {
|
||||
this.toggleList();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
canActivateList(ev: any): boolean {
|
||||
if (this._fabLists.length > 0 && this._mainButton && ev.target) {
|
||||
let ele = ev.target.closest('ion-fab>[ion-fab]');
|
||||
return (ele && ele === this._mainButton.getNativeElement());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
toggleList() {
|
||||
this.setActiveLists(!this._listsActive);
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
setActiveLists(isActive: boolean) {
|
||||
if (isActive === this._listsActive) {
|
||||
return;
|
||||
}
|
||||
let lists = this._fabLists.toArray();
|
||||
for (let list of lists) {
|
||||
list.setVisible(isActive);
|
||||
}
|
||||
this._mainButton.setActiveClose(isActive);
|
||||
this._listsActive = isActive;
|
||||
}
|
||||
|
||||
/**
|
||||
* Close an active FAB list container
|
||||
*/
|
||||
close() {
|
||||
this.setActiveLists(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
ngOnDestroy() {
|
||||
this._events.destroy();
|
||||
}
|
||||
}
|
||||
89
src/components/fab/fab-list.ts
Normal file
89
src/components/fab/fab-list.ts
Normal file
@@ -0,0 +1,89 @@
|
||||
import { ContentChildren, QueryList, Directive, ElementRef, Renderer } from '@angular/core';
|
||||
|
||||
import { Config } from '../../config/config';
|
||||
import { isTrueProperty } from '../../util/util';
|
||||
import { Platform } from '../../platform/platform';
|
||||
|
||||
import { FabButton } from './fab';
|
||||
|
||||
/**
|
||||
* @name FabList
|
||||
* @description
|
||||
* `ion-fab-list` is a container for multiple FAB buttons. They are components of `ion-fab` and allow you to specificy the buttons position, left, right, top, bottom.
|
||||
* @usage
|
||||
*
|
||||
* ```html
|
||||
* <ion-fab bottom right >
|
||||
* <button ion-fab>Share</button>
|
||||
* <ion-fab-list side="top">
|
||||
* <button ion-fab>Facebook</button>
|
||||
* <button ion-fab>Twitter</button>
|
||||
* <button ion-fab>Youtube</button>
|
||||
* </ion-fab-list>
|
||||
* <ion-fab-list side="left">
|
||||
* <button ion-fab>Vimeo</button>
|
||||
* </ion-fab-list>
|
||||
* </ion-fab>
|
||||
* ```
|
||||
* @module ionic
|
||||
*
|
||||
* @demo /docs/v2/demos/src/fab/
|
||||
* @see {@link /docs/v2/components#fab Fab Component Docs}
|
||||
*/
|
||||
@Directive({
|
||||
selector: 'ion-fab-list',
|
||||
})
|
||||
export class FabList {
|
||||
_visible: boolean = false;
|
||||
_fabs: FabButton[] = [];
|
||||
_mode: string;
|
||||
|
||||
constructor(
|
||||
private _elementRef: ElementRef,
|
||||
private _renderer: Renderer,
|
||||
config: Config,
|
||||
private _plt: Platform
|
||||
) {
|
||||
this._mode = config.get('mode');
|
||||
}
|
||||
|
||||
@ContentChildren(FabButton)
|
||||
set _setbuttons(query: QueryList<FabButton>) {
|
||||
const fabs = this._fabs = query.toArray();
|
||||
const className = `fab-${this._mode}-in-list`;
|
||||
for (var fab of fabs) {
|
||||
fab.setElementClass('fab-in-list', true);
|
||||
fab.setElementClass(className, true);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
setVisible(val: boolean) {
|
||||
let visible = isTrueProperty(val);
|
||||
if (visible === this._visible) {
|
||||
return;
|
||||
}
|
||||
this._visible = visible;
|
||||
|
||||
let fabs = this._fabs;
|
||||
let i = 1;
|
||||
if (visible) {
|
||||
fabs.forEach(fab => {
|
||||
this._plt.timeout(() => fab.setElementClass('show', true), i * 30);
|
||||
i++;
|
||||
});
|
||||
} else {
|
||||
fabs.forEach(fab => fab.setElementClass('show', false));
|
||||
}
|
||||
this.setElementClass('fab-list-active', visible);
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
setElementClass(className: string, add: boolean) {
|
||||
this._renderer.setElementClass(this._elementRef.nativeElement, className, add);
|
||||
}
|
||||
}
|
||||
@@ -1,11 +1,7 @@
|
||||
import { Component, ContentChild, Input, ContentChildren, QueryList, ChangeDetectionStrategy, Directive, ElementRef, Renderer, ViewEncapsulation } from '@angular/core';
|
||||
import { Component, Input, ChangeDetectionStrategy, ElementRef, Renderer, ViewEncapsulation } from '@angular/core';
|
||||
|
||||
import { Config } from '../../config/config';
|
||||
import { Ion } from '../ion';
|
||||
import { isTrueProperty } from '../../util/util';
|
||||
import { Platform } from '../../platform/platform';
|
||||
import { UIEventManager } from '../../gestures/ui-event-manager';
|
||||
|
||||
|
||||
/**
|
||||
* @name FabButton
|
||||
@@ -101,266 +97,3 @@ export class FabButton extends Ion {
|
||||
this.setElementClass('fab-close-active', closeVisible);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @name FabList
|
||||
* @description
|
||||
* `ion-fab-list` is a container for multiple FAB buttons. They are components of `ion-fab` and allow you to specificy the buttons position, left, right, top, bottom.
|
||||
* @usage
|
||||
*
|
||||
* ```html
|
||||
* <ion-fab bottom right >
|
||||
* <button ion-fab>Share</button>
|
||||
* <ion-fab-list side="top">
|
||||
* <button ion-fab>Facebook</button>
|
||||
* <button ion-fab>Twitter</button>
|
||||
* <button ion-fab>Youtube</button>
|
||||
* </ion-fab-list>
|
||||
* <ion-fab-list side="left">
|
||||
* <button ion-fab>Vimeo</button>
|
||||
* </ion-fab-list>
|
||||
* </ion-fab>
|
||||
* ```
|
||||
* @module ionic
|
||||
*
|
||||
* @demo /docs/v2/demos/src/fab/
|
||||
* @see {@link /docs/v2/components#fab Fab Component Docs}
|
||||
*/
|
||||
@Directive({
|
||||
selector: 'ion-fab-list',
|
||||
})
|
||||
export class FabList {
|
||||
_visible: boolean = false;
|
||||
_fabs: FabButton[] = [];
|
||||
_mode: string;
|
||||
|
||||
constructor(
|
||||
private _elementRef: ElementRef,
|
||||
private _renderer: Renderer,
|
||||
config: Config,
|
||||
private _plt: Platform
|
||||
) {
|
||||
this._mode = config.get('mode');
|
||||
}
|
||||
|
||||
@ContentChildren(FabButton)
|
||||
set _setbuttons(query: QueryList<FabButton>) {
|
||||
const fabs = this._fabs = query.toArray();
|
||||
const className = `fab-${this._mode}-in-list`;
|
||||
for (var fab of fabs) {
|
||||
fab.setElementClass('fab-in-list', true);
|
||||
fab.setElementClass(className, true);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
setVisible(val: boolean) {
|
||||
let visible = isTrueProperty(val);
|
||||
if (visible === this._visible) {
|
||||
return;
|
||||
}
|
||||
this._visible = visible;
|
||||
|
||||
let fabs = this._fabs;
|
||||
let i = 1;
|
||||
if (visible) {
|
||||
fabs.forEach(fab => {
|
||||
this._plt.timeout(() => fab.setElementClass('show', true), i * 30);
|
||||
i++;
|
||||
});
|
||||
} else {
|
||||
fabs.forEach(fab => fab.setElementClass('show', false));
|
||||
}
|
||||
this.setElementClass('fab-list-active', visible);
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
setElementClass(className: string, add: boolean) {
|
||||
this._renderer.setElementClass(this._elementRef.nativeElement, className, add);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @name FabContainer
|
||||
* @module ionic
|
||||
*
|
||||
* @description
|
||||
* `<ion-fab>` is not a FAB button by itself but a container that assist the fab button (`<button ion-fab>`) allowing it
|
||||
* to be placed in fixed position that does not scroll with the content. It is also used to implement "material design speed dial",
|
||||
* ie. a FAB buttons displays a small lists of related actions when clicked.
|
||||
*
|
||||
* @property [top] - Places the container on the top of the content
|
||||
* @property [bottom] - Places the container on the bottom of the content
|
||||
* @property [left] - Places the container on the left
|
||||
* @property [right] - Places the container on the right
|
||||
* @property [middle] - Places the container on the middle vertically
|
||||
* @property [center] - Places the container on the center horizontally
|
||||
* @property [edge] - Used to place the container between the content and the header/footer
|
||||
*
|
||||
* @usage
|
||||
*
|
||||
* ```html
|
||||
* <!-- this fab is placed at top right -->
|
||||
* <ion-content>
|
||||
* <ion-fab top right>
|
||||
* <button ion-fab>Button</button>
|
||||
* </ion-fab>
|
||||
*
|
||||
* <!-- this fab is placed at the center of the content viewport -->
|
||||
* <ion-fab center middle>
|
||||
* <button ion-fab>Button</button>
|
||||
* </ion-fab>
|
||||
* </ion-content>
|
||||
* ```
|
||||
*
|
||||
* Ionic's FAB also supports "material design's fab speed dial". It is a normal fab button
|
||||
* that shows a list of related actions when clicked.
|
||||
*
|
||||
* The same `ion-fab` container can contain several `ion-fab-list` with different side values:
|
||||
* `top`, `bottom`, `left` and `right`. For example, if you want to have a list of button that are
|
||||
* on the top of the main button, you should use `side="top"` and so on. By default, if side is ommited, `side="bottom"`.
|
||||
*
|
||||
* ```html
|
||||
* <ion-content>
|
||||
* <!-- this fab is placed at bottom right -->
|
||||
* <ion-fab bottom right >
|
||||
* <button ion-fab>Share</button>
|
||||
* <ion-fab-list side="top">
|
||||
* <button ion-fab>Facebook</button>
|
||||
* <button ion-fab>Twitter</button>
|
||||
* <button ion-fab>Youtube</button>
|
||||
* </ion-fab-list>
|
||||
* <ion-fab-list side="left">
|
||||
* <button ion-fab>Vimeo</button>
|
||||
* </ion-fab-list>
|
||||
* </ion-fab>
|
||||
* </ion-content>
|
||||
* ```
|
||||
*
|
||||
* A FAB speed dial can also be closed programatically.
|
||||
*
|
||||
* ```html
|
||||
* <ion-content>
|
||||
* <ion-fab bottom right #fab>
|
||||
* <button ion-fab>Share</button>
|
||||
* <ion-fab-list side="top">
|
||||
* <button ion-fab (click)="share('facebook', fab)">Facebook</button>
|
||||
* <button ion-fab (click)="share('twitter', fab)">Twitter</button>
|
||||
* </ion-fab-list>
|
||||
* </ion-fab>
|
||||
* </ion-content>
|
||||
* ```
|
||||
*
|
||||
* ```ts
|
||||
* share(socialNet: string, fab: FabContainer) {
|
||||
* fab.close();
|
||||
* console.log("Sharing in", socialNet);
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* @demo /docs/v2/demos/src/fab/
|
||||
* @see {@link /docs/v2/components#fabs FAB Component Docs}
|
||||
*/
|
||||
@Component({
|
||||
selector: 'ion-fab',
|
||||
template: '<ng-content></ng-content>'
|
||||
})
|
||||
export class FabContainer {
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
_events: UIEventManager;
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
_listsActive: boolean = false;
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
@ContentChild(FabButton) _mainButton: FabButton;
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
@ContentChildren(FabList) _fabLists: QueryList<FabList>;
|
||||
|
||||
constructor(private _elementRef: ElementRef, plt: Platform) {
|
||||
this._events = new UIEventManager(plt);
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
ngAfterContentInit() {
|
||||
const mainButton = this._mainButton;
|
||||
if (!mainButton || !mainButton.getNativeElement()) {
|
||||
console.error('FAB container needs a main <button ion-fab>');
|
||||
return;
|
||||
}
|
||||
this._events.listen(mainButton.getNativeElement(), 'click', this.clickHandler.bind(this), { zone: true });
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
clickHandler(ev: any) {
|
||||
if (this.canActivateList(ev)) {
|
||||
this.toggleList();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
canActivateList(ev: any): boolean {
|
||||
if (this._fabLists.length > 0 && this._mainButton && ev.target) {
|
||||
let ele = ev.target.closest('ion-fab>[ion-fab]');
|
||||
return (ele && ele === this._mainButton.getNativeElement());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
toggleList() {
|
||||
this.setActiveLists(!this._listsActive);
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
setActiveLists(isActive: boolean) {
|
||||
if (isActive === this._listsActive) {
|
||||
return;
|
||||
}
|
||||
let lists = this._fabLists.toArray();
|
||||
for (let list of lists) {
|
||||
list.setVisible(isActive);
|
||||
}
|
||||
this._mainButton.setActiveClose(isActive);
|
||||
this._listsActive = isActive;
|
||||
}
|
||||
|
||||
/**
|
||||
* Close an active FAB list container
|
||||
*/
|
||||
close() {
|
||||
this.setActiveLists(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
ngOnDestroy() {
|
||||
this._events.destroy();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user