表示中のページのタイトルとURLをキーボードショートカットでクリップボードに保存するChrome拡張を作ってみた


## はじめに
自分が見ている記事を誰かに共有する際、URLだけを共有すると後で見返した時に「あれ、これって何の記事だったっけ…？」「タイトルも書いておいた方がよかったかも…」と思うことがあるかと思います。

そのため、個人的には

* 表示中のページのURLだけでなくタイトルも一緒に取得できて、
* さらに言えば、キーボードショートカットで実行できて、
* 欲を言うと、クリップボードに保存することができる。

といった機能を持つChrome拡張があれば便利だろうと思い、勉強も兼ねて作ってみることにしました。

この記事では、 **表示中のページのタイトルとURL** を **キーボードショートカット** で **クリップボードに保存する** ためのChrome拡張を作成するにあたって調べた情報などをまとめていきます。

## 表示中のページのタイトルとURLを取得する
開いているページ（タブ）のURL、タイトルなどを取得するために`chrome.tabs API`を使用します。

まず、`manifest.json`の`permissions`に`tabs`を追加します。

```json:manifest.json
[
    ...
    "permissions": [
        "tabs"
    ],
    ...
]
```

選択されているタブのTabオブジェクトを取得するには`chrome.tabs.getSelected(integer windowId, function callback)`を使用します。`function callback`を`function(Tab tab) { ... }`のようにすることで、Tabオブジェクトを取得できます。

試しに、タイトルとURLをアラートで表示してみます。`background.js`の内容は以下の通りです。

```js:background.js
chrome.tabs.getSelected(null, function(tab) {
    alert(tab.title + "\n" + tab.url);
});
```

`chrome.tabs API`を使用すると、タブの読み込みが完了したかどうかのステータス（`tab.status`）、FaviconのURL（`tab.favIconUrl`）、開いているタブの横幅（`tab.width`）や縦幅（`tab.height`）などを取得することもできます。

## キーボードショートカットを実行する
Chrome拡張でキーボードショートカットを実現するには、`chrome.commands API`を使用します。

`manifest.json`に`commands`を追加し、イベント名・キーパターン・イベントの説明を指定することで、特定のキーボード入力に応じたイベントを実行することができます。ここでは、`Alt`キーと`C`が同時に入力された時にイベントを実行する例を示します。

```json:manifest.json
{
    ...
    "commands": {
        "EventName": {
            "suggested_key": {
                "default": "Alt+C"
            },
            "description": "description of this event"
        }
    },
    ...
}
```

上記では`"EventName"`がイベント名、`"default": "Alt+C"`がキーパターン、`"description": "description of this event"`がイベントの説明に該当します。

登録されたキーボードショートカットによりイベントが発生した場合の処理を実装するには、`chrome.commands.onCommand.addListener(function callback)`を使用します。`function callback`を`function(string command) { ... }`のようにすることで、発生したイベントのイベント名を取得することができます。

`background.js`の中身を以下のようにすることで、`Alt+C`が入力された時に、開いているページのタイトルとURLをアラートで表示できます。

```js:background.js
chrome.commands.onCommand.addListener(function(command) {
    chrome.tabs.getSelected(null, function(tab) {
        alert(tab.title + "\n" + tab.url);
    });
});
```

なお、キーパターンは`"default"`以外に`"windows"`や`"mac"`を追加することで、OSごとにショートカットの割当を変更することもできます。
また、Macで`Ctrl`キーをショートカットに登録する場合、`Ctrl`ではなく`MacCtrl`として指定する必要があるようです。（Macの場合、`Ctrl`は自動的に`Command`として扱われてしまうらしいです。）

## クリップボードに保存する
Chrome拡張でクリップボードへの保存を実現するには、`document.execCommand('copy')`を使用すればいいようです。

`document.execCommand('copy')`を使用するためには、`manifest.json`の`permissions`に`clipboardWrite`を追加する必要があります。（本記事の場合、タブの情報も使用するので`tabs`も`permissions`に加えておきます。）

```json:manifest.json
{
    ...
    "permissions": [
        "tabs", "clipboardWrite"
    ],
    ...
}
```

ちなみに`document.execCommand('copy')`は`textarea`などの特定の要素しかコピーできないようなので、任意のテキストをクリップボードに保存するためには

1. 任意のテキストを格納したテキストエリアを作成
1. 作成したテキストエリアを選択し、クリップボードに保存
1. テキストエリアを削除

といった手順を踏む必要があります。

表示しているページのタイトルとURLをクリップボードに保存するためには、`background.js`を以下のように実装します。

