8

I'm developing a chrome extension which involves getting selected text of the current tab. Here is the html file that I use:

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8">
        <title></title>
        <script>
            chrome.tabs.executeScript( {
                code: "window.getSelection().toString();"
            }, function(selection) {
                document.getElementById("output").value = selection[0];
            });
        </script>
    </head>
    <body>
        <div id="output"></div>
    </body>
</html>

It doesn't work, why? As followed is the error message from Chrome App & Extension Developer Tool, some of these error messages are cut with ellipses, sorry I haven't figured out how to view the full error messages here, view details only gives me the stack track, not the full error message.

enter image description here

Searene
  • 25,920
  • 39
  • 129
  • 186
  • You cannot have inline scripts in extension pages, see the [documentation](https://developer.chrome.com/extensions/contentSecurityPolicy#JSExecution). Move your code into a separate script file ("popup.js", for example) and reference it from your popup.html using a script tag. Also, not critical, but DIVs don't have a value property. Use a textarea element instead. – cviejo Dec 09 '15 at 07:42
  • Possible duplicate of [Chrome extension Content Security Policy directive error](http://stackoverflow.com/questions/23216884/chrome-extension-content-security-policy-directive-error) – cviejo Dec 09 '15 at 07:44
  • The pointed duplicate is correct _as a first step_, however, there aren't enough details here - what part of your extension are you showing? A popup? A background page? – Xan Dec 09 '15 at 10:53
  • True that. I did think about it, but the assumed the code is taken from [this post using a popup](http://stackoverflow.com/questions/19164474/chrome-extension-get-selected-text). – cviejo Dec 10 '15 at 10:00

2 Answers2

19

As @Xan suggested, the method mentioned before (you can find it here) is overcomplicated. To get it to work, there are only two things to do:

  1. Change value to innerHTML in document.getElementById("output").value

  2. Add an activeTab permission in manifest.json file

Here is the complete source code, three files in total.

manifest.json

{
    "manifest_version": 2,
    "name": "sample",
    "description": "A sample extension to get the selected text",
    "version": "1.0",
    "icons": { 
        "16": "img/icon16.png",
        "48": "img/icon48.png",
        "128": "img/icon128.png" 
    },
    "browser_action": {
        "default_popup": "popup.html"
    },
    "permissions": [
        "activeTab"
    ]
}

popup.html

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8">
        <script src="popup.js"></script>
        <title></title>
    </head>
    <body>
        <div id="output"></div>
    </body>
</html>

popup.js

chrome.tabs.executeScript( {
    code: "window.getSelection().toString();"
}, function(selection) {
    document.getElementById("output").innerHTML = selection[0];
});
Searene
  • 25,920
  • 39
  • 129
  • 186
4

Your original approach was correct (and probably taken from this question).

It had 2 problems:

  1. Inline scripts (<script>...</script>) are not allowed; it's fixed by putting code in a separate file, say, popup.js.

  2. You need permission to access a page for content script injection; in your particular case, there's a specific permission, "activeTab", that does it in a transparent and painless way with no security warnings. When your extension is invoked (by clicking on the button), you are given access to the current tab.

With those fixed, your "direct" approach works.

By the way, to debug such problems in future, you need to inspect the popup page.


As for your own answer, you are over-complicating things a lot.

You don't need an Event page is this particular case; your popup can call executeScript and listen to messages. There are cases when you do need it, specifically when you can't guarantee that popup is open when content script sends messages; but here you can guarantee it.

Supposing you need the event page, consider not using getBackgroundPage to call a method in it - it tightly couples code; you can instead send a message. sendResponse can be used to pass the results back, even asynchronously.

Finally, your schema is confusing with respect to content.js. Only one copy of it executes, in a special context that is attached to the target page (and not in the extension context).

Community
  • 1
  • 1
Xan
  • 74,770
  • 16
  • 179
  • 206