@@ -110,6 +110,10 @@ $.widget( "mobile.selectmenu", $.mobile.selectmenu, {
110110 } ,
111111
112112 _handleMenuPageHide : function ( ) {
113+
114+ // After the dialog's done, we may want to trigger change if the value has actually changed
115+ this . _delayedTrigger ( ) ;
116+
113117 // TODO centralize page removal binding / handling in the page plugin.
114118 // Suggestion from @jblas to do refcounting
115119 //
@@ -132,18 +136,55 @@ $.widget( "mobile.selectmenu", $.mobile.selectmenu, {
132136 }
133137 } ,
134138
139+ _handleListItemClick : function ( event ) {
140+ var listItem = $ ( event . target ) . closest ( "li" ) ,
141+
142+ // Index of option tag to be selected
143+ oldIndex = this . select [ 0 ] . selectedIndex ,
144+ newIndex = $ . mobile . getAttribute ( listItem , "option-index" ) ,
145+ option = this . _selectOptions ( ) . eq ( newIndex ) [ 0 ] ;
146+
147+ // Toggle selected status on the tag for multi selects
148+ option . selected = this . isMultiple ? ! option . selected : true ;
149+
150+ // Toggle checkbox class for multiple selects
151+ if ( this . isMultiple ) {
152+ listItem . find ( "a" )
153+ . toggleClass ( "ui-checkbox-on" , option . selected )
154+ . toggleClass ( "ui-checkbox-off" , ! option . selected ) ;
155+ }
156+
157+ // If it's not a multiple select, trigger change after it has finished closing
158+ if ( ! this . isMultiple && oldIndex !== newIndex ) {
159+ this . _triggerChange = true ;
160+ }
161+
162+ // Trigger change if it's a multiple select
163+ // Hide custom select for single selects only - otherwise focus clicked item
164+ // We need to grab the clicked item the hard way, because the list may have been rebuilt
165+ if ( this . isMultiple ) {
166+ this . select . trigger ( "change" ) ;
167+ this . list . find ( "li:not(.ui-li-divider)" ) . eq ( newIndex )
168+ . find ( "a" ) . first ( ) . focus ( ) ;
169+ }
170+ else {
171+ this . close ( ) ;
172+ }
173+
174+ event . preventDefault ( ) ;
175+ } ,
176+
135177 build : function ( ) {
136178 var selectId , popupId , dialogId , label , thisPage , isMultiple , menuId ,
137179 themeAttr , overlayTheme , overlayThemeAttr , dividerThemeAttr ,
138180 menuPage , listbox , list , header , headerTitle , menuPageContent ,
139- menuPageClose , headerClose , self ,
181+ menuPageClose , headerClose ,
140182 o = this . options ;
141183
142184 if ( o . nativeMenu ) {
143185 return this . _super ( ) ;
144186 }
145187
146- self = this ;
147188 selectId = this . selectId ;
148189 popupId = selectId + "-listbox" ;
149190 dialogId = selectId + "-dialog" ;
@@ -221,52 +262,18 @@ $.widget( "mobile.selectmenu", $.mobile.selectmenu, {
221262 // Events for list items
222263 this . list . attr ( "role" , "listbox" ) ;
223264 this . _on ( this . list , {
224- focusin : "_handleListFocus" ,
225- focusout : "_handleListFocus" ,
226- keydown : "_handleListKeydown"
265+ "focusin" : "_handleListFocus" ,
266+ "focusout" : "_handleListFocus" ,
267+ "keydown" : "_handleListKeydown" ,
268+ "click li:not(.ui-disabled,.ui-state-disabled,.ui-li-divider)" : "_handleListItemClick"
227269 } ) ;
228- this . list
229- . delegate ( "li:not(.ui-disabled,.ui-state-disabled,.ui-li-divider)" , "click" , function ( event ) {
230-
231- // index of option tag to be selected
232- var oldIndex = self . select [ 0 ] . selectedIndex ,
233- newIndex = $ . mobile . getAttribute ( this , "option-index" ) ,
234- option = self . _selectOptions ( ) . eq ( newIndex ) [ 0 ] ;
235-
236- // toggle selected status on the tag for multi selects
237- option . selected = self . isMultiple ? ! option . selected : true ;
238-
239- // toggle checkbox class for multiple selects
240- if ( self . isMultiple ) {
241- $ ( this ) . find ( "a" )
242- . toggleClass ( "ui-checkbox-on" , option . selected )
243- . toggleClass ( "ui-checkbox-off" , ! option . selected ) ;
244- }
245-
246- // trigger change if value changed
247- if ( self . isMultiple || oldIndex !== newIndex ) {
248- self . select . trigger ( "change" ) ;
249- }
250-
251- // hide custom select for single selects only - otherwise focus clicked item
252- // We need to grab the clicked item the hard way, because the list may have been rebuilt
253- if ( self . isMultiple ) {
254- self . list . find ( "li:not(.ui-li-divider)" ) . eq ( newIndex )
255- . find ( "a" ) . first ( ) . focus ( ) ;
256- }
257- else {
258- self . close ( ) ;
259- }
260-
261- event . preventDefault ( ) ;
262- } ) ;
263270
264271 // button refocus ensures proper height calculation
265272 // by removing the inline style and ensuring page inclusion
266273 this . _on ( this . menuPage , { pagehide : "_handleMenuPageHide" } ) ;
267274
268275 // Events on the popup
269- this . _on ( this . listbox , { popupafterclose : "close " } ) ;
276+ this . _on ( this . listbox , { popupafterclose : "_popupClosed " } ) ;
270277
271278 // Close button on small overlays
272279 if ( this . isMultiple ) {
@@ -276,6 +283,18 @@ $.widget( "mobile.selectmenu", $.mobile.selectmenu, {
276283 return this ;
277284 } ,
278285
286+ _popupClosed : function ( ) {
287+ this . close ( ) ;
288+ this . _delayedTrigger ( ) ;
289+ } ,
290+
291+ _delayedTrigger : function ( ) {
292+ if ( this . _triggerChange ) {
293+ this . element . trigger ( "change" ) ;
294+ }
295+ this . _triggerChange = false ;
296+ } ,
297+
279298 _isRebuildRequired : function ( ) {
280299 var list = this . list . find ( "li" ) ,
281300 options = this . _selectOptions ( ) . not ( ".ui-screen-hidden" ) ;
0 commit comments