// ==UserScript== // @name Compass QoL Enhancer // @namespace blankie-scripts // @match http*://*.compass.education/* // @version 1.0.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 // @run-at document-end // ==/UserScript== "use strict"; 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}); function handleNewNode(node) { if (node.nodeType !== 1) { return; } if (node.localName === "div" && node.classList.contains("ext-cal-evt")) { handleNewCalendarEvent(node); } else if (node.classList.contains("ext-cal-hd-ct")) { // learning tasks need to be handled seperately for some reason for (let element of node.querySelectorAll("div.ext-cal-evt")) { handleNewCalendarEvent(element); } } else if (window.location.pathname === "/Organise/Activities/Activity.aspx" && node.classList.contains("activityPage__tabPanel")) { for (let tab of node.querySelectorAll(".x-tab")) { tab.addEventListener("click", function() { handleActivityTabClick(tab); }, {passive: true}); } } } document.body.addEventListener("click", function(event) { // Add the ability to close windows by clicking on the background // 0px check to make sure that the mask is masking the entire background and not just a small subsection (e.g. a calendar) if (event.target.classList.contains("x-mask") && event.target.style.left === "0px") { 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"); for (let attr of element.attributes) { a.setAttribute(attr.name, attr.value); } // fix learning tasks shrinking for some reason a.style.display = "block"; a.replaceChildren(...element.childNodes); let preventCompassHandler = false; if (a.classList.contains("activity-type-1")) { // Add a link for activities/"standard classes" // missing targetUserId parameter, shouldn't matter too much if you're a student let eventId = / calendar-event-(\d+) /.exec(a.className)[1]; a.href = `/Organise/Activities/Activity.aspx#session/${eventId}`; preventCompassHandler = true; } else if (a.classList.contains("activity-type-10")) { // Add a link for learning tasks // missing userId parameter, shouldn't matter too much if you're a student a.href = "/Records/User.aspx#learningTasks"; preventCompassHandler = true; } // prevent ctrl-clicking from changing the current tab // it seems like the link thing actually effectively killed the default handler anyway if (preventCompassHandler) { a.addEventListener("click", function(event) { event.stopImmediatePropagation(); }, {passive: true}); } element.replaceWith(a); } function handleActivityTabClick(element) { // Automatically add or remove &openLearningTaskTab when a tab is clicked let matches = /^(#(?:session|activity)\/\d+)(?:&openLearningTaskTab)?$/.exec(window.location.hash); if (!matches) { return; } let newHash = matches[1]; if (element.classList.contains("sel-learning-tasks-tab")) { newHash += "&openLearningTaskTab"; } if (newHash !== window.location.hash) { history.pushState("", "", newHash); } } // 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 // https://stackoverflow.com/a/10815581 let originalOn = unsafeWindow.CKEDITOR.dom.domObject.prototype.on; unsafeWindow.CKEDITOR.dom.domObject.prototype.on = function(type, listener) { if (type !== "contextmenu") { return originalOn.apply(this, arguments); } };