PageSourceSearch

https://gs-urmitz.de/modules/news_img/js/galleries/lightcase/vendor/jQuery/jquery.events.touch.js?1787299200

js gs-urmitz.de collected 2026-10-09 01:20:02 UTC 68,980 bytes, 2,459 lines download raw bytes

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 = "&shy;<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.