「役立たず」の類語に煽られる方法

#「役立たず」の類語に煽られたい
Weblio類語辞典にて「役立たず」と検索すると、一部の人が喜ぶ言葉が並びます。
[Weblio類語辞典「役立たず」](https://thesaurus.weblio.jp/content/役立たず)
この記事では、ブックマークレットを用いた方法と拡張機能を用いた方法の、2通りの方法で、言葉の区切りに用いられている「・」を「♥」にしたいと思います。

##対象読者
- M～ドMらへんの人
- JavaScriptの基本知識のある人
- ブックマークレットに興味がある人
- ブラウザのアドオンに興味がある人

## ブラウザの表示するページの内容を書き換えるには
今あなたが見ている記事は、サーバー上にあるhtmlデータ等々をダウンロードし、使用しているブラウザが解釈して表示しています。
したがって、ダウンロードした後の、端末内にあるデータについて改変を施せばページの内容は簡単に書き換わります。

もっとも単純な方法は開発者ツールを用いて変更することでしょうか。
「F12」を押せば多くの場合出てきます。
インスペクタータブで適当に文字を変えれば、即座にページ側に反映されるでしょう。

しかし、この方法では都度ページから書き換えたい内容を探して手動で書き換えなくてはならず、面倒です。
こういった何度もする作業を自動化するのが我々プログラマーというものでしょう。

## Method1：ブックマークレットを使う
さて、いろいろすっとばして、類語のページにて次のコードを開発者ツール内のコンソールタブに入力し、実行してください。

```javascript
document.body.innerHTML = document.body.innerHTML.replace(/・/g, "♥")
```

内容は単純。ページのソースに含まれる全ての中点「・」をハート「♥」へ書き換えるものです。
どうでしょうか。ちゃんと~~こうふｎ~~変更できましたでしょうか。

コンソールに直接入力するのは面倒なので、ブックマークレットにしておきましょう。

###ブックマークレットとは
ブックマークから小さなJavaScriptコードを実行する仕組みのことです。
通常のhttpやhttpsのプロトコルではなく、「javascript:」から始まるURLをブックマークし、開くことで実行されます。

### では作りましょう
すっとばしてURL（に入力するコード）をさくっと書きます。

```javascript
javascript:document.body.innerHTML = document.body.innerHTML.replace(/・/g, "♥")
```
これをブックマークして実行していただければ、コンソールに入力したときと同じような変更が加わるでしょう。そりゃ同じコードですから。

うまくブックマークに追加できない場合は、ひとまず適当にこのページをブックマークし、名前を変えておき、ブックマークのメニューから目的のブックマークのプロパティなりからURLを編集するといいでしょう。

### ましなコードにする
多くの人は思うでしょう。このコードは無駄が多いと。
innerHTMLなんてなるべくtextContentにして避けてきた人が多いと思います。
そもそも、今回の目的は、類語の区切り文字である中点「・」を変更したいだけですから、今のコードではページ全体に対して書き換えて、DOMを全て作り変えるのでかなり重たい処理になってしまいます。
分かり易いところでは、最上部（スマホでは最下部）にある、他の辞書の「・」まで変更してしまい、「英和♡和英辞典」などになってしまっています。

類語が並んでいるのはtableタグですから、tableタグ、かつ、「・」を含むものだけにしぼりましょう。

```javascript
(() => {
  const table = document.querySelectorAll("table");
  for (const e of table) {
    if (/・/.test(e.textContent)) {
      for (const r of e.rows) {
        r.cells[1].innerHTML = r.cells[1].innerHTML.replace(/・/g, "♥");
      }
    }
  }
})()
```

名前空間を汚染すると面倒かもしれないので、即時関数にしておきます。
コンソールに入力すると期待した動作になりますね。
完全に類語を表示しているノードを指定することも可能ですが、柔軟性に乏しくなったり、コード量が増えたりするので今回は割愛します。

ブックマークレットにするときは、基本的にはショートコーディングと呼ばれるコーディングの仕方をします。ブックマークに入力できる文字数は制限されていますから、なるべく短くコーディングしなければならないのですね。

```javascript
javascript:((d, p, c, iH) => {
  for (const e of d.querySelectorAll("table"))
    if (p.test(e.textContent))
      for (const r of e.rows)
        r[c][1][iH] = r[c][1][iH].replace(p, "♥")
})(document, /・/g, "cells", "innerHTML")
```

まあこんなところでしょう。見栄えのために入れていますが、改行と空白も不要ですから

```javascript
javascript:((d,p,c,iH)=>{for(const e of d.querySelectorAll("table"))if(p.test(e.textContent))for(const r of e.rows)r[c][1][iH]=r[c][1][iH].replace(p,"♥")})(document,/・/g,"cells","innerHTML")
```

このような感じになります。

これをブックマークから起動してください。ちゃんとできてますか？
実は「javascript:」から始まるこのプログラムは、開発者ツールのコンソールからでも実行可能ですので、そちらからデバッグしてもらっても構いません。このときはラベルとして働くのです。

さて、これでいつでもワンクリック・ワンタップで煽られることができますね。
しかし、こんなので満足できますでしょうか？

## Method2: 拡張機能にする
### 拡張機能について
Chromeでは拡張機能、Firefoxではアドオンと呼んだりしますが、ブラウザ内で実行するプログラムのことです。
イベントドリブンな感じなので、ブラウザの起動時、新しいタブを開いたとき、特定の文字列を含むURLを開いたときなどに、任意のプログラムをページ内外問わず実行できます。

Firefoxの開発元であるMozillaさんはWebextensionsというものを作っており、ブラウザに依存しない拡張機能の開発環境として銘打っています。

これはChromeやOperaの拡張機能のプログラムに少し変更を加えるだけでWebextensionsに対応させることができるものなのですが、とにもかくにもChromeでちゃんと拡張機能を作りたければ、少額ではあるもののお金払って開発者登録しないといけないので、面倒なのでWebextensionsでFirefox向けに作りましょう。

先述の通り、少し変更するだけでChromiumでも動きますので、あなたがそちらを望むのであればそのようにするとよいでしょう。いうまでもありませんね。

また、Android版Firefoxにも拡張機能はインストールできます。うれしいですか？
（上記の文を書いたときは使えたのですが、2020/08/17のアップデートで拡張機能は使えなくなりました。大規模なアップデートで~~大顰蹙を買っｔ~~　いや失礼、大楚蟹を買っているようですね。そのうち戻ってくるといいですが。。。）

iOS版はサンドボックスの制約が厳しいようで、純正Safariでさえ拡張機能を入れられなかったように思いますので、ブックマークレットで我慢してください。

### ファイル構成
拡張機能では、ページ側で動くコンテンツスクリプトと、バックグラウンドで動くバックグラウンドスクリプトを軸に作っていくことになります。

分かりにくいかもしれませんが、コンテンツスクリプトはページ上で実行されますので、そのWebページにscriptタグで埋め込んだ時のような変更を加えることができます。すなわち、DOMをいじるならこちらです。
これはURLの一致などをトリガーに実行され、実行のタイミングも選べます。

バックグラウンドスクリプトは、DOMにアクセスはできませんが、ブラウザ側と連携できます。
ページとは独立して常に実行可能であり、ページの滞在より長期にわたって実行できます。
また、コンテンツスクリプトともメッセージをやり取りできますから、これを起点にページ側で変更を施すことも可能です。

他には拡張機能の設定画面を作るオプションと、拡張機能を入れた後に右上に並ぶアイコンやそれをクリックしたときのポップアップなどのUIコンポーネントと、拡張機能に必ず一つ欲しいマニフェストファイルでもって構成されます。

したがって、今回ではコンテンツスクリプトとマニフェストだけあれば十分です。

```
YakuTatazu/
　├ manifest.json
　└ content_scripts.js
```
こんな感じですかね。好きにしてください。

### コンテンツスクリプト
コンテンツスクリプトの中身は先ほどと全く同じで構いません。どれを選んでもいいですが、無難にショートコーディングしてない見やすいやつを選べばよいと思います。
名前空間は独立なので、即時関数はなくしてもかまいません。

```javascript:content_scripts.js
const table = document.querySelectorAll("table");
for (const e of table) {
  if (/・/.test(e.textContent)) {
    for (const r of e.rows) {
      r.cells[1].innerHTML = r.cells[1].innerHTML.replace(/・/g, "♥");
    }
  }
}
```

innerHTMLはセキュリティの問題で推奨されませんので、一般に公開できません。
公開したい人はinsertAdjacentHTMLを使うとか、なにかしら別の表現を検討してください。

### マニフェスト
マニフェストでは、拡張機能の名前や説明、バージョン情報などを取りまとめますが、大事なのはコンテンツスクリプトの実行タイミングを決定するのもこのファイルであるというところです。

```manifest.json
{
	"manifest_version": 2,
	"name": "役立たず♥",
	"version": "1.0",
	"content_scripts": [
		{
			"matches": [
				"https://thesaurus.weblio.jp/content/%E5%BD%B9%E7%AB%8B%E3%81%9F%E3%81%9A"
			],
			"js": ["content_scripts.js"],
			"run_at": "document_end"
		}
	]
}
```

いやはや、シンプルですね。
全ての類語で煽られたい方は、`content_scripts.matches`の「役立たず」をURIエンコーディングした「%E5%BD%B9%E7%AB%8B%E3%81%9F%E3%81%9A」の部分をワイルドカード「*」にすればいいと思いますが…さすがにドン引きです。

### デバッグ
Firefoxの場合、右上のハンバーガーメニューから、アドオン＞歯車アイコン＞アドオンをデバッグ＞一時的なアドオンを読み込む、として、`manifest.json`を選択すればFirefoxを再起動するまで一時的に有効になります。
この状態で[Weblio類語辞典「役立たず」](https://thesaurus.weblio.jp/content/役立たず)を開いてみましょう。
どうです？煽られました？
うまく動かない場合、エラーは開発者ツールのコンソールに出力されますので、適宜修正しましょう。
なお、backgroundスクリプトの場合は拡張機能専用のコンソール側にエラーが出力されます。

### パッケージ化
さて残すはパッケージ化です。拡張機能パッケージはただのzipballですから、zipに固めてやって拡張子を「xpi」にすればいいのですが、署名が必要ですので、zipのままでも構いませんから[アドオン開発センター](https://addons.mozilla.org/ja/developers/)にアップロードして署名しましょう。
web-extを使う環境が整っているのなら`web-ext sign`を使ってもらって構いません。

zipに固めるときの注意としては、`manifest.json`を含むディレクトリで圧縮すると、展開（高齢者の言う解凍）したときにいったんフォルダができてしまいますので、`manifest.json`と`content_scripts.js`を選択して圧縮するようにすれば間違いないと思います。

署名にはFirefoxアカウントが必要です。その他の手順についてはフィーリングでいけます。

ダウンロードした署名済みxpiファイルをドラッグ＆ドロップするか、ハンバーガーメニューからアドオンを開いてファイルからインストールするなどしてインストールすれば、あとは全自動で煽ってくれるようになります。
ファイルが見つからない場合は、アドオン一覧のページの「その他＞ステータスとバージョンを管理」から任意のバージョン（まだ1.0しかないと思いますが）のファイルをダウンロードまたはインストールできます。
この状態だとブラウザを再起動しても問題ありません。

ちなみにこんな恥ずかしい拡張機能を公開したら後悔すると思ったので、私は公開していませんので自分で作ってください。先述の通り、innerHTMLを用いないプログラムにしてくださいね。

それから、今回は奇しくも、そのままChromiumでも動作します。名前空間がChromeとBrowserだったり、若干APIの実装に差異があったりするだけですから、今回のように拡張機能のAPIを叩かないものはどちらでも使用可能になる場合が多いです。

## さいごに
この拡張機能をインストールしていたことを忘れて、他人の前で煽られても当方は一切関知しません。
こんな記事で拡張機能業界が潤えば面白いと思います。
Android版Firefoxのアドオン対応カムバック！！！