Difference between revisions of "Template:Cologne-Duesseldorf/js-jquery"

Line 2,762: Line 2,762:
 
})( jQuery );
 
})( jQuery );
  
 +
 +
// buttonMarkup is deprecated as of 1.4.0 and will be removed in 1.5.0.
 +
 +
(function( $, undefined ) {
 +
 +
// General policy: Do not access data-* attributes except during enhancement.
 +
// In all other cases we determine the state of the button exclusively from its
 +
// className. That's why optionsToClasses expects a full complement of options,
 +
// and the jQuery plugin completes the set of options from the default values.
 +
 +
// Map classes to buttonMarkup boolean options - used in classNameToOptions()
 +
var reverseBoolOptionMap = {
 +
"ui-shadow" : "shadow",
 +
"ui-corner-all" : "corners",
 +
"ui-btn-inline" : "inline",
 +
"ui-shadow-icon" : "iconshadow", /* TODO: Remove in 1.5 */
 +
"ui-mini" : "mini"
 +
},
 +
getAttrFixed = function() {
 +
var ret = $.mobile.getAttribute.apply( this, arguments );
 +
 +
return ( ret == null ? undefined : ret );
 +
},
 +
capitalLettersRE = /[A-Z]/g;
 +
 +
// optionsToClasses:
 +
// @options: A complete set of options to convert to class names.
 +
// @existingClasses: extra classes to add to the result
 +
//
 +
// Converts @options to buttonMarkup classes and returns the result as an array
 +
// that can be converted to an element's className with .join( " " ). All
 +
// possible options must be set inside @options. Use $.fn.buttonMarkup.defaults
 +
// to get a complete set and use $.extend to override your choice of options
 +
// from that set.
 +
function optionsToClasses( options, existingClasses ) {
 +
var classes = existingClasses ? existingClasses : [];
 +
 +
// Add classes to the array - first ui-btn
 +
classes.push( "ui-btn" );
 +
 +
// If there is a theme
 +
if ( options.theme ) {
 +
classes.push( "ui-btn-" + options.theme );
 +
}
 +
 +
// If there's an icon, add the icon-related classes
 +
if ( options.icon ) {
 +
classes = classes.concat([
 +
"ui-icon-" + options.icon,
 +
"ui-btn-icon-" + options.iconpos
 +
]);
 +
if ( options.iconshadow ) {
 +
classes.push( "ui-shadow-icon" ); /* TODO: Remove in 1.5 */
 +
}
 +
}
 +
 +
// Add the appropriate class for each boolean option
 +
if ( options.inline ) {
 +
classes.push( "ui-btn-inline" );
 +
}
 +
if ( options.shadow ) {
 +
classes.push( "ui-shadow" );
 +
}
 +
if ( options.corners ) {
 +
classes.push( "ui-corner-all" );
 +
}
 +
if ( options.mini ) {
 +
classes.push( "ui-mini" );
 +
}
 +
 +
// Create a string from the array and return it
 +
return classes;
 +
}
 +
 +
// classNameToOptions:
 +
// @classes: A string containing a .className-style space-separated class list
 +
//
 +
// Loops over @classes and calculates an options object based on the
 +
// buttonMarkup-related classes it finds. It records unrecognized classes in an
 +
// array.
 +
//
 +
// Returns: An object containing the following items:
 +
//
 +
// "options": buttonMarkup options found to be present because of the
 +
// presence/absence of corresponding classes
 +
//
 +
// "unknownClasses": a string containing all the non-buttonMarkup-related
 +
// classes found in @classes
 +
//
 +
// "alreadyEnhanced": A boolean indicating whether the ui-btn class was among
 +
// those found to be present
 +
function classNameToOptions( classes ) {
 +
var idx, map, unknownClass,
 +
alreadyEnhanced = false,
 +
noIcon = true,
 +
o = {
 +
icon: "",
 +
inline: false,
 +
shadow: false,
 +
corners: false,
 +
iconshadow: false,
 +
mini: false
 +
},
 +
unknownClasses = [];
 +
 +
classes = classes.split( " " );
 +
 +
// Loop over the classes
 +
for ( idx = 0 ; idx < classes.length ; idx++ ) {
 +
 +
// Assume it's an unrecognized class
 +
unknownClass = true;
 +
 +
// Recognize boolean options from the presence of classes
 +
map = reverseBoolOptionMap[ classes[ idx ] ];
 +
if ( map !== undefined ) {
 +
unknownClass = false;
 +
o[ map ] = true;
 +
 +
// Recognize the presence of an icon and establish the icon position
 +
} else if ( classes[ idx ].indexOf( "ui-btn-icon-" ) === 0 ) {
 +
unknownClass = false;
 +
noIcon = false;
 +
o.iconpos = classes[ idx ].substring( 12 );
 +
 +
// Establish which icon is present
 +
} else if ( classes[ idx ].indexOf( "ui-icon-" ) === 0 ) {
 +
unknownClass = false;
 +
o.icon = classes[ idx ].substring( 8 );
 +
 +
// Establish the theme - this recognizes one-letter theme swatch names
 +
} else if ( classes[ idx ].indexOf( "ui-btn-" ) === 0 && classes[ idx ].length === 8 ) {
 +
unknownClass = false;
 +
o.theme = classes[ idx ].substring( 7 );
 +
 +
// Recognize that this element has already been buttonMarkup-enhanced
 +
} else if ( classes[ idx ] === "ui-btn" ) {
 +
unknownClass = false;
 +
alreadyEnhanced = true;
 +
}
 +
 +
// If this class has not been recognized, add it to the list
 +
if ( unknownClass ) {
 +
unknownClasses.push( classes[ idx ] );
 +
}
 +
}
 +
 +
// If a "ui-btn-icon-*" icon position class is absent there cannot be an icon
 +
if ( noIcon ) {
 +
o.icon = "";
 +
}
 +
 +
return {
 +
options: o,
 +
unknownClasses: unknownClasses,
 +
alreadyEnhanced: alreadyEnhanced
 +
};
 +
}
 +
 +
function camelCase2Hyphenated( c ) {
 +
return "-" + c.toLowerCase();
 +
}
 +
 +
// $.fn.buttonMarkup:
 +
// DOM: gets/sets .className
 +
//
 +
// @options: options to apply to the elements in the jQuery object
 +
// @overwriteClasses: boolean indicating whether to honour existing classes
 +
//
 +
// Calculates the classes to apply to the elements in the jQuery object based on
 +
// the options passed in. If @overwriteClasses is true, it sets the className
 +
// property of each element in the jQuery object to the buttonMarkup classes
 +
// it calculates based on the options passed in.
 +
//
 +
// If you wish to preserve any classes that are already present on the elements
 +
// inside the jQuery object, including buttonMarkup-related classes that were
 +
// added by a previous call to $.fn.buttonMarkup() or during page enhancement
 +
// then you should omit @overwriteClasses or set it to false.
 +
$.fn.buttonMarkup = function( options, overwriteClasses ) {
 +
var idx, data, el, retrievedOptions, optionKey,
 +
defaults = $.fn.buttonMarkup.defaults;
 +
 +
for ( idx = 0 ; idx < this.length ; idx++ ) {
 +
el = this[ idx ];
 +
data = overwriteClasses ?
 +
 +
// Assume this element is not enhanced and ignore its classes
 +
{ alreadyEnhanced: false, unknownClasses: [] } :
 +
 +
// Otherwise analyze existing classes to establish existing options and
 +
// classes
 +
classNameToOptions( el.className );
 +
 +
retrievedOptions = $.extend( {},
 +
 +
// If the element already has the class ui-btn, then we assume that
 +
// it has passed through buttonMarkup before - otherwise, the options
 +
// returned by classNameToOptions do not correctly reflect the state of
 +
// the element
 +
( data.alreadyEnhanced ? data.options : {} ),
 +
 +
// Finally, apply the options passed in
 +
options );
 +
 +
// If this is the first call on this element, retrieve remaining options
 +
// from the data-attributes
 +
if ( !data.alreadyEnhanced ) {
 +
for ( optionKey in defaults ) {
 +
if ( retrievedOptions[ optionKey ] === undefined ) {
 +
retrievedOptions[ optionKey ] = getAttrFixed( el,
 +
optionKey.replace( capitalLettersRE, camelCase2Hyphenated )
 +
);
 +
}
 +
}
 +
}
 +
 +
el.className = optionsToClasses(
 +
 +
// Merge all the options and apply them as classes
 +
$.extend( {},
 +
 +
// The defaults form the basis
 +
defaults,
 +
 +
// Add the computed options
 +
retrievedOptions
 +
),
 +
 +
// ... and re-apply any unrecognized classes that were found
 +
data.unknownClasses ).join( " " );
 +
if ( el.tagName.toLowerCase() !== "button" ) {
 +
el.setAttribute( "role", "button" );
 +
}
 +
}
 +
 +
return this;
 +
};
 +
 +
// buttonMarkup defaults. This must be a complete set, i.e., a value must be
 +
// given here for all recognized options
 +
$.fn.buttonMarkup.defaults = {
 +
icon: "",
 +
iconpos: "left",
 +
theme: null,
 +
inline: false,
 +
shadow: true,
 +
corners: true,
 +
iconshadow: false, /* TODO: Remove in 1.5. Option deprecated in 1.4. */
 +
mini: false
 +
};
 +
 +
$.extend( $.fn.buttonMarkup, {
 +
initSelector: "a:jqmData(role='button'), .ui-bar > a, .ui-bar > :jqmData(role='controlgroup') > a, button:not(:jqmData(role='navbar') button)"
 +
});
 +
 +
})( jQuery );
 +
 +
 +
/*!
 +
* jQuery UI Widget c0ab71056b936627e8a7821f03c044aec6280a40
 +
* http://jqueryui.com
 +
*
 +
* Copyright 2013 jQuery Foundation and other contributors
 +
* Released under the MIT license.
 +
* http://jquery.org/license
 +
*
 +
* http://api.jqueryui.com/jQuery.widget/
 +
*/
 +
(function( $, undefined ) {
 +
 +
var uuid = 0,
 +
slice = Array.prototype.slice,
 +
_cleanData = $.cleanData;
 +
$.cleanData = function( elems ) {
 +
for ( var i = 0, elem; (elem = elems[i]) != null; i++ ) {
 +
try {
 +
$( elem ).triggerHandler( "remove" );
 +
// http://bugs.jquery.com/ticket/8235
 +
} catch( e ) {}
 +
}
 +
_cleanData( elems );
 +
};
 +
 +
$.widget = function( name, base, prototype ) {
 +
var fullName, existingConstructor, constructor, basePrototype,
 +
// proxiedPrototype allows the provided prototype to remain unmodified
 +
// so that it can be used as a mixin for multiple widgets (#8876)
 +
proxiedPrototype = {},
 +
namespace = name.split( "." )[ 0 ];
 +
 +
name = name.split( "." )[ 1 ];
 +
fullName = namespace + "-" + name;
 +
 +
if ( !prototype ) {
 +
prototype = base;
 +
base = $.Widget;
 +
}
 +
 +
// create selector for plugin
 +
$.expr[ ":" ][ fullName.toLowerCase() ] = function( elem ) {
 +
return !!$.data( elem, fullName );
 +
};
 +
 +
$[ namespace ] = $[ namespace ] || {};
 +
existingConstructor = $[ namespace ][ name ];
 +
constructor = $[ namespace ][ name ] = function( options, element ) {
 +
// allow instantiation without "new" keyword
 +
if ( !this._createWidget ) {
 +
return new constructor( options, element );
 +
}
 +
 +
// allow instantiation without initializing for simple inheritance
 +
// must use "new" keyword (the code above always passes args)
 +
if ( arguments.length ) {
 +
this._createWidget( options, element );
 +
}
 +
};
 +
// extend with the existing constructor to carry over any static properties
 +
$.extend( constructor, existingConstructor, {
 +
version: prototype.version,
 +
// copy the object used to create the prototype in case we need to
 +
// redefine the widget later
 +
_proto: $.extend( {}, prototype ),
 +
// track widgets that inherit from this widget in case this widget is
 +
// redefined after a widget inherits from it
 +
_childConstructors: []
 +
});
 +
 +
basePrototype = new base();
 +
// we need to make the options hash a property directly on the new instance
 +
// otherwise we'll modify the options hash on the prototype that we're
 +
// inheriting from
 +
basePrototype.options = $.widget.extend( {}, basePrototype.options );
 +
$.each( prototype, function( prop, value ) {
 +
if ( !$.isFunction( value ) ) {
 +
proxiedPrototype[ prop ] = value;
 +
return;
 +
}
 +
proxiedPrototype[ prop ] = (function() {
 +
var _super = function() {
 +
return base.prototype[ prop ].apply( this, arguments );
 +
},
 +
_superApply = function( args ) {
 +
return base.prototype[ prop ].apply( this, args );
 +
};
 +
return function() {
 +
var __super = this._super,
 +
__superApply = this._superApply,
 +
returnValue;
 +
 +
this._super = _super;
 +
this._superApply = _superApply;
 +
 +
returnValue = value.apply( this, arguments );
 +
 +
this._super = __super;
 +
this._superApply = __superApply;
 +
 +
return returnValue;
 +
};
 +
})();
 +
});
 +
constructor.prototype = $.widget.extend( basePrototype, {
 +
// TODO: remove support for widgetEventPrefix
 +
// always use the name + a colon as the prefix, e.g., draggable:start
 +
// don't prefix for widgets that aren't DOM-based
 +
widgetEventPrefix: existingConstructor ? (basePrototype.widgetEventPrefix || name) : name
 +
}, proxiedPrototype, {
 +
constructor: constructor,
 +
namespace: namespace,
 +
widgetName: name,
 +
widgetFullName: fullName
 +
});
 +
 +
// If this widget is being redefined then we need to find all widgets that
 +
// are inheriting from it and redefine all of them so that they inherit from
 +
// the new version of this widget. We're essentially trying to replace one
 +
// level in the prototype chain.
 +
if ( existingConstructor ) {
 +
$.each( existingConstructor._childConstructors, function( i, child ) {
 +
var childPrototype = child.prototype;
 +
 +
// redefine the child widget using the same prototype that was
 +
// originally used, but inherit from the new version of the base
 +
$.widget( childPrototype.namespace + "." + childPrototype.widgetName, constructor, child._proto );
 +
});
 +
// remove the list of existing child constructors from the old constructor
 +
// so the old child constructors can be garbage collected
 +
delete existingConstructor._childConstructors;
 +
} else {
 +
base._childConstructors.push( constructor );
 +
}
 +
 +
$.widget.bridge( name, constructor );
 +
 +
return constructor;
 +
};
 +
 +
$.widget.extend = function( target ) {
 +
var input = slice.call( arguments, 1 ),
 +
inputIndex = 0,
 +
inputLength = input.length,
 +
key,
 +
value;
 +
for ( ; inputIndex < inputLength; inputIndex++ ) {
 +
for ( key in input[ inputIndex ] ) {
 +
value = input[ inputIndex ][ key ];
 +
if ( input[ inputIndex ].hasOwnProperty( key ) && value !== undefined ) {
 +
// Clone objects
 +
if ( $.isPlainObject( value ) ) {
 +
target[ key ] = $.isPlainObject( target[ key ] ) ?
 +
$.widget.extend( {}, target[ key ], value ) :
 +
// Don't extend strings, arrays, etc. with objects
 +
$.widget.extend( {}, value );
 +
// Copy everything else by reference
 +
} else {
 +
target[ key ] = value;
 +
}
 +
}
 +
}
 +
}
 +
return target;
 +
};
 +
 +
$.widget.bridge = function( name, object ) {
 +
var fullName = object.prototype.widgetFullName || name;
 +
$.fn[ name ] = function( options ) {
 +
var isMethodCall = typeof options === "string",
 +
args = slice.call( arguments, 1 ),
 +
returnValue = this;
 +
 +
// allow multiple hashes to be passed on init
 +
options = !isMethodCall && args.length ?
 +
$.widget.extend.apply( null, [ options ].concat(args) ) :
 +
options;
 +
 +
if ( isMethodCall ) {
 +
this.each(function() {
 +
var methodValue,
 +
instance = $.data( this, fullName );
 +
if ( options === "instance" ) {
 +
returnValue = instance;
 +
return false;
 +
}
 +
if ( !instance ) {
 +
return $.error( "cannot call methods on " + name + " prior to initialization; " +
 +
"attempted to call method '" + options + "'" );
 +
}
 +
if ( !$.isFunction( instance[options] ) || options.charAt( 0 ) === "_" ) {
 +
return $.error( "no such method '" + options + "' for " + name + " widget instance" );
 +
}
 +
methodValue = instance[ options ].apply( instance, args );
 +
if ( methodValue !== instance && methodValue !== undefined ) {
 +
returnValue = methodValue && methodValue.jquery ?
 +
returnValue.pushStack( methodValue.get() ) :
 +
methodValue;
 +
return false;
 +
}
 +
});
 +
} else {
 +
this.each(function() {
 +
var instance = $.data( this, fullName );
 +
if ( instance ) {
 +
instance.option( options || {} )._init();
 +
} else {
 +
$.data( this, fullName, new object( options, this ) );
 +
}
 +
});
 +
}
 +
 +
return returnValue;
 +
};
 +
};
 +
 +
$.Widget = function( /* options, element */ ) {};
 +
$.Widget._childConstructors = [];
 +
 +
$.Widget.prototype = {
 +
widgetName: "widget",
 +
widgetEventPrefix: "",
 +
defaultElement: "<div>",
 +
options: {
 +
disabled: false,
 +
 +
// callbacks
 +
create: null
 +
},
 +
_createWidget: function( options, element ) {
 +
element = $( element || this.defaultElement || this )[ 0 ];
 +
this.element = $( element );
 +
this.uuid = uuid++;
 +
this.eventNamespace = "." + this.widgetName + this.uuid;
 +
this.options = $.widget.extend( {},
 +
this.options,
 +
this._getCreateOptions(),
 +
options );
 +
 +
this.bindings = $();
 +
this.hoverable = $();
 +
this.focusable = $();
 +
 +
if ( element !== this ) {
 +
$.data( element, this.widgetFullName, this );
 +
this._on( true, this.element, {
 +
remove: function( event ) {
 +
if ( event.target === element ) {
 +
this.destroy();
 +
}
 +
}
 +
});
 +
this.document = $( element.style ?
 +
// element within the document
 +
element.ownerDocument :
 +
// element is window or document
 +
element.document || element );
 +
this.window = $( this.document[0].defaultView || this.document[0].parentWindow );
 +
}
 +
 +
this._create();
 +
this._trigger( "create", null, this._getCreateEventData() );
 +
this._init();
 +
},
 +
_getCreateOptions: $.noop,
 +
_getCreateEventData: $.noop,
 +
_create: $.noop,
 +
_init: $.noop,
 +
 +
destroy: function() {
 +
this._destroy();
 +
// we can probably remove the unbind calls in 2.0
 +
// all event bindings should go through this._on()
 +
this.element
 +
.unbind( this.eventNamespace )
 +
.removeData( this.widgetFullName )
 +
// support: jquery <1.6.3
 +
// http://bugs.jquery.com/ticket/9413
 +
.removeData( $.camelCase( this.widgetFullName ) );
 +
this.widget()
 +
.unbind( this.eventNamespace )
 +
.removeAttr( "aria-disabled" )
 +
.removeClass(
 +
this.widgetFullName + "-disabled " +
 +
"ui-state-disabled" );
 +
 +
// clean up events and states
 +
this.bindings.unbind( this.eventNamespace );
 +
this.hoverable.removeClass( "ui-state-hover" );
 +
this.focusable.removeClass( "ui-state-focus" );
 +
},
 +
_destroy: $.noop,
 +
 +
widget: function() {
 +
return this.element;
 +
},
 +
 +
option: function( key, value ) {
 +
var options = key,
 +
parts,
 +
curOption,
 +
i;
 +
 +
if ( arguments.length === 0 ) {
 +
// don't return a reference to the internal hash
 +
return $.widget.extend( {}, this.options );
 +
}
 +
 +
if ( typeof key === "string" ) {
 +
// handle nested keys, e.g., "foo.bar" => { foo: { bar: ___ } }
 +
options = {};
 +
parts = key.split( "." );
 +
key = parts.shift();
 +
if ( parts.length ) {
 +
curOption = options[ key ] = $.widget.extend( {}, this.options[ key ] );
 +
for ( i = 0; i < parts.length - 1; i++ ) {
 +
curOption[ parts[ i ] ] = curOption[ parts[ i ] ] || {};
 +
curOption = curOption[ parts[ i ] ];
 +
}
 +
key = parts.pop();
 +
if ( value === undefined ) {
 +
return curOption[ key ] === undefined ? null : curOption[ key ];
 +
}
 +
curOption[ key ] = value;
 +
} else {
 +
if ( value === undefined ) {
 +
return this.options[ key ] === undefined ? null : this.options[ key ];
 +
}
 +
options[ key ] = value;
 +
}
 +
}
 +
 +
this._setOptions( options );
 +
 +
return this;
 +
},
 +
_setOptions: function( options ) {
 +
var key;
 +
 +
for ( key in options ) {
 +
this._setOption( key, options[ key ] );
 +
}
 +
 +
return this;
 +
},
 +
_setOption: function( key, value ) {
 +
this.options[ key ] = value;
 +
 +
if ( key === "disabled" ) {
 +
this.widget()
 +
.toggleClass( this.widgetFullName + "-disabled", !!value );
 +
this.hoverable.removeClass( "ui-state-hover" );
 +
this.focusable.removeClass( "ui-state-focus" );
 +
}
 +
 +
return this;
 +
},
 +
 +
enable: function() {
 +
return this._setOptions({ disabled: false });
 +
},
 +
disable: function() {
 +
return this._setOptions({ disabled: true });
 +
},
 +
 +
_on: function( suppressDisabledCheck, element, handlers ) {
 +
var delegateElement,
 +
instance = this;
 +
 +
// no suppressDisabledCheck flag, shuffle arguments
 +
if ( typeof suppressDisabledCheck !== "boolean" ) {
 +
handlers = element;
 +
element = suppressDisabledCheck;
 +
suppressDisabledCheck = false;
 +
}
 +
 +
// no element argument, shuffle and use this.element
 +
if ( !handlers ) {
 +
handlers = element;
 +
element = this.element;
 +
delegateElement = this.widget();
 +
} else {
 +
// accept selectors, DOM elements
 +
element = delegateElement = $( element );
 +
this.bindings = this.bindings.add( element );
 +
}
 +
 +
$.each( handlers, function( event, handler ) {
 +
function handlerProxy() {
 +
// allow widgets to customize the disabled handling
 +
// - disabled as an array instead of boolean
 +
// - disabled class as method for disabling individual parts
 +
if ( !suppressDisabledCheck &&
 +
( instance.options.disabled === true ||
 +
$( this ).hasClass( "ui-state-disabled" ) ) ) {
 +
return;
 +
}
 +
return ( typeof handler === "string" ? instance[ handler ] : handler )
 +
.apply( instance, arguments );
 +
}
 +
 +
// copy the guid so direct unbinding works
 +
if ( typeof handler !== "string" ) {
 +
handlerProxy.guid = handler.guid =
 +
handler.guid || handlerProxy.guid || $.guid++;
 +
}
 +
 +
var match = event.match( /^(\w+)\s*(.*)$/ ),
 +
eventName = match[1] + instance.eventNamespace,
 +
selector = match[2];
 +
if ( selector ) {
 +
delegateElement.delegate( selector, eventName, handlerProxy );
 +
} else {
 +
element.bind( eventName, handlerProxy );
 +
}
 +
});
 +
},
 +
 +
_off: function( element, eventName ) {
 +
eventName = (eventName || "").split( " " ).join( this.eventNamespace + " " ) + this.eventNamespace;
 +
element.unbind( eventName ).undelegate( eventName );
 +
},
 +
 +
_delay: function( handler, delay ) {
 +
function handlerProxy() {
 +
return ( typeof handler === "string" ? instance[ handler ] : handler )
 +
.apply( instance, arguments );
 +
}
 +
var instance = this;
 +
return setTimeout( handlerProxy, delay || 0 );
 +
},
 +
 +
_hoverable: function( element ) {
 +
this.hoverable = this.hoverable.add( element );
 +
this._on( element, {
 +
mouseenter: function( event ) {
 +
$( event.currentTarget ).addClass( "ui-state-hover" );
 +
},
 +
mouseleave: function( event ) {
 +
$( event.currentTarget ).removeClass( "ui-state-hover" );
 +
}
 +
});
 +
},
 +
 +
_focusable: function( element ) {
 +
this.focusable = this.focusable.add( element );
 +
this._on( element, {
 +
focusin: function( event ) {
 +
$( event.currentTarget ).addClass( "ui-state-focus" );
 +
},
 +
focusout: function( event ) {
 +
$( event.currentTarget ).removeClass( "ui-state-focus" );
 +
}
 +
});
 +
},
 +
 +
_trigger: function( type, event, data ) {
 +
var prop, orig,
 +
callback = this.options[ type ];
 +
 +
data = data || {};
 +
event = $.Event( event );
 +
event.type = ( type === this.widgetEventPrefix ?
 +
type :
 +
this.widgetEventPrefix + type ).toLowerCase();
 +
// the original event may come from any element
 +
// so we need to reset the target on the new event
 +
event.target = this.element[ 0 ];
 +
 +
// copy original event properties over to the new event
 +
orig = event.originalEvent;
 +
if ( orig ) {
 +
for ( prop in orig ) {
 +
if ( !( prop in event ) ) {
 +
event[ prop ] = orig[ prop ];
 +
}
 +
}
 +
}
 +
 +
this.element.trigger( event, data );
 +
return !( $.isFunction( callback ) &&
 +
callback.apply( this.element[0], [ event ].concat( data ) ) === false ||
 +
event.isDefaultPrevented() );
 +
}
 +
};
 +
 +
$.each( { show: "fadeIn", hide: "fadeOut" }, function( method, defaultEffect ) {
 +
$.Widget.prototype[ "_" + method ] = function( element, options, callback ) {
 +
if ( typeof options === "string" ) {
 +
options = { effect: options };
 +
}
 +
var hasOptions,
 +
effectName = !options ?
 +
method :
 +
options === true || typeof options === "number" ?
 +
defaultEffect :
 +
options.effect || defaultEffect;
 +
options = options || {};
 +
if ( typeof options === "number" ) {
 +
options = { duration: options };
 +
}
 +
hasOptions = !$.isEmptyObject( options );
 +
options.complete = callback;
 +
if ( options.delay ) {
 +
element.delay( options.delay );
 +
}
 +
if ( hasOptions && $.effects && $.effects.effect[ effectName ] ) {
 +
element[ method ]( options );
 +
} else if ( effectName !== method && element[ effectName ] ) {
 +
element[ effectName ]( options.duration, options.easing, callback );
 +
} else {
 +
element.queue(function( next ) {
 +
$( this )[ method ]();
 +
if ( callback ) {
 +
callback.call( element[ 0 ] );
 +
}
 +
next();
 +
});
 +
}
 +
};
 +
});
 +
 +
})( jQuery );
 +
 +
