6

I can't copy the generated link directly (without ctrl+C) I am usign document.execCommand('copy') but it seems it has no effect. If code has no AJAX then its working pefectly. Here's the

HTML:

<div class="permalink-control"> </div>

JQUERY:

    $(".permalink-control")
          .append(
            '<div class="input-group">' +
            '    <span class="input-group-btn"><button type="button" class="btn btn-default" title="Get Permalink"><span class="glyphicon glyphicon-link"></span></button></span>' +
            '    <input type="text" class="form-control">' +
            '</div>'
          );
        $(".permalink-control input")
          .hide()
          .focus(function () {
            // Workaround for broken selection: https://stackoverflow.com/questions/5797539
            var $this = $(this);
            $this.select()
              .mouseup(function () {
                $this.unbind("mouseup");
                return false;
              });
          });
        $(".permalink-control button")
          .click(function () {
            var $this = $(this);
            $.ajax({
              url: "https://api-ssl.bitly.com/shorten",
              dataType: "jsonp",
              data: {
                longUrl: window.location.href,
                access_token: "your access token",
                format: "json"
              },
              success: function (response) {
                var longUrl = Object.keys(response.results)[0];
                var shortUrl = response.results[longUrl].shortUrl;
                if (shortUrl.indexOf(":") === 4) {
                  shortUrl = "https" + shortUrl.substring(4);
                }
                $this.parents(".permalink-control")
                  .find("input")
                  .show()
                  .val(shortUrl)
                  .focus();
              },
              async:false
            });
          });

UPDATE:

How do I copy to the clipboard in JavaScript?

is not answer to my question as My code also copies without using ctrl+C if AJAX is not there. However when I am using AJAX document.execCommand('copy') is not working.

