Controlling URLs For Image Uploads

EditLive! includes the ability to automatically upload local images and when it does, the URL is changed to point to the new version on the server. The simplest way to control the resulting URL is to adjust the base attribute of the httpUpload element in your configuration file. When EditLive! uploads an image it simply appends the image name to the base you provide. So if the base is http://example.com/images/ and the image name is bob.jpg the resulting URL is http://example.com/images/bob.jpg

Sometimes though you need to change the directory or image name to avoid file conflicts or to better organize the image library (eg a folder for each page or each user). In those cases the image upload script can take control of generating the URL itself and simply pass it back to EditLive! All that's required is for the upload script to return only the URL to use on a single line. The URL can be absolute or relative - it will be used exactly as is by EditLive! so it needs to be correctly URL encoded. EditLive! will then ignore the base attribute and use the URL exactly as it was returned by the upload script.

Tutorial: Custom Components for Hyperlink Dialog

EditLive!’s “Hyperlink” dialog consists of a set of panels, used to insert hyperlinks from different sources. EditLive! allows you to customize this dialog, by adding your own custom panels. This can be done using the EditLive! Swing SDK, or as an Advanced API plugin.

For this example, I’ll be creating a custom panel plugin which lets you change the “id” and “class” of a hyperlink. Note: due to the design of the hyperlink dialog, these attributes will only be saved if this panel is active when the user clicks ok.

The key parts are:

  1. Creating the plugin and registering with EditLive!.
  2. Creating the panel.
  3. Writing the new attributes on save.
  4. Reading the existing link’s attributes on load.

1. Creating the plugin and registering with EditLive!

Firstly, we need a basic Advanced API plugin class. This involves creating a class which takes an ELJBean in its constructor. To actually load the plugin, there are other steps required, which are described in the EditLive! documentation. There are also previous LiveWorks! articles to help: Using Plugins To Extend EditLive! and Initializing Background Loading Plugins.

public class CustomPanel {
        public CustomPanel(ELJBean bean) {
        }
}

Next, we need a class which implements the HyperlinkDialogComponent interface in the Advanced API.  We might as well add this to the current class, as it’s not doing much else. For the moment, just provide dummy implementations for the interface’s methods (“Override/Implement Methods” in Eclipse).

public class CustomPanel implements HyperlinkDialogComponent {
...
}

To register this component as a hyperlink dialog, call the “addHyperlinkDialogComponent” bean method. We’ll do this in the constructor. The first parameter is the class that the Hyperlink dialog instantiates to create the custom panel.  In our instance, we’re adding the current class. I’ll discuss the second parameter in a minute.

public CustomPanel(ELJBean bean) {
        bean.addHyperlinkDialogComponent(this.getClass(), new Object[] { bean });
}

Now, when the hyperlink dialog instantiates a custom component, it looks for a constructor which takes an Object[] as its only parameter. So, we will need another constructor in our CustomPanel class.

private ELJBean bean;  
public CustomPanel(Object[] params) {
        this.bean = (ELJBean)params[0];
}

The Object array allows us to pass parameters through from the plugin to the custom panel. In this case, we’re passing a reference to the bean, which we’ll use later. Note that this class is instantiated twice – once as a plugin, and once as a dialog component. In real code it would probably be better to use a separate class for each role to avoid confusion.

2. Creating the panel

Now the framework is in place, its time to implement the HyperlinkDialogComponent methods. Let’s start with the getJComponent() method, which provides the actual panel displayed in the hyperlink dialog. For this example, I’ll use a simple form which asks for the “id” and “class” of the link.

public JComponent getJComponent() {
        panel = new JPanel(new BorderLayout());
        subPanel = new JPanel(new GridLayout(2, 2));
        panel.add(subPanel, BorderLayout.NORTH);
        panel.add(Box.createGlue());  
        subPanel.add(new JLabel("id"));
        idField = new JTextField();
        subPanel.add(idField);
        subPanel.add(new JLabel("class"));
        classField = new JTextField();
        subPanel.add(classField);
        return panel;
}

If you load the plugin now, it should display the panel, but the button to activate the panel will be blank. We can specify these with the getButtonImage() and getButtonText() functions. For simplicity, I’ll just leave the icon blank.

public ImageIcon getButtonImage() {
        return null;
}
public String getButtonText() {
        return "Advanced Link";
}