(function( $, undefined ) {
 +
 +
var rcapitals = /[A-Z]/g,
 +
replaceFunction = function( c ) {
 +
return "-" + c.toLowerCase();
 +
};
 +
 +
$.extend( $.Widget.prototype, {
 +
_getCreateOptions: function() {
 +
var option, value,
 +
elem = this.element[ 0 ],
 +
options = {};
 +
 +
//
 +
if ( !$.mobile.getAttribute( elem, "defaults" ) ) {
 +
for ( option in this.options ) {
 +
value = $.mobile.getAttribute( elem, option.replace( rcapitals, replaceFunction ) );
 +
 +
if ( value != null ) {
 +
options[ option ] = value;
 +
}
 +
}
 +
}
 +
 +
return options;
 +
}
 +
});
 +
 +
//TODO: Remove in 1.5 for backcompat only
 +
$.mobile.widget = $.Widget;
 +
 +
})( jQuery );
 +
 +
(function( $, undefined ) {
 +
$.mobile.widgets = {};
 +
 +
var originalWidget = $.widget,
 +
 +
// Record the original, non-mobileinit-modified version of $.mobile.keepNative
 +
// so we can later determine whether someone has modified $.mobile.keepNative
 +
keepNativeFactoryDefault = $.mobile.keepNative;
 +
 +
$.widget = (function( orig ) {
 +
return function() {
 +
var constructor = orig.apply( this, arguments ),
 +
name = constructor.prototype.widgetName;
 +
 +
constructor.initSelector = ( ( constructor.prototype.initSelector !== undefined ) ?
 +
constructor.prototype.initSelector : ":jqmData(role='" + name + "')" );
 +
 +
$.mobile.widgets[ name ] = constructor;
 +
 +
return constructor;
 +
};
 +
})( $.widget );
 +
 +
// Make sure $.widget still has bridge and extend methods
 +
$.extend( $.widget, originalWidget );
 +
 +
// For backcompat remove in 1.5
 +
$.mobile.document.on( "create", function( event ) {
 +
$( event.target ).enhanceWithin();
 +
});
 +
 +
$.widget( "mobile.page", {
 +
options: {
 +
theme: "a",
 +
domCache: false,
 +
 +
// Deprecated in 1.4 remove in 1.5
 +
keepNativeDefault: $.mobile.keepNative,
 +
 +
// Deprecated in 1.4 remove in 1.5
 +
contentTheme: null,
 +
enhanced: false
 +
},
 +
 +
// DEPRECATED for > 1.4
 +
// TODO remove at 1.5
 +
_createWidget: function() {
 +
$.Widget.prototype._createWidget.apply( this, arguments );
 +
this._trigger( "init" );
 +
},
 +
 +
_create: function() {
 +
// If false is returned by the callbacks do not create the page
 +
if ( this._trigger( "beforecreate" ) === false ) {
 +
return false;
 +
}
 +
 +
if ( !this.options.enhanced ) {
 +
this._enhance();
 +
}
 +
 +
this._on( this.element, {
 +
pagebeforehide: "removeContainerBackground",
 +
pagebeforeshow: "_handlePageBeforeShow"
 +
});
 +
 +
this.element.enhanceWithin();
 +
// Dialog widget is deprecated in 1.4 remove this in 1.5
 +
if ( $.mobile.getAttribute( this.element[0], "role" ) === "dialog" && $.mobile.dialog ) {
 +
this.element.dialog();
 +
}
 +
},
 +
 +
_enhance: function () {
 +
var attrPrefix = "data-" + $.mobile.ns,
 +
self = this;
 +
 +
if ( this.options.role ) {
 +
this.element.attr( "data-" + $.mobile.ns + "role", this.options.role );
 +
}
 +
 +
this.element
 +
.attr( "tabindex", "0" )
 +
.addClass( "ui-page ui-page-theme-" + this.options.theme );
 +
 +
// Manipulation of content os Deprecated as of 1.4 remove in 1.5
 +
this.element.find( "[" + attrPrefix + "role='content']" ).each( function() {
 +
var $this = $( this ),
 +
theme = this.getAttribute( attrPrefix + "theme" ) || undefined;
 +
self.options.contentTheme = theme || self.options.contentTheme || ( self.options.dialog && self.options.theme ) || ( self.element.jqmData("role") === "dialog" &&  self.options.theme );
 +
$this.addClass( "ui-content" );
 +
if ( self.options.contentTheme ) {
 +
$this.addClass( "ui-body-" + ( self.options.contentTheme ) );
 +
}
 +
// Add ARIA role
 +
$this.attr( "role", "main" ).addClass( "ui-content" );
 +
});
 +
},
 +
 +
bindRemove: function( callback ) {
 +
var page = this.element;
 +
 +
// when dom caching is not enabled or the page is embedded bind to remove the page on hide
 +
if ( !page.data( "mobile-page" ).options.domCache &&
 +
page.is( ":jqmData(external-page='true')" ) ) {
 +
 +
// TODO use _on - that is, sort out why it doesn't work in this case
 +
page.bind( "pagehide.remove", callback || function( e, data ) {
 +
 +
//check if this is a same page transition and if so don't remove the page
 +
if( !data.samePage ){
 +
var $this = $( this ),
 +
prEvent = new $.Event( "pageremove" );
 +
 +
$this.trigger( prEvent );
 +
 +
if ( !prEvent.isDefaultPrevented() ) {
 +
$this.removeWithDependents();
 +
}
 +
}
 +
});
 +
}
 +
},
 +
 +
_setOptions: function( o ) {
 +
if ( o.theme !== undefined ) {
 +
this.element.removeClass( "ui-page-theme-" + this.options.theme ).addClass( "ui-page-theme-" + o.theme );
 +
}
 +
 +
if ( o.contentTheme !== undefined ) {
 +
this.element.find( "[data-" + $.mobile.ns + "='content']" ).removeClass( "ui-body-" + this.options.contentTheme )
 +
.addClass( "ui-body-" + o.contentTheme );
 +
}
 +
},
 +
 +
_handlePageBeforeShow: function(/* e */) {
 +
this.setContainerBackground();
 +
},
 +
// Deprecated in 1.4 remove in 1.5
 +
removeContainerBackground: function() {
 +
this.element.closest( ":mobile-pagecontainer" ).pagecontainer({ "theme": "none" });
 +
},
 +
// Deprecated in 1.4 remove in 1.5
 +
// set the page container background to the page theme
 +
setContainerBackground: function( theme ) {
 +
this.element.parent().pagecontainer( { "theme": theme || this.options.theme } );
 +
},
 +
// Deprecated in 1.4 remove in 1.5
 +
keepNativeSelector: function() {
 +
var options = this.options,
 +
keepNative = $.trim( options.keepNative || "" ),
 +
globalValue = $.trim( $.mobile.keepNative ),
 +
optionValue = $.trim( options.keepNativeDefault ),
 +
 +
// Check if $.mobile.keepNative has changed from the factory default
 +
newDefault = ( keepNativeFactoryDefault === globalValue ?
 +
"" : globalValue ),
 +
 +
// If $.mobile.keepNative has not changed, use options.keepNativeDefault
 +
oldDefault = ( newDefault === "" ? optionValue : "" );
 +
 +
// Concatenate keepNative selectors from all sources where the value has
 +
// changed or, if nothing has changed, return the default
 +
return ( ( keepNative ? [ keepNative ] : [] )
 +
.concat( newDefault ? [ newDefault ] : [] )
 +
.concat( oldDefault ? [ oldDefault ] : [] )
 +
.join( ", " ) );
 +
}
 +
});
 +
})( jQuery );
 +
 +
(function( $, undefined ) {
 +
 +
$.mobile.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
 +
};
 +
// Backcompat remove in 1.5
 +
$.mobile.page.prototype.options.degradeInputs = $.mobile.degradeInputs;
 +
 +
// Auto self-init widgets
 +
$.mobile.degradeInputsWithin = function( target ) {
 +
 +
target = $( target );
 +
 +
// Degrade inputs to avoid poorly implemented native functionality
 +
target.find( "input" ).not( $.mobile.page.prototype.keepNativeSelector() ).each(function() {
 +
var element = $( this ),
 +
type = this.getAttribute( "type" ),
 +
optType = $.mobile.degradeInputs[ type ] || "text",
 +
html, hasType, findstr, repstr;
 +
 +
if ( $.mobile.degradeInputs[ type ] ) {
 +
html = $( "<div>" ).html( element.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 ? "" : ">" );
 +
 +
element.replaceWith( html.replace( findstr, repstr ) );
 +
}
 +
});
 +
 +
};
 +
 +
})( jQuery );
 +
 +
 +
(function( $, undefined ) {
 +
 +
// Deprecated in 1.4
 +
$.fn.fieldcontain = function(/* options */) {
 +
return this.addClass( "ui-field-contain" );
 +
};
 +
 +
})( jQuery );
  
  
Line 3,203: Line 4,245:
 
getDocumentBase: path.getDocumentBase
 
getDocumentBase: path.getDocumentBase
 
});
 
});
 +
})( jQuery );
 +
 +
 +
(function( $, undefined ) {
 +
 +
$.mobile.links = function( target ) {
 +
 +
//links within content areas, tests included with page
 +
$( target )
 +
.find( "a" )
 +
.jqmEnhanceable()
 +
.filter( ":jqmData(rel='popup')[href][href!='']" )
 +
.each( function() {
 +
// Accessibility info for popups
 +
var element = this,
 +
idref = element.getAttribute( "href" ).substring( 1 );
 +
 +
if ( idref ) {
 +
element.setAttribute( "aria-haspopup", true );
 +
element.setAttribute( "aria-owns", idref );
 +
element.setAttribute( "aria-expanded", false );
 +
}
 +
})
 +
.end()
 +
.not( ".ui-btn, :jqmData(role='none'), :jqmData(role='nojs')" )
 +
.addClass( "ui-link" );
 +
 +
};
 +
 
})( jQuery );
 
})( jQuery );
  
Line 3,694: Line 4,765:
 
})( jQuery );
 
})( jQuery );
  
 
/*!
 
* jQuery UI Widget c0ab71056b936627e8a7821f03c044aec6280a40
 
* http://jqueryui.com
 
*
 
* Copyright 2013 jQuery Foundation and other contributors
 
* Released under the MIT license.
 
* http://jquery.org/license
 
*
 
* http://api.jqueryui.com/jQuery.widget/
 
*/
 
