Chrome extensionでselectのリストをフィルタする

会社で使ってるツールでselectの中身(dropdown)が大量に出てくるページがあって、
毎度探すのが辛いので調べました。

https://chrome.google.com/webstore/detail/select-filter/pakilipafnfgghkpekpnkbfgjdmodmai?hl=ja

で「CHROMEに追加」すれば各ページ内のselectがフィルタできるようになります。

ただ、どのページでも使えるかどうかは怪しいですね。
単純にoptionを絞り込んでるのでselectedIndexで管理するようにjavascript組まれてたらNGだし、
動的に生成されたselectには適用できない動作している気がします。
あと、多くselectが配置されているページでの利用は少し辛いです。

なので試しに遊びで自作してみました。

自作するのに参考にしたページは下記です。
http://qiita.com/suin/items/5e1aa942e654bce442f7

# ファイル構成
```
├icons
│├icon16.png
│├icon48.png
│└icon128.png
├manifest.json
└selectbox-filter.js
```

iconはいい感じに作ってください。

# manifest.json
```json:manifest.json
{
  "name": "Select options filter",
  "version": "0.0.1",
  "manifest_version": 2,
  "description": "selectをCtrl+Clickするとフィルタモードになります",
  "icons": {
    "16": "icons/icon16.png",
    "48": "icons/icon48.png",
    "128": "icons/icon128.png"
  },
  "content_scripts": [
    {
      "matches": [
        "<all_urls>"
      ],
      "js": [
        "selectbox-filter.js"
      ]
    }
  ],
  "web_accessible_resources": [
    "icons/icon16.png"
  ],
  "permissions": [
    "<all_urls>"
  ]
}
```
content_scriptsに書くとページ操作できるみたいです。
web_accessible_resourcesに記載すると、chrome.extension.getURL()でのURLが使える様子です。

# selectbox-filter.js
```js:selectbox-filter.js
(function() {
  'use strict';
  let input = document.createElement('input');
  input.setAttribute('placeholder', 'enter filter keyword');
  input.style.backgroundImage = 'url("' + chrome.extension.getURL('/icons/icon16.png') + '")';
  input.style.backgroundRepeat = 'no-repeat';
  input.style.backgroundPosition = 'right';
  let select;
  //documentのclickにイベント登録
  document.addEventListener('click', function(e) {
    if (e.ctrlKey && e.target.tagName.toLowerCase() === 'select') {//Ctrl+Click　かつ　selectがClickされた場合フィルタモード開始
      select = e.target;
      input.value = '';
      select.parentElement.insertBefore(input, select);
      input.focus();
    }
  });
  input.addEventListener('keyup', function() {
    let value = input.value;
    let options = select.getElementsByTagName('option');
    let match = value ? function(option) {
      return option.textContent.indexOf(value) > -1;
    } : function(option) {
      return true;
    };
    let dispOpt = [];
    for (var i = 0; i < options.length; i++) {
      if (match(options[i])) {
        options[i].style.display = '';//displayでフィルタ制御
        dispOpt.push(i);
      } else {
        options[i].style.display = 'none';//displayでフィルタ制御
      }
      if (options[i].textContent === value) {//完全一致があったなら選択させる
        select.selectedIndex = i;
      }
    }
    if (dispOpt.length === 1) {//フィルタした結果が1件なら選択させる
      select.selectedIndex = dispOpt[0];
    }
  });
})();

```

# 動作
selectをCtrl押しながらClickするとフィルタ用のinputが横に出てきて、入力すると、selectの中身が絞られます。

左から、通常→Ctrl+Clickしたあと→入力した後のselectの状態
![スクショ.jpg](https://qiita-image-store.s3.amazonaws.com/0/84259/425c650e-59de-173e-7757-300df1d75685.jpeg)

# やりたかったこと
* displayでフィルタするのでselectedIndexを汚さない（はず）
* 一つのselectに対してだけinputを表示するのでページが大きく崩れない。
* documentのクリックイベントで制御するので追加で配置されたselectでも動作する。


# 入手
作成したものをwebstoreに公開しました。
https://chrome.google.com/webstore/detail/select-box-filter/ohgdgoglcbcfofphmmnkkdbpffklhjgh

ソースはgithubにあげています。
https://github.com/ota-meshi/chromeextension_selectbox_filter