From daa35d45db5d9fb6f1dfbe4072e5b685d3760fcf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lu=C3=ADs=20Duarte?= Date: Tue, 9 Jan 2024 16:26:32 +0000 Subject: [PATCH 1/2] Add course enrollment id for each card --- content-scripts/src/pages/profile_page.js | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/content-scripts/src/pages/profile_page.js b/content-scripts/src/pages/profile_page.js index 79afa60..677598f 100644 --- a/content-scripts/src/pages/profile_page.js +++ b/content-scripts/src/pages/profile_page.js @@ -157,10 +157,17 @@ export const changeCourseCards = () => { if(detailsElement != null) { const url = detailsElement.querySelector('a').href; detailsElement.remove(); + const parsedUrlParams = new URLSearchParams(url.split('?')[1]) + let festId = parsedUrlParams.get('pv_fest_id') + if(festId === null){ + festId = new URLSearchParams(location.href.split('?')[1]).get('pv_fest_id') + + } const a = document.createElement('a'); a.classList = card.classList; a.classList.add("se-course-card-clickable"); + a.setAttribute('data-course-id', festId) if(active || hasCardSelected == false) a.classList.add('se-course-card-active') a.append(...card.children); From 16ad7ad3c1ef5b65e13cc0c1d0ba2697425c3528 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lu=C3=ADs=20Duarte?= Date: Tue, 9 Jan 2024 18:25:39 +0000 Subject: [PATCH 2/2] Add favorte course to redirect to it's details --- content-scripts/src/index.js | 9 +- .../src/modules/favorite-course.js | 129 ++++++++++++++++++ content-scripts/src/modules/layout.js | 12 +- content-scripts/src/pages/profile_page.js | 2 +- css/profilePage.css | 18 +++ 5 files changed, 162 insertions(+), 8 deletions(-) create mode 100644 content-scripts/src/modules/favorite-course.js diff --git a/content-scripts/src/index.js b/content-scripts/src/index.js index cd6572a..d294703 100644 --- a/content-scripts/src/index.js +++ b/content-scripts/src/index.js @@ -6,7 +6,7 @@ import { } from "./modules/initialize"; import { injectAllChanges, userPreferences } from "./modules/options/all"; import constructNewData from "./modules/utilities/constructNewData"; -import { getStorage } from "./modules/utilities/storage"; +import { getStorage, setStorage } from "./modules/utilities/storage"; import { rememberLogin } from "./modules/login"; import { replaceIcons } from "./modules/icons"; import { teacherPage } from "./pages/teacher_page"; @@ -16,6 +16,7 @@ import { changeCourseCards, changeProfileRow } from "./pages/profile_page"; import { courseUnitPage } from "./pages/course_unit_page"; import { fixPagination } from "./modules/pagination"; import { changeLayout } from "./modules/layout"; +import { addStarIconToCard } from "./modules/favorite-course"; /*-- - Docs: https://developer.chrome.com/docs/extensions/reference/storage/#synchronous-response-to-storage-updates @@ -47,16 +48,20 @@ const functionsToExecute = [ { name: "classPage", func: classPage }, { name: "courseUnitPage", func: courseUnitPage }, { name: "injectOverrideFunctions", func: injectOverrideFunctions }, + { name: "addStarIconToCard", func: addStarIconToCard} ] const init = async () => { // // Watch for resize events // addResizeListener(); - // // Inject user preferences const data = await getStorage(userPreferences); injectAllChanges(data); + + if(!(await getStorage('favorite_courses'))){ + await setStorage({'favorite_courses': '{}'}) //Insert empty object + } functionsToExecute.forEach(f => { try { diff --git a/content-scripts/src/modules/favorite-course.js b/content-scripts/src/modules/favorite-course.js new file mode 100644 index 0000000..1960b41 --- /dev/null +++ b/content-scripts/src/modules/favorite-course.js @@ -0,0 +1,129 @@ +import { getUP } from "./utilities/sigarra"; +import { getStorage, setStorage } from "./utilities/storage"; + +const pagesWithCourseCards = [ + "fest_geral.cursos_list", + "fest_geral.curso_percurso_academico_view", + "fest_geral.curso_posicao_plano_view", + "fest_geral.ucurr_inscricoes_list", + "fest_geral.estatutos_regimes_view", + "fest_geral.info_ingresso_view", + "fest_geral.info_pessoal_completa_view" +]; + +/** + * + * @param {Element[]} cards + * @param {string | undefined} favoriteCourse + */ +function rerenderStarIcons(cards, favoriteCourse) { + cards.forEach((val) => { + const enrollmentId = val.getAttribute('data-course-enrollment-id') + if(enrollmentId === null) { + throw Error('could not find enrollment id in card') + } + + let isFavoriteCourse = enrollmentId === favoriteCourse + const i = val.querySelector('.se-course-star') + i.classList = [] + + i.classList.add( + isFavoriteCourse ? 'ri-star-fill' : 'ri-star-line', + 'se-course-star' + ) + if(isFavoriteCourse) i.classList.add('se-favorite-course') + }) +} + +function changeProfileLink(favoriteCourses){ + const up = getUP().toString() + const favoriteCourse = favoriteCourses[up] + const profileLink = document.querySelector('.se-auth-profile') + if(favoriteCourse === undefined){ + profileLink.href = `fest_geral.cursos_list?pv_num_unico=${up}` + } else { + profileLink.href = `fest_geral.curso_percurso_academico_view?pv_fest_id=${favoriteCourse}` + } +} + +export async function favoriteCardListener(){ + const favoriteCourses = await getStorage('favorite_courses') + changeProfileLink(JSON.parse(favoriteCourses)) + chrome.storage.local.onChanged.addListener(async (changes) => { + if(!Object.keys(changes).includes('favorite_courses')){ + return + } + changeProfileLink(JSON.parse(changes['favorite_courses'].newValue)) + }) +} + +export async function addStarIconToCard() { + await favoriteCardListener(); + const hasProfileRow = pagesWithCourseCards + .map((value) => document.location.href.toLowerCase().includes(value)) + .reduce((prev, curr) => prev || curr); + + if (!hasProfileRow){ + return; + } + const up = getUP() + let favoriteCourses = JSON.parse(await getStorage('favorite_courses')) + let favoriteCourse = favoriteCourses[up.toString()] + const cards = document.querySelectorAll('.se-course-card') + + cards.forEach((val) => { + const titleBar = val.querySelector('.estudante-lista-curso-nome') + const enrollmentId = val.getAttribute('data-course-enrollment-id') + if(enrollmentId === null) { + throw Error('could not find enrollment id in card') + } + if(titleBar === null){ + throw Error('Could not find titlebar for the course card') + } + + let isFavoriteCourse = enrollmentId === favoriteCourse + const i = document.createElement('i') + i.classList.add( + isFavoriteCourse ? 'ri-star-fill' : 'ri-star-line', + 'se-course-star' + ) + if(isFavoriteCourse) i.classList.add('se-favorite-course') + + i.addEventListener('mouseenter', (_) => { + if(!isFavoriteCourse){ + i.classList.remove('ri-star-line') + i.classList.add('ri-star-fill') + } + }) + + i.addEventListener('mouseleave', (_) => { + if(!isFavoriteCourse){ + i.classList.remove('ri-star-fill') + i.classList.add('ri-star-line') + } + }) + + i.addEventListener('click', async (ev) => { + ev.preventDefault() + ev.stopPropagation() + + if(favoriteCourse === enrollmentId) { + delete favoriteCourses[up.toString()] + favoriteCourse = undefined + isFavoriteCourse = false + i.classList.remove('se-favorite-course') + } else { + favoriteCourses[up.toString()] = enrollmentId + favoriteCourse = enrollmentId + isFavoriteCourse = true + i.classList.add('se-favorite-course') + + } + await setStorage({'favorite_courses': JSON.stringify(favoriteCourses)}) + + rerenderStarIcons(cards, favoriteCourse) + }) + + titleBar.append(i) + }) +} \ No newline at end of file diff --git a/content-scripts/src/modules/layout.js b/content-scripts/src/modules/layout.js index fab38d6..9c03c73 100644 --- a/content-scripts/src/modules/layout.js +++ b/content-scripts/src/modules/layout.js @@ -58,7 +58,7 @@ const authentication = (auth) => ${auth.number}