副表記へ自動的に転送するUserScript
❌から始まるリンクを見つけて転送する点が違う
元々あった [# []]
に飛ぶ機能は書き換えてあるので、 [# []]
を置いても反応しません
これを自分のページに置けば動作する
js import {runCrossLink} from "/api/code/villagepump/副表記へ自動的に転送するUserScript/script.js";
runCrossLink();
ソース
script.jsexport const runCrossLink = async() => {
let mutationObserver;
/**
* 副表記のリンクがあるページへリダイレクトする
* 複数候補がある場合は該当ページをハイライトするに留める
*/
const highlightPagesOrRedirect = async() => {
mutationObserver?.disconnect();
if (!scrapbox.Page.title || scrapbox.Page.title.indexOf("❌") != 0) {
// ページタイトルがない or ❌から始まるページではない
return;
}
// 開いているページの情報を取得
const pageAPIResponse = await fetch(`https://scrapbox.io/api/pages/${
encodeURIComponent(scrapbox.Project.name)
}/${encodeURIComponent(scrapbox.Page.title)}`);
if (!pageAPIResponse.ok) {
throw new Error(`${pageAPIResponse.status} ${pageAPIResponse.statusText}`);
}
const page = await pageAPIResponse.json();
const linkedLinks = [];
for (const { title } of page.relatedPages.links1hop) {
// Links欄(1-hop)にあるページを取得
const relatedPageAPIResponse = await fetch(`https://scrapbox.io/api/pages/${
encodeURIComponent(scrapbox.Project.name)
}/${encodeURIComponent(title)}`);
if (!relatedPageAPIResponse.ok) {
throw new Error(`${relatedPageAPIResponse.status} ${relatedPageAPIResponse.statusText}`);
}
const relatedPage = await relatedPageAPIResponse.json();
// 開いているページへのリンク(つまり逆リンク)を検索
relatedPage.lines.forEach(line => {
if (line.text.indexOf(`[${scrapbox.Page.title}]`) >= 0) {
linkedLinks.push({ line, page: relatedPage})
}
});
}
if (!isPageExists(scrapbox.Page.title) && linkedLinks.length === 1) {
// ページ遷移
const link = document.createElement("a")
link.href = `/${scrapbox.Project.name}/${encodeURIComponent(linkedLinks[0].page.title)}#${linkedLinks[0].line.id}`
document.body.appendChild(link)
link.click()
}
const highlightLinkedPages = () => {
const relatedPageListItemElements = [
...document.querySelectorAll(".related-page-list .grid li")
];
linkedLinks.forEach((linkedLink) =>
relatedPageListItemElements.forEach((relatedPageListItemElement) => {
if (relatedPageListItemElement.dataset.pageTitle !== linkedLink.page.title) {
return;
}
relatedPageListItemElement.querySelector("a .header").style.borderColor
= "var(--telomere-unread, #41b059)";
})
);
};
highlightLinkedPages();
mutationObserver = new MutationObserver(highlightLinkedPages);
mutationObserver.observe(document.body, {
subtree: true,
childList: true,
characterData: true,
});
};
await highlightPagesOrRedirect();
scrapbox.on('page:changed', highlightPagesOrRedirect);
};
/**
* ページが存在するか(既に作成されているか)を確かめる
* @param pageTitle ページのタイトル
* @returns 存在すればtrue, 存在しなければfalse
*/
function isPageExists(pageTitle) {
const pages = scrapbox.Project.pages
for(let page of pages) {
if(page.title == pageTitle) {
return page.exists
}
}
return false
}