3. Writing the new attributes on save.

We now need to get the data from these fields into the actual hyperlink. This is done in the getAttributeMap method. This method gets an input of the current attributes of the link, including those from fields outside the switch panels (like the href, target and title). Add to this map, then return it.

I’ve also wrapped the map additions in a method which ensures the attribute is only in the map if its not blank which avoids adding redundant attributes to the HTML.

private void addIfSpecified(Map in, String name, String value) {
        if (!value.trim().isEmpty()) {
                in.put(name, value.trim());
        } else {
                in.remove(name);
        }
}

public Map getAttributeMap(Map in) {
        addIfSpecified(in, "id", idField.getText());
        addIfSpecified(in, "class", (String)classField.getText());
        return in;
}

4. Reading the existing link’s attributes on load.

At this stage, this panel will set the properties of the hyperlink, but if you edit an existing hyperlink, the custom panel’s fields will not display the current values. This is where we need the ELJBean object.

From the bean, we can get the HTMLPane object – this is the editing pane (JTextPane object) for the “design” view. We then call getInputAttributes to get the “a” element and its attributes. We can then populate our text fields with these attribute values.

private void setFieldFromAttribute(AttributeSet attrs, Object attribute, JTextField field) {
        Object value = attrs.getAttribute(attribute);          
        if (value != null) {
                field.setText(value.toString());
        }
}
public JComponent getJComponent() {
       …
       Object aTag = bean.getHTMLPane().getInputAttributes().getAttribute(HTML.Tag.A);
       if (aTag != null) {
                setFieldFromAttribute((AttributeSet)aTag, HTML.Attribute.CLASS, classField);
                setFieldFromAttribute((AttributeSet)aTag, HTML.Attribute.ID, idField);         
       }
       return panel;
}

There are 3 remaining interface methods which we don’t need for this example. They would be useful for things such as opening/closing connections to external systems.

public void setActive(boolean active) { }      
public void setHyperlinkDialog(HyperlinkDialog parent) { }
public void cleanUp() { }

Where to from here?

The custom panel is complete. Feel free to use this plugin as-is, or as a template for creating your own components.

This example sets special attributes of the hyperlink, however hyperlink dialog components could also be used to provide an integrated way of linking to existing content in a repository.

EditLive! also offers several alternatives for providing similar functionality.

With an Advanced API plugin, you could create an entire JDialog to replace the existing hyperlink dialog. Register this plugin as an EventListener, and listen for TextEvent.HYPERLINK_ACTION. When this event is triggered, display your dialog, then call event.setHandled(true) to prevent the built-in dialog from displaying. When the dialog closes, use the DocumentModifier methods (available from ELJBean.getDocumentModifier()) to edit the content.

Finally, a custom menu item or toolbar button can trigger a Javascript method, which you could use to pop up a new browser window which displays a specific URL containing the dialog. Then, you can use the “insertHTMLAtCursor” or “insertHyperlinkAtCursor” functions from our Javascript API to edit EditLive!’s content.

Download the Custom Hyperlink Dialog Plugin 

Controlling Entity Encoding

There are two key APIs that control how special characters such as non-english characters or complex punctuation are encoded in the HTML output from EditLive!

The setOutputCharset function allows you to control which character set is used when serializing the HTML content (see also Solving Character Set Issues With Legacy Systems). Any characters that are supported by that character set are output directly as single characters without any encoding, any characters that aren't supported are encoded. The outputXHTML and outputXML attributes control whether named or numeric entities are used (see our previous article on how and why that works). The table below shows how these two settings work together when outputting special characters.

  ASCII Output Charset UTF-8 Output Charset
outputXHTML or outputXML is true Numeric entities No encoding
outputXHTML and outputXML is false Named entities No encoding

The ASCII charset is one of the simplest charset and supports very few characters - it also tends to avoid any character set problems with other systems. The UTF-8 character set on the other hand can represent nearly any character supported by HTML directly as a character so you generally don't get any encoded characters.

Dynamic Configuration File Techniques

When integrating EditLive into your application, it is often handy to generate your configuration files using a server-side web scripting language. However, as Adrian mentioned in a previous post, configuration files are cached by EditLive, which causes problems with a dynamic configuration. One of his solutions was to add a "cachebusting" parameter, the other was to use setConfigurationText. Today, I'll be expanding on the use of setConfigurationText with a dynamic configuration file.

