Help us understand the problem. What is going on with this article?

Google Chrome 拡張機能の開発 - 4 - マウスカーソルにある位置のものをコピー

More than 1 year has passed since last update.

やりたいこと:マウスカーソルがある位置で任意のコマンドを実行したら、その場所の要素をインテリジェントにコピーしたい
やれたこと:バックグラウンドによるコンテキストメニュー表示と、メッセージの送受信と、コンテンツスクリプトでのカーソル位置の要素の取出し
【ソースコードも一応GitHubへアップしてあります】(※でも、自分でダウンロードして使ってみたらうまく動かないよ・・・あるぇ~?)

前回の間違いを修正

前回、データ保存にlocalStorageを使用したが、Chrome拡張でのAPIを知ったので書きかえます。

popup.js(旧)
//保存
localStorage.setItem(saveDataName, JSON.stringify(saveData));

//読込
const data = JSON.parse(localStorage.getItem(saveDataName));
popup.js(新)
//保存
chrome.storage.sync.set({
  "CopyFormat": saveData
});

//読込
chrome.storage.sync.get(["CopyFormat"],items=>{
  const data = items.CopyFormat;
});

コンテキストメニューを表示する

マニフェストにバックグラウンド用の定義を加えます。

manifest.json
  "background": {
    "page": "background.html",
    "persistent": true
  },
background.html
<!DOCTYPE html>
<html>
<head>
<title>R Chrome Extension</title>
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
<script src="jquery-3.1.1.min.js"></script>
<script type="text/javascript" src="background.js"></script>
</head>
<body>
<textarea id="text" />
</body>
</html>
background.js
chrome.contextMenus.create({title: "コピー", onclick: info=>{
  console.log("ほげ");
}});

こんな感じで、とりあえずコンテキストメニューにコマンドが追加されて、実行できることを確認しました。

コンテンツスクリプトで表示中のページにスクリプトを加える

マニフェストにコンテンツスクリプト用の定義を加えます。(※今は適当にコピペしてきた形のものを使っていますので、各定義については十分理解できていません)

manifest.json
  "content_scripts": [
    {
      "all_frames": true,
      "js": ["jquery-3.1.1.min.js", "contentscripts.js"],
      "matches": ["<all_urls>"],
      "run_at": "document_end"
    }
  ]  
contentscripts.js
$("*").hover(e=>{
  console.log(e);
},e=>{});

マウスカーソルを動かすと、カーソルのある位置のオブジェクトが取得されていることがわかりました。

バックグラウンドとコンテンツスクリプトの連携

いくつか方法があるようでしたが、chrome.tabs.sendRequestchrome.extension.onRequestを使用する方法をとりました。

background.js
chrome.contextMenus.create({title: "コピー", onclick: info=>{
  chrome.tabs.getSelected(null, tab=>{
    chrome.tabs.sendRequest(tab.id, {command: "Copy"}, response=>{
      console.log(response);
    });
  });
}});
contentscripts.js
chrome.extension.onRequest.addListener((request, sender, sendResponse)=>{
  if (request.command==="Copy")
    sendResponse({"text": "hoge"});
});

コンテキストメニューからコマンドを選択して、値が戻ってくることが確認できました。

カーソルの位置にある文字列をクリップボードへコピーする

ソースコードなどが表示されている場所で、カーソルを合わせてコピーで、そのソースコードをまるっとコピーすることを想定します。

現状、うまくできる場所とできない場所があり、ログ出力を確認すると、イベントが数回発生していたりと問題が多数ありますが、とりあえず、方法的にはこんな感じなのだろうといった段階です。
なので、あまり好ましいソースコードの状態ではありませんし、変なことをしているかもしれませんが、おいおい直していきます。

manifest.json
{
  "name": "R Chrome Extension",
  "manifest_version": 2,
  "version": "0.0.4",
  "description": "コピー&ペーストに関わる作業を効率化するための機能を盛り込んだツールです。(としていく予定)",
  "permissions": [
    "tabs", "clipboardWrite", "contextMenus", "storage"
  ],
  "browser_action": {
    "default_popup": "popup.html"
  },
  "background": {
    "page": "background.html",
    "persistent": true
  },
  "content_scripts": [
    {
      "all_frames": true,
      "js": ["jquery-3.1.1.min.js", "contentscripts.js"],
      "matches": ["<all_urls>"],
      "run_at": "document_end"
    }
  ]  
}

※前回まではversionの指定が適当でしたが、試に公開してみた際、このバージョン設定でミスしました。ご注意ください。

background.html
<!DOCTYPE html>
<html>
<head>
<title>R Chrome Extension</title>
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
<script src="jquery-3.1.1.min.js"></script>
<script type="text/javascript" src="background.js"></script>
</head>
<body>
<textarea id="text" />
</body>
</html>
background.js
chrome.contextMenus.create({title: "コピー", onclick: info=>{
  chrome.tabs.getSelected(null, tab=>{
    chrome.tabs.sendRequest(tab.id, {command: "Copy"}, response=>{
      console.log(response.text);
      const txt = $("#text");
      txt.val(response.text);
      txt.select();
      document.execCommand("copy");
    });
  });
}});
contentscripts.js
let selectionTarget;
let selectionText;
$("*").hover(e=>{
  selectionTarget = e.target;
},e=>{});
$("*").bind("contextmenu",()=>{
  selectionText = selectionTarget.innerText;
});
chrome.extension.onRequest.addListener((request, sender, sendResponse)=>{
  if (request.command==="Copy")
    sendResponse({"text": selectionText});
});

動かしてみた感じ

image
image
一応コピーできているなぁ・・・

今回参考にした記事

以上

前回 一覧 次回
保存できるようにする シリーズ一覧 コピーした履歴をわかるようにする
Why do not you register as a user and use Qiita more conveniently?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away