BetterOghma

A userscript to improve https://oghma.epcc.pt.

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 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);
});

})();