The key issue is that you need a way to get the output from your configuration web script into a variable, so you can pass it to the setConfigurationText method. Below are several techniques for doing this. The final example provides an alternative to server-side scripting in generating dynamic configuration.

cfsavecontent

I was a ColdFusion programmer in a previous job, so the first solution that came to mind was to use the "cfsavecontent" tag. cfsavecontent is a very handy little tag, which stores the output of your script in a variable, rather than outputting it to the HTTP response. You then URL encode it, and pass it to the setConfigurationText call. e.g.

configuration.cfm

<cfsavecontent variable="myconfig">
<?xml version="1.0" encoding="utf-8"?>
<editlive>

</editlive>
</cfsavecontent>

mypage.cfm

<cfinclude template="configuration.cfm">
<cfoutput>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<script src="./editlivejava/editlivejava.js"></script>
</head>
<body>
<script language="JavaScript">
var editlivejava1;
editlivejava1 = new EditLiveJava("ELJApplet1", "700", "400");
editlivejava1.setConfigurationText("#URLEncodedFormat(myconfig)#");
editlivejava1.setDownloadDirectory("./editlivejava");
editlivejava1.show();
</script>
</body>
</html>
</cfoutput>

ASP line-by-line

I found a very clunky way to do this in ASP, as a response to a support case. This uses a "write" method to build up the configuration string, one line at a time. This isn't very manageable, as each line needs a "write" method. It may also get in the way of the dynamically-generated sections. Adding the "write" calls to the beginning and end of each line can easily be done with a regular expression replace, or with an editor which has "column editing" e.g. in JEdit you can ctrl-drag to select the first character in the line, then everything you type will end up in each line. Still, this is nowhere near as elegant as the cfcontent version.

Note: this example uses EditLive's ASP instantiation API, which does the URL encoding for you.

<%
dim config
config = ""

sub write(text)
config = config & text
end sub

function generateConfig
write("<editLiveForJava> ")
write(" <mediaSettings> ")
write(" <images> ")
write(" <imageList /> ")
write(" </images> ")
write(" </mediaSettings> ")
write(" <hyperlinks> ")
write(" <hyperlinkList /> ")
write(" </hyperlinks> ")
write("</editLiveForJava> ")

generateConfig = config
end function

Dim elglobal
set elglobal= New EditLiveForJavaGlobal
elglobal.DownloadDirectory = "/editlivejava"
elglobal.Init()

Dim editlive1
set editlive1 = new EditLiveForJava
editlive1.name="ELApplet1"
editlive1.width=600
editlive1.height=800
editlive1.configurationtext = generateConfig
editlive1.Body = "<p>loading default content.</p>"
editlive1.show
%>

AJAX

The below code uses the Prototype Javascript library to get the configuration using an AJAX request. Note: this technique causes an extra HTTP request to get the config, which negates a key benefit of setConfigurationText.

However, if you're creating an AJAX application, it may be more cohesive for you to use AJAX to get the config. 

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<script src="/editlivejava/editlivejava.js"></script>
<script src="prototype.js"></script>

<script language="JavaScript">

function loadELJ(transport) {
var editlivejava1;
editlivejava1 = new EditLiveJava("ELJApplet1", "700", "400");
editlivejava1.setConfigurationText(encodeURIComponent(transport.responseText));
editlivejava1.setDownloadDirectory("/editlivejava");
$("mydiv").update(editlivejava1.getAppletHTML());
}

function loadConfigFail() {
alert('Error retrieving EditLive config.');
}

new Ajax.Request('config.asp', {
method:'post',
onSuccess: loadELJ,
onFailure: loadConfigFail
});
</script>
</head>
<body>
<div id="mydiv">
loading…
</div>
</body>
</html>

Server-side HTTP Request

I won't go into this in detail, but the basic concept is to get the configuration by doing a HTTP request from your server-side scripts.

In ASP, this can be done with the Msxml2.ServerXMLHTTP or WinHttp.WinHttpRequest.5.1 COM objects. Examples of using these objects can be found at http://www.asp101.com/samples/http.asp and http://www.asp101.com/samples/winhttp5.asp

