The drag and drop API available in Firefox 3.5 and later has simplified much code both in Firefox itself as well as elsewhere. The next step is to create a similar improvement for clipboard usage, which has a number of things in common with drag and drop. Once this is done, many redundant underlying pieces can be removed and we can rely only on the new APIs. Some parts of Mozilla code (such as the editing components) are still relying on the older interfaces; these will need to be changed. Fortunately, this will mostly involve simplifying code.
For instance, the current code needed to paste from the clipboard, or to cut or copy anything more complicated than simple text is generally 15 or so lines of code.
The general idea is to to allow the use of the DataTransfer object for clipboard operations, in a similar manner as can be done with drag and drop.
There are three possible approaches that could be used to improve clipboard access.
The first method is to fire three events, cut, copy and paste, which provide a data transfer which can be used to set or retrieve data. For example, for a copy event, a listener might set some text onto the data transfer. Once the event has finished firing, any data added would be put on the clipboard. This technique was first implemented by IE, but is also supported in Safari and Chrome. Mozilla implements the events, but does not supply the data transfer object needed to retrieve or modify the clipboard. Thus, in Mozilla, one can know when the events occur, but cannot affect their behaviour except to prevent it by cancelling the event.
A second piece implemented by IE, Safari and Chrome is three additional events, beforecut, beforecopy, and beforepaste. Mozilla does not implement these events. These are odd events, made more odd by poor and incorrect documentation. Their intent is to indicate whether the cut, copy or paste events are allowed or not. They are fired when, for example, the Edit menu is opened, to update the enabled state of the clipboard related menu items.
There are some disadvantages of this approach. The before events are an unusual design, as firing several events every time the Edit menu opens seems tedious. Compounding the problem for Mozilla is that Firefox has toolbar buttons for the cut, copy and paste operations which need to be updated every time the focus is changes, or when a selection is made. This means that the events need to fire quite often. Other browsers ‘work around’ this problem in different ways. IE has toolbar buttons, but never updates the enabled state of them, instead only updating the state on the menu when it is opened. Safari doesn’t have toolbar buttons so gets off easy. And, oddly, Chrome doesn’t update the enabled state of anything, even for its own UI. Likely, it’s just not implemented yet.
The other disadvantage is that the browsers only implement the events for text selections and textboxes, so you can’t really use it for clipboard operations on other kinds of elements.
The HTML specification offers a different model that treats clipboard operations as a special form of drag and drop, in fact, treating the clipboard as just a special virtual drag source and drop target. It is expected that the normal drag and drop events would fire when using the clipboard commands on the menu, although the specification is vague about how this is supposed to work.
There are a number of disadvantages to this approach. Most notably, it isn’t compatible with other browsers. In addition, writing a simple handler for a clipboard action requires handling several events instead of one, separating the code to put items on the clipboard from the code to delete it in the case of a cut, which in some cases can be unweidly. Finally, this model doesn’t provide a means to distinguish a clipboard operation from a real drag and drop operation, nor to indicate whether a cut or copy only is allowed.
If you haven’t guessed already, I don’t like this approach at all. The only advantage of note is that keyboard only usage is provided (presumably) in typical browser usage automatically without having to write additonal code, although it is assumed that keyboard usage will use the clipboard instead, which may not be a given.
An issue for Mozilla applications with either of the above approaches is that one can only manipulate the clipboard when the event is fired. Thus, one cannot, for example, empty the clipboard or retrieve data from it outside of an event. This isn’t an issue for web pages though; as security concerns would want us to prevent web pages from accessing the clipboard unless there has been a real request from the user to do so.
In a sense, IE (unintentionally) handles this by providing the data transfer as a global property of the window called clipboardData. An application can check this property to retrieve the data on the clipboard at any time, and can modify it at any time as well.
In Mozilla, this approach could be used as well, although changes from web pages would be restricted to accessing and modifying this object only during the clipboard events. Extensions and other privileged code could access this at any time. The disadvantage here is when you’re putting multiple types of data on the clipboard, since it would need to update the whole set on the real clipboard every time one type of data is changed.
In case you’re wondering what security issues exist, consider if a web page could retrieve the clipboard data at any time without user intervention. It’s possible that the clipboard could contain passwords or other sensitive information. Likewise, modifying the clipboard is also undesirable, as a web page could put ads onto the clipboard. Naturally, of course, this could pose a problem anyway, but at least we can restrict this to those cases only when a user requests a clipboard operation.
I’m favouring method one, with an appropriately secured method three, possibly chrome only. I’m not sure about the before events though, but there is a need to be able to indicate whether a cut, copy or paste event is allowed at a given time, and to be able to determine this state quickly.
One possibility I’d thought of is to make use of the global clipboardData’s effectAllowed property. Essentially, an application would update it when necessary, and the corresponding UI will check this state as needed. We can solve the issue of the events only firing on selections and text inputs only by instead firing the events on the focused content instead, perhaps only in chrome contexts. For example, when a mail message is selected, the effectAllowed property might be changed to indicate that a cut or copy was allowed, but not a paste. The property would be reset automatically when the focus changes.
<listbox onfocus="clipboardData.effectAllowed = 'copy';" oncopy="event.dataTransfer.setData('text/plain', this.selectedItem.label)"> <listitem label="Item Value"/> <listbox>
For XUL, of course, the controller and command mechanism would still be used as well, and would likely be a cleaner implementation in the case above.