1 /*!
  2  * jQuery Mobile v1.0a3
  3  * http://jquerymobile.com/
  4  *
  5  * Copyright 2010, jQuery Project
  6  * Dual licensed under the MIT or GPL Version 2 licenses.
  7  * http://jquery.org/license
  8  */
  9 /*!
 10  * jQuery UI Widget @VERSION
 11  *
 12  * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
 13  * Dual licensed under the MIT or GPL Version 2 licenses.
 14  * http://jquery.org/license
 15  *
 16  * http://docs.jquery.com/UI/Widget
 17  */
 18 (function( $, undefined ) {
 19 
 20 // jQuery 1.4+
 21 if ( $.cleanData ) {
 22 	var _cleanData = $.cleanData;
 23 	$.cleanData = function( elems ) {
 24 		for ( var i = 0, elem; (elem = elems[i]) != null; i++ ) {
 25 			$( elem ).triggerHandler( "remove" );
 26 		}
 27 		_cleanData( elems );
 28 	};
 29 } else {
 30 	var _remove = $.fn.remove;
 31 	$.fn.remove = function( selector, keepData ) {
 32 		return this.each(function() {
 33 			if ( !keepData ) {
 34 				if ( !selector || $.filter( selector, [ this ] ).length ) {
 35 					$( "*", this ).add( [ this ] ).each(function() {
 36 						$( this ).triggerHandler( "remove" );
 37 					});
 38 				}
 39 			}
 40 			return _remove.call( $(this), selector, keepData );
 41 		});
 42 	};
 43 }
 44 
 45 $.widget = function( name, base, prototype ) {
 46 	var namespace = name.split( "." )[ 0 ],
 47 		fullName;
 48 	name = name.split( "." )[ 1 ];
 49 	fullName = namespace + "-" + name;
 50 
 51 	if ( !prototype ) {
 52 		prototype = base;
 53 		base = $.Widget;
 54 	}
 55 
 56 	// create selector for plugin
 57 	$.expr[ ":" ][ fullName ] = function( elem ) {
 58 		return !!$.data( elem, name );
 59 	};
 60 
 61 	$[ namespace ] = $[ namespace ] || {};
 62 	$[ namespace ][ name ] = function( options, element ) {
 63 		// allow instantiation without initializing for simple inheritance
 64 		if ( arguments.length ) {
 65 			this._createWidget( options, element );
 66 		}
 67 	};
 68 
 69 	var basePrototype = new base();
 70 	// we need to make the options hash a property directly on the new instance
 71 	// otherwise we'll modify the options hash on the prototype that we're
 72 	// inheriting from
 73 //	$.each( basePrototype, function( key, val ) {
 74 //		if ( $.isPlainObject(val) ) {
 75 //			basePrototype[ key ] = $.extend( {}, val );
 76 //		}
 77 //	});
 78 	basePrototype.options = $.extend( true, {}, basePrototype.options );
 79 	$[ namespace ][ name ].prototype = $.extend( true, basePrototype, {
 80 		namespace: namespace,
 81 		widgetName: name,
 82 		widgetEventPrefix: $[ namespace ][ name ].prototype.widgetEventPrefix || name,
 83 		widgetBaseClass: fullName
 84 	}, prototype );
 85 
 86 	$.widget.bridge( name, $[ namespace ][ name ] );
 87 };
 88 
 89 $.widget.bridge = function( name, object ) {
 90 	$.fn[ name ] = function( options ) {
 91 		var isMethodCall = typeof options === "string",
 92 			args = Array.prototype.slice.call( arguments, 1 ),
 93 			returnValue = this;
 94 
 95 		// allow multiple hashes to be passed on init
 96 		options = !isMethodCall && args.length ?
 97 			$.extend.apply( null, [ true, options ].concat(args) ) :
 98 			options;
 99 
100 		// prevent calls to internal methods
101 		if ( isMethodCall && options.charAt( 0 ) === "_" ) {
102 			return returnValue;
103 		}
104 
105 		if ( isMethodCall ) {
106 			this.each(function() {
107 				var instance = $.data( this, name );
108 				if ( !instance ) {
109 					throw "cannot call methods on " + name + " prior to initialization; " +
110 						"attempted to call method '" + options + "'";
111 				}
112 				if ( !$.isFunction( instance[options] ) ) {
113 					throw "no such method '" + options + "' for " + name + " widget instance";
114 				}
115 				var methodValue = instance[ options ].apply( instance, args );
116 				if ( methodValue !== instance && methodValue !== undefined ) {
117 					returnValue = methodValue;
118 					return false;
119 				}
120 			});
121 		} else {
122 			this.each(function() {
123 				var instance = $.data( this, name );
124 				if ( instance ) {
125 					instance.option( options || {} )._init();
126 				} else {
127 					$.data( this, name, new object( options, this ) );
128 				}
129 			});
130 		}
131 
132 		return returnValue;
133 	};
134 };
135 
136 $.Widget = function( options, element ) {
137 	// allow instantiation without initializing for simple inheritance
138 	if ( arguments.length ) {
139 		this._createWidget( options, element );
140 	}
141 };
142 
143 $.Widget.prototype = {
144 	widgetName: "widget",
145 	widgetEventPrefix: "",
146 	options: {
147 		disabled: false
148 	},
149 	_createWidget: function( options, element ) {
150 		// $.widget.bridge stores the plugin instance, but we do it anyway
151 		// so that it's stored even before the _create function runs
152 		$.data( element, this.widgetName, this );
153 		this.element = $( element );
154 		this.options = $.extend( true, {},
155 			this.options,
156 			this._getCreateOptions(),
157 			options );
158 
159 		var self = this;
160 		this.element.bind( "remove." + this.widgetName, function() {
161 			self.destroy();
162 		});
163 
164 		this._create();
165 		this._trigger( "create" );
166 		this._init();
167 	},
168 	_getCreateOptions: function() {
169 		var options = {};
170 		if ( $.metadata ) {
171 			options = $.metadata.get( element )[ this.widgetName ];
172 		}
173 		return options;
174 	},
175 	_create: function() {},
176 	_init: function() {},
177 
178 	destroy: function() {
179 		this.element
180 			.unbind( "." + this.widgetName )
181 			.removeData( this.widgetName );
182 		this.widget()
183 			.unbind( "." + this.widgetName )
184 			.removeAttr( "aria-disabled" )
185 			.removeClass(
186 				this.widgetBaseClass + "-disabled " +
187 				"ui-state-disabled" );
188 	},
189 
190 	widget: function() {
191 		return this.element;
192 	},
193 
194 	option: function( key, value ) {
195 		var options = key;
196 
197 		if ( arguments.length === 0 ) {
198 			// don't return a reference to the internal hash
199 			return $.extend( {}, this.options );
200 		}
201 
202 		if  (typeof key === "string" ) {
203 			if ( value === undefined ) {
204 				return this.options[ key ];
205 			}
206 			options = {};
207 			options[ key ] = value;
208 		}
209 
210 		this._setOptions( options );
211 
212 		return this;
213 	},
214 	_setOptions: function( options ) {
215 		var self = this;
216 		$.each( options, function( key, value ) {
217 			self._setOption( key, value );
218 		});
219 
220 		return this;
221 	},
222 	_setOption: function( key, value ) {
223 		this.options[ key ] = value;
224 
225 		if ( key === "disabled" ) {
226 			this.widget()
227 				[ value ? "addClass" : "removeClass"](
228 					this.widgetBaseClass + "-disabled" + " " +
229 					"ui-state-disabled" )
230 				.attr( "aria-disabled", value );
231 		}
232 
233 		return this;
234 	},
235 
236 	enable: function() {
237 		return this._setOption( "disabled", false );
238 	},
239 	disable: function() {
240 		return this._setOption( "disabled", true );
241 	},
242 
243 	_trigger: function( type, event, data ) {
244 		var callback = this.options[ type ];
245 
246 		event = $.Event( event );
247 		event.type = ( type === this.widgetEventPrefix ?
248 			type :
249 			this.widgetEventPrefix + type ).toLowerCase();
250 		data = data || {};
251 
252 		// copy original event properties over to the new event
253 		// this would happen if we could call $.event.fix instead of $.Event
254 		// but we don't have a way to force an event to be fixed multiple times
255 		if ( event.originalEvent ) {
256 			for ( var i = $.event.props.length, prop; i; ) {
257 				prop = $.event.props[ --i ];
258 				event[ prop ] = event.originalEvent[ prop ];
259 			}
260 		}
261 
262 		this.element.trigger( event, data );
263 
264 		return !( $.isFunction(callback) &&
265 			callback.call( this.element[0], event, data ) === false ||
266 			event.isDefaultPrevented() );
267 	}
268 };
269 
270 })( jQuery );
271 /*
272 * jQuery Mobile Framework : widget factory extentions for mobile
273 * Copyright (c) jQuery Project
274 * Dual licensed under the MIT or GPL Version 2 licenses.
275 * http://jquery.org/license
276 */
277 (function($, undefined ) {
278 
279 $.widget( "mobile.widget", {
280 	_getCreateOptions: function() {
281 		var elem = this.element,
282 			options = {};
283 		$.each( this.options, function( option ) {
284 			var value = elem.data( option.replace( /[A-Z]/g, function( c ) {
285 				return "-" + c.toLowerCase();
286 			} ) );
287 			if ( value !== undefined ) {
288 				options[ option ] = value;
289 			}
290 		});
291 		return options;
292 	}
293 });
294 
295 })( jQuery );
296 /*
297 * jQuery Mobile Framework : resolution and CSS media query related helpers and behavior
298 * Copyright (c) jQuery Project
299 * Dual licensed under the MIT or GPL Version 2 licenses.
300 * http://jquery.org/license
301 */
302 (function($, undefined ) {
303 
304 var $window = $(window),
305 	$html = $( "html" ),
306 
307 	//media-query-like width breakpoints, which are translated to classes on the html element
308 	resolutionBreakpoints = [320,480,768,1024];
309 
310 
311 /* $.mobile.media method: pass a CSS media type or query and get a bool return
312 	note: this feature relies on actual media query support for media queries, though types will work most anywhere
313 	examples:
314 		$.mobile.media('screen') //>> tests for screen media type
315 		$.mobile.media('screen and (min-width: 480px)') //>> tests for screen media type with window width > 480px
316 		$.mobile.media('@media screen and (-webkit-min-device-pixel-ratio: 2)') //>> tests for webkit 2x pixel ratio (iPhone 4)
317 */
318 $.mobile.media = (function() {
319 	// TODO: use window.matchMedia once at least one UA implements it
320 	var cache = {},
321 		testDiv = $( "<div id='jquery-mediatest'>" ),
322 		fakeBody = $( "<body>" ).append( testDiv );
323 
324 	return function( query ) {
325 		if ( !( query in cache ) ) {
326 			var styleBlock = document.createElement('style'),
327         		cssrule = "@media " + query + " { #jquery-mediatest { position:absolute; } }";
328 	        //must set type for IE!	
329 	        styleBlock.type = "text/css";
330 	        if (styleBlock.styleSheet){ 
331 	          styleBlock.styleSheet.cssText = cssrule;
332 	        } 
333 	        else {
334 	          styleBlock.appendChild(document.createTextNode(cssrule));
335 	        } 
336 				
337 			$html.prepend( fakeBody ).prepend( styleBlock );
338 			cache[ query ] = testDiv.css( "position" ) === "absolute";
339 			fakeBody.add( styleBlock ).remove();
340 		}
341 		return cache[ query ];
342 	};
343 })();
344 
345 /*
346 	private function for adding/removing breakpoint classes to HTML element for faux media-query support
347 	It does not require media query support, instead using JS to detect screen width > cross-browser support
348 	This function is called on orientationchange, resize, and mobileinit, and is bound via the 'htmlclass' event namespace
349 */
350 function detectResolutionBreakpoints(){
351 	var currWidth = $window.width(),
352 		minPrefix = "min-width-",
353 		maxPrefix = "max-width-",
354 		minBreakpoints = [],
355 		maxBreakpoints = [],
356 		unit = "px",
357 		breakpointClasses;
358 
359 	$html.removeClass( minPrefix + resolutionBreakpoints.join(unit + " " + minPrefix) + unit + " " +
360 		maxPrefix + resolutionBreakpoints.join( unit + " " + maxPrefix) + unit );
361 
362 	$.each(resolutionBreakpoints,function( i, breakPoint ){
363 		if( currWidth >= breakPoint ){
364 			minBreakpoints.push( minPrefix + breakPoint + unit );
365 		}
366 		if( currWidth <= breakPoint ){
367 			maxBreakpoints.push( maxPrefix + breakPoint + unit );
368 		}
369 	});
370 
371 	if( minBreakpoints.length ){ breakpointClasses = minBreakpoints.join(" "); }
372 	if( maxBreakpoints.length ){ breakpointClasses += " " +  maxBreakpoints.join(" "); }
373 
374 	$html.addClass( breakpointClasses );
375 };
376 
377 /* $.mobile.addResolutionBreakpoints method:
378 	pass either a number or an array of numbers and they'll be added to the min/max breakpoint classes
379 	Examples:
380 		$.mobile.addResolutionBreakpoints( 500 );
381 		$.mobile.addResolutionBreakpoints( [500, 1200] );
382 */
383 $.mobile.addResolutionBreakpoints = function( newbps ){
384 	if( $.type( newbps ) === "array" ){
385 		resolutionBreakpoints = resolutionBreakpoints.concat( newbps );
386 	}
387 	else {
388 		resolutionBreakpoints.push( newbps );
389 	}
390 	resolutionBreakpoints.sort(function(a,b){ return a-b; });
391 	detectResolutionBreakpoints();
392 };
393 
394 /* 	on mobileinit, add classes to HTML element
395 	and set handlers to update those on orientationchange and resize*/
396 $(document).bind("mobileinit.htmlclass", function(){
397 	/* bind to orientationchange and resize
398 	to add classes to HTML element for min/max breakpoints and orientation */
399 	$window.bind("orientationchange.htmlclass resize.htmlclass", function(event){
400 		//add orientation class to HTML element on flip/resize.
401 		if(event.orientation){
402 			$html.removeClass( "portrait landscape" ).addClass( event.orientation );
403 		}
404 		//add classes to HTML element for min/max breakpoints
405 		detectResolutionBreakpoints();
406 	});
407 });
408 
409 /* Manually trigger an orientationchange event when the dom ready event fires.
410    This will ensure that any viewport meta tag that may have been injected
411    has taken effect already, allowing us to properly calculate the width of the
412    document.
413 */
414 $(function(){
415 	//trigger event manually
416 	$window.trigger( "orientationchange.htmlclass" );
417 });
418 
419 })(jQuery);/*
420 * jQuery Mobile Framework : support tests
421 * Copyright (c) jQuery Project
422 * Dual licensed under the MIT (MIT-LICENSE.txt) and GPL (GPL-LICENSE.txt) licenses.
423 * Note: Code is in draft form and is subject to change 
424 */
425 (function($, undefined ) {
426 
427 
428 
429 var fakeBody = $( "<body>" ).prependTo( "html" ),
430 	fbCSS = fakeBody[0].style,
431 	vendors = ['webkit','moz','o'],
432 	webos = window.palmGetResource || window.PalmServiceBridge, //only used to rule out scrollTop 
433 	bb = window.blackberry; //only used to rule out box shadow, as it's filled opaque on BB
434 
435 //thx Modernizr
436 function propExists( prop ){
437 	var uc_prop = prop.charAt(0).toUpperCase() + prop.substr(1),
438 		props   = (prop + ' ' + vendors.join(uc_prop + ' ') + uc_prop).split(' ');
439 	for(var v in props){
440 		if( fbCSS[ v ] !== undefined ){
441 			return true;
442 		}
443 	}
444 };
445 
446 //test for dynamic-updating base tag support (allows us to avoid href,src attr rewriting)
447 function baseTagTest(){
448 	var fauxBase = location.protocol + '//' + location.host + location.pathname + "ui-dir/",
449 		base = $("head base"),
450 		fauxEle = null,
451 		href = '';
452 	if (!base.length) {
453 		base = fauxEle = $("<base>", {"href": fauxBase}).appendTo("head");
454 	}
455 	else {
456 		href = base.attr("href");
457 	}
458 	var link = $( "<a href='testurl'></a>" ).prependTo( fakeBody ),
459 		rebase = link[0].href;
460 	base[0].href = href ? href : location.pathname;
461 	if (fauxEle) {
462 		fauxEle.remove();
463 	}
464 	return rebase.indexOf(fauxBase) === 0;
465 };
466 
467 $.extend( $.support, {
468 	orientation: "orientation" in window,
469 	touch: "ontouchend" in document,
470 	cssTransitions: "WebKitTransitionEvent" in window,
471 	pushState: !!history.pushState,
472 	mediaquery: $.mobile.media('only all'),
473 	cssPseudoElement: !!propExists('content'),
474 	boxShadow: !!propExists('boxShadow') && !bb,
475 	scrollTop: ("pageXOffset" in window || "scrollTop" in document.documentElement || "scrollTop" in fakeBody[0]) && !webos,
476 	dynamicBaseTag: baseTagTest()
477 });
478 
479 fakeBody.remove();
480 
481 //for ruling out shadows via css
482 if( !$.support.boxShadow ){ $('html').addClass('ui-mobile-nosupport-boxshadow'); }
483 
484 })( jQuery );/*
485 * jQuery Mobile Framework : events
486 * Copyright (c) jQuery Project
487 * Dual licensed under the MIT or GPL Version 2 licenses.
488 * http://jquery.org/license
489 */
490 (function($, undefined ) {
491 
492 // add new event shortcuts
493 $.each( "touchstart touchmove touchend orientationchange tap taphold swipe swipeleft swiperight scrollstart scrollstop".split( " " ), function( i, name ) {
494 	$.fn[ name ] = function( fn ) {
495 		return fn ? this.bind( name, fn ) : this.trigger( name );
496 	};
497 	$.attrFn[ name ] = true;
498 });
499 
500 var supportTouch = $.support.touch,
501 	scrollEvent = "touchmove scroll",
502 	touchStartEvent = supportTouch ? "touchstart" : "mousedown",
503 	touchStopEvent = supportTouch ? "touchend" : "mouseup",
504 	touchMoveEvent = supportTouch ? "touchmove" : "mousemove";
505 
506 // also handles scrollstop
507 $.event.special.scrollstart = {
508 	enabled: true,
509 	
510 	setup: function() {
511 		var thisObject = this,
512 			$this = $( thisObject ),
513 			scrolling,
514 			timer;
515 		
516 		function trigger( event, state ) {
517 			scrolling = state;
518 			var originalType = event.type;
519 			event.type = scrolling ? "scrollstart" : "scrollstop";
520 			$.event.handle.call( thisObject, event );
521 			event.type = originalType;
522 		}
523 		
524 		// iPhone triggers scroll after a small delay; use touchmove instead
525 		$this.bind( scrollEvent, function( event ) {
526 			if ( !$.event.special.scrollstart.enabled ) {
527 				return;
528 			}
529 			
530 			if ( !scrolling ) {
531 				trigger( event, true );
532 			}
533 			
534 			clearTimeout( timer );
535 			timer = setTimeout(function() {
536 				trigger( event, false );
537 			}, 50 );
538 		});
539 	}
540 };
541 
542 // also handles taphold
543 $.event.special.tap = {
544 	setup: function() {
545 		var thisObject = this,
546 			$this = $( thisObject );
547 		
548 		$this
549 			.bind( "mousedown touchstart", function( event ) {
550 				if ( event.which && event.which !== 1 ||
551 					//check if event fired once already by a device that fires both mousedown and touchstart (while supporting both events)
552 					$this.data( "prevEvent") && $this.data( "prevEvent") !== event.type ) {
553 					return false;
554 				}
555 				
556 				//save event type so only this type is let through for a temp duration, 
557 				//allowing quick repetitive taps but not duplicative events 
558 				$this.data( "prevEvent", event.type );
559 				setTimeout(function(){
560 					$this.removeData( "prevEvent" );
561 				}, 800);
562 				
563 				var moved = false,
564 					touching = true,
565 					origTarget = event.target,
566 					origEvent = event.originalEvent,
567 					origPos = event.type == "touchstart" ? [origEvent.touches[0].pageX, origEvent.touches[0].pageY] : [ event.pageX, event.pageY ],
568 					originalType,
569 					timer;
570 					
571 				
572 				function moveHandler( event ) {
573 					if( event.type == "scroll" ){
574 						moved = true;
575 						return;
576 					}
577 					var newPageXY = event.type == "touchmove" ? event.originalEvent.touches[0] : event;
578 					if ((Math.abs(origPos[0] - newPageXY.pageX) > 10) ||
579 					    (Math.abs(origPos[1] - newPageXY.pageY) > 10)) {
580 					    moved = true;
581 					}
582 				}
583 				
584 				timer = setTimeout(function() {
585 					if ( touching && !moved ) {
586 						originalType = event.type;
587 						event.type = "taphold";
588 						$.event.handle.call( thisObject, event );
589 						event.type = originalType;
590 					}
591 				}, 750 );
592 				
593 				//scroll now cancels tap
594 				$(window).one("scroll", moveHandler);
595 				
596 				$this
597 					.bind( "mousemove touchmove", moveHandler )
598 					.one( "mouseup touchend", function( event ) {
599 						$this.unbind( "mousemove touchmove", moveHandler );
600 						$(window).unbind("scroll", moveHandler);
601 						clearTimeout( timer );
602 						touching = false;
603 						
604 						/* ONLY trigger a 'tap' event if the start target is
605 						 * the same as the stop target.
606 						 */
607 						if ( !moved && ( origTarget == event.target ) ) {
608 							originalType = event.type;
609 							event.type = "tap";
610 							$.event.handle.call( thisObject, event );
611 							event.type = originalType;
612 						}
613 					});
614 			});
615 	}
616 };
617 
618 // also handles swipeleft, swiperight
619 $.event.special.swipe = {
620 	setup: function() {
621 		var thisObject = this,
622 			$this = $( thisObject );
623 		
624 		$this
625 			.bind( touchStartEvent, function( event ) {
626 				var data = event.originalEvent.touches ?
627 						event.originalEvent.touches[ 0 ] :
628 						event,
629 					start = {
630 						time: (new Date).getTime(),
631 						coords: [ data.pageX, data.pageY ],
632 						origin: $( event.target )
633 					},
634 					stop;
635 				
636 				function moveHandler( event ) {
637 					if ( !start ) {
638 						return;
639 					}
640 					
641 					var data = event.originalEvent.touches ?
642 							event.originalEvent.touches[ 0 ] :
643 							event;
644 					stop = {
645 							time: (new Date).getTime(),
646 							coords: [ data.pageX, data.pageY ]
647 					};
648 					
649 					// prevent scrolling
650 					if ( Math.abs( start.coords[0] - stop.coords[0] ) > 10 ) {
651 						event.preventDefault();
652 					}
653 				}
654 				
655 				$this
656 					.bind( touchMoveEvent, moveHandler )
657 					.one( touchStopEvent, function( event ) {
658 						$this.unbind( touchMoveEvent, moveHandler );
659 						if ( start && stop ) {
660 							if ( stop.time - start.time < 1000 && 
661 									Math.abs( start.coords[0] - stop.coords[0]) > 30 &&
662 									Math.abs( start.coords[1] - stop.coords[1]) < 75 ) {
663 								start.origin
664 								.trigger( "swipe" )
665 								.trigger( start.coords[0] > stop.coords[0] ? "swipeleft" : "swiperight" );
666 							}
667 						}
668 						start = stop = undefined;
669 					});
670 			});
671 	}
672 };
673 
674 (function($){
675 	// "Cowboy" Ben Alman
676 	
677 	var win = $(window),
678 		special_event,
679 		get_orientation,
680 		last_orientation;
681 	
682 	$.event.special.orientationchange = special_event = {
683 		setup: function(){
684 			// If the event is supported natively, return false so that jQuery
685 			// will bind to the event using DOM methods.
686 			if ( $.support.orientation ) { return false; }
687 			
688 			// Get the current orientation to avoid initial double-triggering.
689 			last_orientation = get_orientation();
690 			
691 			// Because the orientationchange event doesn't exist, simulate the
692 			// event by testing window dimensions on resize.
693 			win.bind( "resize", handler );
694 		},
695 		teardown: function(){
696 			// If the event is not supported natively, return false so that
697 			// jQuery will unbind the event using DOM methods.
698 			if ( $.support.orientation ) { return false; }
699 			
700 			// Because the orientationchange event doesn't exist, unbind the
701 			// resize event handler.
702 			win.unbind( "resize", handler );
703 		},
704 		add: function( handleObj ) {
705 			// Save a reference to the bound event handler.
706 			var old_handler = handleObj.handler;
707 			
708 			handleObj.handler = function( event ) {
709 				// Modify event object, adding the .orientation property.
710 				event.orientation = get_orientation();
711 				
712 				// Call the originally-bound event handler and return its result.
713 				return old_handler.apply( this, arguments );
714 			};
715 		}
716 	};
717 	
718 	// If the event is not supported natively, this handler will be bound to
719 	// the window resize event to simulate the orientationchange event.
720 	function handler() {
721 		// Get the current orientation.
722 		var orientation = get_orientation();
723 		
724 		if ( orientation !== last_orientation ) {
725 			// The orientation has changed, so trigger the orientationchange event.
726 			last_orientation = orientation;
727 			win.trigger( "orientationchange" );
728 		}
729 	};
730 	
731 	// Get the current page orientation. This method is exposed publicly, should it
732 	// be needed, as jQuery.event.special.orientationchange.orientation()
733 	special_event.orientation = get_orientation = function() {
734 		var elem = document.documentElement;
735 		return elem && elem.clientWidth / elem.clientHeight < 1.1 ? "portrait" : "landscape";
736 	};
737 	
738 })(jQuery);
739 
740 $.each({
741 	scrollstop: "scrollstart",
742 	taphold: "tap",
743 	swipeleft: "swipe",
744 	swiperight: "swipe"
745 }, function( event, sourceEvent ) {
746 	$.event.special[ event ] = {
747 		setup: function() {
748 			$( this ).bind( sourceEvent, $.noop );
749 		}
750 	};
751 });
752 
753 })( jQuery );
754 /*!
755  * jQuery hashchange event - v1.3 - 7/21/2010
756  * http://benalman.com/projects/jquery-hashchange-plugin/
757  * 
758  * Copyright (c) 2010 "Cowboy" Ben Alman
759  * Dual licensed under the MIT and GPL licenses.
760  * http://benalman.com/about/license/
761  */
762 
763 // Script: jQuery hashchange event
764 //
765 // *Version: 1.3, Last updated: 7/21/2010*
766 // 
767 // Project Home - http://benalman.com/projects/jquery-hashchange-plugin/
768 // GitHub       - http://github.com/cowboy/jquery-hashchange/
769 // Source       - http://github.com/cowboy/jquery-hashchange/raw/master/jquery.ba-hashchange.js
770 // (Minified)   - http://github.com/cowboy/jquery-hashchange/raw/master/jquery.ba-hashchange.min.js (0.8kb gzipped)
771 // 
772 // About: License
773 // 
774 // Copyright (c) 2010 "Cowboy" Ben Alman,
775 // Dual licensed under the MIT and GPL licenses.
776 // http://benalman.com/about/license/
777 // 
778 // About: Examples
779 // 
780 // These working examples, complete with fully commented code, illustrate a few
781 // ways in which this plugin can be used.
782 // 
783 // hashchange event - http://benalman.com/code/projects/jquery-hashchange/examples/hashchange/
784 // document.domain - http://benalman.com/code/projects/jquery-hashchange/examples/document_domain/
785 // 
786 // About: Support and Testing
787 // 
788 // Information about what version or versions of jQuery this plugin has been
789 // tested with, what browsers it has been tested in, and where the unit tests
790 // reside (so you can test it yourself).
791 // 
792 // jQuery Versions - 1.2.6, 1.3.2, 1.4.1, 1.4.2
793 // Browsers Tested - Internet Explorer 6-8, Firefox 2-4, Chrome 5-6, Safari 3.2-5,
794 //                   Opera 9.6-10.60, iPhone 3.1, Android 1.6-2.2, BlackBerry 4.6-5.
795 // Unit Tests      - http://benalman.com/code/projects/jquery-hashchange/unit/
796 // 
797 // About: Known issues
798 // 
799 // While this jQuery hashchange event implementation is quite stable and
800 // robust, there are a few unfortunate browser bugs surrounding expected
801 // hashchange event-based behaviors, independent of any JavaScript
802 // window.onhashchange abstraction. See the following examples for more
803 // information:
804 // 
805 // Chrome: Back Button - http://benalman.com/code/projects/jquery-hashchange/examples/bug-chrome-back-button/
806 // Firefox: Remote XMLHttpRequest - http://benalman.com/code/projects/jquery-hashchange/examples/bug-firefox-remote-xhr/
807 // WebKit: Back Button in an Iframe - http://benalman.com/code/projects/jquery-hashchange/examples/bug-webkit-hash-iframe/
808 // Safari: Back Button from a different domain - http://benalman.com/code/projects/jquery-hashchange/examples/bug-safari-back-from-diff-domain/
809 // 
810 // Also note that should a browser natively support the window.onhashchange 
811 // event, but not report that it does, the fallback polling loop will be used.
812 // 
813 // About: Release History
814 // 
815 // 1.3   - (7/21/2010) Reorganized IE6/7 Iframe code to make it more
816 //         "removable" for mobile-only development. Added IE6/7 document.title
817 //         support. Attempted to make Iframe as hidden as possible by using
818 //         techniques from http://www.paciellogroup.com/blog/?p=604. Added 
819 //         support for the "shortcut" format $(window).hashchange( fn ) and
820 //         $(window).hashchange() like jQuery provides for built-in events.
821 //         Renamed jQuery.hashchangeDelay to <jQuery.fn.hashchange.delay> and
822 //         lowered its default value to 50. Added <jQuery.fn.hashchange.domain>
823 //         and <jQuery.fn.hashchange.src> properties plus document-domain.html
824 //         file to address access denied issues when setting document.domain in
825 //         IE6/7.
826 // 1.2   - (2/11/2010) Fixed a bug where coming back to a page using this plugin
827 //         from a page on another domain would cause an error in Safari 4. Also,
828 //         IE6/7 Iframe is now inserted after the body (this actually works),
829 //         which prevents the page from scrolling when the event is first bound.
830 //         Event can also now be bound before DOM ready, but it won't be usable
831 //         before then in IE6/7.
832 // 1.1   - (1/21/2010) Incorporated document.documentMode test to fix IE8 bug
833 //         where browser version is incorrectly reported as 8.0, despite
834 //         inclusion of the X-UA-Compatible IE=EmulateIE7 meta tag.
835 // 1.0   - (1/9/2010) Initial Release. Broke out the jQuery BBQ event.special
836 //         window.onhashchange functionality into a separate plugin for users
837 //         who want just the basic event & back button support, without all the
838 //         extra awesomeness that BBQ provides. This plugin will be included as
839 //         part of jQuery BBQ, but also be available separately.
840 
841 (function($,window,undefined){
842   '$:nomunge'; // Used by YUI compressor.
843   
844   // Reused string.
845   var str_hashchange = 'hashchange',
846     
847     // Method / object references.
848     doc = document,
849     fake_onhashchange,
850     special = $.event.special,
851     
852     // Does the browser support window.onhashchange? Note that IE8 running in
853     // IE7 compatibility mode reports true for 'onhashchange' in window, even
854     // though the event isn't supported, so also test document.documentMode.
855     doc_mode = doc.documentMode,
856     supports_onhashchange = 'on' + str_hashchange in window && ( doc_mode === undefined || doc_mode > 7 );
857   
858   // Get location.hash (or what you'd expect location.hash to be) sans any
859   // leading #. Thanks for making this necessary, Firefox!
860   function get_fragment( url ) {
861     url = url || location.href;
862     return '#' + url.replace( /^[^#]*#?(.*)$/, '$1' );
863   };
864   
865   // Method: jQuery.fn.hashchange
866   // 
867   // Bind a handler to the window.onhashchange event or trigger all bound
868   // window.onhashchange event handlers. This behavior is consistent with
869   // jQuery's built-in event handlers.
870   // 
871   // Usage:
872   // 
873   // > jQuery(window).hashchange( [ handler ] );
874   // 
875   // Arguments:
876   // 
877   //  handler - (Function) Optional handler to be bound to the hashchange
878   //    event. This is a "shortcut" for the more verbose form:
879   //    jQuery(window).bind( 'hashchange', handler ). If handler is omitted,
880   //    all bound window.onhashchange event handlers will be triggered. This
881   //    is a shortcut for the more verbose
882   //    jQuery(window).trigger( 'hashchange' ). These forms are described in
883   //    the <hashchange event> section.
884   // 
885   // Returns:
886   // 
887   //  (jQuery) The initial jQuery collection of elements.
888   
889   // Allow the "shortcut" format $(elem).hashchange( fn ) for binding and
890   // $(elem).hashchange() for triggering, like jQuery does for built-in events.
891   $.fn[ str_hashchange ] = function( fn ) {
892     return fn ? this.bind( str_hashchange, fn ) : this.trigger( str_hashchange );
893   };
894   
895   // Property: jQuery.fn.hashchange.delay
896   // 
897   // The numeric interval (in milliseconds) at which the <hashchange event>
898   // polling loop executes. Defaults to 50.
899   
900   // Property: jQuery.fn.hashchange.domain
901   // 
902   // If you're setting document.domain in your JavaScript, and you want hash
903   // history to work in IE6/7, not only must this property be set, but you must
904   // also set document.domain BEFORE jQuery is loaded into the page. This
905   // property is only applicable if you are supporting IE6/7 (or IE8 operating
906   // in "IE7 compatibility" mode).
907   // 
908   // In addition, the <jQuery.fn.hashchange.src> property must be set to the
909   // path of the included "document-domain.html" file, which can be renamed or
910   // modified if necessary (note that the document.domain specified must be the
911   // same in both your main JavaScript as well as in this file).
912   // 
913   // Usage:
914   // 
915   // jQuery.fn.hashchange.domain = document.domain;
916   
917   // Property: jQuery.fn.hashchange.src
918   // 
919   // If, for some reason, you need to specify an Iframe src file (for example,
920   // when setting document.domain as in <jQuery.fn.hashchange.domain>), you can
921   // do so using this property. Note that when using this property, history
922   // won't be recorded in IE6/7 until the Iframe src file loads. This property
923   // is only applicable if you are supporting IE6/7 (or IE8 operating in "IE7
924   // compatibility" mode).
925   // 
926   // Usage:
927   // 
928   // jQuery.fn.hashchange.src = 'path/to/file.html';
929   
930   $.fn[ str_hashchange ].delay = 50;
931   /*
932   $.fn[ str_hashchange ].domain = null;
933   $.fn[ str_hashchange ].src = null;
934   */
935   
936   // Event: hashchange event
937   // 
938   // Fired when location.hash changes. In browsers that support it, the native
939   // HTML5 window.onhashchange event is used, otherwise a polling loop is
940   // initialized, running every <jQuery.fn.hashchange.delay> milliseconds to
941   // see if the hash has changed. In IE6/7 (and IE8 operating in "IE7
942   // compatibility" mode), a hidden Iframe is created to allow the back button
943   // and hash-based history to work.
944   // 
945   // Usage as described in <jQuery.fn.hashchange>:
946   // 
947   // > // Bind an event handler.
948   // > jQuery(window).hashchange( function(e) {
949   // >   var hash = location.hash;
950   // >   ...
951   // > });
952   // > 
953   // > // Manually trigger the event handler.
954   // > jQuery(window).hashchange();
955   // 
956   // A more verbose usage that allows for event namespacing:
957   // 
958   // > // Bind an event handler.
959   // > jQuery(window).bind( 'hashchange', function(e) {
960   // >   var hash = location.hash;
961   // >   ...
962   // > });
963   // > 
964   // > // Manually trigger the event handler.
965   // > jQuery(window).trigger( 'hashchange' );
966   // 
967   // Additional Notes:
968   // 
969   // * The polling loop and Iframe are not created until at least one handler
970   //   is actually bound to the 'hashchange' event.
971   // * If you need the bound handler(s) to execute immediately, in cases where
972   //   a location.hash exists on page load, via bookmark or page refresh for
973   //   example, use jQuery(window).hashchange() or the more verbose 
974   //   jQuery(window).trigger( 'hashchange' ).
975   // * The event can be bound before DOM ready, but since it won't be usable
976   //   before then in IE6/7 (due to the necessary Iframe), recommended usage is
977   //   to bind it inside a DOM ready handler.
978   
979   // Override existing $.event.special.hashchange methods (allowing this plugin
980   // to be defined after jQuery BBQ in BBQ's source code).
981   special[ str_hashchange ] = $.extend( special[ str_hashchange ], {
982     
983     // Called only when the first 'hashchange' event is bound to window.
984     setup: function() {
985       // If window.onhashchange is supported natively, there's nothing to do..
986       if ( supports_onhashchange ) { return false; }
987       
988       // Otherwise, we need to create our own. And we don't want to call this
989       // until the user binds to the event, just in case they never do, since it
990       // will create a polling loop and possibly even a hidden Iframe.
991       $( fake_onhashchange.start );
992     },
993     
994     // Called only when the last 'hashchange' event is unbound from window.
995     teardown: function() {
996       // If window.onhashchange is supported natively, there's nothing to do..
997       if ( supports_onhashchange ) { return false; }
998       
999       // Otherwise, we need to stop ours (if possible).
1000       $( fake_onhashchange.stop );
1001     }
1002     
1003   });
1004   
1005   // fake_onhashchange does all the work of triggering the window.onhashchange
1006   // event for browsers that don't natively support it, including creating a
1007   // polling loop to watch for hash changes and in IE 6/7 creating a hidden
1008   // Iframe to enable back and forward.
1009   fake_onhashchange = (function(){
1010     var self = {},
1011       timeout_id,
1012       
1013       // Remember the initial hash so it doesn't get triggered immediately.
1014       last_hash = get_fragment(),
1015       
1016       fn_retval = function(val){ return val; },
1017       history_set = fn_retval,
1018       history_get = fn_retval;
1019     
1020     // Start the polling loop.
1021     self.start = function() {
1022       timeout_id || poll();
1023     };
1024     
1025     // Stop the polling loop.
1026     self.stop = function() {
1027       timeout_id && clearTimeout( timeout_id );
1028       timeout_id = undefined;
1029     };
1030     
1031     // This polling loop checks every $.fn.hashchange.delay milliseconds to see
1032     // if location.hash has changed, and triggers the 'hashchange' event on
1033     // window when necessary.
1034     function poll() {
1035       var hash = get_fragment(),
1036         history_hash = history_get( last_hash );
1037       
1038       if ( hash !== last_hash ) {
1039         history_set( last_hash = hash, history_hash );
1040         
1041         $(window).trigger( str_hashchange );
1042         
1043       } else if ( history_hash !== last_hash ) {
1044         location.href = location.href.replace( /#.*/, '' ) + history_hash;
1045       }
1046       
1047       timeout_id = setTimeout( poll, $.fn[ str_hashchange ].delay );
1048     };
1049     
1050     // vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
1051     // vvvvvvvvvvvvvvvvvvv REMOVE IF NOT SUPPORTING IE6/7/8 vvvvvvvvvvvvvvvvvvv
1052     // vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
1053     $.browser.msie && !supports_onhashchange && (function(){
1054       // Not only do IE6/7 need the "magical" Iframe treatment, but so does IE8
1055       // when running in "IE7 compatibility" mode.
1056       
1057       var iframe,
1058         iframe_src;
1059       
1060       // When the event is bound and polling starts in IE 6/7, create a hidden
1061       // Iframe for history handling.
1062       self.start = function(){
1063         if ( !iframe ) {
1064           iframe_src = $.fn[ str_hashchange ].src;
1065           iframe_src = iframe_src && iframe_src + get_fragment();
1066           
1067           // Create hidden Iframe. Attempt to make Iframe as hidden as possible
1068           // by using techniques from http://www.paciellogroup.com/blog/?p=604.
1069           iframe = $('<iframe tabindex="-1" title="empty"/>').hide()
1070             
1071             // When Iframe has completely loaded, initialize the history and
1072             // start polling.
1073             .one( 'load', function(){
1074               iframe_src || history_set( get_fragment() );
1075               poll();
1076             })
1077             
1078             // Load Iframe src if specified, otherwise nothing.
1079             .attr( 'src', iframe_src || 'javascript:0' )
1080             
1081             // Append Iframe after the end of the body to prevent unnecessary
1082             // initial page scrolling (yes, this works).
1083             .insertAfter( 'body' )[0].contentWindow;
1084           
1085           // Whenever `document.title` changes, update the Iframe's title to
1086           // prettify the back/next history menu entries. Since IE sometimes
1087           // errors with "Unspecified error" the very first time this is set
1088           // (yes, very useful) wrap this with a try/catch block.
1089           doc.onpropertychange = function(){
1090             try {
1091               if ( event.propertyName === 'title' ) {
1092                 iframe.document.title = doc.title;
1093               }
1094             } catch(e) {}
1095           };
1096           
1097         }
1098       };
1099       
1100       // Override the "stop" method since an IE6/7 Iframe was created. Even
1101       // if there are no longer any bound event handlers, the polling loop
1102       // is still necessary for back/next to work at all!
1103       self.stop = fn_retval;
1104       
1105       // Get history by looking at the hidden Iframe's location.hash.
1106       history_get = function() {
1107         return get_fragment( iframe.location.href );
1108       };
1109       
1110       // Set a new history item by opening and then closing the Iframe
1111       // document, *then* setting its location.hash. If document.domain has
1112       // been set, update that as well.
1113       history_set = function( hash, history_hash ) {
1114         var iframe_doc = iframe.document,
1115           domain = $.fn[ str_hashchange ].domain;
1116         
1117         if ( hash !== history_hash ) {
1118           // Update Iframe with any initial `document.title` that might be set.
1119           iframe_doc.title = doc.title;
1120           
1121           // Opening the Iframe's document after it has been closed is what
1122           // actually adds a history entry.
1123           iframe_doc.open();
1124           
1125           // Set document.domain for the Iframe document as well, if necessary.
1126           domain && iframe_doc.write( '<script>document.domain="' + domain + '"</script>' );
1127           
1128           iframe_doc.close();
1129           
1130           // Update the Iframe's hash, for great justice.
1131           iframe.location.hash = hash;
1132         }
1133       };
1134       
1135     })();
1136     // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
1137     // ^^^^^^^^^^^^^^^^^^^ REMOVE IF NOT SUPPORTING IE6/7/8 ^^^^^^^^^^^^^^^^^^^
1138     // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
1139     
1140     return self;
1141   })();
1142   
1143 })(jQuery,this);
1144 /*
1145 * jQuery Mobile Framework : "page" plugin
1146 * Copyright (c) jQuery Project
1147 * Dual licensed under the MIT or GPL Version 2 licenses.
1148 * http://jquery.org/license
1149 */
1150 (function($, undefined ) {
1151 
1152 $.widget( "mobile.page", $.mobile.widget, {
1153 	options: {
1154 		backBtnText: "Back",
1155 		addBackBtn: true,
1156 		degradeInputs: {
1157 			color: false,
1158 			date: false,
1159 			datetime: false,
1160 			"datetime-local": false,
1161 			email: false,
1162 			month: false,
1163 			number: false,
1164 			range: "number",
1165 			search: true,
1166 			tel: false,
1167 			time: false,
1168 			url: false,
1169 			week: false
1170 		},
1171 		keepNative: null
1172 	},
1173 
1174 	_create: function() {
1175 		var $elem = this.element,
1176 			o = this.options;	
1177 
1178 		this.keepNative = "[data-role='none'], [data-role='nojs']" + (o.keepNative ? ", " + o.keepNative : "");
1179 
1180 		if ( this._trigger( "beforeCreate" ) === false ) {
1181 			return;
1182 		}
1183 
1184 		//some of the form elements currently rely on the presence of ui-page and ui-content
1185 		// classes so we'll handle page and content roles outside of the main role processing
1186 		// loop below.
1187 		$elem.find( "[data-role='page'], [data-role='content']" ).andSelf().each(function() {
1188 			$(this).addClass( "ui-" + $(this).data( "role" ) );
1189 		});
1190 
1191 		$elem.find( "[data-role='nojs']" ).addClass( "ui-nojs" );
1192 
1193 		// pre-find data els
1194 		var $dataEls = $elem.find( "[data-role]" ).andSelf().each(function() {
1195 			var $this = $( this ),
1196 				role = $this.data( "role" ),
1197 				theme = $this.data( "theme" );
1198 
1199 			//apply theming and markup modifications to page,header,content,footer
1200 			if ( role === "header" || role === "footer" ) {
1201 				$this.addClass( "ui-bar-" + (theme || $this.parent('[data-role=page]').data( "theme" ) || "a") );
1202 
1203 				// add ARIA role
1204 				$this.attr( "role", role === "header" ? "banner" : "contentinfo" );
1205 
1206 				//right,left buttons
1207 				var $headeranchors = $this.children( "a" ),
1208 					leftbtn = $headeranchors.hasClass( "ui-btn-left" ),
1209 					rightbtn = $headeranchors.hasClass( "ui-btn-right" );
1210 
1211 				if ( !leftbtn ) {
1212 					leftbtn = $headeranchors.eq( 0 ).not( ".ui-btn-right" ).addClass( "ui-btn-left" ).length;
1213 				}
1214 
1215 				if ( !rightbtn ) {
1216 					rightbtn = $headeranchors.eq( 1 ).addClass( "ui-btn-right" ).length;
1217 				}
1218 
1219 				// auto-add back btn on pages beyond first view
1220 				if ( o.addBackBtn && role === "header" &&
1221 						$( ".ui-page" ).length > 1 &&
1222 						$elem.data( "url" ) !== $.mobile.path.stripHash( location.hash ) &&
1223 						!leftbtn && $this.data( "backbtn" ) !== false ) {
1224 
1225 					$( "<a href='#' class='ui-btn-left' data-rel='back' data-icon='arrow-l'>"+ o.backBtnText +"</a>" ).prependTo( $this );
1226 				}
1227 
1228 				//page title
1229 				$this.children( "h1, h2, h3, h4, h5, h6" )
1230 					.addClass( "ui-title" )
1231 					//regardless of h element number in src, it becomes h1 for the enhanced page
1232 					.attr({ "tabindex": "0", "role": "heading", "aria-level": "1" });
1233 
1234 			} else if ( role === "content" ) {
1235 				if ( theme ) {
1236 					$this.addClass( "ui-body-" + theme );
1237 				}
1238 
1239 				// add ARIA role
1240 				$this.attr( "role", "main" );
1241 
1242 			} else if ( role === "page" ) {
1243 				$this.addClass( "ui-body-" + (theme || "c") );
1244 			}
1245 
1246 			switch(role) {
1247 				case "header":
1248 				case "footer":
1249 				case "page":
1250 				case "content":
1251 					$this.addClass( "ui-" + role );
1252 					break;
1253 				case "collapsible":
1254 				case "fieldcontain":
1255 				case "navbar":
1256 				case "listview":
1257 				case "dialog":
1258 					$this[ role ]();
1259 					break;
1260 			}
1261 		});
1262 		
1263 		//enhance form controls
1264   	this._enhanceControls();
1265 
1266 		//links in bars, or those with data-role become buttons
1267 		$elem.find( "[data-role='button'], .ui-bar > a, .ui-header > a, .ui-footer > a" )
1268 			.not( ".ui-btn" )
1269 			.not(this.keepNative)
1270 			.buttonMarkup();
1271 
1272 		$elem
1273 			.find("[data-role='controlgroup']")
1274 			.controlgroup();
1275 
1276 		//links within content areas
1277 		$elem.find( "a:not(.ui-btn):not(.ui-link-inherit)" )
1278 			.not(this.keepNative)
1279 			.addClass( "ui-link" );
1280 
1281 		//fix toolbars
1282 		$elem.fixHeaderFooter();
1283 	},
1284 
1285 	_enhanceControls: function() {
1286 		var o = this.options;
1287 
1288 		// degrade inputs to avoid poorly implemented native functionality
1289 		this.element.find( "input" ).not(this.keepNative).each(function() {
1290 			var type = this.getAttribute( "type" ),
1291 				optType = o.degradeInputs[ type ] || "text";
1292 
1293 			if ( o.degradeInputs[ type ] ) {
1294 				$( this ).replaceWith(
1295 					$( "<div>" ).html( $(this).clone() ).html()
1296 						.replace( /type="([a-zA-Z]+)"/, "type="+ optType +" data-type='$1'" ) );
1297 			}
1298 		});
1299 
1300 		// We re-find form elements since the degredation code above
1301 		// may have injected new elements. We cache the non-native control
1302 		// query to reduce the number of times we search through the entire page.
1303 
1304 		var allControls = this.element.find("input, textarea, select, button"),
1305 			nonNativeControls = allControls.not(this.keepNative);
1306 
1307 		// XXX: Temporary workaround for issue 785. Turn off autocorrect and
1308 		//      autocomplete since the popup they use can't be dismissed by
1309 		//      the user. Note that we test for the presence of the feature
1310 		//      by looking for the autocorrect property on the input element.
1311 
1312 		var textInputs = allControls.filter( "input[type=text]" );
1313 		if (textInputs.length && typeof textInputs[0].autocorrect !== "undefined") {
1314 			textInputs.each(function(){
1315 				// Set the attribute instead of the property just in case there
1316 				// is code that attempts to make modifications via HTML.
1317 				this.setAttribute("autocorrect", "off");
1318 				this.setAttribute("autocomplete", "off");
1319 			});
1320 		}
1321 
1322 		// enchance form controls
1323 		nonNativeControls
1324 			.filter( "[type='radio'], [type='checkbox']" )
1325 			.checkboxradio();
1326 
1327 		nonNativeControls
1328 			.filter( "button, [type='button'], [type='submit'], [type='reset'], [type='image']" )
1329 			.button();
1330 
1331 		nonNativeControls
1332 			.filter( "input, textarea" )
1333 			.not( "[type='radio'], [type='checkbox'], [type='button'], [type='submit'], [type='reset'], [type='image'], [type='hidden']" )
1334 			.textinput();
1335 
1336 		nonNativeControls
1337 			.filter( "input, select" )
1338 			.filter( "[data-role='slider'], [data-type='range']" )
1339 			.slider();
1340 
1341 		nonNativeControls
1342 			.filter( "select:not([data-role='slider'])" )
1343 			.selectmenu();
1344 	}
1345 });
1346 
1347 })( jQuery );
1348 /*!
1349  * jQuery Mobile v@VERSION
1350  * http://jquerymobile.com/
1351  *
1352  * Copyright 2010, jQuery Project
1353  * Dual licensed under the MIT or GPL Version 2 licenses.
1354  * http://jquery.org/license
1355  */
1356 
1357 (function( $, window, undefined ) {
1358 
1359 	//jQuery.mobile configurable options
1360 	$.extend( $.mobile, {
1361 
1362 		//define the url parameter used for referencing widget-generated sub-pages.
1363 		//Translates to to example.html&ui-page=subpageIdentifier
1364 		//hash segment before &ui-page= is used to make Ajax request
1365 		subPageUrlKey: "ui-page",
1366 
1367 		//anchor links with a data-rel, or pages with a data-role, that match these selectors will be untrackable in history
1368 		//(no change in URL, not bookmarkable)
1369 		nonHistorySelectors: "dialog",
1370 
1371 		//class assigned to page currently in view, and during transitions
1372 		activePageClass: "ui-page-active",
1373 
1374 		//class used for "active" button state, from CSS framework
1375 		activeBtnClass: "ui-btn-active",
1376 
1377 		//automatically handle clicks and form submissions through Ajax, when same-domain
1378 		ajaxEnabled: true,
1379 
1380 		//automatically load and show pages based on location.hash
1381 		hashListeningEnabled: true,
1382 
1383 		// TODO: deprecated - remove at 1.0
1384 		//automatically handle link clicks through Ajax, when possible
1385 		ajaxLinksEnabled: true,
1386 
1387 		// TODO: deprecated - remove at 1.0
1388 		//automatically handle form submissions through Ajax, when possible
1389 		ajaxFormsEnabled: true,
1390 
1391 		//set default transition - 'none' for no transitions
1392 		defaultTransition: "slide",
1393 
1394 		//show loading message during Ajax requests
1395 		//if false, message will not appear, but loading classes will still be toggled on html el
1396 		loadingMessage: "loading",
1397 
1398 		//configure meta viewport tag's content attr:
1399 		metaViewportContent: "width=device-width, minimum-scale=1, maximum-scale=1",
1400 
1401 		//support conditions that must be met in order to proceed
1402 		gradeA: function(){
1403 			return $.support.mediaquery;
1404 		},
1405 
1406 		//automatically initialize first pages or not.
1407 		autoInitialize: true,
1408 
1409 		//TODO might be useful upstream in jquery itself ?
1410 		keyCode: {
1411 			ALT: 18,
1412 			BACKSPACE: 8,
1413 			CAPS_LOCK: 20,
1414 			COMMA: 188,
1415 			COMMAND: 91,
1416 			COMMAND_LEFT: 91, // COMMAND
1417 			COMMAND_RIGHT: 93,
1418 			CONTROL: 17,
1419 			DELETE: 46,
1420 			DOWN: 40,
1421 			END: 35,
1422 			ENTER: 13,
1423 			ESCAPE: 27,
1424 			HOME: 36,
1425 			INSERT: 45,
1426 			LEFT: 37,
1427 			MENU: 93, // COMMAND_RIGHT
1428 			NUMPAD_ADD: 107,
1429 			NUMPAD_DECIMAL: 110,
1430 			NUMPAD_DIVIDE: 111,
1431 			NUMPAD_ENTER: 108,
1432 			NUMPAD_MULTIPLY: 106,
1433 			NUMPAD_SUBTRACT: 109,
1434 			PAGE_DOWN: 34,
1435 			PAGE_UP: 33,
1436 			PERIOD: 190,
1437 			RIGHT: 39,
1438 			SHIFT: 16,
1439 			SPACE: 32,
1440 			TAB: 9,
1441 			UP: 38,
1442 			WINDOWS: 91 // COMMAND
1443 		}
1444 	});
1445 
1446     
1447 
1448 	//trigger mobileinit event - useful hook for configuring $.mobile settings before they're used
1449 	$( window.document ).trigger( "mobileinit" );
1450    
1451 	//support conditions
1452 	//if device support condition(s) aren't met, leave things as they are -> a basic, usable experience,
1453 	//otherwise, proceed with the enhancements
1454 	if ( !$.mobile.gradeA() ) {
1455 		return;
1456 	}
1457 
1458 
1459 	//define vars for interal use
1460 	var $window = $(window),
1461 		$html = $( "html" ),
1462 		$head = $( "head" ),
1463 
1464 		//loading div which appears during Ajax requests
1465 		//will not appear if $.mobile.loadingMessage is false
1466 		$loader = $.mobile.loadingMessage ?
1467 			$( "<div class='ui-loader ui-body-a ui-corner-all'>" +
1468 						"<span class='ui-icon ui-icon-loading spin'></span>" +
1469 						"<h1>" + $.mobile.loadingMessage + "</h1>" +
1470 					"</div>" )
1471 			: undefined;
1472 
1473 
1474 	//add mobile, initial load "rendering" classes to docEl
1475 	$html.addClass( "ui-mobile ui-mobile-rendering" );
1476 
1477 
1478 	//define & prepend meta viewport tag, if content is defined
1479 	$.mobile.metaViewportContent ? $( "<meta>", { name: "viewport", content: $.mobile.metaViewportContent}).prependTo( $head ) : undefined;
1480 
1481 
1482 	//expose some core utilities
1483 	$.extend($.mobile, {
1484 
1485 		// turn on/off page loading message.
1486 		pageLoading: function ( done ) {
1487 			if ( done ) {
1488 				$html.removeClass( "ui-loading" );
1489 			} else {
1490 				if( $.mobile.loadingMessage ){
1491 					var activeBtn =$( "." + $.mobile.activeBtnClass ).first();
1492 
1493 					$loader
1494 						.appendTo( $.mobile.pageContainer )
1495 						//position at y center (if scrollTop supported), above the activeBtn (if defined), or just 100px from top
1496 						.css( {
1497 							top: $.support.scrollTop && $(window).scrollTop() + $(window).height() / 2 ||
1498 							activeBtn.length && activeBtn.offset().top || 100
1499 						} );
1500 				}
1501 
1502 				$html.addClass( "ui-loading" );
1503 			}
1504 		},
1505 
1506 		//scroll page vertically: scroll to 0 to hide iOS address bar, or pass a Y value
1507 		silentScroll: function( ypos ) {
1508 			ypos = ypos || 0;
1509 			// prevent scrollstart and scrollstop events
1510 			$.event.special.scrollstart.enabled = false;
1511 
1512 			setTimeout(function() {
1513 				window.scrollTo( 0, ypos );
1514 				$(document).trigger( "silentscroll", { x: 0, y: ypos });
1515 			},20);
1516 
1517 			setTimeout(function() {
1518 				$.event.special.scrollstart.enabled = true;
1519 			}, 150 );
1520 		},
1521 
1522 		// find and enhance the pages in the dom and transition to the first page.
1523 		initializePage: function(){
1524 			//find present pages
1525 			var $pages = $( "[data-role='page']" );
1526             
1527 			//add dialogs, set data-url attrs
1528 			$pages.add( "[data-role='dialog']" ).each(function(){
1529 				$(this).attr( "data-url", $(this).attr( "id" ));
1530 			});
1531 
1532 			//define first page in dom case one backs out to the directory root (not always the first page visited, but defined as fallback)
1533 			$.mobile.firstPage = $pages.first();
1534 
1535 			//define page container
1536 			$.mobile.pageContainer = $pages.first().parent().addClass( "ui-mobile-viewport" );
1537 
1538 			//cue page loading message
1539 			$.mobile.pageLoading();
1540 
1541 			// if hashchange listening is disabled or there's no hash deeplink, change to the first page in the DOM
1542 			if( !$.mobile.hashListeningEnabled || !$.mobile.path.stripHash( location.hash ) ){
1543 				$.mobile.changePage( $.mobile.firstPage, false, true, false, true );
1544 			}
1545 			// otherwise, trigger a hashchange to load a deeplink
1546 			else {
1547 				$window.trigger( "hashchange", [ true ] );
1548 			}
1549 		}
1550 	});
1551 
1552 	//dom-ready inits
1553 	if($.mobile.autoInitialize){
1554 		$($.mobile.initializePage);
1555 	}
1556 
1557 
1558 	//window load event
1559 	//hide iOS browser chrome on load
1560 	$window.load( $.mobile.silentScroll );
1561 
1562 })( jQuery, this );
1563 /*
1564 * jQuery Mobile Framework : core utilities for auto ajax navigation, base tag mgmt,
1565 * Copyright (c) jQuery Project
1566 * Dual licensed under the MIT or GPL Version 2 licenses.
1567 * http://jquery.org/license
1568 */
1569 (function($, undefined ) {
1570 
1571 	//define vars for interal use
1572 	var $window = $(window),
1573 		$html = $('html'),
1574 		$head = $('head'),
1575 
1576 		//url path helpers for use in relative url management
1577 		path = {
1578 
1579 			//get path from current hash, or from a file path
1580 			get: function( newPath ){
1581 				if( newPath == undefined ){
1582 					newPath = location.hash;
1583 				}
1584 				return path.stripHash( newPath ).replace(/[^\/]*\.[^\/*]+$/, '');
1585 			},
1586 
1587 			//return the substring of a filepath before the sub-page key, for making a server request
1588 			getFilePath: function( path ){
1589 				var splitkey = '&' + $.mobile.subPageUrlKey;
1590 				return path && path.split( splitkey )[0].split( dialogHashKey )[0];
1591 			},
1592 
1593 			//set location hash to path
1594 			set: function( path ){
1595 				location.hash = path;
1596 			},
1597 
1598 			//location pathname from intial directory request
1599 			origin: '',
1600 
1601 			setOrigin: function(){
1602 				path.origin = path.get( location.protocol + '//' + location.host + location.pathname );
1603 			},
1604 
1605 			//prefix a relative url with the current path
1606 			makeAbsolute: function( url ){
1607 				return path.get() + url;
1608 			},
1609 
1610 			//return a url path with the window's location protocol/hostname removed
1611 			clean: function( url ){
1612 				return url.replace( location.protocol + "//" + location.host, "");
1613 			},
1614 
1615 			//just return the url without an initial #
1616 			stripHash: function( url ){
1617 				return url.replace( /^#/, "" );
1618 			},
1619 
1620 			//check whether a url is referencing the same domain, or an external domain or different protocol
1621 			//could be mailto, etc
1622 			isExternal: function( url ){
1623 				return path.hasProtocol( path.clean( url ) );
1624 			},
1625 
1626 			hasProtocol: function( url ){
1627 				return /^(:?\w+:)/.test( url );
1628 			},
1629 
1630 			//check if the url is relative
1631 			isRelative: function( url ){
1632 				return  /^[^\/|#]/.test( url ) && !path.hasProtocol( url );
1633 			},
1634 
1635 			isEmbeddedPage: function( url ){
1636 				return /^#/.test( url );
1637 			}
1638 		},
1639 
1640 		//will be defined when a link is clicked and given an active class
1641 		$activeClickedLink = null,
1642 
1643 		//urlHistory is purely here to make guesses at whether the back or forward button was clicked
1644 		//and provide an appropriate transition
1645 		urlHistory = {
1646 			//array of pages that are visited during a single page load. each has a url and optional transition
1647 			stack: [],
1648 
1649 			//maintain an index number for the active page in the stack
1650 			activeIndex: 0,
1651 
1652 			//get active
1653 			getActive: function(){
1654 				return urlHistory.stack[ urlHistory.activeIndex ];
1655 			},
1656 
1657 			getPrev: function(){
1658 				return urlHistory.stack[ urlHistory.activeIndex - 1 ];
1659 			},
1660 
1661 			getNext: function(){
1662 				return urlHistory.stack[ urlHistory.activeIndex + 1 ];
1663 			},
1664 
1665 			// addNew is used whenever a new page is added
1666 			addNew: function( url, transition ){
1667 				//if there's forward history, wipe it
1668 				if( urlHistory.getNext() ){
1669 					urlHistory.clearForward();
1670 				}
1671 
1672 				urlHistory.stack.push( {url : url, transition: transition } );
1673 
1674 				urlHistory.activeIndex = urlHistory.stack.length - 1;
1675 			},
1676 
1677 			//wipe urls ahead of active index
1678 			clearForward: function(){
1679 				urlHistory.stack = urlHistory.stack.slice( 0, urlHistory.activeIndex + 1 );
1680 			},
1681 			
1682 			//disable hashchange event listener internally to ignore one change
1683 			//toggled internally when location.hash is updated to match the url of a successful page load
1684 			ignoreNextHashChange: true
1685 		},
1686 
1687 		//define first selector to receive focus when a page is shown
1688 		focusable = "[tabindex],a,button:visible,select:visible,input",
1689 
1690 		//contains role for next page, if defined on clicked link via data-rel
1691 		nextPageRole = null,
1692 
1693 		//queue to hold simultanious page transitions
1694 		pageTransitionQueue = [],
1695 
1696 		// indicates whether or not page is in process of transitioning
1697 		isPageTransitioning = false,
1698 
1699 		//nonsense hash change key for dialogs, so they create a history entry
1700 		dialogHashKey = "&ui-state=dialog";
1701 
1702 		//existing base tag?
1703 		var $base = $head.children("base"),
1704 			hostURL = location.protocol + '//' + location.host,
1705 			docLocation = path.get( hostURL + location.pathname ),
1706 			docBase = docLocation;
1707 
1708 		if ($base.length){
1709 			var href = $base.attr("href");
1710 			if (href){
1711 				if (href.search(/^[^:/]+:\/\/[^/]+\/?/) == -1){
1712 					//the href is not absolute, we need to turn it into one
1713 					//so that we can turn paths stored in our location hash into
1714 					//relative paths.
1715 					if (href.charAt(0) == '/'){
1716 						//site relative url
1717 						docBase = hostURL + href;
1718 					}
1719 					else {
1720 						//the href is a document relative url
1721 						docBase = docLocation + href;
1722 						//XXX: we need some code here to calculate the final path
1723 						// just in case the docBase contains up-level (../) references.
1724 					}
1725 				}
1726 				else {
1727 					//the href is an absolute url
1728 					docBase = href;
1729 				}
1730 			}
1731 			//make sure docBase ends with a slash
1732 			docBase = docBase  + (docBase.charAt(docBase.length - 1) == '/' ? ' ' : '/');
1733 		}
1734 
1735 		//base element management, defined depending on dynamic base tag support
1736 		base = $.support.dynamicBaseTag ? {
1737 
1738 			//define base element, for use in routing asset urls that are referenced in Ajax-requested markup
1739 			element: ($base.length ? $base : $("<base>", { href: docBase }).prependTo( $head )),
1740 
1741 			//set the generated BASE element's href attribute to a new page's base path
1742 			set: function( href ){
1743 				base.element.attr('href', docBase + path.get( href ));
1744 			},
1745 
1746 			//set the generated BASE element's href attribute to a new page's base path
1747 			reset: function(){
1748 				base.element.attr('href', docBase );
1749 			}
1750 
1751 		} : undefined;
1752 
1753 
1754 
1755 		//set location pathname from intial directory request
1756 		path.setOrigin();
1757 
1758 /*
1759 	internal utility functions
1760 --------------------------------------*/
1761 
1762 
1763 	//direct focus to the page title, or otherwise first focusable element
1764 	function reFocus( page ){
1765 		var pageTitle = page.find( ".ui-title:eq(0)" );
1766 		if( pageTitle.length ){
1767 			pageTitle.focus();
1768 		}
1769 		else{
1770 			page.find( focusable ).eq(0).focus();
1771 		}
1772 	};
1773 
1774 	//remove active classes after page transition or error
1775 	function removeActiveLinkClass( forceRemoval ){
1776 		if( !!$activeClickedLink && (!$activeClickedLink.closest( '.ui-page-active' ).length || forceRemoval )){
1777 			$activeClickedLink.removeClass( $.mobile.activeBtnClass );
1778 		}
1779 		$activeClickedLink = null;
1780 	};
1781 
1782 	//animation complete callback
1783 	$.fn.animationComplete = function( callback ){
1784 		if($.support.cssTransitions){
1785 			return $(this).one('webkitAnimationEnd', callback);
1786 		}
1787 		else{
1788 			// defer execution for consistency between webkit/non webkit
1789 			setTimeout(callback, 0);
1790 		}
1791 	};
1792 
1793 
1794 
1795 /* exposed $.mobile methods	 */
1796 
1797 	//update location.hash, with or without triggering hashchange event
1798 	//TODO - deprecate this one at 1.0
1799 	$.mobile.updateHash = path.set;
1800 
1801 	//expose path object on $.mobile
1802 	$.mobile.path = path;
1803 
1804 	//expose base object on $.mobile
1805 	$.mobile.base = base;
1806 
1807 	//url stack, useful when plugins need to be aware of previous pages viewed
1808 	//TODO: deprecate this one at 1.0
1809 	$.mobile.urlstack = urlHistory.stack;
1810 
1811 	//history stack
1812 	$.mobile.urlHistory = urlHistory;
1813 
1814 	// changepage function
1815 	// TODO : consider moving args to an object hash
1816 	$.mobile.changePage = function( to, transition, reverse, changeHash, fromHashChange ){
1817 		//from is always the currently viewed page
1818 		var toIsArray = $.type(to) === "array",
1819 			toIsObject = $.type(to) === "object",
1820 			from = toIsArray ? to[0] : $.mobile.activePage,
1821 			to = toIsArray ? to[1] : to,
1822 			url = fileUrl = $.type(to) === "string" ? path.stripHash( to ) : "",
1823 			data = undefined,
1824 			type = 'get',
1825 			isFormRequest = false,
1826 			duplicateCachedPage = null,
1827 			currPage = urlHistory.getActive(),
1828 			back = false,
1829 			forward = false;
1830 
1831 
1832 		// If we are trying to transition to the same page that we are currently on ignore the request.
1833 		// an illegal same page request is defined by the current page being the same as the url, as long as there's history
1834 		// and to is not an array or object (those are allowed to be "same")
1835 		if( currPage && urlHistory.stack.length > 1 && currPage.url === url && !toIsArray && !toIsObject ) {
1836 			return;
1837 		}
1838 		else if(isPageTransitioning) {
1839 			pageTransitionQueue.unshift(arguments);
1840 			return;
1841 		}
1842 		
1843 		isPageTransitioning = true;
1844 
1845 		// if the changePage was sent from a hashChange event
1846 		// guess if it came from the history menu
1847 		if( fromHashChange ){
1848 
1849 			// check if url is in history and if it's ahead or behind current page
1850 			$.each( urlHistory.stack, function( i ){
1851 				//if the url is in the stack, it's a forward or a back
1852 				if( this.url == url ){
1853 					urlIndex = i;
1854 					//define back and forward by whether url is older or newer than current page
1855 					back = i < urlHistory.activeIndex;
1856 					//forward set to opposite of back
1857 					forward = !back;
1858 					//reset activeIndex to this one
1859 					urlHistory.activeIndex = i;
1860 				}
1861 			});
1862 
1863 			//if it's a back, use reverse animation
1864 			if( back ){
1865 				reverse = true;
1866 				transition = transition || currPage.transition;
1867 			}
1868 			else if ( forward ){
1869 				transition = transition || urlHistory.getActive().transition;
1870 			}
1871 		}
1872 
1873 
1874 		if( toIsObject && to.url ){
1875 			url = to.url,
1876 			data = to.data,
1877 			type = to.type,
1878 			isFormRequest = true;
1879 			//make get requests bookmarkable
1880 			if( data && type == 'get' ){
1881 				if($.type( data ) == "object" ){
1882 					data = $.param(data);
1883 				}
1884 
1885 				url += "?" + data;
1886 				data = undefined;
1887 			}
1888 		}
1889 
1890 		//reset base to pathname for new request
1891 		if(base){ base.reset(); }
1892 
1893 		//kill the keyboard
1894 		$( window.document.activeElement ).add( "input:focus, textarea:focus, select:focus" ).blur();
1895 
1896 		function defaultTransition(){
1897 			if(transition === undefined){
1898 				transition = $.mobile.defaultTransition;
1899 			}
1900 		}
1901 
1902 		//function for transitioning between two existing pages
1903 		function transitionPages() {
1904 		    $.mobile.silentScroll();
1905 
1906 			//get current scroll distance
1907 			var currScroll = $window.scrollTop(),
1908 					perspectiveTransitions = [ "flip" ],
1909 					pageContainerClasses = [];
1910 
1911 			//support deep-links to generated sub-pages
1912 			if( url.indexOf( "&" + $.mobile.subPageUrlKey ) > -1 ){
1913 				to = $( "[data-url='" + url + "']" );
1914 			}
1915 			
1916 			if( from ){
1917 				//set as data for returning to that spot
1918 				from.data( "lastScroll", currScroll);
1919 				//trigger before show/hide events
1920 				from.data( "page" )._trigger( "beforehide", { nextPage: to } );
1921 			}	
1922 			to.data( "page" )._trigger( "beforeshow", { prevPage: from || $("") } );
1923 
1924 			function loadComplete(){
1925 
1926 				if( changeHash !== false && url ){
1927 					//disable hash listening temporarily
1928 					urlHistory.ignoreNextHashChange = false;
1929 					//update hash and history
1930 					path.set( url );
1931 				}
1932 
1933 				//add page to history stack if it's not back or forward
1934 				if( !back && !forward ){
1935 					urlHistory.addNew( url, transition );
1936 				}
1937 
1938 				removeActiveLinkClass();
1939 
1940 				//jump to top or prev scroll, sometimes on iOS the page has not rendered yet.  I could only get by this with a setTimeout, but would like to avoid that.
1941 				$.mobile.silentScroll( to.data( "lastScroll" ) ); 
1942 
1943 				reFocus( to );
1944 
1945 				//trigger show/hide events
1946 				if( from ){
1947 					from.data( "page" )._trigger( "hide", null, { nextPage: to } );
1948 				}
1949 				//trigger pageshow, define prevPage as either from or empty jQuery obj
1950 				to.data( "page" )._trigger( "show", null, { prevPage: from || $("") } );
1951 				
1952 				//set "to" as activePage
1953 				$.mobile.activePage = to;
1954 
1955 				//if there's a duplicateCachedPage, remove it from the DOM now that it's hidden
1956 				if (duplicateCachedPage != null) {
1957 				    duplicateCachedPage.remove();
1958 				}
1959 				
1960 				//remove initial build class (only present on first pageshow)
1961 				$html.removeClass( "ui-mobile-rendering" );
1962 
1963 				isPageTransitioning = false
1964 				if(pageTransitionQueue.length>0) {
1965 					$.mobile.changePage.apply($.mobile, pageTransitionQueue.pop());
1966 				}
1967 			};
1968 
1969 			function addContainerClass(className){
1970 				$.mobile.pageContainer.addClass(className);
1971 				pageContainerClasses.push(className);
1972 			};
1973 
1974 			function removeContainerClasses(){
1975 				$.mobile
1976 					.pageContainer
1977 					.removeClass(pageContainerClasses.join(" "));
1978 
1979 				pageContainerClasses = [];
1980 			};
1981 
1982 
1983 
1984 			if(transition && (transition !== 'none')){
1985 			    $.mobile.pageLoading( true );
1986 				if( $.inArray(transition, perspectiveTransitions) >= 0 ){
1987 					addContainerClass('ui-mobile-viewport-perspective');
1988 				}
1989 
1990 				addContainerClass('ui-mobile-viewport-transitioning');
1991 
1992 				if( from ){
1993 					from.addClass( transition + " out " + ( reverse ? "reverse" : "" ) );
1994 				}
1995 				to.addClass( $.mobile.activePageClass + " " + transition +
1996 					" in " + ( reverse ? "reverse" : "" ) );
1997 
1998 				// callback - remove classes, etc
1999 				to.animationComplete(function() {
2000 					from.add( to ).removeClass("out in reverse " + transition );
2001 					if( from ){
2002 						from.removeClass( $.mobile.activePageClass );
2003 					}	
2004 					loadComplete();
2005 					removeContainerClasses();
2006 				});
2007 			}
2008 			else{
2009 			    $.mobile.pageLoading( true );
2010 			    if( from ){
2011 					from.removeClass( $.mobile.activePageClass );
2012 				}	
2013 				to.addClass( $.mobile.activePageClass );
2014 				loadComplete();
2015 			}
2016 		};
2017 
2018 		//shared page enhancements
2019 		function enhancePage(){
2020 
2021 			//set next page role, if defined
2022 			if ( nextPageRole || to.data('role') == 'dialog' ) {
2023 				url = urlHistory.getActive().url + dialogHashKey;
2024 				if(nextPageRole){
2025 					to.attr( "data-role", nextPageRole );
2026 					nextPageRole = null;
2027 				}
2028 			}
2029 
2030 			//run page plugin
2031 			to.page();
2032 		};
2033 
2034 		//if url is a string
2035 		if( url ){
2036 			to = $( "[data-url='" + url + "']" );
2037 			fileUrl = path.getFilePath(url);
2038 		}
2039 		else{ //find base url of element, if avail
2040 			var toID = to.attr('data-url'),
2041 				toIDfileurl = path.getFilePath(toID);
2042 
2043 			if(toID != toIDfileurl){
2044 				fileUrl = toIDfileurl;
2045 			}
2046 		}
2047 
2048 		// ensure a transition has been set where pop is undefined
2049 		defaultTransition();
2050 
2051 		// find the "to" page, either locally existing in the dom or by creating it through ajax
2052 		if ( to.length && !isFormRequest ) {
2053 			if( fileUrl && base ){
2054 				base.set( fileUrl );
2055 			}			
2056 			enhancePage();
2057 			transitionPages();
2058 		} else {
2059 
2060 			//if to exists in DOM, save a reference to it in duplicateCachedPage for removal after page change
2061 			if( to.length ){
2062 				duplicateCachedPage = to;
2063 			}
2064 
2065 			$.mobile.pageLoading();
2066 
2067 			$.ajax({
2068 				url: fileUrl,
2069 				type: type,
2070 				data: data,
2071 				success: function( html ) {
2072 
2073 					//pre-parse html to check for a data-url,
2074 					//use it as the new fileUrl, base path, etc
2075 					var redirectLoc = / data-url="(.*)"/.test( html ) && RegExp.$1;
2076 
2077 					if( redirectLoc ){
2078 						if(base){
2079 							base.set( redirectLoc );
2080 						}
2081 						url = fileUrl = path.getFilePath( redirectLoc );
2082 					}
2083 					else {
2084 						if(base){
2085 							base.set(fileUrl);
2086 						}
2087 					}
2088 
2089 					var all = $("<div></div>");
2090 					//workaround to allow scripts to execute when included in page divs
2091 					all.get(0).innerHTML = html;
2092 					to = all.find('[data-role="page"], [data-role="dialog"]').first();
2093 
2094 					//rewrite src and href attrs to use a base url
2095 					if( !$.support.dynamicBaseTag ){
2096 						var newPath = path.get( fileUrl );
2097 						to.find('[src],link[href]').each(function(){
2098 							var thisAttr = $(this).is('[href]') ? 'href' : 'src',
2099 								thisUrl = $(this).attr(thisAttr);
2100 
2101 							//if full path exists and is same, chop it - helps IE out
2102 							thisUrl.replace( location.protocol + '//' + location.host + location.pathname, '' );
2103 
2104 							if( !/^(\w+:|#|\/)/.test(thisUrl) ){
2105 								$(this).attr(thisAttr, newPath + thisUrl);
2106 							}
2107 						});
2108 					}
2109 
2110 					//append to page and enhance
2111 					to
2112 						.attr( "data-url", fileUrl )
2113 						.appendTo( $.mobile.pageContainer );
2114 
2115 					enhancePage();
2116 					setTimeout(function() { transitionPages() }, 0);
2117 				},
2118 				error: function() {
2119 					$.mobile.pageLoading( true );
2120 					removeActiveLinkClass(true);
2121 					if(base){
2122 						base.set(path.get());
2123 					}
2124 					$("<div class='ui-loader ui-overlay-shadow ui-body-e ui-corner-all'><h1>Error Loading Page</h1></div>")
2125 						.css({ "display": "block", "opacity": 0.96, "top": $(window).scrollTop() + 100 })
2126 						.appendTo( $.mobile.pageContainer )
2127 						.delay( 800 )
2128 						.fadeOut( 400, function(){
2129 							$(this).remove();
2130 						});
2131 				}
2132 			});
2133 		}
2134 
2135 	};
2136 
2137 
2138 /* Event Bindings - hashchange, submit, and click */
2139 
2140 	//bind to form submit events, handle with Ajax
2141 	$( "form[data-ajax!='false']" ).live('submit', function(event){
2142 		if( !$.mobile.ajaxEnabled ||
2143 			//TODO: deprecated - remove at 1.0
2144 			!$.mobile.ajaxFormsEnabled ){ return; }
2145 
2146 		var type = $(this).attr("method"),
2147 			url = path.clean( $(this).attr( "action" ) );
2148 
2149 		//external submits use regular HTTP
2150 		if( path.isExternal( url ) ){
2151 			return;
2152 		}
2153 
2154 		//if it's a relative href, prefix href with base url
2155 		if( path.isRelative( url ) ){
2156 			url = path.makeAbsolute( url );
2157 		}
2158 
2159 		$.mobile.changePage({
2160 				url: url,
2161 				type: type,
2162 				data: $(this).serialize()
2163 			},
2164 			undefined,
2165 			undefined,
2166 			true
2167 		);
2168 		event.preventDefault();
2169 	});
2170 
2171 
2172 	//click routing - direct to HTTP or Ajax, accordingly
2173 	$( "a" ).live( "click", function(event) {
2174 
2175 		var $this = $(this),
2176 		
2177 			//get href, if defined, otherwise fall to null #
2178 			href = $this.attr( "href" ) || "#",
2179 			
2180 			//get href, remove same-domain protocol and host
2181 			url = path.clean( href ),
2182 
2183 			//rel set to external
2184 			isRelExternal = $this.is( "[rel='external']" ),
2185 
2186 			//rel set to external
2187 			isEmbeddedPage = path.isEmbeddedPage( url ),
2188 
2189 			//check for protocol or rel and its not an embedded page
2190 			//TODO overlap in logic from isExternal, rel=external check should be
2191 			//     moved into more comprehensive isExternalLink
2192 			isExternal = path.isExternal( url ) || isRelExternal && !isEmbeddedPage,
2193 
2194 			//if target attr is specified we mimic _blank... for now
2195 			hasTarget = $this.is( "[target]" ),
2196 
2197 			//if data-ajax attr is set to false, use the default behavior of a link
2198 			hasAjaxDisabled = $this.is( "[data-ajax='false']" );
2199 
2200 		//if there's a data-rel=back attr, go back in history
2201 		if( $this.is( "[data-rel='back']" ) ){
2202 			window.history.back();
2203 			return false;
2204 		}
2205 
2206 		if( url === "#" ){
2207 			//for links created purely for interaction - ignore
2208 			return false;
2209 		}
2210 
2211 		$activeClickedLink = $this.closest( ".ui-btn" ).addClass( $.mobile.activeBtnClass );
2212 
2213 		if( isExternal || hasAjaxDisabled || hasTarget || !$.mobile.ajaxEnabled ||
2214 			// TODO: deprecated - remove at 1.0
2215 			!$.mobile.ajaxLinksEnabled ){
2216 			//remove active link class if external (then it won't be there if you come back)
2217 			removeActiveLinkClass(true);
2218 
2219 			//deliberately redirect, in case click was triggered
2220 			if( hasTarget ){
2221 				window.open( url );
2222 			}
2223 			else if( hasAjaxDisabled ){
2224 			  return;
2225 			}
2226 			else{
2227 				location.href = url;
2228 			}
2229 		}
2230 		else {
2231 			//use ajax
2232 			var transition = $this.data( "transition" ),
2233 				direction = $this.data("direction"),
2234 				reverse = direction && direction == "reverse" ||
2235 				// deprecated - remove by 1.0
2236 				$this.data( "back" );
2237 
2238 			//this may need to be more specific as we use data-rel more
2239 			nextPageRole = $this.attr( "data-rel" );
2240 
2241 			//if it's a relative href, prefix href with base url
2242 			if( path.isRelative( url ) ){
2243 				url = path.makeAbsolute( url );
2244 			}
2245 
2246 			url = path.stripHash( url );
2247 
2248 			$.mobile.changePage( url, transition, reverse);
2249 		}
2250 		event.preventDefault();
2251 	});
2252 
2253 
2254 	//hashchange event handler
2255 	$window.bind( "hashchange", function( e, triggered ) {
2256 		//find first page via hash
2257 		var to = path.stripHash( location.hash ),
2258 			//transition is false if it's the first page, undefined otherwise (and may be overridden by default)
2259 			transition = $.mobile.urlHistory.stack.length === 0 ? false : undefined;
2260 			
2261 		//if listening is disabled (either globally or temporarily), or it's a dialog hash
2262 		if( !$.mobile.hashListeningEnabled || !urlHistory.ignoreNextHashChange ||
2263 				urlHistory.stack.length > 1 && to.indexOf( dialogHashKey ) > -1 && !$.mobile.activePage.is( ".ui-dialog" )
2264 		){
2265 			if( !urlHistory.ignoreNextHashChange ){
2266 				urlHistory.ignoreNextHashChange = true;
2267 			}
2268 			return;
2269 		}
2270 
2271 		//if to is defined, load it
2272 		if ( to ){
2273 			$.mobile.changePage( to, transition, undefined, false, true );
2274 		}
2275 		//there's no hash, go to the first page in the dom
2276 		else {
2277 			$.mobile.changePage( $.mobile.firstPage, transition, true, false, true );
2278 		}
2279 	});
2280 })( jQuery );
2281 /*
2282 * jQuery Mobile Framework : "fixHeaderFooter" plugin - on-demand positioning for headers,footers
2283 * Copyright (c) jQuery Project
2284 * Dual licensed under the MIT or GPL Version 2 licenses.
2285 * http://jquery.org/license
2286 */
2287 (function($, undefined ) {
2288 $.fn.fixHeaderFooter = function(options){
2289 	if( !$.support.scrollTop ){ return this; }
2290 	
2291 	return this.each(function(){
2292 		var $this = $(this);
2293 		
2294 		if( $this.data('fullscreen') ){ $this.addClass('ui-page-fullscreen'); }
2295 		$this.find('.ui-header[data-position="fixed"]').addClass('ui-header-fixed ui-fixed-inline fade'); //should be slidedown
2296 		$this.find('.ui-footer[data-position="fixed"]').addClass('ui-footer-fixed ui-fixed-inline fade'); //should be slideup		
2297 	});
2298 };
2299 
2300 //single controller for all showing,hiding,toggling		
2301 $.fixedToolbars = (function(){
2302 	if( !$.support.scrollTop ){ return; }
2303 	var currentstate = 'inline',
2304 		autoHideMode = false,
2305 		showDelay = 100,
2306 		delayTimer,
2307 		ignoreTargets = 'a,input,textarea,select,button,label,.ui-header-fixed,.ui-footer-fixed',
2308 		toolbarSelector = '.ui-header-fixed:first, .ui-footer-fixed:not(.ui-footer-duplicate):last',
2309 		stickyFooter, //for storing quick references to duplicate footers
2310 		supportTouch = $.support.touch,
2311 		touchStartEvent = supportTouch ? "touchstart" : "mousedown",
2312 		touchStopEvent = supportTouch ? "touchend" : "mouseup",
2313 		stateBefore = null,
2314 		scrollTriggered = false,
2315         touchToggleEnabled = true;
2316 
2317 	function showEventCallback(event)
2318 	{
2319 		// An event that affects the dimensions of the visual viewport has
2320 		// been triggered. If the header and/or footer for the current page are in overlay
2321 		// mode, we want to hide them, and then fire off a timer to show them at a later
2322 		// point. Events like a resize can be triggered continuously during a scroll, on
2323 		// some platforms, so the timer is used to delay the actual positioning until the
2324 		// flood of events have subsided.
2325 		//
2326 		// If we are in autoHideMode, we don't do anything because we know the scroll
2327 		// callbacks for the plugin will fire off a show when the scrolling has stopped.
2328 		if (!autoHideMode && currentstate == 'overlay') {
2329 			if (!delayTimer)
2330 				$.fixedToolbars.hide(true);
2331 			$.fixedToolbars.startShowTimer();
2332 		}
2333 	}
2334 
2335 	$(function() {
2336 		$(document)
2337 			.bind(touchStartEvent,function(event){
2338 				if( touchToggleEnabled ) {
2339 					if( $(event.target).closest(ignoreTargets).length ){ return; }
2340 					stateBefore = currentstate;
2341 				}
2342 			})
2343 			.bind(touchStopEvent,function(event){
2344 				if( touchToggleEnabled ) {
2345 					if( $(event.target).closest(ignoreTargets).length ){ return; }
2346 					if( !scrollTriggered ){
2347 						$.fixedToolbars.toggle(stateBefore);
2348 						stateBefore = null;
2349 					}
2350 				}
2351 			})
2352 			.bind('scrollstart',function(event){
2353 				if( $(event.target).closest(ignoreTargets).length ){ return; } //because it could be a touchmove...
2354 				scrollTriggered = true;
2355 				if(stateBefore == null){ stateBefore = currentstate; }
2356 
2357 				// We only enter autoHideMode if the headers/footers are in
2358 				// an overlay state or the show timer was started. If the
2359 				// show timer is set, clear it so the headers/footers don't
2360 				// show up until after we're done scrolling.
2361 				var isOverlayState = stateBefore == 'overlay';
2362 				autoHideMode = isOverlayState || !!delayTimer;
2363 				if (autoHideMode){
2364 					$.fixedToolbars.clearShowTimer();
2365 					if (isOverlayState) {
2366 						$.fixedToolbars.hide(true);
2367 					}
2368 				}
2369 			})
2370 			.bind('scrollstop',function(event){
2371 				if( $(event.target).closest(ignoreTargets).length ){ return; }
2372 				scrollTriggered = false;
2373 				if (autoHideMode) {
2374 					autoHideMode = false;
2375 					$.fixedToolbars.startShowTimer();
2376 				}
2377 				stateBefore = null;
2378 			})
2379 			.bind('silentscroll', showEventCallback);
2380 
2381 			$(window).bind('resize', showEventCallback);
2382 	});
2383 		
2384 	//before page is shown, check for duplicate footer
2385 	$('.ui-page').live('pagebeforeshow', function(event, ui){
2386 		var page = $(event.target),
2387 			footer = page.find('[data-role="footer"]:not(.ui-sticky-footer)'),
2388 			id = footer.data('id');
2389 		stickyFooter = null;
2390 		if (id)
2391 		{
2392 			stickyFooter = $('.ui-footer[data-id="' + id + '"].ui-sticky-footer');
2393 			if (stickyFooter.length == 0) {
2394 				// No sticky footer exists for this data-id. We'll use this
2395 				// footer as the sticky footer for the group and then create
2396 				// a placeholder footer for the page.
2397 				stickyFooter = footer;
2398 				footer = stickyFooter.clone(); // footer placeholder
2399 				stickyFooter.addClass('ui-sticky-footer').before(footer);
2400 			}
2401 			footer.addClass('ui-footer-duplicate');
2402 			stickyFooter.appendTo($.pageContainer).css('top',0);
2403 			setTop(stickyFooter);
2404 		}
2405 	});
2406 
2407 	//after page is shown, append footer to new page
2408 	$('.ui-page').live('pageshow', function(event, ui){
2409 		if( stickyFooter && stickyFooter.length ){
2410 			stickyFooter.appendTo(event.target).css('top',0);
2411 		}
2412 		$.fixedToolbars.show(true, this);
2413 	});
2414 		
2415 	
2416 	// element.getBoundingClientRect() is broken in iOS 3.2.1 on the iPad. The
2417 	// coordinates inside of the rect it returns don't have the page scroll position
2418 	// factored out of it like the other platforms do. To get around this,
2419 	// we'll just calculate the top offset the old fashioned way until core has
2420 	// a chance to figure out how to handle this situation.
2421 	//
2422 	// TODO: We'll need to get rid of getOffsetTop() once a fix gets folded into core.
2423 
2424 	function getOffsetTop(ele)
2425 	{
2426 		var top = 0;
2427 		if (ele)
2428 		{
2429 			var op = ele.offsetParent, body = document.body;
2430 			top = ele.offsetTop;
2431 			while (ele && ele != body)
2432 			{
2433 				top += ele.scrollTop || 0;
2434 				if (ele == op)
2435 				{
2436 					top += op.offsetTop;
2437 					op = ele.offsetParent;
2438 				}
2439 				ele = ele.parentNode;
2440 			}
2441 		}
2442 		return top;
2443 	}
2444 
2445 	function setTop(el){
2446 		var fromTop = $(window).scrollTop(),
2447 			thisTop = getOffsetTop(el[0]), // el.offset().top returns the wrong value on iPad iOS 3.2.1, call our workaround instead.
2448 			thisCSStop = el.css('top') == 'auto' ? 0 : parseFloat(el.css('top')),
2449 			screenHeight = window.innerHeight,
2450 			thisHeight = el.outerHeight(),
2451 			useRelative = el.parents('.ui-page:not(.ui-page-fullscreen)').length,
2452 			relval;
2453 		if( el.is('.ui-header-fixed') ){
2454 			relval = fromTop - thisTop + thisCSStop;
2455 			if( relval < thisTop){ relval = 0; }
2456 			return el.css('top', ( useRelative ) ? relval : fromTop);
2457 		}
2458 		else{
2459 			//relval = -1 * (thisTop - (fromTop + screenHeight) + thisCSStop + thisHeight);
2460 			//if( relval > thisTop ){ relval = 0; }
2461 			relval = fromTop + screenHeight - thisHeight - (thisTop - thisCSStop);
2462 			return el.css('top', ( useRelative ) ? relval : fromTop + screenHeight - thisHeight );
2463 		}
2464 	}
2465 
2466 	//exposed methods
2467 	return {
2468 		show: function(immediately, page){
2469 			$.fixedToolbars.clearShowTimer();
2470 			currentstate = 'overlay';
2471 			var $ap = page ? $(page) : ($.mobile.activePage ? $.mobile.activePage : $(".ui-page-active"));
2472 			return $ap.children( toolbarSelector ).each(function(){
2473 				var el = $(this),
2474 					fromTop = $(window).scrollTop(),
2475 					thisTop = getOffsetTop(el[0]), // el.offset().top returns the wrong value on iPad iOS 3.2.1, call our workaround instead.
2476 					screenHeight = window.innerHeight,
2477 					thisHeight = el.outerHeight(),
2478 					alreadyVisible = (el.is('.ui-header-fixed') && fromTop <= thisTop + thisHeight) || (el.is('.ui-footer-fixed') && thisTop <= fromTop + screenHeight);	
2479 				
2480 				//add state class
2481 				el.addClass('ui-fixed-overlay').removeClass('ui-fixed-inline');	
2482 					
2483 				if( !alreadyVisible && !immediately ){
2484 					el.animationComplete(function(){
2485 						el.removeClass('in');
2486 					}).addClass('in');
2487 				}
2488 				setTop(el);
2489 			});	
2490 		},
2491 		hide: function(immediately){
2492 			currentstate = 'inline';
2493 			var $ap = $.mobile.activePage ? $.mobile.activePage : $(".ui-page-active");
2494 			return $ap.children( toolbarSelector ).each(function(){
2495 				var el = $(this);
2496 
2497 				var thisCSStop = el.css('top'); thisCSStop = thisCSStop == 'auto' ? 0 : parseFloat(thisCSStop);
2498 				
2499 				//add state class
2500 				el.addClass('ui-fixed-inline').removeClass('ui-fixed-overlay');
2501 				
2502 				if (thisCSStop < 0 || (el.is('.ui-header-fixed') && thisCSStop != 0))
2503 				{
2504 					if(immediately){
2505 						el.css('top',0);
2506 					}
2507 					else{
2508 						if( el.css('top') !== 'auto' && parseFloat(el.css('top')) !== 0 ){
2509 							var classes = 'out reverse';
2510 							el.animationComplete(function(){
2511 								el.removeClass(classes);
2512 								el.css('top',0);
2513 							}).addClass(classes);	
2514 						}
2515 					}
2516 				}
2517 			});
2518 		},
2519 		startShowTimer: function(){
2520 			$.fixedToolbars.clearShowTimer();
2521 			var args = $.makeArray(arguments);
2522 			delayTimer = setTimeout(function(){
2523 				delayTimer = undefined;
2524 				$.fixedToolbars.show.apply(null, args);
2525 			}, showDelay);
2526 		},
2527 		clearShowTimer: function() {
2528 			if (delayTimer) {
2529 				clearTimeout(delayTimer);
2530 			}
2531 			delayTimer = undefined;
2532 		},
2533 		toggle: function(from){
2534 			if(from){ currentstate = from; }
2535 			return (currentstate == 'overlay') ? $.fixedToolbars.hide() : $.fixedToolbars.show();
2536 		},
2537         setTouchToggleEnabled: function(enabled) {
2538             touchToggleEnabled = enabled;
2539         }
2540 	};
2541 })();
2542 
2543 })(jQuery);/*
2544 * jQuery Mobile Framework : "checkboxradio" plugin
2545 * Copyright (c) jQuery Project
2546 * Dual licensed under the MIT or GPL Version 2 licenses.
2547 * http://jquery.org/license
2548 */  
2549 (function($, undefined ) {
2550 $.widget( "mobile.checkboxradio", $.mobile.widget, {
2551 	options: {
2552 		theme: null
2553 	},
2554 	_create: function(){
2555 		var self = this,
2556 			input = this.element,
2557 			label = input.closest("form,fieldset,[data-role='page']").find("label[for='" + input.attr( "id" ) + "']"),
2558 			inputtype = input.attr( "type" ),
2559 			checkedicon = "ui-icon-" + inputtype + "-on",
2560 			uncheckedicon = "ui-icon-" + inputtype + "-off";
2561 
2562 		if ( inputtype != "checkbox" && inputtype != "radio" ) { return; }
2563 
2564 		// If there's no selected theme...
2565 		if( !this.options.theme ) {
2566 			this.options.theme = this.element.data( "theme" );
2567 		}
2568 
2569 		label
2570 			.buttonMarkup({
2571 				theme: this.options.theme,
2572 				icon: this.element.parents( "[data-type='horizontal']" ).length ? undefined : uncheckedicon,
2573 				shadow: false
2574 			});
2575 		
2576 		// wrap the input + label in a div 
2577 		input
2578 			.add( label )
2579 			.wrapAll( "<div class='ui-" + inputtype +"'></div>" );
2580 		
2581 		label.bind({
2582 			mouseover: function() {
2583 				if( $(this).parent().is('.ui-disabled') ){ return false; }
2584 			},
2585 			
2586 			"touchmove": function( event ){
2587 				var oe = event.originalEvent.touches[0];
2588 				if( label.data("movestart") ){
2589 					if( Math.abs( label.data("movestart")[0] - oe.pageX ) > 10 ||
2590 						Math.abs( abel.data("movestart")[1] - oe.pageY ) > 10 ){
2591 							label.data("moved", true);
2592 						}
2593 				}
2594 				else{
2595 					label.data("movestart", [ parseFloat( oe.pageX ), parseFloat( oe.pageY ) ]);
2596 				}
2597 			},
2598 			
2599 			"touchend mouseup": function( event ){
2600 				label.removeData("movestart");
2601 				if( label.data("etype") && label.data("etype") !== event.type || label.data("moved") ){
2602 					label.removeData("etype").removeData("moved");
2603 					if( label.data("moved") ){
2604 						label.removeData("moved");
2605 					}
2606 					return false;
2607 				}
2608 				label.data( "etype", event.type );
2609 				self._cacheVals();
2610 				input.attr( "checked", inputtype === "radio" && true || !input.is( ":checked" ) );
2611 				self._updateAll();
2612 				event.preventDefault();
2613 			},
2614 			
2615 			click: false
2616 			
2617 		});
2618 		
2619 		input
2620 			.bind({
2621 				mousedown: function(){
2622 					this._cacheVals();
2623 				},
2624 				
2625 				click: function(){
2626 					self._updateAll();
2627 				},
2628 
2629 				focus: function() { 
2630 					label.addClass( "ui-focus" ); 
2631 				},
2632 
2633 				blur: function() {
2634 					label.removeClass( "ui-focus" );
2635 				}
2636 			});
2637 			
2638 		this.refresh();
2639 		
2640 	},
2641 	
2642 	_cacheVals: function(){
2643 		this._getInputSet().each(function(){
2644 			$(this).data("cacheVal", $(this).is(":checked") );
2645 		});	
2646 	},
2647 		
2648 	//returns either a set of radios with the same name attribute, or a single checkbox
2649 	_getInputSet: function(){
2650 		return this.element.closest( "form,fieldset,[data-role='page']" )
2651 				.find( "input[name='"+ this.element.attr( "name" ) +"'][type='"+ this.element.attr( "type" ) +"']" );
2652 	},
2653 	
2654 	_updateAll: function(){
2655 		this._getInputSet().each(function(){
2656 			var dVal = $(this).data("cacheVal");
2657 			if( dVal && dVal !== $(this).is(":checked") || $(this).is( "[type='checkbox']" ) ){
2658 				$(this).trigger("change");
2659 			}
2660 		})
2661 		.checkboxradio( "refresh" );
2662 	},
2663 	
2664 	refresh: function( ){
2665 		var input = this.element,
2666 			label = input.closest("form,fieldset,[data-role='page']").find("label[for='" + input.attr( "id" ) + "']"),
2667 			inputtype = input.attr( "type" ),
2668 			icon = label.find( ".ui-icon" ),
2669 			checkedicon = "ui-icon-" + inputtype + "-on",
2670 			uncheckedicon = "ui-icon-" + inputtype + "-off";
2671 		
2672 		if ( input[0].checked ) {
2673 			label.addClass( "ui-btn-active" );
2674 			icon.addClass( checkedicon );
2675 			icon.removeClass( uncheckedicon );
2676 
2677 		} else {
2678 			label.removeClass( "ui-btn-active" ); 
2679 			icon.removeClass( checkedicon );
2680 			icon.addClass( uncheckedicon );
2681 		}
2682 		
2683 		if( input.is( ":disabled" ) ){
2684 			this.disable();
2685 		}
2686 		else {
2687 			this.enable();
2688 		}
2689 	},
2690 	
2691 	disable: function(){
2692 		this.element.attr("disabled",true).parent().addClass("ui-disabled");
2693 	},
2694 	
2695 	enable: function(){
2696 		this.element.attr("disabled",false).parent().removeClass("ui-disabled");
2697 	}
2698 });
2699 })( jQuery );
2700 /*
2701 * jQuery Mobile Framework : "textinput" plugin for text inputs, textareas
2702 * Copyright (c) jQuery Project
2703 * Dual licensed under the MIT or GPL Version 2 licenses.
2704 * http://jquery.org/license
2705 */
2706 (function($, undefined ) {
2707 $.widget( "mobile.textinput", $.mobile.widget, {
2708 	options: {
2709 		theme: null
2710 	},
2711 	_create: function(){
2712 		var input = this.element,
2713 			o = this.options,
2714 			theme = o.theme,
2715 			themeclass;
2716 			
2717 		if ( !theme ) {
2718 			var themedParent = this.element.closest("[class*='ui-bar-'],[class*='ui-body-']"); 
2719 				theme = themedParent.length ?
2720 					/ui-(bar|body)-([a-z])/.exec( themedParent.attr("class") )[2] :
2721 					"c";
2722 		}	
2723 		
2724 		themeclass = " ui-body-" + theme;
2725 		
2726 		$('label[for='+input.attr('id')+']').addClass('ui-input-text');
2727 		
2728 		input.addClass('ui-input-text ui-body-'+ o.theme);
2729 		
2730 		var focusedEl = input;
2731 		
2732 		//"search" input widget
2733 		if( input.is('[type="search"],[data-type="search"]') ){
2734 			focusedEl = input.wrap('<div class="ui-input-search ui-shadow-inset ui-btn-corner-all ui-btn-shadow ui-icon-searchfield'+ themeclass +'"></div>').parent();
2735 			var clearbtn = $('<a href="#" class="ui-input-clear" title="clear text">clear text</a>')
2736 				.tap(function( e ){
2737 					input.val('').focus();
2738 					input.trigger('change'); 
2739 					clearbtn.addClass('ui-input-clear-hidden');
2740 					e.preventDefault();
2741 				})
2742 				.appendTo(focusedEl)
2743 				.buttonMarkup({icon: 'delete', iconpos: 'notext', corners:true, shadow:true});
2744 			
2745 			function toggleClear(){
2746 				if(input.val() == ''){
2747 					clearbtn.addClass('ui-input-clear-hidden');
2748 				}
2749 				else{
2750 					clearbtn.removeClass('ui-input-clear-hidden');
2751 				}
2752 			}
2753 			
2754 			toggleClear();
2755 			input.keyup(toggleClear);	
2756 		}
2757 		else{
2758 			input.addClass('ui-corner-all ui-shadow-inset' + themeclass);
2759 		}
2760 				
2761 		input
2762 			.focus(function(){
2763 				focusedEl.addClass('ui-focus');
2764 			})
2765 			.blur(function(){
2766 				focusedEl.removeClass('ui-focus');
2767 			});	
2768 			
2769 		//autogrow
2770 		if ( input.is('textarea') ) {
2771 			var extraLineHeight = 15,
2772 				keyupTimeoutBuffer = 100,
2773 				keyup = function() {
2774 					var scrollHeight = input[0].scrollHeight,
2775 						clientHeight = input[0].clientHeight;
2776 					if ( clientHeight < scrollHeight ) {
2777 						input.css({ height: (scrollHeight + extraLineHeight) });
2778 					}
2779 				},
2780 				keyupTimeout;
2781 			input.keyup(function() {
2782 				clearTimeout( keyupTimeout );
2783 				keyupTimeout = setTimeout( keyup, keyupTimeoutBuffer );
2784 			});
2785 		}
2786 	},
2787 	
2788 	disable: function(){
2789 		( this.element.attr("disabled",true).is('[type="search"],[data-type="search"]') ? this.element.parent() : this.element ).addClass("ui-disabled");
2790 	},
2791 	
2792 	enable: function(){
2793 		( this.element.attr("disabled", false).is('[type="search"],[data-type="search"]') ? this.element.parent() : this.element ).removeClass("ui-disabled");
2794 	}
2795 });
2796 })( jQuery );
2797 /*
2798 * jQuery Mobile Framework : "selectmenu" plugin
2799 * Copyright (c) jQuery Project
2800 * Dual licensed under the MIT or GPL Version 2 licenses.
2801 * http://jquery.org/license
2802 */
2803 (function($, undefined ) {
2804 $.widget( "mobile.selectmenu", $.mobile.widget, {
2805 	options: {
2806 		theme: null,
2807 		disabled: false,
2808 		icon: 'arrow-d',
2809 		iconpos: 'right',
2810 		inline: null,
2811 		corners: true,
2812 		shadow: true,
2813 		iconshadow: true,
2814 		menuPageTheme: 'b',
2815 		overlayTheme: 'a',
2816 		hidePlaceholderMenuItems: true,
2817 		closeText: 'Close',
2818 		nativeMenu: false
2819 	},
2820 	_create: function(){
2821 
2822 		var self = this,
2823 
2824 			o = this.options,
2825 
2826 			select = this.element
2827 						.wrap( "<div class='ui-select'>" ),
2828 			
2829 			selectID = select.attr( "id" ),			
2830 			
2831 			label = $( "label[for="+ selectID +"]" ).addClass( "ui-select" ),
2832 
2833 			button = ( self.options.nativeMenu ? $( "<div/>" ) : $( "<a>", {
2834 					"href": "#",
2835 					"role": "button",
2836 					"id": buttonId,
2837 					"aria-haspopup": "true",
2838 					"aria-owns": menuId
2839 				}) )
2840 				.text( $( select[0].options.item(select[0].selectedIndex) ).text() )
2841 				.insertBefore( select )
2842 				.buttonMarkup({
2843 					theme: o.theme,
2844 					icon: o.icon,
2845 					iconpos: o.iconpos,
2846 					inline: o.inline,
2847 					corners: o.corners,
2848 					shadow: o.shadow,
2849 					iconshadow: o.iconshadow
2850 				}),
2851 			
2852 			//multi select or not
2853 			isMultiple = self.isMultiple = select[0].multiple;
2854 		
2855 		//Opera does not properly support opacity on select elements
2856 		//In Mini, it hides the element, but not its text
2857 		//On the desktop,it seems to do the opposite
2858 		//for these reasons, using the nativeMenu option results in a full native select in Opera
2859 		if( o.nativeMenu && window.opera && window.opera.version ){
2860 			select.addClass( "ui-select-nativeonly" );
2861 		}	
2862 			
2863 			//vars for non-native menus
2864 		if( !o.nativeMenu ){	
2865 			var options = select.find("option"),
2866 				
2867 				buttonId = selectID + "-button",
2868 	
2869 				menuId = selectID + "-menu",
2870 	
2871 				thisPage = select.closest( ".ui-page" ),
2872 				
2873 				//button theme
2874 				theme = /ui-btn-up-([a-z])/.exec( button.attr("class") )[1],
2875 	
2876 				menuPage = $( "<div data-role='dialog' data-theme='"+ o.menuPageTheme +"'>" +
2877 							"<div data-role='header'>" +
2878 								"<div class='ui-title'>" + label.text() + "</div>"+
2879 							"</div>"+
2880 							"<div data-role='content'></div>"+
2881 						"</div>" )
2882 						.appendTo( $.mobile.pageContainer )
2883 						.page(),
2884 	
2885 				menuPageContent = menuPage.find( ".ui-content" ),
2886 	
2887 				menuPageClose = menuPage.find( ".ui-header a" ),
2888 	
2889 				screen = $( "<div>", {"class": "ui-selectmenu-screen ui-screen-hidden"})
2890 							.appendTo( thisPage ),
2891 	
2892 				listbox = $( "<div>", { "class": "ui-selectmenu ui-selectmenu-hidden ui-overlay-shadow ui-corner-all pop ui-body-" + o.overlayTheme } )
2893 						.insertAfter(screen),
2894 	
2895 				list = $( "<ul>", {
2896 						"class": "ui-selectmenu-list",
2897 						"id": menuId,
2898 						"role": "listbox",
2899 						"aria-labelledby": buttonId,
2900 						"data-theme": theme
2901 					})
2902 					.appendTo( listbox ),
2903 	
2904 				header = $( "<div>", {
2905 						"class": "ui-header ui-bar-" + theme
2906 					})
2907 					.prependTo( listbox ),
2908 	
2909 				headerTitle = $( "<h1>", {
2910 						"class": "ui-title"
2911 					})
2912 					.appendTo( header ),
2913 	
2914 				headerClose = $( "<a>", {
2915 						"data-iconpos": "notext",
2916 						"data-icon": "delete",
2917 						"text": o.closeText,
2918 						"href": "#",
2919 						"class": "ui-btn-left"
2920 					})
2921 					.appendTo( header )
2922 					.buttonMarkup(),
2923 	
2924 				menuType;
2925 		} //end non native vars	
2926 
2927 		// add counter for multi selects
2928 		if( isMultiple ){
2929 			self.buttonCount = $('<span>')
2930 				.addClass( 'ui-li-count ui-btn-up-c ui-btn-corner-all' )
2931 				.hide()
2932 				.appendTo( button );
2933 		}
2934 
2935 		//disable if specified
2936 		if( o.disabled ){ this.disable(); }
2937 
2938 		//events on native select
2939 		select
2940 			.change(function(){
2941 				self.refresh();
2942 			});
2943 			
2944 		//expose to other methods
2945 		$.extend(self, {
2946 			select: select,
2947 			optionElems: options,
2948 			selectID: selectID,
2949 			label: label,
2950 			buttonId:buttonId,
2951 			menuId:menuId,
2952 			thisPage:thisPage,
2953 			button:button,
2954 			menuPage:menuPage,
2955 			menuPageContent:menuPageContent,
2956 			screen:screen,
2957 			listbox:listbox,
2958 			list:list,
2959 			menuType:menuType,
2960 			header:header,
2961 			headerClose:headerClose,
2962 			headerTitle:headerTitle,
2963 			placeholder: ''
2964 		});	
2965 
2966 		//support for using the native select menu with a custom button
2967 		if( o.nativeMenu ){
2968 
2969 			select
2970 				.appendTo(button)
2971 				.bind( "touchstart mousedown", function( e ){
2972 					//add active class to button
2973 					button.addClass( $.mobile.activeBtnClass );
2974 				})
2975 				.bind( "focus mouseover", function(){
2976 					button.trigger( "mouseover" );
2977 				})
2978 				.bind( "touchmove", function(){
2979 					//remove active class on scroll/touchmove
2980 					button.removeClass( $.mobile.activeBtnClass );
2981 				})
2982 				.bind( "change blur mouseout", function(){
2983 					button
2984 						.trigger( "mouseout" )
2985 						.removeClass( $.mobile.activeBtnClass );
2986 				});
2987 
2988 			button.attr( "tabindex", "-1" );
2989 		} else {
2990 		
2991 			//create list from select, update state
2992 			self.refresh();
2993 
2994 			select
2995 				.attr( "tabindex", "-1" )
2996 				.focus(function(){
2997 					$(this).blur();
2998 					button.focus();
2999 				});
3000 
3001 			//button events
3002 			button
3003 				.bind( "touchstart" , function( event ){
3004 					//set startTouches to cached copy of
3005 					$( this ).data( "startTouches", $.extend({}, event.originalEvent.touches[ 0 ]) );
3006 				})
3007 				.bind( $.support.touch ? "touchend" : "mouseup" , function( event ){
3008 					//if it's a scroll, don't open
3009 					if( $( this ).data( "moved" ) ){
3010 						$( this ).removeData( "moved" );
3011 					} else {
3012 						self.open();
3013 					}
3014 					event.preventDefault();
3015 				})
3016 				.bind( "touchmove", function( event ){
3017 					//if touch moved enough, set data moved and don't open menu
3018 					var thisTouches = event.originalEvent.touches[ 0 ],
3019 					startTouches = $( this ).data( "startTouches" ),
3020 					deltaX = Math.abs(thisTouches.pageX - startTouches.pageX),
3021 					deltaY = Math.abs(thisTouches.pageY - startTouches.pageY);
3022 
3023 					if( deltaX > 10 || deltaY > 10 ){
3024 						$( this ).data( "moved", true );
3025 					}
3026 				});
3027 		
3028 	
3029 			//events for list items
3030 			list.delegate("li:not(.ui-disabled, .ui-li-divider)", "click", function(event){
3031 				// clicking on the list item fires click on the link in listview.js.
3032 				// to prevent this handler from firing twice if the link isn't clicked on,
3033 				// short circuit unless the target is the link
3034 				if( !$(event.target).is("a") ){ return; }
3035 	
3036 				// index of option tag to be selected
3037 				var newIndex = list.find( "li:not(.ui-li-divider)" ).index( this ),
3038 					option = self.optionElems.eq( newIndex )[0];
3039 	
3040 				// toggle selected status on the tag for multi selects
3041 				option.selected = isMultiple ? !option.selected : true;
3042 	
3043 				// toggle checkbox class for multiple selects
3044 				if( isMultiple ){
3045 					$(this)
3046 						.find('.ui-icon')
3047 						.toggleClass('ui-icon-checkbox-on', option.selected)
3048 						.toggleClass('ui-icon-checkbox-off', !option.selected);
3049 				}
3050 	
3051 				// trigger change
3052 				select.trigger( "change" );
3053 	
3054 				//hide custom select for single selects only
3055 				if( !isMultiple ){
3056 					self.close();
3057 				}
3058 	
3059 				event.preventDefault();
3060 			});
3061 	
3062 			//events on "screen" overlay + close button
3063 			screen
3064 				.add( headerClose )
3065 				.add( menuPageClose )
3066 				.bind("click", function(event){
3067 					self.close();
3068 					event.preventDefault();
3069 	
3070 					// if the dialog's close icon was clicked, prevent the dialog's close
3071 					// handler from firing. selectmenu's should take precedence
3072 					if( $.contains(menuPageClose[0], event.target) ){
3073 						event.stopImmediatePropagation();
3074 					}
3075 				});
3076 		}	
3077 		
3078 		
3079 	},
3080 
3081 	_buildList: function(){
3082 		var self = this,
3083 			o = this.options,
3084 			placeholder = this.placeholder,
3085 			optgroups = [],
3086 			lis = [],
3087 			dataIcon = self.isMultiple ? "checkbox-off" : "false";
3088 
3089 		self.list.empty().filter('.ui-listview').listview('destroy');
3090 
3091 		//populate menu with options from select element
3092 		self.select.find( "option" ).each(function( i ){
3093 			var $this = $(this),
3094 				$parent = $this.parent(),
3095 				text = $this.text(),
3096 				anchor = "<a href='#'>"+ text +"</a>",
3097 				classes = [],
3098 				extraAttrs = [];
3099 
3100 			// are we inside an optgroup?
3101 			if( $parent.is("optgroup") ){
3102 				var optLabel = $parent.attr("label");
3103 
3104 				// has this optgroup already been built yet?
3105 				if( $.inArray(optLabel, optgroups) === -1 ){
3106 					lis.push( "<li data-role='list-divider'>"+ optLabel +"</li>" );
3107 					optgroups.push( optLabel );
3108 				}
3109 			}
3110 			
3111 			//find placeholder text
3112 			if( !this.getAttribute('value') || text.length == 0 || $this.data('placeholder') ){
3113 				if( o.hidePlaceholderMenuItems ){
3114 					classes.push( "ui-selectmenu-placeholder" );
3115 				}
3116 				placeholder = self.placeholder = text;
3117 			}
3118 
3119 			// support disabled option tags
3120 			if( this.disabled ){
3121 				classes.push( "ui-disabled" );
3122 				extraAttrs.push( "aria-disabled='true'" );
3123 			}
3124 
3125 			lis.push( "<li data-icon='"+ dataIcon +"' class='"+ classes.join(" ") + "' " + extraAttrs.join(" ") +">"+ anchor +"</li>" )
3126 		});
3127 		
3128 		self.list.html( lis.join(" ") );
3129 
3130 		// hide header close link for single selects
3131 		if( !this.isMultiple ){
3132 			this.headerClose.hide();
3133 		}
3134 
3135 		// hide header if it's not a multiselect and there's no placeholder
3136 		if( !this.isMultiple && !placeholder.length ){
3137 			this.header.hide();
3138 		} else {
3139 			this.headerTitle.text( this.placeholder );
3140 		}
3141 
3142 		//now populated, create listview
3143 		self.list.listview();
3144 	},
3145 
3146 	refresh: function( forceRebuild ){
3147 		var self = this,
3148 			select = this.element,
3149 			isMultiple = this.isMultiple,
3150 			options = this.optionElems = select.find("option"),
3151 			selected = options.filter(":selected"),
3152 
3153 			// return an array of all selected index's
3154 			indicies = selected.map(function(){
3155 				return options.index( this );
3156 			}).get();
3157 
3158 		if( !self.options.nativeMenu && ( forceRebuild || select[0].options.length > self.list.find('li').length )){
3159 			self._buildList();
3160 		}
3161 
3162 		self.button
3163 			.find( ".ui-btn-text" )
3164 			.text(function(){
3165 				if( !isMultiple ){
3166 					return selected.text();
3167 				}
3168 
3169 				return selected.length ?
3170 					selected.map(function(){ return $(this).text(); }).get().join(', ') :
3171 					self.placeholder;
3172 			});
3173 
3174 		// multiple count inside button
3175 		if( isMultiple ){
3176 			self.buttonCount[ selected.length > 1 ? 'show' : 'hide' ]().text( selected.length );
3177 		}
3178 		
3179 		if( !self.options.nativeMenu ){
3180 			self.list
3181 				.find( 'li:not(.ui-li-divider)' )
3182 				.removeClass( $.mobile.activeBtnClass )
3183 				.attr( 'aria-selected', false )
3184 				.each(function( i ){
3185 					if( $.inArray(i, indicies) > -1 ){
3186 						var item = $(this).addClass( $.mobile.activeBtnClass );
3187 	
3188 						// aria selected attr
3189 						item.find( 'a' ).attr( 'aria-selected', true );
3190 	
3191 						// multiple selects: add the "on" checkbox state to the icon
3192 						if( isMultiple ){
3193 							item.find('.ui-icon').removeClass('ui-icon-checkbox-off').addClass('ui-icon-checkbox-on');
3194 						}
3195 					}
3196 				});
3197 		}	
3198 	},
3199 
3200 	open: function(){
3201 		if( this.options.disabled || this.options.nativeMenu ){ return; }
3202 
3203 		var self = this,
3204 			menuHeight = self.list.outerHeight(),
3205 			menuWidth = self.list.outerWidth(),
3206 			scrollTop = $(window).scrollTop(),
3207 			btnOffset = self.button.offset().top,
3208 			screenHeight = window.innerHeight,
3209 			screenWidth = window.innerWidth,
3210 			dialogUsed = self.list.parents('.ui-dialog').length;
3211 
3212 		//add active class to button
3213 		self.button.addClass( $.mobile.activeBtnClass );
3214 
3215 		function focusMenuItem(){
3216 			self.list.find( ".ui-btn-active" ).focus();
3217 		}
3218 
3219 		// NOTE addresses issue with firefox outerHeight when the parent dialog
3220 		//      is display: none. Upstream?
3221 		if( dialogUsed || menuHeight > screenHeight - 80 || !$.support.scrollTop ){
3222 
3223 			//for webos (set lastscroll using button offset)
3224 			if( scrollTop == 0 && btnOffset > screenHeight ){
3225 				self.thisPage.one('pagehide',function(){
3226 					$(this).data('lastScroll', btnOffset);
3227 				});
3228 			}
3229 
3230 			self.menuPage.one('pageshow', function() {
3231 				// silentScroll() is called whenever a page is shown to restore
3232 				// any previous scroll position the page may have had. We need to
3233 				// wait for the "silentscroll" event before setting focus to avoid
3234 				// the browser's "feature" which offsets rendering to make sure
3235 				// whatever has focus is in view.
3236 				$(window).one("silentscroll", function(){ focusMenuItem(); });
3237 			});
3238 
3239 			self.menuType = "page";
3240 			self.menuPageContent.append( self.list );
3241 			$.mobile.changePage(self.menuPage, 'pop', false, true);
3242 		}
3243 		else {
3244 			self.menuType = "overlay";
3245 
3246 			self.screen
3247 				.height( $(document).height() )
3248 				.removeClass('ui-screen-hidden');
3249 
3250 			//try and center the overlay over the button
3251 			var roomtop = btnOffset - scrollTop,
3252 				roombot = scrollTop + screenHeight - btnOffset,
3253 				halfheight = menuHeight / 2,
3254 				newtop,newleft;
3255 				
3256 				if( roomtop > menuHeight / 2 && roombot > menuHeight / 2 ){
3257 					newtop = btnOffset + ( self.button.outerHeight() / 2 ) - halfheight;
3258 				}
3259 				else{
3260 					//30px tolerance off the edges
3261 					newtop = roomtop > roombot ? scrollTop + screenHeight - menuHeight - 30 : scrollTop + 30;
3262 				}
3263 				
3264 				newleft = self.button.offset().left + self.button.outerWidth() / 2 - menuWidth / 2;
3265 				
3266 
3267 			self.listbox
3268 				.append( self.list )
3269 				.removeClass( "ui-selectmenu-hidden" )
3270 				.css({
3271 					top: newtop,
3272 					left: newleft
3273 				})
3274 				.addClass("in");
3275 
3276 			focusMenuItem();
3277 		}
3278 
3279 		// wait before the dialog can be closed
3280 		setTimeout(function(){
3281 		 	self.isOpen = true;
3282 		}, 400);
3283 	},
3284 
3285 	close: function(){
3286 		if( this.options.disabled || !this.isOpen || this.options.nativeMenu ){ return; }
3287 		var self = this;
3288 
3289 		function focusButton(){
3290 			setTimeout(function(){
3291 				self.button.focus();
3292 
3293 				//remove active class from button
3294 				self.button.removeClass( $.mobile.activeBtnClass );
3295 			}, 40);
3296 
3297 			self.listbox.removeAttr('style').append( self.list );
3298 		}
3299 
3300 		if(self.menuType == "page"){
3301 			$.mobile.changePage([self.menuPage,self.thisPage], 'pop', true, false);
3302 			self.menuPage.one("pagehide", focusButton);
3303 		}
3304 		else{
3305 			self.screen.addClass( "ui-screen-hidden" );
3306 			self.listbox.addClass( "ui-selectmenu-hidden" ).removeAttr( "style" ).removeClass("in");
3307 			focusButton();
3308 		}
3309 
3310 		// allow the dialog to be closed again
3311 		this.isOpen = false;
3312 	},
3313 
3314 	disable: function(){
3315 		this.element.attr("disabled",true);
3316 		this.button.addClass('ui-disabled').attr("aria-disabled", true);
3317 		return this._setOption( "disabled", true );
3318 	},
3319 
3320 	enable: function(){
3321 		this.element.attr("disabled",false);
3322 		this.button.removeClass('ui-disabled').attr("aria-disabled", false);
3323 		return this._setOption( "disabled", false );
3324 	}
3325 });
3326 })( jQuery );
3327 
3328 /*
3329 * jQuery Mobile Framework : plugin for making button-like links
3330 * Copyright (c) jQuery Project
3331 * Dual licensed under the MIT or GPL Version 2 licenses.
3332 * http://jquery.org/license
3333 */
3334 (function($, undefined ) {
3335 
3336 $.fn.buttonMarkup = function( options ){
3337 	return this.each( function() {
3338 		var el = $( this ),
3339 		    o = $.extend( {}, $.fn.buttonMarkup.defaults, el.data(), options),
3340 
3341 			// Classes Defined
3342 			buttonClass,
3343 			innerClass = "ui-btn-inner",
3344 			iconClass;
3345 
3346 		if ( attachEvents ) {
3347 			attachEvents();
3348 		}
3349 
3350 		// if not, try to find closest theme container
3351 		if ( !o.theme ) {
3352 			var themedParent = el.closest("[class*='ui-bar-'],[class*='ui-body-']");
3353 			o.theme = themedParent.length ?
3354 				/ui-(bar|body)-([a-z])/.exec( themedParent.attr("class") )[2] :
3355 				"c";
3356 		}
3357 
3358 		buttonClass = "ui-btn ui-btn-up-" + o.theme;
3359 
3360 		if ( o.inline ) {
3361 			buttonClass += " ui-btn-inline";
3362 		}
3363 
3364 		if ( o.icon ) {
3365 			o.icon = "ui-icon-" + o.icon;
3366 			o.iconpos = o.iconpos || "left";
3367 
3368 			iconClass = "ui-icon " + o.icon;
3369 
3370 			if ( o.shadow ) {
3371 				iconClass += " ui-icon-shadow";
3372 			}
3373 		}
3374 
3375 		if ( o.iconpos ) {
3376 			buttonClass += " ui-btn-icon-" + o.iconpos;
3377 
3378 			if ( o.iconpos == "notext" && !el.attr("title") ) {
3379 				el.attr( "title", el.text() );
3380 			}
3381 		}
3382 
3383 		if ( o.corners ) {
3384 			buttonClass += " ui-btn-corner-all";
3385 			innerClass += " ui-btn-corner-all";
3386 		}
3387 
3388 		if ( o.shadow ) {
3389 			buttonClass += " ui-shadow";
3390 		}
3391 
3392 		el
3393 			.attr( "data-theme", o.theme )
3394 			.addClass( buttonClass );
3395 
3396 		var wrap = ("<D class='" + innerClass + "'><D class='ui-btn-text'></D>" +
3397 			( o.icon ? "<span class='" + iconClass + "'></span>" : "" ) +
3398 			"</D>").replace(/D/g, o.wrapperEls);
3399 
3400 		el.wrapInner( wrap );
3401 	});
3402 };
3403 
3404 $.fn.buttonMarkup.defaults = {
3405 	corners: true,
3406 	shadow: true,
3407 	iconshadow: true,
3408 	wrapperEls: "span"
3409 };
3410 
3411 var attachEvents = function() {
3412 	$(".ui-btn:not(.ui-disabled)").live({
3413 		"touchstart mousedown": function() {
3414 			var theme = $(this).attr( "data-theme" );
3415 			$(this).removeClass( "ui-btn-up-" + theme ).addClass( "ui-btn-down-" + theme );
3416 		},
3417 		"touchmove touchend mouseup": function() {
3418 			var theme = $(this).attr( "data-theme" );
3419 			$(this).removeClass( "ui-btn-down-" + theme ).addClass( "ui-btn-up-" + theme );
3420 		},
3421 		"mouseover focus": function() {
3422 			var theme = $(this).attr( "data-theme" );
3423 			$(this).removeClass( "ui-btn-up-" + theme ).addClass( "ui-btn-hover-" + theme );
3424 		},
3425 		"mouseout blur": function() {
3426 			var theme = $(this).attr( "data-theme" );
3427 			$(this).removeClass( "ui-btn-hover-" + theme ).addClass( "ui-btn-up-" + theme );
3428 		}
3429 	});
3430 
3431 	attachEvents = null;
3432 };
3433 
3434 })(jQuery);
3435 /*
3436 * jQuery Mobile Framework : "button" plugin - links that proxy to native input/buttons
3437 * Copyright (c) jQuery Project
3438 * Dual licensed under the MIT or GPL Version 2 licenses.
3439 * http://jquery.org/license
3440 */ 
3441 (function($, undefined ) {
3442 $.widget( "mobile.button", $.mobile.widget, {
3443 	options: {
3444 		theme: null, 
3445 		icon: null,
3446 		iconpos: null,
3447 		inline: null,
3448 		corners: true,
3449 		shadow: true,
3450 		iconshadow: true
3451 	},
3452 	_create: function(){
3453 		var $el = this.element,
3454 			o = this.options;
3455 		
3456 		//add ARIA role
3457 		this.button = $( "<div></div>" )
3458 			.text( $el.text() || $el.val() )
3459 			.buttonMarkup({
3460 				theme: o.theme, 
3461 				icon: o.icon,
3462 				iconpos: o.iconpos,
3463 				inline: o.inline,
3464 				corners: o.corners,
3465 				shadow: o.shadow,
3466 				iconshadow: o.iconshadow
3467 			})
3468 			.insertBefore( $el )
3469 			.append( $el.addClass('ui-btn-hidden') );
3470 		
3471 		//add hidden input during submit
3472 		if( $el.attr('type') !== 'reset' ){
3473 			$el.click(function(){
3474 				var $buttonPlaceholder = $("<input>", 
3475 						{type: "hidden", name: $el.attr("name"), value: $el.attr("value")})
3476 						.insertBefore($el);
3477 						
3478 				//bind to doc to remove after submit handling	
3479 				$(document).submit(function(){
3480 					 $buttonPlaceholder.remove();
3481 				});
3482 			});
3483 		}
3484 			
3485 	},
3486 
3487 	enable: function(){
3488 		this.element.attr("disabled", false);
3489 		this.button.removeClass("ui-disabled").attr("aria-disabled", false);
3490 		return this._setOption("disabled", false);
3491 	},
3492 
3493 	disable: function(){
3494 		this.element.attr("disabled", true);
3495 		this.button.addClass("ui-disabled").attr("aria-disabled", true);
3496 		return this._setOption("disabled", true);
3497 	}
3498 });
3499 })( jQuery );/*
3500 * jQuery Mobile Framework : "slider" plugin
3501 * Copyright (c) jQuery Project
3502 * Dual licensed under the MIT or GPL Version 2 licenses.
3503 * http://jquery.org/license
3504 */
3505 (function($, undefined ) {
3506 $.widget( "mobile.slider", $.mobile.widget, {
3507 	options: {
3508 		theme: null,
3509 		trackTheme: null,
3510 		disabled: false
3511 	},
3512 	_create: function(){
3513 		var self = this,
3514 
3515 			control = this.element,
3516 
3517 			parentTheme = control.parents('[class*=ui-bar-],[class*=ui-body-]').eq(0),
3518 
3519 			parentTheme = parentTheme.length ? parentTheme.attr('class').match(/ui-(bar|body)-([a-z])/)[2] : 'c',
3520 
3521 			theme = this.options.theme ? this.options.theme : parentTheme,
3522 
3523 			trackTheme = this.options.trackTheme ? this.options.trackTheme : parentTheme,
3524 
3525 			cType = control[0].nodeName.toLowerCase(),
3526 			selectClass = (cType == 'select') ? 'ui-slider-switch' : '',
3527 			controlID = control.attr('id'),
3528 			labelID = controlID + '-label',
3529 			label = $('[for='+ controlID +']').attr('id',labelID),
3530 			val = function(){
3531 				return (cType == 'input') ? parseFloat(control.val()) : control[0].selectedIndex;
3532 			},
3533 			min = (cType == 'input') ? parseFloat(control.attr('min')) : 0,
3534 			max = (cType == 'input') ? parseFloat(control.attr('max')) : control.find('option').length-1,
3535 			step = window.parseFloat(control.attr('step') || 1),
3536 			slider = $('<div class="ui-slider '+ selectClass +' ui-btn-down-'+ trackTheme+' ui-btn-corner-all" role="application"></div>'),
3537 			handle = $('<a href="#" class="ui-slider-handle"></a>')
3538 				.appendTo(slider)
3539 				.buttonMarkup({corners: true, theme: theme, shadow: true})
3540 				.attr({
3541 					'role': 'slider',
3542 					'aria-valuemin': min,
3543 					'aria-valuemax': max,
3544 					'aria-valuenow': val(),
3545 					'aria-valuetext': val(),
3546 					'title': val(),
3547 					'aria-labelledby': labelID
3548 				});
3549 
3550 		$.extend(this, {
3551 			slider: slider,
3552 			handle: handle,
3553 			dragging: false,
3554 			beforeStart: null
3555 		});
3556 
3557 		if(cType == 'select'){
3558 			slider.wrapInner('<div class="ui-slider-inneroffset"></div>');
3559 			var options = control.find('option');
3560 
3561 			control.find('option').each(function(i){
3562 				var side = (i==0) ?'b':'a',
3563 					corners = (i==0) ? 'right' :'left',
3564 					theme = (i==0) ? ' ui-btn-down-' + trackTheme :' ui-btn-active';
3565 				$('<div class="ui-slider-labelbg ui-slider-labelbg-'+ side + theme +' ui-btn-corner-'+ corners+'"></div>').prependTo(slider);
3566 				$('<span class="ui-slider-label ui-slider-label-'+ side + theme +' ui-btn-corner-'+ corners+'" role="img">'+$(this).text()+'</span>').prependTo(handle);
3567 			});
3568 
3569 		}
3570 
3571 		label.addClass('ui-slider');
3572 
3573 		// monitor the input for updated values
3574 		control
3575 			.addClass((cType == 'input') ? 'ui-slider-input' : 'ui-slider-switch')
3576 			.change(function(){
3577 				self.refresh( val(), true );
3578 			})
3579 			.keyup(function(){ // necessary?
3580 				self.refresh( val(), true, true );
3581 			})
3582 			.blur(function(){
3583 				self.refresh( val(), true );
3584 			});
3585 
3586 		// prevent screen drag when slider activated
3587 		$(document).bind( "touchmove mousemove", function(event){
3588 			if ( self.dragging ) {
3589 				self.refresh( event );
3590 				return false;
3591 			}
3592 		});
3593 
3594 		slider
3595 			.bind( "touchstart mousedown", function(event){
3596 				self.dragging = true;
3597 				if ( cType === "select" ) {
3598 					self.beforeStart = control[0].selectedIndex;
3599 				}
3600 				self.refresh( event );
3601 				return false;
3602 			});
3603 
3604 		slider
3605 			.add(document)
3606 			.bind( "touchend mouseup", function(){
3607 				if ( self.dragging ) {
3608 					self.dragging = false;
3609 					if ( cType === "select" ) {
3610 						if ( self.beforeStart === control[0].selectedIndex ) {
3611 							//tap occurred, but value didn't change. flip it!
3612 							self.refresh( self.beforeStart === 0 ? 1 : 0 );
3613 						}
3614 						var curval = val();
3615 						var snapped = Math.round( curval / (max - min) * 100 );
3616 						handle
3617 							.addClass("ui-slider-handle-snapping")
3618 							.css("left", snapped + "%")
3619 							.animationComplete(function(){
3620 								handle.removeClass("ui-slider-handle-snapping");
3621 							});
3622 					}
3623 					return false;
3624 				}
3625 			});
3626 
3627 		slider.insertAfter(control);
3628 
3629 		// NOTE force focus on handle
3630 		this.handle
3631 			.bind( "touchstart mousedown", function(){
3632 				$(this).focus();
3633 			});
3634 
3635 		this.handle
3636 			.bind( "keydown", function( event ) {
3637 				var index = val();
3638 
3639 				if ( self.options.disabled ) {
3640 					return;
3641 				}
3642 
3643 				// In all cases prevent the default and mark the handle as active
3644 				switch ( event.keyCode ) {
3645 				 case $.mobile.keyCode.HOME:
3646 				 case $.mobile.keyCode.END:
3647 				 case $.mobile.keyCode.PAGE_UP:
3648 				 case $.mobile.keyCode.PAGE_DOWN:
3649 				 case $.mobile.keyCode.UP:
3650 				 case $.mobile.keyCode.RIGHT:
3651 				 case $.mobile.keyCode.DOWN:
3652 				 case $.mobile.keyCode.LEFT:
3653 					event.preventDefault();
3654 
3655 					if ( !self._keySliding ) {
3656 						self._keySliding = true;
3657 						$( this ).addClass( "ui-state-active" );
3658 					}
3659 					break;
3660 				}
3661 
3662 				// move the slider according to the keypress
3663 				switch ( event.keyCode ) {
3664 				 case $.mobile.keyCode.HOME:
3665 					self.refresh(min);
3666 					break;
3667 				 case $.mobile.keyCode.END:
3668 					self.refresh(max);
3669 					break;
3670 				 case $.mobile.keyCode.PAGE_UP:
3671 				 case $.mobile.keyCode.UP:
3672 				 case $.mobile.keyCode.RIGHT:
3673 					self.refresh(index + step);
3674 					break;
3675 				 case $.mobile.keyCode.PAGE_DOWN:
3676 				 case $.mobile.keyCode.DOWN:
3677 				 case $.mobile.keyCode.LEFT:
3678 					self.refresh(index - step);
3679 					break;
3680 				}
3681 			}) // remove active mark
3682 			.keyup(function( event ) {
3683 				if ( self._keySliding ) {
3684 					self._keySliding = false;
3685 					$( this ).removeClass( "ui-state-active" );
3686 				}
3687 			});
3688 
3689 		this.refresh();
3690 	},
3691 
3692 	refresh: function(val, isfromControl, preventInputUpdate){
3693 		if ( this.options.disabled ) { return; }
3694 
3695 		var control = this.element, percent,
3696 			cType = control[0].nodeName.toLowerCase(),
3697 			min = (cType === "input") ? parseFloat(control.attr("min")) : 0,
3698 			max = (cType === "input") ? parseFloat(control.attr("max")) : control.find("option").length - 1;
3699 
3700 		if ( typeof val === "object" ) {
3701 			var data = val.originalEvent.touches ? val.originalEvent.touches[ 0 ] : val,
3702 				// a slight tolerance helped get to the ends of the slider
3703 				tol = 8;
3704 			if ( !this.dragging
3705 					|| data.pageX < this.slider.offset().left - tol
3706 					|| data.pageX > this.slider.offset().left + this.slider.width() + tol ) {
3707 				return;
3708 			}
3709 			percent = Math.round( ((data.pageX - this.slider.offset().left) / this.slider.width() ) * 100 );
3710 		} else {
3711 			if ( val == null ) {
3712 				val = (cType === "input") ? parseFloat(control.val()) : control[0].selectedIndex;
3713 			}
3714 			percent = (parseFloat(val) - min) / (max - min) * 100;
3715 		}
3716 
3717 		if ( isNaN(percent) ) { return; }
3718 		if ( percent < 0 ) { percent = 0; }
3719 		if ( percent > 100 ) { percent = 100; }
3720 
3721 		var newval = Math.round( (percent / 100) * (max - min) ) + min;
3722 		if ( newval < min ) { newval = min; }
3723 		if ( newval > max ) { newval = max; }
3724 
3725 		//flip the stack of the bg colors
3726 		if ( percent > 60 && cType === "select" ) {
3727 
3728 		}
3729 		this.handle.css("left", percent + "%");
3730 		this.handle.attr({
3731 				"aria-valuenow": (cType === "input") ? newval : control.find("option").eq(newval).attr("value"),
3732 				"aria-valuetext": (cType === "input") ? newval : control.find("option").eq(newval).text(),
3733 				title: newval
3734 			});
3735 
3736 		// add/remove classes for flip toggle switch
3737 		if ( cType === "select" ) {
3738 			if ( newval === 0 ) {
3739 				this.slider.addClass("ui-slider-switch-a")
3740 					.removeClass("ui-slider-switch-b");
3741 			} else {
3742 				this.slider.addClass("ui-slider-switch-b")
3743 					.removeClass("ui-slider-switch-a");
3744 			}
3745 		}
3746 
3747 		if(!preventInputUpdate){
3748 			// update control's value
3749 			if ( cType === "input" ) {
3750 				control.val(newval);
3751 			} else {
3752 				control[ 0 ].selectedIndex = newval;
3753 			}
3754 			if (!isfromControl) { control.trigger("change"); }
3755 		}
3756 	},
3757 
3758 	enable: function(){
3759 		this.element.attr("disabled", false);
3760 		this.slider.removeClass("ui-disabled").attr("aria-disabled", false);
3761 		return this._setOption("disabled", false);
3762 	},
3763 
3764 	disable: function(){
3765 		this.element.attr("disabled", true);
3766 		this.slider.addClass("ui-disabled").attr("aria-disabled", true);
3767 		return this._setOption("disabled", true);
3768 	}
3769 });
3770 })( jQuery );
3771 
3772 /*
3773 * jQuery Mobile Framework : "collapsible" plugin
3774 * Copyright (c) jQuery Project
3775 * Dual licensed under the MIT or GPL Version 2 licenses.
3776 * http://jquery.org/license
3777 */ 
3778 (function($, undefined ) {
3779 $.widget( "mobile.collapsible", $.mobile.widget, {
3780 	options: {
3781 		expandCueText: ' click to expand contents',
3782 		collapseCueText: ' click to collapse contents',
3783 		collapsed: false,
3784 		heading: '>:header,>legend',
3785 		theme: null,
3786 		iconTheme: 'd'
3787 	},
3788 	_create: function(){
3789 
3790 		var $el = this.element,
3791 			o = this.options,
3792 			collapsibleContain = $el.addClass('ui-collapsible-contain'),
3793 			collapsibleHeading = $el.find(o.heading).eq(0),
3794 			collapsibleContent = collapsibleContain.wrapInner('<div class="ui-collapsible-content"></div>').find('.ui-collapsible-content'),
3795 			collapsibleParent = $el.closest('[data-role="collapsible-set"]').addClass('ui-collapsible-set');				
3796 		
3797 		//replace collapsibleHeading if it's a legend	
3798 		if(collapsibleHeading.is('legend')){
3799 			collapsibleHeading = $('<div role="heading">'+ collapsibleHeading.html() +'</div>').insertBefore(collapsibleHeading);
3800 			collapsibleHeading.next().remove();
3801 		}	
3802 		
3803 		//drop heading in before content
3804 		collapsibleHeading.insertBefore(collapsibleContent);
3805 		
3806 		//modify markup & attributes
3807 		collapsibleHeading.addClass('ui-collapsible-heading')
3808 			.append('<span class="ui-collapsible-heading-status"></span>')
3809 			.wrapInner('<a href="#" class="ui-collapsible-heading-toggle"></a>')
3810 			.find('a:eq(0)')
3811 			.buttonMarkup({
3812 				shadow: !!!collapsibleParent.length,
3813 				corners:false,
3814 				iconPos: 'left',
3815 				icon: 'plus',
3816 				theme: o.theme
3817 			})
3818 			.find('.ui-icon')
3819 			.removeAttr('class')
3820 			.buttonMarkup({
3821 				shadow: true,
3822 				corners:true,
3823 				iconPos: 'notext',
3824 				icon: 'plus',
3825 				theme: o.iconTheme
3826 			});
3827 			
3828 			if( !collapsibleParent.length ){
3829 				collapsibleHeading
3830 					.find('a:eq(0)')	
3831 					.addClass('ui-corner-all')
3832 						.find('.ui-btn-inner')
3833 						.addClass('ui-corner-all');
3834 			}
3835 			else {
3836 				if( collapsibleContain.data('collapsible-last') ){
3837 					collapsibleHeading
3838 						.find('a:eq(0), .ui-btn-inner')	
3839 							.addClass('ui-corner-bottom');
3840 				}					
3841 			}
3842 			
3843 		
3844 		//events
3845 		collapsibleContain	
3846 			.bind('collapse', function(event){
3847 				if( !event.isDefaultPrevented() ){
3848 					event.preventDefault();
3849 					collapsibleHeading
3850 						.addClass('ui-collapsible-heading-collapsed')
3851 						.find('.ui-collapsible-heading-status').text(o.expandCueText);
3852 					
3853 					collapsibleHeading.find('.ui-icon').removeClass('ui-icon-minus').addClass('ui-icon-plus');	
3854 					collapsibleContent.addClass('ui-collapsible-content-collapsed').attr('aria-hidden',true);
3855 					
3856 					if( collapsibleContain.data('collapsible-last') ){
3857 						collapsibleHeading
3858 							.find('a:eq(0), .ui-btn-inner')
3859 							.addClass('ui-corner-bottom');
3860 					}
3861 				}						
3862 				
3863 			})
3864 			.bind('expand', function(event){
3865 				if( !event.isDefaultPrevented() ){
3866 					event.preventDefault();
3867 					collapsibleHeading
3868 						.removeClass('ui-collapsible-heading-collapsed')
3869 						.find('.ui-collapsible-heading-status').text(o.collapseCueText);
3870 					
3871 					collapsibleHeading.find('.ui-icon').removeClass('ui-icon-plus').addClass('ui-icon-minus');	
3872 					collapsibleContent.removeClass('ui-collapsible-content-collapsed').attr('aria-hidden',false);
3873 					
3874 					if( collapsibleContain.data('collapsible-last') ){
3875 						collapsibleHeading
3876 							.find('a:eq(0), .ui-btn-inner')
3877 							.removeClass('ui-corner-bottom');
3878 					}
3879 					
3880 				}
3881 			})
3882 			.trigger(o.collapsed ? 'collapse' : 'expand');
3883 			
3884 		
3885 		//close others in a set
3886 		if( collapsibleParent.length && !collapsibleParent.data("collapsiblebound") ){
3887 			collapsibleParent
3888 				.data("collapsiblebound", true)
3889 				.bind("expand", function( event ){
3890 					$(this).find( ".ui-collapsible-contain" )
3891 						.not( $(event.target).closest( ".ui-collapsible-contain" ) )
3892 						.not( "> .ui-collapsible-contain .ui-collapsible-contain" )
3893 						.trigger( "collapse" );
3894 				})
3895 			var set = collapsibleParent.find('[data-role=collapsible]')
3896 					
3897 			set.first()
3898 				.find('a:eq(0)')	
3899 				.addClass('ui-corner-top')
3900 					.find('.ui-btn-inner')
3901 					.addClass('ui-corner-top');
3902 					
3903 			set.last().data('collapsible-last', true)	
3904 		}
3905 					
3906 		collapsibleHeading.bind( $.support.touch ? "touchstart" : "click", function(){ 
3907 			if( collapsibleHeading.is('.ui-collapsible-heading-collapsed') ){
3908 				collapsibleContain.trigger('expand'); 
3909 			}	
3910 			else {
3911 				collapsibleContain.trigger('collapse'); 
3912 			}
3913 			return false;
3914 		});
3915 			
3916 	}
3917 });
3918 })( jQuery );/*
3919 * jQuery Mobile Framework: "controlgroup" plugin - corner-rounding for groups of buttons, checks, radios, etc
3920 * Copyright (c) jQuery Project
3921 * Dual licensed under the MIT or GPL Version 2 licenses.
3922 * http://jquery.org/license
3923 */
3924 (function($, undefined ) {
3925 $.fn.controlgroup = function(options){
3926 		
3927 	return this.each(function(){
3928 		var o = $.extend({
3929 			direction: $( this ).data( "type" ) || "vertical",
3930 			shadow: false
3931 		},options);
3932 		var groupheading = $(this).find('>legend'),
3933 			flCorners = o.direction == 'horizontal' ? ['ui-corner-left', 'ui-corner-right'] : ['ui-corner-top', 'ui-corner-bottom'],
3934 			type = $(this).find('input:eq(0)').attr('type');
3935 		
3936 		//replace legend with more stylable replacement div	
3937 		if( groupheading.length ){
3938 			$(this).wrapInner('<div class="ui-controlgroup-controls"></div>');	
3939 			$('<div role="heading" class="ui-controlgroup-label">'+ groupheading.html() +'</div>').insertBefore( $(this).children(0) );	
3940 			groupheading.remove();	
3941 		}
3942 
3943 		$(this).addClass('ui-corner-all ui-controlgroup ui-controlgroup-'+o.direction);
3944 		
3945 		function flipClasses(els){
3946 			els
3947 				.removeClass('ui-btn-corner-all ui-shadow')
3948 				.eq(0).addClass(flCorners[0])
3949 				.end()
3950 				.filter(':last').addClass(flCorners[1]).addClass('ui-controlgroup-last');
3951 		}
3952 		flipClasses($(this).find('.ui-btn'));
3953 		flipClasses($(this).find('.ui-btn-inner'));
3954 		if(o.shadow){
3955 			$(this).addClass('ui-shadow');
3956 		}
3957 	});	
3958 };
3959 })(jQuery);/*
3960 * jQuery Mobile Framework : "fieldcontain" plugin - simple class additions to make form row separators
3961 * Copyright (c) jQuery Project
3962 * Dual licensed under the MIT or GPL Version 2 licenses.
3963 * http://jquery.org/license
3964 */
3965 (function($, undefined ) {
3966 $.fn.fieldcontain = function(options){
3967 	return this.addClass('ui-field-contain ui-body ui-br');
3968 };
3969 })(jQuery);/*
3970 * jQuery Mobile Framework : "listview" plugin
3971 * Copyright (c) jQuery Project
3972 * Dual licensed under the MIT or GPL Version 2 licenses.
3973 * http://jquery.org/license
3974 */
3975 (function($, undefined ) {
3976 
3977 $.widget( "mobile.listview", $.mobile.widget, {
3978 	options: {
3979 		theme: "c",
3980 		countTheme: "c",
3981 		headerTheme: "b",
3982 		dividerTheme: "b",
3983 		splitIcon: "arrow-r",
3984 		splitTheme: "b",
3985 		inset: false
3986 	},
3987 	
3988 	_create: function() {
3989 		var $list = this.element,
3990 			o = this.options;
3991 
3992 		// create listview markup 
3993 		$list
3994 			.addClass( "ui-listview" )
3995 			.attr( "role", "listbox" )
3996 		
3997 		if ( o.inset ) {
3998 			$list.addClass( "ui-listview-inset ui-corner-all ui-shadow" );
3999 		}	
4000 
4001 		$list.delegate( ".ui-li", "focusin", function() {
4002 			$( this ).attr( "tabindex", "0" );
4003 		});
4004 
4005 		this._itemApply( $list, $list );
4006 		
4007 		this.refresh( true );
4008 	
4009 		//keyboard events for menu items
4010 		$list.keydown(function( e ) {
4011 			var target = $( e.target ),
4012 				li = target.closest( "li" );
4013 
4014 			// switch logic based on which key was pressed
4015 			switch ( e.keyCode ) {
4016 				// up or left arrow keys
4017 				case 38:
4018 					var prev = li.prev();
4019 
4020 					// if there's a previous option, focus it
4021 					if ( prev.length ) {
4022 						target
4023 							.blur()
4024 							.attr( "tabindex", "-1" );
4025 
4026 						prev.find( "a" ).first().focus();
4027 					}	
4028 
4029 					return false;
4030 				break;
4031 
4032 				// down or right arrow keys
4033 				case 40:
4034 					var next = li.next();
4035 				
4036 					// if there's a next option, focus it
4037 					if ( next.length ) {
4038 						target
4039 							.blur()
4040 							.attr( "tabindex", "-1" );
4041 						
4042 						next.find( "a" ).first().focus();
4043 					}	
4044 
4045 					return false;
4046 				break;
4047 
4048 				case 39:
4049 					var a = li.find( "a.ui-li-link-alt" );
4050 
4051 					if ( a.length ) {
4052 						target.blur();
4053 						a.first().focus();
4054 					}
4055 
4056 					return false;
4057 				break;
4058 
4059 				case 37:
4060 					var a = li.find( "a.ui-link-inherit" );
4061 
4062 					if ( a.length ) {
4063 						target.blur();
4064 						a.first().focus();
4065 					}
4066 
4067 					return false;
4068 				break;
4069 
4070 				// if enter or space is pressed, trigger click
4071 				case 13:
4072 				case 32:
4073 					 target.trigger( "click" );
4074 
4075 					 return false;
4076 				break;	
4077 			}
4078 		});	
4079 
4080 		// tapping the whole LI triggers click on the first link
4081 		$list.delegate( "li", "click", function(event) {
4082 			if ( !$( event.target ).closest( "a" ).length ) {
4083 				$( this ).find( "a" ).first().trigger( "click" );
4084 				return false;
4085 			}
4086 		});
4087 	},
4088 
4089 	_itemApply: function( $list, item ) {
4090 		// TODO class has to be defined in markup
4091 		item.find( ".ui-li-count" )
4092 			.addClass( "ui-btn-up-" + ($list.data( "counttheme" ) || this.options.countTheme) + " ui-btn-corner-all" );
4093 
4094 		item.find( "h1, h2, h3, h4, h5, h6" ).addClass( "ui-li-heading" );
4095 
4096 		item.find( "p, dl" ).addClass( "ui-li-desc" );
4097 
4098 		item.find( "li" ).find( "img:eq(0)" ).addClass( "ui-li-thumb" ).each(function() {
4099 			$( this ).closest( "li" )
4100 				.addClass( $(this).is( ".ui-li-icon" ) ? "ui-li-has-icon" : "ui-li-has-thumb" );
4101 		});
4102 
4103 		var aside = item.find( ".ui-li-aside" );
4104 
4105 		if ( aside.length ) {
4106             aside.each(function(i, el) {
4107 			    $(el).prependTo( $(el).parent() ); //shift aside to front for css float
4108             });
4109 		}
4110 
4111 		if ( $.support.cssPseudoElement || !$.nodeName( item[0], "ol" ) ) {
4112 			return;
4113 		}
4114 	},
4115 	
4116 	_removeCorners: function(li){
4117 		li
4118 			.add( li.find(".ui-btn-inner, .ui-li-link-alt, .ui-li-thumb") )
4119 			.removeClass( "ui-corner-top ui-corner-bottom ui-corner-br ui-corner-bl ui-corner-tr ui-corner-tl" );
4120 	},
4121 	
4122 	refresh: function( create ) {
4123 		this._createSubPages();
4124 		
4125 		var o = this.options,
4126 			$list = this.element,
4127 			self = this,
4128 			dividertheme = $list.data( "dividertheme" ) || o.dividerTheme,
4129 			li = $list.children( "li" ),
4130 			counter = $.support.cssPseudoElement || !$.nodeName( $list[0], "ol" ) ? 0 : 1;
4131 
4132 		if ( counter ) {
4133 			$list.find( ".ui-li-dec" ).remove();
4134 		}
4135 
4136 		li.attr({ "role": "option", "tabindex": "-1" });
4137 
4138 		li.first().attr( "tabindex", "0" );
4139 
4140 		li.each(function( pos ) {
4141 			var item = $( this ),
4142 				itemClass = "ui-li";
4143 
4144 			// If we're creating the element, we update it regardless
4145 			if ( !create && item.hasClass( "ui-li" ) ) {
4146 				return;
4147 			}
4148 
4149 			var itemTheme = item.data("theme") || o.theme;
4150 
4151 			var a = item.find( "a" );
4152 				
4153 			if ( a.length ) {	
4154 				var icon = item.data("icon");
4155 				
4156 				item
4157 					.buttonMarkup({
4158 						wrapperEls: "div",
4159 						shadow: false,
4160 						corners: false,
4161 						iconpos: "right",
4162 						icon: a.length > 1 || icon === false ? false : icon || "arrow-r",
4163 						theme: itemTheme
4164 					});
4165 
4166 				a.first().addClass( "ui-link-inherit" );
4167 
4168 				if ( a.length > 1 ) {
4169 					itemClass += " ui-li-has-alt";
4170 
4171 					var last = a.last(),
4172 						splittheme = $list.data( "splittheme" ) || last.data( "theme" ) || o.splitTheme;
4173 					
4174 					last
4175 						.appendTo(item)
4176 						.attr( "title", last.text() )
4177 						.addClass( "ui-li-link-alt" )
4178 						.empty()
4179 						.buttonMarkup({
4180 							shadow: false,
4181 							corners: false,
4182 							theme: itemTheme,
4183 							icon: false,
4184 							iconpos: false
4185 						})
4186 						.find( ".ui-btn-inner" )
4187 							.append( $( "<span>" ).buttonMarkup({
4188 								shadow: true,
4189 								corners: true,
4190 								theme: splittheme,
4191 								iconpos: "notext",
4192 								icon: $list.data( "spliticon" ) || last.data( "icon" ) ||  o.splitIcon
4193 							} ) );
4194 				}
4195 
4196 			} else if ( item.data( "role" ) === "list-divider" ) {
4197 				itemClass += " ui-li-divider ui-btn ui-bar-" + dividertheme;
4198 				item.attr( "role", "heading" );
4199 
4200 				//reset counter when a divider heading is encountered
4201 				if ( counter ) {
4202 					counter = 1;
4203 				}
4204 
4205 			} else {
4206 				itemClass += " ui-li-static ui-btn-up-" + itemTheme;
4207 			}
4208 			
4209 			
4210 			if( o.inset ){	
4211 				if ( pos === 0 ) {
4212 						itemClass += " ui-corner-top";
4213 	
4214 						item
4215 							.add( item.find( ".ui-btn-inner" ) )
4216 							.find( ".ui-li-link-alt" )
4217 								.addClass( "ui-corner-tr" )
4218 							.end()
4219 							.find( ".ui-li-thumb" )
4220 								.addClass( "ui-corner-tl" );
4221 						if(item.next().next().length){
4222 							self._removeCorners( item.next() );		
4223 						}
4224 	
4225 				}
4226 				if ( pos === li.length - 1 ) {
4227 						itemClass += " ui-corner-bottom";
4228 	
4229 						item
4230 							.add( item.find( ".ui-btn-inner" ) )
4231 							.find( ".ui-li-link-alt" )
4232 								.addClass( "ui-corner-br" )
4233 							.end()
4234 							.find( ".ui-li-thumb" )
4235 								.addClass( "ui-corner-bl" );
4236 						
4237 						if(item.prev().prev().length){
4238 							self._removeCorners( item.prev() );		
4239 						}	
4240 				}
4241 			}
4242 
4243 
4244 			if ( counter && itemClass.indexOf( "ui-li-divider" ) < 0 ) {
4245 				item
4246 					.find( ".ui-link-inherit" ).first()
4247 					.addClass( "ui-li-jsnumbering" )
4248 					.prepend( "<span class='ui-li-dec'>" + (counter++) + ". </span>" );
4249 			}
4250 
4251 			item.addClass( itemClass );
4252 
4253 			if ( !create ) {
4254 				self._itemApply( $list, item );
4255 			}
4256 		});
4257 	},
4258 	
4259 	//create a string for ID/subpage url creation
4260 	_idStringEscape: function( str ){
4261 		return str.replace(/[^a-zA-Z0-9]/g, '-');
4262 	},
4263 	
4264 	_createSubPages: function() {
4265 		var parentList = this.element,
4266 			parentPage = parentList.closest( ".ui-page" ),
4267 			parentId = parentPage.data( "url" ),
4268 			o = this.options,
4269 			self = this,
4270 			persistentFooterID = parentPage.find( "[data-role='footer']" ).data( "id" );
4271 
4272 		$( parentList.find( "ul, ol" ).toArray().reverse() ).each(function( i ) {
4273 			var list = $( this ),
4274 				parent = list.parent(),
4275 				title = $.trim(parent.contents()[ 0 ].nodeValue) || parent.find('a:first').text(),
4276 				id = parentId + "&" + $.mobile.subPageUrlKey + "=" + self._idStringEscape(title + " " + i),
4277 				theme = list.data( "theme" ) || o.theme,
4278 				countTheme = list.data( "counttheme" ) || parentList.data( "counttheme" ) || o.countTheme,
4279 				newPage = list.wrap( "<div data-role='page'><div data-role='content'></div></div>" )
4280 							.parent()
4281 								.before( "<div data-role='header' data-theme='" + o.headerTheme + "'><div class='ui-title'>" + title + "</div></div>" )
4282 								.after( persistentFooterID ? $( "<div>", { "data-role": "footer", "data-id": persistentFooterID, "class": "ui-footer-duplicate" } ) : "" )
4283 								.parent()
4284 									.attr({
4285 										"data-url": id,
4286 										"data-theme": theme,
4287 										"data-count-theme": countTheme
4288 									})
4289 									.appendTo( $.mobile.pageContainer );
4290 				
4291 				
4292 				
4293 				newPage.page();		
4294 			var anchor = parent.find('a:first');
4295 			if (!anchor.length) {
4296 				anchor = $("<a></a>").html(title).prependTo(parent.empty());
4297 			}
4298 			anchor.attr('href','#' + id);
4299 		}).listview();
4300 	}
4301 });
4302 
4303 })( jQuery );
4304 /*
4305 * jQuery Mobile Framework : "listview" filter extension
4306 * Copyright (c) jQuery Project
4307 * Dual licensed under the MIT or GPL Version 2 licenses.
4308 * http://jquery.org/license
4309 */
4310 (function($, undefined ) {
4311 
4312 $.mobile.listview.prototype.options.filter = false;
4313 
4314 $( "[data-role='listview']" ).live( "listviewcreate", function() {
4315 	var list = $( this ),
4316 		listview = list.data( "listview" );
4317 	if ( !listview.options.filter ) {
4318 		return;
4319 	}
4320 
4321 	var wrapper = $( "<form>", { "class": "ui-listview-filter ui-bar-c", "role": "search" } ),
4322 		
4323 		search = $( "<input>", {
4324 				placeholder: "Filter results...",
4325 				"data-type": "search"
4326 			})
4327 			.bind( "keyup change", function() {
4328 				var val = this.value.toLowerCase();;
4329 				list.children().show();
4330 				if ( val ) {
4331 					list.children().filter(function() {
4332 						return $( this ).text().toLowerCase().indexOf( val ) === -1;
4333 					}).hide();
4334 				}
4335 				
4336 				//listview._numberItems();
4337 			})
4338 			.appendTo( wrapper )
4339 			.textinput();
4340 	
4341 	wrapper.insertBefore( list );
4342 });
4343 
4344 })( jQuery );
4345 /*
4346 * jQuery Mobile Framework : "dialog" plugin.
4347 * Copyright (c) jQuery Project
4348 * Dual licensed under the MIT (MIT-LICENSE.txt) and GPL (GPL-LICENSE.txt) licenses.
4349 * Note: Code is in draft form and is subject to change
4350 */
4351 (function($, undefined ) {
4352 $.widget( "mobile.dialog", $.mobile.widget, {
4353 	options: {},
4354 	_create: function(){
4355 		var self = this,
4356 			$el = self.element;
4357 		
4358 		/* class the markup for dialog styling */	
4359 		this.element			
4360 			//add ARIA role
4361 			.attr("role","dialog")
4362 			.addClass('ui-page ui-dialog ui-body-a')
4363 			.find('[data-role=header]')
4364 			.addClass('ui-corner-top ui-overlay-shadow')
4365 				.prepend( '<a href="#" data-icon="delete" data-rel="back" data-iconpos="notext">Close</a>' )
4366 			.end()
4367 			.find('.ui-content:not([class*="ui-body-"])')
4368 				.addClass('ui-body-c')
4369 			.end()
4370 			.find('.ui-content,[data-role=footer]')
4371 				.last()
4372 				.addClass('ui-corner-bottom ui-overlay-shadow');
4373 		
4374 		/* bind events 
4375 			- clicks and submits should use the closing transition that the dialog opened with
4376 			  unless a data-transition is specified on the link/form
4377 			- if the click was on the close button, or the link has a data-rel="back" it'll go back in history naturally
4378 		*/
4379 		this.element		
4380 			.bind( "click submit", function(e){
4381 				var $targetel;
4382 				if( e.type == "click" ){
4383 					$targetel = $(e.target).closest("a");
4384 				}
4385 				else{
4386 					$targetel = $(e.target).closest("form");
4387 				}
4388 				
4389 				if( $targetel.length && !$targetel.data("transition") ){
4390 					$targetel
4391 						.attr("data-transition", $.mobile.urlHistory.getActive().transition )
4392 						.attr("data-direction", "reverse");
4393 				}
4394 			});
4395 
4396 	},
4397 	
4398 	//close method goes back in history
4399 	close: function(){
4400 		window.history.back();
4401 	}
4402 });
4403 })( jQuery );/*
4404 * jQuery Mobile Framework : "navbar" plugin
4405 * Copyright (c) jQuery Project
4406 * Dual licensed under the MIT or GPL Version 2 licenses.
4407 * http://jquery.org/license
4408 */
4409 (function($, undefined ) {
4410 $.widget( "mobile.navbar", $.mobile.widget, {
4411 	options: {
4412 		iconpos: 'top',
4413 		grid: null
4414 	},
4415 	_create: function(){
4416 		var $navbar = this.element,
4417 			$navbtns = $navbar.find("a"),
4418 			iconpos = $navbtns.filter('[data-icon]').length ? this.options.iconpos : undefined;
4419 		
4420 		$navbar
4421 			.addClass('ui-navbar')
4422 			.attr("role","navigation")
4423 			.find("ul")
4424 				.grid({grid: this.options.grid });		
4425 		
4426 		if( !iconpos ){ 
4427 			$navbar.addClass("ui-navbar-noicons");
4428 		}
4429 		
4430 		$navbtns
4431 			.buttonMarkup({
4432 				corners:	false, 
4433 				shadow:		false, 
4434 				iconpos:	iconpos
4435 			});
4436 		
4437 		$navbar.delegate("a", "click",function(event){
4438 			$navbtns.removeClass( "ui-btn-active" );
4439 			$( this ).addClass( "ui-btn-active" );
4440 		});	
4441 	}
4442 });
4443 })( jQuery );/*
4444 * jQuery Mobile Framework : plugin for creating CSS grids
4445 * Copyright (c) jQuery Project
4446 * Dual licensed under the MIT or GPL Version 2 licenses.
4447 * http://jquery.org/license
4448 */ 
4449 (function($, undefined ) {
4450 $.fn.grid = function(options){
4451 	return this.each(function(){
4452 		var o = $.extend({
4453 			grid: null
4454 		},options);
4455 	
4456 			
4457 		var $kids = $(this).children(),
4458 			gridCols = {a: 2, b:3, c:4, d:5},
4459 			grid = o.grid,
4460 			iterator;
4461 			
4462 			if( !grid ){
4463 				if( $kids.length <= 5 ){
4464 					for(var letter in gridCols){
4465 						if(gridCols[letter] == $kids.length){ grid = letter; }
4466 					}
4467 				}
4468 				else{
4469 					grid = 'a';
4470 				}
4471 			}
4472 			iterator = gridCols[grid];
4473 			
4474 		$(this).addClass('ui-grid-' + grid);
4475 	
4476 		$kids.filter(':nth-child(' + iterator + 'n+1)').addClass('ui-block-a');
4477 		$kids.filter(':nth-child(' + iterator + 'n+2)').addClass('ui-block-b');
4478 			
4479 		if(iterator > 2){	
4480 			$kids.filter(':nth-child(3n+3)').addClass('ui-block-c');
4481 		}	
4482 		if(iterator> 3){	
4483 			$kids.filter(':nth-child(4n+4)').addClass('ui-block-d');
4484 		}	
4485 		if(iterator > 4){	
4486 			$kids.filter(':nth-child(5n+5)').addClass('ui-block-e');
4487 		}
4488 				
4489 	});	
4490 };
4491 })(jQuery);
4492 
4493 console.log("jQuery len:" + jQuery.toString().length);
4494