How to paste on click? It works in google docs

2019-01-10 22:50发布

问题:

I want to be able to initiate real paste event when user clicks. I can understand this may be a security issue, because if any webpage had access to users clipboard, that would be bad. So I thought all browsers disallow accessing clipboard data.

But for example in google docs (in the word-like application), I can Paste from custom context menu (right mouse click on a html element pretending to be a context menu), even if the clipboard data has been copied to clipboard in different application like Microsoft Paint. This works in Google Chrome browser, which is the browser of my interest.

I thought they do it using flash, but it still works even if I completely disable flash in chrome. There was a question about this already, but the answer mentioned there is not correct. Another answer of that question suggests that google is using a chrome extension for this, but it still works even if I disable all extensions in chrome.

How to reproduce in windows:

  • disable flash in chrome, disable all extensions
  • restart
  • go to google docs and open new empty writing document (Docs, not spreadsheet)
  • run microsoft paint application in windows
  • draw something in microsoft paint, press Ctrl+A to select all, Ctrl+C to copy
  • switch back to chrome to the docs empty page, and rightclick the empty page
  • select Paste from the artificial context menu (notice the context menu is not the native menu from windows, but it comes from the html webpage of google docs)
  • you will see that the clipboard image was pasted to the docs document (!)
  • how do they do this?

I know how to access the clipboard data if user presses Ctrl+V on my webpage, because this triggers Paste event on the current window. But, how do I either access the clipboard data or initiate the paste of actual clipboard data (eg. a bitmap copied in mspaint) in javascript (or using jquery) while user just clicks a button or div?

回答1:

I want to be able to initiate real paste event when user clicks. I can understand this may be a security issue, because ...

The above is the bottom line..

Having this code JS Fiddle

var Copy =  document.getElementById('copy'),
    Cut =  document.getElementById('cut'),
    Paste =  document.getElementById('paste');

// Checking Clipboard API without an action from the user
console.log('Copy:' + document.queryCommandSupported('copy'));
console.log('Cut:' + document.queryCommandSupported('cut'));
console.log('Paste:' + document.queryCommandSupported('paste'));


//Now checking the clipboard API upon a user action
Copy.addEventListener('click', function(){
    console.log('Copy:' + document.queryCommandSupported('copy'));
});

Cut.addEventListener('click', function(){
    console.log('Cut:' + document.queryCommandSupported('cut'));
});

Paste.addEventListener('click', function(){
    console.log('Paste:' + document.queryCommandSupported('paste'));
});
<button id="copy">Copy</button>
<button id="cut">Cut</button>
<button id="paste">Pate</button>

If you check it with different browsers you'll see how browsers react differently dealing with the Clipboard API using queryCommandSupported() the result is:

Chrome 47:

  • Without user action, Copy:false , Cut:false , Past:false
  • With user action, Copy:true , Cut:true , Paste:false

Firefox 43:

  • Without user action, Copy:true , Cut:true , Past:false
  • With user action, Copy:true , Cut:true , Paste:false

IE11: - I believe it's same in Edge

  • Without user action, Copy:true , Cut:true , Past:true
  • With user action, Copy:true , Cut:true , Paste:true
  • While all options are true, IE asks the user for permission on all above actions.

Safari: - same for iOS Safari

  • Only fires copy event on a valid selection and only cut and paste in focused editable fields.
  • Only OS clipboard reading/writing via shortcut keys, not through document.execCommand().

For detailed browsers support for Clipboard API caniuse.com/#search=clip

Also browsers support paste using right-click context menu for conteneditable="true" elements as in this JS Fiddle 2


But for example in google docs (in the word-like application), I can Paste from custom context menu (right mouse click on a html element pretending to be a context menu), even if the clipboard data has been copied to clipboard in different application like Microsoft Paint.

I thought they do it using flash, but it still works even if I completely disable flash in chrome.

From Google Apps Script documentation for developing add-ons for Google Apps:
"The Platform: Apps Script's code editor is a web app that you launch from within Google Sheets, Docs, or Forms. The language is based on JavaScript, but executes on Google's servers rather than directly in the user's browser (with the exception of client-side user interfaces...".

Since it is being executed on their servers, I think they can enable certain features, or even use Java, for better experience.


EDIT 1:
If you check clipboard.js, you'll see the library doesn't have an option for "paste", only "copy" and "cut", also in the "Browser Support" section at the end of the page you'll see that the library relies on execCommand API, and doesn't work in Safari.


EDIT 2:
Upon an update of the question as well as comments, for the Google docs part, I pressed Prt Sc to have a screen-shot in the clipboard, opened Google docs in Chrome, right-clicked then clicked on "Paste" from the custom context menu and for sure it works, opened Google docs in Firefox and as soon I clicked on "paste" option I got this response

Also for the record, I tried to do the same in IE11 and it is still trying to launch Google docs since 21 minutes.

So the conclusion is probably, and mostly, "Google" Chrome has an Exception: - something like a conditional statement - for "Google" docs and other Google services in their browser, also I think @julien-gregoire was right about its being an extension in Firefox.

From this Google docs support page:

For security reasons, most browsers don't allow web apps like Docs, Sheets, and Slides to use your computer's clipboard through menus.

However, if you use Chrome, you can give permission to access your clipboard by installing the Google Drive Chrome app. This allows you to use the right-click menu to copy and paste content (or select "Copy" or "Paste" from the Edit menu in the toolbar). To install the app, visit the Chrome Web Store.

And this smallbusiness page:

Without keyboard shortcuts, you have two more options for copying and pasting: either going to the "Edit" menu and selecting "Copy" or "Paste," or right-clicking in the document and selecting either "Copy" or "Paste" from the context menu. In Google Docs, both these options are only available to Chrome users who have the Google Drive Web app installed. The app is free, but is not available for other browsers.

So seems they have already implemented that app as built-in feature in newer versions of Chrome.



回答2:

Custom paste works in Chrome, but only through an extension. If you look at google docs code, you'll see that without the extension installed, you can't paste. And you can try in Firefox to use the context menu paste, it'll tell you it's not available, and that you need to use CTRL+V. You can find this in google docs source code:

Copying and pasting requires the free Google Drive web app. This lets us access your clipboard so you can cut, copy and paste.

So it seems clear that the paste command needs an extension to work.

One way to do it is to use execCommand('paste') which doesn't work when called from a page, but actually works in an extension content script. You only need to add clipboardRead to the manifest.json permissions, like this:

permissions: {
    ...
    "clipboardRead"
    ...
}

Then in your content script document.execCommand('paste') will work.

EDIT:

As pointed by @tomas-M and @Mi-Creativity, the implementation in google docs on Chrome seems to be in Chrome itself, not in an exposed extension. Maybe this can give a clue as to where it is defined: https://code.google.com/p/chromium/codesearch#chromium/src/chrome/common/extensions/api/_permission_features.json&q=clipboardRead&sq=package:chromium&dr=C&l=164

Hard to say if it's really the way it works, but in any case, you can 'unlock' execCommand('paste') for other site through an extension. Not very practical, but it works.

And testing document.execCommand('paste') in console, while on google docs gives true, while on other pages it gives false, so I really think that it's how this feature is implemented in google docs.