In ColdFusion, this can be done with the "cfhttp" tag.

String Replacement

Another way to dynamically generate your configuration file is to use string replacement, rather than a server-side script. With this technique, you have a static configuration file containing "tokens", e.g. 

<images allowLocalImages="[%allowLocalImages%]" allowUserSpecified="[%allowUserSpecified%]">

You then read the file in (via HTTP, or straight off the filesystem), then use string replacement functions to replace the tokens with their actual values. 

This technique is useful when using the EditLive Swing SDK, as you may not have a web scripting environment available. That said, the technique can also be used from server-side and client-side web scripts. It's particularly useful when you only have minor changes to the configuration since it's very simple to implement.

Refreshing Dynamic Configuration Files

For many sites, it can be useful to have different configuration files based on the actual content being edited. For instance, the image and hyperlink lists may be dynamically generated to include only what's relevant to the current page or change where images are uploaded to etc. The first time people try this they tend to run into the caching that EditLive! performs and find that the config file is never reloaded. The reason EditLive! caches this file so heavy-handedly is that we've found that the slowest part of EditLive! starting up is quite often downloading the configuration file and everything else has to wait for that download to finish.

If you really need to the configuration file to update there are a couple of simple ways to achieve it. The best way is to use setConfigurationText instead of setConfigurationFile which provides the config inline in the web page and removes the need to for another HTTP request altogether. EditLive! won't perform any caching of the config in this case so your changes will appear immediately. We strongly recommend taking this approach even if your configuration file never changes to make the editor load faster.

If however you absolutely have to download a separate URL, or if you just want a quick work around and load time isn't an issue for you, then you can simply append a dummy parameter to the end of the URL which will force EditLive! to download it again each time. The current timestamp is generally a good value to use, for example:

editlive.setConfigurationFile("eljconfig.jsp?cacheBuster=" + new Date().getTime());

Just remember that the extra HTTP request is going to cause a delay in the editor loading, so you'll get a big benefit from using setConfigurationText instead.

See also: setConfigurationText in the EditLive! SDK

Getting Content Synchronously

The standard APIs that EditLive! provides are designed to maximize browser compatibility and ensure that the integration works the same way on any browser. The big disadvantage of this approach is that the APIs all need to be asynchronous - instead of returning the requested value directly, they return immediately and call back to another JavaScript function with the value. This is architecture was required for compatibility with Macintosh browsers and Netscape 4, however with advances in browsers and users upgrading, many sites no longer require compatibility with these older browsers and development would be much simpler with a synchronous API.

If you don't need to support old browsers like Netscape 4, Internet Explorer on Mac or Safari before about OS X 10.31, you can safely use the synchronous APIs that EditLive! provides and it's really simple. First you need to get the actual applet instance instead of the JavaScript wrapper object we provide:

var editliveApplet = document.getElementById(editorName + "_elj");

The applet is given an ID attribute consisting of the name you specify in the EditLiveJava constructor with "_elj" appended to it. Once we have the applet instance, we can call methods on it as if it were any other JavaScript object and the results will be returned synchronously. The available methods are:

  • getBody()
  • getDocument()
  • setBody(String)
  • setDocument(String)
  • uploadImages()
  • getSelectedText()
  • isDirty()
  • setIsDirty(boolean)

If you need images to be uploaded, make sure you call uploadImages before getBody or getDocument. If there are other APIs in the JavaScript object that you'd need made available synchronously through the applet, please let us know and we'll see what we can do.

1 - make sure you test in your target versions of Safari, the technology that enables synchronous calls, LiveConnect, was added but with some limitations, then fixed in later updates so it's hard to pinpoint exactly which versions work well.

Integrating EditLive! Is Now Even Easier

The latest early access builds of EditLive! now make integrating even easier by automatically detecting the download directory and providing a default configuration file. Since the very first version of EditLive! the JavaScript instantiation code would include the two lines:

editlive.setDownloadDirectory("editlivejava/");
editlive.setConfigurationFile("editlivejava/sample_eljconfig");

However that's no longer needed as EditLive! will automatically detect the right URL to download it's resources from and if you don't specify a configuration file it will use the sample_eljconfig.xml configuration file.

