diff --git a/README.md b/README.md index 3a137ea..bb234b0 100644 --- a/README.md +++ b/README.md @@ -19,7 +19,7 @@ A program **felturbózza a Neptun-odat**: gyorsabb tárgy- és vizsgafelvétel, > Ez a fork egy work-in-progress, így nem fog minden tökéletesen működni. > Egyenlőre az implementált modulok a következőek az új Neptun felületén: > -> `autoLogin, addVersion, removeTodoBanner, infiniteSession` +> `autoLogin, addVersion, removeTodoBanner, infiniteSession, rememberDashboardWidgets` > > Az egyetlen tesztelt felület egyenlőre az [Óbudai Egyetem](https://neptun.uni-obuda.hu/ujhallgato/) új Neptun felülete. > Testers welcome! @@ -127,11 +127,17 @@ Eleged van abból, hogy minden egyes alkalommal be kell állítanod, hogy 500 el ## Újdonságok +#### 2025. május 11. + +- #### Angular + - **Újdonság:** Az új felület kezdőoldalán az NPU megjegyzi melyik widgeteket (Pl. Vizsgák, Közelgő események) nyitottad ki. + #### 2025. március 31. - #### Angular - **Újdonság:** Az új felületen mostantól nem dob ki a rendszer 5-10 perc után. 🎉 - **Javítva:** NPU nem töltött be, ha a kezdő URL nem tartalmazta a jelenlegi oldalt. (Pl. https://url/hallgato nem töltötte be az NPU-t) + #### 2025. március 27. - #### Angular diff --git a/eslint.config.mjs b/eslint.config.mjs index 9bed7ca..1174a8c 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -66,6 +66,7 @@ export default defineConfig([globalIgnores(["**/*.js", "**/*.mjs", "!src/**/*.js "one-var": ["error", "never"], "prefer-const": "error", "prefer-template": "error", + "semi": ["error", "always"], radix: "error", }, }]); diff --git a/src/angular/index.js b/src/angular/index.js index 73e73e6..ec0f636 100644 --- a/src/angular/index.js +++ b/src/angular/index.js @@ -7,6 +7,7 @@ const modules = [ require("./modules/addVersion"), require("./modules/removeTodoBanner"), require("./modules/infiniteSession"), + require("./modules/rememberDashboardWidgets"), ]; let loadedModules = []; diff --git a/src/angular/modules/rememberDashboardWidgets.js b/src/angular/modules/rememberDashboardWidgets.js new file mode 100644 index 0000000..8e6cdca --- /dev/null +++ b/src/angular/modules/rememberDashboardWidgets.js @@ -0,0 +1,104 @@ +const identifier = ["angular", "rememberDashboardWidgets"]; + +const $ = window.jQuery; +const utils = require("../utils"); +const storage = require("../../shared/storage"); + +let cachedWidgets = null; + +function isOnDashboard() { + const uri = utils.getCurrentPage().pathname.split("/"); + return uri[uri.length - 1] === "dashboard"; +} + +async function getWidgets() { + if (cachedWidgets) { + return cachedWidgets; + } + + return new Promise((resolve, reject) => { + function checkWidgets(attempts = 0) { + // Root elements of Upcoming events, Exams, Messages... + const widgetRoots = $(".widget"); + + // Areas of the widgets that + // - are clickable + // - have a child element who's text can be used for identification (widget__title class) + // - have a class that indicates if it is open or closed (mat-expanded) + const widgets = widgetRoots.find("mat-expansion-panel-header"); + + // In case the widgets were not loaded yet, try again later + if (widgets.length === 0) { + const maxAttempts = 100; + if (attempts === maxAttempts) { + reject(new Error("[rememberDashboardWidgets] failed to find widgets")); + return; + } + setTimeout(() => checkWidgets(attempts + 1), 50); + return; + } + + cachedWidgets = widgets; + resolve(widgets); + } + + checkWidgets(); + }); +} + +async function loadWidgetStates() { + const openWidgets = storage.getForUser("dashboardOpenWidgets"); + if (!openWidgets) { + return; + } + + const widgets = await getWidgets(); + openWidgets.forEach(widgetTitle => { + widgets.each(function() { + const titleElement = $(this).find(".widget__title"); + if (titleElement.text().trim() === widgetTitle) { + $(this).click(); + } + }); + }); + + console.debug("[rememberDashboardWidgets] loaded open widgets:", openWidgets); +} + +async function saveOpenWidgets() { + const widgets = await getWidgets(); + const openWidgets = widgets + .filter(function() { + return $(this).hasClass("mat-expanded"); + }) + .map(function() { + // Use the widget's title as an identifier because the widget's ID is unreliable + // As a downside remembered widgets will be forgotten when the user switches languages + return $(this).find(".widget__title").text().trim(); + }) + .get(); + + storage.setForUser("dashboardOpenWidgets", openWidgets); + console.debug("[rememberDashboardWidgets] saved open widgets:", openWidgets); +} + +async function init() { + await loadWidgetStates(); + const widgets = await getWidgets(); + widgets.on("click", saveOpenWidgets); +} + +async function destroy() { + const widgets = await getWidgets(); + widgets.off("click", saveOpenWidgets); + cachedWidgets = null; +} + +module.exports = { + identifier: identifier.join("."), + shouldActivate: isOnDashboard, + shouldNotDestroy: isOnDashboard, + initialize: init, + // Do actions before destroying + destroy, +};