Hemant
  • 1,900
  • 2
  • 15
  • 26
  • @AndreiGheorghiu the copying works, just not when you click the button. – A. L Apr 12 '17 at 23:04
  • Well my code is also copying the links directly .However when i am using AJAX.The link is not getting copied. – Hemant Apr 12 '17 at 23:06
  • 1
    @AndreiGheorghiu You found an irrelevant answer. The copying works when you directly click onto the input, just not when you click something else like a button. Not to mention the answers are very old and quite irrelevant now. – A. L Apr 12 '17 at 23:13
  • @AndreiGheorghiu I already know that answer read my question carefully – Hemant Apr 12 '17 at 23:20
  • Unfortunately, seems like you can't http://stackoverflow.com/questions/41361081/clipboard-copy-does-not-work-in-jquery-ajax-success-method Second answer – A. L Apr 12 '17 at 23:44
  • @A.Lau tried but not getting it right – Hemant Apr 13 '17 at 00:08
  • I don't think you can get it to work with Ajax because of security issues. So the user will need to manually copy it after it shows up – A. L Apr 13 '17 at 00:10
  • 1
    Your only option is to have the input value populated by the time the user clicks. Is [this possible](https://jsfiddle.net/websiter/6ot87oyu/) in your use-case? If you don't want to trigger a call to `$.ajax()` on each page load, set up a larger invisible element around the button and trigger the ajax on mouse-entering the invisible element. Not bullet proof, but better than nothing. A good trick might be to have the button in a dropdown, drawer, popup, modal or tooltip. When the user opens it, get the response before it opens up. And disable the button before ajax gets back. – tao Apr 13 '17 at 02:02
  • Possible duplicate of [execCommand('copy') does not work in XHR callback?](https://stackoverflow.com/questions/31925944/execcommandcopy-does-not-work-in-xhr-callback) – Kukeltje Jul 27 '17 at 12:03

2 Answers2

6

The reason for this is clearly stated in W3 specs:

Copy and cut commands triggered through a scripting API 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 to allow this.

But, having said that we can try to fool around the browser by copying text when a user does some interaction.

In this case since you are looking for a click event I assume you're user is interacting with mouse

So, what if I attach a $(window).blur() or $(document).click() event after the ajax call is resolved?

That's right, Since, the user has to blur at some point to use the copy selection, user will initiate a blur() or click() (depending on your need) and we can copy text to our clipboard.

Here's the HACKY DEMO

$(document).ready(function(){
    var shortUrl;
    $(".permalink-control")
      .append(
        '<div class="input-group">' +
        '    <span class="input-group-btn"><button type="button" class="btn btn-default" title="Get Permalink"><span class="glyphicon glyphicon-link"></span></button></span>' +
        '    <input type="text" class="form-control">' +
        '</div>'
      );
     $(".permalink-control input")
      .hide()
      .focus(function () {
        // Workaround for broken selection: http://stackoverflow.com/questions/5797539
        var $this = $(this);
        $this.select();
        document.execCommand('copy');
          $this.mouseup(function () {
            $this.unbind("mouseup");
            return false;
          });
      });
    $(".permalink-control button")
      .click(function () {
        var shortUrl ="";
        var $this = $(this);
        $.ajax({
          url: "https://api-ssl.bitly.com/shorten",
          dataType: "jsonp",
          data: {
            longUrl: window.location.href,
            access_token: "48ecf90304d70f30729abe82dfea1dd8a11c4584",
            format: "json"
          },
          success: function (response) {
             var longUrl = Object.keys(response.results)[0];
            shortUrl = response.results[longUrl].shortUrl;
            if (shortUrl.indexOf(":") === 4) {
              shortUrl = "https" + shortUrl.substring(4);
            }
              $this.parents(".permalink-control")
              .find("input")
              .show()
              .val(shortUrl)
              .focus();
            } 
       }).done(function(){
            $(window).blur(function(){
       document.execCommand('copy');
              $(window).off('blur');// make sure we don't copy anything else from the document when window is foucussed out
            });
       })
    });
})
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet"/>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="permalink-control"></div> 
<div class"log"></div>

P.S: This has been tested in chrome.

Nishanth Matha
  • 5,714
  • 2
  • 16
  • 27
  • I get this working with the click event if it is in the current tab, but how does this work with onblur? During the onblur event the selection storage gets cleared due to the pointer entering a new interface. – ploopploop Oct 23 '17 at 13:08
  • Works in IE 11, doesn't work in Chrome 63.x, Firefox 57.x – Dairo Jan 02 '18 at 15:22
4

I had the same problem. I solved it rather primitively: inside the handler of a click event, you can run an interval that will check the variable where ajax will insert the value after the server responds. After the answer is received, we stop the interval and start the work with the clipboard. No problem, because the user himself starts the interval after the click, without any callbacks.

Simple jQuery example:

var ajaxResponse;

function copyText(copiedText){
  $('<textarea class="copied-text">' + copiedText + '</textarea>').appendTo('body');

  if ( navigator.userAgent.match(/ipad|iphone/i) ) {
    var range = document.createRange(),
        textArea = $('.copied-text')[0];
    range.selectNodeContents(textArea);
    var selection = window.getSelection();
    selection.removeAllRanges();
    selection.addRange(range);
    textArea.setSelectionRange(0, 999999);
  } else {
    $('.copied-text').select();
  }

  document.execCommand('copy');
  $('.copied-text').remove();
};

function myAjaxFunc(){
  $.ajax({
    type: 'POST',
    url: yourUrl,
    data: yourData,
    success: function(data){
      ajaxResponse = data;
    }
  });
};

$('.your-button').on('click', function(){
  myAjaxFunc();
  var ajaxCheckTimer = setInterval(function(){
    if ( ajaxResponse ) {
      copyText(ajaxResponse);
      clearInterval(ajaxCheckTimer);
    };
  }, 100);
});

In this example, when clicking on a button, we send some data to the server and start the interval with checking the value of the ajaxResponse variable.

After the response from the server is received, the response of the server is written to this variable, after which the condition in the interval becomes true and the text copy function is called, and the server response variable is specified as the parameter: copyText(ajaxResponse);. The interval stops.

The copyText function creates an textarea on the page with the value of the ajaxResponse variable, copies this value from the field to the clipboard, and deletes the field from the page.


UPDATE 01.07.19

For correct copying to the clipboard on iOS, add the attribute contenteditable with the valuetrue to the text field:

$('<textarea class="copied-text" contenteditable="true">' + copiedText + '</textarea>').appendTo('body');
Alex Shink
  • 176
  • 3
  • 7