Search code examples
javascriptgoogle-chromegoogle-chrome-extensioncontextmenuclipboard-interaction

Copy selected text via a context menu option in a Chrome extension


I am trying to create a context menu option which copies some text to the system clipboard.

Currently, I am just copying a hard-coded string literal, but I am wondering how it could be changed to copy selected text. Specifically, I don't know how to properly create the createProperties object (see bottom)

It is my understanding that this can only be done through a background page.

I have the following background page:

background.html

<textarea id="temp"></textarea>
<script src="context.js"></script>

context.js is as follows:

chrome.contextMenus.create({
    "title": "Freedom",
    "contexts": ["editable"],
    "onclick" : copyToClipboard
  });        

function copyToClipboard()
{ 
    var tempNode = document.getElementById("temp");
    tempNode.value = "some text";
    tempNode.select();
    var status = document.execCommand('copy',false,null);

    if(status) alert('successful');

    else alert('unsuccessful');
}    

my manifest.json is as follows:

{
    "manifest_version": 2,

    "name": "Freedom",
    "description": "Provides users useful and fun context menu options that they can access from anywhere.",
    "version": "1.0",

    "permissions": [
        "contextMenus",
        "clipboardWrite"
        ],  

    "background": {
        "page": "background.html"
    }   

}    

I am apparently declaring the chrome.contextMenus.create() function incorrectly. I have read the docs for it and I can only imagine that I am not properly creating the createProperties object.

I have been trying to mimic these sources:

Is that possible calling content script method by context menu item in Chrome extension?

http://paul.kinlan.me/chrome-extension-adding-context-menus/

some other related questions are:

Copy to Clipboard in Chrome Extension

How to copy text to clipboard from a Google Chrome extension?


Solution

  • "createProperties" in the documentation is the dictionary that is passed to the chrome.contextMenus.create method (i.e. that thing with "title", "contexts", etc.)

    The onclick event description of chrome.contextMenus.create states that the function receives two parameters. The first parameter ("info") is a dictionary with information about the selected text. The second parameter ("tab") contains information about the tab (in your case, you don't need though).
    The "info" dictionary has a property "selectionText" that holds the selected text when the context menu item was clicked. This can be used in your code as follows:

    function copyToClipboard(info) {
        var tempNode = document.getElementById("temp");
        tempNode.value = info.selectionText; // <-- Selected text
        tempNode.select();
        document.execCommand('copy', false, null);
    }
    

    That would solve your immediate question.
    Besides that, your extension can be improved by converting your background page to an event page. The main benefit of event pages over background pages is that your extension will not unnecessarily use memory while sitting idle in the background.

    // background.js
    
    // Register context menu
    chrome.runtime.onInstalled.addListener(function() {
        chrome.contextMenus.create({
            "id": "some id",  // Required for event pages
            "title": "Copy selected text to clipboard",
            "contexts": ["editable"],
            // "onclick" : ...  // Removed in favor of chrome.contextMenus.onClicked
        });
    
    });
    
    // Register a contextmenu click handler.
    chrome.contextMenus.onClicked.addListener(copyToClipboard);
    

    Here is a minimal manifest.json (note the "persistent": false key, which specifies that you want to use an event page)

    {
        "manifest_version": 2,
    
        "name": "Copy selected text to clipboard",
        "version": "1.0",
    
        "permissions": [
            "contextMenus",
            "clipboardWrite"
         ],
    
        "background": {
            "page": "background.html",
            "persistent": false
        }
    }