diff --git a/.gitignore b/.gitignore index b3aed83..a7639ed 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,6 @@ node_modules rename.sh data-persistence.json +log-journal.json +config.json +log-journal.json diff --git a/helpers.js b/helpers.js index 7ffcad1..00c81aa 100644 --- a/helpers.js +++ b/helpers.js @@ -29,4 +29,27 @@ function wrapBooleanConverter(stringBoolean, res) { } } -module.exports = { convertStringBooleanToBoolean, wrapBooleanConverter }; \ No newline at end of file +/** + * Tries to parse a string to a JSON object. Returns false if invalid. Taken from https://stackoverflow.com/a/20392392/11317151 + * @param {String} jsonString A JSON String to parse + * @returns {Object/Boolean} JSON Object if valid or false otherwise + */ +function tryToParseJson(jsonString) { + try { + var o = JSON.parse(jsonString); + + // Handle non-exception-throwing cases: + // Neither JSON.parse(false) or JSON.parse(1234) throw errors, hence the type-checking, + // but... JSON.parse(null) returns null, and typeof null === "object", + // so we must check for that, too. Thankfully, null is falsey, so this suffices: + if (o && typeof o === "object") { + return o; + } + } + catch (e) { } + + return false; +} + + +module.exports = { convertStringBooleanToBoolean, wrapBooleanConverter, tryToParseJson }; \ No newline at end of file diff --git a/index.js b/index.js index ae109b2..96e65d5 100644 --- a/index.js +++ b/index.js @@ -4,6 +4,9 @@ const bodyParser = require("body-parser"); const ws = require('ws'); const helper = require("./helpers.js"); const loggy = require("./logging") +const Eta = require("eta"); +const _ = require("underscore") + loggy.init(true) loggy.log("Preparing server", "info", "Server"); @@ -49,14 +52,34 @@ currentState = { srvTime: 0, enableColoredText: true, debug: false, - sessionToken: Math.random().toString(36).substring(2, 15) + Math.random().toString(36).substring(2, 15), + sessionToken: Math.random().toString(36).substring(2, 15) + Math.random().toString(36).substring(2, 15) }; -const dataToBeWritten = {}; +let configObject = { + language: "en_uk" +} + +const tempJsonText = JSON.parse(fs.readFileSync("config.json", "utf8")); +configObject = _.extend(configObject, tempJsonText); +fs.writeFileSync("config.json", JSON.stringify(configObject)); currentState = Object.assign({}, currentState, loadedData); currentState.textColors = currentState.colorSegments +loggy.log("Searching for languages", "info", "Language") +const languagesRaw = fs.readdirSync("./lang"); +const languages = []; +for (let i = 0; i < languagesRaw.length; i++) { + if (languagesRaw[i].endsWith(".json")) { + languages.push(languagesRaw[i].replace(".json", "")); + } +} +loggy.log("Found " + languages.length + " languages", "info", "Language") + + + +loggy.log("Reading language file", "info", "Language") +let languageProfile = JSON.parse(fs.readFileSync("lang/" + configObject.language + ".json", "utf8")); loggy.log("Preparing websocket", "info", "Websocket"); const wsServer = new ws.Server({ noServer: true }); @@ -88,7 +111,24 @@ function updatedData() { loggy.log("Preparing routes", "info", "Server"); app.get("/", function (req, res) { const data = fs.readFileSync("templates/newAdminPanel.html", "utf8"); - res.send(data); + try { + res.send( + Eta.render(data, { + lang: languageProfile, + additional: { + languages: languages + } + })); + } catch (e) { + loggy.log("Error rendering template", "error", "Server"); + const dataN = fs.readFileSync("templates/brokenTranslation.html", "utf8"); + res.send( + Eta.render(dataN, { + additional: { + languages: languages + } + })); + } }); app.get("/timer", function (req, res) { @@ -299,7 +339,49 @@ app.get("/api/v1/storage/delete", function (req, res) { updatedData() }); -app.use(function(req, res, next) { +// UI Routes +// Returns an object containg all available languages +app.get("/api/ui/v1/lang/list", function handleLangList(req, res){ + const tempRespObject = { + status: "ok", + languages: languages + } + res.json(tempRespObject); +}) + +app.get("/api/ui/v1/lang/set", function (req, res) { + if(req.query.lang == undefined || req.query.lang == ""){ + res.json({ status: "error", reason: "Missing language" }); + return; + } + const testLang = req.query.lang; + loggy.log("Reloading language file", "info", "Language") + if(!fs.existsSync("lang/" + testLang + ".json")){ + loggy.log("Language reload failed, file does not exist", "error", "Language") + res.status(500).json({ status: "error", reason: "Language file not found" }); + return + } + const tempLang = fs.readFileSync("lang/" + testLang + ".json", "utf8"); + const tempLangObj = helper.tryToParseJson(tempLang); + if(!tempLangObj){ + loggy.log("Language reload failed, file is not valid", "error", "Language") + res.status(500).json({ status: "error", reason: "Language file is not valid" }); + return + } + if(tempLangObj._metadata == undefined){ + loggy.log("Language reload failed, file is not valid, metadata missing", "error", "Language") + res.status(500).json({ status: "error", reason: "Language file is not valid" }); + return + } + loggy.log("Language reloaded, loaded " + tempLangObj._metadata.lang + "@" + tempLangObj._metadata.version, "info", "Language") + configObject.language = req.query.lang; + languageProfile = tempLangObj; + res.status(200).json({ status: "ok" }); + fs.writeFileSync("config.json", JSON.stringify(configObject)); +}); + + +app.use(function (req, res, next) { res.status(404); loggy.log("Server responded with 404 error", "warn", "Server", true); @@ -323,18 +405,29 @@ app.use(function(req, res, next) { +/*app.use(function(err, req, res, next) { + console.error(err.stack); + if(String(err.stack).includes("TypeError: Cannot read properties of undefined")) { + const data = fs.readFileSync("templates/brokenTranslation.html", "utf8"); + res.send(data); + }else{ + res.status(500).send('Something broke!'); + } + +});*/ + + + loggy.log("Starting server", "info", "Server"); - -const port = 3005 +const port = 3005; process.on('SIGINT', function () { loggy.log("Caught interrupt signal and shutting down gracefully", "info", "Shutdown"); server.close(); // Make the express server stop - loggy.log("Goodbye! πŸ‘‹", "magic", "Shutdown", true) - loggy.close() - process.exit(); // Quit the application - + loggy.log("Goodbye! πŸ‘‹", "magic", "Shutdown", true) + loggy.close(); // Close and write log + process.exit(); // Quit the application }); const server = app.listen(port); diff --git a/lang/de_de.json b/lang/de_de.json new file mode 100644 index 0000000..9c14a61 --- /dev/null +++ b/lang/de_de.json @@ -0,0 +1,69 @@ +{ + "titles": { + "home": "Startseite", + "preview": "Vorschau", + "mode": "Modus", + "messaging": "Nachrichten", + "countdownToTime": "Auf Uhrzeit runterzΓ€hlen", + "attention": "Achtung", + "hostinfo": "Host Informationen" + }, + "sidebar": { + "home": "Startseite", + "settings": "Einstellungen", + "debug": "Debug", + "about": "Über" + }, + "hints": + { + "previewHint": "Eine Vorschau der Timeransicht.", + "modeHint": "", + "messagingHint": "Zeigt eine Nachricht auf der Timeransicht an.", + "copyHint": "Kopiert den Link zu der Countdown-Seite.", + "openInNewTab": "Γ–ffnet den Link in einem neuen Tab.", + "selectMode": "WΓ€hlt einen Modus fΓΌr die Timeransicht." + }, + "placeholders": { + "msgHere": "Message here" + }, + "others": + { + "timer": "Timer", + "clock": "Uhr", + "black": "Schwarz", + "test": "Testbild" + }, + "labels": + { + "clockOnTimer": "Zeigt die Uhrzeit auf dem Timer:", + "showMillis": "Zeigt Millisekunden auf dem Timer:", + "showProgress": "Zeige Fortschrittsbalken:", + "progbarColors": "Fortschrittsbalken Farben", + "time": "Zeit", + "color": "Farbe", + "remove": "Entfernen", + "enableTextClrs": "Text Farben aktivieren:", + "textClrs": "Text Farben", + "addRow": "Neue Zeile", + "timeVar": "Aktiviere zeitabweichungs display:" + }, + "untis": + { + "seconds": "Sekunden", + "minutes": "Minutes", + "hours": "Stunden", + "days": "Tage", + "weeks": "Wochen", + "months": "Monate", + "years": "Jahre" + }, + "informationTexts": { + "debugInfo": "Das hier ist eine debug seite welche nur von professionellen Personen verwendet werden sollte. ", + "proceedCaution": "Gehen Sie vorsichtig vor." + }, + "_metadata": { + "lang": "de", + "version": "1.0.0", + "authors": ["TheGreydiamond"] + } +} \ No newline at end of file diff --git a/lang/en_uk.json b/lang/en_uk.json new file mode 100644 index 0000000..0c0f6a4 --- /dev/null +++ b/lang/en_uk.json @@ -0,0 +1,72 @@ +{ + "titles": { + "home": "Homepage", + "preview": "Preview", + "mode": "Mode", + "messaging": "Messaging", + "countdownToTime": "Countdown to time", + "attention": "Attention", + "hostinfo": "Host information", + "uiSettings": "UI settings" + }, + "sidebar": { + "home": "Home", + "settings": "Settings", + "debug": "Debug", + "about": "About" + }, + "hints": + { + "previewHint": "A preview of what is currently visible on the countdown view", + "modeHint": "", + "messagingHint": "Shows a given message on the timer view", + "copyHint": "Copies the link to the timer view", + "openInNewTab": "Open the countdown view in a new tab", + "selectMode": "Select what to show on the countdown view" + }, + "placeholders": { + "msgHere": "Message here" + }, + "others": + { + "timer": "Timer", + "clock": "Clock", + "black": "Black", + "test": "Testimage" + }, + "labels": + { + "clockOnTimer": "Show clock on Timer:", + "showMillis": "Show Milliseconds on Timer:", + "showProgress": "Show progressbar:", + "progbarColors": "Progressbar Colors", + "time": "Time", + "color": "Color", + "remove": "Remove", + "enableTextClrs": "Enable Text Colours:", + "textClrs": "Text Colours", + "addRow": "Add Row", + "timeVar": "Enable time variance display:", + "language": "Select a language", + "apply": "Apply" + }, + "untis": + { + "seconds": "Seconds", + "minutes": "Minutes", + "hours": "Hours", + "days": "Days", + "weeks": "Weeks", + "months": "Months", + "years": "Years" + }, + "informationTexts": { + "debugInfo": "This is a debug page which should only be used by professionals. Changing any options below might impact operation.", + "proceedCaution": "Proceed with caution." + }, + "_metadata": { + "lang": "en", + "version": "1.0.0", + "authors": ["TheGreydiamond"] + } +} \ No newline at end of file diff --git a/lang/proto_black.json b/lang/proto_black.json new file mode 100644 index 0000000..d111cde --- /dev/null +++ b/lang/proto_black.json @@ -0,0 +1,70 @@ +{ + "titles": { + "home": "β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ", + "preview": "β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ", + "mode": "β–ˆβ–ˆβ–ˆβ–ˆ", + "messaging": "β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ", + "countdownToTime": "β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ β–ˆβ–ˆ β–ˆβ–ˆβ–ˆβ–ˆ", + "attention": "β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ", + "hostinfo": "β–ˆβ–ˆβ–ˆβ–ˆ β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ" + }, + "sidebar": { + "home": "β–ˆβ–ˆβ–ˆβ–ˆ", + "settings": "β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ", + "debug": "β–ˆβ–ˆβ–ˆβ–ˆβ–ˆ", + "about": "β–ˆβ–ˆβ–ˆβ–ˆβ–ˆ" + }, + "hints": + { + "previewHint": "β–ˆ β–ˆβ–ˆβ–ˆβ–ˆ β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ β–ˆβ–ˆβ–ˆβ–ˆ", + "modeHint": "", + "messagingHint": "β–ˆβ–ˆβ–ˆβ–ˆ β–ˆ β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ β–ˆβ–ˆ β–ˆβ–ˆβ–ˆβ–ˆβ–ˆ", + "copyHint": "β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ β–ˆβ–ˆβ–ˆ β–ˆβ–ˆβ–ˆβ–ˆ β–ˆβ–ˆ β–ˆβ–ˆβ–ˆ β–ˆβ–ˆβ–ˆβ–ˆβ–ˆ β–ˆβ–ˆβ–ˆβ–ˆ", + "openInNewTab": "β–ˆβ–ˆβ–ˆβ–ˆ β–ˆβ–ˆβ–ˆ β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ β–ˆβ–ˆβ–ˆβ–ˆ β–ˆ β–ˆ β–ˆβ–ˆβ–ˆ β–ˆβ–ˆβ–ˆ", + "selectMode": "β–ˆβ–ˆβ–ˆβ–ˆβ–ˆ β–ˆβ–ˆβ–ˆβ–ˆ β–ˆβ–ˆ β–ˆβ–ˆβ–ˆβ–ˆ β–ˆβ–ˆ β–ˆβ–ˆβ–ˆ β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ β–ˆβ–ˆβ–ˆβ–ˆ" + }, + "placeholders": { + "msgHere": "β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ β–ˆβ–ˆβ–ˆβ–ˆ" + }, + "others": + { + "timer": "β–ˆβ–ˆβ–ˆβ–ˆ", + "clock": "β–ˆβ–ˆβ–ˆβ–ˆβ–ˆ", + "black": "β–ˆβ–ˆβ–ˆβ–ˆ", + "test": "β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ" + }, + "labels": + { + "clockOnTimer": "β–ˆβ–ˆβ–ˆβ–ˆ β–ˆβ–ˆβ–ˆβ–ˆβ–ˆ β–ˆβ–ˆ β–ˆβ–ˆβ–ˆβ–ˆβ–ˆ:", + "showMillis": "β–ˆβ–ˆβ–ˆβ–ˆ β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ β–ˆβ–ˆ β–ˆβ–ˆβ–ˆβ–ˆβ–ˆ:", + "showProgress": "β–ˆβ–ˆβ–ˆβ–ˆ β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ:", + "progbarColors": "β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ β–ˆβ–ˆβ–ˆβ–ˆ", + "time": "β–ˆβ–ˆβ–ˆβ–ˆ", + "color": "β–ˆβ–ˆβ–ˆβ–ˆβ–ˆ", + "remove": "β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ", + "enableTextClrs": "β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ β–ˆβ–ˆβ–ˆβ–ˆ β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ:", + "textClrs": "β–ˆβ–ˆβ–ˆβ–ˆ β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ", + "addRow": "β–ˆβ–ˆβ–ˆ β–ˆβ–ˆβ–ˆ", + "timeVar": "β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ β–ˆβ–ˆβ–ˆβ–ˆ β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ:" + }, + "untis": + { + "seconds": "Seconds", + "minutes": "Minutes", + "hours": "Hours", + "days": "Days", + "weeks": "Weeks", + "months": "Months", + "years": "Years" + }, + "informationTexts": { + "debugInfo": "β–ˆβ–ˆβ–ˆβ–ˆ β–ˆβ–ˆ β–ˆ β–ˆβ–ˆβ–ˆβ–ˆβ–ˆ β–ˆβ–ˆβ–ˆβ–ˆ β–ˆβ–ˆβ–ˆβ–ˆβ–ˆ β–ˆβ–ˆβ–ˆβ–ˆβ–ˆ β–ˆβ–ˆβ–ˆβ–ˆ β–ˆβ–ˆ β–ˆβ–ˆβ–ˆβ–ˆ β–ˆβ–ˆ β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ. β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ β–ˆβ–ˆβ–ˆ β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ β–ˆβ–ˆβ–ˆβ–ˆβ–ˆ β–ˆβ–ˆβ–ˆβ–ˆβ–ˆ β–ˆβ–ˆβ–ˆβ–ˆβ–ˆ β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ.", + "proceedCaution": "β–ˆβ–ˆβ–ˆβ–ˆβ–ˆ β–ˆβ–ˆβ–ˆβ–ˆ β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ." + }, + "_metadata": { + "lang": "none", + "version": "1.0.0", + "authors": ["TheGreydiamond"], + "comment": "A test language without proper text and only black blocks. β–ˆ" + } +} \ No newline at end of file diff --git a/log-journal.json b/log-journal.json index 0c3da15..8dfc945 100644 --- a/log-journal.json +++ b/log-journal.json @@ -1 +1 @@ -[{"timestamp":"2022-03-29 20:16:25.083","level":"info","module":"Logging","message":"2022-03-29 20:16:25.083 [info] [Logging] Logging initialized"},{"timestamp":"2022-03-29 20:16:25.084","level":"info","module":"Server","message":"2022-03-29 20:16:25.084 [info] [Server] Preparing server"},{"timestamp":"2022-03-29 20:16:25.085","level":"info","module":"Server","message":"2022-03-29 20:16:25.085 [info] [Server] Preparing static routes"},{"timestamp":"2022-03-29 20:16:25.087","level":"info","module":"Server","message":"2022-03-29 20:16:25.087 [info] [Server] Preparing middlewares"},{"timestamp":"2022-03-29 20:16:25.088","level":"info","module":"Config","message":"2022-03-29 20:16:25.088 [info] [Config] Loading config"},{"timestamp":"2022-03-29 20:16:25.088","level":"info","module":"Websocket","message":"2022-03-29 20:16:25.088 [info] [Websocket] Preparing websocket"},{"timestamp":"2022-03-29 20:16:25.089","level":"info","module":"Server","message":"2022-03-29 20:16:25.089 [info] [Server] Preparing routes"},{"timestamp":"2022-03-29 20:16:25.091","level":"info","module":"Server","message":"2022-03-29 20:16:25.091 [info] [Server] Starting server"},{"timestamp":"2022-03-29 20:16:35.159","level":"info","module":"Shutdown","message":"2022-03-29 20:16:35.159 [info] [Shutdown] Caught interrupt signal and shutting down gracefully"}] \ No newline at end of file +[{"timestamp":"2022-05-12 18:53:40.121","level":"info","module":"Logging","message":"2022-05-12 18:53:40.121 [info] [Logging] Logging initialized"},{"timestamp":"2022-05-12 18:53:40.122","level":"info","module":"Server","message":"2022-05-12 18:53:40.122 [info] [Server] Preparing server"},{"timestamp":"2022-05-12 18:53:40.123","level":"info","module":"Server","message":"2022-05-12 18:53:40.123 [info] [Server] Preparing static routes"},{"timestamp":"2022-05-12 18:53:40.125","level":"info","module":"Server","message":"2022-05-12 18:53:40.125 [info] [Server] Preparing middlewares"},{"timestamp":"2022-05-12 18:53:40.125","level":"info","module":"Config","message":"2022-05-12 18:53:40.125 [info] [Config] Loading config"},{"timestamp":"2022-05-12 18:53:40.127","level":"info","module":"Language","message":"2022-05-12 18:53:40.127 [info] [Language] Searching for languages"},{"timestamp":"2022-05-12 18:53:40.127","level":"info","module":"Language","message":"2022-05-12 18:53:40.127 [info] [Language] Found 3 languages"},{"timestamp":"2022-05-12 18:53:40.127","level":"info","module":"Language","message":"2022-05-12 18:53:40.127 [info] [Language] Reading language file"},{"timestamp":"2022-05-12 18:53:40.128","level":"info","module":"Websocket","message":"2022-05-12 18:53:40.128 [info] [Websocket] Preparing websocket"},{"timestamp":"2022-05-12 18:53:40.128","level":"info","module":"Server","message":"2022-05-12 18:53:40.128 [info] [Server] Preparing routes"},{"timestamp":"2022-05-12 18:53:40.129","level":"info","module":"Server","message":"2022-05-12 18:53:40.129 [info] [Server] Starting server"},{"timestamp":"2022-05-12 18:53:41.756","level":"error","module":"Server","message":"2022-05-12 18:53:41.756 [error] [Server] Error rendering template"},{"timestamp":"2022-05-12 18:54:18.336","level":"error","module":"Server","message":"2022-05-12 18:54:18.336 [error] [Server] Error rendering template"},{"timestamp":"2022-05-12 18:54:20.275","level":"info","module":"Shutdown","message":"2022-05-12 18:54:20.275 [info] [Shutdown] Caught interrupt signal and shutting down gracefully"}] \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 68f645e..9c669c4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -15,12 +15,14 @@ "bootstrap-icons": "^1.8.1", "colors": "^1.4.0", "darkreader": "^4.9.44", + "eta": "^1.12.3", "express": "^4.17.3", "flatpickr": "^4.6.11", "jquery": "^3.6.0", "js-cookie": "^3.0.1", "less": "^3.13", "mdbootstrap": "^4.20.0", + "underscore": "^1.13.3", "ws": "^8.5.0" } }, @@ -215,6 +217,17 @@ "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=" }, + "node_modules/eta": { + "version": "1.12.3", + "resolved": "https://registry.npmjs.org/eta/-/eta-1.12.3.tgz", + "integrity": "sha512-qHixwbDLtekO/d51Yr4glcaUJCIjGVJyTzuqV4GPlgZo1YpgOKG+avQynErZIYrfM6JIJdtiG2Kox8tbb+DoGg==", + "engines": { + "node": ">=6.0.0" + }, + "funding": { + "url": "https://github.com/eta-dev/eta?sponsor=1" + } + }, "node_modules/etag": { "version": "1.8.1", "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", @@ -694,6 +707,11 @@ "node": ">= 0.6" } }, + "node_modules/underscore": { + "version": "1.13.3", + "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.13.3.tgz", + "integrity": "sha512-QvjkYpiD+dJJraRA8+dGAU4i7aBbb2s0S3jA45TFOvg2VgqvdCDd/3N6CqA8gluk1W91GLoXg5enMUx560QzuA==" + }, "node_modules/unpipe": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", @@ -881,6 +899,11 @@ "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=" }, + "eta": { + "version": "1.12.3", + "resolved": "https://registry.npmjs.org/eta/-/eta-1.12.3.tgz", + "integrity": "sha512-qHixwbDLtekO/d51Yr4glcaUJCIjGVJyTzuqV4GPlgZo1YpgOKG+avQynErZIYrfM6JIJdtiG2Kox8tbb+DoGg==" + }, "etag": { "version": "1.8.1", "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", @@ -1238,6 +1261,11 @@ "mime-types": "~2.1.24" } }, + "underscore": { + "version": "1.13.3", + "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.13.3.tgz", + "integrity": "sha512-QvjkYpiD+dJJraRA8+dGAU4i7aBbb2s0S3jA45TFOvg2VgqvdCDd/3N6CqA8gluk1W91GLoXg5enMUx560QzuA==" + }, "unpipe": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", diff --git a/package.json b/package.json index 0583105..b751e7e 100644 --- a/package.json +++ b/package.json @@ -15,12 +15,14 @@ "bootstrap-icons": "^1.8.1", "colors": "^1.4.0", "darkreader": "^4.9.44", + "eta": "^1.12.3", "express": "^4.17.3", "flatpickr": "^4.6.11", "jquery": "^3.6.0", "js-cookie": "^3.0.1", "less": "^3.13", "mdbootstrap": "^4.20.0", + "underscore": "^1.13.3", "ws": "^8.5.0" } } diff --git a/static/css/styles.css b/static/css/styles.css index 953a446..dcc820c 100644 --- a/static/css/styles.css +++ b/static/css/styles.css @@ -55,7 +55,7 @@ html, body { .progBar { appearance: none; height: 100%; - width: 80%; + width: 0%; border-radius: 0px; background-color: darkcyan; } diff --git a/static/js/interface.js b/static/js/interface.js index 4822c9e..be723bc 100644 --- a/static/js/interface.js +++ b/static/js/interface.js @@ -50,6 +50,19 @@ $(function () { jsonview.expand(tree2); }) + $("#applyLang").on("click", function (event) { + const lang = $("#lang").val() + saveOption("/api/ui/v1/lang/set?lang=" + lang, function handleLangSelect(event, xmlHttp) { + const temp = JSON.parse(xmlHttp.responseText) + if(temp.status == "error") { + alert("Request failed reason: " + temp.reason) + } else { + location.reload() + } + console.log(JSON.parse(xmlHttp.responseText)) + }) + }) + $("#addRow").on("click", function (event) { const tableEntryDom = document.getElementById("tableCopySource").cloneNode(true) let temp = tableEntryDom.innerHTML diff --git a/templates/brokenTranslation.html b/templates/brokenTranslation.html new file mode 100644 index 0000000..ee0cc76 --- /dev/null +++ b/templates/brokenTranslation.html @@ -0,0 +1,146 @@ + + + + + + + + openCountdown - Admin + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + +
+
+ +

Oh no!

+

+ +

+
+ There is a critical error with the current language template. Please select a diffrent + language. +
+ + + + +
+
+ +
+
+
+ + + + + + + \ No newline at end of file diff --git a/templates/newAdminPanel.html b/templates/newAdminPanel.html index 6282241..5d533b5 100644 --- a/templates/newAdminPanel.html +++ b/templates/newAdminPanel.html @@ -48,25 +48,25 @@
  • - Settings + <%= it.lang.sidebar.settings %>
  • - Debug + <%= it.lang.sidebar.debug %>
  • - About + <%= it.lang.sidebar.about %>
  • @@ -109,24 +109,24 @@ -

    Home page

    +

    <%= it.lang.titles.home %>

    -

    Preview +

    <%= it.lang.titles.preview %>
    + title="<%= it.lang.hints.copyHint %>" data-toggle="tooltip"> + title="<%= it.lang.hints.openInNewTab %>" data-toggle="tooltip"> @@ -136,23 +136,23 @@
    -

    Mode +

    <%= it.lang.titles.mode %>

    - + - + - + - +


    @@ -183,12 +183,12 @@


    -

    Messaging +

    <%= it.lang.titles.messaging %>

    -
    @@ -201,7 +201,7 @@




    -

    Timer

    +

    <%= it.lang.others.timer %>

    @@ -229,15 +229,12 @@
    - Countdown to time + <%= it.lang.titles.countdownToTime %>
    - - -
    @@ -250,17 +247,17 @@