mirror of
https://github.com/ionic-team/ionic-framework.git
synced 2025-08-21 13:01:01 +08:00
feat(toggle): boolean input directive
This commit is contained in:
124
src/bindings/angular/components/boolean-input.ts
Normal file
124
src/bindings/angular/components/boolean-input.ts
Normal file
@ -0,0 +1,124 @@
|
|||||||
|
import { Directive, ElementRef, EventEmitter, HostListener, Input, Output } from '@angular/core';
|
||||||
|
import { NG_VALUE_ACCESSOR } from '@angular/forms';
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @hidden
|
||||||
|
*/
|
||||||
|
@Directive({
|
||||||
|
selector: 'ion-toggle',
|
||||||
|
providers: [{ provide: NG_VALUE_ACCESSOR, useExisting: BooleanInput, multi: true }],
|
||||||
|
})
|
||||||
|
export class BooleanInput {
|
||||||
|
id: string;
|
||||||
|
_labelId: string;
|
||||||
|
_chg: Function;
|
||||||
|
_tch: Function;
|
||||||
|
_dis: Function;
|
||||||
|
|
||||||
|
@Output() ionChange: EventEmitter<any> = new EventEmitter<any>();
|
||||||
|
@Output() ionFocus: EventEmitter<any> = new EventEmitter<any>();
|
||||||
|
@Output() ionBlur: EventEmitter<any> = new EventEmitter<any>();
|
||||||
|
|
||||||
|
|
||||||
|
constructor(public _el: ElementRef) {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @input {boolean} If true, the element is selected.
|
||||||
|
*/
|
||||||
|
@Input()
|
||||||
|
get checked(): boolean {
|
||||||
|
return this._el.nativeElement.checked;
|
||||||
|
}
|
||||||
|
set checked(val: boolean) {
|
||||||
|
this._el.nativeElement.checked = val;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @input {boolean} If true, the user cannot interact with this element.
|
||||||
|
*/
|
||||||
|
@Input()
|
||||||
|
get disabled(): boolean {
|
||||||
|
return this._el.nativeElement.disabled;
|
||||||
|
}
|
||||||
|
set disabled(val: boolean) {
|
||||||
|
this._el.nativeElement.disabled = val;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @input {string}
|
||||||
|
*/
|
||||||
|
@Input()
|
||||||
|
get value(): string {
|
||||||
|
return this._el.nativeElement.value;
|
||||||
|
}
|
||||||
|
set value(val: string) {
|
||||||
|
this._el.nativeElement.value = val;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @hidden
|
||||||
|
*/
|
||||||
|
@HostListener('$ionChange', ['$event'])
|
||||||
|
_onChange(ev: any) {
|
||||||
|
ev.stopPropagation();
|
||||||
|
this._chg && this._chg(ev.detail.checked);
|
||||||
|
this._tch && this._tch();
|
||||||
|
this.ionChange.emit(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @hidden
|
||||||
|
*/
|
||||||
|
@HostListener('$ionFocus', ['$event'])
|
||||||
|
_onFocus(ev: any) {
|
||||||
|
ev.stopPropagation();
|
||||||
|
this.ionFocus.emit(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @hidden
|
||||||
|
*/
|
||||||
|
@HostListener('$ionBlur', ['$event'])
|
||||||
|
_onBlur(ev: any) {
|
||||||
|
ev.stopPropagation();
|
||||||
|
this.ionBlur.emit(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @hidden
|
||||||
|
*/
|
||||||
|
writeValue(val: any) {
|
||||||
|
if (this.checked !== val) {
|
||||||
|
this.checked = val;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @hidden
|
||||||
|
*/
|
||||||
|
registerOnChange(fn: any) {
|
||||||
|
this._chg = fn;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @hidden
|
||||||
|
*/
|
||||||
|
registerOnTouched(fn: any) {
|
||||||
|
this._tch = fn;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @hidden
|
||||||
|
*/
|
||||||
|
registerOnDisabledChange(fn: any) {
|
||||||
|
this._dis = fn;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @hidden
|
||||||
|
*/
|
||||||
|
setDisabledState(isDisabled: boolean) {
|
||||||
|
this.disabled = isDisabled;
|
||||||
|
}
|
||||||
|
}
|
@ -1,7 +1,7 @@
|
|||||||
import { Config } from '../config/config';
|
import { Config } from '../../../config/config';
|
||||||
import { DomController } from '../platform/dom-controller';
|
import { DomController } from '../../../platform/dom-controller';
|
||||||
import { NgZone } from '@angular/core';
|
import { NgZone } from '@angular/core';
|
||||||
import { Platform } from '../platform/platform';
|
import { Platform } from '../../../platform/platform';
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -27,6 +27,9 @@ export function setupCore(config: Config, plt: Platform, domCtrl: DomController,
|
|||||||
// keep core and angular dom reads/writes *nsync
|
// keep core and angular dom reads/writes *nsync
|
||||||
ionic['domCtrl'] = domCtrl;
|
ionic['domCtrl'] = domCtrl;
|
||||||
|
|
||||||
|
// keep core and angular dom reads/writes *nsync
|
||||||
|
ionic['eventNamePrefix'] = '$';
|
||||||
|
|
||||||
// next tick controller created here so that it can
|
// next tick controller created here so that it can
|
||||||
// be created to run outside of angular
|
// be created to run outside of angular
|
||||||
ionic['nextTickCtrl'] = getNextTickController(zone, plt.userAgent().toLowerCase());
|
ionic['nextTickCtrl'] = getNextTickController(zone, plt.userAgent().toLowerCase());
|
@ -15,7 +15,7 @@ ion-badge,
|
|||||||
:host {
|
:host {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
visibility: inherit !important;
|
visibility: inherit !important;
|
||||||
contain: layout content;
|
contain: content;
|
||||||
}
|
}
|
||||||
|
|
||||||
.badge {
|
.badge {
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { Component } from '../../util/decorators';
|
import { Component } from '../../index';
|
||||||
|
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
|
3
src/components/card/card-content.ios.scss
Normal file
3
src/components/card/card-content.ios.scss
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
@import "../../themes/ionic.globals";
|
||||||
|
@import "./card-content";
|
||||||
|
|
3
src/components/card/card-content.md.scss
Normal file
3
src/components/card/card-content.md.scss
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
@import "../../themes/ionic.globals";
|
||||||
|
@import "./card-content";
|
||||||
|
|
9
src/components/card/card-content.scss
Normal file
9
src/components/card/card-content.scss
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
@import "../../themes/ionic.globals";
|
||||||
|
|
||||||
|
// Card
|
||||||
|
// --------------------------------------------------
|
||||||
|
|
||||||
|
ion-card-content,
|
||||||
|
:host {
|
||||||
|
display: block;
|
||||||
|
}
|
@ -1,17 +1,12 @@
|
|||||||
import { Directive, ElementRef, Renderer } from '@angular/core';
|
import { Component } from '../../index';
|
||||||
|
|
||||||
import { Config } from '../../config/config';
|
|
||||||
import { Ion } from '../ion';
|
|
||||||
|
|
||||||
/**
|
@Component({
|
||||||
* @hidden
|
tag: 'ion-card-content',
|
||||||
*/
|
styleUrls: {
|
||||||
@Directive({
|
ios: 'card-content.ios.scss',
|
||||||
selector: 'ion-card-content'
|
md: 'card-content.md.scss',
|
||||||
})
|
wp: 'card-content.wp.scss'
|
||||||
export class CardContent extends Ion {
|
|
||||||
|
|
||||||
constructor(config: Config, elementRef: ElementRef, renderer: Renderer) {
|
|
||||||
super(config, elementRef, renderer, 'card-content');
|
|
||||||
}
|
}
|
||||||
}
|
})
|
||||||
|
export class CardContent {}
|
||||||
|
3
src/components/card/card-content.wp.scss
Normal file
3
src/components/card/card-content.wp.scss
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
@import "../../themes/ionic.globals";
|
||||||
|
@import "./card-content";
|
||||||
|
|
2
src/components/card/card-header.ios.scss
Normal file
2
src/components/card/card-header.ios.scss
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
@import "../../themes/ionic.globals";
|
||||||
|
@import "./card-header";
|
2
src/components/card/card-header.md.scss
Normal file
2
src/components/card/card-header.md.scss
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
@import "../../themes/ionic.globals";
|
||||||
|
@import "./card-header";
|
14
src/components/card/card-header.scss
Normal file
14
src/components/card/card-header.scss
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
@import "../../themes/ionic.globals";
|
||||||
|
|
||||||
|
// Card Header
|
||||||
|
// --------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
ion-card-header,
|
||||||
|
:host {
|
||||||
|
display: block;
|
||||||
|
overflow: hidden;
|
||||||
|
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
@ -1,17 +1,12 @@
|
|||||||
import { Directive, ElementRef, Renderer } from '@angular/core';
|
import { Component } from '../../index';
|
||||||
|
|
||||||
import { Config } from '../../config/config';
|
|
||||||
import { Ion } from '../ion';
|
|
||||||
|
|
||||||
/**
|
@Component({
|
||||||
* @hidden
|
tag: 'ion-card-header',
|
||||||
*/
|
styleUrls: {
|
||||||
@Directive({
|
ios: 'card-header.ios.scss',
|
||||||
selector: 'ion-card-header'
|
md: 'card-header.md.scss',
|
||||||
})
|
wp: 'card-header.wp.scss'
|
||||||
export class CardHeader extends Ion {
|
|
||||||
|
|
||||||
constructor(config: Config, elementRef: ElementRef, renderer: Renderer) {
|
|
||||||
super(config, elementRef, renderer, 'card-header');
|
|
||||||
}
|
}
|
||||||
}
|
})
|
||||||
|
export class CardHeader {}
|
||||||
|
2
src/components/card/card-header.wp.scss
Normal file
2
src/components/card/card-header.wp.scss
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
@import "../../themes/ionic.globals";
|
||||||
|
@import "./card-header";
|
@ -1,17 +1,12 @@
|
|||||||
import { Directive, ElementRef, Renderer } from '@angular/core';
|
import { Component } from '../../index';
|
||||||
|
|
||||||
import { Config } from '../../config/config';
|
|
||||||
import { Ion } from '../ion';
|
|
||||||
|
|
||||||
/**
|
@Component({
|
||||||
* @hidden
|
tag: 'ion-card-title',
|
||||||
*/
|
styleUrls: {
|
||||||
@Directive({
|
ios: 'card.ios.scss',
|
||||||
selector: 'ion-card-title'
|
md: 'card.md.scss',
|
||||||
})
|
wp: 'card.wp.scss'
|
||||||
export class CardTitle extends Ion {
|
|
||||||
|
|
||||||
constructor(config: Config, elementRef: ElementRef, renderer: Renderer) {
|
|
||||||
super(config, elementRef, renderer, 'card-title');
|
|
||||||
}
|
}
|
||||||
}
|
})
|
||||||
|
export class CardTitle {}
|
||||||
|
@ -4,25 +4,15 @@
|
|||||||
// --------------------------------------------------
|
// --------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
ion-card {
|
ion-card,
|
||||||
|
:host {
|
||||||
display: block;
|
display: block;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
ion-card img {
|
ion-card img,
|
||||||
|
:host img {
|
||||||
display: block;
|
display: block;
|
||||||
|
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
ion-card-header {
|
|
||||||
display: block;
|
|
||||||
overflow: hidden;
|
|
||||||
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
white-space: nowrap;
|
|
||||||
}
|
|
||||||
|
|
||||||
ion-card-content {
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
|
@ -1,18 +1,12 @@
|
|||||||
import { Directive, ElementRef, Renderer } from '@angular/core';
|
import { Component } from '../../index';
|
||||||
|
|
||||||
import { Config } from '../../config/config';
|
|
||||||
import { Ion } from '../ion';
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
@Component({
|
||||||
* @hidden
|
tag: 'ion-card',
|
||||||
*/
|
styleUrls: {
|
||||||
@Directive({
|
ios: 'card.ios.scss',
|
||||||
selector: 'ion-card'
|
md: 'card.md.scss',
|
||||||
})
|
wp: 'card.wp.scss'
|
||||||
export class Card extends Ion {
|
|
||||||
|
|
||||||
constructor(config: Config, elementRef: ElementRef, renderer: Renderer) {
|
|
||||||
super(config, elementRef, renderer, 'card');
|
|
||||||
}
|
}
|
||||||
}
|
})
|
||||||
|
export class Card {}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { NgModule } from '@angular/core';
|
import { NgModule, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
|
||||||
import { IonicPageModule } from '../../../../../..';
|
import { IonicPageModule } from '../../../../../..';
|
||||||
|
|
||||||
import { RootPage } from './root-page';
|
import { RootPage } from './root-page';
|
||||||
@ -9,6 +9,9 @@ import { RootPage } from './root-page';
|
|||||||
],
|
],
|
||||||
imports: [
|
imports: [
|
||||||
IonicPageModule.forChild(RootPage)
|
IonicPageModule.forChild(RootPage)
|
||||||
|
],
|
||||||
|
schemas: [
|
||||||
|
CUSTOM_ELEMENTS_SCHEMA
|
||||||
]
|
]
|
||||||
})
|
})
|
||||||
export class RootPageModule {}
|
export class RootPageModule {}
|
||||||
|
173
src/components/gesture/gesture-controller.ts
Normal file
173
src/components/gesture/gesture-controller.ts
Normal file
@ -0,0 +1,173 @@
|
|||||||
|
|
||||||
|
|
||||||
|
export class GestureController {
|
||||||
|
private id: number = 0;
|
||||||
|
private requestedStart: { [eventId: number]: number } = {};
|
||||||
|
private disabledGestures: { [eventName: string]: Set<number> } = {};
|
||||||
|
private disabledScroll: Set<number> = new Set<number>();
|
||||||
|
private capturedID: number = null;
|
||||||
|
|
||||||
|
|
||||||
|
createGesture(gestureName: string, gesturePriority: number, disableScroll: boolean): GestureDelegate {
|
||||||
|
return new GestureDelegate(this, ++this.id, gestureName, gesturePriority, disableScroll);
|
||||||
|
}
|
||||||
|
|
||||||
|
start(gestureName: string, id: number, priority: number): boolean {
|
||||||
|
if (!this.canStart(gestureName)) {
|
||||||
|
delete this.requestedStart[id];
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.requestedStart[id] = priority;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
capture(gestureName: string, id: number, priority: number): boolean {
|
||||||
|
if (!this.start(gestureName, id, priority)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
let requestedStart = this.requestedStart;
|
||||||
|
let maxPriority = -10000;
|
||||||
|
for (let gestureID in requestedStart) {
|
||||||
|
maxPriority = Math.max(maxPriority, requestedStart[gestureID]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (maxPriority === priority) {
|
||||||
|
this.capturedID = id;
|
||||||
|
this.requestedStart = {};
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
delete requestedStart[id];
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
release(id: number) {
|
||||||
|
delete this.requestedStart[id];
|
||||||
|
|
||||||
|
if (this.capturedID && id === this.capturedID) {
|
||||||
|
this.capturedID = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
disableGesture(gestureName: string, id: number) {
|
||||||
|
let set = this.disabledGestures[gestureName];
|
||||||
|
if (!set) {
|
||||||
|
set = new Set<number>();
|
||||||
|
this.disabledGestures[gestureName] = set;
|
||||||
|
}
|
||||||
|
set.add(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
enableGesture(gestureName: string, id: number) {
|
||||||
|
let set = this.disabledGestures[gestureName];
|
||||||
|
if (set) {
|
||||||
|
set.delete(id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
disableScroll(id: number) {
|
||||||
|
// let isEnabled = !this.isScrollDisabled();
|
||||||
|
this.disabledScroll.add(id);
|
||||||
|
// if (this._app && isEnabled && this.isScrollDisabled()) {
|
||||||
|
// console.debug('GestureController: Disabling scrolling');
|
||||||
|
// this._app._setDisableScroll(true);
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
enableScroll(id: number) {
|
||||||
|
// let isDisabled = this.isScrollDisabled();
|
||||||
|
this.disabledScroll.delete(id);
|
||||||
|
// if (this._app && isDisabled && !this.isScrollDisabled()) {
|
||||||
|
// console.debug('GestureController: Enabling scrolling');
|
||||||
|
// this._app._setDisableScroll(false);
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
canStart(gestureName: string): boolean {
|
||||||
|
if (this.capturedID) {
|
||||||
|
// a gesture already captured
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.isDisabled(gestureName)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
isCaptured(): boolean {
|
||||||
|
return !!this.capturedID;
|
||||||
|
}
|
||||||
|
|
||||||
|
isScrollDisabled(): boolean {
|
||||||
|
return this.disabledScroll.size > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
isDisabled(gestureName: string): boolean {
|
||||||
|
let disabled = this.disabledGestures[gestureName];
|
||||||
|
if (disabled && disabled.size > 0) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export class GestureDelegate {
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private ctrl: GestureController,
|
||||||
|
private id: number,
|
||||||
|
private name: string,
|
||||||
|
private priority: number,
|
||||||
|
private disableScroll: boolean
|
||||||
|
) { }
|
||||||
|
|
||||||
|
canStart(): boolean {
|
||||||
|
if (!this.ctrl) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.ctrl.canStart(this.name);
|
||||||
|
}
|
||||||
|
|
||||||
|
start(): boolean {
|
||||||
|
if (!this.ctrl) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.ctrl.start(this.name, this.id, this.priority);
|
||||||
|
}
|
||||||
|
|
||||||
|
capture(): boolean {
|
||||||
|
if (!this.ctrl) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
let captured = this.ctrl.capture(this.name, this.id, this.priority);
|
||||||
|
if (captured && this.disableScroll) {
|
||||||
|
this.ctrl.disableScroll(this.id);
|
||||||
|
}
|
||||||
|
|
||||||
|
return captured;
|
||||||
|
}
|
||||||
|
|
||||||
|
release() {
|
||||||
|
if (this.ctrl) {
|
||||||
|
this.ctrl.release(this.id);
|
||||||
|
|
||||||
|
if (this.disableScroll) {
|
||||||
|
this.ctrl.enableScroll(this.id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
destroy() {
|
||||||
|
this.release();
|
||||||
|
this.ctrl = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
365
src/components/gesture/gesture.ts
Normal file
365
src/components/gesture/gesture.ts
Normal file
@ -0,0 +1,365 @@
|
|||||||
|
import { applyStyles, getElementReference, pointerCoordX, pointerCoordY } from '../../util/dom';
|
||||||
|
import { Component, Listen, Ionic, Prop } from '../../index';
|
||||||
|
import { GestureCallback, GestureDetail } from '../../util/interfaces';
|
||||||
|
import { GestureController, GestureDelegate } from './gesture-controller';
|
||||||
|
import { PanRecognizer } from './recognizers';
|
||||||
|
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
tag: 'ion-gesture',
|
||||||
|
shadow: false
|
||||||
|
})
|
||||||
|
export class Gesture {
|
||||||
|
private $el: HTMLElement;
|
||||||
|
private detail: GestureDetail = {};
|
||||||
|
private positions: number[] = [];
|
||||||
|
private gesture: GestureDelegate;
|
||||||
|
private lastTouch = 0;
|
||||||
|
private pan: PanRecognizer;
|
||||||
|
private hasCapturedPan = false;
|
||||||
|
private hasPress = false;
|
||||||
|
private hasStartedPan = false;
|
||||||
|
private requiresMove = false;
|
||||||
|
|
||||||
|
@Prop() direction: string = 'x';
|
||||||
|
@Prop() gestureName: string = '';
|
||||||
|
@Prop() gesturePriority: number = 0;
|
||||||
|
@Prop() listenOn: string = 'child';
|
||||||
|
@Prop() maxAngle: number = 40;
|
||||||
|
@Prop() threshold: number = 20;
|
||||||
|
@Prop() type: string = 'pan';
|
||||||
|
|
||||||
|
@Prop() canStart: GestureCallback;
|
||||||
|
@Prop() onStart: GestureCallback;
|
||||||
|
@Prop() onMove: GestureCallback;
|
||||||
|
@Prop() onEnd: GestureCallback;
|
||||||
|
@Prop() onPress: GestureCallback;
|
||||||
|
@Prop() notCaptured: GestureCallback;
|
||||||
|
|
||||||
|
|
||||||
|
ionViewDidLoad() {
|
||||||
|
Ionic.controllers.gesture = (Ionic.controllers.gesture || new GestureController());
|
||||||
|
|
||||||
|
this.gesture = (<GestureController>Ionic.controllers.gesture).createGesture(this.gestureName, this.gesturePriority, false);
|
||||||
|
|
||||||
|
const types = this.type.replace(/\s/g, '').toLowerCase().split(',');
|
||||||
|
|
||||||
|
if (types.indexOf('pan') > -1) {
|
||||||
|
this.pan = new PanRecognizer(this.direction, this.threshold, this.maxAngle);
|
||||||
|
this.requiresMove = true;
|
||||||
|
}
|
||||||
|
this.hasPress = (types.indexOf('press') > -1);
|
||||||
|
|
||||||
|
if (this.pan || this.hasPress) {
|
||||||
|
Ionic.listener.enable(this, 'touchstart', true, this.listenOn);
|
||||||
|
Ionic.listener.enable(this, 'mousedown', true, this.listenOn);
|
||||||
|
|
||||||
|
Ionic.dom.write(() => {
|
||||||
|
applyStyles(getElementReference(this.$el, this.listenOn), GESTURE_INLINE_STYLES);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// DOWN *************************
|
||||||
|
|
||||||
|
@Listen('touchstart', { passive: true, enabled: false })
|
||||||
|
onTouchStart(ev: TouchEvent) {
|
||||||
|
this.lastTouch = now(ev);
|
||||||
|
|
||||||
|
this.enableMouse(false);
|
||||||
|
this.enableTouch(true);
|
||||||
|
|
||||||
|
this.pointerDown(ev, this.lastTouch);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Listen('mousedown', { passive: true, enabled: false })
|
||||||
|
onMouseDown(ev: MouseEvent) {
|
||||||
|
const timeStamp = now(ev);
|
||||||
|
|
||||||
|
if (this.lastTouch === 0 || (this.lastTouch + MOUSE_WAIT < timeStamp)) {
|
||||||
|
this.enableMouse(true);
|
||||||
|
this.enableTouch(false);
|
||||||
|
|
||||||
|
this.pointerDown(ev, timeStamp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private pointerDown(ev: UIEvent, timeStamp: number): boolean {
|
||||||
|
if (!this.gesture || this.hasStartedPan) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const detail = this.detail;
|
||||||
|
|
||||||
|
detail.startX = detail.currentX = pointerCoordX(ev);
|
||||||
|
detail.startY = detail.currentY = pointerCoordY(ev);
|
||||||
|
detail.startTimeStamp = detail.timeStamp = timeStamp;
|
||||||
|
detail.velocityX = detail.velocityY = detail.deltaX = detail.deltaY = 0;
|
||||||
|
detail.directionX = detail.directionY = detail.velocityDirectionX = detail.velocityDirectionY = null;
|
||||||
|
detail.event = ev;
|
||||||
|
this.positions.length = 0;
|
||||||
|
|
||||||
|
if (this.canStart && this.canStart(detail) === false) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.positions.push(detail.currentX, detail.currentY, timeStamp);
|
||||||
|
|
||||||
|
// Release fallback
|
||||||
|
this.gesture.release();
|
||||||
|
|
||||||
|
// Start gesture
|
||||||
|
if (!this.gesture.start()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.pan) {
|
||||||
|
this.hasStartedPan = true;
|
||||||
|
this.hasCapturedPan = false;
|
||||||
|
|
||||||
|
this.pan.start(detail.startX, detail.startY);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// MOVE *************************
|
||||||
|
|
||||||
|
@Listen('touchmove', { passive: true, enabled: false })
|
||||||
|
onTouchMove(ev: TouchEvent) {
|
||||||
|
this.lastTouch = this.detail.timeStamp = now(ev);
|
||||||
|
|
||||||
|
this.pointerMove(ev);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Listen('document:mousemove', { passive: true, enabled: false })
|
||||||
|
onMoveMove(ev: TouchEvent) {
|
||||||
|
const timeStamp = now(ev);
|
||||||
|
|
||||||
|
if (this.lastTouch === 0 || (this.lastTouch + MOUSE_WAIT < timeStamp)) {
|
||||||
|
this.detail.timeStamp = timeStamp;
|
||||||
|
this.pointerMove(ev);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private pointerMove(ev: UIEvent) {
|
||||||
|
const detail = this.detail;
|
||||||
|
this.calcGestureData(ev);
|
||||||
|
|
||||||
|
if (this.pan) {
|
||||||
|
if (this.hasCapturedPan) {
|
||||||
|
Ionic.dom.write(() => {
|
||||||
|
detail.type = 'pan';
|
||||||
|
|
||||||
|
if (this.onMove) {
|
||||||
|
this.onMove(detail);
|
||||||
|
} else {
|
||||||
|
Ionic.emit(this, 'ionGestureMove', this.detail);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
} else if (this.pan.detect(detail.currentX, detail.currentY)) {
|
||||||
|
if (this.pan.isGesture() !== 0) {
|
||||||
|
if (!this.tryToCapturePan(ev)) {
|
||||||
|
this.abortGesture();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private calcGestureData(ev: UIEvent) {
|
||||||
|
const detail = this.detail;
|
||||||
|
detail.currentX = pointerCoordX(ev);
|
||||||
|
detail.currentY = pointerCoordY(ev);
|
||||||
|
detail.deltaX = (detail.currentX - detail.startX);
|
||||||
|
detail.deltaY = (detail.currentY - detail.startY);
|
||||||
|
detail.event = ev;
|
||||||
|
|
||||||
|
// figure out which direction we're movin'
|
||||||
|
detail.directionX = detail.velocityDirectionX = (detail.deltaX > 0 ? 'left' : (detail.deltaX < 0 ? 'right' : null));
|
||||||
|
detail.directionY = detail.velocityDirectionY = (detail.deltaY > 0 ? 'up' : (detail.deltaY < 0 ? 'down' : null));
|
||||||
|
|
||||||
|
const positions = this.positions;
|
||||||
|
positions.push(detail.currentX, detail.currentY, detail.timeStamp);
|
||||||
|
|
||||||
|
var endPos = (positions.length - 1);
|
||||||
|
var startPos = endPos;
|
||||||
|
var timeRange = (detail.timeStamp - 100);
|
||||||
|
|
||||||
|
// move pointer to position measured 100ms ago
|
||||||
|
for (var i = endPos; i > 0 && positions[i] > timeRange; i -= 3) {
|
||||||
|
startPos = i;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (startPos !== endPos) {
|
||||||
|
// compute relative movement between these two points
|
||||||
|
var movedX = (positions[startPos - 2] - positions[endPos - 2]);
|
||||||
|
var movedY = (positions[startPos - 1] - positions[endPos - 1]);
|
||||||
|
var factor = 16 / (positions[endPos] - positions[startPos]);
|
||||||
|
|
||||||
|
// based on XXms compute the movement to apply for each render step
|
||||||
|
detail.velocityX = movedX * factor;
|
||||||
|
detail.velocityY = movedY * factor;
|
||||||
|
|
||||||
|
detail.velocityDirectionX = (detail.velocityX > 0 ? 'left' : (detail.velocityX < 0 ? 'right' : null));
|
||||||
|
detail.velocityDirectionY = (detail.velocityY > 0 ? 'up' : (detail.velocityY < 0 ? 'down' : null));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private tryToCapturePan(ev: UIEvent): boolean {
|
||||||
|
if (this.gesture && !this.gesture.capture()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.detail.event = ev;
|
||||||
|
|
||||||
|
if (this.onStart) {
|
||||||
|
this.onStart(this.detail);
|
||||||
|
} else {
|
||||||
|
Ionic.emit(this, 'ionGestureStart', this.detail);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.hasCapturedPan = true;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private abortGesture() {
|
||||||
|
this.hasStartedPan = false;
|
||||||
|
this.hasCapturedPan = false;
|
||||||
|
|
||||||
|
this.gesture.release();
|
||||||
|
|
||||||
|
this.enable(false);
|
||||||
|
this.notCaptured(this.detail);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// END *************************
|
||||||
|
|
||||||
|
@Listen('touchend', { passive: true, enabled: false })
|
||||||
|
onTouchEnd(ev: TouchEvent) {
|
||||||
|
this.lastTouch = this.detail.timeStamp = now(ev);
|
||||||
|
|
||||||
|
this.pointerUp(ev);
|
||||||
|
this.enableTouch(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Listen('document:mouseup', { passive: true, enabled: false })
|
||||||
|
onMouseUp(ev: TouchEvent) {
|
||||||
|
const timeStamp = now(ev);
|
||||||
|
|
||||||
|
if (this.lastTouch === 0 || (this.lastTouch + MOUSE_WAIT < timeStamp)) {
|
||||||
|
this.detail.timeStamp = timeStamp;
|
||||||
|
this.pointerUp(ev);
|
||||||
|
this.enableMouse(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private pointerUp(ev: UIEvent) {
|
||||||
|
const detail = this.detail;
|
||||||
|
|
||||||
|
this.gesture && this.gesture.release();
|
||||||
|
|
||||||
|
detail.event = ev;
|
||||||
|
|
||||||
|
this.calcGestureData(ev);
|
||||||
|
|
||||||
|
if (this.pan) {
|
||||||
|
if (this.hasCapturedPan) {
|
||||||
|
detail.type = 'pan';
|
||||||
|
if (this.onEnd) {
|
||||||
|
this.onEnd(detail);
|
||||||
|
} else {
|
||||||
|
Ionic.emit(this, 'ionGestureEnd', detail);
|
||||||
|
}
|
||||||
|
|
||||||
|
} else if (this.hasPress) {
|
||||||
|
this.detectPress();
|
||||||
|
|
||||||
|
} else {
|
||||||
|
if (this.notCaptured) {
|
||||||
|
this.notCaptured(detail);
|
||||||
|
} else {
|
||||||
|
Ionic.emit(this, 'ionGestureNotCaptured', detail);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} else if (this.hasPress) {
|
||||||
|
this.detectPress();
|
||||||
|
}
|
||||||
|
|
||||||
|
this.hasCapturedPan = false;
|
||||||
|
this.hasStartedPan = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private detectPress() {
|
||||||
|
const detail = this.detail;
|
||||||
|
|
||||||
|
if (Math.abs(detail.startX - detail.currentX) < 10 && Math.abs(detail.startY - detail.currentY) < 10) {
|
||||||
|
detail.type = 'press';
|
||||||
|
|
||||||
|
if (this.onPress) {
|
||||||
|
this.onPress(detail);
|
||||||
|
} else {
|
||||||
|
Ionic.emit(this, 'ionPress', detail);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// ENABLE LISTENERS *************************
|
||||||
|
|
||||||
|
private enableMouse(shouldEnable: boolean) {
|
||||||
|
if (this.requiresMove) {
|
||||||
|
Ionic.listener.enable(this, 'document:mousemove', shouldEnable);
|
||||||
|
}
|
||||||
|
Ionic.listener.enable(this, 'document:mouseup', shouldEnable);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private enableTouch(shouldEnable: boolean) {
|
||||||
|
if (this.requiresMove) {
|
||||||
|
Ionic.listener.enable(this, 'touchmove', shouldEnable);
|
||||||
|
}
|
||||||
|
Ionic.listener.enable(this, 'touchend', shouldEnable);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private enable(shouldEnable: boolean) {
|
||||||
|
this.enableMouse(shouldEnable);
|
||||||
|
this.enableTouch(shouldEnable);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
ionViewWillUnload() {
|
||||||
|
this.gesture && this.gesture.destroy();
|
||||||
|
this.gesture = this.pan = this.detail = this.detail.event = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const GESTURE_INLINE_STYLES = {
|
||||||
|
'touch-action': 'none',
|
||||||
|
'user-select': 'none',
|
||||||
|
'-webkit-user-drag': 'none',
|
||||||
|
'-webkit-tap-highlight-color': 'rgba(0,0,0,0)'
|
||||||
|
};
|
||||||
|
|
||||||
|
const MOUSE_WAIT = 2500;
|
||||||
|
|
||||||
|
|
||||||
|
function now(ev: UIEvent) {
|
||||||
|
return ev.timeStamp || Date.now();
|
||||||
|
}
|
||||||
|
|
66
src/components/gesture/recognizers.ts
Normal file
66
src/components/gesture/recognizers.ts
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
|
||||||
|
|
||||||
|
export class PanRecognizer {
|
||||||
|
private startX: number;
|
||||||
|
private startY: number;
|
||||||
|
|
||||||
|
private dirty: boolean = false;
|
||||||
|
private threshold: number;
|
||||||
|
private maxCosine: number;
|
||||||
|
|
||||||
|
private angle = 0;
|
||||||
|
private isPan = 0;
|
||||||
|
|
||||||
|
|
||||||
|
constructor(private direction: string, threshold: number, maxAngle: number) {
|
||||||
|
const radians = maxAngle * (Math.PI / 180);
|
||||||
|
this.maxCosine = Math.cos(radians);
|
||||||
|
this.threshold = threshold * threshold;
|
||||||
|
}
|
||||||
|
|
||||||
|
start(x: number, y: number) {
|
||||||
|
this.startX = x;
|
||||||
|
this.startY = y;
|
||||||
|
this.angle = 0;
|
||||||
|
this.isPan = 0;
|
||||||
|
this.dirty = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
detect(x: number, y: number): boolean {
|
||||||
|
if (!this.dirty) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const deltaX = (x - this.startX);
|
||||||
|
const deltaY = (y - this.startY);
|
||||||
|
const distance = deltaX * deltaX + deltaY * deltaY;
|
||||||
|
|
||||||
|
if (distance >= this.threshold) {
|
||||||
|
var angle = Math.atan2(deltaY, deltaX);
|
||||||
|
var cosine = (this.direction === 'y')
|
||||||
|
? Math.sin(angle)
|
||||||
|
: Math.cos(angle);
|
||||||
|
|
||||||
|
this.angle = angle;
|
||||||
|
|
||||||
|
if (cosine > this.maxCosine) {
|
||||||
|
this.isPan = 1;
|
||||||
|
|
||||||
|
} else if (cosine < -this.maxCosine) {
|
||||||
|
this.isPan = -1;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
this.isPan = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.dirty = false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
isGesture(): number {
|
||||||
|
return this.isPan;
|
||||||
|
}
|
||||||
|
}
|
@ -1,37 +0,0 @@
|
|||||||
import { CommonModule } from '@angular/common';
|
|
||||||
import { NgModule, ModuleWithProviders, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
|
|
||||||
|
|
||||||
import { IconModule } from '../icon/icon.module';
|
|
||||||
|
|
||||||
import { Tab } from './tab';
|
|
||||||
import { TabButton } from './tab-button';
|
|
||||||
import { TabHighlight } from './tab-highlight';
|
|
||||||
import { Tabs } from './tabs';
|
|
||||||
|
|
||||||
/** @hidden */
|
|
||||||
@NgModule({
|
|
||||||
imports: [
|
|
||||||
CommonModule,
|
|
||||||
IconModule
|
|
||||||
],
|
|
||||||
declarations: [
|
|
||||||
Tab,
|
|
||||||
TabButton,
|
|
||||||
TabHighlight,
|
|
||||||
Tabs
|
|
||||||
],
|
|
||||||
exports: [
|
|
||||||
Tab,
|
|
||||||
TabButton,
|
|
||||||
TabHighlight,
|
|
||||||
Tabs
|
|
||||||
],
|
|
||||||
schemas: [CUSTOM_ELEMENTS_SCHEMA]
|
|
||||||
})
|
|
||||||
export class TabsModule {
|
|
||||||
public static forRoot(): ModuleWithProviders {
|
|
||||||
return {
|
|
||||||
ngModule: TabsModule, providers: []
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,7 +1,6 @@
|
|||||||
import { Component } from '@angular/core';
|
import { Component } from '@angular/core';
|
||||||
import { FormControl, FormGroup } from '@angular/forms';
|
import { FormControl, FormGroup } from '@angular/forms';
|
||||||
|
|
||||||
import { Toggle } from '../../../../../../';
|
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
templateUrl: 'root-page.html'
|
templateUrl: 'root-page.html'
|
||||||
@ -38,20 +37,20 @@ export class RootPage {
|
|||||||
this.grapeCtrl.enabled ? this.grapeCtrl.disable() : this.grapeCtrl.enable();
|
this.grapeCtrl.enabled ? this.grapeCtrl.disable() : this.grapeCtrl.enable();
|
||||||
}
|
}
|
||||||
|
|
||||||
appleChange(toggle: Toggle) {
|
appleChange(toggle: any) {
|
||||||
console.log('appleChange', toggle);
|
console.log('appleChange', toggle);
|
||||||
}
|
}
|
||||||
|
|
||||||
bananaChange(toggle: Toggle) {
|
bananaChange(toggle: any) {
|
||||||
console.log('bananaChange', toggle);
|
console.log('bananaChange', toggle);
|
||||||
}
|
}
|
||||||
|
|
||||||
kiwiChange(toggle: Toggle) {
|
kiwiChange(toggle: any) {
|
||||||
console.log('kiwiChange', toggle);
|
console.log('kiwiChange', toggle);
|
||||||
this.kiwiValue = toggle.checked;
|
this.kiwiValue = toggle.checked;
|
||||||
}
|
}
|
||||||
|
|
||||||
strawberryChange(toggle: Toggle) {
|
strawberryChange(toggle: any) {
|
||||||
console.log('strawberryChange', toggle);
|
console.log('strawberryChange', toggle);
|
||||||
this.strawberryValue = toggle.checked;
|
this.strawberryValue = toggle.checked;
|
||||||
}
|
}
|
||||||
|
@ -1,29 +0,0 @@
|
|||||||
|
|
||||||
import { Toggle } from '../toggle';
|
|
||||||
import { mockConfig, mockPlatform, mockHaptic, mockElementRef, mockGestureController, mockRenderer, mockItem, mockForm, mockChangeDetectorRef, mockZone } from '../../../util/mock-providers';
|
|
||||||
import { commonInputTest, BOOLEAN_CORPUS } from '../../../util/input-tester';
|
|
||||||
|
|
||||||
describe('Toggle', () => {
|
|
||||||
|
|
||||||
it('should pass common test', () => {
|
|
||||||
|
|
||||||
const platform = mockPlatform();
|
|
||||||
const config = mockConfig();
|
|
||||||
const elementRef = mockElementRef();
|
|
||||||
const renderer = mockRenderer();
|
|
||||||
const item: any = mockItem();
|
|
||||||
const form = mockForm();
|
|
||||||
const haptic = mockHaptic();
|
|
||||||
const cd = mockChangeDetectorRef();
|
|
||||||
const gesture = mockGestureController();
|
|
||||||
const zone = mockZone();
|
|
||||||
const toggle = new Toggle(form, config, platform, elementRef, renderer, haptic, item, gesture, null, cd, zone);
|
|
||||||
|
|
||||||
commonInputTest(toggle, {
|
|
||||||
defaultValue: false,
|
|
||||||
corpus: BOOLEAN_CORPUS,
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
|
@ -1,53 +0,0 @@
|
|||||||
import { GestureController, GESTURE_PRIORITY_TOGGLE, GESTURE_TOGGLE } from '../../gestures/gesture-controller';
|
|
||||||
import { DomController } from '../../platform/dom-controller';
|
|
||||||
import { PanGesture } from '../../gestures/pan-gesture';
|
|
||||||
import { Platform } from '../../platform/platform';
|
|
||||||
import { pointerCoord } from '../../util/dom';
|
|
||||||
import { Toggle } from './toggle';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @hidden
|
|
||||||
*/
|
|
||||||
export class ToggleGesture extends PanGesture {
|
|
||||||
|
|
||||||
constructor(
|
|
||||||
plt: Platform,
|
|
||||||
public toggle: Toggle,
|
|
||||||
gestureCtrl: GestureController,
|
|
||||||
domCtrl: DomController
|
|
||||||
) {
|
|
||||||
super(
|
|
||||||
plt,
|
|
||||||
toggle.getNativeElement(), {
|
|
||||||
threshold: 0,
|
|
||||||
zone: false,
|
|
||||||
domController: domCtrl,
|
|
||||||
gesture: gestureCtrl.createGesture({
|
|
||||||
name: GESTURE_TOGGLE,
|
|
||||||
priority: GESTURE_PRIORITY_TOGGLE
|
|
||||||
})
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
canStart(ev: any): boolean {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
onDragStart(ev: any) {
|
|
||||||
ev.preventDefault();
|
|
||||||
|
|
||||||
this.toggle._onDragStart(pointerCoord(ev).x);
|
|
||||||
}
|
|
||||||
|
|
||||||
onDragMove(ev: any) {
|
|
||||||
ev.preventDefault();
|
|
||||||
|
|
||||||
this.toggle._onDragMove(pointerCoord(ev).x);
|
|
||||||
}
|
|
||||||
|
|
||||||
onDragEnd(ev: any) {
|
|
||||||
ev.preventDefault();
|
|
||||||
|
|
||||||
this.toggle._onDragEnd(pointerCoord(ev).x);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,4 +1,6 @@
|
|||||||
@import "../../themes/ionic.globals.ios";
|
@import "../../themes/ionic.globals.ios";
|
||||||
|
@import "./toggle";
|
||||||
|
|
||||||
|
|
||||||
// iOS Toggle
|
// iOS Toggle
|
||||||
// --------------------------------------------------
|
// --------------------------------------------------
|
||||||
|
@ -1,4 +1,6 @@
|
|||||||
@import "../../themes/ionic.globals.md";
|
@import "../../themes/ionic.globals.md";
|
||||||
|
@import "./toggle";
|
||||||
|
|
||||||
|
|
||||||
// Material Design Toggle
|
// Material Design Toggle
|
||||||
// --------------------------------------------------
|
// --------------------------------------------------
|
||||||
|
35
src/components/toggle/toggle.scss
Normal file
35
src/components/toggle/toggle.scss
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
@import "../../themes/ionic.globals";
|
||||||
|
|
||||||
|
|
||||||
|
// Toggle
|
||||||
|
// --------------------------------------------------
|
||||||
|
|
||||||
|
:host {
|
||||||
|
display: inline-block;
|
||||||
|
visibility: inherit !important;
|
||||||
|
contain: content;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.toggle-cover {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
|
||||||
|
border: 0;
|
||||||
|
|
||||||
|
background: transparent;
|
||||||
|
|
||||||
|
font-family: inherit;
|
||||||
|
font-style: inherit;
|
||||||
|
font-variant: inherit;
|
||||||
|
|
||||||
|
line-height: 1;
|
||||||
|
text-transform: none;
|
||||||
|
|
||||||
|
cursor: pointer;
|
||||||
|
outline: none;
|
||||||
|
}
|
@ -1,238 +1,147 @@
|
|||||||
import { NgZone, AfterViewInit, ChangeDetectorRef, Component, ElementRef, HostListener, Input, OnDestroy, Optional, Renderer, ViewEncapsulation } from '@angular/core';
|
import { BooleanInputComponent, GestureDetail } from '../../util/interfaces';
|
||||||
import { NG_VALUE_ACCESSOR } from '@angular/forms';
|
import { Component, h, Ionic, Listen, Prop, Watch } from '../../index';
|
||||||
|
|
||||||
import { Config } from '../../config/config';
|
|
||||||
import { DomController } from '../../platform/dom-controller';
|
|
||||||
import { Form, IonicTapInput } from '../../util/form';
|
|
||||||
import { GestureController } from '../../gestures/gesture-controller';
|
|
||||||
import { Haptic } from '../../tap-click/haptic';
|
|
||||||
import { assert, isTrueProperty } from '../../util/util';
|
|
||||||
import { BaseInput } from '../../util/base-input';
|
|
||||||
import { Item } from '../item/item';
|
|
||||||
import { KEY_ENTER, KEY_SPACE } from '../../platform/key';
|
|
||||||
import { Platform } from '../../platform/platform';
|
|
||||||
import { ToggleGesture } from './toggle-gesture';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @name Toggle
|
|
||||||
* @description
|
|
||||||
* A toggle technically is the same thing as an HTML checkbox input,
|
|
||||||
* except it looks different and is easier to use on a touch device.
|
|
||||||
* Toggles can also have colors assigned to them, by adding any color
|
|
||||||
* attribute.
|
|
||||||
*
|
|
||||||
* See the [Angular 2 Docs](https://angular.io/docs/ts/latest/guide/forms.html)
|
|
||||||
* for more info on forms and inputs.
|
|
||||||
*
|
|
||||||
* @usage
|
|
||||||
* ```html
|
|
||||||
*
|
|
||||||
* <ion-list>
|
|
||||||
*
|
|
||||||
* <ion-item>
|
|
||||||
* <ion-label>Pepperoni</ion-label>
|
|
||||||
* <ion-toggle [(ngModel)]="pepperoni"></ion-toggle>
|
|
||||||
* </ion-item>
|
|
||||||
*
|
|
||||||
* <ion-item>
|
|
||||||
* <ion-label>Sausage</ion-label>
|
|
||||||
* <ion-toggle [(ngModel)]="sausage" disabled="true"></ion-toggle>
|
|
||||||
* </ion-item>
|
|
||||||
*
|
|
||||||
* <ion-item>
|
|
||||||
* <ion-label>Mushrooms</ion-label>
|
|
||||||
* <ion-toggle [(ngModel)]="mushrooms"></ion-toggle>
|
|
||||||
* </ion-item>
|
|
||||||
*
|
|
||||||
* </ion-list>
|
|
||||||
* ```
|
|
||||||
*
|
|
||||||
* @demo /docs/demos/src/toggle/
|
|
||||||
* @see {@link /docs/components#toggle Toggle Component Docs}
|
|
||||||
*/
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'ion-toggle',
|
tag: 'ion-toggle',
|
||||||
template:
|
styleUrls: {
|
||||||
'<div class="toggle-icon">' +
|
ios: 'toggle.ios.scss',
|
||||||
'<div class="toggle-inner"></div>' +
|
md: 'toggle.md.scss',
|
||||||
'</div>' +
|
wp: 'toggle.wp.scss'
|
||||||
'<button role="checkbox" ' +
|
}
|
||||||
'type="button" ' +
|
|
||||||
'ion-button="item-cover" ' +
|
|
||||||
'[id]="id" ' +
|
|
||||||
'[attr.aria-checked]="_value" ' +
|
|
||||||
'[attr.aria-labelledby]="_labelId" ' +
|
|
||||||
'[attr.aria-disabled]="_disabled" ' +
|
|
||||||
'class="item-cover" disable-activated>' +
|
|
||||||
'</button>',
|
|
||||||
host: {
|
|
||||||
'[class.toggle-disabled]': '_disabled',
|
|
||||||
'[class.toggle-checked]': '_value',
|
|
||||||
'[class.toggle-activated]': '_activated',
|
|
||||||
},
|
|
||||||
providers: [ { provide: NG_VALUE_ACCESSOR, useExisting: Toggle, multi: true } ],
|
|
||||||
encapsulation: ViewEncapsulation.None,
|
|
||||||
})
|
})
|
||||||
export class Toggle extends BaseInput<boolean> implements IonicTapInput, AfterViewInit, OnDestroy {
|
export class Toggle implements BooleanInputComponent {
|
||||||
|
activated: boolean;
|
||||||
|
hasFocus: boolean;
|
||||||
|
id: string;
|
||||||
|
labelId: string;
|
||||||
|
startX: number;
|
||||||
|
|
||||||
_activated: boolean = false;
|
@Prop() checked: boolean;
|
||||||
_startX: number;
|
@Prop() disabled: boolean;
|
||||||
_msPrv: number = 0;
|
@Prop() value: string;
|
||||||
_gesture: ToggleGesture;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @input {boolean} If true, the element is selected.
|
@Watch('checked')
|
||||||
*/
|
changed(val: boolean) {
|
||||||
@Input()
|
Ionic.emit(this, 'ionChange', { checked: val });
|
||||||
get checked(): boolean {
|
|
||||||
return this.value;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
set checked(val: boolean) {
|
|
||||||
this.value = val;
|
canStart() {
|
||||||
|
return !this.disabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor(
|
|
||||||
form: Form,
|
onDragStart(detail: GestureDetail) {
|
||||||
config: Config,
|
this.startX = detail.startX;
|
||||||
private _plt: Platform,
|
this.fireFocus();
|
||||||
elementRef: ElementRef,
|
|
||||||
renderer: Renderer,
|
|
||||||
private _haptic: Haptic,
|
|
||||||
@Optional() item: Item,
|
|
||||||
private _gestureCtrl: GestureController,
|
|
||||||
private _domCtrl: DomController,
|
|
||||||
private _cd: ChangeDetectorRef,
|
|
||||||
private _zone: NgZone,
|
|
||||||
) {
|
|
||||||
super(config, elementRef, renderer, 'toggle', false, form, item, null);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @hidden
|
onDragMove(detail: GestureDetail) {
|
||||||
*/
|
if (this.checked) {
|
||||||
ngAfterViewInit() {
|
if (detail.currentX + 15 < this.startX) {
|
||||||
this._initialize();
|
this.checked = false;
|
||||||
this._gesture = new ToggleGesture(this._plt, this, this._gestureCtrl, this._domCtrl);
|
this.activated = true;
|
||||||
this._gesture.listen();
|
this.startX = detail.currentX;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
} else if (detail.currentX - 15 > this.startX) {
|
||||||
* @hidden
|
this.checked = true;
|
||||||
*/
|
this.activated = (detail.currentX < this.startX + 5);
|
||||||
_inputCheckHasValue() {}
|
this.startX = detail.currentX;
|
||||||
|
}
|
||||||
/**
|
|
||||||
* @hidden
|
|
||||||
*/
|
|
||||||
_inputNormalize(val: any): boolean {
|
|
||||||
return isTrueProperty(val);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @hidden
|
|
||||||
*/
|
|
||||||
_onDragStart(startX: number) {
|
|
||||||
assert(startX, 'startX must be valid');
|
|
||||||
console.debug('toggle, _onDragStart', startX);
|
|
||||||
|
|
||||||
this._zone.run(() => {
|
onDragEnd(detail: GestureDetail) {
|
||||||
this._startX = startX;
|
if (this.checked) {
|
||||||
this._fireFocus();
|
if (detail.startX + 4 > detail.currentX) {
|
||||||
this._activated = true;
|
this.checked = false;
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
} else if (detail.startX - 4 < detail.currentX) {
|
||||||
* @hidden
|
this.checked = true;
|
||||||
*/
|
|
||||||
_onDragMove(currentX: number) {
|
|
||||||
if (!this._startX) {
|
|
||||||
assert(false, '_startX must be valid');
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let dirty = false;
|
this.activated = false;
|
||||||
let value: boolean;
|
this.fireBlur();
|
||||||
let activated: boolean;
|
this.startX = null;
|
||||||
|
|
||||||
if (this._value) {
|
|
||||||
if (currentX + 15 < this._startX) {
|
|
||||||
dirty = true;
|
|
||||||
value = false;
|
|
||||||
activated = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} else if (currentX - 15 > this._startX) {
|
|
||||||
dirty = true;
|
|
||||||
value = true;
|
|
||||||
activated = (currentX < this._startX + 5);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (dirty) {
|
@Listen('keydown.space')
|
||||||
this._zone.run(() => {
|
onSpace(ev: KeyboardEvent) {
|
||||||
this.value = value;
|
this.toggle();
|
||||||
this._startX = currentX;
|
|
||||||
this._activated = activated;
|
|
||||||
this._haptic.selection();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @hidden
|
|
||||||
*/
|
|
||||||
_onDragEnd(endX: number) {
|
|
||||||
if (!this._startX) {
|
|
||||||
assert(false, '_startX must be valid');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
console.debug('toggle, _onDragEnd', endX);
|
|
||||||
|
|
||||||
this._zone.run(() => {
|
|
||||||
if (this._value) {
|
|
||||||
if (this._startX + 4 > endX) {
|
|
||||||
this.value = false;
|
|
||||||
this._haptic.selection();
|
|
||||||
}
|
|
||||||
|
|
||||||
} else if (this._startX - 4 < endX) {
|
|
||||||
this.value = true;
|
|
||||||
this._haptic.selection();
|
|
||||||
}
|
|
||||||
|
|
||||||
this._activated = false;
|
|
||||||
this._fireBlur();
|
|
||||||
this._startX = null;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @hidden
|
|
||||||
*/
|
|
||||||
@HostListener('keyup', ['$event']) _keyup(ev: KeyboardEvent) {
|
|
||||||
if (ev.keyCode === KEY_SPACE || ev.keyCode === KEY_ENTER) {
|
|
||||||
console.debug(`toggle, keyup: ${ev.keyCode}`);
|
|
||||||
ev.preventDefault();
|
|
||||||
ev.stopPropagation();
|
ev.stopPropagation();
|
||||||
this.value = !this.value;
|
ev.preventDefault();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
toggle() {
|
||||||
|
if (!this.disabled) {
|
||||||
|
this.checked = !this.checked;
|
||||||
|
this.fireFocus();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @hidden
|
fireFocus() {
|
||||||
*/
|
if (!this.hasFocus) {
|
||||||
initFocus() {
|
this.hasFocus = true;
|
||||||
this._elementRef.nativeElement.querySelector('button').focus();
|
Ionic.emit(this, 'ionFocus');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @hidden
|
fireBlur() {
|
||||||
*/
|
if (this.hasFocus) {
|
||||||
ngOnDestroy() {
|
this.hasFocus = false;
|
||||||
super.ngOnDestroy();
|
Ionic.emit(this, 'ionBlur');
|
||||||
this._gesture && this._gesture.destroy();
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return h(this,
|
||||||
|
h('ion-gesture', Ionic.theme(this, 'toggle', {
|
||||||
|
class: {
|
||||||
|
'toggle-activated': this.activated,
|
||||||
|
'toggle-checked': this.checked,
|
||||||
|
'toggle-disabled': this.disabled,
|
||||||
|
},
|
||||||
|
props: {
|
||||||
|
'canStart': this.canStart.bind(this),
|
||||||
|
'onStart': this.onDragStart.bind(this),
|
||||||
|
'onMove': this.onDragMove.bind(this),
|
||||||
|
'onEnd': this.onDragEnd.bind(this),
|
||||||
|
'onPress': this.toggle.bind(this),
|
||||||
|
'gestureName': 'toggle',
|
||||||
|
'gesturePriority': 30,
|
||||||
|
'type': 'pan,press',
|
||||||
|
'direction': 'x',
|
||||||
|
'threshold': 20,
|
||||||
|
'listenOn': 'parent'
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
[
|
||||||
|
h('div.toggle-icon',
|
||||||
|
h('div.toggle-inner')
|
||||||
|
),
|
||||||
|
h('div.toggle-cover', {
|
||||||
|
attrs: {
|
||||||
|
'id': this.id,
|
||||||
|
'aria-checked': this.checked ? 'true' : false,
|
||||||
|
'aria-disabled': this.disabled ? 'true' : false,
|
||||||
|
'aria-labelledby': this.labelId,
|
||||||
|
'role': 'checkbox',
|
||||||
|
'tabindex': 0
|
||||||
|
}
|
||||||
|
})
|
||||||
|
]
|
||||||
|
)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,6 @@
|
|||||||
@import "../../themes/ionic.globals.wp";
|
@import "../../themes/ionic.globals.wp";
|
||||||
|
@import "./toggle";
|
||||||
|
|
||||||
|
|
||||||
// Windows Toggle
|
// Windows Toggle
|
||||||
// --------------------------------------------------
|
// --------------------------------------------------
|
||||||
|
27
src/index.ts
27
src/index.ts
@ -12,12 +12,7 @@ export { AlertCmp } from './components/alert/alert-component';
|
|||||||
export { App } from './components/app/app';
|
export { App } from './components/app/app';
|
||||||
export { Avatar } from './components/avatar/avatar';
|
export { Avatar } from './components/avatar/avatar';
|
||||||
export { Backdrop } from './components/backdrop/backdrop';
|
export { Backdrop } from './components/backdrop/backdrop';
|
||||||
export { Badge } from './components/badge/badge';
|
|
||||||
export { Button } from './components/button/button';
|
export { Button } from './components/button/button';
|
||||||
export { Card } from './components/card/card';
|
|
||||||
export { CardContent } from './components/card/card-content';
|
|
||||||
export { CardHeader } from './components/card/card-header';
|
|
||||||
export { CardTitle } from './components/card/card-title';
|
|
||||||
export { Checkbox } from './components/checkbox/checkbox';
|
export { Checkbox } from './components/checkbox/checkbox';
|
||||||
export { Chip } from './components/chip/chip';
|
export { Chip } from './components/chip/chip';
|
||||||
export { Content, ScrollEvent } from './components/content/content';
|
export { Content, ScrollEvent } from './components/content/content';
|
||||||
@ -102,7 +97,6 @@ export { Toast } from './components/toast/toast';
|
|||||||
export { ToastCmp } from './components/toast/toast-component';
|
export { ToastCmp } from './components/toast/toast-component';
|
||||||
export { ToastController } from './components/toast/toast-controller';
|
export { ToastController } from './components/toast/toast-controller';
|
||||||
export { ToastOptions } from './components/toast/toast-options';
|
export { ToastOptions } from './components/toast/toast-options';
|
||||||
export { Toggle } from './components/toggle/toggle';
|
|
||||||
export { Footer } from './components/toolbar/toolbar-footer';
|
export { Footer } from './components/toolbar/toolbar-footer';
|
||||||
export { Header } from './components/toolbar/toolbar-header';
|
export { Header } from './components/toolbar/toolbar-header';
|
||||||
export { Toolbar } from './components/toolbar/toolbar';
|
export { Toolbar } from './components/toolbar/toolbar';
|
||||||
@ -115,6 +109,7 @@ export { VirtualFooter } from './components/virtual-scroll/virtual-footer';
|
|||||||
export { VirtualHeader } from './components/virtual-scroll/virtual-header';
|
export { VirtualHeader } from './components/virtual-scroll/virtual-header';
|
||||||
export { VirtualItem } from './components/virtual-scroll/virtual-item';
|
export { VirtualItem } from './components/virtual-scroll/virtual-item';
|
||||||
export { VirtualScroll } from './components/virtual-scroll/virtual-scroll';
|
export { VirtualScroll } from './components/virtual-scroll/virtual-scroll';
|
||||||
|
export { BooleanInput } from './bindings/angular/components/boolean-input';
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -130,6 +125,7 @@ export { NavController } from './navigation/nav-controller';
|
|||||||
export { NavControllerBase } from './navigation/nav-controller-base';
|
export { NavControllerBase } from './navigation/nav-controller-base';
|
||||||
export { NavParams } from './navigation/nav-params';
|
export { NavParams } from './navigation/nav-params';
|
||||||
export { NavLink, NavOptions, DeepLinkConfig, DeepLinkMetadata, DeepLinkMetadataFactory } from './navigation/nav-util';
|
export { NavLink, NavOptions, DeepLinkConfig, DeepLinkMetadata, DeepLinkMetadataFactory } from './navigation/nav-util';
|
||||||
|
export { setupCore } from './bindings/angular/providers/ionic-core';
|
||||||
export { TapClick, setupTapClick, isActivatable } from './tap-click/tap-click';
|
export { TapClick, setupTapClick, isActivatable } from './tap-click/tap-click';
|
||||||
export { UrlSerializer, DeepLinkConfigToken } from './navigation/url-serializer';
|
export { UrlSerializer, DeepLinkConfigToken } from './navigation/url-serializer';
|
||||||
export { ViewController } from './navigation/view-controller';
|
export { ViewController } from './navigation/view-controller';
|
||||||
@ -169,3 +165,22 @@ export { IonicGestureConfig } from './gestures/gesture-config';
|
|||||||
|
|
||||||
export { IonicModule, IonicPageModule, provideLocationStrategy } from './module';
|
export { IonicModule, IonicPageModule, provideLocationStrategy } from './module';
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Core
|
||||||
|
*/
|
||||||
|
|
||||||
|
import * as interfaces from './util/interfaces';
|
||||||
|
|
||||||
|
export declare const Component: interfaces.ComponentDecorator;
|
||||||
|
|
||||||
|
export declare const h: interfaces.Hyperscript;
|
||||||
|
|
||||||
|
export declare const Ionic: interfaces.Ionic;
|
||||||
|
|
||||||
|
export declare const Listen: interfaces.ListenDecorator;
|
||||||
|
|
||||||
|
export declare const Prop: interfaces.PropDecorator;
|
||||||
|
|
||||||
|
export declare const Watch: interfaces.WatchDecorator;
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/**
|
/**
|
||||||
* Import Angular
|
* Import Angular
|
||||||
*/
|
*/
|
||||||
import { ANALYZE_FOR_ENTRY_COMPONENTS, APP_INITIALIZER, ComponentFactoryResolver, Inject, Injector, ModuleWithProviders, NgModule, NgZone, Optional } from '@angular/core';
|
import { ANALYZE_FOR_ENTRY_COMPONENTS, APP_INITIALIZER, ComponentFactoryResolver, CUSTOM_ELEMENTS_SCHEMA, Inject, Injector, ModuleWithProviders, NgModule, NgZone, Optional } from '@angular/core';
|
||||||
import { APP_BASE_HREF, Location, LocationStrategy, HashLocationStrategy, PathLocationStrategy, PlatformLocation } from '@angular/common';
|
import { APP_BASE_HREF, Location, LocationStrategy, HashLocationStrategy, PathLocationStrategy, PlatformLocation } from '@angular/common';
|
||||||
import { DOCUMENT, HAMMER_GESTURE_CONFIG } from '@angular/platform-browser';
|
import { DOCUMENT, HAMMER_GESTURE_CONFIG } from '@angular/platform-browser';
|
||||||
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
|
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
|
||||||
@ -31,6 +31,7 @@ import { ModuleLoader, provideModuleLoader, setupPreloading, LAZY_LOADED_TOKEN }
|
|||||||
import { NgModuleLoader } from './util/ng-module-loader';
|
import { NgModuleLoader } from './util/ng-module-loader';
|
||||||
import { Platform, setupPlatform } from './platform/platform';
|
import { Platform, setupPlatform } from './platform/platform';
|
||||||
import { PlatformConfigToken, providePlatformConfigs } from './platform/platform-registry';
|
import { PlatformConfigToken, providePlatformConfigs } from './platform/platform-registry';
|
||||||
|
import { setupCore } from './bindings/angular/providers/ionic-core';
|
||||||
import { TapClick, setupTapClick } from './tap-click/tap-click';
|
import { TapClick, setupTapClick } from './tap-click/tap-click';
|
||||||
import { registerModeConfigs } from './config/mode-registry';
|
import { registerModeConfigs } from './config/mode-registry';
|
||||||
import { TransitionController } from './transitions/transition-controller';
|
import { TransitionController } from './transitions/transition-controller';
|
||||||
@ -49,12 +50,7 @@ import { IonicApp } from './components/app/app-root';
|
|||||||
import { OverlayPortal } from './components/app/overlay-portal';
|
import { OverlayPortal } from './components/app/overlay-portal';
|
||||||
import { Avatar } from './components/avatar/avatar';
|
import { Avatar } from './components/avatar/avatar';
|
||||||
import { Backdrop } from './components/backdrop/backdrop';
|
import { Backdrop } from './components/backdrop/backdrop';
|
||||||
import { Badge } from './components/badge/badge';
|
|
||||||
import { Button } from './components/button/button';
|
import { Button } from './components/button/button';
|
||||||
import { Card } from './components/card/card';
|
|
||||||
import { CardContent } from './components/card/card-content';
|
|
||||||
import { CardHeader } from './components/card/card-header';
|
|
||||||
import { CardTitle } from './components/card/card-title';
|
|
||||||
import { Checkbox } from './components/checkbox/checkbox';
|
import { Checkbox } from './components/checkbox/checkbox';
|
||||||
import { Chip } from './components/chip/chip';
|
import { Chip } from './components/chip/chip';
|
||||||
import { Content } from './components/content/content';
|
import { Content } from './components/content/content';
|
||||||
@ -128,7 +124,6 @@ import { Tabs } from './components/tabs/tabs';
|
|||||||
import { Thumbnail } from './components/thumbnail/thumbnail';
|
import { Thumbnail } from './components/thumbnail/thumbnail';
|
||||||
import { ToastCmp } from './components/toast/toast-component';
|
import { ToastCmp } from './components/toast/toast-component';
|
||||||
import { ToastController } from './components/toast/toast-controller';
|
import { ToastController } from './components/toast/toast-controller';
|
||||||
import { Toggle } from './components/toggle/toggle';
|
|
||||||
import { Footer } from './components/toolbar/toolbar-footer';
|
import { Footer } from './components/toolbar/toolbar-footer';
|
||||||
import { Header } from './components/toolbar/toolbar-header';
|
import { Header } from './components/toolbar/toolbar-header';
|
||||||
import { Toolbar } from './components/toolbar/toolbar';
|
import { Toolbar } from './components/toolbar/toolbar';
|
||||||
@ -140,6 +135,7 @@ import { VirtualFooter } from './components/virtual-scroll/virtual-footer';
|
|||||||
import { VirtualHeader } from './components/virtual-scroll/virtual-header';
|
import { VirtualHeader } from './components/virtual-scroll/virtual-header';
|
||||||
import { VirtualItem } from './components/virtual-scroll/virtual-item';
|
import { VirtualItem } from './components/virtual-scroll/virtual-item';
|
||||||
import { VirtualScroll } from './components/virtual-scroll/virtual-scroll';
|
import { VirtualScroll } from './components/virtual-scroll/virtual-scroll';
|
||||||
|
import { BooleanInput } from './bindings/angular/components/boolean-input';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @name IonicModule
|
* @name IonicModule
|
||||||
@ -190,12 +186,7 @@ import { VirtualScroll } from './components/virtual-scroll/virtual-scroll';
|
|||||||
OverlayPortal,
|
OverlayPortal,
|
||||||
Avatar,
|
Avatar,
|
||||||
Backdrop,
|
Backdrop,
|
||||||
Badge,
|
|
||||||
Button,
|
Button,
|
||||||
Card,
|
|
||||||
CardContent,
|
|
||||||
CardHeader,
|
|
||||||
CardTitle,
|
|
||||||
Checkbox,
|
Checkbox,
|
||||||
Chip,
|
Chip,
|
||||||
Col,
|
Col,
|
||||||
@ -263,7 +254,6 @@ import { VirtualScroll } from './components/virtual-scroll/virtual-scroll';
|
|||||||
TextInput,
|
TextInput,
|
||||||
Thumbnail,
|
Thumbnail,
|
||||||
ToastCmp,
|
ToastCmp,
|
||||||
Toggle,
|
|
||||||
Footer,
|
Footer,
|
||||||
Header,
|
Header,
|
||||||
Toolbar,
|
Toolbar,
|
||||||
@ -274,7 +264,8 @@ import { VirtualScroll } from './components/virtual-scroll/virtual-scroll';
|
|||||||
VirtualFooter,
|
VirtualFooter,
|
||||||
VirtualHeader,
|
VirtualHeader,
|
||||||
VirtualItem,
|
VirtualItem,
|
||||||
VirtualScroll
|
VirtualScroll,
|
||||||
|
BooleanInput
|
||||||
],
|
],
|
||||||
imports: [
|
imports: [
|
||||||
CommonModule,
|
CommonModule,
|
||||||
@ -293,12 +284,7 @@ import { VirtualScroll } from './components/virtual-scroll/virtual-scroll';
|
|||||||
OverlayPortal,
|
OverlayPortal,
|
||||||
Avatar,
|
Avatar,
|
||||||
Backdrop,
|
Backdrop,
|
||||||
Badge,
|
|
||||||
Button,
|
Button,
|
||||||
Card,
|
|
||||||
CardContent,
|
|
||||||
CardHeader,
|
|
||||||
CardTitle,
|
|
||||||
Checkbox,
|
Checkbox,
|
||||||
Chip,
|
Chip,
|
||||||
Col,
|
Col,
|
||||||
@ -366,7 +352,6 @@ import { VirtualScroll } from './components/virtual-scroll/virtual-scroll';
|
|||||||
TextInput,
|
TextInput,
|
||||||
Thumbnail,
|
Thumbnail,
|
||||||
ToastCmp,
|
ToastCmp,
|
||||||
Toggle,
|
|
||||||
Footer,
|
Footer,
|
||||||
Header,
|
Header,
|
||||||
Toolbar,
|
Toolbar,
|
||||||
@ -377,7 +362,8 @@ import { VirtualScroll } from './components/virtual-scroll/virtual-scroll';
|
|||||||
VirtualFooter,
|
VirtualFooter,
|
||||||
VirtualHeader,
|
VirtualHeader,
|
||||||
VirtualItem,
|
VirtualItem,
|
||||||
VirtualScroll
|
VirtualScroll,
|
||||||
|
BooleanInput
|
||||||
],
|
],
|
||||||
entryComponents: [
|
entryComponents: [
|
||||||
ActionSheetCmp,
|
ActionSheetCmp,
|
||||||
@ -389,7 +375,8 @@ import { VirtualScroll } from './components/virtual-scroll/virtual-scroll';
|
|||||||
PopoverCmp,
|
PopoverCmp,
|
||||||
SelectPopover,
|
SelectPopover,
|
||||||
ToastCmp
|
ToastCmp
|
||||||
]
|
],
|
||||||
|
schemas: [CUSTOM_ELEMENTS_SCHEMA]
|
||||||
})
|
})
|
||||||
export class IonicModule {
|
export class IonicModule {
|
||||||
|
|
||||||
@ -418,6 +405,7 @@ export class IonicModule {
|
|||||||
|
|
||||||
// useFactory: ionic app initializers
|
// useFactory: ionic app initializers
|
||||||
{ provide: APP_INITIALIZER, useFactory: registerModeConfigs, deps: [ Config ], multi: true },
|
{ provide: APP_INITIALIZER, useFactory: registerModeConfigs, deps: [ Config ], multi: true },
|
||||||
|
{ provide: APP_INITIALIZER, useFactory: setupCore, deps: [ Config, Platform, DomController, NgZone ], multi: true },
|
||||||
{ provide: APP_INITIALIZER, useFactory: setupProvideEvents, deps: [ Platform, DomController ], multi: true },
|
{ provide: APP_INITIALIZER, useFactory: setupProvideEvents, deps: [ Platform, DomController ], multi: true },
|
||||||
{ provide: APP_INITIALIZER, useFactory: setupTapClick, deps: [ Config, Platform, DomController, App, NgZone, GestureController ], multi: true },
|
{ provide: APP_INITIALIZER, useFactory: setupTapClick, deps: [ Config, Platform, DomController, App, NgZone, GestureController ], multi: true },
|
||||||
{ provide: APP_INITIALIZER, useFactory: setupPreloading, deps: [ Config, DeepLinkConfigToken, ModuleLoader, NgZone ], multi: true },
|
{ provide: APP_INITIALIZER, useFactory: setupPreloading, deps: [ Config, DeepLinkConfigToken, ModuleLoader, NgZone ], multi: true },
|
||||||
|
@ -1,19 +0,0 @@
|
|||||||
|
|
||||||
export const Component: ComponentDecorator = function(opts?: ComponentOptions): (target: any) => any {
|
|
||||||
return function() {};
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
export interface ComponentDecorator {
|
|
||||||
(opts?: ComponentOptions): any;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
export interface ComponentOptions {
|
|
||||||
tag: string;
|
|
||||||
styleUrls?: string[] | ModeStyles;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface ModeStyles {
|
|
||||||
[modeName: string]: string | string[];
|
|
||||||
}
|
|
@ -113,3 +113,89 @@ export interface PointerCoordinates {
|
|||||||
x?: number;
|
x?: number;
|
||||||
y?: number;
|
y?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
export function pointerCoordX(ev: any): number {
|
||||||
|
// get X coordinates for either a mouse click
|
||||||
|
// or a touch depending on the given event
|
||||||
|
if (ev) {
|
||||||
|
var changedTouches = ev.changedTouches;
|
||||||
|
if (changedTouches && changedTouches.length > 0) {
|
||||||
|
return changedTouches[0].clientX;
|
||||||
|
}
|
||||||
|
if (ev.pageX !== undefined) {
|
||||||
|
return ev.pageX;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export function pointerCoordY(ev: any): number {
|
||||||
|
// get Y coordinates for either a mouse click
|
||||||
|
// or a touch depending on the given event
|
||||||
|
if (ev) {
|
||||||
|
var changedTouches = ev.changedTouches;
|
||||||
|
if (changedTouches && changedTouches.length > 0) {
|
||||||
|
return changedTouches[0].clientY;
|
||||||
|
}
|
||||||
|
if (ev.pageY !== undefined) {
|
||||||
|
return ev.pageY;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export function getElementReference(elm: any, ref: string) {
|
||||||
|
if (ref === 'child') {
|
||||||
|
return elm.firstElementChild;
|
||||||
|
}
|
||||||
|
if (ref === 'parent') {
|
||||||
|
if (elm.parentElement ) {
|
||||||
|
// normal element with a parent element
|
||||||
|
return elm.parentElement;
|
||||||
|
}
|
||||||
|
if (elm.parentNode && elm.parentNode.host) {
|
||||||
|
// shadow dom's document fragment
|
||||||
|
return elm.parentNode.host;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (ref === 'body') {
|
||||||
|
return elm.ownerDocument.body;
|
||||||
|
}
|
||||||
|
if (ref === 'document') {
|
||||||
|
return elm.ownerDocument;
|
||||||
|
}
|
||||||
|
if (ref === 'window') {
|
||||||
|
return elm.ownerDocument.defaultView;
|
||||||
|
}
|
||||||
|
return elm;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export function getKeyCodeByName(keyName: string) {
|
||||||
|
if (keyName === 'enter') {
|
||||||
|
return 13;
|
||||||
|
}
|
||||||
|
if (keyName === 'escape') {
|
||||||
|
return 27;
|
||||||
|
}
|
||||||
|
if (keyName === 'space') {
|
||||||
|
return 32;
|
||||||
|
}
|
||||||
|
if (keyName === 'tab') {
|
||||||
|
return 9;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export function applyStyles(elm: HTMLElement, styles: {[styleProp: string]: string|number}) {
|
||||||
|
const styleProps = Object.keys(styles);
|
||||||
|
|
||||||
|
for (var i = 0; i < styleProps.length; i++) {
|
||||||
|
(<any>elm.style)[styleProps[i]] = styles[styleProps[i]];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
424
src/util/interfaces.ts
Normal file
424
src/util/interfaces.ts
Normal file
@ -0,0 +1,424 @@
|
|||||||
|
|
||||||
|
export interface Ionic {
|
||||||
|
emit: EventEmit;
|
||||||
|
listener: {
|
||||||
|
enable: EventListenerEnable;
|
||||||
|
};
|
||||||
|
theme: IonicTheme;
|
||||||
|
controllers: {
|
||||||
|
gesture?: any;
|
||||||
|
};
|
||||||
|
dom: DomControllerApi;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export interface EventEmit {
|
||||||
|
(instance: any, eventName: string, data?: any): void;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export interface EventListenerEnable {
|
||||||
|
(instance: any, eventName: string, enabled: boolean, listenOn?: string): void;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export interface EventListenerCallback {
|
||||||
|
(ev?: any): void;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export interface GestureDetail {
|
||||||
|
type?: string;
|
||||||
|
event?: UIEvent;
|
||||||
|
startX?: number;
|
||||||
|
startY?: number;
|
||||||
|
startTimeStamp?: number;
|
||||||
|
currentX?: number;
|
||||||
|
currentY?: number;
|
||||||
|
velocityX?: number;
|
||||||
|
velocityY?: number;
|
||||||
|
deltaX?: number;
|
||||||
|
deltaY?: number;
|
||||||
|
directionX?: 'left'|'right';
|
||||||
|
directionY?: 'up'|'down';
|
||||||
|
velocityDirectionX?: 'left'|'right';
|
||||||
|
velocityDirectionY?: 'up'|'down';
|
||||||
|
timeStamp?: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export interface GestureCallback {
|
||||||
|
(detail?: GestureDetail): boolean|void;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export interface IonicGlobal {
|
||||||
|
staticDir?: string;
|
||||||
|
components?: LoadComponents;
|
||||||
|
loadComponents?: {(bundleId: string): void};
|
||||||
|
config?: Object;
|
||||||
|
configCtrl?: ConfigApi;
|
||||||
|
domCtrl?: DomControllerApi;
|
||||||
|
nextTickCtrl?: NextTickApi;
|
||||||
|
eventNamePrefix?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export interface NextTickApi {
|
||||||
|
nextTick: NextTick;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export interface NextTick {
|
||||||
|
(cb: Function): void;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export interface DomRead {
|
||||||
|
(cb: Function): void;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export interface DomWrite {
|
||||||
|
(cb: Function): void;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export interface DomControllerApi {
|
||||||
|
read: DomRead;
|
||||||
|
write: DomWrite;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export interface RafCallback {
|
||||||
|
(timeStamp?: number): void;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export interface RequestAnimationFrame {
|
||||||
|
(cb: RafCallback): void;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export interface LoadComponents {
|
||||||
|
[tag: string]: any[];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export interface ComponentModeData {
|
||||||
|
/**
|
||||||
|
* tag name (ion-badge)
|
||||||
|
*/
|
||||||
|
[0]: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* component class name (Badge)
|
||||||
|
*/
|
||||||
|
[1]: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* listeners
|
||||||
|
*/
|
||||||
|
[2]: ComponentListenersData[];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* watchers
|
||||||
|
*/
|
||||||
|
[3]: ComponentWatchersData[];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* shadow
|
||||||
|
*/
|
||||||
|
[4]: boolean;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* mode name (ios, md, wp)
|
||||||
|
*/
|
||||||
|
[5]: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* component mode styles
|
||||||
|
*/
|
||||||
|
[6]: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* import component function
|
||||||
|
*/
|
||||||
|
[7]: ComponentModeImporterFn;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export interface ComponentListenersData {
|
||||||
|
/**
|
||||||
|
* methodName
|
||||||
|
*/
|
||||||
|
[0]: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* eventName
|
||||||
|
*/
|
||||||
|
[1]: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* capture
|
||||||
|
*/
|
||||||
|
[2]: number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* passive
|
||||||
|
*/
|
||||||
|
[3]: number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* enabled
|
||||||
|
*/
|
||||||
|
[4]: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export interface ComponentWatchersData {
|
||||||
|
[methodName: string]: any;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export interface ComponentModeImporterFn {
|
||||||
|
(importer: any, h: Hyperscript, Ionic: Ionic): void;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export interface ComponentDecorator {
|
||||||
|
(opts?: ComponentOptions): any;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export interface ComponentOptions {
|
||||||
|
tag: string;
|
||||||
|
styleUrls?: string[] | ModeStyles;
|
||||||
|
shadow?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ModeStyles {
|
||||||
|
[modeName: string]: string | string[];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export interface PropDecorator {
|
||||||
|
(opts?: PropOptions): any;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export interface PropOptions {
|
||||||
|
type?: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export interface Props {
|
||||||
|
[propName: string]: PropOptions;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export interface ListenDecorator {
|
||||||
|
(eventName: string, opts?: ListenOpts): any;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export interface ComponentMetaListeners {
|
||||||
|
[methodName: string]: ListenOpts;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export interface ListenOpts {
|
||||||
|
eventName?: string;
|
||||||
|
capture?: boolean;
|
||||||
|
passive?: boolean;
|
||||||
|
enabled?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export interface WatchDecorator {
|
||||||
|
(propName: string): any;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export interface WatchOpts {
|
||||||
|
fn: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export interface Watchers {
|
||||||
|
[propName: string]: WatchOpts;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export interface IonicTheme {
|
||||||
|
(instance: any, cssClassName: string, vnodeData: VNodeData): VNodeData;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export interface ConfigApi {
|
||||||
|
get: (key: string, fallback?: any) => any;
|
||||||
|
getBoolean: (key: string, fallback?: boolean) => boolean;
|
||||||
|
getNumber: (key: string, fallback?: number) => number;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export interface ComponentMeta {
|
||||||
|
tag?: string;
|
||||||
|
props?: Props;
|
||||||
|
listeners?: ComponentMetaListeners;
|
||||||
|
watchers?: Watchers;
|
||||||
|
shadow?: boolean;
|
||||||
|
obsAttrs?: string[];
|
||||||
|
hostCss?: string;
|
||||||
|
componentModule?: any;
|
||||||
|
modes: {[modeName: string]: ComponentMode};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export interface ComponentMode {
|
||||||
|
bundleId?: string;
|
||||||
|
styles?: string;
|
||||||
|
styleUrls?: string[];
|
||||||
|
styleElm?: HTMLElement;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export interface Component {
|
||||||
|
ionViewDidLoad?: {(): void};
|
||||||
|
ionViewWillUnload?: {(): void};
|
||||||
|
|
||||||
|
render?: {(): VNode};
|
||||||
|
|
||||||
|
mode?: string;
|
||||||
|
color?: string;
|
||||||
|
|
||||||
|
$el?: ProxyElement;
|
||||||
|
$meta?: ComponentMeta;
|
||||||
|
$listeners?: ComponentActiveListeners;
|
||||||
|
$root?: HTMLElement | ShadowRoot;
|
||||||
|
$vnode?: VNode;
|
||||||
|
|
||||||
|
[memberName: string]: any;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export interface ComponentActiveListeners {
|
||||||
|
[eventName: string]: Function;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export interface BaseInputComponent extends Component {
|
||||||
|
disabled: boolean;
|
||||||
|
hasFocus: boolean;
|
||||||
|
value: string;
|
||||||
|
|
||||||
|
fireFocus: {(): void};
|
||||||
|
fireBlur: {(): void};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export interface BooleanInputComponent extends BaseInputComponent {
|
||||||
|
checked: boolean;
|
||||||
|
toggle: {(ev: UIEvent): void};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export interface ComponentModule {
|
||||||
|
new (): Component;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export interface ComponentRegistry {
|
||||||
|
[tag: string]: ComponentMeta;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export interface ProxyElement extends HTMLElement {
|
||||||
|
connectedCallback: {(): void};
|
||||||
|
attributeChangedCallback: {(attrName: string, oldVal: string, newVal: string, namespace: string): void};
|
||||||
|
disconnectedCallback: {(): void};
|
||||||
|
|
||||||
|
$queued?: boolean;
|
||||||
|
$instance?: Component;
|
||||||
|
|
||||||
|
[memberName: string]: any;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export interface RendererApi {
|
||||||
|
(oldVnode: VNode | Element, vnode: VNode): VNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export type Key = string | number;
|
||||||
|
|
||||||
|
|
||||||
|
export interface Hyperscript {
|
||||||
|
(sel: any): VNode;
|
||||||
|
(sel: Node, data: VNodeData): VNode;
|
||||||
|
(sel: any, data: VNodeData): VNode;
|
||||||
|
(sel: any, text: string): VNode;
|
||||||
|
(sel: any, children: Array<any>): VNode;
|
||||||
|
(sel: any, data: VNodeData, text: string): VNode;
|
||||||
|
(sel: any, data: VNodeData, children: Array<any|string>): VNode;
|
||||||
|
(sel: any, data: VNodeData, children: any): VNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export interface VNode {
|
||||||
|
sel: string | undefined;
|
||||||
|
vdata: VNodeData | undefined;
|
||||||
|
vchildren: Array<VNode | string> | undefined;
|
||||||
|
elm: Node | undefined;
|
||||||
|
vtext: string | undefined;
|
||||||
|
vkey: Key;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export interface VNodeData {
|
||||||
|
props?: any;
|
||||||
|
attrs?: any;
|
||||||
|
class?: any;
|
||||||
|
style?: any;
|
||||||
|
dataset?: any;
|
||||||
|
on?: any;
|
||||||
|
attachData?: any;
|
||||||
|
vkey?: Key;
|
||||||
|
vns?: string; // for SVGs
|
||||||
|
[key: string]: any; // for any other 3rd party module
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export interface PlatformApi {
|
||||||
|
registerComponent: (tag: string, data: any[]) => ComponentMeta;
|
||||||
|
getComponentMeta: (tag: string) => ComponentMeta;
|
||||||
|
loadComponent: (bundleId: string, cb: Function) => void;
|
||||||
|
nextTick: NextTick;
|
||||||
|
domRead: DomRead;
|
||||||
|
domWrite: DomWrite;
|
||||||
|
|
||||||
|
isElement: (node: Node) => node is Element;
|
||||||
|
isText: (node: Node) => node is Text;
|
||||||
|
isComment: (node: Node) => node is Comment;
|
||||||
|
|
||||||
|
$createElement<K extends keyof HTMLElementTagNameMap>(tagName: K): HTMLElementTagNameMap[K];
|
||||||
|
$createElementNS: (namespaceURI: string, qualifiedName: string) => Element;
|
||||||
|
$createTextNode: (text: string) => Text;
|
||||||
|
$createComment: (text: string) => Comment;
|
||||||
|
$insertBefore: (parentNode: Node, newNode: Node, referenceNode: Node | null) => void;
|
||||||
|
$removeChild: (parentNode: Node, childNode: Node) => void;
|
||||||
|
$appendChild: (parentNode: Node, childNode: Node) => void;
|
||||||
|
$parentNode: (node: Node) => Node;
|
||||||
|
$nextSibling: (node: Node) => Node;
|
||||||
|
$tagName: (elm: Element) => string;
|
||||||
|
$setTextContent: (node: Node, text: string | null) => void;
|
||||||
|
$getTextContent: (node: Node) => string | null;
|
||||||
|
$getAttribute: (elm: Element, attrName: string) => string;
|
||||||
|
$attachShadow: (elm: Element, cmpMode: ComponentMode, cmpModeId: string) => ShadowRoot;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export interface ServerInitConfig {
|
||||||
|
staticDir: string;
|
||||||
|
config?: Object;
|
||||||
|
}
|
Reference in New Issue
Block a user