HTML5 Zone is brought to you in partnership with:

Clark is a web evangelist for Microsoft based in Illinois. A Chicago native who can’t spell, Clark as a kid actually made his money building cars, getting grease under his nails. That art of building would later lead him to software development where he drinks the Web Development Kool-Aid. Writing code is what keeps Clark awake at night, while continually working on his craft and rapping with others over a few cold CORS. You can hear Clark muse about software on his podcast Developer Smackdown, or find his family cruising around in a 1968 Camaro SS. Clark is a DZone MVB and is not an employee of DZone and has posted 32 posts at DZone. You can read more from them at their website. View Full User Profile

31 Days of Windows 8 for HTML5 | Day #17 The Clipboard

11.24.2012
| 5679 views |
  • submit to reddit

 

This article is Day #17 in a series called 31 Days of Windows 8.  Each of the articles in this series will be published foXAMLCalloutr both HTML5/JS and XAML/C#. You can find additional resources, downloads, and source code on our website.

Today, we’re going to focus on the Windows 8 clipboard exclusively. More specifically, we’re going to look at how we can save and retrieve data from this system-wide and heavily used mechanism.  There are generally four types of data that we are going to see a user want to copy and paste:

  • Text
  • HTML
  • Images
  • Files

These are called the Standard Clipboard Formats. We’ll write some code in this article that shows not only how to copy and paste these values, but also how to detect which type of data the clipboard currently contains. There are 4 other categories of Clipboard Formats:

We will leave those for another day but get ready to do some copying!

Saving Data to the Clipboard

As we saw briefly in yesterday’s article on context menus, we took a very quick look at saving some text to the clipboard.  This time, we’ll cover that in more depth, and include saving images and files to the clipboard as well.  It’s important to note that some controls like the paragraph that we made selectable yesterday can copy by default. An input element of type=”text” can read from the clipboard. The point of today is to learn how to interact with the clipboard outside of those default scenarios.

To get started, we should talk about the DataPackage object. A DataPackage is what we are going to use to transport our data.  We will create a DataPackagewhen we save data to the clipboard, and we will use the Clipboard object to get the content ( actually calling a method called getContent() ) method to retrieve the data when we’re pasting it.

In my sample project (which you can download from GitHub), you will see that I’ve created a button with an event handler for each data type.  We’ll spend the rest of this section looking at how we store these different types of data to the Clipboard.

It is important to note that the clipboard is actually divided into several sections, one for each data type.  You can save data to one or many of these sections, and the target for pasting will make the determination as to what type of data it will display when pasted.  This might sound very similar to how the Share Contract works, and for the most part, it is.

It’s also likely that you’ve encountered this in the past: you copy content from one app, and try to paste it in another, only to have it paste something else.  This is a direct artifact of the “sections” of the clipboard.  Let’s take a look at how to save each data type:

Text

Certainly the simplest example, text can be stored to the Clipboard in just a few lines of code. First let’s just grab some selected text:

var selectedText = window.getSelection();

Certainly the text of which you decide to grab is up to you. With some text in hand now we need to create our DataPackage and set the text on it.

var _clipboard = Windows.ApplicationModel.DataTransfer.Clipboard,
    _dataTransfer = Windows.ApplicationModel.DataTransfer;

var dataPackage = new _dataTransfer.DataPackage();
dataPackage.setText(selectedText);

_clipboard.setContent(dataPackage);

ou will see a pattern form as we move through the other examples, but this is about as basic as they come.  We create a new DataPackage object, call the setText() method with the text we want to save, and then set the content of the Clipboard to that DataPackage.

HTML

HTML, while similar to text, has its own quirks and formatting, and because of this, requires slightly different treatment when adding it to a DataPackage.  In this example, I am just grabbing the innerHtml of an element on our default.html page and using that as my DataPackage contents. Let’s that a first pass at things.

