PageSourceSearch

https://sso.inet.vn/public/angularjs/node_modules/angular-touch/angular-touch.js

js inet.vn collected 2026-10-01 13:59:17 UTC 26,995 bytes, 747 lines download raw bytes

1/**
2 * @license AngularJS v1.5.11
3 * (c) 2010-2017 Google, Inc. http://angularjs.org
4 * License: MIT
5 */
6(function(window, angular) {'use strict';
7
8/* global ngTouchClickDirectiveFactory: false */
9
10/**
11 * @ngdoc module
12 * @name ngTouch
13 * @description
14 *
15 * # ngTouch
16 *
17 * The `ngTouch` module provides touch events and other helpers for touch-enabled devices.
18 * The implementation is based on jQuery Mobile touch event handling
19 * ([jquerymobile.com](http://jquerymobile.com/)).
20 *
21 *
22 * See {@link ngTouch.$swipe `$swipe`} for usage.
23 *
24 * <div doc-module-components="ngTouch"></div>
25 *
26 */
27
28// define ngTouch module
29/* global -ngTouch */
30var ngTouch = angular.module('ngTouch', []);
31
32ngTouch.provider('$touch', $TouchProvider);
33
34function nodeName_(element) {
35  return angular.lowercase(element.nodeName || (element[0] && element[0].nodeName));
36}
37
38/**
39 * @ngdoc provider
40 * @name $touchProvider
41 *
42 * @description
43 * The `$touchProvider` allows enabling / disabling {@link ngTouch.ngClick ngTouch's ngClick directive}.
44 */
45$TouchProvider.$inject = ['$provide', '$compileProvider'];
46function $TouchProvider($provide, $compileProvider) {
47
48  /**
49   * @ngdoc method
50   * @name  $touchProvider#ngClickOverrideEnabled
51   *
52   * @param {boolean=} enabled update the ngClickOverrideEnabled state if provided, otherwise just return the
53   * current ngClickOverrideEnabled state
54   * @returns {*} current value if used as getter or itself (chaining) if used as setter
55   *
56   * @kind function
57   *
58   * @description
59   * Call this method to enable/disable {@link ngTouch.ngClick ngTouch's ngClick directive}. If enabled,
60   * the default ngClick directive will be replaced by a version that eliminates the 300ms delay for
61   * click events on browser for touch-devices.
62   *
63   * The default is `false`.
64   *
65   */
66  var ngClickOverrideEnabled = false;
67  var ngClickDirectiveAdded = false;
68  // eslint-disable-next-line no-invalid-this
69  this.ngClickOverrideEnabled = function(enabled) {
70    if (angular.isDefined(enabled)) {
71
72      if (enabled && !ngClickDirectiveAdded) {
73        ngClickDirectiveAdded = true;
74
75        // Use this to identify the correct directive in the delegate
76        ngTouchClickDirectiveFactory.$$moduleName = 'ngTouch';
77        $compileProvider.directive('ngClick', ngTouchClickDirectiveFactory);
78
79        $provide.decorator('ngClickDirective', ['$delegate', function($delegate) {
80          if (ngClickOverrideEnabled) {
81            // drop the default ngClick directive
82            $delegate.shift();
83          } else {
84            // drop the ngTouch ngClick directive if the override has been re-disabled (because
85            // we cannot de-register added directives)
86            var i = $delegate.length - 1;
87            while (i >= 0) {
88              if ($delegate[i].$$moduleName === 'ngTouch') {
89                $delegate.splice(i, 1);
90                break;
91              }
92              i--;
93            }
94          }
95
96          return $delegate;
97        }]);
98      }
99
100      ngClickOverrideEnabled = enabled;
101      return this;
102    }
103
104    return ngClickOverrideEnabled;
105  };
106
107  /**
108  * @ngdoc service
109  * @name $touch
110  * @kind object
111  *
112  * @description
113  * Provides the {@link ngTouch.$touch#ngClickOverrideEnabled `ngClickOverrideEnabled`} method.
114  *
115  */
116  // eslint-disable-next-line no-invalid-this
117  this.$get = function() {
118    return {
119      /**
120       * @ngdoc method
121       * @name  $touch#ngClickOverrideEnabled
122       *
123       * @returns {*} current value of `ngClickOverrideEnabled` set in the {@link ngTouch.$touchProvider $touchProvider},
124       * i.e. if {@link ngTouch.ngClick ngTouch's ngClick} directive is enabled.
125       *
126       * @kind function
127       */
128      ngClickOverrideEnabled: function() {
129        return ngClickOverrideEnabled;
130      }
131    };
132  };
133
134}
135
136/* global ngTouch: false */
137
138    /**
139     * @ngdoc service
140     * @name $swipe
141     *
142     * @description
143     * The `$swipe` service is a service that abstracts the messier details of hold-and-drag swipe
144     * behavior, to make implementing swipe-related directives more convenient.
145     *
146     * Requires the {@link ngTouch `ngTouch`} module to be installed.
147     *
148     * `$swipe` is used by the `ngSwipeLeft` and `ngSwipeRight` directives in `ngTouch`.
149     *
150     * # Usage
151     * The `$swipe` service is an object with a single method: `bind`. `bind` takes an element
152     * which is to be watched for swipes, and an object with four handler functions. See the
153     * documentation for `bind` below.
154     */
155
156ngTouch.factory('$swipe', [function() {
157  // The total distance in any direction before we make the call on swipe vs. scroll.
158  var MOVE_BUFFER_RADIUS = 10;
159
160  var POINTER_EVENTS = {
161    'mouse': {
162      start: 'mousedown',
163      move: 'mousemove',
164      end: 'mouseup'
165    },
166    'touch': {
167      start: 'touchstart',
168      move: 'touchmove',
169      end: 'touchend',
170      cancel: 'touchcancel'
171    },
172    'pointer': {
173      start: 'pointerdown',
174      move: 'pointermove',
175      end: 'pointerup',
176      cancel: 'pointercancel'
177    }
178  };
179
180  function getCoordinates(event) {
181    var originalEvent = event.originalEvent || event;
182    var touches = originalEvent.touches && originalEvent.touches.length ? originalEvent.touches : [originalEvent];
183    var e = (originalEvent.changedTouches && originalEvent.changedTouches[0]) || touches[0];
184
185    return {
186      x: e.clientX,
187      y: e.clientY
188    };
189  }
190
191  function getEvents(pointerTypes, eventType) {
192    var res = [];
193    angular.forEach(pointerTypes, function(pointerType) {
194      var eventName = POINTER_EVENTS[pointerType][eventType];
195      if (eventName) {
196        res.push(eventName);
197      }
198    });
199    return res.join(' ');
200  }
201
202  return {
203    /**
204     * @ngdoc method
205     * @name $swipe#bind
206     *
207     * @description
208     * The main method of `$swipe`. It takes an element to be watched for swipe motions, and an
209     * object containing event handlers.
210     * The pointer types that should be used can be specified via the optional
211     * third argument, which is an array of strings `'mouse'`, `'touch'` and `'pointer'`. By default,
212     * `$swipe` will listen for `mouse`, `touch` and `pointer` events.
213     *
214     * The four events are `start`, `move`, `end`, and `cancel`. `start`, `move`, and `end`
215     * receive as a parameter a coordinates object of the form `{ x: 150, y: 310 }` and the raw
216     * `event`. `cancel` receives the raw `event` as its single parameter.
217     *
218     * `start` is called on either `mousedown`, `touchstart` or `pointerdown`. After this event, `$swipe` is
219     * watching for `touchmove`, `mousemove` or `pointermove` events. These events are ignored until the total
220     * distance moved in either dimension exceeds a small threshold.
221     *
222     * Once this threshold is exceeded, either the horizontal or vertical delta is greater.
223     * - If the horizontal distance is greater, this is a swipe and `move` and `end` events follow.
224     * - If the vertical distance is greater, this is a scroll, and we let the browser take over.
225     *   A `cancel` event is sent.
226     *
227     * `move` is called on `mousemove`, `touchmove` and `pointermove` after the above logic has determined that
228     * a swipe is in progress.
229     *
230     * `end` is called when a swipe is successfully completed with a `touchend`, `mouseup` or `pointerup`.
231     *
232     * `cancel` is called either on a `touchcancel` or `pointercancel`  from the browser, or when we begin scrolling
233     * as described above.
234     *
235     */
236    bind: function(element, eventHandlers, pointerTypes) {
237      // Absolute total movement, used to control swipe vs. scroll.
238      var totalX, totalY;
239      // Coordinates of the start position.
240      var startCoords;
241      // Last event's position.
242      var lastPos;
243      // Whether a swipe is active.
244      var active = false;
245
246      pointerTypes = pointerTypes || ['mouse', 'touch', 'pointer'];
247      element.on(getEvents(pointerTypes, 'start'), function(event) {
248        startCoords = getCoordinates(event);
249        active = true;
250        totalX = 0;
251        totalY = 0;
252        lastPos = startCoords;
253        if (eventHandlers['start']) {
254          eventHandlers['start'](startCoords, event);
255        }
256      });
257      var events = getEvents(pointerTypes, 'cancel');
258      if (events) {
259        element.on(events, function(event) {
260          active = false;
261          if (eventHandlers['cancel']) {
262            eventHandlers['cancel'](event);
263          }
264        });
265      }
266
267      element.on(getEvents(pointerTypes, 'move'), function(event) {
268        if (!active) return;
269
270        // Android will send a touchcancel if it thinks we're starting to scroll.
271        // So when the total distance (+ or - or both) exceeds 10px in either direction,
272        // we either:
273        // - On totalX > totalY, we send preventDefault() and treat this as a swipe.
274        // - On totalY > totalX, we let the browser handle it as a scroll.
275
276        if (!startCoords) return;
277        var coords = getCoordinates(event);
278
279        totalX += Math.abs(coords.x - lastPos.x);
280        totalY += Math.abs(coords.y - lastPos.y);
281
282        lastPos = coords;
283
284        if (totalX < MOVE_BUFFER_RADIUS && totalY < MOVE_BUFFER_RADIUS) {
285          return;
286        }
287
288        // One of totalX or totalY has exceeded the buffer, so decide on swipe vs. scroll.
289        if (totalY > totalX) {
290          // Allow native scrolling to take over.
291          active = false;
292          if (eventHandlers['cancel']) {
293            eventHandlers['cancel'](event);
294          }
295          return;
296        } else {
297          // Prevent the browser from scrolling.
298          event.preventDefault();
299          if (eventHandlers['move']) {
300            eventHandlers['move'](coords, event);
301          }
302        }
303      });
304
305      element.on(getEvents(pointerTypes, 'end'), function(event) {
306        if (!active) return;
307        active = false;
308        if (eventHandlers['end']) {
309          eventHandlers['end'](getCoordinates(event), event);
310        }
311      });
312    }
313  };
314}]);
315
316/* global ngTouch: false,
317  nodeName_: false
318*/
319
320/**
321 * @ngdoc directive
322 * @name ngClick
323 * @deprecated
324 * sinceVersion="v1.5.0"
325 * This directive is deprecated and **disabled** by default.
326 * The directive will receive no further support and might be removed from future releases.
327 * If you need the directive, you can enable it with the {@link ngTouch.$touchProvider $touchProvider#ngClickOverrideEnabled}
328 * function. We also recommend that you migrate to [FastClick](https://github.com/ftlabs/fastclick).
329 * To learn more about the 300ms delay, this [Telerik article](http://developer.telerik.com/featured/300-ms-click-delay-ios-8/)
330 * gives a good overview.
331 *
332 * @description
333 * A more powerful replacement for the default ngClick designed to be used on touchscreen
334 * devices. Most mobile browsers wait about 300ms after a tap-and-release before sending
335 * the click event. This version handles them immediately, and then prevents the
336 * following click event from propagating.
337 *
338 * Requires the {@link ngTouch `ngTouch`} module to be installed.
339 *
340 * This directive can fall back to using an ordinary click event, and so works on desktop
341 * browsers as well as mobile.
342 *
343 * This directive also sets the CSS class `ng-click-active` while the element is being held
344 * down (by a mouse click or touch) so you can restyle the depressed element if you wish.
345 *
346 * @element ANY
347 * @param {expression} ngClick {@link guide/expression Expression} to evaluate
348 * upon tap. (Event object is available as `$event`)
349 *
350 * @example
351    <example module="ngClickExample" deps="angular-touch.js" name="ng-touch-ng-click">
352      <file name="index.html">
353        <button ng-click="count = count + 1" ng-init="count=0">
354          Increment
355        </button>
356        count: {{ count }}
357      </file>
358      <file name="script.js">
359        angular.module('ngClickExample', ['ngTouch']);
360      </file>
361    </example>
362 */
363
364var ngTouchClickDirectiveFactory = ['$parse', '$timeout', '$rootElement',
365    function($parse, $timeout, $rootElement) {
366  var TAP_DURATION = 750; // Shorter than 750ms is a tap, longer is a taphold or drag.
367  var MOVE_TOLERANCE = 12; // 12px seems to work in most mobile browsers.
368  var PREVENT_DURATION = 2500; // 2.5 seconds maximum from preventGhostClick call to click
369  var CLICKBUSTER_THRESHOLD = 25; // 25 pixels in any dimension is the limit for busting clicks.
370
371  var ACTIVE_CLASS_NAME = 'ng-click-active';
372  var lastPreventedTime;
373  var touchCoordinates;
374  var lastLabelClickCoordinates;
375
376
377  // TAP EVENTS AND GHOST CLICKS
378  //
379  // Why tap events?
380  // Mobile browsers detect a tap, then wait a moment (usually ~300ms) to see if you're
381  // double-tapping, and then fire a click event.
382  //
383  // This delay sucks and makes mobile apps feel unresponsive.
384  // So we detect touchstart, touchcancel and touchend ourselves and determine when
385  // the user has tapped on something.
386  //
387  // What happens when the browser then generates a click event?
388  // The browser, of course, also detects the tap and fires a click after a delay. This results in
389  // tapping/clicking twice. We do "clickbusting" to prevent it.
390  //
391  // How does it work?
392  // We attach global touchstart and click handlers, that run during the capture (early) phase.
393  // So the sequence for a tap is:
394  // - global touchstart: Sets an "allowable region" at the point touched.
395  // - element's touchstart: Starts a touch
396  // (- touchcancel ends the touch, no click follows)
397  // - element's touchend: Determines if the tap is valid (didn't move too far away, didn't hold
398  //   too long) and fires the user's tap handler. The touchend also calls preventGhostClick().
399  // - preventGhostClick() removes the allowable region the global touchstart created.
400  // - The browser generates a click event.
401  // - The global click handler catches the click, and checks whether it was in an allowable region.
402  //     - If preventGhostClick was called, the region will have been removed, the click is busted.
403  //     - If the region is still there, the click proceeds normally. Therefore clicks on links and
404  //       other elements without ngTap on them work normally.
405  //
406  // This is an ugly, terrible hack!
407  // Yeah, tell me about it. The alternatives are using the slow click events, or making our users
408  // deal with the ghost clicks, so I consider this the least of evils. Fortunately Angular
409  // encapsulates this ugly logic away from the user.
410  //
411  // Why not just put click handlers on the element?
412  // We do that too, just to be sure. If the tap event caused the DOM to change,
413  // it is possible another element is now in that position. To take account for these possibly
414  // distinct elements, the handlers are global and care only about coordinates.
415
416  // Checks if the coordinates are close enough to be within the region.
417  function hit(x1, y1, x2, y2) {
418    return Math.abs(x1 - x2) < CLICKBUSTER_THRESHOLD && Math.abs(y1 - y2) < CLICKBUSTER_THRESHOLD;
419  }
420
421  // Checks a list of allowable regions against a click location.
422  // Returns true if the click should be allowed.
423  // Splices out the allowable region from the list after it has been used.
424  function checkAllowableRegions(touchCoordinates, x, y) {
425    for (var i = 0; i < touchCoordinates.length; i += 2) {
426      if (hit(touchCoordinates[i], touchCoordinates[i + 1], x, y)) {
427        touchCoordinates.splice(i, i + 2);
428        return true; // allowable region
429      }
430    }
431    return false; // No allowable region; bust it.
432  }
433
434  // Global click handler that prevents the click if it's in a bustable zone and preventGhostClick
435  // was called recently.
436  function onClick(event) {
437    if (Date.now() - lastPreventedTime > PREVENT_DURATION) {
438      return; // Too old.
439    }
440
441    var touches = event.touches && event.touches.length ? event.touches : [event];
442    var x = touches[0].clientX;
443    var y = touches[0].clientY;
444    // Work around desktop Webkit quirk where clicking a label will fire two clicks (on the label
445    // and on the input element). Depending on the exact browser, this second click we don't want
446    // to bust has either (0,0), negative coordinates, or coordinates equal to triggering label
447    // click event
448    if (x < 1 && y < 1) {
449      return; // offscreen
450    }
451    if (lastLabelClickCoordinates &&
452        lastLabelClickCoordinates[0] === x && lastLabelClickCoordinates[1] === y) {
453      return; // input click triggered by label click
454    }
455    // reset label click coordinates on first subsequent click
456    if (lastLabelClickCoordinates) {
457      lastLabelClickCoordinates = null;
458    }
459    // remember label click coordinates to prevent click busting of trigger click event on input
460    if (nodeName_(event.target) === 'label') {
461      lastLabelClickCoordinates = [x, y];
462    }
463
464    // Look for an allowable region containing this click.
465    // If we find one, that means it was created by touchstart and not removed by
466    // preventGhostClick, so we don't bust it.
467    if (checkAllowableRegions(touchCoordinates, x, y)) {
468      return;
469    }
470
471    // If we didn't find an allowable region, bust the click.
472    event.stopPropagation();
473    event.preventDefault();
474
475    // Blur focused form elements
476    if (event.target && event.target.blur) {
477      event.target.blur();
478    }
479  }
480
481
482  // Global touchstart handler that creates an allowable region for a click event.
483  // This allowable region can be removed by preventGhostClick if we want to bust it.
484  function onTouchStart(event) {
485    var touches = event.touches && event.touches.length ? event.touches : [event];
486    var x = touches[0].clientX;
487    var y = touches[0].clientY;
488    touchCoordinates.push(x, y);
489
490    $timeout(function() {
491      // Remove the allowable region.
492      for (var i = 0; i < touchCoordinates.length; i += 2) {
493        if (touchCoordinates[i] === x && touchCoordinates[i + 1] === y) {
494          touchCoordinates.splice(i, i + 2);
495          return;
496        }
497      }
498    }, PREVENT_DURATION, false);
499  }
500
501  // On the first call, attaches some event handlers. Then whenever it gets called, it creates a
502  // zone around the touchstart where clicks will get busted.
503  function preventGhostClick(x, y) {
504    if (!touchCoordinates) {
505      $rootElement[0].addEventListener('click', onClick, true);
506      $rootElement[0].addEventListener('touchstart', onTouchStart, true);
507      touchCoordinates = [];
508    }
509
510    lastPreventedTime = Date.now();
511
512    checkAllowableRegions(touchCoordinates, x, y);
513  }
514
515  // Actual linking function.
516  return function(scope, element, attr) {
517    var clickHandler = $parse(attr.ngClick),
518        tapping = false,
519        tapElement,  // Used to blur the element after a tap.
520        startTime,   // Used to check if the tap was held too long.
521        touchStartX,
522        touchStartY;
523
524    function resetState() {
525      tapping = false;
526      element.removeClass(ACTIVE_CLASS_NAME);
527    }
528
529    element.on('touchstart', function(event) {
530      tapping = true;
531      tapElement = event.target ? event.target : event.srcElement; // IE uses srcElement.
532      // Hack for Safari, which can target text nodes instead of containers.
533      if (tapElement.nodeType === 3) {
534        tapElement = tapElement.parentNode;
535      }
536
537      element.addClass(ACTIVE_CLASS_NAME);
538
539      startTime = Date.now();
540
541      // Use jQuery originalEvent
542      var originalEvent = event.originalEvent || event;
543      var touches = originalEvent.touches && originalEvent.touches.length ? originalEvent.touches : [originalEvent];
544      var e = touches[0];
545      touchStartX = e.clientX;
546      touchStartY = e.clientY;
547    });
548
549    element.on('touchcancel', function(event) {
550      resetState();
551    });
552
553    element.on('touchend', function(event) {
554      var diff = Date.now() - startTime;
555
556      // Use jQuery originalEvent
557      var originalEvent = event.originalEvent || event;
558      var touches = (originalEvent.changedTouches && originalEvent.changedTouches.length) ?
559          originalEvent.changedTouches :
560          ((originalEvent.touches && originalEvent.touches.length) ? originalEvent.touches : [originalEvent]);
561      var e = touches[0];
562      var x = e.clientX;
563      var y = e.clientY;
564      var dist = Math.sqrt(Math.pow(x - touchStartX, 2) + Math.pow(y - touchStartY, 2));
565
566      if (tapping && diff < TAP_DURATION && dist < MOVE_TOLERANCE) {
567        // Call preventGhostClick so the clickbuster will catch the corresponding click.
568        preventGhostClick(x, y);
569
570        // Blur the focused element (the button, probably) before firing the callback.
571        // This doesn't work perfectly on Android Chrome, but seems to work elsewhere.
572        // I couldn't get anything to work reliably on Android Chrome.
573        if (tapElement) {
574          tapElement.blur();
575        }
576
577        if (!angular.isDefined(attr.disabled) || attr.disabled === false) {
578          element.triggerHandler('click', [event]);
579        }
580      }
581
582      resetState();
583    });
584
585    // Hack for iOS Safari's benefit. It goes searching for onclick handlers and is liable to click
586    // something else nearby.
587    element.onclick = function(event) { };
588
589    // Actual click handler.
590    // There are three different kinds of clicks, only two of which reach this point.
591    // - On desktop browsers without touch events, their clicks will always come here.
592    // - On mobile browsers, the simulated "fast" click will call this.
593    // - But the browser's follow-up slow click will be "busted" before it reaches this handler.
594    // Therefore it's safe to use this directive on both mobile and desktop.
595    element.on('click', function(event, touchend) {
596      scope.$apply(function() {
597        clickHandler(scope, {$event: (touchend || event)});
598      });
599    });
600
601    element.on('mousedown', function(event) {
602      element.addClass(ACTIVE_CLASS_NAME);
603    });
604
605    element.on('mousemove mouseup', function(event) {
606      element.removeClass(ACTIVE_CLASS_NAME);
607    });
608
609  };
610}];
611
612/* global ngTouch: false */
613
614/**
615 * @ngdoc directive
616 * @name ngSwipeLeft
617 *
618 * @description
619 * Specify custom behavior when an element is swiped to the left on a touchscreen device.
620 * A leftward swipe is a quick, right-to-left slide of the finger.
621 * Though ngSwipeLeft is designed for touch-based devices, it will work with a mouse click and drag
622 * too.
623 *
624 * To disable the mouse click and drag functionality, add `ng-swipe-disable-mouse` to
625 * the `ng-swipe-left` or `ng-swipe-right` DOM Element.
626 *
627 * Requires the {@link ngTouch `ngTouch`} module to be installed.
628 *
629 * @element ANY
630 * @param {expression} ngSwipeLeft {@link guide/expression Expression} to evaluate
631 * upon left swipe. (Event object is available as `$event`)
632 *
633 * @example
634    <example module="ngSwipeLeftExample" deps="angular-touch.js" name="ng-swipe-left">
635      <file name="index.html">
636        <div ng-show="!showActions" ng-swipe-left="showActions = true">
637          Some list content, like an email in the inbox
638        </div>
639        <div ng-show="showActions" ng-swipe-right="showActions = false">
640          <button ng-click="reply()">Reply</button>
641          <button ng-click="delete()">Delete</button>
642        </div>
643      </file>
644      <file name="script.js">
645        angular.module('ngSwipeLeftExample', ['ngTouch']);
646      </file>
647    </example>
648 */
649
650/**
651 * @ngdoc directive
652 * @name ngSwipeRight
vendor: 3,592 bytes, lines 652-747
652
653 *
654 * @description
655 * Specify custom behavior when an element is swiped to the right on a touchscreen device.
656 * A rightward swipe is a quick, left-to-right slide of the finger.
657 * Though ngSwipeRight is designed for touch-based devices, it will work with a mouse click and drag
658 * too.
659 *
660 * Requires the {@link ngTouch `ngTouch`} module to be installed.
661 *
662 * @element ANY
663 * @param {expression} ngSwipeRight {@link guide/expression Expression} to evaluate
664 * upon right swipe. (Event object is available as `$event`)
665 *
666 * @example
667    <example module="ngSwipeRightExample" deps="angular-touch.js" name="ng-swipe-right">
668      <file name="index.html">
669        <div ng-show="!showActions" ng-swipe-left="showActions = true">
670          Some list content, like an email in the inbox
671        </div>
672        <div ng-show="showActions" ng-swipe-right="showActions = false">
673          <button ng-click="reply()">Reply</button>
674          <button ng-click="delete()">Delete</button>
675        </div>
676      </file>
677      <file name="script.js">
678        angular.module('ngSwipeRightExample', ['ngTouch']);
679      </file>
680    </example>
681 */
682
683function makeSwipeDirective(directiveName, direction, eventName) {
684  ngTouch.directive(directiveName, ['$parse', '$swipe', function($parse, $swipe) {
685    // The maximum vertical delta for a swipe should be less than 75px.
686    var MAX_VERTICAL_DISTANCE = 75;
687    // Vertical distance should not be more than a fraction of the horizontal distance.
688    var MAX_VERTICAL_RATIO = 0.3;
689    // At least a 30px lateral motion is necessary for a swipe.
690    var MIN_HORIZONTAL_DISTANCE = 30;
691
692    return function(scope, element, attr) {
693      var swipeHandler = $parse(attr[directiveName]);
694
695      var startCoords, valid;
696
697      function validSwipe(coords) {
698        // Check that it's within the coordinates.
699        // Absolute vertical distance must be within tolerances.
700        // Horizontal distance, we take the current X - the starting X.
701        // This is negative for leftward swipes and positive for rightward swipes.
702        // After multiplying by the direction (-1 for left, +1 for right), legal swipes
703        // (ie. same direction as the directive wants) will have a positive delta and
704        // illegal ones a negative delta.
705        // Therefore this delta must be positive, and larger than the minimum.
706        if (!startCoords) return false;
707        var deltaY = Math.abs(coords.y - startCoords.y);
708        var deltaX = (coords.x - startCoords.x) * direction;
709        return valid && // Short circuit for already-invalidated swipes.
710            deltaY < MAX_VERTICAL_DISTANCE &&
711            deltaX > 0 &&
712            deltaX > MIN_HORIZONTAL_DISTANCE &&
713            deltaY / deltaX < MAX_VERTICAL_RATIO;
714      }
715
716      var pointerTypes = ['touch'];
717      if (!angular.isDefined(attr['ngSwipeDisableMouse'])) {
718        pointerTypes.push('mouse');
719      }
720      $swipe.bind(element, {
721        'start': function(coords, event) {
722          startCoords = coords;
723          valid = true;
724        },
725        'cancel': function(event) {
726          valid = false;
727        },
728        'end': function(coords, event) {
729          if (validSwipe(coords)) {
730            scope.$apply(function() {
731              element.triggerHandler(eventName);
732              swipeHandler(scope, {$event: event});
733            });
734          }
735        }
736      }, pointerTypes);
737    };
738  }]);
739}
740
741// Left is negative X-coordinate, right is positive.
742makeSwipeDirective('ngSwipeLeft', -1, 'swipeleft');
743makeSwipeDirective('ngSwipeRight', 1, 'swiperight');
744
745
746
747})(window, window.angular);

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.