diff --git a/browser/dom/mod.ts b/browser/dom/mod.ts index 5fda510..fe57920 100644 --- a/browser/dom/mod.ts +++ b/browser/dom/mod.ts @@ -11,5 +11,6 @@ export * from "./cache.ts"; export * from "./cursor.ts"; export * from "./selection.ts"; export * from "./stores.ts"; +export * from "./takeInternalLines.ts"; export * from "./pushPageTransition.ts"; export * from "./extractCodeFiles.ts"; diff --git a/browser/dom/takeInternalLines.ts b/browser/dom/takeInternalLines.ts new file mode 100644 index 0000000..b6ee927 --- /dev/null +++ b/browser/dom/takeInternalLines.ts @@ -0,0 +1,41 @@ +import { lines } from "./dom.ts"; +import { BaseLine } from "../../deps/scrapbox.ts"; + +/** Scrapbox内部の本文データの参照を取得する + * + * `scrapbox.Page.lines`はdeep cloneされてしまうので、performanceの問題が発生する場合がある + * + * なるべくデータのcloneを発生させたくない場合にこちらを使う + * + * 注意 + * - 参照をそのまま返しているだけなので、中身を書き換えられてしまう。型定義で変更不能にはしてあるが、JS経由ならいくらでも操作できる + * - `scrapbox.Page.lines`とは違って構文解析情報が付与されない + */ +export const takeInternalLines = (): readonly BaseLine[] => { + const linesEl = lines(); + if (!linesEl) { + throw Error(`div.lines is not found.`); + } + + const reactKey = Object.keys(linesEl) + .find((key) => key.startsWith("__reactFiber")); + if (!reactKey) { + throw Error( + 'div.lines must has the property whose name starts with "__reactFiber"', + ); + } + + // @ts-ignore DOMを無理矢理objectとして扱っている + return (linesEl[reactKey] as ReactFiber).return.stateNode.props + .lines as const; +}; + +interface ReactFiber { + return: { + stateNode: { + props: { + lines: BaseLine[]; + }; + }; + }; +}