YUI 2.8: Rich Text Editor

0
175
9 min read

(For more resources on YUI, see here.)

Long gone are the days when we struggled to highlight a word in an e-mail message for lack of underlining or boldfacing. The rich graphic environment that the web provides has extended to anything we do on it; plain text is no longer fashionable.

YUI includes a Rich Text Editor (RTE) component in two varieties, the basic YA-HOO.widget.SimpleEditor and the full YAHOO.widget.Editor. Both editors are very simple to include in a web page and they enable our visitors to enter richly formatted documents which we can easily read and use in our applications. Beyond that, the RTE is highly customizable and allows us to tailor the editor we show the user in any way we want.

In this article we’ll see:

  • What each of the two editors offers
  • How to create either of them
  • Ways to retrieve the text entered
  • How to add toolbar commands

 

The Two Editors

Nothing comes for free, features take bandwidth so the RTE component has two versions, SimpleEditor which provides the basic editing functionality and Editor which is a subclass of SimpleEditor and adds several features at a cost of close to 40% more size plus several more dependencies which we might have already loaded and might not add to the total.

A look at their toolbars can help us to see the differences:

YUI 2.8: Rich Text Editor

The above is the standard toolbar of SimpleEditor. The toolbar allows selection of fonts, sizes and styles, select the color both for the text and the background, create lists and insert links and pictures.

YUI 2.8: Rich Text Editor

The full editor adds to the top toolbar sub and superscript, remove formatting, show source, undo and redo and to the bottom toolbar, text alignment, &ltHn> paragraph styles and indenting commands. The full editor requires, beyond the common dependencies for both, Button and Menu so that the regular HTML &ltselect> boxes can be replaced by a fancier one:

YUI 2.8: Rich Text Editor

Finally, while in the SimpleEditor, when we insert an image or a link, RTE will simply call window.prompt() to show a standard input box asking for the URL for the image or the link destination, the full editor can show a more elaborate dialog box such as the following for the Insert Image command:

YUI 2.8: Rich Text Editor

A simple e-mail editor

It is high time we did some coding, however I hope nobody gets frustrated at how little we’ll do because, even though the RTE is quite a complex component and does wonderful things, there is amazingly little we have to do to get one up and running. This is what our page will look like:

YUI 2.8: Rich Text Editor

This is the HTML for the example:

<form method="get" action="#" id="form1">
<div class="fieldset"><label for="to">To:</label>
<input type="text" name="to" id="to"/></div>
<div class="fieldset"><label for="from">From:</label>
<input type="text" name="from" id="from" value="me" /></div>
<div class="fieldset"><label for="subject">Subject:</label>
<input type="text" name="subject" id="subject"/></div>
<textarea id="msgBody" name="msgBody" rows="20" cols="75">
Lorem ipsum dolor sit amet, and so on
</textarea>
<input type="submit" value=" Send Message " />
</form>

This simple code, assisted by a little CSS would produce something pretty much like the image above, except for the editing toolbar. This is by design, RTE uses Progressive Enhancement to turn the &lttextarea> into a fully featured editing window so, if you don’t have JavaScript enabled, you’ll still be able to get your text edited, though it will be plain text.

The form should have its method set to “post”, since the body of the message might be quite long and exceed the browser limit for a “get” request, but using “get” in this demo will allow us to see in the location bar of the browser what would actually get transmitted to the server.

Our page will require the following dependencies: yahoo-dom-event.js, element-min.js and simpleeditor-min.js along its CSS file, simpleeditor.css. In a <script> tag right before the closing </body> we will have:

YAHOO.util.Event.onDOMReady(function () {
var myEditor = new YAHOO.widget.SimpleEditor('msgBody', {
height: '300px',
width: '740px',
handleSubmit: true
});
myEditor.get('toolbar').titlebar = false;
myEditor.render();
});

This is all the code we need turn that &lttextarea> into an RTE; we simply create an instance of SimpleEditor giving the id of the &lttextarea> and a series of options. In this case we set the size of the editor and tell it that it should take care of submitting the data on the RTE along the rest of the form. What the RTE does when this option is true is to set a listener for the form submission and dump the contents of the editor window back into the &lttextarea> so it gets submitted along the rest of the form.

The RTE normally shows a title bar over the toolbar; we don’t want this in our application and we eliminate it simply by setting the titlebar property in the toolbar configuration attribute to false. Alternatively, we could have set it to any HTML string we wanted shown on that area

