pin-diary-2
今日の日記ページをPin留めするUserScript version 2 /emoji/warning.iconまだバグが残っています
使い方
2. 以下のどちらかを自分のページに書く
:projectnameを自分のprojectの名前に書き換えてください
code:js
import {execute} from '/api/code/:projectname/pin-diary/user.js';
execute();
// debug messageを出力するとき
// execute({verbose: true});
code:js
import('/api/code/:projectname/pin-diary/user.js')
.then(({execute}) => execute());
/emoji/good.icon
/icons/たしかに.icontakker.icon
説明変えました
code:diff
+ '/api/code/:projectname/pin-diary/user.js';
- '/api/code/villagepump/pin-diary/user.js';
既知の問題
title以外の更新でページリストが変わるとPinがむちゃくちゃになる
https://gyazo.com/db094f75613d41bb38d8bb1c59abd0c2
ページリストの更新が、<a>タグのhrefのみを更新しているのが原因
PinしたDOMがそのまま残ってしまう
対策
#dropdownMenuSortではなくページリストそのものを監視する
.app .container .grid
無限ループを回避するために、フラグを立てておく
Module内で使うglobal変数
code:user.js
const targetProject = 'villagepump';
let VERBOSE = false;
let executed = false;
let diaryCard = null;
entry point
一回だけ実行できる
code:user.js
export function execute({verbose = false} = {}) {
if (executed) return;
executed = true;
VERBOSE = verbose;
const today = toYYYYMMDD(new Date());
const path = /${targetProject}/${encodeURIComponent(today)}
handlePageChange(async () => {
// top page以外では実行しない
if (scrapbox.Project.name !== targetProject && scrapbox.Layout === 'list') return;
// 全てのカードを含む<ul>
const cards = document
.getElementsByClassName('page-list')?.0 ?.getElementsByClassName('grid')?.0; // ページの並び替えが終わるまで少し待つ
await sleep(1000);
// 前回の日付ページに相当するカードのPinを外す
if(diaryCard) {
_log('Removing a pin from %o \n href = %o', diaryCard, diaryCard.querySelector('a').href);
removePin({card: diaryCard});
_log('Removed.');
}
// 日付ページを取得する
diaryCard = cards
.querySelector(li.page-list-item a[href="${path}"])
?.parentNode
// なければ新しく作る
?? (() => {
_log('The diary card doesn\'t exist. Creating new diary card...');
return createEmptyPageCard({title: today, path: path});
})();
_log({diaryCard});
// Pinしたカードの数
// 日付ページにPinする前の数を取得しておく
const pins = cards
.getElementsByClassName('page-list-item grid-style-item pin')
.length;
_log({pins});
// DOMにPin留めをつける
_log('Adding a pin on %o \n href = %o', diaryCard, diaryCard.querySelector('a').href);
appendPin({card: diaryCard});
_log('Added a pin on the diary card.');
//日付ページが常にPinなしページの前に来るように移動する
_log('Move the diary card before %o', cards.childrenpins); cards.insertBefore(diaryCard, cards.childrenpins); console.log('Finish pinning the today\'s diary page.')
});
}
Utilities
code:user.js
const zero = n => String(n).padStart(2, '0');
const toYYYYMMDD =
date => ${date.getFullYear()}/${zero(date.getMonth() + 1)}/${zero(date.getDate())}
const sleep = milliseconds => new Promise(resolve => setTimeout(resolve, milliseconds));
ページカードを作成する
code:user.js
function createEmptyPageCard({title, path}) {
const card = document.createElement('li');
card.insertAdjacentHTML('beforeend',
`<li id="pin-diary-card" class="page-list-item grid-style-item" style="opacity: 0.7;">
<a href="${path}" rel="route">
<div class="hover"></div>
<div class="content">
<div class="header">
<div class="title">${title}</div>
</div>
<div class="description">
<div class="line-img">
<div></div><div></div><div></div><div></div><div></div>
</div>
</div>
</div>
</a>
</li>`);
return card;
}
function appendPin({card}) {
card.getElementsByClassName('hover')?.0 ?.insertAdjacentHTML('afterend', '<div class="pin"></div>');
card.classList.add('pin');
}
function removePin({card}) {
card.getElementsByClassName('pin')?.0?.remove(); card.classList.remove('pin');
}
Top pageの更新を監視する関数
code:user.js
function handlePageChange(callback) {
callback(); // 初回の実行
const observer = new MutationObserver(() => callback());
// 監視を開始する
observer.observe(document.getElementsByTagName('title')0, {childList: true}); observer.observe(document.getElementById('dropdownMenuSort'),
// この3つを指定しないと変更を捕捉できない
{subtree: true,childList:true,characterData:true});
};
debug用
code:user.js
function _log(message, ...objects) {
if (!VERBOSE) return;
if (objects.length !== 0) {
if ((typeof message) === 'string') {
console.log(${header}${message}, ...objects);
} else {
console.log(header, message, ...objects);
}
} else {
if ((typeof message) === 'string') {
console.log(${header}${message});
} else {
console.log(header, message);
}
}
}