24

I have a problem with my extension. I want to paste data from the clipboard.

So far, I've got this:

function pasteAndGo()
{
    document.execCommand('paste')
    alert("Pasted")
}

The alert comes up, but nothing has been pasted.

I've got a feeling it's the document part that needs changing, but I don't know what to do. Any ideas?

Krisztián Balla
  • 19,223
  • 13
  • 68
  • 84
Joseph Duffy
  • 4,566
  • 9
  • 38
  • 68
  • 1
    Where are you executing this code? – serg Aug 06 '11 at 22:42
  • 6
    Take a look at this: http://farter.users.sourceforge.net/blog/2010/11/20/accessing-operating-system-clipboard-in-chromium-chrome-extensions/ – Dr.Molle Aug 06 '11 at 22:50
  • 1
    This code is being executed on a regular webpage, not background.html. However, this is no longer an experimental API, and a built in part of Chrome as of version 13 (http://code.google.com/chrome/extensions/whats_new.html#13) This means it should work now. Also, I have added the permissions for it :) – Joseph Duffy Aug 07 '11 at 10:42
  • 1
    How can you grant permissions to a regular webpage? – Krisztián Balla Dec 05 '18 at 11:21

8 Answers8

20

Calling document.execCommand("paste") is not supported by "reasonable" browsers, because of security concerns as it might enable the script to read sensitive data (like passwords) from the clipboard.

This is the compatibility matrix of document.execCommand("...") concerning clipboard events:

"copy" "paste" "cut"
IE OK OK n/a
Edge OK n/a OK
Firefox OK n/a OK
Chrome OK n/a OK

My two cents to this:

  • The behaviour of Edge, Firefox and Chrome is "reasonable" as they prevent pasting/reading data from the clipboard. They do enable cut, as cut is simply a copy followed by a delete.
  • The behaviour of IE makes no sense to me, as it enables the "risky" paste, but does not execute the cut event.

You can feature detect the possible commands using the document.queryCommandSupported method.

Edit: According to MDN document.queryCommandSupported is now deprecated and should no longer be used.

Krisztián Balla
  • 19,223
  • 13
  • 68
  • 84
19

There used to be an experimental clipboard API in Chrome, but this was removed in Chrome 13.

Chrome has moved towards the more standard document.execCommand('paste'), document.execCommand('copy') and document.execCommand('cut') commands:

In Chrome you'll need permissions need to be added to your manifest: "clipboardRead" and "clipboardWrite".

Up until Chrome 38, these clipboard permissions were only available to extension pages such as background scripts. As of Chrome 39, content scripts can also use these clipboard APIs after declaring the clipboard permissions in the manifest file.

rozsazoltan
  • 2,831
  • 2
  • 7
  • 20
Boris Smus
  • 8,220
  • 2
  • 36
  • 33
9

This works well for me in a background page.

function getClipboard() {
    var pasteTarget = document.createElement("div");
    pasteTarget.contentEditable = true;
    var actElem = document.activeElement.appendChild(pasteTarget).parentNode;
    pasteTarget.focus();
    document.execCommand("Paste", null, null);
    var paste = pasteTarget.innerText;
    actElem.removeChild(pasteTarget);
    return paste;
};

Of course your extension still needs "clipboardRead" permission and you have to use message passing to get this information back to your content script:

content.js:

chrome.extension.sendMessage({
    cmd: "clipboard", //$NON-NLS-0$
    action: "paste" //$NON-NLS-0$
}, function(response) {
    if (response.paste) {
        var range = document.getSelection().getRangeAt(0);
        range.deleteContents();
        range.insertNode(document.createTextNode(response.paste));
    }
});

background.js:

function getClipboard() {
    var pasteTarget = document.createElement("div");
    pasteTarget.contentEditable = true;
    var actElem = document.activeElement.appendChild(pasteTarget).parentNode;
    pasteTarget.focus();
    document.execCommand("Paste", null, null);
    var paste = pasteTarget.innerText;
    actElem.removeChild(pasteTarget);
    return paste;
};

function onClipboardMessage(request, sender, sendResponse) {
    if (request.action === "paste") { //$NON-NLS-0$
        sendResponse({
            paste: getClipboard()
        });
    }
}

chrome.extension.onMessage.addListener(onClipboardMessage);
stackunderflow
  • 953
  • 7
  • 17
2

You need to set the clipboardRead permission to use document.execCommand('paste') and the clipboardWrite permission to use execCommand('copy') and execCommand('cut').
Otherwise, the permissions will be denied and nothing will happen.

Check this link for more details.

Sudarshan
  • 18,140
  • 7
  • 53
  • 61
realkstrawn93
  • 722
  • 1
  • 6
  • 13
2

You can't execute it on a regular page, only in a background page.

serg
  • 109,619
  • 77
  • 317
  • 330
1

You can mimic a paste by doing the same thing yourself by hand:

  1. Optional: trigger when the user tries to paste
  2. Get the contents of the clipboard (requires permission from user via a pop-up the browser will provide)
  3. Insert content into the active control
  4. Optional: trigger the events a real paste would have triggered (for the benefit of any listeners)

Focusing on steps #2 and #3 first, in this example, I check whether the active element is a text input. If so, I simulate a paste by replacing that text box's highlighted content and repositioning the cursor.

function myPaste() {
  navigator.clipboard.readText()
    .then(clipText => {
      const el = document.activeElement;
      if (el.nodeName === 'INPUT') {
        const newCursorPos = el.selectionStart + clipText.length;
        el.value =
          el.value.substring(0, el.selectionStart) +
          clipText +
          el.value.substring(el.selectionEnd);
        el.setSelectionRange(newCursorPos, newCursorPos);
      }
    });
}

For #1, add a listener to intercept the user's paste attempts:

addEventListener("paste", pasteHandler);

function pasteHandler(e) {
  e.preventDefault();
  myPaste();
}

For #4, add this after el.setSelectionRange(newCursorPos, newCursorPos);:

el.dispatchEvent(new Event('input'));
el.dispatchEvent(new Event('change'));

Note that if you are using a reactive framework that manipulates the DOM on your behalf based on data binding, you will need to defer the cursor position update until after the next DOM render. For instance:

Vue.nextTick(() => {
  el.setSelectionRange(newCursorPos, newCursorPos);
});
MarredCheese
  • 17,541
  • 8
  • 92
  • 91
1

you need to a control in focues which is capable of receiving the content...

For some examples regarding clipboard in JS see http://www.geekpedia.com/tutorial126_Clipboard-cut-copy-and-paste-with-JavaScript.html
and http://help.dottoro.com/ljcvtcaw.php

Regarding Chrome extensions see Copy/Paste Not Working in Chrome Extension

Community
  • 1
  • 1
Yahia
  • 69,653
  • 9
  • 115
  • 144
  • That's the exact page I found my information form (The link to the other Stack Overflow question). I'll try and work on getting it to paste in the right area? :S – Joseph Duffy Aug 07 '11 at 10:50
  • you need to have the focus on something that can accept what is in the clipboard - like a textarea when the clipboard contains text... – Yahia Aug 07 '11 at 11:45
0

Because on manifest v3 does not work with service worker, I found a better solution after long researches: (You still need to set the clipboardRead permission in manifest)

navigator.clipboard
        .readText()
        .then(
            (clipText) => console.log(clipText)
        );
Crypto-Frank
  • 142
  • 6