Chrome 拡張機能を作って公開しよう③ 〜形にする〜

1回15分でサクッと開発。いよいよ形にしていきます!

投稿: 2021年8月3日 (最終更新: 2023年5月21日) • 読了目安: 6 分
Chrome 拡張機能を作って公開しよう③ 〜形にする〜
画像: Jantine Doornbos via Unsplash

こんにちは。1回15分で拡張機能を作るシリーズ、第3弾です。

今回は、前回作成したファイルをもとに、拡張機能を形にしていきます。

今回はボリュームが大きいので、15分で終わらないかもしれません。その時はごめんなさい。

仕様

まずは今回の拡張機能の仕様を紹介します。

  • 2つの独立したテキストボックスに、URL・ページタイトルをそれぞれ代入する
  • URL・ページタイトルは、それぞれコピーできる
  • URLとページタイトルを両方コピーすることもできる
  • Facebook や Twitter、LINE へのシェア機能も実装する

とりあえずこのような仕様でいきます。

ポップアップの作成

前回作ったものは、「Hello, world」と出力するだけのものでしたが、今回は更に拡張機能っぽくしていきます。

なお、今から記述していく HTML と CSS は簡単なものなのでコピペで済ませて構いません。後半の JavaScript が難しいので…

では、まずは HTML から。popup.htmlの中身をすべて消して、以下の内容を記述してください。

<!DOCTYPE html>
<html lang="ja">

<head>
  <meta charset="UTF-8">
  <link rel="stylesheet" type="text/css" href="popup.css">
</head>

<body>
  <div class="content">
  <label for="pageTitle" class="column">タイトル</label>
  <div class="grid">
    <div class="text">
      <input type="text" id="pageTitle" class="column" readonly>
    </div>
  </div>
</div>
<div class="content">
  <label for="pageURL" class="column">URL</label>
  <div class="grid">
    <div class="text">
      <input type="url" id="pageURL" class="column" readonly>
    </div>
  </div>
  </div>

  <script src="popup.js" defer></script>
</body>

</html>

HTML を保存したら、ポップアップを開いてみてください。

以下のようになっていれば OK です。

ポップアップHTMLのみ

しかし、これでは味気ないので、CSS の登場です!popup.cssの中身をすべて消して、以下の内容を記述してください。

body {
    letter-spacing: .15em;
    width: 400px;
    font-size: 16px;
}

* {
    color: #606c76;
    box-sizing: border-box;
    font-family: -apple-system, blinkMacSystemFont, "Helvetica Neue", "Segoe UI", "Arial", "Roboto", "Hiragino Kaku Gothic ProN", YuGothicM, YuGothic, Meiryo, 'Noto Sans JP', sans-serif;
}

@font-face {
    font-family: YuGothicM;
    font-weight: normal;
    src: local("YuGothic-Medium"), local("Yu Gothic Medium"), local("YuGothic-Regular");
    /* Windows8.1ではMediumがないのでRegularを指定 */
}

@font-face {
    font-family: YuGothicM;
    font-weight: bold;
    src: local("YoGothic-Bold"), local("Yu Gothic");
}

.content{
    margin: 2em 0;
}

.grid {
    display: grid;
    grid-template-columns: 1fr auto;
    gap: 1.2em 1em;
    width: 100%;
    margin-top: .3em;
}

.text {
    position: relative;
}

.text input {
    color: #727d86;
    font: 16px sans-serif;
    width: 100%;
    padding: 0;
    padding-bottom: .1em;
    letter-spacing: 1px;
    border: 0;
}

.text input:focus {
    outline: none;
}

.text input:focus::after {
    outline: none;
}

.text::after {
    display: block;
    width: 100%;
    height: 1px;
    margin-top: 0;
    content: '';
    border-width: 0 1px 1px 1px;
    border-style: solid;
    border-color: #4c3cda;
}

.text .column {
    width: 100%;
    height: 100%;
}

これでポップアップを開いてみると…?

CSS付きポップアップ

いい感じになっています!

JavaScript で動きをつける

さあ、続いて JavaScript の記述です!まずは、popup.jsの中身を消して、「タイトル」を表示させる要素と「URL」を表示させる要素を取得して定数に代入します。

const title = document.getElementById("pageTitle");
const url = document.getElementById("pageURL");

テキストボックスにテキストを代入するには、element.value = (代入したい文字列) を使えばよいのでした。きっと多くの人が下記のプログラムを思いついたでしょう。

const title = document.getElementById("pageTitle");
const url = document.getElementById("pageURL");

/* ココから追記分 */
title.value = document.title;// タイトルを代入
url.value = location.href;  //URLを代入
/* ココまで追記分 */

