Using the Clipboard

  • Revision slug: Using_the_Clipboard
  • Revision title: Using the Clipboard
  • Revision id: 98131
  • Created:
  • Creator: Sheppy
  • Is current revision? No
  • Comment no wording changes

Revision Content

This section provides information about cutting, copying and pasting to and from the clipboard.

The Clipboard

Mozilla provides a number of interfaces for accessing the clipboard. The component @mozilla.org/widget/clipboardhelper;1 can be used to copy text to the clipboard. This component implements the interface nsIClipboardHelper, which has a function copyString which can be used to copy a string.

const gClipboardHelper = Components.classes["@mozilla.org/widget/clipboardhelper;1"].
                                    getService(Components.interfaces.nsIClipboardHelper);
gClipboardHelper.copyString("Put me on the clipboard, please.");

This example will first create a clipboard helper and then copy a short string to the clipboard. This method only works to put strings on the clipboard. For other types of data, such as URLs or images, you will need to use a more complex method.

A component @mozilla.org/widget/clipboard;1 and an interface nsIClipboard provide general access to the system clipboard. You can use it to copy and paste any type of data from your application to the clipboard. Three XPCOM objects are needed to handle clipboard operations. The first is an object that holds the data to put on the clipboard. The second is the clipboard object. The third is an object which is used to transfer the data from the first object to the clipboard. The clipboard model in Mozilla requires you to perform the following steps to copy data:

  1. Create an XPCOM wrapper for the data which you want to put on the clipboard. This is needed because you can put anything on the clipboard from text to images.
  2. Create a transferring object. This object can be the component @mozilla.org/widget/transferable;1 which implements the interface nsITransferable.
  3. Tell the transferring object about the type of data being copied.
  4. Tell the transferring object about the data to copy.
  5. Create a clipboard object which refers to the system clipboard.
  6. Tell the clipboard object to copy the data using the transferring object.

You might wonder why a transferring object is needed instead of just putting the object directly on the clipboard. One reason is that some systems do not copy the data right away. Instead, they wait until the data is pasted. Another reason is that the transferable can hold multiple representations of the same data. For example, a piece of HTML can be represented in both its original HTML form and in plain text. If an application wants to get the data from the clipboard and doesn't understand HTML, it can use the plain text version. If it does understand HTML, it can grab that version. The transferring object will hold the clipboard contents until the application has decided what it needs. This allows the clipboard to be used by another application right away.

Let's break down the steps needed to copy data to the clipboard. First, we need to create an XPCOM object to wrap what we want to copy. We'll assume that we want to copy some text. We will use the interface nsISupportsString which can be used to represent strings (specifically, Unicode strings).

var copytext = "Text to copy";
var str      = Components.classes["@mozilla.org/supports-string;1"].
                          createInstance(Components.interfaces.nsISupportsString);
str.data     = copytext;

The first line holds the text that we want to copy. Next, the variable str is assigned to a component that can be used to hold a string. The third line assigns the string to the component using the data property. Here, the string "Text to copy" will be copied but you can replace this with the text string that you want to copy. Now that we have the object to copy, a transferring object needs to be created:

var trans = Components.classes["@mozilla.org/widget/transferable;1"].
                       createInstance(Components.interfaces.nsITransferable);
trans.addDataFlavor("text/unicode");
trans.setTransferData("text/unicode", str, copytext.length * 2);

The first line gets the transferring component which implements nsITransferable. Next, we need to tell the transferable what type of data we want to use. The type of data is referred to as a data flavor. The function addDataFlavor is used to tell the transferable that it needs to transfer data of a certain flavour. In this case, we are transferring the flavor "text/unicode" which is a Unicode string. Then, the function setTransferData is called which copies the data from the string into the transferable. This function takes three parameters. The first is the flavor we are setting, the second is the object holding the string and the third is the length of the data, in bytes. Here, the length is multiplied by two because we are using a Unicode string which requires two bytes per character.

You can repeat the last two lines and call addDataFlavor and setTransferData for multiple flavors. That way, you could have a text version and an HTML version of the content. The Transferable object will hold its own copy of the data. When you've added all the flavors you want, you can put it all on the clipboard at once. The transferable object will hold all of the data that you want until you're ready to put it on the clipboard.

Next, we need to create a clipboard object that refers to the system clipboard.

var clipid = Components.interfaces.nsIClipboard;
var clip   = Components.classes["@mozilla.org/widget/clipboard;1"].getService(clipid);
clip.setData(trans, null, clipid.kGlobalClipboard);

