summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAnton Luka Šijanec <sijanecantonluka@gmail.com>2020-06-04 16:31:04 +0200
committerGitHub <noreply@github.com>2020-06-04 16:31:04 +0200
commitf3a11185852127f70599295fdc5c7e9b72d790b6 (patch)
tree5e0f9eb2e0e41e6ff40f17ada1f508557ef3ab63
parentMerge pull request #21 from beziapp/github-actions-fix (diff)
parentslovnična napaka == crirical bug (diff)
downloadbeziapp-f3a11185852127f70599295fdc5c7e9b72d790b6.tar
beziapp-f3a11185852127f70599295fdc5c7e9b72d790b6.tar.gz
beziapp-f3a11185852127f70599295fdc5c7e9b72d790b6.tar.bz2
beziapp-f3a11185852127f70599295fdc5c7e9b72d790b6.tar.lz
beziapp-f3a11185852127f70599295fdc5c7e9b72d790b6.tar.xz
beziapp-f3a11185852127f70599295fdc5c7e9b72d790b6.tar.zst
beziapp-f3a11185852127f70599295fdc5c7e9b72d790b6.zip
-rw-r--r--README.md75
-rw-r--r--assets/css/styles.css8
-rw-r--r--assets/js/grades.js424
-rw-r--r--assets/js/gradings.js40
-rw-r--r--assets/js/gsec.js74
-rw-r--r--assets/js/lang/bundle.js22
-rw-r--r--assets/js/login.js3
-rw-r--r--assets/js/messaging.js2
-rw-r--r--assets/js/setup-storage.js2
-rw-r--r--assets/pages-src/grades.bvr3
-rw-r--r--assets/pages-src/gradings.bvr38
-rw-r--r--assets/pages-src/misc/grading-add-modal.bvr35
-rw-r--r--assets/pages-src/misc/msg-compose-modal.bvr4
-rwxr-xr-xbin/compose-htmlbin27248 -> 31664 bytes
-rwxr-xr-xbin/compose-singlebin27104 -> 31488 bytes
-rwxr-xr-xbin/jsbundlebin13296 -> 17576 bytes
-rwxr-xr-xbin/jsminbin13664 -> 17904 bytes
-rwxr-xr-xdist/css/styles.css8
-rwxr-xr-xdist/js/app.js4
-rw-r--r--dist/js/grades.js7
-rw-r--r--dist/js/gradings.js1
-rw-r--r--dist/js/gsec.js9
-rw-r--r--dist/js/lang/bundle.js4
-rw-r--r--dist/js/login.js2
-rw-r--r--dist/js/messaging.js2
-rw-r--r--dist/js/setup-storage.js2
-rwxr-xr-xdist/pages/about.html4
-rwxr-xr-xdist/pages/grades.html3
-rwxr-xr-xdist/pages/gradings.html69
-rwxr-xr-xdist/pages/messaging.html4
-rwxr-xr-xdist/sw.js4
-rw-r--r--global.bvr2
32 files changed, 490 insertions, 365 deletions
diff --git a/README.md b/README.md
index ed69792..3de1c5d 100644
--- a/README.md
+++ b/README.md
@@ -1,33 +1,60 @@
-# for developers (rstular)
+# BežiApp
-from sijanec
+BežiApp je bolj tako uporabnikom kot strojem prijazen sistem za povezavo in pridobivanje informacij Gimnazije Bežigrad, ki ga
+razvija ekipa gimb-dev (@rstular in @asijanec).
-I was frustrated by the fact that I needed to change side navigation on 10+ individual html files if I added a page or wanted
-to change a single icon. So I wrote this small script that includes html files from other html files. Syntax `<@?i
-navigation@>` in a .bvr file in [pages-src](pages-src) will include [`navigation.bvr` from
-`pages-src/misc/`](pages-src/misc/navigation.bvr). PATH (where to search for files to include) can be set in
-[`global.bvr`](global.bvr) (separated with a space). Variables can also be set without touching the disk (faster, idrk) with
-`<@?s variable_name variable value@>` and read with `<@?s variable_name@>`. To execute a command and surpress output, use
-`<@#?x arg@>` where `x` is the command.
+## zakaj?
-So pages are now in pages-src and before deployment, `./compose_html pages-src/ pages/` has to be run to update the pages
-dir.
+brez BežiApp orodij je uporaba eRedovalnice za dijake in starše grozna uporabniška izkušnja. Uradna aplikacija je bila narejena
+leta 2009, in teče na Microsoft ASPX .NET C# okolju. Verjamemo, da uporaba takih orodij nikakor ni dobra izbira, saj na dolgi rok
+prinaša vedno več težav. BežiApp lepo izgleda, je izdelan v minimalističnem, a kompaktnem slogu, ki deluje na dlančnikih in
+računalniških zaslonih in ima lepo dokumentirane APIje. Poleg tega je 100% odprtokoden.
+brez BežiApp orodij je strojno upravljanje s podatki oteženo. GimB za podatke nima APIja, vse gre prek izdelanih HTML strani.
-idkr, it seemed like a good idea, but feel free not to use it (write about it here so I won't override your commits).
+za bežigrajske programe je znanih veliko programskih lukenj, ki ogrožajo uporabniško varnost. Najditelji napak zgimsisa in ostalih
+storitev njihove razvijalce o svojih varnostnih pomislekih opozorili, vendar programerji napak nikoli niso odpravili. Ker večina
+ljudi, s tem tudi jaz, nočemo uporabljati programov, ki naša računalniška orodja vzpostavljajo napadalcem, smo razvili 100%
+preverljivo programje, ki med drugim te napake tudi večinoma odpravi.
-the compiled binaries work on "`Linux kondenzator 5.3.0-46-generic #38~18.04.1-Ubuntu SMP Tue Mar 31 04:17:56 UTC 2020 x86_64
-x86_64 x86_64 GNU/Linux`".
+## APIji
-there's now a configure script (bash) that compiles all binaries (use if the prebuilt binaries don't work).
+BežiApp programerji izdelujemo knjižnice za integracijo avtomatskih zahtev v bežigrajske storitve, kot so lopolis in
+zgimsisext. Te knjižnice so javno dostopne.
-```
-# install dependencies
-sudo apt install git gcc
-# run from project directory
-./configure
-```
-creates binaries so you can use the ./install everytime you make changes (and hook to post-commit)
+* https://github.com/rstular/lopolis-api se uporablja za avtomatizirano naročanje hrane
+* `gsec.js` se uporablja za avtomatizirano obdelavo podatkov GimSISExt platforme v Javascript jeziku
+* https://github.com/sijanec/gimsisextclient se uporablja za avtomatizirano obdelavo podatkov GimSISExt platforme v PHP jeziku
-should there be any conflicts with the developers on different platforms, .gitignore files will be created to ignore binaries
-from being comitted every time.
+## uporaba BežiAppa
+
+za uporabnike bo verjetno najlažje BežiApp uporabljati iz strežnikov, ki jih vzpostavlja ekipa gimb-dev (gimb.tk). Aplikacija je
+dostopna iz trgovine Android Market (Google Play Store).
+
+za uporabnike iPhone telefov je proces nastavitve malce drugačen, vendar sila preprost. Navodila so na naši instagram strani,
+https://www.instagram.com/p/B8bZGkugjKp/.
+
+### namestitev na lasten strežnik.
+
+pogruntaj sam!
+
+## gimb.tk strežniki
+
+dijaki GimB, ki so člani gimb-dev skupine, postavljajo strežnike v dobro Gimnazije. Te strežniki so javno dostopni na domeni
+gimb.tk in kdorkoli se lahko poslužuje njihovih storitev, povsem brezplačno.
+
+med drugim te strežniki gostujejo:
+
+* GimB Meet aplikacijo za videokonference (video.gimb.tk),
+* spletne učilnice s šifrirano povezavo in lajševalniki za izdelavo kvizov (ucilnice.gimb.tk),
+* zgimsisext s šifrirano povezavo (zgimsis.gimb.tk),
+* avtentikacijski strežnik GimB osebja, dijakov in staršev (auth.gimb.tk),
+* portal za prijavo napak razvijalcem BežiAppa (beziapp-report.gimb.tk),
+* BežiApp (app.gimb.tk, dev.gimb.tk)
+* gimsisextclient inštalacijo (gimb.tk/test.php)
+* reddit bota za preverjanje pristnosti dijakov podbralnika r/bezigrad (reddit.gimb.tk)
+
+in še veliko več.
+
+strežniki delujejo povsem v skladu z zakoni in so povezani v akademsko in raziskovalno internacionalno omrežje GÉANT. Vanj jih
+povezuje operater akademskega in izobraževalnega omrežja Grčije, grNET.
diff --git a/assets/css/styles.css b/assets/css/styles.css
index 4e6050b..3f403e7 100644
--- a/assets/css/styles.css
+++ b/assets/css/styles.css
@@ -417,3 +417,11 @@ p {
h1, h2, h3, h4, h5, h6 {
color: var(--color-text) !important;
}
+
+.card {
+ background-color: var(--background-accent) !important;
+}
+
+.zakljucna-grade {
+ color: red;
+} \ No newline at end of file
diff --git a/assets/js/grades.js b/assets/js/grades.js
index aff62e4..549ac7c 100644
--- a/assets/js/grades.js
+++ b/assets/js/grades.js
@@ -2,234 +2,244 @@
let checkbox_state = false;
var grades;
async function checkLogin() {
- localforage.getItem("logged_in").then((value) => {
- // This code runs once the value has been loaded
- // from the offline store.
- if (value !== true) {
- window.location.replace("/index.html");
- }
- }).catch((err) => {
- // This code runs if there were any errors
- console.log(err);
- });
+ localforage.getItem("logged_in").then((value) => {
+ // This code runs once the value has been loaded
+ // from the offline store.
+ if (value !== true) {
+ window.location.replace("/index.html");
+ }
+ }).catch((err) => {
+ // This code runs if there were any errors
+ console.log(err);
+ });
}
// Set loading bar visibility
function setLoading(state) {
- if (state) {
- $("#loading-bar").removeClass("hidden");
- } else {
- $("#loading-bar").addClass("hidden");
- }
+ if (state) {
+ $("#loading-bar").removeClass("hidden");
+ } else {
+ $("#loading-bar").addClass("hidden");
+ }
}
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) {
- try {
-
- let gsecInstance = new gsec();
- await gsecInstance.login(username, password);
-
- gsecInstance.fetchGrades().then( (value) => {
- grades = value;
- localforage.setItem("grades", value).then(() => {
- displayGrades();
- setLoading(false);
- });
- setLoading(false);
- }).catch( (err) => {
- gsecErrorHandlerUI(err);
- setLoading(false);
- });
-
- } catch (err) {
- gsecErrorHandlerUI(err);
- 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(() => {
+ 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["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();
+ let grades_by_subject = {};
+ let zakljucne_grades_by_subject = {};
+ grades.forEach((grade, index) => {
+ if (grade["gradeType"] != GSEC_NORMAL_GRADE) {
+ zakljucne_grades_by_subject[grade["subject"]] = grade["grade"];
+ } else {
+ 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";
+ if (subject in zakljucne_grades_by_subject) {
+ subject_header_average.innerText = zakljucne_grades_by_subject[subject];
+ subject_header_average.classList.add("zakljucna-grade");
+ } else {
+ 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() {
- const table = document.getElementById("grades-collapsible");
- while (table.firstChild) {
- table.removeChild(table.firstChild);
- }
+ const table = document.getElementById("grades-collapsible");
+ while (table.firstChild) {
+ table.removeChild(table.firstChild);
+ }
}
function refreshGrades(force) {
- clearGrades();
- loadGrades(force);
+ clearGrades();
+ loadGrades(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["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();
- });
+ $("#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();
-
- let coll_elem = document.querySelectorAll('.collapsible');
- 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');
- 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 });
-
- clearGrades();
- await loadGrades();
+ checkLogin();
+
+ let coll_elem = document.querySelectorAll('.collapsible');
+ 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');
+ 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 });
+
+ clearGrades();
+ await loadGrades();
+
});
diff --git a/assets/js/gradings.js b/assets/js/gradings.js
index f884bf2..4730248 100644
--- a/assets/js/gradings.js
+++ b/assets/js/gradings.js
@@ -131,6 +131,18 @@ function displayData() {
calendar_obj.addEventSource(transformed_gradings);
}
+async function validateInputs() {
+ if ($("#input-grading-name").val() != null && $("#input-grading-name").val().length > 0) {
+ $("#btn-add-grading").removeAttr("disabled");
+ $("#input-grading-name").addClass("valid");
+ $("#input-grading-name").removeClass("invalid");
+ } else {
+ $("#btn-add-grading").attr("disabled", "disabled");
+ $("#input-grading-name").addClass("invalid");
+ $("#input-grading-name").removeClass("valid");
+ }
+}
+
function gradingClickHandler(eventClickInfo) {
let grading_id = parseInt(eventClickInfo.event.id);
let grading_subject = gradings[grading_id]["subject"];
@@ -144,19 +156,21 @@ function gradingClickHandler(eventClickInfo) {
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
- }
- instances = M.Datepicker.init(elems, options);
+
+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
}
+ instances = M.Datepicker.init(elems, options);
+}
+
document.addEventListener("DOMContentLoaded", () => {
@@ -176,6 +190,7 @@ document.addEventListener("DOMContentLoaded", () => {
calendar_obj.render();
// Modal for adding gradings
+
// setupPickers(); // todo (adding an event), to be stored in messages
// // Setup modals
// const modal_elems = document.querySelectorAll('.modal');
@@ -186,6 +201,7 @@ document.addEventListener("DOMContentLoaded", () => {
// };
// M.Modal.init(modal_elems, modal_options);
+
loadGradings(true);
// Setup refresh handler
$("#refresh-icon").click(() => {
diff --git a/assets/js/gsec.js b/assets/js/gsec.js
index 96ea624..6cef90e 100644
--- a/assets/js/gsec.js
+++ b/assets/js/gsec.js
@@ -28,6 +28,8 @@ const GSEC_MSGTYPE_DELETED = 2;
const GSEC_ERR_LOGIN = "GSEC LOGIN ERROR";
const GSEC_NO_ABSENCES = "noAbsences";
const GSEC_MSGTYPES = ["msgReceived", "msgSent", "msgDeleted"];
+const GSEC_NORMAL_GRADE = "GSEC NORMAL GRADE";
+const GSEC_ZAKLJUCNA_GRADE = "GSEC ZAKLJUCNA GRADE";
class gsec {
@@ -480,39 +482,49 @@ class gsec {
let gradeSpans = parsed.getElementsByClassName("txtVOcObd");
for (const grade of gradeSpans) {
var ist = grade.getElementsByTagName("span")[0].getAttribute("title").split("\n");
- var date = ist[0].split(": ")[1].trim().split(".");
- var dateObj = new Date(Date.parse(`${date[2]}-${date[1]}-${date[0]}`));
- var teacher = ist[1].split(": ")[1].trim();
- var subject = ist[2].split(": ")[1].trim();
- var name = [];
-
- name.push(ist[3].split(": ")[1].trim())
- name.push(ist[4].split(": ")[1].trim())
- name.push(ist[5].split(": ")[1].trim())
-
- var gradeNumber = Number(grade.getElementsByTagName("span")[0].innerHTML);
- var temporary = grade.getElementsByTagName("span")[0].classList.contains("ocVmesna");
-
- var gradeToAdd = {
- "date": dateObj,
- "teacher": teacher,
- "subject": subject,
- "name": name,
- "temporary": temporary,
- "grade": gradeNumber
- };
-
- if (grade.getElementsByTagName("span").length > 1) {
- if(grade.getElementsByTagName("span")[1].classList.contains("ocVmesna")) {
- gradeToAdd["temporary"] = true;
- } else {
- gradeToAdd["temporary"] = false;
+ if (ist.length == 1) { // that means the txtVOcObd defines a zaključno oceno // gimsis is just utter crap
+ var gradeToAdd = {
+ "gradeType": GSEC_ZAKLJUCNA_GRADE,
+ "grade": Number(grade.getElementsByTagName("span")[0].innerHTML),
+ "subject": grade.parentElement.parentElement.parentElement.parentElement.
+ getElementsByTagName("th")[0].innerText // I fucking hope this works
}
- gradeToAdd["grade"] = Number(grade.getElementsByTagName("span")[1].innerHTML);
- gradeToAdd["oldgrade"] = Number(grade.getElementsByTagName("span")[0].innerHTML);
+ grades.push(gradeToAdd);
+ } else {
+ var date = ist[0].split(": ")[1].trim().split(".");
+ var dateObj = new Date(Date.parse(`${date[2]}-${date[1]}-${date[0]}`));
+ var teacher = ist[1].split(": ")[1].trim();
+ var subject = ist[2].split(": ")[1].trim();
+ var name = [];
+
+ name.push(ist[3].split(": ")[1].trim())
+ name.push(ist[4].split(": ")[1].trim())
+ name.push(ist[5].split(": ")[1].trim())
+
+ var gradeNumber = Number(grade.getElementsByTagName("span")[0].innerHTML);
+ var temporary = grade.getElementsByTagName("span")[0].classList.contains("ocVmesna");
+
+ var gradeToAdd = {
+ "gradeType": GSEC_NORMAL_GRADE, // well said I must say
+ "date": dateObj,
+ "teacher": teacher,
+ "subject": subject,
+ "name": name,
+ "temporary": temporary,
+ "grade": gradeNumber
+ };
+
+ if (grade.getElementsByTagName("span").length > 1) {
+ if(grade.getElementsByTagName("span")[1].classList.contains("ocVmesna")) {
+ gradeToAdd["temporary"] = true;
+ } else {
+ gradeToAdd["temporary"] = false;
+ }
+ gradeToAdd["grade"] = Number(grade.getElementsByTagName("span")[1].innerHTML);
+ gradeToAdd["oldgrade"] = Number(grade.getElementsByTagName("span")[0].innerHTML);
+ }
+ grades.push(gradeToAdd);
}
- grades.push(gradeToAdd);
-
}
resolve(grades);
},
diff --git a/assets/js/lang/bundle.js b/assets/js/lang/bundle.js
index 8270527..b311bf4 100644
--- a/assets/js/lang/bundle.js
+++ b/assets/js/lang/bundle.js
@@ -10,7 +10,7 @@ var dateString = {
return mesecileta[mesl];
},
longFormatted: (dateObject) => {
- return dateString.day(dateObject.getDay())+", "+(dateObject.getDate())+". "+dateString.month(dateObject.getMonth())+" "+dateObject.getFullYear();
+ return `${dateString.day(dateObject.getDay())}, ${(dateObject.getDate())}. ${dateString.month(dateObject.getMonth())} ${dateObject.getFullYear()}`;
}
};
async function refreshLangDOM() {
@@ -143,7 +143,7 @@ var langstrings = {
and: "and",
thePrivacyPolicy: "the privacy policy",
loginFailed: "login failed",
- browserNotSupported: "bežiapp won't work on your device, unless you update your Internet browser",
+ browserNotSupported: "bežiapp won't work on your device, unless you update your Internet browser",
// index
timetable: "timetable",
gradings: "gradings",
@@ -158,7 +158,11 @@ var langstrings = {
// timetable
noPeriods: "no periods in selected week",
// gradings
+ date: "date",
+ description: "description",
+ add: "add",
requestFailed: "request failed",
+ addGrading: "add grading",
noInternetConnection: "no internet connection",
// grades
temporary: "temporary",
@@ -168,6 +172,7 @@ var langstrings = {
type: "type",
term: "term",
teacher: "teacher",
+ zakljucneGradess: "grades in red are final grades that appear on your end-of-year certificate and are decided by your teacher. They are not averages like grades in black. Should you have any questions or complaints about them, contact your teacher",
// teachers
name: "name",
schoolSubject: "subject",
@@ -186,6 +191,7 @@ var langstrings = {
// messaging
loadingMessages: "Loading messages...",
sendAMessage: "send a message",
+ send: "send",
recipient: "recipient",
messageSubject: "subject",
messageBody: "message body",
@@ -226,7 +232,7 @@ var langstrings = {
recipientNotInDirectory: "recipient is not in directory.",
chatExternalInfo: "you have just received a chat. Chats are not supported by GimSIS, so you must reply by changing the subject to something else. Chat body: ",
// meals
- loginError: "login error",
+ loginError: "login error",
loginToLopolis: "login to Lopolis",
loginToLopolisNote: "it seems like you're not currently logged in to eRestavracija, so this form has been presented to you. You have a different username and password combination used for applying and opting out of of menus. In order to use this feature, you have to log in with your Lopolis account.",
logInToLopolis: "log in to Lopolis",
@@ -359,7 +365,11 @@ var langstrings = {
logout: "odjava",
settings: "nastavitve",
// gradings
+ date: "datum",
+ description: "opis",
+ add: "dodaj",
requestFailed: "zahteva spodletela",
+ addGrading: "dodaj ocenjevanje",
noInternetConnection: "ni povezave s spletom",
// grades
temporary: "začasno",
@@ -369,6 +379,7 @@ var langstrings = {
type: "tip",
term: "rok",
teacher: "profesor",
+ zakljucneGradess: "zaključne ocene, ki bodo na spričevalu, so označene z rdečo, povprečja ocen pa so v črni barvi. V kolikor imate kakršnekoli pritožbe ali vprašanja glede zaključnih ocen, povprašajte profesorja",
// teachers
name: "ime",
schoolSubject: "predmet",
@@ -376,7 +387,7 @@ var langstrings = {
// absences
from: "od",
to: "do",
- cancel: "preklic",
+ cancel: "prekliči",
ok: "v redu",
noAbsences: "ni izostankov v izbranem časovnem obdobju",
lesson: "ura",
@@ -387,6 +398,7 @@ var langstrings = {
// messaging
loadingMessages: "Nalagam sporočila...",
sendAMessage: "pošlji sporočilo",
+ send: "pošlji",
recipient: "prejemnik",
messageSubject: "zadeva",
messageBody: "telo",
@@ -499,7 +511,7 @@ var langstrings = {
on: "vklopljeno",
off: "izklopljeno",
selectErrorReporting: "ali naj so napake v aplikaciji posredovane razvijalcem?",
- triggerWarning: "spodnji gumb omogoči dodatne možnosti, ki lahko razburijo/vznevoljijo nekatere uporabnike. Če omogočite stikalo se strinjate, da avtorjev in/ali njihovih osebnih prepričanj ne boste povezovali s katerokoli od dodatnih omogočenih možnosti.",
+ triggerWarning: "spodnji gumb omogoči dodatne možnosti, ki lahko razburijo/vznevoljijo nekatere uporabnike. Če omogočite stikalo, se strinjate, da avtorjev in/ali njihovih osebnih prepričanj ne boste povezovali s katerokoli od dodatnih omogočenih možnosti",
triggerAgreement: "strinjam se z zgoraj navedenimi pogoji",
triggerWarningSet: "spremenili ste stanje dodatnih nastavitev",
additionalOptions: "dodatne nastavitve",
diff --git a/assets/js/login.js b/assets/js/login.js
index ab59058..fc6dfcd 100644
--- a/assets/js/login.js
+++ b/assets/js/login.js
@@ -33,7 +33,7 @@ function login() {
dataType: "script",
});
try {
- gsecInstance = new gsec();
+ gsecInstance = new gsec();
} catch (error) {
alert(D("browserNotSupported"));
}
@@ -45,6 +45,7 @@ function login() {
localforage.setItem("username", username),
localforage.setItem("password", password)
];
+ read_val(0);
Promise.all(promises_to_run).then(function () {
window.location.replace("/pages/timetable.html");
});
diff --git a/assets/js/messaging.js b/assets/js/messaging.js
index 890da18..0f55e1a 100644
--- a/assets/js/messaging.js
+++ b/assets/js/messaging.js
@@ -587,7 +587,7 @@ function setupEventListeners() {
function getUrlParameter(sParam) {
const url_params = new URLSearchParams(window.location.search);
const found_param = url_params.get(sParam);
- return found_param
+ return found_param;
}
var additionalstufftoaddtomessage = "";
diff --git a/assets/js/setup-storage.js b/assets/js/setup-storage.js
index 0d2552a..c862d5f 100644
--- a/assets/js/setup-storage.js
+++ b/assets/js/setup-storage.js
@@ -15,7 +15,7 @@ async function setupStorage(force = false) {
localforage.setItem("gradings", []),
localforage.setItem("grades", []),
localforage.setItem("absences", {}),
- localforage.setItem("messages", { "0": [], "1": [], "2": []}), // see messages.js:129, commit 8eb9ca9caca30fbbe023243657535ab4088be377
+ localforage.setItem("messages", [[], [], []]), // see messages.js:129, commit 8eb9ca9caca30fbbe023243657535ab4088be377
localforage.setItem("directory", {}), //\\ well I could remember my own code but I didn't.
localforage.setItem("meals", {}),
localforage.setItem("chosenLang", "en"),
diff --git a/assets/pages-src/grades.bvr b/assets/pages-src/grades.bvr
index f47d462..5d05c3e 100644
--- a/assets/pages-src/grades.bvr
+++ b/assets/pages-src/grades.bvr
@@ -91,7 +91,8 @@
</span>
</label>
</p>
- <ul class="collapsible" id="grades-collapsible"></ul>
+ <ul class="collapsible" id="grades-collapsible"></ul>
+ <p><x-du>zakljucneGradess</x-du></p>
</div>
</body>
diff --git a/assets/pages-src/gradings.bvr b/assets/pages-src/gradings.bvr
index 672b8a2..20a2d39 100644
--- a/assets/pages-src/gradings.bvr
+++ b/assets/pages-src/gradings.bvr
@@ -75,37 +75,15 @@
<br>
<div id="calendar"></div>
</div>
-<!--
- <div class="container">
- <div class="row">
- <div class="col s12">
- <h4>Add a personal event</h4>
- <div class="row">
- <div class="input-field col s5">
- <input required="required" type="text" class="datepicker" id="datepicker-add">
- <label for="datepicker-add">Date</label>
- </div>
- <div class="input-field col s5">
- <input required="required" id="event_name" type="text" class="validate">
- <label for="event_name">Name</label>
- </div>
- <div class="input-field col s2">
- <button id="event_btn" class="btn waves-effect waves-light" type="text" class="validate">
- <i class="material-icons">event_available</i>
- </button>
- </div>
- </div>
- <div class="row">
- <div class="input-field col s12">
- <textarea required="required" id="event_description" class="materialize-textarea"></textarea>
- <label for="event_description">Description</label>
- </div>
- </div>
- </div>
- </div>
- </div>
--->
+ <!-- FAB -->
+ <!-- <div class="fixed-action-btn" id="fab-new">
+ <a class="btn-floating btn-large fab-new-message modal-trigger" href="#beziapp-add-grading">
+ <i class="large material-icons">add</i>
+ </a>
+ </div> -->
+ <@?i grading-add-modal@>
+
</body>
</html>
diff --git a/assets/pages-src/misc/grading-add-modal.bvr b/assets/pages-src/misc/grading-add-modal.bvr
new file mode 100644
index 0000000..0b7189d
--- /dev/null
+++ b/assets/pages-src/misc/grading-add-modal.bvr
@@ -0,0 +1,35 @@
+ <!-- Modal Structure -->
+ <div id="beziapp-add-grading" class="modal modal-fixed-footer">
+
+ <div class="modal-content">
+
+ <h4 class="general-text"><x-su>addGrading</x-su></h4>
+
+ <div class="row">
+ <div class="input-field col s6">
+ <input required="required" type="text" class="datepicker" id="datepicker-add">
+ <label for="datepicker-add"><x-su>date</x-su></label>
+ </div>
+ <div class="input-field col s6">
+ <input required="required" id="input-grading-name" type="text" class="validate">
+ <label for="event_name"><x-su>name</x-su></label>
+ </div>
+ </div>
+
+ <div class="row">
+ <div class="input-field col s12">
+ <textarea required="required" id="input-grading-description" class="materialize-textarea"></textarea>
+ <label for="event_description"><x-su>description</x-su></label>
+ </div>
+ </div>
+
+ </div>
+
+ <div class="modal-footer">
+ <div id="modal-footer-right">
+ <a href="#" class="modal-close waves-effect waves-green btn-flat"><x-su>cancel</x-su> <i class="material-icons right">close</i></a>
+ <a href="#" id="btn-add-grading" class="modal-close waves-effect waves-green btn-flat" disabled><x-su>add</x-su> <i class="material-icons right">add</i></a>
+ </div>
+ </div>
+ </div>
+
diff --git a/assets/pages-src/misc/msg-compose-modal.bvr b/assets/pages-src/misc/msg-compose-modal.bvr
index 5889214..48afaaf 100644
--- a/assets/pages-src/misc/msg-compose-modal.bvr
+++ b/assets/pages-src/misc/msg-compose-modal.bvr
@@ -57,8 +57,8 @@
<div class="modal-footer">
<div id="modal-footer-right">
- <a href="#" class="modal-close waves-effect waves-green btn-flat">Cancel <i class="material-icons right">close</i></a>
- <a href="#" id="msg-send" class="modal-close waves-effect waves-green btn-flat" disabled>Send <i class="material-icons right">send</i></a>
+ <a href="#" class="modal-close waves-effect waves-green btn-flat"><x-su>cancel</x-su> <i class="material-icons right">close</i></a>
+ <a href="#" id="msg-send" class="modal-close waves-effect waves-green btn-flat" disabled><x-su>send</x-su> <i class="material-icons right">send</i></a>
</div>
</div>
</div>
diff --git a/bin/compose-html b/bin/compose-html
index 4889f0c..2b50168 100755
--- a/bin/compose-html
+++ b/bin/compose-html
Binary files differ
diff --git a/bin/compose-single b/bin/compose-single
index 108e083..d9fe49e 100755
--- a/bin/compose-single
+++ b/bin/compose-single
Binary files differ
diff --git a/bin/jsbundle b/bin/jsbundle
index d1bc0dc..c1bce8c 100755
--- a/bin/jsbundle
+++ b/bin/jsbundle
Binary files differ
diff --git a/bin/jsmin b/bin/jsmin
index 34d72a2..fe78f98 100755
--- a/bin/jsmin
+++ b/bin/jsmin
Binary files differ
diff --git a/dist/css/styles.css b/dist/css/styles.css
index 4e6050b..3f403e7 100755
--- a/dist/css/styles.css
+++ b/dist/css/styles.css
@@ -417,3 +417,11 @@ p {
h1, h2, h3, h4, h5, h6 {
color: var(--color-text) !important;
}
+
+.card {
+ background-color: var(--background-accent) !important;
+}
+
+.zakljucna-grade {
+ color: red;
+} \ No newline at end of file
diff --git a/dist/js/app.js b/dist/js/app.js
index 053135a..d44995d 100755
--- a/dist/js/app.js
+++ b/dist/js/app.js
@@ -2,8 +2,8 @@
-const app_version = "1.0.14-beta";
-const previous_commit = "20505fc48713c600c345814d4a9c2e0747c77152";
+const app_version = "1.0.14.1-beta";
+const previous_commit = "ab895dc64437ac9ea42b2c9790a0b29550bdbc17";
if ("serviceWorker" in navigator) {
navigator.serviceWorker.register("/sw.js")
diff --git a/dist/js/grades.js b/dist/js/grades.js
index dceb911..5f9f9be 100644
--- a/dist/js/grades.js
+++ b/dist/js/grades.js
@@ -2,12 +2,13 @@
let checkbox_state=false;var grades;async function checkLogin(){localforage.getItem("logged_in").then((value)=>{if(value!==true){window.location.replace("/index.html");}}).catch((err)=>{console.log(err);});}
function setLoading(state){if(state){$("#loading-bar").removeClass("hidden");}else{$("#loading-bar").addClass("hidden");}}
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(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(()=>{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["subject"]in grades_by_subject)){grades_by_subject[grade["subject"]]=[];}
+function displayGrades(){let grades_by_subject={};let zakljucne_grades_by_subject={};grades.forEach((grade,index)=>{if(grade["gradeType"]!=GSEC_NORMAL_GRADE){zakljucne_grades_by_subject[grade["subject"]]=grade["grade"];}else{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)=>{let subject_entry=document.createElement("li");let subject_header=document.createElement("div");subject_header.classList.add("collapsible-header");subject_header.classList.add("collapsible-header-root");let subject_header_text=document.createElement("span");subject_header_text.innerText=subject;let subject_body=document.createElement("div");subject_body.className="collapsible-body";let subject_body_root=document.createElement("ul");subject_body_root.className="collection";let grade_sum=0;let grade_tot=0;grades_by_subject[subject].forEach((grade)=>{let grade_node=document.createElement("li");grade_node.className="collection-item";grade_node.classList.add("collection-item")
+grades_by_subject[grade["subject"]].push(grade_object);}});let root_element=document.getElementById("grades-collapsible");Object.keys(grades_by_subject).forEach((subject)=>{let subject_entry=document.createElement("li");let subject_header=document.createElement("div");subject_header.classList.add("collapsible-header");subject_header.classList.add("collapsible-header-root");let subject_header_text=document.createElement("span");subject_header_text.innerText=subject;let subject_body=document.createElement("div");subject_body.className="collapsible-body";let subject_body_root=document.createElement("ul");subject_body_root.className="collection";let grade_sum=0;let grade_tot=0;grades_by_subject[subject].forEach((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");let grade_text=document.createElement("span");let grade_number=document.createElement("div");grade_number.className="secondary-content";if(grade["temporary"]){let grade_text_italic=document.createElement("i");grade_text_italic.innerText=grade["date"]+" - "+grade["title"];grade_text.appendChild(grade_text_italic);let grade_number_italic=document.createElement("i");grade_number_italic.innerText=grade["grade"].toString();grade_number.appendChild(grade_number_italic);}else{grade_text.innerText=grade["date"]+" - "+grade["title"];grade_number.innerText=grade["grade"].toString();}
grade_node_div.appendChild(grade_text);grade_node_div.appendChild(grade_number);grade_node.appendChild(grade_node_div);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();}
+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";if(subject in zakljucne_grades_by_subject){subject_header_average.innerText=zakljucne_grades_by_subject[subject];subject_header_average.classList.add("zakljucna-grade");}else{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(){const table=document.getElementById("grades-collapsible");while(table.firstChild){table.removeChild(table.firstChild);}}
function refreshGrades(force){clearGrades();loadGrades(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["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";}
diff --git a/dist/js/gradings.js b/dist/js/gradings.js
index b9b3d5c..713ea20 100644
--- a/dist/js/gradings.js
+++ b/dist/js/gradings.js
@@ -10,6 +10,7 @@ function getDateString(){let date=new Date();let year_str=date.getFullYear();let
month_str=month_str.toString().padStart(2,"0");let day_str=date.getDate();day_str=day_str.toString().padStart(2,"0");let date_string=year_str+"-"+month_str+"-"+day_str;return date_string;}
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;})];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(()=>{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["acronym"]);let fg_color=getForegroundFromBackground(bg_color);let grading_object={start:element["date"].toISOString().substring(0,10),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);}
+async function validateInputs(){if($("#input-grading-name").val()!=null&&$("#input-grading-name").val().length>0){$("#btn-add-grading").removeAttr("disabled");$("#input-grading-name").addClass("valid");$("#input-grading-name").removeClass("invalid");}else{$("#btn-add-grading").attr("disabled","disabled");$("#input-grading-name").addClass("invalid");$("#input-grading-name").removeClass("valid");}}
function gradingClickHandler(eventClickInfo){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"];$("#grading-subject").text(grading_subject);$("#grading-date").text(grading_date);$("#grading-description").text(grading_description);const modal=document.querySelectorAll(".side-modal")[0];M.Sidenav.getInstance(modal).open();}
function setupPickers(){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}
instances=M.Datepicker.init(elems,options);}
diff --git a/dist/js/gsec.js b/dist/js/gsec.js
index 7925d00..36d49a5 100644
--- a/dist/js/gsec.js
+++ b/dist/js/gsec.js
@@ -4,7 +4,7 @@ function stripHtml(html){var tmp=document.createElement("DIV");tmp.innerHTML=htm
function slDayToInt(inputString){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"
const GSEC_ERR_NET_POSTBACK_POST="GSEC NETWORK ERROR (ajax error) in postback POST"
-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{constructor(){}
+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"];const GSEC_NORMAL_GRADE="GSEC NORMAL GRADE";const GSEC_ZAKLJUCNA_GRADE="GSEC ZAKLJUCNA GRADE";class gsec{constructor(){}
parseAndPost(inputHTML,params,formId=null,useDiffAction=null){return new Promise((resolve,reject)=>{let parser=new DOMParser();let parsed=parser.parseFromString(inputHTML,"text/html");var form;if(formId==null){form=parsed.getElementsByTagName("form")[0];}else{form=parsed.getElementById(formId);}
var otherParams=$(form).serializeArray();for(const input of otherParams){if(!(input.name in params)){params[input.name]=input.value;}}
var action;if(useDiffAction==null||useDiffAction==false){action=new URL($(form).attr("action"),GSE_URL);}else{action=useDiffAction;}
@@ -32,12 +32,13 @@ var dataToBeSent={"ctl00$ContentPlaceHolder1$edtDatZacetka":`${fromDate.getDay()
var absences=[];for(const izostanek of rowElements){var subFields=izostanek.getElementsByTagName("td");var date=subFields[0].innerHTML.trim().split(".");var dateObj=new Date(Date.parse(`${date[2]}-${date[1]}-${date[0]}`));var subjects=[];subFields[2].innerHTML.match(SUBJECT_LIST_REGEX).forEach((subject)=>{subjects.push(subject);});var absencesBySubject={};for(const subject of subjects){const matched_info=FIELDS_REGEX.exec(subject);var subjectName=matched_info[1];var status=Number(matched_info[2]);var period=matched_info[3];period=period.includes("P")?Number(period.replace("P",""))+7:Number(period);absencesBySubject[period]={status:status,subject:subjectName};}
absences.push({subjects:absencesBySubject,date:dateObj});}
resolve(absences);});});}
-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)=>{let parser=new DOMParser();let parsed=parser.parseFromString(data,"text/html");let gradeSpans=parsed.getElementsByClassName("txtVOcObd");for(const grade of gradeSpans){var ist=grade.getElementsByTagName("span")[0].getAttribute("title").split("\n");var date=ist[0].split(": ")[1].trim().split(".");var dateObj=new Date(Date.parse(`${date[2]}-${date[1]}-${date[0]}`));var teacher=ist[1].split(": ")[1].trim();var subject=ist[2].split(": ")[1].trim();var name=[];name.push(ist[3].split(": ")[1].trim())
+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)=>{let parser=new DOMParser();let parsed=parser.parseFromString(data,"text/html");let gradeSpans=parsed.getElementsByClassName("txtVOcObd");for(const grade of gradeSpans){var ist=grade.getElementsByTagName("span")[0].getAttribute("title").split("\n");if(ist.length==1){var gradeToAdd={"gradeType":GSEC_ZAKLJUCNA_GRADE,"grade":Number(grade.getElementsByTagName("span")[0].innerHTML),"subject":grade.parentElement.parentElement.parentElement.parentElement.getElementsByTagName("th")[0].innerText}
+grades.push(gradeToAdd);}else{var date=ist[0].split(": ")[1].trim().split(".");var dateObj=new Date(Date.parse(`${date[2]}-${date[1]}-${date[0]}`));var teacher=ist[1].split(": ")[1].trim();var subject=ist[2].split(": ")[1].trim();var name=[];name.push(ist[3].split(": ")[1].trim())
name.push(ist[4].split(": ")[1].trim())
name.push(ist[5].split(": ")[1].trim())
-var gradeNumber=Number(grade.getElementsByTagName("span")[0].innerHTML);var temporary=grade.getElementsByTagName("span")[0].classList.contains("ocVmesna");var gradeToAdd={"date":dateObj,"teacher":teacher,"subject":subject,"name":name,"temporary":temporary,"grade":gradeNumber};if(grade.getElementsByTagName("span").length>1){if(grade.getElementsByTagName("span")[1].classList.contains("ocVmesna")){gradeToAdd["temporary"]=true;}else{gradeToAdd["temporary"]=false;}
+var gradeNumber=Number(grade.getElementsByTagName("span")[0].innerHTML);var temporary=grade.getElementsByTagName("span")[0].classList.contains("ocVmesna");var gradeToAdd={"gradeType":GSEC_NORMAL_GRADE,"date":dateObj,"teacher":teacher,"subject":subject,"name":name,"temporary":temporary,"grade":gradeNumber};if(grade.getElementsByTagName("span").length>1){if(grade.getElementsByTagName("span")[1].classList.contains("ocVmesna")){gradeToAdd["temporary"]=true;}else{gradeToAdd["temporary"]=false;}
gradeToAdd["grade"]=Number(grade.getElementsByTagName("span")[1].innerHTML);gradeToAdd["oldgrade"]=Number(grade.getElementsByTagName("span")[0].innerHTML);}
-grades.push(gradeToAdd);}
+grades.push(gradeToAdd);}}
resolve(grades);},error:()=>{reject(new Error(GSEC_ERR_NET));}});});}
fetchMessageOld(selectId){const TIME_REGEX=/ \(.+ (.+?)\)/;const DATE_REGEX=/ \(.+? /;const SENDER_REGEX=/^(.+?) \(/;var message;return new Promise((resolve)=>{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");let subject=parsed.getElementsByClassName("msgSubjectS")[0].innerHTML.trim();let body=parsed.getElementsByClassName("gCursorAuto")[0].innerHTML.trim();let sender=SENDER_REGEX.exec(parsed.querySelectorAll("[id$=Label7]")[0].innerHTML)[1];let recipient=parsed.querySelectorAll("[id$=Label8]")[0].innerHTML;var date=DATE_REGEX.exec(parsed.querySelectorAll("[id$=Label7]")[0].innerHTML)[1];var tume=TIME_REGEX.exec(parsed.querySelectorAll("[id$=Label7]")[0].innerHTML)[1];var dateObj=new Date(Date.parse(`${date[2]}-${date[1]}-${date[0]} ${tume}`));var msgId=parsed.getElementById("ctl00_ContentPlaceHolder1_hfIdSporocilo").getAttribute("value");message={"subject":subject,"body":body,"sender":sender,"recipient":recipient,"date":dateObj,"msgId":msgId};resolve(message);});});}
fetchMessagesLastPageNumber(category=GSEC_MSGTYPE_RECEIVED){var msgCategory=GSEC_MSGTYPES[category];return new Promise((resolve)=>{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");let currentPage;if(parsed.getElementsByClassName("pager").length==0){currentPage=1;}else{currentPage=Number(parsed.getElementsByClassName("pager")[0].getElementsByTagName("span")[0].innerHTML);}
diff --git a/dist/js/lang/bundle.js b/dist/js/lang/bundle.js
index c375a9b..adb8d97 100644
--- a/dist/js/lang/bundle.js
+++ b/dist/js/lang/bundle.js
@@ -1,5 +1,5 @@
-var chosenLang;var dateString={day:(danv)=>{let dnevitedna=[S("sunday"),S("monday"),S("tuesday"),S("wednesday"),S("thursday"),S("friday"),S("saturday")];return dnevitedna[danv];},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(){let promises_to_runn=[localforage.getItem("chosenLang").then((value)=>{chosenLang=value;})];await Promise.all(promises_to_runn);let stringContainerss=document.querySelectorAll("x-sl:not(.langFinished)");for(i=0;i<stringContainerss.length;i++){stringContainerss[i].innerHTML=s(stringContainerss[i].innerHTML);stringContainerss[i].classList.add("langFinished");stringContainerss[i].hidden=false;}
+var chosenLang;var dateString={day:(danv)=>{let dnevitedna=[S("sunday"),S("monday"),S("tuesday"),S("wednesday"),S("thursday"),S("friday"),S("saturday")];return dnevitedna[danv];},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(){let promises_to_runn=[localforage.getItem("chosenLang").then((value)=>{chosenLang=value;})];await Promise.all(promises_to_runn);let stringContainerss=document.querySelectorAll("x-sl:not(.langFinished)");for(i=0;i<stringContainerss.length;i++){stringContainerss[i].innerHTML=s(stringContainerss[i].innerHTML);stringContainerss[i].classList.add("langFinished");stringContainerss[i].hidden=false;}
let stringContainersd=document.querySelectorAll("x-dl:not(.langFinished)");for(i=0;i<stringContainersd.length;i++){stringContainersd[i].innerHTML=d(stringContainersd[i].innerHTML);stringContainersd[i].classList.add("langFinished");stringContainersd[i].hidden=false;}
let stringContainersS=document.querySelectorAll("x-su:not(.langFinished)");for(i=0;i<stringContainersS.length;i++){stringContainersS[i].innerHTML=S(stringContainersS[i].innerHTML);stringContainersS[i].classList.add("langFinished");stringContainersS[i].hidden=false;}
let stringContainersD=document.querySelectorAll("x-du:not(.langFinished)");for(i=0;i<stringContainersD.length;i++){stringContainersD[i].innerHTML=D(stringContainersD[i].innerHTML);stringContainersD[i].classList.add("langFinished");stringContainersD[i].hidden=false;}}
@@ -7,4 +7,4 @@ async function setLangConfigAndReload(){let promises_to_run=[localforage.setItem
window.addEventListener("DOMContentLoaded",()=>{localforage.getItem("chosenLang").then((value)=>{if(value==null){setLangConfigAndReload();}else{chosenLang=value;}});refreshLangDOM();});const capitalize=(s)=>{if(typeof s!=='string')return''
return s.charAt(0).toUpperCase()+s.slice(1)}
var s=function(whatString){return getLang.s(whatString);};var d=function(whatString){return getLang.d(whatString);};var S=function(whatString){return getLang.S(whatString);};var D=function(whatString){return getLang.D(whatString);};var getLang={s:function(whatString){return langstrings[chosenLang][whatString];},S:function(whatString){return capitalize(langstrings[chosenLang][whatString]);},d:function(whatString){if(langstrings[chosenLang][whatString].slice(-1)!="."){return langstrings[chosenLang][whatString]+".";}else{return langstrings[chosenLang][whatString];}},D:function(whatString){if(langstrings[chosenLang][whatString].slice(-1)!="."){return capitalize(langstrings[chosenLang][whatString]+".");}else{return capitalize(langstrings[chosenLang][whatString]);}},}
-var langstrings={en:{miscTranslationLanguage:"English",miscTranslationAuthors:"Rok Štular","":"",monday:"monday",tuesday:"tuesday",wednesday:"wednesday",thursday:"thursday",friday:"friday",saturday:"saturday",sunday:"sunday",am:"am",pm:"pm",january:"january",february:"february",march:"march",april:"april",may:"may",june:"june",july:"july",august:"august",september:"september",october:"october",november:"november",december:"december",username:"username",password:"password",signIn:"sign in",bySigningInYouAgreeTo:"by signing in, you agree to",theToS:"the terms and conditions",and:"and",thePrivacyPolicy:"the privacy policy",loginFailed:"login failed",browserNotSupported:"bežiapp won't work on your device, unless you update your Internet browser",timetable:"timetable",gradings:"gradings",grades:"grades",teachers:"teachers",absences:"absences",messaging:"messaging",meals:"meals",about:"about",logout:"logout",settings:"settings",noPeriods:"no periods in selected week",requestFailed:"request failed",noInternetConnection:"no internet connection",temporary:"temporary",useOnlyPermanentGrades:"use only permanent grades",useOnlyPermanentGradesNote1:"if checked, only permanent grades will be used in the average grade calculation",useOnlyPermanentGradesNote2:"if left unchecked, the calculation will include every available grade",type:"type",term:"term",teacher:"teacher",name:"name",schoolSubject:"subject",tpMeetings:"TP meetings",from:"from",to:"to",cancel:"cancel",ok:"ok",noAbsences:"no absences in the chosen time period",lesson:"lesson",notProcessed:"not processed",authorizedAbsence:"authorized",unauthorizedAbsence:"unauthorized",doesNotCount:"does not count",loadingMessages:"Loading messages...",sendAMessage:"send a message",recipient:"recipient",messageSubject:"subject",messageBody:"message body",removeImages:"remove images",note:"note",largeImagesNote:"GimB servers don't like large messages, so only very small images may be attached or your message will not be delivered",attachedImages:"attached images",encryptMessage:"Encrypt message",passwordForE2EE:"password for encrypting the message",messages:"messages",received:"received",sent:"sent",deleted:"deleted",messageStorageUsed:"message storage used in this folder",maxMessagesNote:"you can only have 120 messages per message folder, older messages will not be shown. Remember to delete read and sent messages regulary to avoid any issues.",loadMessageBody:"load message body",thisMessageWasEncrypted:"this message was encrypted",enterPassword:"enter password",decrypt:"decrypt",nameDirectoryNotSet:"name directory not set, sending unavailable",errorFetchingMessages:"error fetching messages",unableToReceiveTheMessage:"unable to receive the message",unableToDeleteTheMessage:"unable to delete the message",messageWasProbablySent:"message was probably sent, check the Sent folder to be sure",errorSendingMessage:"error sending message",imageAddedAsAnAttachment:"image added as an attachment",unableToReadDirectory:"unable to read directory of people",messageCouldNotBeSent:"message could to be sent",incorrectPassword:"incorrect password",chat:"chat",chattingWith:"chatting with",noMessages:"no messages",stillLoading:"loading is still in progress",directory:"directory",select:"select",mustSelectRecipient:"you have to select a recipient before chatting. Open directory on the left side by clicking on the top left addressbook button and select a recipient in order to start chatting with them",recipientNotInDirectory:"recipient is not in directory.",chatExternalInfo:"you have just received a chat. Chats are not supported by GimSIS, so you must reply by changing the subject to something else. Chat body: ",loginError:"login error",loginToLopolis:"login to Lopolis",loginToLopolisNote:"it seems like you're not currently logged in to eRestavracija, so this form has been presented to you. You have a different username and password combination used for applying and opting out of of menus. In order to use this feature, you have to log in with your Lopolis account.",logInToLopolis:"log in to Lopolis",logOutFromLopolis:"log out from Lopolis",readOnly:"read only",usage:"usage",mealsUsageNote:"click on a date to open the collapsible menu with choices and click on a specific meal to select it. Reload the meals when you're done and check the entries.",lunchesNote:"app was not tested with lunches in mind. Meals probably won't work with lunches and having a lunch subscription may even break its functionality.",mealNotShownNote:"if a meal is not present in the meals collapsible field, this does not necessarily mean it does not exist. Meals that haven't been altered by you and are unchangable (read-only) are not shown for clarity.",mealsContributeNote:"you are welcome to contribute to the LopolisAPI project and add features, such as checkouts.",authenticationError:"authentication error",lopolisAPIConnectionError:"LopolisAPI server connection error",errorGettingMenus:"error getting menus",errorUnexpectedResponse:"error: unexpected response",requestForAuthenticationFailed:"request for authentication failed",credentialsMatch:"credentials match",errorSettingMeals:"error setting meals",mealSet:"meal set! Reload meals to be sure",selected:"selected",version:"version",authors:"authors",translatorsForThisLanguage:"translators for this language",whatIsNew:"what's new",whatsNew:"what's new",reportABug:"report a bug",sendASuggestion:"send a suggestion",instagram:"instagram",changelog:"changelog",termsOfUse:"terms of use",termsOfUseDescription:"as a condition of use, you promise not to use the BežiApp (App or application) and its related infrastructure (API, hosting service) for any purpose that is unlawful or prohibited by these Terms, or any other purpose not reasonably intended by the authors of the App. By way of example, and not as a limitation, you agree not to use the App",termsOfUseHarass:"to abuse, harass, threaten, impersonate or intimidate any person",termsOfUsePost:"to post or transmit, or cause to be posted or transmitted, any Content that is libelous, defamatory, obscene, pornographic, abusive, offensive, profane or that infringes any copyright or other right of any person",termsOfUseCommunicate:"to communicate with the App developers or other users in abusive or offensive manner",termsOfUsePurpose:"for any purpose that is not permitted under the laws of the jurisdiction where you use the App",termsOfUseExploit:"to post or transmit, or cause to be posted or transmitted, any Communication designed or intended to obtain password, account or private information of any App user",termsOfUseSpam:"to create or transmit unwanted “spam” to any person or any URL",termsOfUseModify:"you may also not reverse engineer, modify or redistribute the app without written consent from the developers",terminationOfServices:"termination of services",terminationOfServicesDescriptions:"the developers of the App may terminate your access to the App without any prior warning or notice for any of the following reasons",terminationOfServicesBreaching:"breaching the Terms of Service",terminationOfServicesRequest:"receiving a formal request from authorities of Gimnazija Bežigrad administration requesting termination of your access to the App",limitationOfLiability:"limitation of Liability",limitationOfLiabilityContent:"the developers of the App provide no warranty; You expressly acknowledge and agree that the use of the licensed application is at your sole risk. To the maximum extent permited by applicable law, the licensed application and any services performed of provided by the licensed application are provided “as is” and “as available”, with all faults and without warranty of any kind, and licensor hereby disclaims all warranties and conditions with respect to the licensed application and any services, either express, implied or statutory, including, but not limited to, the implied warranties and/or conditions of merchantability, of satisfactory quality, of fitness for a particular purpose, of accuracy, of quiet enjoyment, and of noninfringement of third-party rights. No oral or written information or advice given by licensor or its authorized representative shall create a warranty. Should the licensed application or services prove defective, you assume the entire cost of all necessary servicing, repair or correction. Some jurisdictions do not allow the exclusion of the implied warranties or limitations on applicable statutory rights of a customer, so the above exclusion may not apply to you.",tosAreEffectiveAsOf:"the Terms of Service are effective as of",privacyImportant:"your privacy is important to us. It is the developers' policy to respect your privacy regarding any information we may collect from you through our app, BežiApp.",privacyOnlyAskedWhen:"we only ask for personal information when we truly need it to provide a service to you. We collect it by fair and lawful means, with your knowledge and consent. We also let you know why we’re collecting it and how it will be used.",privacyDataCollection:"we only retain collected information for as long as necessary to provide you with your requested service. What data we store, we’ll protect within commercially acceptable means to prevent loss and theft, as well as unauthorized access, disclosure, copying, use or modification.",privacySharingData:"we don’t share any personally identifying information publicly or with third-parties, except when required to by law",privacyExternalSites:"our app may link to external sites that are not operated by us. Please be aware that we have no control over the content and practices of these sites, and cannot accept responsibility or liability for their respective privacy policies.",privacyRefuse:"you are free to refuse our request for your personal information, with the understanding that we may be unable to provide you with some of your desired services.",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:"language",selectLanguage:"select desired language",languageSet:"language set, open another page for the changes to take effect",theme:"theme",themeLight:"light theme (default)",themeDark:"dark theme",themeNight:"night theme",selectTheme:"select a theme",triggerWarning:"the following switch enables additional settings, which some people may: disagree with, find annoying, be offended by them. By enabling the switch, you agree that you won't be triggered by any of the additional options and will not asociate any of the authors and/or their personal beliefs and opinions with additional options.",triggerAgreement:"i agree with terms and conditions stated above",triggerWarningSet:"additional settings toggled",additionalOptions:"additional settings",themeSet:"theme set, open another page for the changes to take effect",errorReportingSet:"error reporting preference set",errorReporting:"error reporting",on:"on",off:"off",selectErrorReporting:"should error reports be submitted to the developers?",gsecErrNet:"GimSIS connection error",gsecErrLogin:"GimSIS login error (bad password?), try logging out",gsecErrOther:"GimSIS unknown error, try logging out",videoconferences:"GimB meet"},sl:{miscTranslationLanguage:"slovenščina",miscTranslationAuthors:"Anton Luka Šijanec","":"",monday:"ponedeljek",tuesday:"torek",wednesday:"sreda",thursday:"četrtek",friday:"petek",saturday:"sobota",sunday:"nedelja",am:"dop.",pm:"pop.",january:"januar",february:"februar",march:"marec",april:"april",may:"maj",june:"junij",july:"julij",august:"avgust",september:"september",october:"oktober",november:"november",december:"december",username:"uporabniško ime",password:"geslo",signIn:"prijava",bySigningInYouAgreeTo:"s prijavo se strinjate s",theToS:"pogoji uporabe (v angleščini)",and:"in",thePrivacyPolicy:"politika zasebnosti (v angleščini)",loginFailed:"prijava je spodletela",browserNotSupported:"BežiApp ne bo deloval na vaši napravi, če ne posodobite vašega Internetnega brskalnika",noPeriods:"ni ur v izbranem tednu",timetable:"urnik",gradings:"ocenjevanja",grades:"ocene",teachers:"profesorji",absences:"izostanki",messaging:"sporočanje",meals:"obroki",about:"o",logout:"odjava",settings:"nastavitve",requestFailed:"zahteva spodletela",noInternetConnection:"ni povezave s spletom",temporary:"začasno",useOnlyPermanentGrades:"uporabi le stalne ocene",useOnlyPermanentGradesNote1:"če je označeno, bodo za izračun povprečja uporabljene le stalne ocene",useOnlyPermanentGradesNote2:"če pa je polje neoznačeno, pa se ob izračunu povprečne ocene upoštevajo vse ocene",type:"tip",term:"rok",teacher:"profesor",name:"ime",schoolSubject:"predmet",tpMeetings:"govorilne ure",from:"od",to:"do",cancel:"preklic",ok:"v redu",noAbsences:"ni izostankov v izbranem časovnem obdobju",lesson:"ura",notProcessed:"ni obdelano",authorizedAbsence:"opravičeno",unauthorizedAbsence:"neopravičeno",doesNotCount:"ne šteje",loadingMessages:"Nalagam sporočila...",sendAMessage:"pošlji sporočilo",recipient:"prejemnik",messageSubject:"zadeva",messageBody:"telo",removeImages:"odstrani slike",note:"opomba",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",encryptMessage:"Šifriraj sporočilo",passwordForE2EE:"geslo za šifriranje sporočila",messages:"sporočila",received:"prejeta",sent:"poslana",deleted:"izbrisana",messageStorageUsed:"zasedenost shrambe sporočil v tej mapi",maxMessagesNote:"v vsaki mapi imate lahko največ 120 sporočil. Starejša sporočila ne bodo prikazana. Redno brišite sporočila, da se izognete morebitnim težavam.",loadMessageBody:"naloži telo sporočila",thisMessageWasEncrypted:"to sporočilo je šifrirano",enterPassword:"vnesite geslo",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",unableToDeleteTheMessage:"sporočila ni bilo mogoče izbrisati",messageWasProbablySent:"sporočilo je bilo verjetno poslano, prepričajte se in preverite mapo s poslanimi sporočili",errorSendingMessage:"sporočila ni bilo mogoče poslati",imageAddedAsAnAttachment:"slika dodana kot priloga",unableToReadDirectory:"imenika ni bilo mogoče prebrati",messageCouldNotBeSent:"sporočila ni bilo mogoče poslati",incorrectPassword:"nepravilno geslo",chat:"klepet",chattingWith:"klepet z osebo",noMessages:"ni sporočil",stillLoading:"nalaganje še poteka",directory:"imenik",select:"izberi",mustSelectRecipient:"pred klepetom morate izbrati sogovornika. Odprite imenik (meni na levi strani) s pritiskom na gumb \"imenik\" zgoraj desno in izberite sogovornika.",recipientNotInDirectory:"izbrane osebe ni v imeniku",chatExternalInfo:"dobili ste kratko sporočilo v standardu, ki ga GimSIS ne podpira. Pri odgovarjanju spremenite zadevo. Vsebina sporočila: ",loginError:"napaka pri prijavi",loginToLopolis:"prijava v Lopolis",loginToLopolisNote:"izgleda, da niste prijavljeni v eRestavracijo, zato se vam je prikazal prijavni obrazec. Za uporavljanje s prehrano se uporablja druga kombinacija uporabniškega imena in gesla, zato se prijavite s svojimi Lopolis prijavnimi podatki za nadaljevanje.",logInToLopolis:"prijava v Lopolis",logOutFromLopolis:"odjava iz Lopolisa",readOnly:"samo za branje",usage:"uporaba",mealsUsageNote:"kliknite na datum za prikaz menijev, nato pa si enega izberite s klikom na ime menija. Po nastavitvi menijev ponovno naložite menije in se prepričajte o pravilnih nastavitvah.",lunchesNote:"aplikacija ni testirana za naročanje na koslila, zato verjetno to ne deluje. Če ste naročeni na kosila lahko naročanje na menije sploh ne deluje ali pa deluje narobe.",mealNotShownNote:"če nek dan manjka med meniji, to verjetno pomeni, da ni več spremenljiv in zanj niste ročno spremenili menija",mealsContributeNote:"vabimo vas k urejanju LopolisAPI programa za upravljanje z meniji.",authenticationError:"napaka avtentikacije",lopolisAPIConnectionError:"napaka povezave na LopolisAPI strežnik",errorGettingMenus:"napaka branja menijev",errorUnexpectedResponse:"napaka: nepričakovan odgovor",requestForAuthenticationFailed:"zahteva za avtentikacijo ni uspela",credentialsMatch:"prijavni podatki so pravilni",errorSettingMeals:"napaka pri nastavljanju menijev",mealSet:"obrok nastavljen! osvežite obroke in se prepričajte sami",selected:"izbrano",version:"različica",authors:"avtorji",translatorsForThisLanguage:"prevajalci izbranega jezika",whatIsNew:"kaj je novega",whatsNew:"kaj je novega",reportABug:"prijavite napako",sendASuggestion:"pošljite pripombo/predlog/pohvalo/pritožbo",instagram:"instagram",changelog:"dnevnik sprememb",termsOfUse:"terms of use",termsOfUseDescription:"as a condition of use, you promise not to use the BežiApp (App or application) and its related infrastructure (API, hosting service) for any purpose that is unlawful or prohibited by these Terms, or any other purpose not reasonably intended by the authors of the App. By way of example, and not as a limitation, you agree not to use the App",termsOfUseHarass:"to abuse, harass, threaten, impersonate or intimidate any person",termsOfUsePost:"to post or transmit, or cause to be posted or transmitted, any Content that is libelous, defamatory, obscene, pornographic, abusive, offensive, profane or that infringes any copyright or other right of any person",termsOfUseCommunicate:"to communicate with the App developers or other users in abusive or offensive manner",termsOfUsePurpose:"for any purpose that is not permitted under the laws of the jurisdiction where you use the App",termsOfUseExploit:"to post or transmit, or cause to be posted or transmitted, any Communication designed or intended to obtain password, account or private information of any App user",termsOfUseSpam:"to create or transmit unwanted “spam” to any person or any URL",termsOfUseModify:"you may also not reverse engineer, modify or redistribute the app without written consent from the developers",terminationOfServices:"termination of services",terminationOfServicesDescriptions:"the developers of the App may terminate your access to the App without any prior warning or notice for any of the following reasons",terminationOfServicesBreaching:"breaching the Terms of Service",terminationOfServicesRequest:"receiving a formal request from authorities of Gimnazija Bežigrad administration requesting termination of your access to the App",limitationOfLiability:"limitation of Liability",limitationOfLiabilityContent:"the developers of the App provide no warranty; You expressly acknowledge and agree that the use of the licensed application is at your sole risk. To the maximum extent permited by applicable law, the licensed application and any services performed of provided by the licensed application are provided “as is” and “as available”, with all faults and without warranty of any kind, and licensor hereby disclaims all warranties and conditions with respect to the licensed application and any services, either express, implied or statutory, including, but not limited to, the implied warranties and/or conditions of merchantability, of satisfactory quality, of fitness for a particular purpose, of accuracy, of quiet enjoyment, and of noninfringement of third-party rights. No oral or written information or advice given by licensor or its authorized representative shall create a warranty. Should the licensed application or services prove defective, you assume the entire cost of all necessary servicing, repair or correction. Some jurisdictions do not allow the exclusion of the implied warranties or limitations on applicable statutory rights of a customer, so the above exclusion may not apply to you.",tosAreEffectiveAsOf:"the Terms of Service are effective as of",privacyImportant:"your privacy is important to us. It is the developers' policy to respect your privacy regarding any information we may collect from you through our app, BežiApp.",privacyOnlyAskedWhen:"we only ask for personal information when we truly need it to provide a service to you. We collect it by fair and lawful means, with your knowledge and consent. We also let you know why we’re collecting it and how it will be used.",privacyDataCollection:"we only retain collected information for as long as necessary to provide you with your requested service. What data we store, we’ll protect within commercially acceptable means to prevent loss and theft, as well as unauthorized access, disclosure, copying, use or modification.",privacySharingData:"we don’t share any personally identifying information publicly or with third-parties, except when required to by law",privacyExternalSites:"our app may link to external sites that are not operated by us. Please be aware that we have no control over the content and practices of these sites, and cannot accept responsibility or liability for their respective privacy policies.",privacyRefuse:"you are free to refuse our request for your personal information, with the understanding that we may be unable to provide you with some of your desired services.",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",selectLanguage:"izberite željen jezik",languageSet:"jezik nastavljen, odprite neko drugo stran da se pokažejo spremembe",theme:"izgled",themeLight:"svetel izgled (privzeto)",themeDark:"temen izgled",themeNight:"nočni izgled",themeSet:"izgled nastavljen, odprite neko drugo stran da se spremembe uveljavijo",selectTheme:"izberite željen izgled",errorReportingSet:"nastavitev pošiljanja napak izbrana",errorReporting:"pošiljanje napak",on:"vklopljeno",off:"izklopljeno",selectErrorReporting:"ali naj so napake v aplikaciji posredovane razvijalcem?",triggerWarning:"spodnji gumb omogoči dodatne možnosti, ki lahko razburijo/vznevoljijo nekatere uporabnike. Če omogočite stikalo se strinjate, da avtorjev in/ali njihovih osebnih prepričanj ne boste povezovali s katerokoli od dodatnih omogočenih možnosti.",triggerAgreement:"strinjam se z zgoraj navedenimi pogoji",triggerWarningSet:"spremenili ste stanje dodatnih nastavitev",additionalOptions:"dodatne nastavitve",gsecErrNet:"napaka povezave na GimSIS",gsecErrLogin:"prijava v GimSIS ni uspela (napačno geslo?), poskusite se odjaviti",gsecErrOther:"neznana napaka GimSISa, poskusite se odjaviti",videoconferences:"GimB konference"}} \ No newline at end of file
+var langstrings={en:{miscTranslationLanguage:"English",miscTranslationAuthors:"Rok Štular","":"",monday:"monday",tuesday:"tuesday",wednesday:"wednesday",thursday:"thursday",friday:"friday",saturday:"saturday",sunday:"sunday",am:"am",pm:"pm",january:"january",february:"february",march:"march",april:"april",may:"may",june:"june",july:"july",august:"august",september:"september",october:"october",november:"november",december:"december",username:"username",password:"password",signIn:"sign in",bySigningInYouAgreeTo:"by signing in, you agree to",theToS:"the terms and conditions",and:"and",thePrivacyPolicy:"the privacy policy",loginFailed:"login failed",browserNotSupported:"bežiapp won't work on your device, unless you update your Internet browser",timetable:"timetable",gradings:"gradings",grades:"grades",teachers:"teachers",absences:"absences",messaging:"messaging",meals:"meals",about:"about",logout:"logout",settings:"settings",noPeriods:"no periods in selected week",date:"date",description:"description",add:"add",requestFailed:"request failed",addGrading:"add grading",noInternetConnection:"no internet connection",temporary:"temporary",useOnlyPermanentGrades:"use only permanent grades",useOnlyPermanentGradesNote1:"if checked, only permanent grades will be used in the average grade calculation",useOnlyPermanentGradesNote2:"if left unchecked, the calculation will include every available grade",type:"type",term:"term",teacher:"teacher",zakljucneGradess:"grades in red are final grades that appear on your end-of-year certificate and are decided by your teacher. They are not averages like grades in black. Should you have any questions or complaints about them, contact your teacher",name:"name",schoolSubject:"subject",tpMeetings:"TP meetings",from:"from",to:"to",cancel:"cancel",ok:"ok",noAbsences:"no absences in the chosen time period",lesson:"lesson",notProcessed:"not processed",authorizedAbsence:"authorized",unauthorizedAbsence:"unauthorized",doesNotCount:"does not count",loadingMessages:"Loading messages...",sendAMessage:"send a message",send:"send",recipient:"recipient",messageSubject:"subject",messageBody:"message body",removeImages:"remove images",note:"note",largeImagesNote:"GimB servers don't like large messages, so only very small images may be attached or your message will not be delivered",attachedImages:"attached images",encryptMessage:"Encrypt message",passwordForE2EE:"password for encrypting the message",messages:"messages",received:"received",sent:"sent",deleted:"deleted",messageStorageUsed:"message storage used in this folder",maxMessagesNote:"you can only have 120 messages per message folder, older messages will not be shown. Remember to delete read and sent messages regulary to avoid any issues.",loadMessageBody:"load message body",thisMessageWasEncrypted:"this message was encrypted",enterPassword:"enter password",decrypt:"decrypt",nameDirectoryNotSet:"name directory not set, sending unavailable",errorFetchingMessages:"error fetching messages",unableToReceiveTheMessage:"unable to receive the message",unableToDeleteTheMessage:"unable to delete the message",messageWasProbablySent:"message was probably sent, check the Sent folder to be sure",errorSendingMessage:"error sending message",imageAddedAsAnAttachment:"image added as an attachment",unableToReadDirectory:"unable to read directory of people",messageCouldNotBeSent:"message could to be sent",incorrectPassword:"incorrect password",chat:"chat",chattingWith:"chatting with",noMessages:"no messages",stillLoading:"loading is still in progress",directory:"directory",select:"select",mustSelectRecipient:"you have to select a recipient before chatting. Open directory on the left side by clicking on the top left addressbook button and select a recipient in order to start chatting with them",recipientNotInDirectory:"recipient is not in directory.",chatExternalInfo:"you have just received a chat. Chats are not supported by GimSIS, so you must reply by changing the subject to something else. Chat body: ",loginError:"login error",loginToLopolis:"login to Lopolis",loginToLopolisNote:"it seems like you're not currently logged in to eRestavracija, so this form has been presented to you. You have a different username and password combination used for applying and opting out of of menus. In order to use this feature, you have to log in with your Lopolis account.",logInToLopolis:"log in to Lopolis",logOutFromLopolis:"log out from Lopolis",readOnly:"read only",usage:"usage",mealsUsageNote:"click on a date to open the collapsible menu with choices and click on a specific meal to select it. Reload the meals when you're done and check the entries.",lunchesNote:"app was not tested with lunches in mind. Meals probably won't work with lunches and having a lunch subscription may even break its functionality.",mealNotShownNote:"if a meal is not present in the meals collapsible field, this does not necessarily mean it does not exist. Meals that haven't been altered by you and are unchangable (read-only) are not shown for clarity.",mealsContributeNote:"you are welcome to contribute to the LopolisAPI project and add features, such as checkouts.",authenticationError:"authentication error",lopolisAPIConnectionError:"LopolisAPI server connection error",errorGettingMenus:"error getting menus",errorUnexpectedResponse:"error: unexpected response",requestForAuthenticationFailed:"request for authentication failed",credentialsMatch:"credentials match",errorSettingMeals:"error setting meals",mealSet:"meal set! Reload meals to be sure",selected:"selected",version:"version",authors:"authors",translatorsForThisLanguage:"translators for this language",whatIsNew:"what's new",whatsNew:"what's new",reportABug:"report a bug",sendASuggestion:"send a suggestion",instagram:"instagram",changelog:"changelog",termsOfUse:"terms of use",termsOfUseDescription:"as a condition of use, you promise not to use the BežiApp (App or application) and its related infrastructure (API, hosting service) for any purpose that is unlawful or prohibited by these Terms, or any other purpose not reasonably intended by the authors of the App. By way of example, and not as a limitation, you agree not to use the App",termsOfUseHarass:"to abuse, harass, threaten, impersonate or intimidate any person",termsOfUsePost:"to post or transmit, or cause to be posted or transmitted, any Content that is libelous, defamatory, obscene, pornographic, abusive, offensive, profane or that infringes any copyright or other right of any person",termsOfUseCommunicate:"to communicate with the App developers or other users in abusive or offensive manner",termsOfUsePurpose:"for any purpose that is not permitted under the laws of the jurisdiction where you use the App",termsOfUseExploit:"to post or transmit, or cause to be posted or transmitted, any Communication designed or intended to obtain password, account or private information of any App user",termsOfUseSpam:"to create or transmit unwanted “spam” to any person or any URL",termsOfUseModify:"you may also not reverse engineer, modify or redistribute the app without written consent from the developers",terminationOfServices:"termination of services",terminationOfServicesDescriptions:"the developers of the App may terminate your access to the App without any prior warning or notice for any of the following reasons",terminationOfServicesBreaching:"breaching the Terms of Service",terminationOfServicesRequest:"receiving a formal request from authorities of Gimnazija Bežigrad administration requesting termination of your access to the App",limitationOfLiability:"limitation of Liability",limitationOfLiabilityContent:"the developers of the App provide no warranty; You expressly acknowledge and agree that the use of the licensed application is at your sole risk. To the maximum extent permited by applicable law, the licensed application and any services performed of provided by the licensed application are provided “as is” and “as available”, with all faults and without warranty of any kind, and licensor hereby disclaims all warranties and conditions with respect to the licensed application and any services, either express, implied or statutory, including, but not limited to, the implied warranties and/or conditions of merchantability, of satisfactory quality, of fitness for a particular purpose, of accuracy, of quiet enjoyment, and of noninfringement of third-party rights. No oral or written information or advice given by licensor or its authorized representative shall create a warranty. Should the licensed application or services prove defective, you assume the entire cost of all necessary servicing, repair or correction. Some jurisdictions do not allow the exclusion of the implied warranties or limitations on applicable statutory rights of a customer, so the above exclusion may not apply to you.",tosAreEffectiveAsOf:"the Terms of Service are effective as of",privacyImportant:"your privacy is important to us. It is the developers' policy to respect your privacy regarding any information we may collect from you through our app, BežiApp.",privacyOnlyAskedWhen:"we only ask for personal information when we truly need it to provide a service to you. We collect it by fair and lawful means, with your knowledge and consent. We also let you know why we’re collecting it and how it will be used.",privacyDataCollection:"we only retain collected information for as long as necessary to provide you with your requested service. What data we store, we’ll protect within commercially acceptable means to prevent loss and theft, as well as unauthorized access, disclosure, copying, use or modification.",privacySharingData:"we don’t share any personally identifying information publicly or with third-parties, except when required to by law",privacyExternalSites:"our app may link to external sites that are not operated by us. Please be aware that we have no control over the content and practices of these sites, and cannot accept responsibility or liability for their respective privacy policies.",privacyRefuse:"you are free to refuse our request for your personal information, with the understanding that we may be unable to provide you with some of your desired services.",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:"language",selectLanguage:"select desired language",languageSet:"language set, open another page for the changes to take effect",theme:"theme",themeLight:"light theme (default)",themeDark:"dark theme",themeNight:"night theme",selectTheme:"select a theme",triggerWarning:"the following switch enables additional settings, which some people may: disagree with, find annoying, be offended by them. By enabling the switch, you agree that you won't be triggered by any of the additional options and will not asociate any of the authors and/or their personal beliefs and opinions with additional options.",triggerAgreement:"i agree with terms and conditions stated above",triggerWarningSet:"additional settings toggled",additionalOptions:"additional settings",themeSet:"theme set, open another page for the changes to take effect",errorReportingSet:"error reporting preference set",errorReporting:"error reporting",on:"on",off:"off",selectErrorReporting:"should error reports be submitted to the developers?",gsecErrNet:"GimSIS connection error",gsecErrLogin:"GimSIS login error (bad password?), try logging out",gsecErrOther:"GimSIS unknown error, try logging out",videoconferences:"GimB meet"},sl:{miscTranslationLanguage:"slovenščina",miscTranslationAuthors:"Anton Luka Šijanec","":"",monday:"ponedeljek",tuesday:"torek",wednesday:"sreda",thursday:"četrtek",friday:"petek",saturday:"sobota",sunday:"nedelja",am:"dop.",pm:"pop.",january:"januar",february:"februar",march:"marec",april:"april",may:"maj",june:"junij",july:"julij",august:"avgust",september:"september",october:"oktober",november:"november",december:"december",username:"uporabniško ime",password:"geslo",signIn:"prijava",bySigningInYouAgreeTo:"s prijavo se strinjate s",theToS:"pogoji uporabe (v angleščini)",and:"in",thePrivacyPolicy:"politika zasebnosti (v angleščini)",loginFailed:"prijava je spodletela",browserNotSupported:"BežiApp ne bo deloval na vaši napravi, če ne posodobite vašega Internetnega brskalnika",noPeriods:"ni ur v izbranem tednu",timetable:"urnik",gradings:"ocenjevanja",grades:"ocene",teachers:"profesorji",absences:"izostanki",messaging:"sporočanje",meals:"obroki",about:"o",logout:"odjava",settings:"nastavitve",date:"datum",description:"opis",add:"dodaj",requestFailed:"zahteva spodletela",addGrading:"dodaj ocenjevanje",noInternetConnection:"ni povezave s spletom",temporary:"začasno",useOnlyPermanentGrades:"uporabi le stalne ocene",useOnlyPermanentGradesNote1:"če je označeno, bodo za izračun povprečja uporabljene le stalne ocene",useOnlyPermanentGradesNote2:"če pa je polje neoznačeno, pa se ob izračunu povprečne ocene upoštevajo vse ocene",type:"tip",term:"rok",teacher:"profesor",zakljucneGradess:"zaključne ocene, ki bodo na spričevalu, so označene z rdečo, povprečja ocen pa so v črni barvi. V kolikor imate kakršnekoli pritožbe ali vprašanja glede zaključnih ocen, povprašajte profesorja",name:"ime",schoolSubject:"predmet",tpMeetings:"govorilne ure",from:"od",to:"do",cancel:"prekliči",ok:"v redu",noAbsences:"ni izostankov v izbranem časovnem obdobju",lesson:"ura",notProcessed:"ni obdelano",authorizedAbsence:"opravičeno",unauthorizedAbsence:"neopravičeno",doesNotCount:"ne šteje",loadingMessages:"Nalagam sporočila...",sendAMessage:"pošlji sporočilo",send:"pošlji",recipient:"prejemnik",messageSubject:"zadeva",messageBody:"telo",removeImages:"odstrani slike",note:"opomba",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",encryptMessage:"Šifriraj sporočilo",passwordForE2EE:"geslo za šifriranje sporočila",messages:"sporočila",received:"prejeta",sent:"poslana",deleted:"izbrisana",messageStorageUsed:"zasedenost shrambe sporočil v tej mapi",maxMessagesNote:"v vsaki mapi imate lahko največ 120 sporočil. Starejša sporočila ne bodo prikazana. Redno brišite sporočila, da se izognete morebitnim težavam.",loadMessageBody:"naloži telo sporočila",thisMessageWasEncrypted:"to sporočilo je šifrirano",enterPassword:"vnesite geslo",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",unableToDeleteTheMessage:"sporočila ni bilo mogoče izbrisati",messageWasProbablySent:"sporočilo je bilo verjetno poslano, prepričajte se in preverite mapo s poslanimi sporočili",errorSendingMessage:"sporočila ni bilo mogoče poslati",imageAddedAsAnAttachment:"slika dodana kot priloga",unableToReadDirectory:"imenika ni bilo mogoče prebrati",messageCouldNotBeSent:"sporočila ni bilo mogoče poslati",incorrectPassword:"nepravilno geslo",chat:"klepet",chattingWith:"klepet z osebo",noMessages:"ni sporočil",stillLoading:"nalaganje še poteka",directory:"imenik",select:"izberi",mustSelectRecipient:"pred klepetom morate izbrati sogovornika. Odprite imenik (meni na levi strani) s pritiskom na gumb \"imenik\" zgoraj desno in izberite sogovornika.",recipientNotInDirectory:"izbrane osebe ni v imeniku",chatExternalInfo:"dobili ste kratko sporočilo v standardu, ki ga GimSIS ne podpira. Pri odgovarjanju spremenite zadevo. Vsebina sporočila: ",loginError:"napaka pri prijavi",loginToLopolis:"prijava v Lopolis",loginToLopolisNote:"izgleda, da niste prijavljeni v eRestavracijo, zato se vam je prikazal prijavni obrazec. Za uporavljanje s prehrano se uporablja druga kombinacija uporabniškega imena in gesla, zato se prijavite s svojimi Lopolis prijavnimi podatki za nadaljevanje.",logInToLopolis:"prijava v Lopolis",logOutFromLopolis:"odjava iz Lopolisa",readOnly:"samo za branje",usage:"uporaba",mealsUsageNote:"kliknite na datum za prikaz menijev, nato pa si enega izberite s klikom na ime menija. Po nastavitvi menijev ponovno naložite menije in se prepričajte o pravilnih nastavitvah.",lunchesNote:"aplikacija ni testirana za naročanje na koslila, zato verjetno to ne deluje. Če ste naročeni na kosila lahko naročanje na menije sploh ne deluje ali pa deluje narobe.",mealNotShownNote:"če nek dan manjka med meniji, to verjetno pomeni, da ni več spremenljiv in zanj niste ročno spremenili menija",mealsContributeNote:"vabimo vas k urejanju LopolisAPI programa za upravljanje z meniji.",authenticationError:"napaka avtentikacije",lopolisAPIConnectionError:"napaka povezave na LopolisAPI strežnik",errorGettingMenus:"napaka branja menijev",errorUnexpectedResponse:"napaka: nepričakovan odgovor",requestForAuthenticationFailed:"zahteva za avtentikacijo ni uspela",credentialsMatch:"prijavni podatki so pravilni",errorSettingMeals:"napaka pri nastavljanju menijev",mealSet:"obrok nastavljen! osvežite obroke in se prepričajte sami",selected:"izbrano",version:"različica",authors:"avtorji",translatorsForThisLanguage:"prevajalci izbranega jezika",whatIsNew:"kaj je novega",whatsNew:"kaj je novega",reportABug:"prijavite napako",sendASuggestion:"pošljite pripombo/predlog/pohvalo/pritožbo",instagram:"instagram",changelog:"dnevnik sprememb",termsOfUse:"terms of use",termsOfUseDescription:"as a condition of use, you promise not to use the BežiApp (App or application) and its related infrastructure (API, hosting service) for any purpose that is unlawful or prohibited by these Terms, or any other purpose not reasonably intended by the authors of the App. By way of example, and not as a limitation, you agree not to use the App",termsOfUseHarass:"to abuse, harass, threaten, impersonate or intimidate any person",termsOfUsePost:"to post or transmit, or cause to be posted or transmitted, any Content that is libelous, defamatory, obscene, pornographic, abusive, offensive, profane or that infringes any copyright or other right of any person",termsOfUseCommunicate:"to communicate with the App developers or other users in abusive or offensive manner",termsOfUsePurpose:"for any purpose that is not permitted under the laws of the jurisdiction where you use the App",termsOfUseExploit:"to post or transmit, or cause to be posted or transmitted, any Communication designed or intended to obtain password, account or private information of any App user",termsOfUseSpam:"to create or transmit unwanted “spam” to any person or any URL",termsOfUseModify:"you may also not reverse engineer, modify or redistribute the app without written consent from the developers",terminationOfServices:"termination of services",terminationOfServicesDescriptions:"the developers of the App may terminate your access to the App without any prior warning or notice for any of the following reasons",terminationOfServicesBreaching:"breaching the Terms of Service",terminationOfServicesRequest:"receiving a formal request from authorities of Gimnazija Bežigrad administration requesting termination of your access to the App",limitationOfLiability:"limitation of Liability",limitationOfLiabilityContent:"the developers of the App provide no warranty; You expressly acknowledge and agree that the use of the licensed application is at your sole risk. To the maximum extent permited by applicable law, the licensed application and any services performed of provided by the licensed application are provided “as is” and “as available”, with all faults and without warranty of any kind, and licensor hereby disclaims all warranties and conditions with respect to the licensed application and any services, either express, implied or statutory, including, but not limited to, the implied warranties and/or conditions of merchantability, of satisfactory quality, of fitness for a particular purpose, of accuracy, of quiet enjoyment, and of noninfringement of third-party rights. No oral or written information or advice given by licensor or its authorized representative shall create a warranty. Should the licensed application or services prove defective, you assume the entire cost of all necessary servicing, repair or correction. Some jurisdictions do not allow the exclusion of the implied warranties or limitations on applicable statutory rights of a customer, so the above exclusion may not apply to you.",tosAreEffectiveAsOf:"the Terms of Service are effective as of",privacyImportant:"your privacy is important to us. It is the developers' policy to respect your privacy regarding any information we may collect from you through our app, BežiApp.",privacyOnlyAskedWhen:"we only ask for personal information when we truly need it to provide a service to you. We collect it by fair and lawful means, with your knowledge and consent. We also let you know why we’re collecting it and how it will be used.",privacyDataCollection:"we only retain collected information for as long as necessary to provide you with your requested service. What data we store, we’ll protect within commercially acceptable means to prevent loss and theft, as well as unauthorized access, disclosure, copying, use or modification.",privacySharingData:"we don’t share any personally identifying information publicly or with third-parties, except when required to by law",privacyExternalSites:"our app may link to external sites that are not operated by us. Please be aware that we have no control over the content and practices of these sites, and cannot accept responsibility or liability for their respective privacy policies.",privacyRefuse:"you are free to refuse our request for your personal information, with the understanding that we may be unable to provide you with some of your desired services.",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",selectLanguage:"izberite željen jezik",languageSet:"jezik nastavljen, odprite neko drugo stran da se pokažejo spremembe",theme:"izgled",themeLight:"svetel izgled (privzeto)",themeDark:"temen izgled",themeNight:"nočni izgled",themeSet:"izgled nastavljen, odprite neko drugo stran da se spremembe uveljavijo",selectTheme:"izberite željen izgled",errorReportingSet:"nastavitev pošiljanja napak izbrana",errorReporting:"pošiljanje napak",on:"vklopljeno",off:"izklopljeno",selectErrorReporting:"ali naj so napake v aplikaciji posredovane razvijalcem?",triggerWarning:"spodnji gumb omogoči dodatne možnosti, ki lahko razburijo/vznevoljijo nekatere uporabnike. Če omogočite stikalo, se strinjate, da avtorjev in/ali njihovih osebnih prepričanj ne boste povezovali s katerokoli od dodatnih omogočenih možnosti",triggerAgreement:"strinjam se z zgoraj navedenimi pogoji",triggerWarningSet:"spremenili ste stanje dodatnih nastavitev",additionalOptions:"dodatne nastavitve",gsecErrNet:"napaka povezave na GimSIS",gsecErrLogin:"prijava v GimSIS ni uspela (napačno geslo?), poskusite se odjaviti",gsecErrOther:"neznana napaka GimSISa, poskusite se odjaviti",videoconferences:"GimB konference"}} \ No newline at end of file
diff --git a/dist/js/login.js b/dist/js/login.js
index 88cf081..2d79576 100644
--- a/dist/js/login.js
+++ b/dist/js/login.js
@@ -2,4 +2,4 @@
document.addEventListener("DOMContentLoaded",()=>{setupEventListeners();})
function setupEventListeners(){$("#login-button").click(()=>{login();});window.addEventListener("keyup",(event)=>{if(event.keyCode===13){event.preventDefault();login();}});}
function login(){let username=$("#username").val();let password=$("#password").val();var gsecInstance;try{gsecInstance=new gsec();}catch(error){$.ajax({url:'js/gsec.js?ajaxload',async:false,dataType:"script",});try{gsecInstance=new gsec();}catch(error){alert(D("browserNotSupported"));}}
-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("");});} \ No newline at end of file
+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)];read_val(0);Promise.all(promises_to_run).then(function(){window.location.replace("/pages/timetable.html");});}else{UIAlert("loginFailed");$("#password").val("");}}).catch((err)=>{gsecErrorHandlerUI(err);$("#password").val("");});} \ No newline at end of file
diff --git a/dist/js/messaging.js b/dist/js/messaging.js
index 762db73..1650563 100644
--- a/dist/js/messaging.js
+++ b/dist/js/messaging.js
@@ -135,6 +135,6 @@ input.click();});$("#full-name").on("blur",validateName);$("#refresh-icon").clic
</div>
`}
console.log(msgcontent);console.log(encrypted_message);sendMessage(value[$("#full-name").val()],msgsubject,htmlEncode(msgcontent));$("#msg-body").val("");$("#full-name").val("");$("#msg-subject").val("");$("#msg-send").attr("disabled","disabled");additionalstufftoaddtomessage="";$("#msg-added-image").html("");$("#msg-e2ee-pass").hide();}).catch(function(err){UIAlert(`${D("unableToReadDirectory")} ${D("messageCouldNotBeSend")}`,"45245");console.log(err);});});}
-function getUrlParameter(sParam){const url_params=new URLSearchParams(window.location.search);const found_param=url_params.get(sParam);return found_param}
+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",()=>{checkLogin();const modal_elems=document.querySelectorAll('.modal');const modal_options={onOpenStart:()=>{$("#fab-new").hide()},onCloseEnd:()=>{$("#fab-new").show()},dismissible:false};M.Modal.init(modal_elems,modal_options);loadDirectory();setupEventListeners();const tabs=document.querySelectorAll(".tabs");const tab_options={onShow:(tab)=>{if($(tab).hasClass("active")){switch(tab.id){case"beziapp-received":current_tab=0;loadMessages(false,0);break;case"beziapp-sent":current_tab=1;loadMessages(false,1);break;case"beziapp-deleted":current_tab=2;loadMessages(false,2);break;}}}};M.Tabs.init(tabs,tab_options);const fab_options={hoverEnabled:false,toolbarEnabled:false}
const fab_elem=document.querySelectorAll(".fixed-action-btn");M.FloatingActionButton.init(fab_elem,fab_options);var receivedmessages=null;loadMessages(true,0);M.updateTextFields();const menus=document.querySelectorAll(".side-menu");M.Sidenav.init(menus,{edge:"right",draggable:true});}); \ No newline at end of file
diff --git a/dist/js/setup-storage.js b/dist/js/setup-storage.js
index bf28f61..b394f1e 100644
--- a/dist/js/setup-storage.js
+++ b/dist/js/setup-storage.js
@@ -1,2 +1,2 @@
-async function setupStorage(force=false){let logged_in;promises_check_if_already_installed=[localforage.getItem("logged_in").then(function(val){console.log("[setupStorage] logged in status: "+val);logged_in=val;})];await Promise.all(promises_check_if_already_installed);let promises_update=[localforage.setItem("profile",{}),localforage.setItem("timetable",[]),localforage.setItem("teachers",[]),localforage.setItem("gradings",[]),localforage.setItem("grades",[]),localforage.setItem("absences",{}),localforage.setItem("messages",{"0":[],"1":[],"2":[]}),localforage.setItem("directory",{}),localforage.setItem("meals",{}),localforage.setItem("chosenLang","en"),localforage.setItem("theme","light"),localforage.setItem("errorReporting","on"),localforage.setItem("triggerWarningAccepted",false)];if(logged_in&&force==false){await Promise.all(promises_update);console.log("[setupStorage] user logged in: only updated");}else{let promises_first_install=[localforage.setItem("logged_in",false),localforage.setItem("username",""),localforage.setItem("password",""),localforage.setItem("chosenLang","en"),localforage.setItem("theme","light"),localforage.setItem("triggerWarningAccepted",false)];await localforage.clear();await Promise.all(promises_first_install);console.log("[setupStorage] user not logged in: set up whole database");}} \ No newline at end of file
+async function setupStorage(force=false){let logged_in;promises_check_if_already_installed=[localforage.getItem("logged_in").then(function(val){console.log("[setupStorage] logged in status: "+val);logged_in=val;})];await Promise.all(promises_check_if_already_installed);let promises_update=[localforage.setItem("profile",{}),localforage.setItem("timetable",[]),localforage.setItem("teachers",[]),localforage.setItem("gradings",[]),localforage.setItem("grades",[]),localforage.setItem("absences",{}),localforage.setItem("messages",[[],[],[]]),localforage.setItem("directory",{}),localforage.setItem("meals",{}),localforage.setItem("chosenLang","en"),localforage.setItem("theme","light"),localforage.setItem("errorReporting","on"),localforage.setItem("triggerWarningAccepted",false)];if(logged_in&&force==false){await Promise.all(promises_update);console.log("[setupStorage] user logged in: only updated");}else{let promises_first_install=[localforage.setItem("logged_in",false),localforage.setItem("username",""),localforage.setItem("password",""),localforage.setItem("chosenLang","en"),localforage.setItem("theme","light"),localforage.setItem("triggerWarningAccepted",false)];await localforage.clear();await Promise.all(promises_first_install);console.log("[setupStorage] user not logged in: set up whole database");}} \ No newline at end of file
diff --git a/dist/pages/about.html b/dist/pages/about.html
index ebbcfeb..a08ae16 100755
--- a/dist/pages/about.html
+++ b/dist/pages/about.html
@@ -73,7 +73,7 @@
<b class="title-secondary">Beži</b><span class="title-primary">App</span>
</h3>
<!-- One day in the future we may have sw cache version covered by this as well -->
- <h5 class="subheader"><x-su>version</x-su> 1.0.14-beta</h5>
+ <h5 class="subheader"><x-su>version</x-su> 1.0.14.1-beta</h5>
</div>
</div>
<div class="row">
@@ -142,7 +142,7 @@
<div class="row">
<p>
<small>
- ^HEAD 20505fc48713c600c345814d4a9c2e0747c77152
+ ^HEAD ab895dc64437ac9ea42b2c9790a0b29550bdbc17
</small>
</p>
</div>
diff --git a/dist/pages/grades.html b/dist/pages/grades.html
index 0a9abe1..0a8e5ec 100755
--- a/dist/pages/grades.html
+++ b/dist/pages/grades.html
@@ -111,7 +111,8 @@
</span>
</label>
</p>
- <ul class="collapsible" id="grades-collapsible"></ul>
+ <ul class="collapsible" id="grades-collapsible"></ul>
+ <p><x-du>zakljucneGradess</x-du></p>
</div>
</body>
diff --git a/dist/pages/gradings.html b/dist/pages/gradings.html
index 81c0e45..ce30046 100755
--- a/dist/pages/gradings.html
+++ b/dist/pages/gradings.html
@@ -95,37 +95,50 @@
<br>
<div id="calendar"></div>
</div>
-<!--
- <div class="container">
- <div class="row">
- <div class="col s12">
- <h4>Add a personal event</h4>
- <div class="row">
- <div class="input-field col s5">
- <input required="required" type="text" class="datepicker" id="datepicker-add">
- <label for="datepicker-add">Date</label>
- </div>
- <div class="input-field col s5">
- <input required="required" id="event_name" type="text" class="validate">
- <label for="event_name">Name</label>
- </div>
- <div class="input-field col s2">
- <button id="event_btn" class="btn waves-effect waves-light" type="text" class="validate">
- <i class="material-icons">event_available</i>
- </button>
- </div>
- </div>
- <div class="row">
- <div class="input-field col s12">
- <textarea required="required" id="event_description" class="materialize-textarea"></textarea>
- <label for="event_description">Description</label>
- </div>
- </div>
- </div>
+
+ <!-- FAB -->
+ <!-- <div class="fixed-action-btn" id="fab-new">
+ <a class="btn-floating btn-large fab-new-message modal-trigger" href="#beziapp-add-grading">
+ <i class="large material-icons">add</i>
+ </a>
+ </div> -->
+ <!-- Modal Structure -->
+ <div id="beziapp-add-grading" class="modal modal-fixed-footer">
+
+ <div class="modal-content">
+
+ <h4 class="general-text"><x-su>addGrading</x-su></h4>
+
+ <div class="row">
+ <div class="input-field col s6">
+ <input required="required" type="text" class="datepicker" id="datepicker-add">
+ <label for="datepicker-add"><x-su>date</x-su></label>
+ </div>
+ <div class="input-field col s6">
+ <input required="required" id="input-grading-name" type="text" class="validate">
+ <label for="event_name"><x-su>name</x-su></label>
+ </div>
+ </div>
+
+ <div class="row">
+ <div class="input-field col s12">
+ <textarea required="required" id="input-grading-description" class="materialize-textarea"></textarea>
+ <label for="event_description"><x-su>description</x-su></label>
+ </div>
+ </div>
+
</div>
+ <div class="modal-footer">
+ <div id="modal-footer-right">
+ <a href="#" class="modal-close waves-effect waves-green btn-flat"><x-su>cancel</x-su> <i class="material-icons right">close</i></a>
+ <a href="#" id="btn-add-grading" class="modal-close waves-effect waves-green btn-flat" disabled><x-su>add</x-su> <i class="material-icons right">add</i></a>
+ </div>
+ </div>
</div>
--->
+
+
+
</body>
</html>
diff --git a/dist/pages/messaging.html b/dist/pages/messaging.html
index e5c85e5..5c9fb32 100755
--- a/dist/pages/messaging.html
+++ b/dist/pages/messaging.html
@@ -166,8 +166,8 @@
<div class="modal-footer">
<div id="modal-footer-right">
- <a href="#" class="modal-close waves-effect waves-green btn-flat">Cancel <i class="material-icons right">close</i></a>
- <a href="#" id="msg-send" class="modal-close waves-effect waves-green btn-flat" disabled>Send <i class="material-icons right">send</i></a>
+ <a href="#" class="modal-close waves-effect waves-green btn-flat"><x-su>cancel</x-su> <i class="material-icons right">close</i></a>
+ <a href="#" id="msg-send" class="modal-close waves-effect waves-green btn-flat" disabled><x-su>send</x-su> <i class="material-icons right">send</i></a>
</div>
</div>
</div>
diff --git a/dist/sw.js b/dist/sw.js
index 4c1211f..c1ccb21 100755
--- a/dist/sw.js
+++ b/dist/sw.js
@@ -3,8 +3,8 @@
// Change version to cause cache refresh
-const static_cache_name = "site-static-1.0.14-beta-20505fc";
-// commit before the latest is 20505fc48713c600c345814d4a9c2e0747c77152
+const static_cache_name = "site-static-1.0.14.1-beta-ab895dc";
+// commit before the latest is ab895dc64437ac9ea42b2c9790a0b29550bdbc17
// Got them with find . -not -path '*/\.*' | sed "s/.*/\"&\",/" | grep -v sw.js
// sw.js NE SME BITI CACHAN, ker vsebuje verzijo!
diff --git a/global.bvr b/global.bvr
index ea556e2..a6b170e 100644
--- a/global.bvr
+++ b/global.bvr
@@ -1,3 +1,3 @@
<@?s bvr_include_path assets/pages-src/ assets/pages-src/misc/@>
<@?s latest_commit ?u 0 -1 ?i .git/refs/heads/dev@>
-<@?s app_version 1.0.14-beta@>
+<@?s app_version 1.0.14.1-beta@>