]> source.dussan.org Git - jquery-ui.git/commitdiff
Selectmenu: Move selectmenu into widgets folder
authorAlexander Schmitz <arschmitz@gmail.com>
Wed, 15 Jul 2015 02:06:31 +0000 (22:06 -0400)
committerAlexander Schmitz <arschmitz@gmail.com>
Sat, 8 Aug 2015 04:29:39 +0000 (00:29 -0400)
Ref #13885

demos/bootstrap.js
tests/unit/selectmenu/common.js
tests/unit/selectmenu/core.js
tests/unit/selectmenu/events.js
tests/unit/selectmenu/methods.js
tests/unit/selectmenu/options.js
ui/selectmenu.js [deleted file]
ui/widgets/selectmenu.js [new file with mode: 0644]

index b726148c932191a51487fdd375f7fb86874859a9..a773d20e6287536659cde847b89c069cf48a6703 100644 (file)
@@ -36,7 +36,8 @@ var widgets = [
        "mouse",
        "progressbar",
        "resizable",
-       "selectable"
+       "selectable",
+       "selectmenu"
 ];
 
 function getPath( module ) {
index b24b8dace85e6fc9982634677c6eab2d1f6a1c2a..758e004badbf51a8fa4c9196e1ee0224718507f1 100644 (file)
@@ -1,6 +1,6 @@
 define( [
        "lib/common",
-       "ui/selectmenu"
+       "ui/widgets/selectmenu"
 ], function( common ) {
 
 common.testWidget( "selectmenu", {
index e5807817ee413d4fa4b328ae6674088fbb3c4dbf..96e83f69b105f6678c38b9dac8a8dc8b6a954b11 100644 (file)
@@ -1,6 +1,6 @@
 define( [
        "jquery",
-       "ui/selectmenu"
+       "ui/widgets/selectmenu"
 ], function( $ ) {
 
 module( "selectmenu: core" );
index d5c463fa9106bcb0ec62f9ce40289147abf75a38..2ab20c46ce82bd8c437cbd7c0d8be51387b690e0 100644 (file)
@@ -1,6 +1,6 @@
 define( [
        "jquery",
-       "ui/selectmenu"
+       "ui/widgets/selectmenu"
 ], function( $ ) {
 
 module( "selectmenu: events", {
index 8481e804e08fb4e954fb855a39d626dedf1423f1..a386655ce9e11c9ca5e66c20cba7cbb5396587e4 100644 (file)
@@ -1,6 +1,6 @@
 define( [
        "jquery",
-       "ui/selectmenu"
+       "ui/widgets/selectmenu"
 ], function( $ ) {
 
 module( "selectmenu: methods" );
index deb7a6d3a1d909697e0a3d372d018fa5b3e06ebd..be2565e37320ef97c38ed202d0dc5fa1f500a234 100644 (file)
@@ -1,6 +1,6 @@
 define( [
        "jquery",
-       "ui/selectmenu"
+       "ui/widgets/selectmenu"
 ], function( $ ) {
 
 module( "selectmenu: options" );
diff --git a/ui/selectmenu.js b/ui/selectmenu.js
deleted file mode 100644 (file)
index 19a9a05..0000000
+++ /dev/null
@@ -1,684 +0,0 @@
-/*!
- * jQuery UI Selectmenu @VERSION
- * http://jqueryui.com
- *
- * Copyright jQuery Foundation and other contributors
- * Released under the MIT license.
- * http://jquery.org/license
- */
-
-//>>label: Selectmenu
-//>>group: Widgets
-//>>description: Duplicates and extends the functionality of a native HTML select element, allowing it to be customizable in behavior and appearance far beyond the limitations of a native select.
-//>>docs: http://api.jqueryui.com/selectmenu/
-//>>demos: http://jqueryui.com/selectmenu/
-//>>css.structure: ../themes/base/core.css
-//>>css.structure: ../themes/base/selectmenu.css
-//>>css.theme: ../themes/base/theme.css
-
-( function( factory ) {
-       if ( typeof define === "function" && define.amd ) {
-
-               // AMD. Register as an anonymous module.
-               define( [
-                       "jquery",
-                       "./version",
-                       "./escape-selector",
-                       "./widgets/menu",
-                       "./keycode",
-                       "./labels",
-                       "./position",
-                       "./unique-id",
-                       "./version",
-                       "./widget"
-               ], factory );
-       } else {
-
-               // Browser globals
-               factory( jQuery );
-       }
-}( function( $ ) {
-
-return $.widget( "ui.selectmenu", {
-       version: "@VERSION",
-       defaultElement: "<select>",
-       options: {
-               appendTo: null,
-               classes: {
-                       "ui-selectmenu-button-open": "ui-corner-top",
-                       "ui-selectmenu-button-closed": "ui-corner-all"
-               },
-               disabled: null,
-               icons: {
-                       button: "ui-icon-triangle-1-s"
-               },
-               position: {
-                       my: "left top",
-                       at: "left bottom",
-                       collision: "none"
-               },
-               width: false,
-
-               // callbacks
-               change: null,
-               close: null,
-               focus: null,
-               open: null,
-               select: null
-       },
-
-       _create: function() {
-               var selectmenuId = this.element.uniqueId().attr( "id" );
-               this.ids = {
-                       element: selectmenuId,
-                       button: selectmenuId + "-button",
-                       menu: selectmenuId + "-menu"
-               };
-
-               this._drawButton();
-               this._drawMenu();
-
-               this._rendered = false;
-               this.menuItems = $();
-
-               if ( this.options.disabled ) {
-                       this.disable();
-               }
-       },
-
-       _drawButton: function() {
-               var icon,
-                       that = this,
-                       item = this._parseOption(
-                               this.element.find( "option:selected" ),
-                               this.element[ 0 ].selectedIndex
-                       );
-
-               // Associate existing label with the new button
-               this.labels = this.element.labels().attr( "for", this.ids.button );
-               this._on( this.labels, {
-                       click: function( event ) {
-                               this.button.focus();
-                               event.preventDefault();
-                       }
-               } );
-
-               // Hide original select element
-               this.element.hide();
-
-               // Create button
-               this.button = $( "<span>", {
-                       tabindex: this.options.disabled ? -1 : 0,
-                       id: this.ids.button,
-                       role: "combobox",
-                       "aria-expanded": "false",
-                       "aria-autocomplete": "list",
-                       "aria-owns": this.ids.menu,
-                       "aria-haspopup": "true",
-                       title: this.element.attr( "title" )
-               } )
-                       .insertAfter( this.element );
-
-               this._addClass( this.button, "ui-selectmenu-button ui-selectmenu-button-closed",
-                       "ui-widget ui-state-default" );
-
-               icon = $( "<span>" ).prependTo( this.button );
-               this._addClass( icon, null, "ui-icon " + this.options.icons.button );
-
-               this.buttonItem = this._renderButtonItem( item )
-                       .appendTo( this.button );
-
-               if ( this.options.width !== false ) {
-                       this._resizeButton();
-               }
-
-               this._on( this.button, this._buttonEvents );
-               this.button.one( "focusin", function() {
-
-                       // Delay rendering the menu items until the button receives focus.
-                       // The menu may have already been rendered via a programmatic open.
-                       if ( !that._rendered ) {
-                               that._refreshMenu();
-                       }
-               } );
-               this._hoverable( this.button );
-               this._focusable( this.button );
-       },
-
-       _drawMenu: function() {
-               var that = this;
-
-               // Create menu
-               this.menu = $( "<ul>", {
-                       "aria-hidden": "true",
-                       "aria-labelledby": this.ids.button,
-                       id: this.ids.menu
-               } );
-
-               // Wrap menu
-               this.menuWrap = $( "<div>" ).append( this.menu );
-               this._addClass( this.menuWrap, "ui-selectmenu-menu", "ui-front" );
-               this.menuWrap.appendTo( this._appendTo() );
-
-               // Initialize menu widget
-               this.menuInstance = this.menu
-                       .menu( {
-                               classes: {
-                                       "ui-menu": "ui-corner-bottom"
-                               },
-                               role: "listbox",
-                               select: function( event, ui ) {
-                                       event.preventDefault();
-
-                                       // support: IE8
-                                       // If the item was selected via a click, the text selection
-                                       // will be destroyed in IE
-                                       that._setSelection();
-
-                                       that._select( ui.item.data( "ui-selectmenu-item" ), event );
-                               },
-                               focus: function( event, ui ) {
-                                       var item = ui.item.data( "ui-selectmenu-item" );
-
-                                       // Prevent inital focus from firing and check if its a newly focused item
-                                       if ( that.focusIndex != null && item.index !== that.focusIndex ) {
-                                               that._trigger( "focus", event, { item: item } );
-                                               if ( !that.isOpen ) {
-                                                       that._select( item, event );
-                                               }
-                                       }
-                                       that.focusIndex = item.index;
-
-                                       that.button.attr( "aria-activedescendant",
-                                               that.menuItems.eq( item.index ).attr( "id" ) );
-                               }
-                       } )
-                       .menu( "instance" );
-
-               // Don't close the menu on mouseleave
-               this.menuInstance._off( this.menu, "mouseleave" );
-
-               // Cancel the menu's collapseAll on document click
-               this.menuInstance._closeOnDocumentClick = function() {
-                       return false;
-               };
-
-               // Selects often contain empty items, but never contain dividers
-               this.menuInstance._isDivider = function() {
-                       return false;
-               };
-       },
-
-       refresh: function() {
-               this._refreshMenu();
-               this.buttonItem.replaceWith(
-                       this.buttonItem = this._renderButtonItem(
-
-                               // Fall back to an empty object in case there are no options
-                               this._getSelectedItem().data( "ui-selectmenu-item" ) || {}
-                       )
-               );
-               if ( this.options.width === null ) {
-                       this._resizeButton();
-               }
-       },
-
-       _refreshMenu: function() {
-               var item,
-                       options = this.element.find( "option" );
-
-               this.menu.empty();
-
-               this._parseOptions( options );
-               this._renderMenu( this.menu, this.items );
-
-               this.menuInstance.refresh();
-               this.menuItems = this.menu.find( "li" )
-                       .not( ".ui-selectmenu-optgroup" )
-                               .find( ".ui-menu-item-wrapper" );
-
-               this._rendered = true;
-
-               if ( !options.length ) {
-                       return;
-               }
-
-               item = this._getSelectedItem();
-
-               // Update the menu to have the correct item focused
-               this.menuInstance.focus( null, item );
-               this._setAria( item.data( "ui-selectmenu-item" ) );
-
-               // Set disabled state
-               this._setOption( "disabled", this.element.prop( "disabled" ) );
-       },
-
-       open: function( event ) {
-               if ( this.options.disabled ) {
-                       return;
-               }
-
-               // If this is the first time the menu is being opened, render the items
-               if ( !this._rendered ) {
-                       this._refreshMenu();
-               } else {
-
-                       // Menu clears focus on close, reset focus to selected item
-                       this._removeClass( this.menu.find( ".ui-state-active" ), null, "ui-state-active" );
-                       this.menuInstance.focus( null, this._getSelectedItem() );
-               }
-
-               // If there are no options, don't open the menu
-               if ( !this.menuItems.length ) {
-                       return;
-               }
-
-               this.isOpen = true;
-               this._toggleAttr();
-               this._resizeMenu();
-               this._position();
-
-               this._on( this.document, this._documentClick );
-
-               this._trigger( "open", event );
-       },
-
-       _position: function() {
-               this.menuWrap.position( $.extend( { of: this.button }, this.options.position ) );
-       },
-
-       close: function( event ) {
-               if ( !this.isOpen ) {
-                       return;
-               }
-
-               this.isOpen = false;
-               this._toggleAttr();
-
-               this.range = null;
-               this._off( this.document );
-
-               this._trigger( "close", event );
-       },
-
-       widget: function() {
-               return this.button;
-       },
-
-       menuWidget: function() {
-               return this.menu;
-       },
-
-       _renderButtonItem: function( item ) {
-               var buttonItem = $( "<span>" );
-
-               this._setText( buttonItem, item.label );
-               this._addClass( buttonItem, "ui-selectmenu-text" );
-
-               return buttonItem;
-       },
-
-       _renderMenu: function( ul, items ) {
-               var that = this,
-                       currentOptgroup = "";
-
-               $.each( items, function( index, item ) {
-                       var li;
-
-                       if ( item.optgroup !== currentOptgroup ) {
-                               li = $( "<li>", {
-                                       text: item.optgroup
-                               } );
-                               that._addClass( li, "ui-selectmenu-optgroup", "ui-menu-divider" +
-                                       ( item.element.parent( "optgroup" ).prop( "disabled" ) ?
-                                               " ui-state-disabled" :
-                                               "" ) );
-
-                               li.appendTo( ul );
-
-                               currentOptgroup = item.optgroup;
-                       }
-
-                       that._renderItemData( ul, item );
-               } );
-       },
-
-       _renderItemData: function( ul, item ) {
-               return this._renderItem( ul, item ).data( "ui-selectmenu-item", item );
-       },
-
-       _renderItem: function( ul, item ) {
-               var li = $( "<li>" ),
-                       wrapper = $( "<div>", {
-                               title: item.element.attr( "title" )
-                       } );
-
-               if ( item.disabled ) {
-                       this._addClass( li, null, "ui-state-disabled" );
-               }
-               this._setText( wrapper, item.label );
-
-               return li.append( wrapper ).appendTo( ul );
-       },
-
-       _setText: function( element, value ) {
-               if ( value ) {
-                       element.text( value );
-               } else {
-                       element.html( "&#160;" );
-               }
-       },
-
-       _move: function( direction, event ) {
-               var item, next,
-                       filter = ".ui-menu-item";
-
-               if ( this.isOpen ) {
-                       item = this.menuItems.eq( this.focusIndex ).parent( "li" );
-               } else {
-                       item = this.menuItems.eq( this.element[ 0 ].selectedIndex ).parent( "li" );
-                       filter += ":not(.ui-state-disabled)";
-               }
-
-               if ( direction === "first" || direction === "last" ) {
-                       next = item[ direction === "first" ? "prevAll" : "nextAll" ]( filter ).eq( -1 );
-               } else {
-                       next = item[ direction + "All" ]( filter ).eq( 0 );
-               }
-
-               if ( next.length ) {
-                       this.menuInstance.focus( event, next );
-               }
-       },
-
-       _getSelectedItem: function() {
-               return this.menuItems.eq( this.element[ 0 ].selectedIndex ).parent( "li" );
-       },
-
-       _toggle: function( event ) {
-               this[ this.isOpen ? "close" : "open" ]( event );
-       },
-
-       _setSelection: function() {
-               var selection;
-
-               if ( !this.range ) {
-                       return;
-               }
-
-               if ( window.getSelection ) {
-                       selection = window.getSelection();
-                       selection.removeAllRanges();
-                       selection.addRange( this.range );
-
-               // support: IE8
-               } else {
-                       this.range.select();
-               }
-
-               // support: IE
-               // Setting the text selection kills the button focus in IE, but
-               // restoring the focus doesn't kill the selection.
-               this.button.focus();
-       },
-
-       _documentClick: {
-               mousedown: function( event ) {
-                       if ( !this.isOpen ) {
-                               return;
-                       }
-
-                       if ( !$( event.target ).closest( ".ui-selectmenu-menu, #" +
-                                       $.ui.escapeSelector( this.ids.button ) ).length ) {
-                               this.close( event );
-                       }
-               }
-       },
-
-       _buttonEvents: {
-
-               // Prevent text selection from being reset when interacting with the selectmenu (#10144)
-               mousedown: function() {
-                       var selection;
-
-                       if ( window.getSelection ) {
-                               selection = window.getSelection();
-                               if ( selection.rangeCount ) {
-                                       this.range = selection.getRangeAt( 0 );
-                               }
-
-                       // support: IE8
-                       } else {
-                               this.range = document.selection.createRange();
-                       }
-               },
-
-               click: function( event ) {
-                       this._setSelection();
-                       this._toggle( event );
-               },
-
-               keydown: function( event ) {
-                       var preventDefault = true;
-                       switch ( event.keyCode ) {
-                       case $.ui.keyCode.TAB:
-                       case $.ui.keyCode.ESCAPE:
-                               this.close( event );
-                               preventDefault = false;
-                               break;
-                       case $.ui.keyCode.ENTER:
-                               if ( this.isOpen ) {
-                                       this._selectFocusedItem( event );
-                               }
-                               break;
-                       case $.ui.keyCode.UP:
-                               if ( event.altKey ) {
-                                       this._toggle( event );
-                               } else {
-                                       this._move( "prev", event );
-                               }
-                               break;
-                       case $.ui.keyCode.DOWN:
-                               if ( event.altKey ) {
-                                       this._toggle( event );
-                               } else {
-                                       this._move( "next", event );
-                               }
-                               break;
-                       case $.ui.keyCode.SPACE:
-                               if ( this.isOpen ) {
-                                       this._selectFocusedItem( event );
-                               } else {
-                                       this._toggle( event );
-                               }
-                               break;
-                       case $.ui.keyCode.LEFT:
-                               this._move( "prev", event );
-                               break;
-                       case $.ui.keyCode.RIGHT:
-                               this._move( "next", event );
-                               break;
-                       case $.ui.keyCode.HOME:
-                       case $.ui.keyCode.PAGE_UP:
-                               this._move( "first", event );
-                               break;
-                       case $.ui.keyCode.END:
-                       case $.ui.keyCode.PAGE_DOWN:
-                               this._move( "last", event );
-                               break;
-                       default:
-                               this.menu.trigger( event );
-                               preventDefault = false;
-                       }
-
-                       if ( preventDefault ) {
-                               event.preventDefault();
-                       }
-               }
-       },
-
-       _selectFocusedItem: function( event ) {
-               var item = this.menuItems.eq( this.focusIndex ).parent( "li" );
-               if ( !item.hasClass( "ui-state-disabled" ) ) {
-                       this._select( item.data( "ui-selectmenu-item" ), event );
-               }
-       },
-
-       _select: function( item, event ) {
-               var oldIndex = this.element[ 0 ].selectedIndex;
-
-               // Change native select element
-               this.element[ 0 ].selectedIndex = item.index;
-               this.buttonItem.replaceWith( this.buttonItem = this._renderButtonItem( item ) );
-               this._setAria( item );
-               this._trigger( "select", event, { item: item } );
-
-               if ( item.index !== oldIndex ) {
-                       this._trigger( "change", event, { item: item } );
-               }
-
-               this.close( event );
-       },
-
-       _setAria: function( item ) {
-               var id = this.menuItems.eq( item.index ).attr( "id" );
-
-               this.button.attr( {
-                       "aria-labelledby": id,
-                       "aria-activedescendant": id
-               } );
-               this.menu.attr( "aria-activedescendant", id );
-       },
-
-       _setOption: function( key, value ) {
-               if ( key === "icons" ) {
-                       var icon = this.button.find( "span.ui-icon" );
-                       this._removeClass( icon, null, this.options.icons.button )
-                               ._addClass( icon, null, value.button );
-               }
-
-               this._super( key, value );
-
-               if ( key === "appendTo" ) {
-                       this.menuWrap.appendTo( this._appendTo() );
-               }
-
-               if ( key === "disabled" ) {
-                       this.menuInstance.option( "disabled", value );
-                       this.button.attr( "aria-disabled", value );
-                       this._toggleClass( this.button, null, "ui-state-disabled", value );
-
-                       this.element.prop( "disabled", value );
-                       if ( value ) {
-                               this.button.attr( "tabindex", -1 );
-                               this.close();
-                       } else {
-                               this.button.attr( "tabindex", 0 );
-                       }
-               }
-
-               if ( key === "width" ) {
-                       this._resizeButton();
-               }
-       },
-
-       _appendTo: function() {
-               var element = this.options.appendTo;
-
-               if ( element ) {
-                       element = element.jquery || element.nodeType ?
-                               $( element ) :
-                               this.document.find( element ).eq( 0 );
-               }
-
-               if ( !element || !element[ 0 ] ) {
-                       element = this.element.closest( ".ui-front, dialog" );
-               }
-
-               if ( !element.length ) {
-                       element = this.document[ 0 ].body;
-               }
-
-               return element;
-       },
-
-       _toggleAttr: function() {
-               this.button.attr( "aria-expanded", this.isOpen );
-
-               // We can't use two _toggleClass() calls here, because we need to make sure
-               // we always remove classes first and add them second, otherwise if both classes have the
-               // same theme class, it will be removed after we add it.
-               this._removeClass( this.button, "ui-selectmenu-button-" +
-                               ( this.isOpen ? "closed" : "open" ) )
-                       ._addClass( this.button, "ui-selectmenu-button-" +
-                               ( this.isOpen ? "open" : "closed" ) )
-                       ._toggleClass( this.menuWrap, "ui-selectmenu-open", null, this.isOpen );
-
-               this.menu.attr( "aria-hidden", !this.isOpen );
-       },
-
-       _resizeButton: function() {
-               var width = this.options.width;
-
-               // For `width: false`, just remove inline style and stop
-               if ( width === false ) {
-                       this.button.css( "width", "" );
-                       return;
-               }
-
-               // For `width: null`, match the width of the original element
-               if ( width === null ) {
-                       width = this.element.show().outerWidth();
-                       this.element.hide();
-               }
-
-               this.button.outerWidth( width );
-       },
-
-       _resizeMenu: function() {
-               this.menu.outerWidth( Math.max(
-                       this.button.outerWidth(),
-
-                       // support: IE10
-                       // IE10 wraps long text (possibly a rounding bug)
-                       // so we add 1px to avoid the wrapping
-                       this.menu.width( "" ).outerWidth() + 1
-               ) );
-       },
-
-       _getCreateOptions: function() {
-               return { disabled: this.element.prop( "disabled" ) };
-       },
-
-       _parseOptions: function( options ) {
-               var that = this,
-                       data = [];
-               options.each( function( index, item ) {
-                       data.push( that._parseOption( $( item ), index ) );
-               } );
-               this.items = data;
-       },
-
-       _parseOption: function( option, index ) {
-               var optgroup = option.parent( "optgroup" );
-
-               return {
-                       element: option,
-                       index: index,
-                       value: option.val(),
-                       label: option.text(),
-                       optgroup: optgroup.attr( "label" ) || "",
-                       disabled: optgroup.prop( "disabled" ) || option.prop( "disabled" )
-               };
-       },
-
-       _destroy: function() {
-               this.menuWrap.remove();
-               this.button.remove();
-               this.element.show();
-               this.element.removeUniqueId();
-               this.labels.attr( "for", this.ids.element );
-       }
-} );
-
-} ) );
diff --git a/ui/widgets/selectmenu.js b/ui/widgets/selectmenu.js
new file mode 100644 (file)
index 0000000..bf415a8
--- /dev/null
@@ -0,0 +1,683 @@
+/*!
+ * jQuery UI Selectmenu @VERSION
+ * http://jqueryui.com
+ *
+ * Copyright jQuery Foundation and other contributors
+ * Released under the MIT license.
+ * http://jquery.org/license
+ */
+
+//>>label: Selectmenu
+//>>group: Widgets
+//>>description: Duplicates and extends the functionality of a native HTML select element, allowing it to be customizable in behavior and appearance far beyond the limitations of a native select.
+//>>docs: http://api.jqueryui.com/selectmenu/
+//>>demos: http://jqueryui.com/selectmenu/
+//>>css.structure: ../themes/base/core.css
+//>>css.structure: ../themes/base/selectmenu.css
+//>>css.theme: ../themes/base/theme.css
+
+( function( factory ) {
+       if ( typeof define === "function" && define.amd ) {
+
+               // AMD. Register as an anonymous module.
+               define( [
+                       "jquery",
+                       "./menu",
+                       "../escape-selector",
+                       "../keycode",
+                       "../labels",
+                       "../position",
+                       "../unique-id",
+                       "../version",
+                       "../widget"
+               ], factory );
+       } else {
+
+               // Browser globals
+               factory( jQuery );
+       }
+}( function( $ ) {
+
+return $.widget( "ui.selectmenu", {
+       version: "@VERSION",
+       defaultElement: "<select>",
+       options: {
+               appendTo: null,
+               classes: {
+                       "ui-selectmenu-button-open": "ui-corner-top",
+                       "ui-selectmenu-button-closed": "ui-corner-all"
+               },
+               disabled: null,
+               icons: {
+                       button: "ui-icon-triangle-1-s"
+               },
+               position: {
+                       my: "left top",
+                       at: "left bottom",
+                       collision: "none"
+               },
+               width: false,
+
+               // callbacks
+               change: null,
+               close: null,
+               focus: null,
+               open: null,
+               select: null
+       },
+
+       _create: function() {
+               var selectmenuId = this.element.uniqueId().attr( "id" );
+               this.ids = {
+                       element: selectmenuId,
+                       button: selectmenuId + "-button",
+                       menu: selectmenuId + "-menu"
+               };
+
+               this._drawButton();
+               this._drawMenu();
+
+               this._rendered = false;
+               this.menuItems = $();
+
+               if ( this.options.disabled ) {
+                       this.disable();
+               }
+       },
+
+       _drawButton: function() {
+               var icon,
+                       that = this,
+                       item = this._parseOption(
+                               this.element.find( "option:selected" ),
+                               this.element[ 0 ].selectedIndex
+                       );
+
+               // Associate existing label with the new button
+               this.labels = this.element.labels().attr( "for", this.ids.button );
+               this._on( this.labels, {
+                       click: function( event ) {
+                               this.button.focus();
+                               event.preventDefault();
+                       }
+               } );
+
+               // Hide original select element
+               this.element.hide();
+
+               // Create button
+               this.button = $( "<span>", {
+                       tabindex: this.options.disabled ? -1 : 0,
+                       id: this.ids.button,
+                       role: "combobox",
+                       "aria-expanded": "false",
+                       "aria-autocomplete": "list",
+                       "aria-owns": this.ids.menu,
+                       "aria-haspopup": "true",
+                       title: this.element.attr( "title" )
+               } )
+                       .insertAfter( this.element );
+
+               this._addClass( this.button, "ui-selectmenu-button ui-selectmenu-button-closed",
+                       "ui-widget ui-state-default" );
+
+               icon = $( "<span>" ).prependTo( this.button );
+               this._addClass( icon, null, "ui-icon " + this.options.icons.button );
+
+               this.buttonItem = this._renderButtonItem( item )
+                       .appendTo( this.button );
+
+               if ( this.options.width !== false ) {
+                       this._resizeButton();
+               }
+
+               this._on( this.button, this._buttonEvents );
+               this.button.one( "focusin", function() {
+
+                       // Delay rendering the menu items until the button receives focus.
+                       // The menu may have already been rendered via a programmatic open.
+                       if ( !that._rendered ) {
+                               that._refreshMenu();
+                       }
+               } );
+               this._hoverable( this.button );
+               this._focusable( this.button );
+       },
+
+       _drawMenu: function() {
+               var that = this;
+
+               // Create menu
+               this.menu = $( "<ul>", {
+                       "aria-hidden": "true",
+                       "aria-labelledby": this.ids.button,
+                       id: this.ids.menu
+               } );
+
+               // Wrap menu
+               this.menuWrap = $( "<div>" ).append( this.menu );
+               this._addClass( this.menuWrap, "ui-selectmenu-menu", "ui-front" );
+               this.menuWrap.appendTo( this._appendTo() );
+
+               // Initialize menu widget
+               this.menuInstance = this.menu
+                       .menu( {
+                               classes: {
+                                       "ui-menu": "ui-corner-bottom"
+                               },
+                               role: "listbox",
+                               select: function( event, ui ) {
+                                       event.preventDefault();
+
+                                       // support: IE8
+                                       // If the item was selected via a click, the text selection
+                                       // will be destroyed in IE
+                                       that._setSelection();
+
+                                       that._select( ui.item.data( "ui-selectmenu-item" ), event );
+                               },
+                               focus: function( event, ui ) {
+                                       var item = ui.item.data( "ui-selectmenu-item" );
+
+                                       // Prevent inital focus from firing and check if its a newly focused item
+                                       if ( that.focusIndex != null && item.index !== that.focusIndex ) {
+                                               that._trigger( "focus", event, { item: item } );
+                                               if ( !that.isOpen ) {
+                                                       that._select( item, event );
+                                               }
+                                       }
+                                       that.focusIndex = item.index;
+
+                                       that.button.attr( "aria-activedescendant",
+                                               that.menuItems.eq( item.index ).attr( "id" ) );
+                               }
+                       } )
+                       .menu( "instance" );
+
+               // Don't close the menu on mouseleave
+               this.menuInstance._off( this.menu, "mouseleave" );
+
+               // Cancel the menu's collapseAll on document click
+               this.menuInstance._closeOnDocumentClick = function() {
+                       return false;
+               };
+
+               // Selects often contain empty items, but never contain dividers
+               this.menuInstance._isDivider = function() {
+                       return false;
+               };
+       },
+
+       refresh: function() {
+               this._refreshMenu();
+               this.buttonItem.replaceWith(
+                       this.buttonItem = this._renderButtonItem(
+
+                               // Fall back to an empty object in case there are no options
+                               this._getSelectedItem().data( "ui-selectmenu-item" ) || {}
+                       )
+               );
+               if ( this.options.width === null ) {
+                       this._resizeButton();
+               }
+       },
+
+       _refreshMenu: function() {
+               var item,
+                       options = this.element.find( "option" );
+
+               this.menu.empty();
+
+               this._parseOptions( options );
+               this._renderMenu( this.menu, this.items );
+
+               this.menuInstance.refresh();
+               this.menuItems = this.menu.find( "li" )
+                       .not( ".ui-selectmenu-optgroup" )
+                               .find( ".ui-menu-item-wrapper" );
+
+               this._rendered = true;
+
+               if ( !options.length ) {
+                       return;
+               }
+
+               item = this._getSelectedItem();
+
+               // Update the menu to have the correct item focused
+               this.menuInstance.focus( null, item );
+               this._setAria( item.data( "ui-selectmenu-item" ) );
+
+               // Set disabled state
+               this._setOption( "disabled", this.element.prop( "disabled" ) );
+       },
+
+       open: function( event ) {
+               if ( this.options.disabled ) {
+                       return;
+               }
+
+               // If this is the first time the menu is being opened, render the items
+               if ( !this._rendered ) {
+                       this._refreshMenu();
+               } else {
+
+                       // Menu clears focus on close, reset focus to selected item
+                       this._removeClass( this.menu.find( ".ui-state-active" ), null, "ui-state-active" );
+                       this.menuInstance.focus( null, this._getSelectedItem() );
+               }
+
+               // If there are no options, don't open the menu
+               if ( !this.menuItems.length ) {
+                       return;
+               }
+
+               this.isOpen = true;
+               this._toggleAttr();
+               this._resizeMenu();
+               this._position();
+
+               this._on( this.document, this._documentClick );
+
+               this._trigger( "open", event );
+       },
+
+       _position: function() {
+               this.menuWrap.position( $.extend( { of: this.button }, this.options.position ) );
+       },
+
+       close: function( event ) {
+               if ( !this.isOpen ) {
+                       return;
+               }
+
+               this.isOpen = false;
+               this._toggleAttr();
+
+               this.range = null;
+               this._off( this.document );
+
+               this._trigger( "close", event );
+       },
+
+       widget: function() {
+               return this.button;
+       },
+
+       menuWidget: function() {
+               return this.menu;
+       },
+
+       _renderButtonItem: function( item ) {
+               var buttonItem = $( "<span>" );
+
+               this._setText( buttonItem, item.label );
+               this._addClass( buttonItem, "ui-selectmenu-text" );
+
+               return buttonItem;
+       },
+
+       _renderMenu: function( ul, items ) {
+               var that = this,
+                       currentOptgroup = "";
+
+               $.each( items, function( index, item ) {
+                       var li;
+
+                       if ( item.optgroup !== currentOptgroup ) {
+                               li = $( "<li>", {
+                                       text: item.optgroup
+                               } );
+                               that._addClass( li, "ui-selectmenu-optgroup", "ui-menu-divider" +
+                                       ( item.element.parent( "optgroup" ).prop( "disabled" ) ?
+                                               " ui-state-disabled" :
+                                               "" ) );
+
+                               li.appendTo( ul );
+
+                               currentOptgroup = item.optgroup;
+                       }
+
+                       that._renderItemData( ul, item );
+               } );
+       },
+
+       _renderItemData: function( ul, item ) {
+               return this._renderItem( ul, item ).data( "ui-selectmenu-item", item );
+       },
+
+       _renderItem: function( ul, item ) {
+               var li = $( "<li>" ),
+                       wrapper = $( "<div>", {
+                               title: item.element.attr( "title" )
+                       } );
+
+               if ( item.disabled ) {
+                       this._addClass( li, null, "ui-state-disabled" );
+               }
+               this._setText( wrapper, item.label );
+
+               return li.append( wrapper ).appendTo( ul );
+       },
+
+       _setText: function( element, value ) {
+               if ( value ) {
+                       element.text( value );
+               } else {
+                       element.html( "&#160;" );
+               }
+       },
+
+       _move: function( direction, event ) {
+               var item, next,
+                       filter = ".ui-menu-item";
+
+               if ( this.isOpen ) {
+                       item = this.menuItems.eq( this.focusIndex ).parent( "li" );
+               } else {
+                       item = this.menuItems.eq( this.element[ 0 ].selectedIndex ).parent( "li" );
+                       filter += ":not(.ui-state-disabled)";
+               }
+
+               if ( direction === "first" || direction === "last" ) {
+                       next = item[ direction === "first" ? "prevAll" : "nextAll" ]( filter ).eq( -1 );
+               } else {
+                       next = item[ direction + "All" ]( filter ).eq( 0 );
+               }
+
+               if ( next.length ) {
+                       this.menuInstance.focus( event, next );
+               }
+       },
+
+       _getSelectedItem: function() {
+               return this.menuItems.eq( this.element[ 0 ].selectedIndex ).parent( "li" );
+       },
+
+       _toggle: function( event ) {
+               this[ this.isOpen ? "close" : "open" ]( event );
+       },
+
+       _setSelection: function() {
+               var selection;
+
+               if ( !this.range ) {
+                       return;
+               }
+
+               if ( window.getSelection ) {
+                       selection = window.getSelection();
+                       selection.removeAllRanges();
+                       selection.addRange( this.range );
+
+               // support: IE8
+               } else {
+                       this.range.select();
+               }
+
+               // support: IE
+               // Setting the text selection kills the button focus in IE, but
+               // restoring the focus doesn't kill the selection.
+               this.button.focus();
+       },
+
+       _documentClick: {
+               mousedown: function( event ) {
+                       if ( !this.isOpen ) {
+                               return;
+                       }
+
+                       if ( !$( event.target ).closest( ".ui-selectmenu-menu, #" +
+                                       $.ui.escapeSelector( this.ids.button ) ).length ) {
+                               this.close( event );
+                       }
+               }
+       },
+
+       _buttonEvents: {
+
+               // Prevent text selection from being reset when interacting with the selectmenu (#10144)
+               mousedown: function() {
+                       var selection;
+
+                       if ( window.getSelection ) {
+                               selection = window.getSelection();
+                               if ( selection.rangeCount ) {
+                                       this.range = selection.getRangeAt( 0 );
+                               }
+
+                       // support: IE8
+                       } else {
+                               this.range = document.selection.createRange();
+                       }
+               },
+
+               click: function( event ) {
+                       this._setSelection();
+                       this._toggle( event );
+               },
+
+               keydown: function( event ) {
+                       var preventDefault = true;
+                       switch ( event.keyCode ) {
+                       case $.ui.keyCode.TAB:
+                       case $.ui.keyCode.ESCAPE:
+                               this.close( event );
+                               preventDefault = false;
+                               break;
+                       case $.ui.keyCode.ENTER:
+                               if ( this.isOpen ) {
+                                       this._selectFocusedItem( event );
+                               }
+                               break;
+                       case $.ui.keyCode.UP:
+                               if ( event.altKey ) {
+                                       this._toggle( event );
+                               } else {
+                                       this._move( "prev", event );
+                               }
+                               break;
+                       case $.ui.keyCode.DOWN:
+                               if ( event.altKey ) {
+                                       this._toggle( event );
+                               } else {
+                                       this._move( "next", event );
+                               }
+                               break;
+                       case $.ui.keyCode.SPACE:
+                               if ( this.isOpen ) {
+                                       this._selectFocusedItem( event );
+                               } else {
+                                       this._toggle( event );
+                               }
+                               break;
+                       case $.ui.keyCode.LEFT:
+                               this._move( "prev", event );
+                               break;
+                       case $.ui.keyCode.RIGHT:
+                               this._move( "next", event );
+                               break;
+                       case $.ui.keyCode.HOME:
+                       case $.ui.keyCode.PAGE_UP:
+                               this._move( "first", event );
+                               break;
+                       case $.ui.keyCode.END:
+                       case $.ui.keyCode.PAGE_DOWN:
+                               this._move( "last", event );
+                               break;
+                       default:
+                               this.menu.trigger( event );
+                               preventDefault = false;
+                       }
+
+                       if ( preventDefault ) {
+                               event.preventDefault();
+                       }
+               }
+       },
+
+       _selectFocusedItem: function( event ) {
+               var item = this.menuItems.eq( this.focusIndex ).parent( "li" );
+               if ( !item.hasClass( "ui-state-disabled" ) ) {
+                       this._select( item.data( "ui-selectmenu-item" ), event );
+               }
+       },
+
+       _select: function( item, event ) {
+               var oldIndex = this.element[ 0 ].selectedIndex;
+
+               // Change native select element
+               this.element[ 0 ].selectedIndex = item.index;
+               this.buttonItem.replaceWith( this.buttonItem = this._renderButtonItem( item ) );
+               this._setAria( item );
+               this._trigger( "select", event, { item: item } );
+
+               if ( item.index !== oldIndex ) {
+                       this._trigger( "change", event, { item: item } );
+               }
+
+               this.close( event );
+       },
+
+       _setAria: function( item ) {
+               var id = this.menuItems.eq( item.index ).attr( "id" );
+
+               this.button.attr( {
+                       "aria-labelledby": id,
+                       "aria-activedescendant": id
+               } );
+               this.menu.attr( "aria-activedescendant", id );
+       },
+
+       _setOption: function( key, value ) {
+               if ( key === "icons" ) {
+                       var icon = this.button.find( "span.ui-icon" );
+                       this._removeClass( icon, null, this.options.icons.button )
+                               ._addClass( icon, null, value.button );
+               }
+
+               this._super( key, value );
+
+               if ( key === "appendTo" ) {
+                       this.menuWrap.appendTo( this._appendTo() );
+               }
+
+               if ( key === "disabled" ) {
+                       this.menuInstance.option( "disabled", value );
+                       this.button.attr( "aria-disabled", value );
+                       this._toggleClass( this.button, null, "ui-state-disabled", value );
+
+                       this.element.prop( "disabled", value );
+                       if ( value ) {
+                               this.button.attr( "tabindex", -1 );
+                               this.close();
+                       } else {
+                               this.button.attr( "tabindex", 0 );
+                       }
+               }
+
+               if ( key === "width" ) {
+                       this._resizeButton();
+               }
+       },
+
+       _appendTo: function() {
+               var element = this.options.appendTo;
+
+               if ( element ) {
+                       element = element.jquery || element.nodeType ?
+                               $( element ) :
+                               this.document.find( element ).eq( 0 );
+               }
+
+               if ( !element || !element[ 0 ] ) {
+                       element = this.element.closest( ".ui-front, dialog" );
+               }
+
+               if ( !element.length ) {
+                       element = this.document[ 0 ].body;
+               }
+
+               return element;
+       },
+
+       _toggleAttr: function() {
+               this.button.attr( "aria-expanded", this.isOpen );
+
+               // We can't use two _toggleClass() calls here, because we need to make sure
+               // we always remove classes first and add them second, otherwise if both classes have the
+               // same theme class, it will be removed after we add it.
+               this._removeClass( this.button, "ui-selectmenu-button-" +
+                               ( this.isOpen ? "closed" : "open" ) )
+                       ._addClass( this.button, "ui-selectmenu-button-" +
+                               ( this.isOpen ? "open" : "closed" ) )
+                       ._toggleClass( this.menuWrap, "ui-selectmenu-open", null, this.isOpen );
+
+               this.menu.attr( "aria-hidden", !this.isOpen );
+       },
+
+       _resizeButton: function() {
+               var width = this.options.width;
+
+               // For `width: false`, just remove inline style and stop
+               if ( width === false ) {
+                       this.button.css( "width", "" );
+                       return;
+               }
+
+               // For `width: null`, match the width of the original element
+               if ( width === null ) {
+                       width = this.element.show().outerWidth();
+                       this.element.hide();
+               }
+
+               this.button.outerWidth( width );
+       },
+
+       _resizeMenu: function() {
+               this.menu.outerWidth( Math.max(
+                       this.button.outerWidth(),
+
+                       // support: IE10
+                       // IE10 wraps long text (possibly a rounding bug)
+                       // so we add 1px to avoid the wrapping
+                       this.menu.width( "" ).outerWidth() + 1
+               ) );
+       },
+
+       _getCreateOptions: function() {
+               return { disabled: this.element.prop( "disabled" ) };
+       },
+
+       _parseOptions: function( options ) {
+               var that = this,
+                       data = [];
+               options.each( function( index, item ) {
+                       data.push( that._parseOption( $( item ), index ) );
+               } );
+               this.items = data;
+       },
+
+       _parseOption: function( option, index ) {
+               var optgroup = option.parent( "optgroup" );
+
+               return {
+                       element: option,
+                       index: index,
+                       value: option.val(),
+                       label: option.text(),
+                       optgroup: optgroup.attr( "label" ) || "",
+                       disabled: optgroup.prop( "disabled" ) || option.prop( "disabled" )
+               };
+       },
+
+       _destroy: function() {
+               this.menuWrap.remove();
+               this.button.remove();
+               this.element.show();
+               this.element.removeUniqueId();
+               this.labels.attr( "for", this.ids.element );
+       }
+} );
+
+} ) );