From 07cb830c35f2bed8cfa8abcd1e31fc5bf965db9d Mon Sep 17 00:00:00 2001 From: rstular Date: Thu, 14 May 2020 01:51:10 +0200 Subject: Styling changes, first round of bug fixes There are (probably) more changes incoming, but we need to discuss them first --- js/absences.js | 18 +++- js/app.js | 2 + js/chats.js | 53 +++++++++--- js/grades.js | 11 ++- js/gradings.js | 2 +- js/gsec.js | 132 +++++++++++++++++++++-------- js/lang/bundle.js | 8 +- js/meals.js | 50 ++++++++--- js/messaging.js | 244 +++++++++++++++++++++++++++++++++++------------------- js/settings.js | 2 +- js/teachers.js | 9 +- js/timetable.js | 12 +-- 12 files changed, 380 insertions(+), 163 deletions(-) (limited to 'js') diff --git a/js/absences.js b/js/absences.js index a3d33cd..0e0d1fd 100644 --- a/js/absences.js +++ b/js/absences.js @@ -94,22 +94,29 @@ async function loadAbsences(force_refresh = false) { function displayData() { absences.forEach(absence => { let li = document.createElement("li"); + let date_string = dateString.longFormatted(absence["date"]); // javascript sucks - zakaj ob vsej svoji "preprostosti" ne morm met Date za key objecta!?!?'!!11~ let header = document.createElement("div"); header.className = "collapsible-header"; header.innerText = date_string; + let body = document.createElement("div"); body.className = "collapsible-body"; + let body_table = document.createElement("table"); body_table.className = "highlight"; + let body_table_tbody = document.createElement("tbody"); + Object.keys(absence.subjects).forEach(lesson => { let subject_row = document.createElement("tr"); let subject_lesson_icon = document.createElement("td"); let subject_lesson_text = document.createElement("td"); subject_lesson_text.innerText = S("lesson") + " " + lesson; + let subject_lesson_icon_i = document.createElement("i"); subject_lesson_icon_i.className = "material-icons"; + switch (absence["subjects"][lesson]["status"]) { case 0: subject_lesson_icon_i.innerText = "schedule"; @@ -124,7 +131,9 @@ function displayData() { subject_lesson_icon_i.innerText = "not_interested"; break; } + subject_lesson_icon.appendChild(subject_lesson_icon_i); + let subject_name = document.createElement("td"); subject_name.innerText = S(gseAbsenceTypes[absence["subjects"][lesson]["status"]]) + " : " + absence["subjects"][lesson]["subject"]; subject_row.appendChild(subject_lesson_icon); @@ -132,11 +141,13 @@ function displayData() { subject_row.appendChild(subject_name); body_table_tbody.appendChild(subject_row); }); + body_table.appendChild(body_table_tbody); body.appendChild(body_table); + li.appendChild(header); li.appendChild(body); - $("#absences-col").append(li); + $("#absences-col").append(li); }); } @@ -164,10 +175,10 @@ function setupPickers() { setDefaultDate: true, firstDay: 1, onSelect: refreshAbsences - } + } + let instances = M.Datepicker.init(elems, options); - date_object.setDate(date_object.getDate() - 14); elems = document.querySelectorAll('#datepicker-from'); @@ -199,5 +210,4 @@ document.addEventListener("DOMContentLoaded", () => { // Setup side menu const menus = document.querySelectorAll('.side-menu'); M.Sidenav.init(menus, { edge: 'right', draggable: true }); - }); diff --git a/js/app.js b/js/app.js index f7c423f..022b946 100644 --- a/js/app.js +++ b/js/app.js @@ -12,9 +12,11 @@ if (navigator.serviceWorker) { } }); } + if (location.protocol != 'https:') { location.href = 'https:' + window.location.href.substring(window.location.protocol.length); } + async function UIAlert(usermsg, devmsg) { if(true) { // če bo kakšen dev switch? M.toast( { html: usermsg } ); diff --git a/js/chats.js b/js/chats.js index 73dc791..640a2ab 100644 --- a/js/chats.js +++ b/js/chats.js @@ -1,5 +1,6 @@ -const API_ENDPOINT = "https://gimb.tk/test.php"; +// const API_ENDPOINT = "https://gimb.tk/test.php"; const DIRECTORY_URL = "/directory.json"; + // "Global" object for name directory var directory = null; var currentlyChattingWith = null; // msgid @@ -18,9 +19,11 @@ async function checkLogin() { console.log(err); }); } + function getKeyByValue(object, value) { - return Object.keys(object).find(key => object[key] === value); + return Object.keys(object).find(key => object[key] === value); } + // -----------HTML HELPERS----------- function htmlEncode(value) { // Create a in-memory element, set its inner text (which is automatically encoded) @@ -56,7 +59,7 @@ function loadDirectory() { 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) - UIAlert( D("nameDirectoryNotSet"), "loadDirectory(): stored_directory === null" ); + UIAlert( D("nameDirectoryNotSet"), "loadDirectory(): stored_directory === null" ); directory = null; // Disable send button document.getElementById("msg-send").disabled = true; @@ -102,6 +105,7 @@ function setLoading(state) { $("#loading-bar").addClass("hidden"); } } + async function sendMessage(recipient_number = null, body = null) { if(recipient_number == null || recipient_number == undefined) { recipient_number = directory[sogovornik]; @@ -139,27 +143,39 @@ async function sendMessage(recipient_number = null, body = null) { } }); } + function addMessage(whom, body, datePlacement = 0, messageDate = null) { // datePlacement: 0=append bubble to end, 1=append bubble to start. if(whom == 0) { var whos = "mine"; } else { var whos = "yours"; } + var timestamp = Date.now(); - if(messageDate instanceof Date) { timestamp = messageDate.getTime(); } - if(typeof messageDate == "number") { timestamp = messageDate; } + if(messageDate instanceof Date) { + timestamp = messageDate.getTime(); + } + + if(typeof messageDate == "number") { + timestamp = messageDate; + } + var chatarea = document.getElementsByClassName("chat")[0]; var alreadyMessages = chatarea.querySelectorAll(".message"); var textnode = document.createTextNode(body); + var bubblenode = document.createElement("div"); bubblenode.setAttribute("data-date", timestamp); bubblenode.appendChild(textnode); + if(chatarea.childElementCount == 0) { bubblenode.className = "message last"; var messagesnest = document.createElement("div"); var istaoseba = false; } else { + if(datePlacement == 0 || timestamp > Number(alreadyMessages[alreadyMessages.length - 1].getAttribute("data-date"))) { + datePlacement = 0; console.log(alreadyMessages[0].getAttribute("data-date")); bubblenode.className = "message last"; @@ -171,7 +187,9 @@ function addMessage(whom, body, datePlacement = 0, messageDate = null) { // date var istaoseba = false; var messagesnest = document.createElement("div"); } + } else if (datePlacement == 1 || timestamp < Number(alreadyMessages[0].getAttribute("data-date"))) { + datePlacement = 1; console.log(alreadyMessages[0].getAttribute("data-date")); if(chatarea.children.item(0).classList.contains(whos)) { // ista oseba @@ -183,22 +201,25 @@ function addMessage(whom, body, datePlacement = 0, messageDate = null) { // date var istaoseba = false; var messagesnest = document.createElement("div"); } + } else { // auto place (slower, so 0 or 1 are options + console.log("if3"); for(var iter = 0; iter < alreadyMessages.length - 2; iter++) { // (-2 zato, ker potem iter+1 ne obstaja pri zadnjem elementu) - if ( - Number(alreadyMessages[iter].getAttribute("data-date")) < timstamp - && Number(alreadyMessages[iter+1].getAttribute("data-date")) > timestamp - ) { + if (Number(alreadyMessages[iter].getAttribute("data-date")) < timstamp + && Number(alreadyMessages[iter+1].getAttribute("data-date")) > timestamp) { + var zgornjiIsti = alreadyMessages[iter].parentElement.classList.contains(whos); var spodnjiIsti = alreadyMessages[iter+1].parentElement.classList.contains(whos); console.log([zgornjiIsti, spodnjiIsti]); + if(zgornjiIsti && spodnjiIsti) { var messagesnest = alreadyMessages[iter].parentElement; bubblenode.className = "message"; messagesnest.insertBefore(bubblenode, alreadyMessages[iter+1]); return; } + if(zgornjiIsti && !spodnjiIsti) { var messagesnest = alreadyMessages[iter].parentElement; bubblenode.className = "message last"; @@ -206,25 +227,30 @@ function addMessage(whom, body, datePlacement = 0, messageDate = null) { // date messagesnest.appendChild(bubblenode); return; } + if(!zgornjiIsti && spodnjiIsti) { var messagesnest = alreadyMessages[iter+1].parentElement; bubblenode.className = "message"; messagesnest.insertBefore(bubblenode, alreadyMessages[iter+1]); return; } + throw new RangeError("This should not happen!"); } } throw new RangeError("This should not happen!1"); + } } + // autodetect date is not present here anymore - messagesnest.className = whos+" messages"; + messagesnest.className = whos + " messages"; if(datePlacement == 0) { messagesnest.appendChild(bubblenode); } else { messagesnest.prepend(bubblenode); } + if(!istaoseba) { if(datePlacement == 0) { chatarea.appendChild(messagesnest); @@ -233,6 +259,7 @@ function addMessage(whom, body, datePlacement = 0, messageDate = null) { // date } } } + async function validateName() { if (directory !== null) { document.getElementById("full-name").disabled = false; @@ -282,7 +309,6 @@ document.addEventListener("DOMContentLoaded", () => { const modals = document.querySelectorAll('.side-modal'); M.Sidenav.init(modals, { edge: 'left', draggable: false }); prepareAndStartFetchingMessages(); // just opens modal, as there is no recipient selected - }); async function updateSendButton() { @@ -304,13 +330,17 @@ async function setRecipient(name = null) { UIAlert(D("recipientNotInDirectory")); throw new RangeError("Hello from setRecipient(): name is not in directory"); } + var modal = document.querySelectorAll('#directory-side-menu')[0]; var modalInstance = M.Sidenav.getInstance(modal); modalInstance.close(); + document.getElementsByClassName("msg-chattingWith")[0].innerHTML = name; sogovornik = name; currentlyChattingWith = directory[name]; + document.getElementById("chat-mustSelectRecipient").hidden=true; + updateSendButton(); clearMessages(); // <-- do when recipient selected prepareAndStartFetchingMessages(); // <-- same @@ -337,6 +367,7 @@ async function startFetchingMessages() { password = value; }), ]; + setLoading(true); await Promise.all(promises_to_run); try { diff --git a/js/grades.js b/js/grades.js index b77ffd2..9994596 100644 --- a/js/grades.js +++ b/js/grades.js @@ -40,8 +40,10 @@ async function loadGrades(force_refresh = false) { // If we don't have a list of grades, fetch it if (grades === null || grades === [] || force_refresh) { try { + let gsecInstance = new gsec(); - await gsecInstance.login(username, password); + await gsecInstance.login(username, password); + gsecInstance.fetchGrades().then( (value) => { grades = value; localforage.setItem("grades", value).then((value) => { @@ -53,10 +55,12 @@ async function loadGrades(force_refresh = false) { gsecErrorHandlerUI(err); setLoading(false); }); + } catch (err) { gsecErrorHandlerUI(err); setLoading(false); } + } else { displayGrades(); setLoading(false); @@ -69,6 +73,7 @@ function displayGrades() { if (!(grade["subject"] in grades_by_subject)) { grades_by_subject[grade["subject"]] = []; } + let grade_object = { date: dateString.longFormatted(grade["date"]), teacher: grade["teacher"], @@ -81,7 +86,9 @@ function displayGrades() { index: index } grades_by_subject[grade["subject"]].push(grade_object); + }); + let root_element = document.getElementById("grades-collapsible"); Object.keys(grades_by_subject).forEach((subject) => { // Create root element for a subject entry @@ -217,6 +224,6 @@ document.addEventListener("DOMContentLoaded", async () => { // Setup side modal const modals = document.querySelectorAll('.side-modal'); M.Sidenav.init(modals, { edge: 'left', draggable: false }); - await clearGrades(); + clearGrades(); await loadGrades(); }); diff --git a/js/gradings.js b/js/gradings.js index 756db9f..c55e743 100644 --- a/js/gradings.js +++ b/js/gradings.js @@ -91,7 +91,7 @@ async function loadGradings(force_refresh = false) { if (gradings === null || gradings === [] || gradings === -1 || force_refresh) { try { let gsecInstance = new gsec(); - await gsecInstance.login(username, password); + await gsecInstance.login(username, password); gsecInstance.fetchGradings().then( (value) => { gradings = value; localforage.setItem("gradings", value).then((value) => { diff --git a/js/gsec.js b/js/gsec.js index e1c2ffc..3bbb8b1 100644 --- a/js/gsec.js +++ b/js/gsec.js @@ -1,19 +1,23 @@ // tab = 2 || any spaces; use tabs // not tested yet -- NOTE: document.createElement is xssy, use DOMParser! var gseAbsenceTypes = ["notProcessed", "authorizedAbsence", "unauthorizedAbsence", "doesNotCount"]; + function get_string_between(string, start, end) { return string.split(start).pop().split(end)[0]; } + function stripHtml(html) { var tmp = document.createElement("DIV"); tmp.innerHTML = html; return tmp.textContent || tmp.innerText || ""; } + function slDayToInt(inputString) { // wtf let fourChars = inputString.substring(1, 5); let fourCharDays = ["oned", "orek", "reda", "etrt", "etek", "obot", "edel"]; return fourCharDays.indexOf(fourChars); } + const GSE_URL = "https://zgimsis.gimb.tk/gse/"; const GSEC_ERR_NET = "GSEC NETWORK ERROR (ajax error)"; const GSEC_ERR_NET_POSTBACK_GET = "GSEC NETWORK ERROR (ajax error) in postback GET" @@ -26,8 +30,10 @@ const GSEC_NO_ABSENCES = "noAbsences"; const GSEC_MSGTYPES = ["msgReceived", "msgSent", "msgDeleted"]; class gsec { + constructor() { } + parseAndPost(inputHTML, params, formId = null, useDiffAction = null) { return new Promise((resolve, reject) => { let parser = new DOMParser(); @@ -67,6 +73,7 @@ class gsec { }); }); } + postback(getUrl, params = {}, formId = null, useDiffAction = null) { return new Promise( (resolve, reject) => { $.ajax({ @@ -92,6 +99,7 @@ class gsec { }); }); } + login(usernameToLogin, passwordToLogin) { return new Promise((resolve, reject) => { var dataToSend = {"edtGSEUserId": usernameToLogin, "edtGSEUserPassword": passwordToLogin, "btnLogin": "Prijava"}; @@ -113,6 +121,7 @@ class gsec { }); }); } + fetchSessionData() { return new Promise((resolve, reject) => { $.ajax({ @@ -144,6 +153,7 @@ class gsec { }); }); } + fetchTeachersDirectory() { return new Promise((resolve, reject) => { var dejt = new Date(); @@ -162,8 +172,15 @@ class gsec { type: "POST", dataType: "json", contentType: "application/json", - data: JSON.stringify( { "aIdOsebeRe": "", "aIdSolskoLeto": Number(letnica).toString(), "aMsgType": "null", "aIdType": "null", "aIdUcitelj": "", "aFilter": null} ), - // note about the nulls, "null"s and ""s: this is actually how zgimsisext2016 javascripts sends it. + data: JSON.stringify({ + "aIdOsebeRe": "", + "aIdSolskoLeto": Number(letnica).toString(), + "aMsgType": "null", + "aIdType": "null", + "aIdUcitelj": "", + "aFilter": null + }), + // note about the nulls, "null"s and ""s: this is actually how zgimsisext2016 javascripts sends it. processData: false, success: (data, textStatus, xhr) => { var teachersDirectory = data.d.split(";"); // data.d je "12434=Ime Primek (učitelj);75353=Ime Drugega Priimek (učitelj)"; @@ -180,6 +197,7 @@ class gsec { }); }); } + fetchTimetable(datum = null) { if(datum == null) { var dataToSend = {}; @@ -201,12 +219,19 @@ class gsec { var razred = desc[2]; var teacher = desc[3]; var place = desc[4]; - urnik[day][period] = {"subject": subject, "acronym": abkurzung, "class": razred, "teacher": teacher, "place": place}; + urnik[day][period] = { + "subject": subject, + "acronym": abkurzung, + "class": razred, + "teacher": teacher, + "place": place + }; } resolve(urnik); }); }); } + fetchGradings() { return new Promise((resolve, reject) => { var gradings = []; @@ -232,6 +257,7 @@ class gsec { }); }); } + fetchTeachers() { // razrednika ne vrne kot razrednika, če le-ta uči še en predmet. razlog: razrednik je napisan dvakrat, drugič se prepiše. Ne da se mi popravljat. return new Promise((resolve, reject) => { var Teachers = {}; @@ -264,12 +290,16 @@ class gsec { }); }); } + sendMessage(recipient, subject = " ", body = " ") { return new Promise((resolve, reject) => { var dataToSend = { - "ctl00$ModalMasterBody$edtPrejemniki": "" , "ctl00$ModalMasterBody$edtZadeva": subject , - "ctl00$ModalMasterBody$edtBesediloExt": body , "__EVENTTARGET": "ctl00$ModalMasterBody$btnDogodekShrani" , - "__EVENTARGUMENT": "" , "ctl00$ModalMasterBody$hfPrejemniki": recipient + "ctl00$ModalMasterBody$edtPrejemniki": "", + "ctl00$ModalMasterBody$edtZadeva": subject, + "ctl00$ModalMasterBody$edtBesediloExt": body, + "__EVENTTARGET": "ctl00$ModalMasterBody$btnDogodekShrani", + "__EVENTARGUMENT": "", + "ctl00$ModalMasterBody$hfPrejemniki": recipient }; this.postback(GSE_URL+"Page_Gim/Uporabnik/modSporocilo.aspx?params=", dataToSend, null, true).then((response)=>{ resolve(null); @@ -280,7 +310,7 @@ class gsec { return new Promise((resolve, reject) => { $.ajax({ xhrFields: { - withCredentials: true + withCredentials: true }, crossDomain: true, url: GSE_URL+"Page_Gim/Uporabnik/Sporocila.aspx/DeleteMessage", @@ -291,11 +321,11 @@ class gsec { data: JSON.stringify( { "aIdSporocilo": id.split("|")[0], "aIdZapis": id.split("|")[1] } ), processData: false, success: (data, textStatus, xhr) => { - if(data.d == true) { - resolve(true); - } else { - reject(new Error(false)); - } + if(data.d == true) { + resolve(true); + } else { + reject(new Error(false)); + } }, error: () => { reject(new Error(GSEC_ERR_NET)); @@ -303,6 +333,7 @@ class gsec { }); }); } + fetchAbsences(fromDate = null, tillDate = null) { // navedba datumov je deprecated. Internet je dovolj hiter za poslat maksimalno 4160 ur (16 ur/dan, 5 dni/ted, 52 ted/leto) return new Promise((resolve, reject)=>{ if(!(fromDate instanceof Date) || !(tillDate instanceof Date)) { @@ -340,20 +371,21 @@ class gsec { }); }); } + fetchGrades() { var grades = []; return new Promise((resolve, reject) => { - $.ajax({ - xhrFields: { - withCredentials: true - }, - crossDomain: true, - url: GSE_URL+"Page_Gim/Ucenec/OceneUcenec.aspx", - cache: false, - type: "GET", - dataType: "html", - processData: false, - success: (data, textStatus, xhr) => { + $.ajax({ + xhrFields: { + withCredentials: true + }, + crossDomain: true, + url: GSE_URL+"Page_Gim/Ucenec/OceneUcenec.aspx", + cache: false, + type: "GET", + dataType: "html", + processData: false, + success: (data, textStatus, xhr) => { let parser = new DOMParser(); let parsed = parser.parseFromString(data, "text/html"); let gradeSpans = parsed.getElementsByClassName("txtVOcObd"); @@ -386,17 +418,22 @@ class gsec { grades.push(gradeToAdd); } resolve(grades); - }, - error: () => { - reject(new Error(GSEC_ERR_NET)); - } - }); + }, + error: () => { + reject(new Error(GSEC_ERR_NET)); + } + }); }); } + fetchMessageOld(selectId) { // ne dela, glej fix spodaj (fetchMessage) var message; return new Promise((resolve, reject) => { - var dataToBeSent = {"__EVENTTARGET": "ctl00$ContentPlaceHolder1$gvwSporocila", "__EVENTARGUMENT": "Select$"+selectId}; + var dataToBeSent = { + "__EVENTTARGET": "ctl00$ContentPlaceHolder1$gvwSporocila", + "__EVENTARGUMENT": "Select$" + selectId + }; + this.postback(GSE_URL+"Page_Gim/Uporabnik/Sporocila.aspx", dataToBeSent, null, true).then((response) => { let parser = new DOMParser(); let parsed = parser.parseFromString(response.data, "text/html"); @@ -408,15 +445,26 @@ class gsec { var tume = parsed.querySelectorAll("[id$=Label7]")[0].innerHTML.split(" (").pop().split(")")[0].split(" ").pop(); // "tume"! var dateObj = new Date(Date.parse(date[2]+"-"+date[1]+"-"+date[0]+" "+tume)); // "tume"! var msgId = parsed.getElementById("ctl00_ContentPlaceHolder1_hfIdSporocilo").getAttribute("value"); - message = {"subject": subject, "body": body, "sender": sender, "recipient": recipient, "date": dateObj}; + message = { + "subject": subject, + "body": body, + "sender": sender, + "recipient": recipient, + "date": dateObj + }; resolve(message); }); }); } + fetchMessagesLastPageNumber(category = GSEC_MSGTYPE_RECEIVED) { var msgCategory = GSEC_MSGTYPES[category]; return new Promise((resolve, reject) => { - var dataToBeSent = {"ctl00$ContentPlaceHolder1$ddlPrikaz": msgCategory, "__EVENTARGUMENT": "Page$Last", "__EVENTTARGET": "ctl00$ContentPlaceHolder1$gvwSporocila"}; + var dataToBeSent = { + "ctl00$ContentPlaceHolder1$ddlPrikaz": msgCategory, + "__EVENTARGUMENT": "Page$Last", + "__EVENTTARGET": "ctl00$ContentPlaceHolder1$gvwSporocila" + }; this.postback(GSE_URL+"Page_Gim/Uporabnik/Sporocila.aspx", dataToBeSent, null, true).then((response) => { let parser = new DOMParser(); let parsed = parser.parseFromString(response.data, "text/html"); @@ -430,12 +478,17 @@ class gsec { }); }); } + fetchMessagesList(category = GSEC_MSGTYPE_RECEIVED, pageNumber = 1, outputResponse = false) { // outputResponse je probably za debug var msgCategory = GSEC_MSGTYPES[category]; var messages = []; - var requestURi = GSE_URL+"Page_Gim/Uporabnik/Sporocila.aspx"; + var requestURi = GSE_URL + "Page_Gim/Uporabnik/Sporocila.aspx"; return new Promise((resolve, reject) => { - var dataToBeSent = {"ctl00$ContentPlaceHolder1$ddlPrikaz": msgCategory, "__EVENTARGUMENT": "Page$"+pageNumber, "__EVENTTARGET": "ctl00$ContentPlaceHolder1$gvwSporocila"}; + var dataToBeSent = { + "ctl00$ContentPlaceHolder1$ddlPrikaz": msgCategory, + "__EVENTARGUMENT": "Page$" + pageNumber, + "__EVENTTARGET": "ctl00$ContentPlaceHolder1$gvwSporocila" + }; this.postback(requestURi, dataToBeSent, null, true).then((response) => { if(outputResponse == true) { response.url = requestURi; @@ -469,11 +522,21 @@ class gsec { }); }); } + fetchMessage(category = GSEC_MSGTYPE_RECEIVED, pageNumber = 1, messageNumberOnPage = 0) { var message; return new Promise((resolve, reject) => { this.fetchMessagesList(category, pageNumber, true).then( (value) => { - this.parseAndPost(value.data, {"__EVENTTARGET": "ctl00$ContentPlaceHolder1$gvwSporocila", "__EVENTARGUMENT": "Select$"+messageNumberOnPage}, null, value.url).then((response) => { + this.parseAndPost( + value.data, + { + "__EVENTTARGET": "ctl00$ContentPlaceHolder1$gvwSporocila", + "__EVENTARGUMENT": "Select$" + messageNumberOnPage + }, + null, + value.url + ).then((response) => { + let parser = new DOMParser(); let parsed = parser.parseFromString(response.data, "text/html"); let subject = parsed.getElementsByClassName("msgSubjectS")[0].innerHTML.trim(); @@ -486,6 +549,7 @@ class gsec { var msgId = parsed.getElementById("ctl00_ContentPlaceHolder1_hfIdSporocilo").getAttribute("value"); message = {"subject": subject, "body": body, "sender": sender, "recipient": recipient, "date": dateObj, "msgId": msgId}; resolve(message); + }); }); }); diff --git a/js/lang/bundle.js b/js/lang/bundle.js index 2dd0511..6e6c5b6 100644 --- a/js/lang/bundle.js +++ b/js/lang/bundle.js @@ -367,7 +367,7 @@ var langstrings = { messageBody: "telo", removeImages: "odstrani slike", note: "opomba", - largeImagesNote: "GimB strežniki ne marajo velikih sporočil, zato lahko pošiljate le zelo male slike, v nasprotnem primeru sporočilo ne bo dostavljeno", + largeImagesNote: "GimB strežniki ne marajo velikih sporočil, zato lahko pošiljate le zelo majhne slike, v nasprotnem primeru sporočilo ne bo dostavljeno", attachedImages: "pripete slike", passwordForE2EE: "geslo za šifriranje sporočila", messages: "sporočila", @@ -379,7 +379,7 @@ var langstrings = { loadMessageBody: "naloži telo sporočila", thisMessageWasEncrypted: "to sporočilo je šifriral BežiApp", enterPassword: "vnesite geslo", - decrypt: "odšifriraj", + decrypt: "dešifriraj", nameDirectoryNotSet: "imenik ni nastavljen, pošiljanje ni mogoče", errorFetchingMessages: "sporočil ni bilo mogoče prenesti", unableToReceiveTheMessage: "sporočila ni bilo mogoče prenesti", @@ -425,7 +425,7 @@ var langstrings = { translatorsForThisLanguage: "prevajalci izbranega jezika", whatIsNew: "kaj je novega", whatsNew: "kaj je novega", - reportABug: "prijavite napako ali hrošča", + reportABug: "prijavite napako", sendASuggestion: "pošljite pripombo/predlog/pohvalo/pritožbo", instagram: "instagram", // changelog @@ -460,7 +460,7 @@ var langstrings = { languageSet: "jezik nastavljen, odprite neko drugo stran da se pokažejo spremembe", // gsec gsecErrNet: "napaka povezave na GimSIS", - gsecErrLogin: "napaka avtentikacije na GimSISu (napačno geslo?), poskusite se odjaviti", + gsecErrLogin: "prijava v GimSIS ni uspela (napačno geslo?), poskusite se odjaviti", gsecErrOther: "neznana napaka GimSISa, poskusite se odjaviti", // videoconferences videoconferences: "GimB konference" diff --git a/js/meals.js b/js/meals.js index 1ce08f5..3423292 100644 --- a/js/meals.js +++ b/js/meals.js @@ -1,4 +1,5 @@ const API_ENDPOINT = "https://lopolis-api.gimb.tk/"; + async function checkLogin() { localforage.getItem("logged_in_lopolis").then((value) => { if (value != true) { @@ -13,6 +14,7 @@ async function checkLogin() { console.log(err); }); } + function setLoading(state) { if (state) { $("#loading-bar").removeClass("hidden"); @@ -20,6 +22,7 @@ function setLoading(state) { $("#loading-bar").addClass("hidden"); } } + async function getToken(callback, callbackparams = []) { setLoading(true); let promises_to_run = [ @@ -103,16 +106,21 @@ async function getMenus(dataauth, callback, callbackparams = []) { } }); } + await Promise.all(promises_to_wait_for); // javascript is ducking amazing + let allmeals = {}; let passtocallback = {}; + for(const [index, monthmeals] of Object.entries(mealsgathered)) { // although this is not very javascripty allmeals = mergeDeep(allmeals, monthmeals.data); } + passtocallback.data = allmeals; passtocallback.token = dataauth.token; let toBePassed = [passtocallback].concat(callbackparams); callback(...toBePassed); + } async function loadMeals() { @@ -121,29 +129,37 @@ async function loadMeals() { function displayMeals(meals) { // console.log(JSON.stringify(meals)); // debug // dela! + let root_element = document.getElementById("meals-collapsible"); for(const [date, mealzz] of Object.entries(meals.data)) { let unabletochoosequestionmark = ""; let readonly = mealzz.readonly; var datum = new Date(date); + // Create root element for a date entry let subject_entry = document.createElement("li"); + // Create subject collapsible header let subject_header = document.createElement("div"); subject_header.classList.add("collapsible-header"); subject_header.classList.add("collapsible-header-root"); + // Create header text element let subject_header_text = document.createElement("span"); + if(mealzz.readonly) { unabletochoosequestionmark = "*" + S("readOnly") + "*"; } - subject_header_text.innerText = dateString.day(datum.getDay())+", "+datum.getDate()+". "+dateString.month(datum.getMonth())+" "+datum.getFullYear()+" ("+mealzz.meal+"@" - +mealzz.location+") "+unabletochoosequestionmark; + + // Use ES6 templates + subject_header_text = `${dateString.day(datum.getDay())}, ${datum.getDate()}. ${dateString.month(datum.getMonth())} ${datum.getFullYear()} (${mealzz.meal} @ ${mealzz.location}) ${unabletochoosequestionmark}`; + // Create collection for displaying individuals meals let subject_body = document.createElement("div"); subject_body.className = "collapsible-body"; let subject_body_root = document.createElement("ul"); subject_body_root.className = "collection"; + for(const [dindex, dmil] of Object.entries(mealzz.menu_options)) { // Create element for individual meal let meal_node = document.createElement("li"); @@ -151,11 +167,13 @@ function displayMeals(meals) { meal_node.classList.add("collection-item") meal_node.classList.add("meal-node"); meal_node.dataset["index"] = dindex; - if(!readonly) { - meal_node.onclick = function () { + + if (!readonly) { + meal_node.onclick = () => { setMenu(date, dmil.value); } } + let meal_node_div = document.createElement("div"); // Node for left text let meal_lefttext = document.createElement("span"); @@ -165,7 +183,7 @@ function displayMeals(meals) { // Apply different style, if the meal is selected if (dmil.selected) { // Text - meal_lefttext.innerHTML = ""+dmil.text+""; + meal_lefttext.innerHTML = `${dmil.text}`; // Number meal_righttext.innerText = S("selected"); } else { @@ -179,13 +197,14 @@ function displayMeals(meals) { meal_node.appendChild(meal_node_div); subject_body_root.appendChild(meal_node); } + subject_header.appendChild(subject_header_text); subject_body.append(subject_body_root); subject_entry.append(subject_header); subject_entry.append(subject_body); root_element.append(subject_entry); } - $("#grades-collapsible").append(root_element); + $("#meals-collapsible").append(root_element); // refreshClickHandlers(); } @@ -247,11 +266,13 @@ async function lopolisLogin() { } }); } + async function setMenus(currentmeals = 69, toBeSentChoices) { // currentmeals je getMenus response in vsebuje tudi token. if(currentmeals === 69) { getToken(getMenus, [setMenus, toBeSentChoices]); return; } + for(const [mealzzdate, mealzz] of Object.entries(currentmeals.data)) { if(mealzzdate in toBeSentChoices) {} else { for (const [mealid, mealdata] of Object.entries(mealzz.menu_options)) { @@ -263,30 +284,32 @@ async function setMenus(currentmeals = 69, toBeSentChoices) { // currentmeals je } } } + setLoading(true); + $.ajax({ - url: API_ENDPOINT+"setmenus", + url: API_ENDPOINT + "setmenus", crossDomain: true, contentType: "application/json", data: JSON.stringify( { "choices": toBeSentChoices } ), headers: { - "Authorization": "Bearer "+currentmeals.token + "Authorization": "Bearer " + currentmeals.token }, dataType: "json", cache: false, type: "POST", + success: (response) => { if(response === null || response.error == true) { UIAlert( D("errorSettingMeals"), "setMenus(): response error or null"); - setLoading(false); } else if (response.error == false) { - setLoading(false); UIAlert( D("mealSet"), "setMenus(): meni nastavljen"); } else { - setLoading(false); UIAlert( D("errorUnexpectedResponse"), "setMenus(): invalid response, no condition met"); } + setLoading(false); }, + error: () => { setLoading(false); UIAlert( D("lopolisAPIConnectionError"), "setMenus(): AJAX error"); @@ -298,23 +321,28 @@ async function setMenu(date, menu) { choice[date] = menu; getToken(getMenus, [setMenus, choice]); } + // Initialization code document.addEventListener("DOMContentLoaded", async () => { checkLogin(); let coll_elem = document.querySelectorAll('.collapsible'); let coll_instance = M.Collapsible.init(coll_elem, {}); + // Setup refresh handler $("#refresh-icon").click(function () { refreshMeals(true); }); + let elems = document.querySelectorAll('.modal'); let instances = M.Modal.init(elems, {}); // Setup side menu const menus = document.querySelectorAll('.side-menu'); M.Sidenav.init(menus, { edge: 'right', draggable: true }); + // Setup side modal const modals = document.querySelectorAll('.side-modal'); M.Sidenav.init(modals, { edge: 'left', draggable: false }); + var elemsx = document.querySelectorAll('select'); var instancesx = M.FormSelect.init(elemsx); var datepickerelems = document.querySelectorAll('.datepicker'); diff --git a/js/messaging.js b/js/messaging.js index 2b5c065..187df17 100644 --- a/js/messaging.js +++ b/js/messaging.js @@ -51,7 +51,7 @@ function loadDirectory() { 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) - UIAlert( D("nameDirectoryNotSet"), "loadDirectory(): stored_directory === null" ); + UIAlert( D("nameDirectoryNotSet"), "loadDirectory(): stored_directory === null" ); directory = null; // Disable send button document.getElementById("msg-send").disabled = true; @@ -66,7 +66,7 @@ function loadDirectory() { } function populateAutocomplete() { - let elems = document.querySelectorAll('.autocomplete-fullname'); + let elems = document.querySelectorAll(".autocomplete-fullname"); // če se uporablja globalna var directory, ki je shranjena kot objekt (vedno shranjen kot reference), bo pri let x=y x le pointer na object y // in se bo spremenil z spremembo "originala". spodnja stvar itak ni preveč efficent, loop čez vseh 7000 ljudi bi lahko delal težave... // kakšen Object.keys bi bila boljša varianta ampak raje napišem tale komentar... idk, to se mi je zdelo uporabno ampak sedaj obžalujem @@ -75,16 +75,19 @@ function populateAutocomplete() { for (let variableKey in autocomplete_entries) { autocomplete_entries[variableKey] = null; } + M.Autocomplete.init(elems, { data: autocomplete_entries, onAutocomplete: validateName, minLength: 0 }); + if(window.location.hash.length > 1) { - document.getElementById("full-name").value = decodeURIComponent(window.location.hash.substring(1)); + $("#full-name").val(decodeURIComponent(window.location.hash.substring(1))); } else { - document.getElementById("full-name").value = getUrlParameter("m"); + $("#full-name").val(getUrlParameter("m")); } + M.updateTextFields(); validateName(); } @@ -133,7 +136,7 @@ async function loadMessages(force_refresh = true, katera = 0) { success: (data) => { // If data is null, the request failed if (data === null) { - UIAlert( D("requestFailed") ); + UIAlert( D("requestFailed") ); setLoading(false); } else { // Save messages & populate view @@ -147,10 +150,9 @@ async function loadMessages(force_refresh = true, katera = 0) { }, error: () => { - UIAlert( D("errorFetchingMessages") ); + UIAlert( D("errorFetchingMessages") ); setLoading(false); } - }) } else { displayData(); @@ -187,16 +189,15 @@ async function loadMsg(id) { success: (data) => { // If data is null, the request failed if (data === null) { - UIAlert( D("unableToReceiveTheMessage") + " " + D("requestFailed") ); - setLoading(false); + UIAlert( `${D("unableToReceiveTheMessage")} ${D("requestFailed")}` ); } else { displayMessage(id, data); - setLoading(false); } + setLoading(false); }, error: () => { - UIAlert( D("unableToReceiveTheMessage") + " " + D("noInternetConnection") ); + UIAlert( `${D("unableToReceiveTheMessage")} ${D("noInternetConnection")}` ); setLoading(false); } @@ -231,16 +232,15 @@ async function deleteMsg(id) { success: (data) => { // If data is null, the request failed if (data === null) { - UIAlert( D("unableToDeleteTheMessage") + " " + D("requestFailed") ); - setLoading(false); + UIAlert( `${D("unableToDeleteTheMessage")} ${D("requestFailed")}` ); } else { document.getElementById("msg_box-" + id).remove(); - setLoading(false); } + setLoading(false); }, error: () => { - UIAlert( D("unableToDeleteTheMessage") + " " + D("noInternetConnection") ); + UIAlert( `${D("unableToDeleteTheMessage")} ${D("noInternetConnection")}` ); setLoading(false); } @@ -250,50 +250,90 @@ async function deleteMsg(id) { function displayMessage(id, data) { if(data["telo"].substring(0, 21) == ""+msgcontent - +sjcl.encrypt(document.getElementById("msg-e2ee-pass-input").value, document.getElementById("msg-body").value)+""; - } - sendMessage(value[document.getElementById("full-name").value], msgsubject, - htmlEncode(msgcontent)); - document.getElementById("msg-body").value = ""; - document.getElementById("full-name").value = ""; - document.getElementById("msg-subject").value = ""; - document.getElementById("msg-send").disabled = true; + var msgcontent = $("#msg-body").val() + additionalstufftoaddtomessage; + var msgsubject = $("#msg-subject").val(); + if ($("#msg-e2ee-pass").prop("hidden") !== true) { + var randomencdivid = Math.floor(Math.random() * 9999).toString().padStart(4, "0"); + var addrparts = window.location.href.split("/"); // engleski + + msgcontent = ` + +
+ This message was encrypted by BežiApp. + + +
+ + ` + } + sendMessage(value[$("#full-name").val()], msgsubject, htmlEncode(msgcontent)); + $("#msg-body").val(""); + $("#full-name").val(""); + $("#msg-subject").val(""); + $("#msg-send").prop("disabled", true); additionalstufftoaddtomessage = ""; - document.getElementById("msg-added-image").innerHTML = ""; - document.getElementById("msg-e2ee-pass").hidden = true; + + $("#msg-added-image").html(""); + $("#msg-e2ee-pass").hide(); + }).catch(function (err) { - UIAlert( D("unableToReadDirectory") + " " + D("messageCouldNotBeSend"), "45245" ); + UIAlert( `${D("unableToReadDirectory")} ${D("messageCouldNotBeSend")}`, "45245" ); console.log(err); }); }); diff --git a/js/settings.js b/js/settings.js index 41c9df1..5811ee4 100644 --- a/js/settings.js +++ b/js/settings.js @@ -8,7 +8,7 @@ async function setLanguage(langCode) { document.addEventListener("DOMContentLoaded", async () => { $(document).on("click",".settings-language-selector", function () { - let languageToSet = $(this).attr('data-language'); + let languageToSet = $(this).attr("data-language"); setLanguage(languageToSet); }); // Setup side menu diff --git a/js/teachers.js b/js/teachers.js index c41a621..aab7d74 100644 --- a/js/teachers.js +++ b/js/teachers.js @@ -119,10 +119,11 @@ function teacherInfo(teacher_id) { let subject = subjectsString.slice(0, -2); let office_day = dateString.day(teacher_object["tpMeetings"]["day"]); let office_lesson = teacher_object["tpMeetings"]["period"]; - document.getElementById("teacher-name").innerText = name; - document.getElementById("teacher-subject").innerText = S("schoolSubject") + ": " + subject; - document.getElementById("teacher-office").innerText = office_day + ", " + S("lesson") + " " + office_lesson; - const modal = document.querySelectorAll('.side-modal')[0]; + $("#teacher-name").text(name); + $("#teacher-subject").text(`${S("schoolSubject")}: ${subject}`); + $("#teacher-office").text(`${office_day}, ${S("lesson")} ${office_lesson}`); + + const modal = document.querySelectorAll(".side-modal")[0]; M.Sidenav.getInstance(modal).open(); } diff --git a/js/timetable.js b/js/timetable.js index 82baba9..2b718ad 100644 --- a/js/timetable.js +++ b/js/timetable.js @@ -224,13 +224,13 @@ function eventClickHandler(eventClickInfo) { let lesson_class = lesson_metadata["class"]; let lesson_duration = lesson_metadata["start"] + " - " + lesson_metadata["end"]; - document.getElementById("lesson-subject").innerText = lesson_subject; - document.getElementById("lesson-teacher").innerText = lesson_teacher; - document.getElementById("lesson-class").innerText = lesson_class; - document.getElementById("lesson-classroom").innerText = lesson_classroom; - document.getElementById("lesson-duration").innerText = lesson_duration; + $("#lesson-subject").text(lesson_subject); + $("#lesson-teacher").text(lesson_teacher); + $("#lesson-class").text(lesson_class); + $("#lesson-classroom").text(lesson_classroom); + $("#lesson-duration").text(lesson_duration); - const modal = document.querySelectorAll('.side-modal')[0]; + const modal = document.querySelectorAll(".side-modal")[0]; M.Sidenav.getInstance(modal).open(); } -- cgit v1.2.3