import { darken, ColorFmt, lighten } from "./darkmode"; const DEFAULT_OPTS = { alignment: "center", }; export default function (root: HTMLElement, docname: string) { root.querySelectorAll(".mw-editsection").forEach((editLink) => { editLink.parentElement.removeChild(editLink); }); // Darken bgcolor root.querySelectorAll("*[bgcolor]").forEach((td) => { let bgcolor = td.getAttribute("bgcolor"); // Shitty way to detect if it's hex or not // Basically, none of the css colors long 6 letters only use hex letters // THANK FUCKING GOD if (bgcolor.length === 6 && parseInt(bgcolor, 16) !== NaN) { bgcolor = "#" + bgcolor; } td.setAttribute("bgcolor", darken(bgcolor, ColorFmt.HEX).slice(1)); }); root.querySelectorAll("*[style]").forEach((td: HTMLElement) => { if (td.style.backgroundColor != "") { td.style.backgroundColor = darken(td.style.backgroundColor, ColorFmt.RGB); } if (td.style.background != "") { td.style.backgroundColor = darken(td.style.background, ColorFmt.RGB); } }); // Lighten fgcolors root.querySelectorAll("*[color]").forEach((td) => { let color = td.getAttribute("color"); if (color.length === 6 && !isNaN(parseInt(color, 16))) { color = "#" + color; } td.setAttribute("color", lighten(color, ColorFmt.HEX).slice(1)); }); // Remove fixed widths root.querySelectorAll("table[width]").forEach((td) => { td.setAttribute("width", "100%"); }); root.querySelectorAll("table[style]").forEach((td: HTMLTableElement) => { if (td.style.width != "") { td.style.width = "100%"; } }); // Group headers and content so stickies don't overlap root.querySelectorAll("h3,h2").forEach((h3) => { const parent = h3.parentNode; const div = document.createElement("div"); parent.insertBefore(div, h3); while (h3.nextSibling && !h3.nextSibling.nodeName.startsWith("H")) { const sibling = h3.nextSibling; parent.removeChild(sibling); div.appendChild(sibling); } h3.parentNode.removeChild(h3); div.insertBefore(h3, div.firstChild); div.className = "mw-headline-cont"; }); root.querySelectorAll(".mw-headline").forEach((span: HTMLElement) => { // Find nearest container let parent = span.parentElement; while (parent !== null) { if (parent.classList.contains("mw-headline-cont")) { parent.id = span.id; span.id += "-span"; parent.dataset.name = span.innerText; } parent = parent.parentElement; } }); // Tell user that better chemistry is loading const postbody = root; const statusMessage = document.createElement("div"); statusMessage.innerHTML = `
Hang on... Better guides is loading. |
on random parts // Ideally I'd like a
or something on every part, wrapping it completely, but for now let's just kill 'em new Set( Array.from( root.querySelectorAll( "table.wikitable > tbody > tr:not(:first-child) > td:nth-child(2) p" ) ).map((p) => p.parentNode) ).forEach((parent) => { const tmp = parent.cloneNode(); // The cast to Array is necessary because, while childNodes's NodeList technically has a forEach method, it's a live list and operations mess with its lenght in the middle of the loop // Nodes can only have one parent so append removes them from the original NodeList and shifts the following one back into the wrong index Array.from(parent.childNodes).forEach((el: HTMLElement) => { if (el.tagName === "P") { tmp.append(...el.childNodes); } else { tmp.append(el); } }); parent.parentNode.replaceChild(tmp, parent); }); // Enrich "x part" with checkboxes and parts Array.from(root.querySelectorAll("td")) .filter((el) => el.innerText.indexOf(" part") >= 0) .map((el) => [el, el.innerHTML]) .forEach(([el, innerHTML]) => { el.innerHTML = innerHTML.replace( /((\d+)\s+(?:parts?|units?))(.*?(?:<\s*(\/\s*a|br\s*\/?)\s*>|\n|$))/gi, (match, ...m) => `${m[2].replace( /()/gi, '$1' )}` ); }); Array.from(root.querySelectorAll(".bgus_nested_element")).forEach((el) => { el.parentElement.classList.add("bgus_collapsable"); }); // Add event to autofill child checkboxes document .querySelectorAll(".bgus_part_tooltip > .bgus_checkbox") .forEach((box) => { const tooltip = box.parentElement.nextElementSibling; box.addEventListener("click", function () { tooltip .querySelectorAll(".bgus_checkbox") .forEach((el: HTMLInputElement) => (el.checked = this.checked)); }); }); // Add event to collapse subsections root.querySelectorAll(".bgus_nested_element").forEach((twistie) => { twistie.addEventListener("click", function (evt) { twistie.parentElement.classList.toggle("bgus_collapsed"); }); }); // Wrap every recipe with extra metadata root.querySelectorAll(".bgus_part").forEach((el: HTMLElement) => { if ("parts" in el.parentElement.dataset) { el.parentElement.dataset.parts = ( parseInt(el.parentElement.dataset.parts) + parseInt(el.dataset.amount) ).toString(); } else { el.parentElement.dataset.parts = el.dataset.amount; } }); const setPartSize = function (labels, ml) { labels.forEach((el) => { const part = el.parentElement.dataset.amount; const total = el.parentElement.parentElement.dataset.parts; const amt = Math.ceil(ml * (part / total)); el.innerHTML = `${amt} ml`; // Lookup tooltips let next = el.parentElement.nextElementSibling; while (next) { if (next.classList.contains("tooltip")) { let sublabels = []; next.querySelector(".tooltiptext").childNodes.forEach((ch) => { if (ch.classList && ch.classList.contains("bgus_part")) { sublabels.push(ch.querySelector(".bgus_part_label")); } }); setPartSize(sublabels, amt); } if (next.classList.contains("bgus_part")) { // Done searching break; } next = next.nextElementSibling; } }); }; root.classList.add("bchem"); // Init fuzzy search with elements const el = Array.from( root.querySelectorAll( "table.wikitable > tbody > tr:not(:first-child) > th" ) ); const name = el.map((elem) => { let name = ""; elem.childNodes.forEach((t) => { if (t instanceof Text) { name += t.textContent; } }); return name.trim(); }); searchBox( el, name.map((e, i) => ({ id: i, str: e })) ); document.body.addEventListener("keydown", function (ev) { if (ev.shiftKey) { switch (ev.keyCode) { // SHIFT+C = Toggle checkboxes case 67: { root.classList.toggle("bgus_cbox"); root .querySelectorAll(".bgus_checkbox:checked") .forEach((el: HTMLInputElement) => { el.checked = false; }); return; } // SHIFT+B = Set whole size (beaker?) for parts/units case 66: { let size = parseInt(prompt("Write target ml (0 to reset)", "90")); if (isNaN(size) || size <= 0) { // Reset to parts/unit root .querySelectorAll(".bgus_part_label") .forEach((el: HTMLElement) => (el.innerHTML = el.dataset.src)); return; } setPartSize( root.querySelectorAll("td > .bgus_part > .bgus_part_label"), +size ); return; } } } }); } function betterGeneric() { const el = Array.from( root.querySelectorAll("div.mw-headline-cont[id][data-name]") ); const name = el.map((elem: HTMLDivElement) => elem.dataset.name.trim()); // Init fuzzy search with headlines searchBox( el, name.map((e, i) => ({ id: i, str: e })), { alignment: "start" } ); } window.requestAnimationFrame(() => { switch (docname) { case "Guide_to_chemistry": betterChemistry(); break; default: betterGeneric(); break; } // Everything is loaded, remove loading bar statusMessage.innerHTML = ""; }); }