Scrapboxで遊ぶ

この記事は [NCC Advent Calendar 2017](https://qiita.com/advent-calendar/2017/ncc) の2日目の記事です。

今回は、 [Scrapbox](https://scrapbox.io/) の [UserCSS](https://scrapbox.io/help-jp/UserCSS) と [UserScript](https://scrapbox.io/help-jp/UserScript) を使って遊んでみました。
著者はCSSもJavaScriptも書いたことがなかったため、書き方におかしいところがあるかもしれませんがご了承ください。


# UserCSSで遊ぶ

UserCSSはproject内に `settings` ページを作成し、その中にコードブロック記法でファイル名を `style.css` として書きます。
Publicなprojectの `settings` ページを見てみるととても便利なものやかっこいいものがあります。
以下のprojectなどがおすすめです。

- [scrasobox/settings](https://scrapbox.io/scrasobox/settings)
- [daiiz/settings](https://scrapbox.io/daiiz/settings)
- [customize/UserCSS](https://scrapbox.io/customize/UserCSS)


### 文字をalignする

[拡張記法](https://scrapbox.io/scrasobox/%E6%8B%A1%E5%BC%B5%E8%A8%98%E6%B3%95%E3%81%8C%E3%81%8D%E3%81%9F%EF%BC%81) を使って文字列を左右中央のどれかに寄せられるようにします。

```CSS
/* 中央寄せ */
.deco-\| {
  position: absolute;
  width: 100%;
  text-align: center;
}

/* 右寄せ */
.deco-\> {
  position: absolute;
  width: 100%;
  text-align: right;
}

/* 左寄せ */
.deco-\< {
  position: absolute;
  width: 100%;
  text-align: left;
}
```

![align](https://gyazo.com/64ed3f305bcff6adcc8e975bd5b8f354.png)

左寄せは **「いつも通りじゃん！」** という感じですね笑

ですが、このCSSだと `*` を使って文字サイズを大きくした場合、下の行と重なってしまいます。

`[!**********> こんな感じに][******> 重なってしまう]` と書くと、以下の画像のように文字を重ねることができます。(読みづらいので `!` を使った [拡張記法](https://scrapbox.io/help-jp/%E6%96%87%E5%AD%97%E8%A3%85%E9%A3%BE%E8%A8%98%E6%B3%95#59f6c087efa18e0000951556) を使っています)

![overlap](https://gyazo.com/c8ae485a14087fc9ca5e5ed0c4fe738f.png)

これは文字に限らず画像でも同じような結果になるので、上手いこと利用してあげましょう。

こんな感じの透過画像を新しいページの一番上に画像を貼り付けます。(今回は「たいへんよくできました」というページを作りました)

 ![たいへんよくできました](https://gyazo.com/b81474fedad78c7d26cc57306c1cb6ed.png)

そして `[**********< [自分の名前.icon]][**********< [たいへんよくできました.icon]]` と書くことで、以下のように画像を重ねあわせることができます！

![たいへんよくできましたデコレーション](https://gyazo.com/aa3986e358a18e936089f0e0bdf11188.png)

たいへんよくできました :blush:


# UserScriptで遊ぶ

今回は `PopupMenu` をカスタマイズします。
テキストを選択すると上に出てくる黒色のメニューに新たな機能を持ったボタンを追加することができます。

```js
scrapbox.PopupMenu.addButton({
  title: 'タイトル',
  onClick: 選択したテキストを引数として変換したテキストを返す関数
})
```


### Ordered List

書いた文章を一気に箇条書きに変換してくれるUserScriptが欲しかったので作りました。

```js
scrapbox.PopupMenu.addButton({
  title: 'order',
  onClick: text => text.split(/\n/).map((line, index) => `${index+1}. ${line}`).join('\n')
})
```

![Ordered List](https://gyazo.com/aff06557af312185d5d2a5b979ad1266.gif)

自分の思った通りに動作し、それが日常的に使えるので書いていてとても楽しくなりました。
さらにJavaScriptでの文字列処理の勉強にもなっているので一石二鳥といった感じです！


### 汚い文章をいい感じにして欲しい

やたらと文章のスタイルにうるさい人っていますよね、はい僕です。
英数字や括弧は全角じゃなくて半角がいいとか、コードブロック記法や括弧の前後には空白を入れたいなど。
他にもコピペしてきた文章が文字化けしていたり、空白が入りまくっていたりすると見栄えも悪く削除するのも面倒です。
UserScriptで解決してしまいましょう。

ここで気をつける点が一つ、Scrapboxの箇条書きは空白で表現されますが、Tabでも半角でも全角でも同様に箇条書きになります。
しかしそれぞれの文字は入力された状態で保持されるため、少し工夫が必要です。

今回は以下の手順で処理を行っていきます。

1. 箇条書きの先頭を全てTabに置き換える
2. 文中の全角・半角空白を取り除く
3. 文字化けを修正する (今回は `での` を `での` に直す)
4. 全角英数字を半角英数字に置き換える
5. 全角括弧を半角括弧に置き換える
6. 括弧で囲まれた前後に空白を入れる
7. コードブロック記法の前後に空白を入れる

```js
scrapbox.PopupMenu.addButton({
    title: 'format',
    onClick: text => text.split('\n').map(function(line) {
        return line.replace(/^\s*/g, s => s.replace(/\s/g, '\t'))
            .replace(/[ 　]/g, '')
            .replace(/[ぁ-ん|ァ-ヴ]゙/g, s => String.fromCharCode(s.charCodeAt(0) + 1))
            .replace(/[Ａ-Ｚａ-ｚ０-９]/g, s => String.fromCharCode(s.charCodeAt(0) - 0xFEE0))
            .replace('（', '(')
            .replace('）', ')')
            .replace(/\S\(/g, s => s.charAt(0) + ` (`)
            .replace(/\)\S/g, s => ') ' + s.charAt(1))
            .replace(/\S`.*`/g, s => s.charAt(0) + ' ' + s.slice(1))
            .replace(/`.*`\S/g, s => s.slice(0, -1) + ' ' + s.slice(-1))
    }).join('\n')
})
```

![format](https://gyazo.com/911b1d42769b20782bf893415f5b189b.gif)

これに自分が使いやすいような機能を付け加えて使ってみてください！
それにしても、正規表現って素晴らしい...


### 暗号化っぽいことをしてみる

```js
scrapbox.PopupMenu.addButton({
  title: 'encrypt',
  onClick: text => window.btoa(unescape(encodeURIComponent(text))).split('').map(function (c) {
    switch (~~(3 * Math.random())) {
    case 0:
      return ("[| " + c + "]");
    case 1:
      return ("[> " + c + "]");
    case 2:
      return ("[< " + c + "]");
    }
  }).join('')
})
```

![encrypt](https://gyazo.com/d6b1948655ea96e10abcd8962769a19e.gif)

```
[| 4][| 4][| G][< T][> 4][| 4][> G][< u][< 5][> p][| a][| H][< 5][| 6][> u][> g][| 4][| 4][| K][> S][> 5][> p][> q][| X][| 5][< Y][> +][> 3][< 5][< Y][| y][> W][> 4][> 4][| G][| X][> 4][> 4][> G][> m][| 4][< 4][| G][> /][| 4][< 4][> G][| +][< 4][| 4][| G][> X][| 4][| 4][< K][< H][> 4][< 4][> G][< G][> 7][> 7][> y][< B]
```

こんな感じに暗号化。前述のUserCSSを使っています。
復号化のコードも書いてみました。

```js
scrapbox.PopupMenu.addButton({
  title: 'decrypt',
  onClick: text => decodeURIComponent(escape(window.atob(text.replace(/\[[<\|>] .\]/g, s => s.charAt(3)))))
})
```

![decrypt](https://gyazo.com/b7fe8806d7445c96ea4a84a5000288e5.gif)

UserCSSとUserScriptで遊び放題ですね！

# Scrapboxって最高

私は大学でのノートを同学年の友人とScrapboxで取っています。
また、自分だけのprojectを作ってそこにアイデアを残しておいたり、勉強したことをまとめるようにしています。
Scrapboxを使用していく中で、「ここの色を変えたい」や「この機能があったら使いやすい」という点を見つけることが何度かありました。
UserCSS、UserScriptを使えば、自分好みの見た目や機能を追加し、その問題を解決できるかもしれません。