```js:background.js
chrome.tabs.getSelected(null, function(tab) {
    // 1. 任意のテキストを格納したテキストエリアを作成
    var text_area = document.createElement('textarea');
    text_area.value = tab.title + "\n" + tab.url;
    document.body.appendChild(text_area);

    // 2. 作成したテキストエリアを選択し、クリップボードに保存
    text_area.select();
    document.execCommand('copy');

    // 3. テキストエリアを削除
    document.body.removeChild(text_area);
});
```

## まとめ
[キーボードショートカットを実行する](#キーボードショートカットを実行する)と[クリップボードに保存する](#クリップボードに保存する)の内容を組み合わせることで、 **表示中のページのタイトルとURL** を **キーボードショートカット** で **クリップボードに保存する** ためのChrome拡張を作成することができます。

`manifest.json`および`background.js`の最終的な内容は、それぞれ以下のようになります。

```json:manifest.json
{
    ...
    "background": {
        "scripts": ["background.js"]
    },
    "permissions": [
        "tabs",
        "clipboardWrite"
    ],
    "commands": {
        "save_url_and_title": {
            "suggested_key": {
                "default": "Alt+C"
            },
            "description": "Save Title and URL"
        }
    },
    ...
}
```

```js:background.js
chrome.commands.onCommand.addListener(function(command) {
    chrome.tabs.getSelected(null, function(tab) {
        // 1. 任意のテキストを格納したテキストエリアを作成
        var text_area = document.createElement('textarea');
        text_area.value = tab.title + "\n" + tab.url;
        document.body.appendChild(text_area);

        // 2. 作成したテキストエリアを選択し、クリップボードに保存
        text_area.select();
        document.execCommand('copy');

        // 3. テキストエリアを削除
        document.body.removeChild(text_area);
    });
});
```

## おわりに
そもそも表示しているページのタイトルとURLをクリップボードに保存できるChrome拡張って既に存在しているのでは？と思って探してみたら、やっぱり存在していました。

> [BlogLinkClipper](https://chrome.google.com/webstore/detail/bloglinkclipper/jcbdhcdpoagflgclgidimolohhmofnma?hl=ja)
>
> 現在表示中のページの URL とタイトルを様々な形式でクリップボードにコピーする Google Chrome 拡張機能です。Twitter や、ブログ記事作成のお供にどうぞ。

上記の拡張機能は、HTMLリンクタグ形式やMarkdown記法、Redmine記法などの形式でタイトルとURLを保存することができるというとても便利なものでした。

![BlogLinkClipper.png](https://qiita-image-store.s3.amazonaws.com/0/101189/05f70177-6fde-3513-2c70-6ae45b2fda96.png)

今後、こちらを ~~真似して~~ 参考にして今回作成したChrome拡張を普段から使いそうなHTMLリンクタグ形式やMarkdown記法にも対応できるように改良しようと思います。

## 参考にした記事
* Chrome拡張を作成する
  * [chrome extension 作成から公開までやってみました](http://d.sonicjam.co.jp/post/129140167876)
  * [初めてでも理解できるようになる「Google Chrome機能拡張の開発」 | OXY NOTES](http://oxynotes.com/?p=8836)
  * [Chromeのオリジナル拡張機能を開発しよう（ソースコードあり） | 株式会社LIG](http://liginc.co.jp/web/tool/browser/163575)
* 表示中のページのタイトルとURLを取得する
  * [chrome.tabs - Google Chrome](https://developer.chrome.com/extensions/tabs)
  * [Y.A.M の 雑記帳: Google Chrome Extension　タブの情報を取得](http://y-anz-m.blogspot.jp/2010/09/google-chrome-extension_15.html)
* キーボードショートカットを実行する
  * [chrome.commands - Google Chrome](https://developer.chrome.com/extensions/commands)
  * [try catch and ...release: Chrome拡張機能のショートカットキー設定](http://trycatchand.blogspot.jp/2013/08/chrome-keyboard-shortcut.html)
* クリップボードに保存する
  * [Declare Permissions - Google Chrome](https://developer.chrome.com/extensions/declare_permissions#clipboardWrite)
  * [Chrome 43からcutおよびcopyコマンドが使えます - Qiita](http://qiita.com/yoichiro@github/items/43ee75196bf643cde093)
  * [Chrome Extension で content_scripts から clipboard を使う - Qiita](http://qiita.com/ororog/items/146b7cdac85a48690c1e)
  * [Chrome extensionでclipboardに文字列をコピー (2014/01/26時点) - 愛と勇気と缶ビール](http://zentoo.hatenablog.com/entry/2014/01/26/200914)
  * [[JavaScript] テキストをクリップボードにコピーする | tande lab.](http://tande.jp/lab/2012/09/1889)