Skip to content

Commit

Permalink
pointerEvents: add holdDuration option
Browse files Browse the repository at this point in the history
Close #403
  • Loading branch information
taye committed Aug 27, 2016
1 parent 550e545 commit 1c58f92
Show file tree
Hide file tree
Showing 5 changed files with 77 additions and 9 deletions.
6 changes: 6 additions & 0 deletions src/Eventable.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
const { indexOf } = require('./utils/arr');
const extend = require('./utils/extend.js');

function fireUntilImmediateStopped (event, listeners) {
for (let i = 0, len = listeners.length; i < len && !event.immediatePropagationStopped; i++) {
Expand All @@ -7,6 +8,11 @@ function fireUntilImmediateStopped (event, listeners) {
}

class Eventable {

constructor (options) {
this.options = extend({}, options || {});
}

fire (event) {
let listeners;
const onEvent = 'on' + event.type;
Expand Down
2 changes: 0 additions & 2 deletions src/Interaction.js
Original file line number Diff line number Diff line change
Expand Up @@ -259,8 +259,6 @@ class Interaction {
pointerUp (pointer, event, eventTarget, curEventTarget) {
const pointerIndex = this.mouse? 0 : utils.indexOf(this.pointerIds, utils.getPointerId(pointer));

clearTimeout(this.holdTimers[pointerIndex]);

signals.fire(/cancel$/i.test(event.type)? 'cancel' : 'up', {
pointer,
event,
Expand Down
2 changes: 0 additions & 2 deletions src/defaultOptions.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,4 @@ module.exports = {
smoothEndDuration: 300, // animate to snap/restrict endOnly if there's no inertia
},
},

_holdDuration: 600,
};
69 changes: 64 additions & 5 deletions src/pointerEvents/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ const utils = require('../utils');
const browser = require('../utils/browser');
const defaults = require('../defaultOptions');
const signals = require('../utils/Signals').new();
const { filter } = require('../utils/arr');

const simpleSignals = [ 'down', 'up', 'up', 'cancel' ];
const simpleEvents = [ 'down', 'up', 'tap', 'cancel' ];
Expand Down Expand Up @@ -123,7 +124,7 @@ function collectEventTargets (interaction, pointer, event, eventTarget, eventTyp
return;
}

const targets = [];
let targets = [];
const path = utils.getPath(eventTarget);
const signalArg = {
targets,
Expand All @@ -142,6 +143,13 @@ function collectEventTargets (interaction, pointer, event, eventTarget, eventTyp
signals.fire('collect-targets', signalArg);
}

if (eventType === 'hold') {
targets = filter(targets, function (target) {
return (target.eventable.options.holdDuration
=== interaction.holdTimers[pointerIndex].duration);
});
}

// create the tap event even if there are no listeners so that
// doubletap can still be created and fired
if (targets.length || eventType === 'tap') {
Expand All @@ -156,7 +164,7 @@ Interaction.signals.on('move', function ({ interaction, pointer, event, eventTar

if (!duplicateMove && (!interaction.pointerIsDown || interaction.pointerWasMoved)) {
if (interaction.pointerIsDown) {
clearTimeout(interaction.holdTimers[pointerIndex]);
clearTimeout(interaction.holdTimers[pointerIndex].timeout);
}

collectEventTargets(interaction, pointer, event, eventTarget, 'move');
Expand All @@ -166,16 +174,63 @@ Interaction.signals.on('move', function ({ interaction, pointer, event, eventTar
Interaction.signals.on('down', function ({ interaction, pointer, event, eventTarget, pointerIndex }) {
// copy event to be used in timeout for IE8
const eventCopy = browser.isIE8? utils.extend({}, event) : event;
const timers = interaction.holdTimers;
const timeoutIndex = timers.length;

if (!timers[pointerIndex]) {
timers[pointerIndex] = { duration: Infinity, timeout: null };
}

const timer = timers[pointerIndex];
const path = utils.getPath(eventTarget);
const signalArg = {
interaction,
pointer,
event,
eventTarget,
eventType: 'hold',
targets: [],
path,
element: null,
};

for (const element of path) {
signalArg.element = element;

signals.fire('collect-targets', signalArg);
}

if (!signalArg.targets.length) { return; }

interaction.holdTimers[pointerIndex] = setTimeout(function () {
let minDuration = Infinity;

for (let i = 0; i < signalArg.targets.length; i++) {
const target = signalArg.targets[i];
const holdDuration = target.eventable.options.holdDuration;

if (holdDuration < minDuration) {
minDuration = holdDuration;
}
}

timer.duration = minDuration;
timer.timeout = setTimeout(function () {

collectEventTargets(interaction,
browser.isIE8? eventCopy : pointer,
eventCopy,
eventTarget,
'hold');
'hold',
minDuration);
}, minDuration);
});

}, defaults._holdDuration);
['up', 'cancel'].forEach(function (signalName) {
Interaction.signals.on(signalName, function ({ interaction, pointerIndex }) {
if (interaction.holdTimers[pointerIndex]) {
clearTimeout(interaction.holdTimers[pointerIndex].timeout);
}
});
});

function createSignalListener (event) {
Expand All @@ -197,6 +252,10 @@ Interaction.signals.on('new', function (interaction) {
interaction.tapTime = 0; // time of the most recent tap event
});

defaults.pointerEvents = {
holdDuration: 600,
};

module.exports = scope.pointerEvents = {
firePointers,
collectEventTargets,
Expand Down
7 changes: 7 additions & 0 deletions src/pointerEvents/interactableTargets.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ const browser = require('../utils/browser');
const isType = require('../utils/isType');
const domUtils = require('../utils/domUtils');
const scope = require('../scope');
const extend = require('../utils/extend');
const { merge } = require('../utils/arr');

pointerEvents.signals.on('collect-targets', function ({ targets, element, eventType }) {
Expand Down Expand Up @@ -45,3 +46,9 @@ pointerEvents.signals.on('collect-targets', function ({ targets, element, eventT
});

merge(Interactable.eventTypes, pointerEvents.types);

Interactable.prototype.pointerEvents = function (options) {
extend(this.events.options, options);

return this;
};

2 comments on commit 1c58f92

@eweap
Copy link

@eweap eweap commented on 1c58f92 Aug 30, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @taye
Thanks for this commit :)

Can you provide a simple example of how you configure the holdDuration ?

Thanks !

@taye
Copy link
Owner Author

@taye taye commented on 1c58f92 Nov 28, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@eweap this should work:

interact(target).pointerEvents({
  holdDuration: 1000
});

Please sign in to comment.