")
- // inject the contents of the document in, removing the scripts
- // to avoid any 'Permission Denied' errors in IE
- .append(responseText.replace(rscript, ""))
-
- // Locate the specified elements
- .find(selector) :
-
- // If not, just inject the full result
- responseText );
- }
-
- if ( callback ) {
- self.each( callback, [ responseText, status, jqXHR ] );
- }
- }
- });
-
- return this;
- };
-jQuery.prototype.map = function( callback ) {
-///
-/// Pass each element in the current matched set through a function, producing a new jQuery object containing the return values.
-///
-///
-/// A function object that will be invoked for each element in the current set.
-///
-///
-
- return this.pushStack( jQuery.map(this, function( elem, i ) {
- return callback.call( elem, i, elem );
- }));
- };
-jQuery.prototype.mousedown = function( data, fn ) {
-///
-/// Bind an event handler to the "mousedown" JavaScript event, or trigger that event on an element.
-///
1 - mousedown(handler(eventObject))
-///
2 - mousedown(eventData, handler(eventObject))
-///
3 - mousedown()
-///
-///
-/// A map of data that will be passed to the event handler.
-///
-///
-/// A function to execute each time the event is triggered.
-///
-///
-
- if ( fn == null ) {
- fn = data;
- data = null;
- }
-
- return arguments.length > 0 ?
- this.bind( name, data, fn ) :
- this.trigger( name );
- };
-jQuery.prototype.mouseenter = function( data, fn ) {
-///
-/// Bind an event handler to be fired when the mouse enters an element, or trigger that handler on an element.
-///
1 - mouseenter(handler(eventObject))
-///
2 - mouseenter(eventData, handler(eventObject))
-///
3 - mouseenter()
-///
-///
-/// A map of data that will be passed to the event handler.
-///
-///
-/// A function to execute each time the event is triggered.
-///
-///
-
- if ( fn == null ) {
- fn = data;
- data = null;
- }
-
- return arguments.length > 0 ?
- this.bind( name, data, fn ) :
- this.trigger( name );
- };
-jQuery.prototype.mouseleave = function( data, fn ) {
-///
-/// Bind an event handler to be fired when the mouse leaves an element, or trigger that handler on an element.
-///
1 - mouseleave(handler(eventObject))
-///
2 - mouseleave(eventData, handler(eventObject))
-///
3 - mouseleave()
-///
-///
-/// A map of data that will be passed to the event handler.
-///
-///
-/// A function to execute each time the event is triggered.
-///
-///
-
- if ( fn == null ) {
- fn = data;
- data = null;
- }
-
- return arguments.length > 0 ?
- this.bind( name, data, fn ) :
- this.trigger( name );
- };
-jQuery.prototype.mousemove = function( data, fn ) {
-///
-/// Bind an event handler to the "mousemove" JavaScript event, or trigger that event on an element.
-///
1 - mousemove(handler(eventObject))
-///
2 - mousemove(eventData, handler(eventObject))
-///
3 - mousemove()
-///
-///
-/// A map of data that will be passed to the event handler.
-///
-///
-/// A function to execute each time the event is triggered.
-///
-///
-
- if ( fn == null ) {
- fn = data;
- data = null;
- }
-
- return arguments.length > 0 ?
- this.bind( name, data, fn ) :
- this.trigger( name );
- };
-jQuery.prototype.mouseout = function( data, fn ) {
-///
-/// Bind an event handler to the "mouseout" JavaScript event, or trigger that event on an element.
-///
1 - mouseout(handler(eventObject))
-///
2 - mouseout(eventData, handler(eventObject))
-///
3 - mouseout()
-///
-///
-/// A map of data that will be passed to the event handler.
-///
-///
-/// A function to execute each time the event is triggered.
-///
-///
-
- if ( fn == null ) {
- fn = data;
- data = null;
- }
-
- return arguments.length > 0 ?
- this.bind( name, data, fn ) :
- this.trigger( name );
- };
-jQuery.prototype.mouseover = function( data, fn ) {
-///
-/// Bind an event handler to the "mouseover" JavaScript event, or trigger that event on an element.
-///
1 - mouseover(handler(eventObject))
-///
2 - mouseover(eventData, handler(eventObject))
-///
3 - mouseover()
-///
-///
-/// A map of data that will be passed to the event handler.
-///
-///
-/// A function to execute each time the event is triggered.
-///
-///
-
- if ( fn == null ) {
- fn = data;
- data = null;
- }
-
- return arguments.length > 0 ?
- this.bind( name, data, fn ) :
- this.trigger( name );
- };
-jQuery.prototype.mouseup = function( data, fn ) {
-///
-/// Bind an event handler to the "mouseup" JavaScript event, or trigger that event on an element.
-///
1 - mouseup(handler(eventObject))
-///
2 - mouseup(eventData, handler(eventObject))
-///
3 - mouseup()
-///
-///
-/// A map of data that will be passed to the event handler.
-///
-///
-/// A function to execute each time the event is triggered.
-///
-///
-
- if ( fn == null ) {
- fn = data;
- data = null;
- }
-
- return arguments.length > 0 ?
- this.bind( name, data, fn ) :
- this.trigger( name );
- };
-jQuery.prototype.next = function( until, selector ) {
-///
-/// Get the immediately following sibling of each element in the set of matched elements. If a selector is provided, it retrieves the next sibling only if it matches that selector.
-///
-///
-/// A string containing a selector expression to match elements against.
-///
-///
-
- var ret = jQuery.map( this, fn, until ),
- // The variable 'args' was introduced in
- // https://github.com/jquery/jquery/commit/52a0238
- // to work around a bug in Chrome 10 (Dev) and should be removed when the bug is fixed.
- // http://code.google.com/p/v8/issues/detail?id=1050
- args = slice.call(arguments);
-
- if ( !runtil.test( name ) ) {
- selector = until;
- }
-
- if ( selector && typeof selector === "string" ) {
- ret = jQuery.filter( selector, ret );
- }
-
- ret = this.length > 1 && !guaranteedUnique[ name ] ? jQuery.unique( ret ) : ret;
-
- if ( (this.length > 1 || rmultiselector.test( selector )) && rparentsprev.test( name ) ) {
- ret = ret.reverse();
- }
-
- return this.pushStack( ret, name, args.join(",") );
- };
-jQuery.prototype.nextAll = function( until, selector ) {
-///
-/// Get all following siblings of each element in the set of matched elements, optionally filtered by a selector.
-///
-///
-/// A string containing a selector expression to match elements against.
-///
-///
-
- var ret = jQuery.map( this, fn, until ),
- // The variable 'args' was introduced in
- // https://github.com/jquery/jquery/commit/52a0238
- // to work around a bug in Chrome 10 (Dev) and should be removed when the bug is fixed.
- // http://code.google.com/p/v8/issues/detail?id=1050
- args = slice.call(arguments);
-
- if ( !runtil.test( name ) ) {
- selector = until;
- }
-
- if ( selector && typeof selector === "string" ) {
- ret = jQuery.filter( selector, ret );
- }
-
- ret = this.length > 1 && !guaranteedUnique[ name ] ? jQuery.unique( ret ) : ret;
-
- if ( (this.length > 1 || rmultiselector.test( selector )) && rparentsprev.test( name ) ) {
- ret = ret.reverse();
- }
-
- return this.pushStack( ret, name, args.join(",") );
- };
-jQuery.prototype.nextUntil = function( until, selector ) {
-///
-/// Get all following siblings of each element up to but not including the element matched by the selector, DOM node, or jQuery object passed.
-///
1 - nextUntil(selector, filter)
-///
2 - nextUntil(element, filter)
-///
-///
-/// A string containing a selector expression to indicate where to stop matching following sibling elements.
-///
-///
-/// A string containing a selector expression to match elements against.
-///
-///
-
- var ret = jQuery.map( this, fn, until ),
- // The variable 'args' was introduced in
- // https://github.com/jquery/jquery/commit/52a0238
- // to work around a bug in Chrome 10 (Dev) and should be removed when the bug is fixed.
- // http://code.google.com/p/v8/issues/detail?id=1050
- args = slice.call(arguments);
-
- if ( !runtil.test( name ) ) {
- selector = until;
- }
-
- if ( selector && typeof selector === "string" ) {
- ret = jQuery.filter( selector, ret );
- }
-
- ret = this.length > 1 && !guaranteedUnique[ name ] ? jQuery.unique( ret ) : ret;
-
- if ( (this.length > 1 || rmultiselector.test( selector )) && rparentsprev.test( name ) ) {
- ret = ret.reverse();
- }
-
- return this.pushStack( ret, name, args.join(",") );
- };
-jQuery.prototype.not = function( selector ) {
-///
-/// Remove elements from the set of matched elements.
-///
1 - not(selector)
-///
2 - not(elements)
-///
3 - not(function(index))
-///
-///
-/// A string containing a selector expression to match elements against.
-///
-///
-
- return this.pushStack( winnow(this, selector, false), "not", selector);
- };
-jQuery.prototype.offset = function( options ) {
-///
-/// 1: Get the current coordinates of the first element in the set of matched elements, relative to the document.
-///
1.1 - offset()
-///
2: Set the current coordinates of every element in the set of matched elements, relative to the document.
-///
2.1 - offset(coordinates)
-///
2.2 - offset(function(index, coords))
-///
-///
-/// An object containing the properties top and left, which are integers indicating the new top and left coordinates for the elements.
-///
-///
-
- var elem = this[0], box;
-
- if ( options ) {
- return this.each(function( i ) {
- jQuery.offset.setOffset( this, options, i );
- });
- }
-
- if ( !elem || !elem.ownerDocument ) {
- return null;
- }
-
- if ( elem === elem.ownerDocument.body ) {
- return jQuery.offset.bodyOffset( elem );
- }
-
- try {
- box = elem.getBoundingClientRect();
- } catch(e) {}
-
- var doc = elem.ownerDocument,
- docElem = doc.documentElement;
-
- // Make sure we're not dealing with a disconnected DOM node
- if ( !box || !jQuery.contains( docElem, elem ) ) {
- return box ? { top: box.top, left: box.left } : { top: 0, left: 0 };
- }
-
- var body = doc.body,
- win = getWindow(doc),
- clientTop = docElem.clientTop || body.clientTop || 0,
- clientLeft = docElem.clientLeft || body.clientLeft || 0,
- scrollTop = win.pageYOffset || jQuery.support.boxModel && docElem.scrollTop || body.scrollTop,
- scrollLeft = win.pageXOffset || jQuery.support.boxModel && docElem.scrollLeft || body.scrollLeft,
- top = box.top + scrollTop - clientTop,
- left = box.left + scrollLeft - clientLeft;
-
- return { top: top, left: left };
- };
-jQuery.prototype.offsetParent = function() {
-///
-/// Get the closest ancestor element that is positioned.
-///
-///
-
- return this.map(function() {
- var offsetParent = this.offsetParent || document.body;
- while ( offsetParent && (!rroot.test(offsetParent.nodeName) && jQuery.css(offsetParent, "position") === "static") ) {
- offsetParent = offsetParent.offsetParent;
- }
- return offsetParent;
- });
- };
-jQuery.prototype.one = function( type, data, fn ) {
-///
-/// Attach a handler to an event for the elements. The handler is executed at most once per element.
-///
-///
-/// A string containing one or more JavaScript event types, such as "click" or "submit," or custom event names.
-///
-///
-/// A map of data that will be passed to the event handler.
-///
-///
-/// A function to execute at the time the event is triggered.
-///
-///
-
- var handler;
-
- // Handle object literals
- if ( typeof type === "object" ) {
- for ( var key in type ) {
- this[ name ](key, data, type[key], fn);
- }
- return this;
- }
-
- if ( arguments.length === 2 || data === false ) {
- fn = data;
- data = undefined;
- }
-
- if ( name === "one" ) {
- handler = function( event ) {
- jQuery( this ).unbind( event, handler );
- return fn.apply( this, arguments );
- };
- handler.guid = fn.guid || jQuery.guid++;
- } else {
- handler = fn;
- }
-
- if ( type === "unload" && name !== "one" ) {
- this.one( type, data, fn );
-
- } else {
- for ( var i = 0, l = this.length; i < l; i++ ) {
- jQuery.event.add( this[i], type, handler, data );
- }
- }
-
- return this;
- };
-jQuery.prototype.outerHeight = function( margin ) {
-///
-/// Get the current computed height for the first element in the set of matched elements, including padding, border, and optionally margin.
-///
-///
-/// A Boolean indicating whether to include the element's margin in the calculation.
-///
-///
-
- var elem = this[0];
- return elem && elem.style ?
- parseFloat( jQuery.css( elem, type, margin ? "margin" : "border" ) ) :
- null;
- };
-jQuery.prototype.outerWidth = function( margin ) {
-///
-/// Get the current computed width for the first element in the set of matched elements, including padding and border.
-///
-///
-/// A Boolean indicating whether to include the element's margin in the calculation.
-///
-///
-
- var elem = this[0];
- return elem && elem.style ?
- parseFloat( jQuery.css( elem, type, margin ? "margin" : "border" ) ) :
- null;
- };
-jQuery.prototype.parent = function( until, selector ) {
-///
-/// Get the parent of each element in the current set of matched elements, optionally filtered by a selector.
-///
-///
-/// A string containing a selector expression to match elements against.
-///
-///
-
- var ret = jQuery.map( this, fn, until ),
- // The variable 'args' was introduced in
- // https://github.com/jquery/jquery/commit/52a0238
- // to work around a bug in Chrome 10 (Dev) and should be removed when the bug is fixed.
- // http://code.google.com/p/v8/issues/detail?id=1050
- args = slice.call(arguments);
-
- if ( !runtil.test( name ) ) {
- selector = until;
- }
-
- if ( selector && typeof selector === "string" ) {
- ret = jQuery.filter( selector, ret );
- }
-
- ret = this.length > 1 && !guaranteedUnique[ name ] ? jQuery.unique( ret ) : ret;
-
- if ( (this.length > 1 || rmultiselector.test( selector )) && rparentsprev.test( name ) ) {
- ret = ret.reverse();
- }
-
- return this.pushStack( ret, name, args.join(",") );
- };
-jQuery.prototype.parents = function( until, selector ) {
-///
-/// Get the ancestors of each element in the current set of matched elements, optionally filtered by a selector.
-///
-///
-/// A string containing a selector expression to match elements against.
-///
-///
-
- var ret = jQuery.map( this, fn, until ),
- // The variable 'args' was introduced in
- // https://github.com/jquery/jquery/commit/52a0238
- // to work around a bug in Chrome 10 (Dev) and should be removed when the bug is fixed.
- // http://code.google.com/p/v8/issues/detail?id=1050
- args = slice.call(arguments);
-
- if ( !runtil.test( name ) ) {
- selector = until;
- }
-
- if ( selector && typeof selector === "string" ) {
- ret = jQuery.filter( selector, ret );
- }
-
- ret = this.length > 1 && !guaranteedUnique[ name ] ? jQuery.unique( ret ) : ret;
-
- if ( (this.length > 1 || rmultiselector.test( selector )) && rparentsprev.test( name ) ) {
- ret = ret.reverse();
- }
-
- return this.pushStack( ret, name, args.join(",") );
- };
-jQuery.prototype.parentsUntil = function( until, selector ) {
-///
-/// Get the ancestors of each element in the current set of matched elements, up to but not including the element matched by the selector, DOM node, or jQuery object.
-///
1 - parentsUntil(selector, filter)
-///
2 - parentsUntil(element, filter)
-///
-///
-/// A string containing a selector expression to indicate where to stop matching ancestor elements.
-///
-///
-/// A string containing a selector expression to match elements against.
-///
-///
-
- var ret = jQuery.map( this, fn, until ),
- // The variable 'args' was introduced in
- // https://github.com/jquery/jquery/commit/52a0238
- // to work around a bug in Chrome 10 (Dev) and should be removed when the bug is fixed.
- // http://code.google.com/p/v8/issues/detail?id=1050
- args = slice.call(arguments);
-
- if ( !runtil.test( name ) ) {
- selector = until;
- }
-
- if ( selector && typeof selector === "string" ) {
- ret = jQuery.filter( selector, ret );
- }
-
- ret = this.length > 1 && !guaranteedUnique[ name ] ? jQuery.unique( ret ) : ret;
-
- if ( (this.length > 1 || rmultiselector.test( selector )) && rparentsprev.test( name ) ) {
- ret = ret.reverse();
- }
-
- return this.pushStack( ret, name, args.join(",") );
- };
-jQuery.prototype.position = function() {
-///
-/// Get the current coordinates of the first element in the set of matched elements, relative to the offset parent.
-///
-///
-
- if ( !this[0] ) {
- return null;
- }
-
- var elem = this[0],
-
- // Get *real* offsetParent
- offsetParent = this.offsetParent(),
-
- // Get correct offsets
- offset = this.offset(),
- parentOffset = rroot.test(offsetParent[0].nodeName) ? { top: 0, left: 0 } : offsetParent.offset();
-
- // Subtract element margins
- // note: when an element has margin: auto the offsetLeft and marginLeft
- // are the same in Safari causing offset.left to incorrectly be 0
- offset.top -= parseFloat( jQuery.css(elem, "marginTop") ) || 0;
- offset.left -= parseFloat( jQuery.css(elem, "marginLeft") ) || 0;
-
- // Add offsetParent borders
- parentOffset.top += parseFloat( jQuery.css(offsetParent[0], "borderTopWidth") ) || 0;
- parentOffset.left += parseFloat( jQuery.css(offsetParent[0], "borderLeftWidth") ) || 0;
-
- // Subtract the two offsets
- return {
- top: offset.top - parentOffset.top,
- left: offset.left - parentOffset.left
- };
- };
-jQuery.prototype.prepend = function() {
-///
-/// Insert content, specified by the parameter, to the beginning of each element in the set of matched elements.
-///
1 - prepend(content, content)
-///
2 - prepend(function(index, html))
-///
-///
-/// DOM element, array of elements, HTML string, or jQuery object to insert at the beginning of each element in the set of matched elements.
-///
-///
-/// One or more additional DOM elements, arrays of elements, HTML strings, or jQuery objects to insert at the beginning of each element in the set of matched elements.
-///
-///
-
- return this.domManip(arguments, true, function( elem ) {
- if ( this.nodeType === 1 ) {
- this.insertBefore( elem, this.firstChild );
- }
- });
- };
-jQuery.prototype.prependTo = function( selector ) {
-///
-/// Insert every element in the set of matched elements to the beginning of the target.
-///
-///
-/// A selector, element, HTML string, or jQuery object; the matched set of elements will be inserted at the beginning of the element(s) specified by this parameter.
-///
-///
-
- var ret = [],
- insert = jQuery( selector ),
- parent = this.length === 1 && this[0].parentNode;
-
- if ( parent && parent.nodeType === 11 && parent.childNodes.length === 1 && insert.length === 1 ) {
- insert[ original ]( this[0] );
- return this;
-
- } else {
- for ( var i = 0, l = insert.length; i < l; i++ ) {
- var elems = (i > 0 ? this.clone(true) : this).get();
- jQuery( insert[i] )[ original ]( elems );
- ret = ret.concat( elems );
- }
-
- return this.pushStack( ret, name, insert.selector );
- }
- };
-jQuery.prototype.prev = function( until, selector ) {
-///
-/// Get the immediately preceding sibling of each element in the set of matched elements, optionally filtered by a selector.
-///
-///
-/// A string containing a selector expression to match elements against.
-///
-///
-
- var ret = jQuery.map( this, fn, until ),
- // The variable 'args' was introduced in
- // https://github.com/jquery/jquery/commit/52a0238
- // to work around a bug in Chrome 10 (Dev) and should be removed when the bug is fixed.
- // http://code.google.com/p/v8/issues/detail?id=1050
- args = slice.call(arguments);
-
- if ( !runtil.test( name ) ) {
- selector = until;
- }
-
- if ( selector && typeof selector === "string" ) {
- ret = jQuery.filter( selector, ret );
- }
-
- ret = this.length > 1 && !guaranteedUnique[ name ] ? jQuery.unique( ret ) : ret;
-
- if ( (this.length > 1 || rmultiselector.test( selector )) && rparentsprev.test( name ) ) {
- ret = ret.reverse();
- }
-
- return this.pushStack( ret, name, args.join(",") );
- };
-jQuery.prototype.prevAll = function( until, selector ) {
-///
-/// Get all preceding siblings of each element in the set of matched elements, optionally filtered by a selector.
-///
-///
-/// A string containing a selector expression to match elements against.
-///
-///
-
- var ret = jQuery.map( this, fn, until ),
- // The variable 'args' was introduced in
- // https://github.com/jquery/jquery/commit/52a0238
- // to work around a bug in Chrome 10 (Dev) and should be removed when the bug is fixed.
- // http://code.google.com/p/v8/issues/detail?id=1050
- args = slice.call(arguments);
-
- if ( !runtil.test( name ) ) {
- selector = until;
- }
-
- if ( selector && typeof selector === "string" ) {
- ret = jQuery.filter( selector, ret );
- }
-
- ret = this.length > 1 && !guaranteedUnique[ name ] ? jQuery.unique( ret ) : ret;
-
- if ( (this.length > 1 || rmultiselector.test( selector )) && rparentsprev.test( name ) ) {
- ret = ret.reverse();
- }
-
- return this.pushStack( ret, name, args.join(",") );
- };
-jQuery.prototype.prevUntil = function( until, selector ) {
-///
-/// Get all preceding siblings of each element up to but not including the element matched by the selector, DOM node, or jQuery object.
-///
1 - prevUntil(selector, filter)
-///
2 - prevUntil(element, filter)
-///
-///
-/// A string containing a selector expression to indicate where to stop matching preceding sibling elements.
-///
-///
-/// A string containing a selector expression to match elements against.
-///
-///
-
- var ret = jQuery.map( this, fn, until ),
- // The variable 'args' was introduced in
- // https://github.com/jquery/jquery/commit/52a0238
- // to work around a bug in Chrome 10 (Dev) and should be removed when the bug is fixed.
- // http://code.google.com/p/v8/issues/detail?id=1050
- args = slice.call(arguments);
-
- if ( !runtil.test( name ) ) {
- selector = until;
- }
-
- if ( selector && typeof selector === "string" ) {
- ret = jQuery.filter( selector, ret );
- }
-
- ret = this.length > 1 && !guaranteedUnique[ name ] ? jQuery.unique( ret ) : ret;
-
- if ( (this.length > 1 || rmultiselector.test( selector )) && rparentsprev.test( name ) ) {
- ret = ret.reverse();
- }
-
- return this.pushStack( ret, name, args.join(",") );
- };
-jQuery.prototype.promise = function( type, object ) {
-///
-/// Return a Promise object to observe when all actions of a certain type bound to the collection, queued or not, have finished.
-///
-///
-/// The type of queue that needs to be observed.
-///
-///
-/// Object onto which the promise methods have to be attached
-///
-///
-
- if ( typeof type !== "string" ) {
- object = type;
- type = undefined;
- }
- type = type || "fx";
- var defer = jQuery.Deferred(),
- elements = this,
- i = elements.length,
- count = 1,
- deferDataKey = type + "defer",
- queueDataKey = type + "queue",
- markDataKey = type + "mark",
- tmp;
- function resolve() {
- if ( !( --count ) ) {
- defer.resolveWith( elements, [ elements ] );
- }
- }
- while( i-- ) {
- if (( tmp = jQuery.data( elements[ i ], deferDataKey, undefined, true ) ||
- ( jQuery.data( elements[ i ], queueDataKey, undefined, true ) ||
- jQuery.data( elements[ i ], markDataKey, undefined, true ) ) &&
- jQuery.data( elements[ i ], deferDataKey, jQuery._Deferred(), true ) )) {
- count++;
- tmp.done( resolve );
- }
- }
- resolve();
- return defer.promise();
- };
-jQuery.prototype.prop = function( name, value ) {
-///
-/// 1: Get the value of a property for the first element in the set of matched elements.
-///
1.1 - prop(propertyName)
-///
2: Set one or more properties for the set of matched elements.
-///
2.1 - prop(propertyName, value)
-///
2.2 - prop(map)
-///
2.3 - prop(propertyName, function(index, oldPropertyValue))
-///
-///
-/// The name of the property to set.
-///
-///
-/// A value to set for the property.
-///
-///
-
- return jQuery.access( this, name, value, true, jQuery.prop );
- };
-jQuery.prototype.pushStack = function( elems, name, selector ) {
-///
-/// Add a collection of DOM elements onto the jQuery stack.
-///
1 - pushStack(elements)
-///
2 - pushStack(elements, name, arguments)
-///
-///
-/// An array of elements to push onto the stack and make into a new jQuery object.
-///
-///
-/// The name of a jQuery method that generated the array of elements.
-///
-///
-/// The arguments that were passed in to the jQuery method (for serialization).
-///
-///
-
- // Build a new jQuery matched element set
- var ret = this.constructor();
-
- if ( jQuery.isArray( elems ) ) {
- push.apply( ret, elems );
-
- } else {
- jQuery.merge( ret, elems );
- }
-
- // Add the old object onto the stack (as a reference)
- ret.prevObject = this;
-
- ret.context = this.context;
-
- if ( name === "find" ) {
- ret.selector = this.selector + (this.selector ? " " : "") + selector;
- } else if ( name ) {
- ret.selector = this.selector + "." + name + "(" + selector + ")";
- }
-
- // Return the newly-formed element set
- return ret;
- };
-jQuery.prototype.queue = function( type, data ) {
-///
-/// 1: Show the queue of functions to be executed on the matched elements.
-///
1.1 - queue(queueName)
-///
2: Manipulate the queue of functions to be executed on the matched elements.
-///
2.1 - queue(queueName, newQueue)
-///
2.2 - queue(queueName, callback( next ))
-///
-///
-/// A string containing the name of the queue. Defaults to fx, the standard effects queue.
-///
-///
-/// An array of functions to replace the current queue contents.
-///
-///
-
- if ( typeof type !== "string" ) {
- data = type;
- type = "fx";
- }
-
- if ( data === undefined ) {
- return jQuery.queue( this[0], type );
- }
- return this.each(function() {
- var queue = jQuery.queue( this, type, data );
-
- if ( type === "fx" && queue[0] !== "inprogress" ) {
- jQuery.dequeue( this, type );
- }
- });
- };
-jQuery.prototype.ready = function( fn ) {
-///
-/// Specify a function to execute when the DOM is fully loaded.
-///
-///
-/// A function to execute after the DOM is ready.
-///
-///
-
- // Attach the listeners
- jQuery.bindReady();
-
- // Add the callback
- readyList.done( fn );
-
- return this;
- };
-jQuery.prototype.remove = function( selector, keepData ) {
-///
-/// Remove the set of matched elements from the DOM.
-///
-///
-/// A selector expression that filters the set of matched elements to be removed.
-///
-///
-
- for ( var i = 0, elem; (elem = this[i]) != null; i++ ) {
- if ( !selector || jQuery.filter( selector, [ elem ] ).length ) {
- if ( !keepData && elem.nodeType === 1 ) {
- jQuery.cleanData( elem.getElementsByTagName("*") );
- jQuery.cleanData( [ elem ] );
- }
-
- if ( elem.parentNode ) {
- elem.parentNode.removeChild( elem );
- }
- }
- }
-
- return this;
- };
-jQuery.prototype.removeAttr = function( name ) {
-///
-/// Remove an attribute from each element in the set of matched elements.
-///
-///
-/// An attribute to remove.
-///
-///
-
- return this.each(function() {
- jQuery.removeAttr( this, name );
- });
- };
-jQuery.prototype.removeClass = function( value ) {
-///
-/// Remove a single class, multiple classes, or all classes from each element in the set of matched elements.
-///
1 - removeClass(className)
-///
2 - removeClass(function(index, class))
-///
-///
-/// One or more space-separated classes to be removed from the class attribute of each matched element.
-///
-///
-
- var classNames, i, l, elem, className, c, cl;
-
- if ( jQuery.isFunction( value ) ) {
- return this.each(function( j ) {
- jQuery( this ).removeClass( value.call(this, j, this.className) );
- });
- }
-
- if ( (value && typeof value === "string") || value === undefined ) {
- classNames = (value || "").split( rspace );
-
- for ( i = 0, l = this.length; i < l; i++ ) {
- elem = this[ i ];
-
- if ( elem.nodeType === 1 && elem.className ) {
- if ( value ) {
- className = (" " + elem.className + " ").replace( rclass, " " );
- for ( c = 0, cl = classNames.length; c < cl; c++ ) {
- className = className.replace(" " + classNames[ c ] + " ", " ");
- }
- elem.className = jQuery.trim( className );
-
- } else {
- elem.className = "";
- }
- }
- }
- }
-
- return this;
- };
-jQuery.prototype.removeData = function( key ) {
-///
-/// Remove a previously-stored piece of data.
-///
-///
-/// A string naming the piece of data to delete.
-///
-///
-
- return this.each(function() {
- jQuery.removeData( this, key );
- });
- };
-jQuery.prototype.removeProp = function( name ) {
-///
-/// Remove a property for the set of matched elements.
-///
-///
-/// The name of the property to set.
-///
-///
-
- name = jQuery.propFix[ name ] || name;
- return this.each(function() {
- // try/catch handles cases where IE balks (such as removing a property on window)
- try {
- this[ name ] = undefined;
- delete this[ name ];
- } catch( e ) {}
- });
- };
-jQuery.prototype.replaceAll = function( selector ) {
-///
-/// Replace each target element with the set of matched elements.
-///
-///
-/// A selector expression indicating which element(s) to replace.
-///
-///
-
- var ret = [],
- insert = jQuery( selector ),
- parent = this.length === 1 && this[0].parentNode;
-
- if ( parent && parent.nodeType === 11 && parent.childNodes.length === 1 && insert.length === 1 ) {
- insert[ original ]( this[0] );
- return this;
-
- } else {
- for ( var i = 0, l = insert.length; i < l; i++ ) {
- var elems = (i > 0 ? this.clone(true) : this).get();
- jQuery( insert[i] )[ original ]( elems );
- ret = ret.concat( elems );
- }
-
- return this.pushStack( ret, name, insert.selector );
- }
- };
-jQuery.prototype.replaceWith = function( value ) {
-///
-/// Replace each element in the set of matched elements with the provided new content.
-///
1 - replaceWith(newContent)
-///
2 - replaceWith(function)
-///
-///
-/// The content to insert. May be an HTML string, DOM element, or jQuery object.
-///
-///
-
- if ( this[0] && this[0].parentNode ) {
- // Make sure that the elements are removed from the DOM before they are inserted
- // this can help fix replacing a parent with child elements
- if ( jQuery.isFunction( value ) ) {
- return this.each(function(i) {
- var self = jQuery(this), old = self.html();
- self.replaceWith( value.call( this, i, old ) );
- });
- }
-
- if ( typeof value !== "string" ) {
- value = jQuery( value ).detach();
- }
-
- return this.each(function() {
- var next = this.nextSibling,
- parent = this.parentNode;
-
- jQuery( this ).remove();
-
- if ( next ) {
- jQuery(next).before( value );
- } else {
- jQuery(parent).append( value );
- }
- });
- } else {
- return this.length ?
- this.pushStack( jQuery(jQuery.isFunction(value) ? value() : value), "replaceWith", value ) :
- this;
- }
- };
-jQuery.prototype.resize = function( data, fn ) {
-///
-/// Bind an event handler to the "resize" JavaScript event, or trigger that event on an element.
-///
1 - resize(handler(eventObject))
-///
2 - resize(eventData, handler(eventObject))
-///
3 - resize()
-///
-///
-/// A map of data that will be passed to the event handler.
-///
-///
-/// A function to execute each time the event is triggered.
-///
-///
-
- if ( fn == null ) {
- fn = data;
- data = null;
- }
-
- return arguments.length > 0 ?
- this.bind( name, data, fn ) :
- this.trigger( name );
- };
-jQuery.prototype.scroll = function( data, fn ) {
-///
-/// Bind an event handler to the "scroll" JavaScript event, or trigger that event on an element.
-///
1 - scroll(handler(eventObject))
-///
2 - scroll(eventData, handler(eventObject))
-///
3 - scroll()
-///
-///
-/// A map of data that will be passed to the event handler.
-///
-///
-/// A function to execute each time the event is triggered.
-///
-///
-
- if ( fn == null ) {
- fn = data;
- data = null;
- }
-
- return arguments.length > 0 ?
- this.bind( name, data, fn ) :
- this.trigger( name );
- };
-jQuery.prototype.scrollLeft = function( val ) {
-///
-/// 1: Get the current horizontal position of the scroll bar for the first element in the set of matched elements.
-///
1.1 - scrollLeft()
-///
2: Set the current horizontal position of the scroll bar for each of the set of matched elements.
-///
2.1 - scrollLeft(value)
-///
-///
-/// An integer indicating the new position to set the scroll bar to.
-///
-///
-
- var elem, win;
-
- if ( val === undefined ) {
- elem = this[ 0 ];
-
- if ( !elem ) {
- return null;
- }
-
- win = getWindow( elem );
-
- // Return the scroll offset
- return win ? ("pageXOffset" in win) ? win[ i ? "pageYOffset" : "pageXOffset" ] :
- jQuery.support.boxModel && win.document.documentElement[ method ] ||
- win.document.body[ method ] :
- elem[ method ];
- }
-
- // Set the scroll offset
- return this.each(function() {
- win = getWindow( this );
-
- if ( win ) {
- win.scrollTo(
- !i ? val : jQuery( win ).scrollLeft(),
- i ? val : jQuery( win ).scrollTop()
- );
-
- } else {
- this[ method ] = val;
- }
- });
- };
-jQuery.prototype.scrollTop = function( val ) {
-///
-/// 1: Get the current vertical position of the scroll bar for the first element in the set of matched elements.
-///
1.1 - scrollTop()
-///
2: Set the current vertical position of the scroll bar for each of the set of matched elements.
-///
2.1 - scrollTop(value)
-///
-///
-/// An integer indicating the new position to set the scroll bar to.
-///
-///
-
- var elem, win;
-
- if ( val === undefined ) {
- elem = this[ 0 ];
-
- if ( !elem ) {
- return null;
- }
-
- win = getWindow( elem );
-
- // Return the scroll offset
- return win ? ("pageXOffset" in win) ? win[ i ? "pageYOffset" : "pageXOffset" ] :
- jQuery.support.boxModel && win.document.documentElement[ method ] ||
- win.document.body[ method ] :
- elem[ method ];
- }
-
- // Set the scroll offset
- return this.each(function() {
- win = getWindow( this );
-
- if ( win ) {
- win.scrollTo(
- !i ? val : jQuery( win ).scrollLeft(),
- i ? val : jQuery( win ).scrollTop()
- );
-
- } else {
- this[ method ] = val;
- }
- });
- };
-jQuery.prototype.select = function( data, fn ) {
-///
-/// Bind an event handler to the "select" JavaScript event, or trigger that event on an element.
-///
1 - select(handler(eventObject))
-///
2 - select(eventData, handler(eventObject))
-///
3 - select()
-///
-///
-/// A map of data that will be passed to the event handler.
-///
-///
-/// A function to execute each time the event is triggered.
-///
-///
-
- if ( fn == null ) {
- fn = data;
- data = null;
- }
-
- return arguments.length > 0 ?
- this.bind( name, data, fn ) :
- this.trigger( name );
- };
-jQuery.prototype.serialize = function() {
-///
-/// Encode a set of form elements as a string for submission.
-///
-///
-
- return jQuery.param( this.serializeArray() );
- };
-jQuery.prototype.serializeArray = function() {
-///
-/// Encode a set of form elements as an array of names and values.
-///
-///
-
- return this.map(function(){
- return this.elements ? jQuery.makeArray( this.elements ) : this;
- })
- .filter(function(){
- return this.name && !this.disabled &&
- ( this.checked || rselectTextarea.test( this.nodeName ) ||
- rinput.test( this.type ) );
- })
- .map(function( i, elem ){
- var val = jQuery( this ).val();
-
- return val == null ?
- null :
- jQuery.isArray( val ) ?
- jQuery.map( val, function( val, i ){
- return { name: elem.name, value: val.replace( rCRLF, "\r\n" ) };
- }) :
- { name: elem.name, value: val.replace( rCRLF, "\r\n" ) };
- }).get();
- };
-jQuery.prototype.show = function( speed, easing, callback ) {
-///
-/// Display the matched elements.
-///
1 - show()
-///
2 - show(duration, callback)
-///
3 - show(duration, easing, callback)
-///
-///
-/// A string or number determining how long the animation will run.
-///
-///
-/// A string indicating which easing function to use for the transition.
-///
-///
-/// A function to call once the animation is complete.
-///
-///
-
- var elem, display;
-
- if ( speed || speed === 0 ) {
- return this.animate( genFx("show", 3), speed, easing, callback);
-
- } else {
- for ( var i = 0, j = this.length; i < j; i++ ) {
- elem = this[i];
-
- if ( elem.style ) {
- display = elem.style.display;
-
- // Reset the inline display of this element to learn if it is
- // being hidden by cascaded rules or not
- if ( !jQuery._data(elem, "olddisplay") && display === "none" ) {
- display = elem.style.display = "";
- }
-
- // Set elements which have been overridden with display: none
- // in a stylesheet to whatever the default browser style is
- // for such an element
- if ( display === "" && jQuery.css( elem, "display" ) === "none" ) {
- jQuery._data(elem, "olddisplay", defaultDisplay(elem.nodeName));
- }
- }
- }
-
- // Set the display of most of the elements in a second loop
- // to avoid the constant reflow
- for ( i = 0; i < j; i++ ) {
- elem = this[i];
-
- if ( elem.style ) {
- display = elem.style.display;
-
- if ( display === "" || display === "none" ) {
- elem.style.display = jQuery._data(elem, "olddisplay") || "";
- }
- }
- }
-
- return this;
- }
- };
-jQuery.prototype.siblings = function( until, selector ) {
-///
-/// Get the siblings of each element in the set of matched elements, optionally filtered by a selector.
-///
-///
-/// A string containing a selector expression to match elements against.
-///
-///
-
- var ret = jQuery.map( this, fn, until ),
- // The variable 'args' was introduced in
- // https://github.com/jquery/jquery/commit/52a0238
- // to work around a bug in Chrome 10 (Dev) and should be removed when the bug is fixed.
- // http://code.google.com/p/v8/issues/detail?id=1050
- args = slice.call(arguments);
-
- if ( !runtil.test( name ) ) {
- selector = until;
- }
-
- if ( selector && typeof selector === "string" ) {
- ret = jQuery.filter( selector, ret );
- }
-
- ret = this.length > 1 && !guaranteedUnique[ name ] ? jQuery.unique( ret ) : ret;
-
- if ( (this.length > 1 || rmultiselector.test( selector )) && rparentsprev.test( name ) ) {
- ret = ret.reverse();
- }
-
- return this.pushStack( ret, name, args.join(",") );
- };
-jQuery.prototype.size = function() {
-///
-/// Return the number of elements in the jQuery object.
-///
-///
-
- return this.length;
- };
-jQuery.prototype.slice = function() {
-///
-/// Reduce the set of matched elements to a subset specified by a range of indices.
-///
-///
-/// An integer indicating the 0-based position at which the elements begin to be selected. If negative, it indicates an offset from the end of the set.
-///
-///
-/// An integer indicating the 0-based position at which the elements stop being selected. If negative, it indicates an offset from the end of the set. If omitted, the range continues until the end of the set.
-///
-///
-
- return this.pushStack( slice.apply( this, arguments ),
- "slice", slice.call(arguments).join(",") );
- };
-jQuery.prototype.slideDown = function( speed, easing, callback ) {
-///
-/// Display the matched elements with a sliding motion.
-///
1 - slideDown(duration, callback)
-///
2 - slideDown(duration, easing, callback)
-///
-///
-/// A string or number determining how long the animation will run.
-///
-///
-/// A string indicating which easing function to use for the transition.
-///
-///
-/// A function to call once the animation is complete.
-///
-///
-
- return this.animate( props, speed, easing, callback );
- };
-jQuery.prototype.slideToggle = function( speed, easing, callback ) {
-///
-/// Display or hide the matched elements with a sliding motion.
-///
1 - slideToggle(duration, callback)
-///
2 - slideToggle(duration, easing, callback)
-///
-///
-/// A string or number determining how long the animation will run.
-///
-///
-/// A string indicating which easing function to use for the transition.
-///
-///
-/// A function to call once the animation is complete.
-///
-///
-
- return this.animate( props, speed, easing, callback );
- };
-jQuery.prototype.slideUp = function( speed, easing, callback ) {
-///
-/// Hide the matched elements with a sliding motion.
-///
1 - slideUp(duration, callback)
-///
2 - slideUp(duration, easing, callback)
-///
-///
-/// A string or number determining how long the animation will run.
-///
-///
-/// A string indicating which easing function to use for the transition.
-///
-///
-/// A function to call once the animation is complete.
-///
-///
-
- return this.animate( props, speed, easing, callback );
- };
-jQuery.prototype.stop = function( clearQueue, gotoEnd ) {
-///
-/// Stop the currently-running animation on the matched elements.
-///
-///
-/// A Boolean indicating whether to remove queued animation as well. Defaults to false.
-///
-///
-/// A Boolean indicating whether to complete the current animation immediately. Defaults to false.
-///
-///
-
- if ( clearQueue ) {
- this.queue([]);
- }
-
- this.each(function() {
- var timers = jQuery.timers,
- i = timers.length;
- // clear marker counters if we know they won't be
- if ( !gotoEnd ) {
- jQuery._unmark( true, this );
- }
- while ( i-- ) {
- if ( timers[i].elem === this ) {
- if (gotoEnd) {
- // force the next step to be the last
- timers[i](true);
- }
-
- timers.splice(i, 1);
- }
- }
- });
-
- // start the next in the queue if the last step wasn't forced
- if ( !gotoEnd ) {
- this.dequeue();
- }
-
- return this;
- };
-jQuery.prototype.submit = function( data, fn ) {
-///
-/// Bind an event handler to the "submit" JavaScript event, or trigger that event on an element.
-///
1 - submit(handler(eventObject))
-///
2 - submit(eventData, handler(eventObject))
-///
3 - submit()
-///
-///
-/// A map of data that will be passed to the event handler.
-///
-///
-/// A function to execute each time the event is triggered.
-///
-///
-
- if ( fn == null ) {
- fn = data;
- data = null;
- }
-
- return arguments.length > 0 ?
- this.bind( name, data, fn ) :
- this.trigger( name );
- };
-jQuery.prototype.text = function( text ) {
-///
-/// 1: Get the combined text contents of each element in the set of matched elements, including their descendants.
-///
1.1 - text()
-///
2: Set the content of each element in the set of matched elements to the specified text.
-///
2.1 - text(textString)
-///
2.2 - text(function(index, text))
-///
-///
-/// A string of text to set as the content of each matched element.
-///
-///
-
- if ( jQuery.isFunction(text) ) {
- return this.each(function(i) {
- var self = jQuery( this );
-
- self.text( text.call(this, i, self.text()) );
- });
- }
-
- if ( typeof text !== "object" && text !== undefined ) {
- return this.empty().append( (this[0] && this[0].ownerDocument || document).createTextNode( text ) );
- }
-
- return jQuery.text( this );
- };
-jQuery.prototype.toArray = function() {
-///
-/// Retrieve all the DOM elements contained in the jQuery set, as an array.
-///
-///
-
- return slice.call( this, 0 );
- };
-jQuery.prototype.toggle = function( fn, fn2, callback ) {
-///
-/// 1: Bind two or more handlers to the matched elements, to be executed on alternate clicks.
-///
1.1 - toggle(handler(eventObject), handler(eventObject), handler(eventObject))
-///
2: Display or hide the matched elements.
-///
2.1 - toggle(duration, callback)
-///
2.2 - toggle(duration, easing, callback)
-///
2.3 - toggle(showOrHide)
-///
-///
-/// A function to execute every even time the element is clicked.
-///
-///
-/// A function to execute every odd time the element is clicked.
-///
-///
-/// Additional handlers to cycle through after clicks.
-///
-///
-
- var bool = typeof fn === "boolean";
-
- if ( jQuery.isFunction(fn) && jQuery.isFunction(fn2) ) {
- this._toggle.apply( this, arguments );
-
- } else if ( fn == null || bool ) {
- this.each(function() {
- var state = bool ? fn : jQuery(this).is(":hidden");
- jQuery(this)[ state ? "show" : "hide" ]();
- });
-
- } else {
- this.animate(genFx("toggle", 3), fn, fn2, callback);
- }
-
- return this;
- };
-jQuery.prototype.toggleClass = function( value, stateVal ) {
-///
-/// Add or remove one or more classes from each element in the set of matched elements, depending on either the class's presence or the value of the switch argument.
-///
1 - toggleClass(className)
-///
2 - toggleClass(className, switch)
-///
3 - toggleClass(function(index, class, switch), switch)
-///
-///
-/// One or more class names (separated by spaces) to be toggled for each element in the matched set.
-///
-///
-/// A Boolean (not just truthy/falsy) value to determine whether the class should be added or removed.
-///
-///
-
- var type = typeof value,
- isBool = typeof stateVal === "boolean";
-
- if ( jQuery.isFunction( value ) ) {
- return this.each(function( i ) {
- jQuery( this ).toggleClass( value.call(this, i, this.className, stateVal), stateVal );
- });
- }
-
- return this.each(function() {
- if ( type === "string" ) {
- // toggle individual class names
- var className,
- i = 0,
- self = jQuery( this ),
- state = stateVal,
- classNames = value.split( rspace );
-
- while ( (className = classNames[ i++ ]) ) {
- // check each className given, space seperated list
- state = isBool ? state : !self.hasClass( className );
- self[ state ? "addClass" : "removeClass" ]( className );
- }
-
- } else if ( type === "undefined" || type === "boolean" ) {
- if ( this.className ) {
- // store className if set
- jQuery._data( this, "__className__", this.className );
- }
-
- // toggle whole className
- this.className = this.className || value === false ? "" : jQuery._data( this, "__className__" ) || "";
- }
- });
- };
-jQuery.prototype.trigger = function( type, data ) {
-///
-/// Execute all handlers and behaviors attached to the matched elements for the given event type.
-///
1 - trigger(eventType, extraParameters)
-///
2 - trigger(event)
-///
-///
-/// A string containing a JavaScript event type, such as click or submit.
-///
-///
-/// Additional parameters to pass along to the event handler.
-///
-///
-
- return this.each(function() {
- jQuery.event.trigger( type, data, this );
- });
- };
-jQuery.prototype.triggerHandler = function( type, data ) {
-///
-/// Execute all handlers attached to an element for an event.
-///
-///
-/// A string containing a JavaScript event type, such as click or submit.
-///
-///
-/// An array of additional parameters to pass along to the event handler.
-///
-///
-
- if ( this[0] ) {
- return jQuery.event.trigger( type, data, this[0], true );
- }
- };
-jQuery.prototype.unbind = function( type, fn ) {
-///
-/// Remove a previously-attached event handler from the elements.
-///
1 - unbind(eventType, handler(eventObject))
-///
2 - unbind(eventType, false)
-///
3 - unbind(event)
-///
-///
-/// A string containing a JavaScript event type, such as click or submit.
-///
-///
-/// The function that is to be no longer executed.
-///
-///
-
- // Handle object literals
- if ( typeof type === "object" && !type.preventDefault ) {
- for ( var key in type ) {
- this.unbind(key, type[key]);
- }
-
- } else {
- for ( var i = 0, l = this.length; i < l; i++ ) {
- jQuery.event.remove( this[i], type, fn );
- }
- }
-
- return this;
- };
-jQuery.prototype.undelegate = function( selector, types, fn ) {
-///
-/// Remove a handler from the event for all elements which match the current selector, now or in the future, based upon a specific set of root elements.
-///
1 - undelegate()
-///
2 - undelegate(selector, eventType)
-///
3 - undelegate(selector, eventType, handler)
-///
4 - undelegate(selector, events)
-///
5 - undelegate(namespace)
-///
-///
-/// A selector which will be used to filter the event results.
-///
-///
-/// A string containing a JavaScript event type, such as "click" or "keydown"
-///
-///
-/// A function to execute at the time the event is triggered.
-///
-///
-
- if ( arguments.length === 0 ) {
- return this.unbind( "live" );
-
- } else {
- return this.die( types, null, fn, selector );
- }
- };
-jQuery.prototype.unload = function( data, fn ) {
-///
-/// Bind an event handler to the "unload" JavaScript event.
-///
1 - unload(handler(eventObject))
-///
2 - unload(eventData, handler(eventObject))
-///
-///
-/// A map of data that will be passed to the event handler.
-///
-///
-/// A function to execute each time the event is triggered.
-///
-///
-
- if ( fn == null ) {
- fn = data;
- data = null;
- }
-
- return arguments.length > 0 ?
- this.bind( name, data, fn ) :
- this.trigger( name );
- };
-jQuery.prototype.unwrap = function() {
-///
-/// Remove the parents of the set of matched elements from the DOM, leaving the matched elements in their place.
-///
-///
-
- return this.parent().each(function() {
- if ( !jQuery.nodeName( this, "body" ) ) {
- jQuery( this ).replaceWith( this.childNodes );
- }
- }).end();
- };
-jQuery.prototype.val = function( value ) {
-///
-/// 1: Get the current value of the first element in the set of matched elements.
-///
1.1 - val()
-///
2: Set the value of each element in the set of matched elements.
-///
2.1 - val(value)
-///
2.2 - val(function(index, value))
-///
-///
-/// A string of text or an array of strings corresponding to the value of each matched element to set as selected/checked.
-///
-///
-
- var hooks, ret,
- elem = this[0];
-
- if ( !arguments.length ) {
- if ( elem ) {
- hooks = jQuery.valHooks[ elem.nodeName.toLowerCase() ] || jQuery.valHooks[ elem.type ];
-
- if ( hooks && "get" in hooks && (ret = hooks.get( elem, "value" )) !== undefined ) {
- return ret;
- }
-
- ret = elem.value;
-
- return typeof ret === "string" ?
- // handle most common string cases
- ret.replace(rreturn, "") :
- // handle cases where value is null/undef or number
- ret == null ? "" : ret;
- }
-
- return undefined;
- }
-
- var isFunction = jQuery.isFunction( value );
-
- return this.each(function( i ) {
- var self = jQuery(this), val;
-
- if ( this.nodeType !== 1 ) {
- return;
- }
-
- if ( isFunction ) {
- val = value.call( this, i, self.val() );
- } else {
- val = value;
- }
-
- // Treat null/undefined as ""; convert numbers to string
- if ( val == null ) {
- val = "";
- } else if ( typeof val === "number" ) {
- val += "";
- } else if ( jQuery.isArray( val ) ) {
- val = jQuery.map(val, function ( value ) {
- return value == null ? "" : value + "";
- });
- }
-
- hooks = jQuery.valHooks[ this.nodeName.toLowerCase() ] || jQuery.valHooks[ this.type ];
-
- // If set returns undefined, fall back to normal setting
- if ( !hooks || !("set" in hooks) || hooks.set( this, val, "value" ) === undefined ) {
- this.value = val;
- }
- });
- };
-jQuery.prototype.width = function( size ) {
-///
-/// 1: Get the current computed width for the first element in the set of matched elements.
-///
1.1 - width()
-///
2: Set the CSS width of each element in the set of matched elements.
-///
2.1 - width(value)
-///
2.2 - width(function(index, width))
-///
-///
-/// An integer representing the number of pixels, or an integer along with an optional unit of measure appended (as a string).
-///
-///
-
- // Get window width or height
- var elem = this[0];
- if ( !elem ) {
- return size == null ? null : this;
- }
-
- if ( jQuery.isFunction( size ) ) {
- return this.each(function( i ) {
- var self = jQuery( this );
- self[ type ]( size.call( this, i, self[ type ]() ) );
- });
- }
-
- if ( jQuery.isWindow( elem ) ) {
- // Everyone else use document.documentElement or document.body depending on Quirks vs Standards mode
- // 3rd condition allows Nokia support, as it supports the docElem prop but not CSS1Compat
- var docElemProp = elem.document.documentElement[ "client" + name ];
- return elem.document.compatMode === "CSS1Compat" && docElemProp ||
- elem.document.body[ "client" + name ] || docElemProp;
-
- // Get document width or height
- } else if ( elem.nodeType === 9 ) {
- // Either scroll[Width/Height] or offset[Width/Height], whichever is greater
- return Math.max(
- elem.documentElement["client" + name],
- elem.body["scroll" + name], elem.documentElement["scroll" + name],
- elem.body["offset" + name], elem.documentElement["offset" + name]
- );
-
- // Get or set width or height on the element
- } else if ( size === undefined ) {
- var orig = jQuery.css( elem, type ),
- ret = parseFloat( orig );
-
- return jQuery.isNaN( ret ) ? orig : ret;
-
- // Set the width or height on the element (default to pixels if value is unitless)
- } else {
- return this.css( type, typeof size === "string" ? size : size + "px" );
- }
- };
-jQuery.prototype.wrap = function( html ) {
-///
-/// Wrap an HTML structure around each element in the set of matched elements.
-///
1 - wrap(wrappingElement)
-///
2 - wrap(function(index))
-///
-///
-/// An HTML snippet, selector expression, jQuery object, or DOM element specifying the structure to wrap around the matched elements.
-///
-///
-
- return this.each(function() {
- jQuery( this ).wrapAll( html );
- });
- };
-jQuery.prototype.wrapAll = function( html ) {
-///
-/// Wrap an HTML structure around all elements in the set of matched elements.
-///
-///
-/// An HTML snippet, selector expression, jQuery object, or DOM element specifying the structure to wrap around the matched elements.
-///
-///
-
- if ( jQuery.isFunction( html ) ) {
- return this.each(function(i) {
- jQuery(this).wrapAll( html.call(this, i) );
- });
- }
-
- if ( this[0] ) {
- // The elements to wrap the target around
- var wrap = jQuery( html, this[0].ownerDocument ).eq(0).clone(true);
-
- if ( this[0].parentNode ) {
- wrap.insertBefore( this[0] );
- }
-
- wrap.map(function() {
- var elem = this;
-
- while ( elem.firstChild && elem.firstChild.nodeType === 1 ) {
- elem = elem.firstChild;
- }
-
- return elem;
- }).append( this );
- }
-
- return this;
- };
-jQuery.prototype.wrapInner = function( html ) {
-///
-/// Wrap an HTML structure around the content of each element in the set of matched elements.
-///
1 - wrapInner(wrappingElement)
-///
2 - wrapInner(wrappingFunction)
-///
-///
-/// An HTML snippet, selector expression, jQuery object, or DOM element specifying the structure to wrap around the content of the matched elements.
-///
-///
-
- if ( jQuery.isFunction( html ) ) {
- return this.each(function(i) {
- jQuery(this).wrapInner( html.call(this, i) );
- });
- }
-
- return this.each(function() {
- var self = jQuery( this ),
- contents = self.contents();
-
- if ( contents.length ) {
- contents.wrapAll( html );
-
- } else {
- self.append( html );
- }
- });
- };
-jQuery.fn = jQuery.prototype;
-jQuery.fn.init.prototype = jQuery.fn;
-window.jQuery = window.$ = jQuery;
-})(window);
\ No newline at end of file
diff --git a/project/XPST/Scripts/jquery-1.6.2.min.js b/project/XPST/Scripts/jquery-1.6.2.min.js
deleted file mode 100644
index 48590ec..0000000
--- a/project/XPST/Scripts/jquery-1.6.2.min.js
+++ /dev/null
@@ -1,18 +0,0 @@
-/*!
- * jQuery JavaScript Library v1.6.2
- * http://jquery.com/
- *
- * Copyright 2011, John Resig
- * Dual licensed under the MIT or GPL Version 2 licenses.
- * http://jquery.org/license
- *
- * Includes Sizzle.js
- * http://sizzlejs.com/
- * Copyright 2011, The Dojo Foundation
- * Released under the MIT, BSD, and GPL Licenses.
- *
- * Date: Thu Jun 30 14:16:56 2011 -0400
- */
-(function(a,b){function cv(a){return f.isWindow(a)?a:a.nodeType===9?a.defaultView||a.parentWindow:!1}function cs(a){if(!cg[a]){var b=c.body,d=f("<"+a+">").appendTo(b),e=d.css("display");d.remove();if(e==="none"||e===""){ch||(ch=c.createElement("iframe"),ch.frameBorder=ch.width=ch.height=0),b.appendChild(ch);if(!ci||!ch.createElement)ci=(ch.contentWindow||ch.contentDocument).document,ci.write((c.compatMode==="CSS1Compat"?"":"")+""),ci.close();d=ci.createElement(a),ci.body.appendChild(d),e=f.css(d,"display"),b.removeChild(ch)}cg[a]=e}return cg[a]}function cr(a,b){var c={};f.each(cm.concat.apply([],cm.slice(0,b)),function(){c[this]=a});return c}function cq(){cn=b}function cp(){setTimeout(cq,0);return cn=f.now()}function cf(){try{return new a.ActiveXObject("Microsoft.XMLHTTP")}catch(b){}}function ce(){try{return new a.XMLHttpRequest}catch(b){}}function b$(a,c){a.dataFilter&&(c=a.dataFilter(c,a.dataType));var d=a.dataTypes,e={},g,h,i=d.length,j,k=d[0],l,m,n,o,p;for(g=1;g
0){c!=="border"&&f.each(e,function(){c||(d-=parseFloat(f.css(a,"padding"+this))||0),c==="margin"?d+=parseFloat(f.css(a,c+this))||0:d-=parseFloat(f.css(a,"border"+this+"Width"))||0});return d+"px"}d=bx(a,b,b);if(d<0||d==null)d=a.style[b]||0;d=parseFloat(d)||0,c&&f.each(e,function(){d+=parseFloat(f.css(a,"padding"+this))||0,c!=="padding"&&(d+=parseFloat(f.css(a,"border"+this+"Width"))||0),c==="margin"&&(d+=parseFloat(f.css(a,c+this))||0)});return d+"px"}function bm(a,b){b.src?f.ajax({url:b.src,async:!1,dataType:"script"}):f.globalEval((b.text||b.textContent||b.innerHTML||"").replace(be,"/*$0*/")),b.parentNode&&b.parentNode.removeChild(b)}function bl(a){f.nodeName(a,"input")?bk(a):"getElementsByTagName"in a&&f.grep(a.getElementsByTagName("input"),bk)}function bk(a){if(a.type==="checkbox"||a.type==="radio")a.defaultChecked=a.checked}function bj(a){return"getElementsByTagName"in a?a.getElementsByTagName("*"):"querySelectorAll"in a?a.querySelectorAll("*"):[]}function bi(a,b){var c;if(b.nodeType===1){b.clearAttributes&&b.clearAttributes(),b.mergeAttributes&&b.mergeAttributes(a),c=b.nodeName.toLowerCase();if(c==="object")b.outerHTML=a.outerHTML;else if(c!=="input"||a.type!=="checkbox"&&a.type!=="radio"){if(c==="option")b.selected=a.defaultSelected;else if(c==="input"||c==="textarea")b.defaultValue=a.defaultValue}else a.checked&&(b.defaultChecked=b.checked=a.checked),b.value!==a.value&&(b.value=a.value);b.removeAttribute(f.expando)}}function bh(a,b){if(b.nodeType===1&&!!f.hasData(a)){var c=f.expando,d=f.data(a),e=f.data(b,d);if(d=d[c]){var g=d.events;e=e[c]=f.extend({},d);if(g){delete e.handle,e.events={};for(var h in g)for(var i=0,j=g[h].length;i=0===c})}function V(a){return!a||!a.parentNode||a.parentNode.nodeType===11}function N(a,b){return(a&&a!=="*"?a+".":"")+b.replace(z,"`").replace(A,"&")}function M(a){var b,c,d,e,g,h,i,j,k,l,m,n,o,p=[],q=[],r=f._data(this,"events");if(!(a.liveFired===this||!r||!r.live||a.target.disabled||a.button&&a.type==="click")){a.namespace&&(n=new RegExp("(^|\\.)"+a.namespace.split(".").join("\\.(?:.*\\.)?")+"(\\.|$)")),a.liveFired=this;var s=r.live.slice(0);for(i=0;ic)break;a.currentTarget=e.elem,a.data=e.handleObj.data,a.handleObj=e.handleObj,o=e.handleObj.origHandler.apply(e.elem,arguments);if(o===!1||a.isPropagationStopped()){c=e.level,o===!1&&(b=!1);if(a.isImmediatePropagationStopped())break}}return b}}function K(a,c,d){var e=f.extend({},d[0]);e.type=a,e.originalEvent={},e.liveFired=b,f.event.handle.call(c,e),e.isDefaultPrevented()&&d[0].preventDefault()}function E(){return!0}function D(){return!1}function m(a,c,d){var e=c+"defer",g=c+"queue",h=c+"mark",i=f.data(a,e,b,!0);i&&(d==="queue"||!f.data(a,g,b,!0))&&(d==="mark"||!f.data(a,h,b,!0))&&setTimeout(function(){!f.data(a,g,b,!0)&&!f.data(a,h,b,!0)&&(f.removeData(a,e,!0),i.resolve())},0)}function l(a){for(var b in a)if(b!=="toJSON")return!1;return!0}function k(a,c,d){if(d===b&&a.nodeType===1){var e="data-"+c.replace(j,"$1-$2").toLowerCase();d=a.getAttribute(e);if(typeof d=="string"){try{d=d==="true"?!0:d==="false"?!1:d==="null"?null:f.isNaN(d)?i.test(d)?f.parseJSON(d):d:parseFloat(d)}catch(g){}f.data(a,c,d)}else d=b}return d}var c=a.document,d=a.navigator,e=a.location,f=function(){function J(){if(!e.isReady){try{c.documentElement.doScroll("left")}catch(a){setTimeout(J,1);return}e.ready()}}var e=function(a,b){return new e.fn.init(a,b,h)},f=a.jQuery,g=a.$,h,i=/^(?:[^<]*(<[\w\W]+>)[^>]*$|#([\w\-]*)$)/,j=/\S/,k=/^\s+/,l=/\s+$/,m=/\d/,n=/^<(\w+)\s*\/?>(?:<\/\1>)?$/,o=/^[\],:{}\s]*$/,p=/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,q=/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,r=/(?:^|:|,)(?:\s*\[)+/g,s=/(webkit)[ \/]([\w.]+)/,t=/(opera)(?:.*version)?[ \/]([\w.]+)/,u=/(msie) ([\w.]+)/,v=/(mozilla)(?:.*? rv:([\w.]+))?/,w=/-([a-z])/ig,x=function(a,b){return b.toUpperCase()},y=d.userAgent,z,A,B,C=Object.prototype.toString,D=Object.prototype.hasOwnProperty,E=Array.prototype.push,F=Array.prototype.slice,G=String.prototype.trim,H=Array.prototype.indexOf,I={};e.fn=e.prototype={constructor:e,init:function(a,d,f){var g,h,j,k;if(!a)return this;if(a.nodeType){this.context=this[0]=a,this.length=1;return this}if(a==="body"&&!d&&c.body){this.context=c,this[0]=c.body,this.selector=a,this.length=1;return this}if(typeof a=="string"){a.charAt(0)!=="<"||a.charAt(a.length-1)!==">"||a.length<3?g=i.exec(a):g=[null,a,null];if(g&&(g[1]||!d)){if(g[1]){d=d instanceof e?d[0]:d,k=d?d.ownerDocument||d:c,j=n.exec(a),j?e.isPlainObject(d)?(a=[c.createElement(j[1])],e.fn.attr.call(a,d,!0)):a=[k.createElement(j[1])]:(j=e.buildFragment([g[1]],[k]),a=(j.cacheable?e.clone(j.fragment):j.fragment).childNodes);return e.merge(this,a)}h=c.getElementById(g[2]);if(h&&h.parentNode){if(h.id!==g[2])return f.find(a);this.length=1,this[0]=h}this.context=c,this.selector=a;return this}return!d||d.jquery?(d||f).find(a):this.constructor(d).find(a)}if(e.isFunction(a))return f.ready(a);a.selector!==b&&(this.selector=a.selector,this.context=a.context);return e.makeArray(a,this)},selector:"",jquery:"1.6.2",length:0,size:function(){return this.length},toArray:function(){return F.call(this,0)},get:function(a){return a==null?this.toArray():a<0?this[this.length+a]:this[a]},pushStack:function(a,b,c){var d=this.constructor();e.isArray(a)?E.apply(d,a):e.merge(d,a),d.prevObject=this,d.context=this.context,b==="find"?d.selector=this.selector+(this.selector?" ":"")+c:b&&(d.selector=this.selector+"."+b+"("+c+")");return d},each:function(a,b){return e.each(this,a,b)},ready:function(a){e.bindReady(),A.done(a);return this},eq:function(a){return a===-1?this.slice(a):this.slice(a,+a+1)},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},slice:function(){return this.pushStack(F.apply(this,arguments),"slice",F.call(arguments).join(","))},map:function(a){return this.pushStack(e.map(this,function(b,c){return a.call(b,c,b)}))},end:function(){return this.prevObject||this.constructor(null)},push:E,sort:[].sort,splice:[].splice},e.fn.init.prototype=e.fn,e.extend=e.fn.extend=function(){var a,c,d,f,g,h,i=arguments[0]||{},j=1,k=arguments.length,l=!1;typeof i=="boolean"&&(l=i,i=arguments[1]||{},j=2),typeof i!="object"&&!e.isFunction(i)&&(i={}),k===j&&(i=this,--j);for(;j0)return;A.resolveWith(c,[e]),e.fn.trigger&&e(c).trigger("ready").unbind("ready")}},bindReady:function(){if(!A){A=e._Deferred();if(c.readyState==="complete")return setTimeout(e.ready,1);if(c.addEventListener)c.addEventListener("DOMContentLoaded",B,!1),a.addEventListener("load",e.ready,!1);else if(c.attachEvent){c.attachEvent("onreadystatechange",B),a.attachEvent("onload",e.ready);var b=!1;try{b=a.frameElement==null}catch(d){}c.documentElement.doScroll&&b&&J()}}},isFunction:function(a){return e.type(a)==="function"},isArray:Array.isArray||function(a){return e.type(a)==="array"},isWindow:function(a){return a&&typeof a=="object"&&"setInterval"in a},isNaN:function(a){return a==null||!m.test(a)||isNaN(a)},type:function(a){return a==null?String(a):I[C.call(a)]||"object"},isPlainObject:function(a){if(!a||e.type(a)!=="object"||a.nodeType||e.isWindow(a))return!1;if(a.constructor&&!D.call(a,"constructor")&&!D.call(a.constructor.prototype,"isPrototypeOf"))return!1;var c;for(c in a);return c===b||D.call(a,c)},isEmptyObject:function(a){for(var b in a)return!1;return!0},error:function(a){throw a},parseJSON:function(b){if(typeof b!="string"||!b)return null;b=e.trim(b);if(a.JSON&&a.JSON.parse)return a.JSON.parse(b);if(o.test(b.replace(p,"@").replace(q,"]").replace(r,"")))return(new Function("return "+b))();e.error("Invalid JSON: "+b)},parseXML:function(b,c,d){a.DOMParser?(d=new DOMParser,c=d.parseFromString(b,"text/xml")):(c=new ActiveXObject("Microsoft.XMLDOM"),c.async="false",c.loadXML(b)),d=c.documentElement,(!d||!d.nodeName||d.nodeName==="parsererror")&&e.error("Invalid XML: "+b);return c},noop:function(){},globalEval:function(b){b&&j.test(b)&&(a.execScript||function(b){a.eval.call(a,b)})(b)},camelCase:function(a){return a.replace(w,x)},nodeName:function(a,b){return a.nodeName&&a.nodeName.toUpperCase()===b.toUpperCase()},each:function(a,c,d){var f,g=0,h=a.length,i=h===b||e.isFunction(a);if(d){if(i){for(f in a)if(c.apply(a[f],d)===!1)break}else for(;g0&&a[0]&&a[j-1]||j===0||e.isArray(a));if(k)for(;i1?h.call(arguments,0):c,--e||g.resolveWith(g,h.call(b,0))}}var b=arguments,c=0,d=b.length,e=d,g=d<=1&&a&&f.isFunction(a.promise)?a:f.Deferred();if(d>1){for(;ca",d=a.getElementsByTagName("*"),e=a.getElementsByTagName("a")[0];if(!d||!d.length||!e)return{};g=c.createElement("select"),h=g.appendChild(c.createElement("option")),i=a.getElementsByTagName("input")[0],k={leadingWhitespace:a.firstChild.nodeType===3,tbody:!a.getElementsByTagName("tbody").length,htmlSerialize:!!a.getElementsByTagName("link").length,style:/top/.test(e.getAttribute("style")),hrefNormalized:e.getAttribute("href")==="/a",opacity:/^0.55$/.test(e.style.opacity),cssFloat:!!e.style.cssFloat,checkOn:i.value==="on",optSelected:h.selected,getSetAttribute:a.className!=="t",submitBubbles:!0,changeBubbles:!0,focusinBubbles:!1,deleteExpando:!0,noCloneEvent:!0,inlineBlockNeedsLayout:!1,shrinkWrapBlocks:!1,reliableMarginRight:!0},i.checked=!0,k.noCloneChecked=i.cloneNode(!0).checked,g.disabled=!0,k.optDisabled=!h.disabled;try{delete a.test}catch(v){k.deleteExpando=!1}!a.addEventListener&&a.attachEvent&&a.fireEvent&&(a.attachEvent("onclick",function(){k.noCloneEvent=!1}),a.cloneNode(!0).fireEvent("onclick")),i=c.createElement("input"),i.value="t",i.setAttribute("type","radio"),k.radioValue=i.value==="t",i.setAttribute("checked","checked"),a.appendChild(i),l=c.createDocumentFragment(),l.appendChild(a.firstChild),k.checkClone=l.cloneNode(!0).cloneNode(!0).lastChild.checked,a.innerHTML="",a.style.width=a.style.paddingLeft="1px",m=c.getElementsByTagName("body")[0],o=c.createElement(m?"div":"body"),p={visibility:"hidden",width:0,height:0,border:0,margin:0},m&&f.extend(p,{position:"absolute",left:-1e3,top:-1e3});for(t in p)o.style[t]=p[t];o.appendChild(a),n=m||b,n.insertBefore(o,n.firstChild),k.appendChecked=i.checked,k.boxModel=a.offsetWidth===2,"zoom"in a.style&&(a.style.display="inline",a.style.zoom=1,k.inlineBlockNeedsLayout=a.offsetWidth===2,a.style.display="",a.innerHTML="",k.shrinkWrapBlocks=a.offsetWidth!==2),a.innerHTML="",q=a.getElementsByTagName("td"),u=q[0].offsetHeight===0,q[0].style.display="",q[1].style.display="none",k.reliableHiddenOffsets=u&&q[0].offsetHeight===0,a.innerHTML="",c.defaultView&&c.defaultView.getComputedStyle&&(j=c.createElement("div"),j.style.width="0",j.style.marginRight="0",a.appendChild(j),k.reliableMarginRight=(parseInt((c.defaultView.getComputedStyle(j,null)||{marginRight:0}).marginRight,10)||0)===0),o.innerHTML="",n.removeChild(o);if(a.attachEvent)for(t in{submit:1,change:1,focusin:1})s="on"+t,u=s in a,u||(a.setAttribute(s,"return;"),u=typeof a[s]=="function"),k[t+"Bubbles"]=u;o=l=g=h=m=j=a=i=null;return k}(),f.boxModel=f.support.boxModel;var i=/^(?:\{.*\}|\[.*\])$/,j=/([a-z])([A-Z])/g;f.extend({cache:{},uuid:0,expando:"jQuery"+(f.fn.jquery+Math.random()).replace(/\D/g,""),noData:{embed:!0,object:"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000",applet:!0},hasData:function(a){a=a.nodeType?f.cache[a[f.expando]]:a[f.expando];return!!a&&!l(a)},data:function(a,c,d,e){if(!!f.acceptData(a)){var g=f.expando,h=typeof c=="string",i,j=a.nodeType,k=j?f.cache:a,l=j?a[f.expando]:a[f.expando]&&f.expando;if((!l||e&&l&&!k[l][g])&&h&&d===b)return;l||(j?a[f.expando]=l=++f.uuid:l=f.expando),k[l]||(k[l]={},j||(k[l].toJSON=f.noop));if(typeof c=="object"||typeof c=="function")e?k[l][g]=f.extend(k[l][g],c):k[l]=f.extend(k[l],c);i=k[l],e&&(i[g]||(i[g]={}),i=i[g]),d!==b&&(i[f.camelCase(c)]=d);if(c==="events"&&!i[c])return i[g]&&i[g].events;return h?i[f.camelCase(c)]||i[c]:i}},removeData:function(b,c,d){if(!!f.acceptData(b)){var e=f.expando,g=b.nodeType,h=g?f.cache:b,i=g?b[f.expando]:f.expando;if(!h[i])return;if(c){var j=d?h[i][e]:h[i];if(j){delete j[c];if(!l(j))return}}if(d){delete h[i][e];if(!l(h[i]))return}var k=h[i][e];f.support.deleteExpando||h!=a?delete h[i]:h[i]=null,k?(h[i]={},g||(h[i].toJSON=f.noop),h[i][e]=k):g&&(f.support.deleteExpando?delete b[f.expando]:b.removeAttribute?b.removeAttribute(f.expando):b[f.expando]=null)}},_data:function(a,b,c){return f.data(a,b,c,!0)},acceptData:function(a){if(a.nodeName){var b=f.noData[a.nodeName.toLowerCase()];if(b)return b!==!0&&a.getAttribute("classid")===b}return!0}}),f.fn.extend({data:function(a,c){var d=null;if(typeof a=="undefined"){if(this.length){d=f.data(this[0]);if(this[0].nodeType===1){var e=this[0].attributes,g;for(var h=0,i=e.length;h-1)return!0;return!1},val:function(a){var c,d,e=this[0];if(!arguments.length){if(e){c=f.valHooks[e.nodeName.toLowerCase()]||f.valHooks[e.type];if(c&&"get"in c&&(d=c.get(e,"value"))!==b)return d;d=e.value;return typeof d=="string"?d.replace(p,""):d==null?"":d}return b}var g=f.isFunction(a);return this.each(function(d){var e=f(this),h;if(this.nodeType===1){g?h=a.call(this,d,e.val()):h=a,h==null?h="":typeof h=="number"?h+="":f.isArray(h)&&(h=f.map(h,function(a){return a==null?"":a+""})),c=f.valHooks[this.nodeName.toLowerCase()]||f.valHooks[this.type];if(!c||!("set"in c)||c.set(this,h,"value")===b)this.value=h}})}}),f.extend({valHooks:{option:{get:function(a){var b=a.attributes.value;return!b||b.specified?a.value:a.text}},select:{get:function(a){var b,c=a.selectedIndex,d=[],e=a.options,g=a.type==="select-one";if(c<0)return null;for(var h=g?c:0,i=g?c+1:e.length;h=0}),c.length||(a.selectedIndex=-1);return c}}},attrFn:{val:!0,css:!0,html:!0,text:!0,data:!0,width:!0,height:!0,offset:!0},attrFix:{tabindex:"tabIndex"},attr:function(a,c,d,e){var g=a.nodeType;if(!a||g===3||g===8||g===2)return b;if(e&&c in f.attrFn)return f(a)[c](d);if(!("getAttribute"in a))return f.prop(a,c,d);var h,i,j=g!==1||!f.isXMLDoc(a);j&&(c=f.attrFix[c]||c,i=f.attrHooks[c],i||(t.test(c)?i=w:v&&c!=="className"&&(f.nodeName(a,"form")||u.test(c))&&(i=v)));if(d!==b){if(d===null){f.removeAttr(a,c);return b}if(i&&"set"in i&&j&&(h=i.set(a,d,c))!==b)return h;a.setAttribute(c,""+d);return d}if(i&&"get"in i&&j&&(h=i.get(a,c))!==null)return h;h=a.getAttribute(c);return h===null?b:h},removeAttr:function(a,b){var c;a.nodeType===1&&(b=f.attrFix[b]||b,f.support.getSetAttribute?a.removeAttribute(b):(f.attr(a,b,""),a.removeAttributeNode(a.getAttributeNode(b))),t.test(b)&&(c=f.propFix[b]||b)in a&&(a[c]=!1))},attrHooks:{type:{set:function(a,b){if(q.test(a.nodeName)&&a.parentNode)f.error("type property can't be changed");else if(!f.support.radioValue&&b==="radio"&&f.nodeName(a,"input")){var c=a.value;a.setAttribute("type",b),c&&(a.value=c);return b}}},tabIndex:{get:function(a){var c=a.getAttributeNode("tabIndex");return c&&c.specified?parseInt(c.value,10):r.test(a.nodeName)||s.test(a.nodeName)&&a.href?0:b}},value:{get:function(a,b){if(v&&f.nodeName(a,"button"))return v.get(a,b);return b in a?a.value:null},set:function(a,b,c){if(v&&f.nodeName(a,"button"))return v.set(a,b,c);a.value=b}}},propFix:{tabindex:"tabIndex",readonly:"readOnly","for":"htmlFor","class":"className",maxlength:"maxLength",cellspacing:"cellSpacing",cellpadding:"cellPadding",rowspan:"rowSpan",colspan:"colSpan",usemap:"useMap",frameborder:"frameBorder",contenteditable:"contentEditable"},prop:function(a,c,d){var e=a.nodeType;if(!a||e===3||e===8||e===2)return b;var g,h,i=e!==1||!f.isXMLDoc(a);i&&(c=f.propFix[c]||c,h=f.propHooks[c]);return d!==b?h&&"set"in h&&(g=h.set(a,d,c))!==b?g:a[c]=d:h&&"get"in h&&(g=h.get(a,c))!==b?g:a[c]},propHooks:{}}),w={get:function(a,c){return f.prop(a,c)?c.toLowerCase():b},set:function(a,b,c){var d;b===!1?f.removeAttr(a,c):(d=f.propFix[c]||c,d in a&&(a[d]=!0),a.setAttribute(c,c.toLowerCase()));return c}},f.support.getSetAttribute||(f.attrFix=f.propFix,v=f.attrHooks.name=f.attrHooks.title=f.valHooks.button={get:function(a,c){var d;d=a.getAttributeNode(c);return d&&d.nodeValue!==""?d.nodeValue:b},set:function(a,b,c){var d=a.getAttributeNode(c);if(d){d.nodeValue=b;return b}}},f.each(["width","height"],function(a,b){f.attrHooks[b]=f.extend(f.attrHooks[b],{set:function(a,c){if(c===""){a.setAttribute(b,"auto");return c}}})})),f.support.hrefNormalized||f.each(["href","src","width","height"],function(a,c){f.attrHooks[c]=f.extend(f.attrHooks[c],{get:function(a){var d=a.getAttribute(c,2);return d===null?b:d}})}),f.support.style||(f.attrHooks.style={get:function(a){return a.style.cssText.toLowerCase()||b},set:function(a,b){return a.style.cssText=""+b}}),f.support.optSelected||(f.propHooks.selected=f.extend(f.propHooks.selected,{get:function(a){var b=a.parentNode;b&&(b.selectedIndex,b.parentNode&&b.parentNode.selectedIndex)}})),f.support.checkOn||f.each(["radio","checkbox"],function(){f.valHooks[this]={get:function(a){return a.getAttribute("value")===null?"on":a.value}}}),f.each(["radio","checkbox"],function(){f.valHooks[this]=f.extend(f.valHooks[this],{set:function(a,b){if(f.isArray(b))return a.checked=f.inArray(f(a).val(),b)>=0}})});var x=/\.(.*)$/,y=/^(?:textarea|input|select)$/i,z=/\./g,A=/ /g,B=/[^\w\s.|`]/g,C=function(a){return a.replace(B,"\\$&")};f.event={add:function(a,c,d,e){if(a.nodeType!==3&&a.nodeType!==8){if(d===!1)d=D;else if(!d)return;var g,h;d.handler&&(g=d,d=g.handler),d.guid||(d.guid=f.guid++);var i=f._data(a);if(!i)return;var j=i.events,k=i.handle;j||(i.events=j={}),k||(i.handle=k=function(a){return typeof f!="undefined"&&(!a||f.event.triggered!==a.type)?f.event.handle.apply(k.elem,arguments):b}),k.elem=a,c=c.split(" ");var l,m=0,n;while(l=c[m++]){h=g?f.extend({},g):{handler:d,data:e},l.indexOf(".")>-1?(n=l.split("."),l=n.shift(),h.namespace=n.slice(0).sort().join(".")):(n=[],h.namespace=""),h.type=l,h.guid||(h.guid=d.guid);var o=j[l],p=f.event.special[l]||{};if(!o){o=j[l]=[];if(!p.setup||p.setup.call(a,e,n,k)===!1)a.addEventListener?a.addEventListener(l,k,!1):a.attachEvent&&a.attachEvent("on"+l,k)}p.add&&(p.add.call(a,h),h.handler.guid||(h.handler.guid=d.guid)),o.push(h),f.event.global[l]=!0}a=null}},global:{},remove:function(a,c,d,e){if(a.nodeType!==3&&a.nodeType!==8){d===!1&&(d=D);var g,h,i,j,k=0,l,m,n,o,p,q,r,s=f.hasData(a)&&f._data(a),t=s&&s.events;if(!s||!t)return;c&&c.type&&(d=c.handler,c=c.type);if(!c||typeof c=="string"&&c.charAt(0)==="."){c=c||"";for(h in t)f.event.remove(a,h+c);return}c=c.split(" ");while(h=c[k++]){r=h,q=null,l=h.indexOf(".")<0,m=[],l||(m=h.split("."),h=m.shift(),n=new RegExp("(^|\\.)"+f.map(m.slice(0).sort(),C).join("\\.(?:.*\\.)?")+"(\\.|$)")),p=t[h];if(!p)continue;if(!d){for(j=0;j=0&&(h=h.slice(0,-1),j=!0),h.indexOf(".")>=0&&(i=h.split("."),h=i.
-shift(),i.sort());if(!!e&&!f.event.customEvent[h]||!!f.event.global[h]){c=typeof c=="object"?c[f.expando]?c:new f.Event(h,c):new f.Event(h),c.type=h,c.exclusive=j,c.namespace=i.join("."),c.namespace_re=new RegExp("(^|\\.)"+i.join("\\.(?:.*\\.)?")+"(\\.|$)");if(g||!e)c.preventDefault(),c.stopPropagation();if(!e){f.each(f.cache,function(){var a=f.expando,b=this[a];b&&b.events&&b.events[h]&&f.event.trigger(c,d,b.handle.elem)});return}if(e.nodeType===3||e.nodeType===8)return;c.result=b,c.target=e,d=d!=null?f.makeArray(d):[],d.unshift(c);var k=e,l=h.indexOf(":")<0?"on"+h:"";do{var m=f._data(k,"handle");c.currentTarget=k,m&&m.apply(k,d),l&&f.acceptData(k)&&k[l]&&k[l].apply(k,d)===!1&&(c.result=!1,c.preventDefault()),k=k.parentNode||k.ownerDocument||k===c.target.ownerDocument&&a}while(k&&!c.isPropagationStopped());if(!c.isDefaultPrevented()){var n,o=f.event.special[h]||{};if((!o._default||o._default.call(e.ownerDocument,c)===!1)&&(h!=="click"||!f.nodeName(e,"a"))&&f.acceptData(e)){try{l&&e[h]&&(n=e[l],n&&(e[l]=null),f.event.triggered=h,e[h]())}catch(p){}n&&(e[l]=n),f.event.triggered=b}}return c.result}},handle:function(c){c=f.event.fix(c||a.event);var d=((f._data(this,"events")||{})[c.type]||[]).slice(0),e=!c.exclusive&&!c.namespace,g=Array.prototype.slice.call(arguments,0);g[0]=c,c.currentTarget=this;for(var h=0,i=d.length;h-1?f.map(a.options,function(a){return a.selected}).join("-"):"":f.nodeName(a,"select")&&(c=a.selectedIndex);return c},J=function(c){var d=c.target,e,g;if(!!y.test(d.nodeName)&&!d.readOnly){e=f._data(d,"_change_data"),g=I(d),(c.type!=="focusout"||d.type!=="radio")&&f._data(d,"_change_data",g);if(e===b||g===e)return;if(e!=null||g)c.type="change",c.liveFired=b,f.event.trigger(c,arguments[1],d)}};f.event.special.change={filters:{focusout:J,beforedeactivate:J,click:function(a){var b=a.target,c=f.nodeName(b,"input")?b.type:"";(c==="radio"||c==="checkbox"||f.nodeName(b,"select"))&&J.call(this,a)},keydown:function(a){var b=a.target,c=f.nodeName(b,"input")?b.type:"";(a.keyCode===13&&!f.nodeName(b,"textarea")||a.keyCode===32&&(c==="checkbox"||c==="radio")||c==="select-multiple")&&J.call(this,a)},beforeactivate:function(a){var b=a.target;f._data(b,"_change_data",I(b))}},setup:function(a,b){if(this.type==="file")return!1;for(var c in H)f.event.add(this,c+".specialChange",H[c]);return y.test(this.nodeName)},teardown:function(a){f.event.remove(this,".specialChange");return y.test(this.nodeName)}},H=f.event.special.change.filters,H.focus=H.beforeactivate}f.support.focusinBubbles||f.each({focus:"focusin",blur:"focusout"},function(a,b){function e(a){var c=f.event.fix(a);c.type=b,c.originalEvent={},f.event.trigger(c,null,c.target),c.isDefaultPrevented()&&a.preventDefault()}var d=0;f.event.special[b]={setup:function(){d++===0&&c.addEventListener(a,e,!0)},teardown:function(){--d===0&&c.removeEventListener(a,e,!0)}}}),f.each(["bind","one"],function(a,c){f.fn[c]=function(a,d,e){var g;if(typeof a=="object"){for(var h in a)this[c](h,d,a[h],e);return this}if(arguments.length===2||d===!1)e=d,d=b;c==="one"?(g=function(a){f(this).unbind(a,g);return e.apply(this,arguments)},g.guid=e.guid||f.guid++):g=e;if(a==="unload"&&c!=="one")this.one(a,d,e);else for(var i=0,j=this.length;i0?this.bind(b,a,c):this.trigger(b)},f.attrFn&&(f.attrFn[b]=!0)}),function(){function u(a,b,c,d,e,f){for(var g=0,h=d.length;g0){j=i;break}}i=i[a]}d[g]=j}}}function t(a,b,c,d,e,f){for(var g=0,h=d.length;g+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g,d=0,e=Object.prototype.toString,g=!1,h=!0,i=/\\/g,j=/\W/;[0,0].sort(function(){h=!1;return 0});var k=function(b,d,f,g){f=f||[],d=d||c;var h=d;if(d.nodeType!==1&&d.nodeType!==9)return[];if(!b||typeof b!="string")return f;var i,j,n,o,q,r,s,t,u=!0,w=k.isXML(d),x=[],y=b;do{a.exec(""),i=a.exec(y);if(i){y=i[3],x.push(i[1]);if(i[2]){o=i[3];break}}}while(i);if(x.length>1&&m.exec(b))if(x.length===2&&l.relative[x[0]])j=v(x[0]+x[1],d);else{j=l.relative[x[0]]?[d]:k(x.shift(),d);while(x.length)b=x.shift(),l.relative[b]&&(b+=x.shift()),j=v(b,j)}else{!g&&x.length>1&&d.nodeType===9&&!w&&l.match.ID.test(x[0])&&!l.match.ID.test(x[x.length-1])&&(q=k.find(x.shift(),d,w),d=q.expr?k.filter(q.expr,q.set)[0]:q.set[0]);if(d){q=g?{expr:x.pop(),set:p(g)}:k.find(x.pop(),x.length===1&&(x[0]==="~"||x[0]==="+")&&d.parentNode?d.parentNode:d,w),j=q.expr?k.filter(q.expr,q.set):q.set,x.length>0?n=p(j):u=!1;while(x.length)r=x.pop(),s=r,l.relative[r]?s=x.pop():r="",s==null&&(s=d),l.relative[r](n,s,w)}else n=x=[]}n||(n=j),n||k.error(r||b);if(e.call(n)==="[object Array]")if(!u)f.push.apply(f,n);else if(d&&d.nodeType===1)for(t=0;n[t]!=null;t++)n[t]&&(n[t]===!0||n[t].nodeType===1&&k.contains(d,n[t]))&&f.push(j[t]);else for(t=0;n[t]!=null;t++)n[t]&&n[t].nodeType===1&&f.push(j[t]);else p(n,f);o&&(k(o,h,f,g),k.uniqueSort(f));return f};k.uniqueSort=function(a){if(r){g=h,a.sort(r);if(g)for(var b=1;b0},k.find=function(a,b,c){var d;if(!a)return[];for(var e=0,f=l.order.length;e":function(a,b){var c,d=typeof b=="string",e=0,f=a.length;if(d&&!j.test(b)){b=b.toLowerCase();for(;e=0)?c||d.push(h):c&&(b[g]=!1));return!1},ID:function(a){return a[1].replace(i,"")},TAG:function(a,b){return a[1].replace(i,"").toLowerCase()},CHILD:function(a){if(a[1]==="nth"){a[2]||k.error(a[0]),a[2]=a[2].replace(/^\+|\s*/g,"");var b=/(-?)(\d*)(?:n([+\-]?\d*))?/.exec(a[2]==="even"&&"2n"||a[2]==="odd"&&"2n+1"||!/\D/.test(a[2])&&"0n+"+a[2]||a[2]);a[2]=b[1]+(b[2]||1)-0,a[3]=b[3]-0}else a[2]&&k.error(a[0]);a[0]=d++;return a},ATTR:function(a,b,c,d,e,f){var g=a[1]=a[1].replace(i,"");!f&&l.attrMap[g]&&(a[1]=l.attrMap[g]),a[4]=(a[4]||a[5]||"").replace(i,""),a[2]==="~="&&(a[4]=" "+a[4]+" ");return a},PSEUDO:function(b,c,d,e,f){if(b[1]==="not")if((a.exec(b[3])||"").length>1||/^\w/.test(b[3]))b[3]=k(b[3],null,null,c);else{var g=k.filter(b[3],c,d,!0^f);d||e.push.apply(e,g);return!1}else if(l.match.POS.test(b[0])||l.match.CHILD.test(b[0]))return!0;return b},POS:function(a){a.unshift(!0);return a}},filters:{enabled:function(a){return a.disabled===!1&&a.type!=="hidden"},disabled:function(a){return a.disabled===!0},checked:function(a){return a.checked===!0},selected:function(a){a.parentNode&&a.parentNode.selectedIndex;return a.selected===!0},parent:function(a){return!!a.firstChild},empty:function(a){return!a.firstChild},has:function(a,b,c){return!!k(c[3],a).length},header:function(a){return/h\d/i.test(a.nodeName)},text:function(a){var b=a.getAttribute("type"),c=a.type;return a.nodeName.toLowerCase()==="input"&&"text"===c&&(b===c||b===null)},radio:function(a){return a.nodeName.toLowerCase()==="input"&&"radio"===a.type},checkbox:function(a){return a.nodeName.toLowerCase()==="input"&&"checkbox"===a.type},file:function(a){return a.nodeName.toLowerCase()==="input"&&"file"===a.type},password:function(a){return a.nodeName.toLowerCase()==="input"&&"password"===a.type},submit:function(a){var b=a.nodeName.toLowerCase();return(b==="input"||b==="button")&&"submit"===a.type},image:function(a){return a.nodeName.toLowerCase()==="input"&&"image"===a.type},reset:function(a){var b=a.nodeName.toLowerCase();return(b==="input"||b==="button")&&"reset"===a.type},button:function(a){var b=a.nodeName.toLowerCase();return b==="input"&&"button"===a.type||b==="button"},input:function(a){return/input|select|textarea|button/i.test(a.nodeName)},focus:function(a){return a===a.ownerDocument.activeElement}},setFilters:{first:function(a,b){return b===0},last:function(a,b,c,d){return b===d.length-1},even:function(a,b){return b%2===0},odd:function(a,b){return b%2===1},lt:function(a,b,c){return bc[3]-0},nth:function(a,b,c){return c[3]-0===b},eq:function(a,b,c){return c[3]-0===b}},filter:{PSEUDO:function(a,b,c,d){var e=b[1],f=l.filters[e];if(f)return f(a,c,b,d);if(e==="contains")return(a.textContent||a.innerText||k.getText([a])||"").indexOf(b[3])>=0;if(e==="not"){var g=b[3];for(var h=0,i=g.length;h=0}},ID:function(a,b){return a.nodeType===1&&a.getAttribute("id")===b},TAG:function(a,b){return b==="*"&&a.nodeType===1||a.nodeName.toLowerCase()===b},CLASS:function(a,b){return(" "+(a.className||a.getAttribute("class"))+" ").indexOf(b)>-1},ATTR:function(a,b){var c=b[1],d=l.attrHandle[c]?l.attrHandle[c](a):a[c]!=null?a[c]:a.getAttribute(c),e=d+"",f=b[2],g=b[4];return d==null?f==="!=":f==="="?e===g:f==="*="?e.indexOf(g)>=0:f==="~="?(" "+e+" ").indexOf(g)>=0:g?f==="!="?e!==g:f==="^="?e.indexOf(g)===0:f==="$="?e.substr(e.length-g.length)===g:f==="|="?e===g||e.substr(0,g.length+1)===g+"-":!1:e&&d!==!1},POS:function(a,b,c,d){var e=b[2],f=l.setFilters[e];if(f)return f(a,c,b,d)}}},m=l.match.POS,n=function(a,b){return"\\"+(b-0+1)};for(var o in l.match)l.match[o]=new RegExp(l.match[o].source+/(?![^\[]*\])(?![^\(]*\))/.source),l.leftMatch[o]=new RegExp(/(^(?:.|\r|\n)*?)/.source+l.match[o].source.replace(/\\(\d+)/g,n));var p=function(a,b){a=Array.prototype.slice.call(a,0);if(b){b.push.apply(b,a);return b}return a};try{Array.prototype.slice.call(c.documentElement.childNodes,0)[0].nodeType}catch(q){p=function(a,b){var c=0,d=b||[];if(e.call(a)==="[object Array]")Array.prototype.push.apply(d,a);else if(typeof a.length=="number")for(var f=a.length;c",e.insertBefore(a,e.firstChild),c.getElementById(d)&&(l.find.ID=function(a,c,d){if(typeof c.getElementById!="undefined"&&!d){var e=c.getElementById(a[1]);return e?e.id===a[1]||typeof e.getAttributeNode!="undefined"&&e.getAttributeNode("id").nodeValue===a[1]?[e]:b:[]}},l.filter.ID=function(a,b){var c=typeof a.getAttributeNode!="undefined"&&a.getAttributeNode("id");return a.nodeType===1&&c&&c.nodeValue===b}),e.removeChild(a),e=a=null}(),function(){var a=c.createElement("div");a.appendChild(c.createComment("")),a.getElementsByTagName("*").length>0&&(l.find.TAG=function(a,b){var c=b.getElementsByTagName(a[1]);if(a[1]==="*"){var d=[];for(var e=0;c[e];e++)c[e].nodeType===1&&d.push(c[e]);c=d}return c}),a.innerHTML="",a.firstChild&&typeof a.firstChild.getAttribute!="undefined"&&a.firstChild.getAttribute("href")!=="#"&&(l.attrHandle.href=function(a){return a.getAttribute("href",2)}),a=null}(),c.querySelectorAll&&function(){var a=k,b=c.createElement("div"),d="__sizzle__";b.innerHTML="";if(!b.querySelectorAll||b.querySelectorAll(".TEST").length!==0){k=function(b,e,f,g){e=e||c;if(!g&&!k.isXML(e)){var h=/^(\w+$)|^\.([\w\-]+$)|^#([\w\-]+$)/.exec(b);if(h&&(e.nodeType===1||e.nodeType===9)){if(h[1])return p(e.getElementsByTagName(b),f);if(h[2]&&l.find.CLASS&&e.getElementsByClassName)return p(e.getElementsByClassName(h[2]),f)}if(e.nodeType===9){if(b==="body"&&e.body)return p([e.body],f);if(h&&h[3]){var i=e.getElementById(h[3]);if(!i||!i.parentNode)return p([],f);if(i.id===h[3])return p([i],f)}try{return p(e.querySelectorAll(b),f)}catch(j){}}else if(e.nodeType===1&&e.nodeName.toLowerCase()!=="object"){var m=e,n=e.getAttribute("id"),o=n||d,q=e.parentNode,r=/^\s*[+~]/.test(b);n?o=o.replace(/'/g,"\\$&"):e.setAttribute("id",o),r&&q&&(e=e.parentNode);try{if(!r||q)return p(e.querySelectorAll("[id='"+o+"'] "+b),f)}catch(s){}finally{n||m.removeAttribute("id")}}}return a(b,e,f,g)};for(var e in a)k[e]=a[e];b=null}}(),function(){var a=c.documentElement,b=a.matchesSelector||a.mozMatchesSelector||a.webkitMatchesSelector||a.msMatchesSelector;if(b){var d=!b.call(c.createElement("div"),"div"),e=!1;try{b.call(c.documentElement,"[test!='']:sizzle")}catch(f){e=!0}k.matchesSelector=function(a,c){c=c.replace(/\=\s*([^'"\]]*)\s*\]/g,"='$1']");if(!k.isXML(a))try{if(e||!l.match.PSEUDO.test(c)&&!/!=/.test(c)){var f=b.call(a,c);if(f||!d||a.document&&a.document.nodeType!==11)return f}}catch(g){}return k(c,null,null,[a]).length>0}}}(),function(){var a=c.createElement("div");a.innerHTML="";if(!!a.getElementsByClassName&&a.getElementsByClassName("e").length!==0){a.lastChild.className="e";if(a.getElementsByClassName("e").length===1)return;l.order.splice(1,0,"CLASS"),l.find.CLASS=function(a,b,c){if(typeof b.getElementsByClassName!="undefined"&&!c)return b.getElementsByClassName(a[1])},a=null}}(),c.documentElement.contains?k.contains=function(a,b){return a!==b&&(a.contains?a.contains(b):!0)}:c.documentElement.compareDocumentPosition?k.contains=function(a,b){return!!(a.compareDocumentPosition(b)&16)}:k.contains=function(){return!1},k.isXML=function(a){var b=(a?a.ownerDocument||a:0).documentElement;return b?b.nodeName!=="HTML":!1};var v=function(a,b){var c,d=[],e="",f=b.nodeType?[b]:b;while(c=l.match.PSEUDO.exec(a))e+=c[0],a=a.replace(l.match.PSEUDO,"");a=l.relative[a]?a+"*":a;for(var g=0,h=f.length;g0)for(h=g;h0:this.filter(a).length>0)},closest:function(a,b){var c=[],d,e,g=this[0];if(f.isArray(a)){var h,i,j={},k=1;if(g&&a.length){for(d=0,e=a.length;d-1:f(g).is(h))&&c.push({selector:i,elem:g,level:k});g=g.parentNode,k++}}return c}var l=T.test(a)||typeof a!="string"?f(a,b||this.context):0;for(d=0,e=this.length;d-1:f.find.matchesSelector(g,a)){c.push(g);break}g=g.parentNode;if(!g||!g.ownerDocument||g===b||g.nodeType===11)break}}c=c.length>1?f.unique(c):c;return this.pushStack(c,"closest",a)},index:function(a){if(!a||typeof a=="string")return f.inArray(this[0],a?f(a):this.parent().children());return f.inArray(a.jquery?a[0]:a,this)},add:function(a,b){var c=typeof a=="string"?f(a,b):f.makeArray(a&&a.nodeType?[a]:a),d=f.merge(this.get(),c);return this.pushStack(V(c[0])||V(d[0])?d:f.unique(d))},andSelf:function(){return this.add(this.prevObject)}}),f.each({parent:function(a){var b=a.parentNode;return b&&b.nodeType!==11?b:null},parents:function(a){return f.dir(a,"parentNode")},parentsUntil:function(a,b,c){return f.dir(a,"parentNode",c)},next:function(a){return f.nth(a,2,"nextSibling")},prev:function(a){return f.nth(a,2,"previousSibling")},nextAll:function(a){return f.dir(a,"nextSibling")},prevAll:function(a){return f.dir(a,"previousSibling")},nextUntil:function(a,b,c){return f.dir(a,"nextSibling",c)},prevUntil:function(a,b,c){return f.dir(a,"previousSibling",c)},siblings:function(a){return f.sibling(a.parentNode.firstChild,a)},children:function(a){return f.sibling(a.firstChild)},contents:function(a){return f.nodeName(a,"iframe")?a.contentDocument||a.contentWindow.document:f.makeArray(a.childNodes)}},function(a,b){f.fn[a]=function(c,d){var e=f.map(this,b,c),g=S.call(arguments);O.test(a)||(d=c),d&&typeof d=="string"&&(e=f.filter(d,e)),e=this.length>1&&!U[a]?f.unique(e):e,(this.length>1||Q.test(d))&&P.test(a)&&(e=e.reverse());return this.pushStack(e,a,g.join(","))}}),f.extend({filter:function(a,b,c){c&&(a=":not("+a+")");return b.length===1?f.find.matchesSelector(b[0],a)?[b[0]]:[]:f.find.matches(a,b)},dir:function(a,c,d){var e=[],g=a[c];while(g&&g.nodeType!==9&&(d===b||g.nodeType!==1||!f(g).is(d)))g.nodeType===1&&e.push(g),g=g[c];return e},nth:function(a,b,c,d){b=b||1;var e=0;for(;a;a=a[c])if(a.nodeType===1&&++e===b)break;return a},sibling:function(a,b){var c=[];for(;a;a=a.nextSibling)a.nodeType===1&&a!==b&&c.push(a);return c}});var X=/ jQuery\d+="(?:\d+|null)"/g,Y=/^\s+/,Z=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/ig,$=/<([\w:]+)/,_=/",""],legend:[1,""],thead:[1,""],tr:[2,""],td:[3,""],col:[2,""],area:[1,""],_default:[0,"",""]};bf.optgroup=bf.option,bf.tbody=bf.tfoot=bf.colgroup=bf.caption=bf.thead,bf.th=bf.td,f.support.htmlSerialize||(bf._default=[1,"div","
"]),f.fn.extend({text:function(a){if(f.isFunction(a))return this.each(function(b){var c=f(this);c.text(a.call(this,b,c.text()))});if(typeof a!="object"&&a!==b)return this.empty().append((this[0]&&this[0].ownerDocument||c).createTextNode(a));return f.text(this)},wrapAll:function(a){if(f.isFunction(a))return this.each(function(b){f(this).wrapAll(a.call(this,b))});if(this[0]){var b=f(a,this[0].ownerDocument).eq(0).clone(!0);this[0].parentNode&&b.insertBefore(this[0]),b.map(function(){var a=this;while(a.firstChild&&a.firstChild.nodeType===1)a=a.firstChild;return a}).append(this)}return this},wrapInner:function(a){if(f.isFunction(a))return this.each(function(b){f(this).wrapInner(a.call(this,b))});return this.each(function(){var b=f(this),c=b.contents();c.length?c.wrapAll(a):b.append(a)})},wrap:function(a){return this.each(function(){f(this).wrapAll(a)})},unwrap:function(){return this.parent().each(function(){f.nodeName(this,"body")||f(this).replaceWith(this.childNodes)}).end()},append:function(){return this.domManip(arguments,!0,function(a){this.nodeType===1&&this.appendChild(a)})},prepend:function(){return this.domManip(arguments,!0,function(a){this.nodeType===1&&this.insertBefore(a,this.firstChild)})},before:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,!1,function(a){this.parentNode.insertBefore(a,this)});if(arguments.length){var a=f(arguments[0]);a.push.apply(a,this.toArray());return this.pushStack(a,"before",arguments)}},after:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,!1,function(a){this.parentNode.insertBefore(a,this.nextSibling)});if(arguments.length){var a=this.pushStack(this,"after",arguments);a.push.apply(a,f(arguments[0]).toArray());return a}},remove:function(a,b){for(var c=0,d;(d=this[c])!=null;c++)if(!a||f.filter(a,[d]).length)!b&&d.nodeType===1&&(f.cleanData(d.getElementsByTagName("*")),f.cleanData([d])),d.parentNode&&d.parentNode.removeChild(d);return this},empty:function(){for(var a=0,b;(b=this[a])!=null;a++){b.nodeType===1&&f.cleanData(b.getElementsByTagName("*"));while(b.firstChild)b.removeChild(b.firstChild)}return this},clone:function(a,b){a=a==null?!1:a,b=b==null?a:b;return this.map(function(){return f.clone(this,a,b)})},html:function(a){if(a===b)return this[0]&&this[0].nodeType===1?this[0].innerHTML.replace(X,""):null;if(typeof a=="string"&&!bb.test(a)&&(f.support.leadingWhitespace||!Y.test(a))&&!bf[($.exec(a)||["",""])[1].toLowerCase()]){a=a.replace(Z,"<$1>$2>");try{for(var c=0,d=this.length;c1&&l0?this.clone(!0):this).get();f(e[h])[b](j),d=d.concat(j
-)}return this.pushStack(d,a,e.selector)}}),f.extend({clone:function(a,b,c){var d=a.cloneNode(!0),e,g,h;if((!f.support.noCloneEvent||!f.support.noCloneChecked)&&(a.nodeType===1||a.nodeType===11)&&!f.isXMLDoc(a)){bi(a,d),e=bj(a),g=bj(d);for(h=0;e[h];++h)bi(e[h],g[h])}if(b){bh(a,d);if(c){e=bj(a),g=bj(d);for(h=0;e[h];++h)bh(e[h],g[h])}}e=g=null;return d},clean:function(a,b,d,e){var g;b=b||c,typeof b.createElement=="undefined"&&(b=b.ownerDocument||b[0]&&b[0].ownerDocument||c);var h=[],i;for(var j=0,k;(k=a[j])!=null;j++){typeof k=="number"&&(k+="");if(!k)continue;if(typeof k=="string")if(!ba.test(k))k=b.createTextNode(k);else{k=k.replace(Z,"<$1>$2>");var l=($.exec(k)||["",""])[1].toLowerCase(),m=bf[l]||bf._default,n=m[0],o=b.createElement("div");o.innerHTML=m[1]+k+m[2];while(n--)o=o.lastChild;if(!f.support.tbody){var p=_.test(k),q=l==="table"&&!p?o.firstChild&&o.firstChild.childNodes:m[1]===""&&!p?o.childNodes:[];for(i=q.length-1;i>=0;--i)f.nodeName(q[i],"tbody")&&!q[i].childNodes.length&&q[i].parentNode.removeChild(q[i])}!f.support.leadingWhitespace&&Y.test(k)&&o.insertBefore(b.createTextNode(Y.exec(k)[0]),o.firstChild),k=o.childNodes}var r;if(!f.support.appendChecked)if(k[0]&&typeof (r=k.length)=="number")for(i=0;i=0)return b+"px"}}}),f.support.opacity||(f.cssHooks.opacity={get:function(a,b){return bo.test((b&&a.currentStyle?a.currentStyle.filter:a.style.filter)||"")?parseFloat(RegExp.$1)/100+"":b?"1":""},set:function(a,b){var c=a.style,d=a.currentStyle;c.zoom=1;var e=f.isNaN(b)?"":"alpha(opacity="+b*100+")",g=d&&d.filter||c.filter||"";c.filter=bn.test(g)?g.replace(bn,e):g+" "+e}}),f(function(){f.support.reliableMarginRight||(f.cssHooks.marginRight={get:function(a,b){var c;f.swap(a,{display:"inline-block"},function(){b?c=bx(a,"margin-right","marginRight"):c=a.style.marginRight});return c}})}),c.defaultView&&c.defaultView.getComputedStyle&&(by=function(a,c){var d,e,g;c=c.replace(bp,"-$1").toLowerCase();if(!(e=a.ownerDocument.defaultView))return b;if(g=e.getComputedStyle(a,null))d=g.getPropertyValue(c),d===""&&!f.contains(a.ownerDocument.documentElement,a)&&(d=f.style(a,c));return d}),c.documentElement.currentStyle&&(bz=function(a,b){var c,d=a.currentStyle&&a.currentStyle[b],e=a.runtimeStyle&&a.runtimeStyle[b],f=a.style;!bq.test(d)&&br.test(d)&&(c=f.left,e&&(a.runtimeStyle.left=a.currentStyle.left),f.left=b==="fontSize"?"1em":d||0,d=f.pixelLeft+"px",f.left=c,e&&(a.runtimeStyle.left=e));return d===""?"auto":d}),bx=by||bz,f.expr&&f.expr.filters&&(f.expr.filters.hidden=function(a){var b=a.offsetWidth,c=a.offsetHeight;return b===0&&c===0||!f.support.reliableHiddenOffsets&&(a.style.display||f.css(a,"display"))==="none"},f.expr.filters.visible=function(a){return!f.expr.filters.hidden(a)});var bB=/%20/g,bC=/\[\]$/,bD=/\r?\n/g,bE=/#.*$/,bF=/^(.*?):[ \t]*([^\r\n]*)\r?$/mg,bG=/^(?:color|date|datetime|email|hidden|month|number|password|range|search|tel|text|time|url|week)$/i,bH=/^(?:about|app|app\-storage|.+\-extension|file|widget):$/,bI=/^(?:GET|HEAD)$/,bJ=/^\/\//,bK=/\?/,bL=/' );
+
+ iframe_doc.close();
+
+ // Update the Iframe's hash, for great justice.
+ iframe.location.hash = hash;
+ }
+ };
+
+ })();
+ // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ // ^^^^^^^^^^^^^^^^^^^ REMOVE IF NOT SUPPORTING IE6/7/8 ^^^^^^^^^^^^^^^^^^^
+ // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+ return self;
+ })();
+
+})(jQuery,this);
+
+
+(function( $, window, undefined ) {
+
+var createHandler = function( sequential ) {
+
+ // Default to sequential
+ if ( sequential === undefined ) {
+ sequential = true;
+ }
+
+ return function( name, reverse, $to, $from ) {
+
+ var deferred = new $.Deferred(),
+ reverseClass = reverse ? " reverse" : "",
+ active = $.mobile.urlHistory.getActive(),
+ toScroll = active.lastScroll || $.mobile.defaultHomeScroll,
+ screenHeight = $.mobile.getScreenHeight(),
+ maxTransitionOverride = $.mobile.maxTransitionWidth !== false && $( window ).width() > $.mobile.maxTransitionWidth,
+ none = !$.support.cssTransitions || maxTransitionOverride || !name || name === "none" || Math.max( $( window ).scrollTop(), toScroll ) > $.mobile.getMaxScrollForTransition(),
+ toPreClass = " ui-page-pre-in",
+ toggleViewportClass = function() {
+ $.mobile.pageContainer.toggleClass( "ui-mobile-viewport-transitioning viewport-" + name );
+ },
+ scrollPage = function() {
+ // By using scrollTo instead of silentScroll, we can keep things better in order
+ // Just to be precautios, disable scrollstart listening like silentScroll would
+ $.event.special.scrollstart.enabled = false;
+
+ window.scrollTo( 0, toScroll );
+
+ // reenable scrollstart listening like silentScroll would
+ setTimeout( function() {
+ $.event.special.scrollstart.enabled = true;
+ }, 150 );
+ },
+ cleanFrom = function() {
+ $from
+ .removeClass( $.mobile.activePageClass + " out in reverse " + name )
+ .height( "" );
+ },
+ startOut = function() {
+ // if it's not sequential, call the doneOut transition to start the TO page animating in simultaneously
+ if ( !sequential ) {
+ doneOut();
+ }
+ else {
+ $from.animationComplete( doneOut );
+ }
+
+ // Set the from page's height and start it transitioning out
+ // Note: setting an explicit height helps eliminate tiling in the transitions
+ $from
+ .height( screenHeight + $( window ).scrollTop() )
+ .addClass( name + " out" + reverseClass );
+ },
+
+ doneOut = function() {
+
+ if ( $from && sequential ) {
+ cleanFrom();
+ }
+
+ startIn();
+ },
+
+ startIn = function() {
+
+ // Prevent flickering in phonegap container: see comments at #4024 regarding iOS
+ $to.css( "z-index", -10 );
+
+ $to.addClass( $.mobile.activePageClass + toPreClass );
+
+ // Send focus to page as it is now display: block
+ $.mobile.focusPage( $to );
+
+ // Set to page height
+ $to.height( screenHeight + toScroll );
+
+ scrollPage();
+
+ // Restores visibility of the new page: added together with $to.css( "z-index", -10 );
+ $to.css( "z-index", "" );
+
+ if ( !none ) {
+ $to.animationComplete( doneIn );
+ }
+
+ $to
+ .removeClass( toPreClass )
+ .addClass( name + " in" + reverseClass );
+
+ if ( none ) {
+ doneIn();
+ }
+
+ },
+
+ doneIn = function() {
+
+ if ( !sequential ) {
+
+ if ( $from ) {
+ cleanFrom();
+ }
+ }
+
+ $to
+ .removeClass( "out in reverse " + name )
+ .height( "" );
+
+ toggleViewportClass();
+
+ // In some browsers (iOS5), 3D transitions block the ability to scroll to the desired location during transition
+ // This ensures we jump to that spot after the fact, if we aren't there already.
+ if ( $( window ).scrollTop() !== toScroll ) {
+ scrollPage();
+ }
+
+ deferred.resolve( name, reverse, $to, $from, true );
+ };
+
+ toggleViewportClass();
+
+ if ( $from && !none ) {
+ startOut();
+ }
+ else {
+ doneOut();
+ }
+
+ return deferred.promise();
+ };
+};
+
+// generate the handlers from the above
+var sequentialHandler = createHandler(),
+ simultaneousHandler = createHandler( false ),
+ defaultGetMaxScrollForTransition = function() {
+ return $.mobile.getScreenHeight() * 3;
+ };
+
+// Make our transition handler the public default.
+$.mobile.defaultTransitionHandler = sequentialHandler;
+
+//transition handler dictionary for 3rd party transitions
+$.mobile.transitionHandlers = {
+ "default": $.mobile.defaultTransitionHandler,
+ "sequential": sequentialHandler,
+ "simultaneous": simultaneousHandler
+};
+
+$.mobile.transitionFallbacks = {};
+
+// If transition is defined, check if css 3D transforms are supported, and if not, if a fallback is specified
+$.mobile._maybeDegradeTransition = function( transition ) {
+ if ( transition && !$.support.cssTransform3d && $.mobile.transitionFallbacks[ transition ] ) {
+ transition = $.mobile.transitionFallbacks[ transition ];
+ }
+
+ return transition;
+};
+
+// Set the getMaxScrollForTransition to default if no implementation was set by user
+$.mobile.getMaxScrollForTransition = $.mobile.getMaxScrollForTransition || defaultGetMaxScrollForTransition;
+})( jQuery, this );
+
+(function( $, undefined ) {
+
+ //define vars for interal use
+ var $window = $( window ),
+ $html = $( 'html' ),
+ $head = $( 'head' ),
+
+ //url path helpers for use in relative url management
+ path = {
+
+ // This scary looking regular expression parses an absolute URL or its relative
+ // variants (protocol, site, document, query, and hash), into the various
+ // components (protocol, host, path, query, fragment, etc that make up the
+ // URL as well as some other commonly used sub-parts. When used with RegExp.exec()
+ // or String.match, it parses the URL into a results array that looks like this:
+ //
+ // [0]: http://jblas:password@mycompany.com:8080/mail/inbox?msg=1234&type=unread#msg-content
+ // [1]: http://jblas:password@mycompany.com:8080/mail/inbox?msg=1234&type=unread
+ // [2]: http://jblas:password@mycompany.com:8080/mail/inbox
+ // [3]: http://jblas:password@mycompany.com:8080
+ // [4]: http:
+ // [5]: //
+ // [6]: jblas:password@mycompany.com:8080
+ // [7]: jblas:password
+ // [8]: jblas
+ // [9]: password
+ // [10]: mycompany.com:8080
+ // [11]: mycompany.com
+ // [12]: 8080
+ // [13]: /mail/inbox
+ // [14]: /mail/
+ // [15]: inbox
+ // [16]: ?msg=1234&type=unread
+ // [17]: #msg-content
+ //
+ urlParseRE: /^(((([^:\/#\?]+:)?(?:(\/\/)((?:(([^:@\/#\?]+)(?:\:([^:@\/#\?]+))?)@)?(([^:\/#\?\]\[]+|\[[^\/\]@#?]+\])(?:\:([0-9]+))?))?)?)?((\/?(?:[^\/\?#]+\/+)*)([^\?#]*)))?(\?[^#]+)?)(#.*)?/,
+
+ // Abstraction to address xss (Issue #4787) by removing the authority in
+ // browsers that auto decode it. All references to location.href should be
+ // replaced with a call to this method so that it can be dealt with properly here
+ getLocation: function( url ) {
+ var uri = url ? this.parseUrl( url ) : location,
+ hash = this.parseUrl( url || location.href ).hash;
+
+ // mimic the browser with an empty string when the hash is empty
+ hash = hash === "#" ? "" : hash;
+
+ // Make sure to parse the url or the location object for the hash because using location.hash
+ // is autodecoded in firefox, the rest of the url should be from the object (location unless
+ // we're testing) to avoid the inclusion of the authority
+ return uri.protocol + "//" + uri.host + uri.pathname + uri.search + hash;
+ },
+
+ parseLocation: function() {
+ return this.parseUrl( this.getLocation() );
+ },
+
+ //Parse a URL into a structure that allows easy access to
+ //all of the URL components by name.
+ parseUrl: function( url ) {
+ // If we're passed an object, we'll assume that it is
+ // a parsed url object and just return it back to the caller.
+ if ( $.type( url ) === "object" ) {
+ return url;
+ }
+
+ var matches = path.urlParseRE.exec( url || "" ) || [];
+
+ // Create an object that allows the caller to access the sub-matches
+ // by name. Note that IE returns an empty string instead of undefined,
+ // like all other browsers do, so we normalize everything so its consistent
+ // no matter what browser we're running on.
+ return {
+ href: matches[ 0 ] || "",
+ hrefNoHash: matches[ 1 ] || "",
+ hrefNoSearch: matches[ 2 ] || "",
+ domain: matches[ 3 ] || "",
+ protocol: matches[ 4 ] || "",
+ doubleSlash: matches[ 5 ] || "",
+ authority: matches[ 6 ] || "",
+ username: matches[ 8 ] || "",
+ password: matches[ 9 ] || "",
+ host: matches[ 10 ] || "",
+ hostname: matches[ 11 ] || "",
+ port: matches[ 12 ] || "",
+ pathname: matches[ 13 ] || "",
+ directory: matches[ 14 ] || "",
+ filename: matches[ 15 ] || "",
+ search: matches[ 16 ] || "",
+ hash: matches[ 17 ] || ""
+ };
+ },
+
+ //Turn relPath into an asbolute path. absPath is
+ //an optional absolute path which describes what
+ //relPath is relative to.
+ makePathAbsolute: function( relPath, absPath ) {
+ if ( relPath && relPath.charAt( 0 ) === "/" ) {
+ return relPath;
+ }
+
+ relPath = relPath || "";
+ absPath = absPath ? absPath.replace( /^\/|(\/[^\/]*|[^\/]+)$/g, "" ) : "";
+
+ var absStack = absPath ? absPath.split( "/" ) : [],
+ relStack = relPath.split( "/" );
+ for ( var i = 0; i < relStack.length; i++ ) {
+ var d = relStack[ i ];
+ switch ( d ) {
+ case ".":
+ break;
+ case "..":
+ if ( absStack.length ) {
+ absStack.pop();
+ }
+ break;
+ default:
+ absStack.push( d );
+ break;
+ }
+ }
+ return "/" + absStack.join( "/" );
+ },
+
+ //Returns true if both urls have the same domain.
+ isSameDomain: function( absUrl1, absUrl2 ) {
+ return path.parseUrl( absUrl1 ).domain === path.parseUrl( absUrl2 ).domain;
+ },
+
+ //Returns true for any relative variant.
+ isRelativeUrl: function( url ) {
+ // All relative Url variants have one thing in common, no protocol.
+ return path.parseUrl( url ).protocol === "";
+ },
+
+ //Returns true for an absolute url.
+ isAbsoluteUrl: function( url ) {
+ return path.parseUrl( url ).protocol !== "";
+ },
+
+ //Turn the specified realtive URL into an absolute one. This function
+ //can handle all relative variants (protocol, site, document, query, fragment).
+ makeUrlAbsolute: function( relUrl, absUrl ) {
+ if ( !path.isRelativeUrl( relUrl ) ) {
+ return relUrl;
+ }
+
+ if ( absUrl === undefined ) {
+ absUrl = documentBase;
+ }
+
+ var relObj = path.parseUrl( relUrl ),
+ absObj = path.parseUrl( absUrl ),
+ protocol = relObj.protocol || absObj.protocol,
+ doubleSlash = relObj.protocol ? relObj.doubleSlash : ( relObj.doubleSlash || absObj.doubleSlash ),
+ authority = relObj.authority || absObj.authority,
+ hasPath = relObj.pathname !== "",
+ pathname = path.makePathAbsolute( relObj.pathname || absObj.filename, absObj.pathname ),
+ search = relObj.search || ( !hasPath && absObj.search ) || "",
+ hash = relObj.hash;
+
+ return protocol + doubleSlash + authority + pathname + search + hash;
+ },
+
+ //Add search (aka query) params to the specified url.
+ addSearchParams: function( url, params ) {
+ var u = path.parseUrl( url ),
+ p = ( typeof params === "object" ) ? $.param( params ) : params,
+ s = u.search || "?";
+ return u.hrefNoSearch + s + ( s.charAt( s.length - 1 ) !== "?" ? "&" : "" ) + p + ( u.hash || "" );
+ },
+
+ convertUrlToDataUrl: function( absUrl ) {
+ var u = path.parseUrl( absUrl );
+ if ( path.isEmbeddedPage( u ) ) {
+ // For embedded pages, remove the dialog hash key as in getFilePath(),
+ // otherwise the Data Url won't match the id of the embedded Page.
+ return u.hash.split( dialogHashKey )[0].replace( /^#/, "" );
+ } else if ( path.isSameDomain( u, documentBase ) ) {
+ return u.hrefNoHash.replace( documentBase.domain, "" ).split( dialogHashKey )[0];
+ }
+
+ return window.decodeURIComponent(absUrl);
+ },
+
+ //get path from current hash, or from a file path
+ get: function( newPath ) {
+ if ( newPath === undefined ) {
+ newPath = path.parseLocation().hash;
+ }
+ return path.stripHash( newPath ).replace( /[^\/]*\.[^\/*]+$/, '' );
+ },
+
+ //return the substring of a filepath before the sub-page key, for making a server request
+ getFilePath: function( path ) {
+ var splitkey = '&' + $.mobile.subPageUrlKey;
+ return path && path.split( splitkey )[0].split( dialogHashKey )[0];
+ },
+
+ //set location hash to path
+ set: function( path ) {
+ location.hash = path;
+ },
+
+ //test if a given url (string) is a path
+ //NOTE might be exceptionally naive
+ isPath: function( url ) {
+ return ( /\// ).test( url );
+ },
+
+ //return a url path with the window's location protocol/hostname/pathname removed
+ clean: function( url ) {
+ return url.replace( documentBase.domain, "" );
+ },
+
+ //just return the url without an initial #
+ stripHash: function( url ) {
+ return url.replace( /^#/, "" );
+ },
+
+ //remove the preceding hash, any query params, and dialog notations
+ cleanHash: function( hash ) {
+ return path.stripHash( hash.replace( /\?.*$/, "" ).replace( dialogHashKey, "" ) );
+ },
+
+ isHashValid: function( hash ) {
+ return ( /^#[^#]+$/ ).test( hash );
+ },
+
+ //check whether a url is referencing the same domain, or an external domain or different protocol
+ //could be mailto, etc
+ isExternal: function( url ) {
+ var u = path.parseUrl( url );
+ return u.protocol && u.domain !== documentUrl.domain ? true : false;
+ },
+
+ hasProtocol: function( url ) {
+ return ( /^(:?\w+:)/ ).test( url );
+ },
+
+ //check if the specified url refers to the first page in the main application document.
+ isFirstPageUrl: function( url ) {
+ // We only deal with absolute paths.
+ var u = path.parseUrl( path.makeUrlAbsolute( url, documentBase ) ),
+
+ // Does the url have the same path as the document?
+ samePath = u.hrefNoHash === documentUrl.hrefNoHash || ( documentBaseDiffers && u.hrefNoHash === documentBase.hrefNoHash ),
+
+ // Get the first page element.
+ fp = $.mobile.firstPage,
+
+ // Get the id of the first page element if it has one.
+ fpId = fp && fp[0] ? fp[0].id : undefined;
+
+ // The url refers to the first page if the path matches the document and
+ // it either has no hash value, or the hash is exactly equal to the id of the
+ // first page element.
+ return samePath && ( !u.hash || u.hash === "#" || ( fpId && u.hash.replace( /^#/, "" ) === fpId ) );
+ },
+
+ isEmbeddedPage: function( url ) {
+ var u = path.parseUrl( url );
+
+ //if the path is absolute, then we need to compare the url against
+ //both the documentUrl and the documentBase. The main reason for this
+ //is that links embedded within external documents will refer to the
+ //application document, whereas links embedded within the application
+ //document will be resolved against the document base.
+ if ( u.protocol !== "" ) {
+ return ( u.hash && ( u.hrefNoHash === documentUrl.hrefNoHash || ( documentBaseDiffers && u.hrefNoHash === documentBase.hrefNoHash ) ) );
+ }
+ return ( /^#/ ).test( u.href );
+ },
+
+
+ // Some embedded browsers, like the web view in Phone Gap, allow cross-domain XHR
+ // requests if the document doing the request was loaded via the file:// protocol.
+ // This is usually to allow the application to "phone home" and fetch app specific
+ // data. We normally let the browser handle external/cross-domain urls, but if the
+ // allowCrossDomainPages option is true, we will allow cross-domain http/https
+ // requests to go through our page loading logic.
+ isPermittedCrossDomainRequest: function( docUrl, reqUrl ) {
+ return $.mobile.allowCrossDomainPages &&
+ docUrl.protocol === "file:" &&
+ reqUrl.search( /^https?:/ ) !== -1;
+ }
+ },
+
+ //will be defined when a link is clicked and given an active class
+ $activeClickedLink = null,
+
+ //urlHistory is purely here to make guesses at whether the back or forward button was clicked
+ //and provide an appropriate transition
+ urlHistory = {
+ // Array of pages that are visited during a single page load.
+ // Each has a url and optional transition, title, and pageUrl (which represents the file path, in cases where URL is obscured, such as dialogs)
+ stack: [],
+
+ //maintain an index number for the active page in the stack
+ activeIndex: 0,
+
+ //get active
+ getActive: function() {
+ return urlHistory.stack[ urlHistory.activeIndex ];
+ },
+
+ getPrev: function() {
+ return urlHistory.stack[ urlHistory.activeIndex - 1 ];
+ },
+
+ getNext: function() {
+ return urlHistory.stack[ urlHistory.activeIndex + 1 ];
+ },
+
+ // addNew is used whenever a new page is added
+ addNew: function( url, transition, title, pageUrl, role ) {
+ //if there's forward history, wipe it
+ if ( urlHistory.getNext() ) {
+ urlHistory.clearForward();
+ }
+
+ urlHistory.stack.push( {url : url, transition: transition, title: title, pageUrl: pageUrl, role: role } );
+
+ urlHistory.activeIndex = urlHistory.stack.length - 1;
+ },
+
+ //wipe urls ahead of active index
+ clearForward: function() {
+ urlHistory.stack = urlHistory.stack.slice( 0, urlHistory.activeIndex + 1 );
+ },
+
+ directHashChange: function( opts ) {
+ var back , forward, newActiveIndex, prev = this.getActive();
+
+ // check if url is in history and if it's ahead or behind current page
+ $.each( urlHistory.stack, function( i, historyEntry ) {
+
+ //if the url is in the stack, it's a forward or a back
+ if ( decodeURIComponent( opts.currentUrl ) === decodeURIComponent( historyEntry.url ) ) {
+ //define back and forward by whether url is older or newer than current page
+ back = i < urlHistory.activeIndex;
+ forward = !back;
+ newActiveIndex = i;
+ }
+ });
+
+ // save new page index, null check to prevent falsey 0 result
+ this.activeIndex = newActiveIndex !== undefined ? newActiveIndex : this.activeIndex;
+
+ if ( back ) {
+ ( opts.either || opts.isBack )( true );
+ } else if ( forward ) {
+ ( opts.either || opts.isForward )( false );
+ }
+ },
+
+ //disable hashchange event listener internally to ignore one change
+ //toggled internally when location.hash is updated to match the url of a successful page load
+ ignoreNextHashChange: false
+ },
+
+ //define first selector to receive focus when a page is shown
+ focusable = "[tabindex],a,button:visible,select:visible,input",
+
+ //queue to hold simultanious page transitions
+ pageTransitionQueue = [],
+
+ //indicates whether or not page is in process of transitioning
+ isPageTransitioning = false,
+
+ //nonsense hash change key for dialogs, so they create a history entry
+ dialogHashKey = "&ui-state=dialog",
+
+ //existing base tag?
+ $base = $head.children( "base" ),
+
+ //tuck away the original document URL minus any fragment.
+ documentUrl = path.parseLocation(),
+
+ //if the document has an embedded base tag, documentBase is set to its
+ //initial value. If a base tag does not exist, then we default to the documentUrl.
+ documentBase = $base.length ? path.parseUrl( path.makeUrlAbsolute( $base.attr( "href" ), documentUrl.href ) ) : documentUrl,
+
+ //cache the comparison once.
+ documentBaseDiffers = ( documentUrl.hrefNoHash !== documentBase.hrefNoHash ),
+
+ getScreenHeight = $.mobile.getScreenHeight;
+
+ //base element management, defined depending on dynamic base tag support
+ var base = $.support.dynamicBaseTag ? {
+
+ //define base element, for use in routing asset urls that are referenced in Ajax-requested markup
+ element: ( $base.length ? $base : $( "", { href: documentBase.hrefNoHash } ).prependTo( $head ) ),
+
+ //set the generated BASE element's href attribute to a new page's base path
+ set: function( href ) {
+ base.element.attr( "href", path.makeUrlAbsolute( href, documentBase ) );
+ },
+
+ //set the generated BASE element's href attribute to a new page's base path
+ reset: function() {
+ base.element.attr( "href", documentBase.hrefNoHash );
+ }
+
+ } : undefined;
+
+ /* internal utility functions */
+
+ // NOTE Issue #4950 Android phonegap doesn't navigate back properly
+ // when a full page refresh has taken place. It appears that hashchange
+ // and replacestate history alterations work fine but we need to support
+ // both forms of history traversal in our code that uses backward history
+ // movement
+ $.mobile.back = function() {
+ var nav = window.navigator;
+
+ // if the setting is on and the navigator object is
+ // available use the phonegap navigation capability
+ if( this.phonegapNavigationEnabled &&
+ nav &&
+ nav.app &&
+ nav.app.backHistory ){
+ nav.app.backHistory();
+ } else {
+ window.history.back();
+ }
+ };
+
+ //direct focus to the page title, or otherwise first focusable element
+ $.mobile.focusPage = function ( page ) {
+ var autofocus = page.find( "[autofocus]" ),
+ pageTitle = page.find( ".ui-title:eq(0)" );
+
+ if ( autofocus.length ) {
+ autofocus.focus();
+ return;
+ }
+
+ if ( pageTitle.length ) {
+ pageTitle.focus();
+ } else{
+ page.focus();
+ }
+ };
+
+ //remove active classes after page transition or error
+ function removeActiveLinkClass( forceRemoval ) {
+ if ( !!$activeClickedLink && ( !$activeClickedLink.closest( "." + $.mobile.activePageClass ).length || forceRemoval ) ) {
+ $activeClickedLink.removeClass( $.mobile.activeBtnClass );
+ }
+ $activeClickedLink = null;
+ }
+
+ function releasePageTransitionLock() {
+ isPageTransitioning = false;
+ if ( pageTransitionQueue.length > 0 ) {
+ $.mobile.changePage.apply( null, pageTransitionQueue.pop() );
+ }
+ }
+
+ // Save the last scroll distance per page, before it is hidden
+ var setLastScrollEnabled = true,
+ setLastScroll, delayedSetLastScroll;
+
+ setLastScroll = function() {
+ // this barrier prevents setting the scroll value based on the browser
+ // scrolling the window based on a hashchange
+ if ( !setLastScrollEnabled ) {
+ return;
+ }
+
+ var active = $.mobile.urlHistory.getActive();
+
+ if ( active ) {
+ var lastScroll = $window.scrollTop();
+
+ // Set active page's lastScroll prop.
+ // If the location we're scrolling to is less than minScrollBack, let it go.
+ active.lastScroll = lastScroll < $.mobile.minScrollBack ? $.mobile.defaultHomeScroll : lastScroll;
+ }
+ };
+
+ // bind to scrollstop to gather scroll position. The delay allows for the hashchange
+ // event to fire and disable scroll recording in the case where the browser scrolls
+ // to the hash targets location (sometimes the top of the page). once pagechange fires
+ // getLastScroll is again permitted to operate
+ delayedSetLastScroll = function() {
+ setTimeout( setLastScroll, 100 );
+ };
+
+ // disable an scroll setting when a hashchange has been fired, this only works
+ // because the recording of the scroll position is delayed for 100ms after
+ // the browser might have changed the position because of the hashchange
+ $window.bind( $.support.pushState ? "popstate" : "hashchange", function() {
+ setLastScrollEnabled = false;
+ });
+
+ // handle initial hashchange from chrome :(
+ $window.one( $.support.pushState ? "popstate" : "hashchange", function() {
+ setLastScrollEnabled = true;
+ });
+
+ // wait until the mobile page container has been determined to bind to pagechange
+ $window.one( "pagecontainercreate", function() {
+ // once the page has changed, re-enable the scroll recording
+ $.mobile.pageContainer.bind( "pagechange", function() {
+
+ setLastScrollEnabled = true;
+
+ // remove any binding that previously existed on the get scroll
+ // which may or may not be different than the scroll element determined for
+ // this page previously
+ $window.unbind( "scrollstop", delayedSetLastScroll );
+
+ // determine and bind to the current scoll element which may be the window
+ // or in the case of touch overflow the element with touch overflow
+ $window.bind( "scrollstop", delayedSetLastScroll );
+ });
+ });
+
+ // bind to scrollstop for the first page as "pagechange" won't be fired in that case
+ $window.bind( "scrollstop", delayedSetLastScroll );
+
+ // No-op implementation of transition degradation
+ $.mobile._maybeDegradeTransition = $.mobile._maybeDegradeTransition || function( transition ) {
+ return transition;
+ };
+
+ //function for transitioning between two existing pages
+ function transitionPages( toPage, fromPage, transition, reverse ) {
+
+ if ( fromPage ) {
+ //trigger before show/hide events
+ fromPage.data( "page" )._trigger( "beforehide", null, { nextPage: toPage } );
+ }
+
+ toPage.data( "page" )._trigger( "beforeshow", null, { prevPage: fromPage || $( "" ) } );
+
+ //clear page loader
+ $.mobile.hidePageLoadingMsg();
+
+ transition = $.mobile._maybeDegradeTransition( transition );
+
+ //find the transition handler for the specified transition. If there
+ //isn't one in our transitionHandlers dictionary, use the default one.
+ //call the handler immediately to kick-off the transition.
+ var th = $.mobile.transitionHandlers[ transition || "default" ] || $.mobile.defaultTransitionHandler,
+ promise = th( transition, reverse, toPage, fromPage );
+
+ promise.done(function() {
+
+ //trigger show/hide events
+ if ( fromPage ) {
+ fromPage.data( "page" )._trigger( "hide", null, { nextPage: toPage } );
+ }
+
+ //trigger pageshow, define prevPage as either fromPage or empty jQuery obj
+ toPage.data( "page" )._trigger( "show", null, { prevPage: fromPage || $( "" ) } );
+ });
+
+ return promise;
+ }
+
+ //simply set the active page's minimum height to screen height, depending on orientation
+ function resetActivePageHeight() {
+ var aPage = $( "." + $.mobile.activePageClass ),
+ aPagePadT = parseFloat( aPage.css( "padding-top" ) ),
+ aPagePadB = parseFloat( aPage.css( "padding-bottom" ) ),
+ aPageBorderT = parseFloat( aPage.css( "border-top-width" ) ),
+ aPageBorderB = parseFloat( aPage.css( "border-bottom-width" ) );
+
+ aPage.css( "min-height", getScreenHeight() - aPagePadT - aPagePadB - aPageBorderT - aPageBorderB );
+ }
+
+ //shared page enhancements
+ function enhancePage( $page, role ) {
+ // If a role was specified, make sure the data-role attribute
+ // on the page element is in sync.
+ if ( role ) {
+ $page.attr( "data-" + $.mobile.ns + "role", role );
+ }
+
+ //run page plugin
+ $page.page();
+ }
+
+ /* exposed $.mobile methods */
+
+ //animation complete callback
+ $.fn.animationComplete = function( callback ) {
+ if ( $.support.cssTransitions ) {
+ return $( this ).one( 'webkitAnimationEnd animationend', callback );
+ }
+ else{
+ // defer execution for consistency between webkit/non webkit
+ setTimeout( callback, 0 );
+ return $( this );
+ }
+ };
+
+ //expose path object on $.mobile
+ $.mobile.path = path;
+
+ //expose base object on $.mobile
+ $.mobile.base = base;
+
+ //history stack
+ $.mobile.urlHistory = urlHistory;
+
+ $.mobile.dialogHashKey = dialogHashKey;
+
+
+
+ //enable cross-domain page support
+ $.mobile.allowCrossDomainPages = false;
+
+ //return the original document url
+ $.mobile.getDocumentUrl = function( asParsedObject ) {
+ return asParsedObject ? $.extend( {}, documentUrl ) : documentUrl.href;
+ };
+
+ //return the original document base url
+ $.mobile.getDocumentBase = function( asParsedObject ) {
+ return asParsedObject ? $.extend( {}, documentBase ) : documentBase.href;
+ };
+
+ $.mobile._bindPageRemove = function() {
+ var page = $( this );
+
+ // when dom caching is not enabled or the page is embedded bind to remove the page on hide
+ if ( !page.data( "page" ).options.domCache &&
+ page.is( ":jqmData(external-page='true')" ) ) {
+
+ page.bind( 'pagehide.remove', function() {
+ var $this = $( this ),
+ prEvent = new $.Event( "pageremove" );
+
+ $this.trigger( prEvent );
+
+ if ( !prEvent.isDefaultPrevented() ) {
+ $this.removeWithDependents();
+ }
+ });
+ }
+ };
+
+ // Load a page into the DOM.
+ $.mobile.loadPage = function( url, options ) {
+ // This function uses deferred notifications to let callers
+ // know when the page is done loading, or if an error has occurred.
+ var deferred = $.Deferred(),
+
+ // The default loadPage options with overrides specified by
+ // the caller.
+ settings = $.extend( {}, $.mobile.loadPage.defaults, options ),
+
+ // The DOM element for the page after it has been loaded.
+ page = null,
+
+ // If the reloadPage option is true, and the page is already
+ // in the DOM, dupCachedPage will be set to the page element
+ // so that it can be removed after the new version of the
+ // page is loaded off the network.
+ dupCachedPage = null,
+
+ // determine the current base url
+ findBaseWithDefault = function() {
+ var closestBase = ( $.mobile.activePage && getClosestBaseUrl( $.mobile.activePage ) );
+ return closestBase || documentBase.hrefNoHash;
+ },
+
+ // The absolute version of the URL passed into the function. This
+ // version of the URL may contain dialog/subpage params in it.
+ absUrl = path.makeUrlAbsolute( url, findBaseWithDefault() );
+
+
+ // If the caller provided data, and we're using "get" request,
+ // append the data to the URL.
+ if ( settings.data && settings.type === "get" ) {
+ absUrl = path.addSearchParams( absUrl, settings.data );
+ settings.data = undefined;
+ }
+
+ // If the caller is using a "post" request, reloadPage must be true
+ if ( settings.data && settings.type === "post" ) {
+ settings.reloadPage = true;
+ }
+
+ // The absolute version of the URL minus any dialog/subpage params.
+ // In otherwords the real URL of the page to be loaded.
+ var fileUrl = path.getFilePath( absUrl ),
+
+ // The version of the Url actually stored in the data-url attribute of
+ // the page. For embedded pages, it is just the id of the page. For pages
+ // within the same domain as the document base, it is the site relative
+ // path. For cross-domain pages (Phone Gap only) the entire absolute Url
+ // used to load the page.
+ dataUrl = path.convertUrlToDataUrl( absUrl );
+
+ // Make sure we have a pageContainer to work with.
+ settings.pageContainer = settings.pageContainer || $.mobile.pageContainer;
+
+ // Check to see if the page already exists in the DOM.
+ // NOTE do _not_ use the :jqmData psuedo selector because parenthesis
+ // are a valid url char and it breaks on the first occurence
+ page = settings.pageContainer.children( "[data-" + $.mobile.ns +"url='" + dataUrl + "']" );
+
+ // If we failed to find the page, check to see if the url is a
+ // reference to an embedded page. If so, it may have been dynamically
+ // injected by a developer, in which case it would be lacking a data-url
+ // attribute and in need of enhancement.
+ if ( page.length === 0 && dataUrl && !path.isPath( dataUrl ) ) {
+ page = settings.pageContainer.children( "#" + dataUrl )
+ .attr( "data-" + $.mobile.ns + "url", dataUrl )
+ .jqmData( "url", dataUrl );
+ }
+
+ // If we failed to find a page in the DOM, check the URL to see if it
+ // refers to the first page in the application. If it isn't a reference
+ // to the first page and refers to non-existent embedded page, error out.
+ if ( page.length === 0 ) {
+ if ( $.mobile.firstPage && path.isFirstPageUrl( fileUrl ) ) {
+ // Check to make sure our cached-first-page is actually
+ // in the DOM. Some user deployed apps are pruning the first
+ // page from the DOM for various reasons, we check for this
+ // case here because we don't want a first-page with an id
+ // falling through to the non-existent embedded page error
+ // case. If the first-page is not in the DOM, then we let
+ // things fall through to the ajax loading code below so
+ // that it gets reloaded.
+ if ( $.mobile.firstPage.parent().length ) {
+ page = $( $.mobile.firstPage );
+ }
+ } else if ( path.isEmbeddedPage( fileUrl ) ) {
+ deferred.reject( absUrl, options );
+ return deferred.promise();
+ }
+ }
+
+ // If the page we are interested in is already in the DOM,
+ // and the caller did not indicate that we should force a
+ // reload of the file, we are done. Otherwise, track the
+ // existing page as a duplicated.
+ if ( page.length ) {
+ if ( !settings.reloadPage ) {
+ enhancePage( page, settings.role );
+ deferred.resolve( absUrl, options, page );
+ return deferred.promise();
+ }
+ dupCachedPage = page;
+ }
+
+ var mpc = settings.pageContainer,
+ pblEvent = new $.Event( "pagebeforeload" ),
+ triggerData = { url: url, absUrl: absUrl, dataUrl: dataUrl, deferred: deferred, options: settings };
+
+ // Let listeners know we're about to load a page.
+ mpc.trigger( pblEvent, triggerData );
+
+ // If the default behavior is prevented, stop here!
+ if ( pblEvent.isDefaultPrevented() ) {
+ return deferred.promise();
+ }
+
+ if ( settings.showLoadMsg ) {
+
+ // This configurable timeout allows cached pages a brief delay to load without showing a message
+ var loadMsgDelay = setTimeout(function() {
+ $.mobile.showPageLoadingMsg();
+ }, settings.loadMsgDelay ),
+
+ // Shared logic for clearing timeout and removing message.
+ hideMsg = function() {
+
+ // Stop message show timer
+ clearTimeout( loadMsgDelay );
+
+ // Hide loading message
+ $.mobile.hidePageLoadingMsg();
+ };
+ }
+
+ // Reset base to the default document base.
+ if ( base ) {
+ base.reset();
+ }
+
+ if ( !( $.mobile.allowCrossDomainPages || path.isSameDomain( documentUrl, absUrl ) ) ) {
+ deferred.reject( absUrl, options );
+ } else {
+ // Load the new page.
+ $.ajax({
+ url: fileUrl,
+ type: settings.type,
+ data: settings.data,
+ dataType: "html",
+ success: function( html, textStatus, xhr ) {
+ //pre-parse html to check for a data-url,
+ //use it as the new fileUrl, base path, etc
+ var all = $( "" ),
+
+ //page title regexp
+ newPageTitle = html.match( /]*>([^<]*)/ ) && RegExp.$1,
+
+ // TODO handle dialogs again
+ pageElemRegex = new RegExp( "(<[^>]+\\bdata-" + $.mobile.ns + "role=[\"']?page[\"']?[^>]*>)" ),
+ dataUrlRegex = new RegExp( "\\bdata-" + $.mobile.ns + "url=[\"']?([^\"'>]*)[\"']?" );
+
+
+ // data-url must be provided for the base tag so resource requests can be directed to the
+ // correct url. loading into a temprorary element makes these requests immediately
+ if ( pageElemRegex.test( html ) &&
+ RegExp.$1 &&
+ dataUrlRegex.test( RegExp.$1 ) &&
+ RegExp.$1 ) {
+ url = fileUrl = path.getFilePath( $( "" + RegExp.$1 + "
" ).text() );
+ }
+
+ if ( base ) {
+ base.set( fileUrl );
+ }
+
+ //workaround to allow scripts to execute when included in page divs
+ all.get( 0 ).innerHTML = html;
+ page = all.find( ":jqmData(role='page'), :jqmData(role='dialog')" ).first();
+
+ //if page elem couldn't be found, create one and insert the body element's contents
+ if ( !page.length ) {
+ page = $( "" + html.split( /<\/?body[^>]*>/gmi )[1] + "
" );
+ }
+
+ if ( newPageTitle && !page.jqmData( "title" ) ) {
+ if ( ~newPageTitle.indexOf( "&" ) ) {
+ newPageTitle = $( "" + newPageTitle + "
" ).text();
+ }
+ page.jqmData( "title", newPageTitle );
+ }
+
+ //rewrite src and href attrs to use a base url
+ if ( !$.support.dynamicBaseTag ) {
+ var newPath = path.get( fileUrl );
+ page.find( "[src], link[href], a[rel='external'], :jqmData(ajax='false'), a[target]" ).each(function() {
+ var thisAttr = $( this ).is( '[href]' ) ? 'href' :
+ $( this ).is( '[src]' ) ? 'src' : 'action',
+ thisUrl = $( this ).attr( thisAttr );
+
+ // XXX_jblas: We need to fix this so that it removes the document
+ // base URL, and then prepends with the new page URL.
+ //if full path exists and is same, chop it - helps IE out
+ thisUrl = thisUrl.replace( location.protocol + '//' + location.host + location.pathname, '' );
+
+ if ( !/^(\w+:|#|\/)/.test( thisUrl ) ) {
+ $( this ).attr( thisAttr, newPath + thisUrl );
+ }
+ });
+ }
+
+ //append to page and enhance
+ // TODO taging a page with external to make sure that embedded pages aren't removed
+ // by the various page handling code is bad. Having page handling code in many
+ // places is bad. Solutions post 1.0
+ page
+ .attr( "data-" + $.mobile.ns + "url", path.convertUrlToDataUrl( fileUrl ) )
+ .attr( "data-" + $.mobile.ns + "external-page", true )
+ .appendTo( settings.pageContainer );
+
+ // wait for page creation to leverage options defined on widget
+ page.one( 'pagecreate', $.mobile._bindPageRemove );
+
+ enhancePage( page, settings.role );
+
+ // Enhancing the page may result in new dialogs/sub pages being inserted
+ // into the DOM. If the original absUrl refers to a sub-page, that is the
+ // real page we are interested in.
+ if ( absUrl.indexOf( "&" + $.mobile.subPageUrlKey ) > -1 ) {
+ page = settings.pageContainer.children( "[data-" + $.mobile.ns +"url='" + dataUrl + "']" );
+ }
+
+ //bind pageHide to removePage after it's hidden, if the page options specify to do so
+
+ // Remove loading message.
+ if ( settings.showLoadMsg ) {
+ hideMsg();
+ }
+
+ // Add the page reference and xhr to our triggerData.
+ triggerData.xhr = xhr;
+ triggerData.textStatus = textStatus;
+ triggerData.page = page;
+
+ // Let listeners know the page loaded successfully.
+ settings.pageContainer.trigger( "pageload", triggerData );
+
+ deferred.resolve( absUrl, options, page, dupCachedPage );
+ },
+ error: function( xhr, textStatus, errorThrown ) {
+ //set base back to current path
+ if ( base ) {
+ base.set( path.get() );
+ }
+
+ // Add error info to our triggerData.
+ triggerData.xhr = xhr;
+ triggerData.textStatus = textStatus;
+ triggerData.errorThrown = errorThrown;
+
+ var plfEvent = new $.Event( "pageloadfailed" );
+
+ // Let listeners know the page load failed.
+ settings.pageContainer.trigger( plfEvent, triggerData );
+
+ // If the default behavior is prevented, stop here!
+ // Note that it is the responsibility of the listener/handler
+ // that called preventDefault(), to resolve/reject the
+ // deferred object within the triggerData.
+ if ( plfEvent.isDefaultPrevented() ) {
+ return;
+ }
+
+ // Remove loading message.
+ if ( settings.showLoadMsg ) {
+
+ // Remove loading message.
+ hideMsg();
+
+ // show error message
+ $.mobile.showPageLoadingMsg( $.mobile.pageLoadErrorMessageTheme, $.mobile.pageLoadErrorMessage, true );
+
+ // hide after delay
+ setTimeout( $.mobile.hidePageLoadingMsg, 1500 );
+ }
+
+ deferred.reject( absUrl, options );
+ }
+ });
+ }
+
+ return deferred.promise();
+ };
+
+ $.mobile.loadPage.defaults = {
+ type: "get",
+ data: undefined,
+ reloadPage: false,
+ role: undefined, // By default we rely on the role defined by the @data-role attribute.
+ showLoadMsg: false,
+ pageContainer: undefined,
+ loadMsgDelay: 50 // This delay allows loads that pull from browser cache to occur without showing the loading message.
+ };
+
+ // Show a specific page in the page container.
+ $.mobile.changePage = function( toPage, options ) {
+ // If we are in the midst of a transition, queue the current request.
+ // We'll call changePage() once we're done with the current transition to
+ // service the request.
+ if ( isPageTransitioning ) {
+ pageTransitionQueue.unshift( arguments );
+ return;
+ }
+
+ var settings = $.extend( {}, $.mobile.changePage.defaults, options );
+
+ // Make sure we have a pageContainer to work with.
+ settings.pageContainer = settings.pageContainer || $.mobile.pageContainer;
+
+ // Make sure we have a fromPage.
+ settings.fromPage = settings.fromPage || $.mobile.activePage;
+
+ var mpc = settings.pageContainer,
+ pbcEvent = new $.Event( "pagebeforechange" ),
+ triggerData = { toPage: toPage, options: settings };
+
+ // Let listeners know we're about to change the current page.
+ mpc.trigger( pbcEvent, triggerData );
+
+ // If the default behavior is prevented, stop here!
+ if ( pbcEvent.isDefaultPrevented() ) {
+ return;
+ }
+
+ // We allow "pagebeforechange" observers to modify the toPage in the trigger
+ // data to allow for redirects. Make sure our toPage is updated.
+
+ toPage = triggerData.toPage;
+
+ // Set the isPageTransitioning flag to prevent any requests from
+ // entering this method while we are in the midst of loading a page
+ // or transitioning.
+
+ isPageTransitioning = true;
+
+ // If the caller passed us a url, call loadPage()
+ // to make sure it is loaded into the DOM. We'll listen
+ // to the promise object it returns so we know when
+ // it is done loading or if an error ocurred.
+ if ( typeof toPage === "string" ) {
+ $.mobile.loadPage( toPage, settings )
+ .done(function( url, options, newPage, dupCachedPage ) {
+ isPageTransitioning = false;
+ options.duplicateCachedPage = dupCachedPage;
+ $.mobile.changePage( newPage, options );
+ })
+ .fail(function( url, options ) {
+ isPageTransitioning = false;
+
+ //clear out the active button state
+ removeActiveLinkClass( true );
+
+ //release transition lock so navigation is free again
+ releasePageTransitionLock();
+ settings.pageContainer.trigger( "pagechangefailed", triggerData );
+ });
+ return;
+ }
+
+ // If we are going to the first-page of the application, we need to make
+ // sure settings.dataUrl is set to the application document url. This allows
+ // us to avoid generating a document url with an id hash in the case where the
+ // first-page of the document has an id attribute specified.
+ if ( toPage[ 0 ] === $.mobile.firstPage[ 0 ] && !settings.dataUrl ) {
+ settings.dataUrl = documentUrl.hrefNoHash;
+ }
+
+ // The caller passed us a real page DOM element. Update our
+ // internal state and then trigger a transition to the page.
+ var fromPage = settings.fromPage,
+ url = ( settings.dataUrl && path.convertUrlToDataUrl( settings.dataUrl ) ) || toPage.jqmData( "url" ),
+ // The pageUrl var is usually the same as url, except when url is obscured as a dialog url. pageUrl always contains the file path
+ pageUrl = url,
+ fileUrl = path.getFilePath( url ),
+ active = urlHistory.getActive(),
+ activeIsInitialPage = urlHistory.activeIndex === 0,
+ historyDir = 0,
+ pageTitle = document.title,
+ isDialog = settings.role === "dialog" || toPage.jqmData( "role" ) === "dialog";
+
+ // By default, we prevent changePage requests when the fromPage and toPage
+ // are the same element, but folks that generate content manually/dynamically
+ // and reuse pages want to be able to transition to the same page. To allow
+ // this, they will need to change the default value of allowSamePageTransition
+ // to true, *OR*, pass it in as an option when they manually call changePage().
+ // It should be noted that our default transition animations assume that the
+ // formPage and toPage are different elements, so they may behave unexpectedly.
+ // It is up to the developer that turns on the allowSamePageTransitiona option
+ // to either turn off transition animations, or make sure that an appropriate
+ // animation transition is used.
+ if ( fromPage && fromPage[0] === toPage[0] && !settings.allowSamePageTransition ) {
+ isPageTransitioning = false;
+ mpc.trigger( "pagechange", triggerData );
+
+ // Even if there is no page change to be done, we should keep the urlHistory in sync with the hash changes
+ if ( settings.fromHashChange ) {
+ urlHistory.directHashChange({
+ currentUrl: url,
+ isBack: function() {},
+ isForward: function() {}
+ });
+ }
+
+ return;
+ }
+
+ // We need to make sure the page we are given has already been enhanced.
+ enhancePage( toPage, settings.role );
+
+ // If the changePage request was sent from a hashChange event, check to see if the
+ // page is already within the urlHistory stack. If so, we'll assume the user hit
+ // the forward/back button and will try to match the transition accordingly.
+ if ( settings.fromHashChange ) {
+ urlHistory.directHashChange({
+ currentUrl: url,
+ isBack: function() { historyDir = -1; },
+ isForward: function() { historyDir = 1; }
+ });
+ }
+
+ // Kill the keyboard.
+ // XXX_jblas: We need to stop crawling the entire document to kill focus. Instead,
+ // we should be tracking focus with a delegate() handler so we already have
+ // the element in hand at this point.
+ // Wrap this in a try/catch block since IE9 throw "Unspecified error" if document.activeElement
+ // is undefined when we are in an IFrame.
+ try {
+ if ( document.activeElement && document.activeElement.nodeName.toLowerCase() !== 'body' ) {
+ $( document.activeElement ).blur();
+ } else {
+ $( "input:focus, textarea:focus, select:focus" ).blur();
+ }
+ } catch( e ) {}
+
+ // Record whether we are at a place in history where a dialog used to be - if so, do not add a new history entry and do not change the hash either
+ var alreadyThere = false;
+
+ // If we're displaying the page as a dialog, we don't want the url
+ // for the dialog content to be used in the hash. Instead, we want
+ // to append the dialogHashKey to the url of the current page.
+ if ( isDialog && active ) {
+ // on the initial page load active.url is undefined and in that case should
+ // be an empty string. Moving the undefined -> empty string back into
+ // urlHistory.addNew seemed imprudent given undefined better represents
+ // the url state
+
+ // If we are at a place in history that once belonged to a dialog, reuse
+ // this state without adding to urlHistory and without modifying the hash.
+ // However, if a dialog is already displayed at this point, and we're
+ // about to display another dialog, then we must add another hash and
+ // history entry on top so that one may navigate back to the original dialog
+ if ( active.url.indexOf( dialogHashKey ) > -1 && !$.mobile.activePage.is( ".ui-dialog" ) ) {
+ settings.changeHash = false;
+ alreadyThere = true;
+ }
+
+ // Normally, we tack on a dialog hash key, but if this is the location of a stale dialog,
+ // we reuse the URL from the entry
+ url = ( active.url || "" ) + ( alreadyThere ? "" : dialogHashKey );
+
+ // tack on another dialogHashKey if this is the same as the initial hash
+ // this makes sure that a history entry is created for this dialog
+ if ( urlHistory.activeIndex === 0 && url === urlHistory.initialDst ) {
+ url += dialogHashKey;
+ }
+ }
+
+ // Set the location hash.
+ if ( settings.changeHash !== false && url ) {
+ //disable hash listening temporarily
+ urlHistory.ignoreNextHashChange = true;
+ //update hash and history
+ path.set( url );
+ }
+
+ // if title element wasn't found, try the page div data attr too
+ // If this is a deep-link or a reload ( active === undefined ) then just use pageTitle
+ var newPageTitle = ( !active )? pageTitle : toPage.jqmData( "title" ) || toPage.children( ":jqmData(role='header')" ).find( ".ui-title" ).getEncodedText();
+ if ( !!newPageTitle && pageTitle === document.title ) {
+ pageTitle = newPageTitle;
+ }
+ if ( !toPage.jqmData( "title" ) ) {
+ toPage.jqmData( "title", pageTitle );
+ }
+
+ // Make sure we have a transition defined.
+ settings.transition = settings.transition ||
+ ( ( historyDir && !activeIsInitialPage ) ? active.transition : undefined ) ||
+ ( isDialog ? $.mobile.defaultDialogTransition : $.mobile.defaultPageTransition );
+
+ //add page to history stack if it's not back or forward
+ if ( !historyDir ) {
+ // Overwrite the current entry if it's a leftover from a dialog
+ if ( alreadyThere ) {
+ urlHistory.activeIndex = Math.max( 0, urlHistory.activeIndex - 1 );
+ }
+ urlHistory.addNew( url, settings.transition, pageTitle, pageUrl, settings.role );
+ }
+
+ //set page title
+ document.title = urlHistory.getActive().title;
+
+ //set "toPage" as activePage
+ $.mobile.activePage = toPage;
+
+ // If we're navigating back in the URL history, set reverse accordingly.
+ settings.reverse = settings.reverse || historyDir < 0;
+
+ transitionPages( toPage, fromPage, settings.transition, settings.reverse )
+ .done(function( name, reverse, $to, $from, alreadyFocused ) {
+ removeActiveLinkClass();
+
+ //if there's a duplicateCachedPage, remove it from the DOM now that it's hidden
+ if ( settings.duplicateCachedPage ) {
+ settings.duplicateCachedPage.remove();
+ }
+
+ // Send focus to the newly shown page. Moved from promise .done binding in transitionPages
+ // itself to avoid ie bug that reports offsetWidth as > 0 (core check for visibility)
+ // despite visibility: hidden addresses issue #2965
+ // https://github.com/jquery/jquery-mobile/issues/2965
+ if ( !alreadyFocused ) {
+ $.mobile.focusPage( toPage );
+ }
+
+ releasePageTransitionLock();
+
+ // Let listeners know we're all done changing the current page.
+ mpc.trigger( "pagechange", triggerData );
+ });
+ };
+
+ $.mobile.changePage.defaults = {
+ transition: undefined,
+ reverse: false,
+ changeHash: true,
+ fromHashChange: false,
+ role: undefined, // By default we rely on the role defined by the @data-role attribute.
+ duplicateCachedPage: undefined,
+ pageContainer: undefined,
+ showLoadMsg: true, //loading message shows by default when pages are being fetched during changePage
+ dataUrl: undefined,
+ fromPage: undefined,
+ allowSamePageTransition: false
+ };
+
+/* Event Bindings - hashchange, submit, and click */
+ function findClosestLink( ele )
+ {
+ while ( ele ) {
+ // Look for the closest element with a nodeName of "a".
+ // Note that we are checking if we have a valid nodeName
+ // before attempting to access it. This is because the
+ // node we get called with could have originated from within
+ // an embedded SVG document where some symbol instance elements
+ // don't have nodeName defined on them, or strings are of type
+ // SVGAnimatedString.
+ if ( ( typeof ele.nodeName === "string" ) && ele.nodeName.toLowerCase() === "a" ) {
+ break;
+ }
+ ele = ele.parentNode;
+ }
+ return ele;
+ }
+
+ // The base URL for any given element depends on the page it resides in.
+ function getClosestBaseUrl( ele )
+ {
+ // Find the closest page and extract out its url.
+ var url = $( ele ).closest( ".ui-page" ).jqmData( "url" ),
+ base = documentBase.hrefNoHash;
+
+ if ( !url || !path.isPath( url ) ) {
+ url = base;
+ }
+
+ return path.makeUrlAbsolute( url, base);
+ }
+
+ //The following event bindings should be bound after mobileinit has been triggered
+ //the following deferred is resolved in the init file
+ $.mobile.navreadyDeferred = $.Deferred();
+ $.mobile.navreadyDeferred.done(function() {
+ //bind to form submit events, handle with Ajax
+ $( document ).delegate( "form", "submit", function( event ) {
+ var $this = $( this );
+
+ if ( !$.mobile.ajaxEnabled ||
+ // test that the form is, itself, ajax false
+ $this.is( ":jqmData(ajax='false')" ) ||
+ // test that $.mobile.ignoreContentEnabled is set and
+ // the form or one of it's parents is ajax=false
+ !$this.jqmHijackable().length ) {
+ return;
+ }
+
+ var type = $this.attr( "method" ),
+ target = $this.attr( "target" ),
+ url = $this.attr( "action" );
+
+ // If no action is specified, browsers default to using the
+ // URL of the document containing the form. Since we dynamically
+ // pull in pages from external documents, the form should submit
+ // to the URL for the source document of the page containing
+ // the form.
+ if ( !url ) {
+ // Get the @data-url for the page containing the form.
+ url = getClosestBaseUrl( $this );
+ if ( url === documentBase.hrefNoHash ) {
+ // The url we got back matches the document base,
+ // which means the page must be an internal/embedded page,
+ // so default to using the actual document url as a browser
+ // would.
+ url = documentUrl.hrefNoSearch;
+ }
+ }
+
+ url = path.makeUrlAbsolute( url, getClosestBaseUrl( $this ) );
+
+ if ( ( path.isExternal( url ) && !path.isPermittedCrossDomainRequest( documentUrl, url ) ) || target ) {
+ return;
+ }
+
+ $.mobile.changePage(
+ url,
+ {
+ type: type && type.length && type.toLowerCase() || "get",
+ data: $this.serialize(),
+ transition: $this.jqmData( "transition" ),
+ reverse: $this.jqmData( "direction" ) === "reverse",
+ reloadPage: true
+ }
+ );
+ event.preventDefault();
+ });
+
+ //add active state on vclick
+ $( document ).bind( "vclick", function( event ) {
+ // if this isn't a left click we don't care. Its important to note
+ // that when the virtual event is generated it will create the which attr
+ if ( event.which > 1 || !$.mobile.linkBindingEnabled ) {
+ return;
+ }
+
+ var link = findClosestLink( event.target );
+
+ // split from the previous return logic to avoid find closest where possible
+ // TODO teach $.mobile.hijackable to operate on raw dom elements so the link wrapping
+ // can be avoided
+ if ( !$( link ).jqmHijackable().length ) {
+ return;
+ }
+
+ if ( link ) {
+ if ( path.parseUrl( link.getAttribute( "href" ) || "#" ).hash !== "#" ) {
+ removeActiveLinkClass( true );
+ $activeClickedLink = $( link ).closest( ".ui-btn" ).not( ".ui-disabled" );
+ $activeClickedLink.addClass( $.mobile.activeBtnClass );
+ }
+ }
+ });
+
+ // click routing - direct to HTTP or Ajax, accordingly
+ $( document ).bind( "click", function( event ) {
+ if ( !$.mobile.linkBindingEnabled ) {
+ return;
+ }
+
+ var link = findClosestLink( event.target ), $link = $( link ), httpCleanup;
+
+ // If there is no link associated with the click or its not a left
+ // click we want to ignore the click
+ // TODO teach $.mobile.hijackable to operate on raw dom elements so the link wrapping
+ // can be avoided
+ if ( !link || event.which > 1 || !$link.jqmHijackable().length ) {
+ return;
+ }
+
+ //remove active link class if external (then it won't be there if you come back)
+ httpCleanup = function() {
+ window.setTimeout(function() { removeActiveLinkClass( true ); }, 200 );
+ };
+
+ //if there's a data-rel=back attr, go back in history
+ if ( $link.is( ":jqmData(rel='back')" ) ) {
+ $.mobile.back();
+ return false;
+ }
+
+ var baseUrl = getClosestBaseUrl( $link ),
+
+ //get href, if defined, otherwise default to empty hash
+ href = path.makeUrlAbsolute( $link.attr( "href" ) || "#", baseUrl );
+
+ //if ajax is disabled, exit early
+ if ( !$.mobile.ajaxEnabled && !path.isEmbeddedPage( href ) ) {
+ httpCleanup();
+ //use default click handling
+ return;
+ }
+
+ // XXX_jblas: Ideally links to application pages should be specified as
+ // an url to the application document with a hash that is either
+ // the site relative path or id to the page. But some of the
+ // internal code that dynamically generates sub-pages for nested
+ // lists and select dialogs, just write a hash in the link they
+ // create. This means the actual URL path is based on whatever
+ // the current value of the base tag is at the time this code
+ // is called. For now we are just assuming that any url with a
+ // hash in it is an application page reference.
+ if ( href.search( "#" ) !== -1 ) {
+ href = href.replace( /[^#]*#/, "" );
+ if ( !href ) {
+ //link was an empty hash meant purely
+ //for interaction, so we ignore it.
+ event.preventDefault();
+ return;
+ } else if ( path.isPath( href ) ) {
+ //we have apath so make it the href we want to load.
+ href = path.makeUrlAbsolute( href, baseUrl );
+ } else {
+ //we have a simple id so use the documentUrl as its base.
+ href = path.makeUrlAbsolute( "#" + href, documentUrl.hrefNoHash );
+ }
+ }
+
+ // Should we handle this link, or let the browser deal with it?
+ var useDefaultUrlHandling = $link.is( "[rel='external']" ) || $link.is( ":jqmData(ajax='false')" ) || $link.is( "[target]" ),
+
+ // Some embedded browsers, like the web view in Phone Gap, allow cross-domain XHR
+ // requests if the document doing the request was loaded via the file:// protocol.
+ // This is usually to allow the application to "phone home" and fetch app specific
+ // data. We normally let the browser handle external/cross-domain urls, but if the
+ // allowCrossDomainPages option is true, we will allow cross-domain http/https
+ // requests to go through our page loading logic.
+
+ //check for protocol or rel and its not an embedded page
+ //TODO overlap in logic from isExternal, rel=external check should be
+ // moved into more comprehensive isExternalLink
+ isExternal = useDefaultUrlHandling || ( path.isExternal( href ) && !path.isPermittedCrossDomainRequest( documentUrl, href ) );
+
+ if ( isExternal ) {
+ httpCleanup();
+ //use default click handling
+ return;
+ }
+
+ //use ajax
+ var transition = $link.jqmData( "transition" ),
+ reverse = $link.jqmData( "direction" ) === "reverse" ||
+ // deprecated - remove by 1.0
+ $link.jqmData( "back" ),
+
+ //this may need to be more specific as we use data-rel more
+ role = $link.attr( "data-" + $.mobile.ns + "rel" ) || undefined;
+
+ $.mobile.changePage( href, { transition: transition, reverse: reverse, role: role, link: $link } );
+ event.preventDefault();
+ });
+
+ //prefetch pages when anchors with data-prefetch are encountered
+ $( document ).delegate( ".ui-page", "pageshow.prefetch", function() {
+ var urls = [];
+ $( this ).find( "a:jqmData(prefetch)" ).each(function() {
+ var $link = $( this ),
+ url = $link.attr( "href" );
+
+ if ( url && $.inArray( url, urls ) === -1 ) {
+ urls.push( url );
+
+ $.mobile.loadPage( url, { role: $link.attr( "data-" + $.mobile.ns + "rel" ) } );
+ }
+ });
+ });
+
+ $.mobile._handleHashChange = function( hash ) {
+ //find first page via hash
+ var to = path.stripHash( hash ),
+ //transition is false if it's the first page, undefined otherwise (and may be overridden by default)
+ transition = $.mobile.urlHistory.stack.length === 0 ? "none" : undefined,
+
+ // "navigate" event fired to allow others to take advantage of the more robust hashchange handling
+ navEvent = new $.Event( "navigate" ),
+
+ // default options for the changPage calls made after examining the current state
+ // of the page and the hash
+ changePageOptions = {
+ transition: transition,
+ changeHash: false,
+ fromHashChange: true
+ };
+
+ if ( 0 === urlHistory.stack.length ) {
+ urlHistory.initialDst = to;
+ }
+
+ // We should probably fire the "navigate" event from those places that make calls to _handleHashChange,
+ // and have _handleHashChange hook into the "navigate" event instead of triggering it here
+ $.mobile.pageContainer.trigger( navEvent );
+ if ( navEvent.isDefaultPrevented() ) {
+ return;
+ }
+
+ //if listening is disabled (either globally or temporarily), or it's a dialog hash
+ if ( !$.mobile.hashListeningEnabled || urlHistory.ignoreNextHashChange ) {
+ urlHistory.ignoreNextHashChange = false;
+ return;
+ }
+
+ // special case for dialogs
+ if ( urlHistory.stack.length > 1 && to.indexOf( dialogHashKey ) > -1 && urlHistory.initialDst !== to ) {
+
+ // If current active page is not a dialog skip the dialog and continue
+ // in the same direction
+ if ( !$.mobile.activePage.is( ".ui-dialog" ) ) {
+ //determine if we're heading forward or backward and continue accordingly past
+ //the current dialog
+ urlHistory.directHashChange({
+ currentUrl: to,
+ isBack: function() { $.mobile.back(); },
+ isForward: function() { window.history.forward(); }
+ });
+
+ // prevent changePage()
+ return;
+ } else {
+ // if the current active page is a dialog and we're navigating
+ // to a dialog use the dialog objected saved in the stack
+ urlHistory.directHashChange({
+ currentUrl: to,
+
+ // regardless of the direction of the history change
+ // do the following
+ either: function( isBack ) {
+ var active = $.mobile.urlHistory.getActive();
+
+ to = active.pageUrl;
+
+ // make sure to set the role, transition and reversal
+ // as most of this is lost by the domCache cleaning
+ $.extend( changePageOptions, {
+ role: active.role,
+ transition: active.transition,
+ reverse: isBack
+ });
+ }
+ });
+ }
+ }
+
+ //if to is defined, load it
+ if ( to ) {
+ // At this point, 'to' can be one of 3 things, a cached page element from
+ // a history stack entry, an id, or site-relative/absolute URL. If 'to' is
+ // an id, we need to resolve it against the documentBase, not the location.href,
+ // since the hashchange could've been the result of a forward/backward navigation
+ // that crosses from an external page/dialog to an internal page/dialog.
+ to = ( typeof to === "string" && !path.isPath( to ) ) ? ( path.makeUrlAbsolute( '#' + to, documentBase ) ) : to;
+
+ // If we're about to go to an initial URL that contains a reference to a non-existent
+ // internal page, go to the first page instead. We know that the initial hash refers to a
+ // non-existent page, because the initial hash did not end up in the initial urlHistory entry
+ if ( to === path.makeUrlAbsolute( '#' + urlHistory.initialDst, documentBase ) &&
+ urlHistory.stack.length && urlHistory.stack[0].url !== urlHistory.initialDst.replace( dialogHashKey, "" ) ) {
+ to = $.mobile.firstPage;
+ }
+ $.mobile.changePage( to, changePageOptions );
+ } else {
+ //there's no hash, go to the first page in the dom
+ $.mobile.changePage( $.mobile.firstPage, changePageOptions );
+ }
+ };
+
+ //hashchange event handler
+ $window.bind( "hashchange", function( e, triggered ) {
+ // Firefox auto-escapes the location.hash as for v13 but
+ // leaves the href untouched
+ $.mobile._handleHashChange( path.parseLocation().hash );
+ });
+
+ //set page min-heights to be device specific
+ $( document ).bind( "pageshow", resetActivePageHeight );
+ $( window ).bind( "throttledresize", resetActivePageHeight );
+
+ });//navreadyDeferred done callback
+
+})( jQuery );
+
+(function( $, window ) {
+ // For now, let's Monkeypatch this onto the end of $.mobile._registerInternalEvents
+ // Scope self to pushStateHandler so we can reference it sanely within the
+ // methods handed off as event handlers
+ var pushStateHandler = {},
+ self = pushStateHandler,
+ $win = $( window ),
+ url = $.mobile.path.parseLocation(),
+ mobileinitDeferred = $.Deferred(),
+ domreadyDeferred = $.Deferred();
+
+ $( document ).ready( $.proxy( domreadyDeferred, "resolve" ) );
+
+ $( document ).one( "mobileinit", $.proxy( mobileinitDeferred, "resolve" ) );
+
+ $.extend( pushStateHandler, {
+ // TODO move to a path helper, this is rather common functionality
+ initialFilePath: (function() {
+ return url.pathname + url.search;
+ })(),
+
+ hashChangeTimeout: 200,
+
+ hashChangeEnableTimer: undefined,
+
+ initialHref: url.hrefNoHash,
+
+ state: function() {
+ return {
+ // firefox auto decodes the url when using location.hash but not href
+ hash: $.mobile.path.parseLocation().hash || "#" + self.initialFilePath,
+ title: document.title,
+
+ // persist across refresh
+ initialHref: self.initialHref
+ };
+ },
+
+ resetUIKeys: function( url ) {
+ var dialog = $.mobile.dialogHashKey,
+ subkey = "&" + $.mobile.subPageUrlKey,
+ dialogIndex = url.indexOf( dialog );
+
+ if ( dialogIndex > -1 ) {
+ url = url.slice( 0, dialogIndex ) + "#" + url.slice( dialogIndex );
+ } else if ( url.indexOf( subkey ) > -1 ) {
+ url = url.split( subkey ).join( "#" + subkey );
+ }
+
+ return url;
+ },
+
+ // TODO sort out a single barrier to hashchange functionality
+ nextHashChangePrevented: function( value ) {
+ $.mobile.urlHistory.ignoreNextHashChange = value;
+ self.onHashChangeDisabled = value;
+ },
+
+ // on hash change we want to clean up the url
+ // NOTE this takes place *after* the vanilla navigation hash change
+ // handling has taken place and set the state of the DOM
+ onHashChange: function( e ) {
+ // disable this hash change
+ if ( self.onHashChangeDisabled ) {
+ return;
+ }
+
+ var href, state,
+ // firefox auto decodes the url when using location.hash but not href
+ hash = $.mobile.path.parseLocation().hash,
+ isPath = $.mobile.path.isPath( hash ),
+ resolutionUrl = isPath ? $.mobile.path.getLocation() : $.mobile.getDocumentUrl();
+
+ hash = isPath ? hash.replace( "#", "" ) : hash;
+
+
+ // propulate the hash when its not available
+ state = self.state();
+
+ // make the hash abolute with the current href
+ href = $.mobile.path.makeUrlAbsolute( hash, resolutionUrl );
+
+ if ( isPath ) {
+ href = self.resetUIKeys( href );
+ }
+
+ // replace the current url with the new href and store the state
+ // Note that in some cases we might be replacing an url with the
+ // same url. We do this anyways because we need to make sure that
+ // all of our history entries have a state object associated with
+ // them. This allows us to work around the case where $.mobile.back()
+ // is called to transition from an external page to an embedded page.
+ // In that particular case, a hashchange event is *NOT* generated by the browser.
+ // Ensuring each history entry has a state object means that onPopState()
+ // will always trigger our hashchange callback even when a hashchange event
+ // is not fired.
+ history.replaceState( state, document.title, href );
+ },
+
+ // on popstate (ie back or forward) we need to replace the hash that was there previously
+ // cleaned up by the additional hash handling
+ onPopState: function( e ) {
+ var poppedState = e.originalEvent.state,
+ fromHash, toHash, hashChanged;
+
+ // if there's no state its not a popstate we care about, eg chrome's initial popstate
+ if ( poppedState ) {
+ // if we get two pop states in under this.hashChangeTimeout
+ // make sure to clear any timer set for the previous change
+ clearTimeout( self.hashChangeEnableTimer );
+
+ // make sure to enable hash handling for the the _handleHashChange call
+ self.nextHashChangePrevented( false );
+
+ // change the page based on the hash in the popped state
+ $.mobile._handleHashChange( poppedState.hash );
+
+ // prevent any hashchange in the next self.hashChangeTimeout
+ self.nextHashChangePrevented( true );
+
+ // re-enable hash change handling after swallowing a possible hash
+ // change event that comes on all popstates courtesy of browsers like Android
+ self.hashChangeEnableTimer = setTimeout( function() {
+ self.nextHashChangePrevented( false );
+ }, self.hashChangeTimeout );
+ }
+ },
+
+ init: function() {
+ $win.bind( "hashchange", self.onHashChange );
+
+ // Handle popstate events the occur through history changes
+ $win.bind( "popstate", self.onPopState );
+
+ // if there's no hash, we need to replacestate for returning to home
+ if ( location.hash === "" ) {
+ history.replaceState( self.state(), document.title, $.mobile.path.getLocation() );
+ }
+ }
+ });
+
+ // We need to init when "mobileinit", "domready", and "navready" have all happened
+ $.when( domreadyDeferred, mobileinitDeferred, $.mobile.navreadyDeferred ).done(function() {
+ if ( $.mobile.pushStateEnabled && $.support.pushState ) {
+ pushStateHandler.init();
+ }
+ });
+})( jQuery, this );
+
+/*
+* fallback transition for flip in non-3D supporting browsers (which tend to handle complex transitions poorly in general
+*/
+
+(function( $, window, undefined ) {
+
+$.mobile.transitionFallbacks.flip = "fade";
+
+})( jQuery, this );
+/*
+* fallback transition for flow in non-3D supporting browsers (which tend to handle complex transitions poorly in general
+*/
+
+(function( $, window, undefined ) {
+
+$.mobile.transitionFallbacks.flow = "fade";
+
+})( jQuery, this );
+/*
+* fallback transition for pop in non-3D supporting browsers (which tend to handle complex transitions poorly in general
+*/
+
+(function( $, window, undefined ) {
+
+$.mobile.transitionFallbacks.pop = "fade";
+
+})( jQuery, this );
+/*
+* fallback transition for slide in non-3D supporting browsers (which tend to handle complex transitions poorly in general
+*/
+
+(function( $, window, undefined ) {
+
+// Use the simultaneous transitions handler for slide transitions
+$.mobile.transitionHandlers.slide = $.mobile.transitionHandlers.simultaneous;
+
+// Set the slide transitions's fallback to "fade"
+$.mobile.transitionFallbacks.slide = "fade";
+
+})( jQuery, this );
+/*
+* fallback transition for slidedown in non-3D supporting browsers (which tend to handle complex transitions poorly in general
+*/
+
+(function( $, window, undefined ) {
+
+$.mobile.transitionFallbacks.slidedown = "fade";
+
+})( jQuery, this );
+/*
+* fallback transition for slidefade in non-3D supporting browsers (which tend to handle complex transitions poorly in general
+*/
+
+(function( $, window, undefined ) {
+
+// Set the slide transitions's fallback to "fade"
+$.mobile.transitionFallbacks.slidefade = "fade";
+
+})( jQuery, this );
+/*
+* fallback transition for slideup in non-3D supporting browsers (which tend to handle complex transitions poorly in general
+*/
+
+(function( $, window, undefined ) {
+
+$.mobile.transitionFallbacks.slideup = "fade";
+
+})( jQuery, this );
+/*
+* fallback transition for turn in non-3D supporting browsers (which tend to handle complex transitions poorly in general
+*/
+
+(function( $, window, undefined ) {
+
+$.mobile.transitionFallbacks.turn = "fade";
+
+})( jQuery, this );
+
+(function( $, undefined ) {
+
+$.mobile.page.prototype.options.degradeInputs = {
+ color: false,
+ date: false,
+ datetime: false,
+ "datetime-local": false,
+ email: false,
+ month: false,
+ number: false,
+ range: "number",
+ search: "text",
+ tel: false,
+ time: false,
+ url: false,
+ week: false
+};
+
+
+//auto self-init widgets
+$( document ).bind( "pagecreate create", function( e ) {
+
+ var page = $.mobile.closestPageData( $( e.target ) ), options;
+
+ if ( !page ) {
+ return;
+ }
+
+ options = page.options;
+
+ // degrade inputs to avoid poorly implemented native functionality
+ $( e.target ).find( "input" ).not( page.keepNativeSelector() ).each(function() {
+ var $this = $( this ),
+ type = this.getAttribute( "type" ),
+ optType = options.degradeInputs[ type ] || "text";
+
+ if ( options.degradeInputs[ type ] ) {
+ var html = $( "" ).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: {
+ closeBtnText: "Close",
+ overlayTheme: "a",
+ initSelector: ":jqmData(role='dialog')"
+ },
+ _create: function() {
+ var self = this,
+ $el = this.element,
+ headerCloseButton = $( "
"+ this.options.closeBtnText + "" ),
+ dialogWrap = $( "
", {
+ "role" : "dialog",
+ "class" : "ui-dialog-contain ui-corner-all ui-overlay-shadow"
+ });
+
+ $el.addClass( "ui-dialog ui-overlay-" + this.options.overlayTheme );
+
+ // Class the markup for dialog styling
+ // Set aria role
+ $el
+ .wrapInner( dialogWrap )
+ .children()
+ .find( ":jqmData(role='header')" )
+ .prepend( headerCloseButton )
+ .end()
+ .children( ':first-child')
+ .addClass( "ui-corner-top" )
+ .end()
+ .children( ":last-child" )
+ .addClass( "ui-corner-bottom" );
+
+ // 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.
+ headerCloseButton.bind( "click", function() {
+ self.close();
+ });
+
+ /* 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" );
+ }
+ })
+ .bind( "pagehide", function( e, ui ) {
+ $( this ).find( "." + $.mobile.activeBtnClass ).not( ".ui-slider-bg" ).removeClass( $.mobile.activeBtnClass );
+ })
+ // Override the theme set by the page plugin on pageshow
+ .bind( "pagebeforeshow", function() {
+ self._isCloseable = true;
+ if ( self.options.overlayTheme ) {
+ self.element
+ .page( "removeContainerBackground" )
+ .page( "setContainerBackground", self.options.overlayTheme );
+ }
+ });
+ },
+
+ // Close method goes back in history
+ close: function() {
+ var dst;
+
+ if ( this._isCloseable ) {
+ this._isCloseable = false;
+ if ( $.mobile.hashListeningEnabled ) {
+ $.mobile.back();
+ } else {
+ dst = $.mobile.urlHistory.getPrev().url;
+ if ( !$.mobile.path.isPath( dst ) ) {
+ dst = $.mobile.path.makeUrlAbsolute( "#" + dst );
+ }
+
+ $.mobile.changePage( dst, { changeHash: false, fromHashChange: true } );
+ }
+ }
+ }
+});
+
+//auto self-init widgets
+$( 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
+$( document ).bind( "pagecreate", function( e ) {
+ var $page = $( e.target ),
+ o = $page.data( "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 ) {
+
+// 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 ) {
+
+$( document ).bind( "pagecreate create", function( e ) {
+ $( ":jqmData(role='nojs')", e.target ).addClass( "ui-nojs" );
+
+});
+
+})( jQuery );
+
+(function( $, undefined ) {
+
+$.fn.buttonMarkup = function( options ) {
+ var $workingSet = this,
+ mapToDataAttr = function( key, value ) {
+ e.setAttribute( "data-" + $.mobile.ns + key, value );
+ el.jqmData( key, value );
+ };
+
+ // 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 : el.jqmData( "icon" ),
+ iconpos: options.iconpos !== undefined ? options.iconpos : el.jqmData( "iconpos" ),
+ theme: options.theme !== undefined ? options.theme : el.jqmData( "theme" ) || $.mobile.getInheritedTheme( el, "c" ),
+ inline: options.inline !== undefined ? options.inline : el.jqmData( "inline" ),
+ shadow: options.shadow !== undefined ? options.shadow : el.jqmData( "shadow" ),
+ corners: options.corners !== undefined ? options.corners : el.jqmData( "corners" ),
+ iconshadow: options.iconshadow !== undefined ? options.iconshadow : el.jqmData( "iconshadow" ),
+ mini: options.mini !== undefined ? options.mini : el.jqmData( "mini" )
+ }, options ),
+
+ // Classes Defined
+ innerClass = "ui-btn-inner",
+ textClass = "ui-btn-text",
+ buttonClass, iconClass,
+ // Button inner markup
+ buttonInner,
+ buttonText,
+ buttonIcon,
+ buttonElements;
+
+ $.each( o, mapToDataAttr );
+
+ if ( el.jqmData( "rel" ) === "popup" && el.attr( "href" ) ) {
+ e.setAttribute( "aria-haspopup", true );
+ e.setAttribute( "aria-owns", e.getAttribute( "href" ) );
+ }
+
+ // 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;
+ }
+ 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 ui-btn-up-" + 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() );
+ }
+ }
+
+ innerClass += o.corners ? " ui-btn-corner-all" : "";
+
+ if ( o.iconpos && 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 = {
+ 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;
+}
+
+var attachEvents = function() {
+ var hoverDelay = $.mobile.buttonMarkup.hoverDelay, hov, foc;
+
+ $( 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() {
+ $btn.removeClass( "ui-btn-up-" + theme ).addClass( "ui-btn-down-" + theme );
+ }, hoverDelay );
+ } else {
+ $btn.removeClass( "ui-btn-up-" + theme ).addClass( "ui-btn-down-" + theme );
+ }
+ } else if ( evt === "vmousecancel" || evt === "vmouseup" ) {
+ $btn.removeClass( "ui-btn-down-" + theme ).addClass( "ui-btn-up-" + theme );
+ } else if ( evt === "vmouseover" || evt === "focus" ) {
+ if ( isTouchEvent ) {
+ // Use a short delay to determine if the user is scrolling before highlighting
+ foc = setTimeout( function() {
+ $btn.removeClass( "ui-btn-up-" + theme ).addClass( "ui-btn-hover-" + theme );
+ }, hoverDelay );
+ } else {
+ $btn.removeClass( "ui-btn-up-" + theme ).addClass( "ui-btn-hover-" + theme );
+ }
+ } else if ( evt === "vmouseout" || evt === "blur" || evt === "scrollstart" ) {
+ $btn.removeClass( "ui-btn-hover-" + theme + " ui-btn-down-" + theme ).addClass( "ui-btn-up-" + theme );
+ 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
+$( 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",
+ theme: null,
+ contentTheme: null,
+ inset: 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(),
+ collapsedIcon = $el.jqmData( "collapsed-icon" ) || o.collapsedIcon,
+ expandedIcon = $el.jqmData( "expanded-icon" ) || o.expandedIcon,
+ collapsibleContent = collapsible.wrapInner( "
" ).children( ".ui-collapsible-content" ),
+ collapsibleSet = $el.closest( ":jqmData(role='collapsible-set')" ).addClass( "ui-collapsible-set" );
+
+ // 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
+ if ( !o.collapsedIcon ) {
+ o.collapsedIcon = collapsibleSet.jqmData( "collapsed-icon" );
+ }
+ // Get the preference for expanded icon in the set
+ if ( !o.expandedIcon ) {
+ o.expandedIcon = collapsibleSet.jqmData( "expanded-icon" );
+ }
+ // Gets the preference icon position in the set
+ if ( !o.iconPos ) {
+ o.iconPos = collapsibleSet.jqmData( "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;
+ }
+ // 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 ) {
+ collapsible.addClass( "ui-collapsible-inset" );
+ }
+
+ collapsibleContent.addClass( ( o.contentTheme ) ? ( "ui-body-" + o.contentTheme ) : "");
+
+ collapsedIcon = $el.jqmData( "collapsed-icon" ) || o.collapsedIcon || "plus";
+ expandedIcon = $el.jqmData( "expanded-icon" ) || o.expandedIcon || "minus";
+
+ 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: $el.jqmData( "iconpos" ) || o.iconPos || "left",
+ icon: collapsedIcon,
+ mini: o.mini,
+ theme: o.theme
+ });
+
+ if ( !!o.inset ) {
+ collapsibleHeading
+ .find( "a" ).first().add( ".ui-btn-inner", $el )
+ .addClass( "ui-corner-top ui-corner-bottom" );
+ }
+
+ //events
+ collapsible
+ .bind( "expand collapse", function( event ) {
+ if ( !event.isDefaultPrevented() ) {
+ var $this = $( this ),
+ isCollapse = ( event.type === "collapse" ),
+ contentTheme = o.contentTheme;
+
+ 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-" + expandedIcon, !isCollapse )
+ // logic or cause same icon for expanded/collapsed state would remove the ui-icon-class
+ .toggleClass( "ui-icon-" + collapsedIcon, ( isCollapse || expandedIcon === 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 );
+
+ if ( contentTheme && !!o.inset && ( !collapsibleSet.length || collapsible.jqmData( "collapsible-last" ) ) ) {
+ collapsibleHeading
+ .find( "a" ).first().add( collapsibleHeading.find( ".ui-btn-inner" ) )
+ .toggleClass( "ui-corner-bottom", isCollapse );
+ collapsibleContent.toggleClass( "ui-corner-bottom", !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
+$( document ).bind( "pagecreate create", function( e ) {
+ $.mobile.collapsible.prototype.enhanceWithin( e.target );
+});
+
+})( jQuery );
+
+(function( $, undefined ) {
+
+$.widget( "mobile.collapsibleset", $.mobile.widget, {
+ 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" );
+ }
+
+ if ( $el.jqmData( "inset" ) !== undefined ) {
+ o.inset = $el.jqmData( "inset" );
+ }
+ o.inset = o.inset !== undefined ? o.inset : true;
+
+ // Initialize the collapsible set if it's not already initialized
+ if ( !$el.jqmData( "collapsiblebound" ) ) {
+ $el
+ .jqmData( "collapsiblebound", true )
+ .bind( "expand collapse", function( event ) {
+ var isCollapse = ( event.type === "collapse" ),
+ collapsible = $( event.target ).closest( ".ui-collapsible" ),
+ widget = collapsible.data( "collapsible" );
+ if ( collapsible.jqmData( "collapsible-last" ) && !!o.inset ) {
+ collapsible.find( ".ui-collapsible-heading" ).first()
+ .find( "a" ).first()
+ .toggleClass( "ui-corner-bottom", isCollapse )
+ .find( ".ui-btn-inner" )
+ .toggleClass( "ui-corner-bottom", isCollapse );
+ collapsible.find( ".ui-collapsible-content" ).toggleClass( "ui-corner-bottom", !isCollapse );
+ }
+ })
+ .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();
+
+ // 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() {
+ var $el = this.element,
+ o = this.options,
+ collapsiblesInSet = $el.children( ":jqmData(role='collapsible')" );
+
+ $.mobile.collapsible.prototype.enhance( collapsiblesInSet.not( ".ui-collapsible" ) );
+
+ // clean up borders
+ if ( !!o.inset ) {
+ collapsiblesInSet.each(function() {
+ $( this ).jqmRemoveData( "collapsible-last" )
+ .find( ".ui-collapsible-heading" )
+ .find( "a" ).first()
+ .removeClass( "ui-corner-top ui-corner-bottom" )
+ .find( ".ui-btn-inner" )
+ .removeClass( "ui-corner-top ui-corner-bottom" );
+ });
+
+ collapsiblesInSet.first()
+ .find( "a" )
+ .first()
+ .addClass( "ui-corner-top" )
+ .find( ".ui-btn-inner" )
+ .addClass( "ui-corner-top" );
+
+ collapsiblesInSet.last()
+ .jqmData( "collapsible-last", true )
+ .find( "a" )
+ .first()
+ .addClass( "ui-corner-bottom" )
+ .find( ".ui-btn-inner" )
+ .addClass( "ui-corner-bottom" );
+ }
+ }
+});
+
+//auto self-init widgets
+$( document ).bind( "pagecreate create", function( e ) {
+ $.mobile.collapsibleset.prototype.enhanceWithin( e.target );
+});
+
+})( 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 ) {
+ if ( !$(event.target).hasClass( "ui-disabled" ) ) {
+ $navbtns.removeClass( $.mobile.activeBtnClass );
+ $( this ).addClass( $.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
+$( 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, {
+
+ options: {
+ theme: null,
+ countTheme: "c",
+ headerTheme: "b",
+ dividerTheme: "b",
+ splitIcon: "arrow-r",
+ splitTheme: "b",
+ inset: false,
+ initSelector: ":jqmData(role='listview')"
+ },
+
+ _create: function() {
+ var t = this,
+ listviewClasses = "";
+
+ listviewClasses += t.options.inset ? " ui-listview-inset ui-corner-all ui-shadow " : "";
+
+ // create listview markup
+ t.element.addClass(function( i, orig ) {
+ return orig + " ui-listview " + listviewClasses;
+ });
+
+ t.refresh( true );
+ },
+
+ _removeCorners: function( li, which ) {
+ var top = "ui-corner-top ui-corner-tr ui-corner-tl",
+ bot = "ui-corner-bottom ui-corner-br ui-corner-bl";
+
+ li = li.add( li.find( ".ui-btn-inner, .ui-li-link-alt, .ui-li-thumb" ) );
+
+ if ( which === "top" ) {
+ li.removeClass( top );
+ } else if ( which === "bottom" ) {
+ li.removeClass( bot );
+ } else {
+ li.removeClass( top + " " + bot );
+ }
+ },
+
+ _refreshCorners: function( create ) {
+ var $li,
+ $visibleli,
+ $topli,
+ $bottomli;
+
+ $li = this.element.children( "li" );
+ // At create time and when autodividers calls refresh the li are not visible yet so we need to rely on .ui-screen-hidden
+ $visibleli = create || $li.filter( ":visible" ).length === 0 ? $li.not( ".ui-screen-hidden" ) : $li.filter( ":visible" );
+
+ // ui-li-last is used for setting border-bottom on the last li
+ $li.filter( ".ui-li-last" ).removeClass( "ui-li-last" );
+
+ if ( this.options.inset ) {
+ this._removeCorners( $li );
+
+ // Select the first visible li element
+ $topli = $visibleli.first()
+ .addClass( "ui-corner-top" );
+
+ $topli.add( $topli.find( ".ui-btn-inner" )
+ .not( ".ui-li-link-alt span:first-child" ) )
+ .addClass( "ui-corner-top" )
+ .end()
+ .find( ".ui-li-link-alt, .ui-li-link-alt span:first-child" )
+ .addClass( "ui-corner-tr" )
+ .end()
+ .find( ".ui-li-thumb" )
+ .not( ".ui-li-icon" )
+ .addClass( "ui-corner-tl" );
+
+ // Select the last visible li element
+ $bottomli = $visibleli.last()
+ .addClass( "ui-corner-bottom ui-li-last" );
+
+ $bottomli.add( $bottomli.find( ".ui-btn-inner" ) )
+ .find( ".ui-li-link-alt" )
+ .addClass( "ui-corner-br" )
+ .end()
+ .find( ".ui-li-thumb" )
+ .not( ".ui-li-icon" )
+ .addClass( "ui-corner-bl" );
+ } else {
+ $visibleli.last().addClass( "ui-li-last" );
+ }
+ if ( !create ) {
+ this.element.trigger( "updatelayout" );
+ }
+ },
+
+ // 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" ),
+ 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 = parseFloat( start ) - 1;
+ $list.css( "counter-reset", "listnumbering " + startCount );
+ } else {
+ counter = parseFloat( start );
+ }
+ } 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 || "arrow-r",
+ 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", 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-" + dividertheme;
+ item.attr( "role", "heading" );
+
+ if ( ol ) {
+ //reset counter when a divider heading is encountered
+ if ( start || start === 0 ) {
+ if ( !jsCount ) {
+ newStartCount = parseFloat( start ) - 1;
+ item.css( "counter-reset", "listnumbering " + newStartCount );
+ } else {
+ counter = parseFloat( start );
+ }
+ } 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._refreshCorners( 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( "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 + "')" );
+ }
+});
+
+//auto self-init widgets
+$( document ).bind( "pagecreate create", function( e ) {
+ $.mobile.listview.prototype.enhanceWithin( e.target );
+});
+
+})( jQuery );
+
+(function( $, undefined ) {
+
+$.mobile.listview.prototype.options.autodividers = false;
+$.mobile.listview.prototype.options.autodividersSelector = function( elt ) {
+ // look for the text in the given element
+ var text = elt.text() || null;
+
+ if ( !text ) {
+ return null;
+ }
+
+ // create the text for the divider (first uppercased letter)
+ text = text.slice( 0, 1 ).toUpperCase();
+
+ return text;
+};
+
+$( document ).delegate( "ul,ol", "listviewcreate", function() {
+
+ var list = $( this ),
+ listview = list.data( "listview" );
+
+ if ( !listview || !listview.options.autodividers ) {
+ return;
+ }
+
+ var replaceDividers = function () {
+ list.find( "li:jqmData(role='list-divider')" ).remove();
+
+ var lis = list.find( 'li' ),
+ lastDividerText = null, li, dividerText;
+
+ for ( var i = 0; i < lis.length ; i++ ) {
+ li = lis[i];
+ dividerText = listview.options.autodividersSelector( $( li ) );
+
+ if ( dividerText && lastDividerText !== dividerText ) {
+ var divider = document.createElement( 'li' );
+ divider.appendChild( document.createTextNode( dividerText ) );
+ divider.setAttribute( 'data-' + $.mobile.ns + 'role', 'list-divider' );
+ li.parentNode.insertBefore( divider, li );
+ }
+
+ lastDividerText = dividerText;
+ }
+ };
+
+ var afterListviewRefresh = function () {
+ list.unbind( 'listviewafterrefresh', afterListviewRefresh );
+ replaceDividers();
+ listview.refresh();
+ list.bind( 'listviewafterrefresh', afterListviewRefresh );
+ };
+
+ afterListviewRefresh();
+});
+
+})( jQuery );
+
+/*
+* "checkboxradio" plugin
+*/
+
+(function( $, undefined ) {
+
+$.widget( "mobile.checkboxradio", $.mobile.widget, {
+ options: {
+ theme: null,
+ initSelector: "input[type='checkbox'],input[type='radio']"
+ },
+ _create: function() {
+ var self = this,
+ input = this.element,
+ inheritAttr = function( input, dataAttr ) {
+ return input.jqmData( dataAttr ) || input.closest( "form, fieldset" ).jqmData( dataAttr );
+ },
+ // NOTE: Windows Phone could not find the label through a selector
+ // filter works though.
+ parentLabel = $( input ).closest( "label" ),
+ label = parentLabel.length ? parentLabel : $( input ).closest( "form, fieldset, :jqmData(role='page'), :jqmData(role='dialog')" ).find( "label" ).filter( "[for='" + input[0].id + "']" ).first(),
+ inputtype = input[0].type,
+ mini = inheritAttr( input, "mini" ),
+ checkedState = inputtype + "-on",
+ uncheckedState = inputtype + "-off",
+ icon = input.parents( ":jqmData(type='horizontal')" ).length ? undefined : uncheckedState,
+ iconpos = inheritAttr( input, "iconpos" ),
+ activeBtn = icon ? "" : " " + $.mobile.activeBtnClass,
+ checkedClass = "ui-" + checkedState + activeBtn,
+ uncheckedClass = "ui-" + uncheckedState,
+ checkedicon = "ui-icon-" + checkedState,
+ uncheckedicon = "ui-icon-" + uncheckedState;
+
+ if ( inputtype !== "checkbox" && inputtype !== "radio" ) {
+ return;
+ }
+
+ // Expose for other methods
+ $.extend( this, {
+ label: label,
+ inputtype: inputtype,
+ checkedClass: checkedClass,
+ uncheckedClass: uncheckedClass,
+ checkedicon: checkedicon,
+ uncheckedicon: uncheckedicon
+ });
+
+ // If there's no selected theme check the data attr
+ if ( !this.options.theme ) {
+ this.options.theme = $.mobile.getInheritedTheme( this.element, "c" );
+ }
+
+ label.buttonMarkup({
+ theme: this.options.theme,
+ icon: icon,
+ shadow: false,
+ mini: mini,
+ iconpos: iconpos
+ });
+
+ // Wrap the input + label in a div
+ var wrapper = document.createElement('div');
+ wrapper.className = 'ui-' + inputtype;
+
+ input.add( label ).wrapAll( wrapper );
+
+ label.bind({
+ vmouseover: function( event ) {
+ if ( $( this ).parent().is( ".ui-disabled" ) ) {
+ event.stopPropagation();
+ }
+ },
+
+ vclick: function( event ) {
+ if ( input.is( ":disabled" ) ) {
+ event.preventDefault();
+ return;
+ }
+
+ self._cacheVals();
+
+ input.prop( "checked", inputtype === "radio" && true || !input.prop( "checked" ) );
+
+ // trigger click handler's bound directly to the input as a substitute for
+ // how label clicks behave normally in the browsers
+ // TODO: it would be nice to let the browser's handle the clicks and pass them
+ // through to the associate input. we can swallow that click at the parent
+ // wrapper element level
+ input.triggerHandler( 'click' );
+
+ // Input set for common radio buttons will contain all the radio
+ // buttons, but will not for checkboxes. clearing the checked status
+ // of other radios ensures the active button state is applied properly
+ self._getInputSet().not( input ).prop( "checked", false );
+
+ self._updateAll();
+ return false;
+ }
+ });
+
+ input
+ .bind({
+ vmousedown: function() {
+ self._cacheVals();
+ },
+
+ vclick: function() {
+ var $this = $( this );
+
+ // Adds checked attribute to checked input when keyboard is used
+ if ( $this.is( ":checked" ) ) {
+
+ $this.prop( "checked", true);
+ self._getInputSet().not( $this ).prop( "checked", false );
+ } else {
+
+ $this.prop( "checked", false );
+ }
+
+ self._updateAll();
+ },
+
+ focus: function() {
+ label.addClass( $.mobile.focusClass );
+ },
+
+ blur: function() {
+ label.removeClass( $.mobile.focusClass );
+ }
+ });
+
+ this.refresh();
+ },
+
+ _cacheVals: function() {
+ this._getInputSet().each(function() {
+ $( this ).jqmData( "cacheVal", this.checked );
+ });
+ },
+
+ //returns either a set of radios with the same name attribute, or a single checkbox
+ _getInputSet: function() {
+ if ( this.inputtype === "checkbox" ) {
+ return this.element;
+ }
+
+ return this.element.closest( "form, fieldset, :jqmData(role='page'), :jqmData(role='dialog')" )
+ .find( "input[name='" + this.element[0].name + "'][type='" + this.inputtype + "']" );
+ },
+
+ _updateAll: function() {
+ var self = this;
+
+ this._getInputSet().each(function() {
+ var $this = $( this );
+
+ if ( this.checked || self.inputtype === "checkbox" ) {
+ $this.trigger( "change" );
+ }
+ })
+ .checkboxradio( "refresh" );
+ },
+
+ refresh: function() {
+ var input = this.element[0],
+ label = this.label,
+ icon = label.find( ".ui-icon" );
+
+ if ( input.checked ) {
+ label.addClass( this.checkedClass ).removeClass( this.uncheckedClass );
+ icon.addClass( this.checkedicon ).removeClass( this.uncheckedicon );
+ } else {
+ label.removeClass( this.checkedClass ).addClass( this.uncheckedClass );
+ icon.removeClass( this.checkedicon ).addClass( this.uncheckedicon );
+ }
+
+ if ( input.disabled ) {
+ this.disable();
+ } else {
+ this.enable();
+ }
+ },
+
+ disable: function() {
+ this.element.prop( "disabled", true ).parent().addClass( "ui-disabled" );
+ },
+
+ enable: function() {
+ this.element.prop( "disabled", false ).parent().removeClass( "ui-disabled" );
+ }
+});
+
+//auto self-init widgets
+$( document ).bind( "pagecreate create", function( e ) {
+ $.mobile.checkboxradio.prototype.enhanceWithin( e.target, true );
+});
+
+})( jQuery );
+
+(function( $, undefined ) {
+
+$.widget( "mobile.button", $.mobile.widget, {
+ options: {
+ theme: null,
+ icon: null,
+ iconpos: null,
+ corners: true,
+ shadow: true,
+ iconshadow: true,
+ initSelector: "button, [type='button'], [type='submit'], [type='reset']"
+ },
+ _create: function() {
+ var $el = this.element,
+ $button,
+ o = this.options,
+ type,
+ name,
+ inline = o.inline || $el.jqmData( "inline" ),
+ mini = o.mini || $el.jqmData( "mini" ),
+ classes = "",
+ $buttonPlaceholder;
+
+ // if this is a link, check if it's been enhanced and, if not, use the right function
+ if ( $el[ 0 ].tagName === "A" ) {
+ if ( !$el.hasClass( "ui-btn" ) ) {
+ $el.buttonMarkup();
+ }
+
+ return;
+ }
+
+ // get the inherited theme
+ // TODO centralize for all widgets
+ if ( !this.options.theme ) {
+ this.options.theme = $.mobile.getInheritedTheme( this.element, "c" );
+ }
+
+ // TODO: Post 1.1--once we have time to test thoroughly--any classes manually applied to the original element should be carried over to the enhanced element, with an `-enhanced` suffix. See https://github.com/jquery/jquery-mobile/issues/3577
+ /* if ( $el[0].className.length ) {
+ classes = $el[0].className;
+ } */
+ if ( !!~$el[0].className.indexOf( "ui-btn-left" ) ) {
+ classes = "ui-btn-left";
+ }
+
+ if ( !!~$el[0].className.indexOf( "ui-btn-right" ) ) {
+ classes = "ui-btn-right";
+ }
+
+ if ( $el.attr( "type" ) === "submit" || $el.attr( "type" ) === "reset" ) {
+ classes ? classes += " ui-submit" : classes = "ui-submit";
+ }
+ $( "label[for='" + $el.attr( "id" ) + "']" ).addClass( "ui-submit" );
+
+ // Add ARIA role
+ this.button = $( "
" )
+ [ $el.html() ? "html" : "text" ]( $el.html() || $el.val() )
+ .insertBefore( $el )
+ .buttonMarkup({
+ theme: o.theme,
+ icon: o.icon,
+ iconpos: o.iconpos,
+ inline: inline,
+ corners: o.corners,
+ shadow: o.shadow,
+ iconshadow: o.iconshadow,
+ mini: mini
+ })
+ .addClass( classes )
+ .append( $el.addClass( "ui-btn-hidden" ) );
+
+ $button = this.button;
+ type = $el.attr( "type" );
+ name = $el.attr( "name" );
+
+ // Add hidden input during submit if input type="submit" has a name.
+ if ( type !== "button" && type !== "reset" && name ) {
+ $el.bind( "vclick", function() {
+ // Add hidden input if it doesn't already exist.
+ if ( $buttonPlaceholder === undefined ) {
+ $buttonPlaceholder = $( "
", {
+ type: "hidden",
+ name: $el.attr( "name" ),
+ value: $el.attr( "value" )
+ }).insertBefore( $el );
+
+ // Bind to doc to remove after submit handling
+ $( document ).one( "submit", function() {
+ $buttonPlaceholder.remove();
+
+ // reset the local var so that the hidden input
+ // will be re-added on subsequent clicks
+ $buttonPlaceholder = undefined;
+ });
+ }
+ });
+ }
+
+ $el.bind({
+ focus: function() {
+ $button.addClass( $.mobile.focusClass );
+ },
+
+ blur: function() {
+ $button.removeClass( $.mobile.focusClass );
+ }
+ });
+
+ this.refresh();
+ },
+
+ enable: function() {
+ this.element.attr( "disabled", false );
+ this.button.removeClass( "ui-disabled" ).attr( "aria-disabled", false );
+ return this._setOption( "disabled", false );
+ },
+
+ disable: function() {
+ this.element.attr( "disabled", true );
+ this.button.addClass( "ui-disabled" ).attr( "aria-disabled", true );
+ return this._setOption( "disabled", true );
+ },
+
+ refresh: function() {
+ var $el = this.element;
+
+ if ( $el.prop("disabled") ) {
+ this.disable();
+ } else {
+ this.enable();
+ }
+
+ // Grab the button's text element from its implementation-independent data item
+ $( this.button.data( 'buttonElements' ).text )[ $el.html() ? "html" : "text" ]( $el.html() || $el.val() );
+ }
+});
+
+//auto self-init widgets
+$( document ).bind( "pagecreate create", function( e ) {
+ $.mobile.button.prototype.enhanceWithin( e.target, true );
+});
+
+})( jQuery );
+
+(function( $, undefined ) {
+
+$.fn.controlgroup = function( options ) {
+ function flipClasses( els, flCorners ) {
+ els.removeClass( "ui-btn-corner-all ui-corner-top ui-corner-bottom ui-corner-left ui-corner-right ui-controlgroup-last ui-shadow" )
+ .eq( 0 ).addClass( flCorners[ 0 ] )
+ .end()
+ .last().addClass( flCorners[ 1 ] ).addClass( "ui-controlgroup-last" );
+ }
+
+ return this.each(function() {
+ var $el = $( this ),
+ o = $.extend({
+ direction: $el.jqmData( "type" ) || "vertical",
+ shadow: false,
+ excludeInvisible: true,
+ mini: $el.jqmData( "mini" )
+ }, options ),
+ grouplegend = $el.children( "legend" ),
+ groupheading = $el.children( ".ui-controlgroup-label" ),
+ groupcontrols = $el.children( ".ui-controlgroup-controls" ),
+ flCorners = o.direction === "horizontal" ? [ "ui-corner-left", "ui-corner-right" ] : [ "ui-corner-top", "ui-corner-bottom" ],
+ type = $el.find( "input" ).first().attr( "type" );
+
+ // First unwrap the controls if the controlgroup was already enhanced
+ if ( groupcontrols.length ) {
+ groupcontrols.contents().unwrap();
+ }
+ $el.wrapInner( "
" );
+
+ if ( grouplegend.length ) {
+ // Replace legend with more stylable replacement div
+ $( "
" + grouplegend.html() + "
" ).insertBefore( $el.children( 0 ) );
+ grouplegend.remove();
+ } else if ( groupheading.length ) {
+ // Just move the heading if the controlgroup was already enhanced
+ $el.prepend( groupheading );
+ }
+
+ $el.addClass( "ui-corner-all ui-controlgroup ui-controlgroup-" + o.direction );
+
+ flipClasses( $el.find( ".ui-btn" + ( o.excludeInvisible ? ":visible" : "" ) ).not( '.ui-slider-handle' ), flCorners );
+ flipClasses( $el.find( ".ui-btn-inner" ), flCorners );
+
+ if ( o.shadow ) {
+ $el.addClass( "ui-shadow" );
+ }
+
+ if ( o.mini ) {
+ $el.addClass( "ui-mini" );
+ }
+
+ });
+};
+
+// The pagecreate handler for controlgroup is in jquery.mobile.init because of the soft-dependency on the wrapped widgets
+
+})(jQuery);
+
+(function( $, undefined ) {
+
+$( document ).bind( "pagecreate create", function( e ) {
+
+ //links within content areas, tests included with page
+ $( e.target )
+ .find( "a" )
+ .jqmEnhanceable()
+ .not( ".ui-btn, .ui-link-inherit, :jqmData(role='none'), :jqmData(role='nojs')" )
+ .addClass( "ui-link" );
+
+});
+
+})( jQuery );
+
+
+(function( $, undefined ) {
+
+ function fitSegmentInsideSegment( winSize, segSize, offset, desired ) {
+ var ret = desired;
+
+ if ( winSize < segSize ) {
+ // Center segment if it's bigger than the window
+ ret = offset + ( winSize - segSize ) / 2;
+ } else {
+ // Otherwise center it at the desired coordinate while keeping it completely inside the window
+ ret = Math.min( Math.max( offset, desired - segSize / 2 ), offset + winSize - segSize );
+ }
+
+ return ret;
+ }
+
+ function windowCoords() {
+ var $win = $( window );
+
+ return {
+ x: $win.scrollLeft(),
+ y: $win.scrollTop(),
+ cx: ( window.innerWidth || $win.width() ),
+ cy: ( window.innerHeight || $win.height() )
+ };
+ }
+
+ $.widget( "mobile.popup", $.mobile.widget, {
+ options: {
+ theme: null,
+ overlayTheme: null,
+ shadow: true,
+ corners: true,
+ transition: "none",
+ positionTo: "origin",
+ tolerance: null,
+ initSelector: ":jqmData(role='popup')",
+ closeLinkSelector: "a:jqmData(rel='back')",
+ closeLinkEvents: "click.popup",
+ navigateEvents: "navigate.popup",
+ closeEvents: "navigate.popup pagebeforechange.popup",
+
+ // NOTE Windows Phone 7 has a scroll position caching issue that
+ // requires us to disable popup history management by default
+ // https://github.com/jquery/jquery-mobile/issues/4784
+ //
+ // NOTE this option is modified in _create!
+ history: !$.mobile.browser.ie
+ },
+
+ _eatEventAndClose: function( e ) {
+ e.preventDefault();
+ e.stopImmediatePropagation();
+ this.close();
+ return false;
+ },
+
+ // Make sure the screen size is increased beyond the page height if the popup's causes the document to increase in height
+ _resizeScreen: function() {
+ var popupHeight = this._ui.container.outerHeight( true );
+
+ this._ui.screen.removeAttr( "style" );
+ if ( popupHeight > this._ui.screen.height() ) {
+ this._ui.screen.height( popupHeight );
+ }
+ },
+
+ _handleWindowKeyUp: function( e ) {
+ if ( this._isOpen && e.keyCode === $.mobile.keyCode.ESCAPE ) {
+ return this._eatEventAndClose( e );
+ }
+ },
+
+ _maybeRefreshTimeout: function() {
+ var winCoords = windowCoords();
+
+ if ( this._resizeData ) {
+ if ( winCoords.x === this._resizeData.winCoords.x &&
+ winCoords.y === this._resizeData.winCoords.y &&
+ winCoords.cx === this._resizeData.winCoords.cx &&
+ winCoords.cy === this._resizeData.winCoords.cy ) {
+ // timeout not refreshed
+ return false;
+ } else {
+ // clear existing timeout - it will be refreshed below
+ clearTimeout( this._resizeData.timeoutId );
+ }
+ }
+
+ this._resizeData = {
+ timeoutId: setTimeout( $.proxy( this, "_resizeTimeout" ), 200 ),
+ winCoords: winCoords
+ };
+
+ return true;
+ },
+
+ _resizeTimeout: function() {
+ if ( !this._maybeRefreshTimeout() ) {
+ // effectively rapid-open the popup while leaving the screen intact
+ this._trigger( "beforeposition" );
+ this._ui.container
+ .removeClass( "ui-selectmenu-hidden" )
+ .offset( this._placementCoords( this._desiredCoords( undefined, undefined, "window" ) ) );
+
+ this._resizeScreen();
+ this._resizeData = null;
+ this._orientationchangeInProgress = false;
+ }
+ },
+
+ _handleWindowResize: function( e ) {
+ if ( this._isOpen ) {
+ this._maybeRefreshTimeout();
+ }
+ },
+
+ _handleWindowOrientationchange: function( e ) {
+
+ if ( !this._orientationchangeInProgress ) {
+ // effectively rapid-close the popup while leaving the screen intact
+ this._ui.container
+ .addClass( "ui-selectmenu-hidden" )
+ .removeAttr( "style" );
+
+ this._orientationchangeInProgress = true;
+ }
+ },
+
+ _create: function() {
+ var ui = {
+ screen: $( "" ),
+ placeholder: $( "
" ),
+ container: $( "" )
+ },
+ thisPage = this.element.closest( ".ui-page" ),
+ myId = this.element.attr( "id" ),
+ self = this;
+
+ // We need to adjust the history option to be false if there's no AJAX nav.
+ // We can't do it in the option declarations because those are run before
+ // it is determined whether there shall be AJAX nav.
+ this.options.history = this.options.history && $.mobile.ajaxEnabled && $.mobile.hashListeningEnabled;
+
+ if ( thisPage.length === 0 ) {
+ thisPage = $( "body" );
+ }
+
+ // define the container for navigation event bindings
+ // TODO this would be nice at the the mobile widget level
+ this.options.container = this.options.container || $.mobile.pageContainer;
+
+ // Apply the proto
+ thisPage.append( ui.screen );
+ ui.container.insertAfter( ui.screen );
+ // Leave a placeholder where the element used to be
+ ui.placeholder.insertAfter( this.element );
+ if ( myId ) {
+ ui.screen.attr( "id", myId + "-screen" );
+ ui.container.attr( "id", myId + "-popup" );
+ ui.placeholder.html( "" );
+ }
+ ui.container.append( this.element );
+
+ // Add class to popup element
+ this.element.addClass( "ui-popup" );
+
+ // Define instance variables
+ $.extend( this, {
+ _page: thisPage,
+ _ui: ui,
+ _fallbackTransition: "",
+ _currentTransition: false,
+ _prereqs: null,
+ _isOpen: false,
+ _tolerance: null,
+ _resizeData: null,
+ _orientationchangeInProgress: false,
+ _globalHandlers: [
+ {
+ src: $( window ),
+ handler: {
+ orientationchange: $.proxy( this, "_handleWindowOrientationchange" ),
+ resize: $.proxy( this, "_handleWindowResize" ),
+ keyup: $.proxy( this, "_handleWindowKeyUp" )
+ }
+ }
+ ]
+ });
+
+ $.each( this.options, function( key, value ) {
+ // Cause initial options to be applied by their handler by temporarily setting the option to undefined
+ // - the handler then sets it to the initial value
+ self.options[ key ] = undefined;
+ self._setOption( key, value, true );
+ });
+
+ ui.screen.bind( "vclick", $.proxy( this, "_eatEventAndClose" ) );
+
+ $.each( this._globalHandlers, function( idx, value ) {
+ value.src.bind( value.handler );
+ });
+ },
+
+ _applyTheme: function( dst, theme, prefix ) {
+ var classes = ( dst.attr( "class" ) || "").split( " " ),
+ alreadyAdded = true,
+ currentTheme = null,
+ matches,
+ themeStr = String( theme );
+
+ while ( classes.length > 0 ) {
+ currentTheme = classes.pop();
+ matches = ( new RegExp( "^ui-" + prefix + "-([a-z])$" ) ).exec( currentTheme );
+ if ( matches && matches.length > 1 ) {
+ currentTheme = matches[ 1 ];
+ break;
+ } else {
+ currentTheme = null;
+ }
+ }
+
+ if ( theme !== currentTheme ) {
+ dst.removeClass( "ui-" + prefix + "-" + currentTheme );
+ if ( ! ( theme === null || theme === "none" ) ) {
+ dst.addClass( "ui-" + prefix + "-" + themeStr );
+ }
+ }
+ },
+
+ _setTheme: function( value ) {
+ this._applyTheme( this.element, value, "body" );
+ },
+
+ _setOverlayTheme: function( value ) {
+ this._applyTheme( this._ui.screen, value, "overlay" );
+
+ if ( this._isOpen ) {
+ this._ui.screen.addClass( "in" );
+ }
+ },
+
+ _setShadow: function( value ) {
+ this.element.toggleClass( "ui-overlay-shadow", value );
+ },
+
+ _setCorners: function( value ) {
+ this.element.toggleClass( "ui-corner-all", value );
+ },
+
+ _applyTransition: function( value ) {
+ this._ui.container.removeClass( this._fallbackTransition );
+ if ( value && value !== "none" ) {
+ this._fallbackTransition = $.mobile._maybeDegradeTransition( value );
+ this._ui.container.addClass( this._fallbackTransition );
+ }
+ },
+
+ _setTransition: function( value ) {
+ if ( !this._currentTransition ) {
+ this._applyTransition( value );
+ }
+ },
+
+ _setTolerance: function( value ) {
+ var tol = { t: 30, r: 15, b: 30, l: 15 };
+
+ if ( value ) {
+ var ar = String( value ).split( "," );
+
+ $.each( ar, function( idx, val ) { ar[ idx ] = parseInt( val, 10 ); } );
+
+ switch( ar.length ) {
+ // All values are to be the same
+ case 1:
+ if ( !isNaN( ar[ 0 ] ) ) {
+ tol.t = tol.r = tol.b = tol.l = ar[ 0 ];
+ }
+ break;
+
+ // The first value denotes top/bottom tolerance, and the second value denotes left/right tolerance
+ case 2:
+ if ( !isNaN( ar[ 0 ] ) ) {
+ tol.t = tol.b = ar[ 0 ];
+ }
+ if ( !isNaN( ar[ 1 ] ) ) {
+ tol.l = tol.r = ar[ 1 ];
+ }
+ break;
+
+ // The array contains values in the order top, right, bottom, left
+ case 4:
+ if ( !isNaN( ar[ 0 ] ) ) {
+ tol.t = ar[ 0 ];
+ }
+ if ( !isNaN( ar[ 1 ] ) ) {
+ tol.r = ar[ 1 ];
+ }
+ if ( !isNaN( ar[ 2 ] ) ) {
+ tol.b = ar[ 2 ];
+ }
+ if ( !isNaN( ar[ 3 ] ) ) {
+ tol.l = ar[ 3 ];
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ this._tolerance = tol;
+ },
+
+ _setOption: function( key, value ) {
+ var exclusions, setter = "_set" + key.charAt( 0 ).toUpperCase() + key.slice( 1 );
+
+ if ( this[ setter ] !== undefined ) {
+ this[ setter ]( value );
+ }
+
+ // TODO REMOVE FOR 1.2.1 by moving them out to a default options object
+ exclusions = [
+ "initSelector",
+ "closeLinkSelector",
+ "closeLinkEvents",
+ "navigateEvents",
+ "closeEvents",
+ "history",
+ "container"
+ ];
+
+ $.mobile.widget.prototype._setOption.apply( this, arguments );
+ if ( $.inArray( key, exclusions ) === -1 ) {
+ // Record the option change in the options and in the DOM data-* attributes
+ this.element.attr( "data-" + ( $.mobile.ns || "" ) + ( key.replace( /([A-Z])/, "-$1" ).toLowerCase() ), value );
+ }
+ },
+
+ // Try and center the overlay over the given coordinates
+ _placementCoords: function( desired ) {
+ // rectangle within which the popup must fit
+ var
+ winCoords = windowCoords(),
+ rc = {
+ x: this._tolerance.l,
+ y: winCoords.y + this._tolerance.t,
+ cx: winCoords.cx - this._tolerance.l - this._tolerance.r,
+ cy: winCoords.cy - this._tolerance.t - this._tolerance.b
+ },
+ menuSize, ret;
+
+ // Clamp the width of the menu before grabbing its size
+ this._ui.container.css( "max-width", rc.cx );
+ menuSize = {
+ cx: this._ui.container.outerWidth( true ),
+ cy: this._ui.container.outerHeight( true )
+ };
+
+ // Center the menu over the desired coordinates, while not going outside
+ // the window tolerances. This will center wrt. the window if the popup is too large.
+ ret = {
+ x: fitSegmentInsideSegment( rc.cx, menuSize.cx, rc.x, desired.x ),
+ y: fitSegmentInsideSegment( rc.cy, menuSize.cy, rc.y, desired.y )
+ };
+
+ // Make sure the top of the menu is visible
+ ret.y = Math.max( 0, ret.y );
+
+ // If the height of the menu is smaller than the height of the document
+ // align the bottom with the bottom of the document
+
+ // fix for $( document ).height() bug in core 1.7.2.
+ var docEl = document.documentElement, docBody = document.body,
+ docHeight = Math.max( docEl.clientHeight, docBody.scrollHeight, docBody.offsetHeight, docEl.scrollHeight, docEl.offsetHeight );
+
+ ret.y -= Math.min( ret.y, Math.max( 0, ret.y + menuSize.cy - docHeight ) );
+
+ return { left: ret.x, top: ret.y };
+ },
+
+ _createPrereqs: function( screenPrereq, containerPrereq, whenDone ) {
+ var self = this, prereqs;
+
+ // It is important to maintain both the local variable prereqs and self._prereqs. The local variable remains in
+ // the closure of the functions which call the callbacks passed in. The comparison between the local variable and
+ // self._prereqs is necessary, because once a function has been passed to .animationComplete() it will be called
+ // next time an animation completes, even if that's not the animation whose end the function was supposed to catch
+ // (for example, if an abort happens during the opening animation, the .animationComplete handler is not called for
+ // that animation anymore, but the handler remains attached, so it is called the next time the popup is opened
+ // - making it stale. Comparing the local variable prereqs to the widget-level variable self._prereqs ensures that
+ // callbacks triggered by a stale .animationComplete will be ignored.
+
+ prereqs = {
+ screen: $.Deferred(),
+ container: $.Deferred()
+ };
+
+ prereqs.screen.then( function() {
+ if ( prereqs === self._prereqs ) {
+ screenPrereq();
+ }
+ });
+
+ prereqs.container.then( function() {
+ if ( prereqs === self._prereqs ) {
+ containerPrereq();
+ }
+ });
+
+ $.when( prereqs.screen, prereqs.container ).done( function() {
+ if ( prereqs === self._prereqs ) {
+ self._prereqs = null;
+ whenDone();
+ }
+ });
+
+ self._prereqs = prereqs;
+ },
+
+ _animate: function( args ) {
+ // NOTE before removing the default animation of the screen
+ // this had an animate callback that would relove the deferred
+ // now the deferred is resolved immediately
+ // TODO remove the dependency on the screen deferred
+ this._ui.screen
+ .removeClass( args.classToRemove )
+ .addClass( args.screenClassToAdd );
+
+ args.prereqs.screen.resolve();
+
+ if ( args.transition && args.transition !== "none" ) {
+ if ( args.applyTransition ) {
+ this._applyTransition( args.transition );
+ }
+ this._ui.container
+ .animationComplete( $.proxy( args.prereqs.container, "resolve" ) )
+ .addClass( args.containerClassToAdd )
+ .removeClass( args.classToRemove );
+ } else {
+ args.prereqs.container.resolve();
+ }
+ },
+
+ // The desired coordinates passed in will be returned untouched if no reference element can be identified via
+ // desiredPosition.positionTo. Nevertheless, this function ensures that its return value always contains valid
+ // x and y coordinates by specifying the center middle of the window if the coordinates are absent.
+ _desiredCoords: function( x, y, positionTo ) {
+ var dst = null, offset, winCoords = windowCoords();
+
+ // Establish which element will serve as the reference
+ if ( positionTo && positionTo !== "origin" ) {
+ if ( positionTo === "window" ) {
+ x = winCoords.cx / 2 + winCoords.x;
+ y = winCoords.cy / 2 + winCoords.y;
+ } else {
+ try {
+ dst = $( positionTo );
+ } catch( e ) {
+ dst = null;
+ }
+ if ( dst ) {
+ dst.filter( ":visible" );
+ if ( dst.length === 0 ) {
+ dst = null;
+ }
+ }
+ }
+ }
+
+ // If an element was found, center over it
+ if ( dst ) {
+ offset = dst.offset();
+ x = offset.left + dst.outerWidth() / 2;
+ y = offset.top + dst.outerHeight() / 2;
+ }
+
+ // Make sure x and y are valid numbers - center over the window
+ if ( $.type( x ) !== "number" || isNaN( x ) ) {
+ x = winCoords.cx / 2 + winCoords.x;
+ }
+ if ( $.type( y ) !== "number" || isNaN( y ) ) {
+ y = winCoords.cy / 2 + winCoords.y;
+ }
+
+ return { x: x, y: y };
+ },
+
+ _openPrereqsComplete: function() {
+ var self = this;
+
+ self._ui.container.addClass( "ui-popup-active" );
+ self._isOpen = true;
+ self._resizeScreen();
+
+ // Android appears to trigger the animation complete before the popup
+ // is visible. Allowing the stack to unwind before applying focus prevents
+ // the "blue flash" of element focus in android 4.0
+ setTimeout(function(){
+ self._ui.container.attr( "tabindex", "0" ).focus();
+ self._trigger( "afteropen" );
+ });
+ },
+
+ _open: function( options ) {
+ var coords, transition,
+ androidBlacklist = ( function() {
+ var w = window,
+ ua = navigator.userAgent,
+ // Rendering engine is Webkit, and capture major version
+ wkmatch = ua.match( /AppleWebKit\/([0-9\.]+)/ ),
+ wkversion = !!wkmatch && wkmatch[ 1 ],
+ androidmatch = ua.match( /Android (\d+(?:\.\d+))/ ),
+ andversion = !!androidmatch && androidmatch[ 1 ],
+ chromematch = ua.indexOf( "Chrome" ) > -1;
+
+ // Platform is Android, WebKit version is greater than 534.13 ( Android 3.2.1 ) and not Chrome.
+ if( androidmatch !== null && andversion === "4.0" && wkversion && wkversion > 534.13 && !chromematch ) {
+ return true;
+ }
+ return false;
+ }());
+
+ // Make sure options is defined
+ options = ( options || {} );
+
+ // Copy out the transition, because we may be overwriting it later and we don't want to pass that change back to the caller
+ transition = options.transition || this.options.transition;
+
+ // Give applications a chance to modify the contents of the container before it appears
+ this._trigger( "beforeposition" );
+
+ coords = this._placementCoords( this._desiredCoords( options.x, options.y, options.positionTo || this.options.positionTo || "origin" ) );
+
+ // Count down to triggering "popupafteropen" - we have two prerequisites:
+ // 1. The popup window animation completes (container())
+ // 2. The screen opacity animation completes (screen())
+ this._createPrereqs(
+ $.noop,
+ $.noop,
+ $.proxy( this, "_openPrereqsComplete" ) );
+
+ if ( transition ) {
+ this._currentTransition = transition;
+ this._applyTransition( transition );
+ } else {
+ transition = this.options.transition;
+ }
+
+ if ( !this.options.theme ) {
+ this._setTheme( this._page.jqmData( "theme" ) || $.mobile.getInheritedTheme( this._page, "c" ) );
+ }
+
+ this._ui.screen.removeClass( "ui-screen-hidden" );
+
+ this._ui.container
+ .removeClass( "ui-selectmenu-hidden" )
+ .offset( coords );
+
+ if ( this.options.overlayTheme && androidBlacklist ) {
+ /* TODO:
+ The native browser on Android 4.0.X ("Ice Cream Sandwich") suffers from an issue where the popup overlay appears to be z-indexed
+ above the popup itself when certain other styles exist on the same page -- namely, any element set to `position: fixed` and certain
+ types of input. These issues are reminiscent of previously uncovered bugs in older versions of Android's native browser:
+ https://github.com/scottjehl/Device-Bugs/issues/3
+
+ This fix closes the following bugs ( I use "closes" with reluctance, and stress that this issue should be revisited as soon as possible ):
+
+ https://github.com/jquery/jquery-mobile/issues/4816
+ https://github.com/jquery/jquery-mobile/issues/4844
+ https://github.com/jquery/jquery-mobile/issues/4874
+ */
+
+ // TODO sort out why this._page isn't working
+ this.element.closest( ".ui-page" ).addClass( "ui-popup-open" );
+ }
+ this._animate({
+ additionalCondition: true,
+ transition: transition,
+ classToRemove: "",
+ screenClassToAdd: "in",
+ containerClassToAdd: "in",
+ applyTransition: false,
+ prereqs: this._prereqs
+ });
+ },
+
+ _closePrereqScreen: function() {
+ this._ui.screen
+ .removeClass( "out" )
+ .addClass( "ui-screen-hidden" );
+ },
+
+ _closePrereqContainer: function() {
+ this._ui.container
+ .removeClass( "reverse out" )
+ .addClass( "ui-selectmenu-hidden" )
+ .removeAttr( "style" );
+ },
+
+ _closePrereqsDone: function() {
+ var self = this, opts = self.options;
+
+ self._ui.container.removeAttr( "tabindex" );
+
+ // remove nav bindings if they are still present
+ opts.container.unbind( opts.closeEvents );
+
+ // unbind click handlers added when history is disabled
+ self.element.undelegate( opts.closeLinkSelector, opts.closeLinkEvents );
+
+ // remove the global mutex for popups
+ $.mobile.popup.active = undefined;
+
+ // alert users that the popup is closed
+ self._trigger( "afterclose" );
+ },
+
+ _close: function() {
+ this._ui.container.removeClass( "ui-popup-active" );
+ this._page.removeClass( "ui-popup-open" );
+
+ this._isOpen = false;
+
+ // Count down to triggering "popupafterclose" - we have two prerequisites:
+ // 1. The popup window reverse animation completes (container())
+ // 2. The screen opacity animation completes (screen())
+ this._createPrereqs(
+ $.proxy( this, "_closePrereqScreen" ),
+ $.proxy( this, "_closePrereqContainer" ),
+ $.proxy( this, "_closePrereqsDone" ) );
+
+ this._animate( {
+ additionalCondition: this._ui.screen.hasClass( "in" ),
+ transition: ( this._currentTransition || this.options.transition ),
+ classToRemove: "in",
+ screenClassToAdd: "out",
+ containerClassToAdd: "reverse out",
+ applyTransition: true,
+ prereqs: this._prereqs
+ });
+ },
+
+ _destroy: function() {
+ var self = this;
+
+ // hide and remove bindings
+ self._close();
+
+ // Put the element back to where the placeholder was and remove the "ui-popup" class
+ self._setTheme( "none" );
+ self.element
+ .insertAfter( self._ui.placeholder )
+ .removeClass( "ui-popup ui-overlay-shadow ui-corner-all" );
+ self._ui.screen.remove();
+ self._ui.container.remove();
+ self._ui.placeholder.remove();
+
+ // Unbind handlers that were bound to elements outside self.element (the window, in self case)
+ $.each( self._globalHandlers, function( idx, oneSrc ) {
+ $.each( oneSrc.handler, function( eventType, handler ) {
+ oneSrc.src.unbind( eventType, handler );
+ });
+ });
+ },
+
+ // any navigation event after a popup is opened should close the popup
+ // NOTE the pagebeforechange is bound to catch navigation events that don't
+ // alter the url (eg, dialogs from popups)
+ _bindContainerClose: function() {
+ var self = this;
+
+ self.options.container
+ .one( self.options.closeEvents, $.proxy( self._close, self ));
+ },
+
+ // TODO no clear deliniation of what should be here and
+ // what should be in _open. Seems to be "visual" vs "history" for now
+ open: function( options ) {
+ var self = this, opts = this.options, url, hashkey, activePage, currentIsDialog, hasHash, urlHistory;
+
+ // make sure open is idempotent
+ if( $.mobile.popup.active ) {
+ return;
+ }
+
+ // set the global popup mutex
+ $.mobile.popup.active = this;
+
+ // if history alteration is disabled close on navigate events
+ // and leave the url as is
+ if( !( opts.history ) ) {
+ self._open( options );
+ self._bindContainerClose();
+
+ // When histoy is disabled we have to grab the data-rel
+ // back link clicks so we can close the popup instead of
+ // relying on history to do it for us
+ self.element
+ .delegate( opts.closeLinkSelector, opts.closeLinkEvents, function( e ) {
+ self._close();
+
+ // NOTE prevent the browser and navigation handlers from
+ // working with the link's rel=back. This may cause
+ // issues for developers expecting the event to bubble
+ return false;
+ });
+
+ return;
+ }
+
+ // cache some values for min/readability
+ hashkey = $.mobile.dialogHashKey;
+ activePage = $.mobile.activePage;
+ currentIsDialog = activePage.is( ".ui-dialog" );
+ url = $.mobile.urlHistory.getActive().url;
+ hasHash = ( url.indexOf( hashkey ) > -1 ) && !currentIsDialog;
+ urlHistory = $.mobile.urlHistory;
+
+ if ( hasHash ) {
+ self._open( options );
+ self._bindContainerClose();
+ return;
+ }
+
+ // if the current url has no dialog hash key proceed as normal
+ // otherwise, if the page is a dialog simply tack on the hash key
+ if ( url.indexOf( hashkey ) === -1 && !currentIsDialog ){
+ url = url + hashkey;
+ } else {
+ url = $.mobile.path.parseLocation().hash + hashkey;
+ }
+
+ // Tack on an extra hashkey if this is the first page and we've just reconstructed the initial hash
+ if ( urlHistory.activeIndex === 0 && url === urlHistory.initialDst ) {
+ url += hashkey;
+ }
+
+ // swallow the the initial navigation event, and bind for the next
+ opts.container.one( opts.navigateEvents, function( e ) {
+ e.preventDefault();
+ self._open( options );
+ self._bindContainerClose();
+ });
+
+ urlHistory.ignoreNextHashChange = currentIsDialog;
+
+ // Gotta love methods with 1mm args :(
+ urlHistory.addNew( url, undefined, undefined, undefined, "dialog" );
+
+ // set the new url with (or without) the new dialog hash key
+ $.mobile.path.set( url );
+ },
+
+ close: function() {
+ // make sure close is idempotent
+ if( !$.mobile.popup.active ){
+ return;
+ }
+
+ if( this.options.history ) {
+ $.mobile.back();
+ } else {
+ this._close();
+ }
+ }
+ });
+
+
+ // TODO this can be moved inside the widget
+ $.mobile.popup.handleLink = function( $link ) {
+ var closestPage = $link.closest( ":jqmData(role='page')" ),
+ scope = ( ( closestPage.length === 0 ) ? $( "body" ) : closestPage ),
+ // NOTE make sure to get only the hash, ie7 (wp7) return the absolute href
+ // in this case ruining the element selection
+ popup = $( $.mobile.path.parseUrl($link.attr( "href" )).hash, scope[0] ),
+ offset;
+
+ if ( popup.data( "popup" ) ) {
+ offset = $link.offset();
+ popup.popup( "open", {
+ x: offset.left + $link.outerWidth() / 2,
+ y: offset.top + $link.outerHeight() / 2,
+ transition: $link.jqmData( "transition" ),
+ positionTo: $link.jqmData( "position-to" ),
+ link: $link
+ });
+ }
+
+ //remove after delay
+ setTimeout( function() {
+ $link.removeClass( $.mobile.activeBtnClass );
+ }, 300 );
+ };
+
+ // TODO move inside _create
+ $( document ).bind( "pagebeforechange", function( e, data ) {
+ if ( data.options.role === "popup" ) {
+ $.mobile.popup.handleLink( data.options.link );
+ e.preventDefault();
+ }
+ });
+
+ $( document ).bind( "pagecreate create", function( e ) {
+ $.mobile.popup.prototype.enhanceWithin( e.target, true );
+ });
+
+})( 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,
+ // 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])",
+ clearSearchButtonText: "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,
+ mini = input.jqmData( "mini" ) === true,
+ miniclass = mini ? " ui-mini" : "",
+ focusedEl, clearbtn;
+
+ 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" input widget
+ if ( input.is( "[type='search'],:jqmData(type='search')" ) ) {
+
+ focusedEl = input.wrap( "
" ).parent();
+ clearbtn = $( "
" + o.clearSearchButtonText + "" )
+ .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: mini
+ });
+
+ toggleClear();
+
+ input.bind( 'paste cut keyup focus change blur', toggleClear );
+
+ } else {
+ input.addClass( "ui-corner-all ui-shadow-inset" + themeclass + miniclass );
+ }
+
+ input.focus(function() {
+ focusedEl.addClass( $.mobile.focusClass );
+ })
+ .blur(function() {
+ focusedEl.removeClass( $.mobile.focusClass );
+ })
+ // In many situations, iOS will zoom into the select upon tap, this prevents that from happening
+ .bind( "focus", function() {
+ if ( o.preventFocusZoom ) {
+ $.mobile.zoom.disable( true );
+ }
+ })
+ .bind( "blur", function() {
+ 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 ) {
+ input.height(scrollHeight + extraLineHeight);
+ }
+ };
+
+ input.keyup(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( $(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( $(window), {"load": "_keyup"});
+ }
+ }
+ if ( input.attr( "disabled" ) ) {
+ this.disable();
+ }
+ },
+
+ disable: function() {
+ var $el;
+ if ( this.element.attr( "disabled", true ).is( "[type='search'], :jqmData(type='search')" ) ) {
+ $el = this.element.parent();
+ } else {
+ $el = this.element;
+ }
+ $el.addClass( "ui-disabled" );
+ return this._setOption( "disabled", true );
+ },
+
+ enable: function() {
+ var $el;
+
+ // TODO using more than one line of code is acceptable ;)
+ if ( this.element.attr( "disabled", false ).is( "[type='search'], :jqmData(type='search')" ) ) {
+ $el = this.element.parent();
+ } else {
+ $el = this.element;
+ }
+ $el.removeClass( "ui-disabled" );
+ return this._setOption( "disabled", false );
+ }
+});
+
+//auto self-init widgets
+$( 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";
+// 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;
+
+$( document ).delegate( ":jqmData(role='listview')", "listviewcreate", function() {
+
+ var list = $( this ),
+ listview = list.data( "listview" );
+
+ if ( !listview.options.filter ) {
+ return;
+ }
+
+ var wrapper = $( "