関連ページリストにタグに応じて色やアイコンをつける
scrapbox-syncで、タグによってページの公開状態を決めているが、関連ページの公開状態を調べるのにいちいち見て回る必要があり面倒だったので作った
アイコン版のほうが、該当するタグが複数種類ついている場合にすべて表示できるので便利
色版でも頑張ればできそうだが
面白そう
例によってちょっと書き換えた
for文を減らした
デバッグしないで書き換えて放置というクソ迷惑なことしていますごめんなさい
ありがとうございます
むしろそれを期待して置いてるところあるw
色版
script1.jsconst tagColorPairs = {
// for default-dark
'private': '#a95756',
'not-private': '#3c763d',
}
mark();
const observer = new MutationObserver(mark);
//observer.observe(document.querySelector('div.related-page-list.clearfix ul.grid'), { childList: true });
addObserver();
function addObserver() {
let elem = document.querySelector('div.related-page-list.clearfix ul.grid');
if (!elem) {
window.setTimeout(addObserver, 500);
return;
}
observer.observe(elem, { childList: true });
}
script1.jsconst encode = s => s.replace(/[^A-Za-z0-9-.!~*();,:@&=+$]/g, match => {
if (match===' ') return '_'
else if (match==='"') return '\\"' // a[href='...']の中なので必要
else if (match==="'") return "\\'"
else return encodeURIComponent(match);
});
async function mark() {
if (!scrapbox.Page.title) return;
const {relatedPages: {links1hop}} = await (await fetch(`/api/pages/${scrapbox.Project.name}/${scrapbox.Page.title}`)).json();
links1hop.forEach(({linksLc, title}) => {
const tag = Object.keys(tagColorPairs).find(tag => linksLc.includes(tag));
if (!tag) return;
const header = document.querySelector(`.related-page-list .grid li.page-list-item a[href="/${scrapbox.Project.name}/${encode(title)}"] .header`);
↑ title
のエンコードを特殊な感じにしないといけないっぽい
encodeURIComponent(title)
:
はそのまま
(半角スペース)は _
に置換
どう書けば良いのかわからない…誰か教えて下さい
title.replace(/ /g, '_').replace(/\/g, encodeURIComponent('/'))....
みたいに列挙するしかない?
title.toLowerCase().replace(/ /g, '_')
でいけると思います
title
を titleLc
に変換できます
jsconst header = document.querySelector(`.related-page-list .grid li.page-list-item a[href="/${scrapbox.Project.name}/${title.toLowerCase().replace(/ /g, '_')}"] .header`);
関連ページリストのカードを、hrefの値で取得しようとしているのですが、他にも
/
とか
#
とかencodeしないといけない文字があるようで、これだけではだめでした
とりあえず以下でいけた
jsfunction _encode(match, offset, string) {
if (match===' ') return '_'
else if (match==="'") return "\\'" // a[href='...']の中なので必要
else if (match==='"') return '\\"' // 一応
else return encodeURIComponent(match);
}
const encode = s => s.replace(/[^A-Za-z0-9-.!~*();,:@&=+$]/g, _encode);
script1.js header.style.borderTop = `${tagColorPairs[tag]} solid 10px`;
});
}
アイコン版
FontAwesomeアイコンを使う場合は、そのためのUserCSSも必要
style.css.grid li {
font-family: "Roboto", Helvetica, Arial, "Hiragino Sans", sans-serif, FontAwesome;
}
.grid i {
font-style: normal;
}
script2.jsconst tagIconPairs = {
// for default-dark
'private': `<i class="fa fa-lock" style="color:#cd5c5c; margin-right:0.3em;"></i>`,
'not-private': `<i class="fas fa-unlock" style="color:#6fac63; margin-right:0.2em;"></i>`,
}
mark();
const observer = new MutationObserver(mark);
addObserver();
function addObserver() {
let elem = document.querySelector('div.related-page-list.clearfix ul.grid');
if (!elem) {
window.setTimeout(addObserver, 500);
return;
}
observer.observe(elem, { childList: true });
}
const encode = s => s.replace(/[^A-Za-z0-9-.!~*();,:@&=+$]/g, match => {
if (match===' ') return '_'
else if (match==='"') return '\\"' // a[href='...']の中なので必要
else if (match==="'") return "\\'"
else return encodeURIComponent(match);
});
async function mark() {
if (!scrapbox.Page.title) return;
const {relatedPages: {links1hop}} = await (await fetch(`/api/pages/${scrapbox.Project.name}/${scrapbox.Page.title}`)).json();
links1hop.forEach(({linksLc, title}) => {
const html = Object.keys(tagIconPairs)
.flatMap(tag => linksLc.includes(tag) ? [tagIconPairs[tag]] : [])
.join('');
const titleElem = document.querySelector(`.related-page-list .grid li.page-list-item a[href="/${scrapbox.Project.name}/${encode(title)}"] .title`);
//const temp = titleElem.textContent;
//titleElem.textContent = '';
//titleElem.textContent = temp;
titleElem.textContent = titleElem.textContent;
titleElem.insertAdjacentHTML('afterbegin', html);
});
}
observerが発火する度にアイコンがふえる!
なるほど…?
なんか直感に反する動作だな…
test
という1hop linkに対して、 titleElem.textContent
は "test"
という文字列だけだが、 titleElem.textContent = ''
とするとアイコンと文字列両方が消える
titleElem.textContent = titleElem.textContent;
だけでよさそう
なんだこの意味不明な行w
草
違和感ありまくりだったのでいろいろ挟んでいたのですが、そんな事せずとも A=A
で動くみたいですね
やっていることは titleElem.setTextContent(titleElem.getTextContent())
みたいな単なる関数呼び出しなので、まあ値が変化するのは当然といえば当然なのですが、いかんせん表記が A=A
なので、違和感を拭えませんね……
何もわからない。。