1/* 2 * jQuery selectBox - A cosmetic, styleable replacement for SELECT elements 3 * 4 * Licensed under the MIT license: http://opensource.org/licenses/MIT 5 * 6 * v1.2.0 7 * 8 * https://github.com/marcj/jquery-selectBox 9 */ 10 11 12;(function ($) { 13 14 /** 15 * SelectBox class. 16 * 17 * @param {HTMLElement|jQuery} select If it's a jQuery object, we use the first element. 18 * @param {Object} options 19 * @constructor 20 */ 21 var SelectBox = window.SelectBox = function (select, options) { 22 if (select instanceof jQuery) { 23 if (select.length > 0) { 24 select = select[0]; 25 } else { 26 return; 27 } 28 } 29 30 this.typeTimer = null; 31 this.typeSearch = ''; 32 this.isMac = navigator.platform.match(/mac/i); 33 options = 'object' === typeof options ? options : {}; 34 this.selectElement = select; 35 36 // Disable for iOS devices (their native controls are more suitable for a touch device) 37 if (!options.mobile && navigator.userAgent.match(/iPad|iPhone|Android|IEMobile|BlackBerry/i)) { 38 return false; 39 } 40 41 // Element must be a select control 42 if ('select' !== select.tagName.toLowerCase()) { 43 return false; 44 } 45 46 this.init(options); 47 }; 48 49 /** 50 * @type {String} 51 */ 52 SelectBox.prototype.version = '1.2.0'; 53 54 /** 55 * @param {Object} options 56 * 57 * @returns {Boolean} 58 */ 59 SelectBox.prototype.init = function (options) { 60 var select = $(this.selectElement); 61 if (select.data('selectBox-control')) { 62 return false; 63 } 64 65 var control = $('<a class="selectBox" />') 66 , inline = select.attr('multiple') || parseInt(select.attr('size')) > 1 67 , settings = options || {} 68 , tabIndex = parseInt(select.prop('tabindex')) || 0 69 , self = this; 70 71 control 72 .width(select.outerWidth()) 73 .addClass(select.attr('class')) 74 .attr('title', select.attr('title') || '') 75 .attr('tabindex', tabIndex) 76 .css('display', 'inline-block') 77 .bind('focus.selectBox', function () { 78 if (this !== document.activeElement && document.body !== document.activeElement) { 79 $(document.activeElement).blur(); 80 } 81 if (control.hasClass('selectBox-active')) { 82 return; 83 } 84 control.addClass('selectBox-active'); 85 select.trigger('focus'); 86 }) 87 .bind('blur.selectBox', function () { 88 if (!control.hasClass('selectBox-active')) { 89 return; 90 } 91 control.removeClass('selectBox-active'); 92 select.trigger('blur'); 93 }); 94 95 if (!$(window).data('selectBox-bindings')) { 96 $(window) 97 .data('selectBox-bindings', true) 98 .bind('scroll.selectBox', (settings.hideOnWindowScroll) ? this.hideMenus : $.noop) 99 .bind('resize.selectBox', this.hideMenus); 100 } 101 102 if (select.attr('disabled')) { 103 control.addClass('selectBox-disabled'); 104 } 105 106 // Focus on control when label is clicked 107 select.bind('click.selectBox', function (event) { 108 control.focus(); 109 event.preventDefault(); 110 }); 111 112 // Generate control 113 if (inline) { 114 // Inline controls 115 options = this.getOptions('inline'); 116 117 control 118 .append(options) 119 .data('selectBox-options', options).addClass('selectBox-inline selectBox-menuShowing') 120 .bind('keydown.selectBox', function (event) { 121 self.handleKeyDown(event); 122 }) 123 .bind('keypress.selectBox',function (event) { 124 self.handleKeyPress(event); 125 }) 126 .bind('mousedown.selectBox',function (event) { 127 if (1 !== event.which) { 128 return; 129 } 130 if ($(event.target).is('A.selectBox-inline')) { 131 event.preventDefault(); 132 } 133 if (!control.hasClass('selectBox-focus')) { 134 control.focus(); 135 } 136 }) 137 .insertAfter(select); 138 139 // Auto-height based on size attribute 140 if (!select[0].style.height) { 141 var size = select.attr('size') ? parseInt(select.attr('size')) : 5; 142 // Draw a dummy control off-screen, measure, and remove it 143 var tmp = control 144 .clone() 145 .removeAttr('id') 146 .css({ 147 position: 'absolute', 148 top: '-9999em' 149 }) 150 .show() 151 .appendTo('body'); 152 tmp.find('.selectBox-options').html('<li><a>\u00A0</a></li>'); 153 var optionHeight = parseInt(tmp.find('.selectBox-options A:first').html(' ').outerHeight()); 154 tmp.remove(); 155 control.height(optionHeight * size); 156 } 157 this.disableSelection(control); 158 } else { 159 // Dropdown controls 160 var label = $('<span class="selectBox-label" />'), 161 arrow = $('<span class="selectBox-arrow" />'); 162 163 // Update label 164 label.attr('class', this.getLabelClass()).html(this.getLabelHtml()); 165 options = this.getOptions('dropdown'); 166 options.appendTo('BODY'); 167 168 control 169 .data('selectBox-options', options) 170 .addClass('selectBox-dropdown') 171 .append(label) 172 .append(arrow) 173 .bind('mousedown.selectBox', function (event) { 174 if (1 === event.which) { 175 if (control.hasClass('selectBox-menuShowing')) { 176 self.hideMenus(); 177 } else { 178 event.stopPropagation(); 179 // Webkit fix to prevent premature selection of options 180 options 181 .data('selectBox-down-at-x', event.screenX) 182 .data('selectBox-down-at-y', event.screenY); 183 self.showMenu(); 184 } 185 } 186 }) 187 .bind('keydown.selectBox', function (event) { 188 self.handleKeyDown(event); 189 }) 190 .bind('keypress.selectBox', function (event) { 191 self.handleKeyPress(event); 192 }) 193 .bind('open.selectBox',function (event, triggerData) { 194 if (triggerData && triggerData._selectBox === true) { 195 return; 196 } 197 self.showMenu(); 198 }) 199 .bind('close.selectBox', function (event, triggerData) { 200 if (triggerData && triggerData._selectBox === true) { 201 return; 202 } 203 self.hideMenus(); 204 }) 205 .insertAfter(select); 206 207 // Set label width 208 var labelWidth = 209 control.width() 210 - arrow.outerWidth() 211 - (parseInt(label.css('paddingLeft')) || 0) 212 - (parseInt(label.css('paddingRight')) || 0); 213 214 label.width(labelWidth); 215 this.disableSelection(control); 216 } 217 // Store data for later use and show the control 218 select 219 .addClass('selectBox') 220 .data('selectBox-control', control) 221 .data('selectBox-settings', settings) 222 .hide(); 223 }; 224 225 /** 226 * @param {String} type 'inline'|'dropdown' 227 * @returns {jQuery} 228 */ 229 SelectBox.prototype.getOptions = function (type) { 230 var options; 231 var select = $(this.selectElement); 232 var self = this; 233 // Private function to handle recursion in the getOptions function. 234 var _getOptions = function (select, options) { 235 // Loop through the set in order of element children. 236 select.children('OPTION, OPTGROUP').each(function () { 237 // If the element is an option, add it to the list. 238 if ($(this).is('OPTION')) { 239 // Check for a value in the option found. 240 if ($(this).length > 0) { 241 // Create an option form the found element. 242 self.generateOptions($(this), options); 243 } else { 244 // No option information found, so add an empty. 245 options.append('<li>\u00A0</li>'); 246 } 247 } else { 248 // If the element is an option group, add the group and call this function on it. 249 var optgroup = $('<li class="selectBox-optgroup" />'); 250 optgroup.text($(this).attr('label')); 251 options.append(optgroup); 252 options = _getOptions($(this), options); 253 } 254 }); 255 // Return the built strin 256 return options; 257 }; 258 259 switch (type) { 260 case 'inline': 261 options = $('<ul class="selectBox-options" />'); 262 options = _getOptions(select, options); 263 options 264 .find('A') 265 .bind('mouseover.selectBox', function (event) { 266 self.addHover($(this).parent()); 267 }) 268 .bind('mouseout.selectBox',function (event) { 269 self.removeHover($(this).parent()); 270 }) 271 .bind('mousedown.selectBox',function (event) { 272 if (1 !== event.which) { 273 return 274 } 275 event.preventDefault(); // Prevent options from being "dragged" 276 if (!select.selectBox('control').hasClass('selectBox-active')) { 277 select.selectBox('control').focus(); 278 } 279 }) 280 .bind('mouseup.selectBox', function (event) { 281 if (1 !== event.which) { 282 return; 283 } 284 self.hideMenus(); 285 self.selectOption($(this).parent(), event); 286 }); 287 288 this.disableSelection(options); 289 return options; 290 case 'dropdown': 291 options = $('<ul class="selectBox-dropdown-menu selectBox-options" />'); 292 options = _getOptions(select, options); 293 294 options 295 .data('selectBox-select', select) 296 .css('display', 'none') 297 .appendTo('BODY') 298 .find('A') 299 .bind('mousedown.selectBox', function (event) { 300 if (event.which === 1) { 301 event.preventDefault(); // Prevent options from being "dragged" 302 if (event.screenX === options.data('selectBox-down-at-x') && 303 event.screenY === options.data('selectBox-down-at-y')) { 304 options.removeData('selectBox-down-at-x').removeData('selectBox-down-at-y'); 305 if (/android/i.test(navigator.userAgent.toLowerCase()) && 306 /chrome/i.test(navigator.userAgent.toLowerCase())) { 307 self.selectOption($(this).parent()); 308 } 309 self.hideMenus(); 310 } 311 } 312 }) 313 .bind('mouseup.selectBox', function (event) { 314 if (1 !== event.which) { 315 return; 316 } 317 if (event.screenX === options.data('selectBox-down-at-x') && 318 event.screenY === options.data('selectBox-down-at-y')) { 319 return; 320 } else { 321 options.removeData('selectBox-down-at-x').removeData('selectBox-down-at-y'); 322 } 323 self.selectOption($(this).parent()); 324 self.hideMenus(); 325 }) 326 .bind('mouseover.selectBox', function (event) { 327 self.addHover($(this).parent()); 328 }) 329 .bind('mouseout.selectBox', function (event) { 330 self.removeHover($(this).parent()); 331 }); 332 333 // Inherit classes for dropdown menu 334 var classes = select.attr('class') || ''; 335 if ('' !== classes) { 336 classes = classes.split(' '); 337 for (var i = 0; i < classes.length; i++) {
338 options.addClass(classes[i] + '-selectBox-dropdown-menu'); 339 } 340 341 } 342 this.disableSelection(options); 343 return options; 344 } 345 }; 346 347 /** 348 * Returns the current class of the selected option. 349 * 350 * @returns {String} 351 */ 352 SelectBox.prototype.getLabelClass = function () { 353 var selected = $(this.selectElement).find('OPTION:selected'); 354 return ('selectBox-label ' + (selected.attr('class') || '')).replace(/\s+$/, ''); 355 }; 356 357 /** 358 * Returns the current label of the selected option. 359 * 360 * @returns {String} 361 */ 362 SelectBox.prototype.getLabelHtml = function () { 363 var selected = $(this.selectElement).find('OPTION:selected'); 364 var labelHtml; 365 if (selected.data('icon')) { 366 labelHtml = '<i class="fa fa-'+selected.data('icon')+' fa-fw fa-lg"></i> '+selected.text(); 367 } else { 368 labelHtml = selected.text(); 369 } 370 return labelHtml || '\u00A0'; 371 }; 372 373 /** 374 * Sets the label. 375 * This method uses the getLabelClass() and getLabelHtml() methods. 376 */ 377 SelectBox.prototype.setLabel = function () { 378 var select = $(this.selectElement); 379 var control = select.data('selectBox-control'); 380 if (!control) { 381 return; 382 } 383 384 control 385 .find('.selectBox-label') 386 .attr('class', this.getLabelClass()) 387 .html(this.getLabelHtml()); 388 }; 389 390 /** 391 * Destroys the SelectBox instance and shows the origin select element. 392 * 393 */ 394 SelectBox.prototype.destroy = function () { 395 var select = $(this.selectElement); 396 var control = select.data('selectBox-control'); 397 if (!control) { 398 return; 399 } 400 401 var options = control.data('selectBox-options'); 402 options.remove(); 403 control.remove(); 404 select 405 .removeClass('selectBox') 406 .removeData('selectBox-control') 407 .data('selectBox-control', null) 408 .removeData('selectBox-settings') 409 .data('selectBox-settings', null) 410 .show(); 411 }; 412 413 /** 414 * Refreshes the option elements. 415 */ 416 SelectBox.prototype.refresh = function () { 417 var select = $(this.selectElement) 418 , control = select.data('selectBox-control') 419 , type = control.hasClass('selectBox-dropdown') ? 'dropdown' : 'inline' 420 , options; 421 422 // Remove old options 423 control.data('selectBox-options').remove(); 424 425 // Generate new options 426 options = this.getOptions(type); 427 control.data('selectBox-options', options); 428 429 switch (type) { 430 case 'inline': 431 control.append(options); 432 break; 433 case 'dropdown': 434 // Update label 435 this.setLabel(); 436 $("BODY").append(options); 437 break; 438 } 439 440 // Restore opened dropdown state (original menu was trashed) 441 if ('dropdown' === type && control.hasClass('selectBox-menuShowing')) { 442 this.showMenu(); 443 } 444 }; 445 446 /** 447 * Shows the dropdown menu. 448 */ 449 SelectBox.prototype.showMenu = function () { 450 var self = this 451 , select = $(this.selectElement) 452 , control = select.data('selectBox-control') 453 , settings = select.data('selectBox-settings') 454 , options = control.data('selectBox-options'); 455 456 if (control.hasClass('selectBox-disabled')) { 457 return false; 458 } 459 460 this.hideMenus(); 461 462 // Get top and bottom width of selectBox 463 var borderBottomWidth = parseInt(control.css('borderBottomWidth')) || 0; 464 var borderTopWidth = parseInt(control.css('borderTopWidth')) || 0; 465 466 // Get proper variables for keeping options in viewport 467 var pos = control.offset() 468 , topPositionCorrelation = (settings.topPositionCorrelation) ? settings.topPositionCorrelation : 0 469 , bottomPositionCorrelation = (settings.bottomPositionCorrelation) ? settings.bottomPositionCorrelation : 0 470 , optionsHeight = options.outerHeight() 471 , controlHeight = control.outerHeight() 472 , maxHeight = parseInt(options.css('max-height')) 473 , scrollPos = $(window).scrollTop() 474 , heightToTop = pos.top - scrollPos 475 , heightToBottom = $(window).height() - ( heightToTop + controlHeight ) 476 , posTop = (heightToTop >
476 heightToBottom) && (settings.keepInViewport == null ? true : settings.keepInViewport) 477 , width = control.innerWidth() >= options.innerWidth() ? control.innerWidth() + 'px' : 'auto' 478 , top = posTop 479 ? pos.top - optionsHeight + borderTopWidth + topPositionCorrelation 480 : pos.top + controlHeight - borderBottomWidth - bottomPositionCorrelation; 481 482 483 // If the height to top and height to bottom are less than the max-height 484 if(heightToTop < maxHeight&& heightToBottom < maxHeight){ 485 486 // Set max-height and top 487 if(posTop){ 488 var maxHeightDiff = maxHeight - ( heightToTop - 5 ); 489 options.css({'max-height': maxHeight - maxHeightDiff + 'px'}); 490 top = top + maxHeightDiff; 491 }else{ 492 var maxHeightDiff = maxHeight - ( heightToBottom - 5 ); 493 options.css({'max-height': maxHeight - maxHeightDiff + 'px'}); 494 } 495 496 } 497 498 // Save if position is top to options data 499 options.data('posTop',posTop); 500 501 502 // Menu position 503 options 504 .width(width) 505 .css({ 506 top: top, 507 left: control.offset().left 508 }) 509 // Add Top and Bottom class based on position 510 .addClass('selectBox-options selectBox-options-'+(posTop?'top':'bottom')); 511 512 if (settings.styleClass) { 513 options.addClass(settings.styleClass); 514 } 515 516 if (select.triggerHandler('beforeopen')) { 517 return false; 518 } 519 520 var dispatchOpenEvent = function () { 521 select.triggerHandler('open', { 522 _selectBox: true 523 }); 524 }; 525 526 // Show menu 527 switch (settings.menuTransition) { 528 case 'fade': 529 options.fadeIn(settings.menuSpeed, dispatchOpenEvent); 530 break; 531 case 'slide': 532 options.slideDown(settings.menuSpeed, dispatchOpenEvent); 533 break; 534 default: 535 options.show(settings.menuSpeed, dispatchOpenEvent); 536 break; 537 } 538 539 if (!settings.menuSpeed) { 540 dispatchOpenEvent(); 541 } 542 543 // Center on selected option 544 var li = options.find('.selectBox-selected:first'); 545 this.keepOptionInView(li, true); 546 this.addHover(li); 547 control.addClass('selectBox-menuShowing selectBox-menuShowing-'+(posTop?'top':'bottom')); 548 549 $(document).bind('mousedown.selectBox', function (event) { 550 if (1 === event.which) { 551 if ($(event.target).parents().andSelf().hasClass('selectBox-options')) { 552 return; 553 } 554 self.hideMenus(); 555 } 556 }); 557 }; 558 559 /** 560 * Hides the menu of all instances. 561 */ 562 SelectBox.prototype.hideMenus = function () { 563 if ($(".selectBox-dropdown-menu:visible").length === 0) { 564 return; 565 } 566 567 $(document).unbind('mousedown.selectBox'); 568 $(".selectBox-dropdown-menu").each(function () { 569 var options = $(this) 570 , select = options.data('selectBox-select') 571 , control = select.data('selectBox-control') 572 , settings = select.data('selectBox-settings') 573 , posTop = options.data('posTop'); 574 575 if (select.triggerHandler('beforeclose')) { 576 return false; 577 } 578 579 var dispatchCloseEvent = function () { 580 select.triggerHandler('close', { 581 _selectBox: true 582 }); 583 }; 584 if (settings) { 585 switch (settings.menuTransition) { 586 case 'fade': 587 options.fadeOut(settings.menuSpeed, dispatchCloseEvent); 588 break; 589 case 'slide': 590 options.slideUp(settings.menuSpeed, dispatchCloseEvent); 591 break; 592 default: 593 options.hide(settings.menuSpeed, dispatchCloseEvent); 594 break; 595 } 596 if (!settings.menuSpeed) { 597 dispatchCloseEvent(); 598 } 599 control.removeClass('selectBox-menuShowing selectBox-menuShowing-'+(posTop?'top':'bottom')); 600 } else { 601 $(this).hide(); 602 $(this).triggerHandler('close', { 603 _selectBox: true 604 }); 605 $(this).removeClass('selectBox-menuShowing selectBox-menuShowing-'+(posTop?'top':'bottom')); 606 } 607 608 options.css('max-height',''); 609 //Remove Top or Bottom class based on position 610 options.removeClass('selectBox-options-'+(posTop?'top':'bottom')); 611 options.data('posTop' , false); 612 }); 613 }; 614 615 /** 616 * Selects an option. 617 * 618 * @param {HTMLElement} li 619 * @param {DOMEvent} event 620 * @returns {Boolean} 621 */ 622 SelectBox.prototype.selectOption = function (li, event) { 623 var select = $(this.selectElement); 624 li = $(li); 625 626 var control = select.data('selectBox-control') 627 , settings = select.data('selectBox-settings'); 628 629 if (control.hasClass('selectBox-disabled')) { 630 return false;
631 } 632 633 if (0 === li.length || li.hasClass('selectBox-disabled')) { 634 return false; 635 } 636 637 if (select.attr('multiple')) { 638 // If event.shiftKey is true, this will select all options between li and the last li selected 639 if (event.shiftKey && control.data('selectBox-last-selected')) { 640 li.toggleClass('selectBox-selected'); 641 var affectedOptions; 642 if (li.index() > control.data('selectBox-last-selected').index()) { 643 affectedOptions = li 644 .siblings() 645 .slice(control.data('selectBox-last-selected').index(), li.index()); 646 } else { 647 affectedOptions = li 648 .siblings() 649 .slice(li.index(), control.data('selectBox-last-selected').index()); 650 } 651 affectedOptions = affectedOptions.not('.selectBox-optgroup, .selectBox-disabled'); 652 if (li.hasClass('selectBox-selected')) { 653 affectedOptions.addClass('selectBox-selected'); 654 } else { 655 affectedOptions.removeClass('selectBox-selected'); 656 } 657 } else if ((this.isMac && event.metaKey) || (!this.isMac && event.ctrlKey)) { 658 li.toggleClass('selectBox-selected'); 659 } else { 660 li.siblings().removeClass('selectBox-selected'); 661 li.addClass('selectBox-selected'); 662 } 663 } else { 664 li.siblings().removeClass('selectBox-selected'); 665 li.addClass('selectBox-selected'); 666 } 667 668 if (control.hasClass('selectBox-dropdown')) { 669 control.find('.selectBox-label').html(li.html()); 670 } 671 672 // Update original control's value 673 var i = 0, selection = []; 674 if (select.attr('multiple')) { 675 control.find('.selectBox-selected A').each(function () { 676 selection[i++] = $(this).attr('rel'); 677 }); 678 } else { 679 selection = li.find('A').attr('rel'); 680 } 681 682 // Remember most recently selected item 683 control.data('selectBox-last-selected', li); 684 685 // Change callback 686 if (select.val() !== selection) { 687 select.val(selection); 688 this.setLabel(); 689 select.trigger('change'); 690 } 691 692 return true; 693 }; 694 695 /** 696 * Adds the hover class. 697 * 698 * @param {HTMLElement} li 699 */ 700 SelectBox.prototype.addHover = function (li) { 701 li = $(li); 702 var select = $(this.selectElement) 703 , control = select.data('selectBox-control') 704 , options = control.data('selectBox-options'); 705 706 options.find('.selectBox-hover').removeClass('selectBox-hover'); 707 li.addClass('selectBox-hover'); 708 }; 709 710 /** 711 * Returns the original HTML select element. 712 * 713 * @returns {HTMLElement} 714 */ 715 SelectBox.prototype.getSelectElement = function () { 716 return this.selectElement; 717 }; 718 719 /** 720 * Remove the hover class. 721 * 722 * @param {HTMLElement} li 723 */ 724 SelectBox.prototype.removeHover = function (li) { 725 li = $(li); 726 var select = $(this.selectElement) 727 , control = select.data('selectBox-control') 728 , options = control.data('selectBox-options'); 729 730 options.find('.selectBox-hover').removeClass('selectBox-hover'); 731 }; 732 733 /** 734 * Checks if the widget is in the view. 735 * 736 * @param {jQuery} li 737 * @param {Boolean} center 738 */ 739 SelectBox.prototype.keepOptionInView = function (li, center) { 740 if (!li || li.length === 0) { 741 return; 742 } 743 744 var select = $(this.selectElement) 745 , control = select.data('selectBox-control') 746 , options = control.data('selectBox-options') 747 , scrollBox = control.hasClass('selectBox-dropdown') ? options : options.parent() 748 , top = parseInt(li.offset().top -scrollBox.position().top) 749 , bottom = parseInt(top + li.outerHeight()); 750 751 if (center) { 752 scrollBox.scrollTop(li.offset().top - scrollBox.offset().top + scrollBox.scrollTop() - 753 (scrollBox.height() / 2)); 754 } else { 755 if (top < 0) { 756 scrollBox.scrollTop(li.offset().top - scrollBox.offset().top + scrollBox.scrollTop()); 757 } 758 if (bottom > scrollBox.height()) { 759 scrollBox.scrollTop((li.offset().top + li.outerHeight()) - scrollBox.offset().top + 760 scrollBox.scrollTop() - scrollBox.height()); 761 } 762 } 763 }; 764 765 /** 766 * Handles the keyDown event. 767 * Handles open/close and arrow key functionality 768 * 769 * @param {DOMEvent} event 770 */ 771 SelectBox.prototype.handleKeyDown = function (event) { 772 var select = $(this.selectElement) 773 , control = select.data('selectBox-control') 774 , options = control.data('selectBox-options') 775 , settings = select.data('selectBox-settings') 776 , totalOptions = 0, i = 0; 777 778 if (control.hasClass('selectBox-disabled')) { 779 return; 780 } 781 782 switch (event.keyCode) { 783 case 8: 784 // backspace 785 event.preventDefault(); 786 this.typeSearch = ''; 787 break; 788 case 9: 789 // tab 790 case 27: 791 // esc 792 this.hideMenus(); 793 this.removeHover(); 794 break; 795 case 13: 796 // enter 797 if (control.hasClass('selectBox-menuShowing')) { 798 this.selectOption(options.find('LI.selectBox-hover:first'), event); 799 if (control.hasClass('selectBox-dropdown')) { 800 this.hideMenus(); 801 } 802 } else { 803 this.showMenu(); 804 } 805 break; 806 case 38: 807 // up 808 case 37: 809 // left 810 event.preventDefault(); 811 if (control.hasClass('selectBox-menuShowing')) { 812 var prev = options.find('.selectBox-hover').prev('LI'); 813 totalOptions = options.find('LI:not(.selectBox-optgroup)').length; 814 i = 0; 815 while (prev.length === 0 || prev.hasClass('selectBox-disabled') || 816 prev.hasClass('selectBox-optgroup')) { 817 prev = prev.prev('LI'); 818 if (prev.length === 0) { 819 if (settings.loopOptions) { 820 prev = options.find('LI:last'); 821 } else { 822 prev = options.find('LI:first'); 823 } 824 } 825 if (++i >= totalOptions) { 826 break; 827 } 828 } 829 this.addHover(prev); 830 this.selectOption(prev, event); 831 this.keepOptionInView(prev); 832 } else { 833 this.showMenu(); 834 } 835 break; 836 case 40: 837 // down 838 case 39: 839 // right 840 event.preventDefault(); 841 if (control.hasClass('selectBox-menuShowing')) { 842 var next = options.find('.selectBox-hover').next('LI'); 843 totalOptions = options.find('LI:not(.selectBox-optgroup)').length; 844 i = 0; 845 while (0 === next.length || next.hasClass('selectBox-disabled') || 846 next.hasClass('selectBox-optgroup')) { 847 next = next.next('LI'); 848 if (next.length === 0) { 849 if (settings.loopOptions) { 850 next = options.find('LI:first'); 851 } else { 852 next = options.find('LI:last'); 853 } 854 } 855 if (++i >= totalOptions) { 856 break; 857 } 858 } 859 this.addHover(next); 860 this.selectOption(next, event); 861 this.keepOptionInView(next); 862 } else { 863 this.showMenu(); 864 } 865 break; 866 } 867 }; 868 869 /** 870 * Handles the keyPress event. 871 * Handles type-to-find functionality 872 * 873 * @param {DOMEvent} event 874 */ 875 SelectBox.prototype.handleKeyPress = function (event) { 876 var select = $(this.selectElement) 877 , control = select.data('selectBox-control') 878 , options = control.data('selectBox-options') 879 , self = this; 880 881 if (control.hasClass('selectBox-disabled')) { 882 return; 883 } 884 885 switch (event.keyCode) { 886 case 9: 887 // tab 888 case 27: 889 // esc 890 case 13: 891 // enter 892 case 38: 893 // up 894 case 37: 895 // left 896 case 40: 897 // down 898 case 39: 899 // right 900 // Don't interfere with the keydown event! 901 break; 902 default: 903 // Type to find 904 if (!control.hasClass('selectBox-menuShowing')) { 905 this.showMenu(); 906 } 907 event.preventDefault(); 908 clearTimeout(this.typeTimer); 909 this.typeSearch += String.fromCharCode(event.charCode || event.keyCode); 910 options.find('A').each(function () { 911 if ($(this).text().substr(0, self.typeSearch.length).toLowerCase() === self.typeSearch.toLowerCase()) { 912 self.addHover($(this).parent()); 913 self.selectOption($(this).parent(), event); 914 self.keepOptionInView($(this).parent()); 915 return false;
916 } 917 }); 918 // Clear after a brief pause 919 this.typeTimer = setTimeout(function () { 920 self.typeSearch = ''; 921 }, 1000); 922 break; 923 } 924 }; 925 926 /** 927 * Enables the selectBox. 928 */ 929 SelectBox.prototype.enable = function () { 930 var select = $(this.selectElement); 931 select.prop('disabled', false); 932 var control = select.data('selectBox-control'); 933 if (!control) { 934 return; 935 } 936 control.removeClass('selectBox-disabled'); 937 }; 938 939 /** 940 * Disables the selectBox. 941 */ 942 SelectBox.prototype.disable = function () { 943 var select = $(this.selectElement); 944 select.prop('disabled', true); 945 var control = select.data('selectBox-control'); 946 if (!control) { 947 return; 948 } 949 control.addClass('selectBox-disabled'); 950 }; 951 952 /** 953 * Sets the current value. 954 * 955 * @param {String} value 956 */ 957 SelectBox.prototype.setValue = function (value) { 958 var select = $(this.selectElement); 959 select.val(value); 960 value = select.val(); // IE9's select would be null if it was set with a non-exist options value 961 962 if (null === value) { // So check it here and set it with the first option's value if possible 963 value = select.children().first().val(); 964 select.val(value); 965 } 966 967 var control = select.data('selectBox-control'); 968 if (!control) { 969 return; 970 } 971 972 var settings = select.data('selectBox-settings') 973 , options = control.data('selectBox-options'); 974 975 // Update label 976 this.setLabel(); 977 978 // Update control values 979 options.find('.selectBox-selected').removeClass('selectBox-selected'); 980 options.find('A').each(function () { 981 if (typeof(value) === 'object') { 982 for (var i = 0; i < value.length; i++) { 983 if ($(this).attr('rel') == value[i]) { 984 $(this).parent().addClass('selectBox-selected'); 985 } 986 } 987 } else { 988 if ($(this).attr('rel') == value) { 989 $(this).parent().addClass('selectBox-selected'); 990 } 991 } 992 }); 993 994 if (settings.change) { 995 settings.change.call(select); 996 } 997 }; 998 999 1000 1001 /** 1002 * Disables the selection. 1003 * 1004 * @param {*} selector 1005 */ 1006 SelectBox.prototype.disableSelection = function (selector) { 1007 $(selector).css('MozUserSelect', 'none').bind('selectstart', function (event) { 1008 event.preventDefault(); 1009 }); 1010 }; 1011 1012 /** 1013 * Generates the options. 1014 * 1015 * @param {jQuery} self 1016 * @param {jQuery} options 1017 */ 1018 SelectBox.prototype.generateOptions = function (self, options) { 1019 var li = $('<li />'), a = $('<a />'); 1020 li.addClass(self.attr('class')); 1021 li.data(self.data()); 1022 if (self.data('icon')) { 1023 a.attr('rel', self.val()).html('<i class="fa fa-'+self.data('icon')+' fa-fw fa-lg"></i> '+self.text()); 1024 } else { 1025 a.attr('rel', self.val()).text(self.text()); 1026 } 1027 li.append(a); 1028 if (self.attr('disabled')) { 1029 li.addClass('selectBox-disabled'); 1030 } 1031 if (self.attr('selected')) { 1032 li.addClass('selectBox-selected'); 1033 } 1034 options.append(li); 1035 }; 1036 1037 /** 1038 * Extends the jQuery.fn object. 1039 */ 1040 $.extend($.fn, { 1041 1042 /** 1043 * Sets the option elements. 1044 * 1045 * @param {String|Object} options 1046 */ 1047 setOptions : function (options) { 1048 var select = $(this) 1049 , control = select.data('selectBox-control'); 1050 1051 1052 switch (typeof(options)) { 1053 case 'string': 1054 select.html(options); 1055 break; 1056 case 'object': 1057 select.html(''); 1058 for (var i in options) { 1059 if (options[i] === null) { 1060 continue; 1061 } 1062 if (typeof(options[i]) === 'object') { 1063 var optgroup = $('<optgroup label="' + i + '" />'); 1064 for (var j in options[i]) { 1065 optgroup.append('<option value="' + j + '">' + options[i][j] + '</option>'); 1066 } 1067 select.append(optgroup); 1068 } else { 1069 var option = $('<option value="' + i + '">' + options[i] + '</option>'); 1070 select.append(option); 1071 } 1072 } 1073 break; 1074 } 1075 1076 if (control) { 1077 // Refresh the control 1078 $(this).selectBox('refresh'); 1079 // Remove old options 1080 1081 } 1082 }, 1083 1084 1085 1086 selectBox: function (method, options) { 1087 var selectBox; 1088 1089 switch (method) { 1090 case 'control': 1091 return $(this).data('selectBox-control'); 1092 case 'settings': 1093 if (!options) { 1094 return $(this).data('selectBox-settings'); 1095 } 1096 $(this).each(function () { 1097 $(this).data('selectBox-settings', $.extend(true, $(this).data('selectBox-settings'), options)); 1098 }); 1099 break; 1100 case 'options': 1101 // Getter 1102 1103 if (undefined === options) { 1104 return $(this).data('selectBox-control').data('selectBox-options'); 1105 } 1106 1107 // Setter 1108 $(this).each(function () { 1109 $(this).setOptions(options); 1110 }); 1111 break; 1112 case 'value': 1113 // Empty string is a valid value 1114 if (undefined === options) { 1115 return $(this).val(); 1116 } 1117 $(this).each(function () { 1118 if (selectBox = $(this).data('selectBox')) { 1119 selectBox.setValue(options); 1120 } 1121 }); 1122 break; 1123 case 'refresh': 1124 $(this).each(function () { 1125 if (selectBox = $(this).data('selectBox')) { 1126 selectBox.refresh(); 1127 } 1128 }); 1129 break; 1130 case 'enable': 1131 $(this).each(function () { 1132 if (selectBox = $(this).data('selectBox')) { 1133 selectBox.enable(this); 1134 } 1135 }); 1136 break; 1137 case 'disable': 1138 $(this).each(function () { 1139 if (selectBox = $(this).data('selectBox')) { 1140 selectBox.disable(); 1141 } 1142 }); 1143 break; 1144 case 'destroy': 1145 $(this).each(function () { 1146 if (selectBox = $(this).data('selectBox')) { 1147 selectBox.destroy(); 1148 $(this).data('selectBox', null); 1149 } 1150 }); 1151 break; 1152 case 'instance': 1153 return $(this).data('selectBox'); 1154 default: 1155 $(this).each(function (idx, select) { 1156 if (!$(select).data('selectBox')) { 1157 $(select).data('selectBox', new SelectBox(select, method)); 1158 } 1159 }); 1160 break; 1161 } 1162 return $(this); 1163 } 1164 }); 1165})(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.