diff --git a/SearchableInput.css b/SearchableInput.css new file mode 100644 index 0000000..a3ec784 --- /dev/null +++ b/SearchableInput.css @@ -0,0 +1,37 @@ +div.searchable-input input +{ + width: 100%; + box-sizing: border-box; +} + +div.searchable-input div.items +{ + padding-top: 0.5em; + padding-bottom: 0.5em; + border: 1px solid #aaa; + /*border-top: 0;*/ + max-width: 100%; + max-height: 10em; + overflow-x: scroll; + overflow-y: scroll; + position: absolute; + background: #fff; + box-sizing: border-box; +} + +div.searchable-input div.item +{ + white-space: normal; + padding-left: 0.5em; + padding-right: 0.5em; + user-select: none; +} + +div.searchable-input div.item:hover +{ + /*background: #0af; + color: #fff;*/ + background: highlight; + color: highlighttext; + cursor: pointer; +} diff --git a/SearchableInput.js b/SearchableInput.js new file mode 100644 index 0000000..bf0e050 --- /dev/null +++ b/SearchableInput.js @@ -0,0 +1,206 @@ +$(function() { + SearchableInput = {}; + + SearchableInput.initItems = function() + { + var items = $("div.searchable-input div.item"); + + items.each(function(i, x) { + x = $(x); + + var parent = x.parents("div.searchable-input").first(); + var input = parent.find("input").first(); + var item = x; + var itemContainer = parent.find("div.items").first(); + + if (item.is("[onclick]")) + return; + + if (!item.is("[data-value]")) + return; + + item.unbind("mousedown"); + item.bind("mousedown", function() { + input.attr("data-value", item.attr("data-value")); + input.val(item.text().trim()); + itemContainer.hide(); + }); + }); + }; + + SearchableInput.init = function() + { + $("div.searchable-input input").each(function(i, x) { + x = $(x); + + var parent = x.parents("div.searchable-input").first(); + var backgroundColor = null; + var selectColor = null; + var input = x; + var itemContainer = parent.find("div.items").first(); + var items = itemContainer.find("div.item"); + var strictSearch = parent.attr("strict-search"); + + // Get first opaque body color: + parent.parents("*").each(function(i, x) { + if (backgroundColor !== null) + return; + + x = $(x); + var color = x.css("backgroundColor"); + + if (/^rgba/.test(color)) + { + var alphaPart = parseFloat(color.split(",")[3]); + + if (isNaN(alphaPart)) + return; + + if (alphaPart > 0.9) + backgroundColor = color; + + return; + } + + if (/^rgb/.test(color)) + backgroundColor = color; + }); + + itemContainer.hide(); + + x.unbind("blur"); + x.bind("blur", function() { + setTimeout(function() { + itemContainer.hide(); + + if (input.val().trim().length < 1) + input.attr("data-value", null); + }, 10); + }); + + x.unbind("input"); + x.bind("input", function() { + + var fnOnInputCooldown = function(itemContainer) + { + var parent = itemContainer.parents("div.searchable-input").first(); + var input = parent.find("input").first(); + var items = itemContainer.find("div.item"); + var searchTermsString = input.val().toLowerCase().trim(); + var searchTerms = searchTermsString.split(" "); + + items.hide(); + + items.each(function(i, x) { + x = $(x); + + var item = x; + var pass = 1; + var itemText = item.text().toLowerCase().trim(); + + if (strictSearch) + { + if (itemText.includes(searchTermsString)) + item.show(); + return; + } + + for (var i = 0; i < searchTerms.length; i++) + { + var searchTerm = searchTerms[i]; + if (searchTerm.length < 1) + continue; + if (!itemText.includes(searchTerm)) + pass = 0; + } + + //item.hide(); + + if (pass == 1) + item.show(); + }); + }; + + + var dataSourceApi = itemContainer.attr("data-source-api"); + + if (dataSourceApi) + { + if (typeof(SearchableInput.timeout) !== "undefined") + clearTimeout(SearchableInput.timeout); + + SearchableInput.timeout = setTimeout(function() { + var searchTermsString = input.val().toLowerCase().trim(); + + console.log(dataSourceApi); + + $.get({ + url: `${dataSourceApi}?q=${searchTermsString}`, + //url: `${dataSourceApi}`, + method: "get", + success: function(data) + { + console.log(data); + itemContainer.html(""); + + for (var i = 0; i < data.length; i++) + { + var item = data[i]; + var itemElement = $("
"); + + itemElement.addClass("item"); + itemElement.attr("data-value", item.value); + itemElement.html(item.name); + + itemContainer.append(itemElement); + } + + SearchableInput.initItems(); + + fnOnInputCooldown(itemContainer); + }, + error: function(xhr, e, m) + { + console.log(e); + console.log(m); + } + }); + }, 1000); + } + + fnOnInputCooldown(itemContainer); + }); + + x.unbind("focus"); + x.bind("focus", function() { + //x.trigger("input"); + + itemContainer.css("width", parent.width() + "px"); + itemContainer.css("background", backgroundColor); + + // If data-source is a valid jQuery selector, use that container's innerHTML: + var dataSource = itemContainer.attr("data-source"); + + if (dataSource) + { + var dataSourceObject = $(dataSource); + if (dataSourceObject.length > 0) + { + itemContainer.html(dataSourceObject.first().html()); + //SearchableInput.init(); + SearchableInput.initItems(); + } + } + + itemContainer.show(); + items.show(); + input.select(); + + }); + + SearchableInput.initItems(); + }); + }; + + SearchableInput.init(); +}); diff --git a/data.json b/data.json new file mode 100644 index 0000000..a158fd8 --- /dev/null +++ b/data.json @@ -0,0 +1,8 @@ +[ + {"name": "Item 1", "value": 0}, + {"name": "Item 2", "value": 1}, + {"name": "Item 3", "value": 2}, + {"name": "Item 4", "value": 3}, + {"name": "Item 5", "value": 4}, + {"name": "Item 6", "value": 5} +] diff --git a/index.html b/index.html new file mode 100644 index 0000000..583f641 --- /dev/null +++ b/index.html @@ -0,0 +1,140 @@ + + + + + + + + + + + + + + + + + + + + +Selection 1 | +
+
+
+
+
+ |
+
Selection 2 | +
+
+
+
+
+ |
+
Selection 3 | +
+
+
+
+
+ |
+
Selection 4 | +
+
+
+
+
+ |
+
Selection 5 | +
+
+
+
+
+ |
+