the activator

This commit is contained in:
Adam Bradley
2015-07-23 00:51:29 -05:00
parent d67ba6f7c1
commit 96a84e593b
10 changed files with 274 additions and 34 deletions

View File

@ -36,7 +36,6 @@ $action-menu-ios-icon-font-size: 1.4em !default;
background: transparent; background: transparent;
&:active,
&.activated { &.activated {
background: $action-menu-ios-background-active; background: $action-menu-ios-background-active;
} }

View File

@ -55,7 +55,6 @@ $action-menu-md-icon-font-size: 2.4rem !default;
font-weight: normal; font-weight: normal;
min-height: $action-menu-md-height; min-height: $action-menu-md-height;
&:active,
&.activated { &.activated {
background: $action-menu-md-background-active; background: $action-menu-md-background-active;
} }

View File

@ -0,0 +1,94 @@
import {App} from 'ionic/ionic';
@App({
templateUrl: 'main.html'
})
class IonicApp {}
function onEvent(ev) {
var c = pointerCoord(ev);
var l = '(' + c.x + ',' + c.y + ')';
if (ev.isIonicTap) {
l += ' isIonicTap';
}
console.debug(ev.type, l);
}
function pointerCoord(ev) {
// get coordinates for either a mouse click
// or a touch depending on the given event
let c = { x: 0, y: 0 };
if (ev) {
const touches = ev.touches && ev.touches.length ? ev.touches : [ev];
const e = (ev.changedTouches && ev.changedTouches[0]) || touches[0];
if (e) {
c.x = e.clientX || e.pageX || 0;
c.y = e.clientY || e.pageY || 0;
}
}
return c;
}
document.addEventListener('touchstart', onEvent);
document.addEventListener('touchcancel', onEvent);
document.addEventListener('touchend', onEvent);
document.addEventListener('mousedown', onEvent);
document.addEventListener('mouseup', onEvent);
document.addEventListener('click', onEvent);
var msgs = [];
var index = 0;
var timeId;
var winConsoleError = console.error;
console.error = function() {
winConsoleError.apply(this, arguments);
var args = ['ERROR!'];
for (var i = 0, j = arguments.length; i < j; i++){
args.push(arguments[i]);
}
console.debug.apply(this, args);
};
console.debug = function() {
index++;
var msg = [];
msg.push(index);
for (var i = 0, j = arguments.length; i < j; i++){
msg.push(arguments[i]);
}
msg.push(getTime());
msg = msg.join(', ');
if(arguments[0] === 'ERROR!') msg = '<span style="color:red;font-weight:bold">' + msg + '</span>';
if(arguments[0] === 'touchstart') msg = '<span style="color:blue">' + msg + '</span>';
if(arguments[0] === 'touchend') msg = '<span style="color:darkblue">' + msg + '</span>';
if(arguments[0] === 'mousedown') msg = '<span style="color:red">' + msg + '</span>';
if(arguments[0] === 'mouseup') msg = '<span style="color:maroon">' + msg + '</span>';
if(arguments[0] === 'click') msg = '<span style="color:purple">' + msg + '</span>';
msgs.unshift( msg );
if(msgs.length > 25) {
msgs.splice(25);
}
// do this so we try not to interfere with the device performance
clearTimeout(timeId);
timeId = setTimeout(function(){
document.getElementById('logs').innerHTML = msgs.join('<br>');
}, 100);
}
function getTime() {
var d = new Date();
return d.getSeconds() + '.' + d.getMilliseconds();
}

View File

@ -0,0 +1,6 @@
<button primary>
<div><div><p>TAP ME</p></div></div>
</button>
<div id="logs"></div>

View File

