Skip to content

Instantly share code, notes, and snippets.

@SaneMethod
Last active August 29, 2015 14:00
Show Gist options
  • Save SaneMethod/11193968 to your computer and use it in GitHub Desktop.
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).
(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