`).firstChild;
let imagecont = document.createElement("div");
imagecont.classList.add("whatsnewImgContainer");
var image = document.createElement("img");
image.src = chrome.runtime.getURL("icons/betterseqta-dark-icon.png");
image.classList.add("whatsnewImg");
imagecont.append(image);
let textcontainer = document.createElement("div");
textcontainer.classList.add("whatsnewTextContainer");
let textheader = stringToHTML(
"
DESIGN OVERHAUL
",
).firstChild;
textcontainer.append(textheader);
let text = stringToHTML(
String.raw`
3.1.1 - Minor Bug fixes
Fixed assessments overlapping
Fixed houses not displaying if they aren't a specific color
Fixed Chrome Webstore Link
3.1.0 - Design Improvements
Minor UI improvements
Added Animation Speed Slider
Animation now enables and disables without reloading SEQTA
Changed logo
3.0.0 - BetterSEQTA+ *Complete Overhaul*
Redesigned appearance
Upgraded to manifest V3 (longer support)
Fixed transitional glitches
Under the hood improvements
Fixed News Feed
2.0.7 - Added support to other domains + Minor bug fixes
Fixed BetterSEQTA+ not loading on some pages
Fixed text colour of notices being unreadable
Fixed pages not reloading when saving changes
2.0.2 - Minor bug fixes
Fixed indicator for current lesson
Fixed text colour for DM messages list in Light mode
Fixed user info text colour
Sleek New Layout
Updated with a new font and presentation, BetterSEQTA+ has never looked better.
New Updated Sidebar
Condensed appearance with new updated icons.
Independent Light Mode and Dark Mode
Dark mode and Light mode are now available to pick alongside your chosen Theme Colour. Your Theme Colour will now become an accent colour for the page.
Light/Dark mode can be toggled with the new button, found in the top-right of the menu bar.
Create Custom Shortcuts
Found in the BetterSEQTA+ Settings menu, custom shortcuts can now be created with a name and URL of your choice.
`,
).firstChild;
let footer = stringToHTML(
String.raw`
Report bugs and feedback:
`).firstChild;
let exitbutton = document.createElement("div");
exitbutton.innerText = "x";
exitbutton.id = "whatsnewclosebutton";
container.append(header);
container.append(imagecont);
container.append(textcontainer);
container.append(text);
container.append(footer);
container.append(exitbutton);
document.getElementById("container").append(background);
document.getElementById("container").append(container);
chrome.storage.local.remove(["justupdated"]);
var bkelement = document.getElementById("whatsnewbk");
bkelement.addEventListener("click", function () {
DeleteWhatsNew();
//WhatsNewOpen = false;
});
var closeelement = document.getElementById("whatsnewclosebutton");
closeelement.addEventListener("click", function () {
DeleteWhatsNew();
//WhatsNewOpen = false;
});
}
async function finishLoad() {
try {
var loadingbk = document.getElementById("loading");
loadingbk.style.opacity = "0";
await delay(501);
loadingbk.remove();
} catch (err) {
console.log(err);
}
chrome.storage.local.get(["justupdated"], function (result) {
if (result.justupdated) {
//WhatsNewOpen = true;
OpenWhatsNewPopup();
}
});
}
async function DeleteWhatsNew() {
var bkelement = document.getElementById("whatsnewbk");
var popup = document.getElementsByClassName("whatsnewContainer")[0];
bkelement.classList.add("whatsnewfadeout");
popup.classList.add("whatsnewzoomout");
await delay(500);
bkelement.remove();
popup.remove();
}
function CreateBackground() {
// Creating and inserting 3 divs containing the background applied to the pages
var bklocation = document.getElementById("container");
var menu = document.getElementById("menu");
var bk = document.createElement("div");
bk.classList.add("bg");
bklocation.insertBefore(bk, menu);
var bk2 = document.createElement("div");
bk2.classList.add("bg");
bk2.classList.add("bg2");
bklocation.insertBefore(bk2, menu);
var bk3 = document.createElement("div");
bk3.classList.add("bg");
bk3.classList.add("bg3");
bklocation.insertBefore(bk3, menu);
}
function RemoveBackground() {
var bk = document.getElementsByClassName("bg");
var bk2 = document.getElementsByClassName("bg2");
var bk3 = document.getElementsByClassName("bg3");
if (bk.length == 0 || bk2.length == 0 || bk3.length == 0) return;
bk[0].remove();
bk2[0].remove();
bk3[0].remove();
}
export function waitForElm(selector) {
return new Promise((resolve) => {
if (document.querySelector(selector)) {
return resolve(document.querySelector(selector));
}
const observer = new MutationObserver(() => {
if (document.querySelector(selector)) {
resolve(document.querySelector(selector));
observer.disconnect();
}
});
observer.observe(document.body, {
childList: true,
subtree: true,
});
});
}
async function RunColourCheck(element) {
if (
typeof element.contentDocument.documentElement.childNodes[1] == "undefined"
) {
await delay(1000);
RunColourCheck(element);
} else {
element.contentDocument.documentElement.childNodes[1].style.color = "white";
}
}
function GetiFrameCSSElement() {
var cssFile = chrome.runtime.getURL("inject/iframe.css");
var fileref = document.createElement("link");
fileref.setAttribute("rel", "stylesheet");
fileref.setAttribute("type", "text/css");
fileref.setAttribute("href", cssFile);
return fileref;
}
function CheckiFrameItems() {
// Injecting CSS File to the webpage to overwrite iFrame default CSS
let fileref = GetiFrameCSSElement();
const observer = new MutationObserver(function (mutations_list) {
mutations_list.forEach(function (mutation) {
mutation.addedNodes.forEach(function (added_node) {
if (added_node.tagName == "IFRAME") {
chrome.storage.local.get(["DarkMode"], function (result) {
DarkMode = result.DarkMode;
if (DarkMode) {
RunColourCheck(added_node);
if (
added_node.contentDocument.documentElement.childNodes[1].style
.color != "white"
) {
added_node.contentDocument.documentElement.childNodes[1].style.color =
"white";
}
if (
!added_node.contentDocument.documentElement.firstChild.innerHTML.includes(
"iframe.css",
)
) {
added_node.contentDocument.documentElement.firstChild.appendChild(
fileref,
);
}
added_node.addEventListener("load", function () {
if (
added_node.contentDocument.documentElement.childNodes[1].style
.color != "white"
) {
added_node.contentDocument.documentElement.childNodes[1].style.color =
"white";
}
if (
!added_node.contentDocument.documentElement.firstChild.innerHTML.includes(
"iframe.css",
)
) {
added_node.contentDocument.documentElement.firstChild.appendChild(
fileref,
);
}
});
}
});
}
});
});
});
observer.observe(document.body, {
subtree: true,
childList: true,
});
}
function SortMessagePageItems(messagesParentElement) {
let filterbutton = document.createElement("div");
filterbutton.classList.add("messages-filterbutton");
filterbutton.innerText = "Filter";
let header = document.getElementsByClassName(
"MessageList__MessageList___3DxoC",
)[0].firstChild;
header.append(filterbutton);
const observer = new MutationObserver(function (mutations_list) {
mutations_list.forEach(function (mutation) {
mutation.addedNodes.forEach(function (added_node) {
if (added_node.dataset.message) {
// Check if added_node.firstChild.title is in block list
}
});
});
});
observer.observe(messagesParentElement, {
subtree: true,
childList: true,
});
}
function LoadPageElements() {
AddBetterSEQTAElements(true);
var sublink = window.location.href.split("/")[4];
switch (sublink) {
case "news":
console.log("[BetterSEQTA+] Started Init");
chrome.storage.local.get(null, function (result) {
if (result.onoff) {
SendNewsPage();
// Sends similar HTTP Post Request for the notices
chrome.storage.local.get(null, function (result) {
if (result.notificationcollector) {
var xhr3 = new XMLHttpRequest();
xhr3.open(
"POST",
`${location.origin}/seqta/student/heartbeat?`,
true,
);
xhr3.setRequestHeader(
"Content-Type",
"application/json; charset=utf-8",
);
xhr3.onreadystatechange = function () {
if (xhr3.readyState === 4) {
var Notifications = JSON.parse(xhr3.response);
var alertdiv = document.getElementsByClassName(
"notifications__bubble___1EkSQ",
)[0];
if (typeof alertdiv == "undefined") {
console.log(
"[BetterSEQTA+] No notifications currently",
);
} else {
alertdiv.textContent =
Notifications.payload.notifications.length;
}
}
};
xhr3.send(
JSON.stringify({
timestamp: "1970-01-01 00:00:00.0",
hash: "#?page=/home",
}),
);
}
});
finishLoad();
}
});
break;
case "home":
window.location.replace(`${location.origin}/#?page=/home`);
LoadInit();
break;
case undefined:
window.location.replace(`${location.origin}/#?page=/home`);
LoadInit();
break;
default:
finishLoad();
// Sends similar HTTP Post Request for the notices
chrome.storage.local.get(null, function (result) {
if (result.notificationcollector) {
var xhr3 = new XMLHttpRequest();
xhr3.open(
"POST",
`${location.origin}/seqta/student/heartbeat?`,
true,
);
xhr3.setRequestHeader(
"Content-Type",
"application/json; charset=utf-8",
);
xhr3.onreadystatechange = function () {
if (xhr3.readyState === 4) {
var Notifications = JSON.parse(xhr3.response);
var alertdiv = document.getElementsByClassName(
"notifications__bubble___1EkSQ",
)[0];
if (typeof alertdiv == "undefined") {
console.log("[BetterSEQTA+] No notifications currently");
} else {
alertdiv.textContent =
Notifications.payload.notifications.length;
}
}
};
xhr3.send(
JSON.stringify({
timestamp: "1970-01-01 00:00:00.0",
hash: "#?page=/home",
}),
);
}
});
break;
}
const observer = new MutationObserver(function (mutations_list) {
mutations_list.forEach(function (mutation) {
mutation.addedNodes.forEach(function (added_node) {
if (added_node.classList.contains("messages")) {
let element = document.getElementById("title").firstChild;
element.innerText = "Direct Messages";
document.title = "Direct Messages ― SEQTA Learn";
SortMessagePageItems(added_node);
} else if (added_node.classList.contains("notices")) {
CheckNoticeTextColour(added_node);
}
});
});
});
observer.observe(document.querySelector("#main"), {
subtree: false,
childList: true,
});
}
function CheckNoticeTextColour(notice) {
const observer = new MutationObserver(function (mutations_list) {
mutations_list.forEach(function (mutation) {
mutation.addedNodes.forEach(function (added_node) {
chrome.storage.local.get(["DarkMode"], function (result) {
DarkMode = result.DarkMode;
if (added_node.classList.contains("notice")) {
var hex = added_node.style.cssText.split(" ")[1];
var threshold = GetThresholdofHex(hex);
if (DarkMode && threshold < 100) {
added_node.style.cssText = "--color: undefined;";
}
}
});
});
});
});
observer.observe(notice, {
subtree: true,
childList: true,
});
}
export function tryLoad() {
waitForElm(".login").then(() => {
finishLoad();
});
waitForElm(".day-container").then(() => {
finishLoad();
});
waitForElm("[data-key=welcome]").then((elm) => {
elm.classList.remove("active");
});
waitForElm(".code").then((elm) => {
if (!elm.innerText.includes("BetterSEQTA")) LoadPageElements();
});
// Waits for page to call on load, run scripts
document.addEventListener(
"load",
function () {
CheckiFrameItems();
},
true,
);
}
function ChangeMenuItemPositions(storage) {
let menuorder = storage;
var menuList = document.querySelector("#menu").firstChild.childNodes;
let listorder = [];
for (let i = 0; i < menuList.length; i++) {
let a = menuorder.indexOf(menuList[i].dataset.key);
listorder.push(a);
}
var newArr = [];
for (var i = 0; i < listorder.length; i++) {
newArr[listorder[i]] = menuList[i];
}
let listItemsDOM = document.getElementById("menu").firstChild;
for (let i = 0; i < newArr.length; i++) {
const element = newArr[i];
if (element) {
element.setAttribute("data-checked", "true");
listItemsDOM.appendChild(element);
}
}
}
export async function ObserveMenuItemPosition() {
chrome.storage.local.get(null, function (result) {
let menuorder = result.menuorder;
if (menuorder && result.onoff) {
const observer = new MutationObserver(function (mutations_list) {
mutations_list.forEach(function (mutation) {
mutation.addedNodes.forEach(function (added_node) {
if (!added_node?.dataset?.checked && !MenuOptionsOpen) {
if (MenuitemSVGKey[added_node?.dataset?.key]) {
ReplaceMenuSVG(
added_node,
MenuitemSVGKey[added_node.dataset.key],
);
}
ChangeMenuItemPositions(menuorder);
}
});
});
});
observer.observe(document.querySelector("#menu").firstChild, {
subtree: true,
childList: true,
});
}
});
}
function main(storedSetting) {
DarkMode = storedSetting.DarkMode;
// If the option is 'on', open BetterSEQTA
if (typeof storedSetting.onoff == "undefined") {
chrome.runtime.sendMessage({ type: "setDefaultStorage" });
}
if (storedSetting.onoff) {
console.log("[BetterSEQTA+] Enabled");
// Injecting CSS File to the webpage to overwrite SEQTA's default CSS
var cssFile = chrome.runtime.getURL("inject/injected.css");
var fileref = document.createElement("link");
fileref.setAttribute("rel", "stylesheet");
fileref.setAttribute("type", "text/css");
fileref.setAttribute("href", cssFile);
document.head.appendChild(fileref);
document.getElementsByTagName("html")[0].appendChild(fileref);
// Injecting custom icons font file
const fontURL = chrome.runtime.getURL("fonts/IconFamily.woff");
const style = document.createElement("style");
style.setAttribute("type", "text/css");
style.innerHTML = `
@font-face {
font-family: 'IconFamily';
src: url('${fontURL}') format('woff');
font-weight: normal;
font-style: normal;
}`;
document.head.appendChild(style);
updateAllColors(storedSetting);
ApplyCSSToHiddenMenuItems();
loading();
CheckLoadOnPeriods();
if (!isChrome || isChrome == "undefined") {
tryLoad();
}
window.addEventListener("load", function () {
tryLoad();
});
} else {
if (!isChrome || isChrome == "undefined") {
waitForElm(".code").then(() => {
AppendElementsToDisabledPage();
});
}
window.addEventListener("load", function () {
waitForElm(".code").then(() => {
AppendElementsToDisabledPage();
});
});
}
}
export function AppendElementsToDisabledPage() {
AddBetterSEQTAElements(false);
let settingsStyle = document.createElement("style");
settingsStyle.innerText = `
.addedButton {
position: absolute !important;
right: 50px;
width: 35px;
height: 35px;
padding: 6px !important;
overflow: unset !important;
border-radius: 50%;
margin: 7px !important;
cursor: pointer;
color: white !important;
}
.addedButton svg {
margin: 6px;
}
.outside-container {
top: 48px !important;
}
`;
document.head.append(settingsStyle);
}
export function lightenAndPaleColor(inputColor, lightenFactor = 0.75, paleFactor = 0.55) {
// Step 1: Convert RGBA to separate R, G and B values
const [r, g, b] = inputColor.match(/\d+/g).map(Number);
// Step 2: Convert RGB to HSL
let r1 = r / 255, g1 = g / 255, b1 = b / 255;
const max = Math.max(r1, g1, b1), min = Math.min(r1, g1, b1);
let h, s, l = (max + min) / 2;
if (max === min) {
h = s = 0;
} else {
const d = max - min;
s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
switch (max) {
case r1: h = (g1 - b1) / d + (g1 < b1 ? 6 : 0); break;
case g1: h = (b1 - r1) / d + 2; break;
case b1: h = (r1 - g1) / d + 4; break;
}
h /= 6;
}
// Step 3: Adjust saturation and lightness
s -= s * paleFactor;
l += (1 - l) * lightenFactor;
// Step 4: Convert HSL back to RGB
const hue2rgb = (p, q, t) => {
if(t < 0) t += 1;
if(t > 1) t -= 1;
if(t < 1/6) return p + (q - p) * 6 * t;
if(t < 1/2) return q;
if(t < 2/3) return p + (q - p) * (2/3 - t) * 6;
return p;
};
let r2, g2, b2;
if (s === 0) {
r2 = g2 = b2 = l;
} else {
const q = l < 0.5 ? l * (1 + s) : l + s - l * s;
const p = 2 * l - q;
r2 = hue2rgb(p, q, h + 1/3);
g2 = hue2rgb(p, q, h);
b2 = hue2rgb(p, q, h - 1/3);
}
// Step 5: Format Output
const result = `rgb(${Math.round(r2 * 255)}, ${Math.round(g2 * 255)}, ${Math.round(b2 * 255)})`;
return `${result}`;
}
export function ColorLuminance(color, lum = 0) {
// Regular expression to match RGBA colors
const rgbaRegex = /rgba?\(([^)]+)\)/g;
// Check if the input color is a gradient (linear or radial)
if (color.includes("gradient")) {
let gradient = color;
// Create a set to hold unique RGBA strings
let uniqueRgbaSet = new Set();
// Find all instances of RGBA in the gradient
let match;
while ((match = rgbaRegex.exec(color)) !== null) {
uniqueRgbaSet.add(match[1]); // Add the unique RGBA string to the set
}
// Loop through each unique RGBA string
for (let rgbaString of uniqueRgbaSet) {
const [r, g, b, a] = rgbaString.split(",").map(str => str.trim());
// Apply the original luminance adjustment logic
let adjustedRgba = [];
for (let c of [r, g, b]) {
c = Math.round(Math.min(Math.max(0, c + c * lum), 255));
adjustedRgba.push(c);
}
adjustedRgba.push(a); // Add the alpha component back
// Replace all occurrences of the original RGBA string with the adjusted one
const regex = new RegExp(`rgba\\(${rgbaString}\\)`, "g");
gradient = gradient.replace(regex, `rgba(${adjustedRgba.join(", ")})`);
}
return gradient;
} else {
// Handle as a simple color (could be HEX, RGBA, etc., as supported by your Color library)
const hexColor = Color(color).hex();
let adjustedHex = String(hexColor).replace(/[^0-9a-f]/gi, "");
if (adjustedHex.length < 6) {
adjustedHex = adjustedHex[0] + adjustedHex[0] + adjustedHex[1] + adjustedHex[1] + adjustedHex[2] + adjustedHex[2];
}
let rgb = "#",
c;
for (let i = 0; i < 3; i++) {
c = parseInt(adjustedHex.substr(i * 2, 2), 16);
c = Math.round(Math.min(Math.max(0, c + c * lum), 255)).toString(16);
rgb += ("00" + c).substring(c.length);
}
return Color(rgb).hex();
}
}
new StorageListener();
var PageLoaded = false;
async function CheckLoadOnPeriods() {
if (!PageLoaded) {
await delay(1000);
var code = document.getElementsByClassName("code")[0];
if (code && !UserInitalCode) {
LoadPageElements();
finishLoad();
PageLoaded = true;
}
if (!code) {
CheckLoadOnPeriods();
}
}
}
var MenuItemMutation = false;
var NonSEQTAPage = false;
var IsSEQTAPage = false;
document.addEventListener(
"load",
function () {
CheckForMenuList();
if (
document.childNodes[1].textContent?.includes(
"Copyright (c) SEQTA Software",
) &&
document.title.includes("SEQTA Learn") &&
!IsSEQTAPage
) {
IsSEQTAPage = true;
console.log("[BetterSEQTA+] Verified SEQTA Page");
var link = document.createElement("link");
link.href = chrome.runtime.getURL("inject/documentload.css");
link.type = "text/css";
link.rel = "stylesheet";
document.getElementsByTagName("html")[0].appendChild(link);
chrome.storage.local.get(null, function (items) {
main(items);
});
}
if (
!document.childNodes[1].textContent?.includes("SEQTA") &&
!NonSEQTAPage
) {
NonSEQTAPage = true;
}
},
true,
);
function CallExtensionSettings() {
let Settings =
stringToHTML(
String.raw`
`);
document.body.append(Settings.firstChild);
// add an iframe to the div:
let iframe = document.createElement("iframe");
iframe.src = chrome.runtime.getURL("interface/index.html");
iframe.allowTransparency = "true";
iframe.style.width = "384px";
iframe.style.height = "590px";
iframe.style.border = "none";
iframe.setAttribute("excludeDarkCheck", "true");
document.getElementById("ExtensionPopup").append(iframe);
var container = document.getElementById("container");
var extensionsettings = document.getElementById("ExtensionPopup");
container.onclick = function () {
if (!SettingsClicked) {
extensionsettings.classList.add("hide");
}
SettingsClicked = false;
};
}
function ApplyDraggableFunctions() {
var listItens = document.querySelectorAll(".draggable");
[].forEach.call(listItens, function (item) {
addEventsDragAndDrop(item);
});
}
var dragSrcEl;
function dragStart(e) {
this.style.opacity = "0.4";
dragSrcEl = this;
e.dataTransfer.effectAllowed = "move";
e.dataTransfer.setData("text/html", this.innerHTML);
}
function dragEnter() {
this.classList.add("over");
}
function dragLeave(e) {
e.stopPropagation();
this.classList.remove("over");
}
function dragOver(e) {
e.preventDefault();
e.dataTransfer.dropEffect = "move";
return false;
}
function dragDrop() {
if (dragSrcEl != this) {
const parentA = this.parentNode;
const siblingA = this.nextSibling === dragSrcEl ? this : this.nextSibling;
// Move `this` to before the `dragSrcEl`
dragSrcEl.parentNode.insertBefore(this, dragSrcEl);
// Move `dragSrcEl` to before the sibling of `this`
parentA.insertBefore(dragSrcEl, siblingA);
// Save position of all menu items
let children = parentA.childNodes;
// console.log(children)
let listorder = [];
for (let i = 0; i < children.length; i++) {
const elm = children[i];
listorder.push(elm.dataset.key);
}
chrome.storage.local.set({ menuorder: listorder });
}
return false;
}
function dragEnd() {
var listItens = document.querySelectorAll(".draggable");
[].forEach.call(listItens, function (item) {
item.classList.remove("over");
});
this.style.opacity = "1";
}
function addEventsDragAndDrop(el) {
el.addEventListener("dragstart", dragStart, false);
el.addEventListener("dragenter", dragEnter, false);
el.addEventListener("dragover", dragOver, false);
el.addEventListener("dragleave", dragLeave, false);
el.addEventListener("drop", dragDrop, false);
el.addEventListener("dragend", dragEnd, false);
}
function cloneAttributes(target, source) {
[...source.attributes].forEach((attr) => {
target.setAttribute(attr.nodeName, attr.nodeValue);
});
}
function OpenMenuOptions() {
chrome.storage.local.get(null, function (result) {
var container = document.getElementById("container");
var menu = document.getElementById("menu");
if (result.defaultmenuorder.length == "0") {
let childnodes = menu.firstChild.childNodes;
let newdefaultmenuorder = [];
for (let i = 0; i < childnodes.length; i++) {
const element = childnodes[i];
newdefaultmenuorder.push(element.dataset.key);
chrome.storage.local.set({ defaultmenuorder: newdefaultmenuorder });
}
}
let childnodes = menu.firstChild.childNodes;
if (result.defaultmenuorder.length != childnodes.length) {
for (let i = 0; i < childnodes.length; i++) {
const element = childnodes[i];
if (!result.defaultmenuorder.indexOf(element.dataset.key)) {
let newdefaultmenuorder = result.defaultmenuorder;
newdefaultmenuorder.push(element.dataset.key);
chrome.storage.local.set({ defaultmenuorder: newdefaultmenuorder });
}
}
}
MenuOptionsOpen = true;
let cover = document.createElement("div");
cover.classList.add("notMenuCover");
menu.style.zIndex = "20";
menu.style.setProperty("--menuHidden", "flex");
container.append(cover);
let menusettings = document.createElement("div");
menusettings.classList.add("editmenuoption-container");
let defaultbutton = document.createElement("div");
defaultbutton.classList.add("editmenuoption");
defaultbutton.innerText = "Restore Default";
defaultbutton.id = "restoredefaultoption";
let savebutton = document.createElement("div");
savebutton.classList.add("editmenuoption");
savebutton.innerText = "Save";
savebutton.id = "restoredefaultoption";
menusettings.appendChild(defaultbutton);
menusettings.appendChild(savebutton);
menu.appendChild(menusettings);
let ListItems = menu.firstChild.childNodes;
for (let i = 0; i < ListItems.length; i++) {
const element = ListItems[i];
element.classList.add("draggable");
element.setAttribute("draggable", true);
if (element.classList.contains("hasChildren")) {
element.classList.remove("active");
menu.firstChild.classList.remove("noscroll");
}
let MenuItemToggle = stringToHTML(
`
`,
).firstChild;
element.append(MenuItemToggle);
if (!element.dataset.betterseqta) {
var a = document.createElement("section");
a.innerHTML = element.innerHTML;
cloneAttributes(a, element);
menu.firstChild.insertBefore(a, element);
element.remove();
}
}
if (Object.keys(result.menuitems).length == 0) {
menubuttons = menu.firstChild.childNodes;
var menuItems = {};
for (var i = 0; i < menubuttons.length; i++) {
var id = menubuttons[i].dataset.key;
const element = {};
element.toggle = true;
menuItems[id] = element;
}
chrome.storage.local.set({ menuitems: menuItems });
}
var menubuttons = document.getElementsByClassName("menuitem");
chrome.storage.local.get(["menuitems"], function (result) {
var menuItems = result.menuitems;
let buttons = document.getElementsByClassName("menuitem");
for (var i = 0; i < buttons.length; i++) {
var id = buttons[i].id;
if (menuItems[id]) {
buttons[i].checked = menuItems[id].toggle;
}
if (!menuItems[id]) {
buttons[i].checked = true;
}
}
});
ApplyDraggableFunctions();
function StoreMenuSettings() {
chrome.storage.local.get(["menuitems"], function () {
var menuItems = {};
menubuttons = menu.firstChild.childNodes;
let button = document.getElementsByClassName("menuitem");
for (var i = 0; i < menubuttons.length; i++) {
var id = menubuttons[i].dataset.key;
const element = {};
element.toggle = button[i].checked;
menuItems[id] = element;
}
chrome.storage.local.set({ menuitems: menuItems });
});
}
function changeDisplayProperty(element) {
if (!element.checked) {
element.parentNode.parentNode.style.display = "var(--menuHidden)";
}
if (element.checked) {
element.parentNode.parentNode.style.setProperty(
"display",
"flex",
"important",
);
}
}
for (let i = 0; i < menubuttons.length; i++) {
const element = menubuttons[i];
element.addEventListener("change", () => {
StoreMenuSettings();
changeDisplayProperty(element);
});
}
function closeAll() {
ListItems = menu.firstChild.childNodes;
menusettings.remove();
cover.remove();
MenuOptionsOpen = false;
menu.style.setProperty("--menuHidden", "none");
for (let i = 0; i < ListItems.length; i++) {
const element = ListItems[i];
element.classList.remove("draggable");
element.setAttribute("draggable", false);
if (!element.dataset.betterseqta) {
var a = document.createElement("li");
a.innerHTML = element.innerHTML;
cloneAttributes(a, element);
menu.firstChild.insertBefore(a, element);
element.remove();
}
}
let switches = menu.querySelectorAll(".onoffswitch");
for (let i = 0; i < switches.length; i++) {
switches[i].remove();
}
StoreMenuSettings();
}
cover.addEventListener("click", closeAll);
savebutton.addEventListener("click", closeAll);
defaultbutton.addEventListener("click", function () {
chrome.storage.local.get(null, function (response) {
const options = response.defaultmenuorder;
chrome.storage.local.set({ menuorder: options });
ChangeMenuItemPositions(options);
for (let i = 0; i < menubuttons.length; i++) {
const element = menubuttons[i];
element.checked = true;
element.parentNode.parentNode.style.setProperty(
"display",
"flex",
"important",
);
}
StoreMenuSettings();
});
});
});
}
function ReplaceMenuSVG(element, svg) {
let item = element.firstChild;
item.firstChild.remove();
if (element.dataset.key == "messages") {
element.firstChild.innerText = "Direct Messages";
}
let newsvg = stringToHTML(svg).firstChild;
item.insertBefore(newsvg, item.firstChild);
}
function AddBetterSEQTAElements(toggle) {
var code = document.getElementsByClassName("code")[0];
// Replaces students code with the version of BetterSEQTA
if (code != null) {
if (!code.innerHTML.includes("BetterSEQTA")) {
UserInitalCode = code.innerText;
code.innerText = `BetterSEQTA v${chrome.runtime.getManifest().version}`;
code.setAttribute("data-hover", "Click for user code");
code.addEventListener("click", function () {
var code = document.getElementsByClassName("code")[0];
if (code.innerText.includes("BetterSEQTA")) {
code.innerText = UserInitalCode;
code.setAttribute("data-hover", "Click for BetterSEQTA version");
} else {
code.innerText = `BetterSEQTA v${
chrome.runtime.getManifest().version
}`;
code.setAttribute("data-hover", "Click for user code");
}
});
if (toggle) {
// Creates Home menu button and appends it as the first child of the list
const result = chrome.storage.local.get(["animatedbk"]);
const sliderVal = chrome.storage.local.get(["bksliderinput"]);
result.then(animbkEnable);
sliderVal.then(updateBgDurations);
// Load darkmode state
chrome.storage.local.get(["DarkMode"], function (result) {
DarkMode = result.DarkMode;
});
var titlebar = document.createElement("div");
titlebar.classList.add("titlebar");
let container = document.getElementById("content");
container.append(titlebar);
var NewButtonStr = "";
var NewButton = stringToHTML(NewButtonStr);
var menu = document.getElementById("menu");
var List = menu.firstChild;
List.insertBefore(NewButton.firstChild, List.firstChild);
fetch(`${location.origin}/seqta/student/login`, {
method: "POST",
headers: {
"Content-Type": "application/json; charset=utf-8",
},
body: JSON.stringify({
mode: "normal",
query: null,
redirect_url: location.origin,
}),
})
.then((result) => result.json())
.then((response) => {
let info = response.payload;
var titlebar = document.getElementsByClassName("titlebar")[0];
titlebar.append(
stringToHTML(
"
",
).firstChild,
);
var userinfostr = `
${info.userDesc}
${UserInitalCode}
`;
var userinfo = stringToHTML(userinfostr).firstChild;
titlebar.append(userinfo);
var logoutbutton = document.getElementsByClassName("logout")[0];
var userInfosvgdiv = document.getElementById("logouttooltip");
userInfosvgdiv.appendChild(logoutbutton);
fetch(`${location.origin}/seqta/student/load/message/people`, {
method: "POST",
headers: {
"Content-Type": "application/json; charset=utf-8",
},
body: JSON.stringify({ mode: "student" }),
})
.then((result) => result.json())
.then((response) => {
let students = response.payload;
var index = students.findIndex(function (person) {
return (
person.firstname == info.userDesc.split(" ")[0] &&
person.surname == info.userDesc.split(" ")[1]
);
});
let houseelement =
document.getElementsByClassName("userInfohouse")[0];
if (students[index]?.house) {
houseelement.style.background = students[index].house_colour;
try {
let colorresult = GetThresholdofHex(
students[index]?.house_colour,
);
if (colorresult && colorresult > 300) {
houseelement.style.color = "black";
} else if (colorresult < 300) {
houseelement.style.color = "white";
} else {
houseelement.style.color = "black";
}
houseelement.innerText =
students[index].year + students[index].house;
} catch (error) {
console.log(students[index]);
houseelement.innerText = students[index].house;
}
} else {
houseelement.innerText = students[index].year;
}
});
});
var NewsButtonStr = "";
var NewsButton = stringToHTML(NewsButtonStr);
List.appendChild(NewsButton.firstChild);
editmenu = document.createElement("div");
editmenu.classList.add("editmenu");
let svg = stringToHTML(
"",
);
editmenu.append(svg.firstChild);
menu.appendChild(editmenu);
let a = document.createElement("div");
a.classList.add("icon-cover");
a.id = "icon-cover";
menu.appendChild(a);
var editmenu = document.querySelector("#editmenu");
editmenu.addEventListener("click", function () {
if (!MenuOptionsOpen) {
OpenMenuOptions();
}
});
var menuCover = document.querySelector("#icon-cover");
menuCover.addEventListener("click", function () {
location.href = "../#?page=/home";
SendHomePage();
document
.getElementById("menu")
.firstChild.classList.remove("noscroll");
});
// Creates the home container when the menu button is pressed
var homebutton = document.getElementById("homebutton");
homebutton.addEventListener("click", function () {
if (!MenuOptionsOpen) {
SendHomePage();
}
});
// Creates the news container when the menu button is pressed
var newsbutton = document.getElementById("newsbutton");
newsbutton.addEventListener("click", function () {
if (!MenuOptionsOpen) {
SendNewsPage();
}
});
}
appendBackgroundToUI();
CallExtensionSettings();
// If betterSEQTA+ is enabled, run the code
if (toggle) {
// Creates settings and dashboard buttons next to alerts
var SettingsButton = stringToHTML(
"",
);
var ContentDiv = document.getElementById("content");
ContentDiv.append(SettingsButton.firstChild);
chrome.storage.local.get(["DarkMode"], function (result) {
DarkMode = result.DarkMode;
let tooltipstring = GetLightDarkModeString(DarkMode);
var LightDarkModeButton = stringToHTML(
String.raw``,
);
ContentDiv.append(LightDarkModeButton.firstChild);
let LightDarkModeElement = document.getElementById("LightDarkModeButton");
if (DarkMode) {
LightDarkModeElement.firstChild.innerHTML = "";
document.documentElement.style.removeProperty("--better-pale");
} else {
LightDarkModeElement.firstChild.innerHTML = "";
try {
chrome.storage.local.get(null, function (result) {
document.documentElement.style.setProperty(
"--better-pale",
lightenAndPaleColor(result.selectedColor),
);
});
} catch (err) {
console.log(err);
}
}
let darklightText = document.getElementById("darklighttooliptext");
LightDarkModeElement.addEventListener("click", function () {
chrome.storage.local.get(["DarkMode"], function (result) {
DarkMode = result.DarkMode;
let alliframes = document.getElementsByTagName("iframe");
let fileref = GetiFrameCSSElement();
if (!DarkMode) {
document.documentElement.style.setProperty(
"--background-primary",
"#232323",
);
document.documentElement.style.setProperty(
"--background-secondary",
"#1a1a1a",
);
document.documentElement.style.setProperty(
"--text-primary",
"white",
);
document.documentElement.style.removeProperty("--better-pale");
LightDarkModeElement.firstChild.innerHTML = "";
for (let i = 0; i < alliframes.length; i++) {
const element = alliframes[i];
if (element.getAttribute("excludeDarkCheck") == "true") {
continue;
}
element.contentDocument.documentElement.childNodes[1].style.color =
"white";
element.contentDocument.documentElement.firstChild.appendChild(
fileref,
);
}
} else {
document.documentElement.style.setProperty(
"--background-primary",
"#ffffff",
);
document.documentElement.style.setProperty(
"--background-secondary",
"#e5e7eb",
);
document.documentElement.style.setProperty(
"--text-primary",
"black",
);
try {
chrome.storage.local.get(null, function (result) {
document.documentElement.style.setProperty(
"--better-pale",
lightenAndPaleColor(result.selectedColor),
);
});
} catch (err) {
console.log(err);
}
LightDarkModeElement.firstChild.innerHTML = "";
for (let i = 0; i < alliframes.length; i++) {
const element = alliframes[i];
if (element.getAttribute("excludeDarkCheck") == "true") {
continue;
}
element.contentDocument.documentElement.childNodes[1].style.color =
"black";
element.contentDocument.documentElement.firstChild.lastChild.remove();
}
}
tooltipstring = GetLightDarkModeString(!result.DarkMode);
darklightText.innerText = tooltipstring;
chrome.storage.local.set({ DarkMode: !result.DarkMode });
});
});
});
} else {
// Creates settings and dashboard buttons next to alerts
SettingsButton = stringToHTML(
"",
);
ContentDiv = document.getElementById("content");
ContentDiv.append(SettingsButton.firstChild);
}
var AddedSettings = document.getElementById("AddedSettings");
var extensionsettings = document.getElementById("ExtensionPopup");
AddedSettings.addEventListener("click", function () {
extensionsettings.classList.toggle("hide");
SettingsClicked = true;
});
}
}
}
let tooltipstring;
function GetLightDarkModeString(darkmodetoggle) {
if (darkmodetoggle) {
tooltipstring = "Switch to light theme";
} else {
tooltipstring = "Switch to dark theme";
}
return tooltipstring;
}
function CheckCurrentLesson(lesson, num) {
var startTime = lesson.from;
var endTime = lesson.until;
// Gets current time
let currentDate = new Date();
// Takes start time of current lesson and makes it into a Date function for comparison
let startDate = new Date(currentDate.getTime());
startDate.setHours(startTime.split(":")[0]);
startDate.setMinutes(startTime.split(":")[1]);
startDate.setSeconds("00");
// Takes end time of current lesson and makes it into a Date function for comparison
let endDate = new Date(currentDate.getTime());
endDate.setHours(endTime.split(":")[0]);
endDate.setMinutes(endTime.split(":")[1]);
endDate.setSeconds("00");
// Gets the difference between the start time and current time
var difference = startDate.getTime() - currentDate.getTime();
// Converts the difference into minutes
var minutes = Math.floor(difference / 1000 / 60);
// Checks if current time is between the start time and end time of current tested lesson
let valid = startDate < currentDate && endDate > currentDate;
let id = lesson.code + num;
const date = new Date();
var elementA = document.getElementById(id);
if (!elementA) {
clearInterval(LessonInterval);
} else {
if (
currentSelectedDate.toLocaleDateString("en-au") ==
date.toLocaleDateString("en-au")
) {
if (valid) {
// Apply the activelesson class to increase the box-shadow of current lesson
elementA.classList.add("activelesson");
} else {
// Removes the activelesson class to ensure only the active lesson have the class
if (elementA != null) {
elementA.classList.remove("activelesson");
}
}
}
}
// If 5 minutes before the start of another lesson:
if (minutes == 5) {
chrome.storage.local.get("lessonalert", function (result) {
if (result.lessonalert) {
// Checks if notifications are supported
if (!window.Notification) {
console.log("Browser does not support notifications.");
} else {
// check if permission is already granted
if (Notification.permission === "granted") {
// show notification here
} else {
// request permission from user
Notification.requestPermission()
.then(function (p) {
if (p === "granted") {
// show notification here
/* notify = new Notification("Next Lesson in 5 Minutes:", {
body:
"Subject: " +
lesson.description +
" \nRoom: " +
lesson.room +
" \nTeacher: " +
lesson.staff,
}); */
} else {
console.log("User blocked notifications.");
}
})
.catch(function (err) {
console.error(err);
});
}
}
}
});
}
}
export function GetThresholdofHex(color) {
// Regular expression for matching RGBA colors
const rgbaRegex = /rgba?\(([^)]+)\)/g;
// Check if the color string is a gradient (linear or radial)
if (color.includes("gradient")) {
let gradient = color;
// Find and replace all instances of RGBA in the gradient
let match;
while ((match = rgbaRegex.exec(color)) !== null) {
// Extract the individual components (r, g, b, a)
const rgbaString = match[1];
const [r, g, b, a] = rgbaString.split(",").map(str => str.trim());
// Compute the threshold using your existing algorithm
const threshold = Math.sqrt(r ** 2 + g ** 2 + b ** 2);
// Replace the original RGBA string with the computed threshold
// Note: You can modify this part based on what you actually want to do with the threshold
gradient = gradient.replace(`rgba(${rgbaString})`, `rgba(${threshold}, ${threshold}, ${threshold}, ${a})`);
}
return gradient;
} else {
// Handle the color as a simple RGBA (or hex, or whatever the Color library supports)
const rgb = Color.rgb(color).string();
return Math.sqrt(rgb.r ** 2 + rgb.g ** 2 + rgb.b ** 2);
}
}
function CheckCurrentLessonAll(lessons) {
// Checks each lesson and sets an interval to run every 60 seconds to continue updating
LessonInterval = setInterval(
function () {
for (let i = 0; i < lessons.length; i++) {
CheckCurrentLesson(lessons[i], i + 1);
}
}.bind(lessons),
60000,
);
}
function MakeLessonDiv(lesson, num) {
let assessmentstring = "";
var lessonstring = `
`;
if (lesson.programmeID != 0) {
lessonstring += `
${assessmentsicon}
${coursesicon}
`;
}
if (lesson.assessments.length > 0) {
for (let i = 0; i < lesson.assessments.length; i++) {
const element = lesson.assessments[i];
assessmentstring += `
${element.title}
`;
}
lessonstring += `
${assessmentstring}
`;
}
lessonstring += "
";
var lessondiv = stringToHTML(lessonstring);
return lessondiv;
}
function CheckUnmarkedAttendance(lessonattendance) {
if (lessonattendance) {
var lesson = lessonattendance.label;
} else {
lesson = " ";
}
return lesson;
}
function callHomeTimetable(date, change) {
// Creates a HTTP Post Request to the SEQTA page for the students timetable
var xhr = new XMLHttpRequest();
xhr.open("POST", `${location.origin}/seqta/student/load/timetable?`, true);
// Sets the response type to json
xhr.setRequestHeader("Content-Type", "application/json; charset=utf-8");
xhr.onreadystatechange = function () {
// Once the response is ready
if (xhr.readyState === 4) {
var serverResponse = JSON.parse(xhr.response);
let lessonArray = [];
var DayContainer = document.getElementById("day-container");
// If items in response:
if (serverResponse.payload.items.length > 0) {
if (!DayContainer.innerText || change) {
// console.log(serverResponse.payload.items.length);
for (let i = 0; i < serverResponse.payload.items.length; i++) {
lessonArray.push(serverResponse.payload.items[i]);
}
lessonArray.sort(function (a, b) {
return a.from.localeCompare(b.from);
});
// If items in the response, set each corresponding value into divs
// lessonArray = lessonArray.splice(1)
GetLessonColours().then((colours) => {
let subjects = colours;
for (let i = 0; i < lessonArray.length; i++) {
let subjectname = `timetable.subject.colour.${lessonArray[i].code}`;
let subject = subjects.find(
(element) => element.name === subjectname,
);
if (!subject) {
lessonArray[i].colour = "--item-colour: #8e8e8e;";
} else {
lessonArray[i].colour = `--item-colour: ${subject.value};`;
let result = GetThresholdofHex(subject.value);
if (result > 300) {
lessonArray[i].invert = true;
}
}
// Removes seconds from the start and end times
lessonArray[i].from = lessonArray[i].from.substring(0, 5);
lessonArray[i].until = lessonArray[i].until.substring(0, 5);
// Checks if attendance is unmarked, and sets the string to " ".
lessonArray[i].attendanceTitle = CheckUnmarkedAttendance(
lessonArray[i].attendance,
);
}
// If on home page, apply each lesson to HTML with information in each div
DayContainer.innerText = "";
for (let i = 0; i < lessonArray.length; i++) {
var div = MakeLessonDiv(lessonArray[i], i + 1);
// Append each of the lessons into the day-container
if (lessonArray[i].invert) {
div.firstChild.classList.add("day-inverted");
}
DayContainer.append(div.firstChild);
}
const today = new Date();
if (currentSelectedDate.getDate() == today.getDate()) {
for (let i = 0; i < lessonArray.length; i++) {
CheckCurrentLesson(lessonArray[i], i + 1);
}
// For each lesson, check the start and end times
CheckCurrentLessonAll(lessonArray);
}
});
}
} else {
if (!DayContainer.innerText || change) {
DayContainer.innerText = "";
var dummyDay = document.createElement("div");
dummyDay.classList.add("day-empty");
let img = document.createElement("img");
img.src = chrome.runtime.getURL("icons/betterseqta-light-icon.png");
let text = document.createElement("p");
text.innerText = "No lessons available.";
dummyDay.append(img);
dummyDay.append(text);
DayContainer.append(dummyDay);
}
}
}
};
xhr.send(
JSON.stringify({
// Information sent to SEQTA page as a request with the dates and student number
from: date,
until: date,
// Funny number
student: 69,
}),
);
}
function GetUpcomingAssessments() {
let func = fetch(`${location.origin}/seqta/student/assessment/list/upcoming?`, {
method: "POST",
headers: {
"Content-Type": "application/json; charset=utf-8",
},
body: JSON.stringify({ student: 69 }),
});
return func
.then((result) => result.json())
.then((response) => response.payload);
}
function GetActiveClasses() {
let func = fetch(`${location.origin}/seqta/student/load/subjects?`, {
method: "POST",
headers: {
"Content-Type": "application/json; charset=utf-8",
},
body: JSON.stringify({}),
});
return func
.then((result) => result.json())
.then((response) => response.payload);
}
function comparedate(obj1, obj2) {
if (obj1.date < obj2.date) {
return -1;
}
if (obj1.date > obj2.date) {
return 1;
}
return 0;
}
function CreateElement(type, class_, id, innerText, innerHTML, style) {
let element = document.createElement(type);
if (class_ !== undefined) {
element.classList.add(class_);
}
if (id !== undefined) {
element.id = id;
}
if (innerText !== undefined) {
element.innerText = innerText;
}
if (innerHTML !== undefined) {
element.innerHTML = innerHTML;
}
if (style !== undefined) {
element.style = style;
}
return element;
}
function createAssessmentDateDiv(date, value, datecase = undefined) {
var options = { weekday: "long", month: "long", day: "numeric" };
const FormattedDate = new Date(date);
const assessments = value.assessments;
const container = value.div;
let DateTitleDiv = document.createElement("div");
DateTitleDiv.classList.add("upcoming-date-title");
if (datecase) {
let datetitle = document.createElement("h5");
datetitle.classList.add("upcoming-special-day");
datetitle.innerText = datecase;
DateTitleDiv.append(datetitle);
container.setAttribute("data-day", datecase);
}
let DateTitle = document.createElement("h5");
DateTitle.innerText = FormattedDate.toLocaleDateString("en-AU", options);
DateTitleDiv.append(DateTitle);
container.append(DateTitleDiv);
let assessmentContainer = document.createElement("div");
assessmentContainer.classList.add("upcoming-date-assessments");
for (let i = 0; i < assessments.length; i++) {
const element = assessments[i];
let item = document.createElement("div");
item.classList.add("upcoming-assessment");
item.setAttribute("data-subject", element.code);
item.id = `assessment${element.id}`;
item.style = element.colour;
let titlediv = document.createElement("div");
titlediv.classList.add("upcoming-subject-title");
let titlesvg =
stringToHTML(``).firstChild;
titlediv.append(titlesvg);
let detailsdiv = document.createElement("div");
detailsdiv.classList.add("upcoming-details");
let detailstitle = document.createElement("h5");
detailstitle.innerText = `${element.subject} assessment`;
let subject = document.createElement("p");
subject.innerText = element.title;
subject.classList.add("upcoming-assessment-title");
subject.onclick = function () {
location.href = `../#?page=/assessments/${element.programmeID}:${element.metaclassID}&item=${element.id}`;
};
detailsdiv.append(detailstitle);
detailsdiv.append(subject);
item.append(titlediv);
item.append(detailsdiv);
assessmentContainer.append(item);
fetch(`${location.origin}/seqta/student/assessment/submissions/get`, {
method: "POST",
headers: {
"Content-Type": "application/json; charset=utf-8",
},
body: JSON.stringify({
assessment: element.id,
metaclass: element.metaclassID,
student: 69,
}),
})
.then((result) => result.json())
.then((response) => {
if (response.payload.length > 0) {
const assessment = document.querySelector(`#assessment${element.id}`);
// ticksvg = stringToHTML(``).firstChild
// ticksvg.classList.add('upcoming-tick');
// assessment.append(ticksvg);
let submittedtext = document.createElement("div");
submittedtext.classList.add("upcoming-submittedtext");
submittedtext.innerText = "Submitted";
assessment.append(submittedtext);
}
});
}
container.append(assessmentContainer);
return container;
}
function CheckSpecialDay(date1, date2) {
if (
date1.getFullYear() === date2.getFullYear() &&
date1.getMonth() === date2.getMonth() &&
date1.getDate() - 1 === date2.getDate()
) {
return "Yesterday";
}
if (
date1.getFullYear() === date2.getFullYear() &&
date1.getMonth() === date2.getMonth() &&
date1.getDate() === date2.getDate()
) {
return "Today";
}
if (
date1.getFullYear() === date2.getFullYear() &&
date1.getMonth() === date2.getMonth() &&
date1.getDate() + 1 === date2.getDate()
) {
return "Tomorrow";
}
}
function CreateSubjectFilter(subjectcode, itemcolour, checked) {
let label = CreateElement("label", "upcoming-checkbox-container");
label.innerText = subjectcode;
let input = CreateElement("input");
input.type = "checkbox";
input.checked = checked;
input.id = `filter-${subjectcode}`;
label.style = itemcolour;
let span = CreateElement("span", "upcoming-checkmark");
label.append(input);
label.append(span);
input.addEventListener("change", function (change) {
chrome.storage.local.get(null, function (storage) {
let filters = storage.subjectfilters;
let id = change.target.id.split("-")[1];
filters[id] = change.target.checked;
chrome.storage.local.set({ subjectfilters: filters });
});
});
return label;
}
function CreateFilters(subjects) {
chrome.storage.local.get(null, function (result) {
let filteroptions = result.subjectfilters;
let filterdiv = document.querySelector("#upcoming-filters");
for (let i = 0; i < subjects.length; i++) {
const element = subjects[i];
// eslint-disable-next-line
if (!Object.prototype.hasOwnProperty.call(filteroptions, element.code)) {
filteroptions[element.code] = true;
chrome.storage.local.set({ subjectfilters: filteroptions });
}
let elementdiv = CreateSubjectFilter(
element.code,
element.colour,
filteroptions[element.code],
);
filterdiv.append(elementdiv);
}
});
}
function CreateUpcomingSection(assessments) {
let upcomingitemcontainer = document.querySelector("#upcoming-items");
let overdueDates = [];
let upcomingDates = {};
// date = '2022/3/20';
// var Today = new Date(date);
var Today = new Date();
// Removes overdue assessments from the upcoming assessments array and pushes to overdue array
for (let i = 0; i < assessments.length; i++) {
const element = assessments[i];
let assessmentdue = new Date(element.due);
CheckSpecialDay(Today, assessmentdue);
if (assessmentdue < Today) {
if (!CheckSpecialDay(Today, assessmentdue)) {
overdueDates.push(element);
assessments.splice(i, 1);
i--;
}
}
}
var TomorrowDate = new Date();
TomorrowDate.setDate(TomorrowDate.getDate() + 1);
GetLessonColours().then((colours) => {
let subjects = colours;
for (let i = 0; i < assessments.length; i++) {
let subjectname = `timetable.subject.colour.${assessments[i].code}`;
let subject = subjects.find((element) => element.name === subjectname);
if (!subject) {
assessments[i].colour = "--item-colour: #8e8e8e;";
} else {
assessments[i].colour = `--item-colour: ${subject.value};`;
GetThresholdofHex(subject.value); // result (originally) result = GetThresholdofHex
}
}
let activeSubjects = []; // TODO: IDK what is going on here, but it didn't exist
for (let i = 0; i < activeSubjects.length; i++) {
const element = activeSubjects[i];
let subjectname = `timetable.subject.colour.${element.code}`;
let colour = colours.find((element) => element.name === subjectname);
if (!colour) {
element.colour = "--item-colour: #8e8e8e;";
} else {
element.colour = `--item-colour: ${colour.value};`;
let result = GetThresholdofHex(colour.value);
if (result > 300) {
element.invert = true;
}
}
}
CreateFilters(activeSubjects);
let type;
let class_;
for (let i = 0; i < assessments.length; i++) {
const element = assessments[i];
if (!upcomingDates[element.due]) {
let dateObj = new Object();
dateObj.div = CreateElement(
// TODO: not sure whats going on here?
// eslint-disable-next-line
type = "div",
// eslint-disable-next-line
class_ = "upcoming-date-container",
);
dateObj.assessments = [];
upcomingDates[element.due] = dateObj;
}
let assessmentDateDiv = upcomingDates[element.due];
assessmentDateDiv.assessments.push(element);
}
for (var date in upcomingDates) {
let assessmentdue = new Date(upcomingDates[date].assessments[0].due);
let specialcase = CheckSpecialDay(Today, assessmentdue);
let assessmentDate;
let datecase;
if (specialcase) {
assessmentDate = createAssessmentDateDiv(
date,
upcomingDates[date],
// eslint-disable-next-line
datecase = specialcase,
);
} else {
assessmentDate = createAssessmentDateDiv(date, upcomingDates[date]);
}
if (specialcase === "Yesterday") {
upcomingitemcontainer.insertBefore(
assessmentDate,
upcomingitemcontainer.firstChild,
);
} else {
upcomingitemcontainer.append(assessmentDate);
}
}
chrome.storage.local.get(null, function (result) {
FilterUpcomingAssessments(result.subjectfilters);
});
});
}
function AddPlaceHolderToParent(parent, numberofassessments) {
let textcontainer = CreateElement("div", "upcoming-blank");
let textblank = CreateElement("p", "upcoming-hiddenassessment");
let s = "";
if (numberofassessments > 1) {
s = "s";
}
textblank.innerText = `${numberofassessments} hidden assessment${s} due`;
textcontainer.append(textblank);
textcontainer.setAttribute("data-hidden", true);
parent.append(textcontainer);
}
function FilterUpcomingAssessments(subjectoptions) {
for (var item in subjectoptions) {
let subjectdivs = document.querySelectorAll(`[data-subject="${item}"]`);
for (let i = 0; i < subjectdivs.length; i++) {
const element = subjectdivs[i];
if (!subjectoptions[item]) {
element.classList.add("hidden");
}
if (subjectoptions[item]) {
element.classList.remove("hidden");
}
element.parentNode.classList.remove("hidden");
let children = element.parentNode.parentNode.children;
for (let i = 0; i < children.length; i++) {
const element = children[i];
if (element.hasAttribute("data-hidden")) {
element.remove();
}
}
if (
element.parentNode.children.length ==
element.parentNode.querySelectorAll(".hidden").length
) {
if (element.parentNode.querySelectorAll(".hidden").length > 0) {
if (!element.parentNode.parentNode.hasAttribute("data-day")) {
element.parentNode.parentNode.classList.add("hidden");
} else {
AddPlaceHolderToParent(
element.parentNode.parentNode,
element.parentNode.querySelectorAll(".hidden").length,
);
}
}
} else {
element.parentNode.parentNode.classList.remove("hidden");
}
}
}
}
chrome.storage.onChanged.addListener(function (changes) {
if (changes.subjectfilters) {
FilterUpcomingAssessments(changes.subjectfilters.newValue);
}
});
function GetLessonColours() {
let func = fetch(`${location.origin}/seqta/student/load/prefs?`, {
method: "POST",
headers: {
"Content-Type": "application/json; charset=utf-8",
},
body: JSON.stringify({ request: "userPrefs", asArray: true, user: 69 }),
});
return func
.then((result) => result.json())
.then((response) => response.payload);
}
export function CreateCustomShortcutDiv(element) {
// Creates the stucture and element information for each seperate shortcut
var shortcut = document.createElement("a");
shortcut.setAttribute("href", element.url);
shortcut.setAttribute("target", "_blank");
var shortcutdiv = document.createElement("div");
shortcutdiv.classList.add("shortcut");
shortcutdiv.classList.add("customshortcut");
let image = stringToHTML(
`
`,
).firstChild;
image.classList.add("shortcuticondiv");
var text = document.createElement("p");
text.textContent = element.name;
shortcutdiv.append(image);
shortcutdiv.append(text);
shortcut.append(shortcutdiv);
document.getElementById("shortcuts").append(shortcut);
}
export function RemoveCustomShortcutDiv(element) {
// Iterate through each shortcut
const shortcuts = document.querySelectorAll(".shortcut");
shortcuts.forEach((shortcut) => {
const anchorElement = shortcut.parentElement; // the element is the parent
const textElement = shortcut.querySelector("p"); //