var htmlContent = document.querySelector("#content").innerHTML;
var dataPackage = new _dataTransfer.DataPackage();
dataPackage.setHtmlFormat(htmlContent);

_clipboard.setContent(dataPackage);

It looks very much in line with what we had done previously. Now if you we’re to run that and try to paste into something like Notepad++ or Visual Studio you in fact wouldn’t see anything. As I briefly mentioned before, HTML requires some slightly different formatting. Let’s modify.

var htmlContent = document.querySelector("#content").innerHTML;
var htmlContentFormated =
    _dataTransfer.HtmlFormatHelper.createHtmlFormat(htmlContent);

var dataPackage = new _dataTransfer.DataPackage();
dataPackage.setHtmlFormat(htmlContentFormated);

_clipboard.setContent(dataPackage);

Now that format helper will take our html and create some special sauce around it, transforming it to something like this:

Version:1.0
StartHTML:00000097
EndHTML:00000806
StartFragment:00000153
EndFragment:00000773
<!DOCTYPE><HTML><HEAD></HEAD><BODY><!--StartFragment -->
        <h1>Day #17 - The Clipboard</h1>

        <br>
        <div>
            <button id="btnCopyText">copy text</button>
            <button id="btnCopyHtml">copy html</button>
            <button id="btnCopyImage">copy image</button>
            <button id="btnCopyFile">copy file</button>
            <br>
            <p class="selectable" id="myText">Bacon ipsum dolor sit amet pig jowl filet mignon sirloin ribeye tenderloin. Sausage cow shank jerky pancetta pig biltong corned beef short loin.</p>
            <input id="inputBox">
            <img id="myImage" src="images/smalllogo.png">
        </div>

    <!--EndFragment --></BODY></HTML>

Interesting. If we run that code again we can in fact copy and paste into an HTML based file in something like Visual Studio but if I go back and try that same thing in Notepad++ I get nothing. Windows is smart enough to only allow you to paste the types content which are applicable for the destination. To fix that we need multiple types I guess. All we need to do is just call SetText() value of this DataPackage, with the original unformatted string. Here is the completed function:

var _clipboard = Windows.ApplicationModel.DataTransfer.Clipboard,
    _dataTransfer = Windows.ApplicationModel.DataTransfer;

function copyHtmlToClipboard() {
    var htmlContent = document.querySelector("#content").innerHTML;
    var htmlContentFormated =
        _dataTransfer.HtmlFormatHelper.createHtmlFormat(htmlContent);

    var dataPackage = new _dataTransfer.DataPackage();
    dataPackage.setHtmlFormat(htmlContentFormated);
    dataPackage.setText(htmlContent);

    _clipboard.setContent(dataPackage);
}

As you can see above, we can set multiple values at the same time, and as you get deeper into this example, you’ll start to notice that most of your favorite apps store data in multiple formats “just in case.”

Images

Our next example is images, and I want to be really clear on this one.  We’re not talking about a file that happens to be an image.  We’re talking about copying an image from a website, for example, and then pasting it into a OneNote file or Windows Live Writer.  In my example, I grabbing an image from the HTML DOM and putting that on the clipboard.

var imageSrc = document.getElementById("myImage").src;
var imageUri = new Windows.Foundation.Uri(imageSrc);
var streamRef = Windows.Storage.Streams.RandomAccessStreamReference.createFromUri(imageUri);

var dataPackage = new _dataTransfer.DataPackage();
dataPackage.setBitmap(streamRef);

_clipboard.setContent(dataPackage);

Above we get the source of an image in the DOM and create a URI from it. Once we have the URI we can create a stream reference to it and pass it along to our DataPackage calling SetBitmap(). As with all of the examples in this article, we end our code with actually setting the Clipboard with our DataPackage to actually complete the action.

Files

Files are treated very similarly to images, but there’s one major difference: we can copy multiple files to the clipboard at once and getting files is async.  You’ve done this before, highlight and grab some of the files cluttering up your desktop before dragging them as a group to the Recycle Bin.  Instead of throwing them away, you could cut/copy them, and paste them to another location.  Files are always passed as a collection of files, even if there is only one. To the code!

