Skip to content

Instantly share code, notes, and snippets.

@mollwe
Last active December 19, 2015 13:59
Show Gist options
  • Save mollwe/5965647 to your computer and use it in GitHub Desktop.
Save mollwe/5965647 to your computer and use it in GitHub Desktop.
Replaces select (dropdowns) with a stylable jQuery UI widget that uses autocomplete.
.ui-combobox {
position: relative;
display: inline-block;
}
.ui-combobox-toggle {
width:1.5em;
right:-1px;
position: absolute !important;
top: 0;
bottom: 0;
margin-left: -1px;
padding: 0;
/* adjust styles for IE 6/7 */
*height: 1.7em;
*top: 0.1em;
}
.ui-combobox-input {
background: white !important;
margin: 0;
padding: .3em 1.5em .3em .3em;
}
/*!
* jquery.ui.combobox.js - v 0.1 (2013-07-10)
* Copyright (C) 2013 by Adam Ydenius ([email protected]) | http://mollwe.se
* Dual licensed under MIT and GPL.
*/
/*
* Replaces select (dropdowns) with a stylable jQuery UI widget that uses autocomplete.
*
* Selects that has been enabled with this plugin has class "ui-combobox-target".
*
* To enable plugin call combobox on the elements you would like to transform.
* Example: $("select:not(.no-ui-combobox)").combobox();
*
* Dependencies:
* jquery
* jquery.ui
*/
(function (factory) {
if (typeof define === 'function' && define.amd) {
// AMD. Register as an anonymous module.
define(['jquery', 'jquery-ui'], factory);
} else {
// Browser globals
factory(jQuery);
}
} (function ($) {
$.widget("ui.combobox", {
_create: function () {
var input,
that = this,
width = this.element.width(),
select = this.element.attr("tabindex", -1).addClass("ui-combobox-target ui-helper-hidden-accessible"),
disabled = select.is(":disabled"),
selected = select.children(":selected"),
empty = select.children("option[value=]"),
value = selected.val() !== "" ? selected.text() : "",
wrapper = this.wrapper = $("<span>")
.addClass("ui-combobox")
.css("margin", select.css("margin"))
.insertAfter(select);
function removeIfInvalid(element) {
var value = $(element).val(),
matcher = new RegExp("^" + $.ui.autocomplete.escapeRegex(value) + "$", "i"),
valid = false;
select.children("option").each(function () {
var text = $(this).text();
if (text.match(matcher)) {
valid = true;
$(element).val(text);
$(element).data("value", this.value);
if (this.selected !== true) {
this.selected = true;
select.change();
}
return false;
}
});
if (!valid) {
// remove invalid value, as it didn't match anything
select.change();
return false;
}
}
input = $("<input>")
.appendTo(wrapper)
.val(value)
.attr("title", "")
.attr("disabled", disabled)
.attr("spellcheck", false)
.attr("placeholder", empty.text())
.attr("data-value", select.val())
.addClass("ui-state-default ui-combobox-input")
.width(width - 20)
//.focus(function(){
// input.autocomplete("search", "");
//})
.autocomplete({
delay: 0,
minLength: 0,
autoFocus: true,
source: function (request, response) {
var matcher = new RegExp($.ui.autocomplete.escapeRegex(request.term), "i");
var filtered = select.children("option").map(function () {
var text = $(this).text();
if (!this.value && !request.term || this.value && (!request.term || matcher.test(text)))
return {
label: text.replace(
new RegExp(
"(?![^&;]+;)(?!<[^<>]*)(" +
$.ui.autocomplete.escapeRegex(request.term) +
")(?![^<>]*>)(?![^&;]+;)+", "gi"
), "<strong>$1</strong>"),
value: this.value === "" ? "" : text,
option: this
};
});
if (request.term !== null && request.term !== undefined && request.term.length) {
filtered = filtered.sort(function (a, b) {
var aIndex = a.value.indexOf(request.term),
bIndex = b.value.indexOf(request.term);
if (aIndex == bIndex) {
if (a.value.length == b.value.length) {
//console.debug("value", a.value, b.value, a.value > b.value ? b.value : a.value);
return a.value > b.value ? 1 : a.value < b.value ? -1 : 0;
}
//console.debug("length", a.value, a.value.length, b.value, b.value.length, a.value.length > b.value.length ? b.value : a.value);
return a.value.length - b.value.length;
}
//console.debug("index", a.value, aIndex, b.value, bIndex, aIndex > bIndex ? b.value : a.value);
return aIndex - bIndex;
});
}
response(filtered);
},
select: function (event, ui) {
var changed = !ui.item.option.selected;
ui.item.option.selected = true;
that._trigger("selected", event, {
item: ui.item.option
});
if (changed) selected.change();
},
change: function (event, ui) {
if (!ui.item)
return removeIfInvalid(this);
}
})
.addClass("ui-widget ui-widget-content ui-corner-left")
.on("blur.combobox", function () {
setTimeout(function () {
select.blur();
}, 0);
});
var autocomplete = input.data("autocomplete");
autocomplete._renderItem = function (ul, item) {
return $("<li>")
.data("item.autocomplete", item)
.append("<a>" + item.label + "</a>")
.appendTo(ul);
};
var button = $("<a>")
.attr("tabIndex", -1)
//.attr("title", "Show All Items")
//.tooltip()
.appendTo(wrapper)
.button({
icons: {
primary: "ui-icon-triangle-1-s"
},
disabled: disabled,
text: false
})
.removeClass("ui-corner-all")
.addClass("ui-corner-right ui-combobox-toggle")
.click(function () {
if (!$(this).button("option", "disabled")) {
// close if already visible
if (input.autocomplete("widget").is(":visible")) {
input.autocomplete("close");
removeIfInvalid(input);
return;
}
// work around a bug (likely same cause as #5265)
$(this).blur();
// pass empty string as value to search for, displaying all results
input.autocomplete("search", "");
input.focus();
}
});
var data = { input: input, select: select, button: button, autocomplete: autocomplete };
select.data("combobox", data);
input.data("combobox", data);
select.on("change.combobox", function () {
var value = select.val();
//if (value !== inputValue) {
var option = select.children("option[value='" + value + "']:first");
var text = option.text() || value;
input.val(value !== "" ? text : "");
input.data("autocomplete").term = text;
input.data("value", value);
//}
select.blur();
});
},
refresh: function () {
var combobox = this.element.data("combobox");
if (combobox.select.is(":disabled")) {
combobox.input.attr("disabled", true);
combobox.button.button("disable");
}
else {
combobox.input.attr("disabled", false);
combobox.button.button("enable");
}
combobox.input.val(combobox.select.val() || "");
},
disable: function () {
var combobox = this.element.data("combobox");
combobox.input.attr("disabled", true);
combobox.button.button("disable");
},
enable: function () {
var combobox = this.element.data("combobox");
combobox.input.attr("disabled", false);
combobox.button.button("enable");
},
destroy: function () {
this.wrapper.remove();
this.element.show();
$.Widget.prototype.destroy.call(this);
}
});
}));
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment