// ==UserScript==
// @name BetterOghma
// @namespace Violentmonkey Scripts
// @description A userscript to improve https://oghma.epcc.pt.
// @match https://oghma.epcc.pt/*
// @version 2.0.0
// @author undefined
// @require https://cdn.jsdelivr.net/combine/npm/@violentmonkey/dom@2,npm/@violentmonkey/[email protected]
// @grant GM_addStyle
// ==/UserScript==
(function () {
'use strict';
const whiteSpaces = new RegExp(/\s/g);
const rmWhiteSpaces = str => str.toString().toLowerCase().replace(whiteSpaces, '');
function setItem(key, value) {
if (value == undefined) {
return;
}
const k = rmWhiteSpaces(key);
const v = rmWhiteSpaces(value);
localStorage.setItem(k, v);
}
function getItem(key, defaultValue) {
var _localStorage$getItem;
const k = rmWhiteSpaces(key);
return (_localStorage$getItem = localStorage.getItem(k)) != null ? _localStorage$getItem : defaultValue;
}
function checkItem(key, value) {
if (value == undefined) {
return false;
}
const k = rmWhiteSpaces(key);
const v = rmWhiteSpaces(value);
return localStorage.getItem(k) === v;
}
const hide = element => element.style.display = 'none';
const grid = element => element.style.display = 'grid';
const flex = element => element.style.display = 'flex';
function get(pattern, callback) {
const element = document.querySelector(pattern);
if (element === null) {
return;
}
callback(element);
}
function getAll(pattern, callback) {
const element = document.querySelectorAll(pattern);
for (const i of element) {
callback(i);
}
}
function getByClass(className, callback) {
const element = document.getElementsByClassName(className);
for (const i of element) {
callback(i);
}
}
function getByText(text, callback) {
const elements = document.getElementsByTagName('*');
for (const i of elements) {
if (i.textContent === text) {
callback(i);
}
}
}
const AVARAGE_DECIMAL_PARTS = 2;
setItem('DECREASE', getItem('DECREASE', 'true'));
function getAvarage(page) {
let avarage = 0;
let sumAll = 0;
let countAll = 0;
page.querySelectorAll('tr').forEach(tr => {
if (tr.className != 'header') {
var _tds$2$textContent, _tds$;
const tds = tr.querySelectorAll('td');
sumAll += parseInt((_tds$2$textContent = (_tds$ = tds[2]) == null ? void 0 : _tds$.textContent) != null ? _tds$2$textContent : '0', 10);
countAll++;
}
});
avarage = sumAll / countAll;
return avarage;
}
async function getAllSubjectsFromCourse(id) {
const couseURL = new URL(`https://oghma.epcc.pt/courses/${id}`);
const data = {
subjects: [],
ids: new Map(),
evaluations: new Map()
};
await fetch(couseURL).then(res => {
if (!res.ok) {
throw new Error( /* TODO */);
}
return res;
}).then(res => res.text()).then(html => {
const parser = new DOMParser();
const doc = parser.parseFromString(html, 'text/html');
const trs = doc.querySelectorAll('tbody > tr');
trs.forEach(tr => {
const td = tr.querySelector('td');
if (td === null) {
return;
}
const subject = td.querySelector('a');
if (subject === null) {
return;
}
let subjectTitle = subject.textContent;
if (subjectTitle === null) {
return;
}
if (subjectTitle.endsWith(' ')) {
subjectTitle = subjectTitle.trimEnd();
}
const subjectId = subject.href.split('/')[4];
if (subjectId === undefined) {
return;
}
data.ids.set(subjectTitle, subjectId);
data.subjects.push(subjectTitle);
});
});
return data;
}
async function getSubjectNyUsername(userName, subjects) {
const newSubjects = subjects;
for (const i of newSubjects.subjects) {
const subjectEvaluationsURL = `https://oghma.epcc.pt/units/${newSubjects.ids.get(i)}/evaluations`;
await fetch(subjectEvaluationsURL).then(async html => {
const parser = new DOMParser();
const doc = parser.parseFromString(await html.text(), 'text/html');
const trs = doc.querySelectorAll('tbody > tr');
trs.forEach(function (tr) {
const tds = tr.querySelectorAll('td');
if (tds.length > 0) {
var _tds$2, _tds$3;
const td1 = (_tds$2 = tds[1]) == null ? void 0 : _tds$2.textContent;
const td2 = (_tds$3 = tds[2]) == null ? void 0 : _tds$3.textContent;
if (td1 == undefined || td2 == undefined) {
return;
}
if (td1.replace(/\s/g, '').toLowerCase() === userName.replace(/\s/g, '').toLowerCase()) {
const evaluation = td2.split(' ')[0];
if (typeof evaluation === 'string') {
newSubjects.evaluations.set(i, evaluation);
}
}
}
});
});
}
return newSubjects;
}
const url = new URL(window.location.href);
const segments = url.pathname.split('/');
const page = segments.at(-1);
async function evaluations () {
if (!checkItem('lastUser', segments[4])) {
const itemToKeep = 'decrease';
for (let i = localStorage.length - 1; i >= 0; i--) {
const key = localStorage.key(i);
if (key != itemToKeep && key != undefined) {
localStorage.removeItem(key);
}
}
setItem('lastUser', segments[4]);
}
get('tbody', grid);
getAll('tr', grid);
getAll('tr', function (element) {
const sons = element.querySelectorAll(element.className == 'header' ? 'th' : 'td');
for (let i = 0; i < sons.length; i++) {
const son = sons[i];
if (son === undefined) {
continue;
}
flex(son);
if (element.className == 'header') {
element.style.order = '-21';
if (i == 0) {
son.style.gridColumn = 'span 2 / span 2';
}
if (i > 0) {
son.style.justifyContent = 'end';
}
if (i > 2) {
hide(son);
}
} else {
if (i > 1) {
son.style.justifyContent = 'end';
}
if (i == 2) {
element.style.order = (checkItem('DECREASE', 'true') ? '-' : '') + son.textContent;
}
if (i > 3) {
hide(son);
}
}
}
element.style.gridTemplateColumns = '3fr 5fr 1fr 1fr';
});
let subjects;
const coursesURL = 'https://oghma.epcc.pt/users/' + segments[4] + '/subscriptions';
let courseId = 0;
await fetch(coursesURL).then(async html => {
const parser = new DOMParser();
const doc = parser.parseFromString(await html.text(), 'text/html');
const tr = doc.querySelector('tbody > tr');
if (tr === null) {
return;
}
const anchor = tr.querySelector('td:nth(2) a');
if (anchor === null) {
return;
}
const id = anchor.href.split('/')[4];
if (id === undefined) {
return;
}
courseId = parseInt(id, 10);
});
if (!checkItem('allSubjectsSet', 'true')) {
var _document$getElements, _userh1$textContent;
const userh1 = (_document$getElements = document.getElementsByClassName('well clearfix')[0]) == null ? void 0 : _document$getElements.querySelector('h1');
if (userh1 == undefined) {
return;
}
const smallElement = userh1.querySelector('small');
if (smallElement === null) {
return;
}
const smallText = smallElement.textContent;
if (smallText === null) {
return;
}
const userName = (_userh1$textContent = userh1.textContent) == null ? void 0 : _userh1$textContent.substring(smallText.length);
if (userName === undefined) {
return;
}
subjects = await getAllSubjectsFromCourse(courseId.toString());
subjects = await getSubjectNyUsername(userName, subjects);
for (let i = 0; i < subjects.subjects.length; i++) {
const title = subjects.subjects[i];
if (title === undefined) {
continue;
}
setItem(title, getItem(title, subjects.evaluations.get(title)));
setItem(title + '_isActived', getItem(title + '_isActived', 'true'));
}
setItem('allSubjectsSet', 'true');
} else {
subjects = await getAllSubjectsFromCourse(courseId.toString());
subjects.evaluations = new Map();
subjects.subjects.forEach(function (title) {
const evaluation = getItem(title, '0');
if (typeof evaluation === 'string') {
subjects.evaluations.set(title, evaluation);
}
});
}
await getByClass('well clearfix', async function (element) {
let avarageSubjectSum = 0;
let subjectsCount = 0;
subjects.subjects.forEach(function (title) {
if (subjects.evaluations.get(title) != '' && checkItem(title + '_isActived', 'true')) {
subjectsCount++;
const evaluation = subjects.evaluations.get(title);
if (evaluation === undefined) {
return;
}
avarageSubjectSum += parseFloat(evaluation);
}
});
const avarage = (avarageSubjectSum / subjectsCount).toFixed(AVARAGE_DECIMAL_PARTS);
let averageElement = null;
if (document.getElementById('alunoAvarageText')) {
averageElement = document.getElementById('alunoAvarageText');
} else {
averageElement = document.createElement('p');
averageElement.id = 'alunoAvarageText';
}
if (averageElement === null) {
return;
}
averageElement.innerText = `O aluno tem uma média de ${avarage} pontos`;
if (!document.getElementById('alunoAvarageText')) {
element.appendChild(averageElement);
}
});
getByClass('span2 sidebar', function (element) {
if (document.getElementById('evaluationsCheckers')) return;
const div = document.createElement('div');
div.id = 'evaluationsCheckers';
div.style.paddingLeft = '0.8rem';
div.style.paddingRight = '0.8rem';
element.appendChild(div);
for (let i = 0; i < subjects.subjects.length; i++) {
const title = subjects.subjects[i];
const subjectElementDiv = document.createElement('div');
subjectElementDiv.style.display = 'flex';
subjectElementDiv.style.flexDirection = 'row';
subjectElementDiv.style.alignItems = 'center';
subjectElementDiv.style.justifyContent = 'start';
subjectElementDiv.style.padding = '0.25rem';
const subjectElementCheckbox = document.createElement('input');
subjectElementCheckbox.type = 'checkbox';
subjectElementCheckbox.id = title + '_checkbox';
if (checkItem(title + '_isActived', 'true')) {
subjectElementCheckbox.checked = true;
}
subjectElementCheckbox.onclick = function () {
setItem(title + '_isActived', checkItem(title + '_isActived', 'true') ? 'false' : 'true');
executeSite();
};
const subjectElementText = document.createElement('label');
subjectElementText.style.fontSize = '0.8rem';
subjectElementText.style.marginBottom = '0rem';
subjectElementText.style.userSelect = 'none';
subjectElementText.htmlFor = title + '_checkbox';
if (typeof title === 'string') {
subjectElementText.innerText = title === 'Tecnologias de Informação e Comunicação' ? 'TIC' : title;
}
subjectElementText.style.paddingLeft = '0.5rem';
const subjectAvarageScore = document.createElement('span');
if (typeof title === 'string') {
var _subjects$evaluations;
subjectAvarageScore.innerText = (_subjects$evaluations = subjects.evaluations.get(title)) != null ? _subjects$evaluations : NaN.toString();
}
subjectAvarageScore.style.paddingLeft = '0.5rem';
subjectElementDiv.appendChild(subjectElementCheckbox);
subjectElementDiv.appendChild(subjectElementText);
subjectElementDiv.appendChild(subjectAvarageScore);
div.appendChild(subjectElementDiv);
}
});
}
function subscriptions () {
getByClass('student active', function (element) {
element.querySelectorAll('a').forEach(function (a) {
a.href += '/evaluations';
});
});
getAll('.student:not(.active)', hide);
getByClass('users-list photo', flex);
getByClass('users-list photo', function (element) {
element.style.flexWrap = 'wrap';
});
let avarageSum = 0;
let totalStudents = 0;
getByClass('student active', async function (element) {
var _element$querySelecto;
const id = (_element$querySelecto = element.querySelector('a')) == null ? void 0 : _element$querySelecto.href.split('/')[4];
const 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');
const avarage = getAvarage(doc);
avarageSum += avarage;
totalStudents++;
element.style.order = (checkItem('DECREASE', 'true') ? '-' : '') + (avarage * 1000).toFixed(0);
const averageElement = document.createElement('p');
averageElement.textContent = 'Média de ' + avarage.toFixed(AVARAGE_DECIMAL_PARTS) + ' pontos';
element.appendChild(averageElement);
});
} else {
const totalAvarage = avarageSum / totalStudents;
const p = element.querySelector('p');
if (p === null) {
return;
}
p.textContent = `Média de ${totalAvarage.toFixed(AVARAGE_DECIMAL_PARTS)} pontos`;
element.style.order = (checkItem('DECREASE', 'true') ? '-' : '') + (totalAvarage * 1000).toFixed(0);
}
});
getByClass('users-list photo', function (element) {
const avarageStudent = document.createElement('li');
const imageA = document.createElement('a');
const image = document.createElement('img');
const br = document.createElement('br');
const span = document.createElement('span');
const a = document.createElement('a');
const 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);
});
}
const sites = new Map([['evaluations', evaluations], ['subscriptions', subscriptions]]);
const executeSite = () => {
if (typeof page === 'string') {
var _sites$get;
(_sites$get = sites.get(page)) == null ? void 0 : _sites$get();
}
};
getByText('Inscrições nos Exames', hide);
getByClass('events announcements', hide);
getByText('Importante!', hide);
executeSite();
getByClass('nav pull-right', element => {
flex(element);
element.style.alignItems = 'center';
const li = document.createElement('li');
const checkbox = document.createElement('input');
checkbox.type = 'checkbox';
if (checkItem('DECREASE', 'true')) checkbox.checked = true;
checkbox.onclick = function () {
setItem('DECREASE', checkItem('DECREASE', 'true') ? 'false' : 'true');
executeSite();
};
const text = document.createElement('span');
text.textContent = 'Ordem decrescente';
text.style.padding = '1rem';
li.style.display = 'flex';
li.appendChild(text);
li.appendChild(checkbox);
li.style.order = '-1';
element.appendChild(li);
});
})();