(function( $, undefined ) {
 
 
var uuid = 0,
 
slice = Array.prototype.slice,
 
_cleanData = $.cleanData;
 
$.cleanData = function( elems ) {
 
for ( var i = 0, elem; (elem = elems[i]) != null; i++ ) {
 
try {
 
$( elem ).triggerHandler( "remove" );
 
// http://bugs.jquery.com/ticket/8235
 
} catch( e ) {}
 
}
 
_cleanData( elems );
 
};
 
 
$.widget = function( name, base, prototype ) {
 
var fullName, existingConstructor, constructor, basePrototype,
 
// proxiedPrototype allows the provided prototype to remain unmodified
 
// so that it can be used as a mixin for multiple widgets (#8876)
 
proxiedPrototype = {},
 
namespace = name.split( "." )[ 0 ];
 
 
name = name.split( "." )[ 1 ];
 
fullName = namespace + "-" + name;
 
 
if ( !prototype ) {
 
prototype = base;
 
base = $.Widget;
 
}
 
 
// create selector for plugin
 
$.expr[ ":" ][ fullName.toLowerCase() ] = function( elem ) {
 
return !!$.data( elem, fullName );
 
};
 
 
$[ namespace ] = $[ namespace ] || {};
 
existingConstructor = $[ namespace ][ name ];
 
constructor = $[ namespace ][ name ] = function( options, element ) {
 
// allow instantiation without "new" keyword
 
if ( !this._createWidget ) {
 
return new constructor( options, element );
 
}
 
 
// allow instantiation without initializing for simple inheritance
 
// must use "new" keyword (the code above always passes args)
 
if ( arguments.length ) {
 
this._createWidget( options, element );
 
}
 
};
 
// extend with the existing constructor to carry over any static properties
 
$.extend( constructor, existingConstructor, {
 
version: prototype.version,
 
// copy the object used to create the prototype in case we need to
 
// redefine the widget later
 
_proto: $.extend( {}, prototype ),
 
// track widgets that inherit from this widget in case this widget is
 
// redefined after a widget inherits from it
 
_childConstructors: []
 
});
 
 
basePrototype = new base();
 
// we need to make the options hash a property directly on the new instance
 
// otherwise we'll modify the options hash on the prototype that we're
 
// inheriting from
 
basePrototype.options = $.widget.extend( {}, basePrototype.options );
 
$.each( prototype, function( prop, value ) {
 
if ( !$.isFunction( value ) ) {
 
proxiedPrototype[ prop ] = value;
 
return;
 
}
 
proxiedPrototype[ prop ] = (function() {
 
var _super = function() {
 
return base.prototype[ prop ].apply( this, arguments );
 
},
 
_superApply = function( args ) {
 
return base.prototype[ prop ].apply( this, args );
 
};
 
return function() {
 
var __super = this._super,
 
__superApply = this._superApply,
 
returnValue;
 
 
this._super = _super;
 
this._superApply = _superApply;
 
 
returnValue = value.apply( this, arguments );
 
 
this._super = __super;
 
this._superApply = __superApply;
 
 
return returnValue;
 
};
 
})();
 
});
 
constructor.prototype = $.widget.extend( basePrototype, {
 
// TODO: remove support for widgetEventPrefix
 
// always use the name + a colon as the prefix, e.g., draggable:start
 
// don't prefix for widgets that aren't DOM-based
 
widgetEventPrefix: existingConstructor ? (basePrototype.widgetEventPrefix || name) : name
 
}, proxiedPrototype, {
 
constructor: constructor,
 
namespace: namespace,
 
widgetName: name,
 
widgetFullName: fullName
 
});
 
 
// If this widget is being redefined then we need to find all widgets that
 
// are inheriting from it and redefine all of them so that they inherit from
 
// the new version of this widget. We're essentially trying to replace one
 
// level in the prototype chain.
 
if ( existingConstructor ) {
 
$.each( existingConstructor._childConstructors, function( i, child ) {
 
var childPrototype = child.prototype;
 
 
// redefine the child widget using the same prototype that was
 
// originally used, but inherit from the new version of the base
 
$.widget( childPrototype.namespace + "." + childPrototype.widgetName, constructor, child._proto );
 
});
 
// remove the list of existing child constructors from the old constructor
 
// so the old child constructors can be garbage collected
 
delete existingConstructor._childConstructors;
 
} else {
 
base._childConstructors.push( constructor );
 
}
 
 
$.widget.bridge( name, constructor );
 
 
return constructor;
 
};
 
 
$.widget.extend = function( target ) {
 
var input = slice.call( arguments, 1 ),
 
inputIndex = 0,
 
inputLength = input.length,
 
key,
 
value;
 
for ( ; inputIndex < inputLength; inputIndex++ ) {
 
for ( key in input[ inputIndex ] ) {
 
value = input[ inputIndex ][ key ];
 
if ( input[ inputIndex ].hasOwnProperty( key ) && value !== undefined ) {
 
// Clone objects
 
if ( $.isPlainObject( value ) ) {
 
target[ key ] = $.isPlainObject( target[ key ] ) ?
 
$.widget.extend( {}, target[ key ], value ) :
 
// Don't extend strings, arrays, etc. with objects
 
$.widget.extend( {}, value );
 
// Copy everything else by reference
 
} else {
 
target[ key ] = value;
 
}
 
}
 
}
 
}
 
return target;
 
};
 
 
$.widget.bridge = function( name, object ) {
 
var fullName = object.prototype.widgetFullName || name;
 
$.fn[ name ] = function( options ) {
 
var isMethodCall = typeof options === "string",
 
args = slice.call( arguments, 1 ),
 
returnValue = this;
 
 
// allow multiple hashes to be passed on init
 
options = !isMethodCall && args.length ?
 
$.widget.extend.apply( null, [ options ].concat(args) ) :
 
options;
 
 
if ( isMethodCall ) {
 
this.each(function() {
 
var methodValue,
 
instance = $.data( this, fullName );
 
if ( options === "instance" ) {
 
returnValue = instance;
 
return false;
 
}
 
if ( !instance ) {
 
return $.error( "cannot call methods on " + name + " prior to initialization; " +
 
"attempted to call method '" + options + "'" );
 
}
 
if ( !$.isFunction( instance[options] ) || options.charAt( 0 ) === "_" ) {
 
return $.error( "no such method '" + options + "' for " + name + " widget instance" );
 
}
 
methodValue = instance[ options ].apply( instance, args );
 
if ( methodValue !== instance && methodValue !== undefined ) {
 
returnValue = methodValue && methodValue.jquery ?
 
returnValue.pushStack( methodValue.get() ) :
 
methodValue;
 
return false;
 
}
 
});
 
} else {
 
this.each(function() {
 
var instance = $.data( this, fullName );
 
if ( instance ) {
 
instance.option( options || {} )._init();
 
} else {
 
$.data( this, fullName, new object( options, this ) );
 
}
 
});
 
}
 
 
return returnValue;
 
};
 
};
 
 
$.Widget = function( /* options, element */ ) {};
 
$.Widget._childConstructors = [];
 
 
$.Widget.prototype = {
 
widgetName: "widget",
 
widgetEventPrefix: "",
 
defaultElement: "<div>",
 
options: {
 
disabled: false,
 
 
// callbacks
 
create: null
 
},
 
_createWidget: function( options, element ) {
 
element = $( element || this.defaultElement || this )[ 0 ];
 
this.element = $( element );
 
this.uuid = uuid++;
 
this.eventNamespace = "." + this.widgetName + this.uuid;
 
this.options = $.widget.extend( {},
 
this.options,
 
this._getCreateOptions(),
 
options );
 
 
this.bindings = $();
 
this.hoverable = $();
 
this.focusable = $();
 
 
if ( element !== this ) {
 
$.data( element, this.widgetFullName, this );
 
this._on( true, this.element, {
 
remove: function( event ) {
 
if ( event.target === element ) {
 
this.destroy();
 
}
 
}
 
});
 
this.document = $( element.style ?
 
// element within the document
 
element.ownerDocument :
 
// element is window or document
 
element.document || element );
 
this.window = $( this.document[0].defaultView || this.document[0].parentWindow );
 
}
 
 
this._create();
 
this._trigger( "create", null, this._getCreateEventData() );
 
this._init();
 
},
 
_getCreateOptions: $.noop,
 
_getCreateEventData: $.noop,
 
_create: $.noop,
 
_init: $.noop,
 
 
destroy: function() {
 
this._destroy();
 
// we can probably remove the unbind calls in 2.0
 
// all event bindings should go through this._on()
 
this.element
 
.unbind( this.eventNamespace )
 
.removeData( this.widgetFullName )
 
// support: jquery <1.6.3
 
// http://bugs.jquery.com/ticket/9413
 
.removeData( $.camelCase( this.widgetFullName ) );
 
this.widget()
 
.unbind( this.eventNamespace )
 
.removeAttr( "aria-disabled" )
 
.removeClass(
 
this.widgetFullName + "-disabled " +
 
"ui-state-disabled" );
 
 
// clean up events and states
 
this.bindings.unbind( this.eventNamespace );
 
this.hoverable.removeClass( "ui-state-hover" );
 
this.focusable.removeClass( "ui-state-focus" );
 
},
 
_destroy: $.noop,
 
 
widget: function() {
 
return this.element;
 
},
 
 
option: function( key, value ) {
 
var options = key,
 
parts,
 
curOption,
 
i;
 
 
if ( arguments.length === 0 ) {
 
// don't return a reference to the internal hash
 
return $.widget.extend( {}, this.options );
 
}
 
 
if ( typeof key === "string" ) {
 
// handle nested keys, e.g., "foo.bar" => { foo: { bar: ___ } }
 
options = {};
 
parts = key.split( "." );
 
key = parts.shift();
 
if ( parts.length ) {
 
curOption = options[ key ] = $.widget.extend( {}, this.options[ key ] );
 
for ( i = 0; i < parts.length - 1; i++ ) {
 
curOption[ parts[ i ] ] = curOption[ parts[ i ] ] || {};
 
curOption = curOption[ parts[ i ] ];
 
}
 
key = parts.pop();
 
if ( value === undefined ) {
 
return curOption[ key ] === undefined ? null : curOption[ key ];
 
}
 
curOption[ key ] = value;
 
} else {
 
if ( value === undefined ) {
 
return this.options[ key ] === undefined ? null : this.options[ key ];
 
}
 
options[ key ] = value;
 
}
 
}
 
 
this._setOptions( options );
 
 
return this;
 
},
 
_setOptions: function( options ) {
 
var key;
 
 
for ( key in options ) {
 
this._setOption( key, options[ key ] );
 
}
 
 
return this;
 
},
 
_setOption: function( key, value ) {
 
this.options[ key ] = value;
 
 
if ( key === "disabled" ) {
 
this.widget()
 
.toggleClass( this.widgetFullName + "-disabled", !!value );
 
this.hoverable.removeClass( "ui-state-hover" );
 
this.focusable.removeClass( "ui-state-focus" );
 
}
 
 
return this;
 
},
 
 
enable: function() {
 
return this._setOptions({ disabled: false });
 
},
 
disable: function() {
 
return this._setOptions({ disabled: true });
 
},
 
 
_on: function( suppressDisabledCheck, element, handlers ) {
 
var delegateElement,
 
instance = this;
 
 
// no suppressDisabledCheck flag, shuffle arguments
 
if ( typeof suppressDisabledCheck !== "boolean" ) {
 
handlers = element;
 
element = suppressDisabledCheck;
 
suppressDisabledCheck = false;
 
}
 
 
// no element argument, shuffle and use this.element
 
if ( !handlers ) {
 
handlers = element;
 
element = this.element;
 
delegateElement = this.widget();
 
} else {
 
// accept selectors, DOM elements
 
element = delegateElement = $( element );
 
this.bindings = this.bindings.add( element );
 
}
 
 
$.each( handlers, function( event, handler ) {
 
function handlerProxy() {
 
// allow widgets to customize the disabled handling
 
// - disabled as an array instead of boolean
 
// - disabled class as method for disabling individual parts
 
if ( !suppressDisabledCheck &&
 
( instance.options.disabled === true ||
 
$( this ).hasClass( "ui-state-disabled" ) ) ) {
 
return;
 
}
 
return ( typeof handler === "string" ? instance[ handler ] : handler )
 
.apply( instance, arguments );
 
}
 
 
// copy the guid so direct unbinding works
 
if ( typeof handler !== "string" ) {
 
handlerProxy.guid = handler.guid =
 
handler.guid || handlerProxy.guid || $.guid++;
 
}
 
 
var match = event.match( /^(\w+)\s*(.*)$/ ),
 
eventName = match[1] + instance.eventNamespace,
 
selector = match[2];
 
if ( selector ) {
 
delegateElement.delegate( selector, eventName, handlerProxy );
 
} else {
 
element.bind( eventName, handlerProxy );
 
}
 
});
 
},
 
 
_off: function( element, eventName ) {
 
eventName = (eventName || "").split( " " ).join( this.eventNamespace + " " ) + this.eventNamespace;
 
element.unbind( eventName ).undelegate( eventName );
 
},
 
 
_delay: function( handler, delay ) {
 
function handlerProxy() {
 
return ( typeof handler === "string" ? instance[ handler ] : handler )
 
.apply( instance, arguments );
 
}
 
var instance = this;
 
return setTimeout( handlerProxy, delay || 0 );
 
},
 
 
_hoverable: function( element ) {
 
this.hoverable = this.hoverable.add( element );
 
this._on( element, {
 
mouseenter: function( event ) {
 
$( event.currentTarget ).addClass( "ui-state-hover" );
 
},
 
mouseleave: function( event ) {
 
$( event.currentTarget ).removeClass( "ui-state-hover" );
 
}
 
});
 
},
 
 
_focusable: function( element ) {
 
this.focusable = this.focusable.add( element );
 
this._on( element, {
 
focusin: function( event ) {
 
$( event.currentTarget ).addClass( "ui-state-focus" );
 
},
 
focusout: function( event ) {
 
$( event.currentTarget ).removeClass( "ui-state-focus" );
 
}
 
});
 
},
 
 
_trigger: function( type, event, data ) {
 
var prop, orig,
 
callback = this.options[ type ];
 
 
data = data || {};
 
event = $.Event( event );
 
event.type = ( type === this.widgetEventPrefix ?
 
type :
 
this.widgetEventPrefix + type ).toLowerCase();
 
// the original event may come from any element
 
// so we need to reset the target on the new event
 
event.target = this.element[ 0 ];
 
 
// copy original event properties over to the new event
 
orig = event.originalEvent;
 
if ( orig ) {
 
for ( prop in orig ) {
 
if ( !( prop in event ) ) {
 
event[ prop ] = orig[ prop ];
 
}
 
}
 
}
 
 
this.element.trigger( event, data );
 
return !( $.isFunction( callback ) &&
 
callback.apply( this.element[0], [ event ].concat( data ) ) === false ||
 
event.isDefaultPrevented() );
 
}
 
};
 
 
$.each( { show: "fadeIn", hide: "fadeOut" }, function( method, defaultEffect ) {
 
$.Widget.prototype[ "_" + method ] = function( element, options, callback ) {
 
if ( typeof options === "string" ) {
 
options = { effect: options };
 
}
 
var hasOptions,
 
effectName = !options ?
 
method :
 
options === true || typeof options === "number" ?
 
defaultEffect :
 
options.effect || defaultEffect;
 
options = options || {};
 
if ( typeof options === "number" ) {
 
options = { duration: options };
 
}
 
hasOptions = !$.isEmptyObject( options );
 
options.complete = callback;
 
if ( options.delay ) {
 
element.delay( options.delay );
 
}
 
if ( hasOptions && $.effects && $.effects.effect[ effectName ] ) {
 
element[ method ]( options );
 
} else if ( effectName !== method && element[ effectName ] ) {
 
element[ effectName ]( options.duration, options.easing, callback );
 
} else {
 
element.queue(function( next ) {
 
$( this )[ method ]();
 
if ( callback ) {
 
callback.call( element[ 0 ] );
 
}
 
next();
 
});
 
}
 
};
 
});
 
 
})( jQuery );
 
 
(function( $, undefined ) {
 
 
var rcapitals = /[A-Z]/g,
 
replaceFunction = function( c ) {
 
return "-" + c.toLowerCase();
 
};
 
 
$.extend( $.Widget.prototype, {
 
_getCreateOptions: function() {
 
var option, value,
 
elem = this.element[ 0 ],
 
options = {};
 
 
//
 
if ( !$.mobile.getAttribute( elem, "defaults" ) ) {
 
for ( option in this.options ) {
 
value = $.mobile.getAttribute( elem, option.replace( rcapitals, replaceFunction ) );
 
 
if ( value != null ) {
 
options[ option ] = value;
 
}
 
}
 
}
 
 
return options;
 
}
 
});
 
 
//TODO: Remove in 1.5 for backcompat only
 
$.mobile.widget = $.Widget;
 
 
})( jQuery );
 
 
(function( $, undefined ) {
 
$.mobile.widgets = {};
 
 
var originalWidget = $.widget,
 
 
// Record the original, non-mobileinit-modified version of $.mobile.keepNative
 
// so we can later determine whether someone has modified $.mobile.keepNative
 
keepNativeFactoryDefault = $.mobile.keepNative;
 
 
$.widget = (function( orig ) {
 
return function() {
 
var constructor = orig.apply( this, arguments ),
 
name = constructor.prototype.widgetName;
 
 
constructor.initSelector = ( ( constructor.prototype.initSelector !== undefined ) ?
 
constructor.prototype.initSelector : ":jqmData(role='" + name + "')" );
 
 
$.mobile.widgets[ name ] = constructor;
 
 
return constructor;
 
};
 
})( $.widget );
 
 
// Make sure $.widget still has bridge and extend methods
 
$.extend( $.widget, originalWidget );
 
 
// For backcompat remove in 1.5
 
$.mobile.document.on( "create", function( event ) {
 
$( event.target ).enhanceWithin();
 
});
 
 
$.widget( "mobile.page", {
 
options: {
 
theme: "a",
 
domCache: false,
 
 
// Deprecated in 1.4 remove in 1.5
 
keepNativeDefault: $.mobile.keepNative,
 
 
// Deprecated in 1.4 remove in 1.5
 
contentTheme: null,
 
enhanced: false
 
},
 
 
// DEPRECATED for > 1.4
 
// TODO remove at 1.5
 
_createWidget: function() {
 
$.Widget.prototype._createWidget.apply( this, arguments );
 
this._trigger( "init" );
 
},
 
 
_create: function() {
 
// If false is returned by the callbacks do not create the page
 
if ( this._trigger( "beforecreate" ) === false ) {
 
return false;
 
}
 
 
if ( !this.options.enhanced ) {
 
this._enhance();
 
}
 
 
this._on( this.element, {
 
pagebeforehide: "removeContainerBackground",
 
pagebeforeshow: "_handlePageBeforeShow"
 
});
 
 
this.element.enhanceWithin();
 
// Dialog widget is deprecated in 1.4 remove this in 1.5
 
if ( $.mobile.getAttribute( this.element[0], "role" ) === "dialog" && $.mobile.dialog ) {
 
this.element.dialog();
 
}
 
},
 
 
_enhance: function () {
 
var attrPrefix = "data-" + $.mobile.ns,
 
self = this;
 
 
if ( this.options.role ) {
 
this.element.attr( "data-" + $.mobile.ns + "role", this.options.role );
 
}
 
 
this.element
 
.attr( "tabindex", "0" )
 
.addClass( "ui-page ui-page-theme-" + this.options.theme );
 
 
// Manipulation of content os Deprecated as of 1.4 remove in 1.5
 
this.element.find( "[" + attrPrefix + "role='content']" ).each( function() {
 
var $this = $( this ),
 
theme = this.getAttribute( attrPrefix + "theme" ) || undefined;
 
self.options.contentTheme = theme || self.options.contentTheme || ( self.options.dialog && self.options.theme ) || ( self.element.jqmData("role") === "dialog" &&  self.options.theme );
 
$this.addClass( "ui-content" );
 
if ( self.options.contentTheme ) {
 
$this.addClass( "ui-body-" + ( self.options.contentTheme ) );
 
}
 
// Add ARIA role
 
$this.attr( "role", "main" ).addClass( "ui-content" );
 
});
 
},
 
 
bindRemove: function( callback ) {
 
var page = this.element;
 
 
// when dom caching is not enabled or the page is embedded bind to remove the page on hide
 
if ( !page.data( "mobile-page" ).options.domCache &&
 
page.is( ":jqmData(external-page='true')" ) ) {
 
 
// TODO use _on - that is, sort out why it doesn't work in this case
 
page.bind( "pagehide.remove", callback || function( e, data ) {
 
 
//check if this is a same page transition and if so don't remove the page
 
if( !data.samePage ){
 
var $this = $( this ),
 
prEvent = new $.Event( "pageremove" );
 
 
$this.trigger( prEvent );
 
 
if ( !prEvent.isDefaultPrevented() ) {
 
$this.removeWithDependents();
 
}
 
}
 
});
 
}
 
},
 
 
_setOptions: function( o ) {
 
if ( o.theme !== undefined ) {
 
this.element.removeClass( "ui-page-theme-" + this.options.theme ).addClass( "ui-page-theme-" + o.theme );
 
}
 
 
if ( o.contentTheme !== undefined ) {
 
this.element.find( "[data-" + $.mobile.ns + "='content']" ).removeClass( "ui-body-" + this.options.contentTheme )
 
.addClass( "ui-body-" + o.contentTheme );
 
}
 
},
 
 
_handlePageBeforeShow: function(/* e */) {
 
this.setContainerBackground();
 
},
 
// Deprecated in 1.4 remove in 1.5
 
removeContainerBackground: function() {
 
this.element.closest( ":mobile-pagecontainer" ).pagecontainer({ "theme": "none" });
 
},
 
// Deprecated in 1.4 remove in 1.5
 
// set the page container background to the page theme
 
setContainerBackground: function( theme ) {
 
this.element.parent().pagecontainer( { "theme": theme || this.options.theme } );
 
},
 
// Deprecated in 1.4 remove in 1.5
 
keepNativeSelector: function() {
 
var options = this.options,
 
keepNative = $.trim( options.keepNative || "" ),
 
globalValue = $.trim( $.mobile.keepNative ),
 
optionValue = $.trim( options.keepNativeDefault ),
 
 
// Check if $.mobile.keepNative has changed from the factory default
 
newDefault = ( keepNativeFactoryDefault === globalValue ?
 
"" : globalValue ),
 
 
// If $.mobile.keepNative has not changed, use options.keepNativeDefault
 
oldDefault = ( newDefault === "" ? optionValue : "" );
 
 
// Concatenate keepNative selectors from all sources where the value has
 
// changed or, if nothing has changed, return the default
 
return ( ( keepNative ? [ keepNative ] : [] )
 
.concat( newDefault ? [ newDefault ] : [] )
 
.concat( oldDefault ? [ oldDefault ] : [] )
 
.join( ", " ) );
 
}
 
});
 
})( jQuery );
 
  
  
