Cross-Browser approach to Copy content to Clipboard with javascript

rahul's picture

Before anything else, here is a sample demonstration of what I am discussing in this blog post. Enter some text in the textbox, and click the Flash's Copy icon below. You should have the text on your system clipboard. The .swf file for the same is attached with the post. Feel free to use it anywhere you like.

 

This is one of those topics, that has been blogged and written about furiously on the web. So, when I myself needed this functionality, I expected to find something useful on the web easily. And I thought I immediately hit the jackpot when a quick Google search threw up tons of pages for exactly what I was looking. However, it was not to be so, as I found out later.

Almost every solution that the Google search revealed worked, but the problem was only on Internet Explorer, not on other browsers and certainly not on Firefox. Some more research into the issue led me to pages like this, this and this, which clearly mention that FF considers it a security issue for Clipboard to be accessible to a web page. The crux of the matter was that you either need to explicitly enable Clipboard access to web pages in Firefox, or install add-ons that enable Clipboard access to web pages. As can be seen, none of these was a viable approach, as you do not expect the audience at large to configure settings or install add-ons on a page's request.

I was almost desperate that someone should have found a cross-browser solution of implementing this, as the problem is way too common. The tons of links I searched and followed took me no-where, everyone worked on IE but not on FF out-of-the-box.

I was wondering whether it is at all feasible to accomplish this, when something different struck my mind. Remember, Syntax Highlighter, the good old and wonderful syntax highlighting plugin from from Alex Gorbatchev (that it used on this site also for making the code stand-out and readable). The plugin put a toolbar on every piece of code, that had along with others a Copy button to copy the code. And as far as I knew, it worked on every browser, I had tested it on. Finally, I felt a way out here.

I immediately began debugging my own site's markup through Firebug to see how Syntax Highlighter handled Clipboard copying. And I was immediately stumped to see that it uses Flash for this purpose. Some more research revealed that it uses the Flash's System.setClipboard method for access to Clipboard.

Having figured out this, it should have been easy from here on. But again, it was not so. I immediately created a Flash movie, and enabled it to interact with javascript through Flash's ExternalInterface. What I thought of achieving was to embed a 1x1 pixel Flash movie into a page, and call a Flash javascript exported method from javascript to access Clipboard.

It did not take much time to assemble code, but the code did not work. I tried everything, from tweaking markup to browser settings to ActionScript code, but it simply did not work. Then I came across this post on adobe.com, which clearly spelt out that explicit user interaction is required in Flash 10 for successful access to clipboard (I tried bypassing this by manually raising Click Event on a button, and accessing Clipboard in the handler, needless to say, it failed).

So, in the end, it boiled down to this. The Flash movie itself required to have a UI against which User action would allow me to access clipboard. It was better than having nothing at all.

Now coming on to the coding part, you simple need to embed the Flash movie normally into a web page. Here's how I do it on this page:

 

<object id='clipboard' codebase='http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=9,0,0,0' width='16' height='16' align='middle'>
	<param name='allowScriptAccess' value='always' />
	<param name='allowFullScreen' value='false' />
	<param name='movie' value='clipboard.swf' />
	<param name='quality' value='high' />
	<param name='bgcolor' value='#ffffff' />
	<param name='wmode' value='transparent' />
	<param name='flashvars' value='callback=f1' />
	<embed src='clipboard.swf' flashvars='callback=f1' quality='high' bgcolor='#ffffff' width='16' height='16' wmode='transparent' name='clipboard' align='middle' allowscriptaccess='always' allowfullscreen='false' type='application/x-shockwave-flash' pluginspage='http://www.adobe.com/go/getflashplayer' />
</object>

 

There are 2 important things above. One, the Flash has been granted script access vis allowScriptAccess="true". Second, the content for copying normally would come from your page, and the movie is not aware of the content to place in clipboard. Therefore, you specify a callback method in the flashvars for the movie. This should be a fully-qualified reference to a method name in your javascript that should return a string which would be copied onto the clipboard. Here's the javascript method used on this page:

{syntaxhighlighter brush: jscript;fontsize: 100; first-line: 1; }function f1() { var s = document.getElementById('text1').value; var div = document.createElement('div'); div.innerText = '"' + s + '" copied to clipboard.'; document.body.appendChild(div); if (window.clipboardData) window.clipboardData.setData('text', s); else return (s); } {/syntaxhighlighter}

What you should particularly note above is that IE provides out-of-the box window.clipboardData.setData method for putting data on the clipboard, which has been used. The Flash approach is used for all other browsers which do not support this. The user interaction still has to be through the Flash movie by clicking against it for everything to be able to work in a cross-browser fashion.

Use the comment form below to discuss any issue you face using this approach. I have tested it on IE, FF & Chrome, and it works!!

The html file attached below together with the clipboard Flash movie was used to create the example on the page above.

