hogashi.*

日記から何から

Scrapboxの編集履歴をスライダーで眺められるUserScript

 Scrapbox のページの編集履歴を、スライダーで動かしながら眺められる UserScript を書きました*1

scrapbox.io

 ページメニューに追加されたボタンを押すと、そのページの編集履歴を取得して、履歴ビューを表示します (メンバーでないプロジェクトでは API で取得できないので見られません)。
 上にあるスライダーを右へ左へ移動すると、新しくなったり古くなったりします。

f:id:hogashi:20191004223909g:plain

詳しく

 Scrapbox編集履歴 API を使っています。

scrapbox.io

 全く同じように編集履歴を取得し、commits の changes のひとつごとに、ページの内容の状態をつくり、スライダーが動いたらその状態を表示する感じです。

 最初は、 change ごとの、その時々のページの状態を持つようにしていました。ページの状態とは、行の id とその行に書いてある文字列の、ページ全体分です。

イメージ:

// 最初の行を追加
const history1 = [
  { id: "0123456789abcdef01234567", text: "これは" },
];
// 最初の行を更新
const history2 = [
  { id: "0123456789abcdef01234567", text: "これはタイトル" },
];
// 次の行を追加
const history3 = [
  { id: "0123456789abcdef01234567", text: "これはタイトル" },
  { id: "0123456789abcdef01234568", text: "そして本文" },
];
// 今の行を削除
const history4 = [
  { id: "0123456789abcdef01234567", text: "これはタイトル" },
];
...
const histories = [history1, history2, ...];

 実際にこれをやったところメモリを食いつぶして Chrome が落ちたので、文字列は文字列で持つだけにして、行にはそのインデックスを保存するようにしたりもしました。 change ごとにテキストが増えたり減ったり編集されたりするのですが、全て新しい文字列として持ちます。(今気づいたけど行 id も同じことをやっても良さそう?)

const texts = [
  "これは",
  "これはタイトル",
  "そして本文",
];
const history1 = [
  { id: "0123456789abcdef01234567", text: 0 },
];
const history2 = [
  { id: "0123456789abcdef01234567", text: 1 },
];
const history3 = [
  { id: "0123456789abcdef01234567", text: 1 },
  { id: "0123456789abcdef01234568", text: 2 },
];
...

 これでもメモリが足りないようで、つくりを変えて、ページが生まれてから今までのすべての行を持つひとつの配列だけ持つようにしました。行削除のときは新しい文字列はないですが、 null を入れて changes のインデックスと合わせてわかりやすくしています。

const texts = [
  "これは",
  "これはタイトル",
  "そして本文",
  null,
];
const history = [
  { id: "0123456789abcdef01234567", updated: [0, 1] },
  { id: "0123456789abcdef01234568", updated: [2], deleted: 3 },
  ...
];

 これで、 updated のうちスライダーの値より小さいものの最大のものが、そのときの文字列となります。ただし、 deleted がスライダーの値より小さいときは、その行は消えているので、表示しません。
 表示するべき行を集めて表示してあげれば、その時々のページの内容を表示することができます。

*1:寝られないからと言って一晩でつくったので見やすいコードではなさそう