datepicker: 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 c1e9571c2fd4147beef18ae61f97206f8b9a29eb
 (DIR) parent 9e1bb1464a150fa8b9d1d253ccd5ca571b105c53
 (HTM) Author: Hiltjo Posthuma <hiltjo@codemadness.org>
       Date:   Thu,  2 Jun 2016 18:45:33 +0200
       
       datepicker: improvements
       
       - rename display to render (show vs display is more confusing), render only
         inserts the nodes.
       - fix relative positioning of datepicker dialog: for example in a table.
       - escape key closes dialog.
       - fix empty row on certain months (where the first day of the month is the same
         as the day to start the week.
       - use "1" as day when a date is partially input to highlight the date, else a
         date like: 2015-01-0 would display december 2015.
       
       Diffstat:
         M datepicker/datepicker.js            |      62 ++++++++++++++++---------------
       
       1 file changed, 33 insertions(+), 29 deletions(-)
       ---
 (DIR) diff --git a/datepicker/datepicker.js b/datepicker/datepicker.js
       @@ -29,7 +29,7 @@ function datepicker_init(input) {
                td.innerHTML = "&lt;";
                td.addEventListener("mousedown", function(e) {
                        datepicker_nextmon(-1);
       -                datepicker_display();
       +                datepicker_render();
                        return !!e.stopPropagation();
                }, false);
                var tr = document.createElement("tr");
       @@ -45,7 +45,7 @@ function datepicker_init(input) {
                td.innerHTML = "&gt;";
                td.addEventListener("mousedown", function(e) {
                        datepicker_nextmon(1);
       -                datepicker_display();
       +                datepicker_render();
                        return !!e.stopPropagation();
                }, false);
                tr.appendChild(td);
       @@ -66,7 +66,7 @@ function datepicker_init(input) {
                var datepicker_dateparse = function(s) {
                        var v = (s || "").split(/-/);
                        if (v.length == 3)
       -                        return new Date(v[0], parseInt(v[1]) - 1, v[2]);
       +                        return new Date(v[0], parseInt(v[1]) - 1, parseInt(v[2]) || 1);
                        return NaN;
                };
                var datepicker_hide = function() {
       @@ -77,15 +77,20 @@ function datepicker_init(input) {
                        table.hidden = false;
                        table.style.display = "table";
                        table.style.position = "absolute";
       -                table.style.left = String(input.offsetLeft) + "px";
       -                // scroll if outside window.
       +                var left = 0;
       +                for (var c = input; c; c = c.offsetParent) {
       +                        if (["absolute", "fixed"].indexOf(c.style.position) == -1)
       +                                left += c.offsetLeft;
       +                }
       +                table.style.left = String(left) + "px";
       +                /* scroll if outside window. */
                        input.scrollIntoView();
                };
                var datepicker_nextmon = function(n) {
                        curdate = new Date(curdate.getFullYear(), curdate.getMonth() + n, 1);
                };
       -        var datepicker_display = function() {
       -                datepicker_nextmon(0); // fix date
       +        var datepicker_render = function() {
       +                datepicker_nextmon(0); /* fix date */
                        var y = curdate.getFullYear(), m = curdate.getMonth();
                        header.innerHTML = datepicker_mons[m] + "&nbsp;" + String(y);
        
       @@ -110,14 +115,16 @@ function datepicker_init(input) {
                        for (var i = 1; i <= endday; i++) {
                                if ((datepicker_isoweekdate && !(((i - 1 % 7) + startidx) % 7)) ||
                                    (!datepicker_isoweekdate && !((i + startidx - 1) % 7))) {
       -                                tbody.appendChild(tr);
       -                                tr = document.createElement("tr");
       +                                if (tr.childNodes.length) {
       +                                        tbody.appendChild(tr);
       +                                        tr = document.createElement("tr");
       +                                }
                                }
                                var td = document.createElement("td");
                                td.setAttribute("data-value", String(y) + "-" + pad0(m + 1) + "-" + pad0(i));
                                td.appendChild(document.createTextNode(String(i)));
        
       -                        // check if valid date (enabled or disabled).
       +                        /* check if valid date (enabled or disabled). */
                                var classes = [];
                                var d = parsedateutc(td.getAttribute("data-value")) || 0;
                                if ((!isNaN(mindate) && d < mindate) ||
       @@ -125,7 +132,7 @@ function datepicker_init(input) {
                                        classes.push("d");
                                } else {
                                        classes.push("v");
       -                                // NOTE: onmousedown is handled before input.blur event.
       +                                /* NOTE: onmousedown is handled before input.blur event. */
                                        td.addEventListener("mousedown", function(e) {
                                                input.value = this.getAttribute("data-value");
                                                curdate = seldate = datepicker_dateparse(input.value);
       @@ -133,10 +140,10 @@ function datepicker_init(input) {
                                                return !!e.stopPropagation();
                                        }, false);
                                }
       -                        // selected date?
       +                        /* selected date? */
                                if (!isNaN(sel) && sel >= d && sel < d + 86400000)
                                        classes.push("sel");
       -                        // is date today?
       +                        /* is date today? */
                                if (now.getFullYear() == y && now.getMonth() == m && now.getDate() == i)
                                        classes.push("today");
                                td.className = classes.join(" ");
       @@ -149,16 +156,17 @@ function datepicker_init(input) {
                        tbodyel.parentNode.replaceChild(tbody, tbodyel);
                        tbodyel = tbody;
                };
       -
                var inparent = function(p, c) {
                        for (; c; c = c.parentNode)
                                if (c === p)
                                        return true;
                        return false;
                };
       -
       +        var pad0 = function(n) {
       +                return (n < 10 ? "0" : "") + String(n);
       +        };
                var focuschange = function(e) {
       -                if (e.target === input) {
       +                if (e.which !== 27 && e.target == input) {
                                if (input.value.length) {
                                        var d = datepicker_dateparse(input.value);
                                        if (!isNaN(d))
       @@ -166,35 +174,31 @@ function datepicker_init(input) {
                                } else {
                                        curdate = new Date();
                                }
       -                        datepicker_display();
       +                        datepicker_render();
                                datepicker_show();
       -                } else if (inparent(table, e.target)) {
       -                        // is in parent?
       -                        return;
       -                } else {
       -                        // format date onblur.
       +                } else if (!inparent(table, e.target)) {
       +                        /* is in parent? ignore */
       +                        /* format date onblur. */
                                var d = datepicker_dateparse(this.value);
                                if (!isNaN(d)) {
                                        curdate = seldate = d;
       -                                var pad0 = function(n) {
       -                                        return (n < 10 ? "0" : "") + String(n);
       -                                };
                                        input.value = String(d.getFullYear()) + "-" +
                                                pad0(d.getMonth() + 1) + "-" + pad0(d.getDate());
                                }
                                datepicker_hide();
                        }
                };
       -        document.addEventListener("keyup", focuschange, false);
       -        document.addEventListener("focus", focuschange, false);
                document.addEventListener("click", focuschange, false);
       +        input.addEventListener("input", focuschange, false);
       +        input.addEventListener("focus", focuschange, false);
       +        document.addEventListener("keyup", focuschange, false);
        
       -        datepicker_display();
       +        datepicker_render();
                datepicker_hide();
                input.parentNode.insertBefore(table, input.nextSibling);
        }
        
       -// Has native HTML5 date input type support? type is "text" if it isn't.
       +/* has native HTML5 date input type support? type is "text" if it isn't. */
        if (!(function() { var input = document.createElement("input"); try { input.type = "date"; return (input.type === "date"); } catch(e) {} return false; })()) {
                var els = document.getElementsByClassName && document.getElementsByClassName("date") || [];
                for (var i = 0; i < els.length; i++)