UPDATE:

  • Oct 24, 2010 - I later needed to pass custom parameters to the callback function also. So, enhanced the clipboard flash movie to support another flashvar called: callbackArg. You can use this to pass a string to the flash movie which the movie forwards to the javascript callback method when you click on the movie. Here's a sample code html for the same:
    <object id='clipboard' codebase='http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=9,0,0,0' width='16' height='16' align='middle'>
    	<param name='allowScriptAccess' value='always' />
    	<param name='allowFullScreen' value='false' />
    	<param name='movie' value='../resources/flash/clipboard.swf' />
    	<param name='quality' value='high' />
    	<param name='bgcolor' value='#ffffff' />
    	<param name='flashvars' value='callback=f1&callbackArg=MyCallbackArg' />
    	<embed src='../resources/flash/clipboard.swf' flashvars='callback=f1&callbackArg=MyCallbackArgument' quality='high' bgcolor='#ffffff' width='16' height='16' name='clipboard' align='middle' allowscriptaccess='always' allowfullscreen='false' type='application/x-shockwave-flash' pluginspage='http://www.adobe.com/go/getflashplayer' />
    </object>
    

    If you need to have multiple parameters for the callback method, or non-string argument, you can easily serialize those parameters as json, url encode them, and then set them as the callbackArg for the movie. then in your callback method, you would first url decode them and then deserialize them from json.
    For Json serialization, you can pick code from here or here, and for url encoding/decoding, you can use the browser's native encodeURIComponent and decodeURIComponent methods.
AttachmentSize
Clipboard.swf2.51 KB
Clipboard.htm1.67 KB

Comments

thank's for sharing

i wonder, if i want to use it without click the copy button,

but directly attach listener on html tag

like <a href='some text to copy' >clipboard</a>

how can i deal with it ? 

By ovi (not verified)
rahul's picture

Hi ovi, If you read the blog post carefully, I have answered this in the post itself. My approach is based on the use of a Flash movie and you could have achieved your objective prior to Flash 10 (i.e. in Flash 9 and earlier).

However, as per security changes in Flash 10 (read this post), user interaction is necessary for setting data on the system clipboard.

The Flash file attached above actually provides a method to call from javascript to do exactly what you are intending, but I did not discuss it in the blog, as any system would receive Flash 10 on a fresh install, and a majority of existing installs have automatic update enabled for Flash Player.

So, there's no point in discussing that option as that would work in only a limited number of cases. 

By rahul

Is there a cross-browser approach to CLEAR the clipboard with javascript (without user interaction) ?

Greetings,

Martin
The Netherlands

By Martin Verbeek (not verified)
rahul's picture

Hi Martin,

Clearing the clipboard in itself should be as simple as simply using the attached flash file and passing an empty string. That should effectively erase any existing data off the clipboard.

However, as far as I know, there isn't a cross browser approach to accomplish this without user interaction. Only Internet Explorer provides an out-of-the-box way to put data on the clipboard (through window.clipboardData object, that is accessible in javascript). For all other browsers, Flash is your best bet for accessing the system clipboard (javascript does not provide any interface to the System clipboard in browsers except IE).

And as per security changes in Flash Player 10 (links are provided above), User Interaction against the Flash movie is a prerequisite to access the clipboard. Flash Player 10 silently ignores all accesses to clipboard (without raising any error) that happen outside an event handler initiated by user action.

By rahul

Thanks for the tutorial.  Quite detailed and easy to follow.

I am, however, running into problems when I try to pass the id of a textarea field as a parameter for the callback function.  In IE, everything works as expected, but in Firefox the value doesn't get copied to the clipboard.

This is how I pass the parameter (which is also specified in the embed tag):

<param name='flashvars' value="callback=f1('MyTextareaId')" />

Again, the return value from the f1 function is correct (I checked using an alert box), but it's just not copying to the clipboard.  Any idea what I might be doing wrong?

Thanks in advance,

Tony

By Tony (not verified)
rahul's picture

Hi Tony, I think you have got it completely wrong. The callback needs to be the name of the function (i.e. just f1 and not f1('MyTextareaId')).

If you need to pass-in some parameter to the callback method, maintain it as a global variable or some other Object Oriented way.

See the attached file for an example with textarea. It's just identical for a text input field.

By rahul

Hi,

I've been postponing this for a while, but I can't seem to do it no longer. So when i found your examples working I was really happy. However, when I started implementing it in my environment I can't seem to get it to work.

I need to copy ExtJS grid data as in you other blog, but went back to your original examples after having some problems. Also in this case I can not get it to work in my environment even tough ot works fine from you're site. 

I've done the following:

Saved the htm and the swf to my local disk. Opened the htm file in the same browser that succesfully ran you're demo (FF 3.5.9). The page is shown fine, but when clicking the copy icon nothing new is inserted to the clipboard.

If inserting an alert in the f1 script, nothing is displayed when clicking the copy icon. Any ideas as to what I'm missing here?

BR

Roger

By Roger (not verified)

Add new comment