1/*!� 2 * jQuery Mobile Events� 3 * by Ben Major (www.ben-major.co.uk)� 4 *� 5 * Copyright 2011, Ben Major� 6 * Licensed under the MIT License:� 7 * � 8 * Permission is hereby granted, free of charge, to any person obtaining a copy� 9 * of this software and associated documentation files (the "Software"), to deal� 10 * in the Software without restriction, including without limitation the rights� 11 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell� 12 * copies of the Software, and to permit persons to whom the Software is� 13 * furnished to do so, subject to the following conditions:� 14 *� 15 * The above copyright notice and this permission notice shall be included in� 16 * all copies or substantial portions of the Software.� 17 *� 18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR� 19 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,� 20 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE� 21 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER� 22 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,� 23 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN� 24 * THE SOFTWARE.� 25 * � 26 */� 27(function ($) {� 28 $.attrFn = $.attrFn || {};� 29� 30 // navigator.userAgent.toLowerCase() isn't reliable for Chrome installs� 31 // on mobile devices. As such, we will create a boolean isChromeDesktop� 32 // The reason that we need to do this is because Chrome annoyingly� 33 // purports support for touch events even if the underlying hardware� 34 // does not!� 35 var agent = navigator.userAgent.toLowerCase(),� 36 isChromeDesktop = (agent.indexOf('chrome') > -1 && ((agent.indexOf('windows') > -1) || (agent.indexOf('macintosh') > -1) || (agent.indexOf('linux') > -1)) && agent.indexOf('mobile') < 0 && agent.indexOf('android') < 0),� 37� 38 settings = {� 39 tap_pixel_range: 5,� 40 swipe_h_threshold: 50,� 41 swipe_v_threshold: 50,� 42 taphold_threshold: 750,� 43 doubletap_int: 500,� 44� 45 touch_capable: ('ontouchstart' in window && !isChromeDesktop),� 46 orientation_support: ('orientation' in window && 'onorientationchange' in window),� 47� 48 startevent: ('ontouchstart' in window && !isChromeDesktop) ? 'touchstart' : 'mousedown',� 49 endevent: ('ontouchstart' in window && !isChromeDesktop) ? 'touchend' : 'mouseup',� 50 moveevent: ('ontouchstart' in window && !isChromeDesktop) ? 'touchmove' : 'mousemove',� 51 tapevent: ('ontouchstart' in window && !isChromeDesktop) ? 'tap' : 'click',� 52 scrollevent: ('ontouchstart' in window && !isChromeDesktop) ? 'touchmove' : 'scroll',� 53� 54 hold_timer: null,� 55 tap_timer: null� 56 };� 57� 58 // Convenience functions:� 59 $.isTouchCapable = function() { return settings.touch_capable; };� 60 $.getStartEvent = function() { return settings.startevent; };� 61 $.getEndEvent = function() { return settings.endevent; };� 62 $.getMoveEvent = function() { return settings.moveevent; };� 63 $.getTapEvent = function() { return settings.tapevent; };� 64 $.getScrollEvent = function() { return settings.scrollevent; };� 65� 66 // Add Event shortcuts:� 67 $.each(['tapstart', 'tapend', 'tapmove', 'tap', 'tap2', 'tap3', 'tap4', 'singletap', 'doubletap', 'taphold', 'swipe', 'swipeup', 'swiperight', 'swipedown', 'swipeleft', 'swipeend', 'scrollstart', 'scrollend', 'orientationchange'], function (i, name) {� 68 $.fn[name] = function (fn) {� 69 return fn ? this.on(name, fn) : this.trigger(name);� 70 };� 71� 72 $.attrFn[name] = true;� 73 });� 74� 75 // tapstart Event:� 76 $.event.special.tapstart = {� 77 setup: function () {� 78 var thisObject = this,� 79 $this = $(thisObject);� 80� 81 $this.on(settings.startevent, function (e) {� 82 $this.data('callee', arguments.callee);� 83 if (e.which && e.which !== 1) {� 84 return false;� 85 }� 86� 87 var origEvent = e.originalEvent,� 88 touchData = {� 89 'position': {� 90 'x': ((settings.touch_capable) ? origEvent.touches[0].screenX : e.screenX),� 91 'y': (settings.touch_capable) ? origEvent.touches[0].screenY : e.screenY� 92 },� 93 'offset': {� 94 'x': (settings.touch_capable) ? origEvent.touches[0].pageX - origEvent.touches[0].target.offsetLeft : e.offsetX,� 95 'y': (settings.touch_capable) ? origEvent.touches[0].pageY - origEvent.touches[0].target.offsetTop : e.offsetY� 96 },� 97 'time': Date.now(),� 98 'target': e.target� 99 };� 100� 101 triggerCustomEvent(thisObject, 'tapstart', e, touchData);� 102 return true;� 103 });� 104 },� 105� 106 remove: function () {� 107 $(this).off(settings.startevent, $(this).data.callee);� 108 }� 109 };� 110� 111 // tapmove Event:� 112 $.event.special.tapmove = {� 113 setup: function() {� 114 var thisObject = this,� 115 $this = $(thisObject);� 116� 117 $this.on(settings.moveevent, function(e) {� 118 $this.data('callee', arguments.callee);� 119� 120 var origEvent = e.originalEvent,� 121 touchData = {� 122 'position': {� 123 'x': ((settings.touch_capable) ? origEvent.touches[0].screenX : e.screenX),� 124 'y': (settings.touch_capable) ? origEvent.touches[0].screenY : e.screenY� 125 },� 126 'offset': {� 127 'x': (settings.touch_capable) ? origEvent.touches[0].pageX - origEvent.touches[0].target.offsetLeft : e.offsetX,� 128 'y': (settings.touch_capable) ? origEvent.touches[0].pageY - origEvent.touches[0].target.offsetTop : e.offsetY� 129 },� 130 'time': Date.now(),� 131 'target': e.target� 132 };� 133� 134 triggerCustomEvent(thisObject, 'tapmove', e, touchData);� 135 return true;� 136 });� 137 },� 138 remove: function() {� 139 $(this).off(settings.moveevent, $(this).data.callee);� 140 }� 141 }� 142� 143 // tapend Event:� 144 $.event.special.tapend = {� 145 setup: function () {� 146 var thisObject = this,� 147 $this = $(thisObject);� 148� 149 $this.on(settings.endevent, function (e) {� 150 // Touch event data:� 151 $this.data('callee', arguments.callee);� 152� 153 var origEvent = e.originalEvent;� 154 var touchData = {� 155 'position': {� 156 'x': (settings.touch_capable) ? origEvent.changedTouches[0].screenX : e.screenX,� 157 'y': (settings.touch_capable) ? origEvent.changedTouches[0].screenY : e.screenY� 158 },� 159 'offset': {� 160 'x': (settings.touch_capable) ? origEvent.changedTouches[0].pageX - origEvent.changedTouches[0].target.offsetLeft : e.offsetX,� 161 'y': (settings.touch_capable) ? origEvent.changedTouches[0].pageY - origEvent.changedTouches[0].target.offsetTop : e.offsetY� 162 },� 163 'time': Date.now(),� 164 'target': e.target� 165 };� 166 triggerCustomEvent(thisObject, 'tapend', e, touchData);� 167 return true;� 168 });� 169 },� 170 remove: function () {� 171 $(this).off(settings.endevent, $(this).data.callee);� 172 }� 173 };� 174� 175 // taphold Event:� 176 $.event.special.taphold = {� 177 setup: function () {� 178 var thisObject = this,� 179 $this = $(thisObject),� 180 origTarget,� 181 timer,� 182 start_pos = {� 183 x: 0,� 184 y: 0� 185 },� 186 end_x = 0,� 187 end_y = 0;� 188� 189 $this.on(settings.startevent, function (e) {� 190 if (e.which && e.which !== 1) {� 191 return false;� 192 } else {� 193 $this.data('tapheld', false);� 194 origTarget = e.target;� 195� 196 var origEvent = e.originalEvent;� 197 var start_time = Date.now(),� 198 startPosition = {� 199 'x': (settings.touch_capable) ? origEvent.touches[0].screenX : e.screenX,� 200 'y': (settings.touch_capable) ? origEvent.touches[0].screenY : e.screenY� 201 },� 202 startOffset = {� 203 'x': (settings.touch_capable) ? origEvent.touches[0].pageX - origEvent.touches[0].target.offsetLeft : e.offsetX,� 204 'y': (settings.touch_capable) ? origEvent.touches[0].pageY - origEvent.touches[0].target.offsetTop : e.offsetY� 205 };� 206� 207 start_pos.x = (e.originalEvent.targetTouches) ? e.originalEvent.targetTouches[0].pageX : e.pageX;� 208 start_pos.y = (e.originalEvent.targetTouches) ? e.originalEvent.targetTouches[0].pageY : e.pageY;� 209� 210 end_x = start_pos.x;� 211 end_y = start_pos.y;� 212� 213 settings.hold_timer = window.setTimeout(function () {� 214� 215 var diff_x = (start_pos.x - end_x),� 216 diff_y = (start_pos.y - end_y);� 217� 218 if (e.target == origTarget && ((start_pos.x == end_x && start_pos.y == end_y) || (diff_x >= -(settings.tap_pixel_range) && diff_x <= settings.tap_pixel_range && diff_y >= -(settings.tap_pixel_range) && diff_y <= settings.tap_pixel_range))) {� 219 $this.data('tapheld', true);� 220� 221 var end_time = Date.now(),� 222 endPosition = {� 223 'x': (settings.touch_capable) ? origEvent.touches[0].screenX : e.screenX,� 224 'y': (settings.touch_capable) ? origEvent.touches[0].screenY : e.screenY� 225 },� 226 endOffset = {� 227 'x': (settings.touch_capable) ? origEvent.touches[0].pageX - origEvent.touches[0].target.offsetLeft : e.offsetX,� 228 'y': (settings.touch_capable) ? origEvent.touches[0].pageY - origEvent.touches[0].target.offsetTop : e.offsetY� 229 };� 230 duration = end_time - start_time;� 231� 232 // Build the touch data:� 233 var touchData = {� 234 'startTime': start_time,� 235 'endTime': end_time,� 236 'startPosition': startPosition,� 237 'startOffset': startOffset,� 238 'endPosition': endPosition,� 239 'endOffset': endOffset,� 240 'duration': duration,� 241 'target': e.target� 242 }� 243 $this.data('callee1', arguments.callee);� 244 triggerCustomEvent(thisObject, 'taphold', e, touchData);� 245 }� 246 }, settings.taphold_threshold);� 247� 248 return true;� 249 }� 250 }).on(settings.endevent, function () {� 251 $this.data('callee2', arguments.callee);� 252 $this.data('tapheld', false);� 253 window.clearTimeout(settings.hold_timer);� 254 })� 255 .on(settings.moveevent, function (e) {� 256 $this.data('callee3', arguments.callee);� 257� 258 end_x = (e.originalEvent.targetTouches) ? e.originalEvent.targetTouches[0].pageX : e.pageX;� 259 end_y = (e.originalEvent.targetTouches) ? e.originalEvent.targetTouches[0].pageY : e.pageY;� 260 });� 261 },� 262� 263 remove: function () {� 264 $(this).off(settings.startevent, $(this).data.callee1).off(settings.endevent, $(this).data.callee2).off(settings.moveevent, $(this).data.callee3);� 265 }� 266 };� 267� 268 // doubletap Event:� 269 $.event.special.doubletap = {� 270 setup: function () {� 271 var thisObject = this,� 272 $this = $(thisObject),� 273 origTarget,� 274 action,� 275 firstTap,� 276 origEvent,� 277 cooloff,� 278 cooling = false;� 279� 280 $this.on(settings.startevent, function (e) {� 281 if (e.which && e.which !== 1) {� 282 return false;� 283 }� 284 $this.data('doubletapped', false);� 285 origTarget = e.target;� 286 $this.data('callee1', arguments.callee);� 287� 288 origEvent = e.originalEvent;� 289 firstTap = {� 290 'position': {� 291 'x': (settings.touch_capable) ? origEvent.touches[0].screenX : e.screenX,� 292 'y': (settings.touch_capable) ? origEvent.touches[0].screenY : e.screenY� 293 },� 294 'offset': {� 295 'x': (settings.touch_capable) ? origEvent.touches[0].pageX - origEvent.touches[0].target.offsetLeft : e.offsetX,� 296 'y': (settings.touch_capable) ? origEvent.touches[0].pageY - origEvent.touches[0].target.offsetTop : e.offsetY� 297 },� 298 'time': Date.now(),� 299 'target': e.target� 300 };� 301� 302 return true;� 303 }).on(settings.endevent, function (e) {� 304� 305 var now = Date.now();� 306 var lastTouch = $this.data('lastTouch') || now + 1;� 307 var delta = now - lastTouch;� 308 window.clearTimeout(action);� 309 $this.data('callee2', arguments.callee);� 310� 311 if (delta < settings.doubletap_int && (e.target == origTarget) && delta > 100) {� 312 $this.data('doubletapped', true);� 313 window.clearTimeout(settings.tap_timer);� 314� 315 // Now get the current event:� 316 var lastTap = {� 317 'position': {� 318 'x': (settings.touch_capable) ? e.originalEvent.changedTouches[0].screenX : e.screenX,� 319 'y': (settings.touch_capable) ? e.originalEvent.changedTouches[0].screenY : e.screenY� 320 },� 321 'offset': {� 322 'x': (settings.touch_capable) ? e.originalEvent.changedTouches[0].pageX - e.originalEvent.changedTouches[0].target.offsetLeft : e.offsetX,� 323 'y': (settings.touch_capable) ? e.originalEvent.changedTouches[0].pageY - e.originalEvent.changedTouches[0].target.offsetTop : e.offsetY� 324 },� 325 'time': Date.now(),� 326 'target': e.target� 327 }� 328� 329 var touchData = {� 330 'firstTap': firstTap,� 331 'secondTap': lastTap,� 332 'interval': lastTap.time - firstTap.time� 333 };� 334� 335 if (!cooling) {� 336 triggerCustomEvent(thisObject, 'doubletap', e, touchData);� 337 }� 338� 339 cooling = true;� 340� 341 cooloff = window.setTimeout(function (e) {� 342 cooling = false;� 343
343 }, settings.doubletap_int);� 344� 345 } else {� 346 $this.data('lastTouch', now);� 347 action = window.setTimeout(function (e) {� 348 window.clearTimeout(action);� 349 }, settings.doubletap_int, [e]);� 350 }� 351 $this.data('lastTouch', now);� 352 });� 353 },� 354 remove: function () {� 355 $(this).off(settings.startevent, $(this).data.callee1).off(settings.endevent, $(this).data.callee2);� 356 }� 357 };� 358� 359 // singletap Event:� 360 // This is used in conjuction with doubletap when both events are needed on the same element� 361 $.event.special.singletap = {� 362 setup: function () {� 363 var thisObject = this,� 364 $this = $(thisObject),� 365 origTarget = null,� 366 startTime = null,� 367 start_pos = {� 368 x: 0,� 369 y: 0� 370 };� 371� 372 $this.on(settings.startevent, function (e) {� 373 if (e.which && e.which !== 1) {� 374 return false;� 375 } else {� 376 startTime = Date.now();� 377 origTarget = e.target;� 378 $this.data('callee1', arguments.callee);� 379� 380 // Get the start x and y position:� 381 start_pos.x = (e.originalEvent.targetTouches) ? e.originalEvent.targetTouches[0].pageX : e.pageX;� 382 start_pos.y = (e.originalEvent.targetTouches) ? e.originalEvent.targetTouches[0].pageY : e.pageY;� 383 return true;� 384 }� 385 }).on(settings.endevent, function (e) {� 386 $this.data('callee2', arguments.callee);� 387 if (e.target == origTarget) {� 388 // Get the end point:� 389 end_pos_x = (e.originalEvent.changedTouches) ? e.originalEvent.changedTouches[0].pageX : e.pageX;� 390 end_pos_y = (e.originalEvent.changedTouches) ? e.originalEvent.changedTouches[0].pageY : e.pageY;� 391� 392 // We need to check if it was a taphold:� 393� 394 settings.tap_timer = window.setTimeout(function () {� 395 if (!$this.data('doubletapped') && !$this.data('tapheld') && (start_pos.x == end_pos_x) && (start_pos.y == end_pos_y)) {� 396 var origEvent = e.originalEvent;� 397 var touchData = {� 398 'position': {� 399 'x': (settings.touch_capable) ? origEvent.changedTouches[0].screenX : e.screenX,� 400 'y': (settings.touch_capable) ? origEvent.changedTouches[0].screenY : e.screenY� 401 },� 402 'offset': {� 403 'x': (settings.touch_capable) ? origEvent.changedTouches[0].pageX - origEvent.changedTouches[0].target.offsetLeft : e.offsetX,� 404 'y': (settings.touch_capable) ? origEvent.changedTouches[0].pageY - origEvent.changedTouches[0].target.offsetTop : e.offsetY� 405 },� 406 'time': Date.now(),� 407 'target': e.target� 408 };� 409� 410 // Was it a taphold?� 411 if((touchData.time - startTime) < settings.taphold_threshold)� 412 {� 413 triggerCustomEvent(thisObject, 'singletap', e, touchData);� 414 }� 415 }� 416 }, settings.doubletap_int);� 417 }� 418 });� 419 },� 420� 421 remove: function () {� 422 $(this).off(settings.startevent, $(this).data.callee1).off(settings.endevent, $(this).data.callee2);� 423 }� 424 };� 425� 426 // tap Event:� 427 $.event.special.tap = {� 428 setup: function () {� 429 var thisObject = this,� 430 $this = $(thisObject),� 431 started = false,� 432 origTarget = null,� 433 start_time,� 434 start_pos = {� 435 x: 0,� 436 y: 0� 437 },� 438 touches;� 439� 440 $this.on(settings.startevent, function (e) {� 441 $this.data('callee1', arguments.callee);� 442� 443 if (e.which && e.which !== 1) {� 444 return false;� 445 } else {� 446 started = true;� 447 start_pos.x = (e.originalEvent.targetTouches) ? e.originalEvent.targetTouches[0].pageX : e.pageX;� 448 start_pos.y = (e.originalEvent.targetTouches) ? e.originalEvent.targetTouches[0].pageY : e.pageY;� 449 start_time = Date.now();� 450 origTarget = e.target;� 451� 452 touches = (e.originalEvent.targetTouches) ? e.originalEvent.targetTouches : [ e ];� 453 return true;� 454 }� 455 }).on(settings.endevent, function (e) {� 456 $this.data('callee2', arguments.callee);� 457� 458 // Only trigger if they've started, and the target matches:� 459 var end_x = (e.originalEvent.targetTouches) ? e.originalEvent.changedTouches[0].pageX : e.pageX,� 460 end_y = (e.originalEvent.targetTouches) ? e.originalEvent.changedTouches[0].pageY : e.pageY,� 461 diff_x = (start_pos.x - end_x),� 462 diff_y = (start_pos.y - end_y),� 463 eventName;� 464� 465 if (origTarget == e.target && started && ((Date.now() - start_time) < settings.taphold_threshold) && ((start_pos.x == end_x && start_pos.y == end_y) || (diff_x >= -(settings.tap_pixel_range) && diff_x <= settings.tap_pixel_range && diff_y >= -(settings.tap_pixel_range) && diff_y <= settings.tap_pixel_range))) {� 466 var origEvent = e.originalEvent;� 467 var touchData = [ ];� 468� 469 for( var i = 0; i < touches.length; i++)� 470 {� 471 var touch = {� 472 'position': {� 473 'x': (settings.touch_capable) ? origEvent.changedTouches[i].screenX : e.screenX,� 474 'y': (settings.touch_capable) ? origEvent.changedTouches[i].screenY : e.screenY� 475 },� 476 'offset': {� 477 'x': (settings.touch_capable) ? origEvent.changedTouches[i].pageX - origEvent.changedTouches[i].target.offsetLeft : e.offsetX,� 478 'y': (settings.touch_capable) ? origEvent.changedTouches[i].pageY - origEvent.changedTouches[i].target.offsetTop : e.offsetY� 479 },� 480 'time': Date.now(),� 481 'target': e.target� 482 };� 483� 484 touchData.push( touch );� 485 }� 486� 487 switch( touches.length )� 488 {� 489 case 1:� 490 eventName = 'tap';� 491 break;� 492� 493 case 2:� 494 eventName = 'tap2';� 495 break;� 496� 497 case 3:� 498 eventName = 'tap3';� 499 break;� 500� 501 case 4:� 502 eventName = 'tap4';� 503 break;� 504 }� 505� 506 triggerCustomEvent(thisObject, eventName, e, touchData);� 507 }� 508 });� 509 },� 510� 511 remove: function () {� 512 $(this).off(settings.startevent, $(this).data.callee1).off(settings.endevent, $(this).data.callee2);� 513 }� 514 };� 515� 516 // swipe Event (also handles swipeup, swiperight, swipedown and swipeleft):� 517 $.event.special.swipe = {� 518 setup: function () {� 519 var thisObject = this,� 520 $this = $(thisObject),� 521 started = false,� 522 hasSwiped = false,� 523 originalCoord = {� 524 x: 0,� 525 y: 0� 526 },� 527 finalCoord = {� 528 x: 0,� 529 y: 0� 530 },� 531 startEvnt;� 532� 533 // Screen touched, store the original coordinate� 534� 535 function touchStart(e) {� 536 $this = $(e.target);� 537 $this.data('callee1', arguments.callee);� 538 originalCoord.x = (e.originalEvent.targetTouches) ? e.originalEvent.targetTouches[0].pageX : e.pageX;� 539 originalCoord.y = (e.originalEvent.targetTouches) ? e.originalEvent.targetTouches[0].pageY : e.pageY;� 540 finalCoord.x = originalCoord.x;� 541 finalCoord.y = originalCoord.y;� 542 started = true;� 543 var origEvent = e.originalEvent;� 544 // Read event data into our startEvt:� 545 startEvnt = {� 546 'position': {� 547 'x': (settings.touch_capable) ? origEvent.touches[0].screenX : e.screenX,� 548 'y': (settings.touch_capable) ? origEvent.touches[0].screenY : e.screenY� 549 },� 550 'offset': {� 551 'x': (settings.touch_capable) ? origEvent.touches[0].pageX - origEvent.touches[0].target.offsetLeft : e.offsetX,� 552 'y': (settings.touch_capable) ? origEvent.touches[0].pageY - origEvent.touches[0].target.offsetTop : e.offsetY� 553 },� 554 'time': Date.now(),� 555 'target': e.target� 556 };� 557 }� 558� 559 // Store coordinates as finger is swiping� 560� 561 function touchMove(e) {� 562 $this = $(e.target);� 563 $this.data('callee2', arguments.callee);� 564 finalCoord.x = (e.originalEvent.targetTouches) ? e.originalEvent.targetTouches[0].pageX : e.pageX;� 565 finalCoord.y = (e.originalEvent.targetTouches) ? e.originalEvent.targetTouches[0].pageY : e.pageY;� 566� 567 var swipedir;� 568� 569 // We need to check if the element to which the event was bound contains a data-xthreshold | data-vthreshold:� 570 var ele_x_threshold = $this.data('xthreshold'),� 571 ele_y_threshold = $this.data('ythreshold'),� 572 h_threshold = (typeof ele_x_threshold !== 'undefined' && ele_x_threshold !== false && parseInt(ele_x_threshold)) ? parseInt(ele_x_threshold) : settings.swipe_h_threshold,� 573 v_threshold = (typeof ele_y_threshold !== 'undefined' && ele_y_threshold !== false && parseInt(ele_y_threshold)) ? parseInt(ele_y_threshold) : settings.swipe_v_threshold;� 574� 575 if (originalCoord.y > finalCoord.y && (originalCoord.y - finalCoord.y > v_threshold)) {� 576 swipedir = 'swipeup';� 577 }� 578 if (originalCoord.x < finalCoord.x && (finalCoord.x - originalCoord.x > h_threshold)) {� 579 swipedir = 'swiperight';� 580 }�
581 if (originalCoord.y < finalCoord.y && (finalCoord.y - originalCoord.y > v_threshold)) {� 582 swipedir = 'swipedown';� 583 }� 584 if (originalCoord.x > finalCoord.x && (originalCoord.x - finalCoord.x > h_threshold)) {� 585 swipedir = 'swipeleft';� 586 }� 587 if (swipedir != undefined && started) {� 588 originalCoord.x = 0;� 589 originalCoord.y = 0;� 590 finalCoord.x = 0;� 591 finalCoord.y = 0;� 592 started = false;� 593� 594 // Read event data into our endEvnt:� 595 var origEvent = e.originalEvent;� 596 endEvnt = {� 597 'position': {� 598 'x': (settings.touch_capable) ? origEvent.touches[0].screenX : e.screenX,� 599 'y': (settings.touch_capable) ? origEvent.touches[0].screenY : e.screenY� 600 },� 601 'offset': {� 602 'x': (settings.touch_capable) ? origEvent.touches[0].pageX - origEvent.touches[0].target.offsetLeft : e.offsetX,� 603 'y': (settings.touch_capable) ? origEvent.touches[0].pageY - origEvent.touches[0].target.offsetTop : e.offsetY� 604 },� 605 'time': Date.now(),� 606 'target': e.target� 607 };� 608� 609 // Calculate the swipe amount (normalized):� 610 var xAmount = Math.abs(startEvnt.position.x - endEvnt.position.x),� 611 yAmount = Math.abs(startEvnt.position.y - endEvnt.position.y);� 612� 613 var touchData = {� 614 'startEvnt': startEvnt,� 615 'endEvnt': endEvnt,� 616 'direction': swipedir.replace('swipe', ''),� 617 'xAmount': xAmount,� 618 'yAmount': yAmount,� 619 'duration': endEvnt.time - startEvnt.time� 620 }� 621 hasSwiped = true;� 622 $this.trigger('swipe', touchData).trigger(swipedir, touchData);� 623 }� 624 }� 625� 626 function touchEnd(e) {� 627 $this = $(e.target);� 628 var swipedir = "";� 629 $this.data('callee3', arguments.callee);� 630 if (hasSwiped) {� 631 // We need to check if the element to which the event was bound contains a data-xthreshold | data-vthreshold:� 632 var ele_x_threshold = $this.data('xthreshold'),� 633 ele_y_threshold = $this.data('ythreshold'),� 634 h_threshold = (typeof ele_x_threshold !== 'undefined' && ele_x_threshold !== false && parseInt(ele_x_threshold)) ? parseInt(ele_x_threshold) : settings.swipe_h_threshold,� 635 v_threshold = (typeof ele_y_threshold !== 'undefined' && ele_y_threshold !== false && parseInt(ele_y_threshold)) ? parseInt(ele_y_threshold) : settings.swipe_v_threshold;� 636� 637 var origEvent = e.originalEvent;� 638 endEvnt = {� 639 'position': {� 640 'x': (settings.touch_capable) ? origEvent.changedTouches[0].screenX : e.screenX,� 641 'y': (settings.touch_capable) ? origEvent.changedTouches[0].screenY : e.screenY� 642 },� 643 'offset': {� 644 'x': (settings.touch_capable) ? origEvent.changedTouches[0].pageX - origEvent.changedTouches[0].target.offsetLeft : e.offsetX,� 645 'y': (settings.touch_capable) ? origEvent.changedTouches[0].pageY - origEvent.changedTouches[0].target.offsetTop : e.offsetY� 646 },� 647 'time': Date.now(),� 648 'target': e.target� 649 };� 650� 651 // Read event data into our endEvnt:� 652 if (startEvnt.position.y > endEvnt.position.y && (startEvnt.position.y - endEvnt.position.y > v_threshold)) {� 653 swipedir = 'swipeup';� 654 }� 655 if (startEvnt.position.x < endEvnt.position.x && (endEvnt.position.x - startEvnt.position.x > h_threshold)) {� 656 swipedir = 'swiperight';� 657 }� 658 if (startEvnt.position.y < endEvnt.position.y && (endEvnt.position.y - startEvnt.position.y > v_threshold)) {� 659 swipedir = 'swipedown';� 660 }� 661 if (startEvnt.position.x > endEvnt.position.x && (startEvnt.position.x - endEvnt.position.x > h_threshold)) {� 662 swipedir = 'swipeleft';� 663 }� 664� 665 // Calculate the swipe amount (normalized):� 666 var xAmount = Math.abs(startEvnt.position.x - endEvnt.position.x),� 667 yAmount = Math.abs(startEvnt.position.y - endEvnt.position.y);� 668� 669 var touchData = {� 670 'startEvnt': startEvnt,� 671 'endEvnt': endEvnt,� 672 'direction': swipedir.replace('swipe', ''),� 673 'xAmount': xAmount,� 674 'yAmount': yAmount,� 675 'duration': endEvnt.time - startEvnt.time� 676 }� 677 $this.trigger('swipeend', touchData);� 678 }� 679� 680 started = false;� 681 hasSwiped = false;� 682 }� 683� 684 $this.on(settings.startevent, touchStart);� 685 $this.on(settings.moveevent, touchMove);� 686 $this.on(settings.endevent, touchEnd);� 687 },� 688� 689 remove: function () {� 690 $(this).off(settings.startevent, $(this).data.callee1).off(settings.moveevent, $(this).data.callee2).off(settings.endevent, $(this).data.callee3);� 691 }� 692 };� 693� 694 // scrollstart Event (also handles scrollend):� 695 $.event.special.scrollstart = {� 696 setup: function () {� 697 var thisObject = this,� 698 $this = $(thisObject),� 699 scrolling,� 700 timer;� 701� 702 function trigger(event, state) {� 703 scrolling = state;� 704 triggerCustomEvent(thisObject, scrolling ? 'scrollstart' : 'scrollend', event);� 705 }� 706� 707 // iPhone triggers scroll after a small delay; use touchmove instead� 708 $this.on(settings.scrollevent, function (event) {� 709 $this.data('callee', arguments.callee);� 710� 711 if (!scrolling) {� 712 trigger(event, true);� 713 }� 714� 715 clearTimeout(timer);� 716 timer = setTimeout(function () {� 717 trigger(event, false);� 718 }, 50);� 719 });� 720 },� 721� 722 remove: function () {� 723 $(this).off(settings.scrollevent, $(this).data.callee);� 724 }� 725 };� 726� 727 // This is the orientation change (largely borrowed from jQuery Mobile):� 728 var win = $(window),� 729 special_event,� 730 get_orientation,� 731 last_orientation,� 732 initial_orientation_is_landscape,� 733 initial_orientation_is_default,� 734 portrait_map = {� 735 '0': true,� 736 '180': true� 737 };� 738� 739 if (settings.orientation_support) {� 740 var ww = window.innerWidth || win.width(),� 741 wh = window.innerHeight || win.height(),� 742 landscape_threshold = 50;� 743� 744 initial_orientation_is_landscape = ww > wh && (ww - wh) > landscape_threshold;� 745 initial_orientation_is_default = portrait_map[window.orientation];� 746� 747 if ((initial_orientation_is_landscape && initial_orientation_is_default) || (!initial_orientation_is_landscape && !initial_orientation_is_default)) {� 748 portrait_map = {�
749 '-90': true,� 750 '90': true� 751 };� 752 }� 753 }� 754� 755 $.event.special.orientationchange = special_event = {� 756 setup: function () {� 757 // If the event is supported natively, return false so that jQuery� 758 // will on to the event using DOM methods.� 759 if (settings.orientation_support) {� 760 return false;� 761 }� 762� 763 // Get the current orientation to avoid initial double-triggering.� 764 last_orientation = get_orientation();� 765� 766 win.on('throttledresize', handler);� 767 return true;� 768 },� 769 teardown: function () {� 770 if (settings.orientation_support) {� 771 return false;� 772 }� 773� 774 win.off('throttledresize', handler);� 775 return true;� 776 },� 777 add: function (handleObj) {� 778 // Save a reference to the bound event handler.� 779 var old_handler = handleObj.handler;� 780� 781 handleObj.handler = function (event) {� 782 event.orientation = get_orientation();� 783 return old_handler.apply(this, arguments);� 784 };� 785 }� 786 };� 787� 788 // If the event is not supported natively, this handler will be bound to� 789 // the window resize event to simulate the orientationchange event.� 790� 791 function handler() {� 792 // Get the current orientation.� 793 var orientation = get_orientation();� 794� 795 if (orientation !== last_orientation) {� 796 // The orientation has changed, so trigger the orientationchange event.� 797 last_orientation = orientation;� 798 win.trigger("orientationchange");� 799 }� 800 }� 801� 802 $.event.special.orientationchange.orientation = get_orientation = function () {� 803 var isPortrait = true,� 804 elem = document.documentElement;� 805� 806 if (settings.orientation_support) {� 807 isPortrait = portrait_map[window.orientation];� 808 } else {� 809 isPortrait = elem && elem.clientWidth / elem.clientHeight < 1.1;� 810 }� 811� 812 return isPortrait ? 'portrait' : 'landscape';� 813 };� 814� 815 // throttle Handler:� 816 $.event.special.throttledresize = {� 817 setup: function () {� 818 $(this).on('resize', throttle_handler);� 819 },� 820 teardown: function () {� 821 $(this).off('resize', throttle_handler);� 822 }� 823 };� 824� 825 var throttle = 250,� 826 throttle_handler = function () {� 827 curr = Date.now();� 828 diff = curr - lastCall;� 829� 830 if (diff >= throttle) {� 831 lastCall = curr;� 832 $(this).trigger('throttledresize');� 833� 834 } else {� 835 if (heldCall) {� 836 window.clearTimeout(heldCall);� 837 }� 838� 839 // Promise a held call will still execute� 840 heldCall = window.setTimeout(handler, throttle - diff);� 841 }� 842 },� 843 lastCall = 0,� 844 heldCall,� 845 curr,� 846 diff;� 847� 848 // Trigger a custom event:� 849� 850 function triggerCustomEvent(obj, eventType, event, touchData) {� 851 var originalType = event.type;� 852 event.type = eventType;� 853� 854 $.event.dispatch.call(obj, event, touchData);� 855 event.type = originalType;� 856 }� 857� 858 // Correctly on anything we've overloaded:� 859 $.each({� 860 scrollend: 'scrollstart',� 861 swipeup: 'swipe',� 862 swiperight: 'swipe',� 863 swipedown: 'swipe',� 864 swipeleft: 'swipe',� 865 swipeend: 'swipe',� 866 tap2: 'tap'� 867 }, function (e, srcE, touchData) {� 868 $.event.special[e] = {� 869 setup: function () {� 870 $(this).on(srcE, $.noop);� 871 }� 872 };� 873 });� 874� 875})(jQuery);�
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.