Line 6,281: Line 6,624:
 
})( jQuery );
 
})( jQuery );
  
 +
(function( $, undefined ) {
 +
 +
$.mobile.nojs = function( target ) {
 +
$( ":jqmData(role='nojs')", target ).addClass( "ui-nojs" );
 +
};
 +
 +
})( jQuery );
  
 
(function( $ ) {
 
(function( $ ) {
// TODO move loader class down into the widget settings
+
var meta = $( "meta[name=viewport]" ),
var loaderClass = "ui-loader", $html = $( "html" );
+
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 );
  
$.widget( "mobile.loader", {
+
$.mobile.zoom = $.extend( {}, {
// NOTE if the global config settings are defined they will override these
+
enabled: !disabledInitially,
//      options
+
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( $, window ) {
 +
 
 +
$.mobile.iosorientationfixEnabled = true;
 +
 
 +
// This fix addresses an iOS bug, so return early if the UA claims it's something else.
 +
var ua = navigator.userAgent,
 +
zoom,
 +
evt, x, y, z, aig;
 +
if ( !( /iPhone|iPad|iPod/.test( navigator.platform ) && /OS [1-5]_[0-9_]* like Mac OS X/i.test( ua ) && ua.indexOf( "AppleWebKit" ) > -1 ) ) {
 +
$.mobile.iosorientationfixEnabled = false;
 +
return;
 +
}
 +
 
 +
zoom = $.mobile.zoom;
 +
 
 +
function checkTilt( e ) {
 +
evt = e.originalEvent;
 +
aig = evt.accelerationIncludingGravity;
 +
 
 +
x = Math.abs( aig.x );
 +
y = Math.abs( aig.y );
 +
z = Math.abs( aig.z );
 +
 
 +
// If portrait orientation and in one of the danger zones
 +
if ( !window.orientation && ( x > 7 || ( ( z > 6 && y < 8 || z < 8 && y > 6 ) && x > 5 ) ) ) {
 +
if ( zoom.enabled ) {
 +
zoom.disable();
 +
}
 +
} else if ( !zoom.enabled ) {
 +
zoom.enable();
 +
}
 +
}
 +
 
 +
$.mobile.document.on( "mobileinit", function() {
 +
if ( $.mobile.iosorientationfixEnabled ) {
 +
$.mobile.window
 +
.bind( "orientationchange.iosorientationfix", zoom.enable )
 +
.bind( "devicemotion.iosorientationfix", checkTilt );
 +
}
 +
});
 +
 
 +
}( 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 ) {
 +
 
 +
$.widget( "mobile.textinput", {
 +
initSelector: "input[type='text']," +
 +
"input[type='search']," +
 +
":jqmData(type='search')," +
 +
"input[type='number']," +
 +
":jqmData(type='number')," +
 +
"input[type='password']," +
 +
"input[type='email']," +
 +
"input[type='url']," +
 +
"input[type='tel']," +
 +
"textarea," +
 +
"input[type='time']," +
 +
"input[type='date']," +
 +
"input[type='month']," +
 +
"input[type='week']," +
 +
"input[type='datetime']," +
 +
"input[type='datetime-local']," +
 +
"input[type='color']," +
 +
"input:not([type])," +
 +
"input[type='file']",
 +
 
 +
options: {
 +
theme: null,
 +
corners: true,
 +
mini: false,
 +
// This option defaults to true on iOS devices.
 +
preventFocusZoom: /iPhone|iPad|iPod/.test( navigator.platform ) && navigator.userAgent.indexOf( "AppleWebKit" ) > -1,
 +
wrapperClass: "",
 +
enhanced: false
 +
},
 +
 
 +
_create: function() {
 +
 
 +
var options = this.options,
 +
isSearch = this.element.is( "[type='search'], :jqmData(type='search')" ),
 +
isTextarea = this.element[ 0 ].tagName === "TEXTAREA",
 +
isRange = this.element.is( "[data-" + ( $.mobile.ns || "" ) + "type='range']" ),
 +
inputNeedsWrap = ( (this.element.is( "input" ) ||
 +
this.element.is( "[data-" + ( $.mobile.ns || "" ) + "type='search']" ) ) &&
 +
!isRange );
 +
 
 +
if ( this.element.prop( "disabled" ) ) {
 +
options.disabled = true;
 +
}
 +
 
 +
$.extend( this, {
 +
classes: this._classesFromOptions(),
 +
isSearch: isSearch,
 +
isTextarea: isTextarea,
 +
isRange: isRange,
 +
inputNeedsWrap: inputNeedsWrap
 +
});
 +
 
 +
this._autoCorrect();
 +
 
 +
if ( !options.enhanced ) {
 +
this._enhance();
 +
}
 +
 
 +
this._on( {
 +
"focus": "_handleFocus",
 +
"blur": "_handleBlur"
 +
});
 +
 
 +
},
 +
 
 +
refresh: function() {
 +
this.setOptions({
 +
"disabled" : this.element.is( ":disabled" )
 +
});
 +
},
 +
 
 +
_enhance: function() {
 +
var elementClasses = [];
 +
 
 +
if ( this.isTextarea ) {
 +
elementClasses.push( "ui-input-text" );
 +
}
 +
 
 +
if ( this.isTextarea || this.isRange ) {
 +
elementClasses.push( "ui-shadow-inset" );
 +
}
 +
 
 +
//"search" and "text" input widgets
 +
if ( this.inputNeedsWrap ) {
 +
this.element.wrap( this._wrap() );
 +
} else {
 +
elementClasses = elementClasses.concat( this.classes );
 +
}
 +
 
 +
this.element.addClass( elementClasses.join( " " ) );
 +
},
 +
 
 +
widget: function() {
 +
return ( this.inputNeedsWrap ) ? this.element.parent() : this.element;
 +
},
 +
 
 +
_classesFromOptions: function() {
 +
var options = this.options,
 +
classes = [];
 +
 
 +
classes.push( "ui-body-" + ( ( options.theme === null ) ? "inherit" : options.theme ) );
 +
if ( options.corners ) {
 +
classes.push( "ui-corner-all" );
 +
}
 +
if ( options.mini ) {
 +
classes.push( "ui-mini" );
 +
}
 +
if ( options.disabled ) {
 +
classes.push( "ui-state-disabled" );
 +
}
 +
if ( options.wrapperClass ) {
 +
classes.push( options.wrapperClass );
 +
}
 +
 
 +
return classes;
 +
},
 +
 
 +
_wrap: function() {
 +
return $( "<div class='" +
 +
( this.isSearch ? "ui-input-search " : "ui-input-text " ) +
 +
this.classes.join( " " ) + " " +
 +
"ui-shadow-inset'></div>" );
 +
},
 +
 
 +
_autoCorrect: function() {
 +
// 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 this.element[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.
 +
this.element[0].setAttribute( "autocorrect", "off" );
 +
this.element[0].setAttribute( "autocomplete", "off" );
 +
}
 +
},
 +
 
 +
_handleBlur: function() {
 +
this.widget().removeClass( $.mobile.focusClass );
 +
if ( this.options.preventFocusZoom ) {
 +
$.mobile.zoom.enable( true );
 +
}
 +
},
 +
 
 +
_handleFocus: function() {
 +
// In many situations, iOS will zoom into the input upon tap, this
 +
// prevents that from happening
 +
if ( this.options.preventFocusZoom ) {
 +
$.mobile.zoom.disable( true );
 +
}
 +
this.widget().addClass( $.mobile.focusClass );
 +
},
 +
 
 +
_setOptions: function ( options ) {
 +
var outer = this.widget();
 +
 
 +
this._super( options );
 +
 
 +
if ( !( options.disabled === undefined &&
 +
options.mini === undefined &&
 +
options.corners === undefined &&
 +
options.theme === undefined &&
 +
options.wrapperClass === undefined ) ) {
 +
 
 +
outer.removeClass( this.classes.join( " " ) );
 +
this.classes = this._classesFromOptions();
 +
outer.addClass( this.classes.join( " " ) );
 +
}
 +
 
 +
if ( options.disabled !== undefined ) {
 +
this.element.prop( "disabled", !!options.disabled );
 +
}
 +
},
 +
 
 +
_destroy: function() {
 +
if ( this.options.enhanced ) {
 +
return;
 +
}
 +
if ( this.inputNeedsWrap ) {
 +
this.element.unwrap();
 +
}
 +
this.element.removeClass( "ui-input-text " + this.classes.join( " " ) );
 +
}
 +
});
 +
 
 +
})( jQuery );
 +
 
 +
(function( $, undefined ) {
 +
 
 +
$.widget( "mobile.textinput", $.mobile.textinput, {
 
options: {
 
options: {
// the theme for the loading message
+
autogrow:true,
theme: "a",
+
keyupTimeoutBuffer: 100
 +
},
  
// whether the text in the loading message is shown
+
_create: function() {
textVisible: false,
+
this._super();
  
// custom html for the inner content of the loading message
+
if ( this.options.autogrow && this.isTextarea ) {
html: "",
+
this._autogrow();
 +
}
 +
},
  
// the text to be displayed when the popup is shown
+
_autogrow: function() {
text: "loading"
+
this.element.addClass( "ui-textinput-autogrow" );
 +
 
 +
this._on({
 +
"keyup": "_timeout",
 +
"change": "_timeout",
 +
"input": "_timeout",
 +
"paste": "_timeout"
 +
});
 +
 
 +
// Attach to the various you-have-become-visible notifications that the
 +
// various framework elements emit.
 +
// TODO: Remove all but the updatelayout handler once #6426 is fixed.
 +
this._on( true, this.document, {
 +
 
 +
// TODO: Move to non-deprecated event
 +
"pageshow": "_handleShow",
 +
"popupbeforeposition": "_handleShow",
 +
"updatelayout": "_handleShow",
 +
"panelopen": "_handleShow"
 +
});
 
},
 
},
  
defaultHtml: "<div class='" + loaderClass + "'>" +
+
// Synchronously fix the widget height if this widget's parents are such
"<span class='ui-icon-loading'></span>" +
+
// that they show/hide content at runtime. We still need to check whether
"<h1></h1>" +
+
// the widget is actually visible in case it is contained inside multiple
"</div>",
+
// such containers. For example: panel contains collapsible contains
 +
// autogrow textinput. The panel may emit "panelopen" indicating that its
 +
// content has become visible, but the collapsible is still collapsed, so
 +
// the autogrow textarea is still not visible.
 +
_handleShow: function( event ) {
 +
if ( $.contains( event.target, this.element[ 0 ] ) &&
 +
this.element.is( ":visible" ) ) {
  
// For non-fixed supportin browsers. Position at y center (if scrollTop supported), above the activeBtn (if defined), or just 100px from top
+
if ( event.type !== "popupbeforeposition" ) {
fakeFixLoader: function() {
+
this.element
var activeBtn = $( "." + $.mobile.activeBtnClass ).first();
+
.addClass( "ui-textinput-autogrow-resize" )
 +
.animationComplete(
 +
$.proxy( function() {
 +
this.element.removeClass( "ui-textinput-autogrow-resize" );
 +
}, this ),
 +
"transition" );
 +
}
 +
this._prepareHeightUpdate();
 +
}
 +
},
  
this.element
+
_unbindAutogrow: function() {
.css({
+
this.element.removeClass( "ui-textinput-autogrow" );
top: $.support.scrollTop && this.window.scrollTop() + this.window.height() / 2 ||
+
this._off( this.element, "keyup change input paste" );
activeBtn.length && activeBtn.offset().top || 100
+
this._off( this.document,
});
+
"pageshow popupbeforeposition updatelayout panelopen" );
 
},
 
},
  
// check position of loader to see if it appears to be "fixed" to center
+
keyupTimeout: null,
// if not, use abs positioning
+
checkLoaderPosition: function() {
+
var offset = this.element.offset(),
+
scrollTop = this.window.scrollTop(),
+
screenHeight = $.mobile.getScreenHeight();
+
  
if ( offset.top < scrollTop || ( offset.top - scrollTop ) > screenHeight ) {
+
_prepareHeightUpdate: function( delay ) {
this.element.addClass( "ui-loader-fakefix" );
+
if ( this.keyupTimeout ) {
this.fakeFixLoader();
+
clearTimeout( this.keyupTimeout );
this.window
+
}
.unbind( "scroll", this.checkLoaderPosition )
+
if ( delay === undefined ) {
.bind( "scroll", $.proxy( this.fakeFixLoader, this ) );
+
this._updateHeight();
 +
} else {
 +
this.keyupTimeout = this._delay( "_updateHeight", delay );
 
}
 
}
 
},
 
},
  
resetHtml: function() {
+
_timeout: function() {
this.element.html( $( this.defaultHtml ).html() );
+
this._prepareHeightUpdate( this.options.keyupTimeoutBuffer );
 
},
 
},
  
// Turn on/off page loading message. Theme doubles as an object argument
+
_updateHeight: function() {
// with the following shape: { theme: '', text: '', html: '', textVisible: '' }
+
var paddingTop, paddingBottom, paddingHeight, scrollHeight, clientHeight,
// NOTE that the $.mobile.loading* settings and params past the first are deprecated
+
borderTop, borderBottom, borderHeight, height,
// TODO sweet jesus we need to break some of this out
+
scrollTop = this.window.scrollTop();
show: function( theme, msgText, textonly ) {
+
this.keyupTimeout = 0;
var textVisible, message, loadSettings;
+
  
this.resetHtml();
+
// IE8 textareas have the onpage property - others do not
 +
if ( !( "onpage" in this.element[ 0 ] ) ) {
 +
this.element.css({
 +
"height": 0,
 +
"min-height": 0,
 +
"max-height": 0
 +
});
 +
}
  
// use the prototype options so that people can set them globally at
+
scrollHeight = this.element[ 0 ].scrollHeight;
// mobile init. Consistency, it's what's for dinner
+
clientHeight = this.element[ 0 ].clientHeight;
if ( $.type( theme ) === "object" ) {
+
borderTop = parseFloat( this.element.css( "border-top-width" ) );
loadSettings = $.extend( {}, this.options, theme );
+
borderBottom = parseFloat( this.element.css( "border-bottom-width" ) );
 +
borderHeight = borderTop + borderBottom;
 +
height = scrollHeight + borderHeight + 15;
  
theme = loadSettings.theme;
+
// Issue 6179: Padding is not included in scrollHeight and
} else {
+
// clientHeight by Firefox if no scrollbar is visible. Because
loadSettings = this.options;
+
// textareas use the border-box box-sizing model, padding should be
 +
// included in the new (assigned) height. Because the height is set
 +
// to 0, clientHeight == 0 in Firefox. Therefore, we can use this to
 +
// check if padding must be added.
 +
if ( clientHeight === 0 ) {
 +
paddingTop = parseFloat( this.element.css( "padding-top" ) );
 +
paddingBottom = parseFloat( this.element.css( "padding-bottom" ) );
 +
paddingHeight = paddingTop + paddingBottom;
  
// here we prefer the theme value passed as a string argument, then
+
height += paddingHeight;
// we prefer the global option because we can't use undefined default
+
// prototype options, then the prototype option
+
theme = theme || loadSettings.theme;
+
 
}
 
}
  
// set the message text, prefer the param, then the settings object
+
this.element.css({
// then loading message
+
"height": height,
message = msgText || ( loadSettings.text === false ? "" : loadSettings.text );
+
"min-height": "",
 +
"max-height": ""
 +
});
  
// prepare the dom
+
this.window.scrollTop( scrollTop );
$html.addClass( "ui-loading" );
+
},
  
textVisible = loadSettings.textVisible;
+
refresh: function() {
 +
if ( this.options.autogrow && this.isTextarea ) {
 +
this._updateHeight();
 +
}
 +
},
  
// add the proper css given the options (theme, text, etc)
+
_setOptions: function( options ) {
// Force text visibility if the second argument was supplied, or
+
// if the text was explicitly set in the object args
+
this.element.attr("class", loaderClass +
+
" ui-corner-all ui-body-" + theme +
+
" ui-loader-" + ( textVisible || msgText || theme.text ? "verbose" : "default" ) +
+
( loadSettings.textonly || textonly ? " ui-loader-textonly" : "" ) );
+
  
// TODO verify that jquery.fn.html is ok to use in both cases here
+
this._super( options );
//      this might be overly defensive in preventing unknowing xss
+
 
// if the html attribute is defined on the loading settings, use that
+
if ( options.autogrow !== undefined && this.isTextarea ) {
// otherwise use the fallbacks from above
+
if ( options.autogrow ) {
if ( loadSettings.html ) {
+
this._autogrow();
this.element.html( loadSettings.html );
+
} else {
} else {
+
this._unbindAutogrow();
this.element.find( "h1" ).text( message );
+
}
 
}
 
}
 +
}
  
// If the pagecontainer widget has been defined we may use the :mobile-pagecontainer
+
});
// and attach to the element on which the pagecontainer widget has been defined. If not,
+
})( jQuery );
// we attach to the body.
+
this.element.appendTo( $.mobile.pagecontainer ?
+
$( ":mobile-pagecontainer" ) : $( "body" ) );
+
  
// check that the loader is visible
+
(function( $, undefined ) {
this.checkLoaderPosition();
+
  
// on scroll check the loader position
+
$.widget( "mobile.button", {
this.window.bind( "scroll", $.proxy( this.checkLoaderPosition, this ) );
+
},
+
  
hide: function() {
+
initSelector: "input[type='button'], input[type='submit'], input[type='reset']",
$html.removeClass( "ui-loading" );
+
 
 +
options: {
 +
theme: null,
 +
icon: null,
 +
iconpos: "left",
 +
iconshadow: false, /* TODO: Deprecated in 1.4, remove in 1.5. */
 +
corners: true,
 +
shadow: true,
 +
inline: null,
 +
mini: null,
 +
wrapperClass: null,
 +
enhanced: false
 +
},
 +
 
 +
_create: function() {
 +
 
 +
if ( this.element.is( ":disabled" ) ) {
 +
this.options.disabled = true;
 +
}
 +
 
 +
if ( !this.options.enhanced ) {
 +
this._enhance();
 +
}
 +
 
 +
$.extend( this, {
 +
wrapper: this.element.parent()
 +
});
 +
 
 +
this._on( {
 +
focus: function() {
 +
this.widget().addClass( $.mobile.focusClass );
 +
},
  
if ( this.options.text ) {
+
blur: function() {
this.element.removeClass( "ui-loader-fakefix" );
+
this.widget().removeClass( $.mobile.focusClass );
 
}
 
}
 +
});
 +
 +
this.refresh( true );
 +
},
 +
 +
_enhance: function() {
 +
this.element.wrap( this._button() );
 +
},
 +
 +
_button: function() {
 +
var options = this.options,
 +
iconClasses = this._getIconClasses( this.options );
 +
 +
return $("<div class='ui-btn ui-input-btn" +
 +
( options.wrapperClass ? " " + options.wrapperClass : "" ) +
 +
( options.theme ? " ui-btn-" + options.theme : "" ) +
 +
( options.corners ? " ui-corner-all" : "" ) +
 +
( options.shadow ? " ui-shadow" : "" ) +
 +
( options.inline ? " ui-btn-inline" : "" ) +
 +
( options.mini ? " ui-mini" : "" ) +
 +
( options.disabled ? " ui-state-disabled" : "" ) +
 +
( iconClasses ? ( " " + iconClasses ) : "" ) +
 +
"' >" + this.element.val() + "</div>" );
 +
},
 +
 +
widget: function() {
 +
return this.wrapper;
 +
},
 +
 +
_destroy: function() {
 +
this.element.insertBefore( this.wrapper );
 +
this.wrapper.remove();
 +
},
 +
 +
_getIconClasses: function( options ) {
 +
return ( options.icon ? ( "ui-icon-" + options.icon +
 +
( options.iconshadow ? " ui-shadow-icon" : "" ) + /* TODO: Deprecated in 1.4, remove in 1.5. */
 +
" ui-btn-icon-" + options.iconpos ) : "" );
 +
},
 +
 +
_setOptions: function( options ) {
 +
var outer = this.widget();
  
this.window.unbind( "scroll", this.fakeFixLoader );
+
if ( options.theme !== undefined ) {
this.window.unbind( "scroll", this.checkLoaderPosition );
+
outer
 +
.removeClass( this.options.theme )
 +
.addClass( "ui-btn-" + options.theme );
 +
}
 +
if ( options.corners !== undefined ) {
 +
outer.toggleClass( "ui-corner-all", options.corners );
 +
}
 +
if ( options.shadow !== undefined ) {
 +
outer.toggleClass( "ui-shadow", options.shadow );
 +
}
 +
if ( options.inline !== undefined ) {
 +
outer.toggleClass( "ui-btn-inline", options.inline );
 +
}
 +
if ( options.mini !== undefined ) {
 +
outer.toggleClass( "ui-mini", options.mini );
 +
}
 +
if ( options.disabled !== undefined ) {
 +
this.element.prop( "disabled", options.disabled );
 +
outer.toggleClass( "ui-state-disabled", options.disabled );
 
}
 
}
});
 
  
})(jQuery, this);
+
if ( options.icon !== undefined ||
 +
options.iconshadow !== undefined || /* TODO: Deprecated in 1.4, remove in 1.5. */
 +
options.iconpos !== undefined ) {
 +
outer
 +
.removeClass( this._getIconClasses( this.options ) )
 +
.addClass( this._getIconClasses(
 +
$.extend( {}, this.options, options ) ) );
 +
}
  
 +
this._super( options );
 +
},
  
(function( $, window, undefined ) {
+
refresh: function( create ) {
var $html = $( "html" ),
+
var originalElement,
$window = $.mobile.window;
+
isDisabled = this.element.prop( "disabled" );
  
//remove initial build class (only present on first pageshow)
+
if ( this.options.icon && this.options.iconpos === "notext" && this.element.attr( "title" ) ) {
function hideRenderingClass() {
+
this.element.attr( "title", this.element.val() );
$html.removeClass( "ui-mobile-rendering" );
+
}
 +
if ( !create ) {
 +
originalElement = this.element.detach();
 +
$( this.wrapper ).text( this.element.val() ).append( originalElement );
 +
}
 +
if ( this.options.disabled !== isDisabled ) {
 +
this._setOptions({ disabled: isDisabled });
 +
}
 
}
 
}
 +
});
  
// trigger mobileinit event - useful hook for configuring $.mobile settings before they're used
+
})( jQuery );
$( window.document ).trigger( "mobileinit" );
+
  
// support conditions
+
(function( $, undefined ) {
// if device support condition(s) aren't met, leave things as they are -> a basic, usable experience,
+
 
// otherwise, proceed with the enhancements
+
$.mobile.behaviors.formReset = {
if ( !$.mobile.gradeA() ) {
+
_handleFormReset: function() {
return;
+
this._on( this.element.closest( "form" ), {
 +
reset: function() {
 +
this._delay( "_reset" );
 +
}
 +
});
 
}
 
}
 +
};
  
// override ajaxEnabled on platforms that have known conflicts with hash history updates
+
})( jQuery );
// or generally work better browsing in regular http for full page refreshes (BB5, Opera Mini)
+
 
if ( $.mobile.ajaxBlacklist ) {
+
/*
$.mobile.ajaxEnabled = false;
+
* "checkboxradio" plugin
 +
*/
 +
 
 +
(function( $, undefined ) {
 +
 
 +
var escapeId = $.mobile.path.hashToSelector;
 +
 
 +
$.widget( "mobile.checkboxradio", $.extend( {
 +
 
 +
initSelector: "input:not( :jqmData(role='flipswitch' ) )[type='checkbox'],input[type='radio']:not( :jqmData(role='flipswitch' ))",
 +
 
 +
options: {
 +
theme: "inherit",
 +
mini: false,
 +
wrapperClass: null,
 +
enhanced: false,
 +
iconpos: "left"
 +
 
 +
},
 +
_create: function() {
 +
var input = this.element,
 +
o = this.options,
 +
inheritAttr = function( input, dataAttr ) {
 +
return input.jqmData( dataAttr ) ||
 +
input.closest( "form, fieldset" ).jqmData( dataAttr );
 +
},
 +
label = this.options.enhanced ?
 +
{
 +
element: this.element.siblings( "label" ),
 +
isParent: false
 +
} :
 +
this._findLabel(),
 +
inputtype = input[0].type,
 +
checkedClass = "ui-" + inputtype + "-on",
 +
uncheckedClass = "ui-" + inputtype + "-off";
 +
 
 +
if ( inputtype !== "checkbox" && inputtype !== "radio" ) {
 +
return;
 +
}
 +
 
 +
if ( this.element[0].disabled ) {
 +
this.options.disabled = true;
 +
}
 +
 
 +
o.iconpos = inheritAttr( input, "iconpos" ) ||
 +
label.element.attr( "data-" + $.mobile.ns + "iconpos" ) || o.iconpos,
 +
 
 +
// Establish options
 +
o.mini = inheritAttr( input, "mini" ) || o.mini;
 +
 
 +
// Expose for other methods
 +
$.extend( this, {
 +
input: input,
 +
label: label.element,
 +
labelIsParent: label.isParent,
 +
inputtype: inputtype,
 +
checkedClass: checkedClass,
 +
uncheckedClass: uncheckedClass
 +
});
 +
 
 +
if ( !this.options.enhanced ) {
 +
this._enhance();
 +
}
 +
 
 +
this._on( label.element, {
 +
vmouseover: "_handleLabelVMouseOver",
 +
vclick: "_handleLabelVClick"
 +
});
 +
 
 +
this._on( input, {
 +
vmousedown: "_cacheVals",
 +
vclick: "_handleInputVClick",
 +
focus: "_handleInputFocus",
 +
blur: "_handleInputBlur"
 +
});
 +
 
 +
this._handleFormReset();
 +
this.refresh();
 +
},
 +
 
 +
_findLabel: function() {
 +
var parentLabel, label, isParent,
 +
input = this.element,
 +
labelsList = input[ 0 ].labels;
 +
 
 +
if( labelsList && labelsList.length > 0 ) {
 +
label = $( labelsList[ 0 ] );
 +
isParent = $.contains( label[ 0 ], input[ 0 ] );
 +
} else {
 +
parentLabel = input.closest( "label" );
 +
isParent = ( parentLabel.length > 0 );
 +
 
 +
// NOTE: Windows Phone could not find the label through a selector
 +
// filter works though.
 +
label = isParent ? parentLabel :
 +
$( this.document[ 0 ].getElementsByTagName( "label" ) )
 +
.filter( "[for='" + escapeId( input[ 0 ].id ) + "']" )
 +
.first();
 +
}
 +
 
 +
return {
 +
element: label,
 +
isParent: isParent
 +
};
 +
},
 +
 
 +
_enhance: function() {
 +
this.label.addClass( "ui-btn ui-corner-all");
 +
 
 +
if ( this.labelIsParent ) {
 +
this.input.add( this.label ).wrapAll( this._wrapper() );
 +
} else {
 +
//this.element.replaceWith( this.input.add( this.label ).wrapAll( this._wrapper() ) );
 +
this.element.wrap( this._wrapper() );
 +
this.element.parent().prepend( this.label );
 +
}
 +
 
 +
// Wrap the input + label in a div
 +
 
 +
this._setOptions({
 +
"theme": this.options.theme,
 +
"iconpos": this.options.iconpos,
 +
"mini": this.options.mini
 +
});
 +
 
 +
},
 +
 
 +
_wrapper: function() {
 +
return $( "<div class='"  +
 +
( this.options.wrapperClass ? this.options.wrapperClass : "" ) +
 +
" ui-" + this.inputtype +
 +
( this.options.disabled ? " ui-state-disabled" : "" ) + "' ></div>" );
 +
},
 +
 
 +
_handleInputFocus: function() {
 +
this.label.addClass( $.mobile.focusClass );
 +
},
 +
 
 +
_handleInputBlur: function() {
 +
this.label.removeClass( $.mobile.focusClass );
 +
},
 +
 
 +
_handleInputVClick: function() {
 +
// Adds checked attribute to checked input when keyboard is used
 +
this.element.prop( "checked", this.element.is( ":checked" ) );
 +
this._getInputSet().not( this.element ).prop( "checked", false );
 +
this._updateAll( true );
 +
},
 +
 
 +
_handleLabelVMouseOver: function( event ) {
 +
if ( this.label.parent().hasClass( "ui-state-disabled" ) ) {
 +
event.stopPropagation();
 +
}
 +
},
 +
 
 +
_handleLabelVClick: function( event ) {
 +
var input = this.element;
 +
 
 +
if ( input.is( ":disabled" ) ) {
 +
event.preventDefault();
 +
return;
 +
}
 +
 
 +
this._cacheVals();
 +
 
 +
input.prop( "checked", this.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
 +
this._getInputSet().not( input ).prop( "checked", false );
 +
 
 +
this._updateAll();
 +
return false;
 +
},
 +
 
 +
_cacheVals: function() {
 +
this._getInputSet().each( function() {
 +
$( this ).attr("data-" + $.mobile.ns + "cacheVal", this.checked );
 +
});
 +
},
 +
 
 +
// Returns those radio buttons that are supposed to be in the same group as
 +
// this radio button. In the case of a checkbox or a radio lacking a name
 +
// attribute, it returns this.element.
 +
_getInputSet: function() {
 +
var selector, formId,
 +
radio = this.element[ 0 ],
 +
name = radio.name,
 +
form = radio.form,
 +
doc = this.element.parents().last().get( 0 ),
 +
 
 +
// A radio is always a member of its own group
 +
radios = this.element;
 +
 
 +
// Only start running selectors if this is an attached radio button with a name
 +
if ( name && this.inputtype === "radio" && doc ) {
 +
selector = "input[type='radio'][name='" + escapeId( name ) + "']";
 +
 
 +
// If we're inside a form
 +
if ( form ) {
 +
formId = form.getAttribute( "id" );
 +
 
 +
// If the form has an ID, collect radios scattered throught the document which
 +
// nevertheless are part of the form by way of the value of their form attribute
 +
if ( formId ) {
 +
radios = $( selector + "[form='" + escapeId( formId ) + "']", doc );
 +
}
 +
 
 +
// Also add to those the radios in the form itself
 +
radios = $( form ).find( selector ).filter( function() {
 +
 
 +
// Some radios inside the form may belong to some other form by virtue of
 +
// having a form attribute defined on them, so we must filter them out here
 +
return ( this.form === form );
 +
}).add( radios );
 +
 
 +
// If we're outside a form
 +
} else {
 +
 
 +
// Collect all those radios which are also outside of a form and match our name
 +
radios = $( selector, doc ).filter( function() {
 +
return !this.form;
 +
});
 +
}
 +
}
 +
return radios;
 +
},
 +
 
 +
_updateAll: function( changeTriggered ) {
 +
var self = this;
 +
 
 +
this._getInputSet().each( function() {
 +
var $this = $( this );
 +
 
 +
if ( ( this.checked || self.inputtype === "checkbox" ) && !changeTriggered ) {
 +
$this.trigger( "change" );
 +
}
 +
})
 +
.checkboxradio( "refresh" );
 +
},
 +
 
 +
_reset: function() {
 +
this.refresh();
 +
},
 +
 
 +
// Is the widget supposed to display an icon?
 +
_hasIcon: function() {
 +
var controlgroup, controlgroupWidget,
 +
controlgroupConstructor = $.mobile.controlgroup;
 +
 
 +
// If the controlgroup widget is defined ...
 +
if ( controlgroupConstructor ) {
 +
controlgroup = this.element.closest(
 +
":mobile-controlgroup," +
 +
controlgroupConstructor.prototype.initSelector );
 +
 
 +
// ... and the checkbox is in a controlgroup ...
 +
if ( controlgroup.length > 0 ) {
 +
 
 +
// ... look for a controlgroup widget instance, and ...
 +
controlgroupWidget = $.data( controlgroup[ 0 ], "mobile-controlgroup" );
 +
 
 +
// ... if found, decide based on the option value, ...
 +
return ( ( controlgroupWidget ? controlgroupWidget.options.type :
 +
 
 +
// ... otherwise decide based on the "type" data attribute.
 +
controlgroup.attr( "data-" + $.mobile.ns + "type" ) ) !== "horizontal" );
 +
}
 +
}
 +
 
 +
// Normally, the widget displays an icon.
 +
return true;
 +
},
 +
 
 +
refresh: function() {
 +
var isChecked = this.element[ 0 ].checked,
 +
active = $.mobile.activeBtnClass,
 +
iconposClass = "ui-btn-icon-" + this.options.iconpos,
 +
addClasses = [],
 +
removeClasses = [];
 +
 
 +
if ( this._hasIcon() ) {
 +
removeClasses.push( active );
 +
addClasses.push( iconposClass );
 +
} else {
 +
removeClasses.push( iconposClass );
 +
( isChecked ? addClasses : removeClasses ).push( active );
 +
}
 +
 
 +
if ( isChecked ) {
 +
addClasses.push( this.checkedClass );
 +
removeClasses.push( this.uncheckedClass );
 +
} else {
 +
addClasses.push( this.uncheckedClass );
 +
removeClasses.push( this.checkedClass );
 +
}
 +
 
 +
this.widget().toggleClass( "ui-state-disabled", this.element.prop( "disabled" ) );
 +
 
 +
this.label
 +
.addClass( addClasses.join( " " ) )
 +
.removeClass( removeClasses.join( " " ) );
 +
},
 +
 
 +
widget: function() {
 +
return this.label.parent();
 +
},
 +
 
 +
_setOptions: function( options ) {
 +
var label = this.label,
 +
currentOptions = this.options,
 +
outer = this.widget(),
 +
hasIcon = this._hasIcon();
 +
 
 +
if ( options.disabled !== undefined ) {
 +
this.input.prop( "disabled", !!options.disabled );
 +
outer.toggleClass( "ui-state-disabled", !!options.disabled );
 +
}
 +
if ( options.mini !== undefined ) {
 +
outer.toggleClass( "ui-mini", !!options.mini );
 +
}
 +
if ( options.theme !== undefined ) {
 +
label
 +
.removeClass( "ui-btn-" + currentOptions.theme )
 +
.addClass( "ui-btn-" + options.theme );
 +
}
 +
if ( options.wrapperClass !== undefined ) {
 +
outer
 +
.removeClass( currentOptions.wrapperClass )
 +
.addClass( options.wrapperClass );
 +
}
 +
if ( options.iconpos !== undefined && hasIcon ) {
 +
label.removeClass( "ui-btn-icon-" + currentOptions.iconpos ).addClass( "ui-btn-icon-" + options.iconpos );
 +
} else if ( !hasIcon ) {
 +
label.removeClass( "ui-btn-icon-" + currentOptions.iconpos );
 +
}
 +
this._super( options );
 
}
 
}
  
// Add mobile, initial load "rendering" classes to docEl
+
}, $.mobile.behaviors.formReset ) );
$html.addClass( "ui-mobile ui-mobile-rendering" );
+
  
// This is a fallback. If anything goes wrong (JS errors, etc), or events don't fire,
+
})( jQuery );
// this ensures the rendering class is removed after 5 seconds, so content is visible and accessible
+
setTimeout( hideRenderingClass, 5000 );
+
  
$.extend( $.mobile, {
+
(function( $, undefined ) {
// find and enhance the pages in the dom and transition to the first page.
+
initializePage: function() {
+
// find present pages
+
var path = $.mobile.path,
+
$pages = $( ":jqmData(role='page'), :jqmData(role='dialog')" ),
+
hash = path.stripHash( path.stripQueryParams(path.parseLocation().hash) ),
+
theLocation = $.mobile.path.parseLocation(),
+
hashPage = hash ? document.getElementById( hash ) : undefined;
+
  
// if no pages are found, create one with body's inner html
+
$.widget( "mobile.textinput", $.mobile.textinput, {
if ( !$pages.length ) {
+
options: {
$pages = $( "body" ).wrapInner( "<div data-" + $.mobile.ns + "role='page'></div>" ).children( 0 );
+
clearBtn: false,
 +
clearBtnText: "Clear text"
 +
},
 +
 
 +
_create: function() {
 +
this._super();
 +
 
 +
if ( this.isSearch ) {
 +
this.options.clearBtn = true;
 
}
 
}
  
// add dialogs, set data-url attrs
+
if ( !!this.options.clearBtn && this.inputNeedsWrap ) {
$pages.each(function() {
+
this._addClearBtn();
var $this = $( this );
+
}
 +
},
  
// unless the data url is already set set it to the pathname
+
clearButton: function() {
if ( !$this[ 0 ].getAttribute( "data-" + $.mobile.ns + "url" ) ) {
+
return $( "<a href='#' tabindex='-1' aria-hidden='true' " +
$this.attr( "data-" + $.mobile.ns + "url", $this.attr( "id" ) ||
+
"class='ui-input-clear ui-btn ui-icon-delete ui-btn-icon-notext ui-corner-all'>" +
path.convertUrlToDataUrl( theLocation.pathname + theLocation.search ) );
+
"</a>" )
}
+
.attr( "title", this.options.clearBtnText )
 +
.text( this.options.clearBtnText );
 +
},
 +
 
 +
_clearBtnClick: function( event ) {
 +
this.element.val( "" )
 +
.focus()
 +
.trigger( "change" );
 +
 
 +
this._clearBtn.addClass( "ui-input-clear-hidden" );
 +
event.preventDefault();
 +
},
 +
 
 +
_addClearBtn: function() {
 +
 
 +
if ( !this.options.enhanced ) {
 +
this._enhanceClear();
 +
}
 +
 
 +
$.extend( this, {
 +
_clearBtn: this.widget().find("a.ui-input-clear")
 
});
 
});
  
// define first page in dom case one backs out to the directory root (not always the first page visited, but defined as fallback)
+
this._bindClearEvents();
$.mobile.firstPage = $pages.first();
+
  
// define page container
+
this._toggleClear();
$.mobile.pageContainer = $.mobile.firstPage
+
.parent()
+
.addClass( "ui-mobile-viewport" )
+
.pagecontainer();
+
  
// initialize navigation events now, after mobileinit has occurred and the page container
+
},
// has been created but before the rest of the library is alerted to that fact
+
$.mobile.navreadyDeferred.resolve();
+
  
// alert listeners that the pagecontainer has been determined for binding
+
_enhanceClear: function() {
// to events triggered on it
+
$window.trigger( "pagecontainercreate" );
+
  
// cue page loading message
+
this.clearButton().appendTo( this.widget() );
$.mobile.loading( "show" );
+
this.widget().addClass( "ui-input-has-clear" );
  
//remove initial build class (only present on first pageshow)
+
},
hideRenderingClass();
+
  
// if hashchange listening is disabled, there's no hash deeplink,
+
_bindClearEvents: function() {
// the hash is not valid (contains more than one # or does not start with #)
+
// or there is no page with that hash, change to the first page in the DOM
+
// Remember, however, that the hash can also be a path!
+
if ( ! ( $.mobile.hashListeningEnabled &&
+
$.mobile.path.isHashValid( location.hash ) &&
+
( $( hashPage ).is( ":jqmData(role='page')" ) ||
+
$.mobile.path.isPath( hash ) ||
+
hash === $.mobile.dialogHashKey ) ) ) {
+
  
// make sure to set initial popstate state if it exists
+
this._on( this._clearBtn, {
// so that navigation back to the initial page works properly
+
"click": "_clearBtnClick"
if ( $.event.special.navigate.isPushStateEnabled() ) {
+
});
$.mobile.navigate.navigator.squash( path.parseLocation().href );
+
}
+
  
$.mobile.changePage( $.mobile.firstPage, {
+
this._on({
transition: "none",
+
"keyup": "_toggleClear",
reverse: true,
+
"change": "_toggleClear",
changeHash: false,
+
"input": "_toggleClear",
fromHashChange: true
+
"focus": "_toggleClear",
});
+
"blur": "_toggleClear",
} else {
+
"cut": "_toggleClear",
// trigger hashchange or navigate to squash and record the correct
+
"paste": "_toggleClear"
// history entry for an initial hash path
+
 
if ( !$.event.special.navigate.isPushStateEnabled() ) {
+
});
$window.trigger( "hashchange", [true] );
+
 
 +
},
 +
 
 +
_unbindClear: function() {
 +
this._off( this._clearBtn, "click");
 +
this._off( this.element, "keyup change input focus blur cut paste" );
 +
},
 +
 
 +
_setOptions: function( options ) {
 +
this._super( options );
 +
 
 +
if ( options.clearBtn !== undefined &&
 +
!this.element.is( "textarea, :jqmData(type='range')" ) ) {
 +
if ( options.clearBtn ) {
 +
this._addClearBtn();
 
} else {
 
} else {
// TODO figure out how to simplify this interaction with the initial history entry
+
this._destroyClear();
// at the bottom js/navigate/navigate.js
+
$.mobile.navigate.history.stack = [];
+
$.mobile.navigate( $.mobile.path.isPath( location.hash ) ? location.hash : location.href );
+
 
}
 
}
 +
}
 +
 +
if ( options.clearBtnText !== undefined && this._clearBtn !== undefined ) {
 +
this._clearBtn.text( options.clearBtnText )
 +
.attr("title", options.clearBtnText);
 +
}
 +
},
 +
 +
_toggleClear: function() {
 +
this._delay( "_toggleClearClass", 0 );
 +
},
 +
 +
_toggleClearClass: function() {
 +
this._clearBtn.toggleClass( "ui-input-clear-hidden", !this.element.val() );
 +
},
 +
 +
_destroyClear: function() {
 +
this.widget().removeClass( "ui-input-has-clear" );
 +
this._unbindClear();
 +
this._clearBtn.remove();
 +
},
 +
 +
_destroy: function() {
 +
this._super();
 +
if ( this.options.clearBtn ) {
 +
this._destroyClear();
 
}
 
}
 
}
 
}
 +
 
});
 
});
  
$(function() {
+
})( jQuery );
//Run inlineSVG support test
+
$.support.inlineSVG();
+
  
// check which scrollTop value should be used by scrolling to 1 immediately at domready
+
(function( $, undefined ) {
// then check what the scroll top is. Android will report 0... others 1
+
// note that this initial scroll won't hide the address bar. It's just for the check.
+
  
// hide iOS browser chrome on load if hideUrlBar is true this is to try and do it as soon as possible
+
$.widget( "mobile.flipswitch", $.extend({
if ( $.mobile.hideUrlBar ) {
+
 
window.scrollTo( 0, 1 );
+
options: {
 +
onText: "On",
 +
offText: "Off",
 +
theme: null,
 +
enhanced: false,
 +
wrapperClass: null,
 +
corners: true,
 +
mini: false
 +
},
 +
 
 +
_create: function() {
 +
if ( !this.options.enhanced ) {
 +
this._enhance();
 +
} else {
 +
$.extend( this, {
 +
flipswitch: this.element.parent(),
 +
on: this.element.find( ".ui-flipswitch-on" ).eq( 0 ),
 +
off: this.element.find( ".ui-flipswitch-off" ).eq(0),
 +
type: this.element.get( 0 ).tagName
 +
});
 +
}
 +
 
 +
this._handleFormReset();
 +
 
 +
// Transfer tabindex to "on" element and make input unfocusable
 +
this._originalTabIndex = this.element.attr( "tabindex" );
 +
if ( this._originalTabIndex != null ) {
 +
this.on.attr( "tabindex", this._originalTabIndex );
 +
}
 +
this.element.attr( "tabindex", "-1" );
 +
this._on({
 +
"focus" : "_handleInputFocus"
 +
});
 +
 
 +
if ( this.element.is( ":disabled" ) ) {
 +
this._setOptions({
 +
"disabled": true
 +
});
 +
}
 +
 
 +
this._on( this.flipswitch, {
 +
"click": "_toggle",
 +
"swipeleft": "_left",
 +
"swiperight": "_right"
 +
});
 +
 
 +
this._on( this.on, {
 +
"keydown": "_keydown"
 +
});
 +
 
 +
this._on( {
 +
"change": "refresh"
 +
});
 +
},
 +
 
 +
_handleInputFocus: function() {
 +
this.on.focus();
 +
},
 +
 
 +
widget: function() {
 +
return this.flipswitch;
 +
},
 +
 
 +
_left: function() {
 +
this.flipswitch.removeClass( "ui-flipswitch-active" );
 +
if ( this.type === "SELECT" ) {
 +
this.element.get( 0 ).selectedIndex = 0;
 +
} else {
 +
this.element.prop( "checked", false );
 
}
 
}
 +
this.element.trigger( "change" );
 +
},
  
// if defaultHomeScroll hasn't been set yet, see if scrollTop is 1
+
_right: function() {
// it should be 1 in most browsers, but android treats 1 as 0 (for hiding addr bar)
+
this.flipswitch.addClass( "ui-flipswitch-active" );
// so if it's 1, use 0 from now on
+
if ( this.type === "SELECT" ) {
$.mobile.defaultHomeScroll = ( !$.support.scrollTop || $.mobile.window.scrollTop() === 1 ) ? 0 : 1;
+
this.element.get( 0 ).selectedIndex = 1;
 +
} else {
 +
this.element.prop( "checked", true );
 +
}
 +
this.element.trigger( "change" );
 +
},
  
//dom-ready inits
+
_enhance: function() {
if ( $.mobile.autoInitializePage ) {
+
var flipswitch = $( "<div>" ),
$.mobile.initializePage();
+
options = this.options,
 +
element = this.element,
 +
theme = options.theme ? options.theme : "inherit",
 +
 
 +
// The "on" button is an anchor so it's focusable
 +
on = $( "<a></a>", {
 +
"href": "#"
 +
}),
 +
off = $( "<span></span>" ),
 +
type = element.get( 0 ).tagName,
 +
onText = ( type === "INPUT" ) ?
 +
options.onText : element.find( "option" ).eq( 1 ).text(),
 +
offText = ( type === "INPUT" ) ?
 +
options.offText : element.find( "option" ).eq( 0 ).text();
 +
 
 +
on
 +
.addClass( "ui-flipswitch-on ui-btn ui-shadow ui-btn-inherit" )
 +
.text( onText );
 +
off
 +
.addClass( "ui-flipswitch-off" )
 +
.text( offText );
 +
 
 +
flipswitch
 +
.addClass( "ui-flipswitch ui-shadow-inset " +
 +
"ui-bar-" + theme + " " +
 +
( options.wrapperClass ? options.wrapperClass : "" ) + " " +
 +
( ( element.is( ":checked" ) ||
 +
element
 +
.find( "option" )
 +
.eq( 1 )
 +
.is( ":selected" ) ) ? "ui-flipswitch-active" : "" ) +
 +
( element.is(":disabled") ? " ui-state-disabled": "") +
 +
( options.corners ? " ui-corner-all": "" ) +
 +
( options.mini ? " ui-mini": "" ) )
 +
.append( on, off );
 +
 
 +
element
 +
.addClass( "ui-flipswitch-input" )
 +
.after( flipswitch )
 +
.appendTo( flipswitch );
 +
 
 +
$.extend( this, {
 +
flipswitch: flipswitch,
 +
on: on,
 +
off: off,
 +
type: type
 +
});
 +
},
 +
 
 +
_reset: function() {
 +
this.refresh();
 +
},
 +
 
 +
refresh: function() {
 +
var direction,
 +
existingDirection = this.flipswitch.hasClass( "ui-flipswitch-active" ) ? "_right" : "_left";
 +
 
 +
if ( this.type === "SELECT" ) {
 +
direction = ( this.element.get( 0 ).selectedIndex > 0 ) ? "_right": "_left";
 +
} else {
 +
direction = this.element.prop( "checked" ) ? "_right": "_left";
 
}
 
}
  
// window load event
+
if ( direction !== existingDirection ) {
// hide iOS browser chrome on load if hideUrlBar is true this is as fall back incase we were too early before
+
this[ direction ]();
if ( $.mobile.hideUrlBar ) {
+
$window.load( $.mobile.silentScroll );
+
 
}
 
}
 +
},
  
if ( !$.support.cssPointerEvents ) {
+
_toggle: function() {
// IE and Opera don't support CSS pointer-events: none that we use to disable link-based buttons
+
var direction = this.flipswitch.hasClass( "ui-flipswitch-active" ) ? "_left" : "_right";
// by adding the 'ui-disabled' class to them. Using a JavaScript workaround for those browser.
+
// https://github.com/jquery/jquery-mobile/issues/3558
+
  
// DEPRECATED as of 1.4.0 - remove ui-disabled after 1.4.0 release
+
this[ direction ]();
// only ui-state-disabled should be present thereafter
+
},
$.mobile.document.delegate( ".ui-state-disabled,.ui-disabled", "vclick",
+
 
function( e ) {
+
_keydown: function( e ) {
e.preventDefault();
+
if ( e.which === $.mobile.keyCode.LEFT ) {
e.stopImmediatePropagation();
+
this._left();
 +
} else if ( e.which === $.mobile.keyCode.RIGHT ) {
 +
this._right();
 +
} else if ( e.which === $.mobile.keyCode.SPACE ) {
 +
this._toggle();
 +
e.preventDefault();
 +
}
 +
},
 +
 
 +
_setOptions: function( options ) {
 +
if ( options.theme !== undefined ) {
 +
var currentTheme = options.theme ? options.theme : "inherit",
 +
newTheme = options.theme ? options.theme : "inherit";
 +
 
 +
this.widget()
 +
.removeClass( "ui-bar-" + currentTheme )
 +
.addClass( "ui-bar-" + newTheme );
 +
}
 +
if ( options.onText !== undefined ) {
 +
this.on.text( options.onText );
 +
}
 +
if ( options.offText !== undefined ) {
 +
this.off.text( options.offText );
 +
}
 +
if ( options.disabled !== undefined ) {
 +
this.widget().toggleClass( "ui-state-disabled", options.disabled );
 +
}
 +
if ( options.mini !== undefined ) {
 +
this.widget().toggleClass( "ui-mini", options.mini );
 +
}
 +
if ( options.corners !== undefined ) {
 +
this.widget().toggleClass( "ui-corner-all", options.corners );
 +
}
 +
 
 +
this._super( options );
 +
},
 +
 
 +
_destroy: function() {
 +
if ( this.options.enhanced ) {
 +
return;
 +
}
 +
if ( this._originalTabIndex != null ) {
 +
this.element.attr( "tabindex", this._originalTabIndex );
 +
} else {
 +
this.element.removeAttr( "tabindex" );
 +
}
 +
this.on.remove();
 +
this.off.remove();
 +
this.element.unwrap();
 +
this.flipswitch.remove();
 +
this.removeClass( "ui-flipswitch-input" );
 +
}
 +
 
 +
}, $.mobile.behaviors.formReset ) );
 +
 
 +
})( jQuery );
 +
 
 +
(function( $, undefined ) {
 +
 
 +
$.widget( "mobile.slider", $.extend( {
 +
initSelector: "input[type='range'], :jqmData(type='range'), :jqmData(role='slider')",
 +
 
 +
widgetEventPrefix: "slide",
 +
 
 +
options: {
 +
theme: null,
 +
trackTheme: null,
 +
corners: true,
 +
mini: false,
 +
highlight: false
 +
},
 +
 
 +
_create: function() {
 +
 
 +
// TODO: Each of these should have comments explain what they're for
 +
var self = this,
 +
control = this.element,
 +
trackTheme = this.options.trackTheme || $.mobile.getAttribute( control[ 0 ], "theme" ),
 +
trackThemeClass = trackTheme ? " ui-bar-" + trackTheme : " ui-bar-inherit",
 +
cornerClass = ( this.options.corners || control.jqmData( "corners" ) ) ? " ui-corner-all" : "",
 +
miniClass = ( this.options.mini || control.jqmData( "mini" ) ) ? " ui-mini" : "",
 +
cType = control[ 0 ].nodeName.toLowerCase(),
 +
isToggleSwitch = ( cType === "select" ),
 +
isRangeslider = control.parent().is( ":jqmData(role='rangeslider')" ),
 +
selectClass = ( isToggleSwitch ) ? "ui-slider-switch" : "",
 +
controlID = control.attr( "id" ),
 +
$label = $( "[for='" + controlID + "']" ),
 +
labelID = $label.attr( "id" ) || controlID + "-label",
 +
min = !isToggleSwitch ? parseFloat( control.attr( "min" ) ) : 0,
 +
max =  !isToggleSwitch ? parseFloat( control.attr( "max" ) ) : control.find( "option" ).length-1,
 +
step = window.parseFloat( control.attr( "step" ) || 1 ),
 +
domHandle = document.createElement( "a" ),
 +
handle = $( domHandle ),
 +
domSlider = document.createElement( "div" ),
 +
slider = $( domSlider ),
 +
valuebg = this.options.highlight && !isToggleSwitch ? (function() {
 +
var bg = document.createElement( "div" );
 +
bg.className = "ui-slider-bg " + $.mobile.activeBtnClass;
 +
return $( bg ).prependTo( slider );
 +
})() : false,
 +
options,
 +
wrapper,
 +
j, length,
 +
i, optionsCount, origTabIndex,
 +
side, activeClass, sliderImg;
 +
 
 +
$label.attr( "id", labelID );
 +
this.isToggleSwitch = isToggleSwitch;
 +
 
 +
domHandle.setAttribute( "href", "#" );
 +
domSlider.setAttribute( "role", "application" );
 +
domSlider.className = [ this.isToggleSwitch ? "ui-slider ui-slider-track ui-shadow-inset " : "ui-slider-track ui-shadow-inset ", selectClass, trackThemeClass, cornerClass, miniClass ].join( "" );
 +
domHandle.className = "ui-slider-handle";
 +
domSlider.appendChild( domHandle );
 +
 
 +
handle.attr({
 +
"role": "slider",
 +
"aria-valuemin": min,
 +
"aria-valuemax": max,
 +
"aria-valuenow": this._value(),
 +
"aria-valuetext": this._value(),
 +
"title": this._value(),
 +
"aria-labelledby": labelID
 +
});
 +
 
 +
$.extend( this, {
 +
slider: slider,
 +
handle: handle,
 +
control: control,
 +
type: cType,
 +
step: step,
 +
max: max,
 +
min: min,
 +
valuebg: valuebg,
 +
isRangeslider: isRangeslider,
 +
dragging: false,
 +
beforeStart: null,
 +
userModified: false,
 +
mouseMoved: false
 +
});
 +
 
 +
if ( isToggleSwitch ) {
 +
// TODO: restore original tabindex (if any) in a destroy method
 +
origTabIndex = control.attr( "tabindex" );
 +
if ( origTabIndex ) {
 +
handle.attr( "tabindex", origTabIndex );
 +
}
 +
control.attr( "tabindex", "-1" ).focus(function() {
 +
$( this ).blur();
 +
handle.focus();
 +
});
 +
 
 +
wrapper = document.createElement( "div" );
 +
wrapper.className = "ui-slider-inneroffset";
 +
 
 +
for ( j = 0, length = domSlider.childNodes.length; j < length; j++ ) {
 +
wrapper.appendChild( domSlider.childNodes[j] );
 +
}
 +
 
 +
domSlider.appendChild( wrapper );
 +
 
 +
// slider.wrapInner( "<div class='ui-slider-inneroffset'></div>" );
 +
 
 +
// make the handle move with a smooth transition
 +
handle.addClass( "ui-slider-handle-snapping" );
 +
 
 +
options = control.find( "option" );
 +
 
 +
for ( i = 0, optionsCount = options.length; i < optionsCount; i++ ) {
 +
side = !i ? "b" : "a";
 +
activeClass = !i ? "" : " " + $.mobile.activeBtnClass;
 +
sliderImg = document.createElement( "span" );
 +
 
 +
sliderImg.className = [ "ui-slider-label ui-slider-label-", side, activeClass ].join( "" );
 +
sliderImg.setAttribute( "role", "img" );
 +
sliderImg.appendChild( document.createTextNode( options[i].innerHTML ) );
 +
$( sliderImg ).prependTo( slider );
 +
}
 +
 
 +
self._labels = $( ".ui-slider-label", slider );
 +
 
 +
}
 +
 
 +
// monitor the input for updated values
 +
control.addClass( isToggleSwitch ? "ui-slider-switch" : "ui-slider-input" );
 +
 
 +
this._on( control, {
 +
"change": "_controlChange",
 +
"keyup": "_controlKeyup",
 +
"blur": "_controlBlur",
 +
"vmouseup": "_controlVMouseUp"
 +
});
 +
 
 +
slider.bind( "vmousedown", $.proxy( this._sliderVMouseDown, this ) )
 +
.bind( "vclick", false );
 +
 
 +
// We have to instantiate a new function object for the unbind to work properly
 +
// since the method itself is defined in the prototype (causing it to unbind everything)
 +
this._on( document, { "vmousemove": "_preventDocumentDrag" });
 +
this._on( slider.add( document ), { "vmouseup": "_sliderVMouseUp" });
 +
 
 +
slider.insertAfter( control );
 +
 
 +
// wrap in a div for styling purposes
 +
if ( !isToggleSwitch && !isRangeslider ) {
 +
wrapper = this.options.mini ? "<div class='ui-slider ui-mini'>" : "<div class='ui-slider'>";
 +
 
 +
control.add( slider ).wrapAll( wrapper );
 +
}
 +
 
 +
// bind the handle event callbacks and set the context to the widget instance
 +
this._on( this.handle, {
 +
"vmousedown": "_handleVMouseDown",
 +
"keydown": "_handleKeydown",
 +
"keyup": "_handleKeyup"
 +
});
 +
 
 +
this.handle.bind( "vclick", false );
 +
 
 +
this._handleFormReset();
 +
 
 +
this.refresh( undefined, undefined, true );
 +
},
 +
 
 +
_setOptions: function( options ) {
 +
if ( options.theme !== undefined ) {
 +
this._setTheme( options.theme );
 +
}
 +
 
 +
if ( options.trackTheme !== undefined ) {
 +
this._setTrackTheme( options.trackTheme );
 +
}
 +
 
 +
if ( options.corners !== undefined ) {
 +
this._setCorners( options.corners );
 +
}
 +
 
 +
if ( options.mini !== undefined ) {
 +
this._setMini( options.mini );
 +
}
 +
 
 +
if ( options.highlight !== undefined ) {
 +
this._setHighlight( options.highlight );
 +
}
 +
 
 +
if ( options.disabled !== undefined ) {
 +
this._setDisabled( options.disabled );
 +
}
 +
this._super( options );
 +
},
 +
 
 +
_controlChange: function( event ) {
 +
// if the user dragged the handle, the "change" event was triggered from inside refresh(); don't call refresh() again
 +
if ( this._trigger( "controlchange", event ) === false ) {
 +
return false;
 +
}
 +
if ( !this.mouseMoved ) {
 +
this.refresh( this._value(), true );
 +
}
 +
},
 +
 
 +
_controlKeyup: function(/* event */) { // necessary?
 +
this.refresh( this._value(), true, true );
 +
},
 +
 
 +
_controlBlur: function(/* event */) {
 +
this.refresh( this._value(), true );
 +
},
 +
 
 +
// it appears the clicking the up and down buttons in chrome on
 +
// range/number inputs doesn't trigger a change until the field is
 +
// blurred. Here we check thif the value has changed and refresh
 +
_controlVMouseUp: function(/* event */) {
 +
this._checkedRefresh();
 +
},
 +
 
 +
// NOTE force focus on handle
 +
_handleVMouseDown: function(/* event */) {
 +
this.handle.focus();
 +
},
 +
 
 +
_handleKeydown: function( event ) {
 +
var index = this._value();
 +
if ( this.options.disabled ) {
 +
return;
 +
}
 +
 
 +
// In all cases prevent the default and mark the handle as active
 +
switch ( event.keyCode ) {
 +
case $.mobile.keyCode.HOME:
 +
case $.mobile.keyCode.END:
 +
case $.mobile.keyCode.PAGE_UP:
 +
case $.mobile.keyCode.PAGE_DOWN:
 +
case $.mobile.keyCode.UP:
 +
case $.mobile.keyCode.RIGHT:
 +
case $.mobile.keyCode.DOWN:
 +
case $.mobile.keyCode.LEFT:
 +
event.preventDefault();
 +
 
 +
if ( !this._keySliding ) {
 +
this._keySliding = true;
 +
this.handle.addClass( "ui-state-active" ); /* TODO: We don't use this class for styling. Do we need to add it? */
 
}
 
}
);
+
 
 +
break;
 
}
 
}
});
 
}( jQuery, this ));
 
  
 +
// move the slider according to the keypress
 +
switch ( event.keyCode ) {
 +
case $.mobile.keyCode.HOME:
 +
this.refresh( this.min );
 +
break;
 +
case $.mobile.keyCode.END:
 +
this.refresh( this.max );
 +
break;
 +
case $.mobile.keyCode.PAGE_UP:
 +
case $.mobile.keyCode.UP:
 +
case $.mobile.keyCode.RIGHT:
 +
this.refresh( index + this.step );
 +
break;
 +
case $.mobile.keyCode.PAGE_DOWN:
 +
case $.mobile.keyCode.DOWN:
 +
case $.mobile.keyCode.LEFT:
 +
this.refresh( index - this.step );
 +
break;
 +
}
 +
}, // remove active mark
  
}));
+
_handleKeyup: function(/* event */) {
 +
if ( this._keySliding ) {
 +
this._keySliding = false;
 +
this.handle.removeClass( "ui-state-active" ); /* See comment above. */
 +
}
 +
},
  
 +
_sliderVMouseDown: function( event ) {
 +
// NOTE: we don't do this in refresh because we still want to
 +
//      support programmatic alteration of disabled inputs
 +
if ( this.options.disabled || !( event.which === 1 || event.which === 0 || event.which === undefined ) ) {
 +
return false;
 +
}
 +
if ( this._trigger( "beforestart", event ) === false ) {
 +
return false;
 +
}
 +
this.dragging = true;
 +
this.userModified = false;
 +
this.mouseMoved = false;
  
</script>
+
if ( this.isToggleSwitch ) {
 +
this.beforeStart = this.element[0].selectedIndex;
 +
}
  
 +
this.refresh( event );
 +
this._trigger( "start" );
 +
return false;
 +
},
  
 +
_sliderVMouseUp: function() {
 +
if ( this.dragging ) {
 +
this.dragging = false;
 +
 +
if ( this.isToggleSwitch ) {
 +
// make the handle move with a smooth transition
 +
this.handle.addClass( "ui-slider-handle-snapping" );
 +
 +
if ( this.mouseMoved ) {
 +
// this is a drag, change the value only if user dragged enough
 +
if ( this.userModified ) {
 +
this.refresh( this.beforeStart === 0 ? 1 : 0 );
 +
} else {
 +
this.refresh( this.beforeStart );
 +
}
 +
} else {
 +
// this is just a click, change the value
 +
this.refresh( this.beforeStart === 0 ? 1 : 0 );
 +
}
 +
}
 +
 +
this.mouseMoved = false;
 +
this._trigger( "stop" );
 +
return false;
 +
}
 +
},
 +
 +
_preventDocumentDrag: function( event ) {
 +
// NOTE: we don't do this in refresh because we still want to
 +
//      support programmatic alteration of disabled inputs
 +
if ( this._trigger( "drag", event ) === false) {
 +
return false;
 +
}
 +
if ( this.dragging && !this.options.disabled ) {
 +
 +
// this.mouseMoved must be updated before refresh() because it will be used in the control "change" event
 +
this.mouseMoved = true;
 +
 +
if ( this.isToggleSwitch ) {
 +
// make the handle move in sync with the mouse
 +
this.handle.removeClass( "ui-slider-handle-snapping" );
 +
}
 +
 +
this.refresh( event );
 +
 +
// only after refresh() you can calculate this.userModified
 +
this.userModified = this.beforeStart !== this.element[0].selectedIndex;
 +
return false;
 +
}
 +
},
 +
 +
_checkedRefresh: function() {
 +
if ( this.value !== this._value() ) {
 +
this.refresh( this._value() );
 +
}
 +
},
 +
 +
_value: function() {
 +
return  this.isToggleSwitch ? this.element[0].selectedIndex : parseFloat( this.element.val() ) ;
 +
},
 +
 +
_reset: function() {
 +
this.refresh( undefined, false, true );
 +
},
 +
 +
refresh: function( val, isfromControl, preventInputUpdate ) {
 +
// NOTE: we don't return here because we want to support programmatic
 +
//      alteration of the input value, which should still update the slider
 +
 +
var self = this,
 +
parentTheme = $.mobile.getAttribute( this.element[ 0 ], "theme" ),
 +
theme = this.options.theme || parentTheme,
 +
themeClass =  theme ? " ui-btn-" + theme : "",
 +
trackTheme = this.options.trackTheme || parentTheme,
 +
trackThemeClass = trackTheme ? " ui-bar-" + trackTheme : " ui-bar-inherit",
 +
cornerClass = this.options.corners ? " ui-corner-all" : "",
 +
miniClass = this.options.mini ? " ui-mini" : "",
 +
left, width, data, tol,
 +
pxStep, percent,
 +
control, isInput, optionElements, min, max, step,
 +
newval, valModStep, alignValue, percentPerStep,
 +
handlePercent, aPercent, bPercent,
 +
valueChanged;
 +
 +
self.slider[0].className = [ this.isToggleSwitch ? "ui-slider ui-slider-switch ui-slider-track ui-shadow-inset" : "ui-slider-track ui-shadow-inset", trackThemeClass, cornerClass, miniClass ].join( "" );
 +
if ( this.options.disabled || this.element.prop( "disabled" ) ) {
 +
this.disable();
 +
}
 +
 +
// set the stored value for comparison later
 +
this.value = this._value();
 +
if ( this.options.highlight && !this.isToggleSwitch && this.slider.find( ".ui-slider-bg" ).length === 0 ) {
 +
this.valuebg = (function() {
 +
var bg = document.createElement( "div" );
 +
bg.className = "ui-slider-bg " + $.mobile.activeBtnClass;
 +
return $( bg ).prependTo( self.slider );
 +
})();
 +
}
 +
this.handle.addClass( "ui-btn" + themeClass + " ui-shadow" );
 +
 +
control = this.element;
 +
isInput = !this.isToggleSwitch;
 +
optionElements = isInput ? [] : control.find( "option" );
 +
min =  isInput ? parseFloat( control.attr( "min" ) ) : 0;
 +
max = isInput ? parseFloat( control.attr( "max" ) ) : optionElements.length - 1;
 +
step = ( isInput && parseFloat( control.attr( "step" ) ) > 0 ) ? parseFloat( control.attr( "step" ) ) : 1;
 +
 +
if ( typeof val === "object" ) {
 +
data = val;
 +
// a slight tolerance helped get to the ends of the slider
 +
tol = 8;
 +
 +
left = this.slider.offset().left;
 +
width = this.slider.width();
 +
pxStep = width/((max-min)/step);
 +
if ( !this.dragging ||
 +
data.pageX < left - tol ||
 +
data.pageX > left + width + tol ) {
 +
return;
 +
}
 +
if ( pxStep > 1 ) {
 +
percent = ( ( data.pageX - left ) / width ) * 100;
 +
} else {
 +
percent = Math.round( ( ( data.pageX - left ) / width ) * 100 );
 +
}
 +
} else {
 +
if ( val == null ) {
 +
val = isInput ? parseFloat( control.val() || 0 ) : control[0].selectedIndex;
 +
}
 +
percent = ( parseFloat( val ) - min ) / ( max - min ) * 100;
 +
}
 +
 +
if ( isNaN( percent ) ) {
 +
return;
 +
}
 +
 +
newval = ( percent / 100 ) * ( max - min ) + min;
 +
 +
//from jQuery UI slider, the following source will round to the nearest step
 +
valModStep = ( newval - min ) % step;
 +
alignValue = newval - valModStep;
 +
 +
if ( Math.abs( valModStep ) * 2 >= step ) {
 +
alignValue += ( valModStep > 0 ) ? step : ( -step );
 +
}
 +
 +
percentPerStep = 100/((max-min)/step);
 +
// Since JavaScript has problems with large floats, round
 +
// the final value to 5 digits after the decimal point (see jQueryUI: #4124)
 +
newval = parseFloat( alignValue.toFixed(5) );
 +
 +
if ( typeof pxStep === "undefined" ) {
 +
pxStep = width / ( (max-min) / step );
 +
}
 +
if ( pxStep > 1 && isInput ) {
 +
percent = ( newval - min ) * percentPerStep * ( 1 / step );
 +
}
 +
if ( percent < 0 ) {
 +
percent = 0;
 +
}
 +
 +
if ( percent > 100 ) {
 +
percent = 100;
 +
}
 +
 +
if ( newval < min ) {
 +
newval = min;
 +
}
 +
 +
if ( newval > max ) {
 +
newval = max;
 +
}
 +
 +
this.handle.css( "left", percent + "%" );
 +
 +
this.handle[0].setAttribute( "aria-valuenow", isInput ? newval : optionElements.eq( newval ).attr( "value" ) );
 +
 +
this.handle[0].setAttribute( "aria-valuetext", isInput ? newval : optionElements.eq( newval ).getEncodedText() );
 +
 +
this.handle[0].setAttribute( "title", isInput ? newval : optionElements.eq( newval ).getEncodedText() );
 +
 +
if ( this.valuebg ) {
 +
this.valuebg.css( "width", percent + "%" );
 +
}
 +
 +
// drag the label widths
 +
if ( this._labels ) {
 +
handlePercent = this.handle.width() / this.slider.width() * 100;
 +
aPercent = percent && handlePercent + ( 100 - handlePercent ) * percent / 100;
 +
bPercent = percent === 100 ? 0 : Math.min( handlePercent + 100 - aPercent, 100 );
 +
 +
this._labels.each(function() {
 +
var ab = $( this ).hasClass( "ui-slider-label-a" );
 +
$( this ).width( ( ab ? aPercent : bPercent  ) + "%" );
 +
});
 +
}
 +
 +
if ( !preventInputUpdate ) {
 +
valueChanged = false;
 +
 +
// update control"s value
 +
if ( isInput ) {
 +
valueChanged = parseFloat( control.val() ) !== newval;
 +
control.val( newval );
 +
} else {
 +
valueChanged = control[ 0 ].selectedIndex !== newval;
 +
control[ 0 ].selectedIndex = newval;
 +
}
 +
if ( this._trigger( "beforechange", val ) === false) {
 +
return false;
 +
}
 +
if ( !isfromControl && valueChanged ) {
 +
control.trigger( "change" );
 +
}
 +
}
 +
},
 +
 +
_setHighlight: function( value ) {
 +
value = !!value;
 +
if ( value ) {
 +
this.options.highlight = !!value;
 +
this.refresh();
 +
} else if ( this.valuebg ) {
 +
this.valuebg.remove();
 +
this.valuebg = false;
 +
}
 +
},
 +
 +
_setTheme: function( value ) {
 +
this.handle
 +
.removeClass( "ui-btn-" + this.options.theme )
 +
.addClass( "ui-btn-" + value );
 +
 +
var currentTheme = this.options.theme ? this.options.theme : "inherit",
 +
newTheme = value ? value : "inherit";
 +
 +
this.control
 +
.removeClass( "ui-body-" + currentTheme )
 +
.addClass( "ui-body-" + newTheme );
 +
},
 +
 +
_setTrackTheme: function( value ) {
 +
var currentTrackTheme = this.options.trackTheme ? this.options.trackTheme : "inherit",
 +
newTrackTheme = value ? value : "inherit";
 +
 +
this.slider
 +
.removeClass( "ui-body-" + currentTrackTheme )
 +
.addClass( "ui-body-" + newTrackTheme );
 +
},
 +
 +
_setMini: function( value ) {
 +
value = !!value;
 +
if ( !this.isToggleSwitch && !this.isRangeslider ) {
 +
this.slider.parent().toggleClass( "ui-mini", value );
 +
this.element.toggleClass( "ui-mini", value );
 +
}
 +
this.slider.toggleClass( "ui-mini", value );
 +
},
 +
 +
_setCorners: function( value ) {
 +
this.slider.toggleClass( "ui-corner-all", value );
 +
 +
if ( !this.isToggleSwitch ) {
 +
this.control.toggleClass( "ui-corner-all", value );
 +
}
 +
},
 +
 +
_setDisabled: function( value ) {
 +
value = !!value;
 +
this.element.prop( "disabled", value );
 +
this.slider
 +
.toggleClass( "ui-state-disabled", value )
 +
.attr( "aria-disabled", value );
 +
 +
this.element.toggleClass( "ui-state-disabled", value );
 +
}
 +
 +
}, $.mobile.behaviors.formReset ) );
 +
 +
})( jQuery );
 +
 +