Finally, we simply render the editor. That is all we need to do; the RTE will take care of all editing chores and when the form is about to be submitted, it will take care of sending its data along with the rest.

Filtering the data

The RTE will not send the data unfiltered, it will process the HTML in its editing area to make sure it is clean, safe, and compliant. Why would we expect our data to contain anything invalid? If all text was written from within the RTE, there would be no problem at all as the RTE won’t generate anything wrong, but that is not always the case. Plenty of text will be cut from somewhere else and pasted into the RTE, and that text brings with it plenty of existing markup.

To clean up the text, the RTE will consider the idiosyncrasies of a few user agents and the settings of a couple of configuration attributes.

The filterWord configuration attribute will make sure that the extra markup introduced by text pasted into the editor from MS Word does not get through.

The markup configuration attribute has four possible settings:

  • semantic: This is the default setting; it will favor semantic tags in contrast to styling tags, for example, it will change &ltb> into &ltstrong>, &ltti&g into &ltem> and &ltfont> into &ltspan style=”font: ….
  • css: It will favor CSS style attributes, for example, changing &ltb> into &ltspan style=”font-weight:bold”>.
  • default: It does the minimum amount of changes required for safety and compliance.
  • xhtml: Among other changes, it makes sure all tags are closed such as &ltbr />, &ltimg />, and &ltinput />.

 

The default setting, which is not the default, offers the least filtering that will be done in all cases; it will make sure tags have their matching closing tags, extra whitespace is stripped off, and the tags and attributes are in lower case. It will also drop several tags that don’t fit in an HTML fragment, such as &lthtml> or &ltbody>, that are unsafe, such as &ltscript> or &ltiframe>, or would involve actions, such as &ltform> or form input elements. The list of invalid tags is stored in property .invalidHTML and can be freely changed.

More validation

We can further validate what the RTE sends in the form; instead of letting the RTE handle the data submission automatically, we can handle it ourselves by simply changing the previous code to this:

YAHOO.util.Event.onDOMReady(function () {
var Dom = YAHOO.util.Dom,
Event = YAHOO.util.Event;

var myEditor = new YAHOO.widget.SimpleEditor('msgBody', {
height: '300px',
width: '740px'
});
myEditor.get('toolbar').titlebar = false;
myEditor.render();

Event.on('form1', 'submit', function (ev) {
var html = myEditor.getEditorHTML();
html = myEditor.cleanHTML(html);
if (html.search(/<strong/gi) > -1) {
alert("Don't shout at me!");
Event.stopEvent(ev);
}
this.msgBody.innerHTML = html;
});
});

We have dropped the handleSubmit configuration attribute when creating the SimpleEditor instance as we want to handle it ourselves.

We listen to the submit event for the form and in the listener we read the actual rich text from the RTE via .getEditorHTML(). We may or may not want to clean it; in this example, we do so by calling .cleanHTML(). In fact, if we call .cleanHTML() with no arguments we will get the cleaned-up rich text; we don’t need to call .getEditorHTML() first. Then we can do any validation that we want on that string and any of the other values. We use the Event utility .stopEvent() method to prevent the form from submitting if an error is found, but if everything checks fine, we save the HTML we recovered from the RTE into the &lttextarea>, just as if we had the handleSubmit configuration attribute set, except that now we actually control what goes there.

In the case of text in boldface, it would seem easy to filter it out by simply adding this line:

myEditor.invalidHTML.strong = true;

However, this erases the tag and all the content in between, probably not what we wanted. Likewise, we could have set .invalidHTML.em to true to drop italics, but other elements are not so easy. RTE replaces a &ltu> (long deprecated) by &ltspan style=”text-decoration:underline;”> which is impossible to drop in this way. Besides, these replacements depend on the setting of the markup configuration attribute.

This example has also served us to see how data can be read from the RTE and cleaned if desired. Data can also be sent to the RTE by using .setEditorHTML(), but not before the editorContentLoaded event is fired, as the RTE would not be ready to receive it.

In the example, we wanted to manipulate the editor contents, so we read it and saved it back into the &lttextarea> in separate steps; otherwise, we could have used the .saveHTML() method to send the data back to the &lttextarea> directly. In fact, this is what the RTE itself does when we set handleSubmit to true.

LEAVE A REPLY

Please enter your comment!
Please enter your name here