var _clipboard = Windows.ApplicationModel.DataTransfer.Clipboard,
    _dataTransfer = Windows.ApplicationModel.DataTransfer,
    _storageFile = Windows.Storage.StorageFile;

var imageSrc = document.getElementById("myImage").src,
    imageUri = new Windows.Foundation.Uri(imageSrc);

var splashScreenSource = document.getElementById("splashScreen").src,
    splashUri = new Windows.Foundation.Uri(splashScreenSource);

var files = [],
    promises = [];

promises.push(_storageFile.getFileFromApplicationUriAsync(imageUri)
    .then(function (file) {
        files.push(file);
    }));

promises.push(_storageFile.getFileFromApplicationUriAsync(splashUri)
        .then(function (file) {
            files.push(file);
        }));

WinJS.Promise.join(promises)
    .then(function () {
        var dataPackage = new _dataTransfer.DataPackage();
        dataPackage.setStorageItems(files);
        _clipboard.setContent(dataPackage);
    });

A bit different from the image but really only because of the WinJS Promise ( of which we will cover another day ). The core of this code is really the same except for the fact that we’re going to create an array of files aka StorageItems and then add them to the dataPackage calling setStorageItems

So, as far as saving content to the Clipboard, that’s just about it!  Our next step is going to be retrieving it from the Clipboard when the user chooses to paste it.

Detecting the Contents of the Clipboard

When it comes to “getting pasted” as I’ve started saying, I tend to do this all in one method that gets the content, determines which data type is available, and displays the content correctly based on that determination.

I had hoped, when writing this article, that there was going to be some amazing event handler, like OnPastedTo() or something, that would recognize when the user is attempting to paste some content to the app, so that we can take action on it.  (I personally live and die with Ctrl + X, Ctrl + C, and Ctrl + V).  I have not found that event yet, other than mapping the keyboard command directly.For now, I’ve created my own event handler that fires when you click a button.

You’ll see, in the example below, that I call the getContent() method on the Clipboard, and then use a series of if statements to act on the content appropriately.

var dataPackage = _clipboard.getContent(),
    sdFormats = _dataTransfer.StandardDataFormats;

if (dataPackage.contains(sdFormats.text)) {
    dataPackage.getTextAsync().then(function (text) {
        document.querySelector("#pasteResults").innerText = text;
    });
}

if (dataPackage.contains(sdFormats.html)) {
}

if (dataPackage.contains(sdFormats.bitmap)) {
}

if (dataPackage.contains(sdFormats.storageItems)) {
}

Let me quickly discuss each of the if statements.  For text, which is the only one I displayed I am going to just grab the text with a promise and set it as the innerText of a label that I have on my page.  Just like when we put items on the clipboard we will now need to do the reverse. Depending on the data format we will have to do the appropriate thing for what that data type requires. If it’s a collection of files we would need to loop through that collection of files and do something with them.

In all it’s pretty simple, but I was delighted the first time that I copied content from a webpage directly into my app, and it just worked!  The same is true for images, text, and files.  I highly recommend grabbing the source of this project and playing with it.  It will really help you to understand exactly how the clipboard is being used by your other applications.

Summary

Today, we took a deep look at the Clipboard, and how we can save and retrieve data as needed.  It supports several different file types, and I think you’ll be surprised just how redundant most of your favorite applications are when they save data to the Clipboard.

To download the entire code solution for the project discussed in this article, click the icon below:

downloadHTML

Tomorrow, we’re going to add another useful tool to our Windows 8 development tool belt: the FilePicker.  We’ll look at retrieving files from the user’s device, and even filtering them so that we only get our preferred file types.  See you then!

downloadTheTools

Published at DZone with permission of Clark Sell, author and DZone MVB. (source)

(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)