mirror of
https://github.com/BetterSEQTA/BetterSEQTA-Plus.git
synced 2026-08-28 09:11:06 +00:00
fix(sidebar): hide Analytics via toggle
This commit is contained in:
@@ -0,0 +1,29 @@
|
|||||||
|
import type { Plugin } from "vite";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Vite's default base (`/`) emits absolute chunk paths like `/assets/chunk.js`.
|
||||||
|
* In content scripts those resolve against the SEQTA page origin on Firefox,
|
||||||
|
* not the extension — causing MIME type / NS_ERROR_CORRUPTED_CONTENT failures.
|
||||||
|
*
|
||||||
|
* Use relative base plus `chrome.runtime.getURL` for dynamic import targets.
|
||||||
|
*/
|
||||||
|
export function extensionChunkUrls(): Plugin {
|
||||||
|
return {
|
||||||
|
name: "extension-chunk-urls",
|
||||||
|
config() {
|
||||||
|
return {
|
||||||
|
base: "./",
|
||||||
|
experimental: {
|
||||||
|
renderBuiltUrl(filename, { hostType, type }) {
|
||||||
|
if (type === "chunk" && hostType === "js") {
|
||||||
|
const path = filename.replace(/^\//, "");
|
||||||
|
return {
|
||||||
|
runtime: `chrome.runtime.getURL(${JSON.stringify(path)})`,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -626,6 +626,7 @@ browser.runtime.onInstalled.addListener(function (event) {
|
|||||||
void migrateGlobalSearchDefaultsFor365Upgrade(event.previousVersion);
|
void migrateGlobalSearchDefaultsFor365Upgrade(event.previousVersion);
|
||||||
void resetThemeOfTheMonthDisabledFor366Upgrade(event.previousVersion);
|
void resetThemeOfTheMonthDisabledFor366Upgrade(event.previousVersion);
|
||||||
void resetThemeOfTheMonthDismissalFor370Upgrade(event.previousVersion);
|
void resetThemeOfTheMonthDismissalFor370Upgrade(event.previousVersion);
|
||||||
|
reloadSeqtaPages();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -512,6 +512,54 @@ ul.magicDelete > li.deleting {
|
|||||||
#menu:has(> ul > li.hasChildren.active) > ul > li:not(.hasChildren.active) {
|
#menu:has(> ul > li.hasChildren.active) > ul > li:not(.hasChildren.active) {
|
||||||
pointer-events: none !important;
|
pointer-events: none !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Edit Sidebar: every row + toggle must stay clickable (drill stack disables siblings). */
|
||||||
|
#menu.bsplus-sidebar-edit-mode li.item,
|
||||||
|
#menu.bsplus-sidebar-edit-mode section.item,
|
||||||
|
#menu.bsplus-sidebar-edit-mode .bsplus-sidebar-offscreen,
|
||||||
|
#menu.bsplus-sidebar-edit-mode .bsplus-sidebar-offscreen * {
|
||||||
|
pointer-events: auto !important;
|
||||||
|
user-select: auto !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
#menu.bsplus-sidebar-edit-mode:has(> ul > li.hasChildren.active)
|
||||||
|
> ul
|
||||||
|
> li:not(.hasChildren.active) {
|
||||||
|
pointer-events: auto !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
#menu.bsplus-sidebar-edit-mode > ul > .bsplus-sidebar-offscreen:not(.hasChildren.active),
|
||||||
|
#menu.bsplus-sidebar-edit-mode .sub .bsplus-sidebar-offscreen:not(.hasChildren.active) {
|
||||||
|
position: relative !important;
|
||||||
|
left: auto !important;
|
||||||
|
width: auto !important;
|
||||||
|
height: auto !important;
|
||||||
|
margin: inherit !important;
|
||||||
|
padding: inherit !important;
|
||||||
|
overflow: visible !important;
|
||||||
|
clip: auto !important;
|
||||||
|
opacity: 1 !important;
|
||||||
|
visibility: visible !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
#menu.bsplus-sidebar-edit-mode .item.draggable {
|
||||||
|
display: flex !important;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
#menu.bsplus-sidebar-edit-mode .item.draggable > label {
|
||||||
|
flex: 1;
|
||||||
|
min-width: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#menu.bsplus-sidebar-edit-mode .onoffswitch {
|
||||||
|
pointer-events: auto !important;
|
||||||
|
flex-shrink: 0;
|
||||||
|
position: relative;
|
||||||
|
z-index: 2;
|
||||||
|
}
|
||||||
|
|
||||||
#menu section > label {
|
#menu section > label {
|
||||||
align-items: center;
|
align-items: center;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
|
|||||||
@@ -3,6 +3,11 @@ import MenuitemSVGKey from "@/seqta/content/MenuItemSVGKey.json";
|
|||||||
import { waitForElm } from "@/seqta/utils/waitForElm";
|
import { waitForElm } from "@/seqta/utils/waitForElm";
|
||||||
import { isSeqtaEngageExperience } from "@/seqta/utils/isSeqtaEngage";
|
import { isSeqtaEngageExperience } from "@/seqta/utils/isSeqtaEngage";
|
||||||
import { processMenuItemNode } from "@/seqta/utils/sidebarMenuIcons";
|
import { processMenuItemNode } from "@/seqta/utils/sidebarMenuIcons";
|
||||||
|
import { MenuOptionsOpen } from "@/seqta/utils/Openers/OpenMenuOptions";
|
||||||
|
import {
|
||||||
|
applyMenuItemVisibility,
|
||||||
|
isMenuItemHidden,
|
||||||
|
} from "@/seqta/utils/menuItemVisibility";
|
||||||
import { loadAnalyticsPage } from "../loadAnalyticsPage";
|
import { loadAnalyticsPage } from "../loadAnalyticsPage";
|
||||||
import styles from "../styles.css?inline";
|
import styles from "../styles.css?inline";
|
||||||
|
|
||||||
@@ -17,7 +22,7 @@ const gradeAnalyticsPlugin: Plugin<{}> = {
|
|||||||
"Adds an analytics page with grade trends, distribution charts, and assessment history",
|
"Adds an analytics page with grade trends, distribution charts, and assessment history",
|
||||||
version: "1.0.0",
|
version: "1.0.0",
|
||||||
settings: {},
|
settings: {},
|
||||||
disableToggle: false,
|
disableToggle: true,
|
||||||
styles,
|
styles,
|
||||||
|
|
||||||
run: async () => {
|
run: async () => {
|
||||||
@@ -25,6 +30,10 @@ const gradeAnalyticsPlugin: Plugin<{}> = {
|
|||||||
return () => {};
|
return () => {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (isMenuItemHidden("analytics")) {
|
||||||
|
return () => {};
|
||||||
|
}
|
||||||
|
|
||||||
const menuList = (await waitForElm("#menu > ul, #menu ul", true, 100, 60)) as HTMLElement;
|
const menuList = (await waitForElm("#menu > ul, #menu ul", true, 100, 60)) as HTMLElement;
|
||||||
|
|
||||||
const analyticsItem = document.createElement("li");
|
const analyticsItem = document.createElement("li");
|
||||||
@@ -44,8 +53,11 @@ const gradeAnalyticsPlugin: Plugin<{}> = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
processMenuItemNode(analyticsItem);
|
processMenuItemNode(analyticsItem);
|
||||||
|
applyMenuItemVisibility();
|
||||||
|
|
||||||
const menuObserver = new MutationObserver(() => {
|
const menuObserver = new MutationObserver(() => {
|
||||||
|
if (MenuOptionsOpen) return;
|
||||||
|
if (isMenuItemHidden("analytics")) return;
|
||||||
if (!menuList.contains(analyticsItem)) {
|
if (!menuList.contains(analyticsItem)) {
|
||||||
if (homeButton?.parentElement === menuList) {
|
if (homeButton?.parentElement === menuList) {
|
||||||
homeButton.insertAdjacentElement("afterend", analyticsItem);
|
homeButton.insertAdjacentElement("afterend", analyticsItem);
|
||||||
@@ -53,11 +65,20 @@ const gradeAnalyticsPlugin: Plugin<{}> = {
|
|||||||
menuList.insertBefore(analyticsItem, menuList.firstChild);
|
menuList.insertBefore(analyticsItem, menuList.firstChild);
|
||||||
}
|
}
|
||||||
processMenuItemNode(analyticsItem);
|
processMenuItemNode(analyticsItem);
|
||||||
|
applyMenuItemVisibility();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
menuObserver.observe(menuList, { childList: true });
|
menuObserver.observe(menuList, { childList: true });
|
||||||
|
|
||||||
const onClick = (e: Event) => {
|
const onClick = (e: Event) => {
|
||||||
|
const target = e.target as HTMLElement;
|
||||||
|
if (
|
||||||
|
MenuOptionsOpen ||
|
||||||
|
analyticsItem.classList.contains("draggable") ||
|
||||||
|
target.closest(".onoffswitch, .editmenuoption-container")
|
||||||
|
) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
window.history.pushState({}, "", "/#?page=/analytics");
|
window.history.pushState({}, "", "/#?page=/analytics");
|
||||||
void loadAnalyticsPage();
|
void loadAnalyticsPage();
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ const gradeAnalyticsPluginLazy = defineLazyPlugin({
|
|||||||
"Grade trends, distribution charts, and assessment history synced from SEQTA",
|
"Grade trends, distribution charts, and assessment history synced from SEQTA",
|
||||||
version: "1.0.0",
|
version: "1.0.0",
|
||||||
settings,
|
settings,
|
||||||
disableToggle: false,
|
disableToggle: true,
|
||||||
defaultEnabled: true,
|
defaultEnabled: true,
|
||||||
styles,
|
styles,
|
||||||
loader: () => import("./core/index"),
|
loader: () => import("./core/index"),
|
||||||
|
|||||||
+39
-30
@@ -40,29 +40,7 @@ import IconFamily from "@/resources/fonts/IconFamily.woff";
|
|||||||
// Stylesheets
|
// Stylesheets
|
||||||
import iframeCSS from "@/css/iframe.scss?raw";
|
import iframeCSS from "@/css/iframe.scss?raw";
|
||||||
|
|
||||||
function SetDisplayNone(ElementName: string) {
|
import { applyMenuItemVisibility } from "@/seqta/utils/menuItemVisibility";
|
||||||
return `li[data-key=${ElementName}]{display:var(--menuHidden) !important; transition: 1s;}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
async function HideMenuItems(): Promise<void> {
|
|
||||||
try {
|
|
||||||
let stylesheetInnerText: string = "";
|
|
||||||
for (const [menuItem, { toggle }] of Object.entries(
|
|
||||||
settingsState.menuitems,
|
|
||||||
)) {
|
|
||||||
if (!toggle) {
|
|
||||||
stylesheetInnerText += SetDisplayNone(menuItem);
|
|
||||||
console.info(`[BetterSEQTA+] Hiding ${menuItem} menu item`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const menuItemStyle: HTMLStyleElement = document.createElement("style");
|
|
||||||
menuItemStyle.innerText = stylesheetInnerText;
|
|
||||||
document.head.appendChild(menuItemStyle);
|
|
||||||
} catch (error) {
|
|
||||||
console.error("[BetterSEQTA+] An error occurred:", error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export function hideSideBar() {
|
export function hideSideBar() {
|
||||||
const sidebar = document.getElementById("menu"); // The sidebar element to be closed
|
const sidebar = document.getElementById("menu"); // The sidebar element to be closed
|
||||||
@@ -368,11 +346,18 @@ async function handleSublink(sublink: string | undefined): Promise<void> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function handleNewsPage(): Promise<void> {
|
async function handleNewsPage(): Promise<void> {
|
||||||
console.info("[BetterSEQTA+] Started Init");
|
if (!settingsState.onoff) {
|
||||||
if (settingsState.onoff) {
|
|
||||||
SendNewsPage();
|
|
||||||
finishLoad();
|
finishLoad();
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
console.info("[BetterSEQTA+] Started Init");
|
||||||
|
try {
|
||||||
|
await SendNewsPage();
|
||||||
|
} catch (error) {
|
||||||
|
console.error("[BetterSEQTA+] Failed to load news page:", error);
|
||||||
|
}
|
||||||
|
finishLoad();
|
||||||
}
|
}
|
||||||
|
|
||||||
async function handleDefault(): Promise<void> {
|
async function handleDefault(): Promise<void> {
|
||||||
@@ -674,8 +659,24 @@ export function showConflictPopup() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function init() {
|
export function init() {
|
||||||
|
const tryMountDisabledUi = async () => {
|
||||||
|
if (document.getElementById("AddedSettings")) return;
|
||||||
|
|
||||||
|
try {
|
||||||
|
await waitForElm("#content");
|
||||||
|
} catch {
|
||||||
|
try {
|
||||||
|
await waitForElm("#container");
|
||||||
|
} catch {
|
||||||
|
await waitForElm("body");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
AppendElementsToDisabledPage();
|
||||||
|
};
|
||||||
|
|
||||||
const handleDisabled = () => {
|
const handleDisabled = () => {
|
||||||
waitForElm(".code", true, 50).then(AppendElementsToDisabledPage);
|
void tryMountDisabledUi();
|
||||||
};
|
};
|
||||||
|
|
||||||
if (settingsState.onoff) {
|
if (settingsState.onoff) {
|
||||||
@@ -705,7 +706,7 @@ export function init() {
|
|||||||
});
|
});
|
||||||
loading();
|
loading();
|
||||||
InjectCustomIcons();
|
InjectCustomIcons();
|
||||||
HideMenuItems();
|
applyMenuItemVisibility();
|
||||||
tryLoad();
|
tryLoad();
|
||||||
|
|
||||||
// Auto-focus WISP direct online submission editor when pane opens
|
// Auto-focus WISP direct online submission editor when pane opens
|
||||||
@@ -787,7 +788,7 @@ export function init() {
|
|||||||
} else {
|
} else {
|
||||||
handleDisabled();
|
handleDisabled();
|
||||||
InjectCustomIcons();
|
InjectCustomIcons();
|
||||||
window.addEventListener("load", handleDisabled);
|
window.addEventListener("load", handleDisabled, { once: true });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -807,6 +808,8 @@ function InjectCustomIcons() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function AppendElementsToDisabledPage() {
|
export function AppendElementsToDisabledPage() {
|
||||||
|
if (document.getElementById("AddedSettings")) return;
|
||||||
|
|
||||||
console.info("[BetterSEQTA+] Appending elements to disabled page");
|
console.info("[BetterSEQTA+] Appending elements to disabled page");
|
||||||
AddBetterSEQTAElements();
|
AddBetterSEQTAElements();
|
||||||
|
|
||||||
@@ -822,7 +825,13 @@ export function AppendElementsToDisabledPage() {
|
|||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
margin: 7px !important;
|
margin: 7px !important;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
color: white !important;
|
color: #38373d !important;
|
||||||
|
background: rgba(0, 0, 0, 0.08);
|
||||||
|
display: flex !important;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
visibility: visible !important;
|
||||||
|
z-index: 1000;
|
||||||
}
|
}
|
||||||
.addedButton svg {
|
.addedButton svg {
|
||||||
margin: 6px;
|
margin: 6px;
|
||||||
|
|||||||
@@ -278,7 +278,13 @@ function setupEventListeners() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function createSettingsButton(parent?: Element) {
|
async function createSettingsButton(parent?: Element) {
|
||||||
const target = parent ?? document.getElementById("content")!;
|
if (document.getElementById("AddedSettings")) return;
|
||||||
|
|
||||||
|
const target =
|
||||||
|
parent ??
|
||||||
|
document.getElementById("content") ??
|
||||||
|
document.getElementById("container") ??
|
||||||
|
document.body;
|
||||||
target.append(
|
target.append(
|
||||||
stringToHTML(/* html */ `
|
stringToHTML(/* html */ `
|
||||||
<button class="addedButton tooltip" id="AddedSettings">
|
<button class="addedButton tooltip" id="AddedSettings">
|
||||||
@@ -599,7 +605,31 @@ function getDrillFolderChain(
|
|||||||
return chain;
|
return chain;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function isSidebarEditMode(): boolean {
|
||||||
|
const menu = document.getElementById("menu");
|
||||||
|
return (
|
||||||
|
document.querySelector(".editmenuoption-container") != null ||
|
||||||
|
menu?.classList.contains("bsplus-sidebar-edit-mode") === true
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function clearSidebarAccessibilityLocks() {
|
||||||
|
const menu = document.getElementById("menu");
|
||||||
|
if (!menu) return;
|
||||||
|
|
||||||
|
const entries = menu.querySelectorAll("li, section");
|
||||||
|
for (const entry of entries) {
|
||||||
|
if (!(entry instanceof HTMLElement)) continue;
|
||||||
|
entry.classList.remove(BSPLUS_SIDEBAR_OFFSCREEN);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function updateSidebarAccessibility() {
|
function updateSidebarAccessibility() {
|
||||||
|
if (isSidebarEditMode()) {
|
||||||
|
clearSidebarAccessibilityLocks();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const menu = document.getElementById("menu");
|
const menu = document.getElementById("menu");
|
||||||
if (!menu) return;
|
if (!menu) return;
|
||||||
|
|
||||||
|
|||||||
@@ -1,10 +1,40 @@
|
|||||||
import type { SettingsState } from "@/types/storage";
|
import type { SettingsState } from "@/types/storage";
|
||||||
import { settingsState } from "../listeners/SettingsState";
|
import { settingsState } from "../listeners/SettingsState";
|
||||||
|
import { applyMenuItemVisibility } from "../menuItemVisibility";
|
||||||
import stringToHTML from "../stringToHTML";
|
import stringToHTML from "../stringToHTML";
|
||||||
import Sortable from "sortablejs";
|
import Sortable from "sortablejs";
|
||||||
|
|
||||||
export let MenuOptionsOpen = false;
|
export let MenuOptionsOpen = false;
|
||||||
|
|
||||||
|
function mergeMenuItemsFromDom(): Record<string, { toggle: boolean }> {
|
||||||
|
const menu = document.getElementById("menu");
|
||||||
|
const merged = {
|
||||||
|
...(settingsState.menuitems as Record<string, { toggle: boolean }>),
|
||||||
|
};
|
||||||
|
if (!menu?.firstChild) return merged;
|
||||||
|
|
||||||
|
const children = menu.firstChild.childNodes;
|
||||||
|
for (let i = 0; i < children.length; i++) {
|
||||||
|
const key = (children[i] as HTMLElement).dataset.key;
|
||||||
|
if (key && !merged[key]) {
|
||||||
|
merged[key] = { toggle: true };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return merged;
|
||||||
|
}
|
||||||
|
|
||||||
|
function storeMenuSettings(): void {
|
||||||
|
const menuItems: Record<string, { toggle: boolean }> = {};
|
||||||
|
const inputs = document.querySelectorAll<HTMLInputElement>(".menuitem");
|
||||||
|
for (const input of inputs) {
|
||||||
|
if (input.id) {
|
||||||
|
menuItems[input.id] = { toggle: input.checked };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
settingsState.menuitems =
|
||||||
|
menuItems as SettingsState["menuitems"];
|
||||||
|
}
|
||||||
|
|
||||||
export function OpenMenuOptions() {
|
export function OpenMenuOptions() {
|
||||||
var container = document.getElementById("container");
|
var container = document.getElementById("container");
|
||||||
var menu = document.getElementById("menu");
|
var menu = document.getElementById("menu");
|
||||||
@@ -22,19 +52,20 @@ export function OpenMenuOptions() {
|
|||||||
if (settingsState.defaultmenuorder.length != childnodes.length) {
|
if (settingsState.defaultmenuorder.length != childnodes.length) {
|
||||||
for (let i = 0; i < childnodes.length; i++) {
|
for (let i = 0; i < childnodes.length; i++) {
|
||||||
const element = childnodes[i];
|
const element = childnodes[i];
|
||||||
|
const key = (element as HTMLElement).dataset.key;
|
||||||
if (
|
if (
|
||||||
!settingsState.defaultmenuorder.indexOf(
|
key &&
|
||||||
(element as HTMLElement).dataset.key,
|
settingsState.defaultmenuorder.indexOf(key) === -1
|
||||||
)
|
|
||||||
) {
|
) {
|
||||||
let newdefaultmenuorder = settingsState.defaultmenuorder;
|
let newdefaultmenuorder = settingsState.defaultmenuorder;
|
||||||
newdefaultmenuorder.push((element as HTMLElement).dataset.key);
|
newdefaultmenuorder.push(key);
|
||||||
settingsState.defaultmenuorder = newdefaultmenuorder;
|
settingsState.defaultmenuorder = newdefaultmenuorder;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
MenuOptionsOpen = true;
|
MenuOptionsOpen = true;
|
||||||
|
menu!.classList.add("bsplus-sidebar-edit-mode");
|
||||||
|
|
||||||
var cover = document.createElement("div");
|
var cover = document.createElement("div");
|
||||||
cover.classList.add("notMenuCover");
|
cover.classList.add("notMenuCover");
|
||||||
@@ -53,7 +84,7 @@ export function OpenMenuOptions() {
|
|||||||
var savebutton = document.createElement("div");
|
var savebutton = document.createElement("div");
|
||||||
savebutton.classList.add("editmenuoption");
|
savebutton.classList.add("editmenuoption");
|
||||||
savebutton.innerText = "Save";
|
savebutton.innerText = "Save";
|
||||||
savebutton.id = "restoredefaultoption";
|
savebutton.id = "savemenuoption";
|
||||||
|
|
||||||
menusettings.appendChild(defaultbutton);
|
menusettings.appendChild(defaultbutton);
|
||||||
menusettings.appendChild(savebutton);
|
menusettings.appendChild(savebutton);
|
||||||
@@ -86,81 +117,51 @@ export function OpenMenuOptions() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (Object.keys(settingsState.menuitems).length == 0) {
|
if (Object.keys(settingsState.menuitems).length == 0) {
|
||||||
menubuttons = menu!.firstChild!.childNodes;
|
settingsState.menuitems = mergeMenuItemsFromDom() as SettingsState["menuitems"];
|
||||||
let menuItems = {} as any;
|
} else {
|
||||||
for (var i = 0; i < menubuttons.length; i++) {
|
settingsState.menuitems = mergeMenuItemsFromDom() as SettingsState["menuitems"];
|
||||||
var id = (menubuttons[i] as HTMLElement).dataset.key;
|
|
||||||
const element: any = {};
|
|
||||||
element.toggle = true;
|
|
||||||
(menuItems[id as keyof typeof menuItems] as any) = element;
|
|
||||||
}
|
|
||||||
settingsState.menuitems = menuItems;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var menubuttons: any = document.getElementsByClassName("menuitem");
|
let menuItems = settingsState.menuitems as Record<string, { toggle: boolean }>;
|
||||||
|
|
||||||
let menuItems = settingsState.menuitems as any;
|
|
||||||
let buttons = document.getElementsByClassName("menuitem");
|
let buttons = document.getElementsByClassName("menuitem");
|
||||||
for (let i = 0; i < buttons.length; i++) {
|
for (let i = 0; i < buttons.length; i++) {
|
||||||
let id = buttons[i].id as string | undefined;
|
const input = buttons[i] as HTMLInputElement;
|
||||||
if (menuItems[id as keyof typeof menuItems]) {
|
const id = input.id;
|
||||||
(buttons[i] as HTMLInputElement).checked =
|
input.checked =
|
||||||
menuItems[id as keyof typeof menuItems].toggle;
|
id && menuItems[id] ? menuItems[id].toggle : true;
|
||||||
} else {
|
|
||||||
(buttons[i] as HTMLInputElement).checked = true;
|
|
||||||
}
|
|
||||||
(buttons[i] as HTMLInputElement).checked = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let sortable: Sortable | undefined;
|
||||||
try {
|
try {
|
||||||
var el = document.querySelector("#menu > ul");
|
var el = document.querySelector("#menu > ul");
|
||||||
var sortable = Sortable.create(el as HTMLElement, {
|
sortable = Sortable.create(el as HTMLElement, {
|
||||||
draggable: ".draggable",
|
draggable: ".draggable",
|
||||||
dataIdAttr: "data-key",
|
dataIdAttr: "data-key",
|
||||||
animation: 150,
|
animation: 150,
|
||||||
easing: "cubic-bezier(.5,0,.5,1)",
|
easing: "cubic-bezier(.5,0,.5,1)",
|
||||||
onEnd: function () {
|
onEnd: function () {
|
||||||
saveNewOrder(sortable);
|
saveNewOrder(sortable!);
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error(err);
|
console.error(err);
|
||||||
}
|
}
|
||||||
|
|
||||||
function changeDisplayProperty(element: any) {
|
function changeDisplayProperty(input: HTMLInputElement) {
|
||||||
if (!element.checked) {
|
const row = input.closest("li, section") as HTMLElement | null;
|
||||||
element.parentNode.parentNode.style.display = "var(--menuHidden)";
|
if (!row) return;
|
||||||
}
|
if (!input.checked) {
|
||||||
if (element.checked) {
|
row.style.display = "var(--menuHidden)";
|
||||||
element.parentNode.parentNode.style.setProperty(
|
} else {
|
||||||
"display",
|
row.style.setProperty("display", "flex", "important");
|
||||||
"flex",
|
|
||||||
"important",
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function StoreMenuSettings() {
|
const menuInputs = document.querySelectorAll<HTMLInputElement>(".menuitem");
|
||||||
let menu = document.getElementById("menu");
|
for (const input of menuInputs) {
|
||||||
const menuItems: any = {};
|
input.addEventListener("change", () => {
|
||||||
let menubuttons = menu!.firstChild!.childNodes;
|
storeMenuSettings();
|
||||||
const button = document.getElementsByClassName("menuitem");
|
changeDisplayProperty(input);
|
||||||
for (let i = 0; i < menubuttons.length; i++) {
|
|
||||||
const id = (menubuttons[i] as HTMLElement).dataset.key;
|
|
||||||
const element: any = {};
|
|
||||||
element.toggle = (button[i] as HTMLInputElement).checked;
|
|
||||||
|
|
||||||
menuItems[id as keyof typeof menuItems] = element;
|
|
||||||
}
|
|
||||||
settingsState.menuitems = menuItems;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (let i = 0; i < menubuttons.length; i++) {
|
|
||||||
const element = menubuttons[i];
|
|
||||||
element.addEventListener("change", () => {
|
|
||||||
element.parentElement.parentElement.getAttribute("data-key");
|
|
||||||
StoreMenuSettings();
|
|
||||||
changeDisplayProperty(element);
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -168,6 +169,7 @@ export function OpenMenuOptions() {
|
|||||||
menusettings?.remove();
|
menusettings?.remove();
|
||||||
cover?.remove();
|
cover?.remove();
|
||||||
MenuOptionsOpen = false;
|
MenuOptionsOpen = false;
|
||||||
|
menu!.classList.remove("bsplus-sidebar-edit-mode");
|
||||||
menu!.style.setProperty("--menuHidden", "none");
|
menu!.style.setProperty("--menuHidden", "none");
|
||||||
|
|
||||||
for (let i = 0; i < ListItems.length; i++) {
|
for (let i = 0; i < ListItems.length; i++) {
|
||||||
@@ -189,10 +191,21 @@ export function OpenMenuOptions() {
|
|||||||
for (let i = 0; i < switches.length; i++) {
|
for (let i = 0; i < switches.length; i++) {
|
||||||
switches[i].remove();
|
switches[i].remove();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
applyMenuItemVisibility();
|
||||||
|
}
|
||||||
|
|
||||||
|
function saveAndClose() {
|
||||||
|
storeMenuSettings();
|
||||||
|
if (sortable) {
|
||||||
|
saveNewOrder(sortable);
|
||||||
|
}
|
||||||
|
applyMenuItemVisibility();
|
||||||
|
closeAll();
|
||||||
}
|
}
|
||||||
|
|
||||||
cover?.addEventListener("click", closeAll);
|
cover?.addEventListener("click", closeAll);
|
||||||
savebutton?.addEventListener("click", closeAll);
|
savebutton?.addEventListener("click", saveAndClose);
|
||||||
|
|
||||||
defaultbutton?.addEventListener("click", function () {
|
defaultbutton?.addEventListener("click", function () {
|
||||||
const options = settingsState.defaultmenuorder;
|
const options = settingsState.defaultmenuorder;
|
||||||
@@ -200,20 +213,27 @@ export function OpenMenuOptions() {
|
|||||||
|
|
||||||
ChangeMenuItemPositions(options);
|
ChangeMenuItemPositions(options);
|
||||||
|
|
||||||
for (let i = 0; i < menubuttons.length; i++) {
|
const inputs = document.querySelectorAll<HTMLInputElement>(".menuitem");
|
||||||
const element = menubuttons[i];
|
const restored: Record<string, { toggle: boolean }> = {};
|
||||||
element.checked = true;
|
for (const input of inputs) {
|
||||||
element.parentNode.parentNode.style.setProperty(
|
input.checked = true;
|
||||||
"display",
|
const row = input.closest("li, section") as HTMLElement | null;
|
||||||
"flex",
|
if (row) {
|
||||||
"important",
|
row.style.setProperty("display", "flex", "important");
|
||||||
);
|
}
|
||||||
|
if (input.id) {
|
||||||
|
restored[input.id] = { toggle: true };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
settingsState.menuitems = restored as SettingsState["menuitems"];
|
||||||
|
|
||||||
|
if (sortable) {
|
||||||
|
saveNewOrder(sortable);
|
||||||
}
|
}
|
||||||
saveNewOrder(sortable);
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function saveNewOrder(sortable: any) {
|
function saveNewOrder(sortable: Sortable) {
|
||||||
var order = sortable.toArray();
|
var order = sortable.toArray();
|
||||||
settingsState.menuorder = order;
|
settingsState.menuorder = order;
|
||||||
}
|
}
|
||||||
@@ -238,7 +258,10 @@ export function ChangeMenuItemPositions(menuorder: SettingsState["menuorder"]) {
|
|||||||
|
|
||||||
var newArr = [];
|
var newArr = [];
|
||||||
for (var i = 0; i < listorder.length; i++) {
|
for (var i = 0; i < listorder.length; i++) {
|
||||||
newArr[listorder[i]] = menuList[i];
|
const index = listorder[i];
|
||||||
|
if (index >= 0) {
|
||||||
|
newArr[index] = menuList[i];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let listItemsDOM = document.getElementById("menu")!.firstChild;
|
let listItemsDOM = document.getElementById("menu")!.firstChild;
|
||||||
|
|||||||
@@ -12,11 +12,15 @@ export async function SendNewsPage() {
|
|||||||
await delay(10);
|
await delay(10);
|
||||||
|
|
||||||
const element = document.querySelector("[data-key=news]");
|
const element = document.querySelector("[data-key=news]");
|
||||||
element!.classList.add("active");
|
element?.classList.add("active");
|
||||||
|
|
||||||
// Remove all current elements in the main div to add new elements
|
|
||||||
const main = document.getElementById("main");
|
const main = document.getElementById("main");
|
||||||
main!.innerHTML = "";
|
if (!main) {
|
||||||
|
console.warn("[BetterSEQTA+] News page: #main not found");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
main.innerHTML = "";
|
||||||
|
|
||||||
const displayCountry = (() => {
|
const displayCountry = (() => {
|
||||||
switch (settingsState.newsSource?.toLowerCase()) {
|
switch (settingsState.newsSource?.toLowerCase()) {
|
||||||
@@ -40,10 +44,12 @@ export async function SendNewsPage() {
|
|||||||
</div>
|
</div>
|
||||||
</div>`);
|
</div>`);
|
||||||
|
|
||||||
main!.append(html.firstChild!);
|
main.append(html.firstChild!);
|
||||||
|
|
||||||
const titlediv = document.getElementById("title")!.firstChild;
|
const titleBar = document.getElementById("title")?.firstChild;
|
||||||
(titlediv! as HTMLElement).innerText = "News";
|
if (titleBar) {
|
||||||
|
(titleBar as HTMLElement).innerText = "News";
|
||||||
|
}
|
||||||
AppendLoadingSymbol("newsloading", "#news-container");
|
AppendLoadingSymbol("newsloading", "#news-container");
|
||||||
|
|
||||||
const response = (await browser.runtime.sendMessage({
|
const response = (await browser.runtime.sendMessage({
|
||||||
|
|||||||
@@ -38,6 +38,7 @@ export function getDefaultSettingsState(): SettingsState {
|
|||||||
settings: { toggle: true },
|
settings: { toggle: true },
|
||||||
timetable: { toggle: true },
|
timetable: { toggle: true },
|
||||||
welcome: { toggle: true },
|
welcome: { toggle: true },
|
||||||
|
analytics: { toggle: true },
|
||||||
},
|
},
|
||||||
menuorder: [],
|
menuorder: [],
|
||||||
subjectfilters: {},
|
subjectfilters: {},
|
||||||
|
|||||||
@@ -5,6 +5,8 @@ import { applySelectedFont } from "@/seqta/ui/fonts/Manager";
|
|||||||
// Shortcuts rendering
|
// Shortcuts rendering
|
||||||
import { renderShortcuts } from "@/seqta/utils/Render/renderShortcuts";
|
import { renderShortcuts } from "@/seqta/utils/Render/renderShortcuts";
|
||||||
import { FilterUpcomingAssessments } from "@/seqta/utils/FilterUpcomingAssessments";
|
import { FilterUpcomingAssessments } from "@/seqta/utils/FilterUpcomingAssessments";
|
||||||
|
import { applyMenuItemVisibility } from "@/seqta/utils/menuItemVisibility";
|
||||||
|
import { ChangeMenuItemPositions } from "@/seqta/utils/Openers/OpenMenuOptions";
|
||||||
|
|
||||||
import browser from "webextension-polyfill";
|
import browser from "webextension-polyfill";
|
||||||
import type { CustomShortcut } from "@/types/storage";
|
import type { CustomShortcut } from "@/types/storage";
|
||||||
@@ -42,6 +44,12 @@ export class StorageChangeHandler {
|
|||||||
this.handleIconOnlySidebarChange.bind(this),
|
this.handleIconOnlySidebarChange.bind(this),
|
||||||
);
|
);
|
||||||
settingsState.register("selectedFont", () => applySelectedFont());
|
settingsState.register("selectedFont", () => applySelectedFont());
|
||||||
|
settingsState.register("menuitems", () => applyMenuItemVisibility());
|
||||||
|
settingsState.register("menuorder", (order) => {
|
||||||
|
if (Array.isArray(order) && order.length > 0) {
|
||||||
|
ChangeMenuItemPositions(order);
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private handleIconOnlySidebarChange(newValue: boolean | undefined) {
|
private handleIconOnlySidebarChange(newValue: boolean | undefined) {
|
||||||
|
|||||||
@@ -0,0 +1,45 @@
|
|||||||
|
import { settingsState } from "./listeners/SettingsState";
|
||||||
|
|
||||||
|
const STYLE_ID = "bsplus-menuitem-visibility";
|
||||||
|
|
||||||
|
function isEditSidebarOpen(): boolean {
|
||||||
|
return document.querySelector(".editmenuoption-container") != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
function hideRule(menuItem: string): string {
|
||||||
|
return `li[data-key=${menuItem}],section[data-key=${menuItem}]{display:var(--menuHidden) !important;transition:1s;}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Whether a sidebar key is hidden via Edit Sidebar toggles. */
|
||||||
|
export function isMenuItemHidden(key: string): boolean {
|
||||||
|
const items = settingsState.menuitems as Record<string, { toggle?: boolean }>;
|
||||||
|
const entry = items?.[key];
|
||||||
|
return entry != null && entry.toggle === false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Apply hide rules from `menuitems` (re-runnable after edit / storage sync). */
|
||||||
|
export function applyMenuItemVisibility(): void {
|
||||||
|
if (isEditSidebarOpen()) return;
|
||||||
|
|
||||||
|
try {
|
||||||
|
let css = "";
|
||||||
|
for (const [menuItem, config] of Object.entries(
|
||||||
|
settingsState.menuitems ?? {},
|
||||||
|
)) {
|
||||||
|
if (config && !config.toggle) {
|
||||||
|
css += hideRule(menuItem);
|
||||||
|
console.info(`[BetterSEQTA+] Hiding ${menuItem} menu item`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let styleEl = document.getElementById(STYLE_ID) as HTMLStyleElement | null;
|
||||||
|
if (!styleEl) {
|
||||||
|
styleEl = document.createElement("style");
|
||||||
|
styleEl.id = STYLE_ID;
|
||||||
|
document.head.appendChild(styleEl);
|
||||||
|
}
|
||||||
|
styleEl.textContent = css;
|
||||||
|
} catch (error) {
|
||||||
|
console.error("[BetterSEQTA+] Failed to apply menu item visibility:", error);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -6,6 +6,7 @@ export interface SettingsState {
|
|||||||
lessonalert: boolean;
|
lessonalert: boolean;
|
||||||
menuitems: {
|
menuitems: {
|
||||||
assessments: ToggleItem;
|
assessments: ToggleItem;
|
||||||
|
analytics: ToggleItem;
|
||||||
courses: ToggleItem;
|
courses: ToggleItem;
|
||||||
dashboard: ToggleItem;
|
dashboard: ToggleItem;
|
||||||
documents: ToggleItem;
|
documents: ToggleItem;
|
||||||
@@ -21,6 +22,7 @@ export interface SettingsState {
|
|||||||
settings: ToggleItem;
|
settings: ToggleItem;
|
||||||
timetable: ToggleItem;
|
timetable: ToggleItem;
|
||||||
welcome: ToggleItem;
|
welcome: ToggleItem;
|
||||||
|
[key: string]: ToggleItem;
|
||||||
};
|
};
|
||||||
menuorder: any[];
|
menuorder: any[];
|
||||||
onoff: boolean;
|
onoff: boolean;
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import type { BuildTarget, Manifest } from "./lib/types";
|
|||||||
import ClosePlugin from "./lib/closePlugin";
|
import ClosePlugin from "./lib/closePlugin";
|
||||||
import fixCrxWorkerLiveReload from "./lib/fixCrxWorkerLiveReload";
|
import fixCrxWorkerLiveReload from "./lib/fixCrxWorkerLiveReload";
|
||||||
import { firefoxStripFunctionProbe } from "./lib/firefoxStripFunctionProbe";
|
import { firefoxStripFunctionProbe } from "./lib/firefoxStripFunctionProbe";
|
||||||
|
import { extensionChunkUrls } from "./lib/extensionChunkUrls";
|
||||||
|
|
||||||
import million from "million/compiler";
|
import million from "million/compiler";
|
||||||
|
|
||||||
@@ -71,6 +72,7 @@ export default defineConfig(({ command }) => ({
|
|||||||
__BUILD_LABEL__: JSON.stringify(process.env.BUILD_LABEL ?? ""),
|
__BUILD_LABEL__: JSON.stringify(process.env.BUILD_LABEL ?? ""),
|
||||||
},
|
},
|
||||||
plugins: [
|
plugins: [
|
||||||
|
extensionChunkUrls(),
|
||||||
base64Loader,
|
base64Loader,
|
||||||
InlineWorkerPlugin(),
|
InlineWorkerPlugin(),
|
||||||
svelte({
|
svelte({
|
||||||
|
|||||||
Reference in New Issue
Block a user