Last active
August 29, 2015 14:00
-
-
Save SaneMethod/11193968 to your computer and use it in GitHub Desktop.
jQuery plugin workaround for chrome bug which prevents display of visible options when some options are hidden. Also handles hiding/showing of options in apple webkit and internet explorer, which don't respect display:none for option elements (as of 06/2014).
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(function($){ | |
var userAgent = window.navigator.userAgent, | |
needsWrap = (userAgent.indexOf('Trident') !== -1 || userAgent.indexOf('AppleWebKit') !== -1); | |
/** | |
* Workaround for browsers that respect hidden options elements, but then fail to resize the select dropdown | |
* to display any visible elements beyond those that appear before any hidden elements - namely, Chrome. | |
* Based on the filter function, we either select all options that match (or, if invert is true, all that | |
* don't match), set them to disabled (with the expectation that there's a css rule hiding disabled options | |
* somewhere), and then pull the disabled options out of the DOM and insert them back in at the end of the | |
* select - this is tested as working in the most recent version of Chrome (as of this writing, v34). | |
* See also http://code.google.com/p/chromium/issues/detail?id=139595 and | |
* http://stackoverflow.com/questions/17203826/chrome-bug-on-select-element-dropdown-when-many-options-are-hidden | |
* for reports of the browser bug this works around. | |
* | |
* Additionally, we handle browsers that DON'T respect hidden options, by agent-sniffing such browsers | |
* and wrapping and unwrapping as necessary options that we want hidden in a span tag. | |
* | |
* @note This works, but DOM manipulation in IE is SLOW - much slower to perform an appendChild operation | |
* than any of the other major browsers. Wrapping/unwrapping large sets of options will take a relative long time (>2s) | |
* and have the potential to hang the UI thread. | |
* @param {string|HtmlElement|jQuery} el | |
* @param {function} filter | |
* @param {boolean=} invert | |
* @returns {jQuery} | |
*/ | |
$.elideOptions = function(el, filter, invert){ | |
var $el = (el instanceof $) ? el : $(el); | |
$el.each(function(){ | |
if (this.tagName !== 'SELECT') return; | |
var $this = $(this), | |
opts = $this.find('option').prop('disabled', false), | |
spans; | |
// Unwrap all options from their span tags | |
if (needsWrap && (spans = $this.find('span')) && spans.length){ | |
spans.children().unwrap(); | |
} | |
opts = (invert) ? opts.not(filter).prop('disabled', true) : | |
opts.filter(filter).prop('disabled', true); | |
// Wrap options in a single hidden span to hide them on browsers that don't support | |
// display:none for options | |
if (needsWrap) { | |
opts.wrapAll('<span class="hide"></span>'); | |
opts = opts.parent('span'); | |
} | |
opts.detach().appendTo($this); | |
}); | |
return $el; | |
}; | |
/** | |
* Allow for the $(element) form of invocation. | |
* @param {function} filter | |
* @param {boolean=} invert | |
* @returns {jQuery} | |
*/ | |
$.fn.elideOptions = function(filter, invert){ | |
return $.elideOptions(this, filter, invert); | |
}; | |
})(jQuery); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment