From 039c2be687cf25273be71603d13bd8edc8cef1a1 Mon Sep 17 00:00:00 2001 From: Freek Bes <36384333+FreekBes@users.noreply.github.com> Date: Sat, 26 Mar 2022 22:37:28 +0100 Subject: [PATCH 01/45] add todo list --- todo.txt | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 todo.txt diff --git a/todo.txt b/todo.txt new file mode 100644 index 0000000..649cd26 --- /dev/null +++ b/todo.txt @@ -0,0 +1,13 @@ +TODO: +- create backbone structure for local storage and syncing settings, with separate storage for incognito +- create themes folder and move all theme-related stuff in there +- create profile customization folder and move all profile customization stuff in there +- create improvements folder and move all improvements into there (maybe separate some improvements?) +- create way to report user customization features to the server +- create way to see user reports when logged in with an Intra staff account +- reorganize manifests +- split up Codam Monitoring System's cumulative hours and the actual thing into ft_logtime like feature and the previous actual thing +- more security background checks for the server back-end with the Intra API: store generated keys in a non-public database file +- implement more cluster maps, maybe even custom ones into the extension itself? + +DONE: From 79d38e813817d709ad6d014c5fc894551ff6b47b Mon Sep 17 00:00:00 2001 From: Freek Bes <36384333+FreekBes@users.noreply.github.com> Date: Sat, 26 Mar 2022 22:37:37 +0100 Subject: [PATCH 02/45] version bump --- manifest-ff.json | 2 +- manifest.json | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/manifest-ff.json b/manifest-ff.json index 00b5206..17d538c 100644 --- a/manifest-ff.json +++ b/manifest-ff.json @@ -2,7 +2,7 @@ "manifest_version": 2, "name": "__MSG_appName__", "short_name": "__MSG_shortAppName__", - "version": "2.7.0", + "version": "3.0.0", "description": "__MSG_appDesc__", "default_locale": "en", "icons": { diff --git a/manifest.json b/manifest.json index ab05a8a..41d5341 100644 --- a/manifest.json +++ b/manifest.json @@ -2,8 +2,8 @@ "manifest_version": 3, "name": "__MSG_appName__", "short_name": "__MSG_shortAppName__", - "version": "2.7.0", - "version_name": "2.7.0", + "version": "3.0.0", + "version_name": "3.0.0", "description": "__MSG_appDesc__", "default_locale": "en", "icons": { From 0d9d0a909b6f183239704ee50aacfcaf8fb6db1c Mon Sep 17 00:00:00 2001 From: Freek Bes <36384333+FreekBes@users.noreply.github.com> Date: Sat, 26 Mar 2022 23:05:13 +0100 Subject: [PATCH 03/45] add minimum required browser versions based on caniuse.com let and const --- manifest-ff.json | 3 ++- manifest.json | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/manifest-ff.json b/manifest-ff.json index 17d538c..402a4d0 100644 --- a/manifest-ff.json +++ b/manifest-ff.json @@ -18,7 +18,8 @@ "incognito": "not_allowed", "browser_specific_settings": { "gecko": { - "update_url": "https://raw.githubusercontent.com/FreekBes/improved_intra/main/updates.json" + "update_url": "https://raw.githubusercontent.com/FreekBes/improved_intra/main/updates.json", + "strict_min_version": "44" } }, "options_ui": { diff --git a/manifest.json b/manifest.json index 41d5341..54cd4a9 100644 --- a/manifest.json +++ b/manifest.json @@ -1,5 +1,6 @@ { "manifest_version": 3, + "minimum_chrome_version": "49", "name": "__MSG_appName__", "short_name": "__MSG_shortAppName__", "version": "3.0.0", From fff9ef8f8a33b8fcda246aeb44649cf7ada1602d Mon Sep 17 00:00:00 2001 From: Freek Bes <36384333+FreekBes@users.noreply.github.com> Date: Sat, 26 Mar 2022 23:16:59 +0100 Subject: [PATCH 04/45] add intellisense for chrome extensions --- jsconfig.json | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 jsconfig.json diff --git a/jsconfig.json b/jsconfig.json new file mode 100644 index 0000000..06ea283 --- /dev/null +++ b/jsconfig.json @@ -0,0 +1,5 @@ +{ + "typeAcquisition": { + "include": [ "chrome" ] + } +} From 03ba476e64125747fff72efd9bdb176893b43889 Mon Sep 17 00:00:00 2001 From: Freek Bes <36384333+FreekBes@users.noreply.github.com> Date: Sat, 26 Mar 2022 23:54:45 +0100 Subject: [PATCH 05/45] not done, but important push before splitting up background.js --- background.js | 274 +++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 216 insertions(+), 58 deletions(-) diff --git a/background.js b/background.js index 6f0bba7..e0800bd 100644 --- a/background.js +++ b/background.js @@ -10,6 +10,220 @@ /* */ /* ************************************************************************** */ +// sadly this file cannot be split up right now, because Firefox doesn't currently +// support service workers as background scripts yet, so we cannot use the importScripts +// functionality. Everything in this file is split up by comments instead. +// Once Firefox implements service workers, everything should be easily split-uppable. + + +// GENERAL_BACKGROUND_JS /////////////////////////////////////////////////////// + +// (keep everything in this section on split-up) +chrome.runtime.onInstalled.addListener(function(details) { + if (details.reason == "install") { + console.log("First install."); + // setSettingsIfUnset(); + // fetchUserSettings(); + } + else if (details.reason == "update") { + console.log("An update has been installed. Run getSettingsFromSyncServer(username) to force synchronization with the sync server."); + // removeUnusedSettings(); + // setSettingsIfUnset(); + } +}); + +// END GENERAL_BACKGROUND_JS /////////////////////////////////////////////////// + + + + + +// START STORAGE /////////////////////////////////////////////////////////////// + +/* +To start, there's three storages: +- a shared one, for generic usage +- a normal one, where user session storage can be stored +- an incognito one, where user session storage from the incognito browser can be stored +Each storage is separated by STORAGETYPE_ in front of the key originally used for the storage. +EXAMPLE: if one were to fetch something with the key "test"; use "SHARED_test", "NORMAL_test", "INCOGNITO_test" instead. + +The reason behind this is because storage is actually always shared between normal and incognito mode... +Which is not useful in our case, where we often use storage to synchronize settings based on the user who's currently +signed in to intra.42.fr. This can of course differ between normal and incognito mode +as cookies (and thus sessions) are NOT shared between these modes! +*/ + +// helper function to prepare keys for storage use +function prepareStorageKeys(type, keys) { + if (typeof keys == "string") { + keys = [keys]; + } + for (let i = 0; i < keys.length; i++) { + keys[i] = type.toUpperCase() + "-" + keys[i]; + } + return (keys); +} + +// helper function to sanitize storage returned data +function sanitizeStorageData(orig_keys, internal_keys, data) { + const newData = {}; + + for (let i = 0; i < internal_keys.length; i++) { + newData[orig_keys[i]] = data[internal_keys[i]]; + } + return (newData); +} + +// get something from storage by type +function getStorage(type, keys) { + return new Promise(function (resolve) { + const internal_keys = prepareStorageKeys(type, keys); + chrome.storage.local.get(keys, function(data) { + resolve(sanitizeStorageData(keys, internal_keys, data)); + }); + }); +} + +// wrapper for getStorage("shared", keys); +function getSharedStorage(keys) { + return (getStorage("shared", keys)); +} + +// wrapper for getStorage("incognito", keys); +function getIncognitoStorage(keys) { + return (getStorage("incognito", keys)); +} + +// wrapper for getStorage("normal", keys); +function getNormalStorage(keys) { + return (getStorage("normal", keys)); +} + +// END STORAGE ///////////////////////////////////////////////////////////////// + + + + + + +// START COMMUNICATION_SERVICE ///////////////////////////////////////////////// + +const incognitoPortName = "incog_comm"; +const normalPorts = []; +const incognitoPorts = []; + +// message only ports in non-incognito context +function messageNormalPorts(msg) { + for (let i = 0; i < ports.length; i++) { + normalPorts[i].postMessage(msg); + } +} + +// message only ports in incognito context +function messageIncognitoPorts(msg) { + for (let i = 0; i < ports.length; i++) { + incognitoPorts[i].postMessage(msg); + } +} + +// message all ports +function messageAllPorts(msg) { + messageNormalPorts(msg); + messageIncognitoPorts(msg); +} + +// detect if port is incognito or not +function isIncognitoPort(port) { + return (port.name == incognitoPortName); +} + +// resync function +function resync(port, incognitoSession) { + const storageType = (incognitoSession ? "incognito" : "normal"); + + getStorage(storageType, "username").then(function(data) { + if (data["username"]) { + getSettingsFromSyncServer(storageType, data["username"]) + .then(function() { + console.log("Settings successfully retrieved from server. Stored a copy locally."); + if (incognitoSession) { + messageIncognitoPorts({ action: "resynced" }); + } + else { + messageNormalPorts({ action: "resynced" }); + } + }) + .catch(function(err) { + resetSettings().then(function() { + if (incognitoSession) { + messageIncognitoPorts({ action: "resynced" }); + } + else { + messageNormalPorts({ action: "resynced" }); + } + }); + }); + } + else { + console.warn("Could not resync, as no username was given to sync from"); + } + }); +} + +// port message listener +function portMessageListener(msg, port) { + switch(msg["action"]) { + case "ping": + port.postMessage({ action: "pong" }); + break; + case "resync": + resync(port, isIncognitoPort(port)); + break; + case "options-changed": + messageAllPorts({ action: "options-changed", settings: msg["settings"] }); + break; + default: + console.log("Unknown action received over port: ", msg["action"]); + break; + } +} + +chrome.runtime.onConnect.addListener(function(port) { + // add port to array of ports depending on the name + if (port.name == incognitoPortName) { + incognitoPorts.push(port); + } + else { + normalPorts.push(port); + } + + // remove port from array of ports on closure + port.onDisconnect.addListener(function(port) { + const normalIndex = normalPorts.indexOf(port); + const incognitoIndex = incognitoPorts.indexOf(port); + + if (incognitoIndex > -1) { + incognitoPorts.splice(incognitoIndex, 1); + } + else if (normalIndex > -1) { + normalPorts.splice(normalIndex, 1); + } + }); + + // run specific functions on specific messages + // basically treating messages as commands + port.onMessage.addListener(portMessageListener); +}); + +// END COMMUNICATION_SERVICE /////////////////////////////////////////////////// + + + + + +// START OLD_BACKGROUND_JS ///////////////////////////////////////////////////// + var defaultSettings = { "clustermap": "true", "codam-auto-equip-coa-title": "false", @@ -101,7 +315,7 @@ function setSettingsIfUnset() { }); } -function getSettingsFromSyncServer(username) { +function getSettingsFromSyncServer(storageType, username) { return new Promise(function(resolve, reject) { console.log("Retrieving settings of username " + username); fetch("https://darkintra.freekb.es/settings/" + username + ".json?noCache=" + Math.random()) @@ -131,51 +345,6 @@ function getSettingsFromSyncServer(username) { }); } -var ports = []; -function messageAllPorts(msg) { - for (var i = 0; i < ports.length; i++) { - ports[i].postMessage(msg); - } -} -chrome.runtime.onConnect.addListener(function(port) { - ports.push(port); - port.onDisconnect.addListener(function(port) { - ports.splice(ports.indexOf(port), 1); - }); - port.onMessage.addListener(function(msg) { - switch(msg["action"]) { - case "ping": - port.postMessage({ action: "pong" }); - break; - case "resync": - chrome.storage.local.get("username", function(data) { - if (data["username"]) { - getSettingsFromSyncServer(data["username"]) - .then(function() { - console.log("Settings successfully retrieved from server. Stored a copy locally."); - messageAllPorts({ action: "resynced" }); - }) - .catch(function(err) { - resetSettings().then(function() { - messageAllPorts({ action: "resynced" }); - }); - }); - } - else { - console.warn("Could not resync, as no username was given to sync from"); - } - }); - break; - case "options-changed": - messageAllPorts({ action: "options-changed", settings: msg["settings"] }); - break; - default: - console.log("Unknown action received over port: ", msg["action"]); - break; - } - }); -}); - function fetchUserSettings() { tryFetchIntraUsername() .then(getSettingsFromSyncServer) @@ -187,15 +356,4 @@ function fetchUserSettings() { }); } -chrome.runtime.onInstalled.addListener(function(details) { - if (details.reason == "install") { - console.log("First install."); - setSettingsIfUnset(); - fetchUserSettings(); - } - else if (details.reason == "update") { - console.log("An update has been installed. Run getSettingsFromSyncServer(username) to force synchronization with the sync server."); - removeUnusedSettings(); - setSettingsIfUnset(); - } -}); +// END OLD_BACKGROUND_JS /////////////////////////////////////////////////////// From 0352b95dc6dda312560963be87ccee748650e0f2 Mon Sep 17 00:00:00 2001 From: Freek Bes <36384333+FreekBes@users.noreply.github.com> Date: Sun, 27 Mar 2022 00:09:10 +0100 Subject: [PATCH 06/45] add to todo list --- todo.txt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/todo.txt b/todo.txt index 649cd26..f8b10f5 100644 --- a/todo.txt +++ b/todo.txt @@ -1,4 +1,8 @@ +USEFUL: +Manifest v3 options overview: https://developer.chrome.com/docs/extensions/mv3/manifest/ + TODO: +- convert every var to either const or let - create backbone structure for local storage and syncing settings, with separate storage for incognito - create themes folder and move all theme-related stuff in there - create profile customization folder and move all profile customization stuff in there From f8d51c5dfa0fd925da42b3fc83a393ce2a6aa3ed Mon Sep 17 00:00:00 2001 From: Freek Bes <36384333+FreekBes@users.noreply.github.com> Date: Sun, 27 Mar 2022 00:07:12 +0100 Subject: [PATCH 07/45] split up background script --- background.js | 359 ------------------------------------------ background/comm.js | 123 +++++++++++++++ background/main.js | 29 ++++ background/options.js | 148 +++++++++++++++++ background/storage.js | 122 ++++++++++++++ build.sh | 8 +- manifest-ff.json | 9 +- manifest.json | 4 +- sw.js | 28 ++++ todo.txt | 2 +- 10 files changed, 464 insertions(+), 368 deletions(-) delete mode 100644 background.js create mode 100644 background/comm.js create mode 100644 background/main.js create mode 100644 background/options.js create mode 100644 background/storage.js create mode 100644 sw.js diff --git a/background.js b/background.js deleted file mode 100644 index e0800bd..0000000 --- a/background.js +++ /dev/null @@ -1,359 +0,0 @@ -/* ************************************************************************** */ -/* */ -/* :::::::: */ -/* background.js :+: :+: */ -/* +:+ */ -/* By: fbes +#+ */ -/* +#+ */ -/* Created: 2021/11/27 23:25:07 by fbes #+# #+# */ -/* Updated: 2022/03/24 21:19:37 by fbes ######## odam.nl */ -/* */ -/* ************************************************************************** */ - -// sadly this file cannot be split up right now, because Firefox doesn't currently -// support service workers as background scripts yet, so we cannot use the importScripts -// functionality. Everything in this file is split up by comments instead. -// Once Firefox implements service workers, everything should be easily split-uppable. - - -// GENERAL_BACKGROUND_JS /////////////////////////////////////////////////////// - -// (keep everything in this section on split-up) -chrome.runtime.onInstalled.addListener(function(details) { - if (details.reason == "install") { - console.log("First install."); - // setSettingsIfUnset(); - // fetchUserSettings(); - } - else if (details.reason == "update") { - console.log("An update has been installed. Run getSettingsFromSyncServer(username) to force synchronization with the sync server."); - // removeUnusedSettings(); - // setSettingsIfUnset(); - } -}); - -// END GENERAL_BACKGROUND_JS /////////////////////////////////////////////////// - - - - - -// START STORAGE /////////////////////////////////////////////////////////////// - -/* -To start, there's three storages: -- a shared one, for generic usage -- a normal one, where user session storage can be stored -- an incognito one, where user session storage from the incognito browser can be stored -Each storage is separated by STORAGETYPE_ in front of the key originally used for the storage. -EXAMPLE: if one were to fetch something with the key "test"; use "SHARED_test", "NORMAL_test", "INCOGNITO_test" instead. - -The reason behind this is because storage is actually always shared between normal and incognito mode... -Which is not useful in our case, where we often use storage to synchronize settings based on the user who's currently -signed in to intra.42.fr. This can of course differ between normal and incognito mode -as cookies (and thus sessions) are NOT shared between these modes! -*/ - -// helper function to prepare keys for storage use -function prepareStorageKeys(type, keys) { - if (typeof keys == "string") { - keys = [keys]; - } - for (let i = 0; i < keys.length; i++) { - keys[i] = type.toUpperCase() + "-" + keys[i]; - } - return (keys); -} - -// helper function to sanitize storage returned data -function sanitizeStorageData(orig_keys, internal_keys, data) { - const newData = {}; - - for (let i = 0; i < internal_keys.length; i++) { - newData[orig_keys[i]] = data[internal_keys[i]]; - } - return (newData); -} - -// get something from storage by type -function getStorage(type, keys) { - return new Promise(function (resolve) { - const internal_keys = prepareStorageKeys(type, keys); - chrome.storage.local.get(keys, function(data) { - resolve(sanitizeStorageData(keys, internal_keys, data)); - }); - }); -} - -// wrapper for getStorage("shared", keys); -function getSharedStorage(keys) { - return (getStorage("shared", keys)); -} - -// wrapper for getStorage("incognito", keys); -function getIncognitoStorage(keys) { - return (getStorage("incognito", keys)); -} - -// wrapper for getStorage("normal", keys); -function getNormalStorage(keys) { - return (getStorage("normal", keys)); -} - -// END STORAGE ///////////////////////////////////////////////////////////////// - - - - - - -// START COMMUNICATION_SERVICE ///////////////////////////////////////////////// - -const incognitoPortName = "incog_comm"; -const normalPorts = []; -const incognitoPorts = []; - -// message only ports in non-incognito context -function messageNormalPorts(msg) { - for (let i = 0; i < ports.length; i++) { - normalPorts[i].postMessage(msg); - } -} - -// message only ports in incognito context -function messageIncognitoPorts(msg) { - for (let i = 0; i < ports.length; i++) { - incognitoPorts[i].postMessage(msg); - } -} - -// message all ports -function messageAllPorts(msg) { - messageNormalPorts(msg); - messageIncognitoPorts(msg); -} - -// detect if port is incognito or not -function isIncognitoPort(port) { - return (port.name == incognitoPortName); -} - -// resync function -function resync(port, incognitoSession) { - const storageType = (incognitoSession ? "incognito" : "normal"); - - getStorage(storageType, "username").then(function(data) { - if (data["username"]) { - getSettingsFromSyncServer(storageType, data["username"]) - .then(function() { - console.log("Settings successfully retrieved from server. Stored a copy locally."); - if (incognitoSession) { - messageIncognitoPorts({ action: "resynced" }); - } - else { - messageNormalPorts({ action: "resynced" }); - } - }) - .catch(function(err) { - resetSettings().then(function() { - if (incognitoSession) { - messageIncognitoPorts({ action: "resynced" }); - } - else { - messageNormalPorts({ action: "resynced" }); - } - }); - }); - } - else { - console.warn("Could not resync, as no username was given to sync from"); - } - }); -} - -// port message listener -function portMessageListener(msg, port) { - switch(msg["action"]) { - case "ping": - port.postMessage({ action: "pong" }); - break; - case "resync": - resync(port, isIncognitoPort(port)); - break; - case "options-changed": - messageAllPorts({ action: "options-changed", settings: msg["settings"] }); - break; - default: - console.log("Unknown action received over port: ", msg["action"]); - break; - } -} - -chrome.runtime.onConnect.addListener(function(port) { - // add port to array of ports depending on the name - if (port.name == incognitoPortName) { - incognitoPorts.push(port); - } - else { - normalPorts.push(port); - } - - // remove port from array of ports on closure - port.onDisconnect.addListener(function(port) { - const normalIndex = normalPorts.indexOf(port); - const incognitoIndex = incognitoPorts.indexOf(port); - - if (incognitoIndex > -1) { - incognitoPorts.splice(incognitoIndex, 1); - } - else if (normalIndex > -1) { - normalPorts.splice(normalIndex, 1); - } - }); - - // run specific functions on specific messages - // basically treating messages as commands - port.onMessage.addListener(portMessageListener); -}); - -// END COMMUNICATION_SERVICE /////////////////////////////////////////////////// - - - - - -// START OLD_BACKGROUND_JS ///////////////////////////////////////////////////// - -var defaultSettings = { - "clustermap": "true", - "codam-auto-equip-coa-title": "false", - "codam-monit": "true", - "colors": "default", - "custom-banner-url": "", - "custom-banner-pos": "center-center", - "hide-broadcasts": "false", - "hide-goals": "false", - "link-github": "", - "old-blackhole": "false", - "show-custom-profiles": "true", - "sync": "true", - "theme": "system" -}; - -function tryFetchIntraUsername() { - return new Promise(function (resolve, reject) { - fetch("https://meta.intra.42.fr/") - .then(function(response) { - if (!response.ok) { - throw new Error("HTTP Response is not OK: " + response.status); - } - if (response.url.indexOf("//signin.") > -1) { - throw new Error("Not signed in on Intra, cannot fetch username"); - } - return response.text(); - }) - .then(function(body) { - var _userIndex = body.indexOf("this._user"); - var _consumerAddress = body.indexOf("this._consumer_address"); - console.log("Now trying to parse username from meta.intra.42.fr..."); - if (_userIndex > -1) { - var toParse = body.substring(_userIndex, _consumerAddress); - console.log(toParse); - var startOfObj = toParse.indexOf("{"); - var endOfObj = toParse.indexOf("}"); - if (startOfObj < -1) { - reject("Could not find start of _user object"); - } - toParse = toParse.substring(startOfObj, endOfObj + 1); - console.log(toParse); - var jsonUser = JSON.parse(toParse); - if ("login" in jsonUser) { - console.log("Hooray, found logged in user! Hello, " + jsonUser["login"] + "!"); - chrome.storage.local.set({username: jsonUser["login"]}, function() { - console.log("Set username in local storage"); - resolve(jsonUser["login"]); - }); - } - else { - reject("Could not parse username from Intranet website (username not in _user object)"); - } - } - else { - reject("Could not parse username from Intranet website (_user object not found)"); - } - }) - .catch(function(err) { - reject(err); - }); - }); -} - -function removeUnusedSettings() { - var noLongerUsedSettings = []; - - if (noLongerUsedSettings.length > 0) { - chrome.storage.local.remove(noLongerUsedSettings, function() { - console.log("Removed no longer used settings"); - }); - } -} - -function resetSettings() { - return (chrome.storage.local.set(defaultSettings)); -} - -function setSettingsIfUnset() { - // get set settings - chrome.storage.local.get(Object.keys(defaultSettings), function(data) { - for (var key in defaultSettings) { - if (data[key] === undefined) { - chrome.storage.local.set({[key]: defaultSettings[key]}, function() { - console.log("Setting created in local storage"); - }); - } - } - }); -} - -function getSettingsFromSyncServer(storageType, username) { - return new Promise(function(resolve, reject) { - console.log("Retrieving settings of username " + username); - fetch("https://darkintra.freekb.es/settings/" + username + ".json?noCache=" + Math.random()) - .then(function(response) { - if (response.status == 404) { - console.log("No settings found on the sync server for this username"); - return null; - } - else if (!response.ok) { - throw new Error("Could not fetch settings from server due to an error"); - } - return response.json(); - }) - .then(function(json) { - if (json == null) { - reject(); - } - else { - chrome.storage.local.set(json, function() { - resolve(json); - }); - } - }) - .catch(function(err) { - reject(err); - }); - }); -} - -function fetchUserSettings() { - tryFetchIntraUsername() - .then(getSettingsFromSyncServer) - .then(function(settings) { - messageAllPorts({ action: "options-changed", settings: settings }); - }) - .catch(function(err) { - console.error("Could not parse username and synchronize settings", err); - }); -} - -// END OLD_BACKGROUND_JS /////////////////////////////////////////////////////// diff --git a/background/comm.js b/background/comm.js new file mode 100644 index 0000000..24836e6 --- /dev/null +++ b/background/comm.js @@ -0,0 +1,123 @@ +/* ************************************************************************** */ +/* */ +/* :::::::: */ +/* comm.js :+: :+: */ +/* +:+ */ +/* By: fbes +#+ */ +/* +#+ */ +/* Created: 2022/03/26 23:57:53 by fbes #+# #+# */ +/* Updated: 2022/03/26 23:57:53 by fbes ######## odam.nl */ +/* */ +/* ************************************************************************** */ + +const incognitoPortName = "incog_comm"; +const normalPorts = []; +const incognitoPorts = []; + +// message only ports in non-incognito context +function messageNormalPorts(msg) { + for (let i = 0; i < normalPorts.length; i++) { + normalPorts[i].postMessage(msg); + } +} + +// message only ports in incognito context +function messageIncognitoPorts(msg) { + for (let i = 0; i < incognitoPorts.length; i++) { + incognitoPorts[i].postMessage(msg); + } +} + +// message all ports +function messageAllPorts(msg) { + messageNormalPorts(msg); + messageIncognitoPorts(msg); +} + +// message ports of specified type +function messagePortsOfType(type, msg) { + if (type == "incognito") { + messageIncognitoPorts(msg); + } + else { + messageNormalPorts(msg); + } +} + +// detect if port is incognito or not +function isIncognitoPort(port) { + return (port.name == incognitoPortName); +} + +// resync on port message function +function resyncOnPortMessage(incognitoSession) { + const type = (incognitoSession ? "incognito" : "normal"); + + getStorage(type, "username").then(function(data) { + if (data["username"]) { + getSettingsFromSyncServer(type, data["username"]) + .then(function() { + console.log("Settings successfully retrieved from server. Stored a copy locally."); + messagePortsOfType(type, { action: "resynced" }); + }) + .catch(function(err) { + resetSettings().then(function() { + messagePortsOfType(type, { action: "resynced" }); + }); + }); + } + else { + console.warn("Could not resync, as no username was given to sync from"); + } + }); +} + +// port message listener +function portMessageListener(msg, port) { + switch(msg["action"]) { + case "ping": + port.postMessage({ action: "pong" }); + break; + case "resync": + resyncOnPortMessage(isIncognitoPort(port)); + break; + case "options-changed": + if (isIncognitoPort(port)) { + messageIncognitoPorts({ action: "options-changed", settings: msg["settings"] }); + } + else { + messageNormalPorts({ action: "options-changed", settings: msg["settings"] }) + } + break; + default: + console.log("Unknown action received over port: ", msg["action"]); + break; + } +} + +chrome.runtime.onConnect.addListener(function(port) { + // add port to array of ports depending on the name + if (port.name == incognitoPortName) { + incognitoPorts.push(port); + } + else { + normalPorts.push(port); + } + + // remove port from array of ports on closure + port.onDisconnect.addListener(function(port) { + const normalIndex = normalPorts.indexOf(port); + const incognitoIndex = incognitoPorts.indexOf(port); + + if (incognitoIndex > -1) { + incognitoPorts.splice(incognitoIndex, 1); + } + else if (normalIndex > -1) { + normalPorts.splice(normalIndex, 1); + } + }); + + // run specific functions on specific messages + // basically treating messages as commands + port.onMessage.addListener(portMessageListener); +}); diff --git a/background/main.js b/background/main.js new file mode 100644 index 0000000..35c7f1d --- /dev/null +++ b/background/main.js @@ -0,0 +1,29 @@ +/* ************************************************************************** */ +/* */ +/* :::::::: */ +/* main.js :+: :+: */ +/* +:+ */ +/* By: fbes +#+ */ +/* +#+ */ +/* Created: 2022/03/26 23:54:09 by fbes #+# #+# */ +/* Updated: 2022/03/26 23:54:09 by fbes ######## odam.nl */ +/* */ +/* ************************************************************************** */ + +function resyncOptions() { + setOptionsIfUnset(normalStorage); + setOptionsIfUnset(incognitoStorage); + fetchUserSettings(normalStorage); +} + +chrome.runtime.onInstalled.addListener(function(details) { + if (details.reason == "install") { + console.log("First install."); + resyncOptions(); + } + else if (details.reason == "update") { + console.log("An update has been installed."); + removeUnusedOptions(); + resyncOptions(); + } +}); diff --git a/background/options.js b/background/options.js new file mode 100644 index 0000000..5734d7e --- /dev/null +++ b/background/options.js @@ -0,0 +1,148 @@ +/* ************************************************************************** */ +/* */ +/* :::::::: */ +/* options.js :+: :+: */ +/* +:+ */ +/* By: fbes +#+ */ +/* +#+ */ +/* Created: 2022/03/27 00:13:45 by fbes #+# #+# */ +/* Updated: 2022/03/27 00:13:45 by fbes ######## odam.nl */ +/* */ +/* ************************************************************************** */ + +const defaults = { + "clustermap": "true", + "codam-auto-equip-coa-title": "false", + "codam-monit": "true", + "colors": "default", + "custom-banner-url": "", + "custom-banner-pos": "center-center", + "hide-broadcasts": "false", + "hide-goals": "false", + "link-github": "", + "old-blackhole": "false", + "show-custom-profiles": "true", + "sync": "true", + "theme": "system" +}; + +const noLongerUsedOptions = []; + +function tryFetchIntraUsername(improvedStorage) { + return new Promise(function (resolve, reject) { + fetch("https://meta.intra.42.fr/") + .then(function(response) { + if (!response.ok) { + reject("HTTP Response is not OK: " + response.status); + } + if (response.url.indexOf("//signin.") > -1) { + reject("Not signed in on Intra, cannot fetch username"); + } + return response.text(); + }) + .then(function(metaBody) { + const _userIndex = metaBody.indexOf("this._user"); + const _consumerAddress = metaBody.indexOf("this._consumer_address"); + console.log("Now trying to parse username from meta.intra.42.fr..."); + if (_userIndex > -1) { + let toParse = metaBody.substring(_userIndex, _consumerAddress); + console.log(toParse); + const startOfObj = toParse.indexOf("{"); + const endOfObj = toParse.indexOf("}"); + if (startOfObj < -1) { + reject("Could not find start of _user object"); + } + toParse = toParse.substring(startOfObj, endOfObj + 1); + console.log(toParse); + const jsonUser = JSON.parse(toParse); + if ("login" in jsonUser) { + console.log("Hooray, found logged in user! Hello, " + jsonUser["login"] + "!"); + improvedStorage.set({username: jsonUser["login"]}).then(function() { + console.log("Set username in " + improvedStorage.getType() + " storage"); + resolve(jsonUser["login"]); + }); + } + else { + reject("Could not parse username from Intranet website (username not in _user object)"); + } + } + else { + reject("Could not parse username from Intranet website (_user object not found)"); + } + }) + .catch(function(err) { + reject(err); + }); + }); +} + +function removeUnusedOptions() { + if (noLongerUsedOptions.length > 0) { + normalStorage.remove(noLongerUsedOptions).then(function() { + console.log("Removed no longer used options from normal storage"); + }); + incognitoStorage.remove(noLongerUsedOptions).then(function() { + console.log("Removed no longer used options from incognito storage"); + }); + } +} + +function resetOptions(improvedStorage) { + return (improvedStorage.set(defaults)); +} + +function setOptionsIfUnset(improvedStorage) { + // get set options and only set them if they seem to not be set (equal to undefined) + improvedStorage.get(Object.keys(defaults), function(data) { + for (const key in defaults) { + if (data[key] === undefined) { + improvedStorage.set({[key]: defaults[key]}, function() { + console.log("Default setting with key " + key + " created in " + improvedStorage.getType() + " storage (value: " + defaults[key] + ")"); + }); + } + } + }); +} + +function getSettingsFromSyncServer(storageType, username) { + return new Promise(function(resolve, reject) { + console.log("Retrieving settings of username " + username); + fetch("https://darkintra.freekb.es/settings/" + username + ".json?noCache=" + Math.random()) + .then(function(response) { + if (response.status == 404) { + reject("No settings found on the sync server for this username"); + return (null); + } + else if (!response.ok) { + reject("Could not fetch settings from server due to an error"); + return (null); + } + return (response.json()); + }) + .then(function(json) { + if (json != null) { + storageType.set(json, function() { + resolve(json); + }); + } + }) + .catch(function(err) { + reject(err); + }); + }); +} + +function fetchUserSettings(improvedStorage) { + const storageType = improvedStorage.getType(); + + tryFetchIntraUsername(improvedStorage) + .then(function(username) { + getSettingsFromSyncServer(improvedStorage, username); + }) + .then(function(settings) { + messagePortsOfType(storageType, { action: "options-changed", settings: settings }); + }) + .catch(function(err) { + console.error("Could not parse username and synchronize settings", err); + }); +} diff --git a/background/storage.js b/background/storage.js new file mode 100644 index 0000000..e21d4d3 --- /dev/null +++ b/background/storage.js @@ -0,0 +1,122 @@ +/* ************************************************************************** */ +/* */ +/* :::::::: */ +/* storage.js :+: :+: */ +/* +:+ */ +/* By: fbes +#+ */ +/* +#+ */ +/* Created: 2022/03/26 23:55:04 by fbes #+# #+# */ +/* Updated: 2022/03/26 23:55:04 by fbes ######## odam.nl */ +/* */ +/* ************************************************************************** */ + +/* +WARNING! THIS SCRIPT RUNS BOTH IN THE BACKGROUND AS A SERVICE WORKER AND +IN THE FOREGROUND AS A CONTENT SCRIPT, AS IT IS INTENDED AS A WRAPPER FOR STORAGE FUNCTION UTILITIES. +DO NOT USE ANY FUNCTIONS DEPENDENT ON MODULES OF EXTENSIONS THAT ONLY WORK IN ONE OF THOSE. + +To start, there's three storages: +- a shared one, for generic usage +- a normal one, where user session storage can be stored +- an incognito one, where user session storage from the incognito browser can be stored +Each storage is separated by STORAGETYPE_ in front of the key originally used for the storage. +EXAMPLE: if one were to fetch something with the key "test"; use "SHARED_test", "NORMAL_test", "INCOGNITO_test" instead. + +The reason behind this is because storage is actually always shared between normal and incognito mode... +Which is not useful in our case, where we often use storage to synchronize settings based on the user who's currently +signed in to intra.42.fr. This can of course differ between normal and incognito mode +as cookies (and thus sessions) are NOT shared between these modes! +*/ + +// helper function to prepare keys for storage use +function prepareStorageKeys(type, keys) { + const internalKeys = Array.from(keys); + for (let i = 0; i < keys.length; i++) { + internalKeys[i] = type + "-" + keys[i]; + } + return (internalKeys); +} + +// helper function to prepare data for storage saving +function prepareStorageData(type, data) { + const newData = {}; + const keys = Object.keys(data); + const internalKeys = prepareStorageKeys(type, keys); + + for (let i = 0; i < keys.length; i++) { + newData[internalKeys[i]] = data[keys[i]]; + } + return (newData); +} + +// helper function to sanitize storage returned data +function sanitizeStorageData(origKeys, internalKeys, data) { + const newData = {}; + + for (let i = 0; i < internalKeys.length; i++) { + newData[origKeys[i]] = data[internalKeys[i]]; + } + return (newData); +} + +function ImprovedStorage(type) { + this.type = type.toUpperCase(); + + this.getType = function() { + return (this.type.toLowerCase()); + }; + + this.get = function(keys) { + if (typeof keys == "string") { + keys = [keys]; + } + const internalKeys = prepareStorageKeys(this.type, keys); + return new Promise(function(resolve) { + chrome.storage.local.get(internalKeys, function(data) { + resolve(sanitizeStorageData(keys, internalKeys, data)); + }); + }); + }; + + this.set = function(data) { + const internalData = prepareStorageData(this.type, data); + return new Promise(function(resolve) { + chrome.storage.local.set(internalData, resolve); + }); + }; + + this.remove = function(keys) { + if (typeof keys == "string") { + keys = [keys]; + } + const internalKeys = prepareStorageKeys(this.type, keys); + return new Promise(function(resolve) { + chrome.storage.local.remove(internalKeys, resolve); + }); + }; + + this.getBytesInUse = function(keys) { + if (typeof keys == "string") { + keys = [keys]; + } + const internalKeys = prepareStorageKeys(this.type, keys); + return new Promise(function(resolve) { + chrome.storage.local.getBytesInUse(internalKeys, resolve); + }); + }; +} + +// do not use this function from any background script: +// chrome.extension.inIncognitoContext will always be false! +// background scripts never run in incognito context. +function getSessionStorage() { + if (chrome.extension.inIncognitoContext) { + return (incognitoStorage); + } + return (normalStorage); +} + +// set up different kinds of storage +const sharedStorage = new ImprovedStorage("shared"); +const normalStorage = new ImprovedStorage("normal"); +const incognitoStorage = new ImprovedStorage("incognito"); diff --git a/build.sh b/build.sh index d8ea5de..03a2fee 100755 --- a/build.sh +++ b/build.sh @@ -1,18 +1,18 @@ #!/bin/bash if [[ $OSTYPE == 'darwin'* ]] || [[ $OSTYPE == 'linux-gnu' ]]; then rm -f chromium.zip firefox.zip - zip -r chromium.zip manifest.json LICENSE PRIVACY-POLICY.md background.js js/* options/* css/* campus_specifics/* images/logo*.png _locales/* + zip -r chromium.zip manifest.json LICENSE PRIVACY-POLICY.md sw.js background/* js/* options/* css/* campus_specifics/* images/logo*.png _locales/* mv manifest.json manifest-chromium.json mv manifest-ff.json manifest.json - zip -r firefox.zip manifest.json LICENSE PRIVACY-POLICY.md background.js js/* options/* css/* campus_specifics/* images/logo*.png _locales/* + zip -r firefox.zip manifest.json LICENSE PRIVACY-POLICY.md background/* js/* options/* css/* campus_specifics/* images/logo*.png _locales/* mv manifest.json manifest-ff.json mv manifest-chromium.json manifest.json else rm -f chromium.zip firefox.zip - 7z a chromium.zip manifest.json LICENSE PRIVACY-POLICY.md background.js js/* options/* css/* campus_specifics/* images/logo*.png _locales/* + 7z a chromium.zip manifest.json LICENSE PRIVACY-POLICY.md sw.js background/* js/* options/* css/* campus_specifics/* images/logo*.png _locales/* mv manifest.json manifest-chromium.json mv manifest-ff.json manifest.json - 7z a firefox.zip manifest.json LICENSE PRIVACY-POLICY.md background.js js/* options/* css/* campus_specifics/* images/logo*.png _locales/* + 7z a firefox.zip manifest.json LICENSE PRIVACY-POLICY.md background/* js/* options/* css/* campus_specifics/* images/logo*.png _locales/* mv manifest.json manifest-ff.json mv manifest-chromium.json manifest.json fi diff --git a/manifest-ff.json b/manifest-ff.json index 402a4d0..057a612 100644 --- a/manifest-ff.json +++ b/manifest-ff.json @@ -15,7 +15,7 @@ "256": "images/logo256.png", "512": "images/logo512.png" }, - "incognito": "not_allowed", + "incognito": "spanning", "browser_specific_settings": { "gecko": { "update_url": "https://raw.githubusercontent.com/FreekBes/improved_intra/main/updates.json", @@ -103,6 +103,11 @@ } ], "background": { - "scripts": [ "background.js" ] + "scripts": [ + "background/main.js", + "background/storage.js", + "background/comm.js", + "background/options.js" + ] } } diff --git a/manifest.json b/manifest.json index 54cd4a9..e4a73ed 100644 --- a/manifest.json +++ b/manifest.json @@ -17,7 +17,7 @@ "256": "images/logo256.png", "512": "images/logo512.png" }, - "incognito": "not_allowed", + "incognito": "spanning", "options_page": "options/options.html", "permissions": [ "storage" @@ -101,6 +101,6 @@ } ], "background": { - "service_worker": "background.js" + "service_worker": "sw.js" } } diff --git a/sw.js b/sw.js new file mode 100644 index 0000000..49b42f6 --- /dev/null +++ b/sw.js @@ -0,0 +1,28 @@ +/* ************************************************************************** */ +/* */ +/* :::::::: */ +/* sw.js :+: :+: */ +/* +:+ */ +/* By: fbes +#+ */ +/* +#+ */ +/* Created: 2022/03/26 23:58:26 by fbes #+# #+# */ +/* Updated: 2022/03/26 23:58:26 by fbes ######## odam.nl */ +/* */ +/* ************************************************************************** */ + +// This is a wrapper for the lack of multiple background scripts in Google's +// extension manifest V3. Just use a "service worker" and import all the +// neccessary background scripts here. +// Sadly it does need to be in the root folder of the extension. + +try { + importScripts( + "background/main.js", + "background/storage.js", + "background/comm.js", + "background/options.js" + ); +} +catch (err) { + console.error(err); +} diff --git a/todo.txt b/todo.txt index f8b10f5..3b97ab3 100644 --- a/todo.txt +++ b/todo.txt @@ -3,7 +3,6 @@ Manifest v3 options overview: https://developer.chrome.com/docs/extensions/mv3/m TODO: - convert every var to either const or let -- create backbone structure for local storage and syncing settings, with separate storage for incognito - create themes folder and move all theme-related stuff in there - create profile customization folder and move all profile customization stuff in there - create improvements folder and move all improvements into there (maybe separate some improvements?) @@ -15,3 +14,4 @@ TODO: - implement more cluster maps, maybe even custom ones into the extension itself? DONE: +- create backbone structure for local storage and syncing settings, with separate storage for incognito From d40d0c3119d0355239a951e4c6799ef0429e99c7 Mon Sep 17 00:00:00 2001 From: Freek Bes <36384333+FreekBes@users.noreply.github.com> Date: Sun, 27 Mar 2022 03:16:02 +0200 Subject: [PATCH 08/45] now using new storage system & fix inject.js injected many times --- background/comm.js | 5 +++-- campus_specifics/codam/coa-titles.js | 2 +- campus_specifics/codam/monit.js | 11 ++-------- js/improv.js | 22 +++++++++---------- js/init.js | 26 ++++++++++++++++++++++ js/profiles.js | 24 ++++++--------------- js/theme.js | 8 +++---- manifest-ff.json | 5 +++++ manifest.json | 5 +++++ options/auth.js | 16 +++++++------- options/options.html | 1 + options/options.js | 32 ++++++++++++++-------------- options/sync.js | 10 ++++----- options/unsync.js | 4 ++-- 14 files changed, 96 insertions(+), 75 deletions(-) create mode 100644 js/init.js diff --git a/background/comm.js b/background/comm.js index 24836e6..5bab33b 100644 --- a/background/comm.js +++ b/background/comm.js @@ -52,8 +52,9 @@ function isIncognitoPort(port) { // resync on port message function function resyncOnPortMessage(incognitoSession) { const type = (incognitoSession ? "incognito" : "normal"); + const improvedStorage = (incognitoSession ? incognitoStorage : normalStorage); - getStorage(type, "username").then(function(data) { + improvedStorage.get("username").then(function(data) { if (data["username"]) { getSettingsFromSyncServer(type, data["username"]) .then(function() { @@ -61,7 +62,7 @@ function resyncOnPortMessage(incognitoSession) { messagePortsOfType(type, { action: "resynced" }); }) .catch(function(err) { - resetSettings().then(function() { + resetOptions().then(function() { messagePortsOfType(type, { action: "resynced" }); }); }); diff --git a/campus_specifics/codam/coa-titles.js b/campus_specifics/codam/coa-titles.js index d0c9f4a..773f8f4 100644 --- a/campus_specifics/codam/coa-titles.js +++ b/campus_specifics/codam/coa-titles.js @@ -48,7 +48,7 @@ function autoEquipCoaTitle(loggedInUserName) { } } -chrome.storage.local.get(["username", "codam-auto-equip-coa-title"], function(data) { +improvedStorage.get(["username", "codam-auto-equip-coa-title"]).then(function(data) { if (data["codam-auto-equip-coa-title"] === true || data["codam-auto-equip-coa-title"] === "true") { autoEquipCoaTitle(data["username"]); } diff --git a/campus_specifics/codam/monit.js b/campus_specifics/codam/monit.js index a0b8a2c..d098fff 100644 --- a/campus_specifics/codam/monit.js +++ b/campus_specifics/codam/monit.js @@ -488,18 +488,11 @@ var monit = { } }; -chrome.storage.local.get("codam-monit", function(data) { +improvedStorage.get("codam-monit").then(function(data) { if (data["codam-monit"] === true || data["codam-monit"] === "true") { if (!document.getElementById("monit-progress-old")) { monit.init(); - var s = document.createElement('script'); - s.src = chrome.runtime.getURL('js/inject.js'); - (document.head || document.documentElement).appendChild(s); - s.onload = function() { - setTimeout(function() { - monit.getProgress(); - }, 250); - }; + monit.getProgress(); } else { document.getElementById("codam_intra_monit_system_display_deprecation_notice").className = "upgraded"; diff --git a/js/improv.js b/js/improv.js index 3dbcf3d..de3f21d 100644 --- a/js/improv.js +++ b/js/improv.js @@ -139,7 +139,7 @@ function colorizeLogtimeChart(event) { function setOptionalImprovements() { var broadcastNav = document.querySelector(".broadcast-nav"); if (broadcastNav) { - chrome.storage.local.get("hide-broadcasts", function(data) { + improvedStorage.get("hide-broadcasts").then(function(data) { if (data["hide-broadcasts"] === true || data["hide-broadcasts"] === "true") { broadcastNav.style.display = "none"; } @@ -148,7 +148,7 @@ function setOptionalImprovements() { var goalsContainer = document.getElementById("goals_container"); if (goalsContainer) { - chrome.storage.local.get("hide-goals", function(data) { + improvedStorage.get("hide-goals").then(function(data) { if (data["hide-goals"] === true || data["hide-goals"] === "true") { goalsContainer.style.display = "none"; } @@ -158,7 +158,7 @@ function setOptionalImprovements() { if (hasProfileBanner()) { var userPosteInfos = document.querySelector(".user-poste-infos"); if (userPosteInfos) { - chrome.storage.local.get("clustermap", function(data) { + improvedStorage.get("clustermap").then(function(data) { if ((data["clustermap"] === true || data["clustermap"] === "true") && userPosteInfos.innerText != "-") { userPosteInfos.className += " improved"; userPosteInfos.setAttribute("tabindex", "0"); @@ -207,13 +207,13 @@ function setGeneralImprovements() { // and if old-blackhole setting is enabled, replace text with old countdown style var bhColorTimer = setInterval(function() { var bhDate = document.querySelector("#bh-date"); - var bhDateTitle = bhDate.parentNode.getAttribute("data-original-title"); if (bhDate) { + var bhDateTitle = bhDate.parentNode.getAttribute("data-original-title"); if (bhDate.innerText.indexOf("absorbed") > -1) { clearInterval(bhColorTimer); bhDate.style.color = "var(--fail-color)"; if (getProfileUserName) { - chrome.storage.local.get("username", function(data) { + improvedStorage.get("username").then(function(data) { if (data["username"] && data["username"] != getProfileUserName()) { bhDate.innerText = "User has been absorbed by the Black Hole."; } @@ -227,7 +227,7 @@ function setGeneralImprovements() { } clearInterval(bhColorTimer); console.log("Black Hole days remaining: ", daysRemaining); - chrome.storage.local.get("old-blackhole", function(data) { + improvedStorage.get("old-blackhole").then(function(data) { if (data["old-blackhole"] === true || data["old-blackhole"] === "true") { bhDate.parentNode.setAttribute("data-original-title", bhDate.innerText); bhDate.innerText = daysRemaining.toString() + " days left"; @@ -360,11 +360,11 @@ setGeneralImprovements(); setOptionalImprovements(); // communication between background.js and this script -var syncPort = chrome.runtime.connect({ name: "sync_port" }); -syncPort.onDisconnect.addListener(function() { +let improvPort = chrome.runtime.connect({ name: portName }); +improvPort.onDisconnect.addListener(function() { console.log("%c[Improved Intra]%c Disconnected from service worker", "color: #00babc;", ""); }); -syncPort.onMessage.addListener(function(msg) { +improvPort.onMessage.addListener(function(msg) { switch (msg["action"]) { case "pong": console.log("pong"); @@ -388,6 +388,6 @@ syncPort.onMessage.addListener(function(msg) { // reconnect every 4-5 minutes to keep service worker running in background setInterval(function() { - syncPort.disconnect(); - syncPort = chrome.runtime.connect({ name: "sync_port" }); + improvPort.disconnect(); + improvPort = chrome.runtime.connect({ name: portName }); }, 250000); diff --git a/js/init.js b/js/init.js new file mode 100644 index 0000000..ca689d7 --- /dev/null +++ b/js/init.js @@ -0,0 +1,26 @@ +/* ************************************************************************** */ +/* */ +/* :::::::: */ +/* init.js :+: :+: */ +/* +:+ */ +/* By: fbes +#+ */ +/* +#+ */ +/* Created: 2022/03/27 03:00:23 by fbes #+# #+# */ +/* Updated: 2022/03/27 03:00:23 by fbes ######## odam.nl */ +/* */ +/* ************************************************************************** */ + +// this script initializes all global functions and variables for use elsewhere +// in this extension's content scripts + +// inject script to apply framework functions to elements generated by Improved Intra +// only inject it on the subdomains of *.intra.42.fr +if (window.location.origin.indexOf(".intra.42.fr") > -1) { + const s = document.createElement('script'); + s.src = chrome.runtime.getURL('js/inject.js'); + (document.head || document.documentElement).appendChild(s); +} + +// global variables +const improvedStorage = getSessionStorage(); +const portName = (chrome.extension.inIncognitoContext ? "incog_comm" : "normal_comm"); diff --git a/js/profiles.js b/js/profiles.js index d515b39..97550a5 100644 --- a/js/profiles.js +++ b/js/profiles.js @@ -10,11 +10,6 @@ /* */ /* ************************************************************************** */ -// inject script to apply framework functions to elements generated by Improved Intra -var s = document.createElement('script'); -s.src = chrome.runtime.getURL('js/inject.js'); -(document.head || document.documentElement).appendChild(s); - // from https://stackoverflow.com/questions/8667070/javascript-regular-expression-to-validate-url (jesus) function validateUrl(value) { return /^(?:(?:(?:https?|ftp):)?\/\/)(?:\S+(?::\S*)?@)?(?:(?!(?:10|127)(?:\.\d{1,3}){3})(?!(?:169\.254|192\.168)(?:\.\d{1,3}){2})(?!172\.(?:1[6-9]|2\d|3[0-1])(?:\.\d{1,3}){2})(?:[1-9]\d?|1\d\d|2[01]\d|22[0-3])(?:\.(?:1?\d{1,2}|2[0-4]\d|25[0-5])){2}(?:\.(?:[1-9]\d?|1\d\d|2[0-4]\d|25[0-4]))|(?:(?:[a-z\u00a1-\uffff0-9]-*)*[a-z\u00a1-\uffff0-9]+)(?:\.(?:[a-z\u00a1-\uffff0-9]-*)*[a-z\u00a1-\uffff0-9]+)*(?:\.(?:[a-z\u00a1-\uffff]{2,})))(?::\d{2,5})?(?:[/?#]\S*)?$/i.test(value); @@ -243,18 +238,13 @@ function confirmProfileUpdatedForFiveSeconds() { gUName = getProfileUserName(); gProfileBanner = document.querySelector(".container-inner-item.profile-item-top.profile-banner"); -var s2 = document.createElement('script'); -s2.src = chrome.runtime.getURL('js/inject.js'); -(document.head || document.documentElement).appendChild(s2); -s2.onload = function() { - immediateProfileChanges(); - chrome.storage.local.get(["username", "show-custom-profiles", "custom-banner-url", "custom-banner-pos", "link-github"], function(data) { - gExtSettings = data; - setCustomBannerWrapper(); - setCustomProfile(); - confirmProfileUpdatedForFiveSeconds(); - }); -}; +immediateProfileChanges(); +improvedStorage.get(["username", "show-custom-profiles", "custom-banner-url", "custom-banner-pos", "link-github"]).then(function(data) { + gExtSettings = data; + setCustomBannerWrapper(); + setCustomProfile(); + confirmProfileUpdatedForFiveSeconds(); +}); var cursusSelector = document.querySelector(".cursus-user-select"); if (cursusSelector) { diff --git a/js/theme.js b/js/theme.js index 77ae923..d211f9e 100644 --- a/js/theme.js +++ b/js/theme.js @@ -55,8 +55,8 @@ function enableTheme(theme, colors) { } function checkThemeSetting() { - chrome.storage.local.get(["theme", "colors"], function(data) { - if (data["theme"] == "system") { + improvedStorage.get(["theme", "colors"]).then(function(data) { + if (data["theme"] == "system" || !data["theme"]) { if (window.matchMedia('(prefers-color-scheme: dark)').matches) { enableTheme("dark", data["colors"]); } @@ -69,7 +69,7 @@ function checkThemeSetting() { } else { // fallback to default - enableTheme("system", null); + enableTheme("light", null); } }); } @@ -83,7 +83,7 @@ checkThemeSetting(); // fix sign in page issue with background image window.addEventListener("DOMContentLoaded", function() { - if (window.location.pathname == "/users/sign_in") { + if (window.location.origin.indexOf("intra.42.fr") > -1 && window.location.pathname == "/users/sign_in") { document.getElementsByTagName("html")[0].setAttribute("style", "background-color: unset !important;"); } }); diff --git a/manifest-ff.json b/manifest-ff.json index 057a612..9cddba8 100644 --- a/manifest-ff.json +++ b/manifest-ff.json @@ -43,6 +43,11 @@ "js/inject.js" ], "content_scripts": [ + { + "matches": [ "*://darkintra.freekb.es/*", "*://*.intra.42.fr/*" ], + "js": [ "background/storage.js", "js/init.js" ], + "run_at": "document_start" + }, { "matches": [ "*://*.intra.42.fr/*" ], "css": [ "css/improv.css", "css/animations.css", "css/theme-apply.css" ], diff --git a/manifest.json b/manifest.json index e4a73ed..1abd659 100644 --- a/manifest.json +++ b/manifest.json @@ -41,6 +41,11 @@ } ], "content_scripts": [ + { + "matches": [ "*://darkintra.freekb.es/*", "*://*.intra.42.fr/*" ], + "js": [ "background/storage.js", "js/init.js" ], + "run_at": "document_start" + }, { "matches": [ "*://*.intra.42.fr/*" ], "css": [ "css/improv.css", "css/animations.css", "css/theme-apply.css" ], diff --git a/options/auth.js b/options/auth.js index 5dcf6bc..2fa3e2c 100644 --- a/options/auth.js +++ b/options/auth.js @@ -10,11 +10,11 @@ /* */ /* ************************************************************************** */ -var syncPort = chrome.runtime.connect({ name: "sync_port" }); -syncPort.onDisconnect.addListener(function() { +let authPort = chrome.runtime.connect({ name: portName }); +authPort.onDisconnect.addListener(function() { console.log("%c[Improved Intra]%c Disconnected from service worker", "color: #00babc;", ""); }); -syncPort.onMessage.addListener(function(msg) { +authPort.onMessage.addListener(function(msg) { switch (msg["action"]) { case "pong": console.log("pong"); @@ -29,8 +29,8 @@ syncPort.onMessage.addListener(function(msg) { } }); setInterval(function() { - syncPort.disconnect(); - syncPort = chrome.runtime.connect({ name: "sync_port" }); + authPort.disconnect(); + authPort = chrome.runtime.connect({ name: portName }); }, 250000); var authResElem = document.getElementById("result"); @@ -58,10 +58,10 @@ if (authResElem) { } }, 2000); - chrome.storage.local.set(authRes, function() { - chrome.storage.local.set({"username": authRes["user"]["login"]}, function() { + sessionStorage.set(authRes).then(function() { + sessionStorage.set({"username": authRes["user"]["login"]}).then(function() { console.log("%c[Improved Intra]%c Authentication details saved in local storage!", "color: #00babc;", ""); - syncPort.postMessage({ action: "resync" }); + authPort.postMessage({ action: "resync" }); }); }); } diff --git a/options/options.html b/options/options.html index 2bb6a6a..4243c21 100644 --- a/options/options.html +++ b/options/options.html @@ -6,6 +6,7 @@ + diff --git a/options/options.js b/options/options.js index ddcf440..79f9206 100644 --- a/options/options.js +++ b/options/options.js @@ -53,11 +53,11 @@ function showSettingsSavedNotif() { }, 2000); } -var syncPort = chrome.runtime.connect({ name: "sync_port" }); -syncPort.onDisconnect.addListener(function() { +var optionsPort = chrome.runtime.connect({ name: portName }); +optionsPort.onDisconnect.addListener(function() { console.log("%c[Improved Intra]%c Disconnected from service worker", "color: #00babc;", ""); }); -syncPort.onMessage.addListener(function(msg) { +optionsPort.onMessage.addListener(function(msg) { switch (msg["action"]) { case "pong": console.log("pong"); @@ -75,14 +75,14 @@ syncPort.onMessage.addListener(function(msg) { } }); setInterval(function() { - syncPort.disconnect(); - syncPort = chrome.runtime.connect({ name: "sync_port" }); + optionsPort.disconnect(); + optionsPort = chrome.runtime.connect({ name: portName }); }, 250000); function storeSettingsAndUpdateForm(newSettings) { - chrome.storage.local.set(newSettings, function() { - if (syncPort) { - syncPort.postMessage({ action: "options-changed", settings: newSettings }); + improvedStorage.set(newSettings).then(function() { + if (optionsPort) { + optionsPort.postMessage({ action: "options-changed", settings: newSettings }); } }); document.getElementById("custom-banner-upload").value = ""; @@ -127,7 +127,7 @@ function syncSettings(event) { // store on sync server if sync is enabled if (settingsObj["sync"] === "true") { - chrome.storage.local.get(["user", "auth"], function(data) { + improvedStorage.get(["user", "auth"]).then(function(data) { if (data["user"] && data["auth"]) { syncBtn.className = "syncing"; formData.append("access_token", data["auth"]["access_token"]); @@ -167,7 +167,7 @@ function syncSettings(event) { }); } else { - chrome.storage.local.get(["sync", "auth"], function(data) { + improvedStorage.get(["sync", "auth"]).then(function(data) { if ((data["sync"] === true || data["sync"] === "true") && data["auth"]) { syncBtn.className = "syncing"; formData = new FormData(form); @@ -193,10 +193,10 @@ function syncSettings(event) { req.send(formData); } - chrome.storage.local.set(settingsObj, function() { + improvedStorage.set(settingsObj).then(function() { console.log("Settings stored locally"); - if (syncPort) { - syncPort.postMessage({ action: "options-changed", settings: settingsObj }); + if (optionsPort) { + optionsPort.postMessage({ action: "options-changed", settings: settingsObj }); } }); }); @@ -213,7 +213,7 @@ function retrieveSettings() { keysToGet.push(formElems[i].getAttribute("name")); } console.log(keysToGet); - chrome.storage.local.get(keysToGet, function(data) { + improvedStorage.get(keysToGet).then(function(data) { resolve(data); }); } @@ -230,7 +230,7 @@ function loadSettingsIntoForm(settings) { settingElem = document.getElementsByName(key); if (settingElem.length > 0) { settingElem = settingElem[0]; - chrome.storage.local.set({[key]: settings[key]}); + improvedStorage.set({[key]: settings[key]}); } else { console.warn("Found unknown setting key '" + key + "'"); @@ -308,7 +308,7 @@ window.onload = function() { event.preventDefault(); }); - chrome.storage.local.get(["username", "auth", "user"], function(data) { + improvedStorage.get(["username", "auth", "user"]).then(function(data) { console.log(data); if (data["username"] === undefined || data["auth"] === undefined || data["user"] == undefined || data["user"]["login"] != data["username"]) { diff --git a/options/sync.js b/options/sync.js index 44232c0..747ec0a 100644 --- a/options/sync.js +++ b/options/sync.js @@ -19,7 +19,7 @@ function getLoggedInUserName() { } } -var syncPort = chrome.runtime.connect({ name: "sync_port" }); +var syncPort = chrome.runtime.connect({ name: portName }); syncPort.onDisconnect.addListener(function() { console.log("%c[Improved Intra]%c Disconnected from service worker", "color: #00babc;", ""); }); @@ -35,14 +35,14 @@ syncPort.onMessage.addListener(function(msg) { }); setInterval(function() { syncPort.disconnect(); - syncPort = chrome.runtime.connect({ name: "sync_port" }); + syncPort = chrome.runtime.connect({ name: portName }); }, 250000); -chrome.storage.local.get("username", function(data) { +improvedStorage.get("username").then(function(data) { var curUsername = getLoggedInUserName(); - if (curUsername != data["username"] && curUsername != null) { + if (true || curUsername != data["username"] && curUsername != null) { // a new user logged in! - chrome.storage.local.set({"username": curUsername}, function() { + improvedStorage.set({"username": curUsername}).then(function() { console.log("%c[Improved Intra]%c Intra username stored in local storage", "color: #00babc;", ""); syncPort.postMessage({ action: "resync" }); }); diff --git a/options/unsync.js b/options/unsync.js index 9d9c3a8..3dc3a40 100644 --- a/options/unsync.js +++ b/options/unsync.js @@ -12,6 +12,6 @@ // these functions are run when signing out from Intranet at https://intra.42.fr -chrome.storage.local.remove("username", function() { +improvedStorage.remove("username").then(function() { console.log("Signed out from Intra, so removed the username to synchronize with. Settings will be kept locally, until another person signs in."); -}); \ No newline at end of file +}); From d80f6f6356d2ea11fe0eab54a315af0b52bdfb55 Mon Sep 17 00:00:00 2001 From: Freek Bes <36384333+FreekBes@users.noreply.github.com> Date: Sun, 27 Mar 2022 04:50:33 +0200 Subject: [PATCH 09/45] bugfixes in options synchronization --- background/comm.js | 7 ++++--- background/main.js | 2 ++ background/options.js | 17 +++++++++++++---- js/improv.js | 3 ++- options/options.js | 11 +++++++---- options/sync.js | 17 ++++++++++++----- 6 files changed, 40 insertions(+), 17 deletions(-) diff --git a/background/comm.js b/background/comm.js index 5bab33b..7e3144f 100644 --- a/background/comm.js +++ b/background/comm.js @@ -56,13 +56,14 @@ function resyncOnPortMessage(incognitoSession) { improvedStorage.get("username").then(function(data) { if (data["username"]) { - getSettingsFromSyncServer(type, data["username"]) + getSettingsFromSyncServer(improvedStorage, data["username"]) .then(function() { - console.log("Settings successfully retrieved from server. Stored a copy locally."); + console.log("Settings successfully retrieved from server. Stored a copy locally in " + type + " storage."); messagePortsOfType(type, { action: "resynced" }); }) .catch(function(err) { - resetOptions().then(function() { + console.error(err); + resetOptions(improvedStorage).then(function() { messagePortsOfType(type, { action: "resynced" }); }); }); diff --git a/background/main.js b/background/main.js index 35c7f1d..9871294 100644 --- a/background/main.js +++ b/background/main.js @@ -23,6 +23,8 @@ chrome.runtime.onInstalled.addListener(function(details) { } else if (details.reason == "update") { console.log("An update has been installed."); + resetLastSyncTimestamp(normalStorage); + resetLastSyncTimestamp(incognitoStorage); removeUnusedOptions(); resyncOptions(); } diff --git a/background/options.js b/background/options.js index 5734d7e..3efea2a 100644 --- a/background/options.js +++ b/background/options.js @@ -104,9 +104,9 @@ function setOptionsIfUnset(improvedStorage) { }); } -function getSettingsFromSyncServer(storageType, username) { +function getSettingsFromSyncServer(improvedStorage, username) { return new Promise(function(resolve, reject) { - console.log("Retrieving settings of username " + username); + console.log("Retrieving settings of username " + username + " for " + improvedStorage.getType()); fetch("https://darkintra.freekb.es/settings/" + username + ".json?noCache=" + Math.random()) .then(function(response) { if (response.status == 404) { @@ -121,8 +121,11 @@ function getSettingsFromSyncServer(storageType, username) { }) .then(function(json) { if (json != null) { - storageType.set(json, function() { - resolve(json); + console.log("Storing settings in " + improvedStorage.getType() + " storage..."); + improvedStorage.set(json).then(function() { + improvedStorage.set({ "last-sync": new Date().getTime() }).then(function() { + resolve(json); + }); }); } }) @@ -132,6 +135,12 @@ function getSettingsFromSyncServer(storageType, username) { }); } +function resetLastSyncTimestamp(improvedStorage) { + return new Promise(function(resolve) { + improvedStorage.remove("last-sync").then(resolve); + }); +} + function fetchUserSettings(improvedStorage) { const storageType = improvedStorage.getType(); diff --git a/js/improv.js b/js/improv.js index de3f21d..b1c6c67 100644 --- a/js/improv.js +++ b/js/improv.js @@ -307,7 +307,8 @@ function setGeneralImprovements() { } var extensionSettings = document.createElement("li"); var extensionSettingsLink = document.createElement("a"); - extensionSettingsLink.setAttribute("href", chrome.runtime.getURL('options/options.html')); + // extensionSettingsLink.setAttribute("href", chrome.runtime.getURL('options/options.html')); + extensionSettingsLink.setAttribute("href", "https://darkintra.freekb.es/options.php"); extensionSettingsLink.setAttribute("target", "_self"); extensionSettingsLink.innerText = "Improved Intra Settings"; extensionSettings.appendChild(extensionSettingsLink); diff --git a/options/options.js b/options/options.js index 79f9206..766ecee 100644 --- a/options/options.js +++ b/options/options.js @@ -194,10 +194,12 @@ function syncSettings(event) { } improvedStorage.set(settingsObj).then(function() { - console.log("Settings stored locally"); - if (optionsPort) { - optionsPort.postMessage({ action: "options-changed", settings: settingsObj }); - } + improvedStorage.set({ "last-sync": new Date().getTime() }, function() { + console.log("Settings stored locally"); + if (optionsPort) { + optionsPort.postMessage({ action: "options-changed", settings: settingsObj }); + } + }); }); }); } @@ -255,6 +257,7 @@ function loadSettingsIntoForm(settings) { continue; } } + improvedStorage.set({ "last-sync": new Date().getTime() }); document.getElementById("current-custom-banner").setAttribute("src", settings["custom-banner-url"]); if (!settings["custom-banner-url"]) { document.getElementById("custom-header-preview").style.display = "none"; diff --git a/options/sync.js b/options/sync.js index 747ec0a..a6ad8b5 100644 --- a/options/sync.js +++ b/options/sync.js @@ -28,6 +28,9 @@ syncPort.onMessage.addListener(function(msg) { case "pong": console.log("pong"); break; + case "resynced": + console.log("%c[Improved Intra]%c Resync done.", "color: #00babc;", ""); + break; case "error": console.error(msg["message"]); break; @@ -38,16 +41,20 @@ setInterval(function() { syncPort = chrome.runtime.connect({ name: portName }); }, 250000); -improvedStorage.get("username").then(function(data) { - var curUsername = getLoggedInUserName(); - if (true || curUsername != data["username"] && curUsername != null) { +improvedStorage.get(["last-sync", "username"]).then(function(data) { + const curUsername = getLoggedInUserName(); + const curTime = new Date().getTime(); + // if username in storage does not equal the currently logged in user + // or the last sync was over an hour ago, resynchronize settings with server + if (!data["username"] || !data["last-sync"] || parseInt(data["last-sync"]) - curTime < -3600000 || (curUsername != data["username"] && curUsername != null)) { // a new user logged in! improvedStorage.set({"username": curUsername}).then(function() { - console.log("%c[Improved Intra]%c Intra username stored in local storage", "color: #00babc;", ""); + console.log("%c[Improved Intra]%c Intra username stored in local storage, now resyncing settings...", "color: #00babc;", ""); syncPort.postMessage({ action: "resync" }); }); } else { - console.log("%c[Improved Intra]%c Hello there, " + curUsername + "!", "color: #00babc;", ""); + const lastSync = new Date(parseInt(data["last-sync"])); + console.log("%c[Improved Intra]%c Hello there, " + curUsername + "! Your settings have last been synced on " + lastSync.toString(), "color: #00babc;", ""); } }); From b5c6d3d54ab749680cec483d0c743368497317e5 Mon Sep 17 00:00:00 2001 From: Freek Bes <36384333+FreekBes@users.noreply.github.com> Date: Sun, 27 Mar 2022 04:54:21 +0200 Subject: [PATCH 10/45] options page now listens to theme changes --- options/options.js | 1 + 1 file changed, 1 insertion(+) diff --git a/options/options.js b/options/options.js index 766ecee..363b83d 100644 --- a/options/options.js +++ b/options/options.js @@ -265,6 +265,7 @@ function loadSettingsIntoForm(settings) { else { document.getElementById("custom-header-preview").style.display = "block"; } + checkThemeSetting(); hideLoading(); } From 0151d2777d1437b4c5cf8561788c26c6eaa997b5 Mon Sep 17 00:00:00 2001 From: Freek Bes <36384333+FreekBes@users.noreply.github.com> Date: Sun, 27 Mar 2022 04:54:31 +0200 Subject: [PATCH 11/45] bugfixes internal css --- options/options.css | 34 +++++++++++++++++++++++++++++++--- 1 file changed, 31 insertions(+), 3 deletions(-) diff --git a/options/options.css b/options/options.css index 21dd6ff..083656f 100644 --- a/options/options.css +++ b/options/options.css @@ -58,6 +58,34 @@ font-style: normal } +@font-face { + font-family: "futura"; + src: url(https://profile.intra.42.fr/assets/ParaType-FuturaPTBook-85be74ee15c50c39cb5601ec40aee5fc3c79090582047140fc0a9827cc3f7dab.otf) format("opentype"); + font-weight: 400; + font-style: normal; +} + +@font-face { + font-family:"futura"; + src:url(https://profile.intra.42.fr/assets/ParaType-FuturaPTBookOblique-c68d7786d4e95e7b01a9b6815a590fd8e0893e4c2ac7866781a6dd7cf553e479.ttf) format("truetype"); + font-weight: 400; + font-style: italic; +} + +@font-face { + font-family: "futura-bold"; + src: url(https://profile.intra.42.fr/assets/ParaType-FuturaPTHeavy-518b96256003be903332541a3c2ac7a54d5ba38eaeebb9bed930a530f2b8ddf9.otf) format("opentype"); + font-weight: 700; + font-style: normal; +} + +@font-face { + font-family: "futura-bold"; + src: url(https://profile.intra.42.fr/assets/ParaType-FuturaPTHeavyOblique-b844b203a563c9cd175071a8a162b77459d4ac16b2493f65c0840a54385bfc8b.otf) format("opentype"); + font-weight: 700; + font-style: italic; +} + @keyframes spin { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } @@ -80,7 +108,7 @@ body, background-color: var(--container-background-color); color: var(--text-color); caret-color: var(--text-color); - font-family: "Futura PT", "Futura", "Helvetica", Verdana, Arial, Sans-Serif; + font-family: "Futura PT", "Futura", "futura", "Helvetica", Verdana, Arial, Sans-Serif; font-size: 16px; padding: 0px; cursor: default; @@ -209,11 +237,11 @@ header button#sync-button.syncing { header button#sync-button::after { display: inline-block; transform-origin: center; - content: '\e3b7'; + content: '\1F4BE'; } header button#sync-button.syncing::after { - content: '\e29b'; + content: '\1F5D8'; animation: spin 1.3s linear infinite; animation-direction: reverse; } From 1ffd8fc9c4bbe55d3ed5125e69843731a3c4fad1 Mon Sep 17 00:00:00 2001 From: Freek Bes <36384333+FreekBes@users.noreply.github.com> Date: Sun, 27 Mar 2022 04:15:03 +0200 Subject: [PATCH 12/45] move options page to server-side it is always synced anyways --- options/options.css => css/internal.css | 112 ++++++++--------- manifest-ff.json | 6 + manifest.json | 20 ++- options/auth.js | 6 +- options/options.html | 137 ++------------------- server/connect.php | 72 ----------- server/options.php | 154 ++++++++++++++++++++++++ 7 files changed, 242 insertions(+), 265 deletions(-) rename options/options.css => css/internal.css (75%) create mode 100644 server/options.php diff --git a/options/options.css b/css/internal.css similarity index 75% rename from options/options.css rename to css/internal.css index 083656f..fc8056c 100644 --- a/options/options.css +++ b/css/internal.css @@ -1,62 +1,14 @@ -@font-face { - font-family: "Futura PT"; - src: url(https://profile.intra.42.fr/assets/ParaType-FuturaPTLight-e7a52027b9b5978e6a6f83b096aea906b0e79399145e65e19024f94967a2411f.otf) format("opentype"); - font-weight: 200; - font-style: normal; -} - -@font-face { - font-family:"Futura PT"; - src: url(https://profile.intra.42.fr/assets/ParaType-FuturaPTLightOblique-5212d3b9dd70f3017a3bd3478c96b37e8457b7d216a6f4658cbc0cdf15aea289.otf) format("opentype"); - font-weight: 200; - font-style: italic; -} - -@font-face { - font-family: "Futura PT"; - src: url(https://profile.intra.42.fr/assets/ParaType-FuturaPTBook-85be74ee15c50c39cb5601ec40aee5fc3c79090582047140fc0a9827cc3f7dab.otf) format("opentype"); - font-weight: 400; - font-style: normal; -} - -@font-face { - font-family:"Futura PT"; - src:url(https://profile.intra.42.fr/assets/ParaType-FuturaPTBookOblique-c68d7786d4e95e7b01a9b6815a590fd8e0893e4c2ac7866781a6dd7cf553e479.ttf) format("truetype"); - font-weight: 400; - font-style: italic; -} - -@font-face { - font-family: "Futura PT"; - src: url(https://profile.intra.42.fr/assets/ParaType-FuturaPTHeavy-518b96256003be903332541a3c2ac7a54d5ba38eaeebb9bed930a530f2b8ddf9.otf) format("opentype"); - font-weight: 700; - font-style: normal; -} - -@font-face { - font-family: "Futura PT"; - src: url(https://profile.intra.42.fr/assets/ParaType-FuturaPTHeavyOblique-b844b203a563c9cd175071a8a162b77459d4ac16b2493f65c0840a54385bfc8b.otf) format("opentype"); - font-weight: 700; - font-style: italic; -} - -@font-face { - font-family: "Noto Sans"; - src: url(https://profile.intra.42.fr/assets/NotoSans-Regular-f1ce78a25f519ef928b5b8755ca230314e47f8821e7aa89ecf000f033f389a9f.ttf) format("truetype"); - font-weight: 400; - font-style: normal; -} - -@font-face { - font-family: "streamline-filled"; - src: url(https://profile.intra.42.fr/assets/streamline-30px-filled-in-4646a777f76d366ec26caad7921e728e2d01b9dca49053c6b316fe596700e252.eot); - src: url(https://profile.intra.42.fr/assets/streamline-30px-filled-in-4646a777f76d366ec26caad7921e728e2d01b9dca49053c6b316fe596700e252.eot?#iefix) format("embedded-opentype"), - url(https://profile.intra.42.fr/assets/streamline-30px-filled-in-62fdf8602f56c68e259582d7ad3eb0e30b2808efaa03a074086faedcaf9017e2.woff) format("woff"), - url(https://profile.intra.42.fr/assets/streamline-30px-filled-in-9c4de7ac5c05533207755509de4a14b25d1b8d7276ce055fe9ed3f43b38c8328.ttf) format("truetype"), - url(https://profile.intra.42.fr/assets/streamline-30px-filled-in-c547d434f0242cda67f4d0438ae132de5fe5794afd2366906e2f1d3480756732.svg#streamline-30px-filled-in) format("svg"); - font-weight: normal; - font-style: normal -} +/* ************************************************************************** */ +/* */ +/* :::::::: */ +/* internal.css :+: :+: */ +/* +:+ */ +/* By: fbes +#+ */ +/* +#+ */ +/* Created: 2022/03/27 03:34:57 by fbes #+# #+# */ +/* Updated: 2022/03/27 03:34:57 by fbes ######## odam.nl */ +/* */ +/* ************************************************************************** */ @font-face { font-family: "futura"; @@ -91,6 +43,11 @@ 100% { transform: rotate(360deg); } } +#improved-intra-no-extension-block { + display: none !important; + z-index: -1 !important; +} + html, body { display: block; @@ -193,13 +150,48 @@ h1 { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; - padding: 0px 8px; + padding: 0px; margin: 0px; line-height: 56px; font-size: 18px; font-weight: 800; } +code { + display: block; + white-space: pre-wrap; + word-break: break-word; + font-size: smaller; + padding: 16px 0px; +} + +h2 { + margin: 0px; + padding: 16px 0px; +} + +details { + padding: 8px; + border: 1px solid #4a4a4a; + background: #3a3a3a; + border-radius: 4px; +} + +summary { + font-size: initial; +} + +details[open] summary { + border-bottom: 1px solid #4a4a4a; + padding-bottom: 8px; + margin-bottom: 8px; +} + +hr { + border: none; + border-bottom: solid 1px var(--general-border-color); +} + header button { float: right; background-color: rgba(0,0,0,0); diff --git a/manifest-ff.json b/manifest-ff.json index 9cddba8..d079faf 100644 --- a/manifest-ff.json +++ b/manifest-ff.json @@ -48,6 +48,12 @@ "js": [ "background/storage.js", "js/init.js" ], "run_at": "document_start" }, + { + "matches": [ "*://darkintra.freekb.es/*" ], + "css": [ "css/internal.css", "css/animations.css" ], + "js": [ "js/theme.js" ], + "run_at": "document_start" + }, { "matches": [ "*://*.intra.42.fr/*" ], "css": [ "css/improv.css", "css/animations.css", "css/theme-apply.css" ], diff --git a/manifest.json b/manifest.json index 1abd659..565a0af 100644 --- a/manifest.json +++ b/manifest.json @@ -31,21 +31,24 @@ "css/theme-dark.css", "css/colors-cetus.css", "css/colors-pyxis.css", - "css/colors-vela.css" + "css/colors-vela.css", + "options/options.html" ], - "matches": [ "*://*.intra.42.fr/*" ] - }, - { - "resources": [ "options/options.html" ], "matches": [ "*://*.intra.42.fr/*", "*://darkintra.freekb.es/*" ] } ], "content_scripts": [ { - "matches": [ "*://darkintra.freekb.es/*", "*://*.intra.42.fr/*" ], + "matches": [ "*://*.intra.42.fr/*", "*://darkintra.freekb.es/*" ], "js": [ "background/storage.js", "js/init.js" ], "run_at": "document_start" }, + { + "matches": [ "*://darkintra.freekb.es/*" ], + "css": [ "css/internal.css", "css/animations.css" ], + "js": [ "js/theme.js" ], + "run_at": "document_start" + }, { "matches": [ "*://*.intra.42.fr/*" ], "css": [ "css/improv.css", "css/animations.css", "css/theme-apply.css" ], @@ -72,6 +75,11 @@ "js": [ "options/auth.js" ], "run_at": "document_end" }, + { + "matches": [ "*://darkintra.freekb.es/options.php*" ], + "js": [ "options/options.js" ], + "run_at": "document_end" + }, { "matches": [ "*://profile.intra.42.fr/", "*://*.intra.42.fr/users/*" ], "js": [ "js/profiles.js" ], diff --git a/options/auth.js b/options/auth.js index 2fa3e2c..99b9080 100644 --- a/options/auth.js +++ b/options/auth.js @@ -38,7 +38,7 @@ if (authResElem) { try { var authRes = JSON.parse(authResElem.innerText); if (!("error" in authRes["auth"])) { - var optionsURL = chrome.runtime.getURL('options/options.html'); + var optionsURL = "https://darkintra.freekb.es/options.php"; var action = document.getElementById("action"); if (action) { action.innerText = "Please wait while we redirect you to the Improved Intra 42 options page..."; @@ -58,8 +58,8 @@ if (authResElem) { } }, 2000); - sessionStorage.set(authRes).then(function() { - sessionStorage.set({"username": authRes["user"]["login"]}).then(function() { + improvedStorage.set(authRes).then(function() { + improvedStorage.set({"username": authRes["user"]["login"]}).then(function() { console.log("%c[Improved Intra]%c Authentication details saved in local storage!", "color: #00babc;", ""); authPort.postMessage({ action: "resync" }); }); diff --git a/options/options.html b/options/options.html index 4243c21..07586ab 100644 --- a/options/options.html +++ b/options/options.html @@ -3,132 +3,21 @@ Improved Intra 42 Settings - - - + + - + + + -
-
-
-
Settings saved!
-
-
- -

