generated at
ページを転送するUserScript
あるprojectにあるページを別のprojectに転送するUserScript

cf.

バグ
あー、これ行の更新日時を反映できないのか
api/page-data/import/:projectname.jsonでページを送って、元ページだけwebsocketで削除するようにしたほうがいいかな
いやそれだとAPI rate limitに引っかかってしまう
流石に無理だとは思うが

使用例
現在ページを特定のprojectに転送する
pageMenu.ts
import { transportPage } from "./transportPage.ts"; import type { Scrapbox } from "../scrapbox-jp%2Ftypes/userscript.ts"; declare const scrapbox: Scrapbox; scrapbox.PageMenu.addItem({ title: "Transport", onClick: async () => { await transportPage(); }, }); scrapbox.PageMenu.addItem({ title: "Transport and Open", onClick: async () => { const url = await transportPage(); if (!url) return; window.open(url); }, });
transportPage.ts
import { transport } from "./mod.ts"; import { useStatusBar, encodeTitleURI, } from "../scrapbox-userscript-std/dom.ts"; import type { Scrapbox } from "../scrapbox-jp%2Ftypes/userscript.ts"; declare const scrapbox: Scrapbox; export const transportPage = async (): Promise<string | undefined> => { const title = scrapbox.Page.title!; const from = scrapbox.Project.name; const to = globalThis.prompt( `Take "/${from}/${title}" from "${from}" to:`, "takker", ); if (!to) return; const { render, dispose } = useStatusBar(); render( { type: "spinner" }, { type: "text", text: `/${from}/${title} → /${to}/${title}` } ); try { const result = await transport(title, { from, to, merge: true }); if (!result.success) { render( { type: "exclamation-triangle" }, { type: "text", text: `${result.name} ${result.message}`, }, ); return; } render( { type: "check-circle" }, { type: "text", text: `Moved ${result.dup ? "and merged " : ""}to "/${to}/${title}".` }, ); return `https://scrapbox.io/${to}/${encodeTitleURI(title)}`; } catch(e: unknown) { render( { type: "exclamation-triangle" }, { type: "text", text: e instanceof Error ? `${e.name} ${e.message}` : `Unknown error! (see developper console)`, }, ); console.error(e); } finally { setTimeout(() => dispose(), 1000); } };

dependencies
mod.ts
/// <reference no-default-lib="true" /> /// <reference lib="esnext" /> /// <reference lib="dom" /> import { deletePage, getPage, patch } from "../scrapbox-userscript-std/mod.ts"; import { isErr, unwrapErr, unwrapOk } from "npm:option-t@49/plain_result"; export interface TransportInit { /** 転送元project */ from: string; /** 転送先project */ to: string; /** 転送先に同じタイトルのページがあったときの挙動 * * - `true`: 末尾に追記する * - `false`: 何もしない * @default false */ merge?: boolean; } export type TransportResult = { success: true; /** 同名のページが転送先にあったらtrue */ dup: boolean; } | { success: false; at: "from" | "to"; name: string; message: string; }; export async function transport(title: string, { from, to, merge, }: TransportInit): Promise<TransportResult> { if (from === to) return { success: true, dup: false }; // 転送するページを取得 const res = await getPage(from, title); if (isErr(res)) { return { success: false, at: "from", name: unwrapErr(res).name, message: unwrapErr(res).message, }; } const page = unwrapOk(res); if (!page.persistent) { return { success: false, at: "from", name: "EmptyPageError", message: "The request page is empty.", }; } // 転送先ページがあるかどうかを調べる const res2 = await getPage(to, title); if (isErr(res2)) { return { success: false, at: "to", name: unwrapErr(res2).name, message: unwrapErr(res2).message, }; } const page2 = unwrapOk(res); if (page2.persistent && !merge) { return { success: false, at: "to", name: "NoEmptyPageError", message: `The same page already exists in "/${to}"`, }; } // 転送する await patch( to, title, (lines) => [...lines, ...page.lines.slice(1)].map((line) => line.text), ); await deletePage(from, title); return { success: true, dup: page2.persistent }; }

#2024-11-13 16:47:10 scrapbox-userscript-stdの破壊的変更に対応
#2022-03-12 21:42:38
#2022-02-22 14:59:02
#2022-02-21 17:23:26