1 | /** |
||
2 | * @license AngularJS v1.8.3 |
||
3 | * (c) 2010-2020 Google LLC. http://angularjs.org |
||
4 | * License: MIT |
||
5 | */ |
||
6 | (function(window, angular) {'use strict'; |
||
7 | |||
8 | /** |
||
9 | * @ngdoc module |
||
10 | * @name ngTouch |
||
11 | * @description |
||
12 | * |
||
13 | * The `ngTouch` module provides helpers for touch-enabled devices. |
||
14 | * The implementation is based on jQuery Mobile touch event handling |
||
15 | * ([jquerymobile.com](http://jquerymobile.com/)). * |
||
16 | * |
||
17 | * See {@link ngTouch.$swipe `$swipe`} for usage. |
||
18 | * |
||
19 | * @deprecated |
||
20 | * sinceVersion="1.7.0" |
||
21 | * The ngTouch module with the {@link ngTouch.$swipe `$swipe`} service and |
||
22 | * the {@link ngTouch.ngSwipeLeft} and {@link ngTouch.ngSwipeRight} directives are |
||
23 | * deprecated. Instead, stand-alone libraries for touch handling and gesture interaction |
||
24 | * should be used, for example [HammerJS](https://hammerjs.github.io/) (which is also used by |
||
25 | * Angular). |
||
26 | */ |
||
27 | |||
28 | // define ngTouch module |
||
29 | /* global ngTouch */ |
||
30 | var ngTouch = angular.module('ngTouch', []); |
||
31 | |||
32 | ngTouch.info({ angularVersion: '1.8.3' }); |
||
33 | |||
34 | function nodeName_(element) { |
||
0 ignored issues
–
show
introduced
by
![]() |
|||
35 | return angular.$$lowercase(element.nodeName || (element[0] && element[0].nodeName)); |
||
36 | } |
||
37 | |||
38 | /* global ngTouch: false */ |
||
39 | |||
40 | /** |
||
41 | * @ngdoc service |
||
42 | * @name $swipe |
||
43 | * |
||
44 | * @deprecated |
||
45 | * sinceVersion="1.7.0" |
||
46 | * |
||
47 | * See the {@link ngTouch module} documentation for more information. |
||
48 | * |
||
49 | * @description |
||
50 | * The `$swipe` service is a service that abstracts the messier details of hold-and-drag swipe |
||
51 | * behavior, to make implementing swipe-related directives more convenient. |
||
52 | * |
||
53 | * Requires the {@link ngTouch `ngTouch`} module to be installed. |
||
54 | * |
||
55 | * `$swipe` is used by the `ngSwipeLeft` and `ngSwipeRight` directives in `ngTouch`. |
||
56 | * |
||
57 | * # Usage |
||
58 | * The `$swipe` service is an object with a single method: `bind`. `bind` takes an element |
||
59 | * which is to be watched for swipes, and an object with four handler functions. See the |
||
60 | * documentation for `bind` below. |
||
61 | */ |
||
62 | |||
63 | ngTouch.factory('$swipe', [function() { |
||
64 | // The total distance in any direction before we make the call on swipe vs. scroll. |
||
65 | var MOVE_BUFFER_RADIUS = 10; |
||
66 | |||
67 | var POINTER_EVENTS = { |
||
68 | 'mouse': { |
||
69 | start: 'mousedown', |
||
70 | move: 'mousemove', |
||
71 | end: 'mouseup' |
||
72 | }, |
||
73 | 'touch': { |
||
74 | start: 'touchstart', |
||
75 | move: 'touchmove', |
||
76 | end: 'touchend', |
||
77 | cancel: 'touchcancel' |
||
78 | }, |
||
79 | 'pointer': { |
||
80 | start: 'pointerdown', |
||
81 | move: 'pointermove', |
||
82 | end: 'pointerup', |
||
83 | cancel: 'pointercancel' |
||
84 | } |
||
85 | }; |
||
86 | |||
87 | function getCoordinates(event) { |
||
88 | var originalEvent = event.originalEvent || event; |
||
89 | var touches = originalEvent.touches && originalEvent.touches.length ? originalEvent.touches : [originalEvent]; |
||
90 | var e = (originalEvent.changedTouches && originalEvent.changedTouches[0]) || touches[0]; |
||
91 | |||
92 | return { |
||
93 | x: e.clientX, |
||
94 | y: e.clientY |
||
95 | }; |
||
96 | } |
||
97 | |||
98 | function getEvents(pointerTypes, eventType) { |
||
99 | var res = []; |
||
100 | angular.forEach(pointerTypes, function(pointerType) { |
||
101 | var eventName = POINTER_EVENTS[pointerType][eventType]; |
||
102 | if (eventName) { |
||
103 | res.push(eventName); |
||
104 | } |
||
105 | }); |
||
106 | return res.join(' '); |
||
107 | } |
||
108 | |||
109 | return { |
||
110 | /** |
||
111 | * @ngdoc method |
||
112 | * @name $swipe#bind |
||
113 | * |
||
114 | * @description |
||
115 | * The main method of `$swipe`. It takes an element to be watched for swipe motions, and an |
||
116 | * object containing event handlers. |
||
117 | * The pointer types that should be used can be specified via the optional |
||
118 | * third argument, which is an array of strings `'mouse'`, `'touch'` and `'pointer'`. By default, |
||
119 | * `$swipe` will listen for `mouse`, `touch` and `pointer` events. |
||
120 | * |
||
121 | * The four events are `start`, `move`, `end`, and `cancel`. `start`, `move`, and `end` |
||
122 | * receive as a parameter a coordinates object of the form `{ x: 150, y: 310 }` and the raw |
||
123 | * `event`. `cancel` receives the raw `event` as its single parameter. |
||
124 | * |
||
125 | * `start` is called on either `mousedown`, `touchstart` or `pointerdown`. After this event, `$swipe` is |
||
126 | * watching for `touchmove`, `mousemove` or `pointermove` events. These events are ignored until the total |
||
127 | * distance moved in either dimension exceeds a small threshold. |
||
128 | * |
||
129 | * Once this threshold is exceeded, either the horizontal or vertical delta is greater. |
||
130 | * - If the horizontal distance is greater, this is a swipe and `move` and `end` events follow. |
||
131 | * - If the vertical distance is greater, this is a scroll, and we let the browser take over. |
||
132 | * A `cancel` event is sent. |
||
133 | * |
||
134 | * `move` is called on `mousemove`, `touchmove` and `pointermove` after the above logic has determined that |
||
135 | * a swipe is in progress. |
||
136 | * |
||
137 | * `end` is called when a swipe is successfully completed with a `touchend`, `mouseup` or `pointerup`. |
||
138 | * |
||
139 | * `cancel` is called either on a `touchcancel` or `pointercancel` from the browser, or when we begin scrolling |
||
140 | * as described above. |
||
141 | * |
||
142 | */ |
||
143 | bind: function(element, eventHandlers, pointerTypes) { |
||
144 | // Absolute total movement, used to control swipe vs. scroll. |
||
145 | var totalX, totalY; |
||
146 | // Coordinates of the start position. |
||
147 | var startCoords; |
||
148 | // Last event's position. |
||
149 | var lastPos; |
||
150 | // Whether a swipe is active. |
||
151 | var active = false; |
||
152 | |||
153 | pointerTypes = pointerTypes || ['mouse', 'touch', 'pointer']; |
||
154 | element.on(getEvents(pointerTypes, 'start'), function(event) { |
||
155 | startCoords = getCoordinates(event); |
||
156 | active = true; |
||
157 | totalX = 0; |
||
158 | totalY = 0; |
||
159 | lastPos = startCoords; |
||
160 | if (eventHandlers['start']) { |
||
161 | eventHandlers['start'](startCoords, event); |
||
162 | } |
||
163 | }); |
||
164 | var events = getEvents(pointerTypes, 'cancel'); |
||
165 | if (events) { |
||
166 | element.on(events, function(event) { |
||
167 | active = false; |
||
168 | if (eventHandlers['cancel']) { |
||
169 | eventHandlers['cancel'](event); |
||
170 | } |
||
171 | }); |
||
172 | } |
||
173 | |||
174 | element.on(getEvents(pointerTypes, 'move'), function(event) { |
||
175 | if (!active) return; |
||
176 | |||
177 | // Android will send a touchcancel if it thinks we're starting to scroll. |
||
178 | // So when the total distance (+ or - or both) exceeds 10px in either direction, |
||
179 | // we either: |
||
180 | // - On totalX > totalY, we send preventDefault() and treat this as a swipe. |
||
181 | // - On totalY > totalX, we let the browser handle it as a scroll. |
||
182 | |||
183 | if (!startCoords) return; |
||
184 | var coords = getCoordinates(event); |
||
185 | |||
186 | totalX += Math.abs(coords.x - lastPos.x); |
||
187 | totalY += Math.abs(coords.y - lastPos.y); |
||
188 | |||
189 | lastPos = coords; |
||
190 | |||
191 | if (totalX < MOVE_BUFFER_RADIUS && totalY < MOVE_BUFFER_RADIUS) { |
||
192 | return; |
||
193 | } |
||
194 | |||
195 | // One of totalX or totalY has exceeded the buffer, so decide on swipe vs. scroll. |
||
196 | if (totalY > totalX) { |
||
197 | // Allow native scrolling to take over. |
||
198 | active = false; |
||
199 | if (eventHandlers['cancel']) { |
||
200 | eventHandlers['cancel'](event); |
||
201 | } |
||
202 | return; |
||
0 ignored issues
–
show
|
|||
203 | } else { |
||
204 | // Prevent the browser from scrolling. |
||
205 | event.preventDefault(); |
||
206 | if (eventHandlers['move']) { |
||
207 | eventHandlers['move'](coords, event); |
||
208 | } |
||
209 | } |
||
210 | }); |
||
211 | |||
212 | element.on(getEvents(pointerTypes, 'end'), function(event) { |
||
213 | if (!active) return; |
||
214 | active = false; |
||
215 | if (eventHandlers['end']) { |
||
216 | eventHandlers['end'](getCoordinates(event), event); |
||
217 | } |
||
218 | }); |
||
219 | } |
||
220 | }; |
||
221 | }]); |
||
222 | |||
223 | /* global ngTouch: false */ |
||
224 | |||
225 | /** |
||
226 | * @ngdoc directive |
||
227 | * @name ngSwipeLeft |
||
228 | * |
||
229 | * @deprecated |
||
230 | * sinceVersion="1.7.0" |
||
231 | * |
||
232 | * See the {@link ngTouch module} documentation for more information. |
||
233 | * |
||
234 | * @description |
||
235 | * Specify custom behavior when an element is swiped to the left on a touchscreen device. |
||
236 | * A leftward swipe is a quick, right-to-left slide of the finger. |
||
237 | * Though ngSwipeLeft is designed for touch-based devices, it will work with a mouse click and drag |
||
238 | * too. |
||
239 | * |
||
240 | * To disable the mouse click and drag functionality, add `ng-swipe-disable-mouse` to |
||
241 | * the `ng-swipe-left` or `ng-swipe-right` DOM Element. |
||
242 | * |
||
243 | * Requires the {@link ngTouch `ngTouch`} module to be installed. |
||
244 | * |
||
245 | * @element ANY |
||
246 | * @param {expression} ngSwipeLeft {@link guide/expression Expression} to evaluate |
||
247 | * upon left swipe. (Event object is available as `$event`) |
||
248 | * |
||
249 | * @example |
||
250 | <example module="ngSwipeLeftExample" deps="angular-touch.js" name="ng-swipe-left"> |
||
251 | <file name="index.html"> |
||
252 | <div ng-show="!showActions" ng-swipe-left="showActions = true"> |
||
253 | Some list content, like an email in the inbox |
||
254 | </div> |
||
255 | <div ng-show="showActions" ng-swipe-right="showActions = false"> |
||
256 | <button ng-click="reply()">Reply</button> |
||
257 | <button ng-click="delete()">Delete</button> |
||
258 | </div> |
||
259 | </file> |
||
260 | <file name="script.js"> |
||
261 | angular.module('ngSwipeLeftExample', ['ngTouch']); |
||
262 | </file> |
||
263 | </example> |
||
264 | */ |
||
265 | |||
266 | /** |
||
267 | * @ngdoc directive |
||
268 | * @name ngSwipeRight |
||
269 | * |
||
270 | * @deprecated |
||
271 | * sinceVersion="1.7.0" |
||
272 | * |
||
273 | * See the {@link ngTouch module} documentation for more information. |
||
274 | * |
||
275 | * @description |
||
276 | * Specify custom behavior when an element is swiped to the right on a touchscreen device. |
||
277 | * A rightward swipe is a quick, left-to-right slide of the finger. |
||
278 | * Though ngSwipeRight is designed for touch-based devices, it will work with a mouse click and drag |
||
279 | * too. |
||
280 | * |
||
281 | * Requires the {@link ngTouch `ngTouch`} module to be installed. |
||
282 | * |
||
283 | * @element ANY |
||
284 | * @param {expression} ngSwipeRight {@link guide/expression Expression} to evaluate |
||
285 | * upon right swipe. (Event object is available as `$event`) |
||
286 | * |
||
287 | * @example |
||
288 | <example module="ngSwipeRightExample" deps="angular-touch.js" name="ng-swipe-right"> |
||
289 | <file name="index.html"> |
||
290 | <div ng-show="!showActions" ng-swipe-left="showActions = true"> |
||
291 | Some list content, like an email in the inbox |
||
292 | </div> |
||
293 | <div ng-show="showActions" ng-swipe-right="showActions = false"> |
||
294 | <button ng-click="reply()">Reply</button> |
||
295 | <button ng-click="delete()">Delete</button> |
||
296 | </div> |
||
297 | </file> |
||
298 | <file name="script.js"> |
||
299 | angular.module('ngSwipeRightExample', ['ngTouch']); |
||
300 | </file> |
||
301 | </example> |
||
302 | */ |
||
303 | |||
304 | function makeSwipeDirective(directiveName, direction, eventName) { |
||
305 | ngTouch.directive(directiveName, ['$parse', '$swipe', function($parse, $swipe) { |
||
306 | // The maximum vertical delta for a swipe should be less than 75px. |
||
307 | var MAX_VERTICAL_DISTANCE = 75; |
||
308 | // Vertical distance should not be more than a fraction of the horizontal distance. |
||
309 | var MAX_VERTICAL_RATIO = 0.3; |
||
310 | // At least a 30px lateral motion is necessary for a swipe. |
||
311 | var MIN_HORIZONTAL_DISTANCE = 30; |
||
312 | |||
313 | return function(scope, element, attr) { |
||
314 | var swipeHandler = $parse(attr[directiveName]); |
||
315 | |||
316 | var startCoords, valid; |
||
317 | |||
318 | function validSwipe(coords) { |
||
319 | // Check that it's within the coordinates. |
||
320 | // Absolute vertical distance must be within tolerances. |
||
321 | // Horizontal distance, we take the current X - the starting X. |
||
322 | // This is negative for leftward swipes and positive for rightward swipes. |
||
323 | // After multiplying by the direction (-1 for left, +1 for right), legal swipes |
||
324 | // (ie. same direction as the directive wants) will have a positive delta and |
||
325 | // illegal ones a negative delta. |
||
326 | // Therefore this delta must be positive, and larger than the minimum. |
||
327 | if (!startCoords) return false; |
||
328 | var deltaY = Math.abs(coords.y - startCoords.y); |
||
329 | var deltaX = (coords.x - startCoords.x) * direction; |
||
330 | return valid && // Short circuit for already-invalidated swipes. |
||
331 | deltaY < MAX_VERTICAL_DISTANCE && |
||
332 | deltaX > 0 && |
||
333 | deltaX > MIN_HORIZONTAL_DISTANCE && |
||
334 | deltaY / deltaX < MAX_VERTICAL_RATIO; |
||
335 | } |
||
336 | |||
337 | var pointerTypes = ['touch']; |
||
338 | if (!angular.isDefined(attr['ngSwipeDisableMouse'])) { |
||
339 | pointerTypes.push('mouse'); |
||
340 | } |
||
341 | $swipe.bind(element, { |
||
342 | 'start': function(coords, event) { |
||
343 | startCoords = coords; |
||
344 | valid = true; |
||
345 | }, |
||
346 | 'cancel': function(event) { |
||
347 | valid = false; |
||
348 | }, |
||
349 | 'end': function(coords, event) { |
||
350 | if (validSwipe(coords)) { |
||
351 | scope.$apply(function() { |
||
352 | element.triggerHandler(eventName); |
||
353 | swipeHandler(scope, {$event: event}); |
||
354 | }); |
||
355 | } |
||
356 | } |
||
357 | }, pointerTypes); |
||
358 | }; |
||
359 | }]); |
||
360 | } |
||
361 | |||
362 | // Left is negative X-coordinate, right is positive. |
||
363 | makeSwipeDirective('ngSwipeLeft', -1, 'swipeleft'); |
||
364 | makeSwipeDirective('ngSwipeRight', 1, 'swiperight'); |
||
365 | |||
366 | |||
367 | |||
368 | })(window, window.angular); |
||
369 |