diff options
author | rstular <rok@stular.eu> | 2020-02-17 15:15:55 +0100 |
---|---|---|
committer | rstular <rok@stular.eu> | 2020-02-17 15:15:55 +0100 |
commit | fefeee7ccf1b6fb6a133c8b9c5eb07b1760c2d94 (patch) | |
tree | 803184e820a5002418a19ce4685d4621b7910b76 | |
parent | neki sm delu, sam ne do konca (diff) | |
download | beziapp-fefeee7ccf1b6fb6a133c8b9c5eb07b1760c2d94.tar beziapp-fefeee7ccf1b6fb6a133c8b9c5eb07b1760c2d94.tar.gz beziapp-fefeee7ccf1b6fb6a133c8b9c5eb07b1760c2d94.tar.bz2 beziapp-fefeee7ccf1b6fb6a133c8b9c5eb07b1760c2d94.tar.lz beziapp-fefeee7ccf1b6fb6a133c8b9c5eb07b1760c2d94.tar.xz beziapp-fefeee7ccf1b6fb6a133c8b9c5eb07b1760c2d94.tar.zst beziapp-fefeee7ccf1b6fb6a133c8b9c5eb07b1760c2d94.zip |
-rw-r--r-- | css/styles.css | 48 | ||||
-rw-r--r-- | directory.json | 4 | ||||
-rw-r--r-- | index.html | 6 | ||||
-rw-r--r-- | js/app.js | 12 | ||||
-rw-r--r-- | js/initialize.js | 36 | ||||
-rw-r--r-- | js/lib/xss.js | 1 | ||||
-rw-r--r-- | js/login.js | 19 | ||||
-rw-r--r-- | js/messaging.js | 462 | ||||
-rw-r--r-- | js/timetable.js | 2 | ||||
-rw-r--r-- | login.html | 5 | ||||
-rw-r--r-- | logout.html | 6 | ||||
-rw-r--r-- | pages/about.html | 11 | ||||
-rw-r--r-- | pages/absences.html | 11 | ||||
-rw-r--r-- | pages/changelog.html | 9 | ||||
-rw-r--r-- | pages/grades.html | 11 | ||||
-rw-r--r-- | pages/gradings.html | 11 | ||||
-rw-r--r-- | pages/messaging.html | 101 | ||||
-rw-r--r-- | pages/privacypolicy.html | 2 | ||||
-rw-r--r-- | pages/teachers.html | 11 | ||||
-rw-r--r-- | pages/timetable.html | 11 | ||||
-rw-r--r-- | pages/tos.html | 2 | ||||
-rw-r--r-- | sw.js | 194 |
22 files changed, 556 insertions, 419 deletions
diff --git a/css/styles.css b/css/styles.css index 73c6be6..8ad12a0 100644 --- a/css/styles.css +++ b/css/styles.css @@ -3,6 +3,12 @@ --color-secondary: rgba(0, 77, 50, 1); --color-accent: rgba(0, 156, 101, 1); --color-primary-light: rgba(230, 250, 231, 1); + --color-invalid: rgba(192, 0, 0, 1); + --background-color: rgba(255, 255, 255, 1); +} + +body { + background: var(--background-color); } .title-primary { @@ -99,4 +105,46 @@ a.collection-item { -ms-user-select: none; user-select: none; -webkit-tap-highlight-color: transparent; +} + +/* label focus color */ + +.input-field input[type=text]:focus+label { + color: var(--color-primary); +} + +/* label underline focus color */ + +.input-field input[type=text]:focus { + border-bottom: 1px solid var(--color-primary) !important; + box-shadow: 0 1px 0 0 var(--color-primary) !important; +} + +/* valid color */ + +.input-field input[type=text].valid { + border-bottom: 1px solid var(--color-secondary); + box-shadow: 0 1px 0 0 var(--color-secondary); +} + +/* invalid color */ + +.input-field input[type=text].invalid { + border-bottom: 1px solid var(--color-invalid); + box-shadow: 0 1px 0 0 var(--color-invalid); +} + +/* icon prefix focus color */ + +.input-field .prefix.active { + color: var(--color-primary); +} + +.input-field textarea:not([readonly]):focus+label { + color: var(--color-primary) !important; +} + +.input-field textarea:not([readonly]):focus { + border-bottom: 1px solid var(--color-primary) !important; + box-shadow: 0 1px 0 0 var(--color-primary) !important; }
\ No newline at end of file diff --git a/directory.json b/directory.json new file mode 100644 index 0000000..6a50675 --- /dev/null +++ b/directory.json @@ -0,0 +1,4 @@ +{ + "Anton Luka Šijanec": 6326, + "Rok Štular": 5313 +}
\ No newline at end of file @@ -9,10 +9,10 @@ <script type="text/javascript" src="/js/lib/localforage.min.js"></script> <script type="text/javascript" src="/js/initialize.js"></script> - + <link rel="manifest" href="/manifest.json"> <script src="/js/app.js"></script> - <link rel="shortcut icon" type="image/png" href="/favicon.png"/> + <link rel="shortcut icon" type="image/png" href="/favicon.png" /> <!-- iOS support --> <link rel="apple-touch-icon" href="/img/icons/icon_96.png"> @@ -23,4 +23,4 @@ <body> </body> -</html> +</html>
\ No newline at end of file @@ -5,12 +5,12 @@ if ("serviceWorker" in navigator) { } // Listen to messages from service workers. -if(navigator.serviceWorker) { -navigator.serviceWorker.addEventListener('message', (event) => { - if (event.data.msg === "install") { - window.location.replace("/index.html"); - } -}); +if (navigator.serviceWorker) { + navigator.serviceWorker.addEventListener('message', (event) => { + if (event.data.msg === "install") { + window.location.replace("/index.html"); + } + }); } if (location.protocol != 'https:') { diff --git a/js/initialize.js b/js/initialize.js index 2023921..ca29e2f 100644 --- a/js/initialize.js +++ b/js/initialize.js @@ -1,15 +1,13 @@ function getUrlParameter(sParam) { - var sPageURL = window.location.search.substring(1), - sURLVariables = sPageURL.split('&'), - sParameterName, - i; - for (i = 0; i < sURLVariables.length; i++) { - sParameterName = sURLVariables[i].split('='); - if (sParameterName[0] === sParam) { - return sParameterName[1] === undefined ? true : decodeURIComponent(sParameterName[1]); - } + const url_params = new URLSearchParams(window.location.search); + const found_param = url_params.get(sParam); + if (found_param === null) { + return "" + } else { + return found_param } -}; +} + function setupStorage() { promises_to_run = [ localforage.setItem("logged_in", false), @@ -21,7 +19,8 @@ function setupStorage() { localforage.setItem("gradings", []), localforage.setItem("grades", []), localforage.setItem("absences", {}), - localforage.setItem("messages", {}) + localforage.setItem("messages", {}), + localforage.setItem("directory", {}) ]; Promise.all(promises_to_run) @@ -36,15 +35,20 @@ localforage.getItem("logged_in") // This code runs once the value has been loaded // from the offline store. if (value === null) { + // Setup the storage if it doesn't exist setupStorage(); } else if (value === false) { + // If storage exists, but user isn't logged in, redirect to login window.location.replace("/login.html"); } else { - if(getUrlParameter("m")) { - window.location.replace("pages/messaging.html?"+getUrlParameter("m")); - } else { - window.location.replace("/pages/timetable.html"); - } + // User is logged in, execute appropriate action + + if (getUrlParameter("m") !== "") { + window.location.replace("/pages/messaging.html?m=" + getUrlParameter("m")); + } else { + window.location.replace("/pages/timetable.html"); + } + } } ).catch( diff --git a/js/lib/xss.js b/js/lib/xss.js index bddbdd8..e0a6ba0 100644 --- a/js/lib/xss.js +++ b/js/lib/xss.js @@ -1611,4 +1611,3 @@ module.exports = { }; },{}]},{},[2]); - diff --git a/js/login.js b/js/login.js index 6a68d98..aba0fa3 100644 --- a/js/login.js +++ b/js/login.js @@ -7,17 +7,18 @@ document.addEventListener("DOMContentLoaded", () => { function setupEventListeners() { // Setup login button listener - $("#login-button").click(function () { + $("#login-button").click(() => { login(); }); - window.addEventListener("keyup", function(event) { - // Number 13 is the "Enter" key on the keyboard - if (event.keyCode === 13) { - // Cancel the default action, if needed - event.preventDefault(); - login(); - } - }); + + window.addEventListener("keyup", (event) => { + // Number 13 is the "Enter" key on the keyboard + if (event.keyCode === 13) { + // Cancel the default action, if needed + event.preventDefault(); + login(); + } + }); } // Handle login button click diff --git a/js/messaging.js b/js/messaging.js index 42bbd0b..4004147 100644 --- a/js/messaging.js +++ b/js/messaging.js @@ -1,3 +1,10 @@ +const API_ENDPOINT = "https://gimb.tk/test.php"; +const DIRECTORY_URL = "/directory.json"; +// const API_ENDPOINT = "http://localhost:5000/test.php"; + +// "Global" object for name directory +var directory = null; + async function checkLogin() { localforage.getItem("logged_in").then(function (value) { // This code runs once the value has been loaded @@ -11,31 +18,72 @@ async function checkLogin() { }); } -function htmlEncode(value){ - // Create a in-memory element, set its inner text (which is automatically encoded) - // Then grab the encoded contents back out. The element never exists on the DOM. - return $('<textarea/>').text(value).html(); +// -----------HTML HELPERS----------- +function htmlEncode(value) { + // Create a in-memory element, set its inner text (which is automatically encoded) + // Then grab the encoded contents back out. The element never exists on the DOM. + return $("<textarea/>").text(value).html(); } -function htmlDecode(value){ - return $('<textarea/>').html(value).text(); +function htmlDecode(value) { + return $("<textarea/>").html(value).text(); } +// --------------------------------- -const API_ENDPOINT = "https://gimb.tk/test.php"; -// const API_ENDPOINT = "http://localhost:5000/test.php"; +// Try to fetch name:id directory +function loadDirectory() { + $.ajax({ + url: DIRECTORY_URL, + crossDomain: true, -localforage.setItem('directory', { -"Anton Luka Šijanec": 6326, -"Rok Štular": 5313 -}).then(function (value) { - // Do other things once the value has been saved. - console.log("fake directory set"); -}).catch(function(err) { - // This code runs if there were any errors - M.toast({ html: "Unable to set fake directory."}); - console.log(err); -}); + dataType: "json", + cache: false, + type: "GET", + + success: (data) => { + // If we were able to retrieve it, update the saved directory + localforage.setItem("directory", data); + directory = data; + // Populate autocomplete + populateAutocomplete(); + }, + + error: () => { + // Otherwise, try to retrieve stored directory + localforage.getItem("directory").then((stored_directory) => { + if (stored_directory === null) { + // If unable, set directory to null (so other functions know that we don't have it) + M.toast({ html: "Name directory not set, sending disabled" }); + directory = null; + // Disable send button + document.getElementById("msg-send").disabled = true; + } else { + directory = stored_directory; + // Populate autocomplete + populateAutocomplete(); + } + }); + } + }); +} + +function populateAutocomplete() { + let elems = document.querySelectorAll('.autocomplete-fullname'); + + // vse editam v nanotu + let autocomplete_entries = directory; + for (let variableKey in autocomplete_entries) { + autocomplete_entries[variableKey] = null; + } + M.Autocomplete.init(elems, { + data: autocomplete_entries, + onAutocomplete: validateName, + minLength: 0 + }); +} + +// Function to toggle loading bar function setLoading(state) { if (state) { $("#loading-bar").removeClass("hidden"); @@ -43,6 +91,7 @@ function setLoading(state) { $("#loading-bar").addClass("hidden"); } } + // Function, responsible for fetching and displaying data async function loadMessages(force_refresh = true, katera = 0) { setLoading(true); @@ -58,8 +107,9 @@ async function loadMessages(force_refresh = true, katera = 0) { messages = value; }) ]; + Promise.all(promises_to_run).then(() => { - // If we don't have a list of teachers, query it + if (messages === null || force_refresh) { $.ajax({ url: API_ENDPOINT, @@ -68,18 +118,20 @@ async function loadMessages(force_refresh = true, katera = 0) { "u": username, "p": password, "m": "fetchsporocilaseznam", - "a": katera // prejeta + "a": katera // Message type, see API doc for details }, dataType: "json", cache: false, type: "GET", + success: (data) => { // If data is null, the request failed if (data === null) { M.toast({ html: "Request failed!" }); setLoading(false); } else { - // Save teachers & populate table + // Save messages & populate view + console.log(data); localforage.setItem("messages", data).then((value) => { messages = value; displayData(); @@ -100,6 +152,7 @@ async function loadMessages(force_refresh = true, katera = 0) { } }); } + async function loadMsg(id) { setLoading(true); // Load required data @@ -111,111 +164,116 @@ async function loadMsg(id) { password = value; }), ]; - Promise.all(promises_to_run).then(() => { - $.ajax({ - url: API_ENDPOINT, - crossDomain: true, - data: { - "u": username, - "p": password, - "m": "fetchsporocilo", - "a": id - }, - dataType: "json", - cache: false, - type: "GET", - success: (data) => { - // If data is null, the request failed - if (data === null) { - M.toast({ html: "Unable to receive the message, Request failed!" }); - setLoading(false); - } else { - displayMessage(id, data); - setLoading(false); - } - }, - error: () => { - M.toast({ html: "Error fetching message, No Internet connnection?" }); + Promise.all(promises_to_run).then(() => { + $.ajax({ + url: API_ENDPOINT, + crossDomain: true, + data: { + "u": username, + "p": password, + "m": "fetchsporocilo", + "a": id + }, + dataType: "json", + cache: false, + type: "GET", + success: (data) => { + // If data is null, the request failed + if (data === null) { + M.toast({ html: "Unable to receive the message, Request failed!" }); + setLoading(false); + } else { + displayMessage(id, data); setLoading(false); } + }, - }) + error: () => { + M.toast({ html: "Error fetching message, No Internet connnection?" }); + setLoading(false); + } + + }) }); } + + async function deleteMsg(id) { setLoading(true); // Load required data let promises_to_run = [ localforage.getItem("username").then((value) => { username = value; - }), localforage.getItem("password").then((value) => { + }), localforage.getItem("password").then((value) => { password = value; }), ]; Promise.all(promises_to_run).then(() => { - $.ajax({ - url: API_ENDPOINT, - crossDomain: true, - data: { - "u": username, - "p": password, - "m": "izbrisisporocilo", - "a": id - }, - dataType: "json", - cache: false, - type: "GET", - success: (data) => { - // If data is null, the request failed - if (data === null) { - M.toast({ html: "Unable to delete the message, Request failed!" }); - setLoading(false); - } else { - document.getElementById("msg_box-"+id).remove(); - setLoading(false); - } - }, - - error: () => { - M.toast({ html: "Unable to delete the message, No Internet connnection?" }); + $.ajax({ + url: API_ENDPOINT, + crossDomain: true, + data: { + "u": username, + "p": password, + "m": "izbrisisporocilo", + "a": id + }, + dataType: "json", + cache: false, + type: "GET", + success: (data) => { + // If data is null, the request failed + if (data === null) { + M.toast({ html: "Unable to delete the message, Request failed!" }); + setLoading(false); + } else { + document.getElementById("msg-box-" + id).remove(); setLoading(false); } + }, - }) + error: () => { + M.toast({ html: "Unable to delete the message, No Internet connnection?" }); + setLoading(false); + } + + }) }); } + function displayMessage(id, data) { - document.getElementById("msg_body-"+id).innerHTML = filterXSS(data["telo"]); + document.getElementById("msg-body-" + id).innerHTML = filterXSS(data["telo"]); } + // Function for displaying data function displayData() { - var msg_list = document.getElementById("msg_list"); - msg_list.innerHTML = ""; + let msg_list = document.getElementById("msg_list"); + msg_list.innerHTML = ""; messages.forEach(element => { - if(element["zadeva"].substr(0, 14) != "beziapp-ctlmsg") - msg_list.innerHTML += '<div class="col s12 m6" id="msg_box-'+ -filterXSS(element["id"])+ -'"><div class="card blue-grey darken-1"><div class="card-content white-text"><span class="card-title">'+ -filterXSS(element["zadeva"])+ -'</span><p id="msg_body-'+ -filterXSS(element["id"])+ -'"><button class="btn waves-effect waves-light" onclick=loadMsg("'+ -filterXSS(element["id"])+ -'"); type="submit">Load message body<i class="material-icons right">system_update</i></button></p></div><div class="card-action"><a href=javascript:deleteMsg("'+ -filterXSS(element["id"])+ -'");><i class="material-icons">delete</i></a><a href=\'javascript:document.getElementById("full_name").value="'+ -filterXSS(element["posiljatelj"])+ -'";document.getElementById("msg_subject").value="Re: '+ -filterXSS(element["zadeva"])+ -'";M.updateTextFields();document.getElementById("navigation-main").scrollIntoView();\'><i class="material-icons">reply</i></a>'+ -filterXSS(element["posiljatelj"])+" » "+filterXSS(element["datum"]["dan"])+". "+filterXSS(element["datum"]["mesec"])+". "+filterXSS(element["datum"]["leto"])+" at "+ -filterXSS(element["cas"]["ura"])+":"+filterXSS(element["cas"]["minuta"])+ -'</div></div></div>'; + if (element["zadeva"].substr(0, 14) != "beziapp-ctlmsg") + msg_list.innerHTML += '<div class="col s12 m6" id="msg_box-' + + filterXSS(element["id"]) + + '"><div class="card blue-grey darken-1"><div class="card-content white-text"><span class="card-title">' + + filterXSS(element["zadeva"]) + + '</span><p id="msg_body-' + + filterXSS(element["id"]) + + '"><button class="btn waves-effect waves-light" onclick=loadMsg("' + + filterXSS(element["id"]) + + '"); type="submit">Load message body<i class="material-icons right">system_update</i></button></p></div><div class="card-action"><a href=javascript:deleteMsg("' + + filterXSS(element["id"]) + + '");><i class="material-icons">delete</i></a><a href=\'javascript:document.getElementById("full_name").value="' + + filterXSS(element["posiljatelj"]) + + '";document.getElementById("msg_subject").value="Re: ' + + filterXSS(element["zadeva"]) + + '";M.updateTextFields();document.getElementById("navigation-main").scrollIntoView();\'><i class="material-icons">reply</i></a>' + + filterXSS(element["posiljatelj"]) + " » " + filterXSS(element["datum"]["dan"]) + ". " + filterXSS(element["datum"]["mesec"]) + ". " + filterXSS(element["datum"]["leto"]) + " at " + + filterXSS(element["cas"]["ura"]) + ":" + filterXSS(element["cas"]["minuta"]) + + '</div></div></div>'; }); } -async function sendMessage(number, subject, bofdy) { +async function sendMessage(recipient_number, subject, body) { setLoading(true); let promises_to_run = [ localforage.getItem("username").then((value) => { @@ -226,117 +284,113 @@ async function sendMessage(number, subject, bofdy) { }), ]; Promise.all(promises_to_run).then(() => { - $.ajax({ - url: API_ENDPOINT, - crossDomain: true, - data: { - "u": username, - "p": password, - "m": "posljisporocilo", - "a": number, - "b": subject, - "c": bofdy - }, - dataType: "json", - cache: false, - type: "POST", // big data not good, maybe u wanna many charzz - success: (data) => { - // we CAN't know wether the mesgg was delievered - M.toast({ html: "Message was probably sent, but check the Sent folder to be sure!" }); - setLoading(false); - }, - error: () => { - M.toast({ html: "Error sending message, No Internet connnection?" }); - setLoading(false); - } - }) + $.ajax({ + url: API_ENDPOINT, + crossDomain: true, + data: { + "u": username, + "p": password, + "m": "posljisporocilo", + "a": recipient_number, + "b": subject, + "c": body + }, + + dataType: "json", + cache: false, + + type: "POST", + success: () => { + // we CAN'T know wether the mesgg was delievered + M.toast({ html: "Message was <i>probably</i> sent, check the Sent folder to be sure!" }); + setLoading(false); + }, + error: () => { + M.toast({ html: "Error sending message, no Internet connnection?" }); + setLoading(false); + } + }) }); } + function validateName() { - localforage.getItem('directory').then(function(value) { - if(value == null) { - M.toast({ html: "Unable to read directory of people. Name could not be verified. Directory is empty."}); + if (directory !== null) { + + if ($("#full-name").val() in directory) { + $("#full-name").addClass("valid"); + $("#full-name").removeClass("invalid"); + document.getElementById("msg-send").disabled = false; + } else { + $("#full-name").addClass("invalid"); + $("#full-name").removeClass("valid"); + document.getElementById("msg-send").disabled = true; + } + + } +} + +// Setup event listeners for buttons +function setupEventListeners() { + // Button to add a photo + $("#msg-add-photo").click(() => { + let input = document.createElement("input"); + input.type = "file"; + input.onchange = (e) => { + // getting a hold of the file reference + let file = e.target.files[0]; + // setting up the reader + let reader = new FileReader(); + reader.readAsDataURL(file); // this is reading as data url + // here we tell the reader what to do when it's done reading... + reader.onload = readerEvent => { + additionalstufftoaddtomessage += '<br><img src="' + readerEvent.target.result + '" />'; // this is the content! + M.toast({ html: "Image added as an attachment." }); } - var evals = value; - for (var variableKey in evals){ - if (evals.hasOwnProperty(variableKey)){ - evals[variableKey] = null; - } - } - array =Object.getOwnPropertyNames(evals); - if(array.includes(document.getElementById("full_name").value)) { - document.getElementById("full_name").classList.add("valid"); - document.getElementById("msg_send").disabled = false; - } else { - document.getElementById("full_name").classList.add("invalid"); - document.getElementById("msg_send").disabled = true; - } - }).catch(function(err) { - M.toast({ html: "Unable to read directory of people. Name could not be verified."}); + } + input.click(); + }); + + // Verify recipient when input loses focus + $("#full-name").on("blur", validateName); + + // Button to send message + $("#msg-send").click(() => { + localforage.getItem("directory").then(function (value) { + sendMessage(value[document.getElementById("full-name").value], document.getElementById("msg-subject").value, + htmlEncode(document.getElementById("msg-body").value + additionalstufftoaddtomessage)); + document.getElementById("msg-body").value = ""; + document.getElementById("full-name").value = ""; + document.getElementById("msg-subject").value = ""; + additionalstufftoaddtomessage = ""; + }).catch(function (err) { + M.toast({ html: "Unable to read directory of people. Message could not be sent." }); console.log(err); }); + }); +} + +function getUrlParameter(sParam) { + const url_params = new URLSearchParams(window.location.search); + const found_param = url_params.get(sParam); + return found_param } + var additionalstufftoaddtomessage = ""; - document.addEventListener('DOMContentLoaded', function() { - checkLogin(); - var elems = document.querySelectorAll('.autocomplete-fullname'); - localforage.getItem('directory').then(function(value) { - // vse editam v nanotu - var evals = value; - for (var variableKey in evals){ - if (evals.hasOwnProperty(variableKey)){ - evals[variableKey] = null; - } - } - var instances = M.Autocomplete.init(elems, { - data: evals, - onAutocomplete: validateName, - minLength: 0 - }); - }).catch(function(err) { - M.toast({ html: "Unable to read directory of people. Unable to autocomplete the name of the person."}); - console.log(err); - }); - if(window.location.search.substring(1)) { - document.getElementById("full_name").value = decodeURIComponent(window.location.search.substring(1)); - M.updateTextFields(); - validateName(); - } - document.getElementById("full_name").addEventListener("blur", validateName); - document.getElementById("msg_send").addEventListener("click", function() { - localforage.getItem('directory').then(function(value) { - sendMessage(value[document.getElementById("full_name").value], document.getElementById("msg_subject").value, - htmlEncode(document.getElementById("msg_body").value+additionalstufftoaddtomessage)); - document.getElementById("msg_body").value = ""; - document.getElementById("full_name").value = ""; - document.getElementById("msg_subject").value = ""; - additionalstufftoaddtomessage = ""; - }).catch(function(err) { - M.toast({ html: "Unable to read directory of people. Message could not be sent."}); - console.log(err); - }); - }); - // Setup side menu - const menus = document.querySelectorAll(".side-menu"); - M.Sidenav.init(menus, { edge: "right", draggable: true }); - var receivedmessages = null; - loadMessages(true, 0); - - document.getElementById("msg_add_a_photo").addEventListener("click", function() { - var input = document.createElement('input'); - input.type = 'file'; - input.onchange = e => { - // getting a hold of the file reference - var file = e.target.files[0]; - // setting up the reader - var reader = new FileReader(); - reader.readAsDataURL(file); // this is reading as data url - // here we tell the reader what to do when it's done reading... - reader.onload = readerEvent => { - additionalstufftoaddtomessage += '<br><img src="' + readerEvent.target.result + '" />'; // this is the content! - M.toast({html:"Image added as an attachment."}); - } - } - input.click(); - }); - }); +document.addEventListener("DOMContentLoaded", () => { + + checkLogin(); + loadDirectory(); + setupEventListeners(); + + var receivedmessages = null; + loadMessages(true, 0); + + document.getElementById("full-name").value = getUrlParameter("m"); + M.updateTextFields(); + validateName(); + + // Setup side menu + const menus = document.querySelectorAll(".side-menu"); + M.Sidenav.init(menus, { edge: "right", draggable: true }); + +}); diff --git a/js/timetable.js b/js/timetable.js index 0f85f24..40d1d52 100644 --- a/js/timetable.js +++ b/js/timetable.js @@ -80,7 +80,7 @@ function getDateString(date) { function getLastMonday(date_object) { if (date_object.getDay() === 0) { - date_object.setDate(asdf.getDate() - 6); + date_object.setDate(date_object.getDate() - 6); } else { date_object.setDate(date_object.getDate() - date_object.getDay() + 1); } @@ -53,11 +53,12 @@ <button id="login-button" class="btn waves-effect waves-light">Sign in</button> </div> <div class="row"> - <p class="grey-text text-darken-2">By signing in, you agree to the <a href="/pages/tos.html">terms and conditions</a> + <p class="grey-text text-darken-2">By signing in, you agree to the <a href="/pages/tos.html">terms and + conditions</a> and the <a href="/pages/privacypolicy.html">privacy policy</a>.</p> </div> </div> </div> </body> -</html> +</html>
\ No newline at end of file diff --git a/logout.html b/logout.html index 934fa14..e94f331 100644 --- a/logout.html +++ b/logout.html @@ -9,10 +9,10 @@ <script type="text/javascript" src="/js/lib/localforage.min.js"></script> <script type="text/javascript" src="/js/logout.js"></script> - + <link rel="manifest" href="/manifest.json"> <script src="/js/app.js"></script> - <link rel="shortcut icon" type="image/png" href="/favicon.png"/> + <link rel="shortcut icon" type="image/png" href="/favicon.png" /> <!-- iOS support --> <link rel="apple-touch-icon" href="/img/icons/icon_96.png"> @@ -23,4 +23,4 @@ <body> </body> -</html> +</html>
\ No newline at end of file diff --git a/pages/about.html b/pages/about.html index 0e5f61f..682af72 100644 --- a/pages/about.html +++ b/pages/about.html @@ -48,11 +48,14 @@ <h4><b>Beži</b>App</h4> </a> </li> - <li><a href="/pages/timetable.html" class="waves-effect"><i class="material-icons">view_module</i>Timetable</a></li> + <li><a href="/pages/timetable.html" class="waves-effect"><i class="material-icons">view_module</i>Timetable</a> + </li> <li><a href="/pages/gradings.html" class="waves-effect"><i class="material-icons">event</i>Gradings</a></li> <li><a href="/pages/grades.html" class="waves-effect"><i class="material-icons">receipt</i>Grades</a></li> - <li><a href="/pages/teachers.html" class="waves-effect"><i class="material-icons">supervisor_account</i>Teachers</a></li> - <li><a href="/pages/absences.html" class="waves-effect"><i class="material-icons">query_builder</i>Absences</a></li> + <li><a href="/pages/teachers.html" class="waves-effect"><i + class="material-icons">supervisor_account</i>Teachers</a></li> + <li><a href="/pages/absences.html" class="waves-effect"><i class="material-icons">query_builder</i>Absences</a> + </li> <li><a href="/pages/messaging.html" class="waves-effect"><i class="material-icons">message</i>Messaging</a></li> <li><a href="/pages/meals.html" class="waves-effect"><i class="material-icons">fastfood</i>Meals</a></li> <li> @@ -115,4 +118,4 @@ </div> </body> -</html> +</html>
\ No newline at end of file diff --git a/pages/absences.html b/pages/absences.html index 765f684..adf957c 100644 --- a/pages/absences.html +++ b/pages/absences.html @@ -50,11 +50,14 @@ <h4><b>Beži</b>App</h4> </a> </li> - <li><a href="/pages/timetable.html" class="waves-effect"><i class="material-icons">view_module</i>Timetable</a></li> + <li><a href="/pages/timetable.html" class="waves-effect"><i class="material-icons">view_module</i>Timetable</a> + </li> <li><a href="/pages/gradings.html" class="waves-effect"><i class="material-icons">event</i>Gradings</a></li> <li><a href="/pages/grades.html" class="waves-effect"><i class="material-icons">receipt</i>Grades</a></li> - <li><a href="/pages/teachers.html" class="waves-effect"><i class="material-icons">supervisor_account</i>Teachers</a></li> - <li><a href="/pages/absences.html" class="waves-effect"><i class="material-icons">query_builder</i>Absences</a></li> + <li><a href="/pages/teachers.html" class="waves-effect"><i + class="material-icons">supervisor_account</i>Teachers</a></li> + <li><a href="/pages/absences.html" class="waves-effect"><i class="material-icons">query_builder</i>Absences</a> + </li> <li><a href="/pages/messaging.html" class="waves-effect"><i class="material-icons">message</i>Messaging</a></li> <li><a href="/pages/meals.html" class="waves-effect"><i class="material-icons">fastfood</i>Meals</a></li> <li> @@ -93,4 +96,4 @@ </body> -</html> +</html>
\ No newline at end of file diff --git a/pages/changelog.html b/pages/changelog.html index 36b37d5..dd97c72 100644 --- a/pages/changelog.html +++ b/pages/changelog.html @@ -53,25 +53,28 @@ <li class="collection-item">Added image sending support to messaging</li> </ul> </div> + <div class="collapsible-header">Version 1.0.8-beta</div> <div class="collapsible-body"> <ul class="collection"> <li class="collection-item">Added messaging</li> </ul> </div> + <div class="collapsible-header">Version 1.0.7-beta</div> <div class="collapsible-body"> <ul class="collection"> <li class="collection-item">Enter key now triggers login in the login form</li> </ul> </div> + <div class="collapsible-header">Version 1.0.6-beta</div> <div class="collapsible-body"> <ul class="collection"> <li class="collection-item">Fixed a typo (related to #5)</li> </ul> </div> - + <div class="collapsible-header">Version 1.0.5-beta</div> <div class="collapsible-body"> <ul class="collection"> @@ -79,7 +82,7 @@ <li class="collection-item">Changed promise handling in gradings (#5)</li> </ul> </div> - + <div class="collapsible-header">Version 1.0.4-beta</div> <div class="collapsible-body"> <ul class="collection"> @@ -97,4 +100,4 @@ </body> -</html> +</html>
\ No newline at end of file diff --git a/pages/grades.html b/pages/grades.html index e82ed89..8c8350b 100644 --- a/pages/grades.html +++ b/pages/grades.html @@ -50,11 +50,14 @@ <h4><b>Beži</b>App</h4> </a> </li> - <li><a href="/pages/timetable.html" class="waves-effect"><i class="material-icons">view_module</i>Timetable</a></li> + <li><a href="/pages/timetable.html" class="waves-effect"><i class="material-icons">view_module</i>Timetable</a> + </li> <li><a href="/pages/gradings.html" class="waves-effect"><i class="material-icons">event</i>Gradings</a></li> <li><a href="/pages/grades.html" class="waves-effect"><i class="material-icons">receipt</i>Grades</a></li> - <li><a href="/pages/teachers.html" class="waves-effect"><i class="material-icons">supervisor_account</i>Teachers</a></li> - <li><a href="/pages/absences.html" class="waves-effect"><i class="material-icons">query_builder</i>Absences</a></li> + <li><a href="/pages/teachers.html" class="waves-effect"><i + class="material-icons">supervisor_account</i>Teachers</a></li> + <li><a href="/pages/absences.html" class="waves-effect"><i class="material-icons">query_builder</i>Absences</a> + </li> <li><a href="/pages/messaging.html" class="waves-effect"><i class="material-icons">message</i>Messaging</a></li> <li><a href="/pages/meals.html" class="waves-effect"><i class="material-icons">fastfood</i>Meals</a></li> <li> @@ -117,4 +120,4 @@ </body> -</html> +</html>
\ No newline at end of file diff --git a/pages/gradings.html b/pages/gradings.html index 9534d3a..b54ddc2 100644 --- a/pages/gradings.html +++ b/pages/gradings.html @@ -57,11 +57,14 @@ <h4><b>Beži</b>App</h4> </a> </li> - <li><a href="/pages/timetable.html" class="waves-effect"><i class="material-icons">view_module</i>Timetable</a></li> + <li><a href="/pages/timetable.html" class="waves-effect"><i class="material-icons">view_module</i>Timetable</a> + </li> <li><a href="/pages/gradings.html" class="waves-effect"><i class="material-icons">event</i>Gradings</a></li> <li><a href="/pages/grades.html" class="waves-effect"><i class="material-icons">receipt</i>Grades</a></li> - <li><a href="/pages/teachers.html" class="waves-effect"><i class="material-icons">supervisor_account</i>Teachers</a></li> - <li><a href="/pages/absences.html" class="waves-effect"><i class="material-icons">query_builder</i>Absences</a></li> + <li><a href="/pages/teachers.html" class="waves-effect"><i + class="material-icons">supervisor_account</i>Teachers</a></li> + <li><a href="/pages/absences.html" class="waves-effect"><i class="material-icons">query_builder</i>Absences</a> + </li> <li><a href="/pages/messaging.html" class="waves-effect"><i class="material-icons">message</i>Messaging</a></li> <li><a href="/pages/meals.html" class="waves-effect"><i class="material-icons">fastfood</i>Meals</a></li> <li> @@ -131,4 +134,4 @@ --> </body> -</html> +</html>
\ No newline at end of file diff --git a/pages/messaging.html b/pages/messaging.html index a012354..70f61a9 100644 --- a/pages/messaging.html +++ b/pages/messaging.html @@ -16,11 +16,11 @@ <script type="text/javascript" src="/js/lib/localforage.min.js"></script> <link type="text/css" href="/css/styles.css" rel="stylesheet"> - <script type="text/javascript" src="../js/messaging.js"></script> + <script type="text/javascript" src="/js/messaging.js"></script> <link rel="manifest" href="/manifest.json"> <script src="/js/app.js"></script> - <script src="../js/lib/xss.js"></script> + <script src="/js/lib/xss.js"></script> <link rel="shortcut icon" type="image/png" href="/favicon.png" /> <!-- iOS support --> @@ -48,11 +48,15 @@ <h4><b>Beži</b>App</h4> </a> </li> - <li><a href="/pages/timetable.html" class="waves-effect"><i class="material-icons">view_module</i>Timetable</a></li> + <li><a href="/pages/timetable.html" class="waves-effect"><i class="material-icons">view_module</i>Timetable</a> + </li> <li><a href="/pages/gradings.html" class="waves-effect"><i class="material-icons">event</i>Gradings</a></li> <li><a href="/pages/grades.html" class="waves-effect"><i class="material-icons">receipt</i>Grades</a></li> - <li><a href="/pages/teachers.html" class="waves-effect"><i class="material-icons">supervisor_account</i>Teachers</a></li> - <li><a href="/pages/absences.html" class="waves-effect"><i class="material-icons">query_builder</i>Absences</a></li> + <li><a href="/pages/teachers.html" class="waves-effect"><i + class="material-icons">supervisor_account</i>Teachers</a> + </li> + <li><a href="/pages/absences.html" class="waves-effect"><i class="material-icons">query_builder</i>Absences</a> + </li> <li><a href="/pages/messaging.html" class="waves-effect"><i class="material-icons">message</i>Messaging</a></li> <li><a href="/pages/meals.html" class="waves-effect"><i class="material-icons">fastfood</i>Meals</a></li> <li> @@ -71,56 +75,59 @@ <div class="container"> <h4>Send a message</h4> - <div class="row"> + <div class="row"> <div class="col s12"> - <div class="row"> - <div class="input-field col s5"> - <i class="material-icons prefix">account_circle</i> - <input id="full_name" type="text" class="autocomplete-fullname validate"> - <label for="full_name">Recipient</label> - </div> - <div class="input-field col s5"> - <i class="material-icons prefix">subject</i> - <input id="msg_subject" type="text" class=""> - <label for="msg_subject">Subject</label> + <div class="row"> + <div class="input-field col s5"> + <i class="material-icons prefix">account_circle</i> + <input id="full-name" type="text" class="autocomplete-fullname validate"> + <label for="full-name">Recipient</label> + </div> + <div class="input-field col s5"> + <i class="material-icons prefix">subject</i> + <input id="msg-subject" type="text" class=""> + <label for="msg-subject">Subject</label> + </div> + <div class="input-field col s2"> + <button class="btn waves-effect waves-light" id="msg-send" type="button" disabled="disabled" + name="action"> + <i class="material-icons">send</i> + </button> + </div> </div> - <div class="input-field col s2"> - <button class="btn waves-effect waves-light" id="msg_send" type="button" disabled="disabled" name="action"> - <i class="material-icons">send</i> - </button> + <div class="row"> + <div class="input-field col s10"> + <i class="material-icons prefix">mode_edit</i> + <textarea id="msg-body" class="materialize-textarea"></textarea> + <label for="msg-body">Message body</label> + </div> + <div class="input-field col s2"> + <button class="btn waves-effect waves-light" id="msg-add-photo" type="button"> + <i class="material-icons" style="margin: 0 auto">add_a_photo</i> + </button> + </div> </div> - </div> - <div class="row"> - <div class="input-field col s10"> - <i class="material-icons prefix">mode_edit</i> - <textarea id="msg_body" class="materialize-textarea"></textarea> - <label for="msg_body">Message body</label> - </div> - <div class="input-field col s2"> - <button class="btn waves-effect waves-light" id="msg_add_a_photo" type="button"> - <i class="material-icons" style="margin: 0 auto">add_a_photo</i> - </button> - </div> - </div> </div> - <div id="msg_added_image"></div> - </div> + <div id="msg-added-image"></div> + </div> <h4>Messages</h4> - <button class="btn waves-effect waves-light" id="msg_load-btn" onclick="loadMessages(true, 0);" type="button">Received - <i class="material-icons right">system_update</i> - </button> - <button class="btn waves-effect waves-light" id="msg_load-btn" onclick="loadMessages(true, 1);" type="button">Sent - <i class="material-icons right">system_update</i> - </button> - <button class="btn waves-effect waves-light" id="msg_load-btn" onclick="loadMessages(true, 2);" type="button">Deleted - <i class="material-icons right">system_update</i> - </button> -<div id="msg_list"></div> + <button class="btn waves-effect waves-light" id="msg-load-btn" onclick="loadMessages(true, 0);" + type="button">Received + <i class="material-icons right">system_update</i> + </button> + <button class="btn waves-effect waves-light" id="msg-load-btn" onclick="loadMessages(true, 1);" + type="button">Sent + <i class="material-icons right">system_update</i> + </button> + <button class="btn waves-effect waves-light" id="msg-load-btn" onclick="loadMessages(true, 2);" + type="button">Deleted + <i class="material-icons right">system_update</i> + </button> + <div id="msg-list"></div> </div> </body> -</html> - +</html>
\ No newline at end of file diff --git a/pages/privacypolicy.html b/pages/privacypolicy.html index 6ff7f56..d5a4b0c 100644 --- a/pages/privacypolicy.html +++ b/pages/privacypolicy.html @@ -67,4 +67,4 @@ </body> -</html> +</html>
\ No newline at end of file diff --git a/pages/teachers.html b/pages/teachers.html index 5f7fa8f..ee4f49c 100644 --- a/pages/teachers.html +++ b/pages/teachers.html @@ -50,11 +50,14 @@ <h4><b>Beži</b>App</h4> </a> </li> - <li><a href="/pages/timetable.html" class="waves-effect"><i class="material-icons">view_module</i>Timetable</a></li> + <li><a href="/pages/timetable.html" class="waves-effect"><i class="material-icons">view_module</i>Timetable</a> + </li> <li><a href="/pages/gradings.html" class="waves-effect"><i class="material-icons">event</i>Gradings</a></li> <li><a href="/pages/grades.html" class="waves-effect"><i class="material-icons">receipt</i>Grades</a></li> - <li><a href="/pages/teachers.html" class="waves-effect"><i class="material-icons">supervisor_account</i>Teachers</a></li> - <li><a href="/pages/absences.html" class="waves-effect"><i class="material-icons">query_builder</i>Absences</a></li> + <li><a href="/pages/teachers.html" class="waves-effect"><i + class="material-icons">supervisor_account</i>Teachers</a></li> + <li><a href="/pages/absences.html" class="waves-effect"><i class="material-icons">query_builder</i>Absences</a> + </li> <li><a href="/pages/messaging.html" class="waves-effect"><i class="material-icons">message</i>Messaging</a></li> <li><a href="/pages/meals.html" class="waves-effect"><i class="material-icons">fastfood</i>Meals</a></li> <li> @@ -102,4 +105,4 @@ </body> -</html> +</html>
\ No newline at end of file diff --git a/pages/timetable.html b/pages/timetable.html index 19b5fa4..98110c1 100644 --- a/pages/timetable.html +++ b/pages/timetable.html @@ -59,11 +59,14 @@ <h4><b>Beži</b>App</h4> </a> </li> - <li><a href="/pages/timetable.html" class="waves-effect"><i class="material-icons">view_module</i>Timetable</a></li> + <li><a href="/pages/timetable.html" class="waves-effect"><i class="material-icons">view_module</i>Timetable</a> + </li> <li><a href="/pages/gradings.html" class="waves-effect"><i class="material-icons">event</i>Gradings</a></li> <li><a href="/pages/grades.html" class="waves-effect"><i class="material-icons">receipt</i>Grades</a></li> - <li><a href="/pages/teachers.html" class="waves-effect"><i class="material-icons">supervisor_account</i>Teachers</a></li> - <li><a href="/pages/absences.html" class="waves-effect"><i class="material-icons">query_builder</i>Absences</a></li> + <li><a href="/pages/teachers.html" class="waves-effect"><i + class="material-icons">supervisor_account</i>Teachers</a></li> + <li><a href="/pages/absences.html" class="waves-effect"><i class="material-icons">query_builder</i>Absences</a> + </li> <li><a href="/pages/messaging.html" class="waves-effect"><i class="material-icons">message</i>Messaging</a></li> <li><a href="/pages/meals.html" class="waves-effect"><i class="material-icons">fastfood</i>Meals</a></li> <li> @@ -106,4 +109,4 @@ </body> -</html> +</html>
\ No newline at end of file diff --git a/pages/tos.html b/pages/tos.html index 622fd1d..ed37acb 100644 --- a/pages/tos.html +++ b/pages/tos.html @@ -119,4 +119,4 @@ </body> -</html> +</html>
\ No newline at end of file @@ -1,85 +1,82 @@ // Change version to cause cache refresh const static_cache_name = "site-static-v1.0.9"; + +// Tukej ne met notr directory namov, samo imena fajlov, +// ker v primeru index.html to prpele do double-cachinga, oz. do velik 404 + // Got them with find . -not -path '*/\.*' | sed "s/.*/\"&\",/" | grep -v sw.js // sw.js NE SME BITI CACHAN, ker vsebuje verzijo! const assets = [ -".", -"./login.html", -"./logout.html", -"./css", -"./css/materialize.min.css", -"./css/fontawesome.min.css", -"./css/materialicons.css", -"./css/styles.css", -"./css/fullcalendar", -"./css/fullcalendar/custom.css", -"./css/fullcalendar/daygrid", -"./css/fullcalendar/daygrid/main.min.css", -"./css/fullcalendar/core", -"./css/fullcalendar/core/main.min.css", -"./css/fullcalendar/timegrid", -"./css/fullcalendar/timegrid/main.min.css", -"./favicon.png", -"./fonts", -"./fonts/fa-solid-900.eot", -"./fonts/fa-solid-900.woff2", -"./fonts/fa-brands-400.woff2", -"./fonts/fa-regular-400.eot", -"./fonts/fa-regular-400.woff2", -"./fonts/fa-brands-400.eot", -"./fonts/materialicons.woff2", -"./index.html", -"./img", -"./img/avatars", -"./img/avatars/asijanec.png", -"./img/avatars/rstular.png", -"./img/icons", -"./img/icons/icon_384.png", -"./img/icons/icon_192.png", -"./img/icons/icon_72.png", -"./img/icons/icon_144.png", -"./img/icons/icon_512.png", -"./img/icons/icon_96.png", -"./img/icons/icon_48.png", -"./js", -"./js/timetable.js", -"./js/gradings.js", -"./js/messaging.js", -"./js/privacypolicy.js", -"./js/teachers.js", -"./js/tos.js", -"./js/login.js", -"./js/app.js", -"./js/lib", -"./js/lib/materialize.min.js", -"./js/lib/jquery.min.js", -"./js/lib/localforage.min.js", -"./js/lib/xss.js", -"./js/lib/fullcalendar", -"./js/lib/fullcalendar/daygrid", -"./js/lib/fullcalendar/daygrid/main.min.js", -"./js/lib/fullcalendar/core", -"./js/lib/fullcalendar/core/main.min.js", -"./js/lib/fullcalendar/timegrid", -"./js/lib/fullcalendar/timegrid/main.min.js", -"./js/grades.js", -"./js/about.js", -"./js/logout.js", -"./js/initialize.js", -"./js/absences.js", -"./js/changelog.js", -"./manifest.json", -"./pages", -"./pages/timetable.html", -"./pages/teachers.html", -"./pages/absences.html", -"./pages/about.html", -"./pages/changelog.html", -"./pages/messaging.html", -"./pages/gradings.html", -"./pages/grades.html", -"./pages/privacypolicy.html", -"./pages/tos.html" + + + + "/css/materialize.min.css", + "/css/fontawesome.min.css", + "/css/materialicons.css", + "/css/styles.css", + "/css/fullcalendar/custom.css", + "/css/fullcalendar/daygrid/main.min.css", + "/css/fullcalendar/core/main.min.css", + "/css/fullcalendar/timegrid/main.min.css", + + "/fonts/fa-solid-900.eot", + "/fonts/fa-solid-900.woff2", + "/fonts/fa-brands-400.woff2", + "/fonts/fa-regular-400.eot", + "/fonts/fa-regular-400.woff2", + "/fonts/fa-brands-400.eot", + "/fonts/materialicons.woff2", + + "/img/avatars/asijanec.png", + "/img/avatars/rstular.png", + "/img/icons/icon_384.png", + "/img/icons/icon_192.png", + "/img/icons/icon_72.png", + "/img/icons/icon_144.png", + "/img/icons/icon_512.png", + "/img/icons/icon_96.png", + "/img/icons/icon_48.png", + + "/js/timetable.js", + "/js/gradings.js", + "/js/messaging.js", + "/js/privacypolicy.js", + "/js/teachers.js", + "/js/tos.js", + "/js/login.js", + "/js/app.js", + + "/js/lib/materialize.min.js", + "/js/lib/jquery.min.js", + "/js/lib/localforage.min.js", + "/js/lib/xss.js", + + "/js/lib/fullcalendar/daygrid/main.min.js", + "/js/lib/fullcalendar/core/main.min.js", + "/js/lib/fullcalendar/timegrid/main.min.js", + "/js/grades.js", + "/js/about.js", + "/js/logout.js", + "/js/initialize.js", + "/js/absences.js", + "/js/changelog.js", + + "/pages/timetable.html", + "/pages/teachers.html", + "/pages/absences.html", + "/pages/about.html", + "/pages/changelog.html", + "/pages/messaging.html", + "/pages/gradings.html", + "/pages/grades.html", + "/pages/privacypolicy.html", + "/pages/tos.html", + + "/manifest.json", + "/index.html", + "/login.html", + "/logout.html", + "/favicon.png" ]; importScripts("/js/lib/localforage.min.js"); @@ -109,28 +106,29 @@ self.addEventListener("activate", evt => { ); }); -self.addEventListener('message', event => { - if (event.data) { - let data = JSON.parse(event.data); // parse the message back to JSON - if (data.action == "addtocache") { // check the action - event.waitUntil( - caches.open(static_cache_name).then(function(cache) { - try { - return cache.add([data.url]); - } - catch(error) { - console.error("[sw.js] error: "+error); - } - }) - ); - } else if (data.action == "deletecaches") { - caches.keys().then(function(names) { - for (let name of names) - console.log("[sw.js] deleting cache named "+name); - caches.delete(name); - }); +self.addEventListener("message", event => { + + if (event.data) { + let data = JSON.parse(event.data); // parse the message back to JSON + if (data.action == "addtocache") { // check the action + event.waitUntil( + caches.open(static_cache_name).then(function (cache) { + try { + return cache.add([data.url]); + } + catch (error) { + console.error("[sw.js] error: " + error); + } + }) + ); + } else if (data.action == "deletecaches") { + caches.keys().then(function (names) { + for (let name of names) + console.log("[sw.js] deleting cache named " + name); + caches.delete(name); + }); + } } - } }); self.addEventListener("fetch", (evt) => { |