chrome拡張機能の開発チュートリアル! wordpressの入力文字の置換を行う 後編

chrome拡張機能

前回の続きである

残るはjavascriptの記述のみとなった

現状は全てのページで拡張機能が有効なので、有効なURLを限定するなどの工夫も入れつつ、作成の続きを行おう

開発工程の振り返り

  1. ディレクトリの作成
  2. manifest.jsonの作成と、基本情報の記述
  3. manifest.jsonに追加で必要な情報を記述
  4. browser_action(HTML)の作成(置換する文字の入力ボックスなどを持つ)
  5. manifest.jsonにbrowser_actionのHTMLを登録
    ※ここまで出来た※
  6. browser_actionの情報を元にcontent scriptへメッセージを送るjsを書く
  7. メッセージを待ち受けるcontent scriptに置換処理を記述する
  8. content scriptをmanifest.jsonに登録する

残りは3つの手順のみだが、少し手前に作業を加えたい

有効範囲を指定できるpage_action

現在までは全てのページで拡張機能が文字の読み取りなどを行うことが出来る状態だ 配布する機会がある場合は、配慮が足りないだろう

そこで、拡張機能が動作するサイトを限定する

そのためには既存のbrowser_actionpage_actionに切り替えて出動作させる必要がある 手順は以下の通り

  1. manifest.jsonの書き換え
  2. background script (background.jsの作成)

では、やってしまおう

manifest.jsonの書き換え

次の3つの手順に従ってmanifest.jsonを変更しよう

  1. browser_action から page_action へ書き換える
  2. permissionにdeclarativeContentを追加。
    "permissions": ["activeTab", "declarativeContent"],
  3. background script(background.js) の登録
    manifest.jsonへ次のように追記しよう
    
        <前略>
        "page_action": {
            "default_popup": "popup.html"
        },
        "background": {
            "scripts": ["background.js"],
            "persistent": false
        },
        "manifest_version": 2
    }
    
    background: でbackground script の設定を行う
    background.jsは今から作る persistent: はバックグラウンドで動き続けるかって設定らしい。falseが推奨されている
    詳しくは以下の記事が参考になる
    Chrome Extension の作り方 (その4: Event Page / Background Page) – Qiita

background.js の作成

ちょっと複雑なので、次をコピペしてURL(hostContains:の項目)を変えるだけで良い

new Promise(resolve => {
    // インストール時とアップデート時に実行
    chrome.runtime.onInstalled.addListener(resolve)
}).then(() => {
    return new Promise(resolve => {
        // 元のルールを削除した上で、
        chrome.declarativeContent.onPageChanged.removeRules(undefined, resolve)
    })
}).then(() => {
    // 再度新しいルールを設定する
    chrome.declarativeContent.onPageChanged.addRules([{
        conditions: [
            new chrome.declarativeContent.PageStateMatcher({
                pageUrl: {
                    hostContains: 'your-domain.com',  // 対象のURLを指定
                    schemes: ['https']
                }
            }),
            // URLを複数指定する場合は、このように複製する
            new chrome.declarativeContent.PageStateMatcher({
                pageUrl: {
                    hostEquals: 'www.hogehoge.com',  // 対象のURLを指定
                    schemes: ['https']
                }
            }),
        ],
        actions: [new chrome.declarativeContent.ShowPageAction()]
    }])
})

対象のURLを指定」と書かれている箇所を分の有効にしたいページに書き換えよう このコードはこちらを参考にさせて頂いた

Chrome拡張機能にてpage_actionモードの時にpopup.htmlが表示されない|teratail
前提・実現したいことこんにちは。 Chromeの拡張機能を初めて作っております。拡張機能のpopup表示方法について教えてください。 manifest.jsonにてpage_actionを選択した場合にて、Chrome右上の拡張機能アイコンをクリックした際のpopupが自作のpopup.html

もし、URLの指定の仕方を変えたかったら(URLの部分一致、前方一致など)公式ページを参考にhostContains: の箇所などを書き換えてみよう。書き換え方は公式ページに掲載されている

chrome.declarativeContent

動作確認

変更を適用するために拡張機能の再読み込みをしよう

  1. chrome://extensions/ にアクセス
  2. 拡張機能の再読み込みボタンを押す
  3. 対象外のURLだとアイコンがグレーアウトすることを確認する
  4. 対象のURLにアクセスすると、アイコンに色が付き、クリックするとHTMLが表示されることを確認する

4の手順で、既に開いていたタブで動作させる場合は、おかしなエラーが出ることがあるため再読み込みをしよう

これで対象のURLでのみ動作するようになる

前回の続き

少し前処理が長くなってしまったが、続きを行おう

残るは次の手順だ

  1. page_actionの情報を元にcontent scriptへメッセージを送るjsを書く
  2. メッセージを待ち受けるcontent scriptに置換処理を記述する
  3. content scriptをmanifest.jsonに登録する

少し手順が複雑になってしまっているのは、content script の性質が影響している。

content script のみが表示されているページのDOMを操作できる。そして、content script は同時に拡張機能側(page_action)のDOMを操作できない。

そのため、content script のjavascriptへ、拡張機能側の(page_actionのHTMLに紐づく)javascriptからメッセージパッシングという仕組みを用いて命令を送る必要があり、手順が複雑になっている

▽メッセージパッシングについては、以下の記事が参考になる▽

Chrome Extension の作り方 (最終話: メッセージパッシング) – Qiita

page_actionの情報を元にcontent scriptへメッセージを送るjsを書く

やることは大きく分けて2つ

  • 置換前と置換後の文字をpage_actionから受け取る
  • content script に情報を渡す

