Merge branch 'ui-rework'
This commit is contained in:
		
							
								
								
									
										2
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							| @@ -1 +1,3 @@ | |||||||
| node_modules | node_modules | ||||||
|  | rename.sh | ||||||
|  | data-persistence.json | ||||||
|   | |||||||
							
								
								
									
										17
									
								
								.vscode/launch.json
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								.vscode/launch.json
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -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": [ | ||||||
|  |                 "<node_internals>/**" | ||||||
|  |             ], | ||||||
|  |             "program": "${workspaceFolder}/index.js" | ||||||
|  |         } | ||||||
|  |     ] | ||||||
|  | } | ||||||
							
								
								
									
										165
									
								
								LICENSE.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										165
									
								
								LICENSE.txt
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,165 @@ | |||||||
|  |                    GNU LESSER GENERAL PUBLIC LICENSE | ||||||
|  |                        Version 3, 29 June 2007 | ||||||
|  |  | ||||||
|  |  Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/> | ||||||
|  |  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. | ||||||
| @@ -1,10 +1,5 @@ | |||||||
| # openCountdown | # openCountdown | ||||||
|  |  | ||||||
| # ToDo | # ToDo | ||||||
| - [X] Pausing functions |  | ||||||
| - [X] Presets |  | ||||||
| - [X] time on countdown page |  | ||||||
| - [X] one-way messaging |  | ||||||
| - [ ] Better UI |  | ||||||
| - [X] Progress bar |  | ||||||
| - [P] Endpoint docs | - [P] Endpoint docs | ||||||
|  | - [ ] Better WS frames | ||||||
							
								
								
									
										32
									
								
								helpers.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								helpers.js
									
									
									
									
									
										Normal file
									
								
							| @@ -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 }; | ||||||
							
								
								
									
										209
									
								
								index.js
									
									
									
									
									
								
							
							
						
						
									
										209
									
								
								index.js
									
									
									
									
									
								
							| @@ -1,7 +1,10 @@ | |||||||
