Friday, August 8, 2008
In anticipation of a featured interview in a popular web development blog, I thought a good developer-focused post was in order. One of the features customers frequently require on their sites is inclusion of a file upload as part of a custom form. As any web developer knows, uploading files is always a tricky subject, and there are a few different ways to skin this cat. So let's dig in.
Note: This article is intended for web developers who have some familiarity with web-based file uploading on other platforms. This post is focused on how it's done with EditMe specifically.
Because the EditMe API doesn't provide server-level access, you can't just write your own file upload mechanism. The only way to get files into EditMe is through the built-in Upload servlet, which is how files get attached to pages. Until now, this has been undocumented and some study of the attachments screen was required to figure it out.
By default, EditMe's built-in Upload servlet supports use by the _Attachments form, in that the action of the upload form on the _Attachments screen is /servlet/Upload. It accepts the following input fields, and then redirects back to _Attachments:
The Upload servlet also supports an optional field named response, which accepts the following values: redirect, json or xml. The redirect option will simply redirect the browser to the specified URL after the upload is complete. This is the best method to use if you're building your own attachments page and want it to redirect back to your page instead of _Attachments. But know that any additional information you include in the form will be lost.
Since any other data posted to the Upload servlet is ignored, this makes building a custom file upload form with additional fields problematic. There are two options to get around this: 1) you can use Ajax to post your form content to a script of your own making before submitting the form to the Upload servlet, or 2) you can use a trick to upload the file(s) in an Ajaxy way, so that no page refresh is required at all.
If either json or xml is specified for the response field, Upload will return summary information on the files uploaded in either JSON or XML format, respectively. This is what you want to use if doing an Ajax upload. Here's what a sample response looks like in each format, assuming two files were uploaded:
JSON:
{uploaded: [
{name: 'file1.txt', description: 'this is file1', size: '103 bytes'},
{name: 'file2.txt', description: 'this is file2', size: '52 bytes'}
]}
If you eval() this string in JavaScript, it gives you an object with a single field named 'uploaded', which is an array of objects describing the files that were just uploaded. So, assuming you've got this string in a variable called json, you could get the name of the first file using eval(json).uploaded[0].name.
XML:
<response>
<attachment>
<name>file1.ext</name>
<description>this is file1</description>
<size>103 bytes</size>
</attachment>
<attachment>
<name>file2.ext</name>
<description>this is file2</description>
<size>52 bytes</size>
</attachment>
</response>
There are lots of things you can do with an XML response, but my preference is to use jQuery to parse it. So, if you had the above in a string variable named xml, you could get the name of the first file using $(xml).find('response attachment name:first').text().
Since browsers cannot upload files using traditional Ajax methods (this is a security thing), there is a clever trick that uses a form posting to a hidden IFRAME. I could write up how to do this here, but it has little to do with EditMe and has already been nicely done by Webtoolkit.info. We have built several forms for custom development projects using this method and it works well.
Just specify json in a hidden response field in your form. Then your completeCallback function can use the data like this:
function completeCallback(response) {
var data = eval(response);
alert('You uploaded ' + data.uploads.length + ' files.');
}
Once the new editing screen comes out, you'll have a complete working example of this, as the new attachments mechanism uses it. Until then, feel free to drop a question over at the forums if you get stuck.