You can of course continue to set the download directory and configuration file but you no longer need to. Below are some best practices to make the most of these latest changes:

  • Don't set a download directory. It's simpler to leave EditLive! calculate the right URL and it avoids potential errors.
  • If you don't need to make any changes to the configuration, don't set a configuration file and simply use the default. This avoids the potential for specifying the URL incorrectly and getting errors.
  • If you do modify the configuration file, make a copy in a separate location and instruct EditLive! to use your version with setConfigurationFile or setConfigurationText. By making your own copy instead of modifying the sample, you remove the potential for overwriting your modifications when you upgrade EditLive!
  • If possible, use setConfigurationText instead of setConfigurationFile to improve the editor start up time. With setConfigurationFile, EditLive! must wait while the configuration file downloads.

Improving The First Run Experience

One of the really nice features of EditLive! is the highly responsive interface - dialogs open immediately without needing to send extra requests back to the server. That kind of responsiveness comes with a price though - when you first run EditLive! you have to wait for it to download. From then on, the files are all stored on the local machine so you never have to wait again but you still get the responsive interface. The engineers at Ephox have been working hard on making that initial experience better for users and it's something we'll continue to work on, but there are a number of improvements in the 6.2 release that you can take advantage of today.

Firstly, just by upgrading to 6.2 every EditLive! installation will find that the editor starts up faster. We've done a lot of work on start up times and overall performance so that once the files are downloaded everything's ready to go much sooner. We also provide much better feedback to users on startup progress and it just generally looks pretty.

Secondly, with just a minor modification to your site you can make that download time disappear for most users by taking advantage of the new QuickStart function. All you need to do a simple JavaScript function call somewhere like you're login page which will start the download of EditLive! in the background. In most cases by the time the user actually goes to edit their first bit of content the editor will already be downloaded and ready to go. The key advantage to this approach is that it won't distract the user at all. If they don't yet have Java installed it won't start installing it and there are no security dialogs that pop up. It just quietly goes about the download.

To make the experience as seamless as possible for users, we've carefully selected which environments to actually activate QuickStart in. It's all handle behind the scenes for you, but the best experience will be for people using IE on Windows where everything will be downloaded. For FireFox on Windows, we'll warm up the Java runtime but due to bugs in FireFox downloading the resources would sometimes interrupt the user's browsing so we don't actually start the download. On Mac even starting up the JRE might interrupt the user so QuickStart simply doesn't run on Mac. We'll be continuously reviewing what we can do to get more benefits from QuickStart so if you deploy it today you should automatically see the improvements when you upgrade in the future.

To set it up, just add the JavaScript below to the bottom of your login page or even every page on your site - it doesn't matter if the user visits multiple pages with QuickStart, the download will only happen once.

<script src="/product/editliveforjava/editlivejava/editlivejava.js" type="text/javascript"></script>
<script type="text/javascript">ephoxQuickStart("/product/editliveforjava/editlivejava/");</script>

The first script tag includes the EditLive! javascript library which provides the ephoxQuickStart function. The second one actually activates QuickStart. The parameter just specifies the EditLive! download directory where the editor resources are stored. With that one simple change your users will spend less time waiting for things to get started and can just focus on getting their work done which is what EditLive! is really about.

Automatically Choosing Spelling Dictionaries

One of the most commonly changed settings for EditLive! is the location of the spelling dictionary. It's not only annoying to keep the URL to the dictionary correct across different sites but it can also be difficult to support clients using different languages. Fortunately, EditLive! 6.0 introduced automatic selection of dictionaries. The correct dictionary for the user's locale is automatically selected and downloaded without needing to be specified in the configuration file.

To take advantage of this all you have to do is:

  1. Make sure that you copied the dictionaries folder into the download directory for EditLive! This should already be the case for most deployments.
  2. Remove the "jar" attribute from the spellCheck element in your configuration file.

Of course, if you want to specify a specific language regardless of the user's locale or a custom dictionary you can still specify the download location for the spelling jar as usual. Otherwise, sit back, relax and let EditLive! do all the work.

Replacing A Textarea With EditLive!

One really useful technique for integrating EditLive! into an existing system is to configure the system to simply output a plain text area with the content to edit and then use JavaScript to replace the text area with EditLive! Since using a plain text area for editing is generally fairly simple to achieve on the back-end, this is often a quick way to integrate EditLive! without having to make significant changes to the back-end system.

