BetterOghma

This is a userscript.

Dovrai installare un'estensione come Tampermonkey, Greasemonkey o Violentmonkey per installare questo script.

You will need to install an extension such as Tampermonkey to install this script.

Dovrai installare un'estensione come Tampermonkey o Violentmonkey per installare questo script.

Dovrai installare un'estensione come Tampermonkey o Userscripts per installare questo script.

Dovrai installare un'estensione come ad esempio Tampermonkey per installare questo script.

Dovrai installare un gestore di script utente per installare questo script.

(Ho già un gestore di script utente, lasciamelo installare!)

Dovrai installare un'estensione come ad esempio Stylus per installare questo stile.

Dovrai installare un'estensione come ad esempio Stylus per installare questo stile.

Dovrai installare un'estensione come ad esempio Stylus per installare questo stile.

Dovrai installare un'estensione per la gestione degli stili utente per installare questo stile.

Dovrai installare un'estensione per la gestione degli stili utente per installare questo stile.

Dovrai installare un'estensione per la gestione degli stili utente per installare questo stile.

(Ho già un gestore di stile utente, lasciamelo installare!)

// ==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