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 ); | ||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
Line 6,281: | Line 6,624: | ||
})( jQuery ); | })( jQuery ); | ||
+ | (function( $, undefined ) { | ||
+ | |||
+ | $.mobile.nojs = function( target ) { | ||
+ | $( ":jqmData(role='nojs')", target ).addClass( "ui-nojs" ); | ||
+ | }; | ||
+ | |||
+ | })( jQuery ); | ||
(function( $ ) { | (function( $ ) { | ||
− | + | var meta = $( "meta[name=viewport]" ), | |
− | var | + | 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. | + | $.mobile.zoom = $.extend( {}, { |
− | // | + | 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: { | ||
− | + | autogrow:true, | |
− | + | keyupTimeoutBuffer: 100 | |
+ | }, | ||
− | + | _create: function() { | |
− | + | this._super(); | |
− | + | if ( this.options.autogrow && this.isTextarea ) { | |
− | + | this._autogrow(); | |
+ | } | ||
+ | }, | ||
− | // | + | _autogrow: function() { |
− | + | 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" | ||
+ | }); | ||
}, | }, | ||
− | + | // Synchronously fix the widget height if this widget's parents are such | |
− | + | // that they show/hide content at runtime. We still need to check whether | |
− | + | // the widget is actually visible in case it is contained inside multiple | |
− | " | + | // 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" ) ) { | ||
− | + | if ( event.type !== "popupbeforeposition" ) { | |
− | + | this.element | |
− | + | .addClass( "ui-textinput-autogrow-resize" ) | |
+ | .animationComplete( | ||
+ | $.proxy( function() { | ||
+ | this.element.removeClass( "ui-textinput-autogrow-resize" ); | ||
+ | }, this ), | ||
+ | "transition" ); | ||
+ | } | ||
+ | this._prepareHeightUpdate(); | ||
+ | } | ||
+ | }, | ||
− | this.element | + | _unbindAutogrow: function() { |
− | + | this.element.removeClass( "ui-textinput-autogrow" ); | |
− | + | this._off( this.element, "keyup change input paste" ); | |
− | + | this._off( this.document, | |
− | + | "pageshow popupbeforeposition updatelayout panelopen" ); | |
}, | }, | ||
− | + | keyupTimeout: null, | |
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | if ( | + | _prepareHeightUpdate: function( delay ) { |
− | this. | + | if ( this.keyupTimeout ) { |
− | this. | + | clearTimeout( this.keyupTimeout ); |
− | this. | + | } |
− | + | if ( delay === undefined ) { | |
− | + | this._updateHeight(); | |
+ | } else { | ||
+ | this.keyupTimeout = this._delay( "_updateHeight", delay ); | ||
} | } | ||
}, | }, | ||
− | + | _timeout: function() { | |
− | this. | + | this._prepareHeightUpdate( this.options.keyupTimeoutBuffer ); |
}, | }, | ||
− | + | _updateHeight: function() { | |
− | + | var paddingTop, paddingBottom, paddingHeight, scrollHeight, clientHeight, | |
− | + | borderTop, borderBottom, borderHeight, height, | |
− | + | scrollTop = this.window.scrollTop(); | |
− | + | this.keyupTimeout = 0; | |
− | + | ||
− | this. | + | // 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 | ||
+ | }); | ||
+ | } | ||
− | + | scrollHeight = this.element[ 0 ].scrollHeight; | |
− | + | clientHeight = this.element[ 0 ].clientHeight; | |
− | + | borderTop = parseFloat( this.element.css( "border-top-width" ) ); | |
− | + | borderBottom = parseFloat( this.element.css( "border-bottom-width" ) ); | |
+ | borderHeight = borderTop + borderBottom; | ||
+ | height = scrollHeight + borderHeight + 15; | ||
− | + | // Issue 6179: Padding is not included in scrollHeight and | |
− | + | // clientHeight by Firefox if no scrollbar is visible. Because | |
− | + | // 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; | ||
− | + | height += paddingHeight; | |
− | + | ||
− | + | ||
− | + | ||
} | } | ||
− | + | this.element.css({ | |
− | + | "height": height, | |
− | + | "min-height": "", | |
+ | "max-height": "" | ||
+ | }); | ||
− | + | this.window.scrollTop( scrollTop ); | |
− | + | }, | |
− | + | refresh: function() { | |
+ | if ( this.options.autogrow && this.isTextarea ) { | ||
+ | this._updateHeight(); | ||
+ | } | ||
+ | }, | ||
− | + | _setOptions: function( options ) { | |
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | this._super( options ); | |
− | + | ||
− | + | if ( options.autogrow !== undefined && this.isTextarea ) { | |
− | + | if ( options.autogrow ) { | |
− | + | this._autogrow(); | |
− | + | } else { | |
− | + | this._unbindAutogrow(); | |
− | + | } | |
} | } | ||
+ | } | ||
− | + | }); | |
− | + | })( jQuery ); | |
− | + | ||
− | + | ||
− | + | ||
− | + | (function( $, undefined ) { | |
− | + | ||
− | + | $.widget( "mobile.button", { | |
− | + | ||
− | + | ||
− | + | initSelector: "input[type='button'], input[type='submit'], input[type='reset']", | |
− | + | ||
+ | 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 ); | ||
+ | }, | ||
− | + | blur: function() { | |
− | this. | + | 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. | + | if ( options.theme !== undefined ) { |
− | + | 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 ); | ||
} | } | ||
− | |||
− | + | 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 ); | ||
+ | }, | ||
− | + | refresh: function( create ) { | |
− | + | var originalElement, | |
− | + | isDisabled = this.element.prop( "disabled" ); | |
− | + | if ( this.options.icon && this.options.iconpos === "notext" && this.element.attr( "title" ) ) { | |
− | + | this.element.attr( "title", this.element.val() ); | |
− | $ | + | } |
+ | if ( !create ) { | ||
+ | originalElement = this.element.detach(); | ||
+ | $( this.wrapper ).text( this.element.val() ).append( originalElement ); | ||
+ | } | ||
+ | if ( this.options.disabled !== isDisabled ) { | ||
+ | this._setOptions({ disabled: isDisabled }); | ||
+ | } | ||
} | } | ||
+ | }); | ||
− | + | })( jQuery ); | |
− | + | ||
− | + | (function( $, undefined ) { | |
− | + | ||
− | + | $.mobile.behaviors.formReset = { | |
− | + | _handleFormReset: function() { | |
− | + | this._on( this.element.closest( "form" ), { | |
+ | reset: function() { | ||
+ | this._delay( "_reset" ); | ||
+ | } | ||
+ | }); | ||
} | } | ||
+ | }; | ||
− | + | })( jQuery ); | |
− | // or | + | |
− | if ( $.mobile. | + | /* |
− | $.mobile. | + | * "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 ); | ||
} | } | ||
− | + | }, $.mobile.behaviors.formReset ) ); | |
− | + | ||
− | + | })( jQuery ); | |
− | + | ||
− | + | ||
− | + | (function( $, undefined ) { | |
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | $.widget( "mobile.textinput", $.mobile.textinput, { | |
− | + | options: { | |
− | + | clearBtn: false, | |
+ | clearBtnText: "Clear text" | ||
+ | }, | ||
+ | |||
+ | _create: function() { | ||
+ | this._super(); | ||
+ | |||
+ | if ( this.isSearch ) { | ||
+ | this.options.clearBtn = true; | ||
} | } | ||
− | + | if ( !!this.options.clearBtn && this.inputNeedsWrap ) { | |
− | + | this._addClearBtn(); | |
− | + | } | |
+ | }, | ||
− | + | clearButton: function() { | |
− | + | return $( "<a href='#' tabindex='-1' aria-hidden='true' " + | |
− | + | "class='ui-input-clear ui-btn ui-icon-delete ui-btn-icon-notext ui-corner-all'>" + | |
− | + | "</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") | ||
}); | }); | ||
− | + | this._bindClearEvents(); | |
− | + | ||
− | + | this._toggleClear(); | |
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | }, | |
− | + | ||
− | + | ||
− | + | _enhanceClear: function() { | |
− | + | ||
− | + | ||
− | + | this.clearButton().appendTo( this.widget() ); | |
− | + | this.widget().addClass( "ui-input-has-clear" ); | |
− | + | }, | |
− | + | ||
− | + | _bindClearEvents: function() { | |
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | this._on( this._clearBtn, { | |
− | + | "click": "_clearBtnClick" | |
− | + | }); | |
− | + | ||
− | + | ||
− | + | this._on({ | |
− | + | "keyup": "_toggleClear", | |
− | + | "change": "_toggleClear", | |
− | + | "input": "_toggleClear", | |
− | + | "focus": "_toggleClear", | |
− | }); | + | "blur": "_toggleClear", |
− | } | + | "cut": "_toggleClear", |
− | + | "paste": "_toggleClear" | |
− | + | ||
− | + | }); | |
− | + | ||
+ | }, | ||
+ | |||
+ | _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 { | ||
− | + | this._destroyClear(); | |
− | + | ||
− | + | ||
− | + | ||
} | } | ||
+ | } | ||
+ | |||
+ | 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(); | ||
} | } | ||
} | } | ||
+ | |||
}); | }); | ||
− | + | })( jQuery ); | |
− | + | ||
− | + | ||
− | + | (function( $, undefined ) { | |
− | + | ||
− | + | ||
− | // | + | $.widget( "mobile.flipswitch", $.extend({ |
− | + | ||
− | + | 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" ); | ||
+ | }, | ||
− | + | _right: function() { | |
− | + | this.flipswitch.addClass( "ui-flipswitch-active" ); | |
− | + | if ( this.type === "SELECT" ) { | |
− | + | this.element.get( 0 ).selectedIndex = 1; | |
+ | } else { | ||
+ | this.element.prop( "checked", true ); | ||
+ | } | ||
+ | this.element.trigger( "change" ); | ||
+ | }, | ||
− | // | + | _enhance: function() { |
− | if ( | + | var flipswitch = $( "<div>" ), |
− | + | 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"; | ||
} | } | ||
− | + | if ( direction !== existingDirection ) { | |
− | + | this[ direction ](); | |
− | if ( | + | |
− | + | ||
} | } | ||
+ | }, | ||
− | + | _toggle: function() { | |
− | + | var direction = this.flipswitch.hasClass( "ui-flipswitch-active" ) ? "_left" : "_right"; | |
− | + | ||
− | + | ||
− | // | + | this[ direction ](); |
− | // | + | }, |
− | $.mobile.document. | + | |
− | + | _keydown: function( e ) { | |
− | + | if ( e.which === $.mobile.keyCode.LEFT ) { | |
− | + | 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; | ||
} | } | ||
− | |||
− | |||
+ | // 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; | ||
− | + | 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 which we write as   to be XHTML compliant - see gh-6699 | ||
+ | span.html( " " ); | ||
+ | } | ||
+ | |||
+ | // 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