小説家になろう閲覧用の便利ブックマークレット

[小説家になろう](https://syosetu.com/)の閲覧時に便利な[ブックマークレット](https://ja.wikipedia.org/wiki/%E3%83%96%E3%83%83%E3%82%AF%E3%83%9E%E3%83%BC%E3%82%AF%E3%83%AC%E3%83%83%E3%83%88)のメモです。

ブックマークレットとはざっくり言うと、ブラウザのお気に入りに登録して使う形のJavaScript関数です。
登録方法はこちらの記事（[ブックマークレットの登録方法 - Qiita](https://qiita.com/aqril_1132/items/b5f9040ccb8cbc705d04)）が分かりやすいと思います。

## 作成のコツなど

まだブックマークレット作りに慣れていませんが、分かった範囲で書いておきます。

### クロージャにする

つらつら書くのも面倒だし副作用が出そうなので、クロージャ形式にします。
どうせ使う`document`は１文字引数で渡すと少し文字数を減らせます。
`document.querySelector`なんかも１文字変数にバインドしておくと便利かもしれません。

```javascript:クロージャ例
((d)=>{
  s=d.querySelector.bind(d),
  // 処理
})(document)
```

参考：[Bookmarkletの作成Tips - kotamat's site](https://kotamat.com/post/bookmarklet-tips/)

### minify

行を連結して、リテラル以外のスペースを削ります。

### エンコード

ブックマークレットでは使える文字列に制限があるため、URIエンコード（`encodeURI()`）する必要があります。
ただエンコードせずにブックマーク登録してもそこそこうまくいったので、挙動がおかしいときにやるだけでもよいかもしれません。
エンコードせずに使える文字は`A-Z a-z 0-9 ; , / ? : @ & = + $ - _ . ! ~ * ' ( ) #`のようです。なのでクオーテーションはシングル、ifは短絡演算とコンマ演算にするとエンコード不要で少し短くできます。
`encodeURIComponent()`相当のエンコード（`A-Z a-z 0-9 - _ . ! ~ * ' ( )`以外）が必要かもしれませんが、調べてもよく分かりませんでした。

参考：[encodeURI() - JavaScript | MDN](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/encodeURI)

WindowsのFirefox＆Edgeと、iPadOSのSafariでは、以下のエンコードくらいでよさそうでした。

```text: 主な文字の対応
{   }   <   >   "   %   \
%7B %7D %3C %3E %22 %25 %5C
```

`console.log(encodeURI("minifyしたコード（要"\のエスケープ）"))`とするのが手っ取り早いです。

### その他

#### Bookmarkletify

vscode用の機能拡張がありました。参考までに。

[Bookmarkletify - Visual Studio Marketplace](https://marketplace.visualstudio.com/items?itemName=saasan.bookmarkletify)

## 横幅拡大

2023/01/01現在、小説家になろうは小説本文の横幅が`600px`に固定されています。
長い小説だと縦に間延びして読みづらいので、横幅を拡大して１行の文字数を増やします。
倍率は[prompt()](https://developer.mozilla.org/ja/docs/Web/API/Window/prompt)なんかで対話的にしてもよいかもしれません。

```javascript:横幅拡大（プレーン）
((d)=>{
  s=d.querySelector.bind(d),
  (x = '90%'),
  x &&
    ((s('#novel_color').style.width = 'auto'),
    (s('#novel_honbun').style.width = x))
})(document)
```

```javascript:横幅拡大（minify＆エンコード）
javascript:((d)=%3E%7Bs=d.querySelector.bind(d),(x='90%25'),x&&((s('#novel_color').style.width='auto'),(s('#novel_honbun').style.width=x))%7D)(document)
```

## 空行除去

むやみやたらと空行が入って読みにくい記事があります。隔行に空行が入っているようなの。
小説家になろうでは、空行は`<p id="L1"><br></p>`のような形で入っています。
空白文字だけの行とかもあってややこしい。

### １つずつ削除

```javascript:空行除去（プレーン）
((d)=>{
  s=d.querySelector.bind(d),
  s('#novel_honbun').innerHTML = s('#novel_honbun').innerHTML.replaceAll(/<p id="L\d+">(?:<br>|[ 　]+)<\/p>\n(?!<p id="L\d+">(?:<br>|[ 　]+)<\/p>\n)/g, '')
})(document)
```

```javascript:空行除去（minify＆エンコード）
javascript:((d)=%3E%7Bs=d.querySelector.bind(d),s('#novel_honbun').innerHTML=s('#novel_honbun').innerHTML.replaceAll(/%3Cp%20id=%22L%5Cd+%22%3E(?:%3Cbr%3E%7C%5B%20%E3%80%80%5D+)%3C%5C/p%3E%5Cn(?!%3Cp%20id=%22L%5Cd+%22%3E(?:%3Cbr%3E%7C%5B%20%E3%80%80%5D+)%3C%5C/p%3E%5Cn)/g,'')%7D)(document)
```

### 複数の空行を１つにまとめつつ、単体の空行を削除

```javascript:空行圧縮（プレーン）
((d)=>{
  s=d.querySelector.bind(d),
  s('#novel_honbun').innerHTML = s('#novel_honbun').innerHTML.replaceAll(/(<p id="L\d+">(<br>| +|　+)<\/p>\n)+/g, (m,p1)=>((m.match(/\n/g)?.length>1) ? p1 : ''))
})(document)
```

```javascript:空行圧縮（minify＆エンコード）
javascript:((d)=%3E%7Bs=d.querySelector.bind(d),s('#novel_honbun').innerHTML=s('#novel_honbun').innerHTML.replaceAll(/(%3Cp%20id=%22L%5Cd+%22%3E(%3Cbr%3E%7C%20+%7C%E3%80%80+)%3C%5C/p%3E%5Cn)+/g,(m,p1)=%3E((m.match(/%5Cn/g)?.length%3E1)?p1:''))%7D)(document)
```

<!--
PDFタイトル

javascript:(function()%7Bconst%20e=document.createElement('input');e.value=%60%5B$%7Bdocument.querySelector(%22%23pdf_contents%20strong%22).innerText.replace(%22作者名：%20%22,%22%22).trim()%7D%5D%20$%7Bdocument.querySelector(%22body%3Ediv%3Ediv%3Ea%22).innerText%7D%60;document.querySelector('body').append(e);e.select();document.execCommand('copy');e.remove();%7D)();
-->

# 2024-09の変更対応

最近のブラウザだとエンコードやminifyせずとも大抵動くのでそのまま。

```javascript:横幅拡大
javascript:((d) => {
  s = d.querySelector.bind(d);
  s('.l-main').style.width = 'auto';
})(document);
```

```javascript:空行圧縮
javascript: ((d) => {
  s = d.querySelector.bind(d);
  honbun = s('.js-novel-text.p-novel__text:not(.p-novel__text--preface)');
  honbun.innerHTML = honbun.innerHTML.replaceAll(
    /(<p id="L\d+">(<br>| +|　+)<\/p>\n)+/g,
    (m, p1) => (m.match(/\n/g)?.length > 1 ? p1 : '')
  );
})(document);
```