| const express = require("express"); | const express = require("express"); | ||||||
| const fs = require("fs"); | const fs = require("fs"); | ||||||
| const bodyParser = require("body-parser"); | const bodyParser = require("body-parser"); | ||||||
|  | const ws = require('ws'); | ||||||
|  | const helper = require("./helpers.js"); | ||||||
|  |  | ||||||
|  | console.log("Preparing server..."); | ||||||
| const app = express(); | const app = express(); | ||||||
|  |  | ||||||
| app.use(express.static("static")); | 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 = { | currentState = { | ||||||
|   mode: "clock", |   mode: "clock", | ||||||
|   countdownGoal: new Date().getTime(), |   countdownGoal: new Date().getTime(), | ||||||
|   showMilliSeconds: true, |   showMilliSeconds: true, | ||||||
|   defaultFullScreen: true, |   defaultFullScreen: true, | ||||||
|   timeAmountInital: 0, |   timeAmountInital: 0, | ||||||
|   timerRunState: true, |   timerRunState: false, | ||||||
|   pauseMoment: 0, |   pauseMoment: 0, | ||||||
|   showTimeOnCountdown: true, |   showTimeOnCountdown: true, | ||||||
|   message: "", |   message: "", | ||||||
|   showMessage: false, |   showMessage: false, | ||||||
|   messageAppearTime: 0, |   messageAppearTime: 0, | ||||||
|   showProgressbar: true, |   showProgressbar: true, | ||||||
|   colorSegments: {20000: "#FFAE00", 5000: "#ff0000", "START": "yellow"}, |   colorSegments: { 40000: "yellow", 20000: "#FFAE00", 5000: "#ff0000", "START": "green" }, | ||||||
|   textColors: {}, |   textColors: {}, | ||||||
|   srvTime: 0, |   srvTime: 0, | ||||||
|   enableColoredText: true, |   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 | 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) { | app.get("/", function (req, res) { | ||||||
|   const data = fs.readFileSync("templates/adminPanel.html", "utf8"); |   const data = fs.readFileSync("templates/newAdminPanel.html", "utf8"); | ||||||
|   res.send(data); |   res.send(data); | ||||||
| }); | }); | ||||||
|  |  | ||||||
| @@ -53,78 +97,155 @@ app.get("/api/v1/data", function (req, res) { | |||||||
|   res.json(currentState); |   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) { | app.get("/api/v1/set/mode", function (req, res) { | ||||||
|   currentState.mode = req.query.mode; |   currentState.mode = req.query.mode; | ||||||
|  |   updatedData() | ||||||
|   res.json({ status: "ok" }); |   res.json({ status: "ok" }); | ||||||
| }); | }); | ||||||
|  |  | ||||||
| app.get("/api/v1/set/layout/showMillis", function (req, res) { | app.get("/api/v1/set/layout/showMillis", function (req, res) { | ||||||
|   currentState.showMilliSeconds = (req.query.show === 'true'); |   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" }); |     res.json({ status: "ok" }); | ||||||
|  |   } | ||||||
|  |   updatedData() | ||||||
|  |  | ||||||
| }); | }); | ||||||
|  |  | ||||||
| app.get("/api/v1/set/timerGoal", function (req, res) { | app.get("/api/v1/set/timerGoal", function (req, res) { | ||||||
|   currentState.countdownGoal = new Date(parseInt(req.query.time)).getTime(); // ToDO error handling |   currentState.countdownGoal = new Date(parseInt(req.query.time)).getTime(); // ToDO error handling | ||||||
|   res.json({ status: "ok" }); |   res.json({ status: "ok" }); | ||||||
|  |   updatedData() | ||||||
| }); | }); | ||||||
|  |  | ||||||
| app.get("/api/v1/set/addMillisToTimer", function (req, res) { | app.get("/api/v1/set/addMillisToTimer", function (req, res) { | ||||||
|   currentState.timeAmountInital = req.query.time; |   currentState.timeAmountInital = req.query.time; | ||||||
|   currentState.countdownGoal = new Date().getTime() + parseInt(req.query.time) |   currentState.countdownGoal = new Date().getTime() + parseInt(req.query.time) | ||||||
|  |   currentState.pauseMoment = new Date().getTime(); | ||||||
|   res.json({ status: "ok" }); |   res.json({ status: "ok" }); | ||||||
|  |   updatedData() | ||||||
| }); | }); | ||||||
|  |  | ||||||
| app.get("/api/v1/ctrl/timer/pause", function (req, res) { | app.get("/api/v1/ctrl/timer/pause", function (req, res) { | ||||||
|   currentState.timerRunState = false; |   currentState.timerRunState = false; | ||||||
|   currentState.pauseMoment = new Date().getTime(); |   currentState.pauseMoment = new Date().getTime(); | ||||||
|   res.json({ status: "ok" }); |   res.json({ status: "ok" }); | ||||||
|  |   updatedData() | ||||||
| }); | }); | ||||||
|  |  | ||||||
| app.get("/api/v1/ctrl/timer/play", function (req, res) { | app.get("/api/v1/ctrl/timer/play", function (req, res) { | ||||||
|  |  | ||||||
|  |   if (currentState.timerRunState == false) { | ||||||
|     currentState.timerRunState = true |     currentState.timerRunState = true | ||||||
|     currentState.countdownGoal += new Date().getTime() - currentState.pauseMoment; |     currentState.countdownGoal += new Date().getTime() - currentState.pauseMoment; | ||||||
|  |   } | ||||||
|   res.json({ status: "ok" }); |   res.json({ status: "ok" }); | ||||||
|  |   updatedData() | ||||||
| }); | }); | ||||||
|  |  | ||||||
| app.get("/api/v1/ctrl/timer/restart", function (req, res) { | app.get("/api/v1/ctrl/timer/restart", function (req, res) { | ||||||
|   currentState.countdownGoal = new Date().getTime() + parseInt(currentState.timeAmountInital) |   currentState.countdownGoal = new Date().getTime() + parseInt(currentState.timeAmountInital) | ||||||
|   res.json({ status: "ok" }); |   res.json({ status: "ok" }); | ||||||
|  |   updatedData() | ||||||
| }); | }); | ||||||
|  |  | ||||||
| app.get("/api/v1/set/layout/showTime", function (req, res) { | app.get("/api/v1/set/layout/showTime", function (req, res) { | ||||||
|   currentState.showTimeOnCountdown = (req.query.show === 'true'); |   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" }); |     res.json({ status: "ok" }); | ||||||
|  |   } | ||||||
|  |   updatedData() | ||||||
| }); | }); | ||||||
|  |  | ||||||
| app.get("/api/v1/set/progressbar/show", function (req, res) { | app.get("/api/v1/set/progressbar/show", function (req, res) { | ||||||
|   currentState.showProgressbar = (req.query.show === 'true'); |   currentState.showProgressbar = (req.query.show === 'true'); | ||||||
|  |   if (req.query.persist === 'true') { | ||||||
|  |     dataToBeWritten.showProgressbar = currentState.showProgressbar | ||||||
|  |   } | ||||||
|   res.json({ status: "ok" }); |   res.json({ status: "ok" }); | ||||||
|  |   updatedData() | ||||||
| }); | }); | ||||||
|  |  | ||||||
| app.get("/api/v1/set/progressbar/colors", function (req, res) { | app.get("/api/v1/set/progressbar/colors", function (req, res) { | ||||||
|   try { |   try { | ||||||
|     currentState.colorSegments = 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" }); |     res.json({ status: "ok" }); | ||||||
|   } catch (error) { |   } catch (error) { | ||||||
|     res.json({ status: "error", message: error }); |     res.json({ status: "error", message: error }); | ||||||
|  |     console.error(error) | ||||||
|   } |   } | ||||||
|  |   updatedData() | ||||||
| }); | }); | ||||||
|  |  | ||||||
| app.get("/api/v1/set/text/colors", function (req, res) { | app.get("/api/v1/set/text/colors", function (req, res) { | ||||||
|   try { |   try { | ||||||
|     if(req.query.copy === "true"){ |     if (req.query.copy === "true") { | ||||||
|       currentState.textColors = currentState.colorSegments; |       currentState.textColors = currentState.colorSegments | ||||||
|  |       res.json({ status: "ok" }); | ||||||
|     } else { |     } else { | ||||||
|       currentState.textColors = JSON.parse(req.query.colors); |       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" }); |     res.json({ status: "ok" }); | ||||||
|   } catch (error) { |   } catch (error) { | ||||||
|     res.json({ status: "error", message: error }); |     res.json({ status: "error", message: error }); | ||||||
|  |     console.error(error) | ||||||
|   } |   } | ||||||
|  |   updatedData() | ||||||
| }); | }); | ||||||
|  |  | ||||||
| app.get("/api/v1/set/text/enableColoring", function (req, res) { | app.get("/api/v1/set/text/enableColoring", function (req, res) { | ||||||
|   currentState.enableColoredText = (req.query.enable === 'true'); |   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) { | 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.showMessage = true | ||||||
|   currentState.messageAppearTime = new Date().getTime() |   currentState.messageAppearTime = new Date().getTime() | ||||||
|   res.json({ status: "ok" }); |   res.json({ status: "ok" }); | ||||||
|  |   updatedData() | ||||||
| }); | }); | ||||||
|  |  | ||||||
| app.get("/api/v1/debug", function (req, res) { | app.get("/api/v1/debug", function (req, res) { | ||||||
|   currentState.debug = (req.query.enable === 'true'); |   currentState.debug = (req.query.enable === 'true'); | ||||||
|   res.json({ status: "ok" }); |   res.json({ status: "ok" }); | ||||||
|  |   updatedData() | ||||||
| }); | }); | ||||||
|  |  | ||||||
| app.get("/api/v1/ctrl/message/hide", function (req, res) { | app.get("/api/v1/ctrl/message/hide", function (req, res) { | ||||||
|   currentState.showMessage = false |   currentState.showMessage = false | ||||||
|   res.json({ status: "ok" }); |   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"); | ||||||
|   | |||||||
							
								
								
									
										387
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										387
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							| @@ -1,17 +1,36 @@ | |||||||
| { | { | ||||||
|   "name": "opencountdown", |   "name": "opencountdown", | ||||||
|   "version": "1.0.0", |   "version": "1.0.1", | ||||||
|   "lockfileVersion": 2, |   "lockfileVersion": 2, | ||||||
|   "requires": true, |   "requires": true, | ||||||
|   "packages": { |   "packages": { | ||||||
|     "": { |     "": { | ||||||
|       "name": "opencountdown", |       "name": "opencountdown", | ||||||
|       "version": "1.0.0", |       "version": "1.0.1", | ||||||
|       "license": "ISC", |       "license": "LGPL-3.0", | ||||||
|       "dependencies": { |       "dependencies": { | ||||||
|         "body-parser": "^1.19.2", |         "body-parser": "^1.19.2", | ||||||
|         "countdown": "^2.6.0", |         "bootstrap": "^5.1.3", | ||||||
|         "express": "^4.17.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": { |     "node_modules/accepts": { | ||||||
| @@ -51,6 +70,31 @@ | |||||||
|         "node": ">= 0.8" |         "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": { |     "node_modules/bytes": { | ||||||
|       "version": "3.1.2", |       "version": "3.1.2", | ||||||
|       "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", |       "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", |       "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", | ||||||
|       "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=" |       "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=" | ||||||
|     }, |     }, | ||||||
|     "node_modules/countdown": { |     "node_modules/copy-anything": { | ||||||
|       "version": "2.6.0", |       "version": "2.0.6", | ||||||
|       "resolved": "https://registry.npmjs.org/countdown/-/countdown-2.6.0.tgz", |       "resolved": "https://registry.npmjs.org/copy-anything/-/copy-anything-2.0.6.tgz", | ||||||
|       "integrity": "sha1-Z3+446nUzE52QVkBuiU7UYrzQXc=" |       "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": { |     "node_modules/debug": { | ||||||
|       "version": "2.6.9", |       "version": "2.6.9", | ||||||
| @@ -130,6 +189,18 @@ | |||||||
|         "node": ">= 0.8" |         "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": { |     "node_modules/escape-html": { | ||||||
|       "version": "1.0.3", |       "version": "1.0.3", | ||||||
|       "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", |       "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", | ||||||
| @@ -200,6 +271,11 @@ | |||||||
|         "node": ">= 0.8" |         "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": { |     "node_modules/forwarded": { | ||||||
|       "version": "0.2.0", |       "version": "0.2.0", | ||||||
|       "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", |       "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", | ||||||
| @@ -216,6 +292,12 @@ | |||||||
|         "node": ">= 0.6" |         "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": { |     "node_modules/http-errors": { | ||||||
|       "version": "1.8.1", |       "version": "1.8.1", | ||||||
|       "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.8.1.tgz", |       "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.8.1.tgz", | ||||||
| @@ -242,6 +324,18 @@ | |||||||
|         "node": ">=0.10.0" |         "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": { |     "node_modules/inherits": { | ||||||
|       "version": "2.0.4", |       "version": "2.0.4", | ||||||
|       "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", |       "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", | ||||||
| @@ -255,6 +349,66 @@ | |||||||
|         "node": ">= 0.10" |         "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": { |     "node_modules/media-typer": { | ||||||
|       "version": "0.3.0", |       "version": "0.3.0", | ||||||
|       "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", |       "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", |       "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", | ||||||
|       "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" |       "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": { |     "node_modules/negotiator": { | ||||||
|       "version": "0.6.3", |       "version": "0.6.3", | ||||||
|       "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", |       "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", |       "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", | ||||||
|       "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=" |       "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": { |     "node_modules/proxy-addr": { | ||||||
|       "version": "2.0.7", |       "version": "2.0.7", | ||||||
|       "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", |       "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", | ||||||
| @@ -355,6 +524,12 @@ | |||||||
|         "node": ">= 0.10" |         "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": { |     "node_modules/qs": { | ||||||
|       "version": "6.9.7", |       "version": "6.9.7", | ||||||
|       "resolved": "https://registry.npmjs.org/qs/-/qs-6.9.7.tgz", |       "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", |       "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", | ||||||
|       "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" |       "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": { |     "node_modules/send": { | ||||||
|       "version": "0.17.2", |       "version": "0.17.2", | ||||||
|       "resolved": "https://registry.npmjs.org/send/-/send-0.17.2.tgz", |       "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", |       "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", | ||||||
|       "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" |       "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": { |     "node_modules/statuses": { | ||||||
|       "version": "1.5.0", |       "version": "1.5.0", | ||||||
|       "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", |       "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", | ||||||
| @@ -475,6 +668,11 @@ | |||||||
|         "node": ">=0.6" |         "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": { |     "node_modules/type-is": { | ||||||
|       "version": "1.6.18", |       "version": "1.6.18", | ||||||
|       "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", |       "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", | ||||||
| @@ -510,9 +708,35 @@ | |||||||
|       "engines": { |       "engines": { | ||||||
|         "node": ">= 0.8" |         "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": { |   "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": { |     "accepts": { | ||||||
|       "version": "1.3.8", |       "version": "1.3.8", | ||||||
|       "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", |       "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", | ||||||
| @@ -544,6 +768,22 @@ | |||||||
|         "type-is": "~1.6.18" |         "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": { |     "bytes": { | ||||||
|       "version": "3.1.2", |       "version": "3.1.2", | ||||||
|       "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", |       "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", |       "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", | ||||||
|       "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=" |       "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=" | ||||||
|     }, |     }, | ||||||
|     "countdown": { |     "copy-anything": { | ||||||
|       "version": "2.6.0", |       "version": "2.0.6", | ||||||
|       "resolved": "https://registry.npmjs.org/countdown/-/countdown-2.6.0.tgz", |       "resolved": "https://registry.npmjs.org/copy-anything/-/copy-anything-2.0.6.tgz", | ||||||
|       "integrity": "sha1-Z3+446nUzE52QVkBuiU7UYrzQXc=" |       "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": { |     "debug": { | ||||||
|       "version": "2.6.9", |       "version": "2.6.9", | ||||||
| @@ -605,6 +853,15 @@ | |||||||
|       "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", |       "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", | ||||||
|       "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=" |       "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": { |     "escape-html": { | ||||||
|       "version": "1.0.3", |       "version": "1.0.3", | ||||||
|       "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", |       "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", | ||||||
| @@ -666,6 +923,11 @@ | |||||||
|         "unpipe": "~1.0.0" |         "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": { |     "forwarded": { | ||||||
|       "version": "0.2.0", |       "version": "0.2.0", | ||||||
|       "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", |       "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", |       "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", | ||||||
|       "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=" |       "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": { |     "http-errors": { | ||||||
|       "version": "1.8.1", |       "version": "1.8.1", | ||||||
|       "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.8.1.tgz", |       "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.8.1.tgz", | ||||||
| @@ -696,6 +964,12 @@ | |||||||
|         "safer-buffer": ">= 2.1.2 < 3" |         "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": { |     "inherits": { | ||||||
|       "version": "2.0.4", |       "version": "2.0.4", | ||||||
|       "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", |       "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", |       "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", | ||||||
|       "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==" |       "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": { |     "media-typer": { | ||||||
|       "version": "0.3.0", |       "version": "0.3.0", | ||||||
|       "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", |       "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", |       "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", | ||||||
|       "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" |       "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": { |     "negotiator": { | ||||||
|       "version": "0.6.3", |       "version": "0.6.3", | ||||||
|       "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", |       "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", |       "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", | ||||||
|       "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=" |       "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": { |     "proxy-addr": { | ||||||
|       "version": "2.0.7", |       "version": "2.0.7", | ||||||
|       "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", |       "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", | ||||||
| @@ -776,6 +1108,12 @@ | |||||||
|         "ipaddr.js": "1.9.1" |         "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": { |     "qs": { | ||||||
|       "version": "6.9.7", |       "version": "6.9.7", | ||||||
|       "resolved": "https://registry.npmjs.org/qs/-/qs-6.9.7.tgz", |       "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", |       "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", | ||||||
|       "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" |       "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": { |     "send": { | ||||||
|       "version": "0.17.2", |       "version": "0.17.2", | ||||||
|       "resolved": "https://registry.npmjs.org/send/-/send-0.17.2.tgz", |       "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", |       "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", | ||||||
|       "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" |       "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": { |     "statuses": { | ||||||
|       "version": "1.5.0", |       "version": "1.5.0", | ||||||
|       "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", |       "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", |       "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", | ||||||
|       "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==" |       "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": { |     "type-is": { | ||||||
|       "version": "1.6.18", |       "version": "1.6.18", | ||||||
|       "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", |       "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", | ||||||
| @@ -883,6 +1238,12 @@ | |||||||
|       "version": "1.1.2", |       "version": "1.1.2", | ||||||
|       "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", |       "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", | ||||||
|       "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=" |       "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=" | ||||||
|  |     }, | ||||||
|  |     "ws": { | ||||||
|  |       "version": "8.5.0", | ||||||
|  |       "resolved": "https://registry.npmjs.org/ws/-/ws-8.5.0.tgz", | ||||||
|  |       "integrity": "sha512-BWX0SWVgLPzYwF8lTzEy1egjhS4S4OEAHfsO8o65WOVsrnSRGaSiUaa9e0ggGlkMTtBlmOpEXiie9RUcBO86qg==", | ||||||
|  |       "requires": {} | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
| } | } | ||||||
|   | |||||||
							
								
								
									
										15
									
								
								package.json
									
									
									
									
									
								
							
							
						
						
									
										15
									
								
								package.json
									
									
									
									
									
								
							| @@ -1,6 +1,6 @@ | |||||||
| { | { | ||||||
|   "name": "opencountdown", |   "name": "opencountdown", | ||||||
|   "version": "1.0.0", |   "version": "1.0.1", | ||||||
|   "description": "An opensource countdown", |   "description": "An opensource countdown", | ||||||
|   "main": "index.js", |   "main": "index.js", | ||||||
|   "scripts": { |   "scripts": { | ||||||
| @@ -10,7 +10,16 @@ | |||||||
|   "license": "LGPL-3.0", |   "license": "LGPL-3.0", | ||||||
|   "dependencies": { |   "dependencies": { | ||||||
|     "body-parser": "^1.19.2", |     "body-parser": "^1.19.2", | ||||||
|     "countdown": "^2.6.0", |     "bootstrap": "^5.1.3", | ||||||
|     "express": "^4.17.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" | ||||||
|   } |   } | ||||||
| } | } | ||||||
|   | |||||||
							
								
								
									
										1
									
								
								static/bootstrap-duration-picker
									
									
									
									
									
										Symbolic link
									
								
							
							
						
						
									
										1
									
								
								static/bootstrap-duration-picker
									
									
									
									
									
										Symbolic link
									
								
							| @@ -0,0 +1 @@ | |||||||
|  | ../node_modules/bootstrap-duration-picker/dist/ | ||||||
							
								
								
									
										1
									
								
								static/bootstrap/dist
									
									
									
									
									
										Symbolic link
									
								
							
							
						
						
									
										1
									
								
								static/bootstrap/dist
									
									
									
									
									
										Symbolic link
									
								
							| @@ -0,0 +1 @@ | |||||||
|  | ../../node_modules/bootstrap/dist | ||||||
							
								
								
									
										1
									
								
								static/coloris/coloris.min.css
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								static/coloris/coloris.min.css
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
							
								
								
									
										6
									
								
								static/coloris/coloris.min.js
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								static/coloris/coloris.min.js
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
							
								
								
									
										1
									
								
								static/colorpicker/css
									
									
									
									
									
										Symbolic link
									
								
							
							
						
						
									
										1
									
								
								static/colorpicker/css
									
									
									
									
									
										Symbolic link
									
								
							| @@ -0,0 +1 @@ | |||||||
|  | ../../node_modules/bootstrap-colorpicker/dist/css | ||||||
							
								
								
									
										1
									
								
								static/colorpicker/js
									
									
									
									
									
										Symbolic link
									
								
							
							
						
						
									
										1
									
								
								static/colorpicker/js
									
									
									
									
									
										Symbolic link
									
								
							| @@ -0,0 +1 @@ | |||||||
|  | ../../node_modules/bootstrap-colorpicker/dist/js | ||||||
							
								
								
									
										1
									
								
								static/css/bootstrap-icons.css
									
									
									
									
										vendored
									
									
										Symbolic link
									
								
							
							
						
						
									
										1
									
								
								static/css/bootstrap-icons.css
									
									
									
									
										vendored
									
									
										Symbolic link
									
								
							| @@ -0,0 +1 @@ | |||||||
|  | ../../node_modules/bootstrap-icons/font/bootstrap-icons.css | ||||||
							
								
								
									
										86
									
								
								static/css/errorPage/style.css
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										86
									
								
								static/css/errorPage/style.css
									
									
									
									
									
										Normal file
									
								
							| @@ -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;} | ||||||
|  | } | ||||||
							
								
								
									
										62
									
								
								static/css/errorPage/styles.less
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										62
									
								
								static/css/errorPage/styles.less
									
									
									
									
									
										Normal file
									
								
							| @@ -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); | ||||||
|  | } | ||||||
							
								
								
									
										1
									
								
								static/css/fonts/bootstrap-icons.woff
									
									
									
									
									
										Symbolic link
									
								
							
							
						
						
									
										1
									
								
								static/css/fonts/bootstrap-icons.woff
									
									
									
									
									
										Symbolic link
									
								
							| @@ -0,0 +1 @@ | |||||||
|  | ../../../node_modules/bootstrap-icons/font/fonts/bootstrap-icons.woff | ||||||
							
								
								
									
										1
									
								
								static/css/fonts/bootstrap-icons.woff2
									
									
									
									
									
										Symbolic link
									
								
							
							
						
						
									
										1
									
								
								static/css/fonts/bootstrap-icons.woff2
									
									
									
									
									
										Symbolic link
									
								
							| @@ -0,0 +1 @@ | |||||||
|  | ../../../node_modules/bootstrap-icons/font/fonts/bootstrap-icons.woff2 | ||||||
							
								
								
									
										129
									
								
								static/css/mainStyle.css
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										129
									
								
								static/css/mainStyle.css
									
									
									
									
									
										Normal file
									
								
							| @@ -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; | ||||||
|  | } | ||||||
| @@ -1,3 +1,3 @@ | |||||||
| body { | body { | ||||||
|     font-size:0.5em; |     font-size:0.3em; | ||||||
| } | } | ||||||
| @@ -104,3 +104,10 @@ html, body { | |||||||
| animation:fade 1000ms infinite; | animation:fade 1000ms infinite; | ||||||
| -webkit-animation:fade 1000ms infinite; | -webkit-animation:fade 1000ms infinite; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | .connectionWarning{ | ||||||
|  |   background-color: red; | ||||||
|  |   width: 100vw; | ||||||
|  |   font-size: x-large; | ||||||
|  |   font-family: sans-serif; | ||||||
|  | } | ||||||
							
								
								
									
										1
									
								
								static/flatpickr/dist
									
									
									
									
									
										Symbolic link
									
								
							
							
						
						
									
										1
									
								
								static/flatpickr/dist
									
									
									
									
									
										Symbolic link
									
								
							| @@ -0,0 +1 @@ | |||||||
|  | ../../node_modules/flatpickr/dist/ | ||||||
							
								
								
									
										1
									
								
								static/js/cookie.js
									
									
									
									
									
										Symbolic link
									
								
							
							
						
						
									
										1
									
								
								static/js/cookie.js
									
									
									
									
									
										Symbolic link
									
								
							| @@ -0,0 +1 @@ | |||||||
|  | ../../node_modules/js-cookie/dist/js.cookie.min.js | ||||||
| @@ -1 +0,0 @@ | |||||||
| ../../node_modules/countdown/countdown.js |  | ||||||
							
								
								
									
										1
									
								
								static/js/darkreader.js
									
									
									
									
									
										Symbolic link
									
								
							
							
						
						
									
										1
									
								
								static/js/darkreader.js
									
									
									
									
									
										Symbolic link
									
								
							| @@ -0,0 +1 @@ | |||||||
|  | ../../node_modules/darkreader/darkreader.js | ||||||
| @@ -1,4 +1,529 @@ | |||||||
| function convertTimeOffset(){ | function convertTimeOffset() { | ||||||
|     selTime = new Date().getTime() + document.getElementById('time2').valueAsNumber |     selTime = new Date().getTime() + document.getElementById('time2').valueAsNumber | ||||||
|     document.getElementById("time").value = selTime |     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 = '<i class="bi bi-flag-fill"></i> 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 = '<i class="bi bi-flag-fill"></i> 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 = '<div class="spinner-border-sm spinner-border"></div>' | ||||||
|  |         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 = '<div class="spinner-border-sm spinner-border"></div>' | ||||||
|  |         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 = '<div class="spinner-border-sm spinner-border"></div>' | ||||||
|  |  | ||||||
|  |         // 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 = '<div class="spinner-border-sm spinner-border"></div>' | ||||||
|  |  | ||||||
|  |         // 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 = '<div class="spinner-border-sm spinner-border"></div>' | ||||||
|  |         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 = '<i class="bi bi-send"></i>' | ||||||
|  |             }, 200) | ||||||
|  |  | ||||||
|  |         }) | ||||||
|  |     }) | ||||||
|  |  | ||||||
|  |  | ||||||
|  |     $("#sendMessage").click(function (event) { | ||||||
|  |         $("#sendMessage")[0].innerHTML = '<div class="spinner-border-sm spinner-border"></div>' | ||||||
|  |         let value = $("#messageContent").val() | ||||||
|  |         saveOption("/api/v1/ctrl/message/show?msg=" + value, function (event) { | ||||||
|  |             setTimeout(function () { | ||||||
|  |                 $("#sendMessage")[0].innerHTML = '<i class="bi bi-send"></i>' | ||||||
|  |             }, 200) | ||||||
|  |  | ||||||
|  |         }) | ||||||
|  |     }) | ||||||
|  |  | ||||||
|  |     $("#ctrlRemoveMessage").click(function (event) { | ||||||
|  |         $("#ctrlRemoveMessage")[0].innerHTML = '<div class="spinner-border-sm spinner-border"></div>' | ||||||
|  |         saveOption("/api/v1/ctrl/message/hide", function (event) { | ||||||
|  |             setTimeout(function () { | ||||||
|  |                 $("#ctrlRemoveMessage")[0].innerHTML = '<i class="bi bi-eye-slash-fill"></i>' | ||||||
|  |             }, 200) | ||||||
|  |  | ||||||
|  |         }) | ||||||
|  |     }) | ||||||
|  |  | ||||||
|  |     $("#funcPlay").click(function (event) { | ||||||
|  |         $("#funcPlay")[0].innerHTML = '<div class="spinner-border-sm spinner-border"></div>' | ||||||
|  |         saveOption("/api/v1/ctrl/timer/play", function (event) { | ||||||
|  |             setTimeout(function () { | ||||||
|  |                 $("#funcPlay")[0].innerHTML = '<i class="bi bi-play-fill"></i>' | ||||||
|  |             }, 200); | ||||||
|  |         }) | ||||||
|  |     }) | ||||||
|  |  | ||||||
|  |  | ||||||
|  |     $("#funcPause").click(function (event) { | ||||||
|  |         $("#funcPause")[0].innerHTML = '<div class="spinner-border-sm spinner-border"></div>' | ||||||
|  |  | ||||||
|  |         saveOption("/api/v1/ctrl/timer/pause", function (event) { | ||||||
|  |             setTimeout(function () { | ||||||
|  |                 $("#funcPause")[0].innerHTML = '<i class="bi bi-pause"></i>' | ||||||
|  |             }, 200); | ||||||
|  |         }) | ||||||
|  |     }) | ||||||
|  |  | ||||||
|  |     $("#funcRestart").click(function (event) { | ||||||
|  |         $("#funcRestart")[0].innerHTML = '<div class="spinner-border-sm spinner-border"></div>' | ||||||
|  |         saveOption("/api/v1/ctrl/timer/restart", function (event) { | ||||||
|  |             setTimeout(function () { | ||||||
|  |                 $("#funcRestart")[0].innerHTML = '<i class="bi bi-arrow-clockwise"></i>' | ||||||
|  |             }, 200) | ||||||
|  |         }) | ||||||
|  |     }) | ||||||
|  |  | ||||||
|  |     $("#applyDebug").click(function (event) { | ||||||
|  |         $("#applyDebug")[0].innerHTML = '<div class="spinner-border-sm spinner-border"></div>' | ||||||
|  |         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 = '<div class="spinner-border-sm spinner-border"></div>' | ||||||
|  |         saveOption("/api/v1/set/addMillisToTimer?time=" + timeDiff, function (ev) { | ||||||
|  |             setTimeout(function () { | ||||||
|  |                 $(".goTimeGoalCountdown")[0].innerHTML = '<i class="bi bi-check2-circle"></i>' | ||||||
|  |             }, 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() | ||||||
|  |     } | ||||||
|  |  | ||||||
|  | } | ||||||
							
								
								
									
										1
									
								
								static/js/jquery.min.js
									
									
									
									
										vendored
									
									
										Symbolic link
									
								
							
							
						
						
									
										1
									
								
								static/js/jquery.min.js
									
									
									
									
										vendored
									
									
										Symbolic link
									
								
							| @@ -0,0 +1 @@ | |||||||
|  | ../../node_modules/jquery/dist/jquery.min.js | ||||||
							
								
								
									
										1
									
								
								static/js/jsonview.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								static/js/jsonview.js
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
							
								
								
									
										1
									
								
								static/js/less.min.js
									
									
									
									
										vendored
									
									
										Symbolic link
									
								
							
							
						
						
									
										1
									
								
								static/js/less.min.js
									
									
									
									
										vendored
									
									
										Symbolic link
									
								
							| @@ -0,0 +1 @@ | |||||||
|  | ../../node_modules/less/dist/less.min.js | ||||||
							
								
								
									
										1
									
								
								static/js/reconnecting-websocket.min.js
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								static/js/reconnecting-websocket.min.js
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -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}); | ||||||
| @@ -1,14 +1,68 @@ | |||||||
| var newDateObj = new Date(); | var newDateObj = new Date(); | ||||||
| newDateObj = new Date(newDateObj.getTime() + 1000 * 20) | 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 | allowFullscreen = true | ||||||
|  | let dataFame = {} | ||||||
|  | let timeDiff = 0 | ||||||
|  |  | ||||||
| function enterFullscreen(element) { | function enterFullscreen(element) { | ||||||
|   if (element.requestFullscreen) { |   if (element.requestFullscreen) { | ||||||
|     element.requestFullscreen(); |     element.requestFullscreen(); | ||||||
|   } else if (element.msRequestFullscreen) {      // for IE11 (remove June 15, 2022) |   } else if (element.msRequestFullscreen) { | ||||||
|     element.msRequestFullscreen(); |     element.msRequestFullscreen(); | ||||||
|   } else if (element.webkitRequestFullscreen) {  // iOS Safari |   } else if (element.webkitRequestFullscreen) { | ||||||
|     element.webkitRequestFullscreen(); |     element.webkitRequestFullscreen(); | ||||||
|   } |   } | ||||||
| } | } | ||||||
| @@ -28,7 +82,6 @@ function updateFullscreen() { | |||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
| function msToTime(s, data) { | function msToTime(s, data) { | ||||||
|   isSmallerThenZero = false |   isSmallerThenZero = false | ||||||
|   if (s < 0) { |   if (s < 0) { | ||||||
| @@ -69,18 +122,38 @@ function findProgessColor(colors, value) { | |||||||
|   return (resColor) |   return (resColor) | ||||||
| } | } | ||||||
|  |  | ||||||
| function handleUpdate() { | function requestBackend() { | ||||||
|   resp = httpGet("/api/v1/data"); |   resp = httpGet("/api/v1/data"); | ||||||
|  |  | ||||||
|   resp.onloadend = function (e) { |   resp.onloadend = function (e) { | ||||||
|     if(resp.status == 200){ |     if (resp.status == 200) { | ||||||
|       resp = resp.responseText; |       resp = resp.responseText; | ||||||
|       var data = JSON.parse(resp); |       var data = JSON.parse(resp); | ||||||
|  |       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("incomeData").innerHTML = JSON.stringify(data) | ||||||
|       document.getElementById("timediff").innerHTML = new Date().getTime() - data.srvTime; |   document.getElementById("timediff").innerHTML = timeDiff + "<br>" + String(new Date().getTime() - data.srvTime); | ||||||
|       if(data.debug){ |   | ||||||
|  |   if (data.debug) { | ||||||
|     document.getElementById("timediff").style.display = "block"; |     document.getElementById("timediff").style.display = "block"; | ||||||
|       }else{ |   } else { | ||||||
|     document.getElementById("timediff").style.display = "none"; |     document.getElementById("timediff").style.display = "none"; | ||||||
|   } |   } | ||||||
|  |  | ||||||
| @@ -93,7 +166,13 @@ function handleUpdate() { | |||||||
|     document.getElementById("overlay").style.display = "block"; |     document.getElementById("overlay").style.display = "block"; | ||||||
|     document.getElementById("text").innerHTML = data.message |     document.getElementById("text").innerHTML = data.message | ||||||
|   } else { |   } else { | ||||||
|         off() |     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 (new Date().getTime() - data.messageAppearTime < 5000) { | ||||||
| @@ -111,14 +190,17 @@ function handleUpdate() { | |||||||
|     document.getElementById("timer").innerHTML = getTime(); |     document.getElementById("timer").innerHTML = getTime(); | ||||||
|     document.getElementById("testImg").style.display = "none"; |     document.getElementById("testImg").style.display = "none"; | ||||||
|     document.getElementById("wholeProgBar").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") { |   } else if (data.mode == "timer") { | ||||||
|    |  | ||||||
|     document.getElementById("wholeProgBar").style.display = "block"; |     document.getElementById("wholeProgBar").style.display = "block"; | ||||||
|    |  | ||||||
|         if (data.timerRunState) { |  | ||||||
|     const now = new Date() |     const now = new Date() | ||||||
|  |  | ||||||
|  |     if(timerCountdownFirst){ | ||||||
|       const diff = data.countdownGoal - now.getTime() |       const diff = data.countdownGoal - now.getTime() | ||||||
|  |       timerCountdownFirst = false | ||||||
|       document.getElementById("timer").innerHTML = msToTime(diff, data); |       document.getElementById("timer").innerHTML = msToTime(diff, data); | ||||||
|       if (diff > 0) { |       if (diff > 0) { | ||||||
|         document.getElementById("progBar").style.width = percentage(diff, data.timeAmountInital) + "%"; |         document.getElementById("progBar").style.width = percentage(diff, data.timeAmountInital) + "%"; | ||||||
| @@ -133,29 +215,43 @@ function handleUpdate() { | |||||||
|       } else { |       } else { | ||||||
|         document.getElementById("timer").style.color = "white" |         document.getElementById("timer").style.color = "white" | ||||||
|       } |       } | ||||||
|    |  | ||||||
|     } |     } | ||||||
|         if (data.showTimeOnCountdown) { |  | ||||||
|           document.getElementById("clockSec").innerHTML = getTime(); |     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 { |       } else { | ||||||
|           document.getElementById("clockSec").innerHTML = ""; |         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") { |   } else if (data.mode == "black") { | ||||||
|  |     timerCountdownFirst = true; | ||||||
|     document.getElementById("timer").innerHTML = ""; |     document.getElementById("timer").innerHTML = ""; | ||||||
|     document.getElementById("testImg").style.display = "none"; |     document.getElementById("testImg").style.display = "none"; | ||||||
|     document.getElementById("wholeProgBar").style.display = "none"; |     document.getElementById("wholeProgBar").style.display = "none"; | ||||||
|  |     document.getElementById("clockSec").innerHTML = ""; | ||||||
|  |  | ||||||
|   } else if (data.mode == "test") { |   } else if (data.mode == "test") { | ||||||
|  |     timerCountdownFirst = true; | ||||||
|     document.getElementById("timer").innerHTML = ""; |     document.getElementById("timer").innerHTML = ""; | ||||||
|     document.getElementById("testImg").style.display = "block"; |     document.getElementById("testImg").style.display = "block"; | ||||||
|     document.getElementById("progBar").style.display = "none"; |     document.getElementById("progBar").style.display = "none"; | ||||||
|  |     document.getElementById("clockSec").innerHTML = ""; | ||||||
|   } |   } | ||||||
|     } |  | ||||||
|      |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| } | } | ||||||
|  |  | ||||||
| function httpGet(theUrl) { | function httpGet(theUrl) { | ||||||
| @@ -182,15 +278,9 @@ function getTime() { | |||||||
|   return time; |   return time; | ||||||
| } | } | ||||||
|  |  | ||||||
| function on() { |  | ||||||
|   document.getElementById("overlay").style.display = "block"; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| function off() { | // setInterval(requestBackend, 500); | ||||||
|   document.getElementById("overlay").style.display = "none"; | updateInter = setInterval(handleUpdate, 2); | ||||||
| } |  | ||||||
|  |  | ||||||
| setInterval(handleUpdate, 200); |  | ||||||
|  |  | ||||||
| let temp = new URLSearchParams(window.location.search).get("smaller"); | let temp = new URLSearchParams(window.location.search).get("smaller"); | ||||||
|  |  | ||||||
|   | |||||||
							
								
								
									
										1
									
								
								static/mdbootstrap/css
									
									
									
									
									
										Symbolic link
									
								
							
							
						
						
									
										1
									
								
								static/mdbootstrap/css
									
									
									
									
									
										Symbolic link
									
								
							| @@ -0,0 +1 @@ | |||||||
|  | ../../node_modules/mdbootstrap/css/ | ||||||
							
								
								
									
										1
									
								
								static/mdbootstrap/js
									
									
									
									
									
										Symbolic link
									
								
							
							
						
						
									
										1
									
								
								static/mdbootstrap/js
									
									
									
									
									
										Symbolic link
									
								
							| @@ -0,0 +1 @@ | |||||||
|  | ../../node_modules/mdbootstrap/js | ||||||
| @@ -1,94 +0,0 @@ | |||||||
| <!doctype html> |  | ||||||
|  |  | ||||||
| <html lang="en"> |  | ||||||
|  |  | ||||||
| <head> |  | ||||||
|   <meta charset="utf-8"> |  | ||||||
|   <meta name="viewport" content="width=device-width, initial-scale=1"> |  | ||||||
|  |  | ||||||
|   <title>openCountdown - Admin</title> |  | ||||||
|   <meta name="description" content="openCountdown"> |  | ||||||
|   <meta name="author" content="TheGreydiamond"> |  | ||||||
|  |  | ||||||
|   <link rel="stylesheet" href="css/styles.css?v=1.1"> |  | ||||||
| </head> |  | ||||||
|  |  | ||||||
| <body> |  | ||||||
|  |  | ||||||
|  |  | ||||||
|   <form action="/api/v1/set/mode" target="hiddenFrame"> |  | ||||||
|     <select id="mode" name="mode"> |  | ||||||
|       <option value="timer">Timer</option> |  | ||||||
|       <option value="clock">Clock</option> |  | ||||||
|       <option value="black">Black</option> |  | ||||||
|       <option value="test">Test</option> |  | ||||||
|     </select> |  | ||||||
|     <button type="submit">Submit</button> |  | ||||||
|   </form> |  | ||||||
|  |  | ||||||
|   <br> |  | ||||||
|   <form action="/api/v1/set/layout/showMillis" target="hiddenFrame"> |  | ||||||
|     <select id="show" name="show"> |  | ||||||
|       <option value="true">Enable Milliseconds</option> |  | ||||||
|       <option value="false">Disable Milliseconds</option> |  | ||||||
|     </select> |  | ||||||
|     <button type="submit">Submit</button> |  | ||||||
|   </form> |  | ||||||
|  |  | ||||||
|   <form action="/api/v1/set/layout/showTime" target="hiddenFrame"> |  | ||||||
|     <select id="show" name="show"> |  | ||||||
|       <option value="true">Show Clock on Countdown page</option> |  | ||||||
|       <option value="false">Do not show Clock on Countdown page</option> |  | ||||||
|     </select> |  | ||||||
|     <button type="submit">Submit</button> |  | ||||||
|   </form> |  | ||||||
|  |  | ||||||
|   <form action="/api/v1/set/addMillisToTimer" target="hiddenFrame"> |  | ||||||
|     <input type="time" step="0.001" name="time2" id="time2" onchange="updateHiddenForm()"></input> |  | ||||||
|     <input type="hidden" step="0.001" name="time" id="time"></input> |  | ||||||
|     <button type="submit">Submit</button> |  | ||||||
|   </form> |  | ||||||
|  |  | ||||||
|   <form action="/api/v1/set/addMillisToTimer" target="hiddenFrame"> |  | ||||||
|     <select id="time" name="time" onchange=""> |  | ||||||
|       <option value="20000">debug 1 (20 secs)</option> |  | ||||||
|       <option value="300000">00:05:00</option> |  | ||||||
|       <option value="600000">00:10:00</option> |  | ||||||
|       <option value="900000">00:15:00</option> |  | ||||||
|       <option value="1200000">00:20:00</option> |  | ||||||
|       <option value="1500000">00:25:00</option> |  | ||||||
|       <option value="1800000">00:30:00</option> |  | ||||||
|       <option value="2100000">00:35:00</option> |  | ||||||
|       <option value="2400000">00:40:00</option> |  | ||||||
|       <option value="2700000">00:45:00</option> |  | ||||||
|     </select> |  | ||||||
|     <button type="submit">Submit</button> |  | ||||||
|   </form> |  | ||||||
|  |  | ||||||
|   Play controls: |  | ||||||
|   <form action="/api/v1/ctrl/timer/play" target="hiddenFrame"> |  | ||||||
|     <button type="submit">Play</button> |  | ||||||
|   </form> |  | ||||||
|   <form action="/api/v1/ctrl/timer/pause" target="hiddenFrame"> |  | ||||||
|     <button type="submit">Pause</button> |  | ||||||
|   </form> |  | ||||||
|   <form action="/api/v1/ctrl/timer/restart" target="hiddenFrame"> |  | ||||||
|     <button type="submit">Restart</button> |  | ||||||
|   </form> |  | ||||||
|  |  | ||||||
|   Message:  |  | ||||||
|   <form action="/api/v1/ctrl/message/show" target="hiddenFrame"> |  | ||||||
|     <input type="text" name="msg"> |  | ||||||
|     <button type="submit">Submit</button> |  | ||||||
|   </form> |  | ||||||
|   <form action="/api/v1/ctrl/message/hide" target="hiddenFrame"> |  | ||||||
|     <button type="submit">Hide</button> |  | ||||||
|   </form> |  | ||||||
|   <iframe name="hiddenFrame" style="display: none"></iframe> |  | ||||||
|  |  | ||||||
|  |  | ||||||
|   <iframe src="/timer?smaller=true" height="80%" width="80%"> </iframe> |  | ||||||
| </body> |  | ||||||
| <script src="js/interface.js"></script> |  | ||||||
|  |  | ||||||
| </html> |  | ||||||
							
								
								
									
										47
									
								
								templates/errorPages/404.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										47
									
								
								templates/errorPages/404.html
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,47 @@ | |||||||
|  | <!DOCTYPE html> | ||||||
|  | <html> | ||||||
|  |  | ||||||
|  | <head> | ||||||
|  |     <meta charset="utf-8"> | ||||||
|  |     <meta name="viewport" content="width=device-width, initial-scale=1"> | ||||||
|  |  | ||||||
|  |     <title>openCountdown - Not found</title> | ||||||
|  |     <meta name="description" content="openCountdown"> | ||||||
|  |     <meta name="author" content="TheGreydiamond"> | ||||||
|  |  | ||||||
|  |     <script type="text/javascript" src="/js/cookie.js"></script> | ||||||
|  |  | ||||||
|  |     <link rel="stylesheet/less" type="text/css" href="/css/errorPage/styles.less" /> | ||||||
|  |  | ||||||
|  |  | ||||||
|  |     <script> | ||||||
|  |         less = { | ||||||
|  |             javascriptEnabled: true | ||||||
|  |         }; | ||||||
|  |     </script> | ||||||
|  |     <script src="/js/less.min.js"></script> | ||||||
|  |  | ||||||
|  |     <link rel="stylesheet" href="/css/errorPage/style.css"> | ||||||
|  |  | ||||||
|  |     <link rel="stylesheet" href="/css/bootstrap-icons.css"> | ||||||
|  | </head> | ||||||
|  |  | ||||||
|  | <body> | ||||||
|  |     <div class="container"> | ||||||
|  |         <h1 class="rainbow"> | ||||||
|  |             <div class="glitch" data-text="404"> | ||||||
|  |                 404 | ||||||
|  |             </div> | ||||||
|  |         </h1> | ||||||
|  |         <h2 class="color-foreground"> | ||||||
|  |             We're sorry, the page you were looking for isn't found here.<br> | ||||||
|  |             The link you followed may either be broken or no longer exists. Please | ||||||
|  |             check your spelling.<br> | ||||||
|  |  | ||||||
|  |             <a href="/"><i class="bi bi-house-door"></i> Back home</a> | ||||||
|  |         </h2> | ||||||
|  |  | ||||||
|  |     </div> | ||||||
|  | </body> | ||||||
|  |  | ||||||
|  | </html> | ||||||
							
								
								
									
										434
									
								
								templates/newAdminPanel.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										434
									
								
								templates/newAdminPanel.html
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,434 @@ | |||||||
|  | <!doctype html> | ||||||
|  | <html lang="en"> | ||||||
|  |  | ||||||
|  | <head> | ||||||
|  |     <meta charset="utf-8"> | ||||||
|  |     <meta name="viewport" content="width=device-width, initial-scale=1"> | ||||||
|  |  | ||||||
|  |     <title>openCountdown - Admin</title> | ||||||
|  |     <meta name="description" content="openCountdown"> | ||||||
|  |     <meta name="author" content="TheGreydiamond"> | ||||||
|  |  | ||||||
|  |  | ||||||
|  |     <link rel="stylesheet" href="/css/bootstrap-icons.css"> | ||||||
|  |     <link rel="stylesheet" href="/mdbootstrap/css/style.css"> | ||||||
|  |  | ||||||
|  |     <script src="/bootstrap/dist/js/bootstrap.bundle.min.js"></script> | ||||||
|  |     <script src="/js/jquery.min.js"></script> | ||||||
|  |     <script type="text/javascript" src="/mdbootstrap/js/mdb.min.js"></script> | ||||||
|  |  | ||||||
|  |     <script type="text/javascript" src="/js/darkreader.js"></script> | ||||||
|  |     <script type="text/javascript" src="/js/cookie.js"></script> | ||||||
|  |     <link href="/bootstrap/dist/css/bootstrap.min.css" rel="stylesheet"> | ||||||
|  |     <link href="/css/mainStyle.css" rel="stylesheet"> | ||||||
|  |     <link rel="stylesheet" href="/coloris/coloris.min.css" /> | ||||||
|  |     <link rel="stylesheet" href="/bootstrap-duration-picker/bootstrap-duration-picker.css" /> | ||||||
|  |     <link rel="stylesheet" href="/flatpickr/dist/flatpickr.min.css" /> | ||||||
|  |     <script src="/bootstrap-duration-picker/bootstrap-duration-picker-debug.js"></script> | ||||||
|  |     <script src="/coloris/coloris.min.js"></script> | ||||||
|  |  | ||||||
|  |     <script type="text/javascript" src="/flatpickr/dist/flatpickr.js"> </script> | ||||||
|  |  | ||||||
|  |     <link rel="stylesheet" href="/css/bootstrap-icons.css"> | ||||||
|  | </head> | ||||||
|  |  | ||||||
|  | <body> | ||||||
|  |  | ||||||
|  |     <main> | ||||||
|  |         <div class="d-flex flex-column flex-shrink-0 p-3 text-white bg-dark trans" style="width: 250px;" | ||||||
|  |             id="navbarToggleExternalContent"> | ||||||
|  |             <a href="/" class="d-flex align-items-center mb-3 mb-md-0 me-md-auto text-white text-decoration-none"> | ||||||
|  |                 <svg class="bi me-2" width="40" height="32"> | ||||||
|  |                     <use xlink:href="#bootstrap" /> | ||||||
|  |                 </svg> | ||||||
|  |                 <span class="fs-4">Sidebar</span> | ||||||
|  |             </a> | ||||||
|  |             <hr> | ||||||
|  |             <ul class="nav nav-pills flex-column mb-auto"> | ||||||
|  |                 <li class="nav-item"> | ||||||
|  |                     <a href="#homeP" class="nav-link active" aria-current="page" id="PageIndex"> | ||||||
|  |                         <i class="bi bi-house-door"></i> | ||||||
|  |                         Home | ||||||
|  |                     </a> | ||||||
|  |                 </li> | ||||||
|  |                 <li> | ||||||
|  |                     <a href="#settings" class="nav-link text-white" id="PageSettings"> | ||||||
|  |                         <i class="bi bi-gear"></i> | ||||||
|  |                         Settings | ||||||
|  |                     </a> | ||||||
|  |                 </li> | ||||||
|  |                 <li> | ||||||
|  |                     <a href="#debug" class="nav-link text-white" id="PageDebug"> | ||||||
|  |                         <i class="bi bi-bug"></i> | ||||||
|  |                         Debug | ||||||
|  |                     </a> | ||||||
|  |                 </li> | ||||||
|  |                 <li> | ||||||
|  |                     <a href="#about" class="nav-link text-white" id="PageAbout"> | ||||||
|  |                         <i class="bi bi-info-circle"></i> | ||||||
|  |                         About | ||||||
|  |                     </a> | ||||||
|  |                 </li> | ||||||
|  |             </ul> | ||||||
|  |             <hr> | ||||||
|  |             openCountdown <div class="btn-group" role="group" aria-label="Basic radio toggle button group"> | ||||||
|  |  | ||||||
|  |                 <input type="radio" class="btn-check" name="btnradio2" id="Mbtnradio1" autocomplete="off" checked> | ||||||
|  |                 <label class="btn btn-outline-primary" for="Mbtnradio1"><svg xmlns="http://www.w3.org/2000/svg" | ||||||
|  |                         width="16" height="16" fill="currentColor" class="bi bi-brightness-high-fill" | ||||||
|  |                         viewBox="0 0 16 16"> | ||||||
|  |                         <path | ||||||
|  |                             d="M12 8a4 4 0 1 1-8 0 4 4 0 0 1 8 0zM8 0a.5.5 0 0 1 .5.5v2a.5.5 0 0 1-1 0v-2A.5.5 0 0 1 8 0zm0 13a.5.5 0 0 1 .5.5v2a.5.5 0 0 1-1 0v-2A.5.5 0 0 1 8 13zm8-5a.5.5 0 0 1-.5.5h-2a.5.5 0 0 1 0-1h2a.5.5 0 0 1 .5.5zM3 8a.5.5 0 0 1-.5.5h-2a.5.5 0 0 1 0-1h2A.5.5 0 0 1 3 8zm10.657-5.657a.5.5 0 0 1 0 .707l-1.414 1.415a.5.5 0 1 1-.707-.708l1.414-1.414a.5.5 0 0 1 .707 0zm-9.193 9.193a.5.5 0 0 1 0 .707L3.05 13.657a.5.5 0 0 1-.707-.707l1.414-1.414a.5.5 0 0 1 .707 0zm9.193 2.121a.5.5 0 0 1-.707 0l-1.414-1.414a.5.5 0 0 1 .707-.707l1.414 1.414a.5.5 0 0 1 0 .707zM4.464 4.465a.5.5 0 0 1-.707 0L2.343 3.05a.5.5 0 1 1 .707-.707l1.414 1.414a.5.5 0 0 1 0 .708z" /> | ||||||
|  |                     </svg> | ||||||
|  |                 </label> | ||||||
|  |  | ||||||
|  |                 <input type="radio" class="btn-check" name="btnradio2" id="Mbtnradio2" autocomplete="off"> | ||||||
|  |                 <label class="btn btn-outline-primary" for="Mbtnradio2"> | ||||||
|  |                     <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" | ||||||
|  |                         class="bi bi-moon-fill" viewBox="0 0 16 16"> | ||||||
|  |                         <path | ||||||
|  |                             d="M6 .278a.768.768 0 0 1 .08.858 7.208 7.208 0 0 0-.878 3.46c0 4.021 3.278 7.277 7.318 7.277.527 0 1.04-.055 1.533-.16a.787.787 0 0 1 .81.316.733.733 0 0 1-.031.893A8.349 8.349 0 0 1 8.344 16C3.734 16 0 12.286 0 7.71 0 4.266 2.114 1.312 5.124.06A.752.752 0 0 1 6 .278z" /> | ||||||
|  |                     </svg> | ||||||
|  |                 </label> | ||||||
|  |  | ||||||
|  |                 <input type="radio" class="btn-check" name="btnradio2" id="Mbtnradio3" autocomplete="off"> | ||||||
|  |                 <label class="btn btn-outline-primary" for="Mbtnradio3"> | ||||||
|  |                     Auto | ||||||
|  |                 </label> | ||||||
|  |  | ||||||
|  |             </div> | ||||||
|  |         </div> | ||||||
|  |         <pages class="d-flex flex-fill" id="pageCont" class="z-index: 50;"> | ||||||
|  |             <div class=""> | ||||||
|  |                 <button type="button" | ||||||
|  |                     class="opacity mx-2 svg-center btn btn-outline-transparent rounded-circle border-0" | ||||||
|  |                     onclick="toogleNav()"> | ||||||
|  |                     <i class="bi bi-list"></i> | ||||||
|  |                 </button> | ||||||
|  |             </div> | ||||||
|  |  | ||||||
|  |  | ||||||
|  |             <page id="homeP" class="pageC flex-fill overflow-auto"> | ||||||
|  |                 <h1>Home page</h1> | ||||||
|  |  | ||||||
|  |                 <div class="container"> | ||||||
|  |                     <div class="row"> | ||||||
|  |                         <div class="col"> | ||||||
|  |                             <h3 class="d-flex">Preview <span class="helperTip" data-placement="right" title="A preview of what is currently visible on the countdown view" data-toggle="tooltip"> | ||||||
|  |                                     <i class="bi bi-question-circle-fill"></i> | ||||||
|  |                                 </span> | ||||||
|  |                                  <div class="ms-auto"> | ||||||
|  |                                     <span class="helperTip" data-placement="right" | ||||||
|  |                                         title="Copies the link to the timer view" data-toggle="tooltip"> | ||||||
|  |                                         <button class="btn" onclick="navigator.clipboard.writeText(window.location.toString() + 'timer')"> | ||||||
|  |                                             <i class="bi bi-clipboard"></i> | ||||||
|  |                                         </button> | ||||||
|  |                                     </span> | ||||||
|  |  | ||||||
|  |                                     <span class="helperTip" data-placement="right" | ||||||
|  |                                         title="Open the countdown view in a new tab" data-toggle="tooltip"> | ||||||
|  |                                         <a href="/timer" class="btn " target="_blank"><i | ||||||
|  |                                                 class="bi bi-box-arrow-up-right"></i></a> | ||||||
|  |                                     </span> | ||||||
|  |                                 </div> | ||||||
|  |                             </h3> | ||||||
|  |                             <iframe src="/timer?smaller=true" height="100%" width="100%" style="min-height: 400px;"> | ||||||
|  |                             </iframe> | ||||||
|  |                         </div> | ||||||
|  |                         <div class="col"> | ||||||
|  |                             <h3>Mode <span class="helperTip" data-placement="right" | ||||||
|  |                                     title="Select what to show on the countdown view" data-toggle="tooltip"> | ||||||
|  |                                     <i class="bi bi-question-circle-fill"></i> | ||||||
|  |                                 </span></h3> | ||||||
|  |                             <div class="btn-group" role="group" aria-label="Basic radio toggle button group"> | ||||||
|  |                                 <input type="radio" class="btn-check" name="btnradio" id="btnradio1" autocomplete="off" | ||||||
|  |                                     checked> | ||||||
|  |                                 <label class="btn btn-outline-primary" for="btnradio1">Timer</label> | ||||||
|  |  | ||||||
|  |                                 <input type="radio" class="btn-check" name="btnradio" id="btnradio2" autocomplete="off"> | ||||||
|  |                                 <label class="btn btn-outline-primary" for="btnradio2">Clock</label> | ||||||
|  |  | ||||||
|  |                                 <input type="radio" class="btn-check" name="btnradio" id="btnradio3" autocomplete="off"> | ||||||
|  |                                 <label class="btn btn-outline-primary" for="btnradio3">Black</label> | ||||||
|  |  | ||||||
|  |                                 <input type="radio" class="btn-check" name="btnradio" id="btnradio4" autocomplete="off"> | ||||||
|  |                                 <label class="btn btn-outline-primary" for="btnradio4">Testimage</label> | ||||||
|  |                             </div> | ||||||
|  |                             <br> | ||||||
|  |                             <br> | ||||||
|  |                             <br> | ||||||
|  |                             <controls> | ||||||
|  |                                 <button class="btn btn-outline-success p-4" id="funcPlay"><svg | ||||||
|  |                                         xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" | ||||||
|  |                                         class="bi bi-play-fill" viewBox="0 0 16 16"> | ||||||
|  |                                         <path | ||||||
|  |                                             d="m11.596 8.697-6.363 3.692c-.54.313-1.233-.066-1.233-.697V4.308c0-.63.692-1.01 1.233-.696l6.363 3.692a.802.802 0 0 1 0 1.393z" /> | ||||||
|  |                                     </svg></button> | ||||||
|  |  | ||||||
|  |                                 <button class="btn btn-outline-warning p-4" id="funcPause"><svg | ||||||
|  |                                         xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" | ||||||
|  |                                         class="bi bi-pause" viewBox="0 0 16 16"> | ||||||
|  |                                         <path | ||||||
|  |                                             d="M6 3.5a.5.5 0 0 1 .5.5v8a.5.5 0 0 1-1 0V4a.5.5 0 0 1 .5-.5zm4 0a.5.5 0 0 1 .5.5v8a.5.5 0 0 1-1 0V4a.5.5 0 0 1 .5-.5z" /> | ||||||
|  |                                     </svg></button> | ||||||
|  |                                 <button class="btn btn-outline-info p-4" id="funcRestart"><svg | ||||||
|  |                                         xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" | ||||||
|  |                                         class="bi bi-arrow-clockwise" viewBox="0 0 16 16"> | ||||||
|  |                                         <path fill-rule="evenodd" | ||||||
|  |                                             d="M8 3a5 5 0 1 0 4.546 2.914.5.5 0 0 1 .908-.417A6 6 0 1 1 8 2v1z" /> | ||||||
|  |                                         <path | ||||||
|  |                                             d="M8 4.466V.534a.25.25 0 0 1 .41-.192l2.36 1.966c.12.1.12.284 0 .384L8.41 4.658A.25.25 0 0 1 8 4.466z" /> | ||||||
|  |                                     </svg></button> | ||||||
|  |                             </controls> | ||||||
|  |                             <br> | ||||||
|  |                             <br> | ||||||
|  |                             <br> | ||||||
|  |                             <h3>Messaging <span class="helperTip" data-placement="right" | ||||||
|  |                                     title="Shows a given message on the timer view" data-toggle="tooltip"> | ||||||
|  |                                     <i class="bi bi-question-circle-fill"></i> | ||||||
|  |                                 </span></h3> | ||||||
|  |  | ||||||
|  |                             <input type="text" id="messageContent" class="form-control" placeholder="Message here" | ||||||
|  |                                 style="width: 50%;"> | ||||||
|  |  | ||||||
|  |                             <br> | ||||||
|  |                             <button class="btn btn-outline-primary m-1" id="sendMessage"><i | ||||||
|  |                                     class="bi bi-send"></i></button> | ||||||
|  |                             <button class="btn btn-outline-primary m-1" id="ctrlRemoveMessage"> | ||||||
|  |                                 <i class="bi bi-eye-slash-fill"></i> | ||||||
|  |                             </button> | ||||||
|  |                         </div> | ||||||
|  |                     </div> | ||||||
|  |                 </div> | ||||||
|  |                 <br><br><br> | ||||||
|  |                 <h3>Timer</h3> | ||||||
|  |                 <div class="container"> | ||||||
|  |  | ||||||
|  |  | ||||||
|  |                     <div class="row"> | ||||||
|  |                         <presets class="d-inline-flex justify-content-center"> | ||||||
|  |                             <button class="btn btn-outline-secondary m-1 pres" value="300000">00:05:00</button> | ||||||
|  |                             <button class="btn btn-outline-secondary m-1 pres" value="600000">00:10:00</button> | ||||||
|  |                             <button class="btn btn-outline-secondary m-1 pres" value="900000">00:15:00</button> | ||||||
|  |                             <button class="btn btn-outline-secondary m-1 pres" value="1200000">00:20:00</button> | ||||||
|  |                             <button class="btn btn-outline-secondary m-1 pres" value="1500000">00:25:00</button> | ||||||
|  |                             <button class="btn btn-outline-secondary m-1 pres" value="1800000">00:30:00</button> | ||||||
|  |                             <button class="btn btn-outline-secondary m-1 pres" value="2100000">00:35:00</button> | ||||||
|  |                             <button class="btn btn-outline-secondary m-1 pres" value="2400000">00:40:00</button> | ||||||
|  |                             <button class="btn btn-outline-secondary m-1 pres" value="2700000">00:45:00</button> | ||||||
|  |                         </presets> | ||||||
|  |                          | ||||||
|  |                         <div class="row" style="width: 100%;"> | ||||||
|  |                              | ||||||
|  |                              | ||||||
|  |                             <div class="d-inline-flex justify-content-center p-2 col"> | ||||||
|  |                                 <input type="text" class="form-control m-1" id="customValue"> | ||||||
|  |                                  | ||||||
|  |                                 <button class="btn btn-outline-primary m-1 mt-0 goTimer"><i | ||||||
|  |                                         class="bi bi-check2-circle"></i></button> | ||||||
|  |                             </div> | ||||||
|  |                         </div> | ||||||
|  |                         <h5> | ||||||
|  |                             Countdown to time | ||||||
|  |                         </h5> | ||||||
|  |                         <div class="row justify-content-center flex-nowrap d-flex" > | ||||||
|  |                             <input id="datetimetester" class="form-control input-sm" style="width: 20%;"> | ||||||
|  |                             <button class="btn btn-outline-primary goTimeGoalCountdown ms-2" style="width: 5%;"><i | ||||||
|  |                                 class="bi bi-check2-circle"></i></button> | ||||||
|  |  | ||||||
|  |                              | ||||||
|  |  | ||||||
|  |                         </input> | ||||||
|  |                         </div> | ||||||
|  |                          | ||||||
|  |                     </div> | ||||||
|  |                 </div> | ||||||
|  |             </page> | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |             <page id="settings" class="pageC hidden flex-fill overflow-auto"> | ||||||
|  |                 <h1>Settings</h1> | ||||||
|  |                 <label for="showTime">Show clock on Timer:</label> | ||||||
|  |                 <input type="checkbox" name="showTime" id="showTime"><br> | ||||||
|  |  | ||||||
|  |                 <label for="showMillis">Show Milliseconds on Timer:</label> | ||||||
|  |                 <input type="checkbox" name="showMillis" id="showMillis"><br> | ||||||
|  |  | ||||||
|  |                 <label for="progBarShow">Show progressbar:</label> | ||||||
|  |                 <input type="checkbox" name="progBarShow" id="progBarShow"><br> | ||||||
|  |                 <details> | ||||||
|  |                     <summary>Progressbar Colors</summary> | ||||||
|  |                     <p> | ||||||
|  |                     <div id="table" class="table-editable"> | ||||||
|  |                         <span class="table-add float-right mb-3 mr-2"><a href="#!" class="text-success"><i | ||||||
|  |                                     class="fas fa-plus fa-2x" aria-hidden="true"></i></a></span> | ||||||
|  |                         <table class="table table-bordered table-responsive-md table-striped text-center" id="colors1"> | ||||||
|  |                             <thead> | ||||||
|  |                                 <tr> | ||||||
|  |                                     <th class="text-center">Time</th> | ||||||
|  |                                     <th class="text-center">Color</th> | ||||||
|  |                                     <th class="text-center">Remove</th> | ||||||
|  |                                 </tr> | ||||||
|  |                             </thead> | ||||||
|  |                             </tbody> | ||||||
|  |                         </table> | ||||||
|  |                     </div> | ||||||
|  |  | ||||||
|  |                     <button type="button" class="btn btn-outline-success" id="addRow">Add row</button> | ||||||
|  |                     </p> | ||||||
|  |                 </details> | ||||||
|  |                 <hr> | ||||||
|  |                 <label for="textColors">Enable Text Colors:</label> | ||||||
|  |                 <input type="checkbox" name="textColors" id="textColors"><br> | ||||||
|  |                 <details> | ||||||
|  |                     <summary>Text Colors</summary> | ||||||
|  |                     <p> | ||||||
|  |  | ||||||
|  |                     <div id="table2" class="table-editable"> | ||||||
|  |                         <table class="table table-bordered table-responsive-md table-striped text-center" id="colors2"> | ||||||
|  |                             <thead> | ||||||
|  |                                 <tr> | ||||||
|  |                                     <th class="text-center">Time</th> | ||||||
|  |                                     <th class="text-center">Color</th> | ||||||
|  |                                     <th class="text-center">Remove</th> | ||||||
|  |                                 </tr> | ||||||
|  |                             </thead> | ||||||
|  |                             </tbody> | ||||||
|  |                         </table> | ||||||
|  |                     </div> | ||||||
|  |                     <button type="button" class="btn btn-outline-success" id="copyColors">Copy from progressbar | ||||||
|  |                         colors</button> | ||||||
|  |  | ||||||
|  |                     <button type="button" class="btn btn-outline-success" id="addRow2">Add row</button> | ||||||
|  |                     </p> | ||||||
|  |                 </details> | ||||||
|  |                 <br> | ||||||
|  |  | ||||||
|  |  | ||||||
|  |                 <button type="button" class="btn btn-outline-success" id="applyLayout"><i class="bi bi-save"></i> Apply | ||||||
|  |                     settings</button> | ||||||
|  |  | ||||||
|  |                 <button type="button" class="btn btn-outline-success" id="saveLayout"><i class="bi bi-save"></i> Save as | ||||||
|  |                     startup settings (Layout | ||||||
|  |                     only)</button> | ||||||
|  |             </page> | ||||||
|  |  | ||||||
|  |             <page id="debug" class="pageC hidden flex-fill overflow-auto"> | ||||||
|  |                 <h1>Debug page</h1> | ||||||
|  |                 <div class="alert alert-danger" role="alert"> | ||||||
|  |                     <h4 class="alert-heading">Attention</h4> | ||||||
|  |                     <p>This is a debug page which should only be used by professionals. Changing any options below might | ||||||
|  |                         impact operation.</p> | ||||||
|  |                     <hr> | ||||||
|  |                     <p class="mb-0"><b>Proceed with caution.</b></p> | ||||||
|  |                 </div> | ||||||
|  |                 <label for="debugMode">Enable time variance display:</label> | ||||||
|  |                 <input type="checkbox" name="debugMode" id="debugModeEnable" value="true"><br><br> | ||||||
|  |  | ||||||
|  |                 <button type="button" class="btn btn-outline-success" id="applyDebug">Apply settings</button> | ||||||
|  |                 <br> | ||||||
|  |                 <hr> | ||||||
|  |                 <br> | ||||||
|  |  | ||||||
|  |                 <h3>Host information</h3> | ||||||
|  |                 <code id="systemInfo" class="overflow-auto"> | ||||||
|  |  | ||||||
|  |                 </code> | ||||||
|  |                 <h3>Raw server reponse</h3> | ||||||
|  |                 <code id="responeSnippet" style="width: 40%; display: inline-block;" class="overflow-auto"> | ||||||
|  |  | ||||||
|  |                 </code> | ||||||
|  |                 <br> | ||||||
|  |                 <hr> | ||||||
|  |                 <br> | ||||||
|  |                 <templateObj> | ||||||
|  |                     <table class="table table-bordered table-responsive-md table-striped text-center" id="colors1"> | ||||||
|  |                         <thead> | ||||||
|  |                             <tr> | ||||||
|  |                                 <th class="text-center">Time</th> | ||||||
|  |                                 <th class="text-center">Color</th> | ||||||
|  |                                 <th class="text-center">Remove</th> | ||||||
|  |                             </tr> | ||||||
|  |                         </thead> | ||||||
|  |                         <tr id="tableCopySource"> | ||||||
|  |                             <td contenteditable="false" class="time"> | ||||||
|  |                                 <input type="text" class="form-control " id="timeValue-ID" value="#VALUE#"> | ||||||
|  |                                 <value></value> | ||||||
|  |                             </td> | ||||||
|  |                             <td class="pt-3-half full" contenteditable="false"> | ||||||
|  |                                 <div class="clr-field" style="color: #bg-COLOR#;"> | ||||||
|  |                                     <button aria-labelledby="clr-open-label"></button> | ||||||
|  |                                     <input type="text" class="coloris" value="#COLOR#"> | ||||||
|  |                                 </div> | ||||||
|  |                                 </div> | ||||||
|  |                             </td> | ||||||
|  |                             <td> | ||||||
|  |                                 <span class="table-remove"><button type="button" | ||||||
|  |                                         class="btn btn-danger btn-rounded btn-sm my-0 deleteRow1"> | ||||||
|  |                                         Remove | ||||||
|  |                                     </button></span> | ||||||
|  |                             </td> | ||||||
|  |                         </tr> | ||||||
|  |                         </tbody> | ||||||
|  |                     </table> | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |                     <tr> | ||||||
|  |                         <td class="pt-3-half numVal" contenteditable="true">#VALUE#</td> | ||||||
|  |                         <td class="pt-3-half full" contenteditable="false"> | ||||||
|  |                             <div class="clr-field" style="color: #bg-COLOR#;"> | ||||||
|  |                                 <button aria-labelledby="clr-open-label"></button> | ||||||
|  |                                 <input id="demo-input1" type="text" class="coloris" value="#COLOR#"> | ||||||
|  |                             </div> | ||||||
|  |                             </div> | ||||||
|  |                         </td> | ||||||
|  |                         <td> | ||||||
|  |                             <span class="table-remove"><button type="button" | ||||||
|  |                                     class="btn btn-danger btn-rounded btn-sm my-0 deleteRow1"> | ||||||
|  |                                     Remove | ||||||
|  |                                 </button></span> | ||||||
|  |                         </td> | ||||||
|  |                     </tr> | ||||||
|  |                 </templateObj> | ||||||
|  |                 <script> | ||||||
|  |                     $('#duration2').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) | ||||||
|  |                         } | ||||||
|  |                     }); | ||||||
|  |                 </script> | ||||||
|  |  | ||||||
|  |                 <br><br> | ||||||
|  |             </page> | ||||||
|  |             <page id="about" class="pageC hidden flex-fill overflow-auto"> | ||||||
|  |                 <h1>About</h1> | ||||||
|  |                 Version: <b id="nodeSwVers"></b><br> | ||||||
|  |                 NodeJS Version: <b id="nodejsVers"></b><br> | ||||||
|  |  | ||||||
|  |             </page> | ||||||
|  |         </pages> | ||||||
|  |     </main> | ||||||
|  |     <script type="text/javascript" src="js/jsonview.js"></script> | ||||||
|  |     <script type="text/javascript" src="/js/interface.js"> </script> | ||||||
|  |     <script type="text/javascript"> | ||||||
|  |  | ||||||
|  |         Coloris({ | ||||||
|  |             el: '.coloris', | ||||||
|  |             alpha: false, | ||||||
|  |         }); | ||||||
|  |         $(function () { | ||||||
|  |             $('[data-toggle="tooltip"]').tooltip({ container: "body" }) | ||||||
|  |         })                         | ||||||
|  |     </script> | ||||||
|  |  | ||||||
|  | </body> | ||||||
|  |  | ||||||
|  | </html> | ||||||
| @@ -11,14 +11,21 @@ | |||||||
|     <meta name="author" content="TheGreydiamond"> |     <meta name="author" content="TheGreydiamond"> | ||||||
|  |  | ||||||
|     <link rel="stylesheet" href="css/styles.css?v=1.1"> |     <link rel="stylesheet" href="css/styles.css?v=1.1"> | ||||||
|  |      | ||||||
| </head> | </head> | ||||||
|  |  | ||||||
| <body onclick="updateFullscreen()"> | <body onclick="updateFullscreen()"> | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|     <div id="overlay" onclick="off()"> |     <div id="overlay" onclick="off()"> | ||||||
|         <div id="text">Message here</div> |         <div id="text">Message here</div> | ||||||
|     </div> |     </div> | ||||||
|  |  | ||||||
|  |     <div class="connectionWarning" id="warningBanner" style="display: none;"> | ||||||
|  |         Connection lost. Trying to reconnect... | ||||||
|  |     </div> | ||||||
|  |  | ||||||
|     <img src='SMPTE_Color_Bars.svg' class='testImg' id="testImg" style="display: none;"> |     <img src='SMPTE_Color_Bars.svg' class='testImg' id="testImg" style="display: none;"> | ||||||
|     </img> |     </img> | ||||||
|     <valueStore style="display: none;"> |     <valueStore style="display: none;"> | ||||||
| @@ -39,7 +46,7 @@ | |||||||
|              |              | ||||||
|         </div> |         </div> | ||||||
|     </div> |     </div> | ||||||
|     <script src="js/countdown.js"></script> |     <script src="js/reconnecting-websocket.min.js"></script> | ||||||
|     <script src="js/script.js"></script> |     <script src="js/script.js"></script> | ||||||
| </body> | </body> | ||||||
|  |  | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user