3
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										3
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							@@ -1,3 +1,6 @@
 | 
			
		||||
node_modules
 | 
			
		||||
rename.sh
 | 
			
		||||
data-persistence.json
 | 
			
		||||
log-journal.json
 | 
			
		||||
config.json
 | 
			
		||||
log-journal.json
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										25
									
								
								helpers.js
									
									
									
									
									
								
							
							
						
						
									
										25
									
								
								helpers.js
									
									
									
									
									
								
							@@ -29,4 +29,27 @@ function wrapBooleanConverter(stringBoolean, res) {
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
module.exports = { convertStringBooleanToBoolean, wrapBooleanConverter };
 | 
			
		||||
/**
 | 
			
		||||
 * 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 };
 | 
			
		||||
							
								
								
									
										109
									
								
								index.js
									
									
									
									
									
								
							
							
						
						
									
										109
									
								
								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()
 | 
			
		||||
  loggy.close(); // Close and write log
 | 
			
		||||
  process.exit(); // Quit the application
 | 
			
		||||
  
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
const server = app.listen(port);
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										69
									
								
								lang/de_de.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										69
									
								
								lang/de_de.json
									
									
									
									
									
										Normal file
									
								
							@@ -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"]
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										72
									
								
								lang/en_uk.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										72
									
								
								lang/en_uk.json
									
									
									
									
									
										Normal file
									
								
							@@ -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"]
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										70
									
								
								lang/proto_black.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										70
									
								
								lang/proto_black.json
									
									
									
									
									
										Normal file
									
								
							@@ -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. █"
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -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"}]
 | 
			
		||||
[{"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"}]
 | 
			
		||||
							
								
								
									
										28
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										28
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							@@ -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",
 | 
			
		||||
 
 | 
			
		||||
@@ -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"
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -55,7 +55,7 @@ html, body {
 | 
			
		||||
.progBar {
 | 
			
		||||
  appearance: none;
 | 
			
		||||
  height: 100%;
 | 
			
		||||
  width: 80%;
 | 
			
		||||
  width: 0%;
 | 
			
		||||
  border-radius: 0px;
 | 
			
		||||
  background-color: darkcyan;
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -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
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										146
									
								
								templates/brokenTranslation.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										146
									
								
								templates/brokenTranslation.html
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,146 @@
 | 
			
		||||
<!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>
 | 
			
		||||
            </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;">
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
            <page id="homeP" class="pageC flex-fill overflow-auto">
 | 
			
		||||
 | 
			
		||||
                <div class="container">
 | 
			
		||||
                    <div class=""
 | 
			
		||||
                        style=" display: flex;align-items: center;justify-content: center; flex-wrap: wrap; flex-direction: column;">
 | 
			
		||||
 | 
			
		||||
                        <h1>Oh no!</h1>
 | 
			
		||||
                        <h1>
 | 
			
		||||
                            <i class="bi bi-translate"></i>
 | 
			
		||||
                        </h1>
 | 
			
		||||
                        <h5>
 | 
			
		||||
                            There is a critical error with the current language template. Please select a diffrent
 | 
			
		||||
                            language.
 | 
			
		||||
                        </h5>
 | 
			
		||||
                        <label for="lang">Please choose a language: </label>
 | 
			
		||||
                        <select name="lang" id="lang">
 | 
			
		||||
                            <% it.additional.languages.forEach(function(lang){ %>
 | 
			
		||||
                                <option value="<%= lang %>">
 | 
			
		||||
                                    <%= lang %>
 | 
			
		||||
                                </option>
 | 
			
		||||
                                <% }) %>
 | 
			
		||||
                        </select>
 | 
			
		||||
                        <button id="applyLang" class="btn btn-outline-success">
 | 
			
		||||
                            Apply & Reload
 | 
			
		||||
                        </button>
 | 
			
		||||
 | 
			
		||||
                    </div>
 | 
			
		||||
                </div>
 | 
			
		||||
 | 
			
		||||
            </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" })
 | 
			
		||||
        })
 | 
			
		||||
        $("#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))
 | 
			
		||||
            })
 | 
			
		||||
        })
 | 
			
		||||
 | 
			
		||||
    </script>
 | 
			
		||||
 | 
			
		||||
</body>
 | 
			
		||||
 | 
			
		||||
</html>
 | 
			
		||||
@@ -48,25 +48,25 @@
 | 
			
		||||
                <li class="nav-item">
 | 
			
		||||
                    <a href="#homeP" class="nav-link active" aria-current="page" id="PageIndex">
 | 
			
		||||
                        <i class="bi bi-house-door"></i>
 | 
			
		||||
                        Home
 | 
			
		||||
                        <%= it.lang.sidebar.home %>
 | 
			
		||||
                    </a>
 | 
			
		||||
                </li>
 | 
			
		||||
                <li>
 | 
			
		||||
                    <a href="#settings" class="nav-link text-white" id="PageSettings">
 | 
			
		||||
                        <i class="bi bi-gear"></i>
 | 
			
		||||
                        Settings
 | 
			
		||||
                        <%= it.lang.sidebar.settings %>
 | 
			
		||||
                    </a>
 | 
			
		||||
                </li>
 | 
			
		||||
                <li>
 | 
			
		||||
                    <a href="#debug" class="nav-link text-white" id="PageDebug">
 | 
			
		||||
                        <i class="bi bi-bug"></i>
 | 
			
		||||
                        Debug
 | 
			
		||||
                        <%= it.lang.sidebar.debug %>
 | 
			
		||||
                    </a>
 | 
			
		||||
                </li>
 | 
			
		||||
                <li>
 | 
			
		||||
                    <a href="#about" class="nav-link text-white" id="PageAbout">
 | 
			
		||||
                        <i class="bi bi-info-circle"></i>
 | 
			
		||||
                        About
 | 
			
		||||
                        <%= it.lang.sidebar.about %>
 | 
			
		||||
                    </a>
 | 
			
		||||
                </li>
 | 
			
		||||
            </ul>
 | 
			
		||||
@@ -109,24 +109,24 @@
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
            <page id="homeP" class="pageC flex-fill overflow-auto">
 | 
			
		||||
                <h1>Home page</h1>
 | 
			
		||||
                <h1><%= it.lang.titles.home %></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">
 | 
			
		||||
                            <h3 class="d-flex"><%= it.lang.titles.preview %> <span class="helperTip" data-placement="right" title="<%= it.lang.hints.previewHint %>" 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">
 | 
			
		||||
                                        title="<%= it.lang.hints.copyHint %>" 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">
 | 
			
		||||
                                        title="<%= it.lang.hints.openInNewTab %>" data-toggle="tooltip">
 | 
			
		||||
                                        <a href="/timer" class="btn " target="_blank"><i
 | 
			
		||||
                                                class="bi bi-box-arrow-up-right"></i></a>
 | 
			
		||||
                                    </span>
 | 
			
		||||
@@ -136,23 +136,23 @@
 | 
			
		||||
                            </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">
 | 
			
		||||
                            <h3><%= it.lang.titles.mode %> <span class="helperTip" data-placement="right"
 | 
			
		||||
                                    title="<%= it.lang.hints.selectMode %>" 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>
 | 
			
		||||
                                <label class="btn btn-outline-primary" for="btnradio1"><%= it.lang.others.timer %></label>
 | 
			
		||||
 | 
			
		||||
                                <input type="radio" class="btn-check" name="btnradio" id="btnradio2" autocomplete="off">
 | 
			
		||||
                                <label class="btn btn-outline-primary" for="btnradio2">Clock</label>
 | 
			
		||||
                                <label class="btn btn-outline-primary" for="btnradio2"><%= it.lang.others.clock %></label>
 | 
			
		||||
 | 
			
		||||
                                <input type="radio" class="btn-check" name="btnradio" id="btnradio3" autocomplete="off">
 | 
			
		||||
                                <label class="btn btn-outline-primary" for="btnradio3">Black</label>
 | 
			
		||||
                                <label class="btn btn-outline-primary" for="btnradio3"><%= it.lang.others.black %></label>
 | 
			
		||||
 | 
			
		||||
                                <input type="radio" class="btn-check" name="btnradio" id="btnradio4" autocomplete="off">
 | 
			
		||||
                                <label class="btn btn-outline-primary" for="btnradio4">Testimage</label>
 | 
			
		||||
                                <label class="btn btn-outline-primary" for="btnradio4"><%= it.lang.others.test %></label>
 | 
			
		||||
                            </div>
 | 
			
		||||
                            <br>
 | 
			
		||||
                            <br>
 | 
			
		||||
@@ -183,12 +183,12 @@
 | 
			
		||||
                            <br>
 | 
			
		||||
                            <br>
 | 
			
		||||
                            <br>
 | 
			
		||||
                            <h3>Messaging <span class="helperTip" data-placement="right"
 | 
			
		||||
                                    title="Shows a given message on the timer view" data-toggle="tooltip">
 | 
			
		||||
                            <h3><%= it.lang.titles.messaging %> <span class="helperTip" data-placement="right"
 | 
			
		||||
                                    title="<%= it.lang.hints.messagingHint %>" data-toggle="tooltip">
 | 
			
		||||
                                    <i class="bi bi-question-circle-fill"></i>
 | 
			
		||||
                                </span></h3>
 | 
			
		||||
 | 
			
		||||
                            <input type="text" id="messageContent" class="form-control" placeholder="Message here"
 | 
			
		||||
                            <input type="text" id="messageContent" class="form-control" placeholder="<%= it.lang.placeholders.msgHere %>"
 | 
			
		||||
                                style="width: 50%;">
 | 
			
		||||
 | 
			
		||||
                            <br>
 | 
			
		||||
@@ -201,7 +201,7 @@
 | 
			
		||||
                    </div>
 | 
			
		||||
                </div>
 | 
			
		||||
                <br><br><br>
 | 
			
		||||
                <h3>Timer</h3>
 | 
			
		||||
                <h3><%= it.lang.others.timer %></h3>
 | 
			
		||||
                <div class="container">
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@@ -229,15 +229,12 @@
 | 
			
		||||
                            </div>
 | 
			
		||||
                        </div>
 | 
			
		||||
                        <h5>
 | 
			
		||||
                            Countdown to time
 | 
			
		||||
                            <%= it.lang.titles.countdownToTime %>
 | 
			
		||||
                        </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>
 | 
			
		||||
                        
 | 
			
		||||
@@ -250,17 +247,17 @@
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
            <page id="settings" class="pageC hidden flex-fill overflow-auto">
 | 
			
		||||
                <h1>Settings</h1>
 | 
			
		||||
                <label for="showTime">Show clock on Timer:</label>
 | 
			
		||||
                <h1><%= it.lang.sidebar.settings %></h1>
 | 
			
		||||
                <label for="showTime"><%= it.lang.labels.clockOnTimer %></label>
 | 
			
		||||
                <input type="checkbox" name="showTime" id="showTime"><br>
 | 
			
		||||
 | 
			
		||||
                <label for="showMillis">Show Milliseconds on Timer:</label>
 | 
			
		||||
                <label for="showMillis"><%= it.lang.labels.showMillis %></label>
 | 
			
		||||
                <input type="checkbox" name="showMillis" id="showMillis"><br>
 | 
			
		||||
 | 
			
		||||
                <label for="progBarShow">Show progressbar:</label>
 | 
			
		||||
                <label for="progBarShow"><%= it.lang.labels.showProgress %></label>
 | 
			
		||||
                <input type="checkbox" name="progBarShow" id="progBarShow"><br>
 | 
			
		||||
                <details>
 | 
			
		||||
                    <summary>Progressbar Colors</summary>
 | 
			
		||||
                    <summary><%= it.lang.labels.progbarColors %></summary>
 | 
			
		||||
                    <p>
 | 
			
		||||
                    <div id="table" class="table-editable">
 | 
			
		||||
                        <span class="table-add float-right mb-3 mr-2"><a href="#!" class="text-success"><i
 | 
			
		||||
@@ -268,9 +265,9 @@
 | 
			
		||||
                        <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>
 | 
			
		||||
                                    <th class="text-center"><%= it.lang.labels.time %></th>
 | 
			
		||||
                                    <th class="text-center"><%= it.lang.labels.color %></th>
 | 
			
		||||
                                    <th class="text-center"><%= it.lang.labels.remove %></th>
 | 
			
		||||
                                </tr>
 | 
			
		||||
                            </thead>
 | 
			
		||||
                            </tbody>
 | 
			
		||||
@@ -281,19 +278,19 @@
 | 
			
		||||
                    </p>
 | 
			
		||||
                </details>
 | 
			
		||||
                <hr>
 | 
			
		||||
                <label for="textColors">Enable Text Colors:</label>
 | 
			
		||||
                <label for="textColors"><%= it.lang.labels.enableTextClrs %></label>
 | 
			
		||||
                <input type="checkbox" name="textColors" id="textColors"><br>
 | 
			
		||||
                <details>
 | 
			
		||||
                    <summary>Text Colors</summary>
 | 
			
		||||
                    <summary><%= it.lang.labels.textClrs %></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>
 | 
			
		||||
                                    <th class="text-center"><%= it.lang.labels.time %></th>
 | 
			
		||||
                                    <th class="text-center"><%= it.lang.labels.color %></th>
 | 
			
		||||
                                    <th class="text-center"><%= it.lang.labels.remove %></th>
 | 
			
		||||
                                </tr>
 | 
			
		||||
                            </thead>
 | 
			
		||||
                            </tbody>
 | 
			
		||||
@@ -302,7 +299,7 @@
 | 
			
		||||
                    <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>
 | 
			
		||||
                    <button type="button" class="btn btn-outline-success" id="addRow2"><%= it.lang.labels.row %></button>
 | 
			
		||||
                    </p>
 | 
			
		||||
                </details>
 | 
			
		||||
                <br>
 | 
			
		||||
@@ -314,18 +311,30 @@
 | 
			
		||||
                <button type="button" class="btn btn-outline-success" id="saveLayout"><i class="bi bi-save"></i> Save as
 | 
			
		||||
                    startup settings (Layout
 | 
			
		||||
                    only)</button>
 | 
			
		||||
 | 
			
		||||
                <hr>
 | 
			
		||||
                <h2><%= it.lang.titles.uiSettings %></h2>
 | 
			
		||||
                <label for="lang"><%= it.lang.labels.language %>:</label>
 | 
			
		||||
                <select name="lang" id="lang">-
 | 
			
		||||
                  <% it.additional.languages.forEach(function(lang){ %>
 | 
			
		||||
                    <option value="<%= lang %>"><%= lang %></option>
 | 
			
		||||
                  <% }) %>
 | 
			
		||||
                </select>
 | 
			
		||||
                <button id="applyLang" class="btn btn-outline-success">
 | 
			
		||||
                    <%= it.lang.labels.apply %>
 | 
			
		||||
                </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>
 | 
			
		||||
                    <h4 class="alert-heading"><%= it.lang.titles.attention %></h4>
 | 
			
		||||
                    <p><%= it.lang.informationTexts.debugInfo %></p>
 | 
			
		||||
                    <hr>
 | 
			
		||||
                    <p class="mb-0"><b>Proceed with caution.</b></p>
 | 
			
		||||
                    <p class="mb-0"><b><%= it.lang.informationTexts.proceedCaution %></b></p>
 | 
			
		||||
                </div>
 | 
			
		||||
                <label for="debugMode">Enable time variance display:</label>
 | 
			
		||||
                <label for="debugMode"><%= it.lang.labels.timeVar %></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>
 | 
			
		||||
@@ -333,7 +342,7 @@
 | 
			
		||||
                <hr>
 | 
			
		||||
                <br>
 | 
			
		||||
 | 
			
		||||
                <h3>Host information</h3>
 | 
			
		||||
                <h3><%= it.lang.titles.hostinfo %></h3>
 | 
			
		||||
                <code id="systemInfo" class="overflow-auto">
 | 
			
		||||
 | 
			
		||||
                </code>
 | 
			
		||||
@@ -347,10 +356,10 @@
 | 
			
		||||
                <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><%= it.lang.labels.time %>
 | 
			
		||||
                                <th class="text-center"><%= it.lang.labels.time %></th>
 | 
			
		||||
                                <th class="text-center"><%= it.lang.labels.color %></th>
 | 
			
		||||
                                <th class="text-center"><%= it.lang.labels.remove %></th>
 | 
			
		||||
                            </tr>
 | 
			
		||||
                        </thead>
 | 
			
		||||
                        <tr id="tableCopySource">
 | 
			
		||||
@@ -374,9 +383,6 @@
 | 
			
		||||
                        </tr>
 | 
			
		||||
                        </tbody>
 | 
			
		||||
                    </table>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
                    <tr>
 | 
			
		||||
                        <td class="pt-3-half numVal" contenteditable="true">#VALUE#</td>
 | 
			
		||||
                        <td class="pt-3-half full" contenteditable="false">
 | 
			
		||||
@@ -412,7 +418,10 @@
 | 
			
		||||
                <h1>About</h1>
 | 
			
		||||
                Version: <b id="nodeSwVers"></b><br>
 | 
			
		||||
                NodeJS Version: <b id="nodejsVers"></b><br>
 | 
			
		||||
 | 
			
		||||
                <h2>About the translation</h2>
 | 
			
		||||
                Author: <%= it.lang._metadata.authors %><br>
 | 
			
		||||
                Language: <%= it.lang._metadata.lang %><br>
 | 
			
		||||
                Version: <%= it.lang._metadata.version %><br>
 | 
			
		||||
            </page>
 | 
			
		||||
        </pages>
 | 
			
		||||
    </main>
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user