UNPKG

4.83 kBJavaScriptView Raw
1/*!
2 * (C) Ionic http://ionicframework.com - MIT License
3 */
4import { q as now, p as pointerCoord } from './helpers.js';
5
6const startTapClick = (config) => {
7 let lastTouch = -MOUSE_WAIT * 10;
8 let lastActivated = 0;
9 let scrollingEl;
10 let activatableEle;
11 let activeRipple;
12 let activeDefer;
13 const useRippleEffect = config.getBoolean('animated', true) && config.getBoolean('rippleEffect', true);
14 const clearDefers = new WeakMap();
15 const isScrolling = () => {
16 return scrollingEl !== undefined && scrollingEl.parentElement !== null;
17 };
18 // Touch Events
19 const onTouchStart = (ev) => {
20 lastTouch = now(ev);
21 pointerDown(ev);
22 };
23 const onTouchEnd = (ev) => {
24 lastTouch = now(ev);
25 pointerUp(ev);
26 };
27 const onMouseDown = (ev) => {
28 const t = now(ev) - MOUSE_WAIT;
29 if (lastTouch < t) {
30 pointerDown(ev);
31 }
32 };
33 const onMouseUp = (ev) => {
34 const t = now(ev) - MOUSE_WAIT;
35 if (lastTouch < t) {
36 pointerUp(ev);
37 }
38 };
39 const onContextMenu = (ev) => {
40 pointerUp(ev);
41 };
42 const cancelActive = () => {
43 clearTimeout(activeDefer);
44 activeDefer = undefined;
45 if (activatableEle) {
46 removeActivated(false);
47 activatableEle = undefined;
48 }
49 };
50 const pointerDown = (ev) => {
51 if (activatableEle || isScrolling()) {
52 return;
53 }
54 scrollingEl = undefined;
55 setActivatedElement(getActivatableTarget(ev), ev);
56 };
57 const pointerUp = (ev) => {
58 setActivatedElement(undefined, ev);
59 };
60 const setActivatedElement = (el, ev) => {
61 // do nothing
62 if (el && el === activatableEle) {
63 return;
64 }
65 clearTimeout(activeDefer);
66 activeDefer = undefined;
67 const { x, y } = pointerCoord(ev);
68 // deactivate selected
69 if (activatableEle) {
70 if (clearDefers.has(activatableEle)) {
71 throw new Error('internal error');
72 }
73 if (!activatableEle.classList.contains(ACTIVATED)) {
74 addActivated(activatableEle, x, y);
75 }
76 removeActivated(true);
77 }
78 // activate
79 if (el) {
80 const deferId = clearDefers.get(el);
81 if (deferId) {
82 clearTimeout(deferId);
83 clearDefers.delete(el);
84 }
85 const delay = isInstant(el) ? 0 : ADD_ACTIVATED_DEFERS;
86 el.classList.remove(ACTIVATED);
87 activeDefer = setTimeout(() => {
88 addActivated(el, x, y);
89 activeDefer = undefined;
90 }, delay);
91 }
92 activatableEle = el;
93 };
94 const addActivated = (el, x, y) => {
95 lastActivated = Date.now();
96 el.classList.add(ACTIVATED);
97 const rippleEffect = useRippleEffect && getRippleEffect(el);
98 if (rippleEffect && rippleEffect.addRipple) {
99 removeRipple();
100 activeRipple = rippleEffect.addRipple(x, y);
101 }
102 };
103 const removeRipple = () => {
104 if (activeRipple !== undefined) {
105 activeRipple.then(remove => remove());
106 activeRipple = undefined;
107 }
108 };
109 const removeActivated = (smooth) => {
110 removeRipple();
111 const active = activatableEle;
112 if (!active) {
113 return;
114 }
115 const time = CLEAR_STATE_DEFERS - Date.now() + lastActivated;
116 if (smooth && time > 0 && !isInstant(active)) {
117 const deferId = setTimeout(() => {
118 active.classList.remove(ACTIVATED);
119 clearDefers.delete(active);
120 }, CLEAR_STATE_DEFERS);
121 clearDefers.set(active, deferId);
122 }
123 else {
124 active.classList.remove(ACTIVATED);
125 }
126 };
127 const doc = document;
128 doc.addEventListener('ionScrollStart', ev => {
129 scrollingEl = ev.target;
130 cancelActive();
131 });
132 doc.addEventListener('ionScrollEnd', () => {
133 scrollingEl = undefined;
134 });
135 doc.addEventListener('ionGestureCaptured', cancelActive);
136 doc.addEventListener('touchstart', onTouchStart, true);
137 doc.addEventListener('touchcancel', onTouchEnd, true);
138 doc.addEventListener('touchend', onTouchEnd, true);
139 doc.addEventListener('mousedown', onMouseDown, true);
140 doc.addEventListener('mouseup', onMouseUp, true);
141 doc.addEventListener('contextmenu', onContextMenu, true);
142};
143const getActivatableTarget = (ev) => {
144 if (ev.composedPath) {
145 const path = ev.composedPath();
146 for (let i = 0; i < path.length - 2; i++) {
147 const el = path[i];
148 if (el.classList && el.classList.contains('ion-activatable')) {
149 return el;
150 }
151 }
152 }
153 else {
154 return ev.target.closest('.ion-activatable');
155 }
156};
157const isInstant = (el) => {
158 return el.classList.contains('ion-activatable-instant');
159};
160const getRippleEffect = (el) => {
161 if (el.shadowRoot) {
162 const ripple = el.shadowRoot.querySelector('ion-ripple-effect');
163 if (ripple) {
164 return ripple;
165 }
166 }
167 return el.querySelector('ion-ripple-effect');
168};
169const ACTIVATED = 'ion-activated';
170const ADD_ACTIVATED_DEFERS = 200;
171const CLEAR_STATE_DEFERS = 200;
172const MOUSE_WAIT = 2500;
173
174export { startTapClick };