Pages

2009/12/05

File upload in CKEditor

CKEditor redefines the way that dialogs are created by defining them as a hierarchy of "uiElements", each element is defined as a JS object and its type define its behavior.

You can see this if you open the source of any of the dialogs and search for "contents :", there you'll find the structure of the tabs and you can see how the "type" property is used with values such "hbox"/"vbox" (for layout of several elements: horizontal/vertical box), other values that matches typical HTML form elements: "text", "button", "password", "textarea", "checkbox", "radio", "select", "html" (this one allows any kind of html to be used directly), and some special ones: "file", "fileButton". These elements and behaviors are defined in the dialogui plugin.

File upload

When you want to provide the "quickupload" feature you must use the "file" uiElement, this one takes care of creating an iframe whose contents are a form with an <input type="file">. But of course, you must specify the url to POST the file, so this is handled by the fileBrowser plugin. This plugin scans every dialog based on the dialogDefinition event and then adjust the properties so the form is created correctly as well as adjusting the buttons used to launch the file browser. This is done based on the existence of a "filebrowser" property in the element definition.

The current definition of the "file" uiElement has some bugs/problems, and so far I haven't fixed all of them as it took me long enough to understand the behavior and I needed to move forward, but I'll try to look at them in order to finish the easyUpload plugin.

One of the problems is that if a user selects a local file but presses the dialog "OK" button instead of the "upload file" [hey, we're talking about users ;-) ] then the dialog might close without any warning and no file is uploaded. This is due to the fact that the .getValue() function is hardcoded to return an empty string, fortunately it's easy to fix that problem at the initialization of our plugin:

This only causes a little issue: now if you try to close the dialog with the Cancel button it will always state "Some of the options have been changed..." (quite unfriendly message by the way, it would be much better to state "The file upload has been changed..." using the proper label for each element). So we just need to force the initialization of the "initial value" for the element to match the empty string (as I'll explain next, the initialization code is using the container instead of the real <input> so it's doing wrong things at that time)

Of course these two changes are easy and should be available also in the core code, but I needed them right now, so it's easier to provide the fix in the plugin instead of waiting for the patch to get approved.

Pending issues

In the original easyUpload I added the code (that it was then merged into the core) that instead of just letting the user wait for the upload to finish without any indication that there's something going on, he would see the loading throbber. Of course, it's not really "useful" as it doesn't correctly state how much of the file has been uploaded or how much time remains, to see that kind of info you should use Firefox 3.5 with CKFinder 1.4.1.
And it might be argued that sometimes people report problems because they try to upload a file with a wrongly configured connector and they just see the infinite throbber, but the ones that see that problem are the developers setting up CKEditor and I would argue that they should learn a little about all the tools that are available for developers to find javascript errors, server responses, etc...
But let's get back to the topic: the "please wait" message is still missing, and the aim of the plugin is to be user-friendly so it should get one.

Another friendly feature was the automatic upload of the file as soon as it was selected from their computer instead of having to click on the "upload" button.
First let's understand the 'file' widget; it's quite different from the rest of elements as it does create it's own upload iframe, and that iframe is recreated each time the .reset() method is called on it. That happens when you load the dialog, or when a file is uploaded or when the dialog is closed. So every now and the the iframe with the inner form and the <input type="file"> will be recreated, but currently it doesn't fires any event to the parent window, so it can't be tracked to reassign the needed events on it. Besides that, the creation logic of the uiElements is based on assigning the event listeners required on them after they have been created, but due to the iframe element and the oddities of this element, at the time that those assignments happen the inner frame still isn't ready and instead it tries to work with the container of the iframe (quite useless). So the fix for this means that the 'file' uiElement must keep the list of events that it must assign to the inner <input> and that the iframe must notify to the parent container that it has finished loading so it gets reapplied the desired set of events.
Quite a lot of work for a little detail, but the end user just care to use the program without having to take a semminar about uploading files.

The last difference with regards to FCKeditor is that previously if the user picked a ".doc" file in the image dialog he would get immediately a warning stating that this isn't a recognized image format so that won't be uploaded. Now this check at the client side is missing, so the user will upload the file and it's the server the one that must reject it.
This means two things: poorly written server connectors will allow to upload any kind of files at the image dialog and then users will ask why they have uploaded the .doc and it doesn't work (or even worse: iirc correctly Safari in Mac does allows to use a .pdf as source for an img, so they upload the pdf, put it as source for an image and then only Safari users will see the contents). The second problem is that the user has wasted his time uploading the file to the server instead of getting an immediate feedback stating that the file isn't valid for this dialog.

As you can see, there are some rough edges about this functionality that we should expect to improve in CKEditor as it evolves, and meanwhile I'll try to fix them in the easyUpload plugin.