1/*! ikSelect 1.0.3 2 Copyright (c) 2013 Igor Kozlov 3 http://igorkozlov.me */ 4 5;(function ($, window, document, undefined) { 6 var $window = $(window); 7 var defaults = { 8 syntax: '<div class="ik_select_link"><div class="ik_select_link_text"></div></div><div class="ik_select_dropdown"><div class="ik_select_list"></div></div>', 9 autoWidth: true, // set select width according to the longest option 10 ddFullWidth: true, // set dropdown width according to the longest option 11 equalWidths: true, // include scrollbar width in fake select calculations 12 dynamicWidth: false, // change fake select's width according to it's contents 13 extractLink: false, 14 customClass: '', 15 linkCustomClass: '', 16 ddCustomClass: '', 17 ddMaxHeight: 200, 18 filter: false, 19 nothingFoundText: 'Nothing found', 20 isDisabled: false, 21 onInit: function() {}, 22 onShow: function () {}, 23 onHide: function () {}, 24 onKeyUp: function () {}, 25 onKeyDown: function () {}, 26 onHoverMove: function () {} 27 }; 28 29 var instOpened; // instance of the currently opened select 30 31 // browser detection part was taken from jQuery migrate 32 // https://github.com/jquery/jquery-migrate/blob/e6bda6a84c294eb1319fceb48c09f51042c80892/src/core.js 33 var uaMatch = function (ua) { 34 ua = ua.toLowerCase(); 35 36 var match = /(chrome)[ \/]([\w.]+)/.exec(ua) || 37 /(webkit)[ \/]([\w.]+)/.exec(ua) || 38 /(opera)(?:.*version|)[ \/]([\w.]+)/.exec(ua) || 39 /(msie) ([\w.]+)/.exec(ua) || 40 ua.indexOf('compatible') < 0 && /(mozilla)(?:.*? rv:([\w.]+)|)/.exec(ua) || 41 []; 42 43 return { 44 browser: match[1] || '', 45 version: match[2] || '0' 46 }; 47 }; 48 49 if (! $.browser) { 50 var matched = uaMatch(navigator.userAgent); 51 var browser = {}; 52 53 if (matched.browser) { 54 browser[matched.browser] = true; 55 browser.version = matched.version; 56 } 57 58 if (browser.chrome) { 59 browser.webkit = true; 60 } else if (browser.webkit) { 61 browser.safari = true; 62 } 63 64 $.browser = browser; 65 } 66 67 $.browser.mobile = /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile/i.test(navigator.userAgent); 68 $.browser.operamini = Object.prototype.toString.call(window.operamini) === "[object OperaMini]"; 69 70 function IkSelect(element, options) { 71 var dataOptions = {}; // parsed data- attributes 72 73 this.el = element; 74 this.$el = $(element); // original select 75 76 for (var key in defaults) { 77 dataOptions[key] = this.$el.data(key.toLowerCase()); 78 } 79 80 this.options = $.extend({}, defaults, options, dataOptions); 81 82 if ($.browser.mobile) { 83 this.options.filter = false; 84 } 85 86 this.init(); 87 } 88 89 $.extend(IkSelect.prototype, { 90 init: function () { 91 this.$wrapper = $('<div class="ik_select">' + this.options.syntax + '</div>'); // wrapper for the fake select and the fake dropdown 92 this.$link = $('.ik_select_link', this.$wrapper); // fake select 93 this.$linkText = $('.ik_select_link_text', this.$wrapper); // fake select's text 94 this.$dropdown = $('.ik_select_dropdown', this.$wrapper); // fake dropdown 95 this.$list = $('.ik_select_list', this.$wrapper); // options list inside the fake dropdown
96 this.$listInner = $('<div class="ik_select_list_inner"/>'); // support dropdown for scrolling 97 this.$active = $([]); // active fake option 98 this.$hover = $([]); // hovered fake option 99 this.hoverIndex = 0; // hovered fake option's index 100 101 this.$optionSet = $([]); 102 this.$optgroupSet = $([]); 103 104 this.$list.append(this.$listInner); 105 106 if (this.options.filter) { 107 this.$filter = $([]); // filter text input 108 this.$optionSetOriginal = $([]); // contains original list items when filtering 109 this.$nothingFoundText = $('<div class="ik_select_nothing_found"/>').html(this.options.nothingFoundText); 110 this.$filterWrap = $('.ik_select_filter_wrap', this.$wrapper); 111 112 if (! this.$filterWrap.length) { 113 this.$filterWrap = $('<div class="ik_select_filter_wrap"/>'); 114 } 115 116 this.$filter = $('<input type="text" class="ik_select_filter">'); 117 118 this.$filterWrap.append(this.$filter); 119 this.$list.prepend(this.$filterWrap); 120 121 this.$filter.on({ 122 // keyboard controls should work even if the filter is in focus 123 'keydown.ikSelect keyup.ikSelect': $.proxy(this, '_elKeyUpDown'), 124 // actual filtering happens on keyup 125 'keyup.ikSelect': $.proxy(this, '_filterKeyup') 126 }); 127 } 128 129 this.$wrapper.addClass(this.options.customClass); 130 this.$link.addClass(this.options.linkCustomClass || (this.options.customClass && this.options.customClass + '-link')); 131 this.$dropdown.addClass(this.options.ddCustomClass || (this.options.customClass && this.options.customClass + '-dd')); 132 133 // creating fake option list 134 this.reset(); 135 136 // disable select if an option or attribute are truthy 137 this.toggle(!(this.options.isDisabled || this.$el.prop('disabled') || this.$el.hasClass('hidden'))); 138 139 // click event for fake select 140 this.$link.on('click.ikSelect', $.proxy(this, '_linkClick')); 141 142 this.$el.on({ 143 // when focus is on the original select add a focus class to the fake one 144 'focus.ikSelect': $.proxy(this, '_elFocus'), 145 // when focus lost remove the focus class from the fake one 146 'blur.ikSelect': $.proxy(this, '_elBlur'), 147 // make sure that the fake select shows correct data 148 'change.ikSelect': $.proxy(this, '_syncOriginalOption'), 149 // keyboard controls for the fake select 150 'keydown.ikSelect keyup.ikSelect': $.proxy(this, '_elKeyUpDown') 151 }); 152 153 this.$list.on({ 154 'click.ikSelect': $.proxy(this, '_optionClick'), 155 'mouseover.ikSelect': $.proxy(this, '_optionMouseover') 156 }, '.ik_select_option'); 157 158 // stop propagation of click events on the wrapper 159 this.$wrapper.on('click', function () { 160 return false; 161 }); 162 163 // appending the fake select right after the original one 164 this.$el.after(this.$wrapper); 165 166 // set correct dimensions 167 this.redraw(); 168 169 // move original select inside the wrapper 170 this.$el.appendTo(this.$wrapper); 171 172 this.options.onInit(this); 173 this.$el.trigger('ikinit', this); 174 }, 175 176 // click listener for fake select 177 _linkClick: function () { 178 if (this.isDisabled) { 179 return; 180 } 181 if (this === instOpened) { 182 this.hideDropdown(); 183 } else { 184 this.showDropdown(); 185 } 186 187 }, 188 189 // click listener for the fake options 190 _optionClick: function () { 191 this._makeOptionActive(this.searchIndexes ? this.$optionSetOriginal.index(this.$hover) : this.hoverIndex, true); 192 this.hideDropdown(); 193 this.$el.change().focus(); 194 }, 195 196 // hover listener for the fake options 197 _optionMouseover: function (event) { 198 var $option = $(event.currentTarget); 199 if ($option.hasClass('ik_select_option_disabled')) { 200 return; 201 } 202 this.$hover.removeClass('ik_select_hover'); 203 this.$hover = $option.addClass('ik_select_hover'); 204 this.hoverIndex = this.$optionSet.index(this.$hover); 205 }, 206 207 // makes fake option active without syncing the original select 208 _makeOptionActive: function (index, shouldSync) { 209 var $option = $(this.el.options[index]), 210 text=''; 211 if($option.data('img_src')){ 212 //aspro fix data-missing 213 text+='<span class="icon_color ' + ($option.data('missing') ? 'missing' : '') + '" style="background: url('+$option.data('img_src')+')"></span>'; 214 this.$link.addClass('img'); 215 } 216 if($option.attr('title')){ 217 this.$link.attr('title', $option.attr('title')); 218 } 219 text+=$option.text(); 220 this.$linkText.html(text); 221 222 this.$link.toggleClass('ik_select_link_novalue', !$option.attr('value')); 223 224 this.$hover.removeClass('ik_select_hover'); 225 this.$active.removeClass('ik_select_active'); 226 this.$hover = this.$active = this.$optionSet.eq(index).addClass('ik_select_hover ik_select_active'); 227 this.hoverIndex = index; 228 229 if (shouldSync) { 230 this._syncFakeOption(); 231 } 232 }, 233 234 // keyboard controls for the fake select 235 _elKeyUpDown: function (event) { 236 var $handle = $(event.currentTarget); 237 var type = event.type; 238 var keycode = event.which; 239 var newTop; 240 241 switch (keycode) { 242 case 38: // up 243 if (type === 'keydown') { 244 event.preventDefault(); 245 this._moveToPrevActive(); 246 } 247 break; 248 case 40: // down 249 if (type === 'keydown') { 250 event.preventDefault(); 251 this._moveToNextActive(); 252 } 253 break; 254 case 33: // page up 255 if (type === 'keydown') { 256 event.preventDefault(); 257 newTop = this.$hover.position().top - this.$listInner.height(); 258 this._moveToPrevActive(function (optionTop) { 259 return optionTop <= newTop; 260 }); 261 } 262 break; 263 case 34: // page down 264 if (type === 'keydown') { 265 event.preventDefault(); 266 newTop = this.$hover.position().top + this.$listInner.height(); 267 this._moveToNextActive(function (optionTop) { 268 return optionTop >= newTop; 269 }); 270 } 271 break; 272 case 36: // home 273 if (type === 'keydown' && $handle.is(this.$el)) { 274 event.preventDefault(); 275 this._moveToFirstActive(); 276 } 277 break; 278 case 35: // end 279 if (type === 'keydown' && $handle.is(this.$el)) { 280 event.preventDefault(); 281 this._moveToLastActive(); 282 } 283 break; 284 case 32: // space 285 if (type === 'keydown' && $handle.is(this.$el)) { 286 event.preventDefault(); 287 if (! this.$dropdown.is(':visible')) { 288 this._linkClick(); 289 } else { 290 this.$hover.click(); 291 } 292 } 293 break; 294 case 13: // enter 295 if (type === 'keydown' && this.$dropdown.is(':visible')) { 296 event.preventDefault(); 297 this.$hover.click(); 298 } 299 break; 300 case 27: // esc 301 if (type === 'keydown' && this.$dropdown.is(':visible')) { 302 event.preventDefault(); 303 this.hideDropdown(); 304 } 305 break; 306 case 9: // tab 307 if (type === 'keydown') { 308 if ($.browser.webkit && this.$dropdown.is(':visible')) { 309 event.preventDefault(); 310 } else { 311 this.hideDropdown(); 312 } 313 } 314 break; 315 default: 316 if (type === 'keyup' && $handle.is(this.$el)) { 317 this._syncOriginalOption(); 318 } 319 break; 320 } 321 322 // mozilla ignores preventDefault for select navigation 323 // this ensures that original select is in sync 324 if (type === 'keyup' && $.browser.mozilla) { 325 this._syncFakeOption(); 326 } 327 328 if (type === 'keydown') { 329 this.options.onKeyDown(this, keycode); 330 this.$el.trigger('ikkeydown', [this, keycode]); 331 } 332 if (type === 'keyup') { 333 this.options.onKeyUp(this, keycode); 334 this.$el.trigger('ikkeyup', [this, keycode]); 335 } 336 }, 337 338 // controls hover/active states for options and makes selected with keyboard options fully visible 339 _moveTo: function (index) { 340 var optionTopLine, optionBottomLine; 341 var $optgroup; 342 343 if (!this.$dropdown.is(':visible') && $.browser.webkit) { 344 this.showDropdown(); 345 return this; 346 } 347 348 if (!this.$dropdown.is(':visible') || $.browser.mozilla) { 349 this._makeOptionActive(index, true); 350 } else { 351 this.$hover.removeClass('ik_select_hover'); 352 this.$hover = this.$optionSet.eq(index).addClass('ik_select_hover'); 353 this.hoverIndex = index; 354 } 355 356 // make option fully visible 357 optionTopLine = this.$hover.position().top; 358 optionBottomLine = optionTopLine + this.$active.outerHeight(); 359 // make optgroup label visible if first option witin this optgroup is hovered 360 if (!this.$hover.index()) { 361 $optgroup = this.$hover.closest('.ik_select_optgroup'); 362 if ($optgroup.length) { 363 optionTopLine = $optgroup.position().top; 364 } 365 } 366 if (optionBottomLine > this.$listInner.height()) { 367 this.$listInner.scrollTop(this.$listInner.scrollTop() + optionBottomLine - this.$listInner.height()); 368 } else if (optionTopLine < 0) { 369 this.$listInner.scrollTop(this.$listInner.scrollTop() + optionTopLine); 370 } 371 372 this.options.onHoverMove(this); 373 this.$el.trigger('ikhovermove', this); 374 }, 375 376 _moveToFirstActive: function () { 377 for (var i = 0; i < this.$optionSet.length; i++) { 378 if (!this.$optionSet.eq(i).hasClass('ik_select_option_disabled')) { 379 this._moveTo(i); 380 break; 381 } 382 } 383 }, 384 385 _moveToLastActive: function () { 386 for (var i = this.$optionSet.length - 1; i >= 0; i++) { 387 if (!this.$optionSet.eq(i).hasClass('ik_select_option_disabled')) { 388 this._moveTo(i); 389 break; 390 } 391 } 392 }, 393 394 _moveToPrevActive: function (condition) { 395 var $option; 396 for (var i = this.hoverIndex - 1; i >= 0; i--) { 397 $option = this.$optionSet.eq(i); 398 if (!$option.hasClass('ik_select_option_disabled') && (typeof condition === 'undefined' || condition($option.position().top))) { 399 this._moveTo(i); 400 break; 401 } 402 } 403 }, 404 405 _moveToNextActive: function (condition) { 406 var $option; 407 for (var i = this.hoverIndex + 1; i < this.$optionSet.length; i++) { 408 $option = this.$optionSet.eq(i); 409 if (!$option.hasClass('ik_select_option_disabled') && (typeof condition === 'undefined' || condition($option.position().top))) { 410 this._moveTo(i); 411 break; 412 } 413 } 414 }, 415
416 // when focus is on the original select add a focus class to the fake one 417 _elFocus: function () { 418 var wrapperOffsetTop, wrapperHeight, windowScrollTop, windowHeight; 419 if (this.isDisabled) { 420 return this; 421 } 422 this.$link.addClass('ik_select_link_focus'); 423 424 // scroll the window so that focused select is visible 425 wrapperOffsetTop = this.$wrapper.offset().top; 426 wrapperHeight = this.$wrapper.height(); 427 windowScrollTop = $window.scrollTop(); 428 windowHeight = $window.height(); 429 if ((wrapperOffsetTop + wrapperHeight > windowScrollTop + windowHeight) || 430 (wrapperOffsetTop < windowScrollTop)) { 431 $window.scrollTop(wrapperOffsetTop - windowHeight / 2); 432 } 433 }, 434 435 // when focus lost remove the focus class from the fake one 436 _elBlur: function () { 437 this.$link.removeClass('ik_select_link_focus'); 438 }, 439 440 // filtering on key up 441 _filterKeyup: function () { 442 var filterVal = $.trim(this.$filter.val()); 443 var filterValOld; 444 this.$listInner.show(); 445 446 if (typeof this.searchIndexes === 'undefined') { 447 this.$optionSetOriginal = this.$optionSet; 448 this.searchIndexes = $.makeArray(this.$optionSet.map(function (optionIndex, option) { 449 return $(option).text().toLowerCase(); 450 })); 451 } 452 453 if (filterVal !== filterValOld) { 454 if (filterVal === '') { 455 this.$optionSet = this.$optionSetOriginal.show(); 456 this.$optgroupSet.show(); 457 this.$nothingFoundText.remove(); 458 } else { 459 this.$optionSet = $([]); 460 this.$optgroupSet.show(); 461 this.$optionSetOriginal.each($.proxy(function (optionIndex, option) { 462 var $option = $(option); 463 if (this.searchIndexes[optionIndex].indexOf(filterVal.toLowerCase()) >= 0) { 464 this.$optionSet = this.$optionSet.add($option); 465 $option.show(); 466 } else { 467 $option.hide(); 468 } 469 }, this)); 470 471 if (this.$optionSet.length) { 472 this.$nothingFoundText.remove(); 473 this.$optgroupSet.each(function (optgroupIndex, optgroup) { 474 var $optgroup = $(optgroup); 475 if (!$('.ik_select_option:visible', $optgroup).length) { 476 $optgroup.hide(); 477 } 478 }); 479 480 if (!this.$hover.is(':visible')) { 481 this._moveToFirstActive(); 482 } 483 } else { 484 this.$listInner.hide(); 485 this.$list.append(this.$nothingFoundText); 486 } 487 } 488 489 filterValOld = filterVal; 490 } 491 }, 492 493 // sync selected option in the fake select with the original one 494 _syncFakeOption: function () { 495 this.el.selectedIndex = this.hoverIndex; 496 }, 497 498 // sync selected option in the original select with the fake one 499 _syncOriginalOption: function () { 500 this._makeOptionActive(this.el.selectedIndex); 501 }, 502 503 // sets fixed height to dropdown if it's bigger than ddMaxHeight 504 _fixHeight: function () { 505 this.$dropdown.show(); 506 this.$listInner.css('height', 'auto'); 507 if (this.$listInner.height() > this.options.ddMaxHeight) { 508 this.$listInner.css({ 509 overflow: 'auto', 510 height: this.options.ddMaxHeight, 511 position: 'relative' 512 }); 513 } 514 this.$dropdown.hide(); 515 }, 516 517 // calculates the needed data for showing the dropdown 518 redraw: function () { 519 var maxWidthOuter, scrollbarWidth, wrapperParentWidth; 520 521 if (this.options.filter) { 522 this.$filter.hide(); 523 } 524 525 this.$wrapper.css({ 526 position: 'relative' 527 }); 528 this.$dropdown.css({ 529 position: 'absolute', 530 zIndex: 9998, 531 width: '100%' 532 }); 533 this.$list.css({ 534 position: 'relative' 535 }); 536 537 this._fixHeight(); 538 539 // width calculations for the fake select when "autoWidth" is "true" 540 if (this.options.dynamicWidth || this.options.autoWidth || this.options.ddFullWidth) { 541 this.$wrapper.width(''); 542 543 this.$dropdown.show().width(9999); 544 this.$listInner.css('float', 'left'); 545 this.$list.css('float', 'left'); 546 maxWidthOuter = this.$list.outerWidth(true); 547 scrollbarWidth = this.$listInner.width() - this.$listInnerUl.width(); 548 this.$list.css('float', ''); 549 this.$listInner.css('float', ''); 550 this.$dropdown.css('width', '100%'); 551 552 if (this.options.ddFullWidth) { 553 this.$dropdown.width(maxWidthOuter + scrollbarWidth); 554 } 555 556 if (this.options.dynamicWidth) { 557 this.$wrapper.css({ 558 display: 'inline-block', 559 width: 'auto',
560 verticalAlign: 'top' 561 }); 562 } else if (this.options.autoWidth) { 563 this.$wrapper.width(maxWidthOuter + (this.options.equalWidths ? scrollbarWidth : 0)).addClass('ik_select_autowidth'); 564 } 565 566 wrapperParentWidth = this.$wrapper.parent().width(); 567 if (this.$wrapper.width() > wrapperParentWidth) { 568 this.$wrapper.width(wrapperParentWidth); 569 } 570 } 571 572 if (this.options.filter) { 573 this.$filter.show().outerWidth(this.$filterWrap.width()); 574 } 575 576 this.$dropdown.hide(); 577 578 // hide the original select 579 this.$el.css({ 580 position: 'absolute', 581 margin: 0, 582 padding: 0, 583 top: 0, 584 left: -9999 585 }); 586 587 // show the original select in mobile browsers 588 if ($.browser.mobile) { 589 this.$el.css({ 590 opacity: 0, 591 left: 0, 592 height: this.$wrapper.height(), 593 width: this.$wrapper.width() 594 }); 595 } 596 }, 597 598 // creates or recreates dropdown and sets selected options's text into fake select 599 reset: function () { 600 var html = ''; 601 602 // init fake select's text 603 this.$linkText.html(this.$el.val()); 604 605 this.$listInner.empty(); 606 607 // creating an ul>li list identical to the original dropdown 608 html = '<ul>'; 609 this.$el.children().each($.proxy(function (childIndex, child) { 610 var $child = $(child); 611 var tagName = child.tagName.toLowerCase(); 612 var options; 613 if (tagName === 'optgroup') { 614 options = $child.children().map($.proxy(function (optionIndex, option) { 615 return this._generateOptionObject($(option)); 616 }, this)); 617 options = $.makeArray(options); 618 html += this._renderListOptgroup({ 619 label: $child.attr('label') || ' ', 620 isDisabled: $child.is(':disabled'), 621 options: options 622 }); 623 } else if (tagName === 'option') { 624 html += this._renderListOption(this._generateOptionObject($child)); 625 } 626 }, this)); 627 html += '</ul>'; 628 this.$listInner.append(html); 629 this._syncOriginalOption(); 630 631 this.$listInnerUl = $('> ul', this.$listInner); 632 this.$optgroupSet = $('.ik_select_optgroup', this.$listInner); 633 this.$optionSet = $('.ik_select_option', this.$listInner); 634 }, 635 636 // hides dropdown 637 hideDropdown: function () { 638 if (this.options.filter) { 639 this.$filter.val(''); 640 this._filterKeyup(); 641 } 642 643 this.$dropdown.hide().appendTo(this.$wrapper).css({ 644 'left': '', 645 'top': '' 646 }); 647 if (this.options.extractLink) { 648 this.$wrapper.outerWidth(this.$wrapper.data('outerWidth')); 649 this.$wrapper.height(''); 650 this.$link.removeClass('ik_select_link_extracted').css({ 651 position: '', 652 top: '', 653 left: '', 654 zIndex: '' 655 }).prependTo(this.$wrapper); 656 } 657 instOpened = null; 658 this.$el.focus(); 659 660 this.options.onHide(this); 661 this.$el.trigger('ikhide', this); 662 }, 663 664 // shows dropdown 665 showDropdown: function () { 666 var dropdownOffset, dropdownOuterWidth, dropdownOuterHeight; 667 var wrapperOffset, wrapperOuterWidth; 668 var windowWidth, windowHeight, windowScroll; 669 var linkOffset; 670 671 if (instOpened === this || !this.$optionSet.length) { 672 return; 673 } else if (instOpened) { 674 instOpened.hideDropdown(); 675 } 676 677 this._syncOriginalOption(); 678 if($('.show_un_props').length) 679 this.$dropdown.addClass('show_un_props'); 680 else if($('.unshow_un_props').length) 681 this.$dropdown.addClass('unshow_un_props'); 682 this.$dropdown.show(); 683 684 dropdownOffset = this.$dropdown.offset(); 685 dropdownOuterWidth = this.$dropdown.outerWidth(true); 686 dropdownOuterHeight = this.$dropdown.outerHeight(true); 687 wrapperOffset = this.$wrapper.offset(); 688 windowWidth = $window.width(); 689 windowHeight = $window.height(); 690 windowScroll = $window.scrollTop(); 691 692 // if the dropdown's right border is beyond window's edge then move the dropdown to the left so that it fits 693 if (this.options.ddFullWidth && wrapperOffset.left + dropdownOuterWidth > windowWidth) { 694 dropdownOffset.left = windowWidth - dropdownOuterWidth; 695 } 696 697 // if the dropdown's bottom border is beyond window's edge then move the dropdown to the top so that it fits 698 if (dropdownOffset.top + dropdownOuterHeight > windowScroll + windowHeight) { 699 dropdownOffset.top = windowScroll + windowHeight - dropdownOuterHeight; 700 } 701 702 this.$dropdown.css({ 703 left: dropdownOffset.left, 704 top: dropdownOffset.top, 705 width: this.$dropdown.width() 706 }).appendTo('body'); 707 708 if (this.options.extractLink) { 709 linkOffset = this.$link.offset(); 710 wrapperOuterWidth = this.$wrapper.outerWidth(); 711 this.$wrapper.data('outerWidth', wrapperOuterWidth); 712 this.$wrapper.outerWidth(wrapperOuterWidth); 713 this.$wrapper.outerHeight(this.$wrapper.outerHeight()); 714 this.$link.outerWidth(this.$link.outerWidth()); 715 this.$link.addClass('ik_select_link_extracted').css({ 716 position: 'absolute', 717 top: linkOffset.top, 718 left: linkOffset.left, 719 zIndex: 9999 720 }).appendTo('body'); 721 } 722 723 this.$listInner.scrollTop(this.$active.position().top - this.$list.height() / 2); 724 725 if (this.options.filter) { 726 this.$filter.focus(); 727 } else { 728 this.$el.focus(); 729 } 730 731 instOpened = this; 732 733 this.options.onShow(this); 734 this.$el.trigger('ikshow', this); 735 }, 736 737 _generateOptionObject: function ($option) { 738 739 return { 740 value: $option.val(), 741 label: $option.html() || ' ', 742 isDisabled: $option.is(':disabled'), 743 dataParam: $option.data(), 744 className: $option.attr('class'), 745 title: $option.attr('title') 746 }; 747 }, 748 749 // generates option code for the fake dropdown 750 _renderListOption: function (option) { 751 752 var html 753 var imgClass = ''; 754 var disabledClass = option.isDisabled ? ' ik_select_option_disabled' : ''; 755 756 if(!$.isEmptyObject(option.dataParam)) { 757 imgClass = option.dataParam.img_src ? ' img' : ''; 758 } 759 var missingClass = option.className=='hidden' ? ' missing' : ''; 760 var title = option.title; 761 html = '<li class="ik_select_option' + disabledClass + imgClass + missingClass + '" title="'+title+'" data-value="' + option.value + '">'; 762 html += '<span class="ik_select_option_label" title="'+title+'">'; 763 764 if(imgClass){ 765 //aspro fix data-missing 766 html += '<span class="icon_color ' + (option.dataParam.missing ? 'missing' : '') + '" style="background: url('+option.dataParam.img_src+')"></span>'; 767 } 768 html += option.label; 769 html += '</span>'; 770 html += '</li>'; 771 return html; 772 }, 773 774 // generates optgroup code for the fake dropdown 775 _renderListOptgroup: function (optgroup) { 776 var html; 777 var disabledClass = optgroup.isDisabled ? ' ik_select_optgroup_disabled' : ''; 778 html = '<li class="ik_select_optgroup' + disabledClass + '">'; 779 html += '<div class="ik_select_optgroup_label">' + optgroup.label + '</div>'; 780 html += '<ul>'; 781 if ($.isArray(optgroup.options)) { 782 $.each(optgroup.options, $.proxy(function (optionIndex, option) { 783 html += this._renderListOption({ 784 value: option.value, 785 label: option.label || ' ', 786 isDisabled: option.isDisabled 787 }); 788 }, this)); 789 } 790 html += '</ul>'; 791 html += '</li>'; 792 return html; 793 }, 794 795 // generates option code for the select 796 _renderOption: function (option) { 797 return '<option value="' + option.value + '">' + option.label + '</option>'; 798 }, 799 800 // generates optgroup code for the select 801 _renderOptgroup: function (optgroup) { 802 var html; 803 html = '<optgroup label="' + optgroup.label + '">'; 804 if ($.isArray(optgroup.options)) { 805 $.each(optgroup.options, $.proxy(function (optionIndex, option) { 806 html += this._renderOption(option); 807 }, this)); 808 } 809 html += '</option>'; 810 return html; 811 }, 812 813 addOptions: function (options, optionIndex, optgroupIndex) { 814 var listHtml = '', selectHtml = ''; 815 var $destinationUl = this.$listInnerUl; 816 var $destinationOptgroup = this.$el; 817 var $ulOptions, $optgroupOptions; 818 819 options = $.isArray(options) ? options : [options]; 820 821 $.each(options, $.proxy(function (index, option) { 822 listHtml += this._renderListOption(option); 823 selectHtml += this._renderOption(option); 824 }, this)); 825 826 if ($.isNumeric(optgroupIndex) && optgroupIndex < this.$optgroupSet.length) { 827 $destinationUl = this.$optgroupSet.eq(optgroupIndex); 828 $destinationOptgroup = $('optgroup', this.$el).eq(optgroupIndex); 829 } 830 if ($.isNumeric(optionIndex)) { 831 $ulOptions = $('.ik_select_option', $destinationUl); 832 if (optionIndex < $ulOptions.length) { 833 $ulOptions.eq(optionIndex).before(listHtml); 834 $optgroupOptions = $('option', $destinationOptgroup); 835 $optgroupOptions.eq(optionIndex).before(selectHtml); 836 } 837 } 838 if (!$optgroupOptions) { 839 $destinationUl.append(listHtml); 840 $destinationOptgroup.append(selectHtml); 841 } 842 843 this.$optionSet = $('.ik_select_option', this.$listInner); 844 this._fixHeight(); 845 }, 846 847 addOptgroups: function (optgroups, optgroupIndex) { 848 var listHtml = '', selectHtml = ''; 849 if (!optgroups) { 850 return; 851 } 852 optgroups = $.isArray(optgroups) ? optgroups : [optgroups]; 853 854 $.each(optgroups, $.proxy(function (optgroupIndex, optgroup) { 855 listHtml += this._renderListOptgroup(optgroup); 856 selectHtml += this._renderOptgroup(optgroup); 857 }, this)); 858 859 if ($.isNumeric(optgroupIndex) && optgroupIndex < this.$optgroupSet.length) { 860 this.$optgroupSet.eq(optgroupIndex).before(listHtml); 861 $('optgroup', this.$el).eq(optgroupIndex).before(selectHtml); 862 } else { 863 this.$listInnerUl.append(listHtml); 864 this.$el.append(selectHtml); 865 } 866 867 this.$optgroupSet = $('.ik_select_optgroup', this.$listInner); 868 this.$optionSet = $('.ik_select_option', this.$listInner); 869 this._fixHeight(); 870 }, 871 872 removeOptions: function (optionIndexes, optgroupIndex) { 873 var $removeList = $([]); 874 var $listContext; 875 var $selectContext; 876 877 if ($.isNumeric(optgroupIndex)) { 878 if (optgroupIndex < 0) { 879 $listContext = $('> .ik_select_option', this.$listInnerUl); 880 $selectContext = $('> option', this.$el); 881 } else if (optgroupIndex < this.$optgroupSet.length) { 882 $listContext = $('.ik_select_option', this.$optgroupSet.eq(optgroupIndex)); 883 $selectContext = $('optgroup', this.$el).eq(optgroupIndex).find('option'); 884 } 885 } 886 if (!$listContext) { 887 $listContext = this.$optionSet; 888 $selectContext = $(this.el.options); 889 } 890 891 if (!$.isArray(optionIndexes)) { 892 optionIndexes = [optionIndexes]; 893 } 894 895 $.each(optionIndexes, $.proxy(function (index, optionIndex) { 896 if (optionIndex < $listContext.length) { 897 $removeList = $removeList.add($listContext.eq(optionIndex)).add($selectContext.eq(optionIndex)); 898 } 899 }, this)); 900 901 $removeList.remove(); 902 this.$optionSet = $('.ik_select_option', this.$listInner); 903 this._syncOriginalOption(); 904 this._fixHeight(); 905 }, 906 907 removeOptgroups: function (optgroupIndexes) { 908 var $removeList = $([]); 909 var $selectOptgroupSet = $('optgroup', this.el); 910 911 if (!$.isArray(optgroupIndexes)) { 912 optgroupIndexes = [optgroupIndexes]; 913 } 914 915 $.each(optgroupIndexes, $.proxy(function (index, optgroupIndex) { 916 if (optgroupIndex < this.$optgroupSet.length) { 917 $removeList = $removeList.add(this.$optgroupSet.eq(optgroupIndex)).add($selectOptgroupSet.eq(optgroupIndex)); 918 } 919 }, this)); 920 921 $removeList.remove(); 922 this.$optionSet = $('.ik_select_option', this.$listInner); 923 this.$optgroupSet = $('.ik_select_optgroup', this.$listInner); 924 this._syncOriginalOption(); 925 this._fixHeight(); 926 }, 927 928 // disable select 929 disable: function () { 930 this.toggle(false); 931 }, 932 933 // enable select 934 enable: function () { 935 this.toggle(true); 936 }, 937 938 // toggle select 939 toggle: function (bool) { 940 this.isDisabled = typeof bool !== 'undefined' ? !bool : !this.isDisabled; 941 this.$el.prop('disabled', this.isDisabled); 942 this.$link.toggleClass('ik_select_link_disabled', this.isDisabled); 943 }, 944 945 // make option selected by value 946 select: function (value, isIndex) { 947 if (!isIndex) { 948 this.$el.val(value); 949 } else { 950 this.el.selectedIndex = value; 951 } 952 this._syncOriginalOption(); 953 }, 954 955 disableOptgroups: function (optgroupIndexes) { 956 this.toggleOptgroups(optgroupIndexes, false); 957 }, 958 959 enableOptgroups: function (optgroupIndexes) { 960 this.toggleOptgroups(optgroupIndexes, true); 961 }, 962 963 toggleOptgroups: function (optgroupIndexes, bool) { 964 if (!$.isArray(optgroupIndexes)) { 965 optgroupIndexes = [optgroupIndexes]; 966 } 967 968 $.each(optgroupIndexes, $.proxy(function (index, optgroupIndex) { 969 var isDisabled; 970 var $optionSet, indexes = [], indexFirst; 971 var $optgroup = $('optgroup', this.$el).eq(optgroupIndex); 972 isDisabled = typeof bool !== 'undefined' ? bool : $optgroup.prop('disabled'); 973 $optgroup.prop('disabled', !isDisabled); 974 this.$optgroupSet.eq(optgroupIndex).toggleClass('ik_select_optgroup_disabled', !isDisabled); 975 976 $optionSet = $('option', $optgroup); 977 indexFirst = $(this.el.options).index($optionSet.eq(0)); 978 for (var i = indexFirst; i < indexFirst + $optionSet.length; i++) { 979 indexes.push(i); 980 }
981 this.toggleOptions(indexes, true, isDisabled); 982 }, this)); 983 984 this._syncOriginalOption(); 985 }, 986 987 disableOptions: function (lookupValues, isIndex) { 988 this.toggleOptions(lookupValues, isIndex, false); 989 }, 990 991 enableOptions: function (lookupValues, isIndex) { 992 this.toggleOptions(lookupValues, isIndex, true); 993 }, 994 995 toggleOptions: function (lookupValues, isIndex, bool) { 996 var $selectOptionSet = $('option', this.el); 997 if (!$.isArray(lookupValues)) { 998 lookupValues = [lookupValues]; 999 } 1000 1001 var toggleOption = $.proxy(function ($option, optionIndex) { 1002 var isDisabled = typeof bool !== 'undefined' ? bool : $option.prop('disabled'); 1003 $option.prop('disabled', !isDisabled); 1004 this.$optionSet.eq(optionIndex).toggleClass('ik_select_option_disabled', !isDisabled); 1005 }, this); 1006 1007 $.each(lookupValues, function (index, lookupValue) { 1008 if (!isIndex) { 1009 $selectOptionSet.each(function (optionIndex, option) { 1010 var $option = $(option); 1011 if ($option.val() === lookupValue) { 1012 toggleOption($option, optionIndex); 1013 return this; 1014 } 1015 }); 1016 } else { 1017 toggleOption($selectOptionSet.eq(lookupValue), lookupValue); 1018 } 1019 }); 1020 1021 this._syncOriginalOption(); 1022 }, 1023 1024 // detach plugin from the orignal select 1025 detach: function () { 1026 this.$el.off('.ikSelect').css({ 1027 width: '', 1028 height: '', 1029 left: '', 1030 top: '', 1031 position: '', 1032 margin: '', 1033 padding: '' 1034 }); 1035 1036 this.$wrapper.before(this.$el); 1037 this.$wrapper.remove(); 1038 this.$el.removeData('plugin_ikSelect'); 1039 } 1040 }); 1041 1042 $.fn.ikSelect = function (options) { 1043 var args; 1044 //do nothing if opera mini 1045 if ($.browser.operamini) { 1046 return this; 1047 } 1048 1049 args = Array.prototype.slice.call(arguments, 1); 1050 1051 return this.each(function () { 1052 var plugin; 1053 if (!$.data(this, 'plugin_ikSelect')) { 1054 $.data(this, 'plugin_ikSelect', new IkSelect(this, options)); 1055 } else if (typeof options === 'string') { 1056 plugin = $.data(this, 'plugin_ikSelect'); 1057 if (typeof plugin[options] === 'function') { 1058 plugin[options].apply(plugin, args); 1059 } 1060 } 1061 }); 1062 }; 1063 1064 $.ikSelect = { 1065 extendDefaults: function (options) { 1066 $.extend(defaults, options); 1067 } 1068 }; 1069 1070 $(document).bind('click.ikSelect', function () { 1071 if (instOpened) { 1072 instOpened.hideDropdown(); 1073 } 1074 }); 1075})(jQuery, window, document);
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.