しかし、実行してみると…

失敗例

このように、このポップアップの HTML の URL とタイトルが代入されてしまいます。

(URL は人によって異なるかもしれません。また、ポップアップに <title> タグが指定されていないため、「タイトル」欄は空白になっています。)

そこで、用いるのが、chrome.tabs.queryメソッドです!これは、Chrome の拡張機能のみが使用することができるメソッドとなっています。

このメソッドを使うためには、manifest.jsonに以下の内容を書き加えて、「この拡張機能は開いているタブの情報を必要とするから教えてくれ」ということをブラウザに伝える必要があります。

  "permissions": [
    "tabs"
  ],

このメソッドを用いてプログラムを書き換えると、以下のようになります。「ここは削除!」とコメントしてある部分は、削除してください。

const title = document.getElementById("pageTitle");
const url = document.getElementById("pageURL");

/*========================= ここは削除!

title.value = document.title;// タイトルを代入
url.value = location.href;  //URLを代入

===========================*/


/*ココから追記分*/
chrome.tabs.query({ 'active': true, 'lastFocusedWindow': true }, tabs => {
    title.value = tabs[0].title;
    url.value = tabs[0].url;
});

では、chrome.tabs.query について詳しく説明していきます。

chrome.tabs.queryは、条件に合うタブの情報を、NodeList 形式で返してくれるメソッドです。NodeList がよくわからない人は、普通の JavaScript の配列やオブジェクトと同じようなものと覚えておいてください。

chrome.tabs.query({/*条件を記述*/}, tabs => {
});

例えば、上記のプログラムを実行した場合、/*条件を記述*/ のところに記述した条件に合うタブの情報が格納された NodeList が、tabsに代入されます。

tabs => {} という書き方を初めて見る方もいらっしゃるかもしれませんが、function (tabs) {}と同じです。これは「アロー関数」と呼ばれるものです。気になる方は調べてみてください。

それでは、肝心の条件式について見ていきます。

条件式はオブジェクト形式で、{項目1: true/false, 項目2: true/false, ...} のように書いていきます。

主な「項目」は以下のとおりです。

項目説明
activeウインドウ中のアクティブなタブか
currentWindow現在のウインドウにあるタブか
mutedミュートになっているタブか
pinned固定されているタブか
lastFocusedWindow最後にフォーカスしたウインドウにあるか

その他の「項目」については、以下の公式サイトをご覧ください。

chrome.tabs - Chrome Developers

tabs[0].url で、条件に適したタブのうち1番目のURLを得ることができ、tabs[0].title で、条件に適したタブのうち1番目のタイトルを得ることができます。

この NodeList は「オブジェクト」の「配列」になっているため、配列の1番目(といっても配列の長さは1だけですが)であることを明確にする必要があります。

ここで、先程のコードを読み返してみましょう。

chrome.tabs.query({ 'active': true, 'lastFocusedWindow': true }, tabs => {
    title.value = tabs[0].title;
    url.value = tabs[0].url;
});

条件の部分は、{ 'active': true, 'lastFocusedWindow': true }となっています。これは、「ウインドウの中のアクティブなタブ」かつ「最後に開いたウインドウの中にあるタブ」ということなので、「現在見ているタブ」を指していることが分かります。

まあ、これだけ説明しておいて、chrome.tabs.query は後ほど削除するのですが… 理由は後ほど。

ということで、JavaScript のコード全体は以下のようになります。

const title = document.getElementById("pageTitle");
const url = document.getElementById("pageURL");

chrome.tabs.query({ 'active': true, 'lastFocusedWindow': true }, tabs => {
    title.value = tabs[0].title;
    url.value = tabs[0].url;
})

このコードを動かしてみると…

成功

いい感じですね!

では、今日はこの辺にして、次回はメインの「コピー機能」と SNS への「シェア機能」を実装していきます。お楽しみに!

問題点と予告

実は、このコードにはまだ問題があります。この画像は、Chrome の拡張機能の管理画面のスクリーンショットです。

権限多すぎ

この画像からわかるように、権限が多すぎるのです。この程度のプログラムであれば、「閲覧履歴の読み取り」をしなくとも実装できますが、結果的にユーザーを不安にさせてしまうような権限になってしまいました。

これについては、次々回で対処していきます!

まとめ

  • chrome.tabs.query でタブの検索が行える。

今日はお疲れさまでした!次回をお楽しみに。




「Chrome 拡張機能を作ろう」の記事一覧

  1. 環境構築
  2. ポップアップ作成
  3. 仕様に沿って開発(閲覧中)
  4. コピー機能実装
  5. 権限を減らす
  6. コンテキストメニューの作成
  7. Webストアに公開