(function( $, undefined ) {
 +
$.widget( "mobile.rangeslider", $.extend( {
 +
 +
options: {
 +
theme: null,
 +
trackTheme: null,
 +
corners: true,
 +
mini: false,
 +
highlight: true
 +
},
 +
 +
_create: function() {
 +
var $el = this.element,
 +
elClass = this.options.mini ? "ui-rangeslider ui-mini" : "ui-rangeslider",
 +
_inputFirst = $el.find( "input" ).first(),
 +
_inputLast = $el.find( "input" ).last(),
 +
_label = $el.find( "label" ).first(),
 +
_sliderWidgetFirst = $.data( _inputFirst.get( 0 ), "mobile-slider" ) ||
 +
$.data( _inputFirst.slider().get( 0 ), "mobile-slider" ),
 +
_sliderWidgetLast = $.data( _inputLast.get(0), "mobile-slider" ) ||
 +
$.data( _inputLast.slider().get( 0 ), "mobile-slider" ),
 +
_sliderFirst = _sliderWidgetFirst.slider,
 +
_sliderLast = _sliderWidgetLast.slider,
 +
firstHandle = _sliderWidgetFirst.handle,
 +
_sliders = $( "<div class='ui-rangeslider-sliders' />" ).appendTo( $el );
 +
 +
_inputFirst.addClass( "ui-rangeslider-first" );
 +
_inputLast.addClass( "ui-rangeslider-last" );
 +
$el.addClass( elClass );
 +
 +
_sliderFirst.appendTo( _sliders );
 +
_sliderLast.appendTo( _sliders );
 +
_label.insertBefore( $el );
 +
firstHandle.prependTo( _sliderLast );
 +
 +
$.extend( this, {
 +
_inputFirst: _inputFirst,
 +
_inputLast: _inputLast,
 +
_sliderFirst: _sliderFirst,
 +
_sliderLast: _sliderLast,
 +
_label: _label,
 +
_targetVal: null,
 +
_sliderTarget: false,
 +
_sliders: _sliders,
 +
_proxy: false
 +
});
 +
 +
this.refresh();
 +
this._on( this.element.find( "input.ui-slider-input" ), {
 +
"slidebeforestart": "_slidebeforestart",
 +
"slidestop": "_slidestop",
 +
"slidedrag": "_slidedrag",
 +
"slidebeforechange": "_change",
 +
"blur": "_change",
 +
"keyup": "_change"
 +
});
 +
this._on({
 +
"mousedown":"_change"
 +
});
 +
this._on( this.element.closest( "form" ), {
 +
"reset":"_handleReset"
 +
});
 +
this._on( firstHandle, {
 +
"vmousedown": "_dragFirstHandle"
 +
});
 +
},
 +
_handleReset: function() {
 +
var self = this;
 +
//we must wait for the stack to unwind before updateing other wise sliders will not have updated yet
 +
setTimeout( function() {
 +
self._updateHighlight();
 +
},0);
 +
},
 +
 +
_dragFirstHandle: function( event ) {
 +
//if the first handle is dragged send the event to the first slider
 +
$.data( this._inputFirst.get(0), "mobile-slider" ).dragging = true;
 +
$.data( this._inputFirst.get(0), "mobile-slider" ).refresh( event );
 +
$.data( this._inputFirst.get(0), "mobile-slider" )._trigger( "start" );
 +
return false;
 +
},
 +
 +
_slidedrag: function( event ) {
 +
var first = $( event.target ).is( this._inputFirst ),
 +
otherSlider = ( first ) ? this._inputLast : this._inputFirst;
 +
 +
this._sliderTarget = false;
 +
//if the drag was initiated on an extreme and the other handle is focused send the events to
 +
//the closest handle
 +
if ( ( this._proxy === "first" && first ) || ( this._proxy === "last" && !first ) ) {
 +
$.data( otherSlider.get(0), "mobile-slider" ).dragging = true;
 +
$.data( otherSlider.get(0), "mobile-slider" ).refresh( event );
 +
return false;
 +
}
 +
},
 +
 +
_slidestop: function( event ) {
 +
var first = $( event.target ).is( this._inputFirst );
 +
 +
this._proxy = false;
 +
//this stops dragging of the handle and brings the active track to the front
 +
//this makes clicks on the track go the the last handle used
 +
this.element.find( "input" ).trigger( "vmouseup" );
 +
this._sliderFirst.css( "z-index", first ? 1 : "" );
 +
},
 +
 +
_slidebeforestart: function( event ) {
 +
this._sliderTarget = false;
 +
//if the track is the target remember this and the original value
 +
if ( $( event.originalEvent.target ).hasClass( "ui-slider-track" ) ) {
 +
this._sliderTarget = true;
 +
this._targetVal = $( event.target ).val();
 +
}
 +
},
 +
 +
_setOptions: function( options ) {
 +
if ( options.theme !== undefined ) {
 +
this._setTheme( options.theme );
 +
}
 +
 +
if ( options.trackTheme !== undefined ) {
 +
this._setTrackTheme( options.trackTheme );
 +
}
 +
 +
if ( options.mini !== undefined ) {
 +
this._setMini( options.mini );
 +
}
 +
 +
if ( options.highlight !== undefined ) {
 +
this._setHighlight( options.highlight );
 +
}
 +
 +
if ( options.disabled !== undefined ) {
 +
this._setDisabled( options.disabled );
 +
}
 +
 +
this._super( options );
 +
this.refresh();
 +
},
 +
 +
refresh: function() {
 +
var $el = this.element,
 +
o = this.options;
 +
 +
if ( this._inputFirst.is( ":disabled" ) || this._inputLast.is( ":disabled" ) ) {
 +
this.options.disabled = true;
 +
}
 +
 +
$el.find( "input" ).slider({
 +
theme: o.theme,
 +
trackTheme: o.trackTheme,
 +
disabled: o.disabled,
 +
corners: o.corners,
 +
mini: o.mini,
 +
highlight: o.highlight
 +
}).slider( "refresh" );
 +
this._updateHighlight();
 +
},
 +
 +
_change: function( event ) {
 +
if ( event.type === "keyup" ) {
 +
this._updateHighlight();
 +
return false;
 +
}
 +
 +
var self = this,
 +
min = parseFloat( this._inputFirst.val(), 10 ),
 +
max = parseFloat( this._inputLast.val(), 10 ),
 +
first = $( event.target ).hasClass( "ui-rangeslider-first" ),
 +
thisSlider = first ? this._inputFirst : this._inputLast,
 +
otherSlider = first ? this._inputLast : this._inputFirst;
 +
 +
if ( ( this._inputFirst.val() > this._inputLast.val() && event.type === "mousedown" && !$(event.target).hasClass("ui-slider-handle")) ) {
 +
thisSlider.blur();
 +
} else if ( event.type === "mousedown" ) {
 +
return;
 +
}
 +
if ( min > max && !this._sliderTarget ) {
 +
//this prevents min from being greater then max
 +
thisSlider.val( first ? max: min ).slider( "refresh" );
 +
this._trigger( "normalize" );
 +
} else if ( min > max ) {
 +
//this makes it so clicks on the target on either extreme go to the closest handle
 +
thisSlider.val( this._targetVal ).slider( "refresh" );
 +
 +
//You must wait for the stack to unwind so first slider is updated before updating second
 +
setTimeout( function() {
 +
otherSlider.val( first ? min: max ).slider( "refresh" );
 +
$.data( otherSlider.get(0), "mobile-slider" ).handle.focus();
 +
self._sliderFirst.css( "z-index", first ? "" : 1 );
 +
self._trigger( "normalize" );
 +
}, 0 );
 +
this._proxy = ( first ) ? "first" : "last";
 +
}
 +
//fixes issue where when both _sliders are at min they cannot be adjusted
 +
if ( min === max ) {
 +
$.data( thisSlider.get(0), "mobile-slider" ).handle.css( "z-index", 1 );
 +
$.data( otherSlider.get(0), "mobile-slider" ).handle.css( "z-index", 0 );
 +
} else {
 +
$.data( otherSlider.get(0), "mobile-slider" ).handle.css( "z-index", "" );
 +
$.data( thisSlider.get(0), "mobile-slider" ).handle.css( "z-index", "" );
 +
}
 +
 +
this._updateHighlight();
 +
 +
if ( min >= max ) {
 +
return false;
 +
}
 +
},
 +
 +
_updateHighlight: function() {
 +
var min = parseInt( $.data( this._inputFirst.get(0), "mobile-slider" ).handle.get(0).style.left, 10 ),
 +
max = parseInt( $.data( this._inputLast.get(0), "mobile-slider" ).handle.get(0).style.left, 10 ),
 +
width = (max - min);
 +
 +
this.element.find( ".ui-slider-bg" ).css({
 +
"margin-left": min + "%",
 +
"width": width + "%"
 +
});
 +
},
 +
 +
_setTheme: function( value ) {
 +
this._inputFirst.slider( "option", "theme", value );
 +
this._inputLast.slider( "option", "theme", value );
 +
},
 +
 +
_setTrackTheme: function( value ) {
 +
this._inputFirst.slider( "option", "trackTheme", value );
 +
this._inputLast.slider( "option", "trackTheme", value );
 +
},
 +
 +
_setMini: function( value ) {
 +
this._inputFirst.slider( "option", "mini", value );
 +
this._inputLast.slider( "option", "mini", value );
 +
this.element.toggleClass( "ui-mini", !!value );
 +
},
 +
 +
_setHighlight: function( value ) {
 +
this._inputFirst.slider( "option", "highlight", value );
 +
this._inputLast.slider( "option", "highlight", value );
 +
},
 +
 +
_setDisabled: function( value ) {
 +
this._inputFirst.prop( "disabled", value );
 +
this._inputLast.prop( "disabled", value );
 +
},
 +
 +
_destroy: function() {
 +
this._label.prependTo( this.element );
 +
this.element.removeClass( "ui-rangeslider ui-mini" );
 +
this._inputFirst.after( this._sliderFirst );
 +
this._inputLast.after( this._sliderLast );
 +
this._sliders.remove();
 +
this.element.find( "input" ).removeClass( "ui-rangeslider-first ui-rangeslider-last" ).slider( "destroy" );
 +
}
 +
 +
}, $.mobile.behaviors.formReset ) );
 +
 +
})( jQuery );
 +
 +
