mirror of
https://github.com/GuySandler/CanvasRefined.git
synced 2026-09-24 05:45:10 +02:00
OPTIMIZE OPTIMIZE
This commit is contained in:
parent
d40fc01b42
commit
6820ef1163
113
js/content.js
113
js/content.js
@ -117,6 +117,18 @@ function ensureSubmissionPageButton() {
|
|||||||
return Boolean(content.querySelector("#canvasrefined-assignment-return"));
|
return Boolean(content.querySelector("#canvasrefined-assignment-return"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function isAssignmentPage() {
|
||||||
|
return /^\/courses\/\d+\/assignments(?:\/\d+)?(?:\/|$)/.test(current_page);
|
||||||
|
}
|
||||||
|
|
||||||
|
function removeSequenceFooter() {
|
||||||
|
if (!isAssignmentPage()) return false;
|
||||||
|
const sequenceFooter = document.getElementById("sequence_footer");
|
||||||
|
if (!sequenceFooter) return false;
|
||||||
|
sequenceFooter.remove();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
function watchSequenceFooter() {
|
function watchSequenceFooter() {
|
||||||
if (!isAssignmentPage()) return;
|
if (!isAssignmentPage()) return;
|
||||||
if (removeSequenceFooter()) return;
|
if (removeSequenceFooter()) return;
|
||||||
@ -170,7 +182,8 @@ function watchNewCanvasButton() {
|
|||||||
}
|
}
|
||||||
if (options.hide_new_canvas !== true) return;
|
if (options.hide_new_canvas !== true) return;
|
||||||
removeNewCanvasButton();
|
removeNewCanvasButton();
|
||||||
newCanvasButtonObserver = new MutationObserver(() => {
|
let newCanvasButtonScheduled = false;
|
||||||
|
newCanvasButtonObserver = new MutationObserver((mutationList) => {
|
||||||
if (options.hide_new_canvas !== true) {
|
if (options.hide_new_canvas !== true) {
|
||||||
if (newCanvasButtonObserver) {
|
if (newCanvasButtonObserver) {
|
||||||
newCanvasButtonObserver.disconnect();
|
newCanvasButtonObserver.disconnect();
|
||||||
@ -178,8 +191,19 @@ function watchNewCanvasButton() {
|
|||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
// Only scan when nodes were actually added, and coalesce to one pass per frame.
|
||||||
|
let added = false;
|
||||||
|
for (const mutation of mutationList) {
|
||||||
|
if (mutation.addedNodes && mutation.addedNodes.length) { added = true; break; }
|
||||||
|
}
|
||||||
|
if (!added || newCanvasButtonScheduled) return;
|
||||||
|
newCanvasButtonScheduled = true;
|
||||||
|
requestAnimationFrame(() => {
|
||||||
|
newCanvasButtonScheduled = false;
|
||||||
|
if (options.hide_new_canvas !== true) return;
|
||||||
removeNewCanvasButton();
|
removeNewCanvasButton();
|
||||||
});
|
});
|
||||||
|
});
|
||||||
newCanvasButtonObserver.observe(document.documentElement, { childList: true, subtree: true });
|
newCanvasButtonObserver.observe(document.documentElement, { childList: true, subtree: true });
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -191,35 +215,27 @@ async function getActiveCustomBackground() {
|
|||||||
"customBackgroundScale",
|
"customBackgroundScale",
|
||||||
]);
|
]);
|
||||||
|
|
||||||
console.log("[CanvasRefined] getActiveCustomBackground:", syncOpts);
|
|
||||||
|
|
||||||
if (syncOpts.customBackgroundNasaDaily === true) {
|
if (syncOpts.customBackgroundNasaDaily === true) {
|
||||||
console.log("[CanvasRefined] Using NASA APOD");
|
|
||||||
return await getNasaDailyBackground();
|
return await getNasaDailyBackground();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (syncOpts.customBackgroundDaily === true) {
|
if (syncOpts.customBackgroundDaily === true) {
|
||||||
console.log("[CanvasRefined] Using Wikimedia Featured");
|
|
||||||
const dailyPreset = await getDailyBackgroundPreset();
|
const dailyPreset = await getDailyBackgroundPreset();
|
||||||
if (dailyPreset) {
|
if (dailyPreset) {
|
||||||
console.log("[CanvasRefined] Wikimedia URL:", dailyPreset.url);
|
|
||||||
return {
|
return {
|
||||||
url: dailyPreset.url,
|
url: dailyPreset.url,
|
||||||
scale: dailyPreset.scale,
|
scale: dailyPreset.scale,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
console.log("[CanvasRefined] Wikimedia returned null");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (syncOpts.customBackgroundLink && syncOpts.customBackgroundLink !== "") {
|
if (syncOpts.customBackgroundLink && syncOpts.customBackgroundLink !== "") {
|
||||||
console.log("[CanvasRefined] Using custom link");
|
|
||||||
return {
|
return {
|
||||||
url: syncOpts.customBackgroundLink,
|
url: syncOpts.customBackgroundLink,
|
||||||
scale: syncOpts.customBackgroundScale || 100,
|
scale: syncOpts.customBackgroundScale || 100,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log("[CanvasRefined] No custom background");
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -373,6 +389,7 @@ let timeCheck = null;
|
|||||||
let reminderCheck = null;
|
let reminderCheck = null;
|
||||||
let betterSidebarLoading = false;
|
let betterSidebarLoading = false;
|
||||||
let dashboardReadyTimer = null;
|
let dashboardReadyTimer = null;
|
||||||
|
let sidebarReadyTimer = null;
|
||||||
let sidebarBadgeObserver = null;
|
let sidebarBadgeObserver = null;
|
||||||
let sidebarBadgeSyncTimer = null;
|
let sidebarBadgeSyncTimer = null;
|
||||||
let sidebarBadgeWatchRetries = 0;
|
let sidebarBadgeWatchRetries = 0;
|
||||||
@ -526,9 +543,17 @@ function startExtension() {
|
|||||||
if (footer) footer.remove();
|
if (footer) footer.remove();
|
||||||
};
|
};
|
||||||
removeFooter();
|
removeFooter();
|
||||||
|
let footerScheduled = false;
|
||||||
const footerObserver = new MutationObserver(() => {
|
const footerObserver = new MutationObserver(() => {
|
||||||
|
// Canvas mutates the DOM constantly; only check for the footer at most once
|
||||||
|
// per animation frame instead of running a querySelector on every mutation.
|
||||||
|
if (footerScheduled) return;
|
||||||
|
footerScheduled = true;
|
||||||
|
requestAnimationFrame(() => {
|
||||||
|
footerScheduled = false;
|
||||||
removeFooter();
|
removeFooter();
|
||||||
});
|
});
|
||||||
|
});
|
||||||
footerObserver.observe(document.documentElement, { childList: true, subtree: true });
|
footerObserver.observe(document.documentElement, { childList: true, subtree: true });
|
||||||
|
|
||||||
toggleDarkMode();
|
toggleDarkMode();
|
||||||
@ -578,7 +603,6 @@ function applyOptionsChanges(changes) {
|
|||||||
// so any changes made in the menu no longer require a refresh to apply
|
// so any changes made in the menu no longer require a refresh to apply
|
||||||
|
|
||||||
Object.keys(changes).forEach(key => {
|
Object.keys(changes).forEach(key => {
|
||||||
console.log(key + " changed");
|
|
||||||
switch (key) {
|
switch (key) {
|
||||||
case "dark_mode":
|
case "dark_mode":
|
||||||
case "dark_preset":
|
case "dark_preset":
|
||||||
@ -793,7 +817,6 @@ async function applyCustomBackground() {
|
|||||||
style.id = "canvasrefined-background";
|
style.id = "canvasrefined-background";
|
||||||
|
|
||||||
const activeBackground = await getActiveCustomBackground();
|
const activeBackground = await getActiveCustomBackground();
|
||||||
console.log("[CanvasRefined] activeBackground:", activeBackground);
|
|
||||||
if (!activeBackground) {
|
if (!activeBackground) {
|
||||||
if (style.isConnected) style.remove();
|
if (style.isConnected) style.remove();
|
||||||
return;
|
return;
|
||||||
@ -802,7 +825,6 @@ async function applyCustomBackground() {
|
|||||||
const backgroundScale = Number(activeBackground.scale) || 100;
|
const backgroundScale = Number(activeBackground.scale) || 100;
|
||||||
const backgroundUrl = JSON.stringify(activeBackground.url);
|
const backgroundUrl = JSON.stringify(activeBackground.url);
|
||||||
const fitToScreen = options.fitImageToScreen === true;
|
const fitToScreen = options.fitImageToScreen === true;
|
||||||
console.log("[CanvasRefined] Applying background:", activeBackground.url, "fitToScreen:", fitToScreen);
|
|
||||||
style.textContent = `
|
style.textContent = `
|
||||||
#wrapper {
|
#wrapper {
|
||||||
background-image: url(${backgroundUrl}) !important;
|
background-image: url(${backgroundUrl}) !important;
|
||||||
@ -1010,16 +1032,19 @@ function resetTimer() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function checkDashboardReady() {
|
function checkDashboardReady() {
|
||||||
|
const isDashboard = () => current_page == "/" || current_page == "" || /^\/courses\/(\d+)(?:\/|$)/.test(current_page);
|
||||||
|
|
||||||
const callback = (mutationList) => {
|
const callback = (mutationList) => {
|
||||||
|
// Ignore attribute-only mutations; only structural (childList) changes matter here.
|
||||||
|
let hasChildList = false;
|
||||||
for (const mutation of mutationList) {
|
for (const mutation of mutationList) {
|
||||||
if (mutation.type !== "childList") continue;
|
if (mutation.type === "childList") { hasChildList = true; break; }
|
||||||
if (current_page == "/" || current_page == "" || current_page.match(/^\/courses\/(\d+)(?:\/|$)/)) {
|
|
||||||
if (dashboardReadyTimer) continue;
|
|
||||||
|
|
||||||
const dashboardCards = document.querySelector("#DashboardCard_Container");
|
|
||||||
if (dashboardCards) {
|
|
||||||
}
|
}
|
||||||
|
if (!hasChildList) return;
|
||||||
|
|
||||||
|
if (isDashboard()) {
|
||||||
|
// Debounce: a single setup pass per burst of mutations.
|
||||||
|
if (dashboardReadyTimer) return;
|
||||||
dashboardReadyTimer = setTimeout(() => {
|
dashboardReadyTimer = setTimeout(() => {
|
||||||
dashboardReadyTimer = null;
|
dashboardReadyTimer = null;
|
||||||
|
|
||||||
@ -1047,17 +1072,19 @@ function checkDashboardReady() {
|
|||||||
ensureBetterSidebar();
|
ensureBetterSidebar();
|
||||||
}
|
}
|
||||||
}, 0);
|
}, 0);
|
||||||
} else {
|
} else if (options.better_sidebar) {
|
||||||
console.log("I am outside", current_page);
|
// Throttle sidebar setup checks on non-dashboard (course) pages instead
|
||||||
if (options.better_sidebar) {
|
// of calling ensureBetterSidebar() on every mutation burst.
|
||||||
|
if (sidebarReadyTimer) return;
|
||||||
|
sidebarReadyTimer = setTimeout(() => {
|
||||||
|
sidebarReadyTimer = null;
|
||||||
ensureBetterSidebar();
|
ensureBetterSidebar();
|
||||||
}
|
}, 100);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const observer = new MutationObserver(callback);
|
const observer = new MutationObserver(callback);
|
||||||
observer.observe(document.querySelector('html'), { childList: true, subtree: true });
|
observer.observe(document.documentElement, { childList: true, subtree: true });
|
||||||
}
|
}
|
||||||
|
|
||||||
function recieveMessage(request, sender, sendResponse) {
|
function recieveMessage(request, sender, sendResponse) {
|
||||||
@ -3759,18 +3786,17 @@ let darkStyleInserted = false;
|
|||||||
function toggleDarkMode() {
|
function toggleDarkMode() {
|
||||||
const css = generateDarkModeCSS();
|
const css = generateDarkModeCSS();
|
||||||
const darkOn = options.dark_mode === true || options.device_dark === true;
|
const darkOn = options.dark_mode === true || options.device_dark === true;
|
||||||
if (!darkStyleInserted) {
|
// Reuse the existing #darkcss style if present (never create a duplicate), so a
|
||||||
let style = document.createElement('style');
|
// document_start dark-mode bootstrap and later updates stay on one element.
|
||||||
style.textContent = css;
|
let style = document.querySelector("#darkcss");
|
||||||
document.documentElement.append(style);
|
if (!style) {
|
||||||
|
style = document.createElement('style');
|
||||||
style.id = 'darkcss';
|
style.id = 'darkcss';
|
||||||
|
document.documentElement.append(style);
|
||||||
|
}
|
||||||
|
style.textContent = css;
|
||||||
style.className = darkOn ? "canvasrefined-darkmode-enabled" : "";
|
style.className = darkOn ? "canvasrefined-darkmode-enabled" : "";
|
||||||
darkStyleInserted = true;
|
darkStyleInserted = true;
|
||||||
} else {
|
|
||||||
let style = document.querySelector("#darkcss");
|
|
||||||
style.textContent = css;
|
|
||||||
style.className = darkOn ? "canvasrefined-darkmode-enabled" : "";
|
|
||||||
}
|
|
||||||
runiframeChecker();
|
runiframeChecker();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3801,6 +3827,9 @@ function autoDarkModeCheck() {
|
|||||||
status = currentHour > startHour && currentHour < endHour;
|
status = currentHour > startHour && currentHour < endHour;
|
||||||
}
|
}
|
||||||
if (options.auto_dark === true) {
|
if (options.auto_dark === true) {
|
||||||
|
// Skip the write (and the storage.onChanged cascade it would trigger) when the
|
||||||
|
// computed state already matches dark_mode, so the 60s timer is a cheap no-op.
|
||||||
|
if (status === options.dark_mode) return;
|
||||||
options.dark_mode = status;
|
options.dark_mode = status;
|
||||||
chrome.storage.sync.set({ "dark_mode": status }, toggleDarkMode);
|
chrome.storage.sync.set({ "dark_mode": status }, toggleDarkMode);
|
||||||
}
|
}
|
||||||
@ -3834,19 +3863,27 @@ function runiframeChecker() {
|
|||||||
|
|
||||||
const callback = (mutationList) => {
|
const callback = (mutationList) => {
|
||||||
for (const mutation of mutationList) {
|
for (const mutation of mutationList) {
|
||||||
if (mutation.type === 'childList' && mutation.addedNodes.length > 0 && mutation.addedNodes[0].nodeName == "IFRAME") {
|
if (mutation.type !== 'childList' || !mutation.addedNodes.length) continue;
|
||||||
const frame = mutation.addedNodes[0];
|
for (const node of mutation.addedNodes) {
|
||||||
|
if (node.nodeName !== 'IFRAME') continue;
|
||||||
|
// Cross-origin iframes expose no contentDocument; access it safely so we
|
||||||
|
// don't throw a TypeError into the console on every added iframe.
|
||||||
|
let doc;
|
||||||
|
try { doc = node.contentDocument; } catch (_) { continue; }
|
||||||
|
if (!doc || !doc.documentElement || !doc.body) continue;
|
||||||
|
try {
|
||||||
const new_style_element = document.createElement("style");
|
const new_style_element = document.createElement("style");
|
||||||
new_style_element.textContent = generateDarkModeCSS();
|
new_style_element.textContent = generateDarkModeCSS();
|
||||||
new_style_element.id = "darkcss";
|
new_style_element.id = "darkcss";
|
||||||
frame.contentDocument.body.classList.add("canvasrefined--darkmode--enabled");
|
doc.body.classList.add("canvasrefined--darkmode--enabled");
|
||||||
frame.contentDocument.documentElement.prepend(new_style_element);
|
doc.documentElement.prepend(new_style_element);
|
||||||
|
} catch (_) { /* cross-origin or detached frame: ignore */ }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
iframeObserver = new MutationObserver(callback);
|
iframeObserver = new MutationObserver(callback);
|
||||||
iframeObserver.observe(document.querySelector('html'), { childList: true, subtree: true });
|
iframeObserver.observe(document.documentElement, { childList: true, subtree: true });
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|||||||
53638
lighthouseReport.json
Normal file
53638
lighthouseReport.json
Normal file
File diff suppressed because one or more lines are too long
Loading…
Reference in New Issue
Block a user