https://www.absolon.cz/assets-bda2c34b546e34501eeea8f86e541433/js/selectmenu/jquery.ui.selectmenu.js
1 /* 2 * jQuery UI selectmenu 1.3.0pre version 3 * 4 * Copyright (c) 2009-2010 filament group, http://filamentgroup.com 5 * Copyright (c) 2010-2012 Felix Nagel, http://www.felixnagel.com 6 * Dual licensed under the MIT (MIT-LICENSE.txt) 7 * and GPL (GPL-LICENSE.txt) licenses. 8 * 9 * http://docs.jquery.com/UI 10 * https://github.com/fnagel/jquery-ui/wiki/Selectmenu 11 */ 12 13(function($) { 14 15$.widget("ui.selectmenu", { 16 options: { 17 appendTo: "body", 18 typeAhead: 1000, 19 style: 'dropdown', 20 positionOptions: { 21 my: "left top", 22 at: "left bottom", 23 offset: null 24 }, 25 //width: "97.6%", 26 //menuWidth: "auto", 27 //handleWidth: 26, 28 maxHeight: "auto", 29 icons: null, 30 format: null, 31 escapeHtml: false, 32 bgImage: function() {} 33 }, 34 35 _create: function() { 36 var self = this, o = this.options; 37 38 // set a default id value, generate a new random one if not set by developer 39 var selectmenuId = (this.element.attr( 'id' ) || 'ui-selectmenu-' + Math.random().toString( 16 ).slice( 2, 10 )).replace(/(:|\.)/g,'') 40 41 // quick array of button and menu id's 42 this.ids = [ selectmenuId, selectmenuId + '-button', selectmenuId + '-menu' ]; 43 44 // define safe mouseup for future toggling 45 this._safemouseup = true; 46 this.isOpen = false; 47 48 // create menu button wrapper 49 this.newelement = $( '<a />', { 50 'class': this.widgetBaseClass + ' ui-widget ui-state-default ui-corner-all', 51 'id' : this.ids[ 1 ], 52 'role': 'button', 53 'href': '#nogo', 54 'tabindex': this.element.attr( 'disabled' ) ? 1 : 0, 55 'aria-haspopup': true, 56 'aria-owns': this.ids[ 2 ] 57 }); 58 this.newelementWrap = $( "<span />" ) 59 .append( this.newelement ) 60 .insertAfter( this.element ); 61 62 // transfer tabindex 63 var tabindex = this.element.attr( 'tabindex' ); 64 if ( tabindex ) { 65 this.newelement.attr( 'tabindex', tabindex ); 66 } 67 68 // save reference to select in data for ease in calling methods 69 this.newelement.data( 'selectelement', this.element ); 70 71 // menu icon 72 this.selectmenuIcon = $( '<span class="' + this.widgetBaseClass + '-icon ui-icon"></span>' ) 73 .prependTo( this.newelement ); 74 75 // append status span to button 76 this.newelement.prepend( '<span class="' + self.widgetBaseClass + '-status" />' ); 77 78 // make associated form label trigger focus 79 this.element.bind({ 80 'click.selectmenu': function( event ) { 81 self.newelement.focus(); 82 event.preventDefault(); 83 } 84 }); 85 86 // click toggle for menu visibility 87 this.newelement 88 .bind('mousedown.selectmenu', function(event) { 89 self._toggle(event, true); 90 // make sure a click won't open/close instantly 91 if (o.style == "popup") { 92 self._safemouseup = false; 93 setTimeout(function() { self._safemouseup = true; }, 300); 94 } 95 return false; 96 }) 97 .bind('click.selectmenu', function() { 98 return false; 99 }) 100 .bind("keydown.selectmenu", function(event) { 101 var ret = false;
102 switch (event.keyCode) { 103 case $.ui.keyCode.ENTER: 104 ret = true; 105 break; 106 case $.ui.keyCode.SPACE: 107 self._toggle(event); 108 break; 109 case $.ui.keyCode.UP: 110 if (event.altKey) { 111 self.open(event); 112 } else { 113 self._moveSelection(-1); 114 } 115 break; 116 case $.ui.keyCode.DOWN: 117 if (event.altKey) { 118 self.open(event); 119 } else { 120 self._moveSelection(1); 121 } 122 break; 123 case $.ui.keyCode.LEFT: 124 self._moveSelection(-1); 125 break; 126 case $.ui.keyCode.RIGHT: 127 self._moveSelection(1); 128 break; 129 case $.ui.keyCode.TAB: 130 ret = true; 131 break; 132 case $.ui.keyCode.PAGE_UP: 133 case $.ui.keyCode.HOME: 134 self.index(0); 135 break; 136 case $.ui.keyCode.PAGE_DOWN: 137 case $.ui.keyCode.END: 138 self.index(self._optionLis.length); 139 break; 140 default: 141 ret = true; 142 } 143 return ret; 144 }) 145 .bind('keypress.selectmenu', function(event) { 146 if (event.which > 0) { 147 self._typeAhead(event.which, 'mouseup'); 148 } 149 return true; 150 }) 151 .bind('mouseover.selectmenu', function() { 152 if (!o.disabled) $(this).addClass('ui-state-hover'); 153 }) 154 .bind('mouseout.selectmenu', function() { 155 if (!o.disabled) $(this).removeClass('ui-state-hover'); 156 }) 157 .bind('focus.selectmenu', function() { 158 if (!o.disabled) $(this).addClass('ui-state-focus'); 159 }) 160 .bind('blur.selectmenu', function() { 161 if (!o.disabled) $(this).removeClass('ui-state-focus'); 162 }); 163 164 // document click closes menu 165 $(document).bind("mousedown.selectmenu-" + this.ids[0], function(event) { 166 if ( self.isOpen ) { 167 self.close( event ); 168 } 169 }); 170 171 // change event on original selectmenu 172 this.element 173 .bind("click.selectmenu", function() { 174 self._refreshValue(); 175 }) 176 // FIXME: newelement can be null under unclear circumstances in IE8 177 // TODO not sure if this is still a problem (fnagel 20.03.11) 178 .bind("focus.selectmenu", function() { 179 if (self.newelement) { 180 self.newelement[0].focus(); 181 } 182 }); 183 184 // set width when not set via options 185 if (!o.width) { 186 o.width = $('#VarietiesSelectMenu').width()-10; 187 //o.width = this.element.outerWidth(); 188 } 189 // set menu button width 190 this.newelement.width(o.width); 191 192 // hide original selectmenu element 193 this.element.hide(); 194 195 // create menu portion, append to body 196 this.list = $( '<ul />', { 197 'class': 'ui-widget ui-widget-content', 198 'aria-hidden': true, 199 'role': 'listbox', 200 'aria-labelledby': this.ids[1], 201 'id': this.ids[2] 202 }); 203 this.listWrap = $( "<div />", { 204 'class': self.widgetBaseClass + '-menu' 205 }).append( this.list ).appendTo( o.appendTo ); 206 207 // transfer menu click to menu button 208 this.list 209 .bind("keydown.selectmenu", function(event) { 210 var ret = false;
211 switch (event.keyCode) { 212 case $.ui.keyCode.UP: 213 if (event.altKey) { 214 self.close(event, true); 215 } else { 216 self._moveFocus(-1); 217 } 218 break; 219 case $.ui.keyCode.DOWN: 220 if (event.altKey) { 221 self.close(event, true); 222 } else { 223 self._moveFocus(1); 224 } 225 break; 226 case $.ui.keyCode.LEFT: 227 self._moveFocus(-1); 228 break; 229 case $.ui.keyCode.RIGHT: 230 self._moveFocus(1); 231 break; 232 case $.ui.keyCode.HOME: 233 self._moveFocus(':first'); 234 break; 235 case $.ui.keyCode.PAGE_UP: 236 self._scrollPage('up'); 237 break; 238 case $.ui.keyCode.PAGE_DOWN: 239 self._scrollPage('down'); 240 break; 241 case $.ui.keyCode.END: 242 self._moveFocus(':last'); 243 break; 244 case $.ui.keyCode.ENTER: 245 case $.ui.keyCode.SPACE: 246 self.close(event, true); 247 $(event.target).parents('li:eq(0)').trigger('mouseup'); 248 break; 249 case $.ui.keyCode.TAB: 250 ret = true; 251 self.close(event, true); 252 $(event.target).parents('li:eq(0)').trigger('mouseup'); 253 break; 254 case $.ui.keyCode.ESCAPE: 255 self.close(event, true); 256 break; 257 default: 258 ret = true; 259 } 260 return ret; 261 }) 262 .bind('keypress.selectmenu', function(event) { 263 if (event.which > 0) { 264 self._typeAhead(event.which, 'focus'); 265 } 266 return true; 267 }) 268 // this allows for using the scrollbar in an overflowed list 269 .bind( 'mousedown.selectmenu mouseup.selectmenu', function() { return false; }); 270 271 // needed when window is resized 272 $(window).bind( "resize.selectmenu-" + this.ids[0], $.proxy( self.close, this ) ); 273 }, 274 275 _init: function() { 276 var self = this, o = this.options; 277 278 // serialize selectmenu element options 279 var selectOptionData = []; 280 this.element.find('option').each(function() { 281 var opt = $(this); 282 selectOptionData.push({ 283 value: opt.attr('value'), 284 text: self._formatText(opt.text()), 285 selected: opt.prop('selected'), 286 disabled: opt.prop('disabled'), 287 classes: opt.attr('class'), 288 typeahead: opt.attr('typeahead'), 289 parentOptGroup: opt.parent('optgroup'), 290 bgImage: o.bgImage.call(opt) 291 }); 292 }); 293 294 // active state class is only used in popup style 295 var activeClass = (self.options.style == "popup") ? " ui-state-active" : ""; 296 297 // empty list so we can refresh the selectmenu via selectmenu() 298 this.list.html(""); 299 300 // write li's 301 if (selectOptionData.length) { 302 for (var i = 0; i < selectOptionData.length; i++) { 303 var thisLiAttr = { role : 'presentation' }; 304 if ( selectOptionData[ i ].disabled ) { 305 thisLiAttr[ 'class' ] = this.namespace + '-state-disabled'; 306 } 307 var thisAAttr = { 308 html: selectOptionData[i].text || ' ', 309 href : '#nogo', 310 tabindex : -1, 311 role : 'option', 312 'aria-selected' : false, 313 focus: function() { 314 // bubble the focus event 315 // TODO: this isnt a clean solution, see #241 316 $(this).parent().focus(); 317 } 318 }; 319 if ( selectOptionData[ i ].disabled ) { 320 thisAAttr[ 'aria-disabled' ] = selectOptionData[ i ].disabled; 321 } 322 if ( selectOptionData[ i ].typeahead ) { 323 thisAAttr[ 'typeahead' ] = selectOptionData[ i ].typeahead; 324 } 325 var thisA = $('<a/>', thisAAttr); 326 var thisLi = $('<li/>', thisLiAttr) 327 .append(thisA) 328 .data('index', i) 329 .addClass(selectOptionData[i].classes) 330 .data('optionClasses', selectOptionData[i].classes || '') 331 .bind("mouseup.selectmenu", function(event) { 332 if (self._safemouseup && !self._disabled(event.currentTarget) && !self._disabled($( event.currentTarget ).parents( "ul>li." + self.widgetBaseClass + "-group " )) ) { 333 var changed = $(this).data('index') != self._selectedIndex(); 334 self.index($(this).data('index')); 335 self.select(event); 336 if (changed) { 337 self.change(event); 338 } 339 self.close(event, true); 340 } 341 return false; 342 }) 343 .bind("click.selectmenu", function() { 344 return false; 345 }) 346 .bind('mouseover.selectmenu focus.selectmenu', function(e) { 347 // no hover if diabled 348 if (!$(e.currentTarget).hasClass(self.namespace + '-state-disabled') && !$(e.currentTarget).parent("ul").parent("li").hasClass(self.namespace + '-state-disabled')) { 349 self._selectedOptionLi().addClass(activeClass); 350 self._focusedOptionLi().removeClass(self.widgetBaseClass + '-item-focus ui-state-hover'); 351 $(this).removeClass('ui-state-active').addClass(self.widgetBaseClass + '-item-focus ui-state-hover'); 352 } 353 }) 354 .bind('mouseout.selectmenu blur.selectmenu', function() { 355 if ($(this).is(self._selectedOptionLi().selector)) { 356 $(this).addClass(activeClass); 357 } 358 $(this).removeClass(self.widgetBaseClass + '-item-focus ui-state-hover'); 359 }); 360 361 // optgroup or not... 362 if ( selectOptionData[i].parentOptGroup.length ) { 363 var optGroupName = self.widgetBaseClass + '-group-' + this.element.find( 'optgroup' ).index( selectOptionData[i].parentOptGroup ); 364 if (this.list.find( 'li.' + optGroupName ).length ) { 365 this.list.find( 'li.' + optGroupName + ':last ul' ).append( thisLi ); 366 } else { 367 $(' <li role="presentation" class="' + self.widgetBaseClass + '-group ' + optGroupName + (selectOptionData[i].parentOptGroup.prop("disabled") ? ' ' + this.namespace + '-state-disabled" aria-disabled="true"' : '"' ) + '><span class="' + self.widgetBaseClass + '-group-label">' + selectOptionData[i].parentOptGroup.attr('label') + '</span><ul></ul></li> ') 368 .appendTo( this.list ) 369 .find( 'ul' ) 370 .append( thisLi ); 371 } 372 } else { 373 thisLi.appendTo(this.list); 374 } 375 376 // append icon if option is specified 377 if (o.icons) { 378 for (var j in o.icons) { 379 if (thisLi.is(o.icons[j].find)) { 380 thisLi 381 .data('optionClasses', selectOptionData[i].classes + ' ' + self.widgetBaseClass + '-hasIcon') 382 .addClass(self.widgetBaseClass + '-hasIcon'); 383 var iconClass = o.icons[j].icon || ""; 384 thisLi 385 .find('a:eq(0)') 386 .prepend('<span class="' + self.widgetBaseClass + '-item-icon ui-icon ' + iconClass + '"></span>'); 387 if (selectOptionData[i].bgImage) { 388 thisLi.find('span').css('background-image', selectOptionData[i].bgImage); 389 } 390 } 391 } 392 } 393 } 394 } else { 395 $('<li role="presentation"><a href="#nogo" tabindex="-1" role="option"></a></li>').appendTo(this.list); 396 } 397 // we need to set and unset the CSS classes for dropdown and popup style 398 var isDropDown = ( o.style == 'dropdown' ); 399 this.newelement 400 .toggleClass( self.widgetBaseClass + '-dropdown', isDropDown ) 401 .toggleClass( self.widgetBaseClass + '-popup', !isDropDown ); 402 this.list 403 .toggleClass( self.widgetBaseClass + '-menu-dropdown ui-corner-bottom', isDropDown ) 404 .toggleClass( self.widgetBaseClass + '-menu-popup ui-corner-all', !isDropDown ) 405 // add corners to top and bottom menu items 406 .find( 'li:first' ) 407 .toggleClass( 'ui-corner-top', !isDropDown ) 408 .end().find( 'li:last' ) 409 .addClass( 'ui-corner-bottom' ); 410 this.selectmenuIcon 411 .toggleClass( 'ui-icon-triangle-1-s', isDropDown ) 412 .toggleClass( 'ui-icon-triangle-2-n-s', !isDropDown ); 413 414 // set menu width to either menuWidth option value, width option value, or select width 415 if ( o.style == 'dropdown' ) { 416 this.list.width( $('#VarietiesSelectMenu').width()-10/*o.menuWidth ? o.menuWidth : o.width*/ ); 417 } else { 418 this.list.width( $('#VarietiesSelectMenu').width()-40 /*o.menuWidth ? o.menuWidth : o.width - o.handleWidth */); 419 } 420 421 // reset height to auto 422 this.list.css( 'height', 'auto' ); 423 var listH = this.listWrap.height(); 424 var winH = $( window ).height(); 425 // calculate default max height 426 var maxH = o.maxHeight ? Math.min( o.maxHeight, winH ) : winH / 3; 427 if ( listH > maxH ) this.list.height( maxH ); 428 429 // save reference to actionable li's (not group label li's) 430 this._optionLis = this.list.find( 'li:not(.' + self.widgetBaseClass + '-group)' ); 431 432 // transfer disabled state 433 if ( this.element.attr( 'disabled' ) ) { 434 this.disable(); 435 } else { 436 this.enable(); 437 } 438 439 // update value 440 this._refreshValue(); 441
442 // set selected item so movefocus has intial state 443 this._selectedOptionLi().addClass(this.widgetBaseClass + '-item-focus'); 444 445 // needed when selectmenu is placed at the very bottom / top of the page 446 clearTimeout(this.refreshTimeout); 447 this.refreshTimeout = window.setTimeout(function () { 448 self._refreshPosition(); 449 }, 200); 450 }, 451 452 destroy: function() { 453 this.element.removeData( this.widgetName ) 454 .removeClass( this.widgetBaseClass + '-disabled' + ' ' + this.namespace + '-state-disabled' ) 455 .removeAttr( 'aria-disabled' ) 456 .unbind( ".selectmenu" ); 457 458 $( window ).unbind( ".selectmenu-" + this.ids[0] ); 459 $( document ).unbind( ".selectmenu-" + this.ids[0] ); 460 461 this.newelementWrap.remove(); 462 this.listWrap.remove(); 463 464 // unbind click event and show original select 465 this.element 466 .unbind(".selectmenu") 467 .show(); 468 469 // call widget destroy function 470 $.Widget.prototype.destroy.apply(this, arguments); 471 }, 472 473 _typeAhead: function( code, eventType ) { 474 var self = this, 475 c = String.fromCharCode(code).toLowerCase(), 476 matchee = null, 477 nextIndex = null; 478 479 // Clear any previous timer if present 480 if ( self._typeAhead_timer ) { 481 window.clearTimeout( self._typeAhead_timer ); 482 self._typeAhead_timer = undefined; 483 } 484 485 // Store the character typed 486 self._typeAhead_chars = (self._typeAhead_chars === undefined ? "" : self._typeAhead_chars).concat(c); 487 488 // Detect if we are in cyciling mode or direct selection mode 489 if ( self._typeAhead_chars.length < 2 || 490 (self._typeAhead_chars.substr(-2, 1) === c && self._typeAhead_cycling) ) { 491 self._typeAhead_cycling = true; 492 493 // Match only the first character and loop 494 matchee = c; 495 } 496 else { 497 // We won't be cycling anymore until the timer expires 498 self._typeAhead_cycling = false; 499 500 // Match all the characters typed 501 matchee = self._typeAhead_chars; 502 } 503 504 // We need to determine the currently active index, but it depends on 505 // the used context: if it's in the element, we want the actual 506 // selected index, if it's in the menu, just the focused one 507 // I copied this code from _moveSelection() and _moveFocus() 508 // respectively --thg2k 509 var selectedIndex = (eventType !== 'focus' ? 510 this._selectedOptionLi().data('index') : 511 this._focusedOptionLi().data('index')) || 0; 512 513 for (var i = 0; i < this._optionLis.length; i++) { 514 var thisText = this._optionLis.eq(i).text().substr(0, matchee.length).toLowerCase(); 515 516 if ( thisText === matchee ) { 517 if ( self._typeAhead_cycling ) { 518 if ( nextIndex === null ) 519 nextIndex = i; 520 521 if ( i > selectedIndex ) { 522 nextIndex = i; 523 break; 524 } 525 } else { 526 nextIndex = i; 527 } 528 } 529 } 530 531 if ( nextIndex !== null ) { 532 // Why using trigger() instead of a direct method to select the 533 // index? Because we don't what is the exact action to do, it 534 // depends if the user is typing on the element or on the popped 535 // up menu 536 this._optionLis.eq(nextIndex).find("a").trigger( eventType ); 537 } 538 539 self._typeAhead_timer = window.setTimeout(function() { 540 self._typeAhead_timer = undefined; 541 self._typeAhead_chars = undefined; 542 self._typeAhead_cycling = undefined; 543 }, self.options.typeAhead); 544 }, 545 546 // returns some usefull information, called by callbacks only 547 _uiHash: function() { 548 var index = this.index(); 549 return { 550 index: index, 551 option: $("option", this.element).get(index), 552 value: this.element[0].value 553 }; 554 }, 555 556 open: function(event) { 557 var self = this, o = this.options; 558 if ( self.newelement.attr("aria-disabled") != 'true' ) { 559 self._closeOthers(event); 560 self.newelement.addClass('ui-state-active'); 561 562 self.list.attr('aria-hidden', false);
563 self.listWrap.addClass( self.widgetBaseClass + '-open' ); 564 565 var selected = this._selectedOptionLi(); 566 if ( o.style == "dropdown" ) { 567 self.newelement.removeClass('ui-corner-all').addClass('ui-corner-top'); 568 } else { 569 // center overflow and avoid flickering 570 this.list 571 .css("left", -5000) 572 .scrollTop( this.list.scrollTop() + selected.position().top - this.list.outerHeight()/2 + selected.outerHeight()/2 ) 573 .css("left","auto"); 574 } 575 576 self._refreshPosition(); 577 578 var link = selected.find("a"); 579 if (link.length) link[0].focus(); 580 581 self.isOpen = true; 582 self._trigger("open", event, self._uiHash()); 583 } 584 }, 585 586 close: function(event, retainFocus) { 587 if ( this.newelement.is('.ui-state-active') ) { 588 this.newelement 589 .removeClass('ui-state-active'); 590 this.listWrap.removeClass(this.widgetBaseClass + '-open'); 591 this.list.attr('aria-hidden', true); 592 if ( this.options.style == "dropdown" ) { 593 this.newelement.removeClass('ui-corner-top').addClass('ui-corner-all'); 594 } 595 if ( retainFocus ) { 596 this.newelement.focus(); 597 } 598 this.isOpen = false; 599 this._trigger("close", event, this._uiHash()); 600 } 601 }, 602/* 603 jed: function() { 604 var element = document.getElementById("nextLine"); 605 element.setAttribute("class", "ui-selectmenu-item-content"); 606 element.setAttribute("className", "ui-selectmenu-item-content");// pro IE 607 this.element.removeClass("ui-selectmenu-item-content-detail").addClass("ui-selectmenu-item-content"); 608 }, 609*/ 610 611 change: function(event) { 612 this.element.trigger("change"); 613 this._trigger("change", event, this._uiHash()); 614 }, 615 616 select: function(event) { 617 if (this._disabled(event.currentTarget)) { return false; } 618 this._trigger("select", event, this._uiHash()); 619 }, 620 621 widget: function() { 622 return this.listWrap.add( this.newelementWrap ); 623 }, 624 625 _closeOthers: function(event) { 626 $('.' + this.widgetBaseClass + '.ui-state-active').not(this.newelement).each(function() { 627 $(this).data('selectelement').selectmenu('close', event); 628 }); 629 $('.' + this.widgetBaseClass + '.ui-state-hover').trigger('mouseout'); 630 }, 631 632 _toggle: function(event, retainFocus) { 633 if ( this.isOpen ) { 634 this.close(event, retainFocus); 635 } else { 636 this.open(event); 637 } 638 }, 639 640 _formatText: function(text) { 641 if (this.options.format) { 642 text = this.options.format(text); 643 } else if (this.options.escapeHtml) { 644 text = $('<div />').text(text).html(); 645 } 646 return text; 647 }, 648 649 _selectedIndex: function() { 650 return this.element[0].selectedIndex; 651 }, 652 653 _selectedOptionLi: function() { 654 return this._optionLis.eq(this._selectedIndex()); 655 }, 656 657 _focusedOptionLi: function() { 658 return this.list.find('.' + this.widgetBaseClass + '-item-focus'); 659 }, 660 661 _moveSelection: function(amt, recIndex) { 662 // do nothing if disabled 663 if (!this.options.disabled) { 664 var currIndex = parseInt(this._selectedOptionLi().data('index') || 0, 10); 665 var newIndex = currIndex + amt; 666 // do not loop when using up key 667 668 if (newIndex < 0) { 669 newIndex = 0; 670 } 671 if (newIndex > this._optionLis.size() - 1) { 672 newIndex = this._optionLis.size() - 1; 673 } 674 // Occurs when a full loop has been made 675 if (newIndex === recIndex) { return false; } 676 677 if (this._optionLis.eq(newIndex).hasClass( this.namespace + '-state-disabled' )) { 678 // if option at newIndex is disabled, call _moveFocus, incrementing amt by one 679 (amt > 0) ? ++amt : --amt; 680 this._moveSelection(amt, newIndex); 681 } else { 682 this._optionLis.eq(newIndex).trigger('mouseover').trigger('mouseup'); 683 } 684 } 685 }, 686 687 _moveFocus: function(amt, recIndex) { 688 if (!isNaN(amt)) { 689 var currIndex = parseInt(this._focusedOptionLi().data('index') || 0, 10); 690 var newIndex = currIndex + amt; 691 } else { 692 var newIndex = parseInt(this._optionLis.filter(amt).data('index'), 10); 693 } 694 695 if (newIndex < 0) { 696 newIndex = 0; 697 } 698 if (newIndex > this._optionLis.size() - 1) { 699 newIndex = this._optionLis.size() - 1; 700 } 701 702 //Occurs when a full loop has been made 703 if (newIndex === recIndex) { return false; } 704 705 var activeID = this.widgetBaseClass + '-item-' + Math.round(Math.random() * 1000); 706 707 this._focusedOptionLi().find('a:eq(0)').attr('id', ''); 708 709 if (this._optionLis.eq(newIndex).hasClass( this.namespace + '-state-disabled' )) { 710 // if option at newIndex is disabled, call _moveFocus, incrementing amt by one 711 (amt > 0) ? ++amt : --amt; 712 this._moveFocus(amt, newIndex); 713 } else { 714 this._optionLis.eq(newIndex).find('a:eq(0)').attr('id',activeID).focus(); 715 } 716 717 this.list.attr('aria-activedescendant', activeID); 718 }, 719 720 _scrollPage: function(direction) { 721 var numPerPage = Math.floor(this.list.outerHeight() / this._optionLis.first().outerHeight()); 722 numPerPage = (direction == 'up' ? -numPerPage : numPerPage); 723 this._moveFocus(numPerPage); 724 }, 725 726 _setOption: function(key, value) { 727 this.options[key] = value; 728 // set 729 if (key == 'disabled') { 730 if (value) this.close(); 731 this.element 732 .add(this.newelement) 733 .add(this.list)[value ? 'addClass' : 'removeClass']( 734 this.widgetBaseClass + '-disabled' + ' ' + 735 this.namespace + '-state-disabled') 736 .attr("aria-disabled", value); 737 } 738 }, 739 740 disable: function(index, type){ 741 // if options is not provided, call the parents disable function 742 if ( typeof( index ) == 'undefined' ) { 743 this._setOption( 'disabled', true ); 744 } else { 745 if ( type == "optgroup" ) { 746 this._disableOptgroup(index); 747 } else { 748 this._disableOption(index); 749 } 750 } 751 }, 752 753 enable: function(index, type) { 754 // if options is not provided, call the parents enable function 755 if ( typeof( index ) == 'undefined' ) { 756 this._setOption('disabled', false); 757 } else { 758 if ( type == "optgroup" ) { 759 this._enableOptgroup(index); 760 } else { 761 this._enableOption(index); 762 } 763 } 764 }, 765 766 _disabled: function(elem) { 767 return $(elem).hasClass( this.namespace + '-state-disabled' ); 768 }, 769 770 771 _disableOption: function(index) { 772 var optionElem = this._optionLis.eq(index); 773 if (optionElem) { 774 optionElem.addClass(this.namespace + '-state-disabled') 775 .find("a").attr("aria-disabled", true); 776 this.element.find("option").eq(index).prop("disabled", "disabled"); 777 } 778 }, 779 780 _enableOption: function(index) { 781 var optionElem = this._optionLis.eq(index); 782 if (optionElem) { 783 optionElem.removeClass( this.namespace + '-state-disabled' ) 784 .find("a").attr("aria-disabled", false);
785 this.element.find("option").eq(index).prop("disabled",false); 786 } 787 }, 788 789 _disableOptgroup: function(index) { 790 var optGroupElem = this.list.find( 'li.' + this.widgetBaseClass + '-group-' + index ); 791 if (optGroupElem) { 792 optGroupElem.addClass(this.namespace + '-state-disabled') 793 .attr("aria-disabled", true); 794 this.element.find("optgroup").eq(index).prop("disabled", "disabled"); 795 } 796 }, 797 798 _enableOptgroup: function(index) { 799 var optGroupElem = this.list.find( 'li.' + this.widgetBaseClass + '-group-' + index ); 800 if (optGroupElem) { 801 optGroupElem.removeClass(this.namespace + '-state-disabled') 802 .attr("aria-disabled", false); 803 this.element.find("optgroup").eq(index).removeAttr("disabled"); 804 } 805 }, 806 807 index: function(newValue) { 808 if (arguments.length) { 809 if (!this._disabled($(this._optionLis[newValue]))) { 810 this.element[0].selectedIndex = newValue; 811 this._refreshValue(); 812 } else { 813 return false; 814 } 815 } else { 816 return this._selectedIndex(); 817 } 818 }, 819 820 value: function(newValue) { 821 if (arguments.length) { 822 this.element[0].value = newValue; 823 this._refreshValue(); 824 } else { 825 return this.element[0].value; 826 } 827 }, 828 829 _refreshValue: function() { 830 var activeClass = (this.options.style == "popup") ? " ui-state-active" : ""; 831 var activeID = this.widgetBaseClass + '-item-' + Math.round(Math.random() * 1000); 832 // deselect previous 833 this.list 834 .find('.' + this.widgetBaseClass + '-item-selected') 835 .removeClass(this.widgetBaseClass + "-item-selected" + activeClass) 836 .find('a') 837 .attr('aria-selected', 'false') 838 .attr('id', ''); 839 // select new 840 this._selectedOptionLi() 841 .addClass(this.widgetBaseClass + "-item-selected" + activeClass) 842 .find('a') 843 .attr('aria-selected', 'true') 844 .attr('id', activeID); 845 846 // toggle any class brought in from option 847 var currentOptionClasses = (this.newelement.data('optionClasses') ? this.newelement.data('optionClasses') : ""); 848 var newOptionClasses = (this._selectedOptionLi().data('optionClasses') ? this._selectedOptionLi().data('optionClasses') : ""); 849 this.newelement 850 .removeClass(currentOptionClasses) 851 .data('optionClasses', newOptionClasses) 852 .addClass( newOptionClasses ) 853 .find('.' + this.widgetBaseClass + '-status') 854 .html( 855 this._selectedOptionLi() 856 .find('a:eq(0)') 857 .html() 858 ); 859 860 this.list.attr('aria-activedescendant', activeID); 861 }, 862 863 _refreshPosition: function() { 864 var o = this.options; 865 866 // if its a pop-up we need to calculate the position of the selected li 867 if ( o.style == "popup" && !o.positionOptions.offset ) { 868 var selected = this._selectedOptionLi(); 869 var _offset = "0 " + ( this.list.offset().top - selected.offset().top - ( this.newelement.outerHeight() + selected.outerHeight() ) / 2); 870 } 871 this.listWrap 872 .removeAttr('style') 873 .zIndex( this.element.zIndex() + 1000000 ) 874 .css('position', 'absolute') 875 .position({ 876 // set options for position plugin 877 of: o.positionOptions.of || this.newelement, 878 my: o.positionOptions.my, 879 at: o.positionOptions.at, 880 offset: o.positionOptions.offset || _offset, 881 collision: o.positionOptions.collision || o.style == "popup" ? 'fit' :'flip' 882 }); 883 } 884}); 885 886})(jQuery);
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.