mirror of
https://github.com/ionic-team/ionic-framework.git
synced 2025-08-18 19:21:34 +08:00
Activator: activated
This commit is contained in:
@ -8,7 +8,6 @@
|
||||
|
||||
import {View, Injectable, NgFor, NgIf} from 'angular2/angular2';
|
||||
|
||||
import {TapClick} from '../button/button';
|
||||
import {Icon} from '../icon/icon';
|
||||
import {Overlay} from '../overlay/overlay';
|
||||
import {Animation} from '../../animations/animation';
|
||||
@ -75,7 +74,7 @@ import * as util from 'ionic/util';
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'</action-menu-wrapper>',
|
||||
directives: [NgFor, NgIf, TapClick, Icon]
|
||||
directives: [NgFor, NgIf, Icon]
|
||||
})
|
||||
class ActionMenuDirective {
|
||||
|
||||
|
@ -6,6 +6,7 @@ import {Platform} from '../../platform/platform';
|
||||
import * as util from '../../util/util';
|
||||
|
||||
// injectables
|
||||
import {Activator} from '../../util/activator';
|
||||
import {ActionMenu} from '../action-menu/action-menu';
|
||||
import {Modal} from '../modal/modal';
|
||||
import {Popup} from '../popup/popup';
|
||||
@ -272,6 +273,7 @@ export function ionicBootstrap(rootComponentType, config) {
|
||||
Platform.prepareReady(config);
|
||||
|
||||
// TODO: probs need a better way to inject global injectables
|
||||
let activator = new Activator(app, config, window, document);
|
||||
let actionMenu = new ActionMenu(app, config);
|
||||
let modal = new Modal(app, config);
|
||||
let popup = new Popup(app, config);
|
||||
@ -280,6 +282,7 @@ export function ionicBootstrap(rootComponentType, config) {
|
||||
let appBindings = Injector.resolve([
|
||||
bind(IonicApp).toValue(app),
|
||||
bind(IonicConfig).toValue(config),
|
||||
bind(Activator).toValue(activator),
|
||||
bind(ActionMenu).toValue(actionMenu),
|
||||
bind(Modal).toValue(modal),
|
||||
bind(Popup).toValue(popup),
|
||||
|
@ -4,7 +4,13 @@ import {App} from 'ionic/ionic';
|
||||
@App({
|
||||
templateUrl: 'main.html'
|
||||
})
|
||||
class E2EApp {}
|
||||
class E2EApp {
|
||||
|
||||
tapTest(eleType) {
|
||||
console.debug('test click', eleType);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
function onEvent(ev) {
|
||||
@ -74,6 +80,8 @@ console.debug = function() {
|
||||
|
||||
if(arguments[0] === 'click') msg = '<span style="color:purple">' + msg + '</span>';
|
||||
|
||||
if(arguments[0] === 'test click') msg = '<span style="color:orange">' + msg + '</span>';
|
||||
|
||||
msgs.unshift( msg );
|
||||
|
||||
if(msgs.length > 25) {
|
||||
|
@ -1,6 +1,41 @@
|
||||
|
||||
<button>
|
||||
<div><div><p>TAP ME</p></div></div>
|
||||
</button>
|
||||
<ion-row>
|
||||
|
||||
<ion-col>
|
||||
<button (^click)="tapTest('button')" block>
|
||||
<div><div><p>Button</p></div></div>
|
||||
</button>
|
||||
</ion-col>
|
||||
|
||||
<ion-col>
|
||||
<a button (^click)="tapTest('link')" block>
|
||||
Link
|
||||
</a>
|
||||
</ion-col>
|
||||
|
||||
</ion-row>
|
||||
|
||||
<ion-row>
|
||||
|
||||
<ion-col>
|
||||
<div button (^click)="tapTest('div')" block>
|
||||
Div w/ (click)
|
||||
</div>
|
||||
</ion-col>
|
||||
|
||||
<ion-col>
|
||||
<div button block>
|
||||
Div w/out (click)
|
||||
</div>
|
||||
</ion-col>
|
||||
|
||||
</ion-row>
|
||||
|
||||
|
||||
<div id="logs"></div>
|
||||
|
||||
<style>
|
||||
.activated {
|
||||
background-color: yellow !important;
|
||||
}
|
||||
</style>
|
||||
|
@ -1,9 +1,5 @@
|
||||
import {Directive, ElementRef, Optional, Host, onDestroy, NgZone, Query, QueryList} from 'angular2/angular2';
|
||||
import {Directive} from 'angular2/angular2';
|
||||
|
||||
import {Icon} from '../icon/icon';
|
||||
import {IonicConfig} from '../../config/config';
|
||||
import {Activator} from '../../util/activator';
|
||||
import * as dom from '../../util/dom';
|
||||
|
||||
/**
|
||||
* TODO
|
||||
@ -17,9 +13,7 @@ import * as dom from '../../util/dom';
|
||||
}
|
||||
})
|
||||
export class Button {
|
||||
/**
|
||||
* TODO
|
||||
*/
|
||||
|
||||
constructor() {
|
||||
this.iconLeft = this.iconRight = this.iconOnly = false;
|
||||
}
|
||||
@ -34,190 +28,3 @@ export class Button {
|
||||
this.iconOnly = icon.iconOnly;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO
|
||||
*/
|
||||
@Directive({
|
||||
selector: '[tap-disabled]'
|
||||
})
|
||||
export class TapDisabled {}
|
||||
|
||||
/**
|
||||
* TODO
|
||||
*/
|
||||
@Directive({
|
||||
selector: 'button,[button],[tappable],ion-checkbox,ion-radio',
|
||||
host: {
|
||||
'(^touchstart)': 'touchStart($event)',
|
||||
'(^touchend)': 'touchEnd($event)',
|
||||
'(^touchcancel)': 'pointerCancel()',
|
||||
'(^mousedown)': 'mouseDown($event)',
|
||||
'(^mouseup)': 'mouseUp($event)',
|
||||
'(^click)': 'click($event)',
|
||||
}
|
||||
})
|
||||
export class TapClick {
|
||||
/**
|
||||
* TODO
|
||||
* @param {ElementRef} elementRef TODO
|
||||
* @param {IonicConfig} config TODO
|
||||
* @param {NgZone} ngZone TODO
|
||||
* @param {TapDisabled=} tapDisabled TODO
|
||||
*/
|
||||
constructor(
|
||||
elementRef: ElementRef,
|
||||
config: IonicConfig,
|
||||
ngZone: NgZone,
|
||||
@Optional() @Host() tapDisabled: TapDisabled
|
||||
) {
|
||||
this.ele = elementRef.nativeElement;
|
||||
this.tapEnabled = !tapDisabled;
|
||||
this.tapPolyfill = config.setting('tapPolyfill');
|
||||
this.zone = ngZone;
|
||||
|
||||
let self = this;
|
||||
self.pointerMove = function(ev) {
|
||||
let moveCoord = dom.pointerCoord(ev);
|
||||
console.log('pointerMove', moveCoord, self.start)
|
||||
|
||||
if ( dom.hasPointerMoved(10, self.start, moveCoord) ) {
|
||||
self.pointerCancel();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO
|
||||
* @param {TODO} ev TODO
|
||||
*/
|
||||
touchStart(ev) {
|
||||
this.pointerStart(ev);
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO
|
||||
* @param {TODO} ev TODO
|
||||
*/
|
||||
touchEnd(ev) {
|
||||
let self = this;
|
||||
|
||||
if (this.tapPolyfill && this.tapEnabled) {
|
||||
|
||||
let endCoord = dom.pointerCoord(ev);
|
||||
|
||||
this.disableClick = true;
|
||||
this.zone.runOutsideAngular(() => {
|
||||
clearTimeout(self.disableTimer);
|
||||
self.disableTimer = setTimeout(() => {
|
||||
self.disableClick = false;
|
||||
}, 600);
|
||||
});
|
||||
|
||||
if ( this.start && !dom.hasPointerMoved(3, this.start, endCoord) ) {
|
||||
let clickEvent = document.createEvent('MouseEvents');
|
||||
clickEvent.initMouseEvent('click', true, true, window, 1, 0, 0, endCoord.x, endCoord.y, false, false, false, false, 0, null);
|
||||
clickEvent.isIonicTap = true;
|
||||
this.ele.dispatchEvent(clickEvent);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
this.pointerEnd();
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO
|
||||
* @param {TODO} ev TODO
|
||||
*/
|
||||
mouseDown(ev) {
|
||||
if (this.disableClick) {
|
||||
ev.preventDefault();
|
||||
ev.stopPropagation();
|
||||
|
||||
} else {
|
||||
this.pointerStart(ev);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO
|
||||
* @param {TODO} ev TODO
|
||||
*/
|
||||
mouseUp(ev) {
|
||||
if (this.disableClick) {
|
||||
ev.preventDefault();
|
||||
ev.stopPropagation();
|
||||
}
|
||||
|
||||
this.pointerEnd();
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO
|
||||
* @param {TODO} ev TODO
|
||||
*/
|
||||
pointerStart(ev) {
|
||||
this.start = dom.pointerCoord(ev);
|
||||
|
||||
this.zone.runOutsideAngular(() => {
|
||||
Activator.start(ev.currentTarget);
|
||||
Activator.moveListeners(this.pointerMove, true);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO
|
||||
*/
|
||||
pointerEnd() {
|
||||
this.zone.runOutsideAngular(() => {
|
||||
Activator.end();
|
||||
Activator.moveListeners(this.pointerMove, false);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO
|
||||
*/
|
||||
pointerCancel() {
|
||||
this.start = null;
|
||||
|
||||
this.zone.runOutsideAngular(() => {
|
||||
Activator.clear();
|
||||
Activator.moveListeners(this.pointerMove, false);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether the supplied click event should be allowed or not.
|
||||
* @param {MouseEvent} ev The click event.
|
||||
* @return {boolean} True if click event should be allowed, otherwise false.
|
||||
*/
|
||||
allowClick(ev) {
|
||||
if (!ev.isIonicTap) {
|
||||
if (this.disableClick || !this.start) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO
|
||||
* @param {MouseEvent} ev TODO
|
||||
*/
|
||||
click(ev) {
|
||||
if (!this.allowClick(ev)) {
|
||||
ev.preventDefault();
|
||||
ev.stopPropagation();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO
|
||||
*/
|
||||
onDestroy() {
|
||||
this.ele = null;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -10,7 +10,6 @@ import {Ion} from '../ion';
|
||||
import {IonInput} from '../form/input';
|
||||
import {IonicConfig} from '../../config/config';
|
||||
import {IonicComponent, IonicView} from '../../config/annotations';
|
||||
import {TapClick} from '../button/button';
|
||||
|
||||
/**
|
||||
* @name ionCheckbox
|
||||
@ -37,6 +36,7 @@ import {TapClick} from '../button/button';
|
||||
host: {
|
||||
'class': 'item',
|
||||
'role': 'checkbox',
|
||||
'tappable': 'true',
|
||||
'[attr.tab-index]': 'tabIndex',
|
||||
'[attr.aria-checked]': 'checked',
|
||||
'[attr.aria-disabled]': 'disabled',
|
||||
@ -59,16 +59,13 @@ export class Checkbox extends Ion {
|
||||
* @param {ElementRef} elementRef TODO
|
||||
* @param {IonicConfig} ionicConfig TODO
|
||||
* @param {NgControl=} ngControl TODO
|
||||
* @param {TapClick=} tapClick TODO
|
||||
*/
|
||||
constructor(
|
||||
elementRef: ElementRef,
|
||||
config: IonicConfig,
|
||||
@Optional() ngControl: NgControl,
|
||||
tapClick: TapClick
|
||||
@Optional() ngControl: NgControl
|
||||
) {
|
||||
super(elementRef, config);
|
||||
this.tapClick = tapClick;
|
||||
this.tabIndex = 0;
|
||||
this.id = IonInput.nextId();
|
||||
|
||||
@ -102,11 +99,9 @@ export class Checkbox extends Ion {
|
||||
* @param {MouseEvent} ev The click event.
|
||||
*/
|
||||
click(ev) {
|
||||
if (this.tapClick.allowClick(ev)) {
|
||||
ev.preventDefault();
|
||||
ev.stopPropagation();
|
||||
this.toggle();
|
||||
}
|
||||
ev.preventDefault();
|
||||
ev.stopPropagation();
|
||||
this.toggle();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -3,7 +3,6 @@ import {ElementRef, Host, Optional, NgControl, Query, QueryList} from 'angular2/
|
||||
import {IonicDirective, IonicComponent, IonicView} from '../../config/annotations';
|
||||
import {IonicConfig} from '../../config/config';
|
||||
import {Ion} from '../ion';
|
||||
import {TapClick} from '../button/button';
|
||||
import {ListHeader} from '../list/list';
|
||||
|
||||
|
||||
@ -11,37 +10,37 @@ import {ListHeader} from '../list/list';
|
||||
* @name ionRadioGroup
|
||||
* @classdesc
|
||||
* A radio group is a group of radio components.
|
||||
*
|
||||
*
|
||||
* Selecting a radio button in the group unselects all others in the group.
|
||||
*
|
||||
* New radios can be registered dynamically.
|
||||
*
|
||||
* New radios can be registered dynamically.
|
||||
*
|
||||
* See the [Angular 2 Docs](https://angular.io/docs/js/latest/api/forms/) for more info on forms and input.
|
||||
*
|
||||
*
|
||||
* @example
|
||||
* ```html
|
||||
* <ion-radio-group ng-control="clientside">
|
||||
*
|
||||
*
|
||||
* <ion-header>
|
||||
* Clientside
|
||||
* </ion-header>
|
||||
*
|
||||
*
|
||||
* <ion-radio value="ember">
|
||||
* Ember
|
||||
* </ion-radio>
|
||||
*
|
||||
*
|
||||
* <ion-radio value="angular1">
|
||||
* Angular 1
|
||||
* </ion-radio>
|
||||
*
|
||||
*
|
||||
* <ion-radio value="angular2" checked="true">
|
||||
* Angular 2
|
||||
* </ion-radio>
|
||||
*
|
||||
*
|
||||
* <ion-radio value="react">
|
||||
* React
|
||||
* </ion-radio>
|
||||
*
|
||||
*
|
||||
* </ion-radio-group>
|
||||
* ```
|
||||
*/
|
||||
@ -153,7 +152,7 @@ export class RadioGroup extends Ion {
|
||||
/**
|
||||
* @name ionRadio
|
||||
* @classdesc
|
||||
* A single radio component.
|
||||
* A single radio component.
|
||||
*
|
||||
* See the [Angular 2 Docs](https://angular.io/docs/js/latest/api/forms/) for more info on forms and input.
|
||||
*
|
||||
@ -176,6 +175,7 @@ export class RadioGroup extends Ion {
|
||||
host: {
|
||||
'class': 'item',
|
||||
'role': 'radio',
|
||||
'tappable': 'true',
|
||||
'[attr.id]': 'id',
|
||||
'[attr.tab-index]': 'tabIndex',
|
||||
'[attr.aria-checked]': 'checked',
|
||||
@ -199,16 +199,13 @@ export class RadioButton extends Ion {
|
||||
* @param {RadioGroup=} group The parent radio group, if any.
|
||||
* @param {ElementRef} elementRef TODO
|
||||
* @param {IonicConfig} config TODO
|
||||
* @param {TapClick} tapClick TODO
|
||||
*/
|
||||
constructor(
|
||||
@Host() @Optional() group: RadioGroup,
|
||||
elementRef: ElementRef,
|
||||
config: IonicConfig,
|
||||
tapClick: TapClick
|
||||
config: IonicConfig
|
||||
) {
|
||||
super(elementRef, config);
|
||||
this.tapClick = tapClick;
|
||||
super(elementRef, config)
|
||||
this.group = group;
|
||||
this.tabIndex = 0;
|
||||
}
|
||||
@ -220,11 +217,9 @@ export class RadioButton extends Ion {
|
||||
}
|
||||
|
||||
click(ev) {
|
||||
if (this.tapClick.allowClick(ev)) {
|
||||
ev.preventDefault();
|
||||
ev.stopPropagation();
|
||||
this.check();
|
||||
}
|
||||
ev.preventDefault();
|
||||
ev.stopPropagation();
|
||||
this.check();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -23,6 +23,7 @@ import {pointerCoord} from '../../util/dom';
|
||||
@Directive({
|
||||
selector: '.media-switch',
|
||||
host: {
|
||||
'tappable': 'true',
|
||||
'(^touchstart)': 'swtch.pointerDown($event)',
|
||||
'(^mousedown)': 'swtch.pointerDown($event)',
|
||||
'[class.activated]': 'swtch.isActivated'
|
||||
|
@ -15,7 +15,6 @@ import {
|
||||
Segment, SegmentButton, SegmentControlValueAccessor,
|
||||
RadioGroup, RadioButton, SearchBar,
|
||||
Nav, NavbarTemplate, Navbar, NavPush, NavPop, NavRouter,
|
||||
TapClick, TapDisabled,
|
||||
IdRef,
|
||||
ShowWhen, HideWhen,
|
||||
|
||||
@ -87,10 +86,6 @@ export const IonicDirectives = [
|
||||
forwardRef(() => ShowWhen),
|
||||
forwardRef(() => HideWhen),
|
||||
|
||||
// Gestures
|
||||
forwardRef(() => TapClick),
|
||||
forwardRef(() => TapDisabled),
|
||||
|
||||
// Material
|
||||
forwardRef(() => MaterialButton)
|
||||
];
|
||||
|
@ -1,61 +1,289 @@
|
||||
import {raf} from './dom';
|
||||
|
||||
var queueElements = {}; // elements that should get an active state in XX milliseconds
|
||||
var activeElements = {}; // elements that are currently active
|
||||
var keyId = 0; // a counter for unique keys for the above ojects
|
||||
var ACTIVATED_CLASS = 'activated';
|
||||
var DEACTIVATE_TIMEOUT = 180;
|
||||
import {raf, pointerCoord, hasPointerMoved} from './dom';
|
||||
|
||||
|
||||
export class Activator {
|
||||
|
||||
static start(ele) {
|
||||
queueElements[++keyId] = ele;
|
||||
if (keyId > 9) keyId = 0;
|
||||
raf(Activator.activate);
|
||||
constructor(app: IonicApp, config: IonicConfig, window, document) {
|
||||
const self = this;
|
||||
self.app = app;
|
||||
self.config = config;
|
||||
self.win = window;
|
||||
self.doc = document;
|
||||
|
||||
self.id = 0;
|
||||
self.queue = {};
|
||||
self.active = {};
|
||||
self.activatedClass = 'activated';
|
||||
self.deactivateTimeout = 180;
|
||||
self.pointerTolerance = 4;
|
||||
self.isTouch = false;
|
||||
self.disableClick = 0;
|
||||
self.disableClickLimit = 2500;
|
||||
|
||||
self.tapPolyfill = config.setting('tapPolyfill');
|
||||
|
||||
function bindDom(type, listener, useCapture) {
|
||||
document.addEventListener(type, listener, useCapture);
|
||||
}
|
||||
|
||||
bindDom('click', function(ev) {
|
||||
self.click(ev);
|
||||
}, true);
|
||||
|
||||
bindDom('touchstart', function(ev) {
|
||||
self.isTouch = true;
|
||||
self.pointerStart(ev);
|
||||
});
|
||||
|
||||
bindDom('touchend', function(ev) {
|
||||
self.isTouch = true;
|
||||
self.touchEnd(ev);
|
||||
});
|
||||
|
||||
bindDom('touchcancel', function(ev) {
|
||||
self.isTouch = true;
|
||||
self.touchCancel(ev);
|
||||
});
|
||||
|
||||
bindDom('mousedown', function(ev) {
|
||||
self.mouseDown(ev);
|
||||
}, true);
|
||||
|
||||
bindDom('mouseup', function(ev) {
|
||||
self.mouseUp(ev);
|
||||
}, true);
|
||||
|
||||
|
||||
self.pointerMove = function(ev) {
|
||||
let moveCoord = pointerCoord(ev);
|
||||
console.log('pointerMove', moveCoord, self.start)
|
||||
|
||||
if ( hasPointerMoved(10, self.start, moveCoord) ) {
|
||||
self.pointerCancel();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
self.moveListeners = function(shouldAdd) {
|
||||
document.removeEventListener('touchmove', self.pointerMove);
|
||||
document.removeEventListener('mousemove', self.pointerMove);
|
||||
|
||||
if (shouldAdd) {
|
||||
bindDom('touchmove', self.pointerMove);
|
||||
bindDom('mousemove', self.pointerMove);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
static activate() {
|
||||
// activate all elements in the queue
|
||||
for (var key in queueElements) {
|
||||
if (queueElements[key]) {
|
||||
queueElements[key].classList.add(ACTIVATED_CLASS);
|
||||
activeElements[key] = queueElements[key];
|
||||
|
||||
/**
|
||||
* TODO
|
||||
* @param {TODO} ev TODO
|
||||
*/
|
||||
touchEnd(ev) {
|
||||
let self = this;
|
||||
|
||||
if (self.tapPolyfill && self.start) {
|
||||
let endCoord = pointerCoord(ev);
|
||||
|
||||
if (!hasPointerMoved(self.pointerTolerance, self.start, endCoord)) {
|
||||
console.debug('create click');
|
||||
|
||||
self.disableClick = Date.now();
|
||||
|
||||
let clickEvent = self.doc.createEvent('MouseEvents');
|
||||
clickEvent.initMouseEvent('click', true, true, self.win, 1, 0, 0, endCoord.x, endCoord.y, false, false, false, false, 0, null);
|
||||
clickEvent.isIonicTap = true;
|
||||
ev.target.dispatchEvent(clickEvent);
|
||||
}
|
||||
}
|
||||
queueElements = {};
|
||||
|
||||
self.pointerEnd(ev);
|
||||
}
|
||||
|
||||
static end() {
|
||||
setTimeout(Activator.clear, DEACTIVATE_TIMEOUT);
|
||||
/**
|
||||
* TODO
|
||||
* @param {TODO} ev TODO
|
||||
*/
|
||||
mouseDown(ev) {
|
||||
if (this.isDisabledClick()) {
|
||||
console.debug('mouseDown prevent');
|
||||
preventEvent(ev);
|
||||
|
||||
} else if (!self.isTouch) {
|
||||
this.pointerStart(ev);
|
||||
}
|
||||
}
|
||||
|
||||
static clear() {
|
||||
/**
|
||||
* TODO
|
||||
* @param {TODO} ev TODO
|
||||
*/
|
||||
mouseUp(ev) {
|
||||
if (this.isDisabledClick()) {
|
||||
console.debug('mouseUp prevent');
|
||||
preventEvent(ev);
|
||||
}
|
||||
|
||||
if (!self.isTouch) {
|
||||
this.pointerEnd(ev);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO
|
||||
* @param {TODO} ev TODO
|
||||
*/
|
||||
pointerStart(ev) {
|
||||
let targetEle = this.getActivatableTarget(ev.target);
|
||||
|
||||
if (targetEle) {
|
||||
this.start = pointerCoord(ev);
|
||||
|
||||
this.queueActivate(targetEle);
|
||||
this.moveListeners(true);
|
||||
|
||||
} else {
|
||||
this.start = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO
|
||||
*/
|
||||
pointerEnd(ev) {
|
||||
this.endActive();
|
||||
this.moveListeners(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO
|
||||
*/
|
||||
pointerCancel() {
|
||||
console.debug('pointerCancel')
|
||||
this.clearActive();
|
||||
this.moveListeners(false);
|
||||
this.disableClick = Date.now();
|
||||
}
|
||||
|
||||
isDisabledClick() {
|
||||
return this.disableClick + this.disableClickLimit > Date.now();
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether the supplied click event should be allowed or not.
|
||||
* @param {MouseEvent} ev The click event.
|
||||
* @return {boolean} True if click event should be allowed, otherwise false.
|
||||
*/
|
||||
allowClick(ev) {
|
||||
if (!ev.isIonicTap) {
|
||||
if (this.isDisabledClick()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO
|
||||
* @param {MouseEvent} ev TODO
|
||||
*/
|
||||
click(ev) {
|
||||
if (!this.allowClick(ev)) {
|
||||
console.debug('click prevent');
|
||||
preventEvent(ev);
|
||||
}
|
||||
this.isTouch = false;
|
||||
}
|
||||
|
||||
getActivatableTarget(ele) {
|
||||
var targetEle = ele;
|
||||
for (var x = 0; x < 4; x++) {
|
||||
if (!targetEle) break;
|
||||
if (this.isActivatable(targetEle)) return targetEle;
|
||||
targetEle = targetEle.parentElement;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
isActivatable(ele) {
|
||||
if (/^(A|BUTTON)$/.test(ele.tagName)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
let attributes = ele.attributes;
|
||||
for (let i = 0, l = attributes.length; i < l; i++) {
|
||||
if (/click|tappable/.test(attributes[i].name)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
queueActivate(ele) {
|
||||
const self = this;
|
||||
|
||||
self.queue[++self.id] = ele;
|
||||
if (self.id > 19) self.id = 0;
|
||||
|
||||
raf(function(){
|
||||
// activate all elements in the queue
|
||||
for (var key in self.queue) {
|
||||
if (self.queue[key]) {
|
||||
self.queue[key].classList.add(self.activatedClass);
|
||||
self.active[key] = self.queue[key];
|
||||
}
|
||||
}
|
||||
self.queue = {};
|
||||
});
|
||||
}
|
||||
|
||||
endActive() {
|
||||
const self = this;
|
||||
|
||||
setTimeout(function() {
|
||||
self.clearActive();
|
||||
}, this.deactivateTimeout);
|
||||
}
|
||||
|
||||
clearActive() {
|
||||
const self = this;
|
||||
|
||||
// clear out any elements that are queued to be set to active
|
||||
queueElements = {};
|
||||
self.queue = {};
|
||||
|
||||
// in the next frame, remove the active class from all active elements
|
||||
raf(Activator.deactivate);
|
||||
}
|
||||
|
||||
static deactivate() {
|
||||
|
||||
for (var key in activeElements) {
|
||||
if (activeElements[key]) {
|
||||
activeElements[key].classList.remove(ACTIVATED_CLASS);
|
||||
raf(function() {
|
||||
for (var key in self.active) {
|
||||
if (self.active[key]) {
|
||||
self.active[key].classList.remove(self.activatedClass);
|
||||
}
|
||||
delete self.active[key];
|
||||
}
|
||||
delete activeElements[key];
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
static moveListeners(pointerMove, shouldAdd) {
|
||||
document.removeEventListener('touchmove', pointerMove);
|
||||
document.removeEventListener('mousemove', pointerMove);
|
||||
clickBlock(enable) {
|
||||
console.log('clickBlock', enable);
|
||||
|
||||
if (shouldAdd) {
|
||||
document.addEventListener('touchmove', pointerMove);
|
||||
document.addEventListener('mousemove', pointerMove);
|
||||
this.doc.removeEventListener('click', preventEvent, true);
|
||||
this.doc.removeEventListener('touchmove', preventEvent, true);
|
||||
this.doc.removeEventListener('touchstart', preventEvent, true);
|
||||
this.doc.removeEventListener('touchend', preventEvent, true);
|
||||
|
||||
if (enable) {
|
||||
this.doc.addEventListener('click', preventEvent, true);
|
||||
this.doc.addEventListener('touchmove', preventEvent, true);
|
||||
this.doc.addEventListener('touchstart', preventEvent, true);
|
||||
this.doc.addEventListener('touchend', preventEvent, true);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function preventEvent(ev) {
|
||||
ev.preventDefault();
|
||||
ev.stopPropagation();
|
||||
}
|
||||
|
Reference in New Issue
Block a user