@ -247,7 +247,6 @@ a[button] {
text-decoration: none; text-decoration: none;
} }
&:active,
&.activated { &.activated {
opacity: 1; opacity: 1;
background-color: darken($bg-color, 12%); background-color: darken($bg-color, 12%);

View File

@ -1,16 +1,15 @@
import {Directive, ElementRef, Optional, Ancestor, onDestroy} from 'angular2/angular2'; import {Directive, ElementRef, Optional, Ancestor, onDestroy, NgZone} from 'angular2/angular2';
import {IonicConfig} from '../../config/config'; import {IonicConfig} from '../../config/config';
import {Gesture} from '../../gestures/gesture'; import {Activator} from '../../util/activator';
import * as dom from '../../util/dom'; import * as dom from '../../util/dom';
@Directive({ @Directive({
selector: 'button,[button]' selector: 'button,[button]'
}) })
export class Button { export class Button {}
constructor(elementRef: ElementRef, config: IonicConfig) {
}
}
@Directive({ @Directive({
selector: '[tap-disabled]' selector: '[tap-disabled]'
@ -19,43 +18,126 @@ export class TapDisabled {}
@Directive({ @Directive({
selector: 'a,button,[tappable]' selector: 'a,button,[tappable]',
host: {
'(^touchstart)': 'touchStart($event)',
'(^touchend)': 'touchEnd($event)',
'(^touchcancel)': 'pointerCancel()',
'(^mousedown)': 'mouseDown($event)',
'(^mouseup)': 'mouseUp($event)',
'(^click)': 'click($event)',
}
}) })
export class TapClick { export class TapClick {
constructor( constructor(
elementRef: ElementRef, elementRef: ElementRef,
config: IonicConfig, config: IonicConfig,
ngZone: NgZone,
@Optional() @Ancestor() tapDisabled: TapDisabled @Optional() @Ancestor() tapDisabled: TapDisabled
) { ) {
this.ele = elementRef.nativeElement;
this.tapEnabled = !tapDisabled;
this.tapPolyfill = config.setting('tapPolyfill');
this.zone = ngZone;
if (config.setting('tapPolyfill') && !this.tapGesture && !tapDisabled) { let self = this;
this.tapGesture = new Gesture(elementRef.nativeElement); self.pointerMove = function(ev) {
this.tapGesture.listen(); let moveCoord = dom.pointerCoord(ev);
console.log('pointerMove', moveCoord, self.start)
this.tapGesture.on('tap', (gestureEv) => { if ( dom.hasPointerMoved(10, self.start, moveCoord) ) {
this.onTap(gestureEv.gesture.srcEvent); self.pointerCancel();
}
};
}
touchStart(ev) {
this.pointerStart(ev);
}
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);
} }
} }
onTap(ev) { this.pointerEnd();
if (ev && this.tapGesture) { }
mouseDown(ev) {
if (this.disableClick) {
ev.preventDefault(); ev.preventDefault();
ev.stopPropagation(); ev.stopPropagation();
let c = dom.pointerCoord(ev); } else {
this.pointerStart(ev);
}
}
let clickEvent = document.createEvent("MouseEvents"); mouseUp(ev) {
clickEvent.initMouseEvent('click', true, true, window, 1, 0, 0, c.x, c.y, false, false, false, false, 0, null); if (this.disableClick) {
clickEvent.isIonicTap = true; ev.preventDefault();
this.tapGesture.element.dispatchEvent(clickEvent); ev.stopPropagation();
}
this.pointerEnd();
}
pointerStart(ev) {
this.start = dom.pointerCoord(ev);
this.zone.runOutsideAngular(() => {
Activator.start(ev.currentTarget);
Activator.moveListeners(this.pointerMove, true);
});
}
pointerEnd() {
this.zone.runOutsideAngular(() => {
Activator.end();
Activator.moveListeners(this.pointerMove, false);
});
}
pointerCancel() {
this.start = null;
this.zone.runOutsideAngular(() => {
Activator.clear();
Activator.moveListeners(this.pointerMove, false);
});
}
click(ev) {
if (!ev.isIonicTap) {
if (this.disableClick || !this.start) {
ev.preventDefault();
ev.stopPropagation();
}
} }
} }
onDestroy() { onDestroy() {
this.tapGesture && this.tapGesture.destroy(); this.ele = null;
} }
} }

View File

@ -28,7 +28,7 @@ $button-material-border-radius: 3px !default;
background-color 0.2s $animation-curve-default, background-color 0.2s $animation-curve-default,
color 0.2s $animation-curve-default; color 0.2s $animation-curve-default;
&:active, &.activated { &.activated {
box-shadow: $button-material-box-shadow-active; box-shadow: $button-material-box-shadow-active;
} }
@ -68,7 +68,6 @@ $button-material-border-radius: 3px !default;
} }
} }
&:active,
&.activated { &.activated {
opacity: 1; opacity: 1;
background-color: get-color($color, base); background-color: get-color($color, base);
@ -84,7 +83,7 @@ $button-material-border-radius: 3px !default;
background-color: get-color($color, base); background-color: get-color($color, base);
} }
} }
&:active,
&.activated { &.activated {
opacity: 1; opacity: 1;
background: transparent; background: transparent;
@ -98,10 +97,11 @@ $button-material-border-radius: 3px !default;
color: get-color($color, inverse); color: get-color($color, inverse);
} }
&:hover, &.hover { &:hover,
&.hover {
background-color: rgba(158, 158, 158, 0.2); background-color: rgba(158, 158, 158, 0.2);
} }
&:active, &.active { &:activated {
background-color: rgba(158, 158, 158, 0.4); background-color: rgba(158, 158, 158, 0.4);
} }
} }

View File

@ -3,7 +3,7 @@
// -------------------------------------------------- // --------------------------------------------------
$toolbar-material-title-font-size: 2rem !default; $toolbar-material-title-font-size: 2rem !default;
$toolbar-material-button-font-size: 1.8rem !default; $toolbar-material-button-font-size: 1.4rem !default;
.toolbar[mode="md"] { .toolbar[mode="md"] {

61
ionic/util/activator.ts Normal file
View File

@ -0,0 +1,61 @@
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;
export class Activator {
static start(ele) {
queueElements[++keyId] = ele;
if (keyId > 9) keyId = 0;
raf(Activator.activate);
}
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];
}
}
queueElements = {};
}
static end() {
setTimeout(Activator.clear, DEACTIVATE_TIMEOUT);
}
static clear() {
// clear out any elements that are queued to be set to active
queueElements = {};
// 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);
}
delete activeElements[key];
}
}
static moveListeners(pointerMove, shouldAdd) {
document.removeEventListener('touchmove', pointerMove);
document.removeEventListener('mousemove', pointerMove);
if (shouldAdd) {
document.addEventListener('touchmove', pointerMove);
document.addEventListener('mousemove', pointerMove);
}
}
}

View File

@ -174,9 +174,9 @@ export function pointerCoord(ev) {
return c; return c;
} }
export function hasPointerMoved(tolerance, startCoord, endCoord) { export function hasPointerMoved(threshold, startCoord, endCoord) {
return startCoord && endCoord && return startCoord && endCoord &&
(Math.abs(startCoord.x - endCoord.x) > tolerance || Math.abs(startCoord.y - endCoord.y) > tolerance); (Math.abs(startCoord.x - endCoord.x) > threshold || Math.abs(startCoord.y - endCoord.y) > threshold);
} }
export function hasFocus(ele) { export function hasFocus(ele) {