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.