" ).html( $this.clone() ).html(),
+ // In IE browsers, the type sometimes doesn't exist in the cloned markup, so we replace the closing tag instead
+ hasType = html.indexOf( " type=" ) > -1,
+ findstr = hasType ? /\s+type=["']?\w+['"]?/ : /\/?>/,
+ repstr = " type=\"" + optType + "\" data-" + $.mobile.ns + "type=\"" + type + "\"" + ( hasType ? "" : ">" );
+
+ $this.replaceWith( html.replace( findstr, repstr ) );
+ }
+ });
+
+});
+
+})( jQuery );
+
+(function( $, window, undefined ) {
+
+$.widget( "mobile.dialog", $.mobile.widget, {
+ options: {
+ closeBtn: "left",
+ closeBtnText: "Close",
+ overlayTheme: "a",
+ corners: true,
+ initSelector: ":jqmData(role='dialog')"
+ },
+
+ // Override the theme set by the page plugin on pageshow
+ _handlePageBeforeShow: function() {
+ this._isCloseable = true;
+ if ( this.options.overlayTheme ) {
+ this.element
+ .page( "removeContainerBackground" )
+ .page( "setContainerBackground", this.options.overlayTheme );
+ }
+ },
+
+ _handlePageBeforeHide: function() {
+ this._isCloseable = false;
+ },
+
+ _create: function() {
+ var self = this,
+ $el = this.element,
+ cornerClass = !!this.options.corners ? " ui-corner-all" : "",
+ dialogWrap = $( "
", {
+ "role" : "dialog",
+ "class" : "ui-dialog-contain ui-overlay-shadow" + cornerClass
+ });
+
+ $el.addClass( "ui-dialog ui-overlay-" + this.options.overlayTheme );
+
+ // Class the markup for dialog styling
+ // Set aria role
+ $el.wrapInner( dialogWrap );
+
+ /* bind events
+ - clicks and submits should use the closing transition that the dialog opened with
+ unless a data-transition is specified on the link/form
+ - if the click was on the close button, or the link has a data-rel="back" it'll go back in history naturally
+ */
+ $el.bind( "vclick submit", function( event ) {
+ var $target = $( event.target ).closest( event.type === "vclick" ? "a" : "form" ),
+ active;
+
+ if ( $target.length && !$target.jqmData( "transition" ) ) {
+
+ active = $.mobile.urlHistory.getActive() || {};
+
+ $target.attr( "data-" + $.mobile.ns + "transition", ( active.transition || $.mobile.defaultDialogTransition ) )
+ .attr( "data-" + $.mobile.ns + "direction", "reverse" );
+ }
+ });
+
+ this._on( $el, {
+ pagebeforeshow: "_handlePageBeforeShow",
+ pagebeforehide: "_handlePageBeforeHide"
+ });
+
+ $.extend( this, {
+ _createComplete: false
+ });
+
+ this._setCloseBtn( this.options.closeBtn );
+ },
+
+ _setCloseBtn: function( value ) {
+ var self = this, btn, location;
+
+ if ( this._headerCloseButton ) {
+ this._headerCloseButton.remove();
+ this._headerCloseButton = null;
+ }
+ if ( value !== "none" ) {
+ // Sanitize value
+ location = ( value === "left" ? "left" : "right" );
+ btn = $( "
"+ this.options.closeBtnText + "" );
+ this.element.children().find( ":jqmData(role='header')" ).first().prepend( btn );
+ if ( this._createComplete && $.fn.buttonMarkup ) {
+ btn.buttonMarkup();
+ }
+ this._createComplete = true;
+
+ // this must be an anonymous function so that select menu dialogs can replace
+ // the close method. This is a change from previously just defining data-rel=back
+ // on the button and letting nav handle it
+ //
+ // Use click rather than vclick in order to prevent the possibility of unintentionally
+ // reopening the dialog if the dialog opening item was directly under the close button.
+ btn.bind( "click", function() {
+ self.close();
+ });
+
+ this._headerCloseButton = btn;
+ }
+ },
+
+ _setOption: function( key, value ) {
+ if ( key === "closeBtn" ) {
+ this._setCloseBtn( value );
+ }
+ this._super( key, value );
+ },
+
+ // Close method goes back in history
+ close: function() {
+ var idx, dst, hist = $.mobile.navigate.history;
+
+ if ( this._isCloseable ) {
+ this._isCloseable = false;
+ // If the hash listening is enabled and there is at least one preceding history
+ // entry it's ok to go back. Initial pages with the dialog hash state are an example
+ // where the stack check is necessary
+ if ( $.mobile.hashListeningEnabled && hist.activeIndex > 0 ) {
+ $.mobile.back();
+ } else {
+ idx = Math.max( 0, hist.activeIndex - 1 );
+ dst = hist.stack[ idx ].pageUrl || hist.stack[ idx ].url;
+ hist.previousIndex = hist.activeIndex;
+ hist.activeIndex = idx;
+ if ( !$.mobile.path.isPath( dst ) ) {
+ dst = $.mobile.path.makeUrlAbsolute( "#" + dst );
+ }
+
+ $.mobile.changePage( dst, { direction: "back", changeHash: false, fromHashChange: true } );
+ }
+ }
+ }
+});
+
+//auto self-init widgets
+$.mobile.document.delegate( $.mobile.dialog.prototype.options.initSelector, "pagecreate", function() {
+ $.mobile.dialog.prototype.enhance( this );
+});
+
+})( jQuery, this );
+
+(function( $, undefined ) {
+
+$.mobile.page.prototype.options.backBtnText = "Back";
+$.mobile.page.prototype.options.addBackBtn = false;
+$.mobile.page.prototype.options.backBtnTheme = null;
+$.mobile.page.prototype.options.headerTheme = "a";
+$.mobile.page.prototype.options.footerTheme = "a";
+$.mobile.page.prototype.options.contentTheme = null;
+
+// NOTE bind used to force this binding to run before the buttonMarkup binding
+// which expects .ui-footer top be applied in its gigantic selector
+// TODO remove the buttonMarkup giant selector and move it to the various modules
+// on which it depends
+$.mobile.document.bind( "pagecreate", function( e ) {
+ var $page = $( e.target ),
+ o = $page.data( "mobile-page" ).options,
+ pageRole = $page.jqmData( "role" ),
+ pageTheme = o.theme;
+
+ $( ":jqmData(role='header'), :jqmData(role='footer'), :jqmData(role='content')", $page )
+ .jqmEnhanceable()
+ .each(function() {
+
+ var $this = $( this ),
+ role = $this.jqmData( "role" ),
+ theme = $this.jqmData( "theme" ),
+ contentTheme = theme || o.contentTheme || ( pageRole === "dialog" && pageTheme ),
+ $headeranchors,
+ leftbtn,
+ rightbtn,
+ backBtn;
+
+ $this.addClass( "ui-" + role );
+
+ //apply theming and markup modifications to page,header,content,footer
+ if ( role === "header" || role === "footer" ) {
+
+ var thisTheme = theme || ( role === "header" ? o.headerTheme : o.footerTheme ) || pageTheme;
+
+ $this
+ //add theme class
+ .addClass( "ui-bar-" + thisTheme )
+ // Add ARIA role
+ .attr( "role", role === "header" ? "banner" : "contentinfo" );
+
+ if ( role === "header") {
+ // Right,left buttons
+ $headeranchors = $this.children( "a, button" );
+ leftbtn = $headeranchors.hasClass( "ui-btn-left" );
+ rightbtn = $headeranchors.hasClass( "ui-btn-right" );
+
+ leftbtn = leftbtn || $headeranchors.eq( 0 ).not( ".ui-btn-right" ).addClass( "ui-btn-left" ).length;
+
+ rightbtn = rightbtn || $headeranchors.eq( 1 ).addClass( "ui-btn-right" ).length;
+ }
+
+ // Auto-add back btn on pages beyond first view
+ if ( o.addBackBtn &&
+ role === "header" &&
+ $( ".ui-page" ).length > 1 &&
+ $page.jqmData( "url" ) !== $.mobile.path.stripHash( location.hash ) &&
+ !leftbtn ) {
+
+ backBtn = $( "
"+ o.backBtnText +"" )
+ // If theme is provided, override default inheritance
+ .attr( "data-"+ $.mobile.ns +"theme", o.backBtnTheme || thisTheme )
+ .prependTo( $this );
+ }
+
+ // Page title
+ $this.children( "h1, h2, h3, h4, h5, h6" )
+ .addClass( "ui-title" )
+ // Regardless of h element number in src, it becomes h1 for the enhanced page
+ .attr({
+ "role": "heading",
+ "aria-level": "1"
+ });
+
+ } else if ( role === "content" ) {
+ if ( contentTheme ) {
+ $this.addClass( "ui-body-" + ( contentTheme ) );
+ }
+
+ // Add ARIA role
+ $this.attr( "role", "main" );
+ }
+ });
+});
+
+})( jQuery );
+
+(function( $, undefined ) {
+
+// This function calls getAttribute, which should be safe for data-* attributes
+var getAttrFixed = function( e, key ) {
+ var value = e.getAttribute( key );
+
+ return value === "true" ? true :
+ value === "false" ? false :
+ value === null ? undefined : value;
+};
+
+$.fn.buttonMarkup = function( options ) {
+ var $workingSet = this,
+ nsKey = "data-" + $.mobile.ns,
+ key;
+
+ // Enforce options to be of type string
+ options = ( options && ( $.type( options ) === "object" ) )? options : {};
+ for ( var i = 0; i < $workingSet.length; i++ ) {
+ var el = $workingSet.eq( i ),
+ e = el[ 0 ],
+ o = $.extend( {}, $.fn.buttonMarkup.defaults, {
+ icon: options.icon !== undefined ? options.icon : getAttrFixed( e, nsKey + "icon" ),
+ iconpos: options.iconpos !== undefined ? options.iconpos : getAttrFixed( e, nsKey + "iconpos" ),
+ theme: options.theme !== undefined ? options.theme : getAttrFixed( e, nsKey + "theme" ) || $.mobile.getInheritedTheme( el, "c" ),
+ inline: options.inline !== undefined ? options.inline : getAttrFixed( e, nsKey + "inline" ),
+ shadow: options.shadow !== undefined ? options.shadow : getAttrFixed( e, nsKey + "shadow" ),
+ corners: options.corners !== undefined ? options.corners : getAttrFixed( e, nsKey + "corners" ),
+ iconshadow: options.iconshadow !== undefined ? options.iconshadow : getAttrFixed( e, nsKey + "iconshadow" ),
+ mini: options.mini !== undefined ? options.mini : getAttrFixed( e, nsKey + "mini" )
+ }, options ),
+
+ // Classes Defined
+ innerClass = "ui-btn-inner",
+ textClass = "ui-btn-text",
+ buttonClass, iconClass,
+ hover = false,
+ state = "up",
+ // Button inner markup
+ buttonInner,
+ buttonText,
+ buttonIcon,
+ buttonElements;
+
+ for ( key in o ) {
+ if ( o[ key ] === undefined || o[ key ] === null ) {
+ el.removeAttr( nsKey + key );
+ } else {
+ e.setAttribute( nsKey + key, o[ key ] );
+ }
+ }
+
+ // Check if this element is already enhanced
+ buttonElements = $.data( ( ( e.tagName === "INPUT" || e.tagName === "BUTTON" ) ? e.parentNode : e ), "buttonElements" );
+
+ if ( buttonElements ) {
+ e = buttonElements.outer;
+ el = $( e );
+ buttonInner = buttonElements.inner;
+ buttonText = buttonElements.text;
+ // We will recreate this icon below
+ $( buttonElements.icon ).remove();
+ buttonElements.icon = null;
+ hover = buttonElements.hover;
+ state = buttonElements.state;
+ }
+ else {
+ buttonInner = document.createElement( o.wrapperEls );
+ buttonText = document.createElement( o.wrapperEls );
+ }
+ buttonIcon = o.icon ? document.createElement( "span" ) : null;
+
+ if ( attachEvents && !buttonElements ) {
+ attachEvents();
+ }
+
+ // if not, try to find closest theme container
+ if ( !o.theme ) {
+ o.theme = $.mobile.getInheritedTheme( el, "c" );
+ }
+
+ buttonClass = "ui-btn ";
+ buttonClass += ( hover ? "ui-btn-hover-" + o.theme : "" );
+ buttonClass += ( state ? " ui-btn-" + state + "-" + o.theme : "" );
+ buttonClass += o.shadow ? " ui-shadow" : "";
+ buttonClass += o.corners ? " ui-btn-corner-all" : "";
+
+ if ( o.mini !== undefined ) {
+ // Used to control styling in headers/footers, where buttons default to `mini` style.
+ buttonClass += o.mini === true ? " ui-mini" : " ui-fullsize";
+ }
+
+ if ( o.inline !== undefined ) {
+ // Used to control styling in headers/footers, where buttons default to `inline` style.
+ buttonClass += o.inline === true ? " ui-btn-inline" : " ui-btn-block";
+ }
+
+ if ( o.icon ) {
+ o.icon = "ui-icon-" + o.icon;
+ o.iconpos = o.iconpos || "left";
+
+ iconClass = "ui-icon " + o.icon;
+
+ if ( o.iconshadow ) {
+ iconClass += " ui-icon-shadow";
+ }
+ }
+
+ if ( o.iconpos ) {
+ buttonClass += " ui-btn-icon-" + o.iconpos;
+
+ if ( o.iconpos === "notext" && !el.attr( "title" ) ) {
+ el.attr( "title", el.getEncodedText() );
+ }
+ }
+
+ if ( buttonElements ) {
+ el.removeClass( buttonElements.bcls || "" );
+ }
+ el.removeClass( "ui-link" ).addClass( buttonClass );
+
+ buttonInner.className = innerClass;
+ buttonText.className = textClass;
+ if ( !buttonElements ) {
+ buttonInner.appendChild( buttonText );
+ }
+ if ( buttonIcon ) {
+ buttonIcon.className = iconClass;
+ if ( !( buttonElements && buttonElements.icon ) ) {
+ buttonIcon.innerHTML = " ";
+ buttonInner.appendChild( buttonIcon );
+ }
+ }
+
+ while ( e.firstChild && !buttonElements ) {
+ buttonText.appendChild( e.firstChild );
+ }
+
+ if ( !buttonElements ) {
+ e.appendChild( buttonInner );
+ }
+
+ // Assign a structure containing the elements of this button to the elements of this button. This
+ // will allow us to recognize this as an already-enhanced button in future calls to buttonMarkup().
+ buttonElements = {
+ hover : hover,
+ state : state,
+ bcls : buttonClass,
+ outer : e,
+ inner : buttonInner,
+ text : buttonText,
+ icon : buttonIcon
+ };
+
+ $.data( e, 'buttonElements', buttonElements );
+ $.data( buttonInner, 'buttonElements', buttonElements );
+ $.data( buttonText, 'buttonElements', buttonElements );
+ if ( buttonIcon ) {
+ $.data( buttonIcon, 'buttonElements', buttonElements );
+ }
+ }
+
+ return this;
+};
+
+$.fn.buttonMarkup.defaults = {
+ corners: true,
+ shadow: true,
+ iconshadow: true,
+ wrapperEls: "span"
+};
+
+function closestEnabledButton( element ) {
+ var cname;
+
+ while ( element ) {
+ // Note that we check for typeof className below because the element we
+ // handed could be in an SVG DOM where className on SVG elements is defined to
+ // be of a different type (SVGAnimatedString). We only operate on HTML DOM
+ // elements, so we look for plain "string".
+ cname = ( typeof element.className === 'string' ) && ( element.className + ' ' );
+ if ( cname && cname.indexOf( "ui-btn " ) > -1 && cname.indexOf( "ui-disabled " ) < 0 ) {
+ break;
+ }
+
+ element = element.parentNode;
+ }
+
+ return element;
+}
+
+function updateButtonClass( $btn, classToRemove, classToAdd, hover, state ) {
+ var buttonElements = $.data( $btn[ 0 ], "buttonElements" );
+ $btn.removeClass( classToRemove ).addClass( classToAdd );
+ if ( buttonElements ) {
+ buttonElements.bcls = $( document.createElement( "div" ) )
+ .addClass( buttonElements.bcls + " " + classToAdd )
+ .removeClass( classToRemove )
+ .attr( "class" );
+ if ( hover !== undefined ) {
+ buttonElements.hover = hover;
+ }
+ buttonElements.state = state;
+ }
+}
+
+var attachEvents = function() {
+ var hoverDelay = $.mobile.buttonMarkup.hoverDelay, hov, foc;
+
+ $.mobile.document.bind( {
+ "vmousedown vmousecancel vmouseup vmouseover vmouseout focus blur scrollstart": function( event ) {
+ var theme,
+ $btn = $( closestEnabledButton( event.target ) ),
+ isTouchEvent = event.originalEvent && /^touch/.test( event.originalEvent.type ),
+ evt = event.type;
+
+ if ( $btn.length ) {
+ theme = $btn.attr( "data-" + $.mobile.ns + "theme" );
+
+ if ( evt === "vmousedown" ) {
+ if ( isTouchEvent ) {
+ // Use a short delay to determine if the user is scrolling before highlighting
+ hov = setTimeout( function() {
+ updateButtonClass( $btn, "ui-btn-up-" + theme, "ui-btn-down-" + theme, undefined, "down" );
+ }, hoverDelay );
+ } else {
+ updateButtonClass( $btn, "ui-btn-up-" + theme, "ui-btn-down-" + theme, undefined, "down" );
+ }
+ } else if ( evt === "vmousecancel" || evt === "vmouseup" ) {
+ updateButtonClass( $btn, "ui-btn-down-" + theme, "ui-btn-up-" + theme, undefined, "up" );
+ } else if ( evt === "vmouseover" || evt === "focus" ) {
+ if ( isTouchEvent ) {
+ // Use a short delay to determine if the user is scrolling before highlighting
+ foc = setTimeout( function() {
+ updateButtonClass( $btn, "ui-btn-up-" + theme, "ui-btn-hover-" + theme, true, "" );
+ }, hoverDelay );
+ } else {
+ updateButtonClass( $btn, "ui-btn-up-" + theme, "ui-btn-hover-" + theme, true, "" );
+ }
+ } else if ( evt === "vmouseout" || evt === "blur" || evt === "scrollstart" ) {
+ updateButtonClass( $btn, "ui-btn-hover-" + theme + " ui-btn-down-" + theme, "ui-btn-up-" + theme, false, "up" );
+ if ( hov ) {
+ clearTimeout( hov );
+ }
+ if ( foc ) {
+ clearTimeout( foc );
+ }
+ }
+ }
+ },
+ "focusin focus": function( event ) {
+ $( closestEnabledButton( event.target ) ).addClass( $.mobile.focusClass );
+ },
+ "focusout blur": function( event ) {
+ $( closestEnabledButton( event.target ) ).removeClass( $.mobile.focusClass );
+ }
+ });
+
+ attachEvents = null;
+};
+
+//links in bars, or those with data-role become buttons
+//auto self-init widgets
+$.mobile.document.bind( "pagecreate create", function( e ) {
+
+ $( ":jqmData(role='button'), .ui-bar > a, .ui-header > a, .ui-footer > a, .ui-bar > :jqmData(role='controlgroup') > a", e.target )
+ .jqmEnhanceable()
+ .not( "button, input, .ui-btn, :jqmData(role='none'), :jqmData(role='nojs')" )
+ .buttonMarkup();
+});
+
+})( jQuery );
+
+
+(function( $, undefined ) {
+
+$.widget( "mobile.collapsible", $.mobile.widget, {
+ options: {
+ expandCueText: " click to expand contents",
+ collapseCueText: " click to collapse contents",
+ collapsed: true,
+ heading: "h1,h2,h3,h4,h5,h6,legend",
+ collapsedIcon: "plus",
+ expandedIcon: "minus",
+ iconpos: "left",
+ theme: null,
+ contentTheme: null,
+ inset: true,
+ corners: true,
+ mini: false,
+ initSelector: ":jqmData(role='collapsible')"
+ },
+ _create: function() {
+
+ var $el = this.element,
+ o = this.options,
+ collapsible = $el.addClass( "ui-collapsible" ),
+ collapsibleHeading = $el.children( o.heading ).first(),
+ collapsibleContent = collapsible.wrapInner( "
" ).children( ".ui-collapsible-content" ),
+ collapsibleSet = $el.closest( ":jqmData(role='collapsible-set')" ).addClass( "ui-collapsible-set" ),
+ collapsibleClasses = "";
+
+ // Replace collapsibleHeading if it's a legend
+ if ( collapsibleHeading.is( "legend" ) ) {
+ collapsibleHeading = $( "
"+ collapsibleHeading.html() +"
" ).insertBefore( collapsibleHeading );
+ collapsibleHeading.next().remove();
+ }
+
+ // If we are in a collapsible set
+ if ( collapsibleSet.length ) {
+ // Inherit the theme from collapsible-set
+ if ( !o.theme ) {
+ o.theme = collapsibleSet.jqmData( "theme" ) || $.mobile.getInheritedTheme( collapsibleSet, "c" );
+ }
+ // Inherit the content-theme from collapsible-set
+ if ( !o.contentTheme ) {
+ o.contentTheme = collapsibleSet.jqmData( "content-theme" );
+ }
+
+ // Get the preference for collapsed icon in the set, but override with data- attribute on the individual collapsible
+ o.collapsedIcon = $el.jqmData( "collapsed-icon" ) || collapsibleSet.jqmData( "collapsed-icon" ) || o.collapsedIcon;
+
+ // Get the preference for expanded icon in the set, but override with data- attribute on the individual collapsible
+ o.expandedIcon = $el.jqmData( "expanded-icon" ) || collapsibleSet.jqmData( "expanded-icon" ) || o.expandedIcon;
+
+ // Gets the preference icon position in the set, but override with data- attribute on the individual collapsible
+ o.iconpos = $el.jqmData( "iconpos" ) || collapsibleSet.jqmData( "iconpos" ) || o.iconpos;
+
+ // Inherit the preference for inset from collapsible-set or set the default value to ensure equalty within a set
+ if ( collapsibleSet.jqmData( "inset" ) !== undefined ) {
+ o.inset = collapsibleSet.jqmData( "inset" );
+ } else {
+ o.inset = true;
+ }
+ // Set corners for individual collapsibles to false when in a collapsible-set
+ o.corners = false;
+ // Gets the preference for mini in the set
+ if ( !o.mini ) {
+ o.mini = collapsibleSet.jqmData( "mini" );
+ }
+ } else {
+ // get inherited theme if not a set and no theme has been set
+ if ( !o.theme ) {
+ o.theme = $.mobile.getInheritedTheme( $el, "c" );
+ }
+ }
+
+ if ( !!o.inset ) {
+ collapsibleClasses += " ui-collapsible-inset";
+ if ( !!o.corners ) {
+ collapsibleClasses += " ui-corner-all" ;
+ }
+ }
+ if ( o.contentTheme ) {
+ collapsibleClasses += " ui-collapsible-themed-content";
+ collapsibleContent.addClass( "ui-body-" + o.contentTheme );
+ }
+ if ( collapsibleClasses !== "" ) {
+ collapsible.addClass( collapsibleClasses );
+ }
+
+ collapsibleHeading
+ //drop heading in before content
+ .insertBefore( collapsibleContent )
+ //modify markup & attributes
+ .addClass( "ui-collapsible-heading" )
+ .append( "
" )
+ .wrapInner( "
" )
+ .find( "a" )
+ .first()
+ .buttonMarkup({
+ shadow: false,
+ corners: false,
+ iconpos: o.iconpos,
+ icon: o.collapsedIcon,
+ mini: o.mini,
+ theme: o.theme
+ });
+
+ //events
+ collapsible
+ .bind( "expand collapse", function( event ) {
+ if ( !event.isDefaultPrevented() ) {
+ var $this = $( this ),
+ isCollapse = ( event.type === "collapse" );
+
+ event.preventDefault();
+
+ collapsibleHeading
+ .toggleClass( "ui-collapsible-heading-collapsed", isCollapse )
+ .find( ".ui-collapsible-heading-status" )
+ .text( isCollapse ? o.expandCueText : o.collapseCueText )
+ .end()
+ .find( ".ui-icon" )
+ .toggleClass( "ui-icon-" + o.expandedIcon, !isCollapse )
+ // logic or cause same icon for expanded/collapsed state would remove the ui-icon-class
+ .toggleClass( "ui-icon-" + o.collapsedIcon, ( isCollapse || o.expandedIcon === o.collapsedIcon ) )
+ .end()
+ .find( "a" ).first().removeClass( $.mobile.activeBtnClass );
+
+ $this.toggleClass( "ui-collapsible-collapsed", isCollapse );
+ collapsibleContent.toggleClass( "ui-collapsible-content-collapsed", isCollapse ).attr( "aria-hidden", isCollapse );
+
+ collapsibleContent.trigger( "updatelayout" );
+ }
+ })
+ .trigger( o.collapsed ? "collapse" : "expand" );
+
+ collapsibleHeading
+ .bind( "tap", function( event ) {
+ collapsibleHeading.find( "a" ).first().addClass( $.mobile.activeBtnClass );
+ })
+ .bind( "click", function( event ) {
+
+ var type = collapsibleHeading.is( ".ui-collapsible-heading-collapsed" ) ? "expand" : "collapse";
+
+ collapsible.trigger( type );
+
+ event.preventDefault();
+ event.stopPropagation();
+ });
+ }
+});
+
+//auto self-init widgets
+$.mobile.document.bind( "pagecreate create", function( e ) {
+ $.mobile.collapsible.prototype.enhanceWithin( e.target );
+});
+
+})( jQuery );
+
+(function( $, undefined ) {
+
+$.mobile.behaviors.addFirstLastClasses = {
+ _getVisibles: function( $els, create ) {
+ var visibles;
+
+ if ( create ) {
+ visibles = $els.not( ".ui-screen-hidden" );
+ } else {
+ visibles = $els.filter( ":visible" );
+ if ( visibles.length === 0 ) {
+ visibles = $els.not( ".ui-screen-hidden" );
+ }
+ }
+
+ return visibles;
+ },
+
+ _addFirstLastClasses: function( $els, $visibles, create ) {
+ $els.removeClass( "ui-first-child ui-last-child" );
+ $visibles.eq( 0 ).addClass( "ui-first-child" ).end().last().addClass( "ui-last-child" );
+ if ( !create ) {
+ this.element.trigger( "updatelayout" );
+ }
+ }
+};
+
+})( jQuery );
+
+(function( $, undefined ) {
+
+$.widget( "mobile.collapsibleset", $.mobile.widget, $.extend( {
+ options: {
+ initSelector: ":jqmData(role='collapsible-set')"
+ },
+ _create: function() {
+ var $el = this.element.addClass( "ui-collapsible-set" ),
+ o = this.options;
+
+ // Inherit the theme from collapsible-set
+ if ( !o.theme ) {
+ o.theme = $.mobile.getInheritedTheme( $el, "c" );
+ }
+ // Inherit the content-theme from collapsible-set
+ if ( !o.contentTheme ) {
+ o.contentTheme = $el.jqmData( "content-theme" );
+ }
+ // Inherit the corner styling from collapsible-set
+ if ( !o.corners ) {
+ o.corners = $el.jqmData( "corners" );
+ }
+
+ if ( $el.jqmData( "inset" ) !== undefined ) {
+ o.inset = $el.jqmData( "inset" );
+ }
+ o.inset = o.inset !== undefined ? o.inset : true;
+ o.corners = o.corners !== undefined ? o.corners : true;
+
+ if ( !!o.corners && !!o.inset ) {
+ $el.addClass( "ui-corner-all" );
+ }
+
+ // Initialize the collapsible set if it's not already initialized
+ if ( !$el.jqmData( "collapsiblebound" ) ) {
+ $el
+ .jqmData( "collapsiblebound", true )
+ .bind( "expand", function( event ) {
+ var closestCollapsible = $( event.target )
+ .closest( ".ui-collapsible" );
+ if ( closestCollapsible.parent().is( ":jqmData(role='collapsible-set')" ) ) {
+ closestCollapsible
+ .siblings( ".ui-collapsible" )
+ .trigger( "collapse" );
+ }
+ });
+ }
+ },
+
+ _init: function() {
+ var $el = this.element,
+ collapsiblesInSet = $el.children( ":jqmData(role='collapsible')" ),
+ expanded = collapsiblesInSet.filter( ":jqmData(collapsed='false')" );
+ this._refresh( "true" );
+
+ // Because the corners are handled by the collapsible itself and the default state is collapsed
+ // That was causing https://github.com/jquery/jquery-mobile/issues/4116
+ expanded.trigger( "expand" );
+ },
+
+ _refresh: function( create ) {
+ var collapsiblesInSet = this.element.children( ":jqmData(role='collapsible')" );
+
+ $.mobile.collapsible.prototype.enhance( collapsiblesInSet.not( ".ui-collapsible" ) );
+
+ this._addFirstLastClasses( collapsiblesInSet, this._getVisibles( collapsiblesInSet, create ), create );
+ },
+
+ refresh: function() {
+ this._refresh( false );
+ }
+}, $.mobile.behaviors.addFirstLastClasses ) );
+
+//auto self-init widgets
+$.mobile.document.bind( "pagecreate create", function( e ) {
+ $.mobile.collapsibleset.prototype.enhanceWithin( e.target );
+});
+
+})( jQuery );
+
+(function( $, undefined ) {
+
+// filter function removes whitespace between label and form element so we can use inline-block (nodeType 3 = text)
+$.fn.fieldcontain = function( options ) {
+ return this
+ .addClass( "ui-field-contain ui-body ui-br" )
+ .contents().filter( function() {
+ return ( this.nodeType === 3 && !/\S/.test( this.nodeValue ) );
+ }).remove();
+};
+
+//auto self-init widgets
+$( document ).bind( "pagecreate create", function( e ) {
+ $( ":jqmData(role='fieldcontain')", e.target ).jqmEnhanceable().fieldcontain();
+});
+
+})( jQuery );
+
+(function( $, undefined ) {
+
+$.fn.grid = function( options ) {
+ return this.each(function() {
+
+ var $this = $( this ),
+ o = $.extend({
+ grid: null
+ }, options ),
+ $kids = $this.children(),
+ gridCols = { solo:1, a:2, b:3, c:4, d:5 },
+ grid = o.grid,
+ iterator;
+
+ if ( !grid ) {
+ if ( $kids.length <= 5 ) {
+ for ( var letter in gridCols ) {
+ if ( gridCols[ letter ] === $kids.length ) {
+ grid = letter;
+ }
+ }
+ } else {
+ grid = "a";
+ $this.addClass( "ui-grid-duo" );
+ }
+ }
+ iterator = gridCols[grid];
+
+ $this.addClass( "ui-grid-" + grid );
+
+ $kids.filter( ":nth-child(" + iterator + "n+1)" ).addClass( "ui-block-a" );
+
+ if ( iterator > 1 ) {
+ $kids.filter( ":nth-child(" + iterator + "n+2)" ).addClass( "ui-block-b" );
+ }
+ if ( iterator > 2 ) {
+ $kids.filter( ":nth-child(" + iterator + "n+3)" ).addClass( "ui-block-c" );
+ }
+ if ( iterator > 3 ) {
+ $kids.filter( ":nth-child(" + iterator + "n+4)" ).addClass( "ui-block-d" );
+ }
+ if ( iterator > 4 ) {
+ $kids.filter( ":nth-child(" + iterator + "n+5)" ).addClass( "ui-block-e" );
+ }
+ });
+};
+})( jQuery );
+
+(function( $, undefined ) {
+
+$.widget( "mobile.navbar", $.mobile.widget, {
+ options: {
+ iconpos: "top",
+ grid: null,
+ initSelector: ":jqmData(role='navbar')"
+ },
+
+ _create: function() {
+
+ var $navbar = this.element,
+ $navbtns = $navbar.find( "a" ),
+ iconpos = $navbtns.filter( ":jqmData(icon)" ).length ?
+ this.options.iconpos : undefined;
+
+ $navbar.addClass( "ui-navbar ui-mini" )
+ .attr( "role", "navigation" )
+ .find( "ul" )
+ .jqmEnhanceable()
+ .grid({ grid: this.options.grid });
+
+ $navbtns.buttonMarkup({
+ corners: false,
+ shadow: false,
+ inline: true,
+ iconpos: iconpos
+ });
+
+ $navbar.delegate( "a", "vclick", function( event ) {
+ // ui-btn-inner is returned as target
+ var target = $( event.target ).is( "a" ) ? $( this ) : $( this ).parent( "a" );
+
+ if ( !target.is( ".ui-disabled, .ui-btn-active" ) ) {
+ $navbtns.removeClass( $.mobile.activeBtnClass );
+ $( this ).addClass( $.mobile.activeBtnClass );
+
+ // The code below is a workaround to fix #1181
+ var activeBtn = $( this );
+
+ $( document ).one( "pagehide", function() {
+ activeBtn.removeClass( $.mobile.activeBtnClass );
+ });
+ }
+ });
+
+ // Buttons in the navbar with ui-state-persist class should regain their active state before page show
+ $navbar.closest( ".ui-page" ).bind( "pagebeforeshow", function() {
+ $navbtns.filter( ".ui-state-persist" ).addClass( $.mobile.activeBtnClass );
+ });
+ }
+});
+
+//auto self-init widgets
+$.mobile.document.bind( "pagecreate create", function( e ) {
+ $.mobile.navbar.prototype.enhanceWithin( e.target );
+});
+
+})( jQuery );
+
+(function( $, undefined ) {
+
+//Keeps track of the number of lists per page UID
+//This allows support for multiple nested list in the same page
+//https://github.com/jquery/jquery-mobile/issues/1617
+var listCountPerPage = {};
+
+$.widget( "mobile.listview", $.mobile.widget, $.extend( {
+
+ options: {
+ theme: null,
+ countTheme: "c",
+ headerTheme: "b",
+ dividerTheme: "b",
+ icon: "arrow-r",
+ splitIcon: "arrow-r",
+ splitTheme: "b",
+ corners: true,
+ shadow: true,
+ inset: false,
+ initSelector: ":jqmData(role='listview')"
+ },
+
+ _create: function() {
+ var t = this,
+ listviewClasses = "";
+
+ listviewClasses += t.options.inset ? " ui-listview-inset" : "";
+
+ if ( !!t.options.inset ) {
+ listviewClasses += t.options.corners ? " ui-corner-all" : "";
+ listviewClasses += t.options.shadow ? " ui-shadow" : "";
+ }
+
+ // create listview markup
+ t.element.addClass(function( i, orig ) {
+ return orig + " ui-listview" + listviewClasses;
+ });
+
+ t.refresh( true );
+ },
+
+ // This is a generic utility method for finding the first
+ // node with a given nodeName. It uses basic DOM traversal
+ // to be fast and is meant to be a substitute for simple
+ // $.fn.closest() and $.fn.children() calls on a single
+ // element. Note that callers must pass both the lowerCase
+ // and upperCase version of the nodeName they are looking for.
+ // The main reason for this is that this function will be
+ // called many times and we want to avoid having to lowercase
+ // the nodeName from the element every time to ensure we have
+ // a match. Note that this function lives here for now, but may
+ // be moved into $.mobile if other components need a similar method.
+ _findFirstElementByTagName: function( ele, nextProp, lcName, ucName ) {
+ var dict = {};
+ dict[ lcName ] = dict[ ucName ] = true;
+ while ( ele ) {
+ if ( dict[ ele.nodeName ] ) {
+ return ele;
+ }
+ ele = ele[ nextProp ];
+ }
+ return null;
+ },
+ _getChildrenByTagName: function( ele, lcName, ucName ) {
+ var results = [],
+ dict = {};
+ dict[ lcName ] = dict[ ucName ] = true;
+ ele = ele.firstChild;
+ while ( ele ) {
+ if ( dict[ ele.nodeName ] ) {
+ results.push( ele );
+ }
+ ele = ele.nextSibling;
+ }
+ return $( results );
+ },
+
+ _addThumbClasses: function( containers ) {
+ var i, img, len = containers.length;
+ for ( i = 0; i < len; i++ ) {
+ img = $( this._findFirstElementByTagName( containers[ i ].firstChild, "nextSibling", "img", "IMG" ) );
+ if ( img.length ) {
+ img.addClass( "ui-li-thumb" );
+ $( this._findFirstElementByTagName( img[ 0 ].parentNode, "parentNode", "li", "LI" ) ).addClass( img.is( ".ui-li-icon" ) ? "ui-li-has-icon" : "ui-li-has-thumb" );
+ }
+ }
+ },
+
+ refresh: function( create ) {
+ this.parentPage = this.element.closest( ".ui-page" );
+ this._createSubPages();
+
+ var o = this.options,
+ $list = this.element,
+ self = this,
+ dividertheme = $list.jqmData( "dividertheme" ) || o.dividerTheme,
+ listsplittheme = $list.jqmData( "splittheme" ),
+ listspliticon = $list.jqmData( "spliticon" ),
+ listicon = $list.jqmData( "icon" ),
+ li = this._getChildrenByTagName( $list[ 0 ], "li", "LI" ),
+ ol = !!$.nodeName( $list[ 0 ], "ol" ),
+ jsCount = !$.support.cssPseudoElement,
+ start = $list.attr( "start" ),
+ itemClassDict = {},
+ item, itemClass, itemTheme,
+ a, last, splittheme, counter, startCount, newStartCount, countParent, icon, imgParents, img, linkIcon;
+
+ if ( ol && jsCount ) {
+ $list.find( ".ui-li-dec" ).remove();
+ }
+
+ if ( ol ) {
+ // Check if a start attribute has been set while taking a value of 0 into account
+ if ( start || start === 0 ) {
+ if ( !jsCount ) {
+ startCount = parseInt( start , 10 ) - 1;
+ $list.css( "counter-reset", "listnumbering " + startCount );
+ } else {
+ counter = parseInt( start , 10 );
+ }
+ } else if ( jsCount ) {
+ counter = 1;
+ }
+ }
+
+ if ( !o.theme ) {
+ o.theme = $.mobile.getInheritedTheme( this.element, "c" );
+ }
+
+ for ( var pos = 0, numli = li.length; pos < numli; pos++ ) {
+ item = li.eq( pos );
+ itemClass = "ui-li";
+
+ // If we're creating the element, we update it regardless
+ if ( create || !item.hasClass( "ui-li" ) ) {
+ itemTheme = item.jqmData( "theme" ) || o.theme;
+ a = this._getChildrenByTagName( item[ 0 ], "a", "A" );
+ var isDivider = ( item.jqmData( "role" ) === "list-divider" );
+
+ if ( a.length && !isDivider ) {
+ icon = item.jqmData( "icon" );
+
+ item.buttonMarkup({
+ wrapperEls: "div",
+ shadow: false,
+ corners: false,
+ iconpos: "right",
+ icon: a.length > 1 || icon === false ? false : icon || listicon || o.icon,
+ theme: itemTheme
+ });
+
+ if ( ( icon !== false ) && ( a.length === 1 ) ) {
+ item.addClass( "ui-li-has-arrow" );
+ }
+
+ a.first().removeClass( "ui-link" ).addClass( "ui-link-inherit" );
+
+ if ( a.length > 1 ) {
+ itemClass += " ui-li-has-alt";
+
+ last = a.last();
+ splittheme = listsplittheme || last.jqmData( "theme" ) || o.splitTheme;
+ linkIcon = last.jqmData( "icon" );
+
+ last.appendTo( item )
+ .attr( "title", $.trim(last.getEncodedText()) )
+ .addClass( "ui-li-link-alt" )
+ .empty()
+ .buttonMarkup({
+ shadow: false,
+ corners: false,
+ theme: itemTheme,
+ icon: false,
+ iconpos: "notext"
+ })
+ .find( ".ui-btn-inner" )
+ .append(
+ $( document.createElement( "span" ) ).buttonMarkup({
+ shadow: true,
+ corners: true,
+ theme: splittheme,
+ iconpos: "notext",
+ // link icon overrides list item icon overrides ul element overrides options
+ icon: linkIcon || icon || listspliticon || o.splitIcon
+ })
+ );
+ }
+ } else if ( isDivider ) {
+
+ itemClass += " ui-li-divider ui-bar-" + ( item.jqmData( "theme" ) || dividertheme );
+ item.attr( "role", "heading" );
+
+ if ( ol ) {
+ //reset counter when a divider heading is encountered
+ if ( start || start === 0 ) {
+ if ( !jsCount ) {
+ newStartCount = parseInt( start , 10 ) - 1;
+ item.css( "counter-reset", "listnumbering " + newStartCount );
+ } else {
+ counter = parseInt( start , 10 );
+ }
+ } else if ( jsCount ) {
+ counter = 1;
+ }
+ }
+
+ } else {
+ itemClass += " ui-li-static ui-btn-up-" + itemTheme;
+ }
+ }
+
+ if ( ol && jsCount && itemClass.indexOf( "ui-li-divider" ) < 0 ) {
+ countParent = itemClass.indexOf( "ui-li-static" ) > 0 ? item : item.find( ".ui-link-inherit" );
+
+ countParent.addClass( "ui-li-jsnumbering" )
+ .prepend( "
" + ( counter++ ) + ". " );
+ }
+
+ // Instead of setting item class directly on the list item and its
+ // btn-inner at this point in time, push the item into a dictionary
+ // that tells us what class to set on it so we can do this after this
+ // processing loop is finished.
+
+ if ( !itemClassDict[ itemClass ] ) {
+ itemClassDict[ itemClass ] = [];
+ }
+
+ itemClassDict[ itemClass ].push( item[ 0 ] );
+ }
+
+ // Set the appropriate listview item classes on each list item
+ // and their btn-inner elements. The main reason we didn't do this
+ // in the for-loop above is because we can eliminate per-item function overhead
+ // by calling addClass() and children() once or twice afterwards. This
+ // can give us a significant boost on platforms like WP7.5.
+
+ for ( itemClass in itemClassDict ) {
+ $( itemClassDict[ itemClass ] ).addClass( itemClass ).children( ".ui-btn-inner" ).addClass( itemClass );
+ }
+
+ $list.find( "h1, h2, h3, h4, h5, h6" ).addClass( "ui-li-heading" )
+ .end()
+
+ .find( "p, dl" ).addClass( "ui-li-desc" )
+ .end()
+
+ .find( ".ui-li-aside" ).each(function() {
+ var $this = $( this );
+ $this.prependTo( $this.parent() ); //shift aside to front for css float
+ })
+ .end()
+
+ .find( ".ui-li-count" ).each(function() {
+ $( this ).closest( "li" ).addClass( "ui-li-has-count" );
+ }).addClass( "ui-btn-up-" + ( $list.jqmData( "counttheme" ) || this.options.countTheme) + " ui-btn-corner-all" );
+
+ // The idea here is to look at the first image in the list item
+ // itself, and any .ui-link-inherit element it may contain, so we
+ // can place the appropriate classes on the image and list item.
+ // Note that we used to use something like:
+ //
+ // li.find(">img:eq(0), .ui-link-inherit>img:eq(0)").each( ... );
+ //
+ // But executing a find() like that on Windows Phone 7.5 took a
+ // really long time. Walking things manually with the code below
+ // allows the 400 listview item page to load in about 3 seconds as
+ // opposed to 30 seconds.
+
+ this._addThumbClasses( li );
+ this._addThumbClasses( $list.find( ".ui-link-inherit" ) );
+
+ this._addFirstLastClasses( li, this._getVisibles( li, create ), create );
+ // autodividers binds to this to redraw dividers after the listview refresh
+ this._trigger( "afterrefresh" );
+ },
+
+ //create a string for ID/subpage url creation
+ _idStringEscape: function( str ) {
+ return str.replace(/[^a-zA-Z0-9]/g, '-');
+ },
+
+ _createSubPages: function() {
+ var parentList = this.element,
+ parentPage = parentList.closest( ".ui-page" ),
+ parentUrl = parentPage.jqmData( "url" ),
+ parentId = parentUrl || parentPage[ 0 ][ $.expando ],
+ parentListId = parentList.attr( "id" ),
+ o = this.options,
+ dns = "data-" + $.mobile.ns,
+ self = this,
+ persistentFooterID = parentPage.find( ":jqmData(role='footer')" ).jqmData( "id" ),
+ hasSubPages;
+
+ if ( typeof listCountPerPage[ parentId ] === "undefined" ) {
+ listCountPerPage[ parentId ] = -1;
+ }
+
+ parentListId = parentListId || ++listCountPerPage[ parentId ];
+
+ $( parentList.find( "li>ul, li>ol" ).toArray().reverse() ).each(function( i ) {
+ var self = this,
+ list = $( this ),
+ listId = list.attr( "id" ) || parentListId + "-" + i,
+ parent = list.parent(),
+ nodeElsFull = $( list.prevAll().toArray().reverse() ),
+ nodeEls = nodeElsFull.length ? nodeElsFull : $( "
" + $.trim(parent.contents()[ 0 ].nodeValue) + "" ),
+ title = nodeEls.first().getEncodedText(),//url limits to first 30 chars of text
+ id = ( parentUrl || "" ) + "&" + $.mobile.subPageUrlKey + "=" + listId,
+ theme = list.jqmData( "theme" ) || o.theme,
+ countTheme = list.jqmData( "counttheme" ) || parentList.jqmData( "counttheme" ) || o.countTheme,
+ newPage, anchor;
+
+ //define hasSubPages for use in later removal
+ hasSubPages = true;
+
+ newPage = list.detach()
+ .wrap( "
" )
+ .parent()
+ .before( "
" )
+ .after( persistentFooterID ? $( "
" ) : "" )
+ .parent()
+ .appendTo( $.mobile.pageContainer );
+
+ newPage.page();
+
+ anchor = parent.find( 'a:first' );
+
+ if ( !anchor.length ) {
+ anchor = $( "
" ).html( nodeEls || title ).prependTo( parent.empty() );
+ }
+
+ anchor.attr( "href", "#" + id );
+
+ }).listview();
+
+ // on pagehide, remove any nested pages along with the parent page, as long as they aren't active
+ // and aren't embedded
+ if ( hasSubPages &&
+ parentPage.is( ":jqmData(external-page='true')" ) &&
+ parentPage.data( "mobile-page" ).options.domCache === false ) {
+
+ var newRemove = function( e, ui ) {
+ var nextPage = ui.nextPage, npURL,
+ prEvent = new $.Event( "pageremove" );
+
+ if ( ui.nextPage ) {
+ npURL = nextPage.jqmData( "url" );
+ if ( npURL.indexOf( parentUrl + "&" + $.mobile.subPageUrlKey ) !== 0 ) {
+ self.childPages().remove();
+ parentPage.trigger( prEvent );
+ if ( !prEvent.isDefaultPrevented() ) {
+ parentPage.removeWithDependents();
+ }
+ }
+ }
+ };
+
+ // unbind the original page remove and replace with our specialized version
+ parentPage
+ .unbind( "pagehide.remove" )
+ .bind( "pagehide.remove", newRemove);
+ }
+ },
+
+ // TODO sort out a better way to track sub pages of the listview this is brittle
+ childPages: function() {
+ var parentUrl = this.parentPage.jqmData( "url" );
+
+ return $( ":jqmData(url^='"+ parentUrl + "&" + $.mobile.subPageUrlKey + "')" );
+ }
+}, $.mobile.behaviors.addFirstLastClasses ) );
+
+//auto self-init widgets
+$.mobile.document.bind( "pagecreate create", function( e ) {
+ $.mobile.listview.prototype.enhanceWithin( e.target );
+});
+
+})( jQuery );
+
+(function( $ ) {
+ var meta = $( "meta[name=viewport]" ),
+ initialContent = meta.attr( "content" ),
+ disabledZoom = initialContent + ",maximum-scale=1, user-scalable=no",
+ enabledZoom = initialContent + ",maximum-scale=10, user-scalable=yes",
+ disabledInitially = /(user-scalable[\s]*=[\s]*no)|(maximum-scale[\s]*=[\s]*1)[$,\s]/.test( initialContent );
+
+ $.mobile.zoom = $.extend( {}, {
+ enabled: !disabledInitially,
+ locked: false,
+ disable: function( lock ) {
+ if ( !disabledInitially && !$.mobile.zoom.locked ) {
+ meta.attr( "content", disabledZoom );
+ $.mobile.zoom.enabled = false;
+ $.mobile.zoom.locked = lock || false;
+ }
+ },
+ enable: function( unlock ) {
+ if ( !disabledInitially && ( !$.mobile.zoom.locked || unlock === true ) ) {
+ meta.attr( "content", enabledZoom );
+ $.mobile.zoom.enabled = true;
+ $.mobile.zoom.locked = false;
+ }
+ },
+ restore: function() {
+ if ( !disabledInitially ) {
+ meta.attr( "content", initialContent );
+ $.mobile.zoom.enabled = true;
+ }
+ }
+ });
+
+}( jQuery ));
+
+(function( $, undefined ) {
+
+$.widget( "mobile.textinput", $.mobile.widget, {
+ options: {
+ theme: null,
+ mini: false,
+ // This option defaults to true on iOS devices.
+ preventFocusZoom: /iPhone|iPad|iPod/.test( navigator.platform ) && navigator.userAgent.indexOf( "AppleWebKit" ) > -1,
+ initSelector: "input[type='text'], input[type='search'], :jqmData(type='search'), input[type='number'], :jqmData(type='number'), input[type='password'], input[type='email'], input[type='url'], input[type='tel'], textarea, input[type='time'], input[type='date'], input[type='month'], input[type='week'], input[type='datetime'], input[type='datetime-local'], input[type='color'], input:not([type]), input[type='file']",
+ clearBtn: false,
+ clearSearchButtonText: null, //deprecating for 1.3...
+ clearBtnText: "clear text",
+ disabled: false
+ },
+
+ _create: function() {
+
+ var self = this,
+ input = this.element,
+ o = this.options,
+ theme = o.theme || $.mobile.getInheritedTheme( this.element, "c" ),
+ themeclass = " ui-body-" + theme,
+ miniclass = o.mini ? " ui-mini" : "",
+ isSearch = input.is( "[type='search'], :jqmData(type='search')" ),
+ focusedEl,
+ clearbtn,
+ clearBtnText = o.clearSearchButtonText || o.clearBtnText,
+ clearBtnBlacklist = input.is( "textarea, :jqmData(type='range')" ),
+ inputNeedsClearBtn = !!o.clearBtn && !clearBtnBlacklist,
+ inputNeedsWrap = input.is( "input" ) && !input.is( ":jqmData(type='range')" );
+
+ function toggleClear() {
+ setTimeout( function() {
+ clearbtn.toggleClass( "ui-input-clear-hidden", !input.val() );
+ }, 0 );
+ }
+
+ $( "label[for='" + input.attr( "id" ) + "']" ).addClass( "ui-input-text" );
+
+ focusedEl = input.addClass( "ui-input-text ui-body-"+ theme );
+
+ // XXX: Temporary workaround for issue 785 (Apple bug 8910589).
+ // Turn off autocorrect and autocomplete on non-iOS 5 devices
+ // since the popup they use can't be dismissed by the user. Note
+ // that we test for the presence of the feature by looking for
+ // the autocorrect property on the input element. We currently
+ // have no test for iOS 5 or newer so we're temporarily using
+ // the touchOverflow support flag for jQM 1.0. Yes, I feel dirty. - jblas
+ if ( typeof input[0].autocorrect !== "undefined" && !$.support.touchOverflow ) {
+ // Set the attribute instead of the property just in case there
+ // is code that attempts to make modifications via HTML.
+ input[0].setAttribute( "autocorrect", "off" );
+ input[0].setAttribute( "autocomplete", "off" );
+ }
+
+ //"search" and "text" input widgets
+ if ( isSearch ) {
+ focusedEl = input.wrap( "
" ).parent();
+ } else if ( inputNeedsWrap ) {
+ focusedEl = input.wrap( "
" ).parent();
+ }
+
+ if( inputNeedsClearBtn || isSearch ) {
+ clearbtn = $( "
" + clearBtnText + "" )
+ .bind( "click", function( event ) {
+ input
+ .val( "" )
+ .focus()
+ .trigger( "change" );
+ clearbtn.addClass( "ui-input-clear-hidden" );
+ event.preventDefault();
+ })
+ .appendTo( focusedEl )
+ .buttonMarkup({
+ icon: "delete",
+ iconpos: "notext",
+ corners: true,
+ shadow: true,
+ mini: o.mini
+ });
+
+ if ( !isSearch ) {
+ focusedEl.addClass( "ui-input-has-clear" );
+ }
+
+ toggleClear();
+
+ input.bind( "paste cut keyup input focus change blur", toggleClear );
+ }
+ else if ( !inputNeedsWrap && !isSearch ) {
+ input.addClass( "ui-corner-all ui-shadow-inset" + themeclass + miniclass );
+ }
+
+ input.focus(function() {
+ // In many situations, iOS will zoom into the input upon tap, this prevents that from happening
+ if ( o.preventFocusZoom ) {
+ $.mobile.zoom.disable( true );
+ }
+ focusedEl.addClass( $.mobile.focusClass );
+ })
+ .blur(function() {
+ focusedEl.removeClass( $.mobile.focusClass );
+ if ( o.preventFocusZoom ) {
+ $.mobile.zoom.enable( true );
+ }
+ });
+
+ // Autogrow
+ if ( input.is( "textarea" ) ) {
+ var extraLineHeight = 15,
+ keyupTimeoutBuffer = 100,
+ keyupTimeout;
+
+ this._keyup = function() {
+ var scrollHeight = input[ 0 ].scrollHeight,
+ clientHeight = input[ 0 ].clientHeight;
+
+ if ( clientHeight < scrollHeight ) {
+ var paddingTop = parseFloat( input.css( "padding-top" ) ),
+ paddingBottom = parseFloat( input.css( "padding-bottom" ) ),
+ paddingHeight = paddingTop + paddingBottom;
+
+ input.height( scrollHeight - paddingHeight + extraLineHeight );
+ }
+ };
+
+ input.on( "keyup change input paste", function() {
+ clearTimeout( keyupTimeout );
+ keyupTimeout = setTimeout( self._keyup, keyupTimeoutBuffer );
+ });
+
+ // binding to pagechange here ensures that for pages loaded via
+ // ajax the height is recalculated without user input
+ this._on( true, $.mobile.document, { "pagechange": "_keyup" });
+
+ // Issue 509: the browser is not providing scrollHeight properly until the styles load
+ if ( $.trim( input.val() ) ) {
+ // bind to the window load to make sure the height is calculated based on BOTH
+ // the DOM and CSS
+ this._on( true, $.mobile.window, {"load": "_keyup"});
+ }
+ }
+ if ( input.attr( "disabled" ) ) {
+ this.disable();
+ }
+ },
+
+ disable: function() {
+ var $el,
+ isSearch = this.element.is( "[type='search'], :jqmData(type='search')" ),
+ inputNeedsWrap = this.element.is( "input" ) && !this.element.is( ":jqmData(type='range')" ),
+ parentNeedsDisabled = this.element.attr( "disabled", true ) && ( inputNeedsWrap || isSearch );
+
+ if ( parentNeedsDisabled ) {
+ $el = this.element.parent();
+ } else {
+ $el = this.element;
+ }
+ $el.addClass( "ui-disabled" );
+ return this._setOption( "disabled", true );
+ },
+
+ enable: function() {
+ var $el,
+ isSearch = this.element.is( "[type='search'], :jqmData(type='search')" ),
+ inputNeedsWrap = this.element.is( "input" ) && !this.element.is( ":jqmData(type='range')" ),
+ parentNeedsEnabled = this.element.attr( "disabled", false ) && ( inputNeedsWrap || isSearch );
+
+ if ( parentNeedsEnabled ) {
+ $el = this.element.parent();
+ } else {
+ $el = this.element;
+ }
+ $el.removeClass( "ui-disabled" );
+ return this._setOption( "disabled", false );
+ }
+});
+
+//auto self-init widgets
+$.mobile.document.bind( "pagecreate create", function( e ) {
+ $.mobile.textinput.prototype.enhanceWithin( e.target, true );
+});
+
+})( jQuery );
+
+(function( $, undefined ) {
+
+$.mobile.listview.prototype.options.filter = false;
+$.mobile.listview.prototype.options.filterPlaceholder = "Filter items...";
+$.mobile.listview.prototype.options.filterTheme = "c";
+$.mobile.listview.prototype.options.filterReveal = false;
+// TODO rename callback/deprecate and default to the item itself as the first argument
+var defaultFilterCallback = function( text, searchValue, item ) {
+ return text.toString().toLowerCase().indexOf( searchValue ) === -1;
+ };
+
+$.mobile.listview.prototype.options.filterCallback = defaultFilterCallback;
+
+$.mobile.document.delegate( "ul, ol", "listviewcreate", function() {
+ var list = $( this ),
+ listview = list.data( "mobile-listview" );
+
+ if ( !listview || !listview.options.filter ) {
+ return;
+ }
+
+ if ( listview.options.filterReveal ) {
+ list.children().addClass( "ui-screen-hidden" );
+ }
+
+ var wrapper = $( "