1 //>>excludeStart("jqmBuildExclude", pragmas.jqmBuildExclude);
2 //>>description: Consistent styling for native select menus. Tapping opens a native select menu.
5 //>>css: ../css/themes/default/jquery.mobile.theme.css, ../css/structure/jquery.mobile.forms.select.css
7 define( [ "jquery", "./jquery.mobile.core", "./jquery.mobile.widget", "./jquery.mobile.buttonMarkup", "./jquery.mobile.zoom" ], function( $ ) {
8 //>>excludeEnd("jqmBuildExclude");
9 (function( $, undefined ) {
11 $.widget( "mobile.selectmenu", $.mobile.widget, {
22 hidePlaceholderMenuItems: true,
25 // This option defaults to true on iOS devices.
26 preventFocusZoom: /iPhone|iPad|iPod/.test( navigator.platform ) && navigator.userAgent.indexOf( "AppleWebKit" ) > -1,
27 initSelector: "select:not(:jqmData(role='slider'))",
35 _setDisabled: function( value ) {
36 this.element.attr( "disabled", value );
37 this.button.attr( "aria-disabled", value );
38 return this._setOption( "disabled", value );
41 _focusButton : function() {
44 setTimeout( function() {
49 _selectOptions: function() {
50 return this.select.find( "option" );
53 // setup items that are generally necessary for select menu extension
54 _preExtension: function(){
56 // 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
57 /* if( $el[0].className.length ) {
58 classes = $el[0].className;
60 if( !!~this.element[0].className.indexOf( "ui-btn-left" ) ) {
61 classes = " ui-btn-left";
64 if( !!~this.element[0].className.indexOf( "ui-btn-right" ) ) {
65 classes = " ui-btn-right";
68 this.select = this.element.wrap( "<div class='ui-select" + classes + "'>" );
69 this.selectID = this.select.attr( "id" );
70 this.label = $( "label[for='"+ this.selectID +"']" ).addClass( "ui-select" );
71 this.isMultiple = this.select[ 0 ].multiple;
72 if ( !this.options.theme ) {
73 this.options.theme = $.mobile.getInheritedTheme( this.select, "c" );
80 // Allows for extension of the native select for custom selects and other plugins
81 // see select.custom for example extension
82 // TODO explore plugin registration
83 this._trigger( "beforeCreate" );
85 this.button = this._button();
89 options = this.options,
91 // IE throws an exception at options.item() function when
92 // there is no selected item
93 // select first in this case
94 selectedIndex = this.select[ 0 ].selectedIndex == -1 ? 0 : this.select[ 0 ].selectedIndex,
96 // TODO values buttonId and menuId are undefined here
98 .text( $( this.select[ 0 ].options.item( selectedIndex ) ).text() )
99 .insertBefore( this.select )
101 theme: options.theme,
103 iconpos: options.iconpos,
104 inline: options.inline,
105 corners: options.corners,
106 shadow: options.shadow,
107 iconshadow: options.iconshadow,
111 // Opera does not properly support opacity on select elements
112 // In Mini, it hides the element, but not its text
113 // On the desktop,it seems to do the opposite
114 // for these reasons, using the nativeMenu option results in a full native select in Opera
115 if ( options.nativeMenu && window.opera && window.opera.version ) {
116 this.select.addClass( "ui-select-nativeonly" );
119 // Add counter for multi selects
120 if ( this.isMultiple ) {
121 this.buttonCount = $( "<span>" )
122 .addClass( "ui-li-count ui-btn-up-c ui-btn-corner-all" )
124 .appendTo( button.addClass('ui-li-has-count') );
127 // Disable if specified
128 if ( options.disabled || this.element.attr('disabled')) {
132 // Events on native select
133 this.select.change( function() {
144 .appendTo( self.button )
145 .bind( "vmousedown", function() {
146 // Add active class to button
147 self.button.addClass( $.mobile.activeBtnClass );
149 .bind( "focus", function() {
150 self.button.addClass( $.mobile.focusClass );
152 .bind( "blur", function() {
153 self.button.removeClass( $.mobile.focusClass );
155 .bind( "focus vmouseover", function() {
156 self.button.trigger( "vmouseover" );
158 .bind( "vmousemove", function() {
159 // Remove active class on scroll/touchmove
160 self.button.removeClass( $.mobile.activeBtnClass );
162 .bind( "change blur vmouseout", function() {
163 self.button.trigger( "vmouseout" )
164 .removeClass( $.mobile.activeBtnClass );
166 .bind( "change blur", function() {
167 self.button.removeClass( "ui-btn-down-" + self.options.theme );
170 // In many situations, iOS will zoom into the select upon tap, this prevents that from happening
171 self.button.bind( "vmousedown", function() {
172 if( self.options.preventFocusZoom ){
173 $.mobile.zoom.disable( true );
176 .bind( "mouseup", function() {
177 if( self.options.preventFocusZoom ){
178 $.mobile.zoom.enable( true );
183 selected: function() {
184 return this._selectOptions().filter( ":selected" );
187 selectedIndices: function() {
190 return this.selected().map( function() {
191 return self._selectOptions().index( this );
195 setButtonText: function() {
196 var self = this, selected = this.selected();
198 this.button.find( ".ui-btn-text" ).text( function() {
199 if ( !self.isMultiple ) {
200 return selected.text();
203 return selected.length ? selected.map( function() {
204 return $( this ).text();
205 }).get().join( ", " ) : self.placeholder;
209 setButtonCount: function() {
210 var selected = this.selected();
212 // multiple count inside button
213 if ( this.isMultiple ) {
214 this.buttonCount[ selected.length > 1 ? "show" : "hide" ]().text( selected.length );
218 refresh: function() {
219 this.setButtonText();
220 this.setButtonCount();
223 // open and close preserved in native selects
224 // to simplify users code when looping over selects
228 disable: function() {
229 this._setDisabled( true );
230 this.button.addClass( "ui-disabled" );
234 this._setDisabled( false );
235 this.button.removeClass( "ui-disabled" );
239 //auto self-init widgets
240 $( document ).bind( "pagecreate create", function( e ){
241 $.mobile.selectmenu.prototype.enhanceWithin( e.target, true );
244 //>>excludeStart("jqmBuildExclude", pragmas.jqmBuildExclude);
246 //>>excludeEnd("jqmBuildExclude");