diff --git a/Compass QoL Enhancer.user.js b/Compass QoL Enhancer.user.js index cd743fa..bc9c9a6 100644 --- a/Compass QoL Enhancer.user.js +++ b/Compass QoL Enhancer.user.js @@ -2,7 +2,7 @@ // @name Compass QoL Enhancer // @namespace blankie-scripts // @match http*://*.compass.education/* -// @version 1.4.0 +// @version 1.5.0 // @author blankie // @description A userscript that adds small but useful features for Compass, such as the ability to close windows by clicking on the background // @inject-into page @@ -12,6 +12,9 @@ "use strict"; let qolTabOpened = false; +// we make a copy of window.location.hash because the dashboard tab on a user's page would set the fragment to #dsh for some reason +let hashCopy = window.location.hash; + // needed because .toString() adds a trailing = for empty values function serializeURLSearchParams(query) { let out = ""; @@ -46,65 +49,6 @@ function getPanelItemHash(panelId, isDefault) { return `#${encodeURIComponent(panelId)}`; } -let observer = new MutationObserver(function(mutations) { - for (let mutation of mutations) { - if (mutation.type !== "childList") { - continue; - } - for (let node of mutation.addedNodes) { - handleNewNode(node); - } - } -}); -observer.observe(document.body, {childList: true, subtree: true}); - -// we make a copy of window.location.hash because the dashboard tab on a user's page would set the fragment to #dsh for some reason -let hashCopy = window.location.hash; -function handleNewNode(node) { - if (node.nodeType !== 1) { - return; - } - - if (node.parentElement && (node.classList.contains("ext-cal-hd-ct") || node.classList.contains("ext-cal-bg-tbl") || node.classList.contains("ext-cal-inner-ct"))) { - for (let element of node.querySelectorAll("div.ext-cal-evt")) { - handleNewCalendarEvent(element); - } - } else if (!qolTabOpened && node.classList.contains("x-panel")) { - qolTabOpened = true; - let tabToOpen = hashCopy.substring(1) || null; - if (window.location.pathname === "/Organise/Activities/Activity.aspx") { - tabToOpen = (new URLSearchParams(tabToOpen)).get("qol_open_tab"); - } - let panel = unsafeWindow.Ext.getCmp(node.id); - for (let i = 0; i < panel.items.items.length; i++) { - handlePanelItem(panel, panel.items.items[i], i === 0, tabToOpen); - } - } else if (node.closest("[id^='wikibrowserpanel-'], #CompassWidgetsWikiBrowserPanel")) { - // Make files and folders in wiki/resources clickable for Link Hints - if (node.localName === "td") { - node.setAttribute("role", "button"); - } - for (let element of node.querySelectorAll("td, .x-tree-expander")) { - element.setAttribute("role", "button"); - } - } -} - -document.body.addEventListener("click", function(event) { - // Add the ability to close windows by clicking on the background - if (!event.target.classList.contains("x-mask")) { - return; - } - let maskZIndex = BigInt(event.target.style.zIndex); - for (let maskMsg of document.querySelectorAll(".x-mask-msg")) { - if (BigInt(maskMsg.style.zIndex) >= maskZIndex && maskMsg.style.display !== "none") { - return; - } - } - - document.querySelector(".x-window-closable.x-window-active .x-tool-close").click(); -}, {passive: true}); - function handleNewCalendarEvent(element) { // Turn each calendar event into a link so that Link Hints can recognize it let a = document.createElement("a"); @@ -189,6 +133,89 @@ function handlePanelItem(panel, panelItem, isDefault, tabToOpen) { }); } +function handleCKEditor(instance) { + instance.on("contentDom", function() { + let editable = instance.editable(); + for (let element of editable.$.querySelectorAll("a")) { + handleCKEditorLink(element); + } + observer.observe(editable.$, {childList: true, subtree: true}); + }); +} + +function handleCKEditorLink(element) { + // Make links inside lesson plans open in the parent instead of a new tab + if (element.target !== "_blank" && element.target) { + return; + } + + element.target = "_parent"; + element.addEventListener("click", function(event) { + event.stopImmediatePropagation(); + }, {passive: true}); +} + +function handleNewNode(node, observer) { + if (node.nodeType !== 1) { + return; + } + + if (node.parentElement && (node.classList.contains("ext-cal-hd-ct") || node.classList.contains("ext-cal-bg-tbl") || node.classList.contains("ext-cal-inner-ct"))) { + for (let element of node.querySelectorAll("div.ext-cal-evt")) { + handleNewCalendarEvent(element); + } + } else if (!qolTabOpened && node.classList.contains("x-panel")) { + qolTabOpened = true; + let tabToOpen = hashCopy.substring(1) || null; + if (window.location.pathname === "/Organise/Activities/Activity.aspx") { + tabToOpen = (new URLSearchParams(tabToOpen)).get("qol_open_tab"); + } + let panel = unsafeWindow.Ext.getCmp(node.id); + for (let i = 0; i < panel.items.items.length; i++) { + handlePanelItem(panel, panel.items.items[i], i === 0, tabToOpen); + } + } else if (node.closest("[id^='wikibrowserpanel-'], #CompassWidgetsWikiBrowserPanel")) { + // Make files and folders in wiki/resources clickable for Link Hints + if (node.localName === "td") { + node.setAttribute("role", "button"); + } + for (let element of node.querySelectorAll("td, .x-tree-expander")) { + element.setAttribute("role", "button"); + } + } else if (node.classList.contains("cke")) { + let instance = unsafeWindow.CKEDITOR.instances[node.id.substring(4)]; + handleCKEditor(instance); + } else if (node.localName === "a" && /\bcke_/.test(node.closest("body").className)) { + handleCKEditorLink(node); + } +} + +let observer = new MutationObserver(function(mutations, observer) { + for (let mutation of mutations) { + if (mutation.type !== "childList") { + continue; + } + for (let node of mutation.addedNodes) { + handleNewNode(node, observer); + } + } +}); +observer.observe(document.body, {childList: true, subtree: true}); +document.body.addEventListener("click", function(event) { + // Add the ability to close windows by clicking on the background + if (!event.target.classList.contains("x-mask")) { + return; + } + let maskZIndex = BigInt(event.target.style.zIndex); + for (let maskMsg of document.querySelectorAll(".x-mask-msg")) { + if (BigInt(maskMsg.style.zIndex) >= maskZIndex && maskMsg.style.display !== "none") { + return; + } + } + + document.querySelector(".x-window-closable.x-window-active .x-tool-close").click(); +}, {passive: true}); + // Suppress that annoying barebones context menu that only has Copy // why is it not obvious that you can just hold ctrl or shift to suppress it??? // i know it's compass' fault but i'm still frustrated diff --git a/README.md b/README.md index 38417e4..6dca88c 100644 --- a/README.md +++ b/README.md @@ -27,6 +27,8 @@ A userscript that adds small but useful features for Compass. Features include: open. you can also ctrl+click on them) - Files and folders in Resources is now marked clickable ([Link Hints] can now open them!) +- Links inside lesson plans now open in the parent tab by default instead of + creating a new tab - The context menu that only says "Copy" is now suppressed - The option to remember logins is unchecked by default