Improved Intra 42 Settings

- -
-
-
-
-

Synchronization

-
- - -
-
- - -
-
-
-

Appearance

-
- - -
-
- - -
-
- - -
-
-
-

General improvements

-
- - -
-
- - -
-
- - -
-
- - -
-
-
-

Customize your profile

-
- - -
- -
- - -
-
- - -
-
- - -
-
-
-

Campus specific

-
- - -
-
- - -
-
-
-

Help

-
- - -
-
-
-
-
+
+

Redirecting to the options page...

+

Click here if you are not being redirected.

+
diff --git a/server/connect.php b/server/connect.php index 03225d3..0c894ea 100644 --- a/server/connect.php +++ b/server/connect.php @@ -17,78 +17,6 @@ function respond($type, $msg, $data = null) { Connect Improved Intra 42 with your Intranet account - diff --git a/server/options.php b/server/options.php new file mode 100644 index 0000000..e0eee43 --- /dev/null +++ b/server/options.php @@ -0,0 +1,154 @@ + + + + + Improved Intra 42 Settings + + + +
+

You need to install the Improved Intra 42 extension in order to modify its settings.

+

You can install it from the Chrome Web Store or, if you are using Mozilla Firefox, directly by clicking here.

+

If you do have it installed, then something went horribly wrong. Please message me on Slack @fbes or create a GitHub issue.

+
+
+
+
+
Settings saved!
+
+
+ +

Improved Intra 42 Settings

+ +
+
+
+
+

Synchronization

+
+ + +
+
+ + +
+
+
+

Appearance

+
+ + +
+
+ + +
+
+ + +
+
+
+

General improvements

+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+
+

Customize your profile

+
+ + +
+ +
+ + +
+
+ + +
+
+ + +
+
+
+

Campus specific

+
+ + +
+
+ + +
+
+
+

Help

+
+ + +
+
+
+
+
+ + From 2a923f390c3422289c36497e479a227248040548 Mon Sep 17 00:00:00 2001 From: Freek Bes <36384333+FreekBes@users.noreply.github.com> Date: Sun, 27 Mar 2022 15:35:33 +0200 Subject: [PATCH 13/45] reorganized files and added console wrapper --- background/comm.js | 8 +- background/main.js | 4 +- background/options.js | 22 +++--- build.sh | 8 +- {js => features}/admin.js | 0 .../campus}/codam/coa-titles.js | 10 +-- .../campus}/codam/monit.css | 0 .../campus}/codam/monit.js | 20 ++--- {js => features}/mlx42.js | 0 {js => features}/profiles.js | 8 +- .../themes/apply.css | 0 .../themes/colors/cetus.css | 2 +- .../themes/colors/pyxis.css | 2 +- .../themes/colors/vela.css | 2 +- .../themes/dark.css | 0 .../themes/light.css | 0 js/theme.js => features/themes/loader.js | 10 +-- {css => fixes}/animations.css | 0 {css => fixes}/improv.css | 0 {js => fixes}/improv.js | 10 +-- generic/console.js | 26 +++++++ {js => generic}/init.js | 2 +- {js => generic}/inject.js | 6 +- {css => generic}/internal.css | 0 {background => generic}/storage.js | 0 manifest-ff.json | 46 +++++++----- manifest.json | 36 ++++----- options/auth.js | 14 ++-- options/options.js | 44 +++++------ options/sync.js | 12 +-- options/unsync.js | 2 +- server/connect.php | 73 +++++++++++++++++++ sw.js | 5 +- todo.txt | 8 +- 34 files changed, 244 insertions(+), 136 deletions(-) rename {js => features}/admin.js (100%) rename {campus_specifics => features/campus}/codam/coa-titles.js (85%) rename {campus_specifics => features/campus}/codam/monit.css (100%) rename {campus_specifics => features/campus}/codam/monit.js (95%) rename {js => features}/mlx42.js (100%) rename {js => features}/profiles.js (97%) rename css/theme-apply.css => features/themes/apply.css (100%) rename css/colors-cetus.css => features/themes/colors/cetus.css (94%) rename css/colors-pyxis.css => features/themes/colors/pyxis.css (94%) rename css/colors-vela.css => features/themes/colors/vela.css (94%) rename css/theme-dark.css => features/themes/dark.css (100%) rename css/theme-light.css => features/themes/light.css (100%) rename js/theme.js => features/themes/loader.js (85%) rename {css => fixes}/animations.css (100%) rename {css => fixes}/improv.css (100%) rename {js => fixes}/improv.js (97%) create mode 100644 generic/console.js rename {js => generic}/init.js (96%) rename {js => generic}/inject.js (83%) rename {css => generic}/internal.css (100%) rename {background => generic}/storage.js (100%) diff --git a/background/comm.js b/background/comm.js index 7e3144f..183a8f8 100644 --- a/background/comm.js +++ b/background/comm.js @@ -58,18 +58,18 @@ function resyncOnPortMessage(incognitoSession) { if (data["username"]) { getSettingsFromSyncServer(improvedStorage, data["username"]) .then(function() { - console.log("Settings successfully retrieved from server. Stored a copy locally in " + type + " storage."); + iConsole.log("Settings successfully retrieved from server. Stored a copy locally in " + type + " storage."); messagePortsOfType(type, { action: "resynced" }); }) .catch(function(err) { - console.error(err); + iConsole.error(err); resetOptions(improvedStorage).then(function() { messagePortsOfType(type, { action: "resynced" }); }); }); } else { - console.warn("Could not resync, as no username was given to sync from"); + iConsole.warn("Could not resync, as no username was given to sync from"); } }); } @@ -92,7 +92,7 @@ function portMessageListener(msg, port) { } break; default: - console.log("Unknown action received over port: ", msg["action"]); + iConsole.log("Unknown action received over port: ", msg["action"]); break; } } diff --git a/background/main.js b/background/main.js index 9871294..81af54a 100644 --- a/background/main.js +++ b/background/main.js @@ -18,11 +18,11 @@ function resyncOptions() { chrome.runtime.onInstalled.addListener(function(details) { if (details.reason == "install") { - console.log("First install."); + iConsole.log("First install."); resyncOptions(); } else if (details.reason == "update") { - console.log("An update has been installed."); + iConsole.log("An update has been installed."); resetLastSyncTimestamp(normalStorage); resetLastSyncTimestamp(incognitoStorage); removeUnusedOptions(); diff --git a/background/options.js b/background/options.js index 3efea2a..d80dfc5 100644 --- a/background/options.js +++ b/background/options.js @@ -43,22 +43,22 @@ function tryFetchIntraUsername(improvedStorage) { .then(function(metaBody) { const _userIndex = metaBody.indexOf("this._user"); const _consumerAddress = metaBody.indexOf("this._consumer_address"); - console.log("Now trying to parse username from meta.intra.42.fr..."); + iConsole.log("Now trying to parse username from meta.intra.42.fr..."); if (_userIndex > -1) { let toParse = metaBody.substring(_userIndex, _consumerAddress); - console.log(toParse); + iConsole.log(toParse); const startOfObj = toParse.indexOf("{"); const endOfObj = toParse.indexOf("}"); if (startOfObj < -1) { reject("Could not find start of _user object"); } toParse = toParse.substring(startOfObj, endOfObj + 1); - console.log(toParse); + iConsole.log(toParse); const jsonUser = JSON.parse(toParse); if ("login" in jsonUser) { - console.log("Hooray, found logged in user! Hello, " + jsonUser["login"] + "!"); + iConsole.log("Hooray, found logged in user! Hello, " + jsonUser["login"] + "!"); improvedStorage.set({username: jsonUser["login"]}).then(function() { - console.log("Set username in " + improvedStorage.getType() + " storage"); + iConsole.log("Set username in " + improvedStorage.getType() + " storage"); resolve(jsonUser["login"]); }); } @@ -79,10 +79,10 @@ function tryFetchIntraUsername(improvedStorage) { function removeUnusedOptions() { if (noLongerUsedOptions.length > 0) { normalStorage.remove(noLongerUsedOptions).then(function() { - console.log("Removed no longer used options from normal storage"); + iConsole.log("Removed no longer used options from normal storage"); }); incognitoStorage.remove(noLongerUsedOptions).then(function() { - console.log("Removed no longer used options from incognito storage"); + iConsole.log("Removed no longer used options from incognito storage"); }); } } @@ -97,7 +97,7 @@ function setOptionsIfUnset(improvedStorage) { for (const key in defaults) { if (data[key] === undefined) { improvedStorage.set({[key]: defaults[key]}, function() { - console.log("Default setting with key " + key + " created in " + improvedStorage.getType() + " storage (value: " + defaults[key] + ")"); + iConsole.log("Default setting with key " + key + " created in " + improvedStorage.getType() + " storage (value: " + defaults[key] + ")"); }); } } @@ -106,7 +106,7 @@ function setOptionsIfUnset(improvedStorage) { function getSettingsFromSyncServer(improvedStorage, username) { return new Promise(function(resolve, reject) { - console.log("Retrieving settings of username " + username + " for " + improvedStorage.getType()); + iConsole.log("Retrieving settings of username " + username + " for " + improvedStorage.getType()); fetch("https://darkintra.freekb.es/settings/" + username + ".json?noCache=" + Math.random()) .then(function(response) { if (response.status == 404) { @@ -121,7 +121,7 @@ function getSettingsFromSyncServer(improvedStorage, username) { }) .then(function(json) { if (json != null) { - console.log("Storing settings in " + improvedStorage.getType() + " storage..."); + iConsole.log("Storing settings in " + improvedStorage.getType() + " storage..."); improvedStorage.set(json).then(function() { improvedStorage.set({ "last-sync": new Date().getTime() }).then(function() { resolve(json); @@ -152,6 +152,6 @@ function fetchUserSettings(improvedStorage) { messagePortsOfType(storageType, { action: "options-changed", settings: settings }); }) .catch(function(err) { - console.error("Could not parse username and synchronize settings", err); + iConsole.error("Could not parse username and synchronize settings", err); }); } diff --git a/build.sh b/build.sh index 03a2fee..bb8e101 100755 --- a/build.sh +++ b/build.sh @@ -1,18 +1,18 @@ #!/bin/bash if [[ $OSTYPE == 'darwin'* ]] || [[ $OSTYPE == 'linux-gnu' ]]; then rm -f chromium.zip firefox.zip - zip -r chromium.zip manifest.json LICENSE PRIVACY-POLICY.md sw.js background/* js/* options/* css/* campus_specifics/* images/logo*.png _locales/* + zip -r chromium.zip manifest.json LICENSE PRIVACY-POLICY.md sw.js background/* features/* fixes/* generic/* options/* images/logo*.png _locales/* mv manifest.json manifest-chromium.json mv manifest-ff.json manifest.json - zip -r firefox.zip manifest.json LICENSE PRIVACY-POLICY.md background/* js/* options/* css/* campus_specifics/* images/logo*.png _locales/* + zip -r firefox.zip manifest.json LICENSE PRIVACY-POLICY.md background/* features/* fixes/* generic/* options/* images/logo*.png _locales/* mv manifest.json manifest-ff.json mv manifest-chromium.json manifest.json else rm -f chromium.zip firefox.zip - 7z a chromium.zip manifest.json LICENSE PRIVACY-POLICY.md sw.js background/* js/* options/* css/* campus_specifics/* images/logo*.png _locales/* + 7z a chromium.zip manifest.json LICENSE PRIVACY-POLICY.md sw.js background/* features/* fixes/* generic/* options/* images/logo*.png _locales/* mv manifest.json manifest-chromium.json mv manifest-ff.json manifest.json - 7z a firefox.zip manifest.json LICENSE PRIVACY-POLICY.md background/* js/* options/* css/* campus_specifics/* images/logo*.png _locales/* + 7z a firefox.zip manifest.json LICENSE PRIVACY-POLICY.md background/* features/* fixes/* generic/* options/* images/logo*.png _locales/* mv manifest.json manifest-ff.json mv manifest-chromium.json manifest.json fi diff --git a/js/admin.js b/features/admin.js similarity index 100% rename from js/admin.js rename to features/admin.js diff --git a/campus_specifics/codam/coa-titles.js b/features/campus/codam/coa-titles.js similarity index 85% rename from campus_specifics/codam/coa-titles.js rename to features/campus/codam/coa-titles.js index 773f8f4..ce96758 100644 --- a/campus_specifics/codam/coa-titles.js +++ b/features/campus/codam/coa-titles.js @@ -20,13 +20,13 @@ function autoEquipCoaTitle(loggedInUserName) { var titleSelectButton = headerLoginName.parentNode; if (!titleSelectButton || titleSelectButton.nodeName != "BUTTON") { - console.warn("No title select button, but auto-equipping coalition titles is enabled!"); + iConsole.warn("No title select button, but auto-equipping coalition titles is enabled!"); return; } var titleSelectDropdown = titleSelectButton.nextElementSibling; if (!titleSelectDropdown || titleSelectDropdown.nodeName != "UL") { - console.warn("No title select dropdown, but auto-equipping coalition titles is enabled!"); + iConsole.warn("No title select dropdown, but auto-equipping coalition titles is enabled!"); return; } @@ -36,15 +36,15 @@ function autoEquipCoaTitle(loggedInUserName) { var userTitles = titleSelectDropdown.querySelectorAll("a[href*=\"/titles_users/\"]"); for (var i = 0; i < userTitles.length; i++) { if (userTitles[i].textContent.match(coaTitleRegex)) { - console.log("Found coalition title! Equipping by clicking on it..."); - console.log(userTitles[i]); + iConsole.log("Found coalition title! Equipping by clicking on it..."); + iConsole.log(userTitles[i]); userTitles[i].click(); break; } } } else { - console.log("Coalition title is already equipped, not equipping now."); + iConsole.log("Coalition title is already equipped, not equipping now."); } } diff --git a/campus_specifics/codam/monit.css b/features/campus/codam/monit.css similarity index 100% rename from campus_specifics/codam/monit.css rename to features/campus/codam/monit.css diff --git a/campus_specifics/codam/monit.js b/features/campus/codam/monit.js similarity index 95% rename from campus_specifics/codam/monit.js rename to features/campus/codam/monit.js index d098fff..4bf505c 100644 --- a/campus_specifics/codam/monit.js +++ b/features/campus/codam/monit.js @@ -66,7 +66,7 @@ var monit = { for (var i = 0; i <= monit.dayOfWeek; i++) { thisWeek.push(new Date(timestamp - 86400000 * i).toISOString().split("T")[0]); } - console.log("This week's dates: ", thisWeek); + iConsole.log("This week's dates: ", thisWeek); return (thisWeek); }, @@ -91,9 +91,9 @@ var monit = { else { this.requirements.today = logTimesTotalNoToday + Math.round((this.requirements.min - logTimesTotalNoToday) / (7 - this.dayOfWeek)); } - console.log("Logtime up until today", logTimesTotalNoToday); - console.log("Expected minutes today", this.requirements.today - logTimesTotalNoToday); - console.log("Expected minutes after today", this.requirements.today); + iConsole.log("Logtime up until today", logTimesTotalNoToday); + iConsole.log("Expected minutes today", this.requirements.today - logTimesTotalNoToday); + iConsole.log("Expected minutes after today", this.requirements.today); }, /** @@ -292,10 +292,10 @@ var monit = { this.getLogTimes() .then(this.writeProgress) .catch(function(err) { - console.warn("Could not read logtimes chart:", err); + iConsole.warn("Could not read logtimes chart:", err); monit.getLogTimesWeb(monit.username).then(monit.writeProgress) .catch(function(err) { - console.error("Could not retrieve logtimes from the web", err); + iConsole.error("Could not retrieve logtimes from the web", err); }); }); }, @@ -340,8 +340,8 @@ var monit = { writeProgress: function() { monit.getStatus().then(function(status) { monit.setExpected(); - console.log("Logtimes", monit.logTimes); - console.log("Total minutes", monit.logTimesTotal); + iConsole.log("Logtimes", monit.logTimes); + iConsole.log("Total minutes", monit.logTimesTotal); var aguDate = document.getElementById("agu-date"); if (aguDate && aguDate.className.indexOf("hidden") == -1) { @@ -351,13 +351,13 @@ var monit = { var atLeastRelaxed = false; var partTimeCheck = document.querySelectorAll("a.project-item.block-item[href*='part_time'][data-cursus='42cursus']"); if (partTimeCheck.length > 0 || status["monitoring_system_active"] === false) { - console.log("User is working on Part-Time project or monitoring system is currently disabled, emote will be at least relaxed"); + iConsole.log("User is working on Part-Time project or monitoring system is currently disabled, emote will be at least relaxed"); atLeastRelaxed = true; } var availableStatus = document.querySelector(".user-poste-status"); if (availableStatus && availableStatus.innerText == "Available") { - console.log("User is currently available, emote will be at least relaxed"); + iConsole.log("User is currently available, emote will be at least relaxed"); atLeastRelaxed = true; } diff --git a/js/mlx42.js b/features/mlx42.js similarity index 100% rename from js/mlx42.js rename to features/mlx42.js diff --git a/js/profiles.js b/features/profiles.js similarity index 97% rename from js/profiles.js rename to features/profiles.js index 97550a5..cc0157b 100644 --- a/js/profiles.js +++ b/features/profiles.js @@ -36,11 +36,11 @@ function getUserSettings(username) { resolve(gUserSettings); return; } - console.log("Retrieving settings of username " + username); + iConsole.log("Retrieving settings of username " + username); fetch("https://darkintra.freekb.es/settings/" + username + ".json?noCache=" + Math.random()) .then(function(response) { if (response.status == 404) { - console.log("No settings found on the sync server for this username"); + iConsole.log("No settings found on the sync server for this username"); return null; } else if (!response.ok) { @@ -83,7 +83,7 @@ function setCustomBanner(imageUrl, imagePos) { gProfileBanner.style.backgroundPosition = "center bottom"; break; } - console.log("Custom banner set!"); + iConsole.log("Custom banner set!"); } return (true); } @@ -94,7 +94,7 @@ function unsetCustomBannerIfRequired() { if (gProfileBanner.getAttribute("data-old-bg")) { gProfileBanner.style.backgroundImage = gProfileBanner.getAttribute("data-old-bg"); gProfileBanner.removeAttribute("data-old-bg"); - console.log("Custom banner unset"); + iConsole.log("Custom banner unset"); } } diff --git a/css/theme-apply.css b/features/themes/apply.css similarity index 100% rename from css/theme-apply.css rename to features/themes/apply.css diff --git a/css/colors-cetus.css b/features/themes/colors/cetus.css similarity index 94% rename from css/colors-cetus.css rename to features/themes/colors/cetus.css index c471db0..2c10b45 100644 --- a/css/colors-cetus.css +++ b/features/themes/colors/cetus.css @@ -1,7 +1,7 @@ /* ************************************************************************** */ /* */ /* :::::::: */ -/* colors-cetus.css :+: :+: */ +/* cetus.css :+: :+: */ /* +:+ */ /* By: fbes +#+ */ /* +#+ */ diff --git a/css/colors-pyxis.css b/features/themes/colors/pyxis.css similarity index 94% rename from css/colors-pyxis.css rename to features/themes/colors/pyxis.css index 8155633..544b851 100644 --- a/css/colors-pyxis.css +++ b/features/themes/colors/pyxis.css @@ -1,7 +1,7 @@ /* ************************************************************************** */ /* */ /* :::::::: */ -/* colors-pyxis.css :+: :+: */ +/* pyxis.css :+: :+: */ /* +:+ */ /* By: fbes +#+ */ /* +#+ */ diff --git a/css/colors-vela.css b/features/themes/colors/vela.css similarity index 94% rename from css/colors-vela.css rename to features/themes/colors/vela.css index f895198..b818f11 100644 --- a/css/colors-vela.css +++ b/features/themes/colors/vela.css @@ -1,7 +1,7 @@ /* ************************************************************************** */ /* */ /* :::::::: */ -/* colors-vela.css :+: :+: */ +/* vela.css :+: :+: */ /* +:+ */ /* By: fbes +#+ */ /* +#+ */ diff --git a/css/theme-dark.css b/features/themes/dark.css similarity index 100% rename from css/theme-dark.css rename to features/themes/dark.css diff --git a/css/theme-light.css b/features/themes/light.css similarity index 100% rename from css/theme-light.css rename to features/themes/light.css diff --git a/js/theme.js b/features/themes/loader.js similarity index 85% rename from js/theme.js rename to features/themes/loader.js index d211f9e..67cf2e5 100644 --- a/js/theme.js +++ b/features/themes/loader.js @@ -1,7 +1,7 @@ /* ************************************************************************** */ /* */ /* :::::::: */ -/* theme.js :+: :+: */ +/* loader.js :+: :+: */ /* +:+ */ /* By: fbes +#+ */ /* +#+ */ @@ -31,14 +31,14 @@ function disableTheme(theme, colors) { * Enable a theme, leave colors as null or undefined to use default color scheme */ function enableTheme(theme, colors) { - console.log("%c[Improved Intra]%c Enabling theme '" + theme + "'" + (colors ? " in '" + colors + "' mode..." : ""), "color: #00babc;", ""); + iConsole.log("Enabling theme '" + theme + "'" + (colors ? " in '" + colors + "' mode..." : "")); if (!themeLink) { themeLink = document.createElement("link"); themeLink.setAttribute("type", "text/css"); themeLink.setAttribute("rel", "stylesheet"); document.getElementsByTagName("head")[0].appendChild(themeLink); } - themeLink.setAttribute("href", chrome.runtime.getURL("css/theme-"+theme+".css")); + themeLink.setAttribute("href", chrome.runtime.getURL("features/themes/"+theme+".css")); if (colors && colors !== "default") { if (!themeColorsLink) { @@ -47,7 +47,7 @@ function enableTheme(theme, colors) { themeColorsLink.setAttribute("rel", "stylesheet"); document.getElementsByTagName("head")[0].appendChild(themeColorsLink); } - themeColorsLink.setAttribute("href", chrome.runtime.getURL("css/colors-"+colors+".css")); + themeColorsLink.setAttribute("href", chrome.runtime.getURL("features/themes/colors/"+colors+".css")); } else { disableTheme(false, true); @@ -75,7 +75,7 @@ function checkThemeSetting() { } window.matchMedia("(prefers-color-scheme: dark)").addEventListener("change", function() { - console.log("%c[Improved Intra]%c @media rule prefers-color-scheme changed", "color: #00babc;", ""); + iConsole.log("@media rule prefers-color-scheme changed"); checkThemeSetting(); }); diff --git a/css/animations.css b/fixes/animations.css similarity index 100% rename from css/animations.css rename to fixes/animations.css diff --git a/css/improv.css b/fixes/improv.css similarity index 100% rename from css/improv.css rename to fixes/improv.css diff --git a/js/improv.js b/fixes/improv.js similarity index 97% rename from js/improv.js rename to fixes/improv.js index b1c6c67..263017c 100644 --- a/js/improv.js +++ b/fixes/improv.js @@ -226,7 +226,7 @@ function setGeneralImprovements() { return; } clearInterval(bhColorTimer); - console.log("Black Hole days remaining: ", daysRemaining); + iConsole.log("Black Hole days remaining: ", daysRemaining); improvedStorage.get("old-blackhole").then(function(data) { if (data["old-blackhole"] === true || data["old-blackhole"] === "true") { bhDate.parentNode.setAttribute("data-original-title", bhDate.innerText); @@ -363,17 +363,17 @@ setOptionalImprovements(); // communication between background.js and this script let improvPort = chrome.runtime.connect({ name: portName }); improvPort.onDisconnect.addListener(function() { - console.log("%c[Improved Intra]%c Disconnected from service worker", "color: #00babc;", ""); + iConsole.log("Disconnected from service worker"); }); improvPort.onMessage.addListener(function(msg) { switch (msg["action"]) { case "pong": - console.log("pong"); + iConsole.log("pong"); break; case "resynced": case "prefers-color-scheme-change": case "options-changed": - console.log("%c[Improved Intra]%c Settings changed. Enabling settings that can be enabled. Settings that must be disabled, will disable after a refresh.", "color: #00babc;", ""); + iConsole.log("Settings changed. Enabling settings that can be enabled. Settings that must be disabled, will disable after a refresh."); checkThemeSetting(); setOptionalImprovements(); colorizeLogtimeChart(); @@ -382,7 +382,7 @@ improvPort.onMessage.addListener(function(msg) { } break; case "error": - console.error(msg["message"]); + iConsole.error(msg["message"]); break; } }); diff --git a/generic/console.js b/generic/console.js new file mode 100644 index 0000000..182e5ef --- /dev/null +++ b/generic/console.js @@ -0,0 +1,26 @@ +/* ************************************************************************** */ +/* */ +/* :::::::: */ +/* console.js :+: :+: */ +/* +:+ */ +/* By: fbes +#+ */ +/* +#+ */ +/* Created: 2022/03/27 14:57:20 by fbes #+# #+# */ +/* Updated: 2022/03/27 14:57:20 by fbes ######## odam.nl */ +/* */ +/* ************************************************************************** */ + +function ImprovedConsole() { + for (let c in console) { + if (typeof console[c] == 'function') { + this[c] = console[c].bind(console, "%c[Improved Intra]%c", "color: #00babc;", ""); + } + } + + // overwrite time functions, they do not support styling with %c + this["time"] = console.time.bind(console, "[Improved Intra]"); + this["timeLog"] = console.timeLog.bind(console, "[Improved Intra]"); + this["timeEnd"] = console.timeEnd.bind(console, "[Improved Intra]"); +} + +const iConsole = new ImprovedConsole(); diff --git a/js/init.js b/generic/init.js similarity index 96% rename from js/init.js rename to generic/init.js index ca689d7..be6d224 100644 --- a/js/init.js +++ b/generic/init.js @@ -17,7 +17,7 @@ // only inject it on the subdomains of *.intra.42.fr if (window.location.origin.indexOf(".intra.42.fr") > -1) { const s = document.createElement('script'); - s.src = chrome.runtime.getURL('js/inject.js'); + s.src = chrome.runtime.getURL('generic/inject.js'); (document.head || document.documentElement).appendChild(s); } diff --git a/js/inject.js b/generic/inject.js similarity index 83% rename from js/inject.js rename to generic/inject.js index a4120fc..bea83b6 100644 --- a/js/inject.js +++ b/generic/inject.js @@ -11,9 +11,9 @@ /* ************************************************************************** */ function addToolTip(query) { - console.log("Adding tooltip to element " + query); - var actualCode = '$("'+query+'").tooltip();'; - var script = document.createElement('script'); + console.log("%c[Improved Intra %cinject.js]%c Adding tooltip to element " + query, "color: #00babc;", "color: #02807c;", ""); + const actualCode = '$("'+query+'").tooltip();'; + const script = document.createElement('script'); script.appendChild(document.createTextNode(actualCode)); (document.head || document.documentElement).appendChild(script); script.parentNode.removeChild(script); diff --git a/css/internal.css b/generic/internal.css similarity index 100% rename from css/internal.css rename to generic/internal.css diff --git a/background/storage.js b/generic/storage.js similarity index 100% rename from background/storage.js rename to generic/storage.js diff --git a/manifest-ff.json b/manifest-ff.json index d079faf..7a3e506 100644 --- a/manifest-ff.json +++ b/manifest-ff.json @@ -34,35 +34,35 @@ ], "web_accessible_resources": [ "options/options.html", - "css/theme-apply.css", - "css/theme-light.css", - "css/theme-dark.css", - "css/colors-cetus.css", - "css/colors-pyxis.css", - "css/colors-vela.css", - "js/inject.js" + "features/themes/apply.css", + "features/themes/light.css", + "features/themes/dark.css", + "features/themes/colors/cetus.css", + "features/themes/colors/pyxis.css", + "features/themes/colors/vela.css", + "generic/inject.js" ], "content_scripts": [ { - "matches": [ "*://darkintra.freekb.es/*", "*://*.intra.42.fr/*" ], - "js": [ "background/storage.js", "js/init.js" ], + "matches": [ "*://*.intra.42.fr/*", "*://darkintra.freekb.es/*" ], + "js": [ "generic/console.js", "generic/storage.js", "generic/init.js" ], "run_at": "document_start" }, { "matches": [ "*://darkintra.freekb.es/*" ], - "css": [ "css/internal.css", "css/animations.css" ], - "js": [ "js/theme.js" ], + "css": [ "generic/internal.css", "fixes/animations.css" ], + "js": [ "features/themes/loader.js" ], "run_at": "document_start" }, { "matches": [ "*://*.intra.42.fr/*" ], - "css": [ "css/improv.css", "css/animations.css", "css/theme-apply.css" ], - "js": [ "js/theme.js" ], + "css": [ "fixes/improv.css", "fixes/animations.css", "features/themes/apply.css" ], + "js": [ "features/themes/loader.js" ], "run_at": "document_start" }, { "matches": [ "*://*.intra.42.fr/*" ], - "js": [ "js/improv.js" ], + "js": [ "fixes/improv.js" ], "run_at": "document_end" }, { @@ -80,20 +80,25 @@ "js": [ "options/auth.js" ], "run_at": "document_end" }, + { + "matches": [ "*://darkintra.freekb.es/options.php*" ], + "js": [ "options/options.js" ], + "run_at": "document_end" + }, { "matches": [ "*://profile.intra.42.fr/", "*://*.intra.42.fr/users/*" ], - "js": [ "js/profiles.js" ], + "js": [ "features/profiles.js" ], "run_at": "document_idle" }, { "matches": [ "https://admin.intra.42.fr/*" ], - "js": [ "js/admin.js" ], + "js": [ "features/admin.js" ], "run_at": "document_end" }, { "matches": [ "*://profile.intra.42.fr/", "*://*.intra.42.fr/users/*" ], - "js": [ "campus_specifics/codam/monit.js" ], - "css": [ "campus_specifics/codam/monit.css" ], + "js": [ "features/campus/codam/monit.js", "features/campus/codam/coa-titles.js" ], + "css": [ "features/campus/codam/monit.css" ], "run_at": "document_idle" }, { @@ -109,14 +114,15 @@ "https://projects.intra.42.fr/projects/42cursus-fract-ol/*", "https://projects.intra.42.fr/42cursus-fract-ol/*" ], - "js": [ "js/mlx42.js" ], + "js": [ "features/mlx42.js" ], "run_at": "document_end" } ], "background": { "scripts": [ + "generic/console.js", "background/main.js", - "background/storage.js", + "generic/storage.js", "background/comm.js", "background/options.js" ] diff --git a/manifest.json b/manifest.json index 565a0af..df66b39 100644 --- a/manifest.json +++ b/manifest.json @@ -25,13 +25,13 @@ "web_accessible_resources": [ { "resources": [ - "js/inject.js", - "css/theme-apply.css", - "css/theme-light.css", - "css/theme-dark.css", - "css/colors-cetus.css", - "css/colors-pyxis.css", - "css/colors-vela.css", + "generic/inject.js", + "features/themes/apply.css", + "features/themes/light.css", + "features/themes/dark.css", + "features/themes/colors/cetus.css", + "features/themes/colors/pyxis.css", + "features/themes/colors/vela.css", "options/options.html" ], "matches": [ "*://*.intra.42.fr/*", "*://darkintra.freekb.es/*" ] @@ -40,24 +40,24 @@ "content_scripts": [ { "matches": [ "*://*.intra.42.fr/*", "*://darkintra.freekb.es/*" ], - "js": [ "background/storage.js", "js/init.js" ], + "js": [ "generic/console.js", "generic/storage.js", "generic/init.js" ], "run_at": "document_start" }, { "matches": [ "*://darkintra.freekb.es/*" ], - "css": [ "css/internal.css", "css/animations.css" ], - "js": [ "js/theme.js" ], + "css": [ "generic/internal.css", "fixes/animations.css" ], + "js": [ "features/themes/loader.js" ], "run_at": "document_start" }, { "matches": [ "*://*.intra.42.fr/*" ], - "css": [ "css/improv.css", "css/animations.css", "css/theme-apply.css" ], - "js": [ "js/theme.js" ], + "css": [ "fixes/improv.css", "fixes/animations.css", "features/themes/apply.css" ], + "js": [ "features/themes/loader.js" ], "run_at": "document_start" }, { "matches": [ "*://*.intra.42.fr/*" ], - "js": [ "js/improv.js" ], + "js": [ "fixes/improv.js" ], "run_at": "document_end" }, { @@ -82,18 +82,18 @@ }, { "matches": [ "*://profile.intra.42.fr/", "*://*.intra.42.fr/users/*" ], - "js": [ "js/profiles.js" ], + "js": [ "features/profiles.js" ], "run_at": "document_idle" }, { "matches": [ "https://admin.intra.42.fr/*" ], - "js": [ "js/admin.js" ], + "js": [ "features/admin.js" ], "run_at": "document_end" }, { "matches": [ "*://profile.intra.42.fr/", "*://*.intra.42.fr/users/*" ], - "js": [ "campus_specifics/codam/monit.js", "campus_specifics/codam/coa-titles.js" ], - "css": [ "campus_specifics/codam/monit.css" ], + "js": [ "features/campus/codam/monit.js", "features/campus/codam/coa-titles.js" ], + "css": [ "features/campus/codam/monit.css" ], "run_at": "document_idle" }, { @@ -109,7 +109,7 @@ "https://projects.intra.42.fr/projects/42cursus-fract-ol/*", "https://projects.intra.42.fr/42cursus-fract-ol/*" ], - "js": [ "js/mlx42.js" ], + "js": [ "features/mlx42.js" ], "run_at": "document_end" } ], diff --git a/options/auth.js b/options/auth.js index 99b9080..e76bbac 100644 --- a/options/auth.js +++ b/options/auth.js @@ -12,19 +12,19 @@ let authPort = chrome.runtime.connect({ name: portName }); authPort.onDisconnect.addListener(function() { - console.log("%c[Improved Intra]%c Disconnected from service worker", "color: #00babc;", ""); + iConsole.log("Disconnected from service worker"); }); authPort.onMessage.addListener(function(msg) { switch (msg["action"]) { case "pong": - console.log("pong"); + iConsole.log("pong"); break; case "resynced": - console.log("Options resynced."); + iConsole.log("Options resynced."); window.location.replace(optionsURL); break; case "error": - console.error(msg["message"]); + iConsole.error(msg["message"]); break; } }); @@ -60,17 +60,17 @@ if (authResElem) { improvedStorage.set(authRes).then(function() { improvedStorage.set({"username": authRes["user"]["login"]}).then(function() { - console.log("%c[Improved Intra]%c Authentication details saved in local storage!", "color: #00babc;", ""); + iConsole.log("Authentication details saved in local storage!"); authPort.postMessage({ action: "resync" }); }); }); } else { - console.error("Error " + authRes["auth"]["error"] + ":", authRes["auth"]["error_description"]); + iConsole.error("Error " + authRes["auth"]["error"] + ":", authRes["auth"]["error_description"]); } } catch (err) { - console.error(err); + iConsole.error(err); alert("Unable to retrieve authentication details. Could not authorize in extension's scope. See the Javascript console for details."); } } diff --git a/options/options.js b/options/options.js index 363b83d..359660d 100644 --- a/options/options.js +++ b/options/options.js @@ -55,22 +55,22 @@ function showSettingsSavedNotif() { var optionsPort = chrome.runtime.connect({ name: portName }); optionsPort.onDisconnect.addListener(function() { - console.log("%c[Improved Intra]%c Disconnected from service worker", "color: #00babc;", ""); + iConsole.log("Disconnected from service worker"); }); optionsPort.onMessage.addListener(function(msg) { switch (msg["action"]) { case "pong": - console.log("pong"); + iConsole.log("pong"); break; case "options-changed": loadSettingsIntoForm(msg["settings"]); break; case "resynced": - console.log("Options resynced."); + iConsole.log("Options resynced."); window.location.reload(); break; case "error": - console.error(msg["message"]); + iConsole.error(msg["message"]); break; } }); @@ -90,7 +90,7 @@ function storeSettingsAndUpdateForm(newSettings) { } function syncSettings(event) { - console.log("Syncing settings..."); + iConsole.log("Syncing settings..."); if (event) { event.preventDefault(); } @@ -123,7 +123,7 @@ function syncSettings(event) { formData.set(key, value.trim()); } }); - console.log(settingsObj); + iConsole.log(settingsObj); // store on sync server if sync is enabled if (settingsObj["sync"] === "true") { @@ -141,10 +141,10 @@ function syncSettings(event) { try { var res = JSON.parse(this.responseText); if (res["type"] == "error") { - console.error("Settings sync result", res); + iConsole.error("Settings sync result", res); } else { - console.log("Settings sync result", res); + iConsole.log("Settings sync result", res); } if (res["data"]) { storeSettingsAndUpdateForm(res["data"]); @@ -154,12 +154,12 @@ function syncSettings(event) { } } catch (err) { - console.error("Could not parse settings sync result!", err); + iConsole.error("Could not parse settings sync result!", err); storeSettingsAndUpdateForm(settingsObj); } }); req.addEventListener("error", function(err) { - console.error("Could not sync settings", err); + iConsole.error("Could not sync settings", err); storeSettingsAndUpdateForm(settingsObj); }); req.send(formData); @@ -184,10 +184,10 @@ function syncSettings(event) { syncBtn.className = ""; try { var res = JSON.parse(this.responseText); - console.log("Settings deletion result", res); + iConsole.log("Settings deletion result", res); } catch (err) { - console.error("Could not parse settings deletion result!", err); + iConsole.error("Could not parse settings deletion result!", err); } }); req.send(formData); @@ -195,7 +195,7 @@ function syncSettings(event) { improvedStorage.set(settingsObj).then(function() { improvedStorage.set({ "last-sync": new Date().getTime() }, function() { - console.log("Settings stored locally"); + iConsole.log("Settings stored locally"); if (optionsPort) { optionsPort.postMessage({ action: "options-changed", settings: settingsObj }); } @@ -214,7 +214,7 @@ function retrieveSettings() { for (var i = 0; i < formElems.length; i++) { keysToGet.push(formElems[i].getAttribute("name")); } - console.log(keysToGet); + iConsole.log(keysToGet); improvedStorage.get(keysToGet).then(function(data) { resolve(data); }); @@ -226,7 +226,7 @@ function retrieveSettings() { } function loadSettingsIntoForm(settings) { - console.log("Settings fetched somewhere", settings); + iConsole.log("Settings fetched somewhere", settings); var key, settingElem; for (key in settings) { settingElem = document.getElementsByName(key); @@ -235,7 +235,7 @@ function loadSettingsIntoForm(settings) { improvedStorage.set({[key]: settings[key]}); } else { - console.warn("Found unknown setting key '" + key + "'"); + iConsole.warn("Found unknown setting key '" + key + "'"); continue; } if (settingElem.nodeName == "SELECT") { @@ -253,7 +253,7 @@ function loadSettingsIntoForm(settings) { } } else { - console.warn("Unknown nodetype for setting: " + settingElem.nodeName); + iConsole.warn("Unknown nodetype for setting: " + settingElem.nodeName); continue; } } @@ -270,7 +270,7 @@ function loadSettingsIntoForm(settings) { } window.onload = function() { - console.log("Initializing options page..."); + iConsole.log("Initializing options page..."); var i; var formElems = document.querySelectorAll("form select, form input"); @@ -313,7 +313,7 @@ window.onload = function() { }); improvedStorage.get(["username", "auth", "user"]).then(function(data) { - console.log(data); + iConsole.log(data); if (data["username"] === undefined || data["auth"] === undefined || data["user"] == undefined || data["user"]["login"] != data["username"]) { // authorize user on Intra, link below redirects to the correct auth page @@ -322,16 +322,16 @@ window.onload = function() { else { checkIfKeyStillWorks(data["auth"]["access_token"]) .then(function() { - console.log("Access token still works."); + iConsole.log("Access token still works."); retrieveSettings() .then(loadSettingsIntoForm) .catch(function(err) { - console.error("Could not load settings from local storage.", err); + iConsole.error("Could not load settings from local storage.", err); alert("Failed to load settings"); }); }) .catch(function(res) { - console.log("Access token no longer works!", res); + iConsole.log("Access token no longer works!", res); // authorize user again on Intra, link below redirects to the correct auth page window.location.replace("https://darkintra.freekb.es/connect.php"); }); diff --git a/options/sync.js b/options/sync.js index a6ad8b5..8c66c98 100644 --- a/options/sync.js +++ b/options/sync.js @@ -21,18 +21,18 @@ function getLoggedInUserName() { var syncPort = chrome.runtime.connect({ name: portName }); syncPort.onDisconnect.addListener(function() { - console.log("%c[Improved Intra]%c Disconnected from service worker", "color: #00babc;", ""); + iConsole.log("Disconnected from service worker"); }); syncPort.onMessage.addListener(function(msg) { switch (msg["action"]) { case "pong": - console.log("pong"); + iConsole.log("pong"); break; case "resynced": - console.log("%c[Improved Intra]%c Resync done.", "color: #00babc;", ""); + iConsole.log("Resync done"); break; case "error": - console.error(msg["message"]); + iConsole.error(msg["message"]); break; } }); @@ -49,12 +49,12 @@ improvedStorage.get(["last-sync", "username"]).then(function(data) { if (!data["username"] || !data["last-sync"] || parseInt(data["last-sync"]) - curTime < -3600000 || (curUsername != data["username"] && curUsername != null)) { // a new user logged in! improvedStorage.set({"username": curUsername}).then(function() { - console.log("%c[Improved Intra]%c Intra username stored in local storage, now resyncing settings...", "color: #00babc;", ""); + iConsole.log("Intra username stored in local storage, now resyncing settings..."); syncPort.postMessage({ action: "resync" }); }); } else { const lastSync = new Date(parseInt(data["last-sync"])); - console.log("%c[Improved Intra]%c Hello there, " + curUsername + "! Your settings have last been synced on " + lastSync.toString(), "color: #00babc;", ""); + iConsole.log("Hello there, " + curUsername + "! Your settings have last been synced on " + lastSync.toString()); } }); diff --git a/options/unsync.js b/options/unsync.js index 3dc3a40..cb0d199 100644 --- a/options/unsync.js +++ b/options/unsync.js @@ -13,5 +13,5 @@ // these functions are run when signing out from Intranet at https://intra.42.fr improvedStorage.remove("username").then(function() { - console.log("Signed out from Intra, so removed the username to synchronize with. Settings will be kept locally, until another person signs in."); + iConsole.log("Signed out from Intra, so removed the username to synchronize with. Settings will be kept locally, until another person signs in."); }); diff --git a/server/connect.php b/server/connect.php index 0c894ea..eb5f184 100644 --- a/server/connect.php +++ b/server/connect.php @@ -17,6 +17,79 @@ function respond($type, $msg, $data = null) { Connect Improved Intra 42 with your Intranet account + + diff --git a/sw.js b/sw.js index 49b42f6..e246bcd 100644 --- a/sw.js +++ b/sw.js @@ -17,12 +17,13 @@ try { importScripts( + "generic/console.js", "background/main.js", - "background/storage.js", + "generic/storage.js", "background/comm.js", "background/options.js" ); } catch (err) { - console.error(err); + iConsole.error(err); } diff --git a/todo.txt b/todo.txt index 3b97ab3..d13c4be 100644 --- a/todo.txt +++ b/todo.txt @@ -3,15 +3,17 @@ Manifest v3 options overview: https://developer.chrome.com/docs/extensions/mv3/m TODO: - convert every var to either const or let -- create themes folder and move all theme-related stuff in there -- create profile customization folder and move all profile customization stuff in there -- create improvements folder and move all improvements into there (maybe separate some improvements?) - create way to report user customization features to the server - create way to see user reports when logged in with an Intra staff account - reorganize manifests +- separate some improvements - split up Codam Monitoring System's cumulative hours and the actual thing into ft_logtime like feature and the previous actual thing - more security background checks for the server back-end with the Intra API: store generated keys in a non-public database file - implement more cluster maps, maybe even custom ones into the extension itself? DONE: - create backbone structure for local storage and syncing settings, with separate storage for incognito +- create internal console.log function to deal with styling in the console ("[Improved Intra] msg") +- create themes folder and move all theme-related stuff in there +- create improvements folder and move all improvements into there +- fix auto coalition title equipper not working in Firefox From fd698942c23dddc08f098cd98321b40bf4e0bca3 Mon Sep 17 00:00:00 2001 From: Freek Bes <36384333+FreekBes@users.noreply.github.com> Date: Sun, 27 Mar 2022 15:49:42 +0200 Subject: [PATCH 14/45] var to let and const --- features/admin.js | 10 +++---- features/campus/codam/coa-titles.js | 12 ++++---- features/mlx42.js | 10 +++---- features/themes/loader.js | 4 +-- options/auth.js | 12 ++++---- options/options.js | 46 ++++++++++++++--------------- options/sync.js | 2 +- 7 files changed, 47 insertions(+), 49 deletions(-) diff --git a/features/admin.js b/features/admin.js index 96bc57f..ac9dcfa 100644 --- a/features/admin.js +++ b/features/admin.js @@ -16,20 +16,20 @@ custom user banners from Improved Intra (which can be done on a separate website */ window.addEventListener("load", function(event) { - var improvedIntraPageLink = document.createElement("a"); + const improvedIntraPageLink = document.createElement("a"); improvedIntraPageLink.setAttribute("href", "https://darkintra.freekb.es/imagery.php"); improvedIntraPageLink.setAttribute("target", "_self"); improvedIntraPageLink.setAttribute("class", "sidebar-item-link"); - var icon = document.createElement("span"); + const icon = document.createElement("span"); icon.setAttribute("class", "icon-setting-wrenches sidebar-icon"); improvedIntraPageLink.appendChild(icon); - var text = document.createTextNode(" Improved Intra banners"); + const text = document.createTextNode(" Improved Intra banners"); improvedIntraPageLink.appendChild(text); - var sidebarMenuList = document.querySelector(".sidebar-menu-list"); - var sidebarItemLinkPatronages = document.querySelector(".sidebar-menu-list .sidebar-item-link[href=\'/patronages\']"); + const sidebarMenuList = document.querySelector(".sidebar-menu-list"); + const sidebarItemLinkPatronages = document.querySelector(".sidebar-menu-list .sidebar-item-link[href=\'/patronages\']"); if (sidebarItemLinkPatronages) { sidebarMenuList.insertBefore(improvedIntraPageLink, sidebarItemLinkPatronages); } diff --git a/features/campus/codam/coa-titles.js b/features/campus/codam/coa-titles.js index ce96758..58d9dad 100644 --- a/features/campus/codam/coa-titles.js +++ b/features/campus/codam/coa-titles.js @@ -10,21 +10,21 @@ /* */ /* ************************************************************************** */ -var coaTitleRegex = new RegExp(/ \(([0-9]{1,2}(st|nd|rd|th){1}|[ABCDEF]{1})\)/g); +const coaTitleRegex = new RegExp(/ \(([0-9]{1,2}(st|nd|rd|th){1}|[ABCDEF]{1})\)/g); function autoEquipCoaTitle(loggedInUserName) { - var headerLoginName = document.querySelector("span.login[data-login]"); + const headerLoginName = document.querySelector("span.login[data-login]"); if (!headerLoginName || headerLoginName.textContent !== loggedInUserName) { return; } - var titleSelectButton = headerLoginName.parentNode; + const titleSelectButton = headerLoginName.parentNode; if (!titleSelectButton || titleSelectButton.nodeName != "BUTTON") { iConsole.warn("No title select button, but auto-equipping coalition titles is enabled!"); return; } - var titleSelectDropdown = titleSelectButton.nextElementSibling; + const titleSelectDropdown = titleSelectButton.nextElementSibling; if (!titleSelectDropdown || titleSelectDropdown.nodeName != "UL") { iConsole.warn("No title select dropdown, but auto-equipping coalition titles is enabled!"); return; @@ -33,8 +33,8 @@ function autoEquipCoaTitle(loggedInUserName) { // if no title equipped, the element's text content will just be the user's username // otherwise, the textContent will include the title. if a title is present, we do not override it if (headerLoginName.textContent == headerLoginName.getAttribute("data-login")) { - var userTitles = titleSelectDropdown.querySelectorAll("a[href*=\"/titles_users/\"]"); - for (var i = 0; i < userTitles.length; i++) { + const userTitles = titleSelectDropdown.querySelectorAll("a[href*=\"/titles_users/\"]"); + for (let i = 0; i < userTitles.length; i++) { if (userTitles[i].textContent.match(coaTitleRegex)) { iConsole.log("Found coalition title! Equipping by clicking on it..."); iConsole.log(userTitles[i]); diff --git a/features/mlx42.js b/features/mlx42.js index 5a90c05..9b558bd 100644 --- a/features/mlx42.js +++ b/features/mlx42.js @@ -11,24 +11,24 @@ /* ************************************************************************** */ function addMLX42Link() { - var projectAttachments = document.querySelector(".project-attachment-item"); + let projectAttachments = document.querySelector(".project-attachment-item"); if (!projectAttachments) { return; } projectAttachments = projectAttachments.parentNode; - var mlx42item = document.createElement("div"); + const mlx42item = document.createElement("div"); mlx42item.className = "project-attachment-item"; - var mlx42name = document.createElement("h4"); + const mlx42name = document.createElement("h4"); mlx42name.className = "attachment-name"; - var mlx42icon = document.createElement("span"); + const mlx42icon = document.createElement("span"); mlx42icon.className = "icon-file"; mlx42icon.style.marginRight = "4px"; mlx42name.appendChild(mlx42icon); - var mlx42link = document.createElement("a"); + const mlx42link = document.createElement("a"); mlx42link.setAttribute("href", "https://github.com/W2Codam/MLX42"); mlx42link.setAttribute("target", "_blank"); mlx42link.setAttribute("title", "Open-source OpenGL version of MLX by W2Wizard (lde-la-h). This link was added by Improved Intra 42."); diff --git a/features/themes/loader.js b/features/themes/loader.js index 67cf2e5..e029909 100644 --- a/features/themes/loader.js +++ b/features/themes/loader.js @@ -10,8 +10,8 @@ /* */ /* ************************************************************************** */ -var themeColorsLink = null; -var themeLink = null; +let themeColorsLink = null; +let themeLink = null; /** * Disable a theme, set theme or colors to false to not disable those colors diff --git a/options/auth.js b/options/auth.js index e76bbac..7c0f8f4 100644 --- a/options/auth.js +++ b/options/auth.js @@ -33,18 +33,18 @@ setInterval(function() { authPort = chrome.runtime.connect({ name: portName }); }, 250000); -var authResElem = document.getElementById("result"); +const authResElem = document.getElementById("result"); if (authResElem) { try { - var authRes = JSON.parse(authResElem.innerText); + const authRes = JSON.parse(authResElem.innerText); if (!("error" in authRes["auth"])) { - var optionsURL = "https://darkintra.freekb.es/options.php"; - var action = document.getElementById("action"); + const optionsURL = "https://darkintra.freekb.es/options.php"; + const action = document.getElementById("action"); if (action) { action.innerText = "Please wait while we redirect you to the Improved Intra 42 options page..."; } - var redirLink = document.getElementById("redir_link"); + const redirLink = document.getElementById("redir_link"); if (redirLink) { redirLink.setAttribute("href", optionsURL); } @@ -52,7 +52,7 @@ if (authResElem) { // display clickable link in case redirection does not happen // after 2 seconds setTimeout(function() { - var clicker = document.getElementById("clicker"); + const clicker = document.getElementById("clicker"); if (clicker) { clicker.style.display = "block"; } diff --git a/options/options.js b/options/options.js index 359660d..8ee3c8a 100644 --- a/options/options.js +++ b/options/options.js @@ -20,7 +20,7 @@ function hideLoading() { function checkIfKeyStillWorks(access_token) { return new Promise(function(it_works, it_does_not_work) { - var req = new XMLHttpRequest(); + const req = new XMLHttpRequest(); req.open("POST", "https://darkintra.freekb.es/testkey.php?nc="+encodeURIComponent(Math.random())); req.setRequestHeader('Content-type', 'application/x-www-form-urlencoded'); req.addEventListener("load", function(event) { @@ -41,7 +41,7 @@ function checkIfKeyStillWorks(access_token) { }); } -var savedNotifHider = null; +let savedNotifHider = null; function showSettingsSavedNotif() { document.getElementById("saved-notif").style.top = "12px"; if (savedNotifHider) { @@ -53,7 +53,7 @@ function showSettingsSavedNotif() { }, 2000); } -var optionsPort = chrome.runtime.connect({ name: portName }); +let optionsPort = chrome.runtime.connect({ name: portName }); optionsPort.onDisconnect.addListener(function() { iConsole.log("Disconnected from service worker"); }); @@ -95,19 +95,19 @@ function syncSettings(event) { event.preventDefault(); } - var syncBtn = document.getElementById("sync-button"); - var form = document.querySelector('form'); - var formData = new FormData(form); + const syncBtn = document.getElementById("sync-button"); + const form = document.querySelector('form'); + let formData = new FormData(form); // add unchecked checkboxes to formdata (not done by default...) - var uncheckedCheckBoxes = form.querySelectorAll("input[type=checkbox]:not(:checked)"); - for (var i = 0; i < uncheckedCheckBoxes.length; i++) { + const uncheckedCheckBoxes = form.querySelectorAll("input[type=checkbox]:not(:checked)"); + for (let i = 0; i < uncheckedCheckBoxes.length; i++) { formData.set(uncheckedCheckBoxes[i].getAttribute("name"), "false"); } formData.set("sync", "true"); // check file size limits - var bannerUpload = formData.get("custom-banner-upload"); + const bannerUpload = formData.get("custom-banner-upload"); if (bannerUpload && bannerUpload.size > 10000000) { alert("The file you're trying to upload as your custom banner is too big. The file limit is 10MB."); document.getElementById("custom-banner-upload").value = ""; @@ -116,7 +116,7 @@ function syncSettings(event) { } // get js object version for storing in local storage later - var settingsObj = {}; + const settingsObj = {}; formData.forEach(function(value, key) { if (typeof(value) == "string") { settingsObj[key] = value.trim(); @@ -134,7 +134,7 @@ function syncSettings(event) { formData.append("created_at", data["auth"]["created_at"]); formData.append("expires_in", data["auth"]["expires_in"]); formData.append("refresh_token", data["auth"]["refresh_token"]); - var req = new XMLHttpRequest(); + const req = new XMLHttpRequest(); req.open("POST", "https://darkintra.freekb.es/update.php?v=1"); req.addEventListener("load", function(event) { syncBtn.className = ""; @@ -167,6 +167,7 @@ function syncSettings(event) { }); } else { + // check if sync was enabled before, and if so, delete the user's data from the server improvedStorage.get(["sync", "auth"]).then(function(data) { if ((data["sync"] === true || data["sync"] === "true") && data["auth"]) { syncBtn.className = "syncing"; @@ -177,13 +178,13 @@ function syncSettings(event) { formData.set("expires_in", data["auth"]["expires_in"]); formData.set("refresh_token", data["auth"]["refresh_token"]); - var req = new XMLHttpRequest(); + const req = new XMLHttpRequest(); req.open("POST", "https://darkintra.freekb.es/delete.php"); req.setRequestHeader('Content-type', 'application/x-www-form-urlencoded'); req.addEventListener("load", function(event) { syncBtn.className = ""; try { - var res = JSON.parse(this.responseText); + const res = JSON.parse(this.responseText); iConsole.log("Settings deletion result", res); } catch (err) { @@ -203,14 +204,14 @@ function syncSettings(event) { }); }); } - return false; + return (false); } function retrieveSettings() { return new Promise(function(resolve, reject) { try { - var formElems = document.querySelectorAll("form select, form input"); - var keysToGet = []; + const formElems = document.querySelectorAll("form select, form input"); + const keysToGet = []; for (var i = 0; i < formElems.length; i++) { keysToGet.push(formElems[i].getAttribute("name")); } @@ -227,9 +228,8 @@ function retrieveSettings() { function loadSettingsIntoForm(settings) { iConsole.log("Settings fetched somewhere", settings); - var key, settingElem; - for (key in settings) { - settingElem = document.getElementsByName(key); + for (let key in settings) { + let settingElem = document.getElementsByName(key); if (settingElem.length > 0) { settingElem = settingElem[0]; improvedStorage.set({[key]: settings[key]}); @@ -271,10 +271,8 @@ function loadSettingsIntoForm(settings) { window.onload = function() { iConsole.log("Initializing options page..."); - var i; - - var formElems = document.querySelectorAll("form select, form input"); - for (i = 0; i < formElems.length; i++) { + const formElems = document.querySelectorAll("form select, form input"); + for (let i = 0; i < formElems.length; i++) { formElems[i].addEventListener("change", syncSettings); } document.getElementById("sync-button").addEventListener("click", syncSettings); @@ -287,7 +285,7 @@ window.onload = function() { } }); document.getElementById("rem-custom-banner").addEventListener("click", function(event) { - var con = confirm("Are you sure you want to remove the custom banner from your profile?"); + const con = confirm("Are you sure you want to remove the custom banner from your profile?"); if (con) { document.getElementById("custom-banner-url").value = ""; syncSettings(null); diff --git a/options/sync.js b/options/sync.js index 8c66c98..7c59225 100644 --- a/options/sync.js +++ b/options/sync.js @@ -19,7 +19,7 @@ function getLoggedInUserName() { } } -var syncPort = chrome.runtime.connect({ name: portName }); +let syncPort = chrome.runtime.connect({ name: portName }); syncPort.onDisconnect.addListener(function() { iConsole.log("Disconnected from service worker"); }); From f36fc728984050a0ee91e3f4cb59d183065388dd Mon Sep 17 00:00:00 2001 From: Freek Bes <36384333+FreekBes@users.noreply.github.com> Date: Sun, 27 Mar 2022 16:01:54 +0200 Subject: [PATCH 15/45] add sync.js to admin pages --- manifest-ff.json | 2 +- manifest.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/manifest-ff.json b/manifest-ff.json index 7a3e506..7f29e8a 100644 --- a/manifest-ff.json +++ b/manifest-ff.json @@ -66,7 +66,7 @@ "run_at": "document_end" }, { - "matches": [ "*://profile.intra.42.fr/*", "*://projects.intra.42.fr/*", "*://elearning.intra.42.fr/*", "*://meta.intra.42.fr/*", "*://shop.intra.42.fr/*" ], + "matches": [ "*://profile.intra.42.fr/*", "*://projects.intra.42.fr/*", "*://elearning.intra.42.fr/*", "*://meta.intra.42.fr/*", "*://shop.intra.42.fr/*", "*://admin.intra.42.fr/*" ], "js": [ "options/sync.js" ], "run_at": "document_idle" }, diff --git a/manifest.json b/manifest.json index df66b39..4dc160c 100644 --- a/manifest.json +++ b/manifest.json @@ -61,7 +61,7 @@ "run_at": "document_end" }, { - "matches": [ "*://profile.intra.42.fr/*", "*://projects.intra.42.fr/*", "*://elearning.intra.42.fr/*", "*://meta.intra.42.fr/*", "*://shop.intra.42.fr/*" ], + "matches": [ "*://profile.intra.42.fr/*", "*://projects.intra.42.fr/*", "*://elearning.intra.42.fr/*", "*://meta.intra.42.fr/*", "*://shop.intra.42.fr/*", "*://admin.intra.42.fr/*" ], "js": [ "options/sync.js" ], "run_at": "document_idle" }, From 789262fb873111a2a432de808765654c3281077a Mon Sep 17 00:00:00 2001 From: Freek Bes <36384333+FreekBes@users.noreply.github.com> Date: Sun, 27 Mar 2022 16:09:32 +0200 Subject: [PATCH 16/45] pre-release 1 --- features/campus/codam/monit.js | 4 ++-- manifest-ff.json | 2 +- manifest.json | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/features/campus/codam/monit.js b/features/campus/codam/monit.js index 4bf505c..43da08e 100644 --- a/features/campus/codam/monit.js +++ b/features/campus/codam/monit.js @@ -408,8 +408,8 @@ var monit = { if (monit.logTimesTotal < monit.requirements.today && !atLeastRelaxed) { smiley.setAttribute("class", "icon-smiley-sad-1"); - smiley.setAttribute("style", "color: var(--fail-color);"); - progressPerc.setAttribute("style", "color: var(--fail-color);"); + smiley.setAttribute("style", "color: var(--danger-color);"); + progressPerc.setAttribute("style", "color: var(--danger-color);"); } else if ((atLeastRelaxed && monit.logTimesTotal < monit.requirements.min) || (!atLeastRelaxed && monit.logTimesTotal < monit.requirements.min)) { smiley.setAttribute("class", "icon-smiley-relax"); diff --git a/manifest-ff.json b/manifest-ff.json index 7f29e8a..63efc05 100644 --- a/manifest-ff.json +++ b/manifest-ff.json @@ -2,7 +2,7 @@ "manifest_version": 2, "name": "__MSG_appName__", "short_name": "__MSG_shortAppName__", - "version": "3.0.0", + "version": "3.0.0.1", "description": "__MSG_appDesc__", "default_locale": "en", "icons": { diff --git a/manifest.json b/manifest.json index 4dc160c..d75c2ff 100644 --- a/manifest.json +++ b/manifest.json @@ -3,8 +3,8 @@ "minimum_chrome_version": "49", "name": "__MSG_appName__", "short_name": "__MSG_shortAppName__", - "version": "3.0.0", - "version_name": "3.0.0", + "version": "3.0.0.1", + "version_name": "3.0.0 (pre-release 1)", "description": "__MSG_appDesc__", "default_locale": "en", "icons": { From b8629cb6a7040255b46ac7643997243d5e1671f5 Mon Sep 17 00:00:00 2001 From: Freek Bes <36384333+FreekBes@users.noreply.github.com> Date: Sun, 27 Mar 2022 21:57:20 +0200 Subject: [PATCH 17/45] fix improvedStorage undefined --- manifest-ff.json | 10 ++++------ manifest.json | 10 ++++------ 2 files changed, 8 insertions(+), 12 deletions(-) diff --git a/manifest-ff.json b/manifest-ff.json index 63efc05..eff50c7 100644 --- a/manifest-ff.json +++ b/manifest-ff.json @@ -44,20 +44,18 @@ ], "content_scripts": [ { - "matches": [ "*://*.intra.42.fr/*", "*://darkintra.freekb.es/*" ], - "js": [ "generic/console.js", "generic/storage.js", "generic/init.js" ], + "matches": [ "*://*.intra.42.fr/*" ], + "css": [ "fixes/improv.css", "fixes/animations.css", "features/themes/apply.css" ], "run_at": "document_start" }, { "matches": [ "*://darkintra.freekb.es/*" ], "css": [ "generic/internal.css", "fixes/animations.css" ], - "js": [ "features/themes/loader.js" ], "run_at": "document_start" }, { - "matches": [ "*://*.intra.42.fr/*" ], - "css": [ "fixes/improv.css", "fixes/animations.css", "features/themes/apply.css" ], - "js": [ "features/themes/loader.js" ], + "matches": [ "*://*.intra.42.fr/*", "*://darkintra.freekb.es/*" ], + "js": [ "generic/console.js", "generic/storage.js", "generic/init.js", "features/themes/loader.js" ], "run_at": "document_start" }, { diff --git a/manifest.json b/manifest.json index d75c2ff..d4a41dd 100644 --- a/manifest.json +++ b/manifest.json @@ -39,20 +39,18 @@ ], "content_scripts": [ { - "matches": [ "*://*.intra.42.fr/*", "*://darkintra.freekb.es/*" ], - "js": [ "generic/console.js", "generic/storage.js", "generic/init.js" ], + "matches": [ "*://*.intra.42.fr/*" ], + "css": [ "fixes/improv.css", "fixes/animations.css", "features/themes/apply.css" ], "run_at": "document_start" }, { "matches": [ "*://darkintra.freekb.es/*" ], "css": [ "generic/internal.css", "fixes/animations.css" ], - "js": [ "features/themes/loader.js" ], "run_at": "document_start" }, { - "matches": [ "*://*.intra.42.fr/*" ], - "css": [ "fixes/improv.css", "fixes/animations.css", "features/themes/apply.css" ], - "js": [ "features/themes/loader.js" ], + "matches": [ "*://*.intra.42.fr/*", "*://darkintra.freekb.es/*" ], + "js": [ "generic/console.js", "generic/storage.js", "generic/init.js", "features/themes/loader.js" ], "run_at": "document_start" }, { From 13f1a8389cb2aabd6a072279850a9a66af508381 Mon Sep 17 00:00:00 2001 From: Freek Bes Date: Mon, 28 Mar 2022 17:14:29 +0200 Subject: [PATCH 18/45] fix automatic redirect not working --- options/auth.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/options/auth.js b/options/auth.js index 7c0f8f4..d7ae833 100644 --- a/options/auth.js +++ b/options/auth.js @@ -6,10 +6,12 @@ /* By: fbes +#+ */ /* +#+ */ /* Created: 2021/11/28 20:22:10 by fbes #+# #+# */ -/* Updated: 2022/03/07 04:14:21 by fbes ######## odam.nl */ +/* Updated: 2022/03/28 17:14:03 by fbes ######## odam.nl */ /* */ /* ************************************************************************** */ +const optionsURL = "https://darkintra.freekb.es/options.php"; + let authPort = chrome.runtime.connect({ name: portName }); authPort.onDisconnect.addListener(function() { iConsole.log("Disconnected from service worker"); @@ -38,7 +40,6 @@ if (authResElem) { try { const authRes = JSON.parse(authResElem.innerText); if (!("error" in authRes["auth"])) { - const optionsURL = "https://darkintra.freekb.es/options.php"; const action = document.getElementById("action"); if (action) { action.innerText = "Please wait while we redirect you to the Improved Intra 42 options page..."; From 57a5c32d9424e3c299caec31e0129d9735f6ea39 Mon Sep 17 00:00:00 2001 From: Freek Bes Date: Mon, 28 Mar 2022 18:16:29 +0200 Subject: [PATCH 19/45] font fixes --- fixes/fonts.css | 71 ++++++++++++++++++++++++++++++++++++++++++++ fixes/improv.css | 33 ++------------------ generic/internal.css | 57 +++++++++++------------------------ server/options.php | 15 ++++++---- 4 files changed, 100 insertions(+), 76 deletions(-) create mode 100644 fixes/fonts.css diff --git a/fixes/fonts.css b/fixes/fonts.css new file mode 100644 index 0000000..bee3dba --- /dev/null +++ b/fixes/fonts.css @@ -0,0 +1,71 @@ +/* ************************************************************************** */ +/* */ +/* :::::::: */ +/* fonts.css :+: :+: */ +/* +:+ */ +/* By: fbes +#+ */ +/* +#+ */ +/* Created: 2022/03/28 17:20:47 by fbes #+# #+# */ +/* Updated: 2022/03/28 17:24:08 by fbes ######## odam.nl */ +/* */ +/* ************************************************************************** */ + +@font-face { + font-family: "Futura PT"; + src: url(https://profile.intra.42.fr/assets/ParaType-FuturaPTLight-e7a52027b9b5978e6a6f83b096aea906b0e79399145e65e19024f94967a2411f.otf) format("opentype"); + font-weight: 200; + font-style: normal; +} + +@font-face { + font-family:"Futura PT"; + src: url(https://profile.intra.42.fr/assets/ParaType-FuturaPTLightOblique-5212d3b9dd70f3017a3bd3478c96b37e8457b7d216a6f4658cbc0cdf15aea289.otf) format("opentype"); + font-weight: 200; + font-style: italic; +} + +@font-face { + font-family: "Futura PT"; + src: url(https://profile.intra.42.fr/assets/ParaType-FuturaPTBook-85be74ee15c50c39cb5601ec40aee5fc3c79090582047140fc0a9827cc3f7dab.otf) format("opentype"); + font-weight: 400; + font-style: normal; +} + +@font-face { + font-family:"Futura PT"; + src:url(https://profile.intra.42.fr/assets/ParaType-FuturaPTBookOblique-c68d7786d4e95e7b01a9b6815a590fd8e0893e4c2ac7866781a6dd7cf553e479.ttf) format("truetype"); + font-weight: 400; + font-style: italic; +} + +@font-face { + font-family: "Futura PT"; + src: url(https://profile.intra.42.fr/assets/ParaType-FuturaPTHeavy-518b96256003be903332541a3c2ac7a54d5ba38eaeebb9bed930a530f2b8ddf9.otf) format("opentype"); + font-weight: 700; + font-style: normal; +} + +@font-face { + font-family: "Futura PT"; + src: url(https://profile.intra.42.fr/assets/ParaType-FuturaPTHeavyOblique-b844b203a563c9cd175071a8a162b77459d4ac16b2493f65c0840a54385bfc8b.otf) format("opentype"); + font-weight: 700; + font-style: italic; +} + +@font-face { + font-family: "Noto Sans"; + src: url(https://profile.intra.42.fr/assets/NotoSans-Regular-f1ce78a25f519ef928b5b8755ca230314e47f8821e7aa89ecf000f033f389a9f.ttf) format("truetype"); + font-weight: 400; + font-style: normal; +} + +@font-face { + font-family: "streamline-filled"; + src: url(https://profile.intra.42.fr/assets/streamline-30px-filled-in-4646a777f76d366ec26caad7921e728e2d01b9dca49053c6b316fe596700e252.eot); + src: url(https://profile.intra.42.fr/assets/streamline-30px-filled-in-4646a777f76d366ec26caad7921e728e2d01b9dca49053c6b316fe596700e252.eot?#iefix) format("embedded-opentype"), + url(https://profile.intra.42.fr/assets/streamline-30px-filled-in-62fdf8602f56c68e259582d7ad3eb0e30b2808efaa03a074086faedcaf9017e2.woff) format("woff"), + url(https://profile.intra.42.fr/assets/streamline-30px-filled-in-9c4de7ac5c05533207755509de4a14b25d1b8d7276ce055fe9ed3f43b38c8328.ttf) format("truetype"), + url(https://profile.intra.42.fr/assets/streamline-30px-filled-in-c547d434f0242cda67f4d0438ae132de5fe5794afd2366906e2f1d3480756732.svg#streamline-30px-filled-in) format("svg"); + font-weight: normal; + font-style: normal +} diff --git a/fixes/improv.css b/fixes/improv.css index 61d00e7..9a1b10b 100644 --- a/fixes/improv.css +++ b/fixes/improv.css @@ -6,7 +6,7 @@ /* By: fbes +#+ */ /* +#+ */ /* Created: 2021/11/28 01:00:01 by fbes #+# #+# */ -/* Updated: 2022/03/22 18:42:30 by codam ######## odam.nl */ +/* Updated: 2022/03/28 17:25:50 by fbes ######## odam.nl */ /* */ /* ************************************************************************** */ @@ -15,34 +15,6 @@ * whether in dark or light mode does not matter. */ -@font-face { - font-family: "futura"; - src: url(https://profile.intra.42.fr/assets/ParaType-FuturaPTBook-85be74ee15c50c39cb5601ec40aee5fc3c79090582047140fc0a9827cc3f7dab.otf) format("opentype"); - font-weight: 400; - font-style: normal; -} - -@font-face { - font-family:"futura"; - src:url(https://profile.intra.42.fr/assets/ParaType-FuturaPTBookOblique-c68d7786d4e95e7b01a9b6815a590fd8e0893e4c2ac7866781a6dd7cf553e479.ttf) format("truetype"); - font-weight: 400; - font-style: italic; -} - -@font-face { - font-family: "futura-bold"; - src: url(https://profile.intra.42.fr/assets/ParaType-FuturaPTHeavy-518b96256003be903332541a3c2ac7a54d5ba38eaeebb9bed930a530f2b8ddf9.otf) format("opentype"); - font-weight: 700; - font-style: normal; -} - -@font-face { - font-family: "futura-bold"; - src: url(https://profile.intra.42.fr/assets/ParaType-FuturaPTHeavyOblique-b844b203a563c9cd175071a8a162b77459d4ac16b2493f65c0840a54385bfc8b.otf) format("opentype"); - font-weight: 700; - font-style: italic; -} - /* remove horizontal scrollbar, as it causes visual glitches anyways */ html { overflow-x: hidden !important; @@ -53,7 +25,8 @@ html { .event-modal .head h4, .exam-modal .head h4, #admin-user h3 { - font-family: 'futura-bold', 'futuraBold' !important; + font-family: "Futura PT", "Futura", "futura", "Helvetica", Verdana, Arial, Sans-Serif !important; + font-weight: 700 !important; } /* off-screen account dropdown menu fix for short usernames */ diff --git a/generic/internal.css b/generic/internal.css index fc8056c..ce7b388 100644 --- a/generic/internal.css +++ b/generic/internal.css @@ -6,38 +6,10 @@ /* By: fbes +#+ */ /* +#+ */ /* Created: 2022/03/27 03:34:57 by fbes #+# #+# */ -/* Updated: 2022/03/27 03:34:57 by fbes ######## odam.nl */ +/* Updated: 2022/03/28 18:15:12 by fbes ######## odam.nl */ /* */ /* ************************************************************************** */ -@font-face { - font-family: "futura"; - src: url(https://profile.intra.42.fr/assets/ParaType-FuturaPTBook-85be74ee15c50c39cb5601ec40aee5fc3c79090582047140fc0a9827cc3f7dab.otf) format("opentype"); - font-weight: 400; - font-style: normal; -} - -@font-face { - font-family:"futura"; - src:url(https://profile.intra.42.fr/assets/ParaType-FuturaPTBookOblique-c68d7786d4e95e7b01a9b6815a590fd8e0893e4c2ac7866781a6dd7cf553e479.ttf) format("truetype"); - font-weight: 400; - font-style: italic; -} - -@font-face { - font-family: "futura-bold"; - src: url(https://profile.intra.42.fr/assets/ParaType-FuturaPTHeavy-518b96256003be903332541a3c2ac7a54d5ba38eaeebb9bed930a530f2b8ddf9.otf) format("opentype"); - font-weight: 700; - font-style: normal; -} - -@font-face { - font-family: "futura-bold"; - src: url(https://profile.intra.42.fr/assets/ParaType-FuturaPTHeavyOblique-b844b203a563c9cd175071a8a162b77459d4ac16b2493f65c0840a54385bfc8b.otf) format("opentype"); - font-weight: 700; - font-style: italic; -} - @keyframes spin { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } @@ -65,8 +37,9 @@ body, background-color: var(--container-background-color); color: var(--text-color); caret-color: var(--text-color); - font-family: "Futura PT", "Futura", "futura", "Helvetica", Verdana, Arial, Sans-Serif; - font-size: 16px; + font-family: 'Roboto', "Helvetica", Verdana, Arial, sans-serif; + font-weight: 400; + font-size: 15px; padding: 0px; cursor: default; width: 100%; @@ -153,8 +126,8 @@ h1 { padding: 0px; margin: 0px; line-height: 56px; - font-size: 18px; - font-weight: 800; + font-size: 17px; + font-weight: 500; } code { @@ -166,8 +139,11 @@ code { } h2 { + display: inline-block; + font-weight: 500; margin: 0px; padding: 16px 0px; + font-size: 19px; } details { @@ -202,14 +178,14 @@ header button { padding: 8px 28px; border: none; text-align: center; - font-size: 26px; + font-size: 25px; height: 100%; width: 56px; padding: 0px; font-family: "streamline-filled"; font-style: normal; - font-weight: normal; + font-weight: 400; font-variant: normal; text-transform: none; line-height: 1; @@ -263,9 +239,9 @@ section:last-child { border-bottom: none; } -h2 { +h3 { margin: 0px 12px 12px 12px; - font-weight: 600; + font-weight: 500; text-transform: uppercase; font-size: 0.9em; } @@ -282,8 +258,9 @@ fieldset { } label { + font-family: 'Roboto Condensed', "Helvetica", Verdana, Arial, sans-serif; text-align: left; - font-weight: 100; + font-weight: 300; font-size: 1em; padding-left: 12px; } @@ -397,14 +374,14 @@ input[readonly] { } label[for="sync"] span.failed::after { - font-family: Sans-Serif; + font-family: sans-serif; content: ' \2A2F'; color: var(--fail-color); font-weight: bold; } label[for="sync"] span.success::after { - font-family: Sans-Serif; + font-family: sans-serif; content: ' \2714'; color: var(--success-color); font-weight: bold; diff --git a/server/options.php b/server/options.php index e0eee43..2a91303 100644 --- a/server/options.php +++ b/server/options.php @@ -3,6 +3,9 @@ Improved Intra 42 Settings + + + - + Date: Mon, 28 Mar 2022 19:32:30 +0200 Subject: [PATCH 24/45] restructure javascript files --- features/campus/codam/monit.js | 92 +++++------ features/clustermap.js | 53 ++++++ features/profiles.js | 50 +++--- features/themes/loader.js | 32 +++- fixes/banners.js | 59 +++++++ fixes/blackhole.js | 76 +++++++++ fixes/general.js | 99 +++++++++++ fixes/improv.js | 294 +-------------------------------- fixes/optional.js | 55 ++++++ {fixes => generic}/fonts.css | 0 generic/init.js | 3 +- generic/useful.js | 17 +- manifest-ff.json | 4 +- manifest.json | 4 +- options/options.js | 8 +- 15 files changed, 454 insertions(+), 392 deletions(-) create mode 100644 features/clustermap.js create mode 100644 fixes/banners.js create mode 100644 fixes/blackhole.js create mode 100644 fixes/general.js create mode 100644 fixes/optional.js rename {fixes => generic}/fonts.css (100%) diff --git a/features/campus/codam/monit.js b/features/campus/codam/monit.js index 43da08e..5b3ae23 100644 --- a/features/campus/codam/monit.js +++ b/features/campus/codam/monit.js @@ -6,7 +6,7 @@ /* By: fbes +#+ */ /* +#+ */ /* Created: 2021/11/11 19:23:05 by fbes #+# #+# */ -/* Updated: 2022/03/24 22:46:58 by fbes ######## odam.nl */ +/* Updated: 2022/03/28 19:22:39 by fbes ######## odam.nl */ /* */ /* ************************************************************************** */ @@ -19,7 +19,7 @@ function sum(prevVal, curVal) { return (prevVal + curVal); } -var monit = { +const monit = { httpReq: null, requirements: { today: 205, @@ -61,10 +61,9 @@ var monit = { * Get the dates of this week's days */ getWeekDates: function() { - var thisWeek = []; - var timestamp = new Date().getTime(); - for (var i = 0; i <= monit.dayOfWeek; i++) { - thisWeek.push(new Date(timestamp - 86400000 * i).toISOString().split("T")[0]); + const thisWeek = []; + for (let i = 0; i <= monit.dayOfWeek; i++) { + thisWeek.push(new Date(today.getTime() - 86400000 * i).toISOString().split("T")[0]); } iConsole.log("This week's dates: ", thisWeek); return (thisWeek); @@ -76,8 +75,8 @@ var monit = { * out, equally divided over all remaining days. */ setExpected: function() { - var logTimesNoToday = this.logTimes.slice(1); - var logTimesTotalNoToday; + const logTimesNoToday = this.logTimes.slice(1); + let logTimesTotalNoToday; if (logTimesNoToday && logTimesNoToday.length > 0) { logTimesTotalNoToday = logTimesNoToday.reduce(sum); @@ -100,21 +99,11 @@ var monit = { * Parse a piece of logtime text: in format HHhMM or HH:MM(:SS) */ parseLogTime: function(logTimeText) { - var logTime = 0; - var logTimeSplit; - - if (logTimeText.indexOf("h") > -1) { - logTimeSplit = logTimeText.split("h"); - } - else { - logTimeSplit = logTimeText.split(":"); - } + const logTimeSplit = (logTimeText.indexOf("h") > -1 ? logTimeText.split("h") : logTimeText.split(":")); if (logTimeSplit.length < 2) { return (0); } - logTime += parseInt(logTimeSplit[0]) * 60; - logTime += parseInt(logTimeSplit[1]); - return (logTime); + return (parseInt(logTimeSplit[0]) * 60 + parseInt(logTimeSplit[1])); }, /** @@ -135,10 +124,10 @@ var monit = { monit.httpReq = new XMLHttpRequest(); monit.httpReq.addEventListener("load", function() { try { - var stats = JSON.parse(this.responseText); - var weekDates = monit.getWeekDates(); + const stats = JSON.parse(this.responseText); + const weekDates = monit.getWeekDates(); monit.logTimes = []; - for (var i = 0; i < weekDates.length; i++) { + for (let i = 0; i < weekDates.length; i++) { if (weekDates[i] in stats) { monit.logTimes.push(monit.parseLogTime(stats[weekDates[i]])); } @@ -172,13 +161,13 @@ var monit = { */ getLogTimes: function() { return (new Promise(function (resolve, reject) { - var ltSvg = document.getElementById("user-locations"); + const ltSvg = document.getElementById("user-locations"); if (!ltSvg) { reject("Element #user-locations not found"); } - var ltDays = ltSvg.getElementsByTagName("g"); - var ltDay = ltDays[ltDays.length - 1]; - var i, j; + const ltDays = ltSvg.getElementsByTagName("g"); + let ltDay = ltDays[ltDays.length - 1]; + let i; monit.logTimes = []; for (i = 0; i <= monit.dayOfWeek; i++) { @@ -195,15 +184,16 @@ var monit = { monit.logTimesTotal = 0; } - var daysInWeek = monit.dayOfWeek + 1; - var remainingWeeks = Math.floor(ltDays.length / 7) + (monit.dayOfWeek != 6 ? 1 : 0); - var r = 0; - var tempLogTimes; + let daysInWeek = monit.dayOfWeek + 1; + const remainingWeeks = Math.floor(ltDays.length / 7) + (monit.dayOfWeek != 6 ? 1 : 0); + let r = 0; for (i = 0; i < remainingWeeks; i++) { + let j; + if (i == 1) { daysInWeek = 7; } - tempLogTimes = []; + const tempLogTimes = []; // parse individual logtimes for (j = 0; j < daysInWeek; j++) { @@ -247,7 +237,7 @@ var monit = { if (window.location.pathname.indexOf("/users/") == 0) { // user profile. check if user loaded is from Amsterdam campus // if not, do not display monitoring system progress (return) - var iconLocation = document.getElementsByClassName("icon-location"); + const iconLocation = document.getElementsByClassName("icon-location"); if (iconLocation.length == 0) { return; } @@ -264,9 +254,9 @@ var monit = { // if not, do not display monitoring system progress (return) // check by checking the school record button, should contain Codam // if the button is not there (before handing in Libft), check coalition - var schoolRecordButton = document.querySelector(".school-record-button"); + const schoolRecordButton = document.querySelector(".school-record-button"); if (schoolRecordButton) { - var srFormData = document.getElementsByName("sr_id"); + const srFormData = document.getElementsByName("sr_id"); if (srFormData.length > 0) { if (srFormData[0].textContent.indexOf("Codam") == -1) { return; @@ -277,7 +267,7 @@ var monit = { } } else { - var coalitionName = document.querySelector(".coalition-name .coalition-span"); + const coalitionName = document.querySelector(".coalition-name .coalition-span"); if (coalitionName) { if (["Pyxis", "Vela", "Cetus"].indexOf(coalitionName.textContent) == -1) { return; @@ -302,7 +292,7 @@ var monit = { addTooltip: function() { // add bootstrap tooltip to holder - var evt = new CustomEvent("add-tooltip", { detail: "#lt-holder" }); + const evt = new CustomEvent("add-tooltip", { detail: "#lt-holder" }); document.dispatchEvent(evt); }, @@ -319,7 +309,7 @@ var monit = { monit.httpReq = new XMLHttpRequest(); monit.httpReq.addEventListener("load", function() { try { - var status = JSON.parse(this.responseText); + const status = JSON.parse(this.responseText); resolve(status); } catch (err) { @@ -343,35 +333,35 @@ var monit = { iConsole.log("Logtimes", monit.logTimes); iConsole.log("Total minutes", monit.logTimesTotal); - var aguDate = document.getElementById("agu-date"); + const aguDate = document.getElementById("agu-date"); if (aguDate && aguDate.className.indexOf("hidden") == -1) { return; } - var atLeastRelaxed = false; - var partTimeCheck = document.querySelectorAll("a.project-item.block-item[href*='part_time'][data-cursus='42cursus']"); + let atLeastRelaxed = false; + const partTimeCheck = document.querySelectorAll("a.project-item.block-item[href*='part_time'][data-cursus='42cursus']"); if (partTimeCheck.length > 0 || status["monitoring_system_active"] === false) { iConsole.log("User is working on Part-Time project or monitoring system is currently disabled, emote will be at least relaxed"); atLeastRelaxed = true; } - var availableStatus = document.querySelector(".user-poste-status"); + const availableStatus = document.querySelector(".user-poste-status"); if (availableStatus && availableStatus.innerText == "Available") { iConsole.log("User is currently available, emote will be at least relaxed"); atLeastRelaxed = true; } - for (var i = 0; i < monit.bhContainer.children.length; i++) { + for (let i = 0; i < monit.bhContainer.children.length; i++) { monit.bhContainer.children[i].style.display = "none"; } - var progressNode = document.createElement("div"); + const progressNode = document.createElement("div"); progressNode.setAttribute("id", "monit-progress"); - var progressTitle = document.createElement("div"); + const progressTitle = document.createElement("div"); progressTitle.setAttribute("class", "mb-1"); - var coalitionSpan = document.createElement("span"); + const coalitionSpan = document.createElement("span"); coalitionSpan.setAttribute("class", "coalition-span"); coalitionSpan.style.color = monit.getCoalitionColor(); coalitionSpan.innerText = "Monitoring System progress"; @@ -379,19 +369,19 @@ var monit = { progressTitle.appendChild(coalitionSpan); progressNode.appendChild(progressTitle); - var progressText = document.createElement("div"); + const progressText = document.createElement("div"); progressText.setAttribute("id", "monit-progress-text"); - var ltHolder = document.createElement("div"); + const ltHolder = document.createElement("div"); ltHolder.setAttribute("id", "lt-holder"); ltHolder.setAttribute("class", "emote-lt"); ltHolder.setAttribute("data-toggle", "tooltip"); ltHolder.setAttribute("title", ""); - var smiley = document.createElement("span"); + const smiley = document.createElement("span"); smiley.setAttribute("id", "lt-emote"); - var progressPerc = document.createElement("span"); + const progressPerc = document.createElement("span"); if (status["monitoring_system_active"]) { progressPerc.innerText = Math.floor(monit.logTimesTotal / 1440 * 100) + "% complete"; ltHolder.setAttribute("data-original-title", "Logtime this week: " + monit.logTimeToString(monit.logTimesTotal)); @@ -463,7 +453,7 @@ var monit = { if (!smiley.getAttribute("data-oclass")) { return; } - var tempClass = smiley.getAttribute("class"); + const tempClass = smiley.getAttribute("class"); smiley.setAttribute("class", smiley.getAttribute("data-oclass")); smiley.setAttribute("data-oclass", tempClass); }); diff --git a/features/clustermap.js b/features/clustermap.js new file mode 100644 index 0000000..efcc1ec --- /dev/null +++ b/features/clustermap.js @@ -0,0 +1,53 @@ +/* ************************************************************************** */ +/* */ +/* :::::::: */ +/* clustermap.js :+: :+: */ +/* +:+ */ +/* By: fbes +#+ */ +/* +#+ */ +/* Created: 2022/03/28 18:38:32 by fbes #+# #+# */ +/* Updated: 2022/03/28 19:03:24 by fbes ######## odam.nl */ +/* */ +/* ************************************************************************** */ + +function openClusterMap(event) { + let url = null; + switch (getCampus()) { + case "Amsterdam": + url = "https://codamhero.dev/v2/clusters.php"; + break; + case "Paris": + url = "https://stud42.fr/clusters"; + break; + default: { + if (event.target.textContent.indexOf(".codam.nl") > -1) { + url = "https://codamhero.dev/v2/clusters.php"; + } + else { + url = "https://meta.intra.42.fr/clusters"; + } + break; + } + } + + const win = window.open(url, "improved_intra_cluster_map_win"); + // since we can no longer check when a window is loaded with an event + // for domains that are not of the same origin, we simply try and send + // the location ID multiple times to the opened cluster map window + // could also do it with the extension but then we need more permissions... + setTimeout(function() { + win.location.href = url + "#" + event.target.textContent.split(".")[0]; + }, 250); + setTimeout(function() { + win.location.href = url + "#"; + win.location.href = url + "#" + event.target.textContent.split(".")[0]; + }, 500); + setTimeout(function() { + win.location.href = url + "#"; + win.location.href = url + "#" + event.target.textContent.split(".")[0]; + }, 750); + setTimeout(function() { + win.location.href = url + "#"; + win.location.href = url + "#" + event.target.textContent.split(".")[0]; + }, 1000); +} diff --git a/features/profiles.js b/features/profiles.js index cc0157b..ab32700 100644 --- a/features/profiles.js +++ b/features/profiles.js @@ -6,29 +6,17 @@ /* By: fbes +#+ */ /* +#+ */ /* Created: 2022/01/09 01:01:42 by fbes #+# #+# */ -/* Updated: 2022/02/07 21:05:47 by fbes ######## odam.nl */ +/* Updated: 2022/03/28 19:18:05 by fbes ######## odam.nl */ /* */ /* ************************************************************************** */ -// from https://stackoverflow.com/questions/8667070/javascript-regular-expression-to-validate-url (jesus) -function validateUrl(value) { - return /^(?:(?:(?:https?|ftp):)?\/\/)(?:\S+(?::\S*)?@)?(?:(?!(?:10|127)(?:\.\d{1,3}){3})(?!(?:169\.254|192\.168)(?:\.\d{1,3}){2})(?!172\.(?:1[6-9]|2\d|3[0-1])(?:\.\d{1,3}){2})(?:[1-9]\d?|1\d\d|2[01]\d|22[0-3])(?:\.(?:1?\d{1,2}|2[0-4]\d|25[0-5])){2}(?:\.(?:[1-9]\d?|1\d\d|2[0-4]\d|25[0-4]))|(?:(?:[a-z\u00a1-\uffff0-9]-*)*[a-z\u00a1-\uffff0-9]+)(?:\.(?:[a-z\u00a1-\uffff0-9]-*)*[a-z\u00a1-\uffff0-9]+)*(?:\.(?:[a-z\u00a1-\uffff]{2,})))(?::\d{2,5})?(?:[/?#]\S*)?$/i.test(value); -} - -function getProfileUserName() { - try { - return (document.querySelector(".login[data-login]").getAttribute("data-login")); - } - catch (err) { - return (null); - } -} +// everything for custom profiles -var gUName = null; -var gProfileBanner = null; -var gInterval = null; -var gExtSettings = null; -var gUserSettings = null; +let gUName = null; +let gProfileBanner = null; +let gInterval = null; +let gExtSettings = null; +let gUserSettings = null; function getUserSettings(username) { return new Promise(function(resolve, reject) { @@ -66,7 +54,7 @@ function getUserSettings(username) { function setCustomBanner(imageUrl, imagePos) { if (imageUrl && validateUrl(imageUrl)) { - var newCSSval = "url(\"" + imageUrl + "\")"; + const newCSSval = "url(\"" + imageUrl + "\")"; if (gProfileBanner.style.backgroundImage.indexOf(imageUrl) == -1) { gProfileBanner.className += " customized"; gProfileBanner.setAttribute("data-old-bg", gProfileBanner.style.backgroundImage); @@ -100,7 +88,7 @@ function unsetCustomBannerIfRequired() { function setGitHubLink(gitHubName) { gitHubName = gitHubName.trim(); - var gitHubLink = document.getElementById("ii-profile-link-github"); + const gitHubLink = document.getElementById("ii-profile-link-github"); if (gitHubLink) { if (gitHubName.indexOf("@") == 0) { gitHubName = gitHubName.substring(1); @@ -174,18 +162,18 @@ function immediateProfileChanges() { if (window.location.pathname.indexOf("/users/") == 0) { // improvements to profile boxes - var locations = document.getElementById("locations"); + const locations = document.getElementById("locations"); if (locations) { - var logTimesHeader = document.createElement("h4"); + const logTimesHeader = document.createElement("h4"); logTimesHeader.className = "profile-title"; logTimesHeader.innerText = "Logtime"; locations.parentNode.parentNode.prepend(logTimesHeader); } // add social links to profile - var userInfos = document.querySelector(".profile-infos-bottom"); + const userInfos = document.querySelector(".profile-infos-bottom"); if (userInfos) { - var gitHubItem = document.createElement("div"); + const gitHubItem = document.createElement("div"); gitHubItem.className = "profile-infos-item"; gitHubItem.setAttribute("id", "ii-profile-link-c-github"); gitHubItem.setAttribute("data-placement", "left"); @@ -194,22 +182,22 @@ function immediateProfileChanges() { gitHubItem.setAttribute("data-original-title", "GitHub"); gitHubItem.style.display = "none"; - var gitHubIcon = document.createElement("span"); + const gitHubIcon = document.createElement("span"); gitHubIcon.className = "fa fa-github"; gitHubItem.appendChild(gitHubIcon); - var gitHubLink = document.createElement("a"); + const gitHubLink = document.createElement("a"); gitHubLink.style.marginLeft = "4px"; gitHubLink.style.color = getCoalitionColor(); gitHubLink.setAttribute("target", "_blank"); gitHubItem.appendChild(gitHubLink); - var gitHubName = document.createElement("span"); + const gitHubName = document.createElement("span"); gitHubName.className = "coalition-span"; gitHubName.setAttribute("id", "ii-profile-link-github"); gitHubLink.appendChild(gitHubName); - var locationItem = userInfos.querySelector(".icon-location"); + let locationItem = userInfos.querySelector(".icon-location"); if (locationItem) { locationItem = locationItem.parentNode; userInfos.insertBefore(gitHubItem, locationItem); @@ -218,7 +206,7 @@ function immediateProfileChanges() { userInfos.appendChild(gitHubItem); } - var evt = new CustomEvent("add-tooltip", { detail: "#ii-profile-link-c-github" }); + const evt = new CustomEvent("add-tooltip", { detail: "#ii-profile-link-c-github" }); document.dispatchEvent(evt); } } @@ -246,7 +234,7 @@ improvedStorage.get(["username", "show-custom-profiles", "custom-banner-url", "c confirmProfileUpdatedForFiveSeconds(); }); -var cursusSelector = document.querySelector(".cursus-user-select"); +const cursusSelector = document.querySelector(".cursus-user-select"); if (cursusSelector) { cursusSelector.addEventListener("change", function(event) { confirmProfileUpdatedForFiveSeconds(); diff --git a/features/themes/loader.js b/features/themes/loader.js index e029909..f54db6b 100644 --- a/features/themes/loader.js +++ b/features/themes/loader.js @@ -6,16 +6,14 @@ /* By: fbes +#+ */ /* +#+ */ /* Created: 2021/11/28 01:49:05 by fbes #+# #+# */ -/* Updated: 2022/03/22 18:08:26 by codam ######## odam.nl */ +/* Updated: 2022/03/28 19:05:18 by fbes ######## odam.nl */ /* */ /* ************************************************************************** */ let themeColorsLink = null; let themeLink = null; -/** - * Disable a theme, set theme or colors to false to not disable those colors - */ +// Disable a theme, set theme or colors to false to not disable those colors function disableTheme(theme, colors) { if (theme !== false && themeLink) { themeLink.remove(); @@ -27,9 +25,7 @@ function disableTheme(theme, colors) { } } -/** - * Enable a theme, leave colors as null or undefined to use default color scheme - */ +// Enable a theme, leave colors as null or undefined to use default color scheme function enableTheme(theme, colors) { iConsole.log("Enabling theme '" + theme + "'" + (colors ? " in '" + colors + "' mode..." : "")); if (!themeLink) { @@ -74,6 +70,28 @@ function checkThemeSetting() { }); } +// colorize logtimes chart based on selected color scheme +function colorizeLogtimeChart(event) { + setTimeout(function() { + const ltSvg = document.getElementById("user-locations"); + if (!ltSvg) { + return; + } + const ltDays = ltSvg.getElementsByTagName("rect"); + const col24hex = getComputedStyle(document.documentElement).getPropertyValue('--logtime-chart-24h-color'); + if (col24hex !== "") { + const col24rgb = hexToRgb(col24hex.trim()); + for (let i = 0; i < ltDays.length; i++) { + const fill = ltDays[i].getAttribute("fill"); + if (fill.indexOf("rgba") > -1) { + const opacity = fill.replace(/^.*,(.+)\)/, '$1'); + ltDays[i].setAttribute("fill", "rgba("+col24rgb.r+","+col24rgb.g+","+col24rgb.b+","+opacity+")"); + } + } + } + }, 250); +} + window.matchMedia("(prefers-color-scheme: dark)").addEventListener("change", function() { iConsole.log("@media rule prefers-color-scheme changed"); checkThemeSetting(); diff --git a/fixes/banners.js b/fixes/banners.js new file mode 100644 index 0000000..1d4c678 --- /dev/null +++ b/fixes/banners.js @@ -0,0 +1,59 @@ +/* ************************************************************************** */ +/* */ +/* :::::::: */ +/* banners.js :+: :+: */ +/* +:+ */ +/* By: fbes +#+ */ +/* +#+ */ +/* Created: 2022/03/28 18:53:49 by fbes #+# #+# */ +/* Updated: 2022/03/28 19:17:23 by fbes ######## odam.nl */ +/* */ +/* ************************************************************************** */ + +function fixProfileBanners() { + // fix coalition colored links + setStyleIfExists(".coalition-name a", "color", getCoalitionColor()); + setStyleIfExists(".correction-point-btn", "color", getCoalitionColor(), true); + + // fix black hole container issues, such as text color + fixBlackHoleContainer(); + + const profileActions = document.querySelector(".profile-item .user-primary .user-infos .button-actions"); + if (profileActions) { + profileActions.addEventListener("mouseenter", setCoalitionTextColor); + profileActions.addEventListener("mouseleave", unsetCoalitionTextColor); + } + + const telInfo = document.querySelector(".profile-infos-item a[href*=\"tel:\"]"); + if (telInfo) { + telInfo.addEventListener("mouseenter", setCoalitionTextColor); + } + + const mailInfo = document.querySelector(".profile-infos-item a[href*=\"mailto:\"]"); + if (mailInfo) { + mailInfo.addEventListener("mouseenter", setCoalitionTextColor); + } + + const gitHubInfo = document.querySelector("#ii-profile-link-github"); + if (gitHubInfo) { + gitHubInfo.addEventListener("mouseenter", setCoalitionTextColor); + } + + const cursusSelector = document.querySelector(".cursus-user-select"); + if (cursusSelector) { + // fix coalition colored elements on cursus selector change + cursusSelector.addEventListener("change", function(event) { + setTimeout(function() { + const titleSelectorCaret = document.querySelector(".caret[style*='color:']"); + if (titleSelectorCaret) { + titleSelectorCaret.style.color = getCoalitionColor(); + } + + const gitHubInfo = document.querySelector("#ii-profile-link-github"); + if (gitHubInfo) { + gitHubInfo.parentNode.style.color = getCoalitionColor(); + } + }, 250); + }); + } +} diff --git a/fixes/blackhole.js b/fixes/blackhole.js new file mode 100644 index 0000000..e4a1acb --- /dev/null +++ b/fixes/blackhole.js @@ -0,0 +1,76 @@ +/* ************************************************************************** */ +/* */ +/* :::::::: */ +/* blackhole.js :+: :+: */ +/* +:+ */ +/* By: fbes +#+ */ +/* +#+ */ +/* Created: 2022/03/28 18:28:18 by fbes #+# #+# */ +/* Updated: 2022/03/28 18:35:32 by fbes ######## odam.nl */ +/* */ +/* ************************************************************************** */ + +// fix black hole text color +// and if old-blackhole setting is enabled, replace text with old countdown style +function fixBlackHoleContainer() { + const bhColorTimer = setInterval(function() { + const bhDate = document.querySelector("#bh-date"); + if (bhDate) { + const bhDateTitle = bhDate.parentNode.getAttribute("data-original-title"); + if (bhDate.innerText.indexOf("absorbed") > -1) { + clearInterval(bhColorTimer); + bhDate.style.color = "var(--fail-color)"; + improvedStorage.get("username").then(function(data) { + if (data["username"] && data["username"] != getProfileUserName()) { + bhDate.innerText = "User has been absorbed by the Black Hole."; + } + }); + } + else if (bhDateTitle.indexOf("days left") > -1) { + const daysRemaining = parseInt(bhDateTitle); + if (isNaN(daysRemaining)) { + return; + } + clearInterval(bhColorTimer); + iConsole.log("Black Hole days remaining: ", daysRemaining); + improvedStorage.get("old-blackhole").then(function(data) { + if (data["old-blackhole"] === true || data["old-blackhole"] === "true") { + bhDate.parentNode.setAttribute("data-original-title", bhDate.innerText); + bhDate.innerText = daysRemaining.toString() + " days left"; + + // add bootstrap tooltip to holder + const evt = new CustomEvent("add-tooltip", { detail: "#bh > .emote-bh" }); + document.dispatchEvent(evt); + + const smiley = document.createElement("span"); + smiley.setAttribute("id", "lt-emote"); + if (daysRemaining > 30) { + smiley.setAttribute("class", "icon-smiley-relax"); + bhDate.style.color = "var(--success-color)"; + smiley.style.color = "var(--success-color)"; + } + else { + smiley.setAttribute("class", "icon-smiley-surprise"); + bhDate.style.color = "var(--warning-color)"; + smiley.style.color = "var(--warning-color)"; + } + bhDate.parentNode.insertBefore(smiley, bhDate); + } + else { + if (daysRemaining > 30) { + bhDate.style.color = "var(--text-color)"; + } + else { + // stylize in warning color if less than 30 colors remaining, just to point it out to user + bhDate.style.color = "var(--warning-color)"; + } + } + }); + } + else { + // fallback styling + bhDate.style.color = "var(--text-color)"; + } + } + }, 100); +} diff --git a/fixes/general.js b/fixes/general.js new file mode 100644 index 0000000..d31986a --- /dev/null +++ b/fixes/general.js @@ -0,0 +1,99 @@ +/* ************************************************************************** */ +/* */ +/* :::::::: */ +/* general.js :+: :+: */ +/* +:+ */ +/* By: fbes +#+ */ +/* +#+ */ +/* Created: 2022/03/28 18:52:19 by fbes #+# #+# */ +/* Updated: 2022/03/28 19:17:30 by fbes ######## odam.nl */ +/* */ +/* ************************************************************************** */ + +function setGeneralImprovements() { + // fix things on profile banners + if (hasProfileBanner()) { + fixProfileBanners(); + } + + // add link to options in account/user menu + const userMenu = document.querySelector(".main-navbar-user-nav ul[role='menu']"); + if (userMenu) { + const intraSettingsOption = userMenu.querySelector("a[href='https://profile.intra.42.fr/languages']"); + if (intraSettingsOption) { + intraSettingsOption.innerText = "Intranet Settings"; + } + + const extensionSettingsLink = document.createElement("a"); + // extensionSettingsLink.setAttribute("href", chrome.runtime.getURL('options/options.html')); + extensionSettingsLink.setAttribute("href", "https://darkintra.freekb.es/options.php"); + extensionSettingsLink.setAttribute("target", "_self"); + extensionSettingsLink.innerText = "Improved Intra Settings"; + + const extensionSettings = document.createElement("li"); + extensionSettings.appendChild(extensionSettingsLink); + + userMenu.insertBefore(extensionSettings, userMenu.children[userMenu.children.length - 1]); + } + + // colorize logtime chart based on color scheme + const ltSvg = document.getElementById("user-locations"); + if (ltSvg) { + colorizeLogtimeChart(); + ltSvg.addEventListener("load", colorizeLogtimeChart); + } + + // add titles to achievement names and descriptions for better readability + const achievementItemContents = document.getElementsByClassName("achievement-item--content"); + for (let i = 0; i < achievementItemContents.length; i++) { + const achName = achievementItemContents[i].querySelector("h1"); + if (achName) { + achName.setAttribute("title", achName.textContent.replaceAll("\n", "")); + } + + const achDesc = achievementItemContents[i].querySelector("p"); + if (achDesc) { + achDesc.setAttribute("title", achDesc.textContent); + } + } + + // add day names to agenda overview on dashboard + const eventLefts = document.getElementsByClassName("event-left"); + for (let i = 0; i < eventLefts.length; i++) { + const date = eventLefts[i].querySelector(".date-day").textContent; + const month = eventLefts[i].querySelector(".date-month").textContent; + let jsDate = new Date(date + " " + month + " " + today.getFullYear()); + if (jsDate.getMonth() < today.getMonth()) { + jsDate = new Date(date + " " + month + " " + (today.getFullYear() + 1)); + } + + const dayNameElem = document.createElement("div"); + dayNameElem.className = "date-day-name"; + dayNameElem.innerText = jsDate.toLocaleString("en", { weekday: 'short' }); + eventLefts[i].insertBefore(dayNameElem, eventLefts[i].firstElementChild); + } + + // april 1st easter egg + if (today.getMonth() == 3 && today.getDate() == 1) { + iConsole.log("It's april first! Using Comic Sans everywhere"); + const elements = document.querySelectorAll("body, a, .user-primary, text, .name, .login, .modal-header, h4, h3"); + for (let i = 0; i < elements.length; i++) { + if (elements[i].nodeName == "TEXT") { + elements[i].setAttribute("font-family", "\"Comic Sans MS\", \"Comic Sans\", fantasy"); + } + else { + elements[i].style.fontFamily = "\"Comic Sans MS\", \"Comic Sans\", fantasy"; + } + } + } + + // haha easter egg + if (window.location.hash == "#haha") { + const elements = document.querySelectorAll("*"); + for (let i = 0; i < elements.length; i++) { + elements[i].className += " funnyhaha"; + elements[i].style.animationDuration = randomIntFromInterval(0.1, 10) + "s"; + elements[i].style.animationDelay = randomIntFromInterval(0, 10) + "s"; + } + } +} diff --git a/fixes/improv.js b/fixes/improv.js index acc805e..65d6eb9 100644 --- a/fixes/improv.js +++ b/fixes/improv.js @@ -6,304 +6,12 @@ /* By: fbes +#+ */ /* +#+ */ /* Created: 2021/11/13 00:37:55 by fbes #+# #+# */ -/* Updated: 2022/03/28 17:56:20 by fbes ######## odam.nl */ +/* Updated: 2022/03/28 19:04:09 by fbes ######## odam.nl */ /* */ /* ************************************************************************** */ // this file is used for general improvements on the website -function openLocationMap(event) { - const win = null; - let url = null; - - switch (getCampus()) { - case "Amsterdam": - url = "https://codamhero.dev/v2/clusters.php"; - break; - case "Paris": - url = "https://stud42.fr/clusters"; - break; - default: { - if (event.target.textContent.indexOf(".codam.nl") > -1) { - url = "https://codamhero.dev/v2/clusters.php"; - } - else { - url = "https://meta.intra.42.fr/clusters"; - } - break; - } - } - win = window.open(url, "improved_intra_cluster_map_win"); - // since we can no longer check when a window is loaded with an event - // for domains that are not of the same origin, we simply try and send - // the location ID multiple times to the opened cluster map window - // could also do it with the extension but then we need more permissions... - setTimeout(function() { - win.location.href = url + "#" + event.target.textContent.split(".")[0]; - }, 250); - setTimeout(function() { - win.location.href = url + "#"; - win.location.href = url + "#" + event.target.textContent.split(".")[0]; - }, 500); - setTimeout(function() { - win.location.href = url + "#"; - win.location.href = url + "#" + event.target.textContent.split(".")[0]; - }, 750); - setTimeout(function() { - win.location.href = url + "#"; - win.location.href = url + "#" + event.target.textContent.split(".")[0]; - }, 1000); -} - -function colorizeLogtimeChart(event) { - setTimeout(function() { - const ltSvg = document.getElementById("user-locations"); - if (!ltSvg) { - return; - } - const ltDays = ltSvg.getElementsByTagName("rect"); - const col24hex = getComputedStyle(document.documentElement).getPropertyValue('--logtime-chart-24h-color'); - if (col24hex !== "") { - const col24rgb = hexToRgb(col24hex.trim()); - for (let i = 0; i < ltDays.length; i++) { - const fill = ltDays[i].getAttribute("fill"); - if (fill.indexOf("rgba") > -1) { - const opacity = fill.replace(/^.*,(.+)\)/, '$1'); - ltDays[i].setAttribute("fill", "rgba("+col24rgb.r+","+col24rgb.g+","+col24rgb.b+","+opacity+")"); - } - } - } - }, 250); -} - -function setOptionalImprovements() { - var broadcastNav = document.querySelector(".broadcast-nav"); - if (broadcastNav) { - improvedStorage.get("hide-broadcasts").then(function(data) { - if (data["hide-broadcasts"] === true || data["hide-broadcasts"] === "true") { - broadcastNav.style.display = "none"; - } - }); - } - - var goalsContainer = document.getElementById("goals_container"); - if (goalsContainer) { - improvedStorage.get("hide-goals").then(function(data) { - if (data["hide-goals"] === true || data["hide-goals"] === "true") { - goalsContainer.style.display = "none"; - } - }); - } - - if (hasProfileBanner()) { - var userPosteInfos = document.querySelector(".user-poste-infos"); - if (userPosteInfos) { - improvedStorage.get("clustermap").then(function(data) { - if ((data["clustermap"] === true || data["clustermap"] === "true") && userPosteInfos.innerText != "-") { - userPosteInfos.className += " improved"; - userPosteInfos.setAttribute("tabindex", "0"); - userPosteInfos.addEventListener("mouseenter", setCoalitionTextColor); - userPosteInfos.addEventListener("mouseleave", unsetCoalitionTextColor); - userPosteInfos.addEventListener("click", openLocationMap); - userPosteInfos.addEventListener("keyup", function(event) { - if (event.keyCode == 13) { - openLocationMap(event); - } - }); - } - }); - } - } -} - -function setGeneralImprovements() { - // easter egg - if (window.location.hash == "#haha") { - var elements = document.querySelectorAll("*"); - for (var i = 0; i < elements.length; i++) { - elements[i].className += " funnyhaha"; - elements[i].style.animationDuration = randomIntFromInterval(0.1, 10) + "s"; - elements[i].style.animationDelay = randomIntFromInterval(0, 10) + "s"; - } - } - - // fix things on profile banners - if (hasProfileBanner()) { - var profileActions = document.querySelector(".profile-item .user-primary .user-infos .button-actions"); - var telInfo = document.querySelector(".profile-infos-item a[href*=\"tel:\"]"); - var mailInfo = document.querySelector(".profile-infos-item a[href*=\"mailto:\"]"); - var gitHubInfo = document.querySelector("#ii-profile-link-github"); - var cursusSelector = document.querySelector(".cursus-user-select"); - - // fix coalition colored links - setStyleIfExists(".coalition-name a", "color", getCoalitionColor()); - setStyleIfExists(".correction-point-btn", "color", getCoalitionColor(), true); - - // fix black hole text color - // and if old-blackhole setting is enabled, replace text with old countdown style - var bhColorTimer = setInterval(function() { - var bhDate = document.querySelector("#bh-date"); - if (bhDate) { - var bhDateTitle = bhDate.parentNode.getAttribute("data-original-title"); - if (bhDate.innerText.indexOf("absorbed") > -1) { - clearInterval(bhColorTimer); - bhDate.style.color = "var(--fail-color)"; - if (getProfileUserName) { - improvedStorage.get("username").then(function(data) { - if (data["username"] && data["username"] != getProfileUserName()) { - bhDate.innerText = "User has been absorbed by the Black Hole."; - } - }); - } - } - else if (bhDateTitle.indexOf("days left") > -1) { - var daysRemaining = parseInt(bhDateTitle); - if (isNaN(daysRemaining)) { - return; - } - clearInterval(bhColorTimer); - iConsole.log("Black Hole days remaining: ", daysRemaining); - improvedStorage.get("old-blackhole").then(function(data) { - if (data["old-blackhole"] === true || data["old-blackhole"] === "true") { - bhDate.parentNode.setAttribute("data-original-title", bhDate.innerText); - bhDate.innerText = daysRemaining.toString() + " days left"; - - // add bootstrap tooltip to holder - var evt = new CustomEvent("add-tooltip", { detail: "#bh > .emote-bh" }); - document.dispatchEvent(evt); - - var smiley = document.createElement("span"); - smiley.setAttribute("id", "lt-emote"); - if (daysRemaining > 30) { - smiley.setAttribute("class", "icon-smiley-relax"); - bhDate.style.color = "var(--success-color)"; - smiley.style.color = "var(--success-color)"; - } - else { - smiley.setAttribute("class", "icon-smiley-surprise"); - bhDate.style.color = "var(--warning-color)"; - smiley.style.color = "var(--warning-color)"; - } - bhDate.parentNode.insertBefore(smiley, bhDate); - } - else { - if (daysRemaining > 30) { - bhDate.style.color = "var(--text-color)"; - } - else { - // stylize in warning color if less than 30 colors remaining, just to point it out to user - bhDate.style.color = "var(--warning-color)"; - } - } - }); - } - else { - // fallback styling - bhDate.style.color = "var(--text-color)"; - } - } - }, 100); - - if (profileActions) { - profileActions.addEventListener("mouseenter", setCoalitionTextColor); - profileActions.addEventListener("mouseleave", unsetCoalitionTextColor); - } - - if (telInfo) { - telInfo.addEventListener("mouseenter", setCoalitionTextColor); - } - if (mailInfo) { - mailInfo.addEventListener("mouseenter", setCoalitionTextColor); - } - if (gitHubInfo) { - gitHubInfo.addEventListener("mouseenter", setCoalitionTextColor); - } - if (cursusSelector) { - cursusSelector.addEventListener("change", function(event) { - setTimeout(function() { - var titleSelectorCaret = document.querySelector(".caret[style*='color:']"); - if (titleSelectorCaret) { - titleSelectorCaret.style.color = getCoalitionColor(); - } - var gitHubInfo = document.querySelector("#ii-profile-link-github"); - if (gitHubInfo) { - gitHubInfo.parentNode.style.color = getCoalitionColor(); - } - }, 250); - }); - } - } - - // add link to options in account/user menu - var userMenu = document.querySelector(".main-navbar-user-nav ul[role='menu']"); - if (userMenu) { - var intraSettingsOption = userMenu.querySelector("a[href='https://profile.intra.42.fr/languages']"); - if (intraSettingsOption) { - intraSettingsOption.innerText = "Intranet Settings"; - } - var extensionSettings = document.createElement("li"); - var extensionSettingsLink = document.createElement("a"); - // extensionSettingsLink.setAttribute("href", chrome.runtime.getURL('options/options.html')); - extensionSettingsLink.setAttribute("href", "https://darkintra.freekb.es/options.php"); - extensionSettingsLink.setAttribute("target", "_self"); - extensionSettingsLink.innerText = "Improved Intra Settings"; - extensionSettings.appendChild(extensionSettingsLink); - userMenu.insertBefore(extensionSettings, userMenu.children[userMenu.children.length - 1]); - } - - var ltSvg = document.getElementById("user-locations"); - if (ltSvg) { - colorizeLogtimeChart(); - ltSvg.addEventListener("load", colorizeLogtimeChart); - } - - // add titles to achievement names and descriptions for better readability - var achievementItemContents = document.getElementsByClassName("achievement-item--content"); - for (var i = 0; i < achievementItemContents.length; i++) { - var achName = achievementItemContents[i].querySelector("h1"); - var achDesc = achievementItemContents[i].querySelector("p"); - - if (achName) { - achName.setAttribute("title", achName.textContent.replaceAll("\n", "")); - } - if (achDesc) { - achDesc.setAttribute("title", achDesc.textContent); - } - } - - // add day names to agenda overview on dashboard - var currentDate = new Date(); - var eventLefts = document.getElementsByClassName("event-left"); - var jsDate, date, month; - for (var i = 0; i < eventLefts.length; i++) { - date = eventLefts[i].querySelector(".date-day").textContent; - month = eventLefts[i].querySelector(".date-month").textContent; - jsDate = new Date(date + " " + month + " " + currentDate.getFullYear()); - if (jsDate.getMonth() < currentDate.getMonth()) { - jsDate = new Date(date + " " + month + " " + (currentDate.getFullYear() + 1)); - } - var dayNameElem = document.createElement("div"); - dayNameElem.className = "date-day-name"; - dayNameElem.innerText = jsDate.toLocaleString("en", { weekday: 'short' }); - eventLefts[i].insertBefore(dayNameElem, eventLefts[i].firstElementChild); - } - - // april 1st easter egg - const today = new Date(); - if (today.getMonth() == 3 && today.getDate() == 1) { - iConsole.log("It's april first! Using Comic Sans everywhere"); - const elements = document.querySelectorAll("body, a, .user-primary, text, .name, .login, .modal-header, h4, h3"); - for (let i = 0; i < elements.length; i++) { - if (elements[i].nodeName == "TEXT") { - elements[i].setAttribute("font-family", "\"Comic Sans MS\", \"Comic Sans\", fantasy"); - } - else { - elements[i].style.fontFamily = "\"Comic Sans MS\", \"Comic Sans\", fantasy"; - } - } - } -} - // enable general improvements setGeneralImprovements(); diff --git a/fixes/optional.js b/fixes/optional.js new file mode 100644 index 0000000..080ba13 --- /dev/null +++ b/fixes/optional.js @@ -0,0 +1,55 @@ +/* ************************************************************************** */ +/* */ +/* :::::::: */ +/* optional.js :+: :+: */ +/* +:+ */ +/* By: fbes +#+ */ +/* +#+ */ +/* Created: 2022/03/28 18:55:12 by fbes #+# #+# */ +/* Updated: 2022/03/28 19:22:28 by fbes ######## odam.nl */ +/* */ +/* ************************************************************************** */ + +function setOptionalImprovements() { + // hide broadcasts + const broadcastNav = document.querySelector(".broadcast-nav"); + if (broadcastNav) { + improvedStorage.get("hide-broadcasts").then(function(data) { + if (data["hide-broadcasts"] === true || data["hide-broadcasts"] === "true") { + broadcastNav.style.display = "none"; + } + }); + } + + // hide black hole container + const goalsContainer = document.getElementById("goals_container"); + if (goalsContainer) { + improvedStorage.get("hide-goals").then(function(data) { + if (data["hide-goals"] === true || data["hide-goals"] === "true") { + goalsContainer.style.display = "none"; + } + }); + } + + if (hasProfileBanner()) { + // open cluster map on location click + const userPosteInfos = document.querySelector(".user-poste-infos"); + if (userPosteInfos) { + improvedStorage.get("clustermap").then(function(data) { + if ((data["clustermap"] === true || data["clustermap"] === "true") && userPosteInfos.innerText != "-") { + userPosteInfos.className += " improved"; + userPosteInfos.setAttribute("tabindex", "0"); + userPosteInfos.addEventListener("mouseenter", setCoalitionTextColor); + userPosteInfos.addEventListener("mouseleave", unsetCoalitionTextColor); + userPosteInfos.addEventListener("click", openClusterMap); + userPosteInfos.addEventListener("auxclick", openClusterMap); + userPosteInfos.addEventListener("keyup", function(event) { + if (event.keyCode == 13) { + openClusterMap(event); + } + }); + } + }); + } + } +} diff --git a/fixes/fonts.css b/generic/fonts.css similarity index 100% rename from fixes/fonts.css rename to generic/fonts.css diff --git a/generic/init.js b/generic/init.js index be6d224..fc1b006 100644 --- a/generic/init.js +++ b/generic/init.js @@ -6,7 +6,7 @@ /* By: fbes +#+ */ /* +#+ */ /* Created: 2022/03/27 03:00:23 by fbes #+# #+# */ -/* Updated: 2022/03/27 03:00:23 by fbes ######## odam.nl */ +/* Updated: 2022/03/28 18:44:22 by fbes ######## odam.nl */ /* */ /* ************************************************************************** */ @@ -24,3 +24,4 @@ if (window.location.origin.indexOf(".intra.42.fr") > -1) { // global variables const improvedStorage = getSessionStorage(); const portName = (chrome.extension.inIncognitoContext ? "incog_comm" : "normal_comm"); +const today = new Date(); diff --git a/generic/useful.js b/generic/useful.js index 492f8c1..f3d7311 100644 --- a/generic/useful.js +++ b/generic/useful.js @@ -6,10 +6,15 @@ /* By: fbes +#+ */ /* +#+ */ /* Created: 2022/03/28 17:03:38 by fbes #+# #+# */ -/* Updated: 2022/03/28 17:55:38 by fbes ######## odam.nl */ +/* Updated: 2022/03/28 18:44:11 by fbes ######## odam.nl */ /* */ /* ************************************************************************** */ +// from https://stackoverflow.com/questions/8667070/javascript-regular-expression-to-validate-url (jesus) +function validateUrl(value) { + return /^(?:(?:(?:https?|ftp):)?\/\/)(?:\S+(?::\S*)?@)?(?:(?!(?:10|127)(?:\.\d{1,3}){3})(?!(?:169\.254|192\.168)(?:\.\d{1,3}){2})(?!172\.(?:1[6-9]|2\d|3[0-1])(?:\.\d{1,3}){2})(?:[1-9]\d?|1\d\d|2[01]\d|22[0-3])(?:\.(?:1?\d{1,2}|2[0-4]\d|25[0-5])){2}(?:\.(?:[1-9]\d?|1\d\d|2[0-4]\d|25[0-4]))|(?:(?:[a-z\u00a1-\uffff0-9]-*)*[a-z\u00a1-\uffff0-9]+)(?:\.(?:[a-z\u00a1-\uffff0-9]-*)*[a-z\u00a1-\uffff0-9]+)*(?:\.(?:[a-z\u00a1-\uffff]{2,})))(?::\d{2,5})?(?:[/?#]\S*)?$/i.test(value); +} + // get the coalition color of a user or coalition on a webpage function getCoalitionColor() { try { @@ -31,6 +36,16 @@ function getCampus() { } } +// get the username from a profile +function getProfileUserName() { + try { + return (document.querySelector(".login[data-login]").getAttribute("data-login")); + } + catch (err) { + return (null); + } +} + // convert hex color to rgb color object // from https://stackoverflow.com/questions/5623838/rgb-to-hex-and-hex-to-rgb function hexToRgb(hex) { diff --git a/manifest-ff.json b/manifest-ff.json index 5ca7519..73ca269 100644 --- a/manifest-ff.json +++ b/manifest-ff.json @@ -45,7 +45,7 @@ "content_scripts": [ { "matches": [ "*://*.intra.42.fr/*" ], - "css": [ "fixes/fonts.css", "fixes/improv.css", "fixes/animations.css", "features/themes/apply.css" ], + "css": [ "generic/fonts.css", "fixes/improv.css", "fixes/animations.css", "features/themes/apply.css" ], "run_at": "document_start" }, { @@ -60,7 +60,7 @@ }, { "matches": [ "*://*.intra.42.fr/*" ], - "js": [ "fixes/improv.js" ], + "js": [ "features/clustermap.js", "fixes/blackhole.js", "fixes/banners.js", "fixes/general.js", "fixes/optional.js", "fixes/improv.js" ], "run_at": "document_end" }, { diff --git a/manifest.json b/manifest.json index b9a7ee7..fe13fe4 100644 --- a/manifest.json +++ b/manifest.json @@ -40,7 +40,7 @@ "content_scripts": [ { "matches": [ "*://*.intra.42.fr/*" ], - "css": [ "fixes/fonts.css", "fixes/improv.css", "fixes/animations.css", "features/themes/apply.css" ], + "css": [ "generic/fonts.css", "fixes/improv.css", "fixes/animations.css", "features/themes/apply.css" ], "run_at": "document_start" }, { @@ -55,7 +55,7 @@ }, { "matches": [ "*://*.intra.42.fr/*" ], - "js": [ "fixes/improv.js" ], + "js": [ "features/clustermap.js", "fixes/blackhole.js", "fixes/banners.js", "fixes/general.js", "fixes/optional.js", "fixes/improv.js" ], "run_at": "document_end" }, { diff --git a/options/options.js b/options/options.js index 8ee3c8a..03efd12 100644 --- a/options/options.js +++ b/options/options.js @@ -6,7 +6,7 @@ /* By: fbes +#+ */ /* +#+ */ /* Created: 2021/11/28 02:23:39 by fbes #+# #+# */ -/* Updated: 2022/03/07 04:16:40 by fbes ######## odam.nl */ +/* Updated: 2022/03/28 19:20:10 by fbes ######## odam.nl */ /* */ /* ************************************************************************** */ @@ -25,7 +25,7 @@ function checkIfKeyStillWorks(access_token) { req.setRequestHeader('Content-type', 'application/x-www-form-urlencoded'); req.addEventListener("load", function(event) { try { - var res = JSON.parse(this.responseText); + const res = JSON.parse(this.responseText); if (res["type"] == "error") { it_does_not_work(res); } @@ -139,7 +139,7 @@ function syncSettings(event) { req.addEventListener("load", function(event) { syncBtn.className = ""; try { - var res = JSON.parse(this.responseText); + const res = JSON.parse(this.responseText); if (res["type"] == "error") { iConsole.error("Settings sync result", res); } @@ -212,7 +212,7 @@ function retrieveSettings() { try { const formElems = document.querySelectorAll("form select, form input"); const keysToGet = []; - for (var i = 0; i < formElems.length; i++) { + for (let i = 0; i < formElems.length; i++) { keysToGet.push(formElems[i].getAttribute("name")); } iConsole.log(keysToGet); From fda9668b76b8151d8f6ec26b08f9c7ca7abda0a0 Mon Sep 17 00:00:00 2001 From: Freek Bes Date: Mon, 28 Mar 2022 19:34:19 +0200 Subject: [PATCH 25/45] remove from todo list --- todo.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/todo.txt b/todo.txt index d13c4be..54604fe 100644 --- a/todo.txt +++ b/todo.txt @@ -2,16 +2,16 @@ USEFUL: Manifest v3 options overview: https://developer.chrome.com/docs/extensions/mv3/manifest/ TODO: -- convert every var to either const or let - create way to report user customization features to the server - create way to see user reports when logged in with an Intra staff account - reorganize manifests -- separate some improvements - split up Codam Monitoring System's cumulative hours and the actual thing into ft_logtime like feature and the previous actual thing - more security background checks for the server back-end with the Intra API: store generated keys in a non-public database file - implement more cluster maps, maybe even custom ones into the extension itself? DONE: +- convert every var to either const or let +- separate some improvements - create backbone structure for local storage and syncing settings, with separate storage for incognito - create internal console.log function to deal with styling in the console ("[Improved Intra] msg") - create themes folder and move all theme-related stuff in there From 6902b4bec670cbaa22d10f3589859f5cf46f2465 Mon Sep 17 00:00:00 2001 From: Freek Bes Date: Mon, 28 Mar 2022 22:15:51 +0200 Subject: [PATCH 26/45] fix egg easter egg --- features/themes/apply.css | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/features/themes/apply.css b/features/themes/apply.css index f531c26..a49768a 100644 --- a/features/themes/apply.css +++ b/features/themes/apply.css @@ -6,7 +6,7 @@ /* By: fbes +#+ */ /* +#+ */ /* Created: 2021/11/13 00:38:03 by fbes #+# #+# */ -/* Updated: 2022/03/28 19:13:08 by fbes ######## odam.nl */ +/* Updated: 2022/03/28 22:14:12 by fbes ######## odam.nl */ /* */ /* ************************************************************************** */ @@ -664,8 +664,8 @@ li.scaleteam-list-item .rating:not([data-positive=""]) { border-color: var(--general-border-color) !important; } -.profile-item .profile-item-top.home-banner, -.profile-item .profile-item-top.profile-banner { +.profile-item .profile-item-top.home-banner:not(.egg), +.profile-item .profile-item-top.profile-banner:not(.egg) { background-color: var(--theme-color-dark) !important; } From 57381d08472466fe29dac542b94b4964391eb595 Mon Sep 17 00:00:00 2001 From: Freek Bes <36384333+FreekBes@users.noreply.github.com> Date: Tue, 29 Mar 2022 22:57:14 +0200 Subject: [PATCH 27/45] add @IzaakVellinga sponsor title --- fixes/improv.css | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/fixes/improv.css b/fixes/improv.css index 9a1b10b..c869159 100644 --- a/fixes/improv.css +++ b/fixes/improv.css @@ -333,10 +333,14 @@ a[data-tooltip-login="pde-bakk"]:not(.student-kind-student)::before, a[data-tooltip-login="lde-la-h"]:not(.student-kind-student)::before, .profile-name span.login[data-login="lde-la-h"]::before, a[data-tooltip-login="jlensing"]:not(.student-kind-student)::before, -.profile-name span.login[data-login="jlensing"]::before, +.profile-name span.login[data-login="jlensing"]::before { + content: 'Improved Intra Contributor '; +} + +/* custom titles for sponsors */ a[data-tooltip-login="ieilat"]:not(.student-kind-student)::before, .profile-name span.login[data-login="ieilat"]::before { - content: 'Improved Intra Contributor '; + content: 'Improved Intra Sponsor '; } /* custom title for creator */ From ce5ad70ffef73130cd9b83708dbe2ff26c28e91e Mon Sep 17 00:00:00 2001 From: Freek Bes Date: Fri, 1 Apr 2022 19:27:52 +0200 Subject: [PATCH 28/45] Bugfix theming on notification list Co-authored by: nimon --- features/themes/apply.css | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/features/themes/apply.css b/features/themes/apply.css index a49768a..66ed58f 100644 --- a/features/themes/apply.css +++ b/features/themes/apply.css @@ -6,7 +6,7 @@ /* By: fbes +#+ */ /* +#+ */ /* Created: 2021/11/13 00:38:03 by fbes #+# #+# */ -/* Updated: 2022/03/28 22:14:12 by fbes ######## odam.nl */ +/* Updated: 2022/04/01 19:25:33 by fbes ######## odam.nl */ /* */ /* ************************************************************************** */ @@ -158,6 +158,7 @@ h6 small, h6 .small, .dropdown-menu, .broad-content, .notifications-container, +.notification-list, .tt-menu, .chosen-container .chosen-drop { background-color: var(--container-background-color) !important; From 21ea2d885ef1b546ca5106de87f913c163ca0929 Mon Sep 17 00:00:00 2001 From: Freek Bes Date: Fri, 1 Apr 2022 19:52:41 +0200 Subject: [PATCH 29/45] fixed customized banners flashing in and out of existence --- features/profiles.js | 45 ++++++++++++++++++++------------------------ fixes/improv.css | 29 +++++++++++++++++++++++++--- 2 files changed, 46 insertions(+), 28 deletions(-) diff --git a/features/profiles.js b/features/profiles.js index ab32700..ed090f6 100644 --- a/features/profiles.js +++ b/features/profiles.js @@ -6,7 +6,7 @@ /* By: fbes +#+ */ /* +#+ */ /* Created: 2022/01/09 01:01:42 by fbes #+# #+# */ -/* Updated: 2022/03/28 19:18:05 by fbes ######## odam.nl */ +/* Updated: 2022/04/01 19:49:24 by fbes ######## odam.nl */ /* */ /* ************************************************************************** */ @@ -14,6 +14,7 @@ let gUName = null; let gProfileBanner = null; +let gCustomBanner = null; let gInterval = null; let gExtSettings = null; let gUserSettings = null; @@ -55,20 +56,20 @@ function getUserSettings(username) { function setCustomBanner(imageUrl, imagePos) { if (imageUrl && validateUrl(imageUrl)) { const newCSSval = "url(\"" + imageUrl + "\")"; - if (gProfileBanner.style.backgroundImage.indexOf(imageUrl) == -1) { - gProfileBanner.className += " customized"; - gProfileBanner.setAttribute("data-old-bg", gProfileBanner.style.backgroundImage); - gProfileBanner.style.backgroundImage = newCSSval; + if (gCustomBanner.style.backgroundImage.indexOf(imageUrl) == -1) { + gCustomBanner.className += " customized"; + gCustomBanner.setAttribute("data-old-bg", gProfileBanner.style.backgroundImage); + gCustomBanner.style.backgroundImage = newCSSval; switch (imagePos) { default: case "center-center": - gProfileBanner.style.backgroundPosition = "center center"; + gCustomBanner.style.backgroundPosition = "center center"; break; case "center-top": - gProfileBanner.style.backgroundPosition = "center top"; + gCustomBanner.style.backgroundPosition = "center top"; break; case "center-bottom": - gProfileBanner.style.backgroundPosition = "center bottom"; + gCustomBanner.style.backgroundPosition = "center bottom"; break; } iConsole.log("Custom banner set!"); @@ -79,9 +80,8 @@ function setCustomBanner(imageUrl, imagePos) { } function unsetCustomBannerIfRequired() { - if (gProfileBanner.getAttribute("data-old-bg")) { - gProfileBanner.style.backgroundImage = gProfileBanner.getAttribute("data-old-bg"); - gProfileBanner.removeAttribute("data-old-bg"); + if (gCustomBanner.style.backgroundImage) { + gCustomBanner.style.backgroundImage = null; iConsole.log("Custom banner unset"); } } @@ -155,9 +155,17 @@ function setCustomProfile() { } function immediateProfileChanges() { + // add custom banner image container + if (gProfileBanner) { + gCustomBanner = document.createElement("div"); + gCustomBanner.className = "improved-intra-banner"; + gProfileBanner.insertBefore(gCustomBanner, gProfileBanner.children[0]); + } + // easter egg for user fbes, even when customized profiles are disabled if (gProfileBanner && gUName == "fbes") { gProfileBanner.className += " egg"; + gCustomBanner.className += " egg"; } if (window.location.pathname.indexOf("/users/") == 0) { @@ -212,18 +220,6 @@ function immediateProfileChanges() { } } -// check if the custom profile is kept in an interval for 5 seconds -// sometimes things get overruled by coalition stuff, such as banners -function confirmProfileUpdatedForFiveSeconds() { - if (!gInterval) { - gInterval = setInterval(setCustomBannerWrapper, 150); - setTimeout(function() { - clearInterval(gInterval); - gInterval = null; - }, 5000); - } -} - gUName = getProfileUserName(); gProfileBanner = document.querySelector(".container-inner-item.profile-item-top.profile-banner"); immediateProfileChanges(); @@ -231,12 +227,11 @@ improvedStorage.get(["username", "show-custom-profiles", "custom-banner-url", "c gExtSettings = data; setCustomBannerWrapper(); setCustomProfile(); - confirmProfileUpdatedForFiveSeconds(); }); const cursusSelector = document.querySelector(".cursus-user-select"); if (cursusSelector) { cursusSelector.addEventListener("change", function(event) { - confirmProfileUpdatedForFiveSeconds(); + // confirmProfileUpdatedForFiveSeconds(); }); } diff --git a/fixes/improv.css b/fixes/improv.css index c869159..42cb031 100644 --- a/fixes/improv.css +++ b/fixes/improv.css @@ -6,7 +6,7 @@ /* By: fbes +#+ */ /* +#+ */ /* Created: 2021/11/28 01:00:01 by fbes #+# #+# */ -/* Updated: 2022/03/28 17:25:50 by fbes ######## odam.nl */ +/* Updated: 2022/04/01 19:50:43 by fbes ######## odam.nl */ /* */ /* ************************************************************************** */ @@ -224,7 +224,8 @@ li.scaleteam-list-item .rating { } /* fix background banner repeating on small screens */ -.profile-banner { +.profile-banner, +.improved-intra-banner { background-size: cover !important; } @@ -327,6 +328,7 @@ li.scaleteam-list-item .rating { cursor: pointer !important; } + /* custom titles for contributors */ a[data-tooltip-login="pde-bakk"]:not(.student-kind-student)::before, .profile-name span.login[data-login="pde-bakk"]::before, @@ -349,8 +351,29 @@ a[data-tooltip-login="fbes"]:not(.student-kind-student)::before, content: 'Improved Intra Creator '; } +/* set position relative for profile banner to customize absolute positions based on this element */ +.container-inner-item.profile-item-top.profile-banner { + position: relative; +} + +/* set z-index for all elements in the profile banner to accustom for the custom banner */ +.container-inner-item.profile-item-top.profile-banner > * { + z-index: 1 !important; +} + +/* custom banner element */ +.improved-intra-banner.customized { + position: absolute !important; + top: 0 !important; + left: 0 !important; + right: 0 !important; + bottom: 0 !important; + z-index: 0 !important; +} + /* profile page easter egg for fbes (me, le creator) */ -.container-inner-item.profile-item-top.profile-banner.egg { +.container-inner-item.profile-item-top.profile-banner.egg, +.improved-intra-banner.customized.egg { background-blend-mode: multiply !important; animation: rainbow-bg 16s linear !important; animation-iteration-count: infinite !important; From fef11a05f79aaef06b5923af84af3dad2f22fae6 Mon Sep 17 00:00:00 2001 From: Freek Bes Date: Mon, 4 Apr 2022 21:17:05 +0200 Subject: [PATCH 30/45] remove dark intra reference --- features/campus/codam/monit.css | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/features/campus/codam/monit.css b/features/campus/codam/monit.css index 18a9617..36e3330 100644 --- a/features/campus/codam/monit.css +++ b/features/campus/codam/monit.css @@ -6,7 +6,7 @@ /* By: fbes +#+ */ /* +#+ */ /* Created: 2021/11/11 19:23:10 by fbes #+# #+# */ -/* Updated: 2021/11/28 02:22:44 by fbes ######## odam.nl */ +/* Updated: 2022/04/04 17:41:56 by fbes ######## odam.nl */ /* */ /* ************************************************************************** */ @@ -30,5 +30,5 @@ } #codam_intra_monit_system_display_deprecation_notice.upgraded::before { - content: "Dark Intra 42 has been renamed to Improved Intra 42 and now includes the Monitoring System Progress functionality. You're seeing this message because you still have the old Monitoring Progress extension installed. You can remove it now."; + content: "Improved Intra 42 now includes the Monitoring System Progress functionality. You're seeing this message because you still have the old Monitoring Progress extension installed. You can remove it now."; } \ No newline at end of file From e1cb6fa3aa64c290ab24a60a647e17ae8cee77ce Mon Sep 17 00:00:00 2001 From: Freek Bes <36384333+FreekBes@users.noreply.github.com> Date: Tue, 5 Apr 2022 21:45:55 +0200 Subject: [PATCH 31/45] add peer --- fixes/improv.css | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/fixes/improv.css b/fixes/improv.css index 42cb031..85790b7 100644 --- a/fixes/improv.css +++ b/fixes/improv.css @@ -351,6 +351,34 @@ a[data-tooltip-login="fbes"]:not(.student-kind-student)::before, content: 'Improved Intra Creator '; } +/* easter egg for pde-bakk */ +.user-profile-picture[style*="/pde-bakk/"], +.search-user-picture[style*="/pde-bakk/"], +.profile-image[style*="/pde-bakk/"], +.user-image[style*="/pde-bakk/"] { + border-radius: 50% 15% 50% 50% !important; + transform: rotate(-33deg) !important; + box-shadow: inset 0px 1px 4px 4px #edd65b !important; + overflow: unset !important; +} +.user-profile-picture[style*="/pde-bakk/"]::after, +.search-user-picture[style*="/pde-bakk/"]::after, +.profile-image[style*="/pde-bakk/"]::after, +.user-image[style*="/pde-bakk/"]::after { + content: ""; + width: 3%; + height: 11%; + background-color: brown; + display: block; + position: absolute; + z-index: 2; + left: 95%; + top: -2%; + transform: rotate(45deg); + box-shadow: 0px 3px 7px 0px #6a5f22; + border-radius: 50% 15%; +} + /* set position relative for profile banner to customize absolute positions based on this element */ .container-inner-item.profile-item-top.profile-banner { position: relative; From f1c1ef30ae080456691b47c64b0e1ecef0519057 Mon Sep 17 00:00:00 2001 From: Freek Bes <36384333+FreekBes@users.noreply.github.com> Date: Tue, 5 Apr 2022 21:47:03 +0200 Subject: [PATCH 32/45] futura class font-family fix windows --- fixes/improv.css | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/fixes/improv.css b/fixes/improv.css index 85790b7..aa5ab9b 100644 --- a/fixes/improv.css +++ b/fixes/improv.css @@ -20,7 +20,12 @@ html { overflow-x: hidden !important; } -/* Windows Futura font family fix */ +/* Windows Futura font-family fix */ +.futura { + font-family: "Futura PT", "Futura", "futura", "Helvetica", Verdana, Arial, Sans-Serif !important; +} + +/* Windows Futura font family fix (BOLD) */ .modal-v2 .modal-header, .event-modal .head h4, .exam-modal .head h4, From 39a38167428d28385c99e831a478d0bdc4ec9995 Mon Sep 17 00:00:00 2001 From: Freek Bes <36384333+FreekBes@users.noreply.github.com> Date: Tue, 5 Apr 2022 21:55:45 +0200 Subject: [PATCH 33/45] add peer to tooltip and bg-images --- fixes/improv.css | 40 ++++++++++++++++++++++------------------ 1 file changed, 22 insertions(+), 18 deletions(-) diff --git a/fixes/improv.css b/fixes/improv.css index aa5ab9b..387d42b 100644 --- a/fixes/improv.css +++ b/fixes/improv.css @@ -45,6 +45,24 @@ li.scaleteam-list-item .rating { flex-basis: 50px !important; } +/* set default color on tooltips */ +.tooltip { + cursor: default !important; +} + +/* add box shadow to tooltips */ +.tooltip-content { + box-shadow: 0px 0px 3px -1px #000 !important; +} + +/* fix border radius for tooltip user images */ +.tooltip-content .tooltip-img.rounded[style*="intra.42.fr/users/"] { + background-size: cover !important; + width: 60px !important; + height: 60px !important; + border-radius: 30px !important; +} + /* force user profile pictures to always cover the whole element */ .user-profile-picture { background-size: cover !important; @@ -359,6 +377,8 @@ a[data-tooltip-login="fbes"]:not(.student-kind-student)::before, /* easter egg for pde-bakk */ .user-profile-picture[style*="/pde-bakk/"], .search-user-picture[style*="/pde-bakk/"], +.tooltip-content[data-tooltip="pde-bakk"] .tooltip-img.rounded, +.bg-image-item.rounded[style*="/pde-bakk/"], .profile-image[style*="/pde-bakk/"], .user-image[style*="/pde-bakk/"] { border-radius: 50% 15% 50% 50% !important; @@ -368,6 +388,8 @@ a[data-tooltip-login="fbes"]:not(.student-kind-student)::before, } .user-profile-picture[style*="/pde-bakk/"]::after, .search-user-picture[style*="/pde-bakk/"]::after, +.tooltip-content[data-tooltip="pde-bakk"] .tooltip-img.rounded::after, +.bg-image-item.rounded[style*="/pde-bakk/"]::after, .profile-image[style*="/pde-bakk/"]::after, .user-image[style*="/pde-bakk/"]::after { content: ""; @@ -554,24 +576,6 @@ textarea { max-width: 100% !important; } -/* set default color on tooltips */ -.tooltip { - cursor: default !important; -} - -/* add box shadow to tooltips */ -.tooltip-content { - box-shadow: 0px 0px 3px -1px #000 !important; -} - -/* fix border radius for tooltip user images */ -.tooltip-content .tooltip-img.rounded[style*="intra.42.fr/users/"] { - background-size: cover !important; - width: 60px !important; - height: 60px !important; - border-radius: 30px !important; -} - @media (min-width: 1600px) { /* fix vertical alignment of coalition name in user profile banner on screens >1600px wide */ .profile-banner .coalition-name { From aeb6d3d394bb276ee75bfa1ca83523c2da3b56ed Mon Sep 17 00:00:00 2001 From: Freek Bes <36384333+FreekBes@users.noreply.github.com> Date: Tue, 5 Apr 2022 22:03:54 +0200 Subject: [PATCH 34/45] fixBlackHoleContainer no longer being called if no goals container --- fixes/banners.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/fixes/banners.js b/fixes/banners.js index 1d4c678..a7ffbc7 100644 --- a/fixes/banners.js +++ b/fixes/banners.js @@ -16,7 +16,9 @@ function fixProfileBanners() { setStyleIfExists(".correction-point-btn", "color", getCoalitionColor(), true); // fix black hole container issues, such as text color - fixBlackHoleContainer(); + if (document.getElementById("goals_container")) { + fixBlackHoleContainer(); + } const profileActions = document.querySelector(".profile-item .user-primary .user-infos .button-actions"); if (profileActions) { From a2a50dc3dc0bea8b92998b5da37ef3a2a69b7379 Mon Sep 17 00:00:00 2001 From: Freek Bes <36384333+FreekBes@users.noreply.github.com> Date: Tue, 5 Apr 2022 23:02:38 +0200 Subject: [PATCH 35/45] fix #8 (split up monit.js) finally! cumulative hours per month is still on the todo list. --- background/options.js | 2 + features/campus/codam/monit.css | 9 -- features/campus/codam/monit.js | 179 ++++---------------------------- features/logtimes.js | 83 +++++++++++++++ features/profiles.js | 5 +- fixes/blackhole.js | 3 +- generic/init.js | 2 + generic/useful.js | 20 ++++ manifest-ff.json | 7 +- manifest.json | 7 +- options/addoption.txt | 4 +- server/options.php | 19 +++- server/update.php | 46 +++++++- 13 files changed, 193 insertions(+), 193 deletions(-) create mode 100644 features/logtimes.js diff --git a/background/options.js b/background/options.js index d80dfc5..9970608 100644 --- a/background/options.js +++ b/background/options.js @@ -20,6 +20,8 @@ const defaults = { "hide-broadcasts": "false", "hide-goals": "false", "link-github": "", + "logsum-month": "true", + "logsum-week": "true", "old-blackhole": "false", "show-custom-profiles": "true", "sync": "true", diff --git a/features/campus/codam/monit.css b/features/campus/codam/monit.css index 36e3330..9550cfb 100644 --- a/features/campus/codam/monit.css +++ b/features/campus/codam/monit.css @@ -23,12 +23,3 @@ vertical-align: middle; margin-right: 0.5ch; } - -/* styling to remove deprecated codam_intra_monit_system_display extension */ -#codam_intra_monit_system_display_deprecation_notice.upgraded > span { - display: none !important; -} - -#codam_intra_monit_system_display_deprecation_notice.upgraded::before { - content: "Improved Intra 42 now includes the Monitoring System Progress functionality. You're seeing this message because you still have the old Monitoring Progress extension installed. You can remove it now."; -} \ No newline at end of file diff --git a/features/campus/codam/monit.js b/features/campus/codam/monit.js index 5b3ae23..db4243b 100644 --- a/features/campus/codam/monit.js +++ b/features/campus/codam/monit.js @@ -10,11 +10,14 @@ /* */ /* ************************************************************************** */ -// for checking if user has corrected anything -// implement in the future -// '/users/{user_id}/scale_teams/as_corrected' -// https://github.com/troplolBE/bettercorrectors#sample-1 - +/* +for checking if user has corrected anything +implement in the future +'/users/{user_id}/scale_teams/as_corrected' +https://github.com/troplolBE/bettercorrectors#sample-1 +*/ + +// used in Array.reduce function sum(prevVal, curVal) { return (prevVal + curVal); } @@ -27,42 +30,17 @@ const monit = { achievement1: 3000, achievement2: 4800 }, - dayOfWeek: -1, bhContainer: null, logTimes: [], logTimesTotal: 0, username: "me", - /** - * Get the color of the user's coalition - */ - getCoalitionColor: function() { - try { - return (document.getElementsByClassName("coalition-span")[0].style.color); - } - catch (err) { - return ("#FF0000"); - } - }, - - /** - * Get username of profile - */ - getUserName: function() { - try { - return (document.querySelector(".profile-item .profile-name .login[data-login]").getAttribute("data-login")); - } - catch (err) { - return (null); - } - }, - /** * Get the dates of this week's days */ getWeekDates: function() { const thisWeek = []; - for (let i = 0; i <= monit.dayOfWeek; i++) { + for (let i = 0; i <= dayOfWeek; i++) { thisWeek.push(new Date(today.getTime() - 86400000 * i).toISOString().split("T")[0]); } iConsole.log("This week's dates: ", thisWeek); @@ -84,35 +62,17 @@ const monit = { else { logTimesTotalNoToday = 0; } - if (this.dayOfWeek == 7 || this.logTimesTotal > this.requirements.min) { + if (dayOfWeek == 7 || this.logTimesTotal > this.requirements.min) { this.requirements.today = this.requirements.min; } else { - this.requirements.today = logTimesTotalNoToday + Math.round((this.requirements.min - logTimesTotalNoToday) / (7 - this.dayOfWeek)); + this.requirements.today = logTimesTotalNoToday + Math.round((this.requirements.min - logTimesTotalNoToday) / (7 - dayOfWeek)); } iConsole.log("Logtime up until today", logTimesTotalNoToday); iConsole.log("Expected minutes today", this.requirements.today - logTimesTotalNoToday); iConsole.log("Expected minutes after today", this.requirements.today); }, - /** - * Parse a piece of logtime text: in format HHhMM or HH:MM(:SS) - */ - parseLogTime: function(logTimeText) { - const logTimeSplit = (logTimeText.indexOf("h") > -1 ? logTimeText.split("h") : logTimeText.split(":")); - if (logTimeSplit.length < 2) { - return (0); - } - return (parseInt(logTimeSplit[0]) * 60 + parseInt(logTimeSplit[1])); - }, - - /** - * Convert a logTime into a string with format HHhMM - */ - logTimeToString: function(logTime) { - return (Math.floor(logTime / 60) + "h" + (logTime % 60).toLocaleString(undefined, {minimumIntegerDigits: 2})); - }, - /** * Get a user's logtime from the web and parse it into the logtime array */ @@ -129,7 +89,7 @@ const monit = { monit.logTimes = []; for (let i = 0; i < weekDates.length; i++) { if (weekDates[i] in stats) { - monit.logTimes.push(monit.parseLogTime(stats[weekDates[i]])); + monit.logTimes.push(parseLogTime(stats[weekDates[i]])); } else { monit.logTimes.push(0); @@ -155,79 +115,6 @@ const monit = { })); }, - /** - * Get the logtime from the logtime chart, modify the chart to include - * progress for previous weeks, and parse this week's logtime into the logtime array - */ - getLogTimes: function() { - return (new Promise(function (resolve, reject) { - const ltSvg = document.getElementById("user-locations"); - if (!ltSvg) { - reject("Element #user-locations not found"); - } - const ltDays = ltSvg.getElementsByTagName("g"); - let ltDay = ltDays[ltDays.length - 1]; - let i; - - monit.logTimes = []; - for (i = 0; i <= monit.dayOfWeek; i++) { - ltDay = ltDays[ltDays.length - i - 1]; - if (!ltDay) { - reject("Failed to read data from SVG logtime chart"); - } - monit.logTimes.push(monit.parseLogTime(ltDay.getAttribute("data-original-title"))); - } - if (monit.logTimes && monit.logTimes.length > 0) { - monit.logTimesTotal = monit.logTimes.reduce(sum); - } - else { - monit.logTimesTotal = 0; - } - - let daysInWeek = monit.dayOfWeek + 1; - const remainingWeeks = Math.floor(ltDays.length / 7) + (monit.dayOfWeek != 6 ? 1 : 0); - let r = 0; - for (i = 0; i < remainingWeeks; i++) { - let j; - - if (i == 1) { - daysInWeek = 7; - } - const tempLogTimes = []; - - // parse individual logtimes - for (j = 0; j < daysInWeek; j++) { - ltDay = ltDays[ltDays.length - r - 1]; - if (!ltDay) { - resolve(); - return; - } - tempLogTimes.push(monit.parseLogTime(ltDay.getAttribute("data-original-title"))); - if (tempLogTimes[j] == 0) { - ltDay.setAttribute("data-nolog", ""); - } - r++; - } - - // calculate cumulative logtime - for (j = daysInWeek - 2; j > -1; j--) { - tempLogTimes[j] = tempLogTimes[j] + tempLogTimes[j + 1]; - } - - // add cumulative logtime and percentage to tooltips - for (j = daysInWeek - 1; j > -1; j--) { - ltDay = ltDays[ltDays.length - r + j]; - if (!ltDay) { - resolve(); - return; - } - ltDay.setAttribute("data-original-title", ltDay.getAttribute("data-original-title") + " (" + monit.logTimeToString(tempLogTimes[daysInWeek - 1 - j]) + " / " + Math.floor(tempLogTimes[daysInWeek - 1 - j] / monit.requirements.min * 100) + "%)"); - } - } - resolve(); - })); - }, - /** * Get the progress towards the Monitoring System's goals from the current webpage. * The logtime data is read from the SVG logtime chart, but in case that fails there's @@ -278,22 +165,9 @@ const monit = { } } } - this.username = this.getUserName(); - this.getLogTimes() - .then(this.writeProgress) - .catch(function(err) { - iConsole.warn("Could not read logtimes chart:", err); - monit.getLogTimesWeb(monit.username).then(monit.writeProgress) - .catch(function(err) { - iConsole.error("Could not retrieve logtimes from the web", err); - }); - }); - }, - - addTooltip: function() { - // add bootstrap tooltip to holder - const evt = new CustomEvent("add-tooltip", { detail: "#lt-holder" }); - document.dispatchEvent(evt); + this.getLogTimesWeb(getProfileUserName()).then(this.writeProgress).catch(function(err) { + iConsole.error("Could not retrieve logtimes for Codam Monitoring System progress", err); + }); }, /** @@ -363,7 +237,7 @@ const monit = { const coalitionSpan = document.createElement("span"); coalitionSpan.setAttribute("class", "coalition-span"); - coalitionSpan.style.color = monit.getCoalitionColor(); + coalitionSpan.style.color = getCoalitionColor(); coalitionSpan.innerText = "Monitoring System progress"; progressTitle.appendChild(coalitionSpan); @@ -384,7 +258,7 @@ const monit = { const progressPerc = document.createElement("span"); if (status["monitoring_system_active"]) { progressPerc.innerText = Math.floor(monit.logTimesTotal / 1440 * 100) + "% complete"; - ltHolder.setAttribute("data-original-title", "Logtime this week: " + monit.logTimeToString(monit.logTimesTotal)); + ltHolder.setAttribute("data-original-title", "Logtime this week: " + logTimeToString(monit.logTimesTotal)); } else if (status["work_from_home_required"] && !status["monitoring_system_active"]) { // covid-19 message @@ -392,7 +266,7 @@ const monit = { ltHolder.setAttribute("data-original-title", "You can do this! Codam will at some point reopen again. I'm sure of it! Times will get better."); } else if (!status["monitoring_system_active"]) { - progressPerc.innerText = monit.logTimeToString(monit.logTimesTotal); + progressPerc.innerText = logTimeToString(monit.logTimesTotal); ltHolder.setAttribute("data-original-title", "Logtime this week (Monitoring System is currently disabled)"); } @@ -466,26 +340,13 @@ const monit = { monit.bhContainer.appendChild(progressNode); monit.bhContainer.className = monit.bhContainer.className.replace("hidden", ""); - monit.addTooltip(); + addToolTip("#lt-holder"); }); }, - - init: function() { - this.dayOfWeek = new Date().getDay() - 1; - if (this.dayOfWeek < 0) { - this.dayOfWeek = 6; - } - } }; improvedStorage.get("codam-monit").then(function(data) { if (data["codam-monit"] === true || data["codam-monit"] === "true") { - if (!document.getElementById("monit-progress-old")) { - monit.init(); - monit.getProgress(); - } - else { - document.getElementById("codam_intra_monit_system_display_deprecation_notice").className = "upgraded"; - } + monit.getProgress(); } }); diff --git a/features/logtimes.js b/features/logtimes.js new file mode 100644 index 0000000..239c8d2 --- /dev/null +++ b/features/logtimes.js @@ -0,0 +1,83 @@ +/* ************************************************************************** */ +/* */ +/* :::::::: */ +/* logtimes.js :+: :+: */ +/* +:+ */ +/* By: fbes +#+ */ +/* +#+ */ +/* Created: 2022/04/05 22:04:27 by fbes #+# #+# */ +/* Updated: 2022/04/05 22:04:27 by fbes ######## odam.nl */ +/* */ +/* ************************************************************************** */ + +function codamMonitHelper(settings, logTime) { + if (settings["codam-monit"] === true || settings["codam-monit"] === "true") { + return (" / " + Math.floor(logTime / monit.requirements.min * 100) + "%"); + } + return (""); +} + +function waitForLogTimesChartToLoad(ltSvg) { + const ltDays = ltSvg.getElementsByTagName("g"); + if (ltDays.length < 1) { + // logtimes chart hasn't finished loading yet, try again in 100ms + setTimeout(function() { + waitForLogTimesChartToLoad(ltSvg); + }, 100); + return false; + } + + improvedStorage.get(["logsum-month", "logsum-week", "codam-monit"]).then(function(settings) { + let ltDay = ltDays[ltDays.length - 1]; + let daysInWeek = dayOfWeek + 1; + const remainingWeeks = Math.floor(ltDays.length / 7) + (dayOfWeek != 6 ? 1 : 0); + let r = 0; + const logTimes = []; + for (let i = 0; i < remainingWeeks; i++) { + let j; + + if (i == 1) { + daysInWeek = 7; + } + const tempLogTimes = []; + + // parse individual logtimes + for (j = 0; j < daysInWeek; j++) { + ltDay = ltDays[ltDays.length - r - 1]; + if (!ltDay) { + return true; + } + tempLogTimes.push(parseLogTime(ltDay.getAttribute("data-original-title"))); + if (tempLogTimes[j] == 0) { + ltDay.setAttribute("data-nolog", ""); + } + r++; + } + + // calculate cumulative logtime + for (j = daysInWeek - 2; j > -1; j--) { + tempLogTimes[j] = tempLogTimes[j] + tempLogTimes[j + 1]; + } + + // add cumulative logtime to tooltips (and percentage if Codam Monit System enabled) + for (j = daysInWeek - 1; j > -1; j--) { + ltDay = ltDays[ltDays.length - r + j]; + if (!ltDay) { + return true; + } + ltDay.setAttribute("data-original-title", ltDay.getAttribute("data-original-title") + " (week's cumulative: " + logTimeToString(tempLogTimes[daysInWeek - 1 - j]) + codamMonitHelper(settings, tempLogTimes[daysInWeek - 1 - j]) + ")"); + } + } + }); +} + +if (window.location.pathname == "/" || window.location.pathname.indexOf("/users/") == 0) { + const ltSvg = document.getElementById("user-locations"); + if (ltSvg) { // check if logtimes chart is on page + improvedStorage.get(["logsum-month", "logsum-week"]).then(function(data) { + if (data["logsum-month"] === true || data["logsum-month"] === "true" || data["logsum-week"] === true || data["logsum-week"] === "true") { + waitForLogTimesChartToLoad(ltSvg); + } + }); + } +} diff --git a/features/profiles.js b/features/profiles.js index ed090f6..35846b8 100644 --- a/features/profiles.js +++ b/features/profiles.js @@ -161,7 +161,7 @@ function immediateProfileChanges() { gCustomBanner.className = "improved-intra-banner"; gProfileBanner.insertBefore(gCustomBanner, gProfileBanner.children[0]); } - + // easter egg for user fbes, even when customized profiles are disabled if (gProfileBanner && gUName == "fbes") { gProfileBanner.className += " egg"; @@ -214,8 +214,7 @@ function immediateProfileChanges() { userInfos.appendChild(gitHubItem); } - const evt = new CustomEvent("add-tooltip", { detail: "#ii-profile-link-c-github" }); - document.dispatchEvent(evt); + addToolTip("#ii-profile-link-c-github"); } } } diff --git a/fixes/blackhole.js b/fixes/blackhole.js index e4a1acb..d248b16 100644 --- a/fixes/blackhole.js +++ b/fixes/blackhole.js @@ -39,8 +39,7 @@ function fixBlackHoleContainer() { bhDate.innerText = daysRemaining.toString() + " days left"; // add bootstrap tooltip to holder - const evt = new CustomEvent("add-tooltip", { detail: "#bh > .emote-bh" }); - document.dispatchEvent(evt); + addToolTip("#bh > .emote-bh"); const smiley = document.createElement("span"); smiley.setAttribute("id", "lt-emote"); diff --git a/generic/init.js b/generic/init.js index fc1b006..83d4f39 100644 --- a/generic/init.js +++ b/generic/init.js @@ -25,3 +25,5 @@ if (window.location.origin.indexOf(".intra.42.fr") > -1) { const improvedStorage = getSessionStorage(); const portName = (chrome.extension.inIncognitoContext ? "incog_comm" : "normal_comm"); const today = new Date(); +const dayOfWeek = (today.getDay() > 0 ? today.getDay() - 1 : 6); // fix monday = 0 & sunday = 6 +const dayOfMonth = today.getDate(); diff --git a/generic/useful.js b/generic/useful.js index f3d7311..1cfafcc 100644 --- a/generic/useful.js +++ b/generic/useful.js @@ -95,3 +95,23 @@ function setStyleIfExists(query, style, value, parentPlease) { } return (false); } + +// parse logtime from text (HHhMM or HH:MM) into minutes +function parseLogTime(logTimeText) { + const logTimeSplit = (logTimeText.indexOf("h") > -1 ? logTimeText.split("h") : logTimeText.split(":")); + if (logTimeSplit.length < 2) { + return (0); + } + return (parseInt(logTimeSplit[0]) * 60 + parseInt(logTimeSplit[1])); +} + +// convert an amount of minutes into logtime text (HHhMM) +function logTimeToString(logTime) { + return (Math.floor(logTime / 60) + "h" + (logTime % 60).toLocaleString(undefined, {minimumIntegerDigits: 2})); +} + +// add bootstrap tooltip to holder (send to inject.js) +function addToolTip(query) { + const evt = new CustomEvent("add-tooltip", { detail: query }); + document.dispatchEvent(evt); +} diff --git a/manifest-ff.json b/manifest-ff.json index 73ca269..8cc8942 100644 --- a/manifest-ff.json +++ b/manifest-ff.json @@ -83,11 +83,6 @@ "js": [ "options/options.js" ], "run_at": "document_end" }, - { - "matches": [ "*://profile.intra.42.fr/", "*://*.intra.42.fr/users/*" ], - "js": [ "features/profiles.js" ], - "run_at": "document_idle" - }, { "matches": [ "https://admin.intra.42.fr/*" ], "js": [ "features/admin.js" ], @@ -95,7 +90,7 @@ }, { "matches": [ "*://profile.intra.42.fr/", "*://*.intra.42.fr/users/*" ], - "js": [ "features/campus/codam/monit.js", "features/campus/codam/coa-titles.js" ], + "js": [ "features/profiles.js", "features/campus/codam/monit.js", "features/logtimes.js", "features/campus/codam/coa-titles.js" ], "css": [ "features/campus/codam/monit.css" ], "run_at": "document_idle" }, diff --git a/manifest.json b/manifest.json index fe13fe4..e506d67 100644 --- a/manifest.json +++ b/manifest.json @@ -78,11 +78,6 @@ "js": [ "options/options.js" ], "run_at": "document_end" }, - { - "matches": [ "*://profile.intra.42.fr/", "*://*.intra.42.fr/users/*" ], - "js": [ "features/profiles.js" ], - "run_at": "document_idle" - }, { "matches": [ "https://admin.intra.42.fr/*" ], "js": [ "features/admin.js" ], @@ -90,7 +85,7 @@ }, { "matches": [ "*://profile.intra.42.fr/", "*://*.intra.42.fr/users/*" ], - "js": [ "features/campus/codam/monit.js", "features/campus/codam/coa-titles.js" ], + "js": [ "features/profiles.js", "features/campus/codam/monit.js", "features/logtimes.js", "features/campus/codam/coa-titles.js" ], "css": [ "features/campus/codam/monit.css" ], "run_at": "document_idle" }, diff --git a/options/addoption.txt b/options/addoption.txt index 6292b7c..08244a7 100644 --- a/options/addoption.txt +++ b/options/addoption.txt @@ -1,8 +1,8 @@ A reminder for developers on how to add options, to not forget any steps -1. Add option to options/options.html and set default value +1. Add option to server/options.php and set default value 2. Add option to server/update.php as an expected value 3. Add default value to option in server/update.php -4. Add default value to background.js +4. Add default value to background/options.js 5. If a theme or color scheme, add CSS file to web_accessible_resources in both manifests 6. Make sure the extension does not throw an error anywhere if the setting is not set yet, although this should never happen since on update, all unset settings are set to default by background.js diff --git a/server/options.php b/server/options.php index 2a91303..cb12260 100644 --- a/server/options.php +++ b/server/options.php @@ -83,21 +83,32 @@

General improvements

+
+ + +
- - + + +
+
+ +
+
+
+

Black Hole

- - + +
diff --git a/server/update.php b/server/update.php index 3c17a5e..ecce550 100644 --- a/server/update.php +++ b/server/update.php @@ -36,8 +36,50 @@ function respond($type = "success", $msg, $data = null) { $latest_version = 1; $version_specifics = array(null); $version_defaults = array(null); - array_push($version_specifics, array("S*access_token", "S*username", "B*sync", "S*expires_in", "S*created_at", "S*refresh_token", "Stheme", "Scolors", "Bshow-custom-profiles", "Bhide-broadcasts", "Bhide-goals", "Bold-blackhole", "Bclustermap", "Scustom-banner-url", "Scustom-banner-pos", "Slink-github", "Bcodam-monit", "Bcodam-auto-equip-coa-title")); - array_push($version_defaults, array(null, null, true, null, null, null, "system", "default", true, false, false, false, true, "", "center-center", "", true, false)); + array_push($version_specifics, array( + "S*access_token", + "S*username", + "B*sync", + "S*expires_in", + "S*created_at", + "S*refresh_token", + "Stheme", + "Scolors", + "Bshow-custom-profiles", + "Bhide-broadcasts", + "Blogsum-month", + "Blogsum-week", + "Bhide-goals", + "Bold-blackhole", + "Bclustermap", + "Scustom-banner-url", + "Scustom-banner-pos", + "Slink-github", + "Bcodam-monit", + "Bcodam-auto-equip-coa-title" + )); + array_push($version_defaults, array( + null, + null, + true, + null, + null, + null, + "system", + "default", + true, + false, + true, + true, + false, + false, + true, + "", + "center-center", + "", + true, + false + )); $neverSave = array("access_token", "expires_in", "created_at", "refresh_token"); // check client settings version From bbddb1f4d0856194d92e15b9f28d692aa014e148 Mon Sep 17 00:00:00 2001 From: Freek Bes <36384333+FreekBes@users.noreply.github.com> Date: Tue, 5 Apr 2022 23:11:20 +0200 Subject: [PATCH 36/45] fix logtimes chart first month sometimes not displayed --- features/logtimes.js | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/features/logtimes.js b/features/logtimes.js index 239c8d2..7daa281 100644 --- a/features/logtimes.js +++ b/features/logtimes.js @@ -27,6 +27,19 @@ function waitForLogTimesChartToLoad(ltSvg) { return false; } + // fix first month sometimes outside container + let viewBox = ltSvg.getAttribute("viewBox"); + if (viewBox) { + viewBox = viewBox.split(" ").map(function(item) { + return parseInt(item); + }); + console.log(viewBox); + if (viewBox[0] > 0) { + viewBox[0] = 0; + ltSvg.setAttribute("viewBox", viewBox.join(" ")); + } + } + improvedStorage.get(["logsum-month", "logsum-week", "codam-monit"]).then(function(settings) { let ltDay = ltDays[ltDays.length - 1]; let daysInWeek = dayOfWeek + 1; From c699b0342a3e3cd5f7ee634c1bce3987993f1f15 Mon Sep 17 00:00:00 2001 From: Freek Bes <36384333+FreekBes@users.noreply.github.com> Date: Tue, 5 Apr 2022 23:39:41 +0200 Subject: [PATCH 37/45] add sum of monthly logtime --- features/logtimes.js | 130 +++++++++++++++++++++++++++++-------------- 1 file changed, 89 insertions(+), 41 deletions(-) diff --git a/features/logtimes.js b/features/logtimes.js index 7daa281..55320ef 100644 --- a/features/logtimes.js +++ b/features/logtimes.js @@ -17,9 +17,92 @@ function codamMonitHelper(settings, logTime) { return (""); } +// month logtime has to be calculated from the web since some days may be missing from the logtimes chart +function sumMonthLogTime(ltMonths) { + const httpReq = new XMLHttpRequest(); + httpReq.addEventListener("load", function() { + try { + const stats = JSON.parse(this.responseText); + const dates = Object.keys(stats); + const monthSums = []; + let mIndex = -1; + let lastMonth = -1; + for (const date of dates) { + const month = parseInt(date.split("-")[1]); + if (month != lastMonth) { + lastMonth = month; + mIndex++; + monthSums.push(0); + } + monthSums[mIndex] += parseLogTime(stats[date]); + } + ltMonths = Array.from(ltMonths).reverse(); + for (let i = 0; i < ltMonths.length; i++) { + const oldBbox = ltMonths[i].getBBox(); + const oldX = parseInt(ltMonths[i].getAttribute("x")); + ltMonths[i].textContent = ltMonths[i].textContent + " (" + logTimeToString(monthSums[i]) + ")"; + const newBbox = ltMonths[i].getBBox(); + // move element's x coordinate to the left to account for the width of the text added + ltMonths[i].setAttribute("x", Math.round(oldX - (newBbox.width - oldBbox.width) * 0.5)); + } + } + catch (err) { + iConsole.error(err); + } + }); + httpReq.addEventListener("error", function(err) { + iConsole.error(err); + }); + httpReq.open("GET", window.location.origin + "/users/" + getProfileUserName() + "/locations_stats.json"); + httpReq.send(); +} + +function cumWeekLogTime(ltDays, settings) { + let ltDay = ltDays[ltDays.length - 1]; + let daysInWeek = dayOfWeek + 1; + const remainingWeeks = Math.floor(ltDays.length / 7) + (dayOfWeek != 6 ? 1 : 0); + let r = 0; + for (let i = 0; i < remainingWeeks; i++) { + let j; + + if (i == 1) { + daysInWeek = 7; + } + const tempLogTimes = []; + + // parse individual logtimes + for (j = 0; j < daysInWeek; j++) { + ltDay = ltDays[ltDays.length - r - 1]; + if (!ltDay) { + return; + } + tempLogTimes.push(parseLogTime(ltDay.getAttribute("data-original-title"))); + if (tempLogTimes[j] == 0) { + ltDay.setAttribute("data-nolog", ""); + } + r++; + } + + // calculate cumulative logtime + for (j = daysInWeek - 2; j > -1; j--) { + tempLogTimes[j] = tempLogTimes[j] + tempLogTimes[j + 1]; + } + + // add cumulative logtime to tooltips (and percentage if Codam Monit System enabled) + for (j = daysInWeek - 1; j > -1; j--) { + ltDay = ltDays[ltDays.length - r + j]; + if (!ltDay) { + return; + } + ltDay.setAttribute("data-original-title", ltDay.getAttribute("data-original-title") + " (week's cumulative: " + logTimeToString(tempLogTimes[daysInWeek - 1 - j]) + codamMonitHelper(settings, tempLogTimes[daysInWeek - 1 - j]) + ")"); + } + } +} + function waitForLogTimesChartToLoad(ltSvg) { const ltDays = ltSvg.getElementsByTagName("g"); - if (ltDays.length < 1) { + const ltMonths = ltSvg.querySelectorAll("svg > text"); + if (ltDays.length == 0 || ltMonths.length == 0) { // logtimes chart hasn't finished loading yet, try again in 100ms setTimeout(function() { waitForLogTimesChartToLoad(ltSvg); @@ -33,7 +116,6 @@ function waitForLogTimesChartToLoad(ltSvg) { viewBox = viewBox.split(" ").map(function(item) { return parseInt(item); }); - console.log(viewBox); if (viewBox[0] > 0) { viewBox[0] = 0; ltSvg.setAttribute("viewBox", viewBox.join(" ")); @@ -41,45 +123,11 @@ function waitForLogTimesChartToLoad(ltSvg) { } improvedStorage.get(["logsum-month", "logsum-week", "codam-monit"]).then(function(settings) { - let ltDay = ltDays[ltDays.length - 1]; - let daysInWeek = dayOfWeek + 1; - const remainingWeeks = Math.floor(ltDays.length / 7) + (dayOfWeek != 6 ? 1 : 0); - let r = 0; - const logTimes = []; - for (let i = 0; i < remainingWeeks; i++) { - let j; - - if (i == 1) { - daysInWeek = 7; - } - const tempLogTimes = []; - - // parse individual logtimes - for (j = 0; j < daysInWeek; j++) { - ltDay = ltDays[ltDays.length - r - 1]; - if (!ltDay) { - return true; - } - tempLogTimes.push(parseLogTime(ltDay.getAttribute("data-original-title"))); - if (tempLogTimes[j] == 0) { - ltDay.setAttribute("data-nolog", ""); - } - r++; - } - - // calculate cumulative logtime - for (j = daysInWeek - 2; j > -1; j--) { - tempLogTimes[j] = tempLogTimes[j] + tempLogTimes[j + 1]; - } - - // add cumulative logtime to tooltips (and percentage if Codam Monit System enabled) - for (j = daysInWeek - 1; j > -1; j--) { - ltDay = ltDays[ltDays.length - r + j]; - if (!ltDay) { - return true; - } - ltDay.setAttribute("data-original-title", ltDay.getAttribute("data-original-title") + " (week's cumulative: " + logTimeToString(tempLogTimes[daysInWeek - 1 - j]) + codamMonitHelper(settings, tempLogTimes[daysInWeek - 1 - j]) + ")"); - } + if (settings["logsum-month"]) { + sumMonthLogTime(ltMonths); + } + if (settings["logsum-week"]) { + cumWeekLogTime(ltDays, settings); } }); } From 280fcca388819fd4bd3243ead73742b52f638c84 Mon Sep 17 00:00:00 2001 From: Freek Bes <36384333+FreekBes@users.noreply.github.com> Date: Tue, 5 Apr 2022 23:47:46 +0200 Subject: [PATCH 38/45] pre-release 2 of v3 --- manifest-ff.json | 2 +- manifest.json | 4 ++-- todo.txt | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/manifest-ff.json b/manifest-ff.json index 8cc8942..818573c 100644 --- a/manifest-ff.json +++ b/manifest-ff.json @@ -2,7 +2,7 @@ "manifest_version": 2, "name": "__MSG_appName__", "short_name": "__MSG_shortAppName__", - "version": "3.0.0.1", + "version": "3.0.0.2", "description": "__MSG_appDesc__", "default_locale": "en", "icons": { diff --git a/manifest.json b/manifest.json index e506d67..8f41ee4 100644 --- a/manifest.json +++ b/manifest.json @@ -3,8 +3,8 @@ "minimum_chrome_version": "49", "name": "__MSG_appName__", "short_name": "__MSG_shortAppName__", - "version": "3.0.0.1", - "version_name": "3.0.0 (pre-release 1)", + "version": "3.0.0.2", + "version_name": "3.0.0 (pre-release 2)", "description": "__MSG_appDesc__", "default_locale": "en", "icons": { diff --git a/todo.txt b/todo.txt index 54604fe..0ac407e 100644 --- a/todo.txt +++ b/todo.txt @@ -5,11 +5,11 @@ TODO: - create way to report user customization features to the server - create way to see user reports when logged in with an Intra staff account - reorganize manifests -- split up Codam Monitoring System's cumulative hours and the actual thing into ft_logtime like feature and the previous actual thing - more security background checks for the server back-end with the Intra API: store generated keys in a non-public database file - implement more cluster maps, maybe even custom ones into the extension itself? DONE: +- split up Codam Monitoring System's cumulative hours and the actual thing into ft_logtime like feature and the previous actual thing - convert every var to either const or let - separate some improvements - create backbone structure for local storage and syncing settings, with separate storage for incognito From ebb3e40e192ef750426321aaa71ab8e1fdb5570f Mon Sep 17 00:00:00 2001 From: Freek Bes <36384333+FreekBes@users.noreply.github.com> Date: Sun, 10 Apr 2022 18:55:07 +0200 Subject: [PATCH 39/45] add README to each server dir --- .gitignore | 11 +++++++++-- server/banners/README.txt | 3 +++ server/db/README.txt | 1 + server/settings/README.txt | 2 ++ 4 files changed, 15 insertions(+), 2 deletions(-) create mode 100644 server/banners/README.txt create mode 100644 server/db/README.txt create mode 100644 server/settings/README.txt diff --git a/.gitignore b/.gitignore index 601cff7..b22a1e3 100644 --- a/.gitignore +++ b/.gitignore @@ -4,6 +4,13 @@ *.crx server/nogit.php server/test.php -server/settings/* -server/banners/* +server/db/*.json +server/settings/*.json +server/banners/*.jpeg +server/banners/*.png +server/banners/*.webp +server/banners/*.jpg +server/banners/*.bmp +server/banners/*.gif +server/banners/*.mp4 temp.js diff --git a/server/banners/README.txt b/server/banners/README.txt new file mode 100644 index 0000000..aae5efd --- /dev/null +++ b/server/banners/README.txt @@ -0,0 +1,3 @@ +This folder contains all the custom banners uploaded by users for their profile. +Each user should only have one banner at a time in here, to save on storage space. +This should happen automatically. diff --git a/server/db/README.txt b/server/db/README.txt new file mode 100644 index 0000000..3117958 --- /dev/null +++ b/server/db/README.txt @@ -0,0 +1 @@ +This folder contains files necessary for the back-end of the extension to be secure. diff --git a/server/settings/README.txt b/server/settings/README.txt new file mode 100644 index 0000000..8c78d8e --- /dev/null +++ b/server/settings/README.txt @@ -0,0 +1,2 @@ +This folder contains the settings of all users who chose to synchronize their settings. +Each user has their own .json file, named by their username. From 3d5f7aee3b7fb10e07dd4458f6cb7065a7794a4b Mon Sep 17 00:00:00 2001 From: Freek Bes <36384333+FreekBes@users.noreply.github.com> Date: Sun, 10 Apr 2022 19:18:20 +0200 Subject: [PATCH 40/45] fix limited width of body on server pages --- generic/internal.css | 17 +++++++++-------- server/imagery.php | 2 +- server/options.php | 2 +- 3 files changed, 11 insertions(+), 10 deletions(-) diff --git a/generic/internal.css b/generic/internal.css index 4495741..09c9cb1 100644 --- a/generic/internal.css +++ b/generic/internal.css @@ -31,7 +31,6 @@ html, body { display: block; - width: 100%; } html { @@ -48,19 +47,21 @@ body, font-family: 'Roboto', "Helvetica", Verdana, Arial, sans-serif; font-weight: 400; font-size: 15px; - padding: 0px; + padding: 16px; cursor: default; - width: 100%; - height: 100%; - min-height: 100%; min-width: 360px; - max-width: 540px; margin: 0 auto; user-select: none; } -body.fullwidth { - max-width: 100%; +body.limitwidth { + width: 100% !important; + max-width: 540px !important; + padding: 0px !important; +} + +body.limitwidth #contents { + padding: 0px !important; } body { diff --git a/server/imagery.php b/server/imagery.php index 5c56831..4b95647 100644 --- a/server/imagery.php +++ b/server/imagery.php @@ -38,7 +38,7 @@ } - + - +

You need to install the Improved Intra 42 extension in order to modify its settings.

You can install it from the Chrome Web Store or, if you are using Mozilla Firefox, directly by clicking here.

From 1efd714956f29d4f00e053255bc827cf4e15e65d Mon Sep 17 00:00:00 2001 From: Freek Bes <36384333+FreekBes@users.noreply.github.com> Date: Sun, 10 Apr 2022 20:02:50 +0200 Subject: [PATCH 41/45] fixed security issue access tokens generated by other Intra applications could before be used to modify user settings in Improved Intra. Fixed this by storing a hash of any access token generated by the server, on the server, and comparing any access token used against those stored ones, denying access if the access token was not generated by the server. --- options/options.js | 3 ++- server/auth.php | 38 ++++++++++++++++++++++++++++++++++++++ server/testkey.php | 7 +++++++ server/update.php | 9 ++++++++- 4 files changed, 55 insertions(+), 2 deletions(-) diff --git a/options/options.js b/options/options.js index 03efd12..034bbb6 100644 --- a/options/options.js +++ b/options/options.js @@ -21,7 +21,8 @@ function hideLoading() { function checkIfKeyStillWorks(access_token) { return new Promise(function(it_works, it_does_not_work) { const req = new XMLHttpRequest(); - req.open("POST", "https://darkintra.freekb.es/testkey.php?nc="+encodeURIComponent(Math.random())); + const manifestData = chrome.runtime.getManifest(); + req.open("POST", "https://darkintra.freekb.es/testkey.php?v="+manifestData.version+"&nc="+encodeURIComponent(Math.random())); req.setRequestHeader('Content-type', 'application/x-www-form-urlencoded'); req.addEventListener("load", function(event) { try { diff --git a/server/auth.php b/server/auth.php index 1478c64..b620bee 100644 --- a/server/auth.php +++ b/server/auth.php @@ -69,6 +69,41 @@ function refresh_access_token_if_needed($refreshToken, $createdAt, $expiresIn) { } } + // check if access token was generated by this server + function access_token_accepted($accessToken) { + if (!file_exists("db/tokens.json")) { + return (false); + } + $tokensDB = json_decode(file_get_contents("db/tokens.json")); + // print_r($tokensDB); + // echo "Searching for ".$hashedToken; + $tokenCount = count($tokensDB); + for ($i = 0; $i < $tokenCount; $i++) { + if (password_verify($accessToken, $tokensDB[$i])) { + return (true); + } + } + return (false); + } + + // save generated access tokens on server + function save_access_token($auth) { + $hashedToken = password_hash($auth["access_token"], PASSWORD_DEFAULT); + if ($hashedToken === false) { + return (false); + } + $tokensDB = array(); + if (file_exists("db/tokens.json")) { + $tokensDB = json_decode(file_get_contents("db/tokens.json")); + } + array_push($tokensDB, $hashedToken); + if (file_put_contents("db/tokens.json", json_encode($tokensDB, JSON_UNESCAPED_UNICODE)) !== false) { + return (true); + } + return (false); + } + + // exchange authorization code for access token function exchange($code, $codeType = "authorization_code") { global $clientID, $clientSecret, $redirectURL; @@ -92,6 +127,9 @@ function exchange($code, $codeType = "authorization_code") { $jsonRes = json_decode($response, true); $ret["auth"] = $jsonRes; if (!isset($jsonRes["error"])) { + if (!save_access_token($ret["auth"])) { + return (null); + } $ret["user"] = get_user_info($ret["auth"]["access_token"]); } return ($ret); diff --git a/server/testkey.php b/server/testkey.php index c7dff94..b029055 100644 --- a/server/testkey.php +++ b/server/testkey.php @@ -28,6 +28,13 @@ function respond($type = "success", $msg, $data = null) { die(); } + // check if access token was generated by this server + if (!access_token_accepted($_POST["access_token"])) { + http_response_code(410); + respond("error", "Access token was not generated by this server", null); + die(); + } + $userInfoFromIntra = get_user_info($_POST["access_token"]); if (empty($userInfoFromIntra) || isset($userInfoFromIntra["error"])) { http_response_code(410); diff --git a/server/update.php b/server/update.php index ecce550..1a499ae 100644 --- a/server/update.php +++ b/server/update.php @@ -144,7 +144,14 @@ function respond($type = "success", $msg, $data = null) { } if (preg_match('/[^a-z\-]/', $userSettings["username"])) { http_response_code(406); - respond("warning", "Are you proud of yourself?"); + respond("warning", "Invalid characters in username"); + die(); + } + + // check if access token was generated by this server... + if (!access_token_accepted($userSettings["access_token"])) { + http_response_code(406); + respond("warning", "Used access token was not generated by this server, refused to proceed"); die(); } From 88b23fc8daee84532f53383f10eb81f5269f69fd Mon Sep 17 00:00:00 2001 From: Freek Bes <36384333+FreekBes@users.noreply.github.com> Date: Sun, 10 Apr 2022 20:03:05 +0200 Subject: [PATCH 42/45] add README for server --- server/README.md | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 server/README.md diff --git a/server/README.md b/server/README.md new file mode 100644 index 0000000..9942d0a --- /dev/null +++ b/server/README.md @@ -0,0 +1,27 @@ +# Back-end for Improved Intra +This repository contains the back-end for use with the [Improved Intra](https://github.com/FreekBes/improved_intra) browser extension. + + +## Setup +### Keep in mind... +The extension only talks directly with the [https://darkintra.freekb.es](https://darkintra.freekb.es/) domain. This means you cannot set this server up without forking the extension's source code and changing all references to this domain to whatever domain you choose to run this back-end code on. Or, you can redirect calls to this domain to your domain - that might also work. + + +### Actual setup +Set up a web server to use PHP. This script was written with PHP 7.3 in mind, so I suggest you also install this version or later. Also, make sure to allow all origins from requests (CORS) (e.g. by adding an Apache rule: `Header set Access-Control-Allow-Origin "*"`) + +Fill in the required details in the file *nogit.php.example* and rename it to *nogit.php*. + +Next, make sure to not allow access to any file in the *db* folder, as this folder is intended for internal use by the back-end code only. It contains trival information of the users connecting to your server, such as access tokens and more. Therefore, again, make sure this entire folder is *completely inaccessible* to the outside world. + +With Apache, you can do so by adding the following rule to the configuration of the virtual host (or by using a *.htaccess* file): +```conf + + Order allow,deny + Deny from all + +``` + +Then, move the contents of this repository to the web-accessible folder of your web server (usually */var/www/html*). Make sure that the folders *banners*, *db* and *settings* are owned by the *www-data* user, so that PHP can actually write to those folders. + +That should be all! The extension should now be able to talk with your server and synchronize settings there, etc. From ad15d16f8651c96ac19f5ced32bdcec8f580e8c2 Mon Sep 17 00:00:00 2001 From: Freek Bes <36384333+FreekBes@users.noreply.github.com> Date: Sun, 10 Apr 2022 20:05:49 +0200 Subject: [PATCH 43/45] deleted todo-list --- todo.txt | 19 ------------------- 1 file changed, 19 deletions(-) delete mode 100644 todo.txt diff --git a/todo.txt b/todo.txt deleted file mode 100644 index 0ac407e..0000000 --- a/todo.txt +++ /dev/null @@ -1,19 +0,0 @@ -USEFUL: -Manifest v3 options overview: https://developer.chrome.com/docs/extensions/mv3/manifest/ - -TODO: -- create way to report user customization features to the server -- create way to see user reports when logged in with an Intra staff account -- reorganize manifests -- more security background checks for the server back-end with the Intra API: store generated keys in a non-public database file -- implement more cluster maps, maybe even custom ones into the extension itself? - -DONE: -- split up Codam Monitoring System's cumulative hours and the actual thing into ft_logtime like feature and the previous actual thing -- convert every var to either const or let -- separate some improvements -- create backbone structure for local storage and syncing settings, with separate storage for incognito -- create internal console.log function to deal with styling in the console ("[Improved Intra] msg") -- create themes folder and move all theme-related stuff in there -- create improvements folder and move all improvements into there -- fix auto coalition title equipper not working in Firefox From ad85ba333ce36eb4ad81b1dacc717583be1f2f24 Mon Sep 17 00:00:00 2001 From: Freek Bes <36384333+FreekBes@users.noreply.github.com> Date: Sun, 10 Apr 2022 20:07:26 +0200 Subject: [PATCH 44/45] version bump --- manifest-ff.json | 2 +- manifest.json | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/manifest-ff.json b/manifest-ff.json index 818573c..4e84426 100644 --- a/manifest-ff.json +++ b/manifest-ff.json @@ -2,7 +2,7 @@ "manifest_version": 2, "name": "__MSG_appName__", "short_name": "__MSG_shortAppName__", - "version": "3.0.0.2", + "version": "3.0.0", "description": "__MSG_appDesc__", "default_locale": "en", "icons": { diff --git a/manifest.json b/manifest.json index 8f41ee4..20ff2f0 100644 --- a/manifest.json +++ b/manifest.json @@ -3,8 +3,8 @@ "minimum_chrome_version": "49", "name": "__MSG_appName__", "short_name": "__MSG_shortAppName__", - "version": "3.0.0.2", - "version_name": "3.0.0 (pre-release 2)", + "version": "3.0.0", + "version_name": "3.0.0", "description": "__MSG_appDesc__", "default_locale": "en", "icons": { From 1cd0223f753b3a1d1e2d4ddd77a7bb398452625d Mon Sep 17 00:00:00 2001 From: Freek Bes <36384333+FreekBes@users.noreply.github.com> Date: Sun, 10 Apr 2022 20:18:34 +0200 Subject: [PATCH 45/45] remove custom titles from coalition scores page --- fixes/improv.css | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/fixes/improv.css b/fixes/improv.css index 6c211ec..0c9e60a 100644 --- a/fixes/improv.css +++ b/fixes/improv.css @@ -376,7 +376,8 @@ a[data-tooltip-login="fbes"]::before, /* no custom titles in the following places */ a[data-tooltip-login].student-kind-student::before, -#coalition-top-user a[data-tooltip-login]::before { +#coalition-top-user a[data-tooltip-login]::before, +#coalition-scores a[data-tooltip-login]::before { content: '' !important; }