(function( $, undefined ) {
 +
 +
$.widget( "mobile.selectmenu", $.extend( {
 +
initSelector: "select:not( :jqmData(role='slider')):not( :jqmData(role='flipswitch') )",
 +
 +
options: {
 +
theme: null,
 +
icon: "carat-d",
 +
iconpos: "right",
 +
inline: false,
 +
corners: true,
 +
shadow: true,
 +
iconshadow: false, /* TODO: Deprecated in 1.4, remove in 1.5. */
 +
overlayTheme: null,
 +
dividerTheme: null,
 +
hidePlaceholderMenuItems: true,
 +
closeText: "Close",
 +
nativeMenu: true,
 +
// This option defaults to true on iOS devices.
 +
preventFocusZoom: /iPhone|iPad|iPod/.test( navigator.platform ) && navigator.userAgent.indexOf( "AppleWebKit" ) > -1,
 +
mini: false
 +
},
 +
 +
_button: function() {
 +
return $( "<div/>" );
 +
},
 +
 +
_setDisabled: function( value ) {
 +
this.element.attr( "disabled", value );
 +
this.button.attr( "aria-disabled", value );
 +
return this._setOption( "disabled", value );
 +
},
 +
 +
_focusButton : function() {
 +
var self = this;
 +
 +
setTimeout( function() {
 +
self.button.focus();
 +
}, 40);
 +
},
 +
 +
_selectOptions: function() {
 +
return this.select.find( "option" );
 +
},
 +
 +
// setup items that are generally necessary for select menu extension
 +
_preExtension: function() {
 +
var inline = this.options.inline || this.element.jqmData( "inline" ),
 +
mini = this.options.mini || this.element.jqmData( "mini" ),
 +
classes = "";
 +
// 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 ( !!~this.element[0].className.indexOf( "ui-btn-left" ) ) {
 +
classes = " ui-btn-left";
 +
}
 +
 +
if (  !!~this.element[0].className.indexOf( "ui-btn-right" ) ) {
 +
classes = " ui-btn-right";
 +
}
 +
 +
if ( inline ) {
 +
classes += " ui-btn-inline";
 +
}
 +
if ( mini ) {
 +
classes += " ui-mini";
 +
}
 +
 +
this.select = this.element.removeClass( "ui-btn-left ui-btn-right" ).wrap( "<div class='ui-select" + classes + "'>" );
 +
this.selectId  = this.select.attr( "id" ) || ( "select-" + this.uuid );
 +
this.buttonId = this.selectId + "-button";
 +
this.label = $( "label[for='"+ this.selectId +"']" );
 +
this.isMultiple = this.select[ 0 ].multiple;
 +
},
 +
 +
_destroy: function() {
 +
var wrapper = this.element.parents( ".ui-select" );
 +
if ( wrapper.length > 0 ) {
 +
if ( wrapper.is( ".ui-btn-left, .ui-btn-right" ) ) {
 +
this.element.addClass( wrapper.hasClass( "ui-btn-left" ) ? "ui-btn-left" : "ui-btn-right" );
 +
}
 +
this.element.insertAfter( wrapper );
 +
wrapper.remove();
 +
}
 +
},
 +
 +
_create: function() {
 +
this._preExtension();
 +
 +
this.button = this._button();
 +
 +
var self = this,
 +
 +
options = this.options,
 +
 +
iconpos = options.icon ? ( options.iconpos || this.select.jqmData( "iconpos" ) ) : false,
 +
 +
button = this.button
 +
.insertBefore( this.select )
 +
.attr( "id", this.buttonId )
 +
.addClass( "ui-btn" +
 +
( options.icon ? ( " ui-icon-" + options.icon + " ui-btn-icon-" + iconpos +
 +
( options.iconshadow ? " ui-shadow-icon" : "" ) ) : "" ) + /* TODO: Remove in 1.5. */
 +
( options.theme ? " ui-btn-" + options.theme : "" ) +
 +
( options.corners ? " ui-corner-all" : "" ) +
 +
( options.shadow ? " ui-shadow" : "" ) );
 +
 +
this.setButtonText();
 +
 +
// Opera does not properly support opacity on select elements
 +
// In Mini, it hides the element, but not its text
 +
// On the desktop,it seems to do the opposite
 +
// for these reasons, using the nativeMenu option results in a full native select in Opera
 +
if ( options.nativeMenu && window.opera && window.opera.version ) {
 +
button.addClass( "ui-select-nativeonly" );
 +
}
 +
 +
// Add counter for multi selects
 +
if ( this.isMultiple ) {
 +
this.buttonCount = $( "<span>" )
 +
.addClass( "ui-li-count ui-body-inherit" )
 +
.hide()
 +
.appendTo( button.addClass( "ui-li-has-count" ) );
 +
}
 +
 +
// Disable if specified
 +
if ( options.disabled || this.element.attr( "disabled" )) {
 +
this.disable();
 +
}
 +
 +
// Events on native select
 +
this.select.change(function() {
 +
self.refresh();
 +
 +
if ( !!options.nativeMenu ) {
 +
self._delay( function() {
 +
self.select.blur();
 +
});
 +
}
 +
});
 +
 +
this._handleFormReset();
 +
 +
this._on( this.button, {
 +
keydown: "_handleKeydown"
 +
});
 +
 +
this.build();
 +
},
 +
 +
build: function() {
 +
var self = this;
 +
 +
this.select
 +
.appendTo( self.button )
 +
.bind( "vmousedown", function() {
 +
// Add active class to button
 +
self.button.addClass( $.mobile.activeBtnClass );
 +
})
 +
.bind( "focus", function() {
 +
self.button.addClass( $.mobile.focusClass );
 +
})
 +
.bind( "blur", function() {
 +
self.button.removeClass( $.mobile.focusClass );
 +
})
 +
.bind( "focus vmouseover", function() {
 +
self.button.trigger( "vmouseover" );
 +
})
 +
.bind( "vmousemove", function() {
 +
// Remove active class on scroll/touchmove
 +
self.button.removeClass( $.mobile.activeBtnClass );
 +
})
 +
.bind( "change blur vmouseout", function() {
 +
self.button.trigger( "vmouseout" )
 +
.removeClass( $.mobile.activeBtnClass );
 +
});
 +
 +
// In many situations, iOS will zoom into the select upon tap, this prevents that from happening
 +
self.button.bind( "vmousedown", function() {
 +
if ( self.options.preventFocusZoom ) {
 +
$.mobile.zoom.disable( true );
 +
}
 +
});
 +
self.label.bind( "click focus", function() {
 +
if ( self.options.preventFocusZoom ) {
 +
$.mobile.zoom.disable( true );
 +
}
 +
});
 +
self.select.bind( "focus", function() {
 +
if ( self.options.preventFocusZoom ) {
 +
$.mobile.zoom.disable( true );
 +
}
 +
});
 +
self.button.bind( "mouseup", function() {
 +
if ( self.options.preventFocusZoom ) {
 +
setTimeout(function() {
 +
$.mobile.zoom.enable( true );
 +
}, 0 );
 +
}
 +
});
 +
self.select.bind( "blur", function() {
 +
if ( self.options.preventFocusZoom ) {
 +
$.mobile.zoom.enable( true );
 +
}
 +
});
 +
 +
},
 +
 +
selected: function() {
 +
return this._selectOptions().filter( ":selected" );
 +
},
 +
 +
selectedIndices: function() {
 +
var self = this;
 +
 +
return this.selected().map(function() {
 +
return self._selectOptions().index( this );
 +
}).get();
 +
},
 +
 +
setButtonText: function() {
 +
var self = this,
 +
selected = this.selected(),
 +
text = this.placeholder,
 +
span = $( document.createElement( "span" ) );
 +
 +
this.button.children( "span" ).not( ".ui-li-count" ).remove().end().end().prepend( (function() {
 +
if ( selected.length ) {
 +
text = selected.map(function() {
 +
return $( this ).text();
 +
}).get().join( ", " );
 +
} else {
 +
text = self.placeholder;
 +
}
 +
 +
if ( text ) {
 +
span.text( text );
 +
} else {
 +
 +
// Set the contents to &nbsp; which we write as &#160; to be XHTML compliant - see gh-6699
 +
span.html( "&#160;" );
 +
}
 +
 +
// TODO possibly aggregate multiple select option classes
 +
return span
 +
.addClass( self.select.attr( "class" ) )
 +
.addClass( selected.attr( "class" ) )
 +
.removeClass( "ui-screen-hidden" );
 +
})());
 +
},
 +
 +
setButtonCount: function() {
 +
var selected = this.selected();
 +
 +
// multiple count inside button
 +
if ( this.isMultiple ) {
 +
this.buttonCount[ selected.length > 1 ? "show" : "hide" ]().text( selected.length );
 +
}
 +
},
 +
 +
_handleKeydown: function( /* event */ ) {
 +
this._delay( "_refreshButton" );
 +
},
 +
 +
_reset: function() {
 +
this.refresh();
 +
},
 +
 +
_refreshButton: function() {
 +
this.setButtonText();
 +
this.setButtonCount();
 +
},
 +
 +
refresh: function() {
 +
this._refreshButton();
 +
},
 +
 +
// open and close preserved in native selects
 +
// to simplify users code when looping over selects
 +
open: $.noop,
 +
close: $.noop,
 +
 +
disable: function() {
 +
this._setDisabled( true );
 +
this.button.addClass( "ui-state-disabled" );
 +
},
 +
 +
enable: function() {
 +
this._setDisabled( false );
 +
this.button.removeClass( "ui-state-disabled" );
 +
}
 +
}, $.mobile.behaviors.formReset ) );
 +
 +
})( jQuery );
 +
 +
