GTDを噛み砕くをScrapbox書籍に変換するscript
code:script.js
(() => {
main();
function main() {
const body = document.querySelector("div.uk-width-medium-3-4");
const sections = makeHierarchy(body);
const pages = [];
for (const section of sections) {
if (section0.id === "脚注") continue; if (pages_.length === 0) continue;
pages.push(pages_.pop());
pages.push(...pages_);
}
const footnotes = Array.from(body.querySelectorAll("liid p")) .map((p, i) => ({
title: 脚注${i + 1},
lines: [脚注${i + 1}, p.firstChild.textContent.trim()],
}));
const index = {
title: "目次",
lines: [
"目次",
...pages.map(({ id, level }) => ${" ".repeat(level - 1)}[${id}]),
],
};
const json = {
pages: [index, ...pages.map(({id,lines}) => ({ title: id, lines: id, ...lines })), ...footnotes], };
// download dataを作成
// download linkを生成
const url = URL.createObjectURL(blob);
window.open(url);
}
function* toPages(section) {
const lines = [];
for (const node of section.slice(1)) {
if (Array.isArray(node)) {
if (pages.length === 0) continue;
lines.push([${link}], "");
// 先に親ページを返す
yield pages.pop();
for (const page of pages) {
yield page;
}
continue;
}
switch (node.nodeName) {
case "P":
lines.push(...convertP(node).split("\n"), "");
break;
case "TABLE":
lines.push("table:table", ...node.innerText.split("\n").map((text) => ${text}), "");
break;
case "UL":
lines.push(...convertUl(node), "");
break;
case "PRE":
lines.push("code:txt", ...node.innerText.split("\n").map((text) => ${text}), "");
break;
case "FIGURE": {
const img = node.querySelector("img");
const src = img.src.trim();
const text = img.alt.trim();
lines.push(text, [${src}], "");
break;
}
default:
lines.push(...node.innerText.split("\n"), "");
break;
}
}
yield { ...data, lines };
}
function convertP(p) {
return Array.from(p.childNodes).map((node) => {
switch (node.nodeName) {
case "STRONG":
return node.textContent.split("\n").map((text) => [* ${text}]).join("\n");
case "CODE":
return node.textContent.split("\n").map((text) => \`${text}\`).join("\n");
case "A": {
if (node.id) {
const n = node.textContent.trim();
return ([脚注${n}]);
}
const url = node.href.trim();
const text = node.textContent.trim();
return url === text ? ${url} : [${url} ${text}];
}
case "UL":
return convertUl(node).join("\n");
default:
return node.textContent;
}
}).join("");
}
function convertUl(ul) {
const list = Array.from(ul.children).filter((li) => li.tagName === "LI");
return list.flatMap(
(li) => convertP(li).split("\n").map((text, i) => i === 0 ? ${text} : ${text})
);
}
function makeHierarchy(body) {
let node = body.querySelector("h1");
const sections = [];
while (node) {
node = next;
sections.push(section);
}
return sections;
}
function crawl(node, split = 1) {
if (!node) return [[], undefined];
let child = node.nextElementSibling;
while (child && child.tagName !== H${split}) {
if (parseInt(child.tagName.slice(1)) > split) {
const result = crawl(child, split + 1);
continue;
}
if (parseInt(child.tagName.slice(1)) <= split) break;
section.push(child);
child = child.nextElementSibling;
}
}
})();