Friday, November 20, 2015

'Copy to clipboard' button on web-page

Here are 3 ways to create such button:
  • Use flash-based ZeroClipboard - it's flash - I don't like it
  • Use clipboardData.SetData - works only for IE
  • Use modern w3c clipboard API (supported by modern browsers) - IMHO the best way
And here are my snippet for the last variant.

API: document.execCommand("copy") - returns true if successed
You can check if it enable by document.queryCommandEnabled("copy") - returns true if enable

Simplest case:
<html>
<body>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<script LANGUAGE="JavaScript">
function ClipBoard(element) {
    var $temp = $("<textarea visibility: hidden;>");
    $("body").append($temp);
    $temp.val(element).select();
    document.execCommand("copy");
    $temp.remove();
}
</script>
<button onclick="ClipBoard('test\ntest')">Copy to clipboard</button>
</body>
</html>



I've needed next actions for click:
  1. Ask data from server
  2. Copy it to clipboard

But here are thing - w3c clipboard api works only for 'user-triggered thread' (and in the simplest using of ZeroClipboard it also doesn't work - maybe it need some another API for that - I don't know). And when you asking server by ajax - callback is another thread, not user-triggered. So, you can handle it next ways:
  1. obsolete-but-working - not async ajax query
  2. you can ask data in background and keep it in browser - in button click handler copy existing data. It's bad when you have a lot of data
  3. you can ask user press button twice - first for loading, second for copying
  4. you can in click handler ask data by ajax & show textarea with selected text - let user copy it by himself.
So, I choosed not the best by working - 1st case.

function copy_to_clipboard_button_handler()
{
    if (data == '')
    {
        var request_data = ...;
       
        $.ajax({
            type: "POST",
            url: this.url,
            data: request_data,
            async: false,
       
            success: function(data)
            {
                global_object.clipboard_data = data;
            }
        });

    }
   
    var $temp = $("<textarea visibility: hidden;>");
    $("body").append($temp);
    $temp.val(global_object.clipboard_data).select();
    document.execCommand("copy");
    $temp.remove();
}


So.
  • 'async: false' means it will be user-triggered thread
  • usually in examples used <input> but it kills newline symbols
  • be careful with big amount of data - time for handling '$temp.val(global_object.clipboard_data).select()' grows exponential - on my desktop ~3MB handled ~20 seconds and ~30MB handled ~20 minutes and I didn't get patient to wait when it will finished. So, if you want copy more than several megabytes of data to clipboard - consider another variants - for example saving such amount of data to a file.

1 comment: