// ==UserScript==
// @name BetterOghma
// @namespace Violentmonkey Scripts
// @description This is a userscript.
// @match https://oghma.epcc.pt/*
// @version 2.0.0
// @author Leonardo
// @require https://cdn.jsdelivr.net/combine/npm/@violentmonkey/dom@2,npm/@violentmonkey/[email protected]
// @require https://cdn.jsdelivr.net/npm/@violentmonkey/dom@2
// @grant GM_addStyle
// ==/UserScript==
(function () {
'use strict';
var css_248z = "";
// global CSS
document.head.append(VM.m(VM.h("style", null, css_248z)));
// CSS modules
class LocalStorage {
set(key, value) {
key = key.toString().toLowerCase().replace(/\s/g, "");
value = value.toString();
localStorage.setItem(key, value);
}
get(key, defaultValue = "") {
var _localStorage$getItem;
key = key.toString().toLowerCase().replace(/\s/g, "");
return (_localStorage$getItem = localStorage.getItem(key)) != null ? _localStorage$getItem : defaultValue;
}
check(key, value) {
key = key.toString().toLowerCase().replace(/\s/g, "");
value = value.toString();
return localStorage.getItem(key) == value;
}
}
class MainController {
constructor(url) {
this.AVARAGE_DECIMAL_PARTS = 2;
this.hide = function (element) {
element.style.display = "none";
};
this.grid = function (element) {
element.style.display = "grid";
};
this.flex = function (element) {
element.style.display = "flex";
};
this.url = url;
this.storage = new LocalStorage();
this.getByText("Inscrições nos Exames", this.hide);
this.getByClass("events announcements", this.hide);
this.getByText("Importante!", this.hide);
}
async get(pattern, callback) {
let element = document.querySelector(pattern);
if (!element) return;
callback(element);
}
async getAll(pattern, callback) {
let element = document.querySelectorAll(pattern);
if (!element) return;
for (var i = 0; i < element.length; i++) callback(element[i]);
}
async getByClass(className, callback) {
let element = document.getElementsByClassName(className);
if (!element) return;
for (var i = 0; i < element.length; i++) await callback(element[i]);
}
async getByText(text, callback) {
var elements = document.getElementsByTagName("*");
for (var i = 0; i < elements.length; i++) if (elements[i].textContent === text) callback(elements[i]);
}
setDecrescent() {
this.getByClass("nav pull-right", element => {
element.style.display = "flex";
element.style.alignItems = "center";
});
this.getByClass("nav pull-right", element => {
if (document.querySelector("#decrease")) return;
const Checkbox = () => VM.h("input", {
id: "decrease",
type: "checkbox",
checked: this.storage.check("DECREASE", "true"),
onclick: () => {
this.storage.set('DECREASE', this.storage.check("DECREASE", "true") ? "false" : "true");
this.index();
}
});
const Text = () => VM.h("span", {
style: "padding: 1rem;"
}, "Ordem decrescente");
const Li = () => VM.h("li", {
style: "display: flex; order: -1"
}, VM.h(Text, null), VM.h(Checkbox, null));
element.append(VM.m(VM.h(Li, null)));
});
}
}
class Subject {
setName(name) {
this.name = name;
}
setId(id) {
this.id = id;
}
setEvaluation(evaluation) {
this.evaluation = evaluation;
}
getName() {
return this.name;
}
getId() {
return this.id;
}
getEvaluation() {
return this.evaluation;
}
}
class Evaluations extends MainController {
async index() {
this.setDecrescent();
this.subjects = [];
// Verifica em qual user está salvo a atual data
if (!this.storage.check("lastUser", this.url[4])) {
const itemToKeep = "decrease";
for (let i = localStorage.length - 1; i >= 0; i--) {
const key = localStorage.key(i);
if (key != itemToKeep) {
localStorage.removeItem(key);
}
}
this.storage.set("lastUser", this.url[4]);
}
// CSS
this.get("tbody", this.grid);
this.getAll("tr", this.grid);
this.getAll("tr", element => {
let sons = element.querySelectorAll(element.className == "header" ? "th" : "td");
for (var i = 0; i < sons.length; i++) {
sons[i].style.display = "flex";
if (element.className == "header") {
element.style.order = '-21';
if (i == 0) sons[i].style.gridColumn = "span 2 / span 2";
if (i > 0) sons[i].style.justifyContent = "end";
if (i > 2) this.hide(sons[i]);
} else {
if (i > 1) sons[i].style.justifyContent = "end";
if (i == 2) element.style.order = (this.storage.check("DECREASE", "true") ? '-' : '') + sons[i].textContent;
if (i > 3) this.hide(sons[i]);
}
}
element.style.gridTemplateColumns = "30% 50% 10% 10%";
});
// Pega o id do curso
let coursesURL = "https://oghma.epcc.pt/users/" + this.url[4] + "/subscriptions";
let courseId;
await fetch(coursesURL).then(async html => {
const parser = new DOMParser();
const doc = parser.parseFromString(await html.text(), 'text/html');
let tr = doc.querySelector("tbody > tr");
courseId = tr.querySelectorAll("td")[1].querySelector("a").href.split("/")[4];
});
// Salva todas as notas
if (!this.storage.check("allSubjectsSet", "true")) {
let userh1 = document.getElementsByClassName("well clearfix")[0].querySelector("h1");
var smallElement = userh1.querySelector('small');
var smallText = smallElement.textContent;
let username = userh1.textContent.substring(smallText.length);
let allSubjects = await this.getAllSubjectsFromCourse(courseId);
for (var i = 0; i < allSubjects.names.length; i++) {
let subject = new Subject();
subject.setName(allSubjects.names[i]);
subject.setId(allSubjects.ids[subject.getName()]);
let evaluation = await this.getEvaluationByUsername(username, subject.getId());
subject.setEvaluation(evaluation);
this.subjects.push(subject);
}
this.subjects.forEach((subject, i) => {
this.storage.set(i.toString(), subject.getName().toString());
this.storage.set(subject.getName() + "_id", subject.getId().toString());
this.storage.set(subject.getName() + "_evaluation", subject.getEvaluation().toString());
this.storage.set(subject.getName() + "_isActived", "true");
});
this.storage.set("allSubjectsSet", "true");
this.storage.set("subjectsLength", this.subjects.length.toString());
} else {
for (var i = 0; i < parseFloat(this.storage.get("subjectsLength")); i++) {
let subject = new Subject();
let name = this.storage.get(i.toString());
subject.setName(name);
let id = this.storage.get(name + "_id");
subject.setId(parseFloat(id));
let evaluation = this.storage.get(name + "_evaluation");
subject.setEvaluation(parseFloat(evaluation));
this.subjects.push(subject);
}
}
await this.getByClass("well clearfix", async element => {
let avarageSubjectSum = 0;
let subjectsCount = 0;
this.subjects.forEach(subject => {
if (!isNaN(subject.getEvaluation()) && this.storage.check(subject.getName() + "_isActived", "true")) {
subjectsCount++;
avarageSubjectSum += subject.getEvaluation();
}
});
let avarage = (avarageSubjectSum / subjectsCount).toFixed(this.AVARAGE_DECIMAL_PARTS);
var averageElement = null;
if (document.getElementById("alunoAvarageText")) averageElement = document.getElementById("alunoAvarageText");else {
averageElement = document.createElement("p");
averageElement.id = "alunoAvarageText";
}
averageElement.innerHTML = "O aluno tem uma média de " + avarage + " pontos";
if (!document.getElementById("alunoAvarageText")) element.appendChild(averageElement);
});
this.getByClass("span2 sidebar", element => {
if (document.getElementById("evaluationsCheckers")) return;
const subjects = this.subjects.map(subject => {
const SubjectElementCheckbox = () => VM.h("input", {
type: "checkbox",
id: subject.getName() + "_checkbox",
onclick: () => {
this.storage.set(subject.getName() + "_isActived", this.storage.check(subject.getName() + "_isActived", "true") ? "false" : "true");
this.index();
},
checked: this.storage.check(subject.getName() + "_isActived", "true")
});
const SubjectElementText = () => VM.h("label", {
for: subject.getName() + "_checkbox",
style: "\r font-size: 0.8rem;\r margin-bottom: 0rem;\r user-select: none;\r padding-left: 0.5rem;\r fontSize: 0.8rem;"
}, subject.getName() == "Tecnologias de Informação e Comunicação" ? "TIC" : subject.getName());
const SubjectAvarageScore = () => VM.h("span", {
style: "padding-left: 0.5rem;"
}, subject.getEvaluation().toString());
return VM.h("div", {
style: "display: flex; flex-direction: row; align-items: center; justify-content: start; padding: 0.25rem;"
}, VM.h(SubjectElementCheckbox, null), VM.h(SubjectElementText, null), VM.h(SubjectAvarageScore, null));
});
const Div = () => VM.h("div", {
id: "evaluationsCheckers",
style: "padding-left: 0.8rem; padding-right: 0.8rem;"
}, subjects);
element.append(VM.m(VM.h(Div, null)));
});
}
async getAllSubjectsFromCourse(id) {
let couseURL = "https://oghma.epcc.pt/courses/" + id;
let subjects = {
ids: {},
names: []
};
await fetch(couseURL).then(async html => {
const parser = new DOMParser();
const doc = parser.parseFromString(await html.text(), 'text/html');
let trs = doc.querySelectorAll("tbody > tr");
trs.forEach(function (tr) {
let td = tr.querySelector("td");
let subject = td.querySelector("a");
let subjectTitle = subject.textContent;
if (subjectTitle.endsWith(" ")) {
subjectTitle = subjectTitle.trimEnd();
}
let subjectId = subject.href.split("/")[4];
subjects.ids[subjectTitle] = parseFloat(subjectId);
subjects.names.push(subjectTitle);
});
});
return subjects;
}
async getEvaluationByUsername(username, subjectId) {
let subjectEvaluationsURL = "https://oghma.epcc.pt/units/" + subjectId + "/evaluations";
let evaluation = 0;
await fetch(subjectEvaluationsURL).then(async html => {
const parser = new DOMParser();
const doc = parser.parseFromString(await html.text(), 'text/html');
let trs = doc.querySelectorAll("tbody > tr");
trs.forEach(function (tr) {
let tds = tr.querySelectorAll("td");
if (tds.length > 0) if (tds[1].textContent.replace(/\s/g, "").toLowerCase() == username.replace(/\s/g, "").toLowerCase()) evaluation = parseFloat(tds[2].textContent.split(" ")[0]);
});
});
return evaluation;
}
}
class Subscriptions extends MainController {
async index() {
this.setDecrescent();
this.getByClass("student active", element => {
element.querySelectorAll("a").forEach(function (a) {
a.href += "/evaluations";
});
});
this.getAll(".student:not(.active)", this.hide);
this.getByClass("users-list photo", this.flex);
this.getByClass("users-list photo", element => {
element.style.flexWrap = "wrap";
});
let avarageSum = 0;
let totalStudents = 0;
this.getByClass("student active", async element => {
var id = element.querySelector("a").href.split("/")[4];
var evaluationsURL = "https://oghma.epcc.pt/users/" + id + "/evaluations";
if (id) await fetch(evaluationsURL).then(async html => {
const parser = new DOMParser();
const doc = parser.parseFromString(await html.text(), 'text/html');
var avarage = this.getAvarage(doc);
avarageSum += avarage;
totalStudents++;
element.style.order = (this.storage.check("DECREASE", "true") ? '-' : '') + (avarage * 1000).toFixed(0);
var averageElement = document.createElement("p");
averageElement.textContent = "Média de " + avarage.toFixed(this.AVARAGE_DECIMAL_PARTS) + " pontos";
element.appendChild(averageElement);
});else {
this.totalAvarage = avarageSum / totalStudents;
element.querySelector("p").textContent = "Média de " + this.totalAvarage.toFixed(this.AVARAGE_DECIMAL_PARTS) + " pontos";
element.style.order = (this.storage.check("DECREASE", "true") ? '-' : '') + (this.totalAvarage * 1000).toFixed(0);
}
});
this.getByClass("users-list photo", element => {
var avarageStudent = document.createElement("li");
var imageA = document.createElement("a");
var image = document.createElement("img");
var br = document.createElement("br");
var span = document.createElement("span");
var a = document.createElement("a");
var p = document.createElement("p");
avarageStudent.className = "student active";
image.src = "https://upload.wikimedia.org/wikipedia/commons/9/99/Sample_User_Icon.png";
image.style.height = "79px";
image.style.width = "auto";
span.textContent = "Média";
a.textContent = "Aluno Médio";
imageA.appendChild(image);
avarageStudent.appendChild(imageA);
avarageStudent.appendChild(span);
avarageStudent.appendChild(br);
avarageStudent.appendChild(a);
avarageStudent.appendChild(p);
element.appendChild(avarageStudent);
});
}
getAvarage(page) {
var avarage = 0;
var sumAll = 0;
var countAll = 0;
page.querySelectorAll("tr").forEach(tr => {
if (tr.className != "header") {
var tds = tr.querySelectorAll("td");
sumAll += parseInt(tds[2].textContent);
countAll++;
}
});
avarage = sumAll / countAll;
return avarage;
}
}
class Default extends MainController {
async index() {
this.getByClass("well clearfix", element => {
const App = () => VM.h("div", null, VM.h("h1", null, "Welcome to BetterOghma"));
element.append(VM.m(VM.h(App, null)));
});
}
}
// setItem("DECREASE", getItem("DECREASE", "true"));
let url = window.location.href;
let urlArray = url.split("/");
let page = urlArray[urlArray.length - 1].replace(/#/g, "");
let routes = {
default: Default,
evaluations: Evaluations,
subscriptions: Subscriptions
};
if (!routes[page]) page = 'default';
let controller = new routes[page](urlArray);
controller.index();
})();
// Leonardo Abreu de Paulo 2023