To start with, lets assume that the system has been configured to output the content into a text area called "content":

...
<textarea name="content" id="content" rows="10" cols="60">
&lt;p&gt;This is the content&lt;/p&gt;
</textarea>
...

We'll also need to get the back-end system to include our JavaScript file:

<script language="JavaScript" type="text/javascript" src="loadEditLive.js"></script>

The loadEditLive.js file will do all the hard work of replacing the text area. That one line to include the script file is the only change we need to make to what the back-end system outputs so there is minimal changes required. The JavaScript to make this work is a little bit technical and involves working around the odd browser bug so if you want to get up and running really quickly you can just download the finished JavaScript file. If you have problems you can always come back to understand what the script is doing so you can modify it for your environment.

Still here? Good, lets get into the technical details. First we define a couple of variables that are likely to change based on your particular environment - where the EditLive! files are stored and the ID of the textarea to replace:

/* The URL to the editlivejava directory. */
var editliveDownloadDirectory = "editlivejava";

/* The ID of the textarea we want to replace. */
var textAreaId = "content";

Secondly, we write out a script tag to load the EditLive! JavaScript library:

document.write("<script language='JavaScript' type='text/javascript' src='" +
  editliveDownloadDirectory + "/editlivejava.js'></script>");

To make sure that the textarea and the EditLive! JavaScript library we just inserted have actually loaded, we defer the rest of the loading until the document's onload event fires. We also make sure that we store the original onload function so that any existing functionality isn't broken:

var originalOnLoad = window.onload;
window.onload = function() {
  loadEditLive();
  if (originalOnLoad) {
    originalOnLoad.apply(window);
  }
}

Now we need to define the loadEditLive() function that actually loads EditLive! The first thing to do is to get the textarea we need to replace, find out it's width and height and hide it so it's out of the way:

/* Get the textarea we need to replace. */
var textarea = document.getElementById(textAreaId);

/* We use the offsetWidth and offsetHeight properties to determine
the actual size of the textarea in pixels. */
var width = textarea.offsetWidth;
var height = textarea.offsetHeight;

/** Hide the text area. */
textarea.style.display = "none";

Next we set up an instance of EditLive! just like normal, using the standard JavaScript APIs and configuring it as required. Note that we set AutoSubmit to false so that EditLive! doesn't create its own textarea to submit content back in. We'll handle storing the content back into the existing text area in a moment.

var editlive = new EditLiveJava("EditLive", width, height);
editlive.setDownloadDirectory(editliveDownloadDirectory);
editlive.setConfigurationFile(editliveDownloadDirectory + "/sample_eljconfig.xml");

/* Make sure that autosubmit is set to false as we'll
   manually store the content before submitting. */
editlive.setAutoSubmit(false);

Now we need to set the content of the editor to the content that the back-end system put into the textarea:

editlive.setBody(encodeURIComponent(textarea.value));

The final step in getting the editor to load is to actually insert it into the document. Since we deferred loading until the onload event fired, we can't just use editlive.show() like normal because it calls document.write which would replace the entire document content. Instead, we'll use the getAppletHTML() method to retrieve the HTML that loads EditLive! and insert it into the document ourselves:

var editliveDiv = document.createElement("div");
textarea.parentNode.insertBefore(editliveDiv, textarea);
editliveDiv.innerHTML = editlive.getAppletHTML();

At this point the editor will fully load in the page in place of the textarea. However, when we submit the form the original content submits instead of the modified version from EditLive! This is because we set AutoSubmit to false earlier and haven't yet copied the content back into the original textarea. To take care of that, we add an onsubmit function to the form the textarea is in using the same technique we used to add the onload handler, again making sure we preserve any existing onsubmit function:

var form = textarea.form;
var originalOnSubmit = form.onsubmit;
form.onsubmit = function() {
  storeEditLiveContent();
  if (originalOnSubmit) {
    originalOnSubmit.apply(form);
  }
}

The storeEditLiveContent is fairly straight forward - simply retrieve the content from EditLive! and store it in the textarea. There is one minor complication caused by Safari where setting the value of a hidden textarea doesn't actually do anything. To work around that bug, we simply set the innerText of the textarea when running on Safari.

