MutationObserverでChatWorkのChrome拡張を作ろうとしたら失敗した

## はじめに

この記事は[Hamee Advent Calendar 2015](http://qiita.com/advent-calendar/2015/hamee)最終日の記事です。
[Hamee](http://hamee.co.jp/)では[ChatWork](https://www.chatwork.com)を活用しており、今回はその`Chrome`拡張を作ろうとして失敗した話を書きます。
本当は完成させてドヤ顔キメたかったんですが無理でした(´・ω・｀)

## Chrome拡張の仕様・やりたいこと

**デスクトップ通知にフィルターをかけて「これは通知する、これは通知しない」を実現したい**

## 経緯

* 本当はデスクトップ通知自体を検知し、その中身に対してフィルターをかけて表示する・表示しないを分けたかった。しかしデスクトップ通知イベントが発火したタイミングを知る術がない（発火したオブジェクトを検知できない）
* 仕方なくデスクトップ通知を自前で実装し、発火させる条件をこちらで制御する手法とした。
* `ChatWork`にはAPIが存在するのでAPIを使用することでより正確に新着メッセージを検知できるが、APIには利用制限がある。メッセージの通知は即時性が大事なので定期的に新着メッセージがあるかアクセスしなければならずすぐに制限に達してしまう。
* 以上の理由からフロントで新着メッセージの有無を検知し、それに対してデスクトップ通知イベントを発火させる方針とした。

## 今回使った技術
### MutationObserver

[MutationObserver](https://developer.mozilla.org/ja/docs/Web/API/MutationObserver)とは、DOMの変更を監視することができる仕組みである。
これを利用して新着メッセージがあるかどうかを監視し検知する。

#### 使い方

```js
var target = document.getElementById("_roomListItems");
var mo = new MutationObserver(notification);
mo.observe(target, options);
```

オブザーバのインスタンスを生成、検知した際に実行するメソッドを引数に渡す。
オブジェクトに対して`observe`メソッドで監視開始。
`target`に監視するDOMの要素を指定する。
今回は新しいメッセージが来るとチャットルームに未読バッチが付くことから、チャットルームリストを監視対象としている。
![スクリーンショット 2015-12-23 18.51.25.png](https://qiita-image-store.s3.amazonaws.com/0/67471/ddbbd39f-4632-7119-f562-57c9fc229dc2.png)


### Notifications API

[Notifications API](https://developer.mozilla.org/ja/docs/Web/API/Notifications_API)とはデスクトップ通知を表示させるためのAPIである。
これにより自由にデスクトップ通知を表示させることができる。中の文言等もカスタマイズ可能。

#### 使い方

```js
var title = "タイトルテスト"
var options = {
    body: "内容テスト",
    icon: "https://tky-chat-work-appdata.s3.amazonaws.com/icon/ico_group.png"
}
var notify_obj = new Notification(title ,options);
```

![スクリーンショット 2015-12-23 19.03.18.png](https://qiita-image-store.s3.amazonaws.com/0/67471/66e84669-1637-0ca6-91bf-db0a0d62800f.png)

こちらもコードを見れば分かると思うが`Notification`のオブジェクトを作る際に表示する内容を引数で渡せばそのまま表示してくれる。

## コード

そこそこ長くなったのでここに生のコードを記さずにgithubのリンクのみとする。
https://github.com/yamamoto-hiroya/chatwork_notify/blob/master/js/chatwork_notify.js
結論だけ書く。
失敗した。~~失敗した失敗した失敗した私は失敗したこんな拡張は無意味だった~~

### 仕組み

* チャットルームリストのDOM要素を監視
* 未読バッチがあればイベント発火
* そのチャットルームの最新のチャットのアイコンと内容を取得してデスクトップに通知
* 各チャットルームにはそれぞれ通知をon/offできるようにボタンを設置
* このon/offの設定によってデスクトップに通知を出すかどうかを決めることができる（フィルタリング）
* チャットを通知したかどうかを把握するために`message_id`を画面にキャッシュ

## 失敗原因

最大の失敗理由は`ChatWork`のDOM要素の仕様。
チャット内容がチャットルームを選択していないとそもそもDOM要素にないので取得できない。

* 未読チャットのバッチを検知
* そのチャットの最新のチャットを取得したいがために該当のチャットルームへ移動
* 最新のチャットの取得が可能になるがチャットを表示してしまうので既読になってしまう
* 通知されたら既読になってしまうためチャットを見逃すリスクが高すぎる

また、チャットルームリストに通知のon/offのボタンを設置したが、チャットルームリストは定期的に更新されてしまうためボタンが消えてしまう。
その他にも場当たり的な対応をしている箇所がいくつかあり、精度もイマイチで使い物にならない。

## まとめと反省

今回諸々の事情で全部フロントで解決しようと思ったが、色んなテクニックを駆使して1つ1つの問題を突破していく過程はなかなか面白かった。
今抱えてる問題もチャットを未読にする、という方法で解決しようと試行錯誤中。
ただ全部フロントでやるのはさすがに無茶だったなと反省。
やりたいことを満たすためには別に全部フロントでやる必要はないので、次はサーバをかまえてAPIを利用して定期実行で最新チャットがあるかどうかを確認する方法を取ろうかなと検討中。
またはデスクトップ通知を検知する方法を調べ、その通知の中身に対してフィルタリングをかける（これができると1番早いし嬉しい）
やりたいことに対する解決策は無数にあるはずなので1つダメでもへこたれない気持ちが大事ですね。
今回で`MutationObserver`と`Notifications API`の使い方が分かったので別のことにも活かせそうです:smile:

## おわりに

この記事で[Hamee Advent Calendar 2015](http://qiita.com/advent-calendar/2015/hamee)は終わりです。
Hameeという組織としてアドベントカレンダーを25日フルで埋められたことを大変嬉しく思っています。
エンジニアたるもの、常に技術向上し常にアウトプットしていけるといいなと思っています。
また、Hameeでは[Qiita Organization](http://qiita.com/organizations/hamee)のアカウントがあるのでそちらもチェックして頂けると嬉しいです（宣伝乙）