The system clipboards Mozilla offers to XULRunner apps restricts us to primitive values: strings, numbers, etc. (I haven't yet figured out how they store images, but that's another discussion.) If you're trying to copy a DOM node to the operating system's clipboard, you quickly find out it's not that easy.
Since Verbosio's a XML editor, heavily reliant on the DOM, what am I supposed to do? Well... I cheated. Read on for more details.
UPDATE: A few commenters have suggested I have erred. I'd really appreciate someone coming up with some sample code to demonstrate a better way, using the native clipboard. (I may or may not use it, but it's nice to know.)
Neil Deakin wrote a guide to using the clipboard. Too bad I had a really hard time understanding it. Eventually, I figured I could set my DOM node (which implements nsISupports) as the second argument of nsITransferable's setTransferData() method. Said argument takes a nsISupports value. No problem, right?
Wrong. Read the inline JavaDoc comments, and it says nsISupportsPrimitives or nsIFlavorDataProvider (in nsITransferable.idl). A closer look at nsIFlavorDataProvider suggests again nsISupports is fine... but the JavaDoc says nsISupportsPrimitives.
DOM nodes don't implement nsISupportsPrimitives.
(Note: I consider this lousy interface design. If you have a IDL method that can only take two different types of arguments, and you try to combine them through a commonly supported interface, you're better off breaking it up into two different IDL methods with the more specific types of arguments.)
What did I do to cheat? I added code to a XPCOM service for Verbosio which stores the object I want as a private global variable.
I already have a xeIVerbosioUtilsService.idl
interface, and it now has a few new methods: copySelection(), clipboardType, and getClipboardContents().
These methods handle the system clipboard. The copySelection() method copies from the current document wrapper whatever selection it is, whether text or a DOM node. In the latter case, it serializes the node first, and stores the string in the system clipboard. The method also stores the retrieved node (usually a DocumentFragment) in the component's JavaScript context.
What if someone else (say, Microsoft Word) copies data into the clipboard? How does the utility component know when to forget the DOM node? That's where nsIClipboardOwner comes in to play. By setting a custom clipboard owner from the utility service, the utility can find out when the content it copied to the system clipboard is going away from the system clipboard. When that happens, the utility service can clear its own private object storage.
The clipboardType property simply defines what the content-type of the object stored in the application "clipboard" is. For DOM nodes, I chose an arbitrary "application/x-vnd.verbosio.dom-node" content-type.
I then use getClipboardContents if I have an actual object there, and can then retrieve the object that way.
Steps to reproduce in Verbosio:
That much works. What works and doesn't work beyond that, I don't know yet. :-)
This was ten steps that a user has to perform manually to test a simple feature. Sure, the key part of it takes maybe two steps.
Why does this aggravate me so much? Well, the edge of my MacBook, where the wrist comes off the keyboard / mousepad, is pretty sharp... I haven't cut myself yet (or broken the skin), but I do fear I could hurt myself if I get any kind of pound-the-computer-in-frustration moments.
What I need is some sort of record / playback mechanism for chrome apps. I'd do it myself, except for legal reasons relating to a previous employer, I'm not sure I can. Recording user actions for later playback could be very useful, especially for testing. Rumor has it someone I know is working on that, with no active input from me. I'd really love it if it wasn't rumor, and if it was soon. :-)
Posted by WeirdAl at March 28, 2007 10:23 PMI don't know about DOM nodes but you can certainly put an nsIInputStream into an nsITransferable. (The windows clipboard code does this when you paste a native bitmap.)
Aside: The tab indexes on this blog's form objects seem to be all messed up, the order is [canvas] Name Email URL Comments [links] Yes/No Preview Post.
Aside to aside: Preview page tab order is fine.
(From Alex: I haven't messed with those settings on MovableType.)
Posted by: Neil at March 29, 2007 1:20 AMnsISupportsInterfacePointer is a nsISupportsPrimitive that holds a nsISupports... So you indeed can hold a nsISupports :p
(.dataIID is one of the Components.interfaces.* for a JS consumer; you don't really need it thanks to xpconnect, but can't hurt.)
Posted by: Mook at March 29, 2007 1:58 AMI'm not sure if my wrists have gotten used to the sharp edge, or what, but it doesn't bother be anymore (only took about 8 months!).
Is there not some more generic flavor for a clipboard, or is "application/x-vnd.verbosio.dom-node" it?
(From Alex: It's not for the clipboard, it's for DOM nodes in my app. If I knew of one, I'd use it.)
Posted by: Shawn Wilsher at March 29, 2007 7:25 AM