DomEvent.DoubleTap.js 2.5 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091
  1. import * as DomEvent from './DomEvent';
  2. /*
  3. * Extends the event handling code with double tap support for mobile browsers.
  4. *
  5. * Note: currently most browsers fire native dblclick, with only a few exceptions
  6. * (see https://github.com/Leaflet/Leaflet/issues/7012#issuecomment-595087386)
  7. */
  8. function makeDblclick(event) {
  9. // in modern browsers `type` cannot be just overridden:
  10. // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Errors/Getter_only
  11. var newEvent = {},
  12. prop, i;
  13. for (i in event) {
  14. prop = event[i];
  15. newEvent[i] = prop && prop.bind ? prop.bind(event) : prop;
  16. }
  17. event = newEvent;
  18. newEvent.type = 'dblclick';
  19. newEvent.detail = 2;
  20. newEvent.isTrusted = false;
  21. newEvent._simulated = true; // for debug purposes
  22. return newEvent;
  23. }
  24. var delay = 200;
  25. export function addDoubleTapListener(obj, handler) {
  26. // Most browsers handle double tap natively
  27. obj.addEventListener('dblclick', handler);
  28. // On some platforms the browser doesn't fire native dblclicks for touch events.
  29. // It seems that in all such cases `detail` property of `click` event is always `1`.
  30. // So here we rely on that fact to avoid excessive 'dblclick' simulation when not needed.
  31. var last = 0,
  32. detail;
  33. function simDblclick(e) {
  34. if (e.detail !== 1) {
  35. detail = e.detail; // keep in sync to avoid false dblclick in some cases
  36. return;
  37. }
  38. if (e.pointerType === 'mouse' ||
  39. (e.sourceCapabilities && !e.sourceCapabilities.firesTouchEvents)) {
  40. return;
  41. }
  42. // When clicking on an <input>, the browser generates a click on its
  43. // <label> (and vice versa) triggering two clicks in quick succession.
  44. // This ignores clicks on elements which are a label with a 'for'
  45. // attribute (or children of such a label), but not children of
  46. // a <input>.
  47. var path = DomEvent.getPropagationPath(e);
  48. if (path.some(function (el) {
  49. return el instanceof HTMLLabelElement && el.attributes.for;
  50. }) &&
  51. !path.some(function (el) {
  52. return (
  53. el instanceof HTMLInputElement ||
  54. el instanceof HTMLSelectElement
  55. );
  56. })
  57. ) {
  58. return;
  59. }
  60. var now = Date.now();
  61. if (now - last <= delay) {
  62. detail++;
  63. if (detail === 2) {
  64. handler(makeDblclick(e));
  65. }
  66. } else {
  67. detail = 1;
  68. }
  69. last = now;
  70. }
  71. obj.addEventListener('click', simDblclick);
  72. return {
  73. dblclick: handler,
  74. simDblclick: simDblclick
  75. };
  76. }
  77. export function removeDoubleTapListener(obj, handlers) {
  78. obj.removeEventListener('dblclick', handlers.dblclick);
  79. obj.removeEventListener('click', handlers.simDblclick);
  80. }