From 4118252037b987328b69c682802e3f197b8160f4 Mon Sep 17 00:00:00 2001 From: Conner Harkness Date: Thu, 27 Feb 2025 10:21:01 -0700 Subject: [PATCH] Initial commit --- SearchableInput.css | 37 ++++++++ SearchableInput.js | 206 ++++++++++++++++++++++++++++++++++++++++++++ data.json | 8 ++ index.html | 140 ++++++++++++++++++++++++++++++ 4 files changed, 391 insertions(+) create mode 100644 SearchableInput.css create mode 100644 SearchableInput.js create mode 100644 data.json create mode 100644 index.html 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 +
+ +
+
+
+ +
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
+
+ + + +