DOMを改行で分割する
code:splitDOM.ts
/// <reference no-default-lib="true" />
/// <reference lib="esnext" />
/// <reference lib="dom" />
/// <reference lib="dom.iterable" />
export function* splitDOM(element: Node): Generator<Node, void, unknown> {
if (!element.textContent.includes("\n")) {
yield element;
return;
}
if (!(element instanceof Element) &&
!(element instanceof Document) &&
!(element instanceof DocumentFragment)) {
yield* element.textContent.split("\n").map((text) => document.createTextNode(text));
}
let prev: Node | undefined;
for (const node of element.childNodes) {
let last: Node | undefined;
for (const splitted of splitDOM(node)) {
if (prev) {
prev.appendChild(splitted);
yield prev;
prev = undefined;
continue;
}
const dom = document.createElement(element.tagName);
for (const attr of element.attributes) {
dom.attributes.setNamedItem(attr);
}
dom.appendChild(node);
last = dom;
yield dom;
}
prev = last;
}
if (prev) yield prev;
}
だいぶ複雑だ
簡単なケースから考える
<node>text</node>の場合
code:js
if (!element.textContent.includes("\n")) return element; return element.textContent.split("\n").map((line) => {
const newElement = document.createElement(element.tagName);
newElement.textContent = line;
return newElement;
});
<node>text<node>text</node></node>の場合
code:test.ts
globalThis.document = new DOMParser().parseFromString(
`<!DOCTYPE html>
<html>
<head>
<title>Hello from Deno</title>
</head>
<body></body>
</html>`,
"text/html",
);
await t.step("改行なし", async (t) => {
const cases = [
html<div></div>,
htmltext,
html<div>text</div>,
html<div class="sample" id="test">text</div>,
html<div><span>text</span></div>,
html<div>てきすと<span>text</span></div>,
html<div><span>text</span>テキスト</div>,
html<div>てきすと<span>text</span>テキスト</div>,
];
for (const case of cases) {
}
});
await t.step("改行あり", async (t) => {
const cases = [
htmlline1\nline2,
html<div>line1\nline2</div>,
html<div>line1\n\nline2</div>,
html<div>\nline1\nline2</div>,
html<div>line1\nline2\n</div>,
html<div>line1\nline2\nline3</div>,
html<div class="sample" id="test">text</div>,
html<div><span>text</span></div>,
html<div>てきすと<span>text</span></div>,
html<div><span>text</span>テキスト</div>,
html<div>てきすと<span>text</span>テキスト</div>,
];
}
});