コードは次のようになる

{
    // 入力された文字をオブジェクトとして返す関数
    function get_words() {
        let find_word = document.getElementById('find_word').value;
        let replace_word = document.getElementById('replace_word').value;
        return { "find": find_word, "replace": replace_word };
    }

    button = document.getElementById('button');
    // ボタンが押されたら、タブのIDをもとに content script に情報を渡す処理を行う
    button.addEventListener('click', function () {
        // 現在のタブを指定して、タブのオブジェクトを取得
        chrome.tabs.query( {active:true, currentWindow:true}, function(tabs){
            // タブのIDを指定して、情報を渡す
            chrome.tabs.sendMessage(tabs[0].id, get_words(), function (num) {
                console.log(num + "箇所の置換を行いました");
            });
        });
    });
}

少しコールバック関数が多いため、内側から1つずつ見ていく

chrome.tabs.sendMessage()により、content script へのメッセージの送信が可能になる

  • 第一引数はタブのIDである。事前にこれを取得しておく必要がある
  • 第二引数は、content script へ渡す情報をオブジェクトとして指定する。今回は関数の戻り値がオブジェクトなのでそのまま渡すことが出来る。
  • 第三引数はコールバック関数である。あってもなくてもだが、コンソールに何か所の置換を行ったか出力させている。ただし、このログが出力されるのは拡張機能側(page_action側)の検証画面になるので、ユーザーの目につくことはほぼほぼない。

chrome.tabs.query()により、現在のタブの情報を取得できる

  • 第一引数でどのタブを取得するか指定する。 {active:true, currentWindow:true}としておけば、現在のタブの情報のみを取ることが出来る
  • 第2引数はコールバック関数である。コールバック関数の引数に、タブの情報が入ってくる。 現在のタブのみを指定していた場合、tabs[0]というように指定すれば内容を確認できる

▽この処理内容もこちらの記事を参考にした▽

Chrome Extension の作り方 (最終話: メッセージパッシング) – Qiita

メッセージを待ち受けるcontent scriptに置換処理を記述する

名前と配置する階層は任意だが、とりあえずcontent.jsという名前でファイルを作成し、トップ階層に配置したとする。

content.jsの内容は以下のようになる chrome.runtime.onMessage.addListener() を用いることにより、メッセージが送られたタイミングで動作する処理を記述できる

/* Listen for messages */
chrome.runtime.onMessage.addListener(function (msg, sender, sendResponse) {

    // 全ての文字列を取得
    function get_wordpress_elements() {
        let all_p = document.getElementsByTagName('p');
        let elements = [];

        // elements に置換対象の要素を追加していく
        for (let i = 0; i < all_p.length; i++) {
            if (all_p[i].getAttribute('role') == 'textbox') {
                elements.push(all_p[i]);
            }
        }

        return elements;
    }

    let find = msg.find;       // 置換対象の文字
    let replace = msg.replace; // 置換後の文字
    let str = "";              // 一時的に文字列を格納
    let num = 0;               // 置換した回数を格納
    let elements = get_wordpress_elements(); // 置換対象になり得る要素を取得
    
    // 置換処理
    for (let i = 0; i < elements.length; i++) {
        str = elements[i].innerText;
        // 文字列がすべて置換されるまでループ
        while (str.includes(find)) {
            str = str.replace(find, replace); // 置換処理. 正規表現は考慮されていない
            elements[i].innerText = str;
            num++;
        }
    }

    console.log(num + "箇所の置換を行いました");
    sendResponse(num); // 呼び出し元のコールバック関数へ値を渡すことが出来る
});

chrome.runtime.onMessage.addListener() には関数を渡すことができ、その関数に3つの引数を指定する。引数の役割は次の通り

  • img: 呼び出し元であるchrome.tabs.sendMessage() の第2引数で指定されたオブジェクトが格納されている。msg.~~~ という形で取り出すことが出来る
  • sender: オブジェクトであり、メッセージ送信側の詳細情報らしい。今回は使わないので説明も割愛(というか使い方を知らない)
  • sendResponse: 呼び出し元であるchrome.tabs.sendMessage() の第3引数となるコールバック関数に値を渡すことが出来る。渡す際はsendResponse("渡すもの") というように( ) の中に入れる

後は普通のjavascriptと同じようにDOMの操作を記述していくだけだ

複数のサイトでこの拡張機能を利用したい場合は、location.hostname とすることでサイトの識別が可能なので、追加で分岐処理を記述すれば良いだろう

content scriptをmanifest.jsonに登録する

最後にmanifest.jsonにcontent script(content.js)を登録すれば完了である manifest.jsonに以下のように追記する

    <前略>
    "content_scripts": [{
        "matches": ["<https://your-domain.com/*>", "<https://your-domain2.com/wp-admin/*>"],
        "js": ["content.js"]
    }],
    "manifest_version": 2
}

複数のサイトで動作させたい場合は、matches:に渡す配列でカンマ区切りで指定する 記述の仕方は以下のページを参考にしよう

Match Patterns

js: の項目は、自身が作成したcontent.js へのパスを記述する

これでwordpressの記述内容を置換するchrome拡張機能は完成だ

まとめ

chrome拡張機能は少し癖のある仕様となっている。 background scriptcontent script 、そして拡張機能側のjavascript と3種類が存在することを把握する必要がある

そして、それぞれに記述するべき内容も分かれているため、今回のように1つ1つ手順を確認しながら記述する方が良いだろう

今回はチュートリアルのように作成したため、詳細な解説は外部記事を参考にしてほしい

コメント

タイトルとURLをコピーしました