1 (function( $, undefined ) {
3 $.widget( "mobile.selectmenu", $.mobile.widget, {
14 hidePlaceholderMenuItems: true,
17 // This option defaults to true on iOS devices.
18 preventFocusZoom: /iPhone|iPad|iPod/.test( navigator.platform ) && navigator.userAgent.indexOf( "AppleWebKit" ) > -1,
19 initSelector: "select:not( :jqmData(role='slider') )",
27 _setDisabled: function( value ) {
28 this.element.attr( "disabled", value );
29 this.button.attr( "aria-disabled", value );
30 return this._setOption( "disabled", value );
33 _focusButton : function() {
36 setTimeout( function() {
41 _selectOptions: function() {
42 return this.select.find( "option" );
45 // setup items that are generally necessary for select menu extension
46 _preExtension: function() {
48 // 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
49 /* if ( $el[0].className.length ) {
50 classes = $el[0].className;
52 if ( !!~this.element[0].className.indexOf( "ui-btn-left" ) ) {
53 classes = " ui-btn-left";
56 if ( !!~this.element[0].className.indexOf( "ui-btn-right" ) ) {
57 classes = " ui-btn-right";
60 this.select = this.element.wrap( "<div class='ui-select" + classes + "'>" );
61 this.selectID = this.select.attr( "id" );
62 this.label = $( "label[for='"+ this.selectID +"']" ).addClass( "ui-select" );
63 this.isMultiple = this.select[ 0 ].multiple;
64 if ( !this.options.theme ) {
65 this.options.theme = $.mobile.getInheritedTheme( this.select, "c" );
72 // Allows for extension of the native select for custom selects and other plugins
73 // see select.custom for example extension
74 // TODO explore plugin registration
75 this._trigger( "beforeCreate" );
77 this.button = this._button();
81 options = this.options,
83 inline = options.inline || $.mobile.getAttrFixed( this.select[0], "data-" + $.mobile.ns + "inline" ),
84 mini = options.mini || $.mobile.getAttrFixed( this.select[0], "data-" + $.mobile.ns + "mini" ),
85 iconpos = options.icon ? ( options.iconpos || $.mobile.getAttrFixed( this.select[0], "data-" + $.mobile.ns + "iconpos" ) ) : false,
87 // IE throws an exception at options.item() function when
88 // there is no selected item
89 // select first in this case
90 selectedIndex = this.select[ 0 ].selectedIndex === -1 ? 0 : this.select[ 0 ].selectedIndex,
92 // TODO values buttonId and menuId are undefined here
94 .insertBefore( this.select )
100 corners: options.corners,
101 shadow: options.shadow,
102 iconshadow: options.iconshadow,
106 this.setButtonText();
108 // TIZEN fix: The TIZEN buttonMarkup patch adds 'ui-btn-icon-only' class to the ui-btn-inner.
109 // It makes the text not to be shown, so the class must be removed. (Like JQM)
110 button.children('.ui-btn-inner').removeClass('ui-btn-icon-only');
112 // Opera does not properly support opacity on select elements
113 // In Mini, it hides the element, but not its text
114 // On the desktop,it seems to do the opposite
115 // for these reasons, using the nativeMenu option results in a full native select in Opera
116 if ( options.nativeMenu && window.opera && window.opera.version ) {
117 button.addClass( "ui-select-nativeonly" );
120 // Add counter for multi selects
121 if ( this.isMultiple ) {
122 this.buttonCount = $( "<span>" )
123 .addClass( "ui-li-count ui-btn-up-c ui-btn-corner-all" )
125 .appendTo( button.addClass('ui-li-has-count') );
128 // Disable if specified
129 if ( options.disabled || this.element.attr('disabled')) {
133 // Events on native select
134 this.select.change(function() {
145 .appendTo( self.button )
146 .bind( "vmousedown", function() {
147 // Add active class to button
148 self.button.addClass( $.mobile.activeBtnClass );
150 .bind( "focus", function() {
151 self.button.addClass( $.mobile.focusClass );
153 .bind( "blur", function() {
154 self.button.removeClass( $.mobile.focusClass );
156 .bind( "focus vmouseover", function() {
157 self.button.trigger( "vmouseover" );
159 .bind( "vmousemove", function() {
160 // Remove active class on scroll/touchmove
161 self.button.removeClass( $.mobile.activeBtnClass );
163 .bind( "change blur vmouseout", function() {
164 self.button.trigger( "vmouseout" )
165 .removeClass( $.mobile.activeBtnClass );
167 .bind( "change blur", function() {
168 self.button.removeClass( "ui-btn-down-" + self.options.theme );
171 // In many situations, iOS will zoom into the select upon tap, this prevents that from happening
172 self.button.bind( "vmousedown", function() {
173 if ( self.options.preventFocusZoom ) {
174 $.mobile.zoom.disable( true );
176 }).bind( "mouseup", function() {
177 if ( self.options.preventFocusZoom ) {
178 setTimeout(function() {
179 $.mobile.zoom.enable( true );
185 selected: function() {
186 return this._selectOptions().filter( ":selected" );
189 selectedIndices: function() {
192 return this.selected().map(function() {
193 return self._selectOptions().index( this );
197 setButtonText: function() {
199 selected = this.selected(),
200 text = this.placeholder,
201 span = $( document.createElement( "span" ) );
203 this.button.find( ".ui-btn-text" ).html(function() {
204 if ( selected.length ) {
205 text = selected.map(function() {
206 return $( this ).text();
207 }).get().join( ", " );
209 text = self.placeholder;
212 // TODO possibly aggregate multiple select option classes
213 return span.text( text )
214 .addClass( self.select.attr( "class" ) )
215 .addClass( selected.attr( "class" ) );
219 setButtonCount: function() {
220 var selected = this.selected();
222 // multiple count inside button
223 if ( this.isMultiple ) {
224 this.buttonCount[ selected.length > 1 ? "show" : "hide" ]().text( selected.length );
228 refresh: function() {
229 this.setButtonText();
230 this.setButtonCount();
233 // open and close preserved in native selects
234 // to simplify users code when looping over selects
238 disable: function() {
239 this._setDisabled( true );
240 this.button.addClass( "ui-disabled" );
244 this._setDisabled( false );
245 this.button.removeClass( "ui-disabled" );
249 //auto self-init widgets
250 $.mobile.$document.bind( "pagecreate create", function( e ) {
251 $.mobile.selectmenu.prototype.enhanceWithin( e.target, true );