発狂したときにすべてを爆発できるChrome拡張機能を作った話

こんにちは、[Yui](https://twitter.com/yui_active)です。

皆さんは自分が書いた過去の記事とかを読み返したときに、**あああああああ恥ずかしい〜〜〜〜〜全部爆発させたい〜〜〜〜〜〜**と思ったことありませんか？

あるいはちょっとむずかしい記事を読んだときとか、**難しいんだよ！！全部爆発させてやろうか？？？？？？**とキレたことはありませんか？？

ありますよね？？
**ありますね。**

ということで、今回そんな全人類の要望を叶えるchromeの拡張機能を作ったのでその紹介をします。

## どんな機能か

<blockquote class="twitter-tweet" data-partner="tweetdeck"><p lang="ja" dir="ltr">自分が書いた記事とか読んでたら、うるせ〜〜〜〜全部爆発してやる〜〜〜〜〜っていう気持ちになることってありますよね。そんなときに使えるchromeの拡張機能作りました。 <a href="https://t.co/ruGiOn3EKF">https://t.co/ruGiOn3EKF</a> <a href="https://t.co/aTp7YTd0Oh">pic.twitter.com/aTp7YTd0Oh</a></p>&mdash; ゆい 🌘 Yuiko Ito (@yui_active) <a href="https://twitter.com/yui_active/status/1347886993733267458?ref_src=twsrc%5Etfw">January 9, 2021</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

こちらのツイートにある通り、クリックしたら爆弾が置かれて、500ミリ秒後にその爆弾が破裂してそこにある文字を吹き飛ばすような機能です。

ただ、このツイートをしたあとに気がついたんですが、このままだと**拡張機能を自分でオフにしない限り常に爆弾が置かれてしまうので大変鬱陶しい**です。

例えば、起動していることを忘れて、とある記事の一部をコピーしたいな〜〜なんて思った暁にはこうなります。

<a href="https://gyazo.com/28d9802a6eeebad412587aba39991fc1"><img src="https://i.gyazo.com/28d9802a6eeebad412587aba39991fc1.gif" alt="Image from Gyazo" width="1000"/></a>

ストレス発散のために作ったのに、これではストレスが溜まってしまいますね。

ということで、公開する前に以下の機能を追加でつけることにしました。

- デフォルトでは爆発機能をオフにしておく
- アイコンをクリックするとポップアップが出て爆弾を置けるようにするか選択させる
- ユーザーのブラウザ言語を取得してポップアップを自動で英語又は日本語で表示する（無駄機能）

## インストール方法

以下からインストールしてください。

https://chrome.google.com/webstore/detail/site-bomb/hnnabnffilimfgdcinlijkjkdemdonea/related?hl=ja&authuser=0

Chromeの拡張機能なので基本Chromeでしか使えません。
調べるとこちらで色々やればfirefoxでも使えるようになるみたいでしたが、なんだかめんどくさそうなので今回は割愛します。


## 使い方

使い方は非常に簡単です。

- この拡張機能をインストールする
- 爆発させたい記事を見つける
- 爆弾アイコンをクリックして、OKをクリック
- あとは爆弾を置くだけ！

試しに、こちらの弊記事[「友達がいなくて寂しいので友達を作った（LineBot）」](https://qiita.com/Yui_active/items/04ccc89164c6bb57b09b)を爆発させてみましょう。。

<a href="https://gyazo.com/709b24a394a108f2178405f4ee49e085"><img src="https://i.gyazo.com/709b24a394a108f2178405f4ee49e085.gif" alt="Image from Gyazo" width="1000"/></a>


見事このように木っ端微塵にできました。（爆弾を10個ぐらいおいたあと↓）

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/670446/5f143ae9-f87a-03ad-3815-f955eb7925e0.png)

## 利用上の注意

利用にあたって、いくつかUI面でクソな部分があります。

- ポップアップのOKを押したあとにすぐに爆弾を置けない。

これはbackground.jsでcontent_scriptsを読み込みさせてるからですかね..。多分1クリック目でjsファイルを読み込むので、実際に爆弾を置けるのは2クリック目以降になるようです。
**早く爆発させてくれよ！こっちは発狂しそうなんだよ！**という皆さんには非常に申し訳ないのですが、そこは一息ついて、OKを押したあとに一度どこか画面をクリックしてから、思う存分爆弾を置いて貰えればと思います。

- 一度読み込むとリロードするまで止まらない

これは私の書き方がまずいのかもしれないんですが、アイコンのクリックでオンオフの切り替えをしようとしたところ、オフからオンにはできたんですが、オンからオフにはできなかったので、もし止めたい！となったらリロードしてください。笑
↑もちろんこれは同じページ内の話です。**一度起動をしても、違うページの場合はまた再度オフからのスタートになる**ので安心してください。

- 逆に常に起動ができない

今回、デフォルトでは爆弾を置くためのjsファイルは読み込まないようになっています。
なので、**どんなページでも常に爆発させたい！全部を爆発してやる！**という要望には答えられず申し訳ないのですが、毎回クソなページを見つけたたびにアイコンをクリックしてください。（常についてたら鬱陶しいと思ったのでこれは仕様上あえてこうしてます。）

- リロード後、また同じページを爆発させたいとなったときにアイコンをクリックしてもポップアップが再度開かない。

これは私が``browser_action``部分の設定をあまり理解してないからですね..。一度止めてしまうと、スーパーリロードをかけても再度同じページを爆発ができないんですよね..。でも、安心してください、**別タブで開き直すと再度爆弾がおけます。**

## 簡単に技術的な話など

まず、chromeの拡張機能に必要な``manifest.json``はこんな感じで書いています。

```json:manifest.json
{
  "name": "Site Bomb",
  "version": "1.0",
  "description": "You can drop bombs on any pages",
  "permissions": ["activeTab", "http://*/*", "https://*/*"],
  "background": {
    "scripts": ["background.js"],
    "persistent": false
  },
  "icons": {
    "16": "16.png",
    "48": "48.png",
    "128": "128.png"
  },
  "browser_action": {
    "default_title": "Site Bomb"
  },
  "author": "YuikoIto",
  "manifest_version": 2
}
```

多言語化を本格的に行うためには、[こちら](https://developer.chrome.com/docs/extensions/reference/i18n/)で書いてあるとおり、``_locales``ディレクトリ内でファイルをそれぞれ作らないといけないみたいなんですが、今回はポップアップの言語をちょっと変えればいいだけだったので、もっと簡単にbackground.jsでこのように書くことにしました。

```javascript:background.js

const browserLanguage = function () {
  const ua = window.navigator.userAgent.toLowerCase();
  try {
    // chromeは以下で利用者のブラウザ言語を取得できる
    if (ua.indexOf("chrome") != -1) {
      return (
        navigator.languages[0] ||
        navigator.browserLanguage ||
        navigator.language ||
        navigator.userLanguage
      ).substr(0, 2);
    }
    // それ以外（例えばIEなど）は下記で取得する必要がある
    else {
      return (
        navigator.browserLanguage ||
        navigator.language ||
        navigator.userLanguage
      ).substr(0, 2);
    }
  } catch (e) {
    return undefined;
  }
};

let toggle = false;
chrome.browserAction.onClicked.addListener(function (tab) {
  if (!toggle) {
    explosion();
  }
});

function explosion() {
  if (browserLanguage() == "ja") {
    if (window.confirm("爆弾を置く! \n (最初だけ2回クリックしてください)")) {
      toggle = true;
      chrome.tabs.executeScript({ file: "explosion.js" });
    }
  } else {
    if (window.confirm("Drop bombs on this page! \n (Click twice for the first time only)")) {
      toggle = true;
      chrome.tabs.executeScript({ file: "explosion.js" });
    }
  }
}

```

重複してるので、あんまりよくないな〜とは思いつつ、開き直ってこんな感じで簡単に書いちゃいました。

``chrome.tabs.executeScript({ file: "explosion.js" });``この部分で今回の肝となる``explosion.js``を読み込んでいます。


``explosion.js``に関しては約400行あるのでここで書くことはやめておきますが、ロジックだけ説明すると、以下のような感じです。

- まずページの文字を``text.split("");``で一文字ずつ別々でラップします。
- 上記の文字に``translate``や``rotate``を別途与えてそれぞれにcssを追加しています。
- 常に上記の文字が上に来るようにラップする際にデフォルトでz-indexを設定しています。

上記に合わせて別途``.split("&nbsp;")``でそれぞれの行に合わせても取得して、できるだけ元の文章の改行に変更しないようにしてたりするんですが、どうしても１文字ずつラップをしている関係でこのjsファイルを読み込むと文字間隔などが若干変わったりします...。
**まあどうせすぐに爆発させるので関係ないですね！**

この実装のために、こちらのjsfiddleのコードを参考にしました。→http://jsfiddle.net/dNXVx/37/

[こちらの質問](https://stackoverflow.com/questions/6538546/jquery-animated-text/6538963#6538963)ですごい人が返答してくれていた部分です。
## 最後に

色々不備はありますが、リリースされたらぜひ使ってみてください！
現在審査中なので近日中には公開されるはずです！（多分...きっと...）

1/15追記　公開されました！！遊んでください！！

## 参考

- [API Reference](https://developer.chrome.com/docs/extensions/reference/)
- [壁を殴れるChrome拡張機能を作った💪💪💪](https://qiita.com/Morix1500/items/a671f90c8517988e3c0d)
- [Chrome拡張の作り方 (超概要)](https://qiita.com/RyBB/items/32b2a7b879f21b3edefc)
- [Qiitaをより便利にするChrome拡張機能をつくりました](https://qiita.com/howdy39/items/e6136b8454099ebfef29)
- [Chromeブラウザの拡張機能を作ってみたい初心者向けに開発方法を紹介！【サンプルあり】](https://qiita.com/guru_taka/items/37a90766f4f845e963e5)
- [fontbomb](http://fontbomb.ilex.ca/)