BetterOghma

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

K instalaci tototo skriptu si budete muset nainstalovat rozšíření jako Tampermonkey, Greasemonkey nebo Violentmonkey.

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

K instalaci tohoto skriptu si budete muset nainstalovat rozšíření jako Tampermonkey nebo Violentmonkey.

K instalaci tohoto skriptu si budete muset nainstalovat rozšíření jako Tampermonkey nebo Userscripts.

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

K instalaci tohoto skriptu si budete muset nainstalovat manažer uživatelských skriptů.

(Už mám manažer uživatelských skriptů, nechte mě ho nainstalovat!)

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

(Už mám manažer uživatelských stylů, nechte mě ho nainstalovat!)

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

})();