We get the system clipboard object and store it in the clip variable. We can copy the data to the clipboard by calling the function setData. The first parameter of this function is the transferable. The second parameter can usually be set to null but you could set it to a nsIClipboardOwner so that you can tell when the data you've copied is overwritten by another copy operation. Call setData only when you're ready to copy to the system clipboard.

The third parameter to setData (and the parameter to emptyClipboard) indicates which clipboard buffer to use. The above code uses the constant kGlobalConstant for this, which refers to the global clipboard. This would be the same one that cut and paste operations from the Edit menu typically use. If you use kSelectionClipboard instead, you will copy into the selection buffer, which is generally only available on Unix systems.

This multi-step process has resulted in text being copied on the clipboard. We can cut to the clipboard instead of copying by doing a copy and then deleting the original data. Normally, the text would be in a document or textbox. The code is put together below, with additional error checking:

var copytext = "Text to copy";

var str   = Components.classes["@mozilla.org/supports-string;1"].
                       createInstance(Components.interfaces.nsISupportsString);
if (!str) return false;

str.data  = copytext;

var trans = Components.classes["@mozilla.org/widget/transferable;1"].
                       createInstance(Components.interfaces.nsITransferable);
if (!trans) return false;

trans.addDataFlavor("text/unicode");
trans.setTransferData("text/unicode", str, copytext.length * 2);

var clipid = Components.interfaces.nsIClipboard;
var clip   = Components.classes["@mozilla.org/widget/clipboard;1"].getService(clipid);
if (!clip) return false;

clip.setData(trans, null, clipid.kGlobalClipboard);

The complete function shown below copies some text to the clipboard as HTML, as well as making it a clickable Hyperlink. So we've added a text flavor and an HTML flavor of the content. The Transferable object will hold both flavors.

copyLinkToClipboard : function(copyURL,copyLabel) {	

// generate the Unicode and HTML versions of the Link

var textUnicode = copyURL;
var textHtml = ("<a href=\"" + copyURL + "\">" + copyLabel + "</a>");


// make a copy of the Unicode

var str = Components.classes["@mozilla.org/supports-string;1"].
                       createInstance(Components.interfaces.nsISupportsString);
if (!str) return false; // couldn't get string obj
str.data = textUnicode; // unicode string?


// make a copy of the HTML

var htmlstring = Components.classes["@mozilla.org/supports-string;1"].
                       createInstance(Components.interfaces.nsISupportsString);
if (!htmlstring) return false; // couldn't get string obj
htmlstring.data = textHtml;	        


// add Unicode & HTML flavors to the transferable widget

var trans = Components.classes["@mozilla.org/widget/transferable;1"].
                       createInstance(Components.interfaces.nsITransferable);
if (!trans) return false; //no transferable widget found

trans.addDataFlavor("text/unicode");
trans.setTransferData("text/unicode", str, textUnicode.length * 2); // *2 because it's unicode

trans.addDataFlavor("text/html");
trans.setTransferData("text/html", htmlstring, textHtml.length * 2); // *2 because it's unicode	


// copy the transferable widget!

var clipboard = Components.classes["@mozilla.org/widget/clipboard;1"].
                       getService(Components.interfaces.nsIClipboard);
if (!clipboard) return false; // couldn't get the clipboard

clipboard.setData(trans, null, Components.interfaces.nsIClipboard.kGlobalClipboard);
return true;

},

Pasting Clipboard Contents

To paste data from the clipboard we can use a similar process, except we use getData instead of setData and getTransferData instead of setTransferData. Here are the steps to pasting:

  1. Create a clipboard object which refers to the system clipboard.
  2. Create a transferring object which implements the nsITransferable interface.
  3. Tell the transferring object about the flavor of data you want to get.
  4. Retrieve the data from the clipboard and put it in the transferable.
  5. Get the data from the transferring object.

The first steps are similar to that used for copying:

var clip  = Components.classes["@mozilla.org/widget/clipboard;1"].getService(Components.interfaces.nsIClipboard);
if (!clip) return false;

var trans = Components.classes["@mozilla.org/widget/transferable;1"].createInstance(Components.interfaces.nsITransferable);
if (!trans) return false;
trans.addDataFlavor("text/unicode");

This code gets the system clipboard object and a transferable object. The flavor is added to the transferable. Next, we need to get the data from the clipboard:

clip.getData(trans, clip.kGlobalClipboard);

var str       = new Object();
var strLength = new Object();

trans.getTransferData("text/unicode", str, strLength);

The first line performs the opposite of getData. The data currently on the system clipboard is placed into the transferable. Next we create two JavaScript objects which will hold the data and the length of the data. Note that we have no idea what type of data is currently on the clipboard. It may have been placed there by another application. This is why we use generic Objects for str and strLength.

