|
1 | 1 | (function() { |
2 | | - var isTapping = false; |
3 | | - var touchStartTime = null; |
4 | | - var startX = 0; |
5 | | - var startY = 0; |
6 | | - |
7 | | - document.addEventListener('touchstart', touchstart, false); |
8 | | - document.addEventListener('touchend', touchend, false); |
9 | | - |
10 | | - function touchstart(event) { |
11 | | - isTapping = (event.touches.length == 1); |
12 | | - if (isInteractiveElement(event.target) || !isTapping) { |
13 | | - return; |
14 | | - } |
15 | | - |
16 | | - var touch = event.changedTouches[0]; |
17 | | - startX = touch.pageX; |
18 | | - startY = touch.pageY; |
19 | | - touchStartTime = Date.now(); |
20 | | - } |
| 2 | + window.addEventListener('DOMContentLoaded', function(event) { |
| 3 | + // If we don't set the CSS cursor property to pointer, then the click events are not triggered pre-iOS 13. |
| 4 | + document.body.style.cursor = 'pointer'; |
| 5 | + |
| 6 | + document.addEventListener('click', onClick, false); |
| 7 | + }); |
21 | 8 |
|
22 | | - function touchend(event) { |
23 | | - if (!isTapping || touchStartTime == null || Date.now() - touchStartTime > 500) { |
| 9 | + function onClick(event) { |
| 10 | + if (event.defaultPrevented || isInteractiveElement(event.target)) { |
24 | 11 | return; |
25 | 12 | } |
26 | | - isTapping = false; |
27 | | - |
28 | | - var touch = event.changedTouches[0]; |
29 | 13 |
|
30 | | - function approximatelyEqual(a, b) { |
31 | | - return Math.abs(a - b) < 2; |
32 | | - } |
33 | | - |
34 | | - if (!approximatelyEqual(startX, touch.pageX) || !approximatelyEqual(startY, touch.pageY)) { |
35 | | - return; |
36 | | - } |
37 | | - |
38 | 14 | if (!window.getSelection().isCollapsed) { |
39 | 15 | // There's an on-going selection, the tap will dismiss it so we don't forward it. |
40 | 16 | return; |
41 | 17 | } |
42 | 18 |
|
43 | 19 | webkit.messageHandlers.tap.postMessage({ |
44 | | - "screenX": touch.screenX, |
45 | | - "screenY": touch.screenY, |
46 | | - "clientX": touch.clientX, |
47 | | - "clientY": touch.clientY, |
| 20 | + "screenX": event.screenX, |
| 21 | + "screenY": event.screenY, |
| 22 | + "clientX": event.clientX, |
| 23 | + "clientY": event.clientY, |
48 | 24 | }); |
49 | 25 |
|
50 | 26 | // We don't want to disable the default WebView behavior as it breaks some features without bringing any value. |
51 | 27 | // event.stopPropagation(); |
52 | 28 | // event.preventDefault(); |
53 | 29 | } |
54 | 30 |
|
| 31 | + // See. https://github.com/JayPanoz/architecture/tree/touch-handling/misc/touch-handling |
55 | 32 | function isInteractiveElement(element) { |
56 | 33 | var interactiveTags = [ |
57 | 34 | 'a', |
| 35 | + 'audio', |
58 | 36 | 'button', |
| 37 | + 'canvas', |
| 38 | + 'details', |
59 | 39 | 'input', |
60 | 40 | 'label', |
61 | 41 | 'option', |
|
64 | 44 | 'textarea', |
65 | 45 | 'video', |
66 | 46 | ] |
67 | | - |
68 | | - // https://stackoverflow.com/questions/4878484/difference-between-tagname-and-nodename |
69 | 47 | if (interactiveTags.indexOf(element.nodeName.toLowerCase()) != -1) { |
70 | | - return true; |
| 48 | + return true; |
| 49 | + } |
| 50 | + |
| 51 | + // Checks whether the element is editable by the user. |
| 52 | + if (element.hasAttribute('contenteditable') && element.getAttribute('contenteditable').toLowerCase() != 'false') { |
| 53 | + return true; |
71 | 54 | } |
72 | 55 |
|
73 | 56 | // Checks parents recursively because the touch might be for example on an <em> inside a <a>. |
|
0 commit comments