接頭語で名前空間を分けてUserScriptとUserCSSでアイコンに置き換え可読性を上げる
public.icon
たとえば、コンテキストによって「サービス」が意味するものが違う場合に、それぞれ接頭語を付けて、名前空間を分ける。そのままだと、接頭語の記載がビジーなのでアイコンに置き換える。
https://gyazo.com/7f8a16f99df29348f0be833d641cb8b8
Created with Gemini
code: UserScript.js
/**
* Scrapbox: 複数の接頭語を持つページリンクをアイコンに置換する
*
* バージョン: 4.0 (最終FIX版)
*
* 安定性のための修正 (デバウンス):
* - Scrapboxの編集モード移行時などに発生するDOM操作の競合を回避するため、
* MutationObserver の処理をデバウンス(遅延実行)するように修正。
* - DOM変更が連続して発生した場合は処理を一度にまとめ、
* 最後の変更から指定時間(DEBOUNCE_DELAY)が経過した後に実行する。
*/
// ▼▼▼ 設定箇所: ここに対応したい接頭語とCSSクラス名を追加・編集します ▼▼▼
const PREFIX_CONFIG = [
{ prefix: 'ITIL:', className: 'icon-itil' },
{ prefix: 'Azure:', className: 'icon-azure' },
{ prefix: 'AWS:', className: 'icon-aws' },
// { prefix: 'GCP:', className: 'icon-gcp' },
];
// ▲▲▲ 設定はここまで ▲▲▲
const PROCESSED_ATTRIBUTE = 'data-prefix-icon-processed';
const DEBOUNCE_DELAY = 100; // 処理を遅延させる時間 (ミリ秒)
/**
* 指定されたDOMノード(またはその子孫)内の未処理リンクをアイコン化する関数
* (この関数の中身は変更ありません)
*/
const processNode = (targetNode) => {
if (targetNode.nodeType !== Node.ELEMENT_NODE) return;
const links = targetNode.querySelectorAll(a.page-link:not([${PROCESSED_ATTRIBUTE}]));
links.forEach(link => {
const text = link.textContent.trim();
for (const config of PREFIX_CONFIG) {
if (text.startsWith(config.prefix)) {
const prefixLength = config.prefix.length;
const childSpans = link.children;
if (childSpans.length >= prefixLength) {
for (let i = 0; i < prefixLength; i++) {
childSpansi.classList.add('prefix-char-hidden'); }
const iconSpan = document.createElement('span');
iconSpan.className = config.className;
link.prepend(iconSpan);
link.setAttribute(PROCESSED_ATTRIBUTE, 'true');
break;
}
}
}
});
};
// --- 実行と監視のロジック (デバウンス版) ---
// 1. ページ初期読み込み時に、ページ全体を対象として一度実行
processNode(document.body);
// 2. DOMの変更を監視するための MutationObserver
let debounceTimer = null;
const observer = new MutationObserver(() => {
// 既にタイマーがセットされていれば、それをキャンセル
clearTimeout(debounceTimer);
// 新しいタイマーをセット。指定時間後に処理を一度だけ実行する
debounceTimer = setTimeout(() => {
// 遅延実行されるため、変更があったノードを特定するのは難しい。
// その代わり、ページ全体を対象に処理を実行する。
// 処理済みフラグがあるため、パフォーマンス上の問題はほとんどない。
processNode(document.body);
}, DEBOUNCE_DELAY);
});
// 監視を開始
observer.observe(document.body, {
childList: true,
subtree: true
});
code: UserCSS.css
/* 1. 【共通】接頭語のテキストを非表示にするルール */
.page-link .prefix-char-hidden {
display: none;
}
/* 2. 【共通】すべてのアイコンに適用する基本スタイル */
content: '';
display: inline-block;
width: 16px;
height: 16px;
/* var()関数で、各要素に定義された変数を読み込む */
background-image: var(--icon-image);
background-size: contain;
background-repeat: no-repeat;
background-position: center;
margin-right: 4px;
vertical-align: middle;
}
/* 3. 【個別】各アイコンに画像URLを変数として定義 */
/* ::beforeではなく、span本体に定義するのがポイント */
.page-link span.icon-itil {
}
.page-link span.icon-azure {
}
.page-link span.icon-aws {
}