PageSourceSearch

https://dobbysoven.com/libraries/jquery.mobile.touchevent.js

js dobbysoven.com collected 2026-10-08 23:17:41 UTC 85,921 bytes, 2,682 lines download raw bytes

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

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.