Then we use getTransferData to retrieve the data from the transferable. We specify the flavor we would like to get. The data will be converted if it is not of the desired flavor and a conversion between the actual and desired flavor is possible. If you originally copied data of multiple flavors onto the clipboard, you can retrieve the data in the best format necessary. For example, a textbox would accept "text/unicode" (or "text/plain") while a Composer window might accept HTML and image data.

The variable str now holds the data from the clipboard. We need to convert the data back into a JavaScript string from an XPCOM object. The code below can be used for this purpose:

if (str) str       = str.value.QueryInterface(Components.interfaces.nsISupportsString);
if (str) pastetext = str.data.substring(0, strLength.value / 2);

Because the data from the transferable is a nsISupportsString, we need to convert it into a JavaScript string. The property value of the object filled in by getTransferData, which is str in this case, provides the actual value of the object.

We assign the string to the variable pastetext. We can then put that into a textbox or other location as necessary.

Original Document Information

Revision Source

<p>This section provides information about cutting, copying and pasting to and from the clipboard.</p>
<h3 name="The_Clipboard">The Clipboard</h3>
<p>Mozilla provides a number of interfaces for accessing the clipboard. The component <code>@mozilla.org/widget/clipboardhelper;1</code> can be used to copy text to the clipboard. This component implements the interface <a href="/en/nsIClipboardHelper" title="en/nsIClipboardHelper">nsIClipboardHelper</a>, which has a function <code>copyString</code> which can be used to copy a string.</p>
<pre class="brush: js">const gClipboardHelper = Components.classes["@mozilla.org/widget/clipboardhelper;1"].
                                    getService(Components.interfaces.nsIClipboardHelper);
gClipboardHelper.copyString("Put me on the clipboard, please.");
</pre>
<p>This example will first create a clipboard helper and then copy a short string to the clipboard. This method only works to put strings on the clipboard. For other types of data, such as URLs or images, you will need to use a more complex method.</p>
<p>A component <code>@mozilla.org/widget/clipboard;1</code> and an interface <a href="/en/nsIClipboard" title="en/nsIClipboard">nsIClipboard</a> provide general access to the system clipboard. You can use it to copy and paste any type of data from your application to the clipboard. Three <a href="/en/XPCOM" title="en/XPCOM">XPCOM</a> objects are needed to handle clipboard operations. The first is an object that holds the data to put on the clipboard. The second is the clipboard object. The third is an object which is used to transfer the data from the first object to the clipboard. The clipboard model in Mozilla requires you to perform the following steps to copy data:</p>
<ol> <li>Create an XPCOM wrapper for the data which you want to put on the clipboard. This is needed because you can put anything on the clipboard from text to images.</li> <li>Create a transferring object. This object can be the component <code>@mozilla.org/widget/transferable;1</code> which implements the interface <a href="/en/NsITransferable" title="en/NsITransferable">nsITransferable</a>.</li> <li>Tell the transferring object about the type of data being copied.</li> <li>Tell the transferring object about the data to copy.</li> <li>Create a clipboard object which refers to the system clipboard.</li> <li>Tell the clipboard object to copy the data using the transferring object.</li>
</ol>
<p>You might wonder why a transferring object is needed instead of just putting the object directly on the clipboard. One reason is that some systems do not copy the data right away. Instead, they wait until the data is pasted. Another reason is that the transferable can hold multiple representations of the same data. For example, a piece of HTML can be represented in both its original HTML form and in plain text. If an application wants to get the data from the clipboard and doesn't understand HTML, it can use the plain text version. If it does understand HTML, it can grab that version. The transferring object will hold the clipboard contents until the application has decided what it needs. This allows the clipboard to be used by another application right away.</p>
<p>Let's break down the steps needed to copy data to the clipboard. First, we need to create an XPCOM object to wrap what we want to copy. We'll assume that we want to copy some text. We will use the interface <a href="/en/nsISupportsString" title="en/nsISupportsString">nsISupportsString</a> which can be used to represent strings (specifically, Unicode strings).</p>
<pre class="brush: js">var copytext = "Text to copy";
var str      = Components.classes["@mozilla.org/supports-string;1"].
                          createInstance(Components.interfaces.nsISupportsString);
str.data     = copytext;
</pre>
<p>The first line holds the text that we want to copy. Next, the variable <code>str</code> is assigned to a component that can be used to hold a string. The third line assigns the string to the component using the <code>data</code> property. Here, the string "Text to copy" will be copied but you can replace this with the text string that you want to copy. Now that we have the object to copy, a transferring object needs to be created:</p>
<pre class="brush: js">var trans = Components.classes["@mozilla.org/widget/transferable;1"].
                       createInstance(Components.interfaces.nsITransferable);
