diff options
-rw-r--r-- | demos/selectmenu/background_image.html | 7 | ||||
-rw-r--r-- | demos/selectmenu/default.html | 7 | ||||
-rw-r--r-- | themes/base/jquery.ui.selectmenu.css | 10 | ||||
-rw-r--r-- | ui/jquery.ui.selectmenu.js | 276 |
4 files changed, 161 insertions, 139 deletions
diff --git a/demos/selectmenu/background_image.html b/demos/selectmenu/background_image.html index 9a9913438..d33e0884f 100644 --- a/demos/selectmenu/background_image.html +++ b/demos/selectmenu/background_image.html @@ -19,6 +19,7 @@ fieldset { border:0; } label,select,.ui-select-menu { float: left; margin-right: 10px; } select { width: 200px; } + .ui-selectmenu-menu li a, .ui-selectmenu-status { padding: 0.3em 2em; } /* select with custom icons */ body a.customicons { height: 2.8em;} @@ -29,7 +30,7 @@ body .rss .ui-selectmenu-item-icon { background: url(images/24-rss-square.png) 0 0 no-repeat; } /* select with CSS avatar icons */ - option.css-avatar { background-repeat: no-repeat !important; padding-left: 20px;} + option.css-avatar { background-repeat: no-repeat !important; padding-left: 20px; } /* select with big avatar icons */ a.avatar-big { height: 5em; } @@ -39,6 +40,7 @@ <script type="text/javascript"> $(function(){ $('select#files').selectmenu({ + style:'popup', icons: [ {find: '.script', icon: 'ui-icon-script'}, {find: '.image', icon: 'ui-icon-image'} @@ -46,6 +48,7 @@ }); $('select#filesB').selectmenu({ + style:'popup', icons: [ {find: '.video'}, {find: '.podcast'}, @@ -54,7 +57,6 @@ }); $('select#peopleA').selectmenu({ - style:'dropdown', icons: [ {find: '.avatar'} ], @@ -64,7 +66,6 @@ }); $('select#peopleB').selectmenu({ - style:'dropdown', icons: [ {find: '.css-avatar'} ], diff --git a/demos/selectmenu/default.html b/demos/selectmenu/default.html index 44ec33445..4202a1bc9 100644 --- a/demos/selectmenu/default.html +++ b/demos/selectmenu/default.html @@ -20,13 +20,12 @@ 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 - { color: black !important; } + .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, @@ -85,7 +84,7 @@ }); }); }); - </script> + </script> </head> <body> <br /> diff --git a/themes/base/jquery.ui.selectmenu.css b/themes/base/jquery.ui.selectmenu.css index 781527111..d0acac0c8 100644 --- a/themes/base/jquery.ui.selectmenu.css +++ b/themes/base/jquery.ui.selectmenu.css @@ -1,27 +1,27 @@ /* Selectmenu ----------------------------------*/ -.ui-selectmenu { display: block; position:relative; height:2em; text-decoration: none; overflow:hidden;} +.ui-selectmenu { display: block; display: inline-block; position: relative; height: 2.2em; text-decoration: none; overflow: hidden; zoom: 1; } .ui-selectmenu-icon { position:absolute; right:6px; margin-top:-8px; top: 50%; } .ui-selectmenu-menu { padding:0; margin:0; list-style:none; position:absolute; top: 0; visibility: hidden; overflow: auto; z-index: 1005;} /* z-index: 1005 to make selectmenu work with dialog */ .ui-selectmenu-open { visibility: visible; } .ui-selectmenu-menu-popup { margin-top: -1px; } .ui-selectmenu-menu-dropdown { } .ui-selectmenu-menu li { padding:0; margin:0; display: block; border-top: 1px dotted transparent; border-bottom: 1px dotted transparent; border-right-width: 0 !important; border-left-width: 0 !important; font-weight: normal !important; } -.ui-selectmenu-menu li a,.ui-selectmenu-status {line-height: 1.4em; display:block; padding:.3em 1em; outline:none; text-decoration:none; } +.ui-selectmenu-menu li a,.ui-selectmenu-status { line-height: 1.4em; display: block; padding: .405em 1em; outline:none; text-decoration:none; } .ui-selectmenu-menu li.ui-selectmenu-hasIcon a, .ui-selectmenu-hasIcon .ui-selectmenu-status { padding-left: 20px; position: relative; margin-left: 5px; } .ui-selectmenu-menu li .ui-icon, .ui-selectmenu-status .ui-icon { position: absolute; top: 1em; margin-top: -8px; left: 0; } .ui-selectmenu-status { line-height: 1.4em; } -.ui-selectmenu-open li.ui-selectmenu-item-focus a { } +.ui-selectmenu-open li.ui-selectmenu-item-focus a { } .ui-selectmenu-open li.ui-selectmenu-item-selected { } /* Disabled option styling */ .ui-selectmenu-menu li.disabled { border: 1px solid transparent; } .ui-selectmenu-menu li.disabled a { cursor: default; color: #A9ACAF; background: #EBEBEC; } .ui-selectmenu-menu li span,.ui-selectmenu-status span { display:block; margin-bottom: .2em; } .ui-selectmenu-menu li .ui-selectmenu-item-header { font-weight: bold; } -.ui-selectmenu-menu li .ui-selectmenu-item-content { } +.ui-selectmenu-menu li .ui-selectmenu-item-content { } .ui-selectmenu-menu li .ui-selectmenu-item-footer { opacity: .8; } /*for optgroups*/ .ui-selectmenu-menu .ui-selectmenu-group { font-size: 1em; } -.ui-selectmenu-menu .ui-selectmenu-group .ui-selectmenu-group-label { line-height: 1.4em; display:block; padding:.6em .5em 0; font-weight: bold; } +.ui-selectmenu-menu .ui-selectmenu-group .ui-selectmenu-group-label { line-height: 1.4em; display:block; padding: .6em .5em 0; font-weight: bold; } .ui-selectmenu-menu .ui-selectmenu-group ul { margin: 0; padding: 0; } diff --git a/ui/jquery.ui.selectmenu.js b/ui/jquery.ui.selectmenu.js index 4301688e2..58ffd76de 100644 --- a/ui/jquery.ui.selectmenu.js +++ b/ui/jquery.ui.selectmenu.js @@ -47,20 +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')+']') @@ -69,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); } @@ -85,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'); @@ -128,14 +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.wrap(o.wrapperElement); + 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( + $.proxy(self._refreshPosition, this) + ); + }, + _init: function() { + var self = this, o = this.options; //serialize selectmenu element options var selectOptionData = []; @@ -144,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'), @@ -155,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>') @@ -162,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; @@ -185,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'); @@ -223,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) + .end().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); } @@ -237,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 { @@ -256,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) @@ -363,7 +384,7 @@ $.widget("ui.selectmenu", { _typeAhead: function(code, eventType){ var self = this; //define self._prevChar if needed - if(!self._prevChar){ self._prevChar = ['',0]; } + if (!self._prevChar){ self._prevChar = ['',0]; } var C = String.fromCharCode(code); c = C.toLowerCase(); var focusFound = false; @@ -385,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 { @@ -409,7 +431,7 @@ $.widget("ui.selectmenu", { 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'); } + if (this.options.style == "dropdown"){ this.newelement.removeClass('ui-corner-all').addClass('ui-corner-top'); } this._refreshPosition(); this._trigger("open", event, this._uiHash()); } @@ -421,8 +443,8 @@ $.widget("ui.selectmenu", { this.list .attr('aria-hidden', true) .removeClass(this.widgetBaseClass+'-open'); - if(this.options.style == "dropdown"){ this.newelement.removeClass('ui-corner-top').addClass('ui-corner-all'); } - if(retainFocus){this.newelement.focus();} + if (this.options.style == "dropdown"){ this.newelement.removeClass('ui-corner-top').addClass('ui-corner-all'); } + if (retainFocus){this.newelement.focus();} this._trigger("close", event, this._uiHash()); } }, @@ -544,6 +566,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") { @@ -566,7 +589,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); @@ -591,8 +614,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 |