Remove unused javascript/css
This commit is contained in:
		@@ -1,91 +0,0 @@
 | 
				
			|||||||
.date-selector-wrapper {
 | 
					 | 
				
			||||||
    width: 200px;
 | 
					 | 
				
			||||||
    padding: 3px;
 | 
					 | 
				
			||||||
    background-color: #fff;
 | 
					 | 
				
			||||||
    box-shadow: 1px 1px 10px 1px #5c5c5c;
 | 
					 | 
				
			||||||
    position: absolute;
 | 
					 | 
				
			||||||
    font-size: 12px;
 | 
					 | 
				
			||||||
    -webkit-user-select: none;
 | 
					 | 
				
			||||||
    -khtml-user-select: none;
 | 
					 | 
				
			||||||
    -moz-user-select: none;
 | 
					 | 
				
			||||||
    -ms-user-select: none;
 | 
					 | 
				
			||||||
    -o-user-select: none;
 | 
					 | 
				
			||||||
    /* user-select: none; */
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
.cal-header, .cal-row {
 | 
					 | 
				
			||||||
    display: flex;
 | 
					 | 
				
			||||||
    width: 100%;
 | 
					 | 
				
			||||||
    height: 30px;
 | 
					 | 
				
			||||||
    line-height: 30px;
 | 
					 | 
				
			||||||
    text-align: center;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
.cal-cell, .cal-nav {
 | 
					 | 
				
			||||||
    cursor: pointer;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
.cal-day-names {
 | 
					 | 
				
			||||||
    height: 25px;
 | 
					 | 
				
			||||||
    line-height: 25px;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
.cal-day-names .cal-cell {
 | 
					 | 
				
			||||||
    cursor: default;
 | 
					 | 
				
			||||||
    font-weight: bold;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
.cal-cell-prev, .cal-cell-next {
 | 
					 | 
				
			||||||
    color: #777;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
.cal-months .cal-row, .cal-years .cal-row {
 | 
					 | 
				
			||||||
    height: 60px;
 | 
					 | 
				
			||||||
    line-height: 60px;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
.cal-nav-prev, .cal-nav-next {
 | 
					 | 
				
			||||||
    flex: 0.15;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
.cal-nav-current {
 | 
					 | 
				
			||||||
    flex: 0.75;
 | 
					 | 
				
			||||||
    font-weight: bold;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
.cal-months .cal-cell, .cal-years .cal-cell {
 | 
					 | 
				
			||||||
    flex: 0.25;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
.cal-days .cal-cell {
 | 
					 | 
				
			||||||
    flex: 0.143;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
.cal-value {
 | 
					 | 
				
			||||||
    color: #fff;
 | 
					 | 
				
			||||||
    background-color: #286090;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
.cal-cell:hover, .cal-nav:hover {
 | 
					 | 
				
			||||||
    background-color: #eee;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
.cal-value:hover {
 | 
					 | 
				
			||||||
    background-color: #204d74;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/* time footer */
 | 
					 | 
				
			||||||
.cal-time {
 | 
					 | 
				
			||||||
    display: flex;
 | 
					 | 
				
			||||||
    justify-content: flex-start;
 | 
					 | 
				
			||||||
    height: 27px;
 | 
					 | 
				
			||||||
    line-height: 27px;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
.cal-time-label, .cal-time-value {
 | 
					 | 
				
			||||||
    flex: 0.12;
 | 
					 | 
				
			||||||
    text-align: center;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
.cal-time-slider {
 | 
					 | 
				
			||||||
    flex: 0.77;
 | 
					 | 
				
			||||||
    background-image: linear-gradient(to right, #d1d8dd, #d1d8dd);
 | 
					 | 
				
			||||||
    background-repeat: no-repeat;
 | 
					 | 
				
			||||||
    background-size: 100% 1px;
 | 
					 | 
				
			||||||
    background-position: left 50%;
 | 
					 | 
				
			||||||
    height: 100%;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
.cal-time-slider input {
 | 
					 | 
				
			||||||
    width: 100%;
 | 
					 | 
				
			||||||
    -webkit-appearance: none;
 | 
					 | 
				
			||||||
    background: 0 0;
 | 
					 | 
				
			||||||
    cursor: pointer;
 | 
					 | 
				
			||||||
    height: 100%;
 | 
					 | 
				
			||||||
    outline: 0;
 | 
					 | 
				
			||||||
    user-select: auto;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@@ -1,131 +0,0 @@
 | 
				
			|||||||
document.addEventListener("DOMContentLoaded", () => {
 | 
					 | 
				
			||||||
    fetch("/admin/data")
 | 
					 | 
				
			||||||
        .then((resp) => resp.json())
 | 
					 | 
				
			||||||
        .then((data) => {
 | 
					 | 
				
			||||||
            document.querySelector("#backlog").textContent = data.backlog;
 | 
					 | 
				
			||||||
            document.querySelector("#reminders").textContent = data.count.reminders;
 | 
					 | 
				
			||||||
            document.querySelector("#intervals").textContent = data.count.intervals;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            let historySent = data.historyLong.sent.reduce(
 | 
					 | 
				
			||||||
                (iv, frame) => iv + frame.count,
 | 
					 | 
				
			||||||
                0
 | 
					 | 
				
			||||||
            );
 | 
					 | 
				
			||||||
            let historyFailed = data.historyLong.failed.reduce(
 | 
					 | 
				
			||||||
                (iv, frame) => iv + frame.count,
 | 
					 | 
				
			||||||
                0
 | 
					 | 
				
			||||||
            );
 | 
					 | 
				
			||||||
            let rate = historyFailed / (historySent + historyFailed);
 | 
					 | 
				
			||||||
            let formatted = Math.round(rate * 10000) / 100;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            document.querySelector("#historySent").textContent = historySent;
 | 
					 | 
				
			||||||
            document.querySelector("#historyFailed").textContent = historyFailed;
 | 
					 | 
				
			||||||
            document.querySelector("#failRate").textContent = `${formatted}%`;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            new Chart(document.getElementById("schedule"), {
 | 
					 | 
				
			||||||
                type: "bar",
 | 
					 | 
				
			||||||
                data: {
 | 
					 | 
				
			||||||
                    labels: [
 | 
					 | 
				
			||||||
                        ...data.scheduleShort.once,
 | 
					 | 
				
			||||||
                        ...data.scheduleShort.interval,
 | 
					 | 
				
			||||||
                    ].map((row) => luxon.DateTime.fromISO(row.time_key)),
 | 
					 | 
				
			||||||
                    datasets: [
 | 
					 | 
				
			||||||
                        {
 | 
					 | 
				
			||||||
                            label: "Reminders",
 | 
					 | 
				
			||||||
                            data: data.scheduleShort.once.map((row) => row.count),
 | 
					 | 
				
			||||||
                        },
 | 
					 | 
				
			||||||
                        {
 | 
					 | 
				
			||||||
                            label: "Intervals",
 | 
					 | 
				
			||||||
                            data: data.scheduleShort.interval.map((row) => row.count),
 | 
					 | 
				
			||||||
                        },
 | 
					 | 
				
			||||||
                    ],
 | 
					 | 
				
			||||||
                },
 | 
					 | 
				
			||||||
                options: {
 | 
					 | 
				
			||||||
                    responsive: true,
 | 
					 | 
				
			||||||
                    maintainAspectRatio: false,
 | 
					 | 
				
			||||||
                    scales: {
 | 
					 | 
				
			||||||
                        x: {
 | 
					 | 
				
			||||||
                            stacked: true,
 | 
					 | 
				
			||||||
                            type: "time",
 | 
					 | 
				
			||||||
                            time: {
 | 
					 | 
				
			||||||
                                unit: "minute",
 | 
					 | 
				
			||||||
                            },
 | 
					 | 
				
			||||||
                        },
 | 
					 | 
				
			||||||
                        y: {
 | 
					 | 
				
			||||||
                            stacked: true,
 | 
					 | 
				
			||||||
                        },
 | 
					 | 
				
			||||||
                    },
 | 
					 | 
				
			||||||
                },
 | 
					 | 
				
			||||||
            });
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            new Chart(document.getElementById("scheduleLong"), {
 | 
					 | 
				
			||||||
                type: "bar",
 | 
					 | 
				
			||||||
                data: {
 | 
					 | 
				
			||||||
                    labels: [
 | 
					 | 
				
			||||||
                        ...data.scheduleLong.once,
 | 
					 | 
				
			||||||
                        ...data.scheduleLong.interval,
 | 
					 | 
				
			||||||
                    ].map((row) => luxon.DateTime.fromISO(row.time_key)),
 | 
					 | 
				
			||||||
                    datasets: [
 | 
					 | 
				
			||||||
                        {
 | 
					 | 
				
			||||||
                            label: "Reminders",
 | 
					 | 
				
			||||||
                            data: data.scheduleLong.once.map((row) => row.count),
 | 
					 | 
				
			||||||
                        },
 | 
					 | 
				
			||||||
                        {
 | 
					 | 
				
			||||||
                            label: "Intervals",
 | 
					 | 
				
			||||||
                            data: data.scheduleLong.interval.map((row) => row.count),
 | 
					 | 
				
			||||||
                        },
 | 
					 | 
				
			||||||
                    ],
 | 
					 | 
				
			||||||
                },
 | 
					 | 
				
			||||||
                options: {
 | 
					 | 
				
			||||||
                    responsive: true,
 | 
					 | 
				
			||||||
                    maintainAspectRatio: false,
 | 
					 | 
				
			||||||
                    scales: {
 | 
					 | 
				
			||||||
                        x: {
 | 
					 | 
				
			||||||
                            stacked: true,
 | 
					 | 
				
			||||||
                            type: "time",
 | 
					 | 
				
			||||||
                            time: {
 | 
					 | 
				
			||||||
                                unit: "day",
 | 
					 | 
				
			||||||
                            },
 | 
					 | 
				
			||||||
                        },
 | 
					 | 
				
			||||||
                        y: {
 | 
					 | 
				
			||||||
                            stacked: true,
 | 
					 | 
				
			||||||
                        },
 | 
					 | 
				
			||||||
                    },
 | 
					 | 
				
			||||||
                },
 | 
					 | 
				
			||||||
            });
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            new Chart(document.getElementById("historyLong"), {
 | 
					 | 
				
			||||||
                type: "bar",
 | 
					 | 
				
			||||||
                data: {
 | 
					 | 
				
			||||||
                    labels: [...data.historyLong.sent, ...data.historyLong.failed].map(
 | 
					 | 
				
			||||||
                        (row) => luxon.DateTime.fromISO(row.time_key)
 | 
					 | 
				
			||||||
                    ),
 | 
					 | 
				
			||||||
                    datasets: [
 | 
					 | 
				
			||||||
                        {
 | 
					 | 
				
			||||||
                            label: "Success",
 | 
					 | 
				
			||||||
                            data: data.historyLong.sent.map((row) => row.count),
 | 
					 | 
				
			||||||
                        },
 | 
					 | 
				
			||||||
                        {
 | 
					 | 
				
			||||||
                            label: "Fail",
 | 
					 | 
				
			||||||
                            data: data.historyLong.failed.map((row) => row.count),
 | 
					 | 
				
			||||||
                        },
 | 
					 | 
				
			||||||
                    ],
 | 
					 | 
				
			||||||
                },
 | 
					 | 
				
			||||||
                options: {
 | 
					 | 
				
			||||||
                    responsive: true,
 | 
					 | 
				
			||||||
                    maintainAspectRatio: false,
 | 
					 | 
				
			||||||
                    scales: {
 | 
					 | 
				
			||||||
                        x: {
 | 
					 | 
				
			||||||
                            stacked: true,
 | 
					 | 
				
			||||||
                            type: "time",
 | 
					 | 
				
			||||||
                            time: {
 | 
					 | 
				
			||||||
                                unit: "day",
 | 
					 | 
				
			||||||
                            },
 | 
					 | 
				
			||||||
                        },
 | 
					 | 
				
			||||||
                        y: {
 | 
					 | 
				
			||||||
                            stacked: true,
 | 
					 | 
				
			||||||
                        },
 | 
					 | 
				
			||||||
                    },
 | 
					 | 
				
			||||||
                },
 | 
					 | 
				
			||||||
            });
 | 
					 | 
				
			||||||
        });
 | 
					 | 
				
			||||||
});
 | 
					 | 
				
			||||||
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							@@ -1,7 +0,0 @@
 | 
				
			|||||||
/*!
 | 
					 | 
				
			||||||
 * chartjs-adapter-luxon v1.3.1
 | 
					 | 
				
			||||||
 * https://www.chartjs.org
 | 
					 | 
				
			||||||
 * (c) 2023 chartjs-adapter-luxon Contributors
 | 
					 | 
				
			||||||
 * Released under the MIT license
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(require("chart.js"),require("luxon")):"function"==typeof define&&define.amd?define(["chart.js","luxon"],t):t((e="undefined"!=typeof globalThis?globalThis:e||self).Chart,e.luxon)}(this,(function(e,t){"use strict";const n={datetime:t.DateTime.DATETIME_MED_WITH_SECONDS,millisecond:"h:mm:ss.SSS a",second:t.DateTime.TIME_WITH_SECONDS,minute:t.DateTime.TIME_SIMPLE,hour:{hour:"numeric"},day:{day:"numeric",month:"short"},week:"DD",month:{month:"short",year:"numeric"},quarter:"'Q'q - yyyy",year:{year:"numeric"}};e._adapters._date.override({_id:"luxon",_create:function(e){return t.DateTime.fromMillis(e,this.options)},init(e){this.options.locale||(this.options.locale=e.locale)},formats:function(){return n},parse:function(e,n){const i=this.options,r=typeof e;return null===e||"undefined"===r?null:("number"===r?e=this._create(e):"string"===r?e="string"==typeof n?t.DateTime.fromFormat(e,n,i):t.DateTime.fromISO(e,i):e instanceof Date?e=t.DateTime.fromJSDate(e,i):"object"!==r||e instanceof t.DateTime||(e=t.DateTime.fromObject(e,i)),e.isValid?e.valueOf():null)},format:function(e,t){const n=this._create(e);return"string"==typeof t?n.toFormat(t):n.toLocaleString(t)},add:function(e,t,n){const i={};return i[n]=t,this._create(e).plus(i).valueOf()},diff:function(e,t,n){return this._create(e).diff(this._create(t)).as(n).valueOf()},startOf:function(e,t,n){if("isoWeek"===t){n=Math.trunc(Math.min(Math.max(0,n),6));const t=this._create(e);return t.minus({days:(t.weekday-n+7)%7}).startOf("day").valueOf()}return t?this._create(e).startOf(t).valueOf():e},endOf:function(e,t){return this._create(e).endOf(t).valueOf()}})}));
 | 
					 | 
				
			||||||
@@ -1,931 +0,0 @@
 | 
				
			|||||||
(function () {
 | 
					 | 
				
			||||||
    "use strict";
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    var BODYTYPES = ["DAYS", "MONTHS", "YEARS"];
 | 
					 | 
				
			||||||
    var MONTHS = [
 | 
					 | 
				
			||||||
        "January", "February", "March", "April", "May", "June",
 | 
					 | 
				
			||||||
        "July", "August", "September", "October", "November", "December"
 | 
					 | 
				
			||||||
    ];
 | 
					 | 
				
			||||||
    var WEEKDAYS = [
 | 
					 | 
				
			||||||
        "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"
 | 
					 | 
				
			||||||
    ];
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /** @typedef {Object.<string, Function[]>} Handlers */
 | 
					 | 
				
			||||||
    /** @typedef {function(String, Function): null} AddHandler */
 | 
					 | 
				
			||||||
    /** @typedef {("DAYS"|"MONTHS"|"YEARS")} BodyType */
 | 
					 | 
				
			||||||
    /** @typedef {string|number} StringNum */
 | 
					 | 
				
			||||||
    /** @typedef {Object.<string, StringNum>} StringNumObj */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /**
 | 
					 | 
				
			||||||
     * The local state
 | 
					 | 
				
			||||||
     * @typedef {Object} InstanceState
 | 
					 | 
				
			||||||
     * @property {Date} value
 | 
					 | 
				
			||||||
     * @property {Number} year
 | 
					 | 
				
			||||||
     * @property {Number} month
 | 
					 | 
				
			||||||
     * @property {Number} day
 | 
					 | 
				
			||||||
     * @property {Number} time
 | 
					 | 
				
			||||||
     * @property {Number} hours
 | 
					 | 
				
			||||||
     * @property {Number} minutes
 | 
					 | 
				
			||||||
     * @property {Number} seconds
 | 
					 | 
				
			||||||
     * @property {BodyType} bodyType
 | 
					 | 
				
			||||||
     * @property {Boolean} visible
 | 
					 | 
				
			||||||
     * @property {Number} cancelBlur
 | 
					 | 
				
			||||||
     */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /** 
 | 
					 | 
				
			||||||
     * @typedef {Object} Config
 | 
					 | 
				
			||||||
     * @property {String} dateFormat
 | 
					 | 
				
			||||||
     * @property {String} timeFormat
 | 
					 | 
				
			||||||
     * @property {Boolean} showDate
 | 
					 | 
				
			||||||
     * @property {Boolean} showTime
 | 
					 | 
				
			||||||
     * @property {Number} paddingX
 | 
					 | 
				
			||||||
     * @property {Number} paddingY
 | 
					 | 
				
			||||||
     * @property {BodyType} defaultView
 | 
					 | 
				
			||||||
     * @property {"TOP"|"BOTTOM"} direction
 | 
					 | 
				
			||||||
    */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /**
 | 
					 | 
				
			||||||
     * @class
 | 
					 | 
				
			||||||
     * @param {HTMLElement} elem 
 | 
					 | 
				
			||||||
     * @param {Config} config 
 | 
					 | 
				
			||||||
     */
 | 
					 | 
				
			||||||
    function DTS(elem, config) {
 | 
					 | 
				
			||||||
        var config = config || {};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        /** @type {Config} */
 | 
					 | 
				
			||||||
        var defaultConfig = {
 | 
					 | 
				
			||||||
            defaultView: BODYTYPES[0],
 | 
					 | 
				
			||||||
            dateFormat: "yyyy-mm-dd",
 | 
					 | 
				
			||||||
            timeFormat: "HH:MM:SS",
 | 
					 | 
				
			||||||
            showDate: true,
 | 
					 | 
				
			||||||
            showTime: false,
 | 
					 | 
				
			||||||
            paddingX: 5,
 | 
					 | 
				
			||||||
            paddingY: 5,
 | 
					 | 
				
			||||||
            direction: 'TOP'
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if (!elem) {
 | 
					 | 
				
			||||||
            throw TypeError("input element or selector required for contructor");
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        if (Object.getPrototypeOf(elem) === String.prototype) {
 | 
					 | 
				
			||||||
            var _elem = document.querySelectorAll(elem);
 | 
					 | 
				
			||||||
            if (!_elem[0]){
 | 
					 | 
				
			||||||
                throw Error('"' + elem + '" not found.');
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            elem = _elem[0];
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        this.config = setDefaults(config, defaultConfig);
 | 
					 | 
				
			||||||
        this.dateFormat = this.config.dateFormat;
 | 
					 | 
				
			||||||
        this.timeFormat = this.config.timeFormat;
 | 
					 | 
				
			||||||
        this.dateFormatRegEx = new RegExp("yyyy|yy|mm|dd", "gi");
 | 
					 | 
				
			||||||
        this.timeFormatRegEx = new RegExp("hh|mm|ss|a", "gi");
 | 
					 | 
				
			||||||
        this.inputElem = elem;
 | 
					 | 
				
			||||||
        this.dtbox = null;
 | 
					 | 
				
			||||||
        this.setup();
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    DTS.prototype.setup = function () {
 | 
					 | 
				
			||||||
        var handler = this.inputElemHandler.bind(this);
 | 
					 | 
				
			||||||
        this.inputElem.addEventListener("focus", handler, false)
 | 
					 | 
				
			||||||
        this.inputElem.addEventListener("blur", handler, false);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    DTS.prototype.inputElemHandler = function (e) {
 | 
					 | 
				
			||||||
        if (e.type == "focus") {
 | 
					 | 
				
			||||||
            if (!this.dtbox) {
 | 
					 | 
				
			||||||
                this.dtbox = new DTBox(e.target, this);
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            this.dtbox.visible = true;
 | 
					 | 
				
			||||||
        } else if (e.type == "blur" && this.dtbox && this.dtbox.visible) {
 | 
					 | 
				
			||||||
            var self = this;
 | 
					 | 
				
			||||||
            setTimeout(function () {
 | 
					 | 
				
			||||||
                if (self.dtbox.cancelBlur > 0) {
 | 
					 | 
				
			||||||
                    self.dtbox.cancelBlur -= 1;
 | 
					 | 
				
			||||||
                 } else {
 | 
					 | 
				
			||||||
                    self.dtbox.visible = false;
 | 
					 | 
				
			||||||
                    self.inputElem.blur();
 | 
					 | 
				
			||||||
                 }
 | 
					 | 
				
			||||||
            }, 100);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    /**
 | 
					 | 
				
			||||||
     * @class
 | 
					 | 
				
			||||||
     * @param {HTMLElement} elem 
 | 
					 | 
				
			||||||
     * @param {DTS} settings 
 | 
					 | 
				
			||||||
     */
 | 
					 | 
				
			||||||
    function DTBox(elem, settings) {
 | 
					 | 
				
			||||||
        /** @type {DTBox} */
 | 
					 | 
				
			||||||
        var self = this;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        /** @type {Handlers} */
 | 
					 | 
				
			||||||
        var handlers = {};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        /** @type {InstanceState} */
 | 
					 | 
				
			||||||
        var localState = {};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        /**
 | 
					 | 
				
			||||||
         * @param {String} key 
 | 
					 | 
				
			||||||
         * @param {*} default_val 
 | 
					 | 
				
			||||||
         */
 | 
					 | 
				
			||||||
        function getterSetter(key, default_val) {
 | 
					 | 
				
			||||||
            return {
 | 
					 | 
				
			||||||
                get: function () {
 | 
					 | 
				
			||||||
                    var val = localState[key];
 | 
					 | 
				
			||||||
                    return val === undefined ? default_val : val;
 | 
					 | 
				
			||||||
                },
 | 
					 | 
				
			||||||
                set: function (val) {
 | 
					 | 
				
			||||||
                    var prevState = self.state;
 | 
					 | 
				
			||||||
                    var _handlers = handlers[key] || [];
 | 
					 | 
				
			||||||
                    localState[key] = val;
 | 
					 | 
				
			||||||
                    for (var i = 0; i < _handlers.length; i++) {
 | 
					 | 
				
			||||||
                        _handlers[i].bind(self)(localState, prevState);
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
                },
 | 
					 | 
				
			||||||
            };
 | 
					 | 
				
			||||||
        };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        /** @type {AddHandler} */
 | 
					 | 
				
			||||||
        function addHandler(key, handlerFn) {
 | 
					 | 
				
			||||||
            if (!key || !handlerFn) {
 | 
					 | 
				
			||||||
                return false;
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            if (!handlers[key]) {
 | 
					 | 
				
			||||||
                handlers[key] = [];
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            handlers[key].push(handlerFn);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        Object.defineProperties(this, {
 | 
					 | 
				
			||||||
            visible: getterSetter("visible", false),
 | 
					 | 
				
			||||||
            bodyType: getterSetter("bodyType", settings.config.defaultView),
 | 
					 | 
				
			||||||
            value: getterSetter("value"),
 | 
					 | 
				
			||||||
            year: getterSetter("year", 0),
 | 
					 | 
				
			||||||
            month: getterSetter("month", 0),
 | 
					 | 
				
			||||||
            day: getterSetter("day", 0),
 | 
					 | 
				
			||||||
            hours: getterSetter("hours", 0),
 | 
					 | 
				
			||||||
            minutes: getterSetter("minutes", 0),
 | 
					 | 
				
			||||||
            seconds: getterSetter("seconds", 0),
 | 
					 | 
				
			||||||
            cancelBlur: getterSetter("cancelBlur", 0),
 | 
					 | 
				
			||||||
            addHandler: {value: addHandler},
 | 
					 | 
				
			||||||
            month_long: {
 | 
					 | 
				
			||||||
                get: function () {
 | 
					 | 
				
			||||||
                    return MONTHS[self.month];
 | 
					 | 
				
			||||||
                },
 | 
					 | 
				
			||||||
            },
 | 
					 | 
				
			||||||
            month_short: {
 | 
					 | 
				
			||||||
                get: function () {
 | 
					 | 
				
			||||||
                    return self.month_long.slice(0, 3);
 | 
					 | 
				
			||||||
                },
 | 
					 | 
				
			||||||
            },
 | 
					 | 
				
			||||||
            state: {
 | 
					 | 
				
			||||||
                get: function () {
 | 
					 | 
				
			||||||
                    return Object.assign({}, localState);
 | 
					 | 
				
			||||||
                },
 | 
					 | 
				
			||||||
            },
 | 
					 | 
				
			||||||
            time: {
 | 
					 | 
				
			||||||
                get: function() {
 | 
					 | 
				
			||||||
                    var hours = self.hours * 60 * 60 * 1000;
 | 
					 | 
				
			||||||
                    var minutes = self.minutes * 60 * 1000;
 | 
					 | 
				
			||||||
                    var seconds = self.seconds * 1000;
 | 
					 | 
				
			||||||
                    return  hours + minutes + seconds;
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
            },
 | 
					 | 
				
			||||||
        });
 | 
					 | 
				
			||||||
        this.el = {};
 | 
					 | 
				
			||||||
        this.settings = settings;
 | 
					 | 
				
			||||||
        this.elem = elem;
 | 
					 | 
				
			||||||
        this.setup();
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    DTBox.prototype.setup = function () {
 | 
					 | 
				
			||||||
        Object.defineProperties(this.el, {
 | 
					 | 
				
			||||||
            wrapper: { value: null, configurable: true },
 | 
					 | 
				
			||||||
            header: { value: null, configurable: true },
 | 
					 | 
				
			||||||
            body: { value: null, configurable: true },
 | 
					 | 
				
			||||||
            footer: { value: null, configurable: true }
 | 
					 | 
				
			||||||
        });
 | 
					 | 
				
			||||||
        this.setupWrapper();
 | 
					 | 
				
			||||||
        if (this.settings.config.showDate) {
 | 
					 | 
				
			||||||
            this.setupHeader();
 | 
					 | 
				
			||||||
            this.setupBody();
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        if (this.settings.config.showTime) {
 | 
					 | 
				
			||||||
            this.setupFooter();
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        var self = this;
 | 
					 | 
				
			||||||
        this.addHandler("visible", function (state, prevState) {
 | 
					 | 
				
			||||||
            if (state.visible && !prevState.visible){
 | 
					 | 
				
			||||||
                document.body.appendChild(this.el.wrapper);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                var parts = self.elem.value.split(/\s*,\s*/);
 | 
					 | 
				
			||||||
                var startDate = undefined;
 | 
					 | 
				
			||||||
                var startTime = 0;
 | 
					 | 
				
			||||||
                if (self.settings.config.showDate) {
 | 
					 | 
				
			||||||
                    startDate = parseDate(parts[0], self.settings);
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
                if (self.settings.config.showTime) {
 | 
					 | 
				
			||||||
                    startTime = parseTime(parts[parts.length-1], self.settings);
 | 
					 | 
				
			||||||
                    startTime = startTime || 0;
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
                if (!(startDate && startDate.getTime())) {
 | 
					 | 
				
			||||||
                    startDate = new Date();
 | 
					 | 
				
			||||||
                    startDate = new Date(
 | 
					 | 
				
			||||||
                        startDate.getFullYear(),
 | 
					 | 
				
			||||||
                        startDate.getMonth(),
 | 
					 | 
				
			||||||
                        startDate.getDate()
 | 
					 | 
				
			||||||
                    );
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
                var value = new Date(startDate.getTime() + startTime);
 | 
					 | 
				
			||||||
                self.value = value;
 | 
					 | 
				
			||||||
                self.year = value.getFullYear();
 | 
					 | 
				
			||||||
                self.month = value.getMonth();
 | 
					 | 
				
			||||||
                self.day = value.getDate();
 | 
					 | 
				
			||||||
                self.hours = value.getHours();
 | 
					 | 
				
			||||||
                self.minutes = value.getMinutes();
 | 
					 | 
				
			||||||
                self.seconds = value.getSeconds();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                if (self.settings.config.showDate) {
 | 
					 | 
				
			||||||
                    self.setHeaderContent();
 | 
					 | 
				
			||||||
                    self.setBodyContent();
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
                if (self.settings.config.showTime) {
 | 
					 | 
				
			||||||
                    self.setFooterContent();
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
            } else if (!state.visible && prevState.visible) {
 | 
					 | 
				
			||||||
                document.body.removeChild(this.el.wrapper);
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        });
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    DTBox.prototype.setupWrapper = function () {
 | 
					 | 
				
			||||||
        if (!this.el.wrapper) {
 | 
					 | 
				
			||||||
            var el = document.createElement("div");
 | 
					 | 
				
			||||||
            el.classList.add("date-selector-wrapper");
 | 
					 | 
				
			||||||
            Object.defineProperty(this.el, "wrapper", { value: el });
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        var self = this;
 | 
					 | 
				
			||||||
        var htmlRoot = document.getElementsByTagName('html')[0];
 | 
					 | 
				
			||||||
        function setPosition(e){
 | 
					 | 
				
			||||||
            var minTopSpace = 300;
 | 
					 | 
				
			||||||
            var box = getOffset(self.elem);
 | 
					 | 
				
			||||||
            var config = self.settings.config;
 | 
					 | 
				
			||||||
            var paddingY = config.paddingY || 5;
 | 
					 | 
				
			||||||
            var paddingX = config.paddingX || 5;
 | 
					 | 
				
			||||||
            var top = box.top + self.elem.offsetHeight + paddingY;
 | 
					 | 
				
			||||||
            var left = box.left + paddingX;
 | 
					 | 
				
			||||||
            var bottom = htmlRoot.clientHeight - box.top + paddingY;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            self.el.wrapper.style.left = `${left}px`;
 | 
					 | 
				
			||||||
            if (box.top > minTopSpace && config.direction != 'BOTTOM') {
 | 
					 | 
				
			||||||
                self.el.wrapper.style.bottom = `${bottom}px`;
 | 
					 | 
				
			||||||
                self.el.wrapper.style.top = '';
 | 
					 | 
				
			||||||
            } else {
 | 
					 | 
				
			||||||
                self.el.wrapper.style.top = `${top}px`;
 | 
					 | 
				
			||||||
                self.el.wrapper.style.bottom = ''; 
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        function handler(e) {
 | 
					 | 
				
			||||||
            self.cancelBlur += 1;
 | 
					 | 
				
			||||||
            setTimeout(function(){
 | 
					 | 
				
			||||||
                self.elem.focus();
 | 
					 | 
				
			||||||
            }, 50);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        setPosition();
 | 
					 | 
				
			||||||
        this.setPosition = setPosition;
 | 
					 | 
				
			||||||
        this.el.wrapper.addEventListener("mousedown", handler, false);
 | 
					 | 
				
			||||||
        this.el.wrapper.addEventListener("touchstart", handler, false);
 | 
					 | 
				
			||||||
        window.addEventListener('resize', this.setPosition);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    DTBox.prototype.setupHeader = function () {
 | 
					 | 
				
			||||||
        if (!this.el.header) {
 | 
					 | 
				
			||||||
            var row = document.createElement("div");
 | 
					 | 
				
			||||||
            var classes = ["cal-nav-prev", "cal-nav-current", "cal-nav-next"];
 | 
					 | 
				
			||||||
            row.classList.add("cal-header");
 | 
					 | 
				
			||||||
            for (var i = 0; i < 3; i++) {
 | 
					 | 
				
			||||||
                var cell = document.createElement("div");
 | 
					 | 
				
			||||||
                cell.classList.add("cal-nav", classes[i]);
 | 
					 | 
				
			||||||
                cell.onclick = this.onHeaderChange.bind(this);
 | 
					 | 
				
			||||||
                row.appendChild(cell);
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            row.children[0].innerHTML = "<";
 | 
					 | 
				
			||||||
            row.children[2].innerHTML = ">";
 | 
					 | 
				
			||||||
            Object.defineProperty(this.el, "header", { value: row });
 | 
					 | 
				
			||||||
            tryAppendChild(row, this.el.wrapper);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        this.setHeaderContent();
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    DTBox.prototype.setHeaderContent = function () {
 | 
					 | 
				
			||||||
        var content = this.year;
 | 
					 | 
				
			||||||
        if ("DAYS" == this.bodyType) {
 | 
					 | 
				
			||||||
            content = this.month_long + " " + content;
 | 
					 | 
				
			||||||
        } else if ("YEARS" == this.bodyType) {
 | 
					 | 
				
			||||||
            var start = this.year + 10 - (this.year % 10);
 | 
					 | 
				
			||||||
            content = start - 10 + "-" + (start - 1);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        this.el.header.children[1].innerText = content;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    DTBox.prototype.setupBody = function () {
 | 
					 | 
				
			||||||
        if (!this.el.body) {
 | 
					 | 
				
			||||||
            var el = document.createElement("div");
 | 
					 | 
				
			||||||
            el.classList.add("cal-body");
 | 
					 | 
				
			||||||
            Object.defineProperty(this.el, "body", { value: el });
 | 
					 | 
				
			||||||
            tryAppendChild(el, this.el.wrapper);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        var toAppend = null;
 | 
					 | 
				
			||||||
        function makeGrid(rows, cols, className, firstRowClass, clickHandler) {
 | 
					 | 
				
			||||||
            var grid = document.createElement("div");
 | 
					 | 
				
			||||||
            grid.classList.add(className);
 | 
					 | 
				
			||||||
            for (var i = 1; i < rows + 1; i++) {
 | 
					 | 
				
			||||||
                var row = document.createElement("div");
 | 
					 | 
				
			||||||
                row.classList.add("cal-row", "cal-row-" + i);
 | 
					 | 
				
			||||||
                if (i == 1 && firstRowClass) {
 | 
					 | 
				
			||||||
                    row.classList.add(firstRowClass);
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
                for (var j = 1; j < cols + 1; j++) {
 | 
					 | 
				
			||||||
                    var col = document.createElement("div");
 | 
					 | 
				
			||||||
                    col.classList.add("cal-cell", "cal-col-" + j);
 | 
					 | 
				
			||||||
                    col.onclick = clickHandler;
 | 
					 | 
				
			||||||
                    row.appendChild(col);
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
                grid.appendChild(row);
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            return grid;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        if ("DAYS" == this.bodyType) {
 | 
					 | 
				
			||||||
            toAppend = this.el.body.calDays;
 | 
					 | 
				
			||||||
            if (!toAppend) {
 | 
					 | 
				
			||||||
                toAppend = makeGrid(7, 7, "cal-days", "cal-day-names", this.onDateSelected.bind(this));
 | 
					 | 
				
			||||||
                for (var i = 0; i < 7; i++) {
 | 
					 | 
				
			||||||
                    var cell = toAppend.children[0].children[i];
 | 
					 | 
				
			||||||
                    cell.innerText = WEEKDAYS[i].slice(0, 2);
 | 
					 | 
				
			||||||
                    cell.onclick = null;
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
                this.el.body.calDays = toAppend;
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        } else if ("MONTHS" == this.bodyType) {
 | 
					 | 
				
			||||||
            toAppend = this.el.body.calMonths;
 | 
					 | 
				
			||||||
            if (!toAppend) {
 | 
					 | 
				
			||||||
                toAppend = makeGrid(3, 4, "cal-months", null, this.onMonthSelected.bind(this));
 | 
					 | 
				
			||||||
                for (var i = 0; i < 3; i++) {
 | 
					 | 
				
			||||||
                    for (var j = 0; j < 4; j++) {
 | 
					 | 
				
			||||||
                        var monthShort = MONTHS[4 * i + j].slice(0, 3);
 | 
					 | 
				
			||||||
                        toAppend.children[i].children[j].innerText = monthShort;
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
                this.el.body.calMonths = toAppend;
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        } else if ("YEARS" == this.bodyType) {
 | 
					 | 
				
			||||||
            toAppend = this.el.body.calYears;
 | 
					 | 
				
			||||||
            if (!toAppend) {
 | 
					 | 
				
			||||||
                toAppend = makeGrid(3, 4, "cal-years", null, this.onYearSelected.bind(this));
 | 
					 | 
				
			||||||
                this.el.body.calYears = toAppend;
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        empty(this.el.body);
 | 
					 | 
				
			||||||
        tryAppendChild(toAppend, this.el.body);
 | 
					 | 
				
			||||||
        this.setBodyContent();
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    DTBox.prototype.setBodyContent = function () {
 | 
					 | 
				
			||||||
        var grid = this.el.body.children[0];
 | 
					 | 
				
			||||||
        var classes = ["cal-cell-prev", "cal-cell-next", "cal-value"];
 | 
					 | 
				
			||||||
        if ("DAYS" == this.bodyType) {
 | 
					 | 
				
			||||||
            var oneDayMilliSecs = 24 * 60 * 60 * 1000;
 | 
					 | 
				
			||||||
            var start = new Date(this.year, this.month, 1);
 | 
					 | 
				
			||||||
            var adjusted = new Date(start.getTime() - oneDayMilliSecs * start.getDay());
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            grid.children[6].style.display = "";
 | 
					 | 
				
			||||||
            for (var i = 1; i < 7; i++) {
 | 
					 | 
				
			||||||
                for (var j = 0; j < 7; j++) {
 | 
					 | 
				
			||||||
                    var cell = grid.children[i].children[j];
 | 
					 | 
				
			||||||
                    var month = adjusted.getMonth();
 | 
					 | 
				
			||||||
                    var date = adjusted.getDate();
 | 
					 | 
				
			||||||
                    
 | 
					 | 
				
			||||||
                    cell.innerText = date;
 | 
					 | 
				
			||||||
                    cell.classList.remove(classes[0], classes[1], classes[2]);
 | 
					 | 
				
			||||||
                    if (month != this.month) {
 | 
					 | 
				
			||||||
                        if (i == 6 && j == 0) {
 | 
					 | 
				
			||||||
                            grid.children[6].style.display = "none";
 | 
					 | 
				
			||||||
                            break;
 | 
					 | 
				
			||||||
                        }
 | 
					 | 
				
			||||||
                        cell.classList.add(month < this.month ? classes[0] : classes[1]);
 | 
					 | 
				
			||||||
                    } else if (isEqualDate(adjusted, this.value)){
 | 
					 | 
				
			||||||
                        cell.classList.add(classes[2]);
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
                    adjusted = new Date(adjusted.getTime() + oneDayMilliSecs);
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        } else if ("YEARS" == this.bodyType) {
 | 
					 | 
				
			||||||
            var year = this.year - (this.year % 10) - 1;
 | 
					 | 
				
			||||||
            for (i = 0; i < 3; i++) {
 | 
					 | 
				
			||||||
                for (j = 0; j < 4; j++) {
 | 
					 | 
				
			||||||
                    grid.children[i].children[j].innerText = year;
 | 
					 | 
				
			||||||
                    year += 1;
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            grid.children[0].children[0].classList.add(classes[0]);
 | 
					 | 
				
			||||||
            grid.children[2].children[3].classList.add(classes[1]);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /** @param {Event} e */
 | 
					 | 
				
			||||||
    DTBox.prototype.onTimeChange = function(e) {
 | 
					 | 
				
			||||||
        e.stopPropagation();
 | 
					 | 
				
			||||||
        if (e.type == 'mousedown') {
 | 
					 | 
				
			||||||
            this.cancelBlur += 1;
 | 
					 | 
				
			||||||
            return;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        
 | 
					 | 
				
			||||||
        var el = e.target;
 | 
					 | 
				
			||||||
        this[el.name] = parseInt(el.value) || 0;
 | 
					 | 
				
			||||||
        this.setupFooter();
 | 
					 | 
				
			||||||
        if (e.type == 'change') {
 | 
					 | 
				
			||||||
            var self = this;
 | 
					 | 
				
			||||||
            setTimeout(function(){
 | 
					 | 
				
			||||||
                self.elem.focus();
 | 
					 | 
				
			||||||
            }, 50);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        this.setInputValue();
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    DTBox.prototype.setupFooter = function() {
 | 
					 | 
				
			||||||
        if (!this.el.footer) {
 | 
					 | 
				
			||||||
            var footer = document.createElement("div");
 | 
					 | 
				
			||||||
            var handler = this.onTimeChange.bind(this);
 | 
					 | 
				
			||||||
            var self = this;
 | 
					 | 
				
			||||||
            
 | 
					 | 
				
			||||||
            function makeRow(label, name, range, changeHandler) {
 | 
					 | 
				
			||||||
                var row = document.createElement("div");
 | 
					 | 
				
			||||||
                row.classList.add('cal-time');
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                var labelCol = row.appendChild(document.createElement("div"));
 | 
					 | 
				
			||||||
                labelCol.classList.add('cal-time-label');
 | 
					 | 
				
			||||||
                labelCol.innerText = label;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                var valueCol = row.appendChild(document.createElement("div"));
 | 
					 | 
				
			||||||
                valueCol.classList.add('cal-time-value');
 | 
					 | 
				
			||||||
                valueCol.innerText = '00';
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                var inputCol = row.appendChild(document.createElement("div"));
 | 
					 | 
				
			||||||
                var slider = inputCol.appendChild(document.createElement("input"));
 | 
					 | 
				
			||||||
                Object.assign(slider, {step:1, min:0, max:range, name:name, type:'range'});
 | 
					 | 
				
			||||||
                Object.defineProperty(footer, name, {value: slider});
 | 
					 | 
				
			||||||
                inputCol.classList.add('cal-time-slider');
 | 
					 | 
				
			||||||
                slider.onchange = changeHandler;
 | 
					 | 
				
			||||||
                slider.oninput = changeHandler;
 | 
					 | 
				
			||||||
                slider.onmousedown = changeHandler;
 | 
					 | 
				
			||||||
                self[name] = self[name] || parseInt(slider.value) || 0;
 | 
					 | 
				
			||||||
                footer.appendChild(row)
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            makeRow('HH:', 'hours', 23, handler);
 | 
					 | 
				
			||||||
            makeRow('MM:', 'minutes', 59, handler);
 | 
					 | 
				
			||||||
            makeRow('SS:', 'seconds', 59, handler);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            footer.classList.add("cal-footer");
 | 
					 | 
				
			||||||
            Object.defineProperty(this.el, "footer", { value: footer });
 | 
					 | 
				
			||||||
            tryAppendChild(footer, this.el.wrapper);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        this.setFooterContent();
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    DTBox.prototype.setFooterContent = function() {
 | 
					 | 
				
			||||||
        if (this.el.footer) {
 | 
					 | 
				
			||||||
            var footer = this.el.footer;
 | 
					 | 
				
			||||||
            footer.hours.value = this.hours;
 | 
					 | 
				
			||||||
            footer.children[0].children[1].innerText = padded(this.hours, 2);
 | 
					 | 
				
			||||||
            footer.minutes.value = this.minutes;
 | 
					 | 
				
			||||||
            footer.children[1].children[1].innerText = padded(this.minutes, 2);
 | 
					 | 
				
			||||||
            footer.seconds.value = this.seconds;
 | 
					 | 
				
			||||||
            footer.children[2].children[1].innerText = padded(this.seconds, 2);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    DTBox.prototype.setInputValue = function() {
 | 
					 | 
				
			||||||
        var date = new Date(this.year, this.month, this.day);
 | 
					 | 
				
			||||||
        var strings = [];
 | 
					 | 
				
			||||||
        if (this.settings.config.showDate) {
 | 
					 | 
				
			||||||
            strings.push(renderDate(date, this.settings));
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        if (this.settings.config.showTime) {
 | 
					 | 
				
			||||||
            var joined = new Date(date.getTime() + this.time);
 | 
					 | 
				
			||||||
            strings.push(renderTime(joined, this.settings));
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        this.elem.value = strings.join(', ');
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    DTBox.prototype.onDateSelected = function (e) {
 | 
					 | 
				
			||||||
        var row = e.target.parentNode;
 | 
					 | 
				
			||||||
        var date = parseInt(e.target.innerText);
 | 
					 | 
				
			||||||
        if (!(row.nextSibling && row.nextSibling.nextSibling) && date < 8) {
 | 
					 | 
				
			||||||
            this.month += 1;
 | 
					 | 
				
			||||||
        } else if (!(row.previousSibling && row.previousSibling.previousSibling) && date > 7) {
 | 
					 | 
				
			||||||
            this.month -= 1;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        this.day = parseInt(e.target.innerText);
 | 
					 | 
				
			||||||
        this.value = new Date(this.year, this.month, this.day);
 | 
					 | 
				
			||||||
        this.setInputValue();
 | 
					 | 
				
			||||||
        this.setHeaderContent();
 | 
					 | 
				
			||||||
        this.setBodyContent();
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /** @param {Event} e */
 | 
					 | 
				
			||||||
    DTBox.prototype.onMonthSelected = function (e) {
 | 
					 | 
				
			||||||
        var col = 0;
 | 
					 | 
				
			||||||
        var row = 2;
 | 
					 | 
				
			||||||
        var cell = e.target;
 | 
					 | 
				
			||||||
        if (cell.parentNode.nextSibling){
 | 
					 | 
				
			||||||
            row = cell.parentNode.previousSibling ? 1: 0;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        if (cell.previousSibling) {
 | 
					 | 
				
			||||||
            col = 3;
 | 
					 | 
				
			||||||
            if (cell.nextSibling) {
 | 
					 | 
				
			||||||
                col = cell.previousSibling.previousSibling ? 2 : 1;
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        this.month = 4 * row + col;
 | 
					 | 
				
			||||||
        this.bodyType = "DAYS";
 | 
					 | 
				
			||||||
        this.setHeaderContent();
 | 
					 | 
				
			||||||
        this.setupBody();
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /** @param {Event} e */
 | 
					 | 
				
			||||||
    DTBox.prototype.onYearSelected = function (e) {
 | 
					 | 
				
			||||||
        this.year = parseInt(e.target.innerText);
 | 
					 | 
				
			||||||
        this.bodyType = "MONTHS";
 | 
					 | 
				
			||||||
        this.setHeaderContent();
 | 
					 | 
				
			||||||
        this.setupBody();
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /** @param {Event} e */
 | 
					 | 
				
			||||||
    DTBox.prototype.onHeaderChange = function (e) {
 | 
					 | 
				
			||||||
        var cell = e.target;
 | 
					 | 
				
			||||||
        if (cell.previousSibling && cell.nextSibling) {
 | 
					 | 
				
			||||||
            var idx = BODYTYPES.indexOf(this.bodyType);
 | 
					 | 
				
			||||||
            if (idx < 0 || !BODYTYPES[idx + 1]) {
 | 
					 | 
				
			||||||
                return;
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            this.bodyType = BODYTYPES[idx + 1];
 | 
					 | 
				
			||||||
            this.setupBody();
 | 
					 | 
				
			||||||
        } else {
 | 
					 | 
				
			||||||
            var sign = cell.previousSibling ? 1 : -1;
 | 
					 | 
				
			||||||
            switch (this.bodyType) {
 | 
					 | 
				
			||||||
                case "DAYS":
 | 
					 | 
				
			||||||
                    this.month += sign * 1;
 | 
					 | 
				
			||||||
                    break;
 | 
					 | 
				
			||||||
                case "MONTHS":
 | 
					 | 
				
			||||||
                    this.year += sign * 1;
 | 
					 | 
				
			||||||
                    break;
 | 
					 | 
				
			||||||
                case "YEARS":
 | 
					 | 
				
			||||||
                    this.year += sign * 10;
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            if (this.month > 11 || this.month < 0) {
 | 
					 | 
				
			||||||
                this.year += Math.floor(this.month / 11);
 | 
					 | 
				
			||||||
                this.month = this.month > 11 ? 0 : 11;
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        this.setHeaderContent();
 | 
					 | 
				
			||||||
        this.setBodyContent();
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /**
 | 
					 | 
				
			||||||
     * @param {HTMLElement} elem 
 | 
					 | 
				
			||||||
     * @returns {{left:number, top:number}}
 | 
					 | 
				
			||||||
     */
 | 
					 | 
				
			||||||
    function getOffset(elem) {
 | 
					 | 
				
			||||||
        var box = elem.getBoundingClientRect();
 | 
					 | 
				
			||||||
        var left = window.pageXOffset !== undefined ? window.pageXOffset : 
 | 
					 | 
				
			||||||
            (document.documentElement || document.body.parentNode || document.body).scrollLeft;
 | 
					 | 
				
			||||||
        var top = window.pageYOffset !== undefined ? window.pageYOffset : 
 | 
					 | 
				
			||||||
            (document.documentElement || document.body.parentNode || document.body).scrollTop;
 | 
					 | 
				
			||||||
        return { left: box.left + left, top: box.top + top };
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    function empty(e) {
 | 
					 | 
				
			||||||
        for (; e.children.length; ) e.removeChild(e.children[0]);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    function tryAppendChild(newChild, refNode) {
 | 
					 | 
				
			||||||
        try {
 | 
					 | 
				
			||||||
            refNode.appendChild(newChild);
 | 
					 | 
				
			||||||
            return newChild;
 | 
					 | 
				
			||||||
        } catch (e) {
 | 
					 | 
				
			||||||
            console.trace(e);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /** @class */
 | 
					 | 
				
			||||||
    function hookFuncs() {
 | 
					 | 
				
			||||||
        /** @type {Handlers} */
 | 
					 | 
				
			||||||
        this._funcs = {};
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    /**
 | 
					 | 
				
			||||||
     * @param {string} key 
 | 
					 | 
				
			||||||
     * @param {Function} func 
 | 
					 | 
				
			||||||
     */
 | 
					 | 
				
			||||||
    hookFuncs.prototype.add = function(key, func){
 | 
					 | 
				
			||||||
        if (!this._funcs[key]){
 | 
					 | 
				
			||||||
            this._funcs[key] = [];
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        this._funcs[key].push(func)
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    /**
 | 
					 | 
				
			||||||
     * @param {String} key 
 | 
					 | 
				
			||||||
     * @returns {Function[]} handlers
 | 
					 | 
				
			||||||
     */
 | 
					 | 
				
			||||||
    hookFuncs.prototype.get = function(key){
 | 
					 | 
				
			||||||
        return this._funcs[key] ? this._funcs[key] : [];
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /**
 | 
					 | 
				
			||||||
     * @param {Array.<string>} arr 
 | 
					 | 
				
			||||||
     * @param {String} string 
 | 
					 | 
				
			||||||
     * @returns {Array.<string>} sorted string
 | 
					 | 
				
			||||||
     */
 | 
					 | 
				
			||||||
    function sortByStringIndex(arr, string) {
 | 
					 | 
				
			||||||
        return arr.sort(function(a, b){
 | 
					 | 
				
			||||||
            var h = string.indexOf(a);
 | 
					 | 
				
			||||||
            var l = string.indexOf(b);
 | 
					 | 
				
			||||||
            var rank = 0;
 | 
					 | 
				
			||||||
            if (h < l) {
 | 
					 | 
				
			||||||
                rank = -1;
 | 
					 | 
				
			||||||
            } else if (l < h) {
 | 
					 | 
				
			||||||
                rank = 1;
 | 
					 | 
				
			||||||
            } else if (a.length > b.length) {
 | 
					 | 
				
			||||||
                rank = -1;
 | 
					 | 
				
			||||||
            } else if (b.length > a.length) {
 | 
					 | 
				
			||||||
                rank = 1;
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            return rank;
 | 
					 | 
				
			||||||
        });
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /**
 | 
					 | 
				
			||||||
     * Remove keys from array that are not in format
 | 
					 | 
				
			||||||
     * @param {string[]} keys 
 | 
					 | 
				
			||||||
     * @param {string} format 
 | 
					 | 
				
			||||||
     * @returns {string[]} new filtered array
 | 
					 | 
				
			||||||
     */
 | 
					 | 
				
			||||||
    function filterFormatKeys(keys, format) {
 | 
					 | 
				
			||||||
        var out = [];
 | 
					 | 
				
			||||||
        var formatIdx = 0;
 | 
					 | 
				
			||||||
        for (var i = 0; i<keys.length; i++) {
 | 
					 | 
				
			||||||
            var key = keys[i];
 | 
					 | 
				
			||||||
            if (format.slice(formatIdx).indexOf(key) > -1) {
 | 
					 | 
				
			||||||
                formatIdx += key.length;
 | 
					 | 
				
			||||||
                out.push(key);
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        return out;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /**
 | 
					 | 
				
			||||||
     * @template {StringNumObj} FormatObj
 | 
					 | 
				
			||||||
     * @param {string} value 
 | 
					 | 
				
			||||||
     * @param {string} format 
 | 
					 | 
				
			||||||
     * @param {FormatObj} formatObj 
 | 
					 | 
				
			||||||
     * @param {function(Object.<string, hookFuncs>): null} setHooks 
 | 
					 | 
				
			||||||
     * @returns {FormatObj} formatObj
 | 
					 | 
				
			||||||
     */
 | 
					 | 
				
			||||||
    function parseData(value, format, formatObj, setHooks) {
 | 
					 | 
				
			||||||
        var hooks = {
 | 
					 | 
				
			||||||
            canSkip: new hookFuncs(),
 | 
					 | 
				
			||||||
            updateValue: new hookFuncs(),
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        var keys = sortByStringIndex(Object.keys(formatObj), format);
 | 
					 | 
				
			||||||
        var filterdKeys = filterFormatKeys(keys, format);
 | 
					 | 
				
			||||||
        var vstart = 0; // value start
 | 
					 | 
				
			||||||
        if (setHooks) {
 | 
					 | 
				
			||||||
            setHooks(hooks);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        for (var i = 0; i < keys.length; i++) {
 | 
					 | 
				
			||||||
            var key = keys[i];
 | 
					 | 
				
			||||||
            var fstart = format.indexOf(key);
 | 
					 | 
				
			||||||
            var _vstart = vstart; // next value start
 | 
					 | 
				
			||||||
            var val = null;
 | 
					 | 
				
			||||||
            var canSkip = false;
 | 
					 | 
				
			||||||
            var funcs = hooks.canSkip.get(key);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            vstart = vstart || fstart;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            for (var j = 0; j < funcs.length; j++) {
 | 
					 | 
				
			||||||
                if (funcs[j](formatObj)){
 | 
					 | 
				
			||||||
                    canSkip = true;
 | 
					 | 
				
			||||||
                    break;
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            if (fstart > -1 && !canSkip) {
 | 
					 | 
				
			||||||
                var sep = null;
 | 
					 | 
				
			||||||
                var stop = vstart + key.length;
 | 
					 | 
				
			||||||
                var fnext = -1;
 | 
					 | 
				
			||||||
                var nextKeyIdx = i + 1;
 | 
					 | 
				
			||||||
                _vstart += key.length; // set next value start if current key is found
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                // get next format token used to determine separator
 | 
					 | 
				
			||||||
                while (fnext == -1 && nextKeyIdx < keys.length){
 | 
					 | 
				
			||||||
                    var nextKey = keys[nextKeyIdx];
 | 
					 | 
				
			||||||
                    nextKeyIdx += 1;
 | 
					 | 
				
			||||||
                    if (filterdKeys.indexOf(nextKey) === -1) {
 | 
					 | 
				
			||||||
                        continue;
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
                    fnext = nextKey ? format.indexOf(nextKey) : -1; // next format start
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
                if (fnext > -1){
 | 
					 | 
				
			||||||
                    sep = format.slice(stop, fnext);
 | 
					 | 
				
			||||||
                    if (sep) {
 | 
					 | 
				
			||||||
                        var _stop = value.slice(vstart).indexOf(sep);
 | 
					 | 
				
			||||||
                        if (_stop && _stop > -1){
 | 
					 | 
				
			||||||
                            stop = _stop + vstart;
 | 
					 | 
				
			||||||
                            _vstart = stop + sep.length;
 | 
					 | 
				
			||||||
                        }
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
                val = parseInt(value.slice(vstart, stop));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                var funcs = hooks.updateValue.get(key);
 | 
					 | 
				
			||||||
                for (var k = 0; k < funcs.length; k++) {
 | 
					 | 
				
			||||||
                    val = funcs[k](val, formatObj, vstart, stop);
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            formatObj[key] = { index: vstart, value: val };
 | 
					 | 
				
			||||||
            vstart = _vstart; // set next value start
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        return formatObj;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /**
 | 
					 | 
				
			||||||
     * @param {String} value 
 | 
					 | 
				
			||||||
     * @param {DTS} settings 
 | 
					 | 
				
			||||||
     * @returns {Date} date object
 | 
					 | 
				
			||||||
     */
 | 
					 | 
				
			||||||
    function parseDate(value, settings) {
 | 
					 | 
				
			||||||
        /** @type {{yyyy:number=, yy:number=, mm:number=, dd:number=}} */
 | 
					 | 
				
			||||||
        var formatObj = {yyyy:null, yy:null, mm:null, dd:null};
 | 
					 | 
				
			||||||
        var format = ((settings.dateFormat) || '').toLowerCase();
 | 
					 | 
				
			||||||
        if (!format) {
 | 
					 | 
				
			||||||
            throw new TypeError('dateFormat not found (' + settings.dateFormat + ')');
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        var formatObj = parseData(value, format, formatObj, function(hooks){
 | 
					 | 
				
			||||||
            hooks.canSkip.add("yy", function(data){
 | 
					 | 
				
			||||||
                return data["yyyy"].value;
 | 
					 | 
				
			||||||
            });
 | 
					 | 
				
			||||||
            hooks.updateValue.add("yy", function(val){
 | 
					 | 
				
			||||||
                return 100 * Math.floor(new Date().getFullYear() / 100) + val;
 | 
					 | 
				
			||||||
            });
 | 
					 | 
				
			||||||
        });
 | 
					 | 
				
			||||||
        var year = formatObj["yyyy"].value || formatObj["yy"].value;
 | 
					 | 
				
			||||||
        var month = formatObj["mm"].value - 1;
 | 
					 | 
				
			||||||
        var date = formatObj["dd"].value;
 | 
					 | 
				
			||||||
        var result = new Date(year, month, date);
 | 
					 | 
				
			||||||
        return result;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /**
 | 
					 | 
				
			||||||
     * @param {String} value 
 | 
					 | 
				
			||||||
     * @param {DTS} settings 
 | 
					 | 
				
			||||||
     * @returns {Number} time in milliseconds <= (24 * 60 * 60 * 1000) - 1
 | 
					 | 
				
			||||||
     */
 | 
					 | 
				
			||||||
    function parseTime(value, settings) {
 | 
					 | 
				
			||||||
        var format = ((settings.timeFormat) || '').toLowerCase();
 | 
					 | 
				
			||||||
        if (!format) {
 | 
					 | 
				
			||||||
            throw new TypeError('timeFormat not found (' + settings.timeFormat + ')');
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        /** @type {{hh:number=, mm:number=, ss:number=, a:string=}} */
 | 
					 | 
				
			||||||
        var formatObj = {hh:null, mm:null, ss:null, a:null};
 | 
					 | 
				
			||||||
        var formatObj = parseData(value, format, formatObj, function(hooks){
 | 
					 | 
				
			||||||
            hooks.updateValue.add("a", function(val, data, start, stop){
 | 
					 | 
				
			||||||
                return value.slice(start, start + 2);
 | 
					 | 
				
			||||||
            });
 | 
					 | 
				
			||||||
        });
 | 
					 | 
				
			||||||
        var hours = formatObj["hh"].value;
 | 
					 | 
				
			||||||
        var minutes = formatObj["mm"].value;
 | 
					 | 
				
			||||||
        var seconds = formatObj["ss"].value;
 | 
					 | 
				
			||||||
        var am_pm = formatObj["a"].value;
 | 
					 | 
				
			||||||
        var am_pm_lower = am_pm ? am_pm.toLowerCase() : am_pm;
 | 
					 | 
				
			||||||
        if (am_pm && ["am", "pm"].indexOf(am_pm_lower) > -1){
 | 
					 | 
				
			||||||
            if (am_pm_lower == 'am' && hours == 12){
 | 
					 | 
				
			||||||
                hours = 0;
 | 
					 | 
				
			||||||
            } else if (am_pm_lower == 'pm') {
 | 
					 | 
				
			||||||
                hours += 12;
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        var time = hours * 60 * 60 * 1000 + minutes * 60 * 1000 + seconds * 1000;
 | 
					 | 
				
			||||||
        return time;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /**
 | 
					 | 
				
			||||||
     * @param {Date} value 
 | 
					 | 
				
			||||||
     * @param {DTS} settings 
 | 
					 | 
				
			||||||
     * @returns {String} date string
 | 
					 | 
				
			||||||
     */
 | 
					 | 
				
			||||||
    function renderDate(value, settings) {
 | 
					 | 
				
			||||||
        var format = settings.dateFormat.toLowerCase();
 | 
					 | 
				
			||||||
        var date = value.getDate();
 | 
					 | 
				
			||||||
        var month = value.getMonth() + 1;
 | 
					 | 
				
			||||||
        var year = value.getFullYear();
 | 
					 | 
				
			||||||
        var yearShort = year % 100;
 | 
					 | 
				
			||||||
        var formatObj = {
 | 
					 | 
				
			||||||
            dd: date < 10 ? "0" + date : date,
 | 
					 | 
				
			||||||
            mm: month < 10 ? "0" + month : month,
 | 
					 | 
				
			||||||
            yyyy: year,
 | 
					 | 
				
			||||||
            yy: yearShort < 10 ? "0" + yearShort : yearShort
 | 
					 | 
				
			||||||
        };
 | 
					 | 
				
			||||||
        var str = format.replace(settings.dateFormatRegEx, function (found) {
 | 
					 | 
				
			||||||
            return formatObj[found];
 | 
					 | 
				
			||||||
        });
 | 
					 | 
				
			||||||
        return str;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /**
 | 
					 | 
				
			||||||
     * @param {Date} value 
 | 
					 | 
				
			||||||
     * @param {DTS} settings 
 | 
					 | 
				
			||||||
     * @returns {String} date string
 | 
					 | 
				
			||||||
     */
 | 
					 | 
				
			||||||
    function renderTime(value, settings) {
 | 
					 | 
				
			||||||
        var Format = settings.timeFormat;
 | 
					 | 
				
			||||||
        var format = Format.toLowerCase();
 | 
					 | 
				
			||||||
        var hours = value.getHours();
 | 
					 | 
				
			||||||
        var minutes = value.getMinutes();
 | 
					 | 
				
			||||||
        var seconds = value.getSeconds();
 | 
					 | 
				
			||||||
        var am_pm = null;
 | 
					 | 
				
			||||||
        var hh_am_pm = null;
 | 
					 | 
				
			||||||
        if (format.indexOf('a') > -1) {
 | 
					 | 
				
			||||||
            am_pm = hours >= 12 ? 'pm' : 'am';
 | 
					 | 
				
			||||||
            am_pm = Format.indexOf('A') > -1 ? am_pm.toUpperCase() : am_pm;
 | 
					 | 
				
			||||||
            hh_am_pm = hours == 0 ? '12' : (hours > 12 ? hours%12 : hours);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        var formatObj = {
 | 
					 | 
				
			||||||
            hh: am_pm ? hh_am_pm : (hours < 10 ? "0" + hours : hours),
 | 
					 | 
				
			||||||
            mm: minutes < 10 ? "0" + minutes : minutes,
 | 
					 | 
				
			||||||
            ss: seconds < 10 ? "0" + seconds : seconds,
 | 
					 | 
				
			||||||
            a: am_pm,
 | 
					 | 
				
			||||||
        };
 | 
					 | 
				
			||||||
        var str = format.replace(settings.timeFormatRegEx, function (found) {
 | 
					 | 
				
			||||||
            return formatObj[found];
 | 
					 | 
				
			||||||
        });
 | 
					 | 
				
			||||||
        return str;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /**
 | 
					 | 
				
			||||||
     * checks if two dates are equal
 | 
					 | 
				
			||||||
     * @param {Date} date1 
 | 
					 | 
				
			||||||
     * @param {Date} date2 
 | 
					 | 
				
			||||||
     * @returns {Boolean} true or false
 | 
					 | 
				
			||||||
     */
 | 
					 | 
				
			||||||
    function isEqualDate(date1, date2) {
 | 
					 | 
				
			||||||
        if (!(date1 && date2)) return false;
 | 
					 | 
				
			||||||
        return (date1.getFullYear() == date2.getFullYear() && 
 | 
					 | 
				
			||||||
                date1.getMonth() == date2.getMonth() && 
 | 
					 | 
				
			||||||
                date1.getDate() == date2.getDate());
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /**
 | 
					 | 
				
			||||||
     * @param {Number} val 
 | 
					 | 
				
			||||||
     * @param {Number} pad 
 | 
					 | 
				
			||||||
     * @param {*} default_val 
 | 
					 | 
				
			||||||
     * @returns {String} padded string
 | 
					 | 
				
			||||||
     */
 | 
					 | 
				
			||||||
    function padded(val, pad, default_val) {
 | 
					 | 
				
			||||||
        var default_val = default_val || 0;
 | 
					 | 
				
			||||||
        var valStr = '' + (parseInt(val) || default_val);
 | 
					 | 
				
			||||||
        var diff = Math.max(pad, valStr.length) - valStr.length;
 | 
					 | 
				
			||||||
        return ('' + default_val).repeat(diff) + valStr;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /**
 | 
					 | 
				
			||||||
     * @template X
 | 
					 | 
				
			||||||
     * @template Y
 | 
					 | 
				
			||||||
     * @param {X} obj 
 | 
					 | 
				
			||||||
     * @param {Y} objDefaults 
 | 
					 | 
				
			||||||
     * @returns {X|Y} merged object
 | 
					 | 
				
			||||||
     */
 | 
					 | 
				
			||||||
    function setDefaults(obj, objDefaults) {
 | 
					 | 
				
			||||||
        var keys = Object.keys(objDefaults);
 | 
					 | 
				
			||||||
        for (var i=0; i<keys.length; i++) {
 | 
					 | 
				
			||||||
            var key = keys[i];
 | 
					 | 
				
			||||||
            if (!Object.prototype.hasOwnProperty.call(obj, key)) {
 | 
					 | 
				
			||||||
                obj[key] = objDefaults[key];
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        return obj;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    window.dtsel = Object.create({},{
 | 
					 | 
				
			||||||
        DTS: { value: DTS },
 | 
					 | 
				
			||||||
        DTObj: { value: DTBox },
 | 
					 | 
				
			||||||
        fn: {
 | 
					 | 
				
			||||||
            value: Object.defineProperties({}, {
 | 
					 | 
				
			||||||
                empty: { value: empty },
 | 
					 | 
				
			||||||
                appendAfter: {
 | 
					 | 
				
			||||||
                    value: function (newElem, refNode) {
 | 
					 | 
				
			||||||
                        refNode.parentNode.insertBefore(newElem, refNode.nextSibling);
 | 
					 | 
				
			||||||
                    },
 | 
					 | 
				
			||||||
                },
 | 
					 | 
				
			||||||
                getOffset: { value: getOffset },
 | 
					 | 
				
			||||||
                parseDate: { value: parseDate },
 | 
					 | 
				
			||||||
                renderDate: { value: renderDate },
 | 
					 | 
				
			||||||
                parseTime: {value: parseTime},
 | 
					 | 
				
			||||||
                renderTime: {value: renderTime},
 | 
					 | 
				
			||||||
                setDefaults: {value: setDefaults},
 | 
					 | 
				
			||||||
            }),
 | 
					 | 
				
			||||||
        },
 | 
					 | 
				
			||||||
    });
 | 
					 | 
				
			||||||
})();
 | 
					 | 
				
			||||||
@@ -1,23 +0,0 @@
 | 
				
			|||||||
function collapse_all() {
 | 
					 | 
				
			||||||
    document.querySelectorAll("div.reminderContent:not(.creator)").forEach((el) => {
 | 
					 | 
				
			||||||
        el.classList.add("is-collapsed");
 | 
					 | 
				
			||||||
    });
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
function expand_all() {
 | 
					 | 
				
			||||||
    document.querySelectorAll("div.reminderContent:not(.creator)").forEach((el) => {
 | 
					 | 
				
			||||||
        el.classList.remove("is-collapsed");
 | 
					 | 
				
			||||||
    });
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const expandAll = document.querySelector("#expandAll");
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
expandAll.addEventListener("change", (ev) => {
 | 
					 | 
				
			||||||
    if (ev.target.value === "expand") {
 | 
					 | 
				
			||||||
        expand_all();
 | 
					 | 
				
			||||||
    } else if (ev.target.value === "collapse") {
 | 
					 | 
				
			||||||
        collapse_all();
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    ev.target.value = "";
 | 
					 | 
				
			||||||
});
 | 
					 | 
				
			||||||
@@ -1,94 +0,0 @@
 | 
				
			|||||||
function get_interval(element) {
 | 
					 | 
				
			||||||
    let months = element.querySelector('input[name="interval_months"]').value;
 | 
					 | 
				
			||||||
    let days = element.querySelector('input[name="interval_days"]').value;
 | 
					 | 
				
			||||||
    let hours = element.querySelector('input[name="interval_hours"]').value;
 | 
					 | 
				
			||||||
    let minutes = element.querySelector('input[name="interval_minutes"]').value;
 | 
					 | 
				
			||||||
    let seconds = element.querySelector('input[name="interval_seconds"]').value;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    return {
 | 
					 | 
				
			||||||
        months: parseInt(months) || null,
 | 
					 | 
				
			||||||
        days: parseInt(days) || null,
 | 
					 | 
				
			||||||
        seconds:
 | 
					 | 
				
			||||||
            (parseInt(hours) || 0) * 3600 +
 | 
					 | 
				
			||||||
                (parseInt(minutes) || 0) * 60 +
 | 
					 | 
				
			||||||
                (parseInt(seconds) || 0) || null,
 | 
					 | 
				
			||||||
    };
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
function update_interval(element) {
 | 
					 | 
				
			||||||
    let months = element.querySelector('input[name="interval_months"]');
 | 
					 | 
				
			||||||
    let days = element.querySelector('input[name="interval_days"]');
 | 
					 | 
				
			||||||
    let hours = element.querySelector('input[name="interval_hours"]');
 | 
					 | 
				
			||||||
    let minutes = element.querySelector('input[name="interval_minutes"]');
 | 
					 | 
				
			||||||
    let seconds = element.querySelector('input[name="interval_seconds"]');
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    let interval = get_interval(element);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if (interval.months === null && interval.days === null && interval.seconds === null) {
 | 
					 | 
				
			||||||
        months.value = "";
 | 
					 | 
				
			||||||
        days.value = "";
 | 
					 | 
				
			||||||
        hours.value = "";
 | 
					 | 
				
			||||||
        minutes.value = "";
 | 
					 | 
				
			||||||
        seconds.value = "";
 | 
					 | 
				
			||||||
    } else {
 | 
					 | 
				
			||||||
        months.value = months.value.padStart(1, "0");
 | 
					 | 
				
			||||||
        days.value = days.value.padStart(1, "0");
 | 
					 | 
				
			||||||
        hours.value = hours.value.padStart(2, "0");
 | 
					 | 
				
			||||||
        minutes.value = minutes.value.padStart(2, "0");
 | 
					 | 
				
			||||||
        seconds.value = seconds.value.padStart(2, "0");
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if (seconds.value >= 60) {
 | 
					 | 
				
			||||||
            let quotient = Math.floor(seconds.value / 60);
 | 
					 | 
				
			||||||
            let remainder = seconds.value % 60;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            seconds.value = String(remainder).padStart(2, "0");
 | 
					 | 
				
			||||||
            minutes.value = String(Number(minutes.value) + Number(quotient)).padStart(
 | 
					 | 
				
			||||||
                2,
 | 
					 | 
				
			||||||
                "0"
 | 
					 | 
				
			||||||
            );
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        if (minutes.value >= 60) {
 | 
					 | 
				
			||||||
            let quotient = Math.floor(minutes.value / 60);
 | 
					 | 
				
			||||||
            let remainder = minutes.value % 60;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            minutes.value = String(remainder).padStart(2, "0");
 | 
					 | 
				
			||||||
            hours.value = String(Number(hours.value) + Number(quotient)).padStart(2, "0");
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const $intervalGroup = document.querySelector(".interval-group");
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
document.querySelector(".interval-group").addEventListener(
 | 
					 | 
				
			||||||
    "blur",
 | 
					 | 
				
			||||||
    (ev) => {
 | 
					 | 
				
			||||||
        if (ev.target.nodeName !== "BUTTON") update_interval($intervalGroup);
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
    true
 | 
					 | 
				
			||||||
);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
$intervalGroup.querySelector("button.clear").addEventListener("click", () => {
 | 
					 | 
				
			||||||
    $intervalGroup.querySelectorAll("input").forEach((el) => {
 | 
					 | 
				
			||||||
        el.value = "";
 | 
					 | 
				
			||||||
    });
 | 
					 | 
				
			||||||
});
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
document.addEventListener("remindersLoaded", (event) => {
 | 
					 | 
				
			||||||
    for (reminder of event.detail) {
 | 
					 | 
				
			||||||
        let $intervalGroup = reminder.node.querySelector(".interval-group");
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        $intervalGroup.addEventListener(
 | 
					 | 
				
			||||||
            "blur",
 | 
					 | 
				
			||||||
            (ev) => {
 | 
					 | 
				
			||||||
                if (ev.target.nodeName !== "BUTTON") update_interval($intervalGroup);
 | 
					 | 
				
			||||||
            },
 | 
					 | 
				
			||||||
            true
 | 
					 | 
				
			||||||
        );
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        $intervalGroup.querySelector("button.clear").addEventListener("click", () => {
 | 
					 | 
				
			||||||
            $intervalGroup.querySelectorAll("input").forEach((el) => {
 | 
					 | 
				
			||||||
                el.value = "";
 | 
					 | 
				
			||||||
            });
 | 
					 | 
				
			||||||
        });
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
});
 | 
					 | 
				
			||||||
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
							
								
								
									
										2
									
								
								static/js/js.cookie.min.js
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								static/js/js.cookie.min.js
									
									
									
									
										vendored
									
									
								
							@@ -1,2 +0,0 @@
 | 
				
			|||||||
/*! js-cookie v3.0.0-rc.0 | MIT */
 | 
					 | 
				
			||||||
!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):(e=e||self,function(){var r=e.Cookies,n=e.Cookies=t();n.noConflict=function(){return e.Cookies=r,n}}())}(this,function(){"use strict";function e(e){for(var t=1;t<arguments.length;t++){var r=arguments[t];for(var n in r)e[n]=r[n]}return e}var t={read:function(e){return e.replace(/%3B/g,";")},write:function(e){return e.replace(/;/g,"%3B")}};return function r(n,i){function o(r,o,u){if("undefined"!=typeof document){"number"==typeof(u=e({},i,u)).expires&&(u.expires=new Date(Date.now()+864e5*u.expires)),u.expires&&(u.expires=u.expires.toUTCString()),r=t.write(r).replace(/=/g,"%3D"),o=n.write(String(o),r);var c="";for(var f in u)u[f]&&(c+="; "+f,!0!==u[f]&&(c+="="+u[f].split(";")[0]));return document.cookie=r+"="+o+c}}return Object.create({set:o,get:function(e){if("undefined"!=typeof document&&(!arguments.length||e)){for(var r=document.cookie?document.cookie.split("; "):[],i={},o=0;o<r.length;o++){var u=r[o].split("="),c=u.slice(1).join("="),f=t.read(u[0]).replace(/%3D/g,"=");if(i[f]=n.read(c,f),e===f)break}return e?i[e]:i}},remove:function(t,r){o(t,"",e({},r,{expires:-1}))},withAttributes:function(t){return r(this.converter,e({},this.attributes,t))},withConverter:function(t){return r(e({},this.converter,t),this.attributes)}},{attributes:{value:Object.freeze(i)},converter:{value:Object.freeze(n)}})}(t,{path:"/"})});
 | 
					 | 
				
			||||||
							
								
								
									
										1
									
								
								static/js/luxon.min.js
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								static/js/luxon.min.js
									
									
									
									
										vendored
									
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
							
								
								
									
										1102
									
								
								static/js/main.js
									
									
									
									
									
								
							
							
						
						
									
										1102
									
								
								static/js/main.js
									
									
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							@@ -1,70 +0,0 @@
 | 
				
			|||||||
let guildReminders = document.querySelector("#guildReminders");
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
function sort_by(cond) {
 | 
					 | 
				
			||||||
    if (cond === "channel") {
 | 
					 | 
				
			||||||
        [...guildReminders.children]
 | 
					 | 
				
			||||||
            .sort((a, b) => {
 | 
					 | 
				
			||||||
                let channel1 = a.querySelector("select.channel-selector").value;
 | 
					 | 
				
			||||||
                let channel2 = b.querySelector("select.channel-selector").value;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                return channel1 > channel2 ? 1 : -1;
 | 
					 | 
				
			||||||
            })
 | 
					 | 
				
			||||||
            .forEach((node) => guildReminders.appendChild(node));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        // go through and add channel categories
 | 
					 | 
				
			||||||
        let currentChannelGroup = null;
 | 
					 | 
				
			||||||
        for (let child of guildReminders.querySelectorAll("div.reminderContent")) {
 | 
					 | 
				
			||||||
            let thisChannelGroup = child.querySelector("select.channel-selector").value;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            if (currentChannelGroup !== thisChannelGroup) {
 | 
					 | 
				
			||||||
                let newNode = document.createElement("div");
 | 
					 | 
				
			||||||
                newNode.textContent =
 | 
					 | 
				
			||||||
                    "#" + channels.find((a) => a.id === thisChannelGroup).name;
 | 
					 | 
				
			||||||
                newNode.classList.add("channel-tag");
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                guildReminders.insertBefore(newNode, child);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                currentChannelGroup = thisChannelGroup;
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    } else {
 | 
					 | 
				
			||||||
        // remove any channel tags if previous ordering was by channel
 | 
					 | 
				
			||||||
        guildReminders.querySelectorAll("div.channel-tag").forEach((el) => {
 | 
					 | 
				
			||||||
            el.remove();
 | 
					 | 
				
			||||||
        });
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if (cond === "time") {
 | 
					 | 
				
			||||||
            [...guildReminders.children]
 | 
					 | 
				
			||||||
                .sort((a, b) => {
 | 
					 | 
				
			||||||
                    let time1 = luxon.DateTime.fromISO(
 | 
					 | 
				
			||||||
                        a.querySelector('input[name="time"]').value
 | 
					 | 
				
			||||||
                    );
 | 
					 | 
				
			||||||
                    let time2 = luxon.DateTime.fromISO(
 | 
					 | 
				
			||||||
                        b.querySelector('input[name="time"]').value
 | 
					 | 
				
			||||||
                    );
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                    return time1 > time2 ? 1 : -1;
 | 
					 | 
				
			||||||
                })
 | 
					 | 
				
			||||||
                .forEach((node) => guildReminders.appendChild(node));
 | 
					 | 
				
			||||||
        } else {
 | 
					 | 
				
			||||||
            [...guildReminders.children]
 | 
					 | 
				
			||||||
                .sort((a, b) => {
 | 
					 | 
				
			||||||
                    let name1 = a.querySelector('input[name="name"]').value;
 | 
					 | 
				
			||||||
                    let name2 = b.querySelector('input[name="name"]').value;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                    return name1 > name2 ? 1 : -1;
 | 
					 | 
				
			||||||
                })
 | 
					 | 
				
			||||||
                .forEach((node) => guildReminders.appendChild(node));
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const selector = document.querySelector("#orderBy");
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
selector.addEventListener("change", () => {
 | 
					 | 
				
			||||||
    sort_by(selector.value);
 | 
					 | 
				
			||||||
});
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
document.addEventListener("remindersLoaded", () => {
 | 
					 | 
				
			||||||
    sort_by(selector.value);
 | 
					 | 
				
			||||||
});
 | 
					 | 
				
			||||||
@@ -1,57 +0,0 @@
 | 
				
			|||||||
let timezone = luxon.DateTime.now().zone.name;
 | 
					 | 
				
			||||||
const browserTimezone = luxon.DateTime.now().zone.name;
 | 
					 | 
				
			||||||
let botTimezone = "UTC";
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
function update_times() {
 | 
					 | 
				
			||||||
    document.querySelectorAll("span.set-timezone").forEach((element) => {
 | 
					 | 
				
			||||||
        element.textContent = timezone;
 | 
					 | 
				
			||||||
    });
 | 
					 | 
				
			||||||
    document.querySelectorAll("span.set-time").forEach((element) => {
 | 
					 | 
				
			||||||
        element.textContent = luxon.DateTime.now().setZone(timezone).toFormat("HH:mm");
 | 
					 | 
				
			||||||
    });
 | 
					 | 
				
			||||||
    document.querySelectorAll("span.browser-timezone").forEach((element) => {
 | 
					 | 
				
			||||||
        element.textContent = browserTimezone;
 | 
					 | 
				
			||||||
    });
 | 
					 | 
				
			||||||
    document.querySelectorAll("span.browser-time").forEach((element) => {
 | 
					 | 
				
			||||||
        element.textContent = luxon.DateTime.now().toFormat("HH:mm");
 | 
					 | 
				
			||||||
    });
 | 
					 | 
				
			||||||
    document.querySelectorAll("span.bot-timezone").forEach((element) => {
 | 
					 | 
				
			||||||
        element.textContent = botTimezone;
 | 
					 | 
				
			||||||
    });
 | 
					 | 
				
			||||||
    document.querySelectorAll("span.bot-time").forEach((element) => {
 | 
					 | 
				
			||||||
        element.textContent = luxon.DateTime.now().setZone(botTimezone).toFormat("HH:mm");
 | 
					 | 
				
			||||||
    });
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
window.setInterval(() => {
 | 
					 | 
				
			||||||
    update_times();
 | 
					 | 
				
			||||||
}, 30000);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
document.getElementById("set-bot-timezone").addEventListener("click", () => {
 | 
					 | 
				
			||||||
    timezone = botTimezone;
 | 
					 | 
				
			||||||
    update_times();
 | 
					 | 
				
			||||||
});
 | 
					 | 
				
			||||||
document.getElementById("set-browser-timezone").addEventListener("click", () => {
 | 
					 | 
				
			||||||
    timezone = browserTimezone;
 | 
					 | 
				
			||||||
    update_times();
 | 
					 | 
				
			||||||
});
 | 
					 | 
				
			||||||
document.getElementById("update-bot-timezone").addEventListener("click", () => {
 | 
					 | 
				
			||||||
    timezone = browserTimezone;
 | 
					 | 
				
			||||||
    fetch("/dashboard/api/user", {
 | 
					 | 
				
			||||||
        method: "PATCH",
 | 
					 | 
				
			||||||
        headers: {
 | 
					 | 
				
			||||||
            Accept: "application/json",
 | 
					 | 
				
			||||||
            "Content-Type": "application/json",
 | 
					 | 
				
			||||||
        },
 | 
					 | 
				
			||||||
        body: JSON.stringify({ timezone: timezone }),
 | 
					 | 
				
			||||||
    })
 | 
					 | 
				
			||||||
        .then((response) => response.json())
 | 
					 | 
				
			||||||
        .then((data) => {
 | 
					 | 
				
			||||||
            if (data.error) {
 | 
					 | 
				
			||||||
                show_error(data.error);
 | 
					 | 
				
			||||||
            } else {
 | 
					 | 
				
			||||||
                botTimezone = browserTimezone;
 | 
					 | 
				
			||||||
                update_times();
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        });
 | 
					 | 
				
			||||||
});
 | 
					 | 
				
			||||||
		Reference in New Issue
	
	Block a user