vendor: 68,980 bytes, lines 1-2459
1/* 2* jQuery Mobile v1.5.0-alpha.1 3* http://jquerymobile.com 4* 5* Copyright jQuery Foundation, Inc. and other contributors 6* Released under the MIT license. 7* http://jquery.org/license 8* 9*/ 10 11(function ( root, doc, factory ) { 12 if ( typeof define === "function" && define.amd ) { 13 // AMD. Register as an anonymous module. 14 define( [ "jquery" ], function ( $ ) { 15 factory( $, root, doc ); 16 return $.mobile; 17 }); 18 } else { 19 // Browser globals 20 factory( root.jQuery, root, doc ); 21 } 22}( this, document, function ( jQuery, window, document, undefined ) {/*! 23 * jQuery Mobile Namespace @VERSION 24 * http://jquerymobile.com 25 * 26 * Copyright jQuery Foundation and other contributors 27 * Released under the MIT license. 28 * http://jquery.org/license 29 */ 30 31//>>label: Namespace 32//>>group: Core 33//>>description: The mobile namespace on the jQuery object 34 35( function( factory ) { 36 if ( typeof define === "function" && define.amd ) { 37 38 // AMD. Register as an anonymous module. 39 define( 'ns',[ "jquery" ], factory ); 40 } else { 41 42 // Browser globals 43 factory( jQuery ); 44 } 45} )( function( $ ) { 46 47$.mobile = { version: "@VERSION" }; 48 49return $.mobile; 50} ); 51 52/*! 53 * jQuery Mobile Defaults @VERSION 54 * http://jquerymobile.com 55 * 56 * Copyright jQuery Foundation and other contributors 57 * Released under the MIT license. 58 * http://jquery.org/license 59 */ 60 61//>>label: Defaults 62//>>group: Core 63//>>description: Default values for jQuery Mobile 64//>>css.structure: ../css/structure/jquery.mobile.core.css 65//>>css.theme: ../css/themes/default/jquery.mobile.theme.css 66 67( function( factory ) { 68 if ( typeof define === "function" && define.amd ) { 69 70 // AMD. Register as an anonymous module. 71 define( 'defaults',[ 72 "jquery", 73 "./ns" ], factory ); 74 } else { 75 76 // Browser globals 77 factory( jQuery ); 78 } 79} )( function( $ ) { 80 81return $.extend( $.mobile, { 82 83 hideUrlBar: true, 84 85 // Keepnative Selector 86 keepNative: ":jqmData(role='none'), :jqmData(role='nojs')", 87 88 // Automatically handle clicks and form submissions through Ajax, when same-domain 89 ajaxEnabled: true, 90 91 // Automatically load and show pages based on location.hash 92 hashListeningEnabled: true, 93 94 // disable to prevent jquery from bothering with links 95 linkBindingEnabled: true, 96 97 // Set default page transition - 'none' for no transitions 98 defaultPageTransition: "fade", 99 100 // Set maximum window width for transitions to apply - 'false' for no limit 101 maxTransitionWidth: false, 102 103 // Set default dialog transition - 'none' for no transitions 104 defaultDialogTransition: "pop", 105 106 // Error response message - appears when an Ajax page request fails 107 pageLoadErrorMessage: "Error Loading Page", 108 109 // For error messages, which theme does the box use? 110 pageLoadErrorMessageTheme: "a", 111 112 // replace calls to window.history.back with phonegaps navigation helper 113 // where it is provided on the window object 114 phonegapNavigationEnabled: false, 115 116 //automatically initialize the DOM when it's ready 117 autoInitializePage: true, 118 119 pushStateEnabled: true, 120 121 // allows users to opt in to ignoring content by marking a parent element as 122 // data-ignored 123 ignoreContentEnabled: false, 124 125 // default the property to remove dependency on assignment in init module 126 pageContainer: $(), 127 128 //enable cross-domain page support 129 allowCrossDomainPages: false, 130 131 dialogHashKey: "&ui-state=dialog" 132} ); 133} ); 134 135/*! 136 * jQuery Mobile Data @VERSION 137 * http://jquerymobile.com 138 * 139 * Copyright jQuery Foundation and other contributors 140 * Released under the MIT license. 141 * http://jquery.org/license 142 */ 143 144//>>label: jqmData 145//>>group: Core 146//>>description: Mobile versions of Data functions to allow for namespaceing 147//>>css.structure: ../css/structure/jquery.mobile.core.css 148//>>css.theme: ../css/themes/default/jquery.mobile.theme.css 149 150( function( factory ) { 151 if ( typeof define === "function" && define.amd ) { 152 153 // AMD. Register as an anonymous module. 154 define( 'data',[ 155 "jquery", 156 "./ns" ], factory ); 157 } else { 158 159 // Browser globals 160 factory( jQuery ); 161 } 162} )( function( $ ) { 163 164var nsNormalizeDict = {}, 165 oldFind = $.find, 166 rbrace = /(?:\{[\s\S]*\}|\[[\s\S]*\])$/, 167 jqmDataRE = /:jqmData\(([^)]*)\)/g; 168 169$.extend( $.mobile, { 170 171 // Namespace used framework-wide for data-attrs. Default is no namespace 172 173 ns: $.mobileBackcompat === false ? "ui-" : "", 174 175 // Retrieve an attribute from an element and perform some massaging of the value 176 177 getAttribute: function( element, key ) { 178 var data; 179 180 element = element.jquery ? element[ 0 ] : element; 181 182 if ( element && element.getAttribute ) { 183 data = element.getAttribute( "data-" + $.mobile.ns + key ); 184 } 185 186 // Copied from core's src/data.js:dataAttr() 187 // Convert from a string to a proper data type 188 try { 189 data = data === "true" ? true : 190 data === "false" ? false : 191 data === "null" ? null : 192 // Only convert to a number if it doesn't change the string 193 +data + "" === data ? +data : 194 rbrace.test( data ) ? window.JSON.parse( data ) : 195 data; 196 } catch ( err ) {} 197 198 return data; 199 }, 200 201 // Expose our cache for testing purposes. 202 nsNormalizeDict: nsNormalizeDict, 203 204 // Take a data attribute property, prepend the namespace 205 // and then camel case the attribute string. Add the result 206 // to our nsNormalizeDict so we don't have to do this again. 207 nsNormalize: function( prop ) { 208 return nsNormalizeDict[ prop ] || 209 ( nsNormalizeDict[ prop ] = $.camelCase( $.mobile.ns + prop ) ); 210 }, 211 212 // Find the closest javascript page element to gather settings data jsperf test 213 // http://jsperf.com/single-complex-selector-vs-many-complex-selectors/edit 214 // possibly naive, but it shows that the parsing overhead for *just* the page selector vs 215 // the page and dialog selector is negligable. This could probably be speed up by 216 // doing a similar parent node traversal to the one found in the inherited theme code above 217 closestPageData: function( $target ) { 218 return $target 219 .closest( ":jqmData(role='page'), :jqmData(role='dialog')" ) 220 .data( "mobile-page" ); 221 } 222 223} ); 224 225// Mobile version of data and removeData and hasData methods 226// ensures all data is set and retrieved using jQuery Mobile's data namespace 227$.fn.jqmData = function( prop, value ) { 228 var result; 229 if ( typeof prop !== "undefined" ) { 230 if ( prop ) { 231 prop = $.mobile.nsNormalize( prop ); 232 } 233 234 // undefined is permitted as an explicit input for the second param 235 // in this case it returns the value and does not set it to undefined 236 if ( arguments.length < 2 || value === undefined ) { 237 result = this.data( prop ); 238 } else { 239 result = this.data( prop, value ); 240 } 241 } 242 return result; 243}; 244 245$.jqmData = function( elem, prop, value ) { 246 var result; 247 if ( typeof prop !== "undefined" ) { 248 result = $.data( elem, prop ? $.mobile.nsNormalize( prop ) : prop, value ); 249 } 250 return result; 251}; 252 253$.fn.jqmRemoveData = function( prop ) { 254 return this.removeData( $.mobile.nsNormalize( prop ) ); 255}; 256 257$.jqmRemoveData = function( elem, prop ) { 258 return $.removeData( elem, $.mobile.nsNormalize( prop ) ); 259}; 260 261$.find = function( selector, context, ret, extra ) { 262 if ( selector.indexOf( ":jqmData" ) > -1 ) { 263 selector = selector.replace( jqmDataRE, "[data-" + ( $.mobile.ns || "" ) + "$1]" ); 264 } 265 266 return oldFind.call( this, selector, context, ret, extra ); 267}; 268 269$.extend( $.find, oldFind ); 270 271return $.mobile; 272} ); 273 274( function( factory ) { 275 if ( typeof define === "function" && define.amd ) { 276 277 // AMD. Register as an anonymous module. 278 define( 'jquery-ui/version',[ "jquery" ], factory ); 279 } else { 280 281 // Browser globals 282 factory( jQuery ); 283 } 284} ( function( $ ) { 285 286$.ui = $.ui || {}; 287 288return $.ui.version = "1.12.1"; 289 290} ) ); 291 292/*! 293 * jQuery UI Keycode 1.12.1 294 * http://jqueryui.com 295 * 296 * Copyright jQuery Foundation and other contributors 297 * Released under the MIT license. 298 * http://jquery.org/license 299 */ 300 301//>>label: Keycode 302//>>group: Core 303//>>description: Provide keycodes as keynames 304//>>docs: http://api.jqueryui.com/jQuery.ui.keyCode/ 305 306( function( factory ) { 307 if ( typeof define === "function" && define.amd ) { 308 309 // AMD. Register as an anonymous module. 310 define( 'jquery-ui/keycode',[ "jquery", "./version" ], factory ); 311 } else { 312 313 // Browser globals 314 factory( jQuery ); 315 } 316} ( function( $ ) { 317return $.ui.keyCode = { 318 BACKSPACE: 8, 319 COMMA: 188, 320 DELETE: 46, 321 DOWN: 40, 322 END: 35, 323 ENTER: 13, 324 ESCAPE: 27, 325 HOME: 36, 326 LEFT: 37, 327 PAGE_DOWN: 34, 328 PAGE_UP: 33, 329 PERIOD: 190, 330 RIGHT: 39, 331 SPACE: 32, 332 TAB: 9, 333 UP: 38 334}; 335 336} ) ); 337 338/*! 339 * jQuery Mobile Helpers @VERSION 340 * http://jquerymobile.com 341 * 342 * Copyright jQuery Foundation and other contributors 343 * Released under the MIT license. 344 * http://jquery.org/license 345 */ 346 347//>>label: Helpers 348//>>group: Core 349//>>description: Helper functions and references 350//>>css.structure: ../css/structure/jquery.mobile.core.css 351//>>css.theme: ../css/themes/default/jquery.mobile.theme.css 352 353( function( factory ) { 354 if ( typeof define === "function" && define.amd ) { 355 356 // AMD. Register as an anonymous module. 357 define( 'helpers',[ 358 "jquery", 359 "./ns", 360 "jquery-ui/keycode" ], factory ); 361 } else { 362 363 // Browser globals 364 factory( jQuery ); 365 } 366} )( function( $ ) { 367 368// Subtract the height of external toolbars from the page height, if the page does not have 369// internal toolbars of the same type. We take care to use the widget options if we find a 370// widget instance and the element's data-attributes otherwise. 371var compensateToolbars = function( page, desiredHeight ) { 372 var pageParent = page.parent(), 373 toolbarsAffectingHeight = [], 374 375 // We use this function to filter fixed toolbars with option updatePagePadding set to 376 // true (which is the default) from our height subtraction, because fixed toolbars with 377 // option updatePagePadding set to true compensate for their presence by adding padding 378 // to the active page. We want to avoid double-counting by also subtracting their 379 // height from the desired page height. 380 noPadders = function() { 381 var theElement = $( this ), 382 widgetOptions = $.mobile.toolbar && theElement.data( "mobile-toolbar" ) ? 383 theElement.toolbar( "option" ) : { 384 position: theElement.attr( "data-" + $.mobile.ns + "position" ), 385 updatePagePadding: ( theElement.attr( "data-" + $.mobile.ns + 386 "update-page-padding" ) !== false ) 387 }; 388 389 return !( widgetOptions.position === "fixed" && 390 widgetOptions.updatePagePadding === true ); 391 }, 392 externalHeaders = pageParent.children( ":jqmData(type='header')" ).filter( noPadders ), 393 internalHeaders = page.children( ":jqmData(type='header')" ), 394 externalFooters = pageParent.children( ":jqmData(type='footer')" ).filter( noPadders ), 395 internalFooters = page.children( ":jqmData(type='footer')" ); 396 397 // If we have no internal headers, but we do have external headers, then their height 398 // reduces the page height 399 if ( internalHeaders.length === 0 && externalHeaders.length > 0 ) { 400 toolbarsAffectingHeight = toolbarsAffectingHeight.concat( externalHeaders.toArray() ); 401 } 402 403 // If we have no internal footers, but we do have external footers, then their height 404 // reduces the page height 405 if ( internalFooters.length === 0 && externalFooters.length > 0 ) { 406 toolbarsAffectingHeight = toolbarsAffectingHeight.concat( externalFooters.toArray() ); 407 } 408 409 $.each( toolbarsAffectingHeight, function( index, value ) { 410 desiredHeight -= $( value ).outerHeight(); 411 } ); 412 413 // Height must be at least zero 414 return Math.max( 0, desiredHeight ); 415}; 416 417$.extend( $.mobile, { 418 // define the window and the document objects 419 window: $( window ), 420 document: $( document ), 421 422 // TODO: Remove and use $.ui.keyCode directly 423 keyCode: $.ui.keyCode, 424 425 // Place to store various widget extensions 426 behaviors: {}, 427 428 // Custom logic for giving focus to a page 429 focusPage: function( page ) { 430 431 // First, look for an element explicitly marked for page focus 432 var focusElement = page.find( "[autofocus]" ); 433 434 // If we do not find an element with the "autofocus" attribute, look for the page title 435 if ( !focusElement.length ) { 436 focusElement = page.find( ".ui-title" ).eq( 0 ); 437 } 438 439 // Finally, fall back to focusing the page itself 440 if ( !focusElement.length ) { 441 focusElement = page; 442 } 443 444 focusElement.focus(); 445 }, 446 447 // Scroll page vertically: scroll to 0 to hide iOS address bar, or pass a Y value 448 silentScroll: function( ypos ) { 449 450 // If user has already scrolled then do nothing 451 if ( $.mobile.window.scrollTop() > 0 ) { 452 return; 453 } 454 455 if ( $.type( ypos ) !== "number" ) { 456 ypos = $.mobile.defaultHomeScroll; 457 } 458 459 // prevent scrollstart and scrollstop events 460 $.event.special.scrollstart.enabled = false; 461 462 setTimeout( function() { 463 window.scrollTo( 0, ypos ); 464 $.mobile.document.trigger( "silentscroll", { x: 0, y: ypos } ); 465 }, 20 ); 466 467 setTimeout( function() { 468 $.event.special.scrollstart.enabled = true; 469 }, 150 ); 470 }, 471 472 getClosestBaseUrl: function( ele ) { 473 // Find the closest page and extract out its url. 474 var url = $( ele ).closest( ".ui-page" ).jqmData( "url" ), 475 base = $.mobile.path.documentBase.hrefNoHash; 476 477 if ( !$.mobile.base.dynamicBaseEnabled || !url || !$.mobile.path.isPath( url ) ) { 478 url = base; 479 } 480 481 return $.mobile.path.makeUrlAbsolute( url, base ); 482 }, 483 removeActiveLinkClass: function( forceRemoval ) { 484 if ( !!$.mobile.activeClickedLink && 485 ( !$.mobile.activeClickedLink.closest( ".ui-page-active" ).length || 486 forceRemoval ) ) { 487 488 $.mobile.activeClickedLink.removeClass( "ui-button-active" ); 489 } 490 $.mobile.activeClickedLink = null; 491 }, 492 493 enhanceable: function( elements ) { 494 return this.haveParents( elements, "enhance" ); 495 }, 496 497 hijackable: function( elements ) { 498 return this.haveParents( elements, "ajax" ); 499 }, 500 501 haveParents: function( elements, attr ) { 502 if ( !$.mobile.ignoreContentEnabled ) { 503 return elements; 504 } 505 506 var count = elements.length, 507 $newSet = $(), 508 e, $element, excluded, 509 i, c; 510 511 for ( i = 0; i < count; i++ ) { 512 $element = elements.eq( i ); 513 excluded = false; 514 e = elements[ i ]; 515 516 while ( e ) { 517 c = e.getAttribute ? e.getAttribute( "data-" + $.mobile.ns + attr ) : ""; 518 519 if ( c === "false" ) { 520 excluded = true; 521 break; 522 } 523 524 e = e.parentNode; 525 } 526 527 if ( !excluded ) { 528 $newSet = $newSet.add( $element ); 529 } 530 } 531 532 return $newSet; 533 }, 534 535 getScreenHeight: function() { 536 // Native innerHeight returns more accurate value for this across platforms, 537 // jQuery version is here as a normalized fallback for platforms like Symbian 538 return window.innerHeight || $.mobile.window.height(); 539 }, 540 541 //simply set the active page's minimum height to screen height, depending on orientation 542 resetActivePageHeight: function( height ) { 543 var page = $( ".ui-page-active" ), 544 pageHeight = page.height(), 545 pageOuterHeight = page.outerHeight( true ); 546 547 height = compensateToolbars( page, 548 ( typeof height === "number" ) ? height : $( window ).height() ); 549 550 // Remove any previous min-height setting 551 page.css( "min-height", "" ); 552 553 // Set the minimum height only if the height as determined by CSS is insufficient 554 if ( page.height() < height ) { 555 page.css( "min-height", height - ( pageOuterHeight - pageHeight ) ); 556 } 557 }, 558 559 loading: function() { 560 // If this is the first call to this function, instantiate a loader widget 561 var loader = this.loading._widget || $.mobile.loader().element, 562 563 // Call the appropriate method on the loader 564 returnValue = loader.loader.apply( loader, arguments ); 565 566 // Make sure the loader is retained for future calls to this function. 567 this.loading._widget = loader; 568 569 return returnValue; 570 }, 571 572 isElementCurrentlyVisible: function( el ) { 573 el = typeof el === "string" ? $( el )[ 0 ] : el[ 0 ]; 574 575 if( !el ) { 576 return true; 577 } 578 579 var rect = el.getBoundingClientRect(); 580 581 return ( 582 rect.bottom > 0 && 583 rect.right > 0 && 584 rect.top < 585 ( window.innerHeight || document.documentElement.clientHeight ) && 586 rect.left < 587 ( window.innerWidth || document.documentElement.clientWidth ) ); 588 } 589} ); 590 591$.addDependents = function( elem, newDependents ) { 592 var $elem = $( elem ), 593 dependents = $elem.jqmData( "dependents" ) || $(); 594 595 $elem.jqmData( "dependents", $( dependents ).add( newDependents ) ); 596}; 597 598// plugins 599$.fn.extend( { 600 removeWithDependents: function() { 601 $.removeWithDependents( this ); 602 }, 603 604 addDependents: function( newDependents ) { 605 $.addDependents( this, newDependents ); 606 }, 607 608 // note that this helper doesn't attempt to handle the callback 609 // or setting of an html element's text, its only purpose is 610 // to return the html encoded version of the text in all cases. (thus the name) 611 getEncodedText: function() { 612 return $( "<a>" ).text( this.text() ).html(); 613 }, 614 615 // fluent helper function for the mobile namespaced equivalent 616 jqmEnhanceable: function() { 617 return $.mobile.enhanceable( this ); 618 }, 619 620 jqmHijackable: function() { 621 return $.mobile.hijackable( this ); 622 } 623} ); 624 625$.removeWithDependents = function( nativeElement ) { 626 var element = $( nativeElement ); 627 628 ( element.jqmData( "dependents" ) || $() ).remove(); 629 element.remove(); 630}; 631$.addDependents = function( nativeElement, newDependents ) { 632 var element = $( nativeElement ), 633 dependents = element.jqmData( "dependents" ) || $(); 634 635 element.jqmData( "dependents", $( dependents ).add( newDependents ) ); 636}; 637 638$.find.matches = function( expr, set ) { 639 return $.find( expr, null, null, set ); 640}; 641 642$.find.matchesSelector = function( node, expr ) { 643 return $.find( expr, null, null, [ node ] ).length > 0; 644}; 645 646return $.mobile; 647} ); 648 649/*! 650 * jQuery Mobile Core @VERSION 651 * http://jquerymobile.com 652 * 653 * Copyright jQuery Foundation and other contributors 654 * Released under the MIT license. 655 * http://jquery.org/license 656 */ 657 658//>>group: exclude 659 660( function( factory ) { 661 if ( typeof define === "function" && define.amd ) { 662 663 // AMD. Register as an anonymous module. 664 define( 'core',[ 665 "./defaults", 666 "./data", 667 "./helpers" ], factory ); 668 } else { 669 670 // Browser globals 671 factory( jQuery ); 672 } 673} )( function() {} ); 674 675/*! 676 * jQuery Mobile Match Media Polyfill @VERSION 677 * http://jquerymobile.com 678 * 679 * Copyright jQuery Foundation and other contributors 680 * Released under the MIT license. 681 * http://jquery.org/license 682 */ 683 684//>>label: Match Media Polyfill 685//>>group: Utilities 686//>>description: A workaround for browsers without window.matchMedia 687 688( function( factory ) { 689 if ( typeof define === "function" && define.amd ) { 690 691 // AMD. Register as an anonymous module. 692 define( 'media',[ 693 "jquery", 694 "./core" ], factory ); 695 } else { 696 697 // Browser globals 698 factory( jQuery ); 699 } 700} )( function( $ ) { 701 702/*! matchMedia() polyfill - Test a CSS media type/query in JS. Authors & copyright (c) 2012: Scott Jehl, Paul Irish, Nicholas Zakas. Dual MIT/BSD license */ 703window.matchMedia = window.matchMedia || ( function( doc, undefined ) { 704 705 var bool, 706 docElem = doc.documentElement, 707 refNode = docElem.firstElementChild || docElem.firstChild, 708 // fakeBody required for <FF4 when executed in <head> 709 fakeBody = doc.createElement( "body" ), 710 div = doc.createElement( "div" ); 711 712 div.id = "mq-test-1"; 713 div.style.cssText = "position:absolute;top:-100em"; 714 fakeBody.style.background = "none"; 715 fakeBody.appendChild( div ); 716 717 return function( q ) { 718 719 div.innerHTML = "­<style media=\"" + q + "\"> #mq-test-1 { width: 42px; }</style>"; 720 721 docElem.insertBefore( fakeBody, refNode ); 722 bool = div.offsetWidth === 42; 723 docElem.removeChild( fakeBody ); 724 725 return { 726 matches: bool, 727 media: q 728 }; 729 730 }; 731 732}( document ) ); 733 734// $.mobile.media uses matchMedia to return a boolean. 735$.mobile.media = function( q ) { 736 var mediaQueryList = window.matchMedia( q ); 737 // Firefox returns null in a hidden iframe 738 return mediaQueryList && mediaQueryList.matches; 739}; 740 741return $.mobile.media; 742 743} ); 744 745/*! 746 * jQuery Mobile Touch Support Test @VERSION 747 * http://jquerymobile.com 748 * 749 * Copyright jQuery Foundation and other contributors 750 * Released under the MIT license. 751 * http://jquery.org/license 752 */ 753 754//>>label: Touch support test 755//>>group: Core 756//>>description: Touch feature test 757 758( function( factory ) { 759 if ( typeof define === "function" && define.amd ) { 760 761 // AMD. Register as an anonymous module. 762 define( 'support/touch',[ 763 "jquery", 764 "../ns" ], factory ); 765 } else { 766 767 // Browser globals 768 factory( jQuery ); 769 } 770} )( function( $ ) { 771 772var support = { 773 touch: "ontouchend" in document 774}; 775 776$.mobile.support = $.mobile.support || {}; 777$.extend( $.support, support ); 778$.extend( $.mobile.support, support ); 779 780return $.support; 781} ); 782 783/*! 784 * jQuery Mobile Orientation @VERSION 785 * http://jquerymobile.com 786 * 787 * Copyright jQuery Foundation and other contributors 788 * Released under the MIT license. 789 * http://jquery.org/license 790 */ 791 792//>>label: Orientation support test 793//>>group: Core 794//>>description: Feature test for orientation 795 796( function( factory ) { 797 if ( typeof define === "function" && define.amd ) { 798 799 // AMD. Register as an anonymous module. 800 define( 'support/orientation',[ "jquery" ], factory ); 801 } else { 802 803 // Browser globals 804 factory( jQuery ); 805 } 806} )( function( $ ) { 807 808$.extend( $.support, { 809 orientation: "orientation" in window && "onorientationchange" in window 810} ); 811 812return $.support; 813} ); 814 815 816/*! 817 * jQuery Mobile Support Tests @VERSION 818 * http://jquerymobile.com 819 * 820 * Copyright jQuery Foundation and other contributors 821 * Released under the MIT license. 822 * http://jquery.org/license 823 */ 824 825//>>description: Assorted tests to qualify browsers by detecting features 826//>>label: Support Tests 827//>>group: Core 828 829( function( factory ) { 830 if ( typeof define === "function" && define.amd ) { 831 832 // AMD. Register as an anonymous module. 833 define( 'support',[ 834 "jquery", 835 "./core", 836 "./media", 837 "./support/touch", 838 "./support/orientation" ], factory ); 839 } else { 840 841 // Browser globals 842 factory( jQuery ); 843 } 844} )( function( $ ) { 845 846var fakeBody = $( "<body>" ).prependTo( "html" ), 847 fbCSS = fakeBody[ 0 ].style, 848 vendors = [ "Webkit", "Moz", "O" ], 849 webos = "palmGetResource" in window, //only used to rule out scrollTop 850 operamini = window.operamini && ( {} ).toString.call( window.operamini ) === "[object OperaMini]", 851 nokiaLTE7_3; 852 853// thx Modernizr 854function propExists( prop ) { 855 var uc_prop = prop.charAt( 0 ).toUpperCase() + prop.substr( 1 ), 856 props = ( prop + " " + vendors.join( uc_prop + " " ) + uc_prop ).split( " " ), 857 v; 858 859 for ( v in props ) { 860 if ( fbCSS[ props[ v ] ] !== undefined ) { 861 return true; 862 } 863 } 864} 865var bb = window.blackberry && !propExists( "-webkit-transform" ); //only used to rule out box shadow, as it's filled opaque on BB 5 and lower 866 867// inline SVG support test 868function inlineSVG() { 869 // Thanks Modernizr & Erik Dahlstrom 870 var w = window, 871 svg = !!w.document.createElementNS && !!w.document.createElementNS( "http://www.w3.org/2000/svg", "svg" ).createSVGRect && !( w.opera && navigator.userAgent.indexOf( "Chrome" ) === -1 ), 872 support = function( data ) { 873 if ( !( data && svg ) ) { 874 $( "html" ).addClass( "ui-nosvg" ); 875 } 876 }, 877 img = new w.Image(); 878 879 img.onerror = function() { 880 support( false ); 881 }; 882 img.onload = function() { 883 support( img.width === 1 && img.height === 1 ); 884 }; 885 img.src = "data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///ywAAAAAAQABAAACAUwAOw=="; 886} 887 888function transform3dTest() { 889 var mqProp = "transform-3d", 890 // Because the `translate3d` test below throws false positives in Android: 891 ret = $.mobile.media( "(-" + vendors.join( "-" + mqProp + "),(-" ) + "-" + mqProp + "),(" + mqProp + ")" ), 892 el, transforms, t; 893 894 if ( ret ) { 895 return !!ret; 896 } 897 898 el = document.createElement( "div" ); 899 transforms = { 900 // We’re omitting Opera for the time being; MS uses unprefixed. 901 "MozTransform": "-moz-transform", 902 "transform": "transform" 903 }; 904 905 fakeBody.append( el ); 906 907 for ( t in transforms ) { 908 if ( el.style[ t ] !== undefined ) { 909 el.style[ t ] = "translate3d( 100px, 1px, 1px )"; 910 ret = window.getComputedStyle( el ).getPropertyValue( transforms[ t ] ); 911 } 912 } 913 return ( !!ret && ret !== "none" ); 914} 915 916// Thanks Modernizr 917function cssPointerEventsTest() { 918 var element = document.createElement( "x" ), 919 documentElement = document.documentElement, 920 getComputedStyle = window.getComputedStyle, 921 supports; 922 923 if ( !( "pointerEvents" in element.style ) ) { 924 return false; 925 } 926 927 element.style.pointerEvents = "auto"; 928 element.style.pointerEvents = "x"; 929 documentElement.appendChild( element ); 930 supports = getComputedStyle && 931 getComputedStyle( element, "" ).pointerEvents === "auto"; 932 documentElement.removeChild( element ); 933 return !!supports; 934} 935 936function boundingRect() { 937 var div = document.createElement( "div" ); 938 return typeof div.getBoundingClientRect !== "undefined"; 939} 940 941// non-UA-based IE version check by James Padolsey, modified by jdalton - from http://gist.github.com/527683 942// allows for inclusion of IE 6+, including Windows Mobile 7 943$.extend( $.mobile, { browser: {} } ); 944$.mobile.browser.oldIE = ( function() { 945 var v = 3, 946 div = document.createElement( "div" ), 947 a = div.all || []; 948 949 do { 950 div.innerHTML = "<!--[if gt IE " + ( ++v ) + "]><br><![endif]-->"; 951 } while ( a[ 0 ] ); 952 953 return v > 4 ? v : !v; 954} )(); 955$.mobile.browser.newIEMobile = ( function() { 956 var div = document.createElement( "div" ); 957 return ( ( !$.mobile.browser.oldIE ) && 958 "onmsgesturehold" in div && 959 "ontouchstart" in div && 960 "onpointerdown" in div ); 961} )(); 962 963function fixedPosition() { 964 var w = window, 965 ua = navigator.userAgent, 966 platform = navigator.platform, 967 // Rendering engine is Webkit, and capture major version 968 wkmatch = ua.match( /AppleWebKit\/([0-9]+)/ ), 969 wkversion = !!wkmatch && wkmatch[ 1 ], 970 ffmatch = ua.match( /Fennec\/([0-9]+)/ ), 971 ffversion = !!ffmatch && ffmatch[ 1 ], 972 operammobilematch = ua.match( /Opera Mobi\/([0-9]+)/ ), 973 omversion = !!operammobilematch && operammobilematch[ 1 ]; 974 975 if ( 976 // iOS 4.3 and older : Platform is iPhone/Pad/Touch and Webkit version is less than 534 (ios5) 977 ( ( platform.indexOf( "iPhone" ) > -1 || platform.indexOf( "iPad" ) > -1 || platform.indexOf( "iPod" ) > -1 ) && wkversion && wkversion < 534 ) || 978 // Opera Mini 979 ( w.operamini && ( {} ).toString.call( w.operamini ) === "[object OperaMini]" ) || 980 ( operammobilematch && omversion < 7458 ) || 981 //Android lte 2.1: Platform is Android and Webkit version is less than 533 (Android 2.2) 982 ( ua.indexOf( "Android" ) > -1 && wkversion && wkversion < 533 ) || 983 // Firefox Mobile before 6.0 - 984 ( ffversion && ffversion < 6 ) || 985 // WebOS less than 3 986 ( "palmGetResource" in window && wkversion && wkversion < 534 ) || 987 // MeeGo 988 ( ua.indexOf( "MeeGo" ) > -1 && ua.indexOf( "NokiaBrowser/8.5.0" ) > -1 ) ) { 989 return false; 990 } 991 992 return true; 993} 994 995$.extend( $.support, { 996 // Note, Chrome for iOS has an extremely quirky implementation of popstate. 997 // We've chosen to take the shortest path to a bug fix here for issue #5426 998 // See the following link for information about the regex chosen 999 // https://developers.google.com/chrome/mobile/docs/user-agent#chrome_for_ios_user-agent 1000 pushState: "pushState" in history && 1001 "replaceState" in history && 1002 // When running inside a FF iframe, calling replaceState causes an error 1003 !( window.navigator.userAgent.indexOf( "Firefox" ) >= 0 && window.top !== window ) && 1004 ( window.navigator.userAgent.search( /CriOS/ ) === -1 ), 1005 1006 mediaquery: $.mobile.media( "only all" ), 1007 cssPseudoElement: !!propExists( "content" ), 1008 touchOverflow: !!propExists( "overflowScrolling" ), 1009 cssTransform3d: transform3dTest(), 1010 boxShadow: !!propExists( "boxShadow" ) && !bb, 1011 fixedPosition: fixedPosition(), 1012 scrollTop: ( "pageXOffset" in window || 1013 "scrollTop" in document.documentElement || 1014 "scrollTop" in fakeBody[ 0 ] ) && !webos && !operamini, 1015 1016 cssPointerEvents: cssPointerEventsTest(), 1017 boundingRect: boundingRect(), 1018 inlineSVG: inlineSVG 1019} ); 1020 1021fakeBody.remove(); 1022 1023// $.mobile.ajaxBlacklist is used to override ajaxEnabled on platforms that have known conflicts with hash history updates (BB5, Symbian) 1024// or that generally work better browsing in regular http for full page refreshes (Opera Mini) 1025// Note: This detection below is used as a last resort. 1026// We recommend only using these detection methods when all other more reliable/forward-looking approaches are not possible 1027nokiaLTE7_3 = ( function() { 1028 1029 var ua = window.navigator.userAgent; 1030 1031 //The following is an attempt to match Nokia browsers that are running Symbian/s60, with webkit, version 7.3 or older 1032 return ua.indexOf( "Nokia" ) > -1 && 1033 ( ua.indexOf( "Symbian/3" ) > -1 || ua.indexOf( "Series60/5" ) > -1 ) && 1034 ua.indexOf( "AppleWebKit" ) > -1 && 1035 ua.match( /(BrowserNG|NokiaBrowser)\/7\.[0-3]/ ); 1036} )(); 1037 1038// Support conditions that must be met in order to proceed 1039// default enhanced qualifications are media query support OR IE 7+ 1040 1041$.mobile.gradeA = function() { 1042 return ( ( $.support.mediaquery && $.support.cssPseudoElement ) || $.mobile.browser.oldIE && $.mobile.browser.oldIE >= 8 ) && ( $.support.boundingRect || $.fn.jquery.match( /1\.[0-7+]\.[0-9+]?/ ) !== null ); 1043}; 1044 1045$.mobile.ajaxBlacklist = 1046 // BlackBerry browsers, pre-webkit 1047 window.blackberry && !window.WebKitPoint || 1048 // Opera Mini 1049 operamini || 1050 // Symbian webkits pre 7.3 1051 nokiaLTE7_3; 1052 1053// Lastly, this workaround is the only way we've found so far to get pre 7.3 Symbian webkit devices 1054// to render the stylesheets when they're referenced before this script, as we'd recommend doing. 1055// This simply reappends the CSS in place, which for some reason makes it apply 1056if ( nokiaLTE7_3 ) { 1057 $( function() { 1058 $( "head link[rel='stylesheet']" ).attr( "rel", "alternate stylesheet" ).attr( "rel", "stylesheet" ); 1059 } ); 1060} 1061 1062// For ruling out shadows via css 1063if ( !$.support.boxShadow ) { 1064 $( "html" ).addClass( "ui-noboxshadow" ); 1065} 1066 1067return $.support; 1068 1069} ); 1070 1071/*! 1072 * jQuery Mobile Navigate Event @VERSION 1073 * http://jquerymobile.com 1074 * 1075 * Copyright jQuery Foundation and other contributors 1076 * Released under the MIT license. 1077 * http://jquery.org/license 1078 */ 1079 1080//>>label: Navigate 1081//>>group: Events 1082//>>description: Provides a wrapper around hashchange and popstate 1083//>>docs: http://api.jquerymobile.com/navigate/ 1084//>>demos: http://api.jquerymobile.com/@VERSION/navigation/ 1085 1086// TODO break out pushstate support test so we don't depend on the whole thing 1087( function( factory ) { 1088 if ( typeof define === "function" && define.amd ) { 1089 1090 // AMD. Register as an anonymous module. 1091 define( 'events/navigate',[ 1092 "jquery", 1093 "./../ns", 1094 "./../support" ], factory ); 1095 } else { 1096 1097 // Browser globals 1098 factory( jQuery ); 1099 } 1100} )( function( $ ) { 1101 1102var $win = $.mobile.window, self, 1103 dummyFnToInitNavigate = function() {}; 1104 1105$.event.special.beforenavigate = { 1106 setup: function() { 1107 $win.on( "navigate", dummyFnToInitNavigate ); 1108 }, 1109 1110 teardown: function() { 1111 $win.off( "navigate", dummyFnToInitNavigate ); 1112 } 1113}; 1114 1115$.event.special.navigate = self = { 1116 bound: false, 1117 1118 pushStateEnabled: true, 1119 1120 originalEventName: undefined, 1121 1122 // If pushstate support is present and push state support is defined to 1123 // be true on the mobile namespace. 1124 isPushStateEnabled: function() { 1125 return $.support.pushState && 1126 $.mobile.pushStateEnabled === true && 1127 this.isHashChangeEnabled(); 1128 }, 1129 1130 // !! assumes mobile namespace is present 1131 isHashChangeEnabled: function() { 1132 return $.mobile.hashListeningEnabled === true; 1133 }, 1134 1135 // TODO a lot of duplication between popstate and hashchange 1136 popstate: function( event ) { 1137 var newEvent, beforeNavigate, state; 1138 1139 if ( event.isDefaultPrevented() ) { 1140 return; 1141 } 1142 1143 newEvent = new $.Event( "navigate" ); 1144 beforeNavigate = new $.Event( "beforenavigate" ); 1145 state = event.originalEvent.state || {}; 1146 1147 beforeNavigate.originalEvent = event; 1148 $win.trigger( beforeNavigate ); 1149 1150 if ( beforeNavigate.isDefaultPrevented() ) { 1151 return; 1152 } 1153 1154 if ( event.historyState ) { 1155 $.extend( state, event.historyState ); 1156 } 1157 1158 // Make sure the original event is tracked for the end 1159 // user to inspect incase they want to do something special 1160 newEvent.originalEvent = event; 1161 1162 // NOTE we let the current stack unwind because any assignment to 1163 // location.hash will stop the world and run this event handler. By 1164 // doing this we create a similar behavior to hashchange on hash 1165 // assignment 1166 setTimeout( function() { 1167 $win.trigger( newEvent, { 1168 state: state 1169 } ); 1170 }, 0 ); 1171 }, 1172 1173 hashchange: function( event /*, data */ ) { 1174 var newEvent = new $.Event( "navigate" ), 1175 beforeNavigate = new $.Event( "beforenavigate" ); 1176 1177 beforeNavigate.originalEvent = event; 1178 $win.trigger( beforeNavigate ); 1179 1180 if ( beforeNavigate.isDefaultPrevented() ) { 1181 return; 1182 } 1183 1184 // Make sure the original event is tracked for the end 1185 // user to inspect incase they want to do something special 1186 newEvent.originalEvent = event; 1187 1188 // Trigger the hashchange with state provided by the user 1189 // that altered the hash 1190 $win.trigger( newEvent, { 1191 // Users that want to fully normalize the two events 1192 // will need to do history management down the stack and 1193 // add the state to the event before this binding is fired 1194 // TODO consider allowing for the explicit addition of callbacks 1195 // to be fired before this value is set to avoid event timing issues 1196 state: event.hashchangeState || {} 1197 } ); 1198 }, 1199 1200 // TODO We really only want to set this up once 1201 // but I'm not clear if there's a beter way to achieve 1202 // this with the jQuery special event structure 1203 setup: function( /* data, namespaces */ ) { 1204 if ( self.bound ) { 1205 return; 1206 } 1207 1208 self.bound = true; 1209 1210 if ( self.isPushStateEnabled() ) { 1211 self.originalEventName = "popstate"; 1212 $win.bind( "popstate.navigate", self.popstate ); 1213 } else if ( self.isHashChangeEnabled() ) { 1214 self.originalEventName = "hashchange"; 1215 $win.bind( "hashchange.navigate", self.hashchange ); 1216 } 1217 } 1218}; 1219 1220return $.event.special.navigate; 1221} ); 1222 1223/*! 1224 * jQuery Mobile Virtual Mouse @VERSION 1225 * http://jquerymobile.com 1226 * 1227 * Copyright jQuery Foundation and other contributors 1228 * Released under the MIT license. 1229 * http://jquery.org/license 1230 */ 1231 1232//>>label: Virtual Mouse (vmouse) Bindings 1233//>>group: Core 1234//>>description: Normalizes touch/mouse events. 1235//>>docs: http://api.jquerymobile.com/?s=vmouse 1236 1237// This plugin is an experiment for abstracting away the touch and mouse 1238// events so that developers don't have to worry about which method of input 1239// the device their document is loaded on supports. 1240// 1241// The idea here is to allow the developer to register listeners for the 1242// basic mouse events, such as mousedown, mousemove, mouseup, and click, 1243// and the plugin will take care of registering the correct listeners 1244// behind the scenes to invoke the listener at the fastest possible time 1245// for that device, while still retaining the order of event firing in 1246// the traditional mouse environment, should multiple handlers be registered 1247// on the same element for different events. 1248// 1249// The current version exposes the following virtual events to jQuery bind methods: 1250// "vmouseover vmousedown vmousemove vmouseup vclick vmouseout vmousecancel" 1251 1252( function( factory ) { 1253 if ( typeof define === "function" && define.amd ) { 1254 1255 // AMD. Register as an anonymous module. 1256 define( 'vmouse',[ "jquery" ], factory ); 1257 } else { 1258 1259 // Browser globals 1260 factory( jQuery ); 1261 } 1262} )( function( $ ) { 1263 1264var dataPropertyName = "virtualMouseBindings", 1265 touchTargetPropertyName = "virtualTouchID", 1266 touchEventProps = "clientX clientY pageX pageY screenX screenY".split( " " ), 1267 virtualEventNames = "vmouseover vmousedown vmousemove vmouseup vclick vmouseout vmousecancel".split( " " ), 1268 generalProps = ( "altKey bubbles cancelable ctrlKey currentTarget detail eventPhase " + 1269 "metaKey relatedTarget shiftKey target timeStamp view which" ).split( " " ), 1270 mouseHookProps = $.event.mouseHooks ? $.event.mouseHooks.props : [], 1271 mouseEventProps = generalProps.concat( mouseHookProps ), 1272 activeDocHandlers = {}, 1273 resetTimerID = 0, 1274 startX = 0, 1275 startY = 0, 1276 didScroll = false, 1277 clickBlockList = [], 1278 blockMouseTriggers = false, 1279 blockTouchTriggers = false, 1280 eventCaptureSupported = "addEventListener" in document, 1281 $document = $( document ), 1282 nextTouchID = 1, 1283 lastTouchID = 0, threshold, 1284 i; 1285 1286$.vmouse = { 1287 moveDistanceThreshold: 10, 1288 clickDistanceThreshold: 10, 1289 resetTimerDuration: 1500, 1290 maximumTimeBetweenTouches: 100 1291}; 1292 1293function getNativeEvent( event ) { 1294 1295 while ( event && typeof event.originalEvent !== "undefined" ) { 1296 event = event.originalEvent; 1297 } 1298 return event; 1299} 1300 1301function createVirtualEvent( event, eventType ) { 1302 1303 var t = event.type, 1304 oe, props, ne, prop, ct, touch, i, j, len; 1305 1306 event = $.Event( event ); 1307 event.type = eventType; 1308 1309 oe = event.originalEvent; 1310 props = generalProps; 1311 1312 // addresses separation of $.event.props in to $.event.mouseHook.props and Issue 3280 1313 // https://github.com/jquery/jquery-mobile/issues/3280 1314 if ( t.search( /^(mouse|click)/ ) > -1 ) { 1315 props = mouseEventProps; 1316 } 1317 1318 // copy original event properties over to the new event 1319 // this would happen if we could call $.event.fix instead of $.Event 1320 // but we don't have a way to force an event to be fixed multiple times 1321 if ( oe ) { 1322 for ( i = props.length; i; ) { 1323 prop = props[ --i ]; 1324 event[ prop ] = oe[ prop ]; 1325 } 1326 } 1327 1328 // make sure that if the mouse and click virtual events are generated 1329 // without a .which one is defined 1330 if ( t.search( /mouse(down|up)|click/ ) > -1 && !event.which ) { 1331 event.which = 1; 1332 } 1333 1334 if ( t.search( /^touch/ ) !== -1 ) { 1335 ne = getNativeEvent( oe ); 1336 t = ne.touches; 1337 ct = ne.changedTouches; 1338 touch = ( t && t.length ) ? t[ 0 ] : ( ( ct && ct.length ) ? ct[ 0 ] : undefined ); 1339 1340 if ( touch ) { 1341 for ( j = 0, len = touchEventProps.length; j < len; j++ ) { 1342 prop = touchEventProps[ j ]; 1343 event[ prop ] = touch[ prop ]; 1344 } 1345 } 1346 } 1347 1348 return event; 1349} 1350 1351function getVirtualBindingFlags( element ) { 1352 1353 var flags = {}, 1354 b, k; 1355 1356 while ( element ) { 1357 1358 b = $.data( element, dataPropertyName ); 1359 1360 for ( k in b ) { 1361 if ( b[ k ] ) { 1362 flags[ k ] = flags.hasVirtualBinding = true; 1363 } 1364 } 1365 element = element.parentNode; 1366 } 1367 return flags; 1368} 1369 1370function getClosestElementWithVirtualBinding( element, eventType ) { 1371 var b; 1372 while ( element ) { 1373 1374 b = $.data( element, dataPropertyName ); 1375 1376 if ( b && ( !eventType || b[ eventType ] ) ) { 1377 return element; 1378 } 1379 element = element.parentNode; 1380 } 1381 return null; 1382} 1383 1384function enableTouchBindings() { 1385 blockTouchTriggers = false; 1386} 1387 1388function disableTouchBindings() { 1389 blockTouchTriggers = true; 1390} 1391 1392function enableMouseBindings() { 1393 lastTouchID = 0; 1394 clickBlockList.length = 0; 1395 blockMouseTriggers = false; 1396 1397 // When mouse bindings are enabled, our 1398 // touch bindings are disabled. 1399 disableTouchBindings(); 1400} 1401 1402function disableMouseBindings() { 1403 // When mouse bindings are disabled, our 1404 // touch bindings are enabled. 1405 enableTouchBindings(); 1406} 1407 1408function clearResetTimer() { 1409 if ( resetTimerID ) { 1410 clearTimeout( resetTimerID ); 1411 resetTimerID = 0; 1412 } 1413} 1414 1415function startResetTimer() { 1416 clearResetTimer(); 1417 resetTimerID = setTimeout( function() { 1418 resetTimerID = 0; 1419 enableMouseBindings(); 1420 }, $.vmouse.resetTimerDuration ); 1421} 1422 1423function triggerVirtualEvent( eventType, event, flags ) { 1424 var ve; 1425 1426 if ( ( flags && flags[ eventType ] ) || 1427 ( !flags && getClosestElementWithVirtualBinding( event.target, eventType ) ) ) { 1428 1429 ve = createVirtualEvent( event, eventType ); 1430 1431 $( event.target ).trigger( ve ); 1432 } 1433 1434 return ve; 1435} 1436 1437function mouseEventCallback( event ) { 1438 var touchID = $.data( event.target, touchTargetPropertyName ), 1439 ve; 1440 1441 // It is unexpected if a click event is received before a touchend 1442 // or touchmove event, however this is a known behavior in Mobile 1443 // Safari when Mobile VoiceOver (as of iOS 8) is enabled and the user 1444 // double taps to activate a link element. In these cases if a touch 1445 // event is not received within the maximum time between touches, 1446 // re-enable mouse bindings and call the mouse event handler again. 1447 if ( event.type === "click" && $.data( event.target, "lastTouchType" ) === "touchstart" ) { 1448 setTimeout( function() { 1449 if ( $.data( event.target, "lastTouchType" ) === "touchstart" ) { 1450 enableMouseBindings(); 1451 delete $.data( event.target ).lastTouchType; 1452 mouseEventCallback( event ); 1453 } 1454 }, $.vmouse.maximumTimeBetweenTouches ); 1455 } 1456 1457 if ( !blockMouseTriggers && ( !lastTouchID || lastTouchID !== touchID ) ) { 1458 ve = triggerVirtualEvent( "v" + event.type, event ); 1459 if ( ve ) { 1460 if ( ve.isDefaultPrevented() ) { 1461 event.preventDefault(); 1462 } 1463 if ( ve.isPropagationStopped() ) { 1464 event.stopPropagation(); 1465 } 1466 if ( ve.isImmediatePropagationStopped() ) { 1467 event.stopImmediatePropagation(); 1468 } 1469 } 1470 } 1471} 1472 1473function handleTouchStart( event ) { 1474 1475 var touches = getNativeEvent( event ).touches, 1476 target, flags, t; 1477 1478 if ( touches && touches.length === 1 ) { 1479 1480 target = event.target; 1481 flags = getVirtualBindingFlags( target ); 1482 1483 $.data( event.target, "lastTouchType", event.type ); 1484 1485 if ( flags.hasVirtualBinding ) { 1486 1487 lastTouchID = nextTouchID++; 1488 $.data( target, touchTargetPropertyName, lastTouchID ); 1489 1490 clearResetTimer(); 1491 1492 disableMouseBindings(); 1493 didScroll = false; 1494 1495 t = getNativeEvent( event ).touches[ 0 ]; 1496 startX = t.pageX; 1497 startY = t.pageY; 1498 1499 triggerVirtualEvent( "vmouseover", event, flags ); 1500 triggerVirtualEvent( "vmousedown", event, flags ); 1501 } 1502 } 1503} 1504 1505function handleScroll( event ) { 1506 if ( blockTouchTriggers ) { 1507 return; 1508 } 1509 1510 if ( !didScroll ) { 1511 triggerVirtualEvent( "vmousecancel", event, getVirtualBindingFlags( event.target ) ); 1512 } 1513 1514 $.data( event.target, "lastTouchType", event.type ); 1515 1516 didScroll = true; 1517 startResetTimer(); 1518} 1519 1520function handleTouchMove( event ) { 1521 if ( blockTouchTriggers ) { 1522 return; 1523 } 1524 1525 var t = getNativeEvent( event ).touches[ 0 ], 1526 didCancel = didScroll, 1527 moveThreshold = $.vmouse.moveDistanceThreshold, 1528 flags = getVirtualBindingFlags( event.target ); 1529 1530 $.data( event.target, "lastTouchType", event.type ); 1531 1532 didScroll = didScroll || 1533 ( Math.abs( t.pageX - startX ) > moveThreshold || 1534 Math.abs( t.pageY - startY ) > moveThreshold ); 1535 1536 if ( didScroll && !didCancel ) { 1537 triggerVirtualEvent( "vmousecancel", event, flags ); 1538 } 1539 1540 triggerVirtualEvent( "vmousemove", event, flags ); 1541 startResetTimer(); 1542} 1543 1544function handleTouchEnd( event ) { 1545 if ( blockTouchTriggers || $.data( event.target, "lastTouchType" ) === undefined ) { 1546 return; 1547 } 1548 1549 disableTouchBindings(); 1550 delete $.data( event.target ).lastTouchType; 1551 1552 var flags = getVirtualBindingFlags( event.target ), 1553 ve, t; 1554 triggerVirtualEvent( "vmouseup", event, flags ); 1555 1556 if ( !didScroll ) { 1557 ve = triggerVirtualEvent( "vclick", event, flags ); 1558 if ( ve && ve.isDefaultPrevented() ) { 1559 // The target of the mouse events that follow the touchend 1560 // event don't necessarily match the target used during the 1561 // touch. This means we need to rely on coordinates for blocking 1562 // any click that is generated. 1563 t = getNativeEvent( event ).changedTouches[ 0 ]; 1564 clickBlockList.push( { 1565 touchID: lastTouchID, 1566 x: t.clientX, 1567 y: t.clientY 1568 } ); 1569 1570 // Prevent any mouse events that follow from triggering 1571 // virtual event notifications. 1572 blockMouseTriggers = true; 1573 } 1574 } 1575 triggerVirtualEvent( "vmouseout", event, flags ); 1576 didScroll = false; 1577 1578 startResetTimer(); 1579} 1580 1581function hasVirtualBindings( ele ) { 1582 var bindings = $.data( ele, dataPropertyName ), 1583 k; 1584 1585 if ( bindings ) { 1586 for ( k in bindings ) { 1587 if ( bindings[ k ] ) { 1588 return true; 1589 } 1590 } 1591 } 1592 return false; 1593} 1594 1595function dummyMouseHandler() { 1596} 1597 1598function getSpecialEventObject( eventType ) { 1599 var realType = eventType.substr( 1 ); 1600 1601 return { 1602 setup: function( /* data, namespace */ ) { 1603 // If this is the first virtual mouse binding for this element, 1604 // add a bindings object to its data. 1605 1606 if ( !hasVirtualBindings( this ) ) { 1607 $.data( this, dataPropertyName, {} ); 1608 } 1609 1610 // If setup is called, we know it is the first binding for this 1611 // eventType, so initialize the count for the eventType to zero. 1612 var bindings = $.data( this, dataPropertyName ); 1613 bindings[ eventType ] = true; 1614 1615 // If this is the first virtual mouse event for this type, 1616 // register a global handler on the document. 1617 1618 activeDocHandlers[ eventType ] = ( activeDocHandlers[ eventType ] || 0 ) + 1; 1619 1620 if ( activeDocHandlers[ eventType ] === 1 ) { 1621 $document.bind( realType, mouseEventCallback ); 1622 } 1623 1624 // Some browsers, like Opera Mini, won't dispatch mouse/click events 1625 // for elements unless they actually have handlers registered on them. 1626 // To get around this, we register dummy handlers on the elements. 1627 1628 $( this ).bind( realType, dummyMouseHandler ); 1629 1630 // For now, if event capture is not supported, we rely on mouse handlers. 1631 if ( eventCaptureSupported ) { 1632 // If this is the first virtual mouse binding for the document, 1633 // register our touchstart handler on the document. 1634 1635 activeDocHandlers[ "touchstart" ] = ( activeDocHandlers[ "touchstart" ] || 0 ) + 1; 1636 1637 if ( activeDocHandlers[ "touchstart" ] === 1 ) { 1638 $document.bind( "touchstart", handleTouchStart ) 1639 .bind( "touchend", handleTouchEnd ) 1640 1641 // On touch platforms, touching the screen and then dragging your finger 1642 // causes the window content to scroll after some distance threshold is 1643 // exceeded. On these platforms, a scroll prevents a click event from being 1644 // dispatched, and on some platforms, even the touchend is suppressed. To 1645 // mimic the suppression of the click event, we need to watch for a scroll 1646 // event. Unfortunately, some platforms like iOS don't dispatch scroll 1647 // events until *AFTER* the user lifts their finger (touchend). This means 1648 // we need to watch both scroll and touchmove events to figure out whether 1649 // or not a scroll happenens before the touchend event is fired. 1650 1651 .bind( "touchmove", handleTouchMove ) 1652 .bind( "scroll", handleScroll ); 1653 } 1654 } 1655 }, 1656 1657 teardown: function( /* data, namespace */ ) { 1658 // If this is the last virtual binding for this eventType, 1659 // remove its global handler from the document. 1660 1661 --activeDocHandlers[eventType]; 1662 1663 if ( !activeDocHandlers[ eventType ] ) { 1664 $document.unbind( realType, mouseEventCallback ); 1665 } 1666 1667 if ( eventCaptureSupported ) { 1668 // If this is the last virtual mouse binding in existence, 1669 // remove our document touchstart listener. 1670 1671 --activeDocHandlers["touchstart"]; 1672 1673 if ( !activeDocHandlers[ "touchstart" ] ) { 1674 $document.unbind( "touchstart", handleTouchStart ) 1675 .unbind( "touchmove", handleTouchMove ) 1676 .unbind( "touchend", handleTouchEnd ) 1677 .unbind( "scroll", handleScroll ); 1678 } 1679 } 1680 1681 var $this = $( this ), 1682 bindings = $.data( this, dataPropertyName ); 1683 1684 // teardown may be called when an element was 1685 // removed from the DOM. If this is the case, 1686 // jQuery core may have already stripped the element 1687 // of any data bindings so we need to check it before 1688 // using it. 1689 if ( bindings ) { 1690 bindings[ eventType ] = false; 1691 } 1692 1693 // Unregister the dummy event handler. 1694 1695 $this.unbind( realType, dummyMouseHandler ); 1696 1697 // If this is the last virtual mouse binding on the 1698 // element, remove the binding data from the element. 1699 1700 if ( !hasVirtualBindings( this ) ) { 1701 $this.removeData( dataPropertyName ); 1702 } 1703 } 1704 }; 1705} 1706 1707// Expose our custom events to the jQuery bind/unbind mechanism. 1708 1709for ( i = 0; i < virtualEventNames.length; i++ ) { 1710 $.event.special[ virtualEventNames[ i ] ] = getSpecialEventObject( virtualEventNames[ i ] ); 1711} 1712 1713// Add a capture click handler to block clicks. 1714// Note that we require event capture support for this so if the device 1715// doesn't support it, we punt for now and rely solely on mouse events. 1716if ( eventCaptureSupported ) { 1717 document.addEventListener( "click", function( e ) { 1718 var cnt = clickBlockList.length, 1719 target = e.target, 1720 x, y, ele, i, o, touchID; 1721 1722 if ( cnt ) { 1723 x = e.clientX; 1724 y = e.clientY; 1725 threshold = $.vmouse.clickDistanceThreshold; 1726 1727 // The idea here is to run through the clickBlockList to see if 1728 // the current click event is in the proximity of one of our 1729 // vclick events that had preventDefault() called on it. If we find 1730 // one, then we block the click. 1731 // 1732 // Why do we have to rely on proximity? 1733 // 1734 // Because the target of the touch event that triggered the vclick 1735 // can be different from the target of the click event synthesized 1736 // by the browser. The target of a mouse/click event that is synthesized 1737 // from a touch event seems to be implementation specific. For example, 1738 // some browsers will fire mouse/click events for a link that is near 1739 // a touch event, even though the target of the touchstart/touchend event 1740 // says the user touched outside the link. Also, it seems that with most 1741 // browsers, the target of the mouse/click event is not calculated until the 1742 // time it is dispatched, so if you replace an element that you touched 1743 // with another element, the target of the mouse/click will be the new 1744 // element underneath that point. 1745 // 1746 // Aside from proximity, we also check to see if the target and any 1747 // of its ancestors were the ones that blocked a click. This is necessary 1748 // because of the strange mouse/click target calculation done in the 1749 // Android 2.1 browser, where if you click on an element, and there is a 1750 // mouse/click handler on one of its ancestors, the target will be the 1751 // innermost child of the touched element, even if that child is no where 1752 // near the point of touch. 1753 1754 ele = target; 1755 1756 while ( ele ) { 1757 for ( i = 0; i < cnt; i++ ) { 1758 o = clickBlockList[ i ]; 1759 touchID = 0; 1760 1761 if ( ( ele === target && Math.abs( o.x - x ) < threshold && Math.abs( o.y - y ) < threshold ) || 1762 $.data( ele, touchTargetPropertyName ) === o.touchID ) { 1763 // XXX: We may want to consider removing matches from the block list 1764 // instead of waiting for the reset timer to fire. 1765 e.preventDefault(); 1766 e.stopPropagation(); 1767 return; 1768 } 1769 } 1770 ele = ele.parentNode; 1771 } 1772 } 1773 }, true ); 1774} 1775} ); 1776 1777/*! 1778 * jQuery Mobile Touch Events @VERSION 1779 * http://jquerymobile.com 1780 * 1781 * Copyright jQuery Foundation and other contributors 1782 * Released under the MIT license. 1783 * http://jquery.org/license 1784 */ 1785 1786//>>label: Touch 1787//>>group: Events 1788//>>description: Touch events including: touchstart, touchmove, touchend, tap, taphold, swipe, swipeleft, swiperight 1789 1790( function( factory ) { 1791 if ( typeof define === "function" && define.amd ) { 1792 1793 // AMD. Register as an anonymous module. 1794 define( 'events/touch',[ 1795 "jquery", 1796 "../vmouse", 1797 "../support/touch" ], factory ); 1798 } else { 1799 1800 // Browser globals 1801 factory( jQuery ); 1802 } 1803} )( function( $ ) { 1804var $document = $( document ), 1805 supportTouch = $.mobile.support.touch, 1806 touchStartEvent = supportTouch ? "touchstart" : "mousedown", 1807 touchStopEvent = supportTouch ? "touchend" : "mouseup", 1808 touchMoveEvent = supportTouch ? "touchmove" : "mousemove"; 1809 1810// setup new event shortcuts 1811$.each( ( "touchstart touchmove touchend " + 1812"tap taphold " + 1813"swipe swipeleft swiperight" ).split( " " ), function( i, name ) { 1814 1815 $.fn[ name ] = function( fn ) { 1816 return fn ? this.bind( name, fn ) : this.trigger( name ); 1817 }; 1818 1819 // jQuery < 1.8 1820 if ( $.attrFn ) { 1821 $.attrFn[ name ] = true; 1822 } 1823} ); 1824 1825function triggerCustomEvent( obj, eventType, event, bubble ) { 1826 var originalType = event.type; 1827 event.type = eventType; 1828 if ( bubble ) { 1829 $.event.trigger( event, undefined, obj ); 1830 } else { 1831 $.event.dispatch.call( obj, event ); 1832 } 1833 event.type = originalType; 1834} 1835 1836// also handles taphold 1837$.event.special.tap = { 1838 tapholdThreshold: 750, 1839 emitTapOnTaphold: true, 1840 setup: function() { 1841 var thisObject = this, 1842 $this = $( thisObject ), 1843 isTaphold = false; 1844 1845 $this.bind( "vmousedown", function( event ) { 1846 isTaphold = false; 1847 if ( event.which && event.which !== 1 ) { 1848 return true; 1849 } 1850 1851 var origTarget = event.target, 1852 timer, clickHandler; 1853 1854 function clearTapTimer() { 1855 if ( timer ) { 1856 $this.bind( "vclick", clickHandler ); 1857 clearTimeout( timer ); 1858 } 1859 } 1860 1861 function clearTapHandlers() { 1862 clearTapTimer(); 1863 1864 $this.unbind( "vclick", clickHandler ) 1865 .unbind( "vmouseup", clearTapTimer ); 1866 $document.unbind( "vmousecancel", clearTapHandlers ); 1867 } 1868 1869 clickHandler = function( event ) { 1870 clearTapHandlers(); 1871 1872 // ONLY trigger a 'tap' event if the start target is 1873 // the same as the stop target. 1874 if ( !isTaphold && origTarget === event.target ) { 1875 triggerCustomEvent( thisObject, "tap", event ); 1876 } else if ( isTaphold ) { 1877 event.preventDefault(); 1878 } 1879 }; 1880 1881 $this.bind( "vmouseup", clearTapTimer ); 1882 1883 $document.bind( "vmousecancel", clearTapHandlers ); 1884 1885 timer = setTimeout( function() { 1886 if ( !$.event.special.tap.emitTapOnTaphold ) { 1887 isTaphold = true; 1888 } 1889 timer = 0; 1890 triggerCustomEvent( thisObject, "taphold", $.Event( "taphold", { target: origTarget } ) ); 1891 }, $.event.special.tap.tapholdThreshold ); 1892 } ); 1893 }, 1894 teardown: function() { 1895 $( this ).unbind( "vmousedown" ).unbind( "vclick" ).unbind( "vmouseup" ); 1896 $document.unbind( "vmousecancel" ); 1897 } 1898}; 1899 1900// Also handles swipeleft, swiperight 1901$.event.special.swipe = { 1902 1903 // More than this horizontal displacement, and we will suppress scrolling. 1904 scrollSupressionThreshold: 30, 1905 1906 // More time than this, and it isn't a swipe. 1907 durationThreshold: 1000, 1908 1909 // Swipe horizontal displacement must be more than this. 1910 horizontalDistanceThreshold: window.devicePixelRatio >= 2 ? 15 : 30, 1911 1912 // Swipe vertical displacement must be less than this. 1913 verticalDistanceThreshold: window.devicePixelRatio >= 2 ? 15 : 30, 1914 1915 getLocation: function( event ) { 1916 var winPageX = window.pageXOffset, 1917 winPageY = window.pageYOffset, 1918 x = event.clientX, 1919 y = event.clientY; 1920 1921 if ( event.pageY === 0 && Math.floor( y ) > Math.floor( event.pageY ) || 1922 event.pageX === 0 && Math.floor( x ) > Math.floor( event.pageX ) ) { 1923 1924 // iOS4 clientX/clientY have the value that should have been 1925 // in pageX/pageY. While pageX/page/ have the value 0 1926 x = x - winPageX; 1927 y = y - winPageY; 1928 } else if ( y < ( event.pageY - winPageY ) || x < ( event.pageX - winPageX ) ) { 1929 1930 // Some Android browsers have totally bogus values for clientX/Y 1931 // when scrolling/zooming a page. Detectable since clientX/clientY 1932 // should never be smaller than pageX/pageY minus page scroll 1933 x = event.pageX - winPageX; 1934 y = event.pageY - winPageY; 1935 } 1936 1937 return { 1938 x: x, 1939 y: y 1940 }; 1941 }, 1942 1943 start: function( event ) { 1944 var data = event.originalEvent.touches ? 1945 event.originalEvent.touches[ 0 ] : event, 1946 location = $.event.special.swipe.getLocation( data ); 1947 return { 1948 time: ( new Date() ).getTime(), 1949 coords: [ location.x, location.y ], 1950 origin: $( event.target ) 1951 }; 1952 }, 1953 1954 stop: function( event ) { 1955 var data = event.originalEvent.touches ? 1956 event.originalEvent.touches[ 0 ] : event, 1957 location = $.event.special.swipe.getLocation( data ); 1958 return { 1959 time: ( new Date() ).getTime(), 1960 coords: [ location.x, location.y ] 1961 }; 1962 }, 1963 1964 handleSwipe: function( start, stop, thisObject, origTarget ) { 1965 if ( stop.time - start.time < $.event.special.swipe.durationThreshold && 1966 Math.abs( start.coords[ 0 ] - stop.coords[ 0 ] ) > $.event.special.swipe.horizontalDistanceThreshold && 1967 Math.abs( start.coords[ 1 ] - stop.coords[ 1 ] ) < $.event.special.swipe.verticalDistanceThreshold ) { 1968 var direction = start.coords[ 0 ] > stop.coords[ 0 ] ? "swipeleft" : "swiperight"; 1969 1970 triggerCustomEvent( thisObject, "swipe", $.Event( "swipe", { target: origTarget, swipestart: start, swipestop: stop } ), true ); 1971 triggerCustomEvent( thisObject, direction, $.Event( direction, { target: origTarget, swipestart: start, swipestop: stop } ), true ); 1972 return true; 1973 } 1974 return false; 1975 1976 }, 1977 1978 // This serves as a flag to ensure that at most one swipe event event is 1979 // in work at any given time 1980 eventInProgress: false, 1981 1982 setup: function() { 1983 var events, 1984 thisObject = this, 1985 $this = $( thisObject ), 1986 context = {}; 1987 1988 // Retrieve the events data for this element and add the swipe context 1989 events = $.data( this, "mobile-events" ); 1990 if ( !events ) { 1991 events = { length: 0 }; 1992 $.data( this, "mobile-events", events ); 1993 } 1994 events.length++; 1995 events.swipe = context; 1996 1997 context.start = function( event ) { 1998 1999 // Bail if we're already working on a swipe event 2000 if ( $.event.special.swipe.eventInProgress ) { 2001 return; 2002 } 2003 $.event.special.swipe.eventInProgress = true; 2004 2005 var stop, 2006 start = $.event.special.swipe.start( event ), 2007 origTarget = event.target, 2008 emitted = false; 2009 2010 context.move = function( event ) { 2011 if ( !start || event.isDefaultPrevented() ) { 2012 return; 2013 } 2014 2015 stop = $.event.special.swipe.stop( event ); 2016 if ( !emitted ) { 2017 emitted = $.event.special.swipe.handleSwipe( start, stop, thisObject, origTarget ); 2018 if ( emitted ) { 2019 2020 // Reset the context to make way for the next swipe event 2021 $.event.special.swipe.eventInProgress = false; 2022 } 2023 } 2024 // prevent scrolling 2025 if ( Math.abs( start.coords[ 0 ] - stop.coords[ 0 ] ) > $.event.special.swipe.scrollSupressionThreshold ) { 2026 event.preventDefault(); 2027 } 2028 }; 2029 2030 context.stop = function() { 2031 emitted = true; 2032 2033 // Reset the context to make way for the next swipe event 2034 $.event.special.swipe.eventInProgress = false; 2035 $document.off( touchMoveEvent, context.move ); 2036 context.move = null; 2037 }; 2038 2039 $document.on( touchMoveEvent, context.move ) 2040 .one( touchStopEvent, context.stop ); 2041 }; 2042 $this.on( touchStartEvent, context.start ); 2043 }, 2044 2045 teardown: function() { 2046 var events, context; 2047 2048 events = $.data( this, "mobile-events" ); 2049 if ( events ) { 2050 context = events.swipe; 2051 delete events.swipe; 2052 events.length--; 2053 if ( events.length === 0 ) { 2054 $.removeData( this, "mobile-events" ); 2055 } 2056 } 2057 2058 if ( context ) { 2059 if ( context.start ) { 2060 $( this ).off( touchStartEvent, context.start ); 2061 } 2062 if ( context.move ) { 2063 $document.off( touchMoveEvent, context.move ); 2064 } 2065 if ( context.stop ) { 2066 $document.off( touchStopEvent, context.stop ); 2067 } 2068 } 2069 } 2070}; 2071$.each( { 2072 taphold: "tap", 2073 swipeleft: "swipe.left", 2074 swiperight: "swipe.right" 2075}, function( event, sourceEvent ) { 2076 2077 $.event.special[ event ] = { 2078 setup: function() { 2079 $( this ).bind( sourceEvent, $.noop ); 2080 }, 2081 teardown: function() { 2082 $( this ).unbind( sourceEvent ); 2083 } 2084 }; 2085} ); 2086 2087return $.event.special; 2088} ); 2089 2090 2091/*! 2092 * jQuery Mobile Scroll Events @VERSION 2093 * http://jquerymobile.com 2094 * 2095 * Copyright jQuery Foundation and other contributors 2096 * Released under the MIT license. 2097 * http://jquery.org/license 2098 */ 2099 2100//>>label: Scroll 2101//>>group: Events 2102//>>description: Scroll events including: scrollstart, scrollstop 2103 2104( function( factory ) { 2105 if ( typeof define === "function" && define.amd ) { 2106 2107 // AMD. Register as an anonymous module. 2108 define( 'events/scroll',[ "jquery" ], factory ); 2109 } else { 2110 2111 // Browser globals 2112 factory( jQuery ); 2113 } 2114} )( function( $ ) { 2115 2116var scrollEvent = "touchmove scroll"; 2117 2118// setup new event shortcuts 2119$.each( [ "scrollstart", "scrollstop" ], function( i, name ) { 2120 2121 $.fn[ name ] = function( fn ) { 2122 return fn ? this.bind( name, fn ) : this.trigger( name ); 2123 }; 2124 2125 // jQuery < 1.8 2126 if ( $.attrFn ) { 2127 $.attrFn[ name ] = true; 2128 } 2129} ); 2130 2131// also handles scrollstop 2132$.event.special.scrollstart = { 2133 2134 enabled: true, 2135 setup: function() { 2136 2137 var thisObject = this, 2138 $this = $( thisObject ), 2139 scrolling, 2140 timer; 2141 2142 function trigger( event, state ) { 2143 var originalEventType = event.type; 2144 2145 scrolling = state; 2146 2147 event.type = scrolling ? "scrollstart" : "scrollstop"; 2148 $.event.dispatch.call( thisObject, event ); 2149 event.type = originalEventType; 2150 } 2151 2152 var scrollStartHandler = $.event.special.scrollstart.handler = function ( event ) { 2153 2154 if ( !$.event.special.scrollstart.enabled ) { 2155 return; 2156 } 2157 2158 if ( !scrolling ) { 2159 trigger( event, true ); 2160 } 2161 2162 clearTimeout( timer ); 2163 timer = setTimeout( function() { 2164 trigger( event, false ); 2165 }, 50 ); 2166 }; 2167 2168 // iPhone triggers scroll after a small delay; use touchmove instead 2169 $this.on( scrollEvent, scrollStartHandler ); 2170 }, 2171 teardown: function() { 2172 $( this ).off( scrollEvent, $.event.special.scrollstart.handler ); 2173 } 2174}; 2175 2176$.each( { 2177 scrollstop: "scrollstart" 2178}, function( event, sourceEvent ) { 2179 2180 $.event.special[ event ] = { 2181 setup: function() { 2182 $( this ).bind( sourceEvent, $.noop ); 2183 }, 2184 teardown: function() { 2185 $( this ).unbind( sourceEvent ); 2186 } 2187 }; 2188} ); 2189 2190return $.event.special; 2191} ); 2192 2193/*! 2194 * jQuery Mobile Throttled Resize @VERSION 2195 * http://jquerymobile.com 2196 * 2197 * Copyright jQuery Foundation and other contributors 2198 * Released under the MIT license. 2199 * http://jquery.org/license 2200 */ 2201 2202//>>label: Throttled Resize 2203//>>group: Events 2204//>>description: Fires a resize event with a slight delay to prevent excessive callback invocation 2205//>>docs: http://api.jquerymobile.com/throttledresize/ 2206 2207( function( factory ) { 2208 if ( typeof define === "function" && define.amd ) { 2209 2210 // AMD. Register as an anonymous module. 2211 define( 'events/throttledresize',[ "jquery" ], factory ); 2212 } else { 2213 2214 // Browser globals 2215 factory( jQuery ); 2216 } 2217} )( function( $ ) { 2218 2219var throttle = 250, 2220 lastCall = 0, 2221 heldCall, 2222 curr, 2223 diff, 2224 handler = function() { 2225 curr = ( new Date() ).getTime(); 2226 diff = curr - lastCall; 2227 2228 if ( diff >= throttle ) { 2229 2230 lastCall = curr; 2231 $( this ).trigger( "throttledresize" ); 2232 2233 } else { 2234 2235 if ( heldCall ) { 2236 clearTimeout( heldCall ); 2237 } 2238 2239 // Promise a held call will still execute 2240 heldCall = setTimeout( handler, throttle - diff ); 2241 } 2242 }; 2243 2244// throttled resize event 2245$.event.special.throttledresize = { 2246 setup: function() { 2247 $( this ).bind( "resize", handler ); 2248 }, 2249 teardown: function() { 2250 $( this ).unbind( "resize", handler ); 2251 } 2252}; 2253 2254return $.event.special.throttledresize; 2255} ); 2256 2257/*! 2258 * jQuery Mobile Orientation Change Event @VERSION 2259 * http://jquerymobile.com 2260 * 2261 * Copyright jQuery Foundation and other contributors 2262 * Released under the MIT license. 2263 * http://jquery.org/license 2264 */ 2265 2266//>>label: Orientation Change 2267//>>group: Events 2268//>>description: Provides a wrapper around the inconsistent browser implementations of orientationchange 2269//>>docs: http://api.jquerymobile.com/orientationchange/ 2270 2271( function( factory ) { 2272 if ( typeof define === "function" && define.amd ) { 2273 2274 // AMD. Register as an anonymous module. 2275 define( 'events/orientationchange',[ 2276 "jquery", 2277 "../support/orientation", 2278 "./throttledresize" ], factory ); 2279 } else { 2280 2281 // Browser globals 2282 factory( jQuery ); 2283 } 2284} )( function( $ ) { 2285 2286var win = $( window ), 2287 event_name = "orientationchange", 2288 get_orientation, 2289 last_orientation, 2290 initial_orientation_is_landscape, 2291 initial_orientation_is_default, 2292 portrait_map = { "0": true, "180": true }, 2293 ww, wh, landscape_threshold; 2294 2295// It seems that some device/browser vendors use window.orientation values 0 and 180 to 2296// denote the "default" orientation. For iOS devices, and most other smart-phones tested, 2297// the default orientation is always "portrait", but in some Android and RIM based tablets, 2298// the default orientation is "landscape". The following code attempts to use the window 2299// dimensions to figure out what the current orientation is, and then makes adjustments 2300// to the to the portrait_map if necessary, so that we can properly decode the 2301// window.orientation value whenever get_orientation() is called. 2302// 2303// Note that we used to use a media query to figure out what the orientation the browser 2304// thinks it is in: 2305// 2306// initial_orientation_is_landscape = $.mobile.media("all and (orientation: landscape)"); 2307// 2308// but there was an iPhone/iPod Touch bug beginning with iOS 4.2, up through iOS 5.1, 2309// where the browser *ALWAYS* applied the landscape media query. This bug does not 2310// happen on iPad. 2311 2312if ( $.support.orientation ) { 2313 2314 // Check the window width and height to figure out what the current orientation 2315 // of the device is at this moment. Note that we've initialized the portrait map 2316 // values to 0 and 180, *AND* we purposely check for landscape so that if we guess 2317 // wrong, , we default to the assumption that portrait is the default orientation. 2318 // We use a threshold check below because on some platforms like iOS, the iPhone 2319 // form-factor can report a larger width than height if the user turns on the 2320 // developer console. The actual threshold value is somewhat arbitrary, we just 2321 // need to make sure it is large enough to exclude the developer console case. 2322 2323 ww = window.innerWidth || win.width(); 2324 wh = window.innerHeight || win.height(); 2325 landscape_threshold = 50; 2326 2327 initial_orientation_is_landscape = ww > wh && ( ww - wh ) > landscape_threshold; 2328 2329 // Now check to see if the current window.orientation is 0 or 180. 2330 initial_orientation_is_default = portrait_map[ window.orientation ]; 2331 2332 // If the initial orientation is landscape, but window.orientation reports 0 or 180, *OR* 2333 // if the initial orientation is portrait, but window.orientation reports 90 or -90, we 2334 // need to flip our portrait_map values because landscape is the default orientation for 2335 // this device/browser. 2336 if ( ( initial_orientation_is_landscape && initial_orientation_is_default ) || ( !initial_orientation_is_landscape && !initial_orientation_is_default ) ) { 2337 portrait_map = { "-90": true, "90": true }; 2338 } 2339} 2340 2341// If the event is not supported natively, this handler will be bound to 2342// the window resize event to simulate the orientationchange event. 2343function handler() { 2344 // Get the current orientation. 2345 var orientation = get_orientation(); 2346 2347 if ( orientation !== last_orientation ) { 2348 // The orientation has changed, so trigger the orientationchange event. 2349 last_orientation = orientation; 2350 win.trigger( event_name ); 2351 } 2352} 2353 2354$.event.special.orientationchange = $.extend( {}, $.event.special.orientationchange, { 2355 setup: function() { 2356 // If the event is supported natively, return false so that jQuery 2357 // will bind to the event using DOM methods. 2358 if ( $.support.orientation && !$.event.special.orientationchange.disabled ) { 2359 return false; 2360 } 2361 2362 // Get the current orientation to avoid initial double-triggering. 2363 last_orientation = get_orientation(); 2364 2365 // Because the orientationchange event doesn't exist, simulate the 2366 // event by testing window dimensions on resize. 2367 win.bind( "throttledresize", handler ); 2368 }, 2369 teardown: function() { 2370 // If the event is not supported natively, return false so that 2371 // jQuery will unbind the event using DOM methods. 2372 if ( $.support.orientation && !$.event.special.orientationchange.disabled ) { 2373 return false; 2374 } 2375 2376 // Because the orientationchange event doesn't exist, unbind the 2377 // resize event handler. 2378 win.unbind( "throttledresize", handler ); 2379 }, 2380 add: function( handleObj ) { 2381 // Save a reference to the bound event handler. 2382 var old_handler = handleObj.handler; 2383 2384 handleObj.handler = function( event ) { 2385 // Modify event object, adding the .orientation property. 2386 event.orientation = get_orientation(); 2387 2388 // Call the originally-bound event handler and return its result. 2389 return old_handler.apply( this, arguments ); 2390 }; 2391 } 2392} ); 2393 2394// Get the current page orientation. This method is exposed publicly, should it 2395// be needed, as jQuery.event.special.orientationchange.orientation() 2396$.event.special.orientationchange.orientation = get_orientation = function() { 2397 var isPortrait = true, 2398 elem = document.documentElement; 2399 2400 // prefer window orientation to the calculation based on screensize as 2401 // the actual screen resize takes place before or after the orientation change event 2402 // has been fired depending on implementation (eg android 2.3 is before, iphone after). 2403 // More testing is required to determine if a more reliable method of determining the new screensize 2404 // is possible when orientationchange is fired. (eg, use media queries + element + opacity) 2405 if ( $.support.orientation ) { 2406 // if the window orientation registers as 0 or 180 degrees report 2407 // portrait, otherwise landscape 2408 isPortrait = portrait_map[ window.orientation ]; 2409 } else { 2410 isPortrait = elem && elem.clientWidth / elem.clientHeight < 1.1; 2411 } 2412 2413 return isPortrait ? "portrait" : "landscape"; 2414}; 2415 2416$.fn[ event_name ] = function( fn ) { 2417 return fn ? this.bind( event_name, fn ) : this.trigger( event_name ); 2418}; 2419 2420// jQuery < 1.8 2421if ( $.attrFn ) { 2422 $.attrFn[ event_name ] = true; 2423} 2424 2425return $.event.special; 2426} ); 2427 2428/*! 2429 * jQuery Mobile Events @VERSION 2430 * http://jquerymobile.com 2431 * 2432 * Copyright jQuery Foundation and other contributors 2433 * Released under the MIT license. 2434 * http://jquery.org/license 2435 */ 2436 2437//>>label: Events 2438//>>group: Events 2439//>>description: Custom events and shortcuts. 2440 2441( function( factory ) { 2442 if ( typeof define === "function" && define.amd ) { 2443 2444 // AMD. Register as an anonymous module. 2445 define( 'events',[ 2446 "jquery", 2447 "./events/navigate", 2448 "./events/touch", 2449 "./events/scroll", 2450 "./events/orientationchange" ], factory ); 2451 } else { 2452 2453 // Browser globals 2454 factory( jQuery ); 2455 } 2456} )( function() {} ); 2457 2458 2459}));
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.