Skip to content

Commit

Permalink
Merge pull request #1843 from Polymer/fix-drag-selection
Browse files Browse the repository at this point in the history
Allow user prevention of `tap` and `track` gestures from `down`
  • Loading branch information
Steve Orvell committed Jun 17, 2015
2 parents 6e2d238 + 74a0a6a commit 7920729
Show file tree
Hide file tree
Showing 6 changed files with 184 additions and 69 deletions.
74 changes: 53 additions & 21 deletions src/standard/gestures.html
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,6 @@
}

var POINTERSTATE = {
tapPrevented: false,
mouse: {
target: null,
mouseIgnoreJob: null
Expand All @@ -99,7 +98,6 @@
return ta;
}


var Gestures = {
gestures: {},
recognizers: [],
Expand Down Expand Up @@ -252,6 +250,19 @@
}
},

findRecognizerByEvent: function(evName) {
for (var i = 0, r; i < this.recognizers.length; i++) {
r = this.recognizers[i];
for (var j = 0, n; j < r.emits.length; j++) {
n = r.emits[j];
if (n === evName) {
return r;
}
}
}
return null;
},

// set scrolling direction on node to check later on first move
// must call this before adding event listeners!
setTouchAction: function(node, value) {
Expand All @@ -262,12 +273,27 @@
},

fire: function(target, type, detail) {
var ev = new CustomEvent(type, {
detail: detail,
var ev = Polymer.Base.fire(type, detail, {
node: target,
bubbles: true,
cancelable: true
});
target.dispatchEvent(ev);

// forward `preventDefault` in a clean way
if (ev.defaultPrevented) {
var se = detail.sourceEvent;
// sourceEvent may be a touch, which is not preventable this way
if (se && se.preventDefault) {
se.preventDefault();
}
}
},

prevent: function(evName) {
var recognizer = this.findRecognizerByEvent(evName);
if (recognizer.info) {
recognizer.info.prevent = true;
}
}
};

Expand All @@ -293,10 +319,12 @@
this.fire('up', e.currentTarget, e.changedTouches[0]);
},
fire: function(type, target, event) {
var self = this;
Gestures.fire(target, type, {
x: event.clientX,
y: event.clientY,
sourceEvent: event
sourceEvent: event,
prevent: Gestures.prevent.bind(Gestures)
});
}
});
Expand All @@ -318,7 +346,8 @@
this.moves.shift();
}
this.moves.push(move);
}
},
prevent: false
},

clearInfo: function() {
Expand All @@ -327,9 +356,13 @@
this.info.moves = [];
this.info.x = 0;
this.info.y = 0;
this.info.prevent = false;
},

