datalist improvements - jscancer - Javascript crap (relatively small)
(HTM) git clone git://git.codemadness.org/jscancer
(DIR) Log
(DIR) Files
(DIR) Refs
(DIR) README
(DIR) LICENSE
---
(DIR) commit 9cbdae2212ce9443cee3d20d28d6eeb3d522db6e
(DIR) parent 3c60e3f53de3ffe7c696d316ae627a30cdaa384e
(HTM) Author: Hiltjo Posthuma <hiltjo@codemadness.org>
Date: Sat, 15 Jul 2017 13:43:24 +0200
datalist improvements
- add function to get the request url dynamically: this can
be used for example to combine fields for autocompletion.
- add example for remote url.
- for a remote request open the complete list immediately if it is
unchanged.
- remote url: allow both a list or a dict with { label: "", value: "" }
Diffstat:
M datalist/README | 7 ++++---
M datalist/datalist.js | 66 +++++++++++++++++++++----------
M datalist/example.html | 10 ++++++++++
3 files changed, 60 insertions(+), 23 deletions(-)
---
(DIR) diff --git a/datalist/README b/datalist/README
@@ -8,10 +8,11 @@ FEATURES
--------
- Small:
- - Filesize: +- 6.7KB.
- - Lines: +- 235, not much code, so hopefully easy to understand.
+ - Filesize: +- 7.2KB.
+ - Lines: +- 250, not much code, so hopefully easy to understand.
- No dependencies on other libraries like jQuery.
-- (Graceful) fallback to HTML5 datalist if Javascript is disabled.
+- (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.
- Permissive ISC license, see LICENSE file, feel free to contact me for
(DIR) diff --git a/datalist/datalist.js b/datalist/datalist.js
@@ -9,34 +9,54 @@ function datalist_init(input) {
dropdown = document.createElement("div"),
prevmatches = [],
prevvalue = null,
- url = input.getAttribute("data-url") || "";
+ url = input.getAttribute("data-url") || "",
+ urlfn = input.getAttribute("data-urlfn") || "";
dropdown.className = "datalist-dropdown";
+ var getvalue = function(el) {
+ return el.getAttribute("data-value") ||
+ el.textContent || el.innerText;
+ };
+
var createitem = function(s) {
- var div = document.createElement("div");
- div.innerHTML = s;
+ var label, value, div = document.createElement("div");
+ if (typeof(s) === "string") {
+ label = value = s;
+ } else {
+ label = s.label;
+ value = s.value;
+ }
+
+ div.innerHTML = label;
+ div.setAttribute("data-value", value);
div.addEventListener("mousedown", function() {
- input.value = this.textContent || this.innerText;
+ input.value = getvalue(this);
datalist_show(false);
}, false);
div.addEventListener("mousemove", function() {
if (mouse)
datalist_setsel(this);
}, false);
- return { el: div, search: ((div.textContent || div.innerText).toLowerCase() || "").split(" ") };
+ return { el: div, label: label, value: value };
};
- if (url.length) {
+ if (url.length || urlfn.length) {
+ urlfn = urlfn.length ? window[urlfn] : function(s) {
+ return url + encodeURIComponent(s);
+ };
+
// "throttled" JSON XMLHttpRequest.
- var timer = null;
- datalist_match = function(s, fn) {
+ var timer = null, prevurl = "";
+ datalist_match = function(s, fn, ev) {
clearTimeout(timer);
+
+ url = urlfn(s);
+ if (url === prevurl) {
+ fn(prevmatches);
+ return;
+ }
+
timer = setTimeout(function() {
- s = s.toLowerCase();
- if (s === prevvalue) {
- fn(prevmatches);
- return;
- }
var x = new(XMLHttpRequest);
x.onreadystatechange = function() {
if (x.readyState != 4 || [ 0, 200 ].indexOf(x.status) == -1)
@@ -47,21 +67,26 @@ function datalist_init(input) {
for (var i = 0; i < o.length; i++)
prevmatches.push(createitem(o[i]));
- prevvalue = s;
+ prevurl = url;
fn(prevmatches);
};
- x.open("GET", url + encodeURIComponent(s) + "&t=" + String(new Date().getTime()), true);
+
+ x.open("GET", url + "&t=" + String(new Date().getTime()), true);
x.setRequestHeader("X-Requested-With", "XMLHttpRequest");
x.timeout = 10000;
x.send();
- }, 150); // delay in ms.
+ // delay in ms: throttle request on change, but on focus/click open fast.
+ }, ev == "onchange" ? 150 : 1);
};
} else {
// use inline <datalist>.
if (attrlist === null || ellist === undefined)
return;
- for (var i = 0, ec = ellist.children; i < ec.length; i++)
- items.push(createitem(ec[i].innerHTML));
+ for (var i = 0, ec = ellist.children, o; i < ec.length; i++) {
+ var o = createitem(getvalue(ec[i]));
+ o.search = o.label.toLowerCase().split(" ");
+ items.push(o);
+ }
var datalist_filter = function(data, s) {
var matches = [], tok = s.toLowerCase().split(" ");
@@ -89,6 +114,7 @@ function datalist_init(input) {
fn(prevmatches);
return;
}
+
// if token string is different or string not in previous search: use raw data,
// else filter on existing data and no need to sort.
if (prevvalue === null || (prevvalue.split(" ").length != s.split(" ").length) ||
@@ -131,7 +157,7 @@ function datalist_init(input) {
switch (e.which) {
case 13: // return
if (cursel)
- input.value = cursel.textContent || cursel.innerText;
+ input.value = getvalue(cursel);
if (!datalist_visible)
return;
datalist_show(false);
@@ -195,7 +221,7 @@ function datalist_init(input) {
datalist_setsel(m[0].el);
datalist_render(m);
datalist_show(!!m.length);
- });
+ }, "onchange");
};
input.addEventListener("input", onchange);
input.addEventListener("keyup", function(e) {
(DIR) diff --git a/datalist/example.html b/datalist/example.html
@@ -32,8 +32,18 @@
<label for="remote">OS: </label>
<input type="text" placeholder="Select OS..." value="" data-url="example-data.json?q=" name="remote" id="os" class="datalist" /><br/>
+<p>Using XMLHttpRequest + custom url function + JSON:</p>
+
+<label for="remotecustom">OS: </label>
+<input type="text" placeholder="Select OS..." value="" data-urlfn="custom_urlfn" name="remotecustom" id="os" class="datalist" /><br/>
+
</form>
+<script type="text/javascript">
+function custom_urlfn(s) {
+ return "example-data.json?q=" + encodeURIComponent(s);
+};
+</script>
<script type="text/javascript" src="datalist.js"></script>
</body>