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.

Adrian spends his days working out ways to make life easier for Ephox clients through initiatives like LiveWorks! Previously a senior engineer, he has now moved on to the fancier sounding title of CTO.

Leave a Reply