hasMovedEnough: function(x, y) {
if (this.info.prevent) {
return false;
}
if (this.info.started) {
return true;
}
Expand All @@ -348,13 +381,12 @@
self.info.state = self.info.started ? (e.type === 'mouseup' ? 'end' : 'track') : 'start';
self.info.addMove({x: x, y: y});
self.fire(t, e);
e.preventDefault();
self.info.started = true;
}
};
var upfn = function upfn(e) {
if (self.info.started) {
POINTERSTATE.tapPrevented = true;
Gestures.prevent('tap');
movefn(e);
}
self.clearInfo();
Expand Down Expand Up @@ -393,7 +425,7 @@
// only trackend if track was started and not aborted
if (this.info.started) {
// iff tracking, always prevent tap
POINTERSTATE.tapPrevented = true;
Gestures.prevent('tap');
// reset started state on up
this.info.state = 'end';
this.info.addMove({x: ct.clientX, y: ct.clientY});
Expand Down Expand Up @@ -433,21 +465,22 @@
name: 'tap',
deps: ['mousedown', 'click', 'touchstart', 'touchend'],
emits: ['tap'],
start: {
info: {
x: NaN,
y: NaN
y: NaN,
prevent: false
},
reset: function() {
this.start.x = NaN;
this.start.y = NaN;
this.info.x = NaN;
this.info.y = NaN;
this.info.prevent = false;
},
save: function(e) {
this.start.x = e.clientX;
this.start.y = e.clientY;
this.info.x = e.clientX;
this.info.y = e.clientY;
},

mousedown: function(e) {
POINTERSTATE.tapPrevented = false;
this.save(e);
},

Expand All @@ -456,20 +489,19 @@
},

touchstart: function(e) {
POINTERSTATE.tapPrevented = false;
this.save(e.changedTouches[0]);
},
touchend: function(e) {
this.forward(e.changedTouches[0]);
},

forward: function(e) {
var dx = Math.abs(e.clientX - this.start.x);
var dy = Math.abs(e.clientY - this.start.y);
var dx = Math.abs(e.clientX - this.info.x);
var dy = Math.abs(e.clientY - this.info.y);
// dx,dy can be NaN if `click` has been simulated and there was no `down` for `start`
if (isNaN(dx) || isNaN(dy) || (dx <= TAP_DISTANCE && dy <= TAP_DISTANCE)) {
// prevent taps from being generated if an event has canceled them
if (!POINTERSTATE.tapPrevented) {
if (!this.info.prevent) {
Gestures.fire(e.target, 'tap', {
x: e.clientX,
y: e.clientY,
Expand Down
3 changes: 2 additions & 1 deletion src/standard/utils.html
Original file line number Diff line number Diff line change
Expand Up @@ -158,9 +158,10 @@
var node = options.node || this;
var detail = (detail === null || detail === undefined) ? Polymer.nob : detail;
var bubbles = options.bubbles === undefined ? true : options.bubbles;
var cancelable = Boolean(options.cancelable);
var event = new CustomEvent(type, {
bubbles: Boolean(bubbles),
cancelable: Boolean(options.cancelable),
cancelable: cancelable,
detail: detail
});
node.dispatchEvent(event);
Expand Down
58 changes: 58 additions & 0 deletions test/smoke/gesture-import.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
<link rel="import" href="../../polymer.html">

<dom-module id="x-gestures">
<template>
<style>
#inner {
height: 20px;
width: 20px;
background: blue;
}
#prevent {
height: 20px;
width: 20px;
background: red;
}
</style>
<div id="prevent" on-down="preventTap"></div>
<a href="#" on-click="linkclick" on-touchend="removeLink">LINK</a>
<div id="inner" on-tap="divtap"></div>
</template>
</dom-module>
<script>
Polymer({
is: 'x-gestures',
listeners: {
'tap': 'logger',
'down': 'logger',
'up': 'logger',
'click': 'logger',
'track': 'track'
},
preventTap: function(e, detail) {
detail.prevent('tap');
detail.prevent('track');
e.preventDefault();
},
logger: function(e, detail) {
console.log(e.type);
console.log(detail);
},
track: function(e, detail) {
this.logger(e, detail);
if (detail.state === 'end') {
console.log(detail.hover());
}
},
linkclick: function(e) {
console.log('CLICK!');
},
removeLink: function(e) {
console.log('REMOVE!');
e.target.remove();
},
divtap: function(e) {
console.log('div tap!');
}
});
</script>
48 changes: 2 additions & 46 deletions test/smoke/gestures.html
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width">
<link rel="import" href="../../polymer.html">
<script src="../../../webcomponentsjs/webcomponents-lite.js"></script>
<link rel="import" href="gesture-import.html">
<title>Gestures Demo</title>
<style>
x-gestures {
Expand All @@ -16,50 +17,5 @@
</head>
<body>
<x-gestures id="host"></x-gestures>
<dom-module id="x-gestures">
<template>
<style>
#inner {
height: 20px;
width: 20px;
background: blue;
}
</style>
<a href="#" on-click="linkclick" on-touchend="removeLink">LINK</a>
<div id="inner" on-tap="divtap"></div>
</template>
</dom-module>
<script>
Polymer({
is: 'x-gestures',
listeners: {
'tap': 'logger',
'down': 'logger',
'up': 'logger',
'click': 'logger',
'track': 'track'
},
logger: function(e, detail) {
console.log(e.type);
console.log(detail);
},
track: function(e, detail) {
this.logger(e, detail);
if (detail.state === 'end') {
console.log(detail.hover());
}
},
linkclick: function(e) {
console.log('CLICK!');
},
removeLink: function(e) {
console.log('REMOVE!');
e.target.remove();
},
divtap: function(e) {
console.log('div tap!');
}
});
</script>
</body>
</html>
26 changes: 26 additions & 0 deletions test/unit/gestures-elements.html
Original file line number Diff line number Diff line change
Expand Up @@ -85,3 +85,29 @@
});
</script>
</dom-module>

<dom-module id="x-prevent">
<script>
Polymer({
listeners: {
'down': 'prevent',
'up': 'handle',
'tap': 'handle',
'track': 'handle'
},
is: 'x-prevent',
created: function() {
this.stream = [];
},
handle: function(e) {
this.stream.push(e);
},
prevent: function(e, detail) {
detail.prevent('tap');
detail.prevent('track');
e.preventDefault();
this.handle(e);
}
});
</script>
</dom-module>
44 changes: 43 additions & 1 deletion test/unit/gestures.html
Original file line number Diff line number Diff line change
Expand Up @@ -218,8 +218,50 @@
});
});

// TODO(dfreedm): Add more gesture tests!
suite('Prevention', function() {
var el;
setup(function() {
el = document.createElement('x-prevent');
document.body.appendChild(el);
});
teardown(function() {
el.parentNode.removeChild(el);
});

test('tap', function() {
var ev = new CustomEvent('mousedown', {
bubbles: true,
cancelable: true
});
el.dispatchEvent(ev);
assert.equal(el.stream.length, 1, 'one event dispatched');
assert.equal(el.stream[0].type, 'down', 'was down event');
assert.equal(el.stream[0].defaultPrevented, true, 'was prevented');
assert.equal(ev.defaultPrevented, true, 'base event was prevented');
});

test('track', function() {
var ev = new CustomEvent('mousedown', {
bubbles: true,
cancelable: true
});
ev.clientX = ev.clientY = 0;
el.dispatchEvent(ev);
assert.equal(el.stream.length, 1);
for (var i = 0; i < 10; i++) {
ev = new CustomEvent(
i === 9 ? 'mouseup' : 'mousemove',
{bubbles: true, cancelable: true}
);
ev.clientX = ev.clientY = 10 * i;
el.dispatchEvent(ev);
}
assert.equal(el.stream.length, 2, 'expected only down and up');
assert.equal(el.stream[0].type, 'down', 'down was found');
assert.equal(el.stream[0].defaultPrevented, true, 'down was prevented');
assert.equal(el.stream[1].type, 'up', 'up was found');
});
});
</script>

</body>
Expand Down

0 comments on commit 7920729

Please sign in to comment.