trans.addDataFlavor("text/unicode");
trans.setTransferData("text/unicode", str, copytext.length * 2);
</pre>
<p>The first line gets the transferring component which implements <a href="/en/NsITransferable" title="en/NsITransferable">nsITransferable</a>. Next, we need to tell the transferable what type of data we want to use. The type of data is referred to as a data flavor. The function <code>addDataFlavor</code> is used to tell the transferable that it needs to transfer data of a certain flavour. In this case, we are transferring the flavor "text/unicode" which is a Unicode string. Then, the function <code>setTransferData</code> is called which copies the data from the string into the transferable. This function takes three parameters. The first is the flavor we are setting, the second is the object holding the string and the third is the length of the data, in bytes. Here, the length is multiplied by two because we are using a Unicode string which requires two bytes per character.</p>
<p>You can repeat the last two lines and call <code>addDataFlavor</code> and <code>setTransferData</code> for multiple flavors. That way, you could have a text version and an HTML version of the content. The <code>Transferable</code> object will hold its own copy of the data. When you've added all the flavors you want, you can put it all on the clipboard at once. The transferable object will hold all of the data that you want until you're ready to put it on the clipboard.</p>
<p>Next, we need to create a clipboard object that refers to the system clipboard.</p>
<pre class="brush: js">var clipid = Components.interfaces.nsIClipboard;
var clip   = Components.classes["@mozilla.org/widget/clipboard;1"].getService(clipid);
clip.setData(trans, null, clipid.kGlobalClipboard);
</pre>
<p>We get the system clipboard object and store it in the clip variable. We can copy the data to the clipboard by calling the function <code>setData</code>. The first parameter of this function is the transferable. The second parameter can usually be set to <code>null</code> but you could set it to a <a href="/en/nsIClipboardOwner" title="en/nsIClipboardOwner">nsIClipboardOwner</a> so that you can tell when the data you've copied is overwritten by another copy operation. Call <code>setData</code> only when you're ready to copy to the system clipboard.</p>
<p>The third parameter to <code>setData</code> (and the parameter to <code>emptyClipboard</code>) indicates which clipboard buffer to use. The above code uses the constant <code>kGlobalConstant</code> for this, which refers to the global clipboard. This would be the same one that cut and paste operations from the Edit menu typically use. If you use <code>kSelectionClipboard</code> instead, you will copy into the selection buffer, which is generally only available on Unix systems.</p>
<p>This multi-step process has resulted in text being copied on the clipboard. We can cut to the clipboard instead of copying by doing a copy and then deleting the original data. Normally, the text would be in a document or textbox. The code is put together below, with additional error checking:</p>
<pre class="brush: js">var copytext = "Text to copy";

var str   = Components.classes["@mozilla.org/supports-string;1"].
                       createInstance(Components.interfaces.nsISupportsString);
if (!str) return false;

str.data  = copytext;

var trans = Components.classes["@mozilla.org/widget/transferable;1"].
                       createInstance(Components.interfaces.nsITransferable);
if (!trans) return false;

trans.addDataFlavor("text/unicode");
trans.setTransferData("text/unicode", str, copytext.length * 2);

var clipid = Components.interfaces.nsIClipboard;
var clip   = Components.classes["@mozilla.org/widget/clipboard;1"].getService(clipid);
if (!clip) return false;

