Skip to content

Commit

Permalink
Allow configuring cancelling synthetic click behavior
Browse files Browse the repository at this point in the history
  • Loading branch information
LarsDenBakker committed May 4, 2019
1 parent 969f289 commit 00d4cdf
Show file tree
Hide file tree
Showing 3 changed files with 53 additions and 4 deletions.
13 changes: 9 additions & 4 deletions lib/utils/gestures.js
Expand Up @@ -25,7 +25,7 @@ import './boot.js';

import { timeOut, microTask } from './async.js';
import { Debouncer } from './debounce.js';
import { passiveTouchGestures } from './settings.js';
import { passiveTouchGestures, cancelSyntheticClickEvents } from './settings.js';
import { wrap } from './wrap.js';

// detect native touch action support
Expand Down Expand Up @@ -221,6 +221,9 @@ function setupTeardownMouseCanceller(setup) {
}

function ignoreMouse(e) {
if (!cancelSyntheticClickEvents) {
return;
}
if (!POINTERSTATE.mouse.mouseIgnoreJob) {
setupTeardownMouseCanceller(true);
}
Expand Down Expand Up @@ -328,9 +331,11 @@ function untrackDocument(stateObj) {
stateObj.upfn = null;
}

// use a document-wide touchend listener to start the ghost-click prevention mechanism
// Use passive event listeners, if supported, to not affect scrolling performance
document.addEventListener('touchend', ignoreMouse, SUPPORTS_PASSIVE ? {passive: true} : false);
if (cancelSyntheticClickEvents) {
// use a document-wide touchend listener to start the ghost-click prevention mechanism
// Use passive event listeners, if supported, to not affect scrolling performance
document.addEventListener('touchend', ignoreMouse, SUPPORTS_PASSIVE ? {passive: true} : false);
}

/**
* Returns the composedPath for the given event.
Expand Down
18 changes: 18 additions & 0 deletions lib/utils/settings.js
Expand Up @@ -158,3 +158,21 @@ export let syncInitialRender = false;
export const setSyncInitialRender = function(useSyncInitialRender) {
syncInitialRender = useSyncInitialRender;
};

/**
* Setting to cancel synthetic click events fired by older mobile browsers. Modern browsers
* no longer fire synthetic click events, and the cancellation behavior can interfere
* when programmatically clicking on elements.
*/
export let cancelSyntheticClickEvents = true;

/**
* Sets `setCancelSyntheticEvents` globally for all elements to cancel synthetic click events.
*
* @param {boolean} useCancelSyntheticClickEvents enable or disable cancelling synthetic
* events
* @return {void}
*/
export const setCancelSyntheticClickEvents = function(useCancelSyntheticClickEvents) {
cancelSyntheticClickEvents = useCancelSyntheticClickEvents;
};
26 changes: 26 additions & 0 deletions test/unit/gestures.html
Expand Up @@ -24,6 +24,7 @@
<script type="module">
import './gestures-elements.js';
import { afterNextRender } from '../../lib/utils/render-status.js';
import { setCancelSyntheticClickEvents } from '../../lib/utils/settings.js';
import { resetMouseCanceller, deepTargetFind, recognizers, addListener, removeListener } from '../../lib/utils/gestures.js';

suite('simulate events', function() {
Expand Down Expand Up @@ -104,6 +105,31 @@
});
});

suite('cancelling synthetic click events disabled', () => {
setup(() => {
setCancelSyntheticClickEvents(false);
});

teardown(() => {
setCancelSyntheticClickEvents(true);
});

test('HTMLElement.click triggers a click event', function(done) {
const buttonA = document.createElement('button');
const buttonB = document.createElement('button');
document.body.appendChild(buttonA);
document.body.appendChild(buttonB);
buttonB.addEventListener('click', () => {
buttonB.parentElement.removeChild(buttonA);
buttonB.parentElement.removeChild(buttonB);
done();
});
// simulate a user click on a button on a touch device
buttonA.dispatchEvent(new CustomEvent('touchend', { bubbles: true }));
buttonB.click();
});
});

suite('Event Setup and Teardown', function() {
var outer, inner;
suiteSetup(function(done) {
Expand Down

0 comments on commit 00d4cdf

Please sign in to comment.