Initial commit

This commit is contained in:
Conner Harkness 2025-02-27 10:21:01 -07:00
parent 20dce6b87a
commit 4118252037
4 changed files with 391 additions and 0 deletions

37
SearchableInput.css Normal file
View File

@ -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;
}

206
SearchableInput.js Normal file
View File

@ -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 = $("<div></div>");
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();
});

8
data.json Normal file
View File

@ -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}
]

140
index.html Normal file
View File

@ -0,0 +1,140 @@
<!DOCTYPE html>
<html>
<head>
<!-- Page styles unrelated to SearchableInput -->
<style>
* {
box-sizing: border-box;
}
html, body {
margin: 0;
padding: 0;
background: #aaa;
}
.document {
margin-left: auto;
margin-right: auto;
max-width: 1024px;
background: #fff;
padding: 0.25in;
}
.w-25 { width: 25%; }
</style>
<!-- jQuery is required! -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.7.1/jquery.min.js"></script>
<!-- Importing the CSS and JS -->
<link rel="stylesheet" href="SearchableInput.css" />
<script src="SearchableInput.js"></script>
</head>
<body>
<div id="data-source" style="display: none;">
<!-- Examples:
<div class="item" data-value="0">Item 1</div>
<div class="item" data-value="1">Item 1</div>
<div class="item" data-value="2">Item 1</div>
-->
</div>
<div class="document">
<table class="w-100">
<tbody>
<tr>
<td>Selection 1</td>
<td>
<div class="searchable-input" strict-search="1">
<input type="text" />
<div class="items" data-source="#data-source"></div>
</div>
</td>
</tr>
<tr>
<td>Selection 2</td>
<td>
<div class="searchable-input" strict-search="1">
<input type="text" />
<div class="items" data-source="#data-source"></div>
</div>
</td>
</tr>
<tr>
<td>Selection 3</td>
<td>
<div class="searchable-input" strict-search="1">
<input type="text" />
<div class="items" data-source="#data-source"></div>
</div>
</td>
</tr>
<tr>
<td>Selection 4</td>
<td>
<div class="searchable-input" strict-search="1">
<input type="text" />
<div class="items" data-source="#data-source"></div>
</div>
</td>
</tr>
<tr>
<td>Selection 5</td>
<td>
<div class="searchable-input">
<input type="text" />
<div class="items" data-source-api="data.json"></div>
</div>
</td>
</tr>
</tbody>
</table>
<div>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.</div>
</div>
<script>
$(function() {
fnChooseRandom = function(arr)
{
var min = 0;
var max = arr.length;
var i = Math.floor(Math.random() * (max - min + 1)) + min;
return arr[i];
};
var nouns = ["dog", "cat", "parrot", "fish"];
var colors = ["red", "yellow", "green", "blue"];
var id = 0;
nouns.forEach(function(n1) {
colors.forEach(function(c1) {
var elem = $("<div></div>");
elem.addClass("item");
elem.attr("data-value", id);
elem.html(`The quick ${c1} fox jumped over the lazy ${n1}`);
$("#data-source").first().append(elem);
id++;
});
});
});
</script>
</body>
</html>