|
| 1 | +/** |
| 2 | + * @license AngularJS v1.8.2 |
| 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.2' }); |
| 33 | + |
| 34 | +function nodeName_(element) { |
| 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; |
| 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); |
0 commit comments