How to make a button that receives an external resource and copies it to the clipboard?

So I have a button that should create an attractive sharing URL, shorten it with goo.gl and then copy it to the clipboard. The good news is that I successfully did all this, but not right away.

The problem is with the specification:

Copy commands initiated from document.execCommand () will only affect the contents of the real clipboard if the event is dispatched from an event that is trusted and triggered by the user, or if the implementation is configured for this. How an implementation can be configured to allow write access to the clipboard outside the scope of this specification.

execCommand Unofficial W3C Spec

So it seems that this might not work ...

You see, to shorten the url, I need to make an AJAX call. I only do this when the user clicks the Share button, because I have a limit of 1,000,000 cuts per day (and if I created a new sharing URL every time the page was changed, this could easily become 1000 new URLs for one user, d will be limited to 1000 end users: not the best option). But that means I have to listen to AJAX events from a thread other than the one that triggered the event, effectively losing this blessed state required by execCommand('copy') .

Is there a way to have one singular button that generates the goo.gl url and then copy the specified short url to the clipboard?

For reference, here is what I wrote (Kotlin / JS) and here is the JavaScript output .
Here is a SSCCE that illustrates how it seems like it should work, but not (based on ι™ˆ 杨华 answer ).

+5
source share
2 answers

There are two solutions that work, but both are erroneous. One works only if your request takes less than one second and one of them is out of date, so it cannot be used in a production environment.

First you need to use setTimeout , which is one of the few asynchronous functions that does not lose the execCommand privilege. But it does not lose if it is equal to or less than 1000 ms. Therefore, if your request is less than this, you should go, but if not, then , you have an error. If you combine it with some kind of timeout processing, it may work, but if requests often take more than 1 second, then this may not be enough. For example, for example:

 var toCopy; const buttonClick = () => { setTimeout(function() { if (toCopy) { // strangely, this execCommand will work console.log(document.execCommand('copy')); } }, 1000); var client = new XMLHttpRequest(); client.onload = function(data) { toCopy = this.responseText; }; // by setting your timeout on your request // with the same duration as the setTiemout // you make sure it either works or throws an error client.ontimeout = function(data) { console.log('timeout'); }; client.timeout = 1000; client.open("GET", "https://www.random.org/integers/?num=1&min=1&max=100&col=1&base=10&format=plain"); client.send(); } $(() => { $("button").click(buttonClick) }) document.addEventListener('copy', function(e) { e.preventDefault(); e.clipboardData.setData('text/plain', toCopy); }); 

https://jsfiddle.net/8md4Ltu2/4/

There is another way to make it work, but it is deprecated, so it cannot be used. But to be careful, I will put it here. You can set the asynchronous flag of your XMLHttpRequest to false. The request will be synchronous, and processing execCommand will be very simple. But this synchronous flag is outdated, management should throw an error if you try to use it so that it is not used. See: https://xhr.spec.whatwg.org/#synchronous-flag

 var toCopy; const buttonClick = () => { var client = new XMLHttpRequest(); client.onload = function(data) { toCopy = this.responseText; console.log(document.execCommand('copy')); }; client.open("GET", "https://www.random.org/integers/?num=1&min=1&max=100&col=1&base=10&format=plain", false); client.send(); } $(() => { $("button").click(buttonClick) }) document.addEventListener('copy', function(e) { e.preventDefault(); e.clipboardData.setData('text/plain', toCopy); }); 

https://jsfiddle.net/zezskm2x/2/

+3
source

Like this?

 const cpUrl = (text) => { const oInputDom = document.createElement('input') const content = text oInputDom.setAttribute('value', content) document.body.appendChild(oInputDom) select(oInputDom) document.execCommand('copy') document.body.removeChild(aux) console.log('success', text) } const buttonClick = () => { getData(yourUrl, (yourResponse) => { cpUrl(yourResponseText) }) } 
-2
source

Source: https://habr.com/ru/post/1275635/


All Articles