5

I am working on a bookmarklet that makes an href link of the current browser tab and copies it to the clipboard. This bookmarklet works in Safari:

javascript:
!function(a){
var%20b=document.createElement("textarea"),
c=document.getSelection();
b.textContent=a,document.body.appendChild(b),
c.removeAllRanges(),b.select(),
document.execCommand("copy"),
c.removeAllRanges(),
document.body.removeChild(b)}
('<a%20title="'+document.title+'"%20href="'+document.location.href+'">'+document.title+'</a>');

But in Firefox 65, I get the error "document.execCommand(‘cut’/‘copy’) was denied because it was not called from inside a short running user-generated event handler." In looking at Copying to clipboard with document.execCommand('copy') fails with big texts I'm trying to generate the html of the link before the function to solve the issue pointed out in the answer. But, with the code below, I get a new browser tab with the text "true" and no copied link to the clipboard.

javascript:
const text = ('<a%20title="'+document.title+'"%20href="'+document.location.href+'">'+document.title+'</a>');
!function(a){
var%20b=document.createElement("textarea"),
c=document.getSelection();
b.textContent=a,document.body.appendChild(b),
c.removeAllRanges(),
b.select(),
document.execCommand("copy"),
c.removeAllRanges(),
document.body.removeChild(b)}('text');

Is this a timing issue with the generation of the href link? Or something else?

BlueDogRanch
  • 721
  • 1
  • 16
  • 43

1 Answers1

1

Your problem is not the same than in the other Q/A: In your case, you don't have any user-triggered event.

So no, it is not a timing issue, it's just that you need such an event.

To force it, you could show a splash screen, requiring that the bookmarklet's user clicks on the page. From this click event you'd call execCommand('copy').

javascript:(function(a){
  var splash = document.createElement('div'),
    msg = document.createElement('span');
  splash.style='position:fixed;top:0;left:0;width:100vw;height:100vh;display:flex;justify-content:center;align-items:center;background:#FFF;z-index:999999';
  msg.textContent = 'click me';
  splash.append(msg);
  // wait for the click event
  splash.onclick = evt => {
    var b=document.createElement("textarea"),
    c=document.getSelection();
    b.textContent=a,
    document.body.appendChild(b),
    c.removeAllRanges(),
    b.select(),
    document.execCommand("copy"),
    c.removeAllRanges(),
    document.body.removeChild(b),
    document.body.removeChild(splash);
  };
  document.body.append(splash);
})

Here is a live example of what happens (obviously not as a bookmarklet):

(function(a){
  var splash = document.createElement('div'),
    msg = document.createElement('span');
  splash.style='position:fixed;top:0;left:0;width:100vw;height:100vh;display:flex;justify-content:center;align-items:center;background:#FFF;z-index:999999';
  msg.textContent = 'click me';
  splash.append(msg);
  // wait for the click event
  splash.onclick = evt => {
    var b=document.createElement("textarea"),
    c=document.getSelection();
    b.textContent=a,
    document.body.appendChild(b),
    c.removeAllRanges(),
    b.select(),
    document.execCommand("copy"),
    c.removeAllRanges(),
    document.body.removeChild(b),
    document.body.removeChild(splash);
  };
  document.body.append(splash);
})
('<a%20title="'+document.title+'"%20href="'+document.location.href+'">'+document.title+'</a>');
<textarea>You can paste here to check what's been copied</textarea>
Kaiido
  • 123,334
  • 13
  • 219
  • 285
  • Thanks, that works in Firefox. But how would it be made to not need to click the button to copy to the clipboard? The first example in my question copies directly to the clipboard in Safari when the bookmarklet is run. – BlueDogRanch Feb 13 '19 at 22:44
  • You can't. That's part of the restrictions. That Safari didn't implement this restriction for bookmarklet is their choice, that Firefox did is their own. – Kaiido Feb 14 '19 at 06:19