diff --git a/.gitignore b/.gitignore
index b512c09..b3aed83 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1 +1,3 @@
-node_modules
\ No newline at end of file
+node_modules
+rename.sh
+data-persistence.json
diff --git a/.vscode/launch.json b/.vscode/launch.json
new file mode 100644
index 0000000..ab42783
--- /dev/null
+++ b/.vscode/launch.json
@@ -0,0 +1,17 @@
+{
+ // Use IntelliSense to learn about possible attributes.
+ // Hover to view descriptions of existing attributes.
+ // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
+ "version": "0.2.0",
+ "configurations": [
+ {
+ "type": "pwa-node",
+ "request": "launch",
+ "name": "Launch Program",
+ "skipFiles": [
+ "/**"
+ ],
+ "program": "${workspaceFolder}/index.js"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/LICENSE.txt b/LICENSE.txt
new file mode 100644
index 0000000..0a04128
--- /dev/null
+++ b/LICENSE.txt
@@ -0,0 +1,165 @@
+ GNU LESSER GENERAL PUBLIC LICENSE
+ Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc.
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+
+ This version of the GNU Lesser General Public License incorporates
+the terms and conditions of version 3 of the GNU General Public
+License, supplemented by the additional permissions listed below.
+
+ 0. Additional Definitions.
+
+ As used herein, "this License" refers to version 3 of the GNU Lesser
+General Public License, and the "GNU GPL" refers to version 3 of the GNU
+General Public License.
+
+ "The Library" refers to a covered work governed by this License,
+other than an Application or a Combined Work as defined below.
+
+ An "Application" is any work that makes use of an interface provided
+by the Library, but which is not otherwise based on the Library.
+Defining a subclass of a class defined by the Library is deemed a mode
+of using an interface provided by the Library.
+
+ A "Combined Work" is a work produced by combining or linking an
+Application with the Library. The particular version of the Library
+with which the Combined Work was made is also called the "Linked
+Version".
+
+ The "Minimal Corresponding Source" for a Combined Work means the
+Corresponding Source for the Combined Work, excluding any source code
+for portions of the Combined Work that, considered in isolation, are
+based on the Application, and not on the Linked Version.
+
+ The "Corresponding Application Code" for a Combined Work means the
+object code and/or source code for the Application, including any data
+and utility programs needed for reproducing the Combined Work from the
+Application, but excluding the System Libraries of the Combined Work.
+
+ 1. Exception to Section 3 of the GNU GPL.
+
+ You may convey a covered work under sections 3 and 4 of this License
+without being bound by section 3 of the GNU GPL.
+
+ 2. Conveying Modified Versions.
+
+ If you modify a copy of the Library, and, in your modifications, a
+facility refers to a function or data to be supplied by an Application
+that uses the facility (other than as an argument passed when the
+facility is invoked), then you may convey a copy of the modified
+version:
+
+ a) under this License, provided that you make a good faith effort to
+ ensure that, in the event an Application does not supply the
+ function or data, the facility still operates, and performs
+ whatever part of its purpose remains meaningful, or
+
+ b) under the GNU GPL, with none of the additional permissions of
+ this License applicable to that copy.
+
+ 3. Object Code Incorporating Material from Library Header Files.
+
+ The object code form of an Application may incorporate material from
+a header file that is part of the Library. You may convey such object
+code under terms of your choice, provided that, if the incorporated
+material is not limited to numerical parameters, data structure
+layouts and accessors, or small macros, inline functions and templates
+(ten or fewer lines in length), you do both of the following:
+
+ a) Give prominent notice with each copy of the object code that the
+ Library is used in it and that the Library and its use are
+ covered by this License.
+
+ b) Accompany the object code with a copy of the GNU GPL and this license
+ document.
+
+ 4. Combined Works.
+
+ You may convey a Combined Work under terms of your choice that,
+taken together, effectively do not restrict modification of the
+portions of the Library contained in the Combined Work and reverse
+engineering for debugging such modifications, if you also do each of
+the following:
+
+ a) Give prominent notice with each copy of the Combined Work that
+ the Library is used in it and that the Library and its use are
+ covered by this License.
+
+ b) Accompany the Combined Work with a copy of the GNU GPL and this license
+ document.
+
+ c) For a Combined Work that displays copyright notices during
+ execution, include the copyright notice for the Library among
+ these notices, as well as a reference directing the user to the
+ copies of the GNU GPL and this license document.
+
+ d) Do one of the following:
+
+ 0) Convey the Minimal Corresponding Source under the terms of this
+ License, and the Corresponding Application Code in a form
+ suitable for, and under terms that permit, the user to
+ recombine or relink the Application with a modified version of
+ the Linked Version to produce a modified Combined Work, in the
+ manner specified by section 6 of the GNU GPL for conveying
+ Corresponding Source.
+
+ 1) Use a suitable shared library mechanism for linking with the
+ Library. A suitable mechanism is one that (a) uses at run time
+ a copy of the Library already present on the user's computer
+ system, and (b) will operate properly with a modified version
+ of the Library that is interface-compatible with the Linked
+ Version.
+
+ e) Provide Installation Information, but only if you would otherwise
+ be required to provide such information under section 6 of the
+ GNU GPL, and only to the extent that such information is
+ necessary to install and execute a modified version of the
+ Combined Work produced by recombining or relinking the
+ Application with a modified version of the Linked Version. (If
+ you use option 4d0, the Installation Information must accompany
+ the Minimal Corresponding Source and Corresponding Application
+ Code. If you use option 4d1, you must provide the Installation
+ Information in the manner specified by section 6 of the GNU GPL
+ for conveying Corresponding Source.)
+
+ 5. Combined Libraries.
+
+ You may place library facilities that are a work based on the
+Library side by side in a single library together with other library
+facilities that are not Applications and are not covered by this
+License, and convey such a combined library under terms of your
+choice, if you do both of the following:
+
+ a) Accompany the combined library with a copy of the same work based
+ on the Library, uncombined with any other library facilities,
+ conveyed under the terms of this License.
+
+ b) Give prominent notice with the combined library that part of it
+ is a work based on the Library, and explaining where to find the
+ accompanying uncombined form of the same work.
+
+ 6. Revised Versions of the GNU Lesser General Public License.
+
+ The Free Software Foundation may publish revised and/or new versions
+of the GNU Lesser General Public License from time to time. Such new
+versions will be similar in spirit to the present version, but may
+differ in detail to address new problems or concerns.
+
+ Each version is given a distinguishing version number. If the
+Library as you received it specifies that a certain numbered version
+of the GNU Lesser General Public License "or any later version"
+applies to it, you have the option of following the terms and
+conditions either of that published version or of any later version
+published by the Free Software Foundation. If the Library as you
+received it does not specify a version number of the GNU Lesser
+General Public License, you may choose any version of the GNU Lesser
+General Public License ever published by the Free Software Foundation.
+
+ If the Library as you received it specifies that a proxy can decide
+whether future versions of the GNU Lesser General Public License shall
+apply, that proxy's public statement of acceptance of any version is
+permanent authorization for you to choose that version for the
+Library.
diff --git a/README.MD b/README.MD
index 54bcd5a..05f05d0 100644
--- a/README.MD
+++ b/README.MD
@@ -1,10 +1,5 @@
# openCountdown
# ToDo
-- [X] Pausing functions
-- [X] Presets
-- [X] time on countdown page
-- [X] one-way messaging
-- [ ] Better UI
-- [X] Progress bar
- [P] Endpoint docs
+- [ ] Better WS frames
\ No newline at end of file
diff --git a/helpers.js b/helpers.js
new file mode 100644
index 0000000..7ffcad1
--- /dev/null
+++ b/helpers.js
@@ -0,0 +1,32 @@
+/**
+ * Converts a string into a boolean
+ * @param {String} stringBoolean
+ * @returns Boolean if valid or -1 otherwise
+ */
+function convertStringBooleanToBoolean(stringBoolean) {
+ if (stringBoolean === 'true') {
+ return true;
+ } else if(stringBoolean === 'false') {
+ return false;
+ } else {
+ return(-1)
+ }
+}
+
+/**
+ * Wraps convertStringBooleanToBoolean to be used with express. Will respond with an error if the boolean is invalid. Else dataObj will be set to the converted boolean value.
+ * @param {String} stringBoolean An input string given by the user
+ * @param {*} res Expresses response object
+ * @param {*} dataObj The data to manipulate
+ */
+
+function wrapBooleanConverter(stringBoolean, res) {
+ const temp = convertStringBooleanToBoolean(stringBoolean);
+ if(temp == -1) {
+ res.json({ status: "error", message: "Invalid boolean value" });
+ } else {
+ return(temp);
+ }
+}
+
+module.exports = { convertStringBooleanToBoolean, wrapBooleanConverter };
\ No newline at end of file
diff --git a/index.js b/index.js
index 3597f74..f0a484d 100644
--- a/index.js
+++ b/index.js
@@ -1,7 +1,10 @@
const express = require("express");
const fs = require("fs");
const bodyParser = require("body-parser");
+const ws = require('ws');
+const helper = require("./helpers.js");
+console.log("Preparing server...");
const app = express();
app.use(express.static("static"));
@@ -15,31 +18,72 @@ app.use(
})
);
+let loadedData = {}
+
+if (fs.existsSync("data-persistence.json")) {
+ const loadedDataRaw = fs.readFileSync("data-persistence.json", "utf8");
+ loadedData = JSON.parse(loadedDataRaw);
+} else {
+ console.warn("Unable to load persistent data");
+}
+
currentState = {
mode: "clock",
countdownGoal: new Date().getTime(),
showMilliSeconds: true,
defaultFullScreen: true,
timeAmountInital: 0,
- timerRunState: true,
+ timerRunState: false,
pauseMoment: 0,
showTimeOnCountdown: true,
message: "",
showMessage: false,
messageAppearTime: 0,
showProgressbar: true,
- colorSegments: {20000: "#FFAE00", 5000: "#ff0000", "START": "yellow"},
+ colorSegments: { 40000: "yellow", 20000: "#FFAE00", 5000: "#ff0000", "START": "green" },
textColors: {},
srvTime: 0,
enableColoredText: true,
- debug: false
+ debug: false,
+ sessionToken: Math.random().toString(36).substring(2, 15) + Math.random().toString(36).substring(2, 15),
};
+const dataToBeWritten = {};
+
+currentState = Object.assign({}, currentState, loadedData);
currentState.textColors = currentState.colorSegments
+
+const wsServer = new ws.Server({ noServer: true });
+wsServer.on('connection', socket => {
+ socket.on('message', function incoming(data) {
+ if (data.toString() == "new client") {
+ updatedData()
+ }
+ });
+});
+
+wsServer.broadcast = function broadcast(data) {
+ wsServer.clients.forEach(function each(client) {
+ // The data is coming in correctly
+ // console.log(data);
+ client.send(data);
+ });
+};
+
+let updatey = undefined;
+
+function updatedData() {
+ currentState.srvTime = new Date().getTime()
+ wsServer.broadcast(JSON.stringify(currentState));
+ clearTimeout(updatey);
+ setTimeout(updatedData, 5000);
+}
+
+console.log("Preparing routes...");
app.get("/", function (req, res) {
- const data = fs.readFileSync("templates/adminPanel.html", "utf8");
+ const data = fs.readFileSync("templates/newAdminPanel.html", "utf8");
res.send(data);
});
@@ -53,78 +97,155 @@ app.get("/api/v1/data", function (req, res) {
res.json(currentState);
});
+app.get("/api/v1/system", function (req, res) {
+ const tempPkgFile = fs.readFileSync("package.json", "utf8");
+ const tempPkgObj = JSON.parse(tempPkgFile);
+ const systemData = {
+ uptime: process.uptime(),
+ memoryUsage: process.memoryUsage(),
+ cpuUsage: process.cpuUsage(),
+ platform: process.platform,
+ arch: process.arch,
+ nodeVersion: process.version,
+ nodePath: process.execPath,
+ nodeArgv: process.argv,
+ nodeExecArgv: process.execArgv,
+ nodeCwd: process.cwd(),
+ nodeEnv: process.env,
+ nodeConfig: process.config,
+ nodeTitle: process.title,
+ systemVersion: tempPkgObj.version
+ }
+ res.json(systemData);
+});
+
+
app.get("/api/v1/set/mode", function (req, res) {
currentState.mode = req.query.mode;
+ updatedData()
res.json({ status: "ok" });
});
app.get("/api/v1/set/layout/showMillis", function (req, res) {
- currentState.showMilliSeconds = (req.query.show === 'true');
- res.json({ status: "ok" });
+ const resy = helper.wrapBooleanConverter(req.query.show, res)
+ if (resy != undefined) {
+ currentState.showMilliSeconds = resy;
+ if (req.query.persist === 'true') {
+ dataToBeWritten.showMilliSeconds = currentState.showMilliSeconds
+ }
+ res.json({ status: "ok" });
+ }
+ updatedData()
+
});
app.get("/api/v1/set/timerGoal", function (req, res) {
currentState.countdownGoal = new Date(parseInt(req.query.time)).getTime(); // ToDO error handling
res.json({ status: "ok" });
+ updatedData()
});
app.get("/api/v1/set/addMillisToTimer", function (req, res) {
currentState.timeAmountInital = req.query.time;
currentState.countdownGoal = new Date().getTime() + parseInt(req.query.time)
+ currentState.pauseMoment = new Date().getTime();
res.json({ status: "ok" });
-});
+ updatedData()
+});
app.get("/api/v1/ctrl/timer/pause", function (req, res) {
currentState.timerRunState = false;
currentState.pauseMoment = new Date().getTime();
res.json({ status: "ok" });
+ updatedData()
});
app.get("/api/v1/ctrl/timer/play", function (req, res) {
- currentState.timerRunState = true
- currentState.countdownGoal += new Date().getTime() - currentState.pauseMoment;
+
+ if (currentState.timerRunState == false) {
+ currentState.timerRunState = true
+ currentState.countdownGoal += new Date().getTime() - currentState.pauseMoment;
+ }
res.json({ status: "ok" });
+ updatedData()
});
app.get("/api/v1/ctrl/timer/restart", function (req, res) {
currentState.countdownGoal = new Date().getTime() + parseInt(currentState.timeAmountInital)
res.json({ status: "ok" });
+ updatedData()
});
app.get("/api/v1/set/layout/showTime", function (req, res) {
- currentState.showTimeOnCountdown = (req.query.show === 'true');
- res.json({ status: "ok" });
+ const resy = helper.wrapBooleanConverter(req.query.show, res)
+ if (resy != undefined) {
+ currentState.showTimeOnCountdown = resy;
+ if (req.query.persist === 'true') {
+ dataToBeWritten.showTimeOnCountdown = currentState.showTimeOnCountdown
+ }
+ res.json({ status: "ok" });
+ }
+ updatedData()
});
app.get("/api/v1/set/progressbar/show", function (req, res) {
currentState.showProgressbar = (req.query.show === 'true');
+ if (req.query.persist === 'true') {
+ dataToBeWritten.showProgressbar = currentState.showProgressbar
+ }
res.json({ status: "ok" });
+ updatedData()
});
app.get("/api/v1/set/progressbar/colors", function (req, res) {
try {
- currentState.colorSegments = JSON.parse(req.query.colors);
- res.json({ status: "ok" });
- } catch (error) {
- res.json({ status: "error", message: error });
- }
-});
-
-app.get("/api/v1/set/text/colors", function (req, res) {
- try {
- if(req.query.copy === "true"){
- currentState.textColors = currentState.colorSegments;
- } else {
- currentState.textColors = JSON.parse(req.query.colors);
+ let data = req.query.colors
+ if (req.query.isBase64 === "true") {
+ data = atob(data)
+ }
+ currentState.colorSegments = JSON.parse(data);
+ if (req.query.persist === 'true') {
+ dataToBeWritten.colorSegments = currentState.colorSegments
}
res.json({ status: "ok" });
} catch (error) {
res.json({ status: "error", message: error });
+ console.error(error)
}
+ updatedData()
+});
+
+app.get("/api/v1/set/text/colors", function (req, res) {
+ try {
+ if (req.query.copy === "true") {
+ currentState.textColors = currentState.colorSegments
+ res.json({ status: "ok" });
+ } else {
+ let data = req.query.colors
+ if (req.query.isBase64 === "true") {
+ data = atob(data)
+ }
+ console.debug(data)
+ currentState.textColors = JSON.parse(data);
+ if (req.query.persist === 'true') {
+ dataToBeWritten.textColors = currentState.textColors
+ }
+ }
+ res.json({ status: "ok" });
+ } catch (error) {
+ res.json({ status: "error", message: error });
+ console.error(error)
+ }
+ updatedData()
});
app.get("/api/v1/set/text/enableColoring", function (req, res) {
currentState.enableColoredText = (req.query.enable === 'true');
+ if (req.query.persist === 'true') {
+ dataToBeWritten.enableColoredText = currentState.enableColoredText
+ }
+ res.json({ status: "ok" });
+ updatedData()
});
app.get("/api/v1/ctrl/message/show", function (req, res) {
@@ -132,16 +253,82 @@ app.get("/api/v1/ctrl/message/show", function (req, res) {
currentState.showMessage = true
currentState.messageAppearTime = new Date().getTime()
res.json({ status: "ok" });
+ updatedData()
});
app.get("/api/v1/debug", function (req, res) {
currentState.debug = (req.query.enable === 'true');
res.json({ status: "ok" });
+ updatedData()
});
app.get("/api/v1/ctrl/message/hide", function (req, res) {
currentState.showMessage = false
res.json({ status: "ok" });
+ updatedData()
});
-app.listen(3005);
+app.get("/api/v1/storage/commit", function (req, res) {
+ const tempString = JSON.stringify(dataToBeWritten);
+ try {
+ fs.writeFileSync("data-persistence.json", tempString);
+ res.json({ status: "ok" });
+ } catch (error) {
+ res.json({ status: "error", reason: error });
+ }
+ updatedData()
+});
+
+
+app.get("/api/v1/storage/delete", function (req, res) {
+ if (req.query.delete === "true") {
+ if (fs.existsSync("data-persistence.json")) {
+ fs.unlinkSync("data-persistence.json");
+ res.json({ status: "ok" });
+ } else {
+ res.json({ status: "error", reason: "No persistence data was found" });
+ }
+
+ } else {
+
+ } res.json({ status: "error", reason: "Missing delete argument" });
+ updatedData()
+});
+
+app.use(function(req, res, next) {
+ res.status(404);
+
+ // respond with html page
+ if (req.accepts('html')) {
+ const data = fs.readFileSync("templates/errorPages/404.html", "utf8");
+ res.status(404)
+ res.send(data);
+ return;
+ }
+
+ // respond with json
+ if (req.accepts('json')) {
+ res.json({ error: 'Not found' });
+ return;
+ }
+
+ // default to plain-text. send()
+ res.type('txt').send('Not found');
+});
+
+
+
+console.log("Starting server...");
+const port = 3005
+const server = app.listen(port);
+server.on('upgrade', (request, socket, head) => {
+ wsServer.handleUpgrade(request, socket, head, socket => {
+ wsServer.emit('connection', socket, request);
+ });
+});
+
+
+
+console.info("Server running on port " + port);
+console.info("Visit localhost:" + port + "/timer for the timer page");
+console.info("Visit localhost:" + port + " for the admin page");
diff --git a/package-lock.json b/package-lock.json
index e86fe82..0f8f883 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,17 +1,36 @@
{
"name": "opencountdown",
- "version": "1.0.0",
+ "version": "1.0.1",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "opencountdown",
- "version": "1.0.0",
- "license": "ISC",
+ "version": "1.0.1",
+ "license": "LGPL-3.0",
"dependencies": {
"body-parser": "^1.19.2",
- "countdown": "^2.6.0",
- "express": "^4.17.3"
+ "bootstrap": "^5.1.3",
+ "bootstrap-duration-picker": "^2.1.3",
+ "bootstrap-icons": "^1.8.1",
+ "darkreader": "^4.9.44",
+ "express": "^4.17.3",
+ "flatpickr": "^4.6.11",
+ "jquery": "^3.6.0",
+ "js-cookie": "^3.0.1",
+ "less": "^3.13",
+ "mdbootstrap": "^4.20.0",
+ "ws": "^8.5.0"
+ }
+ },
+ "node_modules/@popperjs/core": {
+ "version": "2.11.2",
+ "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.2.tgz",
+ "integrity": "sha512-92FRmppjjqz29VMJ2dn+xdyXZBrMlE42AV6Kq6BwjWV7CNUW1hs2FtxSNLQE+gJhaZ6AAmYuO9y8dshhcBl7vA==",
+ "peer": true,
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/popperjs"
}
},
"node_modules/accepts": {
@@ -51,6 +70,31 @@
"node": ">= 0.8"
}
},
+ "node_modules/bootstrap": {
+ "version": "5.1.3",
+ "resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-5.1.3.tgz",
+ "integrity": "sha512-fcQztozJ8jToQWXxVuEyXWW+dSo8AiXWKwiSSrKWsRB/Qt+Ewwza+JWoLKiTuQLaEPhdNAJ7+Dosc9DOIqNy7Q==",
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/bootstrap"
+ },
+ "peerDependencies": {
+ "@popperjs/core": "^2.10.2"
+ }
+ },
+ "node_modules/bootstrap-duration-picker": {
+ "version": "2.1.3",
+ "resolved": "https://registry.npmjs.org/bootstrap-duration-picker/-/bootstrap-duration-picker-2.1.3.tgz",
+ "integrity": "sha1-vxctw2psm4lQBpYqLYGIwzYPsmU="
+ },
+ "node_modules/bootstrap-icons": {
+ "version": "1.8.1",
+ "resolved": "https://registry.npmjs.org/bootstrap-icons/-/bootstrap-icons-1.8.1.tgz",
+ "integrity": "sha512-IXUqislddPJfwq6H+2nTkHyr9epO9h6u1AG0OZCx616w+TgzeoCjfmI3qJMQqt1J586gN2IxzB4M99Ip4sTZ1w==",
+ "engines": {
+ "node": ">=10"
+ }
+ },
"node_modules/bytes": {
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz",
@@ -91,10 +135,25 @@
"resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz",
"integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw="
},
- "node_modules/countdown": {
- "version": "2.6.0",
- "resolved": "https://registry.npmjs.org/countdown/-/countdown-2.6.0.tgz",
- "integrity": "sha1-Z3+446nUzE52QVkBuiU7UYrzQXc="
+ "node_modules/copy-anything": {
+ "version": "2.0.6",
+ "resolved": "https://registry.npmjs.org/copy-anything/-/copy-anything-2.0.6.tgz",
+ "integrity": "sha512-1j20GZTsvKNkc4BY3NpMOM8tt///wY3FpIzozTOFO2ffuZcV61nojHXVKIy3WM+7ADCy5FVhdZYHYDdgTU0yJw==",
+ "dependencies": {
+ "is-what": "^3.14.1"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/mesqueeb"
+ }
+ },
+ "node_modules/darkreader": {
+ "version": "4.9.44",
+ "resolved": "https://registry.npmjs.org/darkreader/-/darkreader-4.9.44.tgz",
+ "integrity": "sha512-Mrt5s5eMaFC24Tfi2nNsXpYIfzWK/RUzJxgk0Ysqokvk9lBCn/pkUTyQGYeQbU/U3aKZEYXXqsxZjNfiLoA6QQ==",
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/darkreader/donate"
+ }
},
"node_modules/debug": {
"version": "2.6.9",
@@ -130,6 +189,18 @@
"node": ">= 0.8"
}
},
+ "node_modules/errno": {
+ "version": "0.1.8",
+ "resolved": "https://registry.npmjs.org/errno/-/errno-0.1.8.tgz",
+ "integrity": "sha512-dJ6oBr5SQ1VSd9qkk7ByRgb/1SH4JZjCHSW/mr63/QcXO9zLVxvJ6Oy13nio03rxpSnVDDjFor75SjVeZWPW/A==",
+ "optional": true,
+ "dependencies": {
+ "prr": "~1.0.1"
+ },
+ "bin": {
+ "errno": "cli.js"
+ }
+ },
"node_modules/escape-html": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
@@ -200,6 +271,11 @@
"node": ">= 0.8"
}
},
+ "node_modules/flatpickr": {
+ "version": "4.6.11",
+ "resolved": "https://registry.npmjs.org/flatpickr/-/flatpickr-4.6.11.tgz",
+ "integrity": "sha512-/rnbE/hu5I5zndLEyYfYvqE4vPDvI5At0lFcQA5eOPfjquZLcQ0HMKTL7rv5/+DvbPM3/vJcXpXjB/DjBh+1jw=="
+ },
"node_modules/forwarded": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz",
@@ -216,6 +292,12 @@
"node": ">= 0.6"
}
},
+ "node_modules/graceful-fs": {
+ "version": "4.2.9",
+ "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.9.tgz",
+ "integrity": "sha512-NtNxqUcXgpW2iMrfqSfR73Glt39K+BLwWsPs94yR63v45T0Wbej7eRmL5cWfwEgqXnmjQp3zaJTshdRW/qC2ZQ==",
+ "optional": true
+ },
"node_modules/http-errors": {
"version": "1.8.1",
"resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.8.1.tgz",
@@ -242,6 +324,18 @@
"node": ">=0.10.0"
}
},
+ "node_modules/image-size": {
+ "version": "0.5.5",
+ "resolved": "https://registry.npmjs.org/image-size/-/image-size-0.5.5.tgz",
+ "integrity": "sha1-Cd/Uq50g4p6xw+gLiZA3jfnjy5w=",
+ "optional": true,
+ "bin": {
+ "image-size": "bin/image-size.js"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
"node_modules/inherits": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
@@ -255,6 +349,66 @@
"node": ">= 0.10"
}
},
+ "node_modules/is-what": {
+ "version": "3.14.1",
+ "resolved": "https://registry.npmjs.org/is-what/-/is-what-3.14.1.tgz",
+ "integrity": "sha512-sNxgpk9793nzSs7bA6JQJGeIuRBQhAaNGG77kzYQgMkrID+lS6SlK07K5LaptscDlSaIgH+GPFzf+d75FVxozA=="
+ },
+ "node_modules/jquery": {
+ "version": "3.6.0",
+ "resolved": "https://registry.npmjs.org/jquery/-/jquery-3.6.0.tgz",
+ "integrity": "sha512-JVzAR/AjBvVt2BmYhxRCSYysDsPcssdmTFnzyLEts9qNwmjmu4JTAMYubEfwVOSwpQ1I1sKKFcxhZCI2buerfw=="
+ },
+ "node_modules/js-cookie": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/js-cookie/-/js-cookie-3.0.1.tgz",
+ "integrity": "sha512-+0rgsUXZu4ncpPxRL+lNEptWMOWl9etvPHc/koSRp6MPwpRYAhmk0dUG00J4bxVV3r9uUzfo24wW0knS07SKSw==",
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/less": {
+ "version": "3.13.1",
+ "resolved": "https://registry.npmjs.org/less/-/less-3.13.1.tgz",
+ "integrity": "sha512-SwA1aQXGUvp+P5XdZslUOhhLnClSLIjWvJhmd+Vgib5BFIr9lMNlQwmwUNOjXThF/A0x+MCYYPeWEfeWiLRnTw==",
+ "dependencies": {
+ "copy-anything": "^2.0.1",
+ "tslib": "^1.10.0"
+ },
+ "bin": {
+ "lessc": "bin/lessc"
+ },
+ "engines": {
+ "node": ">=6"
+ },
+ "optionalDependencies": {
+ "errno": "^0.1.1",
+ "graceful-fs": "^4.1.2",
+ "image-size": "~0.5.0",
+ "make-dir": "^2.1.0",
+ "mime": "^1.4.1",
+ "native-request": "^1.0.5",
+ "source-map": "~0.6.0"
+ }
+ },
+ "node_modules/make-dir": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz",
+ "integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==",
+ "optional": true,
+ "dependencies": {
+ "pify": "^4.0.1",
+ "semver": "^5.6.0"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/mdbootstrap": {
+ "version": "4.20.0",
+ "resolved": "https://registry.npmjs.org/mdbootstrap/-/mdbootstrap-4.20.0.tgz",
+ "integrity": "sha512-eIxaYsvHct2BKqkJWphh6j7nFQXHh9NjbbN7a+dctfrVsKaydNW5XpKIxmq2tDSb9+XYGm9hK7hMTlHgeV6wdw=="
+ },
"node_modules/media-typer": {
"version": "0.3.0",
"resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
@@ -311,6 +465,12 @@
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
"integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
},
+ "node_modules/native-request": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/native-request/-/native-request-1.1.0.tgz",
+ "integrity": "sha512-uZ5rQaeRn15XmpgE0xoPL8YWqcX90VtCFglYwAgkvKM5e8fog+vePLAhHxuuv/gRkrQxIeh5U3q9sMNUrENqWw==",
+ "optional": true
+ },
"node_modules/negotiator": {
"version": "0.6.3",
"resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz",
@@ -343,6 +503,15 @@
"resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz",
"integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w="
},
+ "node_modules/pify": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz",
+ "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==",
+ "optional": true,
+ "engines": {
+ "node": ">=6"
+ }
+ },
"node_modules/proxy-addr": {
"version": "2.0.7",
"resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz",
@@ -355,6 +524,12 @@
"node": ">= 0.10"
}
},
+ "node_modules/prr": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz",
+ "integrity": "sha1-0/wRS6BplaRexok/SEzrHXj19HY=",
+ "optional": true
+ },
"node_modules/qs": {
"version": "6.9.7",
"resolved": "https://registry.npmjs.org/qs/-/qs-6.9.7.tgz",
@@ -412,6 +587,15 @@
"resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
},
+ "node_modules/semver": {
+ "version": "5.7.1",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
+ "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==",
+ "optional": true,
+ "bin": {
+ "semver": "bin/semver"
+ }
+ },
"node_modules/send": {
"version": "0.17.2",
"resolved": "https://registry.npmjs.org/send/-/send-0.17.2.tgz",
@@ -459,6 +643,15 @@
"resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz",
"integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw=="
},
+ "node_modules/source-map": {
+ "version": "0.6.1",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
+ "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
+ "optional": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
"node_modules/statuses": {
"version": "1.5.0",
"resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz",
@@ -475,6 +668,11 @@
"node": ">=0.6"
}
},
+ "node_modules/tslib": {
+ "version": "1.14.1",
+ "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
+ "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg=="
+ },
"node_modules/type-is": {
"version": "1.6.18",
"resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz",
@@ -510,9 +708,35 @@
"engines": {
"node": ">= 0.8"
}
+ },
+ "node_modules/ws": {
+ "version": "8.5.0",
+ "resolved": "https://registry.npmjs.org/ws/-/ws-8.5.0.tgz",
+ "integrity": "sha512-BWX0SWVgLPzYwF8lTzEy1egjhS4S4OEAHfsO8o65WOVsrnSRGaSiUaa9e0ggGlkMTtBlmOpEXiie9RUcBO86qg==",
+ "engines": {
+ "node": ">=10.0.0"
+ },
+ "peerDependencies": {
+ "bufferutil": "^4.0.1",
+ "utf-8-validate": "^5.0.2"
+ },
+ "peerDependenciesMeta": {
+ "bufferutil": {
+ "optional": true
+ },
+ "utf-8-validate": {
+ "optional": true
+ }
+ }
}
},
"dependencies": {
+ "@popperjs/core": {
+ "version": "2.11.2",
+ "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.2.tgz",
+ "integrity": "sha512-92FRmppjjqz29VMJ2dn+xdyXZBrMlE42AV6Kq6BwjWV7CNUW1hs2FtxSNLQE+gJhaZ6AAmYuO9y8dshhcBl7vA==",
+ "peer": true
+ },
"accepts": {
"version": "1.3.8",
"resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz",
@@ -544,6 +768,22 @@
"type-is": "~1.6.18"
}
},
+ "bootstrap": {
+ "version": "5.1.3",
+ "resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-5.1.3.tgz",
+ "integrity": "sha512-fcQztozJ8jToQWXxVuEyXWW+dSo8AiXWKwiSSrKWsRB/Qt+Ewwza+JWoLKiTuQLaEPhdNAJ7+Dosc9DOIqNy7Q==",
+ "requires": {}
+ },
+ "bootstrap-duration-picker": {
+ "version": "2.1.3",
+ "resolved": "https://registry.npmjs.org/bootstrap-duration-picker/-/bootstrap-duration-picker-2.1.3.tgz",
+ "integrity": "sha1-vxctw2psm4lQBpYqLYGIwzYPsmU="
+ },
+ "bootstrap-icons": {
+ "version": "1.8.1",
+ "resolved": "https://registry.npmjs.org/bootstrap-icons/-/bootstrap-icons-1.8.1.tgz",
+ "integrity": "sha512-IXUqislddPJfwq6H+2nTkHyr9epO9h6u1AG0OZCx616w+TgzeoCjfmI3qJMQqt1J586gN2IxzB4M99Ip4sTZ1w=="
+ },
"bytes": {
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz",
@@ -572,10 +812,18 @@
"resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz",
"integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw="
},
- "countdown": {
- "version": "2.6.0",
- "resolved": "https://registry.npmjs.org/countdown/-/countdown-2.6.0.tgz",
- "integrity": "sha1-Z3+446nUzE52QVkBuiU7UYrzQXc="
+ "copy-anything": {
+ "version": "2.0.6",
+ "resolved": "https://registry.npmjs.org/copy-anything/-/copy-anything-2.0.6.tgz",
+ "integrity": "sha512-1j20GZTsvKNkc4BY3NpMOM8tt///wY3FpIzozTOFO2ffuZcV61nojHXVKIy3WM+7ADCy5FVhdZYHYDdgTU0yJw==",
+ "requires": {
+ "is-what": "^3.14.1"
+ }
+ },
+ "darkreader": {
+ "version": "4.9.44",
+ "resolved": "https://registry.npmjs.org/darkreader/-/darkreader-4.9.44.tgz",
+ "integrity": "sha512-Mrt5s5eMaFC24Tfi2nNsXpYIfzWK/RUzJxgk0Ysqokvk9lBCn/pkUTyQGYeQbU/U3aKZEYXXqsxZjNfiLoA6QQ=="
},
"debug": {
"version": "2.6.9",
@@ -605,6 +853,15 @@
"resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz",
"integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k="
},
+ "errno": {
+ "version": "0.1.8",
+ "resolved": "https://registry.npmjs.org/errno/-/errno-0.1.8.tgz",
+ "integrity": "sha512-dJ6oBr5SQ1VSd9qkk7ByRgb/1SH4JZjCHSW/mr63/QcXO9zLVxvJ6Oy13nio03rxpSnVDDjFor75SjVeZWPW/A==",
+ "optional": true,
+ "requires": {
+ "prr": "~1.0.1"
+ }
+ },
"escape-html": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
@@ -666,6 +923,11 @@
"unpipe": "~1.0.0"
}
},
+ "flatpickr": {
+ "version": "4.6.11",
+ "resolved": "https://registry.npmjs.org/flatpickr/-/flatpickr-4.6.11.tgz",
+ "integrity": "sha512-/rnbE/hu5I5zndLEyYfYvqE4vPDvI5At0lFcQA5eOPfjquZLcQ0HMKTL7rv5/+DvbPM3/vJcXpXjB/DjBh+1jw=="
+ },
"forwarded": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz",
@@ -676,6 +938,12 @@
"resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz",
"integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac="
},
+ "graceful-fs": {
+ "version": "4.2.9",
+ "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.9.tgz",
+ "integrity": "sha512-NtNxqUcXgpW2iMrfqSfR73Glt39K+BLwWsPs94yR63v45T0Wbej7eRmL5cWfwEgqXnmjQp3zaJTshdRW/qC2ZQ==",
+ "optional": true
+ },
"http-errors": {
"version": "1.8.1",
"resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.8.1.tgz",
@@ -696,6 +964,12 @@
"safer-buffer": ">= 2.1.2 < 3"
}
},
+ "image-size": {
+ "version": "0.5.5",
+ "resolved": "https://registry.npmjs.org/image-size/-/image-size-0.5.5.tgz",
+ "integrity": "sha1-Cd/Uq50g4p6xw+gLiZA3jfnjy5w=",
+ "optional": true
+ },
"inherits": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
@@ -706,6 +980,52 @@
"resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz",
"integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g=="
},
+ "is-what": {
+ "version": "3.14.1",
+ "resolved": "https://registry.npmjs.org/is-what/-/is-what-3.14.1.tgz",
+ "integrity": "sha512-sNxgpk9793nzSs7bA6JQJGeIuRBQhAaNGG77kzYQgMkrID+lS6SlK07K5LaptscDlSaIgH+GPFzf+d75FVxozA=="
+ },
+ "jquery": {
+ "version": "3.6.0",
+ "resolved": "https://registry.npmjs.org/jquery/-/jquery-3.6.0.tgz",
+ "integrity": "sha512-JVzAR/AjBvVt2BmYhxRCSYysDsPcssdmTFnzyLEts9qNwmjmu4JTAMYubEfwVOSwpQ1I1sKKFcxhZCI2buerfw=="
+ },
+ "js-cookie": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/js-cookie/-/js-cookie-3.0.1.tgz",
+ "integrity": "sha512-+0rgsUXZu4ncpPxRL+lNEptWMOWl9etvPHc/koSRp6MPwpRYAhmk0dUG00J4bxVV3r9uUzfo24wW0knS07SKSw=="
+ },
+ "less": {
+ "version": "3.13.1",
+ "resolved": "https://registry.npmjs.org/less/-/less-3.13.1.tgz",
+ "integrity": "sha512-SwA1aQXGUvp+P5XdZslUOhhLnClSLIjWvJhmd+Vgib5BFIr9lMNlQwmwUNOjXThF/A0x+MCYYPeWEfeWiLRnTw==",
+ "requires": {
+ "copy-anything": "^2.0.1",
+ "errno": "^0.1.1",
+ "graceful-fs": "^4.1.2",
+ "image-size": "~0.5.0",
+ "make-dir": "^2.1.0",
+ "mime": "^1.4.1",
+ "native-request": "^1.0.5",
+ "source-map": "~0.6.0",
+ "tslib": "^1.10.0"
+ }
+ },
+ "make-dir": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz",
+ "integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==",
+ "optional": true,
+ "requires": {
+ "pify": "^4.0.1",
+ "semver": "^5.6.0"
+ }
+ },
+ "mdbootstrap": {
+ "version": "4.20.0",
+ "resolved": "https://registry.npmjs.org/mdbootstrap/-/mdbootstrap-4.20.0.tgz",
+ "integrity": "sha512-eIxaYsvHct2BKqkJWphh6j7nFQXHh9NjbbN7a+dctfrVsKaydNW5XpKIxmq2tDSb9+XYGm9hK7hMTlHgeV6wdw=="
+ },
"media-typer": {
"version": "0.3.0",
"resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
@@ -744,6 +1064,12 @@
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
"integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
},
+ "native-request": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/native-request/-/native-request-1.1.0.tgz",
+ "integrity": "sha512-uZ5rQaeRn15XmpgE0xoPL8YWqcX90VtCFglYwAgkvKM5e8fog+vePLAhHxuuv/gRkrQxIeh5U3q9sMNUrENqWw==",
+ "optional": true
+ },
"negotiator": {
"version": "0.6.3",
"resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz",
@@ -767,6 +1093,12 @@
"resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz",
"integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w="
},
+ "pify": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz",
+ "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==",
+ "optional": true
+ },
"proxy-addr": {
"version": "2.0.7",
"resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz",
@@ -776,6 +1108,12 @@
"ipaddr.js": "1.9.1"
}
},
+ "prr": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz",
+ "integrity": "sha1-0/wRS6BplaRexok/SEzrHXj19HY=",
+ "optional": true
+ },
"qs": {
"version": "6.9.7",
"resolved": "https://registry.npmjs.org/qs/-/qs-6.9.7.tgz",
@@ -807,6 +1145,12 @@
"resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
},
+ "semver": {
+ "version": "5.7.1",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
+ "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==",
+ "optional": true
+ },
"send": {
"version": "0.17.2",
"resolved": "https://registry.npmjs.org/send/-/send-0.17.2.tgz",
@@ -850,6 +1194,12 @@
"resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz",
"integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw=="
},
+ "source-map": {
+ "version": "0.6.1",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
+ "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
+ "optional": true
+ },
"statuses": {
"version": "1.5.0",
"resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz",
@@ -860,6 +1210,11 @@
"resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz",
"integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA=="
},
+ "tslib": {
+ "version": "1.14.1",
+ "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
+ "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg=="
+ },
"type-is": {
"version": "1.6.18",
"resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz",
@@ -883,6 +1238,12 @@
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
"integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw="
+ },
+ "ws": {
+ "version": "8.5.0",
+ "resolved": "https://registry.npmjs.org/ws/-/ws-8.5.0.tgz",
+ "integrity": "sha512-BWX0SWVgLPzYwF8lTzEy1egjhS4S4OEAHfsO8o65WOVsrnSRGaSiUaa9e0ggGlkMTtBlmOpEXiie9RUcBO86qg==",
+ "requires": {}
}
}
}
diff --git a/package.json b/package.json
index 33a91c8..0026266 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "opencountdown",
- "version": "1.0.0",
+ "version": "1.0.1",
"description": "An opensource countdown",
"main": "index.js",
"scripts": {
@@ -10,7 +10,16 @@
"license": "LGPL-3.0",
"dependencies": {
"body-parser": "^1.19.2",
- "countdown": "^2.6.0",
- "express": "^4.17.3"
+ "bootstrap": "^5.1.3",
+ "bootstrap-duration-picker": "^2.1.3",
+ "bootstrap-icons": "^1.8.1",
+ "darkreader": "^4.9.44",
+ "express": "^4.17.3",
+ "flatpickr": "^4.6.11",
+ "jquery": "^3.6.0",
+ "js-cookie": "^3.0.1",
+ "less": "^3.13",
+ "mdbootstrap": "^4.20.0",
+ "ws": "^8.5.0"
}
}
diff --git a/static/bootstrap-duration-picker b/static/bootstrap-duration-picker
new file mode 120000
index 0000000..3b83664
--- /dev/null
+++ b/static/bootstrap-duration-picker
@@ -0,0 +1 @@
+../node_modules/bootstrap-duration-picker/dist/
\ No newline at end of file
diff --git a/static/bootstrap/dist b/static/bootstrap/dist
new file mode 120000
index 0000000..8fc3423
--- /dev/null
+++ b/static/bootstrap/dist
@@ -0,0 +1 @@
+../../node_modules/bootstrap/dist
\ No newline at end of file
diff --git a/static/coloris/coloris.min.css b/static/coloris/coloris.min.css
new file mode 100644
index 0000000..1e50bd4
--- /dev/null
+++ b/static/coloris/coloris.min.css
@@ -0,0 +1 @@
+.clr-picker{display:none;flex-wrap:wrap;position:absolute;width:200px;z-index:1000;border-radius:10px;background-color:#fff;justify-content:space-between;box-shadow:0 0 5px rgba(0,0,0,.05),0 5px 20px rgba(0,0,0,.1);-moz-user-select:none;-webkit-user-select:none;user-select:none}.clr-picker.clr-open{display:flex}.clr-gradient{position:relative;width:100%;height:100px;margin-bottom:15px;border-radius:3px 3px 0 0;background-image:linear-gradient(rgba(0,0,0,0),#000),linear-gradient(90deg,#fff,currentColor);cursor:pointer}.clr-marker{position:absolute;width:12px;height:12px;margin:-6px 0 0 -6px;border:1px solid #fff;border-radius:50%;background-color:currentColor;cursor:pointer}.clr-picker input[type=range]::-webkit-slider-runnable-track{width:100%;height:8px}.clr-picker input[type=range]::-webkit-slider-thumb{width:8px;height:8px;-webkit-appearance:none}.clr-picker input[type=range]::-moz-range-track{width:100%;height:8px;border:0}.clr-picker input[type=range]::-moz-range-thumb{width:8px;height:8px;border:0}.clr-hue{background-image:linear-gradient(to right,red 0,#ff0 16.66%,#0f0 33.33%,#0ff 50%,#00f 66.66%,#f0f 83.33%,red 100%)}.clr-alpha,.clr-hue{position:relative;width:calc(100% - 40px);height:8px;margin:5px 20px;border-radius:4px}.clr-alpha span{display:block;height:100%;width:100%;border-radius:inherit;background-image:linear-gradient(90deg,rgba(0,0,0,0),currentColor)}.clr-alpha input,.clr-hue input{position:absolute;width:calc(100% + 16px);height:16px;left:-8px;top:-4px;margin:0;background-color:transparent;opacity:0;cursor:pointer;appearance:none;-webkit-appearance:none}.clr-alpha div,.clr-hue div{position:absolute;width:16px;height:16px;left:0;top:50%;margin-left:-8px;transform:translateY(-50%);border:2px solid #fff;border-radius:50%;background-color:currentColor;box-shadow:0 0 1px #888;pointer-events:none}.clr-alpha div:before{content:'';position:absolute;height:100%;width:100%;left:0;top:0;border-radius:50%;background-color:currentColor}.clr-format{display:none;order:1;width:calc(100% - 40px);margin:0 20px 20px}.clr-segmented{display:flex;position:relative;width:100%;margin:0;padding:0;border:1px solid #ddd;border-radius:15px;box-sizing:border-box;color:#999;font-size:12px}.clr-segmented input,.clr-segmented legend{position:absolute;width:100%;height:100%;margin:0;padding:0;border:0;left:0;top:0;opacity:0;pointer-events:none}.clr-segmented label{flex-grow:1;padding:4px 0;text-align:center;cursor:pointer}.clr-segmented label:first-of-type{border-radius:10px 0 0 10px}.clr-segmented label:last-of-type{border-radius:0 10px 10px 0}.clr-segmented input:checked+label{color:#fff;background-color:#666}.clr-swatches{order:2;width:calc(100% - 32px);margin:0 16px}.clr-swatches div{display:flex;flex-wrap:wrap;padding-bottom:12px;justify-content:center}.clr-swatches button{position:relative;width:20px;height:20px;margin:0 4px 6px 4px;border:0;border-radius:50%;color:inherit;text-indent:-1000px;white-space:nowrap;overflow:hidden;cursor:pointer}.clr-swatches button:after{content:'';display:block;position:absolute;width:100%;height:100%;left:0;top:0;border-radius:inherit;background-color:currentColor;box-shadow:inset 0 0 0 1px rgba(0,0,0,.1)}input.clr-color{order:1;width:calc(100% - 80px);height:32px;margin:15px 20px 20px 0;padding:0 10px;border:1px solid #ddd;border-radius:16px;color:#444;background-color:#fff;font-family:sans-serif;font-size:14px;text-align:center;box-shadow:none}input.clr-color:focus{outline:0;border:1px solid #1e90ff}.clr-clear{display:none;order:2;height:24px;margin:0 20px 20px auto;padding:0 20px;border:0;border-radius:12px;color:#fff;background-color:#666;font-family:inherit;font-size:12px;font-weight:400;cursor:pointer}.clr-preview{position:relative;width:32px;height:32px;margin:15px 0 20px 20px;border:0;border-radius:50%;overflow:hidden;cursor:pointer}.clr-preview:after,.clr-preview:before{content:'';position:absolute;height:100%;width:100%;left:0;top:0;border:1px solid #fff;border-radius:50%}.clr-preview:after{border:0;background-color:currentColor;box-shadow:inset 0 0 0 1px rgba(0,0,0,.1)}.clr-alpha div,.clr-color,.clr-hue div,.clr-marker{box-sizing:border-box}.clr-field{display:inline-block;position:relative;color:transparent}.clr-field button{position:absolute;width:30px;height:100%;right:0;top:50%;transform:translateY(-50%);border:0;color:inherit;text-indent:-1000px;white-space:nowrap;overflow:hidden;pointer-events:none}.clr-field button:after{content:'';display:block;position:absolute;width:100%;height:100%;left:0;top:0;border-radius:inherit;background-color:currentColor;box-shadow:inset 0 0 1px rgba(0,0,0,.5)}.clr-alpha,.clr-alpha div,.clr-field button,.clr-preview:before,.clr-swatches button{background-image:repeating-linear-gradient(45deg,#aaa 25%,transparent 25%,transparent 75%,#aaa 75%,#aaa),repeating-linear-gradient(45deg,#aaa 25%,#fff 25%,#fff 75%,#aaa 75%,#aaa);background-position:0 0,4px 4px;background-size:8px 8px}.clr-marker:focus{outline:0}.clr-keyboard-nav .clr-alpha input:focus+div,.clr-keyboard-nav .clr-hue input:focus+div,.clr-keyboard-nav .clr-marker:focus,.clr-keyboard-nav .clr-segmented input:focus+label{outline:0;box-shadow:0 0 0 2px #1e90ff,0 0 2px 2px #fff}.clr-picker[data-alpha=false] .clr-alpha{display:none}.clr-picker[data-minimal=true]{padding-top:16px}.clr-picker[data-minimal=true] .clr-alpha,.clr-picker[data-minimal=true] .clr-color,.clr-picker[data-minimal=true] .clr-gradient,.clr-picker[data-minimal=true] .clr-hue,.clr-picker[data-minimal=true] .clr-preview{display:none}.clr-dark{background-color:#444}.clr-dark .clr-segmented{border-color:#777}.clr-dark .clr-swatches button:after{box-shadow:inset 0 0 0 1px rgba(255,255,255,.3)}.clr-dark input.clr-color{color:#fff;border-color:#777;background-color:#555}.clr-dark input.clr-color:focus{border-color:#1e90ff}.clr-dark .clr-preview:after{box-shadow:inset 0 0 0 1px rgba(255,255,255,.5)}.clr-dark .clr-alpha,.clr-dark .clr-alpha div,.clr-dark .clr-preview:before,.clr-dark .clr-swatches button{background-image:repeating-linear-gradient(45deg,#666 25%,transparent 25%,transparent 75%,#888 75%,#888),repeating-linear-gradient(45deg,#888 25%,#444 25%,#444 75%,#888 75%,#888)}.clr-picker.clr-polaroid{border-radius:6px;box-shadow:0 0 5px rgba(0,0,0,.1),0 5px 30px rgba(0,0,0,.2)}.clr-picker.clr-polaroid:before{content:'';display:block;position:absolute;width:16px;height:10px;left:20px;top:-10px;border:solid transparent;border-width:0 8px 10px 8px;border-bottom-color:currentColor;box-sizing:border-box;color:#fff;filter:drop-shadow(0 -4px 3px rgba(0,0,0,.1));pointer-events:none}.clr-picker.clr-polaroid.clr-dark:before{color:#444}.clr-picker.clr-polaroid.clr-left:before{left:auto;right:20px}.clr-picker.clr-polaroid.clr-top:before{top:auto;bottom:-10px;transform:rotateZ(180deg)}.clr-polaroid .clr-gradient{width:calc(100% - 20px);height:120px;margin:10px;border-radius:3px}.clr-polaroid .clr-alpha,.clr-polaroid .clr-hue{width:calc(100% - 30px);height:10px;margin:6px 15px;border-radius:5px}.clr-polaroid .clr-alpha div,.clr-polaroid .clr-hue div{box-shadow:0 0 5px rgba(0,0,0,.2)}.clr-polaroid .clr-format{width:calc(100% - 20px);margin:0 10px 15px}.clr-polaroid .clr-swatches{width:calc(100% - 12px);margin:0 6px}.clr-polaroid .clr-swatches div{padding-bottom:10px}.clr-polaroid .clr-swatches button{width:22px;height:22px}.clr-polaroid input.clr-color{width:calc(100% - 60px);margin:10px 10px 15px 0}.clr-polaroid .clr-clear{margin:0 10px 15px auto}.clr-polaroid .clr-preview{margin:10px 0 15px 10px}.clr-picker.clr-large{width:275px}.clr-large .clr-gradient{height:150px}.clr-large .clr-swatches button{width:22px;height:22px}
\ No newline at end of file
diff --git a/static/coloris/coloris.min.js b/static/coloris/coloris.min.js
new file mode 100644
index 0000000..f6a773f
--- /dev/null
+++ b/static/coloris/coloris.min.js
@@ -0,0 +1,6 @@
+/*!
+ * Copyright (c) 2021 Momo Bassit.
+ * Licensed under the MIT License (MIT)
+ * https://github.com/mdbassit/Coloris
+ */
+!function(d,p,s){var h,f,v,c,u,y,i,b,l,g,m,w,k,x,a=p.createElement("canvas").getContext("2d"),E={r:0,g:0,b:0,h:0,s:0,v:0,a:1},L={el:"[data-coloris]",parent:null,theme:"default",themeMode:"light",wrap:!0,margin:2,format:"hex",formatToggle:!1,swatches:[],swatchesOnly:!1,alpha:!0,focusInput:!0,autoClose:!1,clearButton:{show:!1,label:"Clear"},a11y:{open:"Open color picker",close:"Close color picker",marker:"Saturation: {s}. Brightness: {v}.",hueSlider:"Hue slider",alphaSlider:"Opacity slider",input:"Color value field",format:"Color format",swatch:"Color swatch",instruction:"Saturation and brightness selector. Use up, down, left and right arrow keys to select."}};function o(e){if("object"==typeof e)for(var t in e)switch(t){case"el":S(e.el),!1!==e.wrap&&T(e.el);break;case"parent":L.parent=p.querySelector(e.parent),L.parent&&L.parent.appendChild(h);break;case"themeMode":L.themeMode=e.themeMode,"auto"===e.themeMode&&d.matchMedia&&d.matchMedia("(prefers-color-scheme: dark)").matches&&(L.themeMode="dark");case"theme":e.theme&&(L.theme=e.theme),h.className="clr-picker clr-"+L.theme+" clr-"+L.themeMode;break;case"margin":e.margin*=1,L.margin=(isNaN(e.margin)?L:e).margin;break;case"wrap":e.el&&e.wrap&&T(e.el);break;case"formatToggle":N("clr-format").style.display=e.formatToggle?"block":"none",e.formatToggle&&(L.format="auto");break;case"swatches":Array.isArray(e.swatches)&&function(){var a=[];e.swatches.forEach(function(e,t){a.push(''+e+" ")}),a.length&&(N("clr-swatches").innerHTML=""+a.join("")+"
")}();break;case"swatchesOnly":L.swatchesOnly=!!e.swatchesOnly,h.setAttribute("data-minimal",L.swatchesOnly),L.swatchesOnly&&(L.autoClose=!0);break;case"alpha":L.alpha=!!e.alpha,h.setAttribute("data-alpha",L.alpha);break;case"clearButton":var a="none";e.clearButton.show&&(a="block"),e.clearButton.label&&(i.innerHTML=e.clearButton.label),i.style.display=a;break;case"a11y":var l,r=e.a11y,o=!1;if("object"==typeof r)for(var n in r)r[n]&&L.a11y[n]&&(L.a11y[n]=r[n],o=!0);o&&(l=N("clr-open-label"),a=N("clr-swatch-label"),l.innerHTML=L.a11y.open,a.innerHTML=L.a11y.swatch,u.setAttribute("aria-label",L.a11y.close),b.setAttribute("aria-label",L.a11y.hueSlider),g.setAttribute("aria-label",L.a11y.alphaSlider),y.setAttribute("aria-label",L.a11y.input),f.setAttribute("aria-label",L.a11y.instruction));default:L[t]=e[t]}}function S(e){O(p,"click",e,function(e){var t=L.parent,a=e.target.getBoundingClientRect(),l=d.scrollY,r={left:!1,top:!1},o={x:0,y:0},n=a.x,i=l+a.y+a.height+L.margin;w=e.target,x=w.value,k=function(e){e=e.substring(0,3).toLowerCase();return"rgb"!==e&&"hsl"!==e?"hex":e}(x),h.classList.add("clr-open");var c,s=h.offsetWidth,u=h.offsetHeight;t?(c=d.getComputedStyle(t),e=parseFloat(c.marginTop),c=parseFloat(c.borderTopWidth),(o=t.getBoundingClientRect()).y+=c+l,n-=o.x,i-=o.y,n+s>t.clientWidth&&(n+=a.width-s,r.left=!0),i+u>t.clientHeight-e&&(i-=a.height+u+2*L.margin,r.top=!0),i+=t.scrollTop):(n+s>p.documentElement.clientWidth&&(n+=a.width-s,r.left=!0),i+u-l>p.documentElement.clientHeight&&(i=l+a.y-u-L.margin,r.top=!0)),h.classList.toggle("clr-left",r.left),h.classList.toggle("clr-top",r.top),h.style.left=n+"px",h.style.top=i+"px",v={width:f.offsetWidth,height:f.offsetHeight,x:h.offsetLeft+f.offsetLeft+o.x,y:h.offsetTop+f.offsetTop+o.y},A(x),L.focusInput&&y.focus({preventScroll:!0})}),O(p,"input",e,function(e){var t=e.target.parentNode;t.classList.contains("clr-field")&&(t.style.color=e.target.value)})}function T(e){p.querySelectorAll(e).forEach(function(e){var t,a=e.parentNode;a.classList.contains("clr-field")||((t=p.createElement("div")).innerHTML=' ',a.insertBefore(t,e),t.setAttribute("class","clr-field"),t.style.color=e.value,t.appendChild(e))})}function n(e){w&&(e&&x!==w.value&&(w.value=x,w.dispatchEvent(new Event("input",{bubbles:!0}))),x!==w.value&&w.dispatchEvent(new Event("change",{bubbles:!0})),h.classList.remove("clr-open"),L.focusInput&&w.focus({preventScroll:!0}),w=null)}function A(e){var t=function(e){var t;a.fillStyle="#000",a.fillStyle=e,(e=/^((rgba)|rgb)[\D]+([\d.]+)[\D]+([\d.]+)[\D]+([\d.]+)[\D]*?([\d.]+|$)/i.exec(a.fillStyle))?(t={r:+e[3],g:+e[4],b:+e[5],a:+e[6]}).a=+t.a.toFixed(2):(e=a.fillStyle.replace("#","").match(/.{2}/g).map(function(e){return parseInt(e,16)}),t={r:e[0],g:e[1],b:e[2],a:1});return t}(e),e=function(e){var t=e.r/255,a=e.g/255,l=e.b/255,r=s.max(t,a,l),o=s.min(t,a,l),n=r-o,i=r,c=0,o=0;n&&(r===t&&(c=(a-l)/n),r===a&&(c=2+(l-t)/n),r===l&&(c=4+(t-a)/n),r&&(o=n/r));return{h:(c=s.floor(60*c))<0?c+360:c,s:s.round(100*o),v:s.round(100*i),a:e.a}}(t);M(e.s,e.v),H(t,e),b.value=e.h,h.style.color="hsl("+e.h+", 100%, 50%)",l.style.left=e.h/360*100+"%",c.style.left=v.width*e.s/100+"px",c.style.top=v.height-v.height*e.v/100+"px",g.value=100*e.a,m.style.left=100*e.a+"%"}function r(e){w&&(w.value=void 0!==e?e:y.value,w.dispatchEvent(new Event("input",{bubbles:!0})))}function C(e,t){e={h:+b.value,s:e/v.width*100,v:100-t/v.height*100,a:g.value/100},t=function(e){var t=e.s/100,a=e.v/100,l=t*a,r=e.h/60,o=l*(1-s.abs(r%2-1)),n=a-l;l+=n,o+=n;t=s.floor(r)%6,a=[l,o,n,n,o,l][t],r=[o,l,l,o,n,n][t],t=[n,n,o,l,l,o][t];return{r:s.round(255*a),g:s.round(255*r),b:s.round(255*t),a:e.a}}(e);M(e.s,e.v),H(t,e),r()}function M(e,t){var a=L.a11y.marker;e=+e.toFixed(1),t=+t.toFixed(1),a=(a=a.replace("{s}",e)).replace("{v}",t),c.setAttribute("aria-label",a)}function t(e){var t={pageX:((a=e).changedTouches?a.changedTouches[0]:a).pageX,pageY:(a.changedTouches?a.changedTouches[0]:a).pageY},a=t.pageX-v.x,t=t.pageY-v.y;L.parent&&(t+=L.parent.scrollTop),a=a<0?0:a>v.width?v.width:a,t=t<0?0:t>v.height?v.height:t,c.style.left=a+"px",c.style.top=t+"px",C(a,t),e.preventDefault(),e.stopPropagation()}function H(e,t){void 0===t&&(t={});var a,l,r=L.format;for(a in e=void 0===e?{}:e)E[a]=e[a];for(l in t)E[l]=t[l];var o,n=function(e){var t=e.r.toString(16),a=e.g.toString(16),l=e.b.toString(16),r="";e.r<16&&(t="0"+t);e.g<16&&(a="0"+a);e.b<16&&(l="0"+l);L.alpha&&e.a<1&&(e=255*e.a|0,r=e.toString(16),e<16&&(r="0"+r));return"#"+t+a+l+r}(E),i=n.substring(0,7);switch(c.style.color=i,m.parentNode.style.color=i,m.style.color=n,u.style.color=n,f.style.display="none",f.offsetHeight,f.style.display="",m.nextElementSibling.style.display="none",m.nextElementSibling.offsetHeight,m.nextElementSibling.style.display="","mixed"===r?r=1===E.a?"hex":"rgb":"auto"===r&&(r=k),r){case"hex":y.value=n;break;case"rgb":y.value=(o=E,L.alpha&&1!==o.a?"rgba("+o.r+", "+o.g+", "+o.b+", "+o.a+")":"rgb("+o.r+", "+o.g+", "+o.b+")");break;case"hsl":y.value=(o=function(e){var t,a=e.v/100,l=a*(1-e.s/100/2);0
'+L.a11y.format+' Hex RGB HSL
'+L.clearButton.label+' '+L.a11y.open+' '+L.a11y.swatch+" ",p.body.appendChild(h),f=N("clr-color-area"),c=N("clr-color-marker"),i=N("clr-clear"),u=N("clr-color-preview"),y=N("clr-color-value"),b=N("clr-hue-slider"),l=N("clr-hue-marker"),g=N("clr-alpha-slider"),m=N("clr-alpha-marker"),S(L.el),T(L.el),O(h,"mousedown",function(e){h.classList.remove("clr-keyboard-nav"),e.stopPropagation()}),O(f,"mousedown",function(e){O(p,"mousemove",t)}),O(f,"touchstart",function(e){p.addEventListener("touchmove",t,{passive:!1})}),O(c,"mousedown",function(e){O(p,"mousemove",t)}),O(c,"touchstart",function(e){p.addEventListener("touchmove",t,{passive:!1})}),O(y,"change",function(e){A(y.value),r()}),O(i,"click",function(e){r(""),n()}),O(u,"click",function(e){r(),n()}),O(p,"click",".clr-format input",function(e){k=e.target.value,H(),r()}),O(h,"click",".clr-swatches button",function(e){A(e.target.textContent),r(),L.autoClose&&n()}),O(p,"mouseup",function(e){p.removeEventListener("mousemove",t)}),O(p,"touchend",function(e){p.removeEventListener("touchmove",t)}),O(p,"mousedown",function(e){h.classList.remove("clr-keyboard-nav"),n()}),O(p,"keydown",function(e){"Escape"===e.key?n(!0):"Tab"===e.key&&h.classList.add("clr-keyboard-nav")}),O(p,"click",".clr-field button",function(e){e.target.nextElementSibling.dispatchEvent(new Event("click",{bubbles:!0}))}),O(c,"keydown",function(e){var t={ArrowUp:[0,-1],ArrowDown:[0,1],ArrowLeft:[-1,0],ArrowRight:[1,0]};-1!==Object.keys(t).indexOf(e.key)&&(!function(e,t){e=+c.style.left.replace("px","")+e,t=+c.style.top.replace("px","")+t,c.style.left=e+"px",c.style.top=t+"px",C(e,t)}.apply(void 0,t[e.key]),e.preventDefault())}),O(f,"click",t),O(b,"input",e),O(g,"input",B)})}(window,document,Math);
\ No newline at end of file
diff --git a/static/colorpicker/css b/static/colorpicker/css
new file mode 120000
index 0000000..3cf966e
--- /dev/null
+++ b/static/colorpicker/css
@@ -0,0 +1 @@
+../../node_modules/bootstrap-colorpicker/dist/css
\ No newline at end of file
diff --git a/static/colorpicker/js b/static/colorpicker/js
new file mode 120000
index 0000000..cc23749
--- /dev/null
+++ b/static/colorpicker/js
@@ -0,0 +1 @@
+../../node_modules/bootstrap-colorpicker/dist/js
\ No newline at end of file
diff --git a/static/css/bootstrap-icons.css b/static/css/bootstrap-icons.css
new file mode 120000
index 0000000..996baca
--- /dev/null
+++ b/static/css/bootstrap-icons.css
@@ -0,0 +1 @@
+../../node_modules/bootstrap-icons/font/bootstrap-icons.css
\ No newline at end of file
diff --git a/static/css/errorPage/style.css b/static/css/errorPage/style.css
new file mode 100644
index 0000000..27a7671
--- /dev/null
+++ b/static/css/errorPage/style.css
@@ -0,0 +1,86 @@
+html, body {
+ height: 100%;
+ width: 100%;
+ margin: 0;
+ padding: 0;
+}
+
+.container {
+ height: 100%;
+ width: 100%;
+ background-color: #0B161E;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ justify-content: center;
+ font-family: 'Segoe UI';
+ text-align: center;
+}
+
+.color-foreground {
+ color: #474849 !important;
+}
+
+.text-shadow {
+ text-shadow: 1px 1px 2px;
+}
+
+.rainbow {
+ -webkit-animation:rainbow 16s infinite;
+ -ms-animation:rainbow 16s infinite;
+ -o-animation:rainbow 16s infinite;
+ animation:rainbow 16s infinite;
+}
+
+@-webkit-keyframes rainbow {
+0% {color: #ff0000;}
+10% {color: #ff8000;}
+20% {color: #ffff00;}
+30% {color: #80ff00;}
+40% {color: #00ff00;}
+50% {color: #00ff80;}
+60% {color: #00ffff;}
+70% {color: #0080ff;}
+80% {color: #0000ff;}
+90% {color: #8000ff;}
+100% {color: #ff0080;}
+}
+@-ms-keyframes rainbow {
+0% {color: #ff0000;}
+10% {color: #ff8000;}
+20% {color: #ffff00;}
+30% {color: #80ff00;}
+40% {color: #00ff00;}
+50% {color: #00ff80;}
+60% {color: #00ffff;}
+70% {color: #0080ff;}
+80% {color: #0000ff;}
+90% {color: #8000ff;}
+100% {color: #ff0080;}
+}
+@-o-keyframes rainbow {
+0% {color: #ff0000;}
+10% {color: #ff8000;}
+20% {color: #ffff00;}
+30% {color: #80ff00;}
+40% {color: #00ff00;}
+50% {color: #00ff80;}
+60% {color: #00ffff;}
+70% {color: #0080ff;}
+80% {color: #0000ff;}
+90% {color: #8000ff;}
+100% {color: #ff0080;}
+}
+@keyframes rainbow {
+0% {color: #ff0000;}
+10% {color: #ff8000;}
+20% {color: #ffff00;}
+30% {color: #80ff00;}
+40% {color: #00ff00;}
+50% {color: #00ff80;}
+60% {color: #00ffff;}
+70% {color: #0080ff;}
+80% {color: #0000ff;}
+90% {color: #8000ff;}
+100% {color: #ff0080;}
+}
\ No newline at end of file
diff --git a/static/css/errorPage/styles.less b/static/css/errorPage/styles.less
new file mode 100644
index 0000000..b2732f5
--- /dev/null
+++ b/static/css/errorPage/styles.less
@@ -0,0 +1,62 @@
+.glitch-wrapper {
+ height: 100%;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+}
+
+.glitch {
+ @offset1: 2px;
+ @offset2: -2px;
+ @highlight1: #49FC00;
+ @highlight2: spin(@highlight1, 180);
+
+ color: white;
+ font-size: 150px;
+ text-transform: upercase;
+ position: relative;
+ display: inline-block;
+
+ &::before,
+ &::after {
+ content: attr(data-text);
+ position: absolute;
+ top: 0;
+ left: 0;
+ width: 100%;
+ height: 100%;
+ background: #0B161E;
+ }
+
+ &::before {
+ left: @offset1;
+ text-shadow: -2px 0 @highlight1;
+ clip: rect(24px, 550px, 90px, 0);
+ animation: glitch-anim-2 3s infinite linear alternate-reverse;
+ }
+
+ &::after {
+ left: @offset2;
+ text-shadow: -2px 0 @highlight2;
+ clip: rect(85px, 550px, 140px, 0);
+ animation: glitch-anim 2.5s infinite linear alternate-reverse;
+ }
+}
+
+.glitch-frames (@n: 20, @index: 0) when (@index <= @n) {
+ @keyframeSel: percentage(@index/@n);
+ @rand1: unit(round(`Math.random()*150`),px);
+ @rand2: unit(round(`Math.random()*150`), px);
+ @{keyframeSel} {
+ clip: rect(@rand1, 9999px, @rand2, 0);
+ }
+ .glitch-frames(@n, (@index + 1));
+}
+
+@keyframes glitch-anim {
+ .glitch-frames(24);
+}
+
+@keyframes glitch-anim-2 {
+ .glitch-frames(30,2);
+}
\ No newline at end of file
diff --git a/static/css/fonts/bootstrap-icons.woff b/static/css/fonts/bootstrap-icons.woff
new file mode 120000
index 0000000..6a1958f
--- /dev/null
+++ b/static/css/fonts/bootstrap-icons.woff
@@ -0,0 +1 @@
+../../../node_modules/bootstrap-icons/font/fonts/bootstrap-icons.woff
\ No newline at end of file
diff --git a/static/css/fonts/bootstrap-icons.woff2 b/static/css/fonts/bootstrap-icons.woff2
new file mode 120000
index 0000000..90ff4c9
--- /dev/null
+++ b/static/css/fonts/bootstrap-icons.woff2
@@ -0,0 +1 @@
+../../../node_modules/bootstrap-icons/font/fonts/bootstrap-icons.woff2
\ No newline at end of file
diff --git a/static/css/mainStyle.css b/static/css/mainStyle.css
new file mode 100644
index 0000000..2ae1f08
--- /dev/null
+++ b/static/css/mainStyle.css
@@ -0,0 +1,129 @@
+body {
+ min-height: 100vh;
+ min-height: -webkit-fill-available;
+ }
+
+ html {
+ height: -webkit-fill-available;
+ }
+
+ main {
+ display: flex;
+ flex-wrap: nowrap;
+ height: 100vh !important;
+ height: -webkit-fill-available;
+ max-height: 100vh;
+ overflow-x: auto;
+ overflow-y: hidden;
+ }
+
+ .full .clr-field button {
+ width: 100%;
+ height: 100%;
+ border-radius: 5px;
+ }
+
+ .b-example-divider {
+ flex-shrink: 0;
+ width: 1.5rem;
+ height: 100vh;
+ background-color: rgba(0, 0, 0, .1);
+ border: solid rgba(0, 0, 0, .15);
+ border-width: 1px 0;
+ box-shadow: inset 0 .5em 1.5em rgba(0, 0, 0, .1), inset 0 .125em .5em rgba(0, 0, 0, .15);
+ }
+
+ .bi {
+ vertical-align: -.125em;
+ pointer-events: none;
+ fill: currentColor;
+ }
+
+ .dropdown-toggle { outline: 0; }
+
+ .nav-flush .nav-link {
+ border-radius: 0;
+ }
+
+ .btn-toggle {
+ display: inline-flex;
+ align-items: center;
+ padding: .25rem .5rem;
+ font-weight: 600;
+ color: rgba(0, 0, 0, .65);
+ background-color: transparent;
+ border: 0;
+ }
+ .btn-toggle:hover,
+ .btn-toggle:focus {
+ color: rgba(0, 0, 0, .85);
+ background-color: #d2f4ea;
+ }
+
+ .btn-toggle::before {
+ width: 1.25em;
+ line-height: 0;
+ content: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 16 16'%3e%3cpath fill='none' stroke='rgba%280,0,0,.5%29' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M5 14l6-6-6-6'/%3e%3c/svg%3e");
+ transition: transform .35s ease;
+ transform-origin: .5em 50%;
+ }
+
+ .btn-toggle[aria-expanded="true"] {
+ color: rgba(0, 0, 0, .85);
+ }
+ .btn-toggle[aria-expanded="true"]::before {
+ transform: rotate(90deg);
+ }
+
+ .btn-toggle-nav a {
+ display: inline-flex;
+ padding: .1875rem .5rem;
+ margin-top: .125rem;
+ margin-left: 1.25rem;
+ text-decoration: none;
+ }
+ .btn-toggle-nav a:hover,
+ .btn-toggle-nav a:focus {
+ background-color: #d2f4ea;
+ }
+
+ .scrollarea {
+ overflow-y: auto;
+ }
+
+ .fw-semibold { font-weight: 600; }
+ .lh-tight { line-height: 1.25; }
+
+
+ .hidden{
+ display: none;
+ }
+
+ .pageC {
+ padding: 20px;
+ }
+
+
+placeholder {
+ border: red 2px dashed;
+ background-color: yellow;
+}
+
+pre {
+ overflow: auto;
+ word-wrap: normal;
+ white-space: pre;
+}
+
+.hidden {
+ display: none !important;
+}
+
+.trans {
+ transition: .5s
+}
+
+.helperTip {
+ opacity: 0.8;
+ font-size: small;
+}
\ No newline at end of file
diff --git a/static/css/smallerTextMod.css b/static/css/smallerTextMod.css
index 1b5f4ab..211158b 100644
--- a/static/css/smallerTextMod.css
+++ b/static/css/smallerTextMod.css
@@ -1,3 +1,3 @@
body {
- font-size:0.5em;
+ font-size:0.3em;
}
\ No newline at end of file
diff --git a/static/css/styles.css b/static/css/styles.css
index 5800c6c..953a446 100644
--- a/static/css/styles.css
+++ b/static/css/styles.css
@@ -103,4 +103,11 @@ html, body {
.blink {
animation:fade 1000ms infinite;
-webkit-animation:fade 1000ms infinite;
+}
+
+.connectionWarning{
+ background-color: red;
+ width: 100vw;
+ font-size: x-large;
+ font-family: sans-serif;
}
\ No newline at end of file
diff --git a/static/flatpickr/dist b/static/flatpickr/dist
new file mode 120000
index 0000000..9c148d9
--- /dev/null
+++ b/static/flatpickr/dist
@@ -0,0 +1 @@
+../../node_modules/flatpickr/dist/
\ No newline at end of file
diff --git a/static/js/cookie.js b/static/js/cookie.js
new file mode 120000
index 0000000..9097170
--- /dev/null
+++ b/static/js/cookie.js
@@ -0,0 +1 @@
+../../node_modules/js-cookie/dist/js.cookie.min.js
\ No newline at end of file
diff --git a/static/js/countdown.js b/static/js/countdown.js
deleted file mode 120000
index 71edd1e..0000000
--- a/static/js/countdown.js
+++ /dev/null
@@ -1 +0,0 @@
-../../node_modules/countdown/countdown.js
\ No newline at end of file
diff --git a/static/js/darkreader.js b/static/js/darkreader.js
new file mode 120000
index 0000000..f810896
--- /dev/null
+++ b/static/js/darkreader.js
@@ -0,0 +1 @@
+../../node_modules/darkreader/darkreader.js
\ No newline at end of file
diff --git a/static/js/interface.js b/static/js/interface.js
index 827a688..4822c9e 100644
--- a/static/js/interface.js
+++ b/static/js/interface.js
@@ -1,4 +1,529 @@
-function convertTimeOffset(){
+function convertTimeOffset() {
selTime = new Date().getTime() + document.getElementById('time2').valueAsNumber
document.getElementById("time").value = selTime
}
+
+
+function convertColorSegments(elementId) {
+ const raw = document.getElementById(elementId);
+ const segmentData = {}
+ for (elm in raw.children) {
+ if (raw.children[elm].nodeName == "TR") {
+ const child = raw.children[elm].children[1].children[0]
+ let timeVal = parseInt(raw.children[elm].children[0].children[0].value * 1000);
+ if (Number.isInteger(timeVal)) {
+ segmentData[timeVal] = child.style.color
+ } else {
+ segmentData["START"] = child.style.color
+ }
+ }
+ }
+ console.info(segmentData)
+ return (segmentData)
+}
+
+$(function () {
+ // $(".numVal").bind("DOMSubtreeModified", alert);
+
+ const modes = ["timer", "clock", "black", "test"]
+ let selectPresetTime = 0;
+
+ if (Cookies.get("interfaceColor") != undefined) {
+ const color = Cookies.get("interfaceColor");
+ $("#Mbtnradio" + (color))[0].checked = true
+ if (color == 1) {
+ DarkReader.disable()
+ } else if (color == 2) {
+ DarkReader.enable()
+ } else {
+ DarkReader.auto()
+ }
+ }
+
+ saveOption("/api/v1/system", function systemInfoLoader(event) {
+ const dataSystem = JSON.parse(event.target.response)
+ document.getElementById("nodejsVers").innerHTML = dataSystem.nodeVersion
+ document.getElementById("nodeSwVers").innerHTML = dataSystem.systemVersion
+
+ const tree2 = jsonview.create(dataSystem);
+ jsonview.render(tree2, document.getElementById("systemInfo"));
+ jsonview.expand(tree2);
+ })
+
+ $("#addRow").on("click", function (event) {
+ const tableEntryDom = document.getElementById("tableCopySource").cloneNode(true)
+ let temp = tableEntryDom.innerHTML
+ temp = temp.replace("#COLOR#", "gray");
+ temp = temp.replace("#bg-COLOR#", "gray");
+ temp = temp.replace("#VALUE#", 60); // BUG: Doesn't work but not too important
+ temp = temp.replace("timeValue-ID", Math.floor(Math.random() * 9999999))
+ tableEntryDom.innerHTML = temp;
+ tableEntryDom.firstChild.nextSibling.children[0].classList.add("timeDurPicker")
+ tableEntryDom.id = Math.floor(Math.random() * 9999999)
+ document.getElementById("colors1").appendChild(tableEntryDom)
+ $(".deleteRow1").on("click", function removeRowEntry(event) {
+ $(event.target).closest("tr").remove();
+ });
+ $('.timeDurPicker').durationPicker({
+ showSeconds: true,
+ showDays: false,
+ onChanged: function (newVal, test, val2) {
+ // $('#duration-label2').text(newVal);
+ val2.days[0].parentElement.parentElement.parentElement.parentElement.children[1].value = newVal
+ //console.log(val2.days[0].parentElement.parentElement.parentElement.parentElement.children[1].value)
+ //console.log(val2.days[0].parentElement.parentElement.parentElement.parentElement.children[1])
+ }
+ });
+ });
+
+ $("#addRow2").on("click", function (event) {
+ const tableEntryDom = document.getElementById("tableCopySource").cloneNode(true)
+ let temp = tableEntryDom.innerHTML
+ temp = temp.replace("#COLOR#", "gray");
+ temp = temp.replace("#bg-COLOR#", "gray");
+ temp = temp.replace("#VALUE#", 60); // BUG: Doesn't work but not too important
+ temp = temp.replace("timeValue-ID", Math.floor(Math.random() * 9999999))
+ tableEntryDom.innerHTML = temp;
+ tableEntryDom.firstChild.nextSibling.children[0].classList.add("timeDurPicker")
+ tableEntryDom.id = Math.floor(Math.random() * 9999999)
+ document.getElementById("colors2").appendChild(tableEntryDom)
+ $(".deleteRow1").on("click", function removeRowEntry(event) {
+ $(event.target).closest("tr").remove();
+ });
+ $('.timeDurPicker').durationPicker({
+ showSeconds: true,
+ showDays: false,
+ onChanged: function (newVal, test, val2) {
+ // $('#duration-label2').text(newVal);
+ val2.days[0].parentElement.parentElement.parentElement.parentElement.children[1].value = newVal
+ }
+ });
+ });
+
+
+
+ // Restore settings
+ saveOption("/api/v1/data", function (event, xmlHttp) {
+ const jsonResult = JSON.parse(xmlHttp.response)
+ const tree = jsonview.create(jsonResult);
+ jsonview.render(tree, document.getElementById("responeSnippet"));
+ jsonview.expand(tree);
+
+ // Restore mode radio
+ const currentModeInt = modes.indexOf(jsonResult.mode);
+ $("#btnradio" + (currentModeInt + 1))[0].checked = true
+
+ // Restore layout settings
+ $("#showTime")[0].checked = jsonResult.showTimeOnCountdown;
+ $("#showMillis")[0].checked = jsonResult.showMilliSeconds;
+ $("#progBarShow")[0].checked = jsonResult.showProgressbar;
+ $("#textColors")[0].checked = jsonResult.enableColoredText;
+ console.log(document.getElementById("tableCopySource"))
+
+ let tableEntryDom = document.getElementById("tableCopySource").cloneNode(true)
+ let currIndex = 0
+ for (item in jsonResult.colorSegments) {
+ tableEntryDom = document.getElementById("tableCopySource").cloneNode(true)
+ let temp = tableEntryDom.innerHTML
+ temp = temp.replace("#COLOR#", jsonResult.colorSegments[item]);
+ temp = temp.replace("#bg-COLOR#", jsonResult.colorSegments[item]);
+ temp = temp.replace("timeValue-ID", "timeValue-1C" + currIndex)
+
+ if (item != "START") {
+ temp = temp.replace("#VALUE#", item / 1000);
+ tableEntryDom.innerHTML = temp;
+ tableEntryDom.firstChild.nextSibling.children[0].classList.add("timeDurPicker")
+ } else {
+ tableEntryDom.innerHTML = temp;
+ tableEntryDom.children[2].children[0].children[0].disabled = true;
+ tableEntryDom.children[2].children[0].setAttribute("data-toggle", "tooltip")
+ tableEntryDom.children[2].children[0].setAttribute("data-placement", "right")// 'data-placement="right" title="Tooltip on right"'
+ tableEntryDom.children[2].children[0].setAttribute("title", "You cannot delete the start time")
+
+ tableEntryDom.children[0].innerHTML = ' Start'
+ }
+ tableEntryDom.id = "1C" + currIndex
+ tableEntryDom.style.display = "table-row"
+ document.getElementById("colors1").appendChild(tableEntryDom)
+ currIndex++;
+ }
+
+
+ // Text colors
+ currIndex = 0
+ for (item in jsonResult.textColors) {
+ tableEntryDom = document.getElementById("tableCopySource").cloneNode(true)
+ let temp = tableEntryDom.innerHTML
+ temp = temp.replace("#COLOR#", jsonResult.textColors[item]);
+ temp = temp.replace("#bg-COLOR#", jsonResult.textColors[item]);
+ temp = temp.replace("timeValue-ID", "timeValue-1C" + currIndex)
+
+ if (item != "START") {
+ temp = temp.replace("#VALUE#", item / 1000);
+ tableEntryDom.innerHTML = temp;
+ tableEntryDom.firstChild.nextSibling.children[0].classList.add("timeDurPicker")
+ } else {
+ tableEntryDom.innerHTML = temp;
+ tableEntryDom.children[2].children[0].children[0].disabled = true;
+ tableEntryDom.children[2].children[0].setAttribute("data-toggle", "tooltip")
+ tableEntryDom.children[2].children[0].setAttribute("data-placement", "right")// 'data-placement="right" title="Tooltip on right"'
+ tableEntryDom.children[2].children[0].setAttribute("title", "You cannot delete the start time")
+
+ tableEntryDom.children[0].innerHTML = ' Start'
+ }
+
+
+ // timeDurPicker
+ tableEntryDom.id = "1C" + currIndex
+ tableEntryDom.style.display = "table-row"
+ document.getElementById("colors2").appendChild(tableEntryDom)
+ currIndex++;
+ }
+
+
+ $('.timeDurPicker').durationPicker({
+ showSeconds: true,
+ showDays: false,
+ onChanged: function (newVal, test, val2) {
+ val2.days[0].parentElement.parentElement.parentElement.parentElement.children[1].value = newVal
+ }
+ });
+
+
+
+ //console.debug(jsonResult, currentModeInt)
+ $('.colorPicky').on('colorpickerChange', function (event) {
+ event.target.parentElement.style.backgroundColor = event.target.value
+ });
+
+ $(".deleteRow1").on("click", function removeRowEntry(event) {
+ $(event.target).closest("tr").remove();
+ });
+ $('[data-toggle="tooltip"]').tooltip({ container: "body" })
+ })
+
+ $("#copyColors").click(function CopyTextColors(event) {
+ event.target.innerHTML = '
'
+ saveOption("/api/v1/set/text/colors?copy=true", function finishCopyColors(event) {
+ setTimeout(function () {
+ document.getElementById("copyColors").innerHTML = "Copy from progressbar colors"
+ }, 500)
+
+ })
+ });
+
+
+ $("input[name='btnradio2']").click(function (event) {
+ const darkid = parseInt(event.currentTarget.id.replace("Mbtnradio", ""))
+ if (darkid == 1) {
+ DarkReader.disable()
+ } else if (darkid == 2) {
+ DarkReader.enable()
+ } else {
+ DarkReader.auto()
+ }
+ Cookies.set("interfaceColor", darkid)
+ });
+
+ // Presets
+ $(".pres").click(function (event) {
+ currentTime = parseInt(event.currentTarget.value)
+ $("#customValue").data("durationPicker").setValue(currentTime / 1000)
+ })
+
+
+ $(".goTimer").on("click", function (event) {
+ event.currentTarget.innerHTML = '
'
+ setTimeout(function () {
+ event.currentTarget.innerHTML = 'Go'
+ }, 200);
+
+ saveOption("/api/v1/set/addMillisToTimer?time=" + currentTime, function (ev) {
+ })
+ })
+
+ // Layout settings
+ $("#applyLayout").click(function (event) {
+ $("#applyLayout")[0].innerHTML = '
'
+
+ // Collect all data, build all paths
+ const allPathes = [];
+
+ const showTimeB = $("#showTime")[0].checked
+ const showMillisB = $("#showMillis")[0].checked
+ const progBarShowB = $("#progBarShow")[0].checked
+ const textColorsB = $("#textColors")[0].checked
+
+ const colors = convertColorSegments("colors1")
+ const colors2 = convertColorSegments("colors2")
+
+ allPathes.push("/api/v1/set/layout/showTime?show=" + showTimeB)
+ allPathes.push("/api/v1/set/layout/showMillis?show=" + showMillisB)
+ allPathes.push("/api/v1/set/progressbar/show?show=" + progBarShowB)
+ allPathes.push("/api/v1/set/text/enableColoring?enable=" + textColorsB)
+ allPathes.push("/api/v1/set/progressbar/colors?isBase64=true&colors=" + btoa(JSON.stringify(colors)))
+ allPathes.push("/api/v1/set/text/colors?isBase64=true&colors=" + btoa(JSON.stringify(colors2)))
+
+
+ for (pI in allPathes) {
+ const path = allPathes[pI];
+ saveOption(path, function (event) {
+ console.debug(event)
+ })
+ }
+
+ setTimeout(function () {
+ $("#applyLayout")[0].innerHTML = 'Apply settings'
+ }, 500)
+ })
+
+
+ $("#saveLayout").click(function (event) {
+ $("#saveLayout")[0].innerHTML = '
'
+
+ // Collect all data, build all paths3
+ const allPathes = [];
+
+ const showTimeB = $("#showTime")[0].checked
+ const showMillisB = $("#showMillis")[0].checked
+ const progBarShowB = $("#progBarShow")[0].checked
+ const textColorsB = $("#textColors")[0].checked
+
+ allPathes.push("/api/v1/set/layout/showTime?persist=true&show=" + showTimeB)
+ allPathes.push("/api/v1/set/layout/showMillis?persist=true&show=" + showMillisB)
+ allPathes.push("/api/v1/set/progressbar/show?persist=true&show=" + progBarShowB)
+ allPathes.push("/api/v1/set/text/enableColoring?persist=true&enable=" + textColorsB)
+
+ for (pI in allPathes) {
+ const path = allPathes[pI];
+ saveOption(path, function (event) {
+ console.debug(event)
+ })
+ }
+
+ saveOption("/api/v1/storage/commit", function (event) {
+ console.debug(event)
+ setTimeout(function () {
+ $("#saveLayout")[0].innerHTML = 'Save as startup settings (Layout only)'
+ }, 500)
+ })
+
+
+
+ })
+
+
+ function msToTime(s, data) {
+ var ms = s % 1000;
+ s = (s - ms) / 1000;
+ var secs = s % 60;
+ s = (s - secs) / 60;
+ var mins = s % 60;
+ var hrs = (s - mins) / 60;
+ let out = ""
+
+ return [ms, secs, mins, hrs];
+ }
+
+ // Timer custom
+ let currentTime = 0;
+ $("#timerHourInc").click(function (event) {
+ currentTime += 3600000
+ const times = msToTime(currentTime)
+ $("#timerHoursV")[0].innerHTML = times[3];
+ $("#timerMinuteV")[0].innerHTML = times[2];
+ $("#timerSecondsV")[0].innerHTML = times[1];
+ })
+
+ $("#timerHourDec").click(function (event) {
+ if (currentTime >= 3600000) {
+ currentTime -= 3600000
+ const times = msToTime(currentTime)
+ $("#timerHoursV")[0].innerHTML = times[3];
+ $("#timerMinuteV")[0].innerHTML = times[2];
+ $("#timerSecondsV")[0].innerHTML = times[1];
+ }
+ })
+
+ $("#timerMinuteInc").click(function (event) {
+ currentTime += 60000
+ const times = msToTime(currentTime)
+ $("#timerHoursV")[0].innerHTML = times[3];
+ $("#timerMinuteV")[0].innerHTML = times[2];
+ $("#timerSecondsV")[0].innerHTML = times[1];
+ })
+ $("#timerMinuteDec").click(function (event) {
+ if (currentTime >= 60000) {
+ currentTime -= 60000
+ const times = msToTime(currentTime)
+ $("#timerHoursV")[0].innerHTML = times[3];
+ $("#timerMinuteV")[0].innerHTML = times[2];
+ $("#timerSecondsV")[0].innerHTML = times[1];
+ }
+ })
+ $("#timerSecondsInc").click(function (event) {
+ currentTime += 1000
+ const times = msToTime(currentTime)
+ $("#timerHoursV")[0].innerHTML = times[3];
+ $("#timerMinuteV")[0].innerHTML = times[2];
+ $("#timerSecondsV")[0].innerHTML = times[1];
+ })
+ $("#timerSecondsDec").click(function (event) {
+ if (currentTime >= 1000) {
+ currentTime -= 1000
+ const times = msToTime(currentTime)
+ $("#timerHoursV")[0].innerHTML = times[3];
+ $("#timerMinuteV")[0].innerHTML = times[2];
+ $("#timerSecondsV")[0].innerHTML = times[1];
+ }
+ })
+
+ $("input[name='btnradio']").click(function (event) {
+ $("#sendMessage")[0].innerHTML = '
'
+ let value = modes[parseInt(event.currentTarget.id.replace("btnradio", "")) - 1]
+ console.log(value, parseInt(event.currentTarget.id.replace("btnradio", "")))
+ saveOption("/api/v1/set/mode?mode=" + value, function (event) {
+ setTimeout(function () {
+ $("#sendMessage")[0].innerHTML = ' '
+ }, 200)
+
+ })
+ })
+
+
+ $("#sendMessage").click(function (event) {
+ $("#sendMessage")[0].innerHTML = '
'
+ let value = $("#messageContent").val()
+ saveOption("/api/v1/ctrl/message/show?msg=" + value, function (event) {
+ setTimeout(function () {
+ $("#sendMessage")[0].innerHTML = ' '
+ }, 200)
+
+ })
+ })
+
+ $("#ctrlRemoveMessage").click(function (event) {
+ $("#ctrlRemoveMessage")[0].innerHTML = '
'
+ saveOption("/api/v1/ctrl/message/hide", function (event) {
+ setTimeout(function () {
+ $("#ctrlRemoveMessage")[0].innerHTML = ' '
+ }, 200)
+
+ })
+ })
+
+ $("#funcPlay").click(function (event) {
+ $("#funcPlay")[0].innerHTML = '
'
+ saveOption("/api/v1/ctrl/timer/play", function (event) {
+ setTimeout(function () {
+ $("#funcPlay")[0].innerHTML = ' '
+ }, 200);
+ })
+ })
+
+
+ $("#funcPause").click(function (event) {
+ $("#funcPause")[0].innerHTML = '
'
+
+ saveOption("/api/v1/ctrl/timer/pause", function (event) {
+ setTimeout(function () {
+ $("#funcPause")[0].innerHTML = ' '
+ }, 200);
+ })
+ })
+
+ $("#funcRestart").click(function (event) {
+ $("#funcRestart")[0].innerHTML = '
'
+ saveOption("/api/v1/ctrl/timer/restart", function (event) {
+ setTimeout(function () {
+ $("#funcRestart")[0].innerHTML = ' '
+ }, 200)
+ })
+ })
+
+ $("#applyDebug").click(function (event) {
+ $("#applyDebug")[0].innerHTML = '
'
+ let value = $("#debugModeEnable")[0].checked
+ saveOption("/api/v1/debug?enable=" + value, function (event) {
+ setTimeout(function () {
+ $("#applyDebug")[0].innerHTML = "Apply settings"
+ }, 200)
+
+ })
+ })
+
+ $("a.nav-link").click(function (event) {
+ event.preventDefault();
+ $("a.nav-link").removeClass("active")
+
+ event.currentTarget.classList.add("active")
+
+ $(".pageC").addClass("hidden")
+ $("#" + event.target.href.split("#")[1]).removeClass("hidden")
+ // console.log(event.target.href.split("#")[1])
+ });
+ $("#customValue").durationPicker({
+ showSeconds: true,
+ showDays: false,
+ onChanged: function (newVal, test, val2) {
+ currentTime = newVal * 1000
+ }
+ })
+
+ flatty = flatpickr("#datetimetester", {
+ enableTime: true,
+ time_24hr: true,
+ dateFormat: "H:i d.m.Y",
+ });
+
+ $(".goTimeGoalCountdown").on("click", function handleCountdownToTime() {
+ const selectTime = flatty.selectedDates[0].getTime()
+ const timeDiff = selectTime - new Date().getTime()
+ $(".goTimeGoalCountdown")[0].innerHTML = '
'
+ saveOption("/api/v1/set/addMillisToTimer?time=" + timeDiff, function (ev) {
+ setTimeout(function () {
+ $(".goTimeGoalCountdown")[0].innerHTML = ' '
+ }, 200);
+ })
+ })
+});
+
+function saveOption(path, callback) {
+ var xmlHttp = new XMLHttpRequest();
+ xmlHttp.open("GET", path, true); // false for synchronous request
+ xmlHttp.send(null);
+ xmlHttp.onerror = function (e) {
+ console.log(e); // ToDo: Popup, etc.
+ };
+ xmlHttp.onloadend = function (event) {
+ callback(event, xmlHttp)
+ }
+}
+
+navStatus = true
+function openNav() {
+ document.getElementById("navbarToggleExternalContent").style.width = "250px";
+ document.getElementById("navbarToggleExternalContent").style.opacity = "1";
+ document.getElementById("navbarToggleExternalContent").style.display = "block";
+ document.getElementById("navbarToggleExternalContent").style.zIndex = 999999;
+ document.getElementById("pageCont").style.marginLeft = "0px";
+ navStatus = true
+}
+
+function closeNav() {
+ document.getElementById("navbarToggleExternalContent").style.width = "0px";
+ document.getElementById("navbarToggleExternalContent").style.opacity = "0";
+ document.getElementById("navbarToggleExternalContent").style.display = "none";
+ document.getElementById("navbarToggleExternalContent").style.zIndex = -999999;
+ document.getElementById("pageCont").style.marginLeft = "0";
+ navStatus = false
+}
+
+function toogleNav() {
+ if (navStatus) {
+ closeNav()
+ } else {
+ openNav()
+ }
+
+}
\ No newline at end of file
diff --git a/static/js/jquery.min.js b/static/js/jquery.min.js
new file mode 120000
index 0000000..08ac9f2
--- /dev/null
+++ b/static/js/jquery.min.js
@@ -0,0 +1 @@
+../../node_modules/jquery/dist/jquery.min.js
\ No newline at end of file
diff --git a/static/js/jsonview.js b/static/js/jsonview.js
new file mode 100644
index 0000000..1ac71b4
--- /dev/null
+++ b/static/js/jsonview.js
@@ -0,0 +1 @@
+!function(e,n){"object"==typeof exports&&"object"==typeof module?module.exports=n():"function"==typeof define&&define.amd?define([],n):"object"==typeof exports?exports.jsonview=n():e.jsonview=n()}(self,(function(){return(()=>{"use strict";var e={767:(e,n,t)=>{t.d(n,{Z:()=>s});var r=t(81),o=t.n(r),i=t(645),a=t.n(i)()(o());a.push([e.id,'.json-container{font-family:"Open Sans";font-size:16px;background-color:#fff;color:gray;box-sizing:border-box}.json-container .line{margin:4px 0;display:flex;justify-content:flex-start}.json-container .caret-icon{width:18px;text-align:center;cursor:pointer}.json-container .empty-icon{width:18px}.json-container .json-type{margin-right:4px;margin-left:4px}.json-container .json-key{color:#444;margin-right:4px;margin-left:4px}.json-container .json-index{margin-right:4px;margin-left:4px}.json-container .json-value{margin-left:8px}.json-container .json-number{color:#f9ae58}.json-container .json-boolean{color:#ec5f66}.json-container .json-string{color:#86b25c}.json-container .json-size{margin-right:4px;margin-left:4px}.json-container .hidden{display:none}.json-container .fas{display:inline-block;border-style:solid;width:0;height:0}.json-container .fa-caret-down{border-width:6px 5px 0 5px;border-color:gray transparent}.json-container .fa-caret-right{border-width:5px 0 5px 6px;border-color:transparent transparent transparent gray}',""]);const s=a},645:e=>{e.exports=function(e){var n=[];return n.toString=function(){return this.map((function(n){var t="",r=void 0!==n[5];return n[4]&&(t+="@supports (".concat(n[4],") {")),n[2]&&(t+="@media ".concat(n[2]," {")),r&&(t+="@layer".concat(n[5].length>0?" ".concat(n[5]):""," {")),t+=e(n),r&&(t+="}"),n[2]&&(t+="}"),n[4]&&(t+="}"),t})).join("")},n.i=function(e,t,r,o,i){"string"==typeof e&&(e=[[null,e,void 0]]);var a={};if(r)for(var s=0;s0?" ".concat(d[5]):""," {").concat(d[1],"}")),d[5]=i),t&&(d[2]?(d[1]="@media ".concat(d[2]," {").concat(d[1],"}"),d[2]=t):d[2]=t),o&&(d[4]?(d[1]="@supports (".concat(d[4],") {").concat(d[1],"}"),d[4]=o):d[4]="".concat(o)),n.push(d))}},n}},81:e=>{e.exports=function(e){return e[1]}},379:e=>{var n=[];function t(e){for(var t=-1,r=0;r{var n={};e.exports=function(e,t){var r=function(e){if(void 0===n[e]){var t=document.querySelector(e);if(window.HTMLIFrameElement&&t instanceof window.HTMLIFrameElement)try{t=t.contentDocument.head}catch(e){t=null}n[e]=t}return n[e]}(e);if(!r)throw new Error("Couldn't find a style target. This probably means that the value for the 'insert' parameter is invalid.");r.appendChild(t)}},216:e=>{e.exports=function(e){var n=document.createElement("style");return e.setAttributes(n,e.attributes),e.insert(n,e.options),n}},565:(e,n,t)=>{e.exports=function(e){var n=t.nc;n&&e.setAttribute("nonce",n)}},795:e=>{e.exports=function(e){var n=e.insertStyleElement(e);return{update:function(t){!function(e,n,t){var r="";t.supports&&(r+="@supports (".concat(t.supports,") {")),t.media&&(r+="@media ".concat(t.media," {"));var o=void 0!==t.layer;o&&(r+="@layer".concat(t.layer.length>0?" ".concat(t.layer):""," {")),r+=t.css,o&&(r+="}"),t.media&&(r+="}"),t.supports&&(r+="}");var i=t.sourceMap;i&&"undefined"!=typeof btoa&&(r+="\n/*# sourceMappingURL=data:application/json;base64,".concat(btoa(unescape(encodeURIComponent(JSON.stringify(i))))," */")),n.styleTagTransform(r,e,n.options)}(n,e,t)},remove:function(){!function(e){if(null===e.parentNode)return!1;e.parentNode.removeChild(e)}(n)}}}},589:e=>{e.exports=function(e,n){if(n.styleSheet)n.styleSheet.cssText=e;else{for(;n.firstChild;)n.removeChild(n.firstChild);n.appendChild(document.createTextNode(e))}}}},n={};function t(r){var o=n[r];if(void 0!==o)return o.exports;var i=n[r]={id:r,exports:{}};return e[r](i,i.exports,t),i.exports}t.n=e=>{var n=e&&e.__esModule?()=>e.default:()=>e;return t.d(n,{a:n}),n},t.d=(e,n)=>{for(var r in n)t.o(n,r)&&!t.o(e,r)&&Object.defineProperty(e,r,{enumerable:!0,get:n[r]})},t.o=(e,n)=>Object.prototype.hasOwnProperty.call(e,n),t.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})};var r={};return(()=>{t.r(r),t.d(r,{collapse:()=>$,create:()=>O,default:()=>I,destroy:()=>z,expand:()=>P,render:()=>A,renderJSON:()=>N});var e=t(379),n=t.n(e),o=t(795),i=t.n(o),a=t(569),s=t.n(a),c=t(565),l=t.n(c),d=t(216),p=t.n(d),u=t(589),f=t.n(u),v=t(767),y={};function h(e){return Array.isArray(e)?"array":null===e?"null":typeof e}function m(e){return document.createElement(e)}y.styleTagTransform=f(),y.setAttributes=l(),y.insert=s().bind(null,"head"),y.domAPI=i(),y.insertStyleElement=p(),n()(v.Z,y),v.Z&&v.Z.locals&&v.Z.locals;const x="hidden",g="fa-caret-right",j="fa-caret-down";function b(e){e.children.forEach((e=>{e.el.classList.add(x),e.isExpanded&&b(e)}))}function E(e){e.children.forEach((e=>{e.el.classList.remove(x),e.isExpanded&&E(e)}))}function S(e){if(e.children.length>0){const n=e.el.querySelector(".fas");n&&n.classList.replace(g,j)}}function k(e){if(e.children.length>0){const n=e.el.querySelector(".fas");n&&n.classList.replace(j,g)}}function w(e){e.isExpanded?(e.isExpanded=!1,k(e),b(e)):(e.isExpanded=!0,S(e),E(e))}function L(e,n){n(e),e.children.length>0&&e.children.forEach((e=>{L(e,n)}))}function T(e={}){return{key:e.key||null,parent:e.parent||null,value:e.hasOwnProperty("value")?e.value:null,isExpanded:e.isExpanded||!1,type:e.type||null,children:e.children||[],el:e.el||null,depth:e.depth||0,dispose:null}}function M(e,n){if("object"==typeof e)for(let t in e){const r=T({value:e[t],key:t,depth:n.depth+1,type:h(e[t]),parent:n});n.children.push(r),M(e[t],r)}}function C(e){return"string"==typeof e?JSON.parse(e):e}function O(e){const n=C(e),t=T({value:n,key:h(n),type:h(n)});return M(n,t),t}function N(e,n){const t=C(e),r=createTree(t);return A(r,n),r}function A(e,n){const t=function(){const e=m("div");return e.className="json-container",e}();L(e,(function(e){e.el=function(e){let n=m("div");const t=e=>{const n=e.children.length;return"array"===e.type?`[${n}]`:"object"===e.type?`{${n}}`:null};if(e.children.length>0){n.innerHTML=function(e={}){const{key:n,size:t}=e;return`\n \n `}({key:e.key,size:t(e)});const r=n.querySelector(".caret-icon");e.dispose=function(e,n,t){return e.addEventListener(n,t),()=>e.removeEventListener(n,t)}(r,"click",(()=>w(e)))}else n.innerHTML=function(e={}){const{key:n,value:t,type:r}=e;return`\n \n `}({key:e.key,value:e.value,type:typeof e.value});const r=n.children[0];return null!==e.parent&&r.classList.add(x),r.style="margin-left: "+18*e.depth+"px;",r}(e),t.appendChild(e.el)})),n.appendChild(t)}function P(e){L(e,(function(e){e.el.classList.remove(x),e.isExpanded=!0,S(e)}))}function $(e){L(e,(function(n){n.isExpanded=!1,n.depth>e.depth&&n.el.classList.add(x),k(n)}))}function z(e){var n;L(e,(e=>{e.dispose&&e.dispose()})),(n=e.el.parentNode).parentNode.removeChild(n)}const I={render:A,create:O,renderJSON:N,expand:P,collapse:$,traverse:L,destroy:z}})(),r})()}));
\ No newline at end of file
diff --git a/static/js/less.min.js b/static/js/less.min.js
new file mode 120000
index 0000000..9ac4459
--- /dev/null
+++ b/static/js/less.min.js
@@ -0,0 +1 @@
+../../node_modules/less/dist/less.min.js
\ No newline at end of file
diff --git a/static/js/reconnecting-websocket.min.js b/static/js/reconnecting-websocket.min.js
new file mode 100644
index 0000000..3015099
--- /dev/null
+++ b/static/js/reconnecting-websocket.min.js
@@ -0,0 +1 @@
+!function(a,b){"function"==typeof define&&define.amd?define([],b):"undefined"!=typeof module&&module.exports?module.exports=b():a.ReconnectingWebSocket=b()}(this,function(){function a(b,c,d){function l(a,b){var c=document.createEvent("CustomEvent");return c.initCustomEvent(a,!1,!1,b),c}var e={debug:!1,automaticOpen:!0,reconnectInterval:1e3,maxReconnectInterval:3e4,reconnectDecay:1.5,timeoutInterval:2e3};d||(d={});for(var f in e)this[f]="undefined"!=typeof d[f]?d[f]:e[f];this.url=b,this.reconnectAttempts=0,this.readyState=WebSocket.CONNECTING,this.protocol=null;var h,g=this,i=!1,j=!1,k=document.createElement("div");k.addEventListener("open",function(a){g.onopen(a)}),k.addEventListener("close",function(a){g.onclose(a)}),k.addEventListener("connecting",function(a){g.onconnecting(a)}),k.addEventListener("message",function(a){g.onmessage(a)}),k.addEventListener("error",function(a){g.onerror(a)}),this.addEventListener=k.addEventListener.bind(k),this.removeEventListener=k.removeEventListener.bind(k),this.dispatchEvent=k.dispatchEvent.bind(k),this.open=function(b){h=new WebSocket(g.url,c||[]),b||k.dispatchEvent(l("connecting")),(g.debug||a.debugAll)&&console.debug("ReconnectingWebSocket","attempt-connect",g.url);var d=h,e=setTimeout(function(){(g.debug||a.debugAll)&&console.debug("ReconnectingWebSocket","connection-timeout",g.url),j=!0,d.close(),j=!1},g.timeoutInterval);h.onopen=function(){clearTimeout(e),(g.debug||a.debugAll)&&console.debug("ReconnectingWebSocket","onopen",g.url),g.protocol=h.protocol,g.readyState=WebSocket.OPEN,g.reconnectAttempts=0;var d=l("open");d.isReconnect=b,b=!1,k.dispatchEvent(d)},h.onclose=function(c){if(clearTimeout(e),h=null,i)g.readyState=WebSocket.CLOSED,k.dispatchEvent(l("close"));else{g.readyState=WebSocket.CONNECTING;var d=l("connecting");d.code=c.code,d.reason=c.reason,d.wasClean=c.wasClean,k.dispatchEvent(d),b||j||((g.debug||a.debugAll)&&console.debug("ReconnectingWebSocket","onclose",g.url),k.dispatchEvent(l("close")));var e=g.reconnectInterval*Math.pow(g.reconnectDecay,g.reconnectAttempts);setTimeout(function(){g.reconnectAttempts++,g.open(!0)},e>g.maxReconnectInterval?g.maxReconnectInterval:e)}},h.onmessage=function(b){(g.debug||a.debugAll)&&console.debug("ReconnectingWebSocket","onmessage",g.url,b.data);var c=l("message");c.data=b.data,k.dispatchEvent(c)},h.onerror=function(b){(g.debug||a.debugAll)&&console.debug("ReconnectingWebSocket","onerror",g.url,b),k.dispatchEvent(l("error"))}},1==this.automaticOpen&&this.open(!1),this.send=function(b){if(h)return(g.debug||a.debugAll)&&console.debug("ReconnectingWebSocket","send",g.url,b),h.send(b);throw"INVALID_STATE_ERR : Pausing to reconnect websocket"},this.close=function(a,b){"undefined"==typeof a&&(a=1e3),i=!0,h&&h.close(a,b)},this.refresh=function(){h&&h.close()}}return a.prototype.onopen=function(){},a.prototype.onclose=function(){},a.prototype.onconnecting=function(){},a.prototype.onmessage=function(){},a.prototype.onerror=function(){},a.debugAll=!1,a.CONNECTING=WebSocket.CONNECTING,a.OPEN=WebSocket.OPEN,a.CLOSING=WebSocket.CLOSING,a.CLOSED=WebSocket.CLOSED,a});
diff --git a/static/js/script.js b/static/js/script.js
index 88211bb..fd06ada 100644
--- a/static/js/script.js
+++ b/static/js/script.js
@@ -1,14 +1,68 @@
var newDateObj = new Date();
newDateObj = new Date(newDateObj.getTime() + 1000 * 20)
+backReqInt = 0;
+websocketFailed = false
+recoveryAttempts = 0;
+
+let socket = new ReconnectingWebSocket("ws://localhost:" + location.port);
+let ackdSessionToken = false
+let isFirstPacket = true
+
+let lastTime = "00:00:00";
+let timerCountdownFirst = true;
+
+socket.onopen = function (e) {
+ // alert("[open] Connection established");
+ //alert("Sending to server");
+ socket.send("new client");
+};
+
+socket.onmessage = function (event) {
+ // alert(`[message] Data received from server: ${event.data}`);
+ let inData = JSON.parse(event.data)
+ if (isFirstPacket) {
+ isFirstPacket = false
+ dataFame = JSON.parse(event.data);
+ timeDiff = new Date().getTime() - dataFame.srvTime
+ } else {
+ if (inData.sessionToken == dataFame.sessionToken) {
+ dataFame = JSON.parse(event.data);
+ timeDiff = new Date().getTime() - dataFame.srvTime
+ } else {
+ if (ackdSessionToken == false) {
+
+ ackdSessionToken = true
+
+ if (confirm("Session token mismatch, reload the page?")) {
+ location.reload();
+ }
+ }
+ }
+ }
+
+};
+
+socket.onclose = function (event) {
+ if (event.wasClean) {
+ console.log(`[close] Connection closed cleanly, code=${event.code} reason=${event.reason}`);
+ } else {
+ // e.g. server process killed or network down
+ // event.code is usually 1006 in this case
+ console.error('[close] Connection died');
+ }
+};
+
allowFullscreen = true
+let dataFame = {}
+let timeDiff = 0
function enterFullscreen(element) {
if (element.requestFullscreen) {
element.requestFullscreen();
- } else if (element.msRequestFullscreen) { // for IE11 (remove June 15, 2022)
+ } else if (element.msRequestFullscreen) {
element.msRequestFullscreen();
- } else if (element.webkitRequestFullscreen) { // iOS Safari
+ } else if (element.webkitRequestFullscreen) {
element.webkitRequestFullscreen();
}
}
@@ -28,7 +82,6 @@ function updateFullscreen() {
}
-
function msToTime(s, data) {
isSmallerThenZero = false
if (s < 0) {
@@ -69,93 +122,136 @@ function findProgessColor(colors, value) {
return (resColor)
}
-function handleUpdate() {
+function requestBackend() {
resp = httpGet("/api/v1/data");
-
resp.onloadend = function (e) {
- if(resp.status == 200){
+ if (resp.status == 200) {
resp = resp.responseText;
var data = JSON.parse(resp);
- document.getElementById("incomeData").innerHTML = JSON.stringify(data)
- document.getElementById("timediff").innerHTML = new Date().getTime() - data.srvTime;
- if(data.debug){
- document.getElementById("timediff").style.display = "block";
- }else{
- document.getElementById("timediff").style.display = "none";
- }
-
- if (data.defaultFullScreen && document.getElementById("initalDate").innerHTML.includes("true") && allowFullscreen) {
- enterFullscreen(document.documentElement);
- document.getElementById("initalDate").innerHTML = "false"
- }
-
- if (data.showMessage) {
- document.getElementById("overlay").style.display = "block";
- document.getElementById("text").innerHTML = data.message
- } else {
- off()
- }
-
- if (new Date().getTime() - data.messageAppearTime < 5000) {
- if (!document.getElementById("text").classList.contains('blink')) {
- document.getElementById("text").classList.add("blink")
- }
- } else {
- if (document.getElementById("text").classList.contains('blink')) {
- document.getElementById("text").classList.remove("blink")
- }
- }
-
-
- if (data.mode == "clock") {
- document.getElementById("timer").innerHTML = getTime();
- document.getElementById("testImg").style.display = "none";
- document.getElementById("wholeProgBar").style.display = "none";
-
- } else if (data.mode == "timer") {
-
- document.getElementById("wholeProgBar").style.display = "block";
-
- if (data.timerRunState) {
- const now = new Date()
- const diff = data.countdownGoal - now.getTime()
- document.getElementById("timer").innerHTML = msToTime(diff, data);
- if (diff > 0) {
- document.getElementById("progBar").style.width = percentage(diff, data.timeAmountInital) + "%";
- } else {
- document.getElementById("progBar").style.width = "0%";
- }
-
- document.getElementById("progBar").style.backgroundColor = findProgessColor(data.colorSegments, diff)
- document.getElementById("testImg").style.display = "none";
- if (data.enableColoredText) {
- document.getElementById("timer").style.color = findProgessColor(data.textColors, diff)
- } else {
- document.getElementById("timer").style.color = "white"
- }
-
- }
- if (data.showTimeOnCountdown) {
- document.getElementById("clockSec").innerHTML = getTime();
- } else {
- document.getElementById("clockSec").innerHTML = "";
- }
-
- } else if (data.mode == "black") {
- document.getElementById("timer").innerHTML = "";
- document.getElementById("testImg").style.display = "none";
- document.getElementById("wholeProgBar").style.display = "none";
-
- } else if (data.mode == "test") {
- document.getElementById("timer").innerHTML = "";
- document.getElementById("testImg").style.display = "block";
- document.getElementById("progBar").style.display = "none";
- }
+ timeDiff = new Date().getTime() - data.srvTime
+ dataFame = data;
+ }
+ }
+}
+
+let isSlowed = false
+
+function handleRecovery() {
+ var img = document.body.appendChild(document.createElement("img"));
+ img.onload = function () {
+ location.reload();
+ };
+ img.src = "SMPTE_Color_Bars.svg";
+}
+
+let recoInter = -1
+
+function handleUpdate() {
+ var data = dataFame;
+ document.getElementById("incomeData").innerHTML = JSON.stringify(data)
+ document.getElementById("timediff").innerHTML = timeDiff + " " + String(new Date().getTime() - data.srvTime);
+
+ if (data.debug) {
+ document.getElementById("timediff").style.display = "block";
+ } else {
+ document.getElementById("timediff").style.display = "none";
+ }
+
+ if (data.defaultFullScreen && document.getElementById("initalDate").innerHTML.includes("true") && allowFullscreen) {
+ enterFullscreen(document.documentElement);
+ document.getElementById("initalDate").innerHTML = "false"
+ }
+
+ if (data.showMessage) {
+ document.getElementById("overlay").style.display = "block";
+ document.getElementById("text").innerHTML = data.message
+ } else {
+ document.getElementById("overlay").style.display = "none";
+ }
+
+ if (data.showTimeOnCountdown && data.mode == "timer") {
+ document.getElementById("clockSec").innerHTML = getTime();
+ } else {
+ document.getElementById("clockSec").innerHTML = "";
+ }
+
+ if (new Date().getTime() - data.messageAppearTime < 5000) {
+ if (!document.getElementById("text").classList.contains('blink')) {
+ document.getElementById("text").classList.add("blink")
+ }
+ } else {
+ if (document.getElementById("text").classList.contains('blink')) {
+ document.getElementById("text").classList.remove("blink")
}
-
}
+ if (data.mode == "clock") {
+ document.getElementById("timer").innerHTML = getTime();
+ document.getElementById("testImg").style.display = "none";
+ document.getElementById("wholeProgBar").style.display = "none";
+ document.getElementById("clockSec").innerHTML = "";
+ document.getElementById("timer").style.color = "white"
+ timerCountdownFirst = true;
+
+ } else if (data.mode == "timer") {
+ document.getElementById("wholeProgBar").style.display = "block";
+ const now = new Date()
+
+ if(timerCountdownFirst){
+ const diff = data.countdownGoal - now.getTime()
+ timerCountdownFirst = false
+ document.getElementById("timer").innerHTML = msToTime(diff, data);
+ if (diff > 0) {
+ document.getElementById("progBar").style.width = percentage(diff, data.timeAmountInital) + "%";
+ } else {
+ document.getElementById("progBar").style.width = "0%";
+ }
+
+ document.getElementById("progBar").style.backgroundColor = findProgessColor(data.colorSegments, diff)
+ document.getElementById("testImg").style.display = "none";
+ if (data.enableColoredText) {
+ document.getElementById("timer").style.color = findProgessColor(data.textColors, diff)
+ } else {
+ document.getElementById("timer").style.color = "white"
+ }
+ }
+
+ if (data.timerRunState) {
+ const diff = data.countdownGoal - now.getTime()
+ document.getElementById("timer").innerHTML = msToTime(diff, data);
+ lastTime = msToTime(diff, data);
+ if (diff > 0) {
+ document.getElementById("progBar").style.width = percentage(diff, data.timeAmountInital) + "%";
+ } else {
+ document.getElementById("progBar").style.width = "0%";
+ }
+
+ document.getElementById("progBar").style.backgroundColor = findProgessColor(data.colorSegments, diff)
+ document.getElementById("testImg").style.display = "none";
+ if (data.enableColoredText) {
+ document.getElementById("timer").style.color = findProgessColor(data.textColors, diff)
+ } else {
+ document.getElementById("timer").style.color = "white"
+ }
+
+ } else {
+ document.getElementById("timer").innerHTML = lastTime
+ }
+ } else if (data.mode == "black") {
+ timerCountdownFirst = true;
+ document.getElementById("timer").innerHTML = "";
+ document.getElementById("testImg").style.display = "none";
+ document.getElementById("wholeProgBar").style.display = "none";
+ document.getElementById("clockSec").innerHTML = "";
+
+ } else if (data.mode == "test") {
+ timerCountdownFirst = true;
+ document.getElementById("timer").innerHTML = "";
+ document.getElementById("testImg").style.display = "block";
+ document.getElementById("progBar").style.display = "none";
+ document.getElementById("clockSec").innerHTML = "";
+ }
}
function httpGet(theUrl) {
@@ -182,15 +278,9 @@ function getTime() {
return time;
}
-function on() {
- document.getElementById("overlay").style.display = "block";
-}
-function off() {
- document.getElementById("overlay").style.display = "none";
-}
-
-setInterval(handleUpdate, 200);
+// setInterval(requestBackend, 500);
+updateInter = setInterval(handleUpdate, 2);
let temp = new URLSearchParams(window.location.search).get("smaller");
diff --git a/static/mdbootstrap/css b/static/mdbootstrap/css
new file mode 120000
index 0000000..5ada75b
--- /dev/null
+++ b/static/mdbootstrap/css
@@ -0,0 +1 @@
+../../node_modules/mdbootstrap/css/
\ No newline at end of file
diff --git a/static/mdbootstrap/js b/static/mdbootstrap/js
new file mode 120000
index 0000000..6a0f520
--- /dev/null
+++ b/static/mdbootstrap/js
@@ -0,0 +1 @@
+../../node_modules/mdbootstrap/js
\ No newline at end of file
diff --git a/templates/adminPanel.html b/templates/adminPanel.html
deleted file mode 100644
index 3e474ac..0000000
--- a/templates/adminPanel.html
+++ /dev/null
@@ -1,94 +0,0 @@
-
-
-
-
-
-
-
-
- openCountdown - Admin
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Play controls:
-
-
-
-
- Message:
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/templates/errorPages/404.html b/templates/errorPages/404.html
new file mode 100644
index 0000000..edbc836
--- /dev/null
+++ b/templates/errorPages/404.html
@@ -0,0 +1,47 @@
+
+
+
+
+
+
+
+ openCountdown - Not found
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 404
+
+
+
+ We're sorry, the page you were looking for isn't found here.
+ The link you followed may either be broken or no longer exists. Please
+ check your spelling.
+
+ Back home
+
+
+
+
+
+
\ No newline at end of file
diff --git a/templates/newAdminPanel.html b/templates/newAdminPanel.html
new file mode 100644
index 0000000..6282241
--- /dev/null
+++ b/templates/newAdminPanel.html
@@ -0,0 +1,434 @@
+
+
+
+
+
+
+
+ openCountdown - Admin
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Sidebar
+
+
+
+
+ openCountdown
+
+
+
+
+
+
+
+
+
+
+ Home page
+
+
+
+
+
+
Mode
+
+
+
+
+ Timer
+
+
+ Clock
+
+
+ Black
+
+
+ Testimage
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Messaging
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Timer
+
+
+
+
+
+ 00:05:00
+ 00:10:00
+ 00:15:00
+ 00:20:00
+ 00:25:00
+ 00:30:00
+ 00:35:00
+ 00:40:00
+ 00:45:00
+
+
+
+
+ Countdown to time
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Settings
+ Show clock on Timer:
+
+
+ Show Milliseconds on Timer:
+
+
+ Show progressbar:
+
+
+ Progressbar Colors
+
+
+
+
+
+
+ Time
+ Color
+ Remove
+
+
+
+
+
+
+ Add row
+
+
+
+ Enable Text Colors:
+
+
+ Text Colors
+
+
+
+
+
+
+ Time
+ Color
+ Remove
+
+
+
+
+
+ Copy from progressbar
+ colors
+
+ Add row
+
+
+
+
+
+ Apply
+ settings
+
+ Save as
+ startup settings (Layout
+ only)
+
+
+
+ Debug page
+
+
Attention
+
This is a debug page which should only be used by professionals. Changing any options below might
+ impact operation.
+
+
Proceed with caution.
+
+ Enable time variance display:
+
+
+ Apply settings
+
+
+
+
+ Host information
+
+
+
+ Raw server reponse
+
+
+
+
+
+
+
+
+
+
+
+
+ #VALUE#
+
+
+
+
+
+
+
+
+
+ Remove
+
+
+
+
+
+
+
+
+
+ About
+ Version:
+ NodeJS Version:
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/templates/timerPage.html b/templates/timerPage.html
index a08a0a1..faa3e30 100644
--- a/templates/timerPage.html
+++ b/templates/timerPage.html
@@ -11,14 +11,21 @@
+
+
+
+
+ Connection lost. Trying to reconnect...
+
+
@@ -39,7 +46,7 @@
-
+