0

In my extension I have a button in a popup.js file that runs a listener for a button press and sends a command to a content.js file.

document.querySelector('#btn').addEventListener('click', () => {
   chrome.tabs.query({ active: true, currentWindow: true }, (tabs) =>
    chrome.tabs.sendMessage(tabs[0].id, { command: 'getClientName' })
  
    );
});

My content.js file is a little involved and grabs some information off the page to copy to the clipbaord, but for purposes of my problem I just need a listener to wait for the command "getClientName" then save a value to the clipboard like below.

chrome.runtime.onMessage.addListener((msg, sender, response) => {
    navigator.clipboard.writeText("I did it 2!")
      .then(() => {alert("I did it 2!");
      })
      .catch(() => {
        alert("I didn't it 2");
      })
});

However, I cannot get navigator.clipboard.writeText() to work from the content.js page. It will only work if I run it directly from popup.js, which doesn't really work since I need to pull information off the page.

Right now it gets sent to .catch() and sends me the error message.

Manifest (replaced the actual URL in my manifest with "all" for privacy reasons):

    {
      "manifest_version": 3,
      "name": "The Magic Button",
      "version": "1.0.0",
      "description": "Open P.P. client folder in sharepoint",
      "action": {
        "default_icon": {
          "16": "/images/logo16.png",
          "48": "/images/logo48.png",
          "64": "/images/logo64.png",
          "128": "/images/logo64.png"
        },
        "default_popup": "popup.html",
        "default_title": "Open Sharepoint Folder"
      },
      "permissions": ["tabs",
                      "clipboardWrite"],
      "content_scripts": [
      

  {
      "matches": [all],
      "js": ["content.js"],
      "css": ["/styles/contentStyle.css"],
      "run_at": "document_idle",
      "all_frames": false
    }
  ]
}
Zach Morris
  • 367
  • 1
  • 4
  • 12
  • What is the error message? (try adding an `error` property to your catch and logging it: `.catch(error => { console.error(error) })` – Live bug help - www.dialect.so Jan 05 '23 at 19:23
  • Please post your manifest.json – Thomas Mueller Jan 05 '23 at 19:52
  • The clipboard API requires user interaction, so it won't work in a different document, this is the correct behavior. All you need is to pull the info from the web page into the popup page and write the clipboard there. Alternatively you can use the legacy method: textarea + document.execCommand('copy') in the content script. – wOxxOm Jan 05 '23 at 19:53
  • Is the error `Document is not focused` ? `navigator.clipboard.writeText` cannot be used on a DOM that has no focus. This is a tutorial for it. [How to make Chrome Extension 43 Write to clipboard](https://youtu.be/RA1gZCr0160) – Norio Yamamoto Jan 05 '23 at 20:46
  • @wOxxOm doesn't the popup.js not allow you to access the html on the page? – Zach Morris Jan 05 '23 at 20:52
  • @ThomasMueller updated with the manifest – Zach Morris Jan 05 '23 at 20:53
  • Use executeScript or messaging to pass data, see [How to access the webpage DOM/HTML from an extension popup or background script?](https://stackoverflow.com/q/4532236) – wOxxOm Jan 05 '23 at 21:01
  • @NorioYamamoto There really isn't a runtime error being thrown. It just isn't copying the text to the clipboard so it throws the .catch alert. – Zach Morris Jan 05 '23 at 21:03
  • @wOxxOm I'm still having a hard time as the linked article doesn't really explain which code belongs in content.js and popup.js. It also is injecting data into the page and not copying to the clipboard. So kind of doing the opposite thing. – Zach Morris Jan 06 '23 at 01:52
  • All code in the examples is inside the popup (content scripts can't use most of `chrome` API). The injected code runs in the web page and retrieves the data which is automatically transferred into the popup. This is how programmatic injection works. You can also build upon your current approach but add [sendResponse](https://developer.chrome.com/extensions/messaging) to deliver the data back to the popup. In both cases the popup will finally write to the clipboard. And yet another approach is execCommand, a much simpler one if you ask me. – wOxxOm Jan 06 '23 at 02:35

1 Answers1

0

This sample copies the web page title to the clipboard.

manifest.json

{
  "name": "hoge",
  "version": "1.0",
  "manifest_version": 3,
  "permissions": [
    "scripting"
  ],
  "host_permissions": [
    "<all_urls>"
  ],
  "action": {
    "default_popup": "popup.html"
  }
}

popup.html

<html>
<body>
  <button id="copy">Copy</button>
  <script src="popup.js"></script>
</body>
</html>

popup.js

const getTitle = () => {
  console.log("getTitle() = " + document.title);
  return document.title;
}

document.getElementById("copy").onclick = () => {
  chrome.tabs.query({ active: true, currentWindow: true }, (tabs) => {
    console.log("Execute Script");
    chrome.scripting.executeScript({
      target: { tabId: tabs[0].id },
      func: getTitle
    }, (result) => {
      console.log("Recv result = " + result[0].result);
      navigator.clipboard.writeText(result[0].result);
    });
  });
}
Norio Yamamoto
  • 1,495
  • 2
  • 3
  • 10