Add linting and fix lint errors
Some checks failed
continuous-integration/drone/push Build is failing

This commit is contained in:
Hamcha 2020-06-17 15:16:54 +02:00
parent 4978851016
commit 42ed7591b6
Signed by: hamcha
GPG key ID: 41467804B19A3315
11 changed files with 1214 additions and 150 deletions

142
.drone.yml Normal file
View file

@ -0,0 +1,142 @@
kind: pipeline
name: default
steps:
- name: restore-cache
image: drillster/drone-volume-cache
volumes:
- name: cache
path: /cache
settings:
restore: true
mount:
- ./node_modules
- name: dependencies
image: node
failure: ignore
commands:
- yarn
depends_on:
- restore-cache
- name: lint
image: node
commands:
- yarn lint
depends_on:
- dependencies
- name: build_versioned
image: node
commands:
- yarn build
when:
event:
- push
branch:
exclude:
- master
depends_on:
- dependencies
- name: build_pr
image: node
commands:
- yarn build
when:
event:
- pull_request
depends_on:
- dependencies
- name: build_master
image: node
commands:
- yarn build
environment:
SUBPATH: /latest
when:
event:
- push
branch:
- master
depends_on:
- dependencies
- name: upload_build_versioned
image: plugins/s3
settings:
bucket: tghandbook
access_key:
from_secret: minio_access
secret_key:
from_secret: minio_secret
source: dist/**/*
target: /${DRONE_COMMIT_SHA:0:8}/
path_style: true
endpoint: https://artifacts.fromouter.space
when:
event:
- push
branch:
exclude:
- master
depends_on:
- build_versioned
- name: upload_build_pr
image: plugins/s3
settings:
bucket: tghandbook
access_key:
from_secret: minio_access
secret_key:
from_secret: minio_secret
source: dist/**/*
target: /pr-${DRONE_PULL_REQUEST}/
path_style: true
endpoint: https://artifacts.fromouter.space
when:
event:
- pull_request
depends_on:
- build_pr
- name: upload_build_master
image: plugins/s3
settings:
bucket: tghandbook
access_key:
from_secret: minio_access
secret_key:
from_secret: minio_secret
source: dist/**/*
target: /latest/
path_style: true
endpoint: https://artifacts.fromouter.space
when:
event:
- push
branch:
- master
depends_on:
- build_master
- name: rebuild-cache
image: drillster/drone-volume-cache
failure: ignore
volumes:
- name: cache
path: /cache
settings:
rebuild: true
mount:
- ./node_modules
depends_on:
- dependencies
volumes:
- name: cache
host:
path: /opt/gitea/drone-cache/hamcha/tghandbook

29
.eslintrc.js Normal file
View file

@ -0,0 +1,29 @@
module.exports = {
env: {
browser: true,
es2020: true,
},
extends: [
"airbnb-base",
"plugin:@typescript-eslint/recommended",
"plugin:prettier/recommended",
],
parser: "@typescript-eslint/parser",
plugins: ["@typescript-eslint", "prettier"],
rules: {
"prettier/prettier": "error",
"one-var": "off", // WHO CARES?????
"no-use-before-define": "off", // YOU ARE WRONG
"import/extensions": "off",
"import/no-unresolved": "off",
"no-param-reassign": "off",
"no-alert": "off",
"no-console": "off",
"@typescript-eslint/ban-ts-comment": [
"error",
{
"ts-expect-error": "allow-with-description",
},
],
},
};

4
.prettierrc Normal file
View file

@ -0,0 +1,4 @@
{
"singleQuote": false,
"endOfLine": "auto"
}

View file