function storeEditLiveContent() {
  var textarea = document.getElementById(textAreaId);
  var editliveApplet = document.getElementById("EditLive_elj");
  var content = editliveApplet.getBody();
  /* Safari has a bug where setting the value of a hidden textarea
  has no effect. To work around this we set the innerText instead.
  The IsSafari variable is defined in editlivejava.js
  */
  if (IsSafari) {
    textarea.innerText = content;
  } else {
    textarea.value = content;
  }
}

That's it. Not as straight forward as most things with EditLive! but fortunately, now that we've developed the JavaScript file, it's simple to apply it where ever we need it. The full JavaScript is below so it's easy to copy and paste:

/* The URL to the editlivejava directory. */
var editliveDownloadDirectory = "editlivejava";

/* The ID of the textarea we want to replace. */
var textAreaId = "content";

/* Write out a script tag to load the EditLive! JavaScript library. */
document.write("<script language='JavaScript' type='text/javascript' src='" +
  editliveDownloadDirectory + "/editlivejava.js'></script>");

/* Add an onload handler to do the actual replacement.
This ensures that the document and the script library we loaded above have completed loading.
We store the original onload event to ensure that we don't break any existing functionality that may be implemented there.
*/
var originalOnLoad = window.onload;
window.onload = function() {
  loadEditLive();
  if (originalOnLoad) {
  	originalOnLoad.apply(window);
  }
}

function loadEditLive() {
  /* Get the textarea we need to replace. */
  var textarea = document.getElementById(textAreaId);

  /* We use the offsetWidth and offsetHeight properties to determine the actual size of the textarea in pixels. */
  var width = textarea.offsetWidth;
  var height = textarea.offsetHeight;

  /** Hide the text area. */
  textarea.style.display = "none";

  /** Set up EditLive! as normal. Any of the normal EditLive! instantiation options can be configured here.
  Note however that we don't call the show() method, the EditLive! instance is inserted into the document below.
  */
  var editlive = new EditLiveJava("EditLive", width, height);
  editlive.setDownloadDirectory(editliveDownloadDirectory);
  editlive.setConfigurationFile(editliveDownloadDirectory + "/sample_eljconfig.xml");

  /* Make sure that autosubmit is set to false as we'll manually store the content before submitting. */
  editlive.setAutoSubmit(false);

  /* Load the content from the text area into EditLive! */
  editlive.setBody(encodeURIComponent(textarea.value));

  /* Insert EditLive! into the document by creating a DIV to contain the editor, adding the DIV to the document where
  the textarea is and setting the content of the DIV to the editor's instantiation HTML. */
  var editliveDiv = document.createElement("div");
  textarea.parentNode.insertBefore(editliveDiv, textarea);

  /** getAppletHTML() returns the HTML required to load EditLive! We load this directly into the div we created for the editor. */
  editliveDiv.innerHTML = editlive.getAppletHTML();

  /* Now we need to add an onsubmit() handler to store the content back into the hidden DIV before we submit. */
  var form = textarea.form;
  var originalOnSubmit = form.onsubmit;
  form.onsubmit = function() {
    storeEditLiveContent();
    if (originalOnSubmit) {
      originalOnSubmit.apply(form);
    }
  }
}

/* Handles storing the content back into the text area so that it submits back to the server.
We use LiveConnect here to make the call work synchronously instead of using the EditLive! JavaScript apis which work asynchronously.
*/
function storeEditLiveContent() {
  var textarea = document.getElementById(textAreaId);
  var editliveApplet = document.getElementById("EditLive_elj");
  var content = editliveApplet.getBody();
  /* Safari has a bug where setting the value of a hidden textarea has no effect. To work around this we set the innerText instead.
  The IsSafari variable is defined in editlivejava.js
  */
  if (IsSafari) {
    textarea.innerText = content;
  } else {
    textarea.value = content;
  }
}

Here's the HTML page with the script and the textarea all put together:

<html>
<head>
<title>Replacing A Textarea with EditLive!</title>
<script language="JavaScript" type="text/javascript" src="loadEditLive.js"></script>
</head>
<body>
<p>We want to replace the textarea below with EditLive!</p>
<form method="POST" action="form_out.jsp">
<textarea name="content" id="content" rows="40" cols="100">&lt;p&gt;This is the content&lt;/p&gt;</textarea>

<p><input type="submit" /></p>
</form>
</body>
</html>

You can also download both files.