diff options
author | Felix Nagel <info@felixnagel.com> | 2010-12-01 23:42:28 +0100 |
---|---|---|
committer | Felix Nagel <info@felixnagel.com> | 2010-12-15 17:18:24 +0100 |
commit | 201685d8649c87483a41d063b2c0d1360ed94f56 (patch) | |
tree | 306431c6c30fbae535b02ddad7de97d9c4c647ed | |
parent | 50d8199eeefd3645d5332314e7c95620122ad79e (diff) | |
download | jquery-ui-201685d8649c87483a41d063b2c0d1360ed94f56.tar.gz jquery-ui-201685d8649c87483a41d063b2c0d1360ed94f56.zip |
added: possibility to refresh from original select element, please see https://github.com/fnagel/jquery-ui/issues#issue/17 for usage, please test and report feedback as this feature needed major refactoring
fixed: problem when manually selecting an option from original select element
fixed: demo wrapper class
-rw-r--r-- | demos/selectmenu/default.html | 25 | ||||
-rw-r--r-- | ui/jquery.ui.selectmenu.js | 282 |
2 files changed, 173 insertions, 134 deletions
diff --git a/demos/selectmenu/default.html b/demos/selectmenu/default.html index 28ec1c3bd..4202a1bc9 100644 --- a/demos/selectmenu/default.html +++ b/demos/selectmenu/default.html @@ -19,14 +19,17 @@ fieldset { border:0; } label,select,.ui-select-menu { float: left; margin-right: 10px; } select { width: 200px; } + .wrap span.ui-selectmenu-item-header, + .wrap ul.ui-selectmenu-menu li a { text-decoration: underline !important; } </style> <script type="text/javascript"> $(function(){ $('select#speedA').selectmenu({style:'popup'}); - + $('select#speedAa').selectmenu({ style:'popup', - maxHeight: 150 + maxHeight: 150, + wrapperElement: "<div class='wrap' />" }); $('select#speedB').selectmenu({ @@ -69,11 +72,19 @@ } return newText; } + + // add themeswitcher + $(function(){ + var ts = $('<div class="ui-button ui-widget ui-state-default ui-corner-all" style="padding: 5px; position: absolute; top: 20px; right: 10px;">Click here to add Themeswitcher!</div>') + .appendTo('body') + .bind("click", function() { + ts.text("Loading Themeswitcher..."); + $.getScript('http://ui.jquery.com/applications/themeroller/themeswitchertool/', function() { + ts.removeClass("ui-button ui-widget ui-state-default ui-corner-all").text("").unbind("click").themeswitcher(); + }); + }); + }); </script> - <!-- - <script type="text/javascript" src="http://ui.jquery.com/applications/themeroller/themeswitchertool/"></script> - <script type="text/javascript"> $(function(){ $('<div style="position: absolute; top: 20px; right: 10px;" />').appendTo('body').themeswitcher(); }); </script> - --> </head> <body> <br /> @@ -90,7 +101,7 @@ <option value="Faster">Faster</option> </select> </fieldset> - <h2>"default popup" Style with maxHeight set </h2> + <h2>"default popup" Style with maxHeight set and custom wrapper</h2> <fieldset> <label for="speedAa">Select a Speed:</label> <select name="speedAa" id="speedAa"> diff --git a/ui/jquery.ui.selectmenu.js b/ui/jquery.ui.selectmenu.js index d984e1865..b1cfd790b 100644 --- a/ui/jquery.ui.selectmenu.js +++ b/ui/jquery.ui.selectmenu.js @@ -24,11 +24,12 @@ $.widget("ui.selectmenu", { }, width: null, menuWidth: null, - handleWidth: 26, + handleWidth: 26, maxHeight: null, icons: null, format: null, - bgImage: function() {} + bgImage: function() {}, + wrapperElement: "" }, _create: function() { @@ -46,19 +47,21 @@ $.widget("ui.selectmenu", { //create menu button wrapper this.newelement = $('<a class="'+ this.widgetBaseClass +' ui-widget ui-state-default ui-corner-all" id="'+this.ids[0]+'" role="button" href="#" tabindex="0" aria-haspopup="true" aria-owns="'+this.ids[1]+'"></a>') .insertAfter(this.element); + this.newelement.wrap(o.wrapperElement); //transfer tabindex var tabindex = this.element.attr('tabindex'); - if(tabindex){ this.newelement.attr('tabindex', tabindex); } + if (tabindex){ this.newelement.attr('tabindex', tabindex); } //save reference to select in data for ease in calling methods this.newelement.data('selectelement', this.element); //menu icon this.selectmenuIcon = $('<span class="'+ this.widgetBaseClass +'-icon ui-icon"></span>') - .prependTo(this.newelement) - .addClass( (o.style == "popup")? 'ui-icon-triangle-2-n-s' : 'ui-icon-triangle-1-s' ); - + .prependTo(this.newelement); + + //append status span to button + this.newelement.prepend('<span class="'+self.widgetBaseClass+'-status" />'); //make associated form label trigger focus $('label[for='+this.element.attr('id')+']') @@ -67,13 +70,13 @@ $.widget("ui.selectmenu", { self.newelement[0].focus(); return false; }); - + //click toggle for menu visibility this.newelement .bind('mousedown', function(event){ self._toggle(event, true); - //make sure a click won't open/close instantly - if(o.style == "popup"){ + // make sure a click won't open/close instantly + if (o.style == "popup"){ self._safemouseup = false; setTimeout(function(){self._safemouseup = true;}, 300); } @@ -83,28 +86,37 @@ $.widget("ui.selectmenu", { return false; }) .keydown(function(event){ - var ret = true; + var ret = false; switch (event.keyCode) { case $.ui.keyCode.ENTER: ret = true; break; case $.ui.keyCode.SPACE: - ret = false; self._toggle(event); break; case $.ui.keyCode.UP: + if (event.altKey) { + self.open(event); + } else { + self._moveSelection(-1); + } + break; + case $.ui.keyCode.DOWN: + if (event.altKey) { + self.open(event); + } else { + self._moveSelection(1); + } + break; case $.ui.keyCode.LEFT: - ret = false; self._moveSelection(-1); break; - case $.ui.keyCode.DOWN: case $.ui.keyCode.RIGHT: - ret = false; self._moveSelection(1); - break; + break; case $.ui.keyCode.TAB: ret = true; - break; + break; default: ret = true; self._typeAhead(event.keyCode, 'mouseup'); @@ -126,13 +138,85 @@ $.widget("ui.selectmenu", { //change event on original selectmenu this.element - .click(function(){ this._refreshValue(); }) + .click(function(){ self._refreshValue(); }) // newelement can be null under unclear circumstances in IE8 .focus(function () { if (this.newelement) { this.newelement[0].focus(); } }); + //original selectmenu width + var selectWidth = this.element.width(); + //set menu button width + this.newelement.width( (o.width) ? o.width : selectWidth); + + //hide original selectmenu element + this.element.hide(); + //create menu portion, append to body - var cornerClass = (o.style == "dropdown")? " ui-corner-bottom" : " ui-corner-all"; - this.list = $('<ul class="' + self.widgetBaseClass + '-menu ui-widget ui-widget-content'+cornerClass+'" aria-hidden="true" role="listbox" aria-labelledby="'+this.ids[0]+'" id="'+this.ids[1]+'"></ul>').appendTo('body'); + this.list = $('<ul class="' + self.widgetBaseClass + '-menu ui-widget ui-widget-content" aria-hidden="true" role="listbox" aria-labelledby="'+this.ids[0]+'" id="'+this.ids[1]+'"></ul>').appendTo('body'); + this.list.wrap(o.wrapperElement); + + //transfer menu click to menu button + this.list + .keydown(function(event){ + var ret = false; + switch (event.keyCode) { + case $.ui.keyCode.UP: + if (event.altKey) { + self.close(event, true); + } else { + self._moveFocus(-1); + } + break; + case $.ui.keyCode.DOWN: + if (event.altKey) { + self.close(event, true); + } else { + self._moveFocus(1); + } + break; + case $.ui.keyCode.LEFT: + self._moveFocus(-1); + break; + case $.ui.keyCode.RIGHT: + self._moveFocus(1); + break; + case $.ui.keyCode.HOME: + self._moveFocus(':first'); + break; + case $.ui.keyCode.PAGE_UP: + self._scrollPage('up'); + break; + case $.ui.keyCode.PAGE_DOWN: + self._scrollPage('down'); + break; + case $.ui.keyCode.END: + self._moveFocus(':last'); + break; + case $.ui.keyCode.ENTER: + case $.ui.keyCode.SPACE: + self.close(event,true); + $(event.target).parents('li:eq(0)').trigger('mouseup'); + break; + case $.ui.keyCode.TAB: + ret = true; + self.close(event,true); + break; + case $.ui.keyCode.ESCAPE: + self.close(event,true); + break; + default: + ret = true; + break; + } + return ret; + }); + + // needed when window is resized + $(window).resize(function(){ + self._refreshPosition(); + }); + }, + _init: function() { + var self = this, o = this.options; //serialize selectmenu element options var selectOptionData = []; @@ -141,7 +225,7 @@ $.widget("ui.selectmenu", { .each(function(){ selectOptionData.push({ value: $(this).attr('value'), - text: self._formatText(jQuery(this).text()), + text: self._formatText($(this).text()), selected: $(this).attr('selected'), classes: $(this).attr('class'), parentOptGroup: $(this).parent('optgroup').attr('label'), @@ -152,6 +236,9 @@ $.widget("ui.selectmenu", { //active state class is only used in popup style var activeClass = (self.options.style == "popup") ? " ui-state-active" : ""; + // empty list so we can refresh the selectmenu via selectmenu() + this.list.html(""); + //write li's for (var i = 0; i < selectOptionData.length; i++) { var thisLi = $('<li role="presentation"><a href="#" tabindex="-1" role="option" aria-selected="false">'+ selectOptionData[i].text +'</a></li>') @@ -159,11 +246,11 @@ $.widget("ui.selectmenu", { .addClass(selectOptionData[i].classes) .data('optionClasses', selectOptionData[i].classes|| '') .mouseup(function(event){ - if(self._safemouseup){ + if (self._safemouseup){ var changed = $(this).data('index') != self._selectedIndex(); self.index($(this).data('index')); self.select(event); - if(changed){ self.change(event); } + if (changed){ self.change(event); } self.close(event,true); } return false; @@ -182,30 +269,28 @@ $.widget("ui.selectmenu", { }); //optgroup or not... - if(selectOptionData[i].parentOptGroup){ + if (selectOptionData[i].parentOptGroup){ // whitespace in the optgroupname must be replaced, otherwise the li of existing optgroups are never found var optGroupName = self.widgetBaseClass + '-group-' + selectOptionData[i].parentOptGroup.replace(/[^a-zA-Z0-9]/g, ""); if(this.list.find('li.' + optGroupName).size()){ this.list.find('li.' + optGroupName + ':last ul').append(thisLi); - } - else{ + } else { $('<li role="presentation" class="'+self.widgetBaseClass+'-group '+optGroupName+'"><span class="'+self.widgetBaseClass+'-group-label">'+selectOptionData[i].parentOptGroup+'</span><ul></ul></li>') .appendTo(this.list) .find('ul') .append(thisLi); } - } - else{ + } else { thisLi.appendTo(this.list); } //this allows for using the scrollbar in an overflowed list - this.list.bind('mousedown mouseup', function(){return false;}); + this.list.bind('mousedown mouseup', function(){ return false; }); //append icon if option is specified - if(o.icons){ - for(var j in o.icons){ - if(thisLi.is(o.icons[j].find)){ + if (o.icons){ + for (var j in o.icons){ + if (thisLi.is(o.icons[j].find)){ thisLi .data('optionClasses', selectOptionData[i].classes + ' ' + self.widgetBaseClass + '-hasIcon') .addClass(self.widgetBaseClass + '-hasIcon'); @@ -220,13 +305,26 @@ $.widget("ui.selectmenu", { } } } - - //add corners to top and bottom menu items - this.list.find('li:last').addClass("ui-corner-bottom"); - if(o.style == 'popup'){ this.list.find('li:first').addClass("ui-corner-top"); } - + + // we need to set and unset the CSS classes for dropdown and popup style + var isDropDown = (o.style == 'dropdown') ? true : false; + this.newelement + .toggleClass(self.widgetBaseClass+"-dropdown", isDropDown) + .toggleClass(self.widgetBaseClass+"-popup", !isDropDown); + this.list + .toggleClass(self.widgetBaseClass+"-menu-dropdown ui-corner-bottom", isDropDown) + .toggleClass(self.widgetBaseClass+"-menu-popup ui-corner-all", !isDropDown) + // add corners to top and bottom menu items + .find('li:first') + .toggleClass("ui-corner-top", !isDropDown) + .find('li:last') + .addClass("ui-corner-bottom"); + this.selectmenuIcon + .toggleClass('ui-icon-triangle-1-s', isDropDown) + .toggleClass('ui-icon-triangle-2-n-s', !isDropDown); + //transfer classes to selectmenu and list - if(o.transferClasses){ + if (o.transferClasses){ var transferClasses = this.element.attr('class') || ''; this.newelement.add(this.list).addClass(transferClasses); } @@ -234,15 +332,15 @@ $.widget("ui.selectmenu", { //original selectmenu width var selectWidth = this.element.width(); - //set menu button width - this.newelement.width( (o.width) ? o.width : selectWidth); - //set menu width to either menuWidth option value, width option value, or select width - if(o.style == 'dropdown'){ this.list.width( (o.menuWidth) ? o.menuWidth : ((o.width) ? o.width : selectWidth)); } - else { this.list.width( (o.menuWidth) ? o.menuWidth : ((o.width) ? o.width - o.handleWidth : selectWidth - o.handleWidth)); } + if (o.style == 'dropdown') { + this.list.width( (o.menuWidth) ? o.menuWidth : ((o.width) ? o.width : selectWidth)); + } else { + this.list.width( (o.menuWidth) ? o.menuWidth : ((o.width) ? o.width - o.handleWidth : selectWidth - o.handleWidth)); + } // calculate default max height - if(o.maxHeight) { + if (o.maxHeight) { //set max height from option if (o.maxHeight < this.list.height()){ this.list.height(o.maxHeight); } } else { @@ -253,91 +351,17 @@ $.widget("ui.selectmenu", { } //save reference to actionable li's (not group label li's) this._optionLis = this.list.find('li:not(.'+ self.widgetBaseClass +'-group)'); - - //transfer menu click to menu button - this.list - .keydown(function(event){ - var ret = true; - switch (event.keyCode) { - case $.ui.keyCode.UP: - case $.ui.keyCode.LEFT: - ret = false; - self._moveFocus(-1); - break; - case $.ui.keyCode.DOWN: - case $.ui.keyCode.RIGHT: - ret = false; - self._moveFocus(1); - break; - case $.ui.keyCode.HOME: - ret = false; - self._moveFocus(':first'); - break; - case $.ui.keyCode.PAGE_UP: - ret = false; - self._scrollPage('up'); - break; - case $.ui.keyCode.PAGE_DOWN: - ret = false; - self._scrollPage('down'); - break; - case $.ui.keyCode.END: - ret = false; - self._moveFocus(':last'); - break; - case $.ui.keyCode.ENTER: - case $.ui.keyCode.SPACE: - ret = false; - self.close(event,true); - $(event.target).parents('li:eq(0)').trigger('mouseup'); - break; - case $.ui.keyCode.TAB: - ret = true; - self.close(event,true); - break; - case $.ui.keyCode.ESCAPE: - ret = false; - self.close(event,true); - break; - } - return ret; - }); - - //selectmenu style - if(o.style == 'dropdown'){ - this.newelement - .addClass(self.widgetBaseClass+"-dropdown"); - this.list - .addClass(self.widgetBaseClass+"-menu-dropdown"); - } - else { - this.newelement - .addClass(self.widgetBaseClass+"-popup"); - this.list - .addClass(self.widgetBaseClass+"-menu-popup"); - } - - //append status span to button - this.newelement.prepend('<span class="'+self.widgetBaseClass+'-status">'+ selectOptionData[this._selectedIndex()].text +'</span>'); - - //hide original selectmenu element - this.element.hide(); - + //transfer disabled state - if(this.element.attr('disabled') == true){ this.disable(); } + if (this.element.attr('disabled') == true){ this.disable(); } //update value - this.index(this._selectedIndex()); + this.index(this._selectedIndex()); // needed when selectmenu is placed at the very bottom / top of the page window.setTimeout(function() { self._refreshPosition(); }, 200); - - // needed when window is resized - $(window).resize(function(){ - self._refreshPosition(); - }); }, destroy: function() { this.element.removeData(this.widgetName) @@ -350,6 +374,7 @@ $.widget("ui.selectmenu", { .attr('for',this.element.attr('id')) .unbind('click'); this.newelement.remove(); + // FIXME option.wrapper needs this.list.remove(); this.element.show(); @@ -381,6 +406,7 @@ $.widget("ui.selectmenu", { }); this._prevChar[0] = C; }, + // returns some usefull information, called by callbacks only _uiHash: function(){ var index = this.index(); return { @@ -397,10 +423,12 @@ $.widget("ui.selectmenu", { this._closeOthers(event); this.newelement .addClass('ui-state-active'); - - this.list - .appendTo('body') - .addClass(self.widgetBaseClass + '-open') + if (self.options.wrapperElement) { + this.list.parent().appendTo('body'); + } else { + this.list.appendTo('body'); + } + this.list.addClass(self.widgetBaseClass + '-open') .attr('aria-hidden', false) .find('li:not(.'+ self.widgetBaseClass +'-group):eq('+ this._selectedIndex() +') a')[0].focus(); if(this.options.style == "dropdown"){ this.newelement.removeClass('ui-corner-all').addClass('ui-corner-top'); } @@ -500,6 +528,7 @@ $.widget("ui.selectmenu", { value: function(newValue) { if (arguments.length) { // FIXME test for number is a kind of legacy support, could be removed at any time (Dez. 2010) + // see this post for more info: https://github.com/fnagel/jquery-ui/issues#issue/33 if (typeof newValue == "number") { this.index(newValue); } else if (typeof newValue == "string") { @@ -522,7 +551,7 @@ $.widget("ui.selectmenu", { .attr('id', ''); //select new this._selectedOptionLi() - .addClass(this.widgetBaseClass + "-item-selected"+activeClass) + .addClass(this.widgetBaseClass + "-item-selected" + activeClass) .find('a') .attr('aria-selected', 'true') .attr('id', activeID); @@ -547,8 +576,7 @@ $.widget("ui.selectmenu", { var o = this.options; // if its a native pop-up we need to calculate the position of the selected li if (o.style == "popup" && !o.positionOptions.offset) { - var selected = this.list.find('li:not(.ui-selectmenu-group):eq('+this._selectedIndex()+')'); - // var _offset = "0 -" + (selected.outerHeight() + selected.offset().top - this.list.offset().top); + var selected = this._selectedOptionLi(); var _offset = "0 -" + (selected.outerHeight() + selected.offset().top - this.list.offset().top); } this.list |