URI:
       autocomplete/datalist: batch of improvements - jscancer - Javascript crap (relatively small)
  HTML git clone git://git.codemadness.org/jscancer
   DIR Log
   DIR Files
   DIR Refs
   DIR README
   DIR LICENSE
       ---
   DIR commit 2967ba6942ad55041437a01f8603cc43e5e91c0a
   DIR parent 15738be7e39f50783051f26e06d2d7f193653261
  HTML Author: Hiltjo Posthuma <hiltjo@codemadness.org>
       Date:   Sat, 28 May 2016 20:30:30 +0200
       
       autocomplete/datalist: batch of improvements
       
       rename from autocomplete to datalist
       
       Diffstat:
         D autocomplete/README                 |      47 -------------------------------
         D autocomplete/TODO                   |       1 -
         D autocomplete/complete.js            |     161 -------------------------------
         D autocomplete/example.html           |      28 ----------------------------
         D autocomplete/style.css              |      26 --------------------------
         A datalist/README                     |      47 +++++++++++++++++++++++++++++++
         A datalist/TODO                       |       5 +++++
         A datalist/datalist.css               |      27 +++++++++++++++++++++++++++
         A datalist/datalist.js                |     164 +++++++++++++++++++++++++++++++
         A datalist/example.html               |      35 +++++++++++++++++++++++++++++++
       
       10 files changed, 278 insertions(+), 263 deletions(-)
       ---
   DIR diff --git a/autocomplete/README b/autocomplete/README
       @@ -1,47 +0,0 @@
       -autocomplete
       -============
       -
       -small Javascript autocomplete script.
       -
       -
       -FEATURES
       ---------
       -
       -- Small:
       -  - Filesize: +- 4.7KB, +- 2.3KB minified, +- 1KB GZIP'd.
       -  - Lines: +- 162, not much code, so hopefully easy to understand.
       -  - No dependencies on other libraries like jQuery.
       -- (Graceful) fallback to HTML5 datalist if Javascript is disabled.
       -- Filtering values: case-insensitively, tokenized (separated by space).
       -- Permissive ISC license, see LICENSE file, feel free to contact me for
       -  questions or other terms.
       -- No support for legacy browsers, officially supported are:
       -  - Firefox and Firefox ESR.
       -  - Chrome and most recent webkit-based browsers.
       -  - IE Edge.
       -
       -
       -USAGE
       ------
       -
       -
       -EXAMPLES
       ---------
       -
       -See example.html and style.css for an example. A stylesheet file style.css
       -is also included.
       -
       -An input should have the classname "autocomplete" set with the attribute
       -list="idoflist". The id should be of the datalist:
       -
       -<datalist name="nameoflist" id="idoflist">
       -        <option>Item 1</option>
       -        <option>Item 2</option>
       -        <option>Item 3</option>
       -</datalist>
       -
       -
       -Author
       -------
       -
       -Hiltjo Posthuma <hiltjo@codemadness.org>
   DIR diff --git a/autocomplete/TODO b/autocomplete/TODO
       @@ -1 +0,0 @@
       -- improve README and documentation.
   DIR diff --git a/autocomplete/complete.js b/autocomplete/complete.js
       @@ -1,161 +0,0 @@
       -function autocomplete_init(input) {
       -        var attrlist = input.getAttribute("list"), ellist = document.getElementById(attrlist);
       -        if (attrlist === null || ellist === undefined)
       -                return;
       -        input.removeAttribute("list");
       -        input.autocomplete = "off";
       -        var dropdown = document.createElement("div"),
       -                items = [],
       -                mouse = true, // enable mouse event handling.
       -                cursel = null;
       -        dropdown.className = "autocomplete-dropdown";
       -        dropdown.style.left = String(input.offsetLeft) + "px";
       -
       -        var autocomplete_match = function(s) {
       -                var matches = [], tok = s.toLowerCase().split(" ");
       -                for (var i = 0; i < items.length; i++) {
       -                        var fc = 0;
       -                        for (var k = 0; k < tok.length && fc < tok.length; k++) {
       -                                var f = false;
       -                                for (var j = 0; j < items[i].search.length && fc < tok.length && !f; j++)
       -                                        for (var l = 0; l < items[i].search.length && !f; l++)
       -                                                if (items[i].search[l].indexOf(tok[k]) != -1)
       -                                                        f = true;
       -                                if (f)
       -                                        fc++;
       -                        }
       -                        /* all tokens (separated by space) must match. */
       -                        if (fc == tok.length)
       -                                matches.push(items[i]);
       -                }
       -                return matches;
       -        };
       -        var autocomplete_render = function(m) {
       -                var p = dropdown.parentNode;
       -                var dd = dropdown.cloneNode(false);
       -                for (var i = 0; i < m.length; i++)
       -                        dd.appendChild(m[i].el);
       -                p.replaceChild(dd, dropdown)
       -                dropdown = dd;
       -        };
       -        var autocomplete_show = function(status) {
       -                dropdown.className = "autocomplete-dropdown " + (status ? "visible" : "");
       -        };
       -        var autocomplete_setsel = function(el) {
       -                if (cursel)
       -                        cursel.className = "";
       -                cursel = el;
       -                if (el)
       -                        el.className = "sel";
       -        };
       -
       -        for (var i = 0, ec = ellist.children; i < ec.length; i++) {
       -                var div = document.createElement("div");
       -                div.innerHTML = ec[i].innerHTML;
       -                div.onmousedown = function() {
       -                        input.value = this.textContent;
       -                        autocomplete_show(false);
       -                };
       -                div.onmousemove = function() {
       -                        if (mouse)
       -                                autocomplete_setsel(this);
       -                };
       -                items.push({ el: div, search: (div.textContent.toLowerCase() || "").split(" ") });
       -        }
       -        input.onkeydown = function(e) {
       -                mouse = false;
       -                switch (e.which) {
       -                case 13: // return
       -                        if (cursel)
       -                                this.value = cursel.textContent;
       -                        autocomplete_show(false);
       -                case 27: break; // escape
       -                case 33: // page up.
       -                case 34: // page down.
       -                case 38: // arrow up
       -                case 40: // arrow down
       -                        var sel = cursel, dd = dropdown, dc = dropdown.children;
       -
       -                        // if last and down arrow switch to first item, if first and up arrow switch to last item.
       -                        if (dc.length) {
       -                                if (e.which == 38) { // up
       -                                        if (!sel || !(sel = sel.previousSibling))
       -                                                sel = dc[dc.length - 1];
       -                                } else if (e.which == 40) { // down
       -                                        if (!sel || !(sel = sel.nextSibling))
       -                                                sel = dc[0];
       -                                } else if (!sel) {
       -                                        sel = dc[0];
       -                                }
       -                        }
       -                        if (cursel && (e.which == 33 || e.which == 34)) {
       -                                var n = sel.offsetHeight ? (dd.clientHeight / sel.offsetHeight) : 0;
       -                                if (e.which == 33) { // page up.
       -                                        for (; n > 0 && sel && sel.previousSibling;
       -                                                n--, sel = sel.previousSibling)
       -                                                ;
       -                                } else { // page down.
       -                                        for (; n > 0 && sel && sel.nextSibling;
       -                                                n--, sel = sel.nextSibling)
       -                                                ;
       -                                }
       -                        }
       -                        if (sel) {
       -                                autocomplete_setsel(sel);
       -
       -                                // only update scroll if needed.
       -                                if (sel.offsetTop < dd.scrollTop)
       -                                        dd.scrollTop = sel.offsetTop;
       -                                else if (sel.offsetTop + sel.offsetHeight > dd.scrollTop + dd.offsetHeight)
       -                                        dd.scrollTop = sel.offsetTop;
       -                        }
       -                }
       -        };
       -        input.oninput = function() {
       -                var m = autocomplete_match(this.value);
       -                // check if selection is still active in matches.
       -                if (cursel) {
       -                        var hassel = false;
       -                        for (var i = 0; i < m.length && !(hassel = (m[i].el === cursel)); i++)
       -                                ;
       -                        if (!hassel)
       -                                autocomplete_setsel(null);
       -                }
       -                // show list if it has matches.
       -                if (m.length) {
       -                        // only one match? select it.
       -                        if (m.length == 1)
       -                                autocomplete_setsel(m[0].el);
       -                        autocomplete_render(m);
       -                }
       -                autocomplete_show(!!m.length);
       -        };
       -        input.onkeyup = function(e) {
       -                mouse = true;
       -                // return key or escape was not pressed.
       -                if (e.which == 13 || e.which == 27)
       -                        autocomplete_show(false);
       -        };
       -
       -        var focuschange = function(e) {
       -                autocomplete_setsel(null);
       -                if (e.target === input) {
       -                        var m = autocomplete_match(input.value);
       -                        if (m.length)
       -                                autocomplete_render(m);
       -                        autocomplete_show(!!m.length);
       -                        dropdown.scrollTop = 0; // reset scroll.
       -                } else {
       -                        autocomplete_show(false);
       -                }
       -        };
       -        document.addEventListener("focus", focuschange, false);
       -        document.addEventListener("click", focuschange, false);
       -
       -        input.parentNode.insertBefore(dropdown, input.nextSibling);
       -}
       -
       -var els = document.getElementsByClassName("autocomplete");
       -if (els !== null)
       -        for (var i = 0; i < els.length; i++)
       -                autocomplete_init(els[i]);
   DIR diff --git a/autocomplete/example.html b/autocomplete/example.html
       @@ -1,28 +0,0 @@
       -<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
       -<html>
       -<head>
       -        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
       -        <title>jsautocomplete</title>
       -        <link rel="stylesheet" type="text/css" href="style.css" />
       -</head>
       -<body>
       -
       -<label for="os">OS: </label>
       -<input type="text" value="" list="list" name="os" id="os" class="autocomplete" /><br/>
       -
       -<datalist name="list" 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>NetBSD</option>
       -        <option>Plan9</option>
       -        <option>Windows</option>
       -</datalist>
       -
       -<script type="text/javascript" src="complete.js"></script>
       -
       -</body>
       -</html>
   DIR diff --git a/autocomplete/style.css b/autocomplete/style.css
       @@ -1,26 +0,0 @@
       -.autocomplete-dropdown {
       -        max-height: 300px;
       -        position: absolute;
       -        overflow: auto;
       -        z-index: 999;
       -        width: 600px;
       -        padding: 0;
       -        background-color: #fff;
       -        border: 1px solid #33bbff;
       -        display: none;
       -}
       -.autocomplete-dropdown.visible {
       -        display: block;
       -}
       -.autocomplete-dropdown div {
       -        padding: 0px 0px 0px 10px;
       -        cursor: default;
       -}
       -.autocomplete-dropdown div.sel {
       -        background-color: #33bbff;
       -        color: #fff;
       -}
       -/* hide datalist for browsers that don't support it */
       -datalist {
       -        display: none;
       -}
   DIR diff --git a/datalist/README b/datalist/README
       @@ -0,0 +1,47 @@
       +autocomplete
       +============
       +
       +small dropdown / autocomplete script.
       +
       +
       +FEATURES
       +--------
       +
       +- Small:
       +  - Filesize: +- 4.6KB.
       +  - Lines: +- 164, not much code, so hopefully easy to understand.
       +  - No dependencies on other libraries like jQuery.
       +- (Graceful) fallback to HTML5 datalist if Javascript is disabled.
       +- Filtering values: case-insensitively, tokenized (separated by space).
       +- Permissive ISC license, see LICENSE file, feel free to contact me for
       +  questions or other terms.
       +- Officially supported browsers are:
       +  - Firefox and Firefox ESR.
       +  - Chrome and most recent webkit-based browsers.
       +  - IE8+ (use compat.js).
       +
       +
       +USAGE
       +-----
       +
       +
       +EXAMPLES
       +--------
       +
       +See example.html and style.css for an example. A stylesheet file style.css
       +is also included.
       +
       +An input should have the classname "autocomplete" set with the attribute
       +list="idoflist". The id should be of the datalist:
       +
       +<datalist name="nameoflist" id="idoflist">
       +        <option>Item 1</option>
       +        <option>Item 2</option>
       +        <option>Item 3</option>
       +</datalist>
       +
       +
       +Author
       +------
       +
       +Hiltjo Posthuma <hiltjo@codemadness.org>
   DIR diff --git a/datalist/TODO b/datalist/TODO
       @@ -0,0 +1,5 @@
       +- test oninput clear?
       +- update examples.
       +- when autocomplete is closed RETURN should allow the normal event (for example for form submits).
       +        prevent default otherwise.
       +- improve README and documentation.
   DIR diff --git a/datalist/datalist.css b/datalist/datalist.css
       @@ -0,0 +1,27 @@
       +.datalist-dropdown {
       +        max-height: 300px;
       +        position: absolute;
       +        overflow: auto;
       +        z-index: 999;
       +        width: 600px;
       +        padding: 0;
       +        background-color: #fff;
       +        border: 1px solid #33bbff;
       +        display: none;
       +}
       +.datalist-dropdown.visible {
       +        display: block;
       +}
       +.datalist-dropdown div {
       +        padding: 0px 0px 0px 10px;
       +        cursor: default;
       +}
       +.datalist-dropdown div.sel {
       +        background-color: #33bbff;
       +        color: #fff;
       +}
       +/* hide datalist for browsers that don't support it */
       +select.datalist,
       +datalist {
       +        display: none;
       +}
   DIR diff --git a/datalist/datalist.js b/datalist/datalist.js
       @@ -0,0 +1,164 @@
       +function datalist_init(input) {
       +        var attrlist = input.getAttribute("list"), ellist = document.getElementById(attrlist);
       +        if (attrlist === null || ellist === undefined)
       +                return;
       +        input.removeAttribute("list");
       +        input.autocomplete = "off";
       +        var cursel = null, items = [], mouse = true, // enable mouse event handling.
       +                dropdown = document.createElement("div");
       +        dropdown.className = "datalist-dropdown";
       +        dropdown.style.left = String(input.offsetLeft) + "px";
       +
       +        for (var i = 0, ec = ellist.children; i < ec.length; i++) {
       +                var div = document.createElement("div");
       +                div.innerHTML = ec[i].innerHTML;
       +                div.addEventListener("mousedown", function() {
       +                        input.value = this.textContent || this.innerText;
       +                        datalist_show(false);
       +                }, false);
       +                div.addEventListener("mousemove", function() {
       +                        if (mouse)
       +                                datalist_setsel(this);
       +                }, false);
       +                items.push({ el: div, search: ((div.textContent || div.innerText).toLowerCase() || "").split(" ") });
       +        }
       +
       +        var datalist_match = function(s) {
       +                var matches = [], tok = s.toLowerCase().split(" ");
       +                for (var i = 0; i < items.length; i++) {
       +                        var fc = 0;
       +                        for (var k = 0; k < tok.length && fc < tok.length; k++) {
       +                                var f = false;
       +                                for (var j = 0; j < items[i].search.length && fc < tok.length && !f; j++)
       +                                        for (var l = 0; l < items[i].search.length && !f; l++)
       +                                                if (items[i].search[l].indexOf(tok[k]) != -1)
       +                                                        f = true;
       +                                if (f)
       +                                        fc++;
       +                        }
       +                        /* all tokens (separated by space) must match. */
       +                        if (fc == tok.length)
       +                                matches.push(items[i]);
       +                }
       +                return matches;
       +        },
       +        datalist_render = function(m) {
       +                var p = dropdown.parentNode;
       +                var dd = dropdown.cloneNode(false);
       +                for (var i = 0; i < m.length; i++)
       +                        dd.appendChild(m[i].el);
       +                p.replaceChild(dd, dropdown)
       +                dropdown = dd;
       +        },
       +        datalist_show = function(status) {
       +                dropdown.className = "datalist-dropdown " + (status ? "visible" : "");
       +        },
       +        datalist_setsel = function(el) {
       +                if (cursel)
       +                        cursel.className = "";
       +                cursel = el;
       +                if (el)
       +                        el.className = "sel";
       +        };
       +        input.addEventListener("keydown", function(e) {
       +                mouse = false;
       +                switch (e.which) {
       +                case 13: // return
       +                        if (cursel)
       +                                input.value = cursel.textContent || cursel.innerText;
       +                        datalist_show(false);
       +                case 27: break; // escape
       +                case 33: // page up.
       +                case 34: // page down.
       +                case 38: // arrow up
       +                case 40: // arrow down
       +                        var sel = cursel, dd = dropdown, dc = dropdown.children;
       +
       +                        // if last and down arrow switch to first item, if first and up arrow switch to last item.
       +                        if (dc.length) {
       +                                if (e.which == 38) { // up
       +                                        if (!sel || !(sel = sel.previousSibling))
       +                                                sel = dc[dc.length - 1];
       +                                } else if (e.which == 40) { // down
       +                                        if (!sel || !(sel = sel.nextSibling))
       +                                                sel = dc[0];
       +                                } else if (!sel) {
       +                                        sel = dc[0];
       +                                }
       +                        }
       +                        if (cursel && (e.which == 33 || e.which == 34)) {
       +                                var n = sel.offsetHeight ? (dd.clientHeight / sel.offsetHeight) : 0;
       +                                if (e.which == 33) { // page up.
       +                                        for (; n > 0 && sel && sel.previousSibling;
       +                                                n--, sel = sel.previousSibling)
       +                                                ;
       +                                } else { // page down.
       +                                        for (; n > 0 && sel && sel.nextSibling;
       +                                                n--, sel = sel.nextSibling)
       +                                                ;
       +                                }
       +                        }
       +                        if (sel) {
       +                                datalist_setsel(sel);
       +
       +                                // only update scroll if needed.
       +                                if (sel.offsetTop < dd.scrollTop)
       +                                        dd.scrollTop = sel.offsetTop;
       +                                else if (sel.offsetTop + sel.offsetHeight > dd.scrollTop + dd.offsetHeight)
       +                                        dd.scrollTop = sel.offsetTop;
       +                        }
       +                }
       +        }, false);
       +        input.addEventListener("keyup", function(e) {
       +                mouse = true;
       +                switch (e.which) {
       +                case 13: // return
       +                case 27: // escape
       +                        datalist_show(false);
       +                case 33: // page up.
       +                case 34: // page down.
       +                case 38: // arrow up
       +                case 40: // arrow down
       +                        return;
       +                }
       +                var m = datalist_match(input.value);
       +                // check if selection is still active in matches.
       +                if (cursel) {
       +                        var hassel = false;
       +                        for (var i = 0; i < m.length && !(hassel = (m[i].el === cursel)); i++)
       +                                ;
       +                        if (!hassel)
       +                                datalist_setsel(null);
       +                }
       +                // show list if it has matches.
       +                if (m.length) {
       +                        // only one match? select it.
       +                        if (m.length == 1)
       +                                datalist_setsel(m[0].el);
       +                        datalist_render(m);
       +                }
       +                datalist_show(!!m.length);
       +        }, false);
       +
       +        var focuschange = function(e) {
       +                datalist_setsel(null);
       +                if (e.target === input) {
       +                        var m = datalist_match(input.value);
       +                        if (m.length)
       +                                datalist_render(m);
       +                        datalist_show(!!m.length);
       +                        dropdown.scrollTop = 0; // reset scroll.
       +                } else {
       +                        datalist_show(false);
       +                }
       +        };
       +        document.addEventListener("focus", focuschange, false);
       +        document.addEventListener("click", focuschange, false);
       +
       +        input.parentNode.insertBefore(dropdown, input.nextSibling);
       +}
       +
       +var els = document.getElementsByClassName("datalist");
       +if (els !== null)
       +        for (var i = 0; i < els.length; i++)
       +                datalist_init(els[i]);
   DIR diff --git a/datalist/example.html b/datalist/example.html
       @@ -0,0 +1,35 @@
       +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
       +<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" />
       +</head>
       +<body>
       +
       +<form method="post" action="">
       +
       +<label for="os">OS: </label>
       +<input type="text" value="" list="list" name="os" id="os" class="datalist" /><br/>
       +
       +<!--[if lte IE 9]><select class="datalist" id="list"><![endif]-->
       +<!--[if !IE]>--><datalist class="datalist" id="list"><!--<![endif]-->
       +        <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>NetBSD</option>
       +        <option>Plan9</option>
       +        <option>Windows</option>
       +<!--[if !IE]>--></datalist><!--<![endif]-->
       +<!--[if lte IE 9]></select><![endif]-->
       +
       +</form>
       +
       +<!--[if lte IE 8]><script type="text/javascript" src="../compat.js"></script><![endif]-->
       +<script type="text/javascript" src="datalist.js"></script>
       +
       +</body>
       +</html>