(function( $, undefined ) {
 +
 +
var popup;
 +
 +
function getPopup() {
 +
if ( !popup ) {
 +
popup = $( "<div></div>", {
 +
"class": "ui-slider-popup ui-shadow ui-corner-all"
 +
});
 +
}
 +
return popup.clone();
 +
}
 +
 +
$.widget( "mobile.slider", $.mobile.slider, {
 +
options: {
 +
popupEnabled: false,
 +
showValue: false
 +
},
 +
 +
_create: function() {
 +
this._super();
 +
 +
$.extend( this, {
 +
_currentValue: null,
 +
_popup: null,
 +
_popupVisible: false
 +
});
 +
 +
this._setOption( "popupEnabled", this.options.popupEnabled );
 +
 +
this._on( this.handle, { "vmousedown" : "_showPopup" } );
 +
this._on( this.slider.add( this.document ), { "vmouseup" : "_hidePopup" } );
 +
this._refresh();
 +
},
 +
 +
// position the popup centered 5px above the handle
 +
_positionPopup: function() {
 +
var dstOffset = this.handle.offset();
 +
 +
this._popup.offset( {
 +
left: dstOffset.left + ( this.handle.width() - this._popup.width() ) / 2,
 +
top: dstOffset.top - this._popup.outerHeight() - 5
 +
});
 +
},
 +
 +
_setOption: function( key, value ) {
 +
this._super( key, value );
 +
 +
if ( key === "showValue" ) {
 +
this.handle.html( value && !this.options.mini ? this._value() : "" );
 +
} else if ( key === "popupEnabled" ) {
 +
if ( value && !this._popup ) {
 +
this._popup = getPopup()
 +
.addClass( "ui-body-" + ( this.options.theme || "a" ) )
 +
.hide()
 +
.insertBefore( this.element );
 +
}
 +
}
 +
},
 +
 +
// show value on the handle and in popup
 +
refresh: function() {
 +
this._super.apply( this, arguments );
 +
this._refresh();
 +
},
 +
 +
_refresh: function() {
 +
var o = this.options, newValue;
 +
 +
if ( o.popupEnabled ) {
 +
// remove the title attribute from the handle (which is
 +
// responsible for the annoying tooltip); NB we have
 +
// to do it here as the jqm slider sets it every time
 +
// the slider's value changes :(
 +
this.handle.removeAttr( "title" );
 +
}
 +
 +
newValue = this._value();
 +
if ( newValue === this._currentValue ) {
 +
return;
 +
}
 +
this._currentValue = newValue;
 +
 +
if ( o.popupEnabled && this._popup ) {
 +
this._positionPopup();
 +
this._popup.html( newValue );
 +
}
 +
 +
if ( o.showValue && !this.options.mini ) {
 +
this.handle.html( newValue );
 +
}
 +
},
 +
 +
_showPopup: function() {
 +
if ( this.options.popupEnabled && !this._popupVisible ) {
 +
this.handle.html( "" );
 +
this._popup.show();
 +
this._positionPopup();
 +
this._popupVisible = true;
 +
}
 +
},
 +
 +
_hidePopup: function() {
 +
var o = this.options;
 +
 +
if ( o.popupEnabled && this._popupVisible ) {
 +
if ( o.showValue && !o.mini ) {
 +
this.handle.html( this._value() );
 +
}
 +
this._popup.hide();
 +
this._popupVisible = false;
 +
}
 +
}
 +
});
 +
 +
})( jQuery );
 +
 +
 +
}));
 +
 +
 +
 +
 +
 +
 +
</script>
  
  

Revision as of 07:23, 6 May 2017