diff options
-rw-r--r-- | js/absences.js | 230 | ||||
-rw-r--r-- | js/app.js | 13 | ||||
-rw-r--r-- | js/grades.js | 403 | ||||
-rw-r--r-- | js/gradings.js | 248 | ||||
-rw-r--r-- | js/gsec.js | 26 | ||||
-rw-r--r-- | js/lang/bundle.js | 23 | ||||
-rw-r--r-- | js/login.js | 67 | ||||
-rw-r--r-- | js/teachers.js | 173 | ||||
-rw-r--r-- | js/timetable.js | 135 | ||||
-rw-r--r-- | login.html | 1 | ||||
-rw-r--r-- | pages/absences.html | 1 | ||||
-rw-r--r-- | pages/grades.html | 1 | ||||
-rw-r--r-- | pages/gradings.html | 1 | ||||
-rw-r--r-- | pages/teachers.html | 1 |
14 files changed, 601 insertions, 722 deletions
diff --git a/js/absences.js b/js/absences.js index 163b3f0..0540f1f 100644 --- a/js/absences.js +++ b/js/absences.js @@ -1,6 +1,6 @@ -const API_ENDPOINT = "https://gimb.tk/test.php"; +// const API_ENDPOINT = "https://gimb.tk/test.php"; // deprecated // const API_ENDPOINT = "http://localhost:5000/test.php"; - +var absences; async function checkLogin() { localforage.getItem("logged_in").then(function (value) { // This code runs once the value has been loaded @@ -24,128 +24,116 @@ function setLoading(state) { } async function loadAbsences(force_refresh = false) { - setLoading(true); - - // Load required data - let promises_to_run = [ - localforage.getItem("username").then(function (value) { - username = value; - }), - localforage.getItem("password").then(function (value) { - password = value; - }), - localforage.getItem("absences").then(function (value) { - absences = value; - }) - ]; - - await Promise.all(promises_to_run); - - // If we don't have a list of absences, query it - if (absences === null || force_refresh) { - $.ajax({ - url: API_ENDPOINT, - crossDomain: true, - - data: { - "u": username, - "p": password, - "m": "fetchizostanki", - "a": $("#datepicker-from").val(), - "b": $("#datepicker-to").val() - }, - dataType: "json", - - cache: false, - type: "GET", - - success: function (data) { - // If data is null, the credentials were incorrect - if (data === null) { - UIAlert(D("noAbsences"), "loadAbsences(): $.ajax data === null"); - setLoading(false); - } else { - // Save absences & populate UI - localforage.setItem("absences", data).then(function (value) { - absences = value; - displayData(); - setLoading(false); - }); - } - }, - - error: function () { - UIAlert(D("noInternetConnection"), "loadAbsences(): $.ajax.error"); - setLoading(false); - } - - }) - } else { - displayData(); - setLoading(false); - } - + setLoading(true); + // Load required data + let promises_to_run = [ + localforage.getItem("username").then(function (value) { + username = value; + }), + localforage.getItem("password").then(function (value) { + password = value; + }), + localforage.getItem("absences").then(function (value) { + absences = value; + }) + ]; + await Promise.all(promises_to_run); + // If we don't have a list of absences, query it + if (absences === null || force_refresh) { + try { + let gsecInstance = new gsec(); + await gsecInstance.login(username, password); + let date = {}; + date.from = $("#datepicker-from").val().split("."); + date.till = $("#datepicker-to").val().split("."); + Object.keys(date).map((key, index) => { + date[key] = new Date(Date.parse(date[key].reverse().join("-"))); + }); + gsecInstance.fetchAbsences().then( (value) => { + value.sort(function(a,b){ + // Turn your strings into dates, and then subtract them + // to get a value that is either negative, positive, or zero. + return new Date(b.date) - new Date(a.date); + }); + var fromKey = value.findIndex((processedElement, processedIndex) => { + if(processedElement.date.getTime() >= date.from.getTime()) { + return true; + } + }); + var tillKey = value.reverse().findIndex((pE, pI) => { + if(pE.date.getTime() <= date.till.getTime()) { + return true; + } + }); + value.length = tillKey+1; // tillKey in + value.splice(0, fromKey); // fromKey hočemo obdržati + absences = value; + localforage.setItem("absences", value).then((value) => { + displayData(); + setLoading(false); + }); + setLoading(false); + }).catch( (err) => { + gsecErrorHandlerUI(err); + setLoading(false); + }); + } catch (err) { + gsecErrorHandlerUI(err); + setLoading(false); + } + } else { + displayData(); + setLoading(false); + } } function displayData() { - absences.forEach(element => { - let li = document.createElement("li"); - - let date_string = element["datum"]["dan"] + ". " + element["datum"]["mesec"] + ". " + element["datum"]["leto"]; - - 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"); - - element["predmeti"].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["ura"]; - - let subject_lesson_icon_i = document.createElement("i"); - subject_lesson_icon_i.className = "material-icons"; - switch (lesson["opraviceno"]["status"]) { - case 0: - subject_lesson_icon_i.innerText = "schedule"; - break; - case 1: - subject_lesson_icon_i.innerText = "check_circle_outline"; - break; - case 2: - subject_lesson_icon_i.innerText = "error_outline"; - break; - case 3: - 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 = lesson["ime"]; - - subject_row.appendChild(subject_lesson_icon); - subject_row.appendChild(subject_lesson_text); - 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.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"; + break; + case 1: + subject_lesson_icon_i.innerText = "check_circle_outline"; + break; + case 2: + subject_lesson_icon_i.innerText = "error_outline"; + break; + case 3: + 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); + subject_row.appendChild(subject_lesson_text); + 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); + }); } function clearAbsences() { @@ -24,3 +24,16 @@ async function UIAlert(usermsg, devmsg) { } } +function gsecErrorHandlerUI(err) { + console.log("gsecErrorHanderUI: handling "+err); + if(err == GSEC_ERR_NET || err == GSEC_ERR_NET_POSTBACK_GET || err == GSEC_ERR_NET_POSTBACK_POST) { + UIAlert( D("gsecErrNet") ); + } else if(err == GSEC_ERR_LOGIN) { + UIAlert( D("gsecErrLogin") ); + localforage.setItem("logged_in", false).then( () => { + window.location.replace("/index.html"); + }); + } else { + UIAlert( D("gsecErrOther") ); + } +} diff --git a/js/grades.js b/js/grades.js index ec5bbe8..b77ffd2 100644 --- a/js/grades.js +++ b/js/grades.js @@ -1,6 +1,6 @@ -const API_ENDPOINT = "https://gimb.tk/test.php"; +// const API_ENDPOINT = "https://gimb.tk/test.php"; // deprecated let checkbox_state = false; - +var grades; async function checkLogin() { localforage.getItem("logged_in").then((value) => { // This code runs once the value has been loaded @@ -24,178 +24,135 @@ function setLoading(state) { } async function loadGrades(force_refresh = false) { - setLoading(true); - - let promises_to_run = [ - localforage.getItem("username").then((value) => { - username = value; - }), - localforage.getItem("password").then((value) => { - password = value; - }), - localforage.getItem("grades").then((value) => { - grades = value; - }) - ]; - - await Promise.all(promises_to_run); - - // If we don't have a list of grades, fetch it - if (grades === null || grades === [] || force_refresh) { - - $.ajax({ - url: API_ENDPOINT, - crossDomain: true, - - data: { - "u": username, - "p": password, - "m": "fetchocene" - }, - dataType: "json", - - cache: false, - type: "GET", - - success: (data) => { - // If data is null, the request failed - if (data === null) { - UIAlert(S("requestFailed"), "loadGrades(): data === null; request failed"); - setLoading(false); - } else { - // Save grades & populate view - localforage.setItem("grades", data).then((value) => { - grades = value; - displayGrades(); - setLoading(false); - }); - } - }, - - error: () => { - UIAlert(S("noInternetConnection"), "loadGrades(): $ajax-error"); - setLoading(false); - } - - }); - - } else { - displayGrades(); - setLoading(false); - } + setLoading(true); + let promises_to_run = [ + localforage.getItem("username").then((value) => { + username = value; + }), + localforage.getItem("password").then((value) => { + password = value; + }), + localforage.getItem("grades").then((value) => { + grades = value; + }) + ]; + await Promise.all(promises_to_run); + // 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); + gsecInstance.fetchGrades().then( (value) => { + grades = value; + localforage.setItem("grades", value).then((value) => { + displayGrades(); + setLoading(false); + }); + setLoading(false); + }).catch( (err) => { + gsecErrorHandlerUI(err); + setLoading(false); + }); + } catch (err) { + gsecErrorHandlerUI(err); + setLoading(false); + } + } else { + displayGrades(); + setLoading(false); + } } function displayGrades() { - let grades_by_subject = {}; - grades.forEach((grade, index) => { - if (!(grade["predmet"] in grades_by_subject)) { - grades_by_subject[grade["predmet"]] = []; - } - let grade_object = { - date: grade["datum"], - teacher: grade["profesor"], - subject: grade["predmet"], - title: grade["naslov"], - type: grade["vrsta"], - term: grade["rok"], - grade: grade["ocena"], - temporary: grade["zacasna"], - index: index - } - grades_by_subject[grade["predmet"]].push(grade_object); - }); - - let root_element = document.getElementById("grades-collapsible"); - - Object.keys(grades_by_subject).forEach((subject) => { - // Create root element for a subject 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"); - subject_header_text.innerText = subject; - - // Create collection for displaying individuals grades - let subject_body = document.createElement("div"); - subject_body.className = "collapsible-body"; - let subject_body_root = document.createElement("ul"); - subject_body_root.className = "collection"; - - // Setup variables for calculating average - let grade_sum = 0; - let grade_tot = 0; - - grades_by_subject[subject].forEach((grade) => { - // Create element for individual grade - let grade_node = document.createElement("li"); - grade_node.className = "collection-item"; - grade_node.classList.add("collection-item") - grade_node.classList.add("grade-node"); - grade_node.dataset["index"] = grade["index"]; - let grade_node_div = document.createElement("div"); - - // Node for date and subject text - let grade_text = document.createElement("span"); - // Node for the actual number - let grade_number = document.createElement("div"); - grade_number.className = "secondary-content"; - - // Apply different style, if the grade is temporary - if (grade["temporary"]) { - // Styling for text - let grade_text_italic = document.createElement("i"); - grade_text_italic.innerText = grade["date"] + " - " + grade["title"]; - grade_text.appendChild(grade_text_italic); - - // Styling for number - let grade_number_italic = document.createElement("i"); - grade_number_italic.innerText = grade["grade"].toString(); - grade_number.appendChild(grade_number_italic); - } else { - // Text - grade_text.innerText = grade["date"] + " - " + grade["title"]; - // Number - grade_number.innerText = grade["grade"].toString(); - } - - grade_node_div.appendChild(grade_text); - grade_node_div.appendChild(grade_number); - - grade_node.appendChild(grade_node_div); - - - // Count the grade only if it's not temporary or explicitly enabled - if (!grade["temporary"] || !checkbox_state) { - grade_sum += grade["grade"]; - grade_tot += 1; - } - - subject_body_root.appendChild(grade_node); - - }); - - let grade_average = (grade_tot === 0) ? "N/A" : (Math.round(((grade_sum / grade_tot) + Number.EPSILON) * 100) / 100); - let subject_header_average = document.createElement("div"); - subject_header_average.className = "collapsible-header-right"; - subject_header_average.innerText = grade_average.toString(); - - subject_header.appendChild(subject_header_text); - subject_header.appendChild(subject_header_average); - - 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); - - refreshClickHandlers(); + let grades_by_subject = {}; + grades.forEach((grade, index) => { + if (!(grade["subject"] in grades_by_subject)) { + grades_by_subject[grade["subject"]] = []; + } + let grade_object = { + date: dateString.longFormatted(grade["date"]), + teacher: grade["teacher"], + subject: grade["subject"], + title: grade["name"][0], + type: grade["name"][1], + term: grade["name"][2], + grade: grade["grade"], + temporary: grade["temporary"], + 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 + 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"); + subject_header_text.innerText = subject; + // Create collection for displaying individuals grades + let subject_body = document.createElement("div"); + subject_body.className = "collapsible-body"; + let subject_body_root = document.createElement("ul"); + subject_body_root.className = "collection"; + // Setup variables for calculating average + let grade_sum = 0; + let grade_tot = 0; + grades_by_subject[subject].forEach((grade) => { + // Create element for individual grade + let grade_node = document.createElement("li"); + grade_node.className = "collection-item"; + grade_node.classList.add("collection-item") + grade_node.classList.add("grade-node"); + grade_node.dataset["index"] = grade["index"]; + let grade_node_div = document.createElement("div"); + // Node for date and subject text + let grade_text = document.createElement("span"); + // Node for the actual number + let grade_number = document.createElement("div"); + grade_number.className = "secondary-content"; + // Apply different style, if the grade is temporary + if (grade["temporary"]) { + // Styling for text + let grade_text_italic = document.createElement("i"); + grade_text_italic.innerText = grade["date"] + " - " + grade["title"]; + grade_text.appendChild(grade_text_italic); + // Styling for number + let grade_number_italic = document.createElement("i"); + grade_number_italic.innerText = grade["grade"].toString(); + grade_number.appendChild(grade_number_italic); + } else { + // Text + grade_text.innerText = grade["date"] + " - " + grade["title"]; + // Number + grade_number.innerText = grade["grade"].toString(); + } + grade_node_div.appendChild(grade_text); + grade_node_div.appendChild(grade_number); + grade_node.appendChild(grade_node_div); + // Count the grade only if it's not temporary or explicitly enabled + if (!grade["temporary"] || !checkbox_state) { + grade_sum += grade["grade"]; + grade_tot += 1; + } + subject_body_root.appendChild(grade_node); + }); + let grade_average = (grade_tot === 0) ? "N/A" : (Math.round(((grade_sum / grade_tot) + Number.EPSILON) * 100) / 100); + let subject_header_average = document.createElement("div"); + subject_header_average.className = "collapsible-header-right"; + subject_header_average.innerText = grade_average.toString(); + subject_header.appendChild(subject_header_text); + subject_header.appendChild(subject_header_average); + 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); + refreshClickHandlers(); } function clearGrades() { @@ -211,65 +168,55 @@ function refreshGrades(force) { } function refreshClickHandlers() { - $("#grades-collapsible").find(".collection-item.grade-node").click(function () { - let grade_obj = grades[parseInt(this.dataset["index"])]; - document.getElementById("grade-header").innerText = grade_obj["predmet"] + ": " + grade_obj["ocena"]; - document.getElementById("grade-date").innerText = grade_obj["datum"]; - document.getElementById("grade-title").innerText = grade_obj["naslov"]; - document.getElementById("grade-type").innerText = "Type: " + grade_obj["vrsta"]; - - let term_element = document.getElementById("grade-term"); - if (grade_obj["rok"] !== "") { - term_element.innerText = S("term") + ": " + grade_obj["rok"]; - term_element.style["display"] = ""; - } else { - term_element.style["display"] = "none"; - } - - document.getElementById("grade-teacher").innerText = S("teacher") + ": " + grade_obj["profesor"]; - - let temporary_object = document.getElementById("grade-temporary"); - let temporary_object_root = document.getElementById("grade-temporary-root"); - if (grade_obj["zacasna"]) { - temporary_object.innerText = "(" + S("temporary") + ")"; - temporary_object_root.style["display"] = ""; - } else { - temporary_object_root.style["display"] = "none"; - } - - const modal = document.querySelectorAll('.side-modal')[0]; - M.Sidenav.getInstance(modal).open(); - }); + $("#grades-collapsible").find(".collection-item.grade-node").click(function () { + let grade_obj = grades[parseInt(this.dataset["index"])]; + document.getElementById("grade-header").innerText = grade_obj["subject"] + ": " + grade_obj["grade"]; + document.getElementById("grade-date").innerText = dateString.longFormatted(grade_obj["date"]); + document.getElementById("grade-title").innerText = grade_obj["name"][0]; + document.getElementById("grade-type").innerText = S("type") + ": " + grade_obj["name"][1]; + let term_element = document.getElementById("grade-term"); + if (grade_obj["name"][2] !== "") { + term_element.innerText = S("term") + ": " + grade_obj["name"][2]; + term_element.style["display"] = ""; + } else { + term_element.style["display"] = "none"; + } + document.getElementById("grade-teacher").innerText = S("teacher") + ": " + grade_obj["teacher"]; + let temporary_object = document.getElementById("grade-temporary"); + let temporary_object_root = document.getElementById("grade-temporary-root"); + if (grade_obj["temporary"]) { + temporary_object.innerText = "(" + S("temporary") + ")"; + temporary_object_root.style["display"] = ""; + } else { + temporary_object_root.style["display"] = "none"; + } + const modal = document.querySelectorAll('.side-modal')[0]; + M.Sidenav.getInstance(modal).open(); + }); } // Initialization code document.addEventListener("DOMContentLoaded", async () => { - checkLogin(); - await loadGrades(); - - let coll_elem = document.querySelectorAll('.collapsible'); - let coll_instance = M.Collapsible.init(coll_elem, {}); - - // Setup refresh handler - $("#refresh-icon").click(function () { - refreshGrades(true); - }); - - // Setup checkbox handler - $("#permanent-grades-checkbox").change(function () { - checkbox_state = this.checked; - refreshGrades(false); - }); - - 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 }); - await loadGrades(); + checkLogin(); + let coll_elem = document.querySelectorAll('.collapsible'); + let coll_instance = M.Collapsible.init(coll_elem, {}); + // Setup refresh handler + $("#refresh-icon").click(function () { + refreshGrades(true); + }); + // Setup checkbox handler + $("#permanent-grades-checkbox").change(function () { + checkbox_state = this.checked; + refreshGrades(false); + }); + 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 }); + await clearGrades(); + await loadGrades(); }); diff --git a/js/gradings.js b/js/gradings.js index 285f48b..756db9f 100644 --- a/js/gradings.js +++ b/js/gradings.js @@ -1,6 +1,6 @@ -const API_ENDPOINT = "https://gimb.tk/test.php"; +// const API_ENDPOINT = "https://gimb.tk/test.php"; // deprecated var calendar_obj = null; - +var gradings; async function checkLogin() { localforage.getItem("logged_in").then((value) => { // This code runs once the value has been loaded @@ -75,154 +75,116 @@ function getDateString() { } async function loadGradings(force_refresh = false) { - setLoading(true); - - let promises_to_run = [ - localforage.getItem("username").then((value) => { - username = value; - }), - localforage.getItem("password").then((value) => { - password = value; - }), - localforage.getItem("gradings").then((value) => { - gradings = value; - }) - ]; - - Promise.all(promises_to_run).then(() => { - - if (gradings === null || gradings === [] || gradings === -1 || force_refresh) { - $.ajax({ - url: API_ENDPOINT, - crossDomain: true, - - data: { - "u": username, - "p": password, - "m": "fetchocenjevanja" - }, - dataType: "json", - - cache: false, - type: "GET", - - success: (data) => { - - // If data is null, the credentials were incorrect - if (data === null) { - UIAlert( S("requestFailed"), "loadGradings(): data === null; request failed"); - setLoading(false); - } else { - // Save gradings & populate calendar - localforage.setItem("gradings", data).then((value) => { - gradings = value; - displayData(); - setLoading(false); - }); - } - - }, - - error: () => { - UIAlert( S("noInternetConnection"), "loadGradings(): $.ajax:error" ); - setLoading(false); - } - - }); - - } else { - displayData(); - setLoading(false); - } - }); - + setLoading(true); + let promises_to_run = [ + localforage.getItem("username").then((value) => { + username = value; + }), + localforage.getItem("password").then((value) => { + password = value; + }), + localforage.getItem("gradings").then((value) => { + gradings = value; + }) + ]; + await Promise.all(promises_to_run); + if (gradings === null || gradings === [] || gradings === -1 || force_refresh) { + try { + let gsecInstance = new gsec(); + await gsecInstance.login(username, password); + gsecInstance.fetchGradings().then( (value) => { + gradings = value; + localforage.setItem("gradings", value).then((value) => { + displayData(); + setLoading(false); + }); + setLoading(false); + }).catch( (err) => { + gsecErrorHandlerUI(err); + setLoading(false); + }); + } catch (err) { + gsecErrorHandlerUI(err); + setLoading(false); + } + } else { + displayData(); + setLoading(false); + } } function displayData() { - let transformed_gradings = []; - gradings.forEach((element, index) => { - - let bg_color = getHexColorFromString(element["kratica"]); - let fg_color = getForegroundFromBackground(bg_color); - - let grading_object = { - // Convert from dd.mm.yyyy to yyyy-mm-dd - start: element["datum"].split(".").reverse().join("-"), - title: element["kratica"], - id: index.toString(), - backgroundColor: bg_color, - textColor: fg_color - }; - - transformed_gradings.push(grading_object); - }); - - calendar_obj.removeAllEvents(); - calendar_obj.addEventSource(transformed_gradings); + let transformed_gradings = []; + gradings.forEach((element, index) => { + let bg_color = getHexColorFromString(element["acronym"]); + let fg_color = getForegroundFromBackground(bg_color); + let grading_object = { + start: element["date"].toISOString().substring(0, 10), // če se da direktno date object, se doda še 1a zraven (prefixa tajtlu) (verjetno 1am ura) + title: element["acronym"], + id: index.toString(), + backgroundColor: bg_color, + textColor: fg_color + }; + transformed_gradings.push(grading_object); + }); + calendar_obj.removeAllEvents(); + calendar_obj.addEventSource(transformed_gradings); } function gradingClickHandler(eventClickInfo) { - let grading_id = parseInt(eventClickInfo.event.id); - let grading_subject = gradings[grading_id]["predmet"]; - let grading_date = gradings[grading_id]["datum"]; - let grading_description = gradings[grading_id]["opis"]; - - document.getElementById("grading-subject").innerText = grading_subject; - document.getElementById("grading-date").innerText = grading_date; - document.getElementById("grading-description").innerText = grading_description; - - const modal = document.querySelectorAll('.side-modal')[0]; - M.Sidenav.getInstance(modal).open(); -} - -function setupPickers() { - // Setup pickers - var date_object = new Date(); - - let elems = document.querySelectorAll('#datepicker-add'); - let options = { - autoClose: true, - format: "dd.mm.yyyy", - defaultDate: date_object, - setDefaultDate: true, - firstDay: 1 - } - let instances = M.Datepicker.init(elems, options); - - - instances = M.Datepicker.init(elems, options); + let grading_id = parseInt(eventClickInfo.event.id); + let grading_subject = gradings[grading_id]["subject"]; + let grading_date_obj = gradings[grading_id]["date"]; + let grading_date = dateString.longFormatted(grading_date_obj); + let grading_description = gradings[grading_id]["description"]; + document.getElementById("grading-subject").innerText = grading_subject; + document.getElementById("grading-date").innerText = grading_date; + document.getElementById("grading-description").innerText = grading_description; + const modal = document.querySelectorAll('.side-modal')[0]; + M.Sidenav.getInstance(modal).open(); } - +/* + function setupPickers() { + // Setup pickers, todo (adding an event), to be stored in messages + var date_object = new Date(); + let elems = document.querySelectorAll('#datepicker-add'); + let options = { + autoClose: true, + format: "dd.mm.yyyy", + defaultDate: date_object, + setDefaultDate: true, + firstDay: 1 + } + let instances = M.Datepicker.init(elems, options); + instances = M.Datepicker.init(elems, options); + } +*/ document.addEventListener("DOMContentLoaded", () => { - checkLogin(); - - // Calendar setup - var calendarEl = document.getElementById("calendar"); - calendar_obj = new FullCalendar.Calendar(calendarEl, { - firstDay: 1, - plugins: ["dayGrid"], - defaultDate: getDateString(), - navLinks: false, - editable: false, - events: [], - eventClick: gradingClickHandler, - height: "parent" - }); - calendar_obj.render(); - setupPickers(); - loadGradings(); - - // Setup refresh handler - $("#refresh-icon").click(() => { - loadGradings(true); - }); - - // 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 }); + checkLogin(); + // Calendar setup + var calendarEl = document.getElementById("calendar"); + calendar_obj = new FullCalendar.Calendar(calendarEl, { + firstDay: 1, + plugins: ["dayGrid"], + defaultDate: getDateString(), + navLinks: false, + editable: false, + events: [], + eventClick: gradingClickHandler, + height: "parent" + }); + calendar_obj.render(); + // setupPickers(); // todo (adding an event), to be stored in messages + loadGradings(); + // Setup refresh handler + $("#refresh-icon").click(() => { + loadGradings(true); + }); + // 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 }); }); @@ -1,4 +1,3 @@ - // tab = 2 || any spaces; use tabs // not tested yet -- NOTE: document.createElement is xssy, use DOMParser! var gseAbsenceTypes = ["notProcessed", "authorizedAbsence", "unauthorizedAbsence", "doesNotCount"]; @@ -22,7 +21,8 @@ const GSEC_ERR_NET_POSTBACK_POST = "GSEC NETWORK ERROR (ajax error) in postback const GSEC_MSGTYPE_RECEIVED = 0; const GSEC_MSGTYPE_SENT = 1; const GSEC_MSGTYPE_DELETED = 2; - +const GSEC_ERR_LOGIN = "GSEC LOGIN ERROR"; +const GSEC_NO_ABSENCES = "noAbsences"; const GSEC_MSGTYPES = ["msgReceived", "msgSent", "msgDeleted"]; class gsec { @@ -102,10 +102,10 @@ class gsec { resolve(true); } else { if(!!(parsed.getElementById("lblMsg"))) { // če obstaja lblMsg (napaka pri prijavi) - reject(new Error(false)); + reject(new Error(GSEC_ERR_LOGIN)); } if(!(parsed.getElementById("ctl00_lblLoginName"))) { // če ni ctl00_lblLoginName nismo na Default.aspx - reject(new Error(false)); + reject(new Error(GSEC_ERR_LOGIN)); } else { resolve(parsed.getElementById("ctl00_lblLoginName").innerHTML); // vrne ime dijaka, to je lahko uporabno } @@ -232,7 +232,7 @@ class gsec { }); }); } - fetchTeachers() { + 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 = {}; this.postback(GSE_URL+"Page_Gim/Ucenec/UciteljskiZbor.aspx", {}, null, true).then((response)=>{ @@ -246,10 +246,8 @@ class gsec { var subjects = {}; for(const subjectString of subjectStrings) { var abkurzung = ""; - try { - abkurzung = stripHtml(subjectString).split('(').pop().split(')')[0]; - } catch (err) {} var subjectName = stripHtml(subjectString).split(" (")[0]; + abkurzung = stripHtml(subjectString).split('(').pop().split(')')[0]; subjects[abkurzung] = subjectName; } var TP = {}; @@ -305,7 +303,7 @@ class gsec { }); }); } - fetchAbsences(fromDate = null, tillDate = null) { + 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)) { tillDate = new Date(Date.UTC(9999, 11, 30)); // overkill? @@ -318,8 +316,12 @@ class gsec { this.postback(GSE_URL+"Page_Gim/Ucenec/IzostankiUcenec.aspx", dataToBeSent, null, true).then((response)=>{ let parser = new DOMParser(); let parsed = parser.parseFromString(response.data, "text/html"); - var rowElements = parsed.getElementById("ctl00_ContentPlaceHolder1_gvwIzostankiGroup").getElementsByTagName("tbody")[0].getElementsByTagName("tr"); - var absences = {}; + try { + var rowElements = parsed.getElementById("ctl00_ContentPlaceHolder1_gvwIzostankiGroup").getElementsByTagName("tbody")[0].getElementsByTagName("tr"); + } catch (err) { + resolve(GSEC_NO_ABSENCES); + } + var absences = []; for(const izostanek of rowElements) { var subFields = izostanek.getElementsByTagName("td"); var date = subFields[0].innerHTML.trim().split("."); @@ -332,7 +334,7 @@ class gsec { var period = Number(subject.split('">').pop().split('</span>')[0]); subjects[period] = {status: status, subject: subjectName}; } - absences[dateObj] = subjects; + absences.push({subjects: subjects, date: dateObj}); } resolve(absences); }); diff --git a/js/lang/bundle.js b/js/lang/bundle.js index c4c3a0b..8f540b9 100644 --- a/js/lang/bundle.js +++ b/js/lang/bundle.js @@ -8,6 +8,9 @@ var dateString = { month: (mesl) => { let mesecileta = [S("january"), S("february"), S("march"), S("april"), S("may"), S("june"), S("july"), S("august"), S("september"), S("october"), S("november"), S("december")]; return mesecileta[mesl]; + }, + longFormatted: (dateObject) => { + return dateString.day(dateObject.getDay())+", "+(dateObject.getDate())+". "+dateString.month(dateObject.getMonth())+" "+dateObject.getFullYear(); } }; async function refreshLangDOM() { @@ -172,6 +175,10 @@ var langstrings = { ok: "ok", noAbsences: "no absences in the chosen time period", lesson: "lesson", + notProcessed: "not processed", + authorizedAbsence: "authorized", + unauthorizedAbsence: "unauthorized", + doesNotCount: "does not count", // messaging sendAMessage: "send a message", recipient: "recipient", @@ -261,7 +268,11 @@ var langstrings = { privacyEffectiveAsOf: "this policy is effective as of", // settings language: "language", - languageSet: "language set, open another page for the changes to take effect" + languageSet: "language set, open another page for the changes to take effect", + // gsec + gsecErrNet: "GimSIS connection error", + gsecErrLogin: "GimSIS login error (bad password?), try logging out", + gsecErrOther: "GimSIS unknown error, try logging out" }, sl: { miscTranslationLanguage: "slovenščina", @@ -332,6 +343,10 @@ var langstrings = { ok: "v redu", noAbsences: "ni izostankov v izbranem časovnem obdobju", lesson: "ura", + notProcessed: "ni obdelano", + authorizedAbsence: "opravičeno", + unauthorizedAbsence: "neopravičeno", + doesNotCount: "ne šteje", // messaging sendAMessage: "pošlji sporočilo", recipient: "prejemnik", @@ -420,6 +435,10 @@ var langstrings = { privacyAcceptWithUse: "your continued use of our website will be regarded as acceptance of our practices around privacy and personal information. If you have any questions about how we handle user data and personal information, feel free to contact us.", privacyEffectiveAsOf: "this policy is effective as of", language: "jezik", - languageSet: "jezik nastavljen, odprite neko drugo stran da se pokažejo spremembe" + 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", + gsecErrOther: "neznana napaka GimSISa, poskusite se odjaviti" } } diff --git a/js/login.js b/js/login.js index d7c9579..281f7bc 100644 --- a/js/login.js +++ b/js/login.js @@ -1,4 +1,4 @@ -const API_ENDPOINT = "https://gimb.tk/test.php"; +// const API_ENDPOINT = "https://gimb.tk/test.php"; // deprecated document.addEventListener("DOMContentLoaded", () => { setupEventListeners(); }) @@ -21,48 +21,25 @@ function setupEventListeners() { // Handle login button click function login() { - // Get text input values - let username = $("#username").val(); - let password = $("#password").val(); - - // Make a request - $.ajax({ - url: API_ENDPOINT, - crossDomain: true, - - data: { - "u": username, - "p": password, - "m": "fetchprofil" - }, - dataType: "json", - - cache: false, - type: "GET", - - success: function (data) { - - // If ime is null, the password was incorrect - if (data["ime"] === null) { - UIAlert( S("loginFailed"), "login(): fetchprofil null name; bad login info." ); - $("#password").val(""); - } else { - - let promises_to_run = [ - localforage.setItem("logged_in", true), - localforage.setItem("username", username), - localforage.setItem("password", password) - ]; - Promise.all(promises_to_run).then(function () { - window.location.replace("/pages/timetable.html"); - }); - - } - }, - - error: function () { - UIAlert( S("noInternetConnection"), "login(): $.ajax error" ); - } - - }) + let username = $("#username").val(); + let password = $("#password").val(); + var gsecInstance = new gsec(); + gsecInstance.login(username, password).then( (value) => { + if(typeof value == "string") { + let promises_to_run = [ + localforage.setItem("logged_in", true), + localforage.setItem("username", username), + localforage.setItem("password", password) + ]; + Promise.all(promises_to_run).then(function () { + window.location.replace("/pages/timetable.html"); + }); + } else { + UIAlert("loginFailed"); + $("#password").val(""); + } + }).catch((err) => { + gsecErrorHandlerUI(err); + $("#password").val(""); + }); } diff --git a/js/teachers.js b/js/teachers.js index bb5137b..c41a621 100644 --- a/js/teachers.js +++ b/js/teachers.js @@ -1,4 +1,4 @@ -const API_ENDPOINT = "https://gimb.tk/test.php"; +// const API_ENDPOINT = "https://gimb.tk/test.php"; // deprecated // const API_ENDPOINT = "http://localhost:5000/test.php"; var teachers = null; @@ -14,91 +14,71 @@ function setLoading(state) { // Function, responsible for fetching and displaying data async function loadTeachers(force_refresh = false) { - setLoading(true); - - // Load required data - let promises_to_run = [ - localforage.getItem("username").then((value) => { - username = value; - }), - localforage.getItem("password").then((value) => { - password = value; - }), - localforage.getItem("teachers").then((value) => { - teachers = value; - }) - ]; - - Promise.all(promises_to_run).then(() => { - - // If we don't have a list of teachers, query it - if (teachers === null || force_refresh) { - $.ajax({ - url: API_ENDPOINT, - crossDomain: true, - - data: { - "u": username, - "p": password, - "m": "fetchprofesorji" - }, - dataType: "json", - - cache: false, - type: "GET", - - success: (data) => { - // If data is null, the request failed - if (data === null) { - UIAlert(D("requestFailed")); - setLoading(false); - } else { - // Save teachers & populate table - localforage.setItem("teachers", data).then((value) => { - teachers = value; - displayData(); - setLoading(false); - }); - } - }, - - error: () => { - UIAlert(D("noInternetConnection")); - setLoading(false); - } - - }) - } else { - displayData(); - setLoading(false); - } - }); + setLoading(true); + // Load required data + let promises_to_run = [ + localforage.getItem("username").then((value) => { + username = value; + }), + localforage.getItem("password").then((value) => { + password = value; + }), + localforage.getItem("teachers").then((value) => { + teachers = value; + }) + ]; + await Promise.all(promises_to_run); + // If we don't have a list of teachers, query it + if (teachers === null || force_refresh) { + try { + let gsecInstance = new gsec(); + await gsecInstance.login(username, password); + gsecInstance.fetchTeachers().then( (value) => { + teachers = value; + localforage.setItem("teachers", value).then((value) => { + displayData(); + setLoading(false); + }); + setLoading(false); + }).catch( (err) => { + gsecErrorHandlerUI(err); + setLoading(false); + }); + } catch (err) { + gsecErrorHandlerUI(err); + setLoading(false); + } + } else { + displayData(); + setLoading(false); + } } // Function for displaying data function displayData() { - - teachers.forEach(element => { - // Create row - let row = document.createElement("tr"); - // Create cell 1 - let cell_name = document.createElement("td"); - let cell_name_text = document.createTextNode(element["ime"]); - // Create cell 2 - let cell_subject = document.createElement("td"); - // Array ([0]) is useless, since every teacher is duplicated (for each subject) - let cell_subject_text = document.createTextNode(element["predmeti"][0]["ime"]); - - cell_name.appendChild(cell_name_text); - row.appendChild(cell_name); - - cell_subject.appendChild(cell_subject_text); - row.appendChild(cell_subject); - - $("#teachers-body").append(row); - }); - // Refresh handlers - refreshTableClickHandlers(); + for(const teacher of Object.keys(teachers)) { + // Create row + let row = document.createElement("tr"); + // Create cell 1 + let cell_name = document.createElement("td"); + let cell_name_text = document.createTextNode(teacher); + // Create cell 2 + let cell_subject = document.createElement("td"); + // Array ([0]) is useless, since every teacher is duplicated (for each subject) // <-- ne velja za gsec.js, velja pa za gimsisextclient, PHP varianta + var subjectsString = ""; + for(const subject of Object.keys(teachers[teacher]["subjects"])) { + subjectsString += subject; + subjectsString += ", "; + } + let cell_subject_text = document.createTextNode(subjectsString.slice(0, -2)); // slajsnemo zadnji ", " + cell_name.appendChild(cell_name_text); + row.appendChild(cell_name); + cell_subject.appendChild(cell_subject_text); + row.appendChild(cell_subject); + $("#teachers-body").append(row); + }; + // Refresh handlers + refreshTableClickHandlers(); } async function checkLogin() { @@ -129,20 +109,21 @@ function refreshTableClickHandlers() { } function teacherInfo(teacher_id) { - let teacher_object = teachers[teacher_id]; - - let name = teacher_object["ime"]; - let subject = teacher_object["predmeti"][0]["ime"]; - let office_day = dateString.day(teacher_object["govorilneure"]["dan"]); - let office_lesson = teacher_object["govorilneure"]["solskaura"]; - - 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]; - M.Sidenav.getInstance(modal).open(); + let name = Object.keys(teachers)[teacher_id]; + let teacher_object = teachers[name]; + var subjectsString = ""; + for(const subject of Object.keys(teacher_object["subjects"])) { + subjectsString += subject; + subjectsString += ", "; + } + 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]; + M.Sidenav.getInstance(modal).open(); } document.addEventListener("DOMContentLoaded", () => { diff --git a/js/timetable.js b/js/timetable.js index 2aecdb0..82baba9 100644 --- a/js/timetable.js +++ b/js/timetable.js @@ -1,9 +1,8 @@ -const API_ENDPOINT = "https://gimb.tk/test.php"; +// const API_ENDPOINT = "https://gimb.tk/test.php"; // deprecated // const API_ENDPOINT = "http://localhost:5000/test.php"; var calendar_obj = null; var transformed_storage = []; - function checkLogin() { localforage.getItem("logged_in").then((value) => { // This code runs once the value has been loaded @@ -89,73 +88,59 @@ function getLastMonday(date_object) { // ---------------------------------- async function loadTimetable(date_object, force_refresh = false) { - setLoading(true); - - let date_monday = getLastMonday(date_object); - let date_string = getDateString(date_monday); - - // Load required data - let promises_to_run = [ - localforage.getItem("username").then(function (value) { - username = value; - }), - localforage.getItem("password").then(function (value) { - password = value; - }), - localforage.getItem("timetable").then(function (value) { - timetable = value; - }) - ]; - - await Promise.all(promises_to_run); - - if (force_refresh || timetable == null || !(date_string in timetable)) { - $.ajax({ - url: API_ENDPOINT, - crossDomain: true, - - data: { - "u": username, - "p": password, - "m": "fetchurnik", - "a": date_string - }, - dataType: "json", - - cache: false, - type: "GET", - - success: (data) => { - // Check if operation was successful - if (data === null) { - UIAlert( D("noPeriods") ); - setLoading(false); - } else { - - // Populate the calendar & save data - if (timetable === null) { - timetable = {}; - } - - timetable[date_string] = data; - localforage.setItem("timetable", timetable).then(() => { - displayTimetable(data, date_monday); - setLoading(false); - }); - } - }, - - error: () => { - UIAlert( D( "noInternetConnection" ) ); - setLoading(false); - } - - }); - - } else { - displayTimetable(timetable[date_string], date_monday); - setLoading(false); - } + setLoading(true); + var timetable, username, password; + let date_monday = getLastMonday(date_object); + let date_string = getDateString(date_monday); + let promises_to_run = [ + localforage.getItem("username").then(function (value) { + username = value; + }), + localforage.getItem("password").then(function (value) { + password = value; + }), + localforage.getItem("timetable").then(function (value) { + timetable = value; + }) + ]; + await Promise.all(promises_to_run); + if (force_refresh || timetable == null || !(date_string in timetable)) { + try { + let gsecInstance = new gsec(); + await gsecInstance.login(username, password); + gsecInstance.fetchTimetable(date_object).then( (value) => { + containsPeriods = false; + for(var iteration = 0; iteration <= 6; iteration++) { + if(Object.keys(value[iteration]).length > 0) { + containsPeriods = true; + // break; + } + } + if(!containsPeriods) { + UIAlert( D("noPeriods") ); + setLoading(false); + } else { + if (timetable === null) { + timetable = {}; + } + timetable[date_string] = value; + localforage.setItem("timetable", timetable).then(() => { + displayTimetable(value, date_monday); + setLoading(false); + }); + } + }).catch( (err) => { + gsecErrorHandlerUI(err); + setLoading(false); + }); + } catch (err) { + gsecErrorHandlerUI(err); + setLoading(false); + } + } else { + displayTimetable(timetable[date_string], date_monday); + setLoading(false); + } } function getLessonTimes(lesson_number) { @@ -196,21 +181,21 @@ function displayTimetable(weekly_timetable, date_object) { let lesson = daily_timetable[lesson_number]; let lesson_times = getLessonTimes(parseInt(lesson_number)); - let bg_color = getHexColorFromString(lesson["kratica"]); + let bg_color = getHexColorFromString(lesson["acronym"]); let fg_color = getForegroundFromBackground(bg_color); let lesson_metadata = { - subject: lesson["predmet"], - class: lesson["razred"], - teacher: lesson["profesor"], - classroom: lesson["prostor"], + subject: lesson["subject"], + class: lesson["class"], + teacher: lesson["teacher"], + classroom: lesson["place"], start: lesson_times[0].substring(0, 5), end: lesson_times[1].substring(0, 5) } let lesson_object = { id: JSON.stringify(lesson_metadata), - title: lesson["kratica"], + title: lesson["acronym"], start: date_string + " " + lesson_times[0], end: date_string + " " + lesson_times[1], backgroundColor: bg_color, @@ -16,6 +16,7 @@ <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/gsec.js"></script> <!-- gimsisextclient --> <script type="text/javascript" src="/js/login.js"></script> <link rel="manifest" href="/manifest.json"> diff --git a/pages/absences.html b/pages/absences.html index e893cbc..a25d128 100644 --- a/pages/absences.html +++ b/pages/absences.html @@ -20,6 +20,7 @@ <link rel="manifest" href="/manifest.json"> <script src="/js/app.js"></script> + <script src="/js/gsec.js"></script> <!-- gimsisextclient --> <script src="/js/lang/bundle.js"></script> <link rel="shortcut icon" type="image/png" href="/favicon.png" /> diff --git a/pages/grades.html b/pages/grades.html index 03215fd..878ccd2 100644 --- a/pages/grades.html +++ b/pages/grades.html @@ -16,6 +16,7 @@ <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/gsec.js"></script> <!-- gimsisextclient --> <script type="text/javascript" src="/js/grades.js"></script> <link rel="manifest" href="/manifest.json"> diff --git a/pages/gradings.html b/pages/gradings.html index 601e8b8..d18670e 100644 --- a/pages/gradings.html +++ b/pages/gradings.html @@ -23,6 +23,7 @@ <script src="/js/lib/fullcalendar/daygrid/main.min.js"></script> <link type="text/css" href="/css/styles.css" rel="stylesheet"> + <script type="text/javascript" src="/js/gsec.js"></script> <!-- gimsisextclient --> <script type="text/javascript" src="/js/gradings.js"></script> <link rel="manifest" href="/manifest.json"> diff --git a/pages/teachers.html b/pages/teachers.html index 25f1e1e..e68f512 100644 --- a/pages/teachers.html +++ b/pages/teachers.html @@ -16,6 +16,7 @@ <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/gsec.js"></script> <script type="text/javascript" src="/js/teachers.js"></script> <link rel="manifest" href="/manifest.json"> |