clip.setData(trans, null, clipid.kGlobalClipboard);
</pre>
<p>The complete function shown below copies some text to the clipboard as HTML, as well as making it a clickable Hyperlink. So we've added a text flavor and an HTML flavor of the content. The <code>Transferable</code> object will hold both flavors.</p>
<pre class="brush: js">copyLinkToClipboard : function(copyURL,copyLabel) {	

<strong>// generate the Unicode and HTML versions of the Link</strong>

var textUnicode = copyURL;
var textHtml = ("&lt;a href=\"" + copyURL + "\"&gt;" + copyLabel + "&lt;/a&gt;");


<strong>// make a copy of the Unicode</strong>

var str = Components.classes["@mozilla.org/supports-string;1"].
                       createInstance(Components.interfaces.nsISupportsString);
if (!str) return false; // couldn't get string obj
str.data = textUnicode; // unicode string?


<strong>// make a copy of the HTML</strong>

var htmlstring = Components.classes["@mozilla.org/supports-string;1"].
                       createInstance(Components.interfaces.nsISupportsString);
if (!htmlstring) return false; // couldn't get string obj
htmlstring.data = textHtml;	        


<strong>// add Unicode &amp; HTML flavors to the transferable widget</strong>

var trans = Components.classes["@mozilla.org/widget/transferable;1"].
                       createInstance(Components.interfaces.nsITransferable);
if (!trans) return false; //no transferable widget found

trans.addDataFlavor("text/unicode");
trans.setTransferData("text/unicode", str, textUnicode.length * 2); // *2 because it's unicode

trans.addDataFlavor("text/html");
trans.setTransferData("text/html", htmlstring, textHtml.length * 2); // *2 because it's unicode	


<strong>// copy the transferable widget!</strong>

var clipboard = Components.classes["@mozilla.org/widget/clipboard;1"].
                       getService(Components.interfaces.nsIClipboard);
if (!clipboard) return false; // couldn't get the clipboard

clipboard.setData(trans, null, Components.interfaces.nsIClipboard.kGlobalClipboard);
return true;

},
</pre>
<h3 name="Pasting_Clipboard_Contents">Pasting Clipboard Contents</h3>
<p>To paste data from the clipboard we can use a similar process, except we use <code>getData</code> instead of <code>setData</code> and <code>getTransferData</code> instead of <code>setTransferData</code>. Here are the steps to pasting:</p>
<ol> <li>Create a clipboard object which refers to the system clipboard.</li> <li>Create a transferring object which implements the <a href="/en/NsITransferable" title="en/NsITransferable">nsITransferable</a> interface.</li> <li>Tell the transferring object about the flavor of data you want to get.</li> <li>Retrieve the data from the clipboard and put it in the transferable.</li> <li>Get the data from the transferring object.</li>
</ol>
<p>The first steps are similar to that used for copying:</p>
<pre class="brush: js">var clip  = Components.classes["@mozilla.org/widget/clipboard;1"].getService(Components.interfaces.nsIClipboard);
if (!clip) return false;

var trans = Components.classes["@mozilla.org/widget/transferable;1"].createInstance(Components.interfaces.nsITransferable);
if (!trans) return false;
trans.addDataFlavor("text/unicode");
</pre>
<p>This code gets the system clipboard object and a transferable object. The flavor is added to the transferable. Next, we need to get the data from the clipboard:</p>
<pre class="brush: js">clip.getData(trans, clip.kGlobalClipboard);

var str       = new Object();
var strLength = new Object();

trans.getTransferData("text/unicode", str, strLength);
</pre>
<p>The first line performs the opposite of <code>getData</code>. The data currently on the system clipboard is placed into the transferable. Next we create two JavaScript objects which will hold the data and the length of the data. Note that we have no idea what type of data is currently on the clipboard. It may have been placed there by another application. This is why we use generic Objects for <code>str</code> and <code>strLength</code>.</p>
<p>Then we use <code>getTransferData</code> to retrieve the data from the transferable. We specify the flavor we would like to get. The data will be converted if it is not of the desired flavor and a conversion between the actual and desired flavor is possible. If you originally copied data of multiple flavors onto the clipboard, you can retrieve the data in the best format necessary. For example, a textbox would accept "text/unicode" (or "text/plain") while a Composer window might accept HTML and image data.</p>
<p>The variable <code>str</code> now holds the data from the clipboard. We need to convert the data back into a JavaScript string from an XPCOM object. The code below can be used for this purpose:</p>
<pre class="brush: js">if (str) str       = str.value.QueryInterface(Components.interfaces.nsISupportsString);
if (str) pastetext = str.data.substring(0, strLength.value / 2);
</pre>
<p>Because the data from the transferable is a <a href="/en/nsISupportsString" title="en/nsISupportsString">nsISupportsString</a>, we need to convert it into a JavaScript string. The property <code>value</code> of the object filled in by <code>getTransferData</code>, which is <code>str</code> in this case, provides the actual value of the object.</p>
<p>We assign the string to the variable <code>pastetext</code>. We can then put that into a textbox or other location as necessary.</p>
<div class="originaldocinfo">
<h2 name="Original_Document_Information">Original Document Information</h2>
<ul> <li>Author(s): <a class="link-mailto" href="mailto:enndeakin@sympatico.ca">Neil Deakin</a></li> <li>Original Document: <a class=" external" href="http://xulplanet.com/tutorials/mozsdk/clipboard.php" rel="freelink">http://xulplanet.com/tutorials/mozsdk/clipboard.php</a></li> <li>Copyright Information: Copyright (C) <a class="link-mailto" href="mailto:enndeakin@sympatico.ca">Neil Deakin</a></li>
</ul>
</div>
Revert to this revision