Introduction
Introduction Statistics Contact Development Disclaimer Help
datalist: add bloat - jscancer - Javascript crap (relatively small)
git clone git://git.codemadness.org/jscancer
Log
Files
Refs
README
LICENSE
---
commit ce985f99424e909b959b7cf2736312074e00d4cf
parent f57d63c6ffac03ddf58f78a5fb3958c1caf9a7d2
Author: Hiltjo Posthuma <[email protected]>
Date: Thu, 25 Apr 2024 20:04:43 +0200
datalist: add bloat
Diffstat:
M datalist/README | 12 +++++++-----
M datalist/datalist.css | 23 +++++++++++++++++++++++
M datalist/datalist.js | 190 ++++++++++++++++++++++++++---…
A datalist/example-data-cols-small.j… | 28 ++++++++++++++++++++++++++++
A datalist/example-data-cols.json | 79 +++++++++++++++++++++++++++++…
A datalist/example-json.html | 81 ++++++++++++++++++++++++++++++
6 files changed, 377 insertions(+), 36 deletions(-)
---
diff --git a/datalist/README b/datalist/README
@@ -1,25 +1,27 @@
datalist
========
-small dropdown filter / autocomplete script.
+relatively small dropdown filter / autocomplete script.
FEATURES
--------
- Small:
- - Filesize: +- 7.2KB.
- - Lines: +- 275, not much code, so hopefully easy to understand.
+ - Filesize: +- 12KB.
+ - Lines: +- 420, not much code, so hopefully easy to understand.
- No dependencies on other libraries like jQuery.
- (Graceful) fallback to HTML5 datalist if Javascript is disabled for inline
datalist.
- Filtering values: case-insensitively, tokenized (separated by space).
- Supports querying a remote server for results using a JSON XMLHttpRequest.
+- Show a table with multiple columns in the list, with nice alignment of items.
+ - Support HTML, for example for thumbnail images.
+ - Support a callback function per cell, row or to reformat the value.
- Permissive ISC license, see LICENSE file.
-- Officially supported browsers are:
+- Supported browsers are:
- Firefox and Firefox ESR.
- Chrome and most recent webkit-based browsers.
- - IE10+.
EXAMPLES
diff --git a/datalist/datalist.css b/datalist/datalist.css
@@ -23,3 +23,26 @@
datalist {
display: none;
}
+
+/* multi-column table in dropdown */
+.datalist-dropdown table {
+ border-collapse: collapse;
+ width: 100%;
+}
+.datalist-dropdown thead {
+ position: sticky;
+ top: 0;
+}
+.datalist-dropdown table th {
+ text-align: left;
+ background-color: #eee;
+ border-bottom: 2px solid #ccc;
+}
+.datalist-dropdown table th,
+.datalist-dropdown table td {
+ padding: 3px;
+}
+.datalist-dropdown table tr.sel td {
+ background-color: #33bbff;
+ color: #fff;
+}
diff --git a/datalist/datalist.js b/datalist/datalist.js
@@ -1,6 +1,16 @@
function datalist_init(input) {
- var attrlist = input.getAttribute("list"), ellist = document.getElemen…
-
+ var tablemode = false;
+ var attrlist = input.getAttribute("data-table") || "";
+ if (attrlist !== "")
+ tablemode = true;
+ else
+ attrlist = input.getAttribute("list")
+ var ellist = document.getElementById(attrlist);
+ var thead = null;
+ if (tablemode) {
+ if (ellist.tHead)
+ thead = ellist.tHead;
+ }
input.removeAttribute("list");
input.autocomplete = "off";
@@ -10,14 +20,28 @@ function datalist_init(input) {
prevmatches = [],
prevvalue = null,
url = input.getAttribute("data-url") || "",
- urlfn = input.getAttribute("data-urlfn") || "";
+ urlfn = input.getAttribute("data-urlfn") || "",
+ indom = false;
dropdown.className = "datalist-dropdown";
+ var ctx = {input: input, dropdown: dropdown};
+
var getlabel = function(el) {
return el.textContent || el.innerText || "";
};
- var getvalue = function(el) {
+ // set new input value.
+ var setvalue = function(el, value) {
+ var oldvalue = el.value;
+ if (input.oldvalue === value)
+ return;
+ el.value = el.oldvalue = value; // set new value.
+ el.dispatchEvent(new Event("value-changed"));
+ };
+ input.oldvalue = input.defaultValue; // store previous value.
+
+ // get last selection value (can be different from input value).
+ var getselvalue = function(el) {
var value = el.getAttribute("data-value");
if (value !== null)
return value;
@@ -27,39 +51,54 @@ function datalist_init(input) {
return el.textContent || el.innerText || "";
};
- var setvalue = function(el, value) {
- if (el.value !== value) {
- el.value = value;
+ // set selection value (can be different from input value).
+ var setselvalue = function(el, value) {
+ el.dispatchEvent(new Event("selection"));
+ var oldvalue = el.value;
+ setvalue(el, value);
+ if (oldvalue !== value)
el.dispatchEvent(new Event("selection-changed"));
- }
+ };
+
+ var datalist_enabled = function() {
+ return !input.readOnly && !input.disabled && !input.hidden;
};
// create item: expects string, or object with name and label attribut…
var createitem = function(o) {
- var label, value, div = document.createElement("div");
+ var label, row, value;
+ if (!tablemode)
+ row = document.createElement("div");
if (typeof(o) === "string") {
label = value = o;
+ row.textContent = label;
} else if (typeof(o.getAttribute) == "function") {
// element
label = getlabel(o);
- value = getvalue(o);
+ value = getselvalue(o);
+ if (tablemode)
+ row = o.cloneNode(true);
+ else
+ row.textContent = label;
} else {
// (JSON) object
label = o.label;
value = o.value;
+ row.textContent = label;
}
- div.innerHTML = label;
- div.setAttribute("data-value", value);
- div.addEventListener("mousedown", function() {
- setvalue(input, getvalue(this));
+ row.setAttribute("data-value", value);
+ row.addEventListener("mousedown", function() {
+ if (!datalist_enabled())
+ return;
+ setselvalue(input, getselvalue(this));
datalist_show(false);
}, false);
- div.addEventListener("mousemove", function() {
+ row.addEventListener("mousemove", function() {
if (mouse)
datalist_setsel(this);
}, false);
- return { el: div, label: label, value: value };
+ return { el: row, label: label, value: value };
};
if (url.length || urlfn.length) {
@@ -72,6 +111,9 @@ function datalist_init(input) {
datalist_match = function(s, fn, ev) {
clearTimeout(timer);
+ if (!datalist_enabled())
+ return;
+
var requrl = urlfn(s, input);
if (requrl === prevurl) {
fn(prevmatches);
@@ -93,8 +135,56 @@ function datalist_init(input) {
prevmatches = [];
var o = JSON.parse(x.responseText);
- for (var i = 0; i < o.length; i++)
- prevmatches.push(createitem(o[…
+ tablemode = !!o.columns && !!o.items;
+ if (tablemode) {
+ // create table header from co…
+ thead = document.createElement…
+ var tr = document.createElemen…
+ var valueidx = 0; // default i…
+
+ for (var i = 0; i < o.columns.…
+ var th = document.crea…
+ th.className = o.colum…
+ th.textContent = o.col…
+ if (o.columns[i].value)
+ valueidx = i;
+ tr.appendChild(th);
+ }
+ thead.appendChild(tr);
+
+ // add items as table rows: su…
+ for (var i = 0; i < o.items.le…
+ var tr = document.crea…
+ if (Array.isArray(o.it…
+ tr.setAttribut…
+ for (var j = 0…
+ var td…
+ td.tex…
+ tr.app…
+ }
+ } else {
+ tr.setAttribut…
+ for (var j = 0…
+ var co…
+ var td…
+ var va…
+ // cal…
+ var fn…
+ if (ty…
+ …
+ if (o.…
+ …
+ else
+ …
+ tr.app…
+ }
+ }
+ prevmatches.push(creat…
+ }
+ } else {
+ for (var i = 0; i < o.length; …
+ prevmatches.push(creat…
+ }
prevurl = requrl;
fn(prevmatches);
@@ -108,10 +198,11 @@ function datalist_init(input) {
}, ev == "onchange" ? 150 : 1);
};
} else {
- // use inline <datalist>.
- if (attrlist === null || ellist === undefined)
+ // use inline <datalist> or table.
+ if (attrlist === null || ellist === null)
return;
- for (var i = 0, ec = ellist.children, o; i < ec.length; i++) {
+
+ for (var i = 0, ec = (tablemode && ellist.tBodies.length) ? el…
var o = createitem(ec[i]);
o.search = o.label.toLowerCase().split(" ");
items.push(o);
@@ -138,6 +229,9 @@ function datalist_init(input) {
};
datalist_match = function(s, fn) {
+ if (!datalist_enabled())
+ return;
+
s = s.toLowerCase();
if (s === prevvalue) {
fn(prevmatches);
@@ -157,22 +251,55 @@ function datalist_init(input) {
}
var datalist_render = function(m) {
- var dd = dropdown.cloneNode(false);
+ if (!indom) { // add to DOM on first use when needed.
+ document.body.appendChild(dropdown);
+ indom = true;
+ }
+
+ var dd = dropdown.cloneNode(false), table, tbody;
+ if (tablemode) {
+ table = document.createElement("table");
+ if (thead)
+ table.tHead = thead.cloneNode(true);
+ tbody = document.createElement("tbody");
+ }
+
var r = input.getClientRects() || [];
if (r.length) {
dd.style.left = String(r[0].left + window.pageXOffset)…
dd.style.top = String(r[0].top + input.offsetHeight + …
}
- dd.style.minWidth = String(input.clientWidth) + "px";
- for (var i = 0; i < m.length; i++)
- dd.appendChild(m[i].el);
+ dd.style.minWidth = String(input.getAttribute("data-minwidth")…
+ if (tablemode) {
+ for (var i = 0; i < m.length; i++)
+ tbody.appendChild(m[i].el);
+ table.appendChild(tbody);
+ dd.appendChild(table);
+ } else {
+ for (var i = 0; i < m.length; i++)
+ dd.appendChild(m[i].el);
+ }
dropdown.parentNode.replaceChild(dd, dropdown)
dropdown = dd;
};
+
var datalist_visible = false;
var datalist_show = function(status) {
+ if (status && !datalist_enabled()) // do not show when disable…
+ return;
datalist_visible = status;
- dropdown.className = "datalist-dropdown " + (status ? "visible…
+ dropdown.className = "datalist-dropdown " + (status ? "visible…
+ var r = dropdown.getClientRects();
+ // if dropdown popup doesn't fit then adjust x, y scroll posit…
+ if (!r.length)
+ return;
+ if (r[0].left + r[0].width >= window.innerWidth) {
+ dropdown.style.left = "auto";
+ dropdown.style.right = "0px";
+ }
+ var ri = input.getClientRects() || [];
+ if (input.scrollIntoView && ri.length && r[0].top + dropdown.c…
+ input.scrollIntoView();
};
var datalist_setsel = function(el) {
if (cursel)
@@ -187,9 +314,7 @@ function datalist_init(input) {
switch (e.which) {
case 13: // return
if (cursel)
- setvalue(input, getvalue(cursel));
- if (!datalist_visible)
- return;
+ setselvalue(input, getselvalue(cursel));
datalist_show(false);
e.stopPropagation();
return !!e.preventDefault();
@@ -198,7 +323,7 @@ function datalist_init(input) {
case 34: // page down.
case 38: // arrow up
case 40: // arrow down
- var sel = cursel, dd = dropdown, dc = dropdown.childre…
+ var sel = cursel, dd = dropdown, dc = tablemode ? drop…
// if last and down arrow switch to first item, if fir…
if (dc.length) {
@@ -237,6 +362,7 @@ function datalist_init(input) {
}, false);
var onchange = function() {
+ setvalue(input, input.value);
datalist_match(input.value, function(m) {
// check if selection is still active in matches.
if (cursel) {
@@ -253,6 +379,7 @@ function datalist_init(input) {
datalist_show(!!m.length);
}, "onchange");
};
+
input.addEventListener("input", onchange);
input.addEventListener("keyup", function(e) {
mouse = true;
@@ -281,7 +408,8 @@ function datalist_init(input) {
datalist_setsel(null);
datalist_show(false);
}, false);
- document.body.appendChild(dropdown);
+
+ return ctx;
}
var els = document.getElementsByClassName("datalist");
diff --git a/datalist/example-data-cols-small.json b/datalist/example-data-cols…
@@ -0,0 +1,28 @@
+{
+"columns" :
+ [
+ {
+ "name" : "name",
+ "label" : "Name",
+ "value" : true
+ }, {
+ "name" : "type",
+ "label" : "Type"
+ }, {
+ "name" : "proprietary",
+ "label" : "Proprietary?"
+ }
+ ],
+"items" : [
+ ["DragonflyBSD", "BSD", "No"],
+ ["GNU/Hurd", "BSD-like", "No"],
+ ["GNU/Linux", "Linux", "No"],
+ ["FreeBSD", "BSD", "No"],
+ ["MS-DOS 6.11", "DOS", "Yes"],
+ ["OpenBSD", "BSD", "No"],
+ ["OpenSolaris", "BSD-like", "No"],
+ ["NetBSD", "BSD", "No"],
+ ["Plan9", "Plan9", "No"],
+ ["Windows", "Windows", "Yes"]
+]
+}
diff --git a/datalist/example-data-cols.json b/datalist/example-data-cols.json
@@ -0,0 +1,79 @@
+{
+"columns" :
+ [
+ {
+ "name" : "name",
+ "label" : "Name"
+ }, {
+ "name" : "type",
+ "label" : "Type"
+ }, {
+ "name" : "proprietary",
+ "label" : "Proprietary?",
+ "fn" : "item_bool"
+ }
+ ],
+"items" : [
+ {
+ "label" : "DragonflyBSD",
+ "value" : "DragonflyBSD",
+ "name" : "DragonflyBSD",
+ "type" : "BSD",
+ "proprietary" : "No"
+ }, {
+ "label" : "GNU/Hurd",
+ "value" : "GNU/Hurd",
+ "name" : "GNU/Hurd",
+ "type" : "BSD-like",
+ "proprietary" : "No"
+ }, {
+ "label" : "GNU/Linux",
+ "value" : "GNU/Linux",
+ "name" : "GNU/Linux",
+ "type" : "Linux",
+ "proprietary" : "No"
+ }, {
+ "label" : "FreeBSD",
+ "value" : "FreeBSD",
+ "name" : "FreeBSD",
+ "type" : "BSD",
+ "proprietary" : "No"
+ }, {
+ "label" : "MS-DOS 6.11",
+ "value" : "MS-DOS 6.11",
+ "name" : "MS-DOS 6.11",
+ "type" : "DOS",
+ "proprietary" : "Yes"
+ }, {
+ "label" : "OpenBSD",
+ "value" : "OpenBSD",
+ "name" : "OpenBSD",
+ "type" : "BSD",
+ "proprietary" : "No"
+ }, {
+ "label" : "OpenSolaris",
+ "value" : "OpenSolaris",
+ "name" : "OpenSolaris",
+ "type" : "BSD-like",
+ "proprietary" : "No"
+ }, {
+ "label" : "NetBSD",
+ "value" : "NetBSD",
+ "name" : "NetBSD",
+ "type" : "BSD",
+ "proprietary" : "No"
+ }, {
+ "label" : "Plan9",
+ "value" : "Plan9",
+ "name" : "Plan9",
+ "type" : "Plan9",
+ "proprietary" : "No"
+ }, {
+ "label" : "Windows",
+ "value" : "Windows",
+ "name" : "Windows",
+ "type" : "Windows",
+ "proprietary" : "Yes"
+ }
+]
+}
diff --git a/datalist/example-json.html b/datalist/example-json.html
@@ -0,0 +1,81 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR…
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+<title>jsdatalist</title>
+<link rel="stylesheet" type="text/css" href="datalist.css" />
+<style type="text/css">
+.yes {
+ background-color: #92d543;
+}
+.no {
+ background-color: #d54343;
+}
+</style>
+</head>
+<body>
+
+<form method="post" action="">
+
+<p>Inline &lt;datalist&gt;:</p>
+
+<label for="os">OS: </label>
+<input type="text" placeholder="Select OS..." value="" list="list" name="os" i…
+
+<datalist class="datalist" id="list">
+ <option>DragonflyBSD</option>
+ <option>GNU/Hurd</option>
+ <option>GNU/Linux</option>
+ <option>FreeBSD</option>
+ <option>MS-DOS&nbsp;6.11</option>
+ <option>OpenBSD</option>
+ <option>OpenSolaris</option>
+ <option>NetBSD</option>
+ <option>Plan9</option>
+ <option>Windows</option>
+</datalist>
+
+<p>Using XMLHttpRequest + JSON:</p>
+
+<label for="remote">OS: </label>
+<input type="text" placeholder="Select OS..." value="" data-url="example-data.…
+
+<p>Using XMLHttpRequest + custom URL function + JSON:</p>
+
+<label for="remotecustom">OS: </label>
+<input type="text" placeholder="Select OS..." value="" data-urlfn="custom_urlf…
+
+<label for="remotecustom2">OS: </label>
+<input type="text" placeholder="Select OS..." value="" data-urlfn="custom_urlf…
+
+<label for="remotecustom3">OS (multi-table): </label>
+<input type="text" placeholder="Select OS..." value="" data-urlfn="custom_mult…
+
+<label for="remotecustom4">OS (multi-table, small dataset): </label>
+<input type="text" placeholder="Select OS..." value="" data-urlfn="custom_mult…
+
+</form>
+
+<script type="text/javascript">
+function custom_urlfn(s, input) {
+ return "example-data.json?q=" + encodeURIComponent(s);
+}
+
+function custom_multi_urlfn(s, input) {
+ return "example-data-cols.json?q=" + encodeURIComponent(s);
+}
+
+function custom_multi_small_urlfn(s, input) {
+ return "example-data-cols-small.json?q=" + encodeURIComponent(s);
+}
+
+function datalist_format_item_bool(value, td) {
+ td.classList[value === "Yes" ? "add" : "remove"]("yes");
+ td.classList[value !== "Yes" ? "add" : "remove"]("no");
+ return value;
+}
+</script>
+<script type="text/javascript" src="datalist.js"></script>
+
+</body>
+</html>
You are viewing proxied material from codemadness.org. The copyright of proxied material belongs to its original authors. Any comments or complaints in relation to proxied material should be directed to the original authors of the content concerned. Please see the disclaimer for more details.