@ -1,5 +1,7 @@
# /tg/ handbook # /tg/ handbook
[![Build Status](https://drone.zyg.ovh/api/badges/Hamcha/tghandbook/status.svg)](https://drone.zyg.ovh/Hamcha/tghandbook)
## Building ## Building
`yarn build` `yarn build`

View file

@ -3,7 +3,25 @@
<head> <head>
<meta charset="UTF-8" /> <meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="stylesheet" href="assets/fonts/iosevka/iosevka-aile.css" /> <link
rel="preload"
href="assets/fonts/iosevka/iosevka-aile.css"
as="style"
/>
<link
rel="preload"
href="assets/fonts/iosevka/woff2/iosevka-aile-regular.woff2"
as="font"
/>
<link rel="preload" href="style/main.scss" as="style" />
<link rel="preload" href="style/bgus.scss" as="style" />
<link rel="preload" href="lib/index.ts" as="script" />
<link
rel="stylesheet"
href="assets/fonts/iosevka/iosevka-aile.css"
media="async"
onload="this.media='all'"
/>
<link rel="stylesheet" href="style/main.scss" /> <link rel="stylesheet" href="style/main.scss" />
<link rel="stylesheet" href="style/bgus.scss" /> <link rel="stylesheet" href="style/bgus.scss" />
<title>/tg/ Handbook</title> <title>/tg/ Handbook</title>
@ -16,6 +34,6 @@
<nav id="tab-list"></nav> <nav id="tab-list"></nav>
<section id="tabs"></section> <section id="tabs"></section>
</main> </main>
<script src="lib/index.ts"></script> <script src="lib/index.ts" async></script>
</body> </body>
</html> </html>

View file

@ -1,3 +1,4 @@
// @ts-expect-error: Asset imports are handled by parcel
import speen from "~/assets/images/speen.svg"; import speen from "~/assets/images/speen.svg";
import { getPageHTML } from "./wiki"; import { getPageHTML } from "./wiki";
import userscript from "./userscript"; import userscript from "./userscript";
@ -19,7 +20,7 @@ function initWaiting(elem: HTMLElement) {
async function loadPage(page: string, elem: HTMLElement) { async function loadPage(page: string, elem: HTMLElement) {
// Fetch page content // Fetch page content
console.log(page + ": fetching"); console.log(`${page}: fetching`);
let html = await getPageHTML(page); let html = await getPageHTML(page);
// Convert relative links to absolute // Convert relative links to absolute
@ -28,9 +29,9 @@ async function loadPage(page: string, elem: HTMLElement) {
// Set as HTML content and run HTML manipulations on it // Set as HTML content and run HTML manipulations on it
requestAnimationFrame(() => { requestAnimationFrame(() => {
elem.innerHTML = html; elem.innerHTML = html;
console.log(page + ": processing"); console.log(`${page}: processing`);
userscript(elem, page); userscript(elem, page);
console.log(page + ": userscript applied"); console.log(`${page}: userscript applied`);
elem.classList.remove("waiting"); elem.classList.remove("waiting");
}); });
} }
@ -39,7 +40,9 @@ type TabElements = { tabListItem: HTMLElement; tabContentItem: HTMLElement };
export default class TabManager { export default class TabManager {
tabListContainer: HTMLElement; tabListContainer: HTMLElement;
tabContentContainer: HTMLElement; tabContentContainer: HTMLElement;
tabs: Record<string, TabElements> = {}; tabs: Record<string, TabElements> = {};
constructor(tablist: HTMLElement, tabcontent: HTMLElement) { constructor(tablist: HTMLElement, tabcontent: HTMLElement) {
@ -47,7 +50,7 @@ export default class TabManager {
this.tabContentContainer = tabcontent; this.tabContentContainer = tabcontent;
} }
openTab(page: string, setActive: boolean) { openTab(page: string, setActive: boolean): void {
// Create tab list item // Create tab list item
const tabListItem = document.createElement("div"); const tabListItem = document.createElement("div");
tabListItem.className = "tab"; tabListItem.className = "tab";
@ -80,7 +83,7 @@ export default class TabManager {
} }
} }
setActive(page: string) { setActive(page: string): void {
// Make sure tab exists (why wouldn't it?!) // Make sure tab exists (why wouldn't it?!)
if (!(page in this.tabs)) { if (!(page in this.tabs)) {
throw new Error("tab not found"); throw new Error("tab not found");

View file

@ -16,48 +16,61 @@ export enum ColorFmt {
} }
function hsvToRgb({ h, s, v }: ColorHSV): ColorRGB { function hsvToRgb({ h, s, v }: ColorHSV): ColorRGB {
var r, g, b; let r, g, b;
var i = Math.floor(h * 6); const i = Math.floor(h * 6);
var f = h * 6 - i; const f = h * 6 - i;
var p = v * (1 - s); const p = v * (1 - s);
var q = v * (1 - f * s); const q = v * (1 - f * s);
var t = v * (1 - (1 - f) * s); const t = v * (1 - (1 - f) * s);
switch (i % 6) { switch (i % 6) {
case 0: case 0:
(r = v), (g = t), (b = p); r = v;
g = t;
b = p;
break; break;
case 1: case 1:
(r = q), (g = v), (b = p); r = q;
g = v;
b = p;
break; break;
case 2: case 2:
(r = p), (g = v), (b = t); r = p;
g = v;
b = t;
break; break;
case 3: case 3:
(r = p), (g = q), (b = v); r = p;
g = q;
b = v;
break; break;
case 4: case 4:
(r = t), (g = p), (b = v); r = t;
g = p;
b = v;
break; break;
case 5: case 5:
(r = v), (g = p), (b = q); r = v;
g = p;
b = q;
break; break;
default:
throw new Error("unreacheable");
} }
return { r, g, b }; return { r, g, b };
} }
function rgbToHsv({ r, g, b }: ColorRGB): ColorHSV { function rgbToHsv({ r, g, b }: ColorRGB): ColorHSV {
var max = Math.max(r, g, b), const max = Math.max(r, g, b);
min = Math.min(r, g, b); const min = Math.min(r, g, b);
var h, const v = max;
s,
v = max;
var d = max - min; const d = max - min;
s = max == 0 ? 0 : d / max; const s = max === 0 ? 0 : d / max;
if (max == min) { let h;
if (max === min) {
h = 0; // achromatic h = 0; // achromatic
} else { } else {
switch (max) { switch (max) {
@ -70,6 +83,8 @@ function rgbToHsv({ r, g, b }: ColorRGB): ColorHSV {
case b: case b:
h = (r - g) / d + 4; h = (r - g) / d + 4;
break; break;
default:
throw new Error("unreacheable");
} }
h /= 6; h /= 6;
} }
@ -80,13 +95,13 @@ function rgbToHsv({ r, g, b }: ColorRGB): ColorHSV {
// Hacky way to get RGB values FOR SURE! // Hacky way to get RGB values FOR SURE!
function nameToRGB(name: string): ColorRGB { function nameToRGB(name: string): ColorRGB {
// Create fake div // Create fake div
let fakeDiv = document.createElement("div"); const fakeDiv = document.createElement("div");
fakeDiv.style.color = name; fakeDiv.style.color = name;
document.body.appendChild(fakeDiv); document.body.appendChild(fakeDiv);
// Get color of div // Get color of div
let cs = window.getComputedStyle(fakeDiv), const cs = window.getComputedStyle(fakeDiv);
pv = cs.getPropertyValue("color"); const pv = cs.getPropertyValue("color");
// Remove div after obtaining desired color value // Remove div after obtaining desired color value
document.body.removeChild(fakeDiv); document.body.removeChild(fakeDiv);
@ -98,9 +113,9 @@ function nameToRGB(name: string): ColorRGB {
// https://stackoverflow.com/questions/11068240/what-is-the-most-efficient-way-to-parse-a-css-color-in-javascript // https://stackoverflow.com/questions/11068240/what-is-the-most-efficient-way-to-parse-a-css-color-in-javascript
function parseColor(input: string): ColorRGB { function parseColor(input: string): ColorRGB {
// Hex format // Hex format
if (input.substr(0, 1) == "#") { if (input.substr(0, 1) === "#") {
var collen = (input.length - 1) / 3; const collen = (input.length - 1) / 3;
var fact = [17, 1, 0.062272][collen - 1]; const fact = [17, 1, 0.062272][collen - 1];
return { return {
r: Math.round(parseInt(input.substr(1, collen), 16) * fact) / 256, r: Math.round(parseInt(input.substr(1, collen), 16) * fact) / 256,
g: g:
@ -132,11 +147,13 @@ function serializeColor(col: ColorRGB, format: ColorFmt): string {
case ColorFmt.RGB: case ColorFmt.RGB:
return `rgb(${r}, ${g}, ${b})`; return `rgb(${r}, ${g}, ${b})`;
case ColorFmt.HEX: { case ColorFmt.HEX: {
const rhex = ("00" + r.toString(16)).slice(-2); const rhex = `00${r.toString(16)}`.slice(-2);
const ghex = ("00" + g.toString(16)).slice(-2); const ghex = `00${g.toString(16)}`.slice(-2);
const bhex = ("00" + b.toString(16)).slice(-2); const bhex = `00${b.toString(16)}`.slice(-2);
return "#" + rhex + ghex + bhex; return `#${rhex}${ghex}${bhex}`;
} }
default:
return "#000";
} }
} }
@ -147,14 +164,12 @@ export function darken(color: string, format: ColorFmt): string {
hsl.h = 0.6; hsl.h = 0.6;
hsl.s = 0.5; hsl.s = 0.5;
hsl.v = Math.max(0.2, 1 - hsl.v); hsl.v = Math.max(0.2, 1 - hsl.v);
} else { } else if (hsl.v > 0.5) {
if (hsl.v > 0.5) {
hsl.v = 0.4; hsl.v = 0.4;
if (hsl.s > 0.2) { if (hsl.s > 0.2) {
hsl.s = Math.min(1, hsl.s + 0.2); hsl.s = Math.min(1, hsl.s + 0.2);
} }
} }
}
const out = hsvToRgb(hsl); const out = hsvToRgb(hsl);
return serializeColor(out, format); return serializeColor(out, format);
} }

View file

@ -4,7 +4,7 @@ const DEFAULT_OPTS = {
alignment: "center", alignment: "center",
}; };
export default function (root: HTMLElement, docname: string) { export default function userscript(root: HTMLElement, docname: string): void {
root.querySelectorAll(".mw-editsection").forEach((editLink) => { root.querySelectorAll(".mw-editsection").forEach((editLink) => {
editLink.parentElement.removeChild(editLink); editLink.parentElement.removeChild(editLink);
}); });
@ -15,16 +15,16 @@ export default function (root: HTMLElement, docname: string) {
// Shitty way to detect if it's hex or not // Shitty way to detect if it's hex or not
// Basically, none of the css colors long 6 letters only use hex letters // Basically, none of the css colors long 6 letters only use hex letters
// THANK FUCKING GOD // THANK FUCKING GOD
if (bgcolor.length === 6 && parseInt(bgcolor, 16) !== NaN) { if (bgcolor.length === 6 && Number.isNaN(parseInt(bgcolor, 16))) {
bgcolor = "#" + bgcolor; bgcolor = `#${bgcolor}`;
} }
td.setAttribute("bgcolor", darken(bgcolor, ColorFmt.HEX).slice(1)); td.setAttribute("bgcolor", darken(bgcolor, ColorFmt.HEX).slice(1));
}); });
root.querySelectorAll("*[style]").forEach((td: HTMLElement) => { root.querySelectorAll("*[style]").forEach((td: HTMLElement) => {
if (td.style.backgroundColor != "") { if (td.style.backgroundColor !== "") {
td.style.backgroundColor = darken(td.style.backgroundColor, ColorFmt.RGB); td.style.backgroundColor = darken(td.style.backgroundColor, ColorFmt.RGB);
} }
if (td.style.background != "") { if (td.style.background !== "") {
td.style.backgroundColor = darken(td.style.background, ColorFmt.RGB); td.style.backgroundColor = darken(td.style.background, ColorFmt.RGB);
} }
}); });
@ -32,8 +32,8 @@ export default function (root: HTMLElement, docname: string) {
// Lighten fgcolors // Lighten fgcolors
root.querySelectorAll("*[color]").forEach((td) => { root.querySelectorAll("*[color]").forEach((td) => {
let color = td.getAttribute("color"); let color = td.getAttribute("color");
if (color.length === 6 && !isNaN(parseInt(color, 16))) { if (color.length === 6 && !Number.isNaN(parseInt(color, 16))) {
color = "#" + color; color = `#${color}`;
} }
td.setAttribute("color", lighten(color, ColorFmt.HEX).slice(1)); td.setAttribute("color", lighten(color, ColorFmt.HEX).slice(1));
}); });
@ -43,7 +43,7 @@ export default function (root: HTMLElement, docname: string) {
td.setAttribute("width", "100%"); td.setAttribute("width", "100%");
}); });
root.querySelectorAll("table[style]").forEach((td: HTMLTableElement) => { root.querySelectorAll("table[style]").forEach((td: HTMLTableElement) => {
if (td.style.width != "") { if (td.style.width !== "") {
td.style.width = "100%"; td.style.width = "100%";
} }
}); });
@ -88,14 +88,14 @@ export default function (root: HTMLElement, docname: string) {
postbody.insertBefore(statusMessage, postbody.firstChild); postbody.insertBefore(statusMessage, postbody.firstChild);
// TODO Refactor this mess // TODO Refactor this mess
function searchBox(el, search_candidate, options = DEFAULT_OPTS) { function searchBox(el, searchCandidate, options = DEFAULT_OPTS) {
// Fuzzy search box // Fuzzy search box
const resultList = document.createElement("ul"); const resultList = document.createElement("ul");
const searchBox = document.createElement("div"); const searchBoxElem = document.createElement("div");
let selected_result = null; let selectedResult = null;
let results = []; let results = [];
const jumpTo = function (id) { const jumpTo = (id) => {
el[id].scrollIntoView({ el[id].scrollIntoView({
block: options.alignment, block: options.alignment,
inline: "nearest", inline: "nearest",
@ -103,15 +103,15 @@ export default function (root: HTMLElement, docname: string) {
}); });
document document
.querySelectorAll("table.wikitable .bgus_fz_selected") .querySelectorAll("table.wikitable .bgus_fz_selected")
.forEach((el) => el.classList.remove("bgus_fz_selected")); .forEach((sel) => sel.classList.remove("bgus_fz_selected"));
el[id].parentElement.classList.add("bgus_fz_selected"); el[id].parentElement.classList.add("bgus_fz_selected");
}; };
const setSelectedResult = function (i) { const setSelectedResult = (i) => {
selected_result = i; selectedResult = i;
resultList resultList
.querySelectorAll(".selected") .querySelectorAll(".selected")
.forEach((el) => el.classList.remove("selected")); .forEach((sel) => sel.classList.remove("selected"));
resultList.children[i].classList.add("selected"); resultList.children[i].classList.add("selected");
jumpTo(results[i].id); jumpTo(results[i].id);
}; };
@ -121,15 +121,13 @@ export default function (root: HTMLElement, docname: string) {
return; return;
} }
const regex = new RegExp( const regex = new RegExp(
"^(.*?)([" + `^(.*?)([${str
str
.split("") .split("")
.map((c) => (c.includes(["\\", "]", "^"]) ? "\\" + c : c)) .map((c) => (c.includes(["\\", "]", "^"]) ? `\\${c}` : c))
.join("])(.*?)([") + .join("])(.*?)([")}])(.*?)$`,
"])(.*?)$",
"i" "i"
); );
const arr = search_candidate const arr = searchCandidate
.map((o) => { .map((o) => {
o.matches = (o.str.match(regex) || []) o.matches = (o.str.match(regex) || [])
.slice(1) .slice(1)
@ -148,7 +146,7 @@ export default function (root: HTMLElement, docname: string) {
} }
return list; return list;
}, []) }, [])
.map((str) => str.join("")); .map((cstr) => cstr.join(""));
return o; return o;
}) })
// Strike non-matching rows // Strike non-matching rows
@ -164,7 +162,7 @@ export default function (root: HTMLElement, docname: string) {
if (a.length !== 1 && b.length === 1) return 1; if (a.length !== 1 && b.length === 1) return 1;
// Most complete groups (alphanumeric) // Most complete groups (alphanumeric)
const clean = (el) => !/[^a-zA-Z0-9]*$/.test(el); const clean = (cel) => !/[^a-zA-Z0-9]*$/.test(cel);
const cLen = a.filter(clean).length - b.filter(clean).length; const cLen = a.filter(clean).length - b.filter(clean).length;
if (cLen !== 0) return cLen; if (cLen !== 0) return cLen;
@ -187,11 +185,11 @@ export default function (root: HTMLElement, docname: string) {
arr.forEach(({ matches, id }) => { arr.forEach(({ matches, id }) => {
const li = document.createElement("li"); const li = document.createElement("li");
li.innerHTML = matches li.innerHTML = matches
.map((c, i) => (i % 2 ? "<strong>" + c + "</strong>" : c)) .map((c, i) => (i % 2 ? `<strong>${c}</strong>` : c))
.join(""); .join("");
li.addEventListener("click", () => { li.addEventListener("click", () => {
jumpTo(id); jumpTo(id);
searchBox.classList.add("bgus_hidden"); searchBoxElem.classList.add("bgus_hidden");
}); });
resultList.appendChild(li); resultList.appendChild(li);
}); });
@ -203,58 +201,60 @@ export default function (root: HTMLElement, docname: string) {
// Create fuzzy search box // Create fuzzy search box
const sel = document.createElement("input"); const sel = document.createElement("input");
searchBox.id = "bgus_fz_searchbox"; searchBoxElem.id = "bgus_fz_searchbox";
searchBox.classList.add("bgus_hidden"); searchBoxElem.classList.add("bgus_hidden");
searchBox.appendChild(sel); searchBoxElem.appendChild(sel);
searchBox.appendChild(resultList); searchBoxElem.appendChild(resultList);
root.appendChild(searchBox); root.appendChild(searchBoxElem);
// Bind events // Bind events
let oldValue = ""; let oldValue = "";
sel.addEventListener("keyup", function (event) { sel.addEventListener("keyup", (event) => {
switch (event.keyCode) { switch (event.keyCode) {
case 27: // Escape - Hide bar case 27: // Escape - Hide bar
searchBox.classList.add("bgus_hidden"); searchBoxElem.classList.add("bgus_hidden");
return; return;
case 13: // Enter - Jump to first result and hide bar case 13: // Enter - Jump to first result and hide bar
if (results.length > 0) { if (results.length > 0) {
jumpTo(results[selected_result].id); jumpTo(results[selectedResult].id);
} }
searchBox.classList.add("bgus_hidden"); searchBoxElem.classList.add("bgus_hidden");
return; return;
case 40: // Down arrow - Select next result case 40: // Down arrow - Select next result
if (selected_result < results.length - 1) { if (selectedResult < results.length - 1) {
setSelectedResult(selected_result + 1); setSelectedResult(selectedResult + 1);
} }
return; return;
case 38: // Up arrow - Select previous result case 38: // Up arrow - Select previous result
if (selected_result > 0) { if (selectedResult > 0) {
setSelectedResult(selected_result - 1); setSelectedResult(selectedResult - 1);
} }
return; return;
default: default:
if (this.value != oldValue) { if (sel.value !== oldValue) {
search(this.value); search(sel.value);
oldValue = this.value; oldValue = sel.value;
} }
} }
}); });
document.body.addEventListener("keyup", function (ev) { document.body.addEventListener("keyup", (ev) => {
if (ev.keyCode === 83) { if (ev.keyCode === 83) {
sel.focus(); sel.focus();
} }
}); });
document.body.addEventListener("keydown", function (ev) { document.body.addEventListener("keydown", (ev) => {
if (ev.shiftKey) { if (ev.shiftKey) {
switch (ev.keyCode) { switch (ev.keyCode) {
// SHIFT+S = Fuzzy search // SHIFT+S = Fuzzy search
case 83: { case 83: {
searchBox.classList.remove("bgus_hidden"); searchBoxElem.classList.remove("bgus_hidden");
sel.value = ""; sel.value = "";
return; break;
} }
default:
// Do nothing
} }
} }
}); });
@ -268,15 +268,17 @@ export default function (root: HTMLElement, docname: string) {
"table.wikitable > tbody > tr:not(:first-child) > td:nth-child(2), .tooltiptext" "table.wikitable > tbody > tr:not(:first-child) > td:nth-child(2), .tooltiptext"
) )
.forEach((td) => { .forEach((td) => {
const tmp = td.cloneNode(); const tmp = td.cloneNode() as HTMLElement;
// 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. // 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. // 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(td.childNodes).forEach((el) => { Array.from(td.childNodes).forEach((el) => {
if (el instanceof HTMLElement) {
if (el.tagName === "P") { if (el.tagName === "P") {
tmp.append(...el.childNodes); tmp.append(...el.childNodes);
} else { } else {
tmp.append(el); tmp.append(el);
} }
}
}); });
td.parentNode.replaceChild(tmp, td); td.parentNode.replaceChild(tmp, td);
}); });
@ -303,18 +305,20 @@ export default function (root: HTMLElement, docname: string) {
// Add event to autofill child checkboxes // Add event to autofill child checkboxes
root root
.querySelectorAll(".bgus_part_tooltip > .bgus_checkbox") .querySelectorAll(".bgus_part_tooltip > .bgus_checkbox")
.forEach((box) => { .forEach((box: HTMLInputElement) => {
const tooltip = box.parentElement.nextElementSibling; const tooltip = box.parentElement.nextElementSibling;
box.addEventListener("click", function () { box.addEventListener("click", () => {
tooltip tooltip
.querySelectorAll(".bgus_checkbox") .querySelectorAll(".bgus_checkbox")
.forEach((el) => (el.checked = this.checked)); .forEach((el: HTMLInputElement) => {
el.checked = box.checked;
});
}); });
}); });
// Add event to collapse subsections // Add event to collapse subsections
root.querySelectorAll(".bgus_nested_element").forEach((twistie) => { root.querySelectorAll(".bgus_nested_element").forEach((twistie) => {
twistie.addEventListener("click", function (evt) { twistie.addEventListener("click", () => {
twistie.classList.toggle("bgus_collapsed"); twistie.classList.toggle("bgus_collapsed");
}); });
}); });
@ -322,15 +326,16 @@ export default function (root: HTMLElement, docname: string) {
// Wrap every recipe with extra metadata // Wrap every recipe with extra metadata
root.querySelectorAll(".bgus_part").forEach((el: HTMLElement) => { root.querySelectorAll(".bgus_part").forEach((el: HTMLElement) => {
if ("parts" in el.parentElement.dataset) { if ("parts" in el.parentElement.dataset) {
el.parentElement.dataset.parts = el.parentElement.dataset.parts = (
parseInt(el.parentElement.dataset.parts) + parseInt(el.parentElement.dataset.parts, 10) +
parseInt(el.dataset.amount); parseInt(el.dataset.amount, 10)
).toString();
} else { } else {
el.parentElement.dataset.parts = el.dataset.amount; el.parentElement.dataset.parts = el.dataset.amount;
} }
}); });
const setPartSize = function (labels, ml) { const setPartSize = (labels, ml) => {
labels.forEach((el) => { labels.forEach((el) => {
const part = el.parentElement.dataset.amount; const part = el.parentElement.dataset.amount;
const total = el.parentElement.parentElement.dataset.parts; const total = el.parentElement.parentElement.dataset.parts;
@ -340,7 +345,7 @@ export default function (root: HTMLElement, docname: string) {
let next = el.parentElement.nextElementSibling; let next = el.parentElement.nextElementSibling;
while (next) { while (next) {
if (next.classList.contains("tooltip")) { if (next.classList.contains("tooltip")) {
let sublabels = []; const sublabels = [];
next.querySelector(".tooltiptext").childNodes.forEach((ch) => { next.querySelector(".tooltiptext").childNodes.forEach((ch) => {
if (ch.classList && ch.classList.contains("bgus_part")) { if (ch.classList && ch.classList.contains("bgus_part")) {
sublabels.push(ch.querySelector(".bgus_part_label")); sublabels.push(ch.querySelector(".bgus_part_label"));
@ -365,13 +370,13 @@ export default function (root: HTMLElement, docname: string) {
) )
); );
const name = el.map((elem) => { const name = el.map((elem) => {
let name = ""; let partial = "";
elem.childNodes.forEach((t) => { elem.childNodes.forEach((t) => {
if (t instanceof Text) { if (t instanceof Text) {
name += t.textContent; partial += t.textContent;
} }
}); });
return name.trim(); return partial.trim();
}); });
searchBox( searchBox(
el, el,
@ -379,23 +384,23 @@ export default function (root: HTMLElement, docname: string) {
); );
// Remove "Removed medicines" section // Remove "Removed medicines" section
let remTable = root.querySelector( const remTable = root.querySelector(
"#Non-craftable_Medicines + h4 + p + table" "#Non-craftable_Medicines + h4 + p + table"
); );
remTable.parentElement.removeChild(remTable); remTable.parentElement.removeChild(remTable);
root root
.querySelectorAll("div[data-name] .wikitable.sortable tr") .querySelectorAll("div[data-name] .wikitable.sortable tr")
.forEach((el: HTMLElement) => { .forEach((row: HTMLElement) => {
let sectionEl = el.parentElement; let sectionEl = row.parentElement;
while (!sectionEl.dataset.name) { while (!sectionEl.dataset.name) {
sectionEl = sectionEl.parentElement; sectionEl = sectionEl.parentElement;
} }
const section = sectionEl.dataset.name; const section = sectionEl.dataset.name;
if (el.querySelector("td") === null) { if (row.querySelector("td") === null) {
// Remove unused rows if found // Remove unused rows if found
const row = el.querySelectorAll("th"); const headers = row.querySelectorAll("th");
row.forEach((th, i) => { headers.forEach((th, i) => {
if (i < 2) { if (i < 2) {
th.classList.add("table-head"); th.classList.add("table-head");
return; return;
@ -404,7 +409,7 @@ export default function (root: HTMLElement, docname: string) {
}); });
return; return;
} }
let rows = Array.from(el.querySelectorAll("td")).slice(1); const rows = Array.from(row.querySelectorAll("td")).slice(1);
let treatment = null; let treatment = null;
let desc = null; let desc = null;
let metabolism = null; let metabolism = null;
@ -428,7 +433,7 @@ export default function (root: HTMLElement, docname: string) {
// All fields // All fields
[treatment, desc, metabolism, overdose, addiction] = rows; [treatment, desc, metabolism, overdose, addiction] = rows;
} }
const title = el.querySelector("th"); const title = row.querySelector("th");
let content = `<div class="reagent-header">${title.innerHTML}</div>`; let content = `<div class="reagent-header">${title.innerHTML}</div>`;
if (treatment) { if (treatment) {
content += `<p class="treatment">${treatment.innerHTML}</p>`; content += `<p class="treatment">${treatment.innerHTML}</p>`;
@ -436,10 +441,10 @@ export default function (root: HTMLElement, docname: string) {
if (metabolism) { if (metabolism) {
content += `<p class="metabolism">${metabolism.innerHTML}</p>`; content += `<p class="metabolism">${metabolism.innerHTML}</p>`;
} }
if (addiction && addiction.innerHTML.trim() != "N/A") { if (addiction && addiction.innerHTML.trim() !== "N/A") {
content += `<p class="addiction">${addiction.innerHTML}</p>`; content += `<p class="addiction">${addiction.innerHTML}</p>`;
} }
if (overdose && overdose.innerHTML.trim() != "N/A") { if (overdose && overdose.innerHTML.trim() !== "N/A") {
content += `<p class="overdose">${overdose.innerHTML}</p>`; content += `<p class="overdose">${overdose.innerHTML}</p>`;
} }
if (desc) { if (desc) {
@ -454,7 +459,7 @@ export default function (root: HTMLElement, docname: string) {
if (addiction) addiction.parentElement.removeChild(addiction); if (addiction) addiction.parentElement.removeChild(addiction);
}); });
document.body.addEventListener("keydown", function (ev) { document.body.addEventListener("keydown", (ev) => {
if (ev.shiftKey) { if (ev.shiftKey) {
switch (ev.keyCode) { switch (ev.keyCode) {
// SHIFT+C = Toggle checkboxes // SHIFT+C = Toggle checkboxes
@ -462,28 +467,36 @@ export default function (root: HTMLElement, docname: string) {
root.classList.toggle("bgus_cbox"); root.classList.toggle("bgus_cbox");
root root
.querySelectorAll(".bgus_checkbox:checked") .querySelectorAll(".bgus_checkbox:checked")
.forEach((el: HTMLInputElement) => { .forEach((sel: HTMLInputElement) => {
el.checked = false; sel.checked = false;
}); });
return; break;
} }
// SHIFT+B = Set whole size (beaker?) for parts/units // SHIFT+B = Set whole size (beaker?) for parts/units
case 66: { case 66: {
let size = parseInt(prompt("Write target ml (0 to reset)", "90")); const size = parseInt(
if (isNaN(size) || size <= 0) { prompt("Write target ml (0 to reset)", "90"),
10
);
if (Number.isNaN(size) || size <= 0) {
// Reset to parts/unit // Reset to parts/unit
root root
.querySelectorAll(".bgus_part_label") .querySelectorAll(".bgus_part_label")
.forEach((el: HTMLElement) => (el.innerHTML = el.dataset.src)); .forEach((sel: HTMLElement) => {
sel.innerHTML = sel.dataset.src;
});
return; return;
} }
setPartSize( setPartSize(
root.querySelectorAll("td > .bgus_part > .bgus_part_label"), root.querySelectorAll("td > .bgus_part > .bgus_part_label"),
+size +size
); );
return; break;
} }
default:
// Do nothing
} }
} }
}); });

View file

@ -1,4 +1,4 @@
const WIKI_BASE = "https://cors-anywhere.herokuapp.com/tgstation13.org/wiki"; const WIKI_BASE = "https://tgproxy.ovo.ovh/wiki";
/** /**
* Get HTML content of a page using Mediawiki Parse APIs * Get HTML content of a page using Mediawiki Parse APIs
@ -9,3 +9,5 @@ export async function getPageHTML(name: string): Promise<string> {
const apiURL = `/api.php?action=parse&page=${urlname}&prop=text&format=json`; const apiURL = `/api.php?action=parse&page=${urlname}&prop=text&format=json`;
return (await (await fetch(WIKI_BASE + apiURL)).json()).parse.text["*"]; return (await (await fetch(WIKI_BASE + apiURL)).json()).parse.text["*"];
} }
export default { getPageHTML };

View file

@ -5,10 +5,19 @@
"license": "MIT", "license": "MIT",
"scripts": { "scripts": {
"dev": "parcel index.html", "dev": "parcel index.html",
"lint": "eslint lib",
"build": "parcel build index.html" "build": "parcel build index.html"
}, },
"dependencies": { "dependencies": {
"@typescript-eslint/eslint-plugin": "^3.3.0",
"@typescript-eslint/parser": "^3.3.0",
"eslint": "7.2.0",
"eslint-config-airbnb-base": "^14.2.0",
"eslint-config-prettier": "^6.11.0",
"eslint-plugin-import": "2.21.2",
"eslint-plugin-prettier": "^3.1.4",
"parcel-bundler": "^1.12.4", "parcel-bundler": "^1.12.4",
"prettier": "^2.0.5",
"sass": "^1.26.8", "sass": "^1.26.8",
"typescript": "^3.9.5" "typescript": "^3.9.5"
}, },

875
yarn.lock

File diff suppressed because it is too large Load diff