Files
lildra/lildra.js
T

196 lines
5.7 KiB
JavaScript

(() => {
"use strict";
const ROOT_CLASS = "lildra-active";
const STYLE_ID = "lildra-style";
const TITLE_BAR_ID = "lildra-title-bar";
const TITLE_ID = "lildra-title";
const VERSION_LABEL_ID = "lildra-version-label";
const STATE_KEY = "__lildraState";
const existingState = window[STATE_KEY];
if (existingState) {
existingState.remove();
return;
}
function isSupportedRoute() {
return location.protocol === "https:" &&
/^\/courses\/[^/]+\/(?:pages|wiki)\/[^/]+\/?$/.test(location.pathname);
}
function isCanvasContentPage() {
return isSupportedRoute() && Boolean(
document.querySelector("#application #wrapper") &&
document.querySelector("#wiki_page_show")
);
}
if (!isCanvasContentPage()) return;
function getPageTitle() {
const selectors = [
"#breadcrumbs [aria-current='page'] .ellipsible",
"#breadcrumbs [aria-current='page']",
"#wiki_page_show .page-title",
"#content h1.page-title",
"#mobile-header .mobile-header-title div:last-child"
];
for (const selector of selectors) {
const title = document.querySelector(selector)?.textContent?.trim();
if (title) return title;
}
const browserTitle = document.title.trim();
const separator = browserTitle.lastIndexOf(":");
return separator > 0 ? browserTitle.slice(0, separator).trim() : browserTitle;
}
const style = document.createElement("style");
style.id = STYLE_ID;
style.textContent = `
html.${ROOT_CLASS} #header,
html.${ROOT_CLASS} #mobile-header,
html.${ROOT_CLASS} #mobileContextNavContainer,
html.${ROOT_CLASS} .ic-app-nav-toggle-and-crumbs,
html.${ROOT_CLASS} #left-side {
display: none !important;
}
html.${ROOT_CLASS} #wrapper,
html.${ROOT_CLASS} body.primary-nav-expanded #wrapper,
html.${ROOT_CLASS} body.course-menu-expanded #wrapper,
html.${ROOT_CLASS} body.with-left-side #wrapper {
margin-left: 0 !important;
}
html.${ROOT_CLASS} #wrapper {
box-sizing: border-box !important;
padding-top: 42px !important;
}
html.${ROOT_CLASS} #main {
box-sizing: border-box !important;
width: calc(100% - 32px) !important;
max-width: 1100px !important;
margin-right: auto !important;
margin-left: auto !important;
}
html.${ROOT_CLASS} #${TITLE_BAR_ID} {
position: fixed !important;
top: 0 !important;
right: 0 !important;
left: 0 !important;
z-index: 2147483646 !important;
box-sizing: border-box !important;
display: flex !important;
align-items: center !important;
justify-content: center !important;
height: 42px !important;
padding: 0 18px !important;
background: #fff !important;
border-bottom: 1px solid rgb(0 0 0 / 14%) !important;
box-shadow: 0 1px 3px rgb(0 0 0 / 7%) !important;
color: #1d2733 !important;
font: 700 16px/1 Lato, "Helvetica Neue", Helvetica, Arial, sans-serif !important;
}
html.${ROOT_CLASS} #${TITLE_ID} {
min-width: 0 !important;
overflow: hidden !important;
text-align: center !important;
text-overflow: ellipsis !important;
white-space: nowrap !important;
}
html.${ROOT_CLASS} #${VERSION_LABEL_ID} {
position: fixed !important;
right: 10px !important;
bottom: 8px !important;
z-index: 2147483646 !important;
padding: 3px 6px !important;
border-radius: 4px !important;
background: rgb(255 255 255 / 88%) !important;
box-shadow: 0 1px 3px rgb(0 0 0 / 10%) !important;
color: #5f259f !important;
font: 700 11px/1 Lato, "Helvetica Neue", Helvetica, Arial, sans-serif !important;
pointer-events: none !important;
}
@media (max-width: 700px) {
html.${ROOT_CLASS} #wrapper {
padding-top: 38px !important;
}
html.${ROOT_CLASS} #main {
width: calc(100% - 20px) !important;
}
html.${ROOT_CLASS} #${TITLE_BAR_ID} {
height: 38px !important;
padding: 0 10px !important;
font-size: 14px !important;
}
}
`;
const titleBar = document.createElement("div");
titleBar.id = TITLE_BAR_ID;
titleBar.setAttribute("aria-hidden", "true");
const title = document.createElement("div");
title.id = TITLE_ID;
title.textContent = getPageTitle();
titleBar.append(title);
const versionLabel = document.createElement("div");
versionLabel.id = VERSION_LABEL_ID;
versionLabel.setAttribute("aria-hidden", "true");
versionLabel.textContent = `Lildra v${chrome.runtime.getManifest().version}`;
let updatePending = false;
let updateFrame = 0;
const observer = new MutationObserver(() => {
if (updatePending) return;
updatePending = true;
updateFrame = requestAnimationFrame(() => {
updateFrame = 0;
updatePending = false;
if (!isSupportedRoute()) {
remove();
return;
}
const nextTitle = getPageTitle();
if (nextTitle && title.textContent !== nextTitle) title.textContent = nextTitle;
});
});
function remove() {
observer.disconnect();
if (updateFrame) cancelAnimationFrame(updateFrame);
document.documentElement.classList.remove(ROOT_CLASS);
style.remove();
titleBar.remove();
versionLabel.remove();
delete window[STATE_KEY];
}
window[STATE_KEY] = { remove };
document.documentElement.append(style);
document.body.append(titleBar, versionLabel);
document.documentElement.classList.add(ROOT_CLASS);
observer.observe(document.querySelector("#application"), {
childList: true,
subtree: true,
characterData: true
});
observer.observe(document.querySelector("head > title"), {
childList: true,
characterData: true
});
})();