Developer Network Home - Help

YUI 2: Rich Text Editor

YUI 2: Rich Text Editor

The Rich Text Editor interface with the default YUI Sam Skin applied.The Rich Text Editor is a UI control that replaces a standard HTML textarea; it allows for the rich formatting of text content, including common structural treatments like lists, formatting treatments like bold and italic text, and drag-and-drop inclusion and sizing of images. The Rich Text Editor's toolbar is extensible via a plugin architecture so that advanced implementations can achieve a high degree of customization.

In order to give you the greatest possible control over the size and performance of the Rich Text Editor codebase, we provide two versions of the Editor module and two versions of the buttons that live on the Toolbar:

  • Editor: Editor contains all features described on this page;
  • SimpleEditor: SimpleEditor contains a subset of Editor's features. (See "Choosing Between Editor and SimpleEditor" for more details.)
  • ToolbarButtonAdvanced: The advanced Toolbar buttons are based on YUI Buttons; they are more richly featured at the cost of more dependencies.
  • ToolbarButton: The more simple Toolbar buttons have fewer dependencies and so are lighter on the page; they do not support progressive enhancement nor menu-button functionality. (See "Changing the Toolbar" for more about your Toolbar choices.)

Choose the right combination of features in your Editor and Toolbar to get the right tradeoff between size and richness for your application.

Video: Rich Text Editing with YUI

In this 36 minute video, YUI Rich Text Editor author Dav Glass takes you on a guided tour of the component, including both how to use and how to extend the base functionality. [iPod/iPhone compatible download also available.]

Getting Started

To use the Editor, include the following source files in your web page:

  1. <!-- Skin CSS file -->
  2. <link rel="stylesheet" type="text/css" href="https://yui-s.yahooapis.com/2.9.0/build/assets/skins/sam/skin.css">
  3. <!-- Utility Dependencies -->
  4. <script src="https://yui-s.yahooapis.com/2.9.0/build/yahoo-dom-event/yahoo-dom-event.js"></script>
  5. <script src="https://yui-s.yahooapis.com/2.9.0/build/element/element-min.js"></script>
  6. <!-- Needed for Menus, Buttons and Overlays used in the Toolbar -->
  7. <script src="https://yui-s.yahooapis.com/2.9.0/build/container/container_core-min.js"></script>
  8. <script src="https://yui-s.yahooapis.com/2.9.0/build/menu/menu-min.js"></script>
  9. <script src="https://yui-s.yahooapis.com/2.9.0/build/button/button-min.js"></script>
  10. <!-- Source file for Rich Text Editor-->
  11. <script src="https://yui-s.yahooapis.com/2.9.0/build/editor/editor-min.js"></script>
  12.  
<!-- Skin CSS file -->
<link rel="stylesheet" type="text/css" href="https://yui-s.yahooapis.com/2.9.0/build/assets/skins/sam/skin.css">
<!-- Utility Dependencies -->
<script src="https://yui-s.yahooapis.com/2.9.0/build/yahoo-dom-event/yahoo-dom-event.js"></script> 
<script src="https://yui-s.yahooapis.com/2.9.0/build/element/element-min.js"></script> 
<!-- Needed for Menus, Buttons and Overlays used in the Toolbar -->
<script src="https://yui-s.yahooapis.com/2.9.0/build/container/container_core-min.js"></script>
<script src="https://yui-s.yahooapis.com/2.9.0/build/menu/menu-min.js"></script>
<script src="https://yui-s.yahooapis.com/2.9.0/build/button/button-min.js"></script>
<!-- Source file for Rich Text Editor-->
<script src="https://yui-s.yahooapis.com/2.9.0/build/editor/editor-min.js"></script>
 

To use the SimpleEditor, include the following source files in your web page:

  1. <!-- Skin CSS file -->
  2. <link rel="stylesheet" type="text/css" href="https://yui-s.yahooapis.com/2.9.0/build/assets/skins/sam/skin.css">
  3. <!-- Utility Dependencies -->
  4. <script src="https://yui-s.yahooapis.com/2.9.0/build/yahoo-dom-event/yahoo-dom-event.js"></script>
  5. <script src="https://yui-s.yahooapis.com/2.9.0/build/element/element-min.js"></script>
  6. <!-- Needed for Menus, Buttons and Overlays used in the Toolbar -->
  7. <script src="https://yui-s.yahooapis.com/2.9.0/build/container/container_core-min.js"></script>
  8. <!-- Source file for Rich Text Editor-->
  9. <script src="https://yui-s.yahooapis.com/2.9.0/build/editor/simpleeditor-min.js"></script>
  10.  
<!-- Skin CSS file -->
<link rel="stylesheet" type="text/css" href="https://yui-s.yahooapis.com/2.9.0/build/assets/skins/sam/skin.css">
<!-- Utility Dependencies -->
<script src="https://yui-s.yahooapis.com/2.9.0/build/yahoo-dom-event/yahoo-dom-event.js"></script> 
<script src="https://yui-s.yahooapis.com/2.9.0/build/element/element-min.js"></script> 
<!-- Needed for Menus, Buttons and Overlays used in the Toolbar -->
<script src="https://yui-s.yahooapis.com/2.9.0/build/container/container_core-min.js"></script>
<!-- Source file for Rich Text Editor-->
<script src="https://yui-s.yahooapis.com/2.9.0/build/editor/simpleeditor-min.js"></script>
 
Next, apply the yui-skin-sam class name to an element that is a parent of the element in which the Rich Text Editor lives. You can usually accomplish this simply by putting the class on the <body> tag:

  1. <body class="yui-skin-sam">
  2.  
<body class="yui-skin-sam">
 

For more information on skinning YUI components and making use of default skins, see our Understanding YUI Skins article here on the website.

YUI dependency configurator.

YUI Dependency Configurator:

Instead of copying and pasting the filepaths above, try letting the YUI dependency Configurator determine the optimal file list for your desired components; the Configurator uses YUI Loader to write out the full HTML for including the precise files you need for your implementation.

Note: If you wish to include this component via the YUI Loader, its module name is editor. (Click here for the full list of module names for YUI Loader.)

Where these files come from: The files included using the text above will be served from Yahoo! servers; see "Serving YUI Files from Yahoo!" for important information about this service. JavaScript files are minified, meaning that comments and white space have been removed to make them more efficient to download. To use the full, commented versions or the -debug versions of YUI JavaScript files, please download the library distribution and host the files on your own server.

Order matters: As is the case generally with JavaScript and CSS, order matters; these files should be included in the order specified above. If you include files in the wrong order, errors may result.

Using the Rich Text Editor

This section describes several common uses of the Rich Text Editor. It contains these subsections:

Choosing Between Editor and SimpleEditor

The SimpleEditor Control is a smaller more basic version of the Editor Control. Most of the editing features found in the main Editor Control exist in the SimpleEditor version. However a few were removed:

  • Advanced Image editing — replaced with a simple Javascript prompt
  • Advanced Link editing — replaced with a simple Javascript prompt
  • Advanced Drop Down Menus — replaced with standard HTML Select Elements
  • Header editing
  • Removing of Format
  • Superscript & Subscript
  • Indenting & Outdenting
  • No support for YAHOO.widget.EditorWindow — The floating panels used for image and link editing

The major difference between the two editors are their dependencies.

SimpleEditor's dependencies are:

Editor's dependencies are:

Rendering the Editor

The Rich Text Editor is designed to replace an existing HTML <textarea> control. Users whose browsers do not support JavaScript will therefore see a standard <textarea> in place of the Rich Text Editor. The base markup for this approach is as follows:

  1. <body class="yui-skin-sam">
  2. <textarea name="msgpost" id="msgpost" cols="50" rows="10">
  3. <strong>Your</strong> HTML <em>code</em> goes here.<br>
  4. This text will be pre-loaded in the editor when it is rendered.
  5. </textarea>
  6. </body>
  7.  
<body class="yui-skin-sam">
<textarea name="msgpost" id="msgpost" cols="50" rows="10">
    <strong>Your</strong> HTML <em>code</em> goes here.<br>
    This text will be pre-loaded in the editor when it is rendered.
</textarea>
</body>
 

With this markup in place, the JavaScript to instantiate the Rich Text Editor involves a simple constructor to which is passed a configuration object. Once instantiated, you use the render method to place the Rich Text Editor on the page:

  1. var myEditor = new YAHOO.widget.Editor('msgpost', {
  2. height: '300px',
  3. width: '522px',
  4. dompath: true, //Turns on the bar at the bottom
  5. animate: true //Animates the opening, closing and moving of Editor windows
  6. });
  7. myEditor.render();
  8.  
var myEditor = new YAHOO.widget.Editor('msgpost', {
    height: '300px',
    width: '522px',
    dompath: true, //Turns on the bar at the bottom
    animate: true //Animates the opening, closing and moving of Editor windows
});
myEditor.render();
 

The full list of configuration options that you can pass in your constructor can be found in the API documentation.

With the simple markup and script above, and including the skin stylesheet for Rich Text Editor, you will see rendered to your page a rich control that looks like this:

The Rich Text Editor Control

Rendering the SimpleEditor

You render the SimpleEditor Control the same as the Editor Control, only you call the SimpleEditor constructor instead.

  1. var myEditor = new YAHOO.widget.SimpleEditor('msgpost', {
  2. height: '300px',
  3. width: '522px',
  4. dompath: true //Turns on the bar at the bottom
  5. });
  6. myEditor.render();
  7.  
var myEditor = new YAHOO.widget.SimpleEditor('msgpost', {
    height: '300px',
    width: '522px',
    dompath: true //Turns on the bar at the bottom
});
myEditor.render();
 

With the simple markup and script above, and including the skin stylesheet for Rich Text Editor, you will see rendered to your page a rich control that looks like this:

The Simple Rich Text Editor Control

Getting the data from the Editor

There are a couple of ways to get the data from the editor. The first way is to let the Editor do it for you by setting the handleSubmit configuration option.

Setting the handleSubmit configuration option, the Editor will attempt to attach itself to its parent form's submit event. Then it will call its saveHTML method, then proceed with the form submission.

The manual way, is to call the saveHTML method yourself. Like this:

  1. var myEditor = new YAHOO.widget.Editor('msgpost');
  2. myEditor.render();
  3.  
  4. //Inside an event handler after the Editor is rendered
  5. YAHOO.util.Event.on('somebutton', 'click', function() {
  6. //Put the HTML back into the text area
  7. myEditor.saveHTML();
  8.  
  9. //The var html will now have the contents of the textarea
  10. var html = myEditor.get('element').value;
  11. });
  12.  
var myEditor = new YAHOO.widget.Editor('msgpost');
myEditor.render();
 
//Inside an event handler after the Editor is rendered
YAHOO.util.Event.on('somebutton', 'click', function() {
    //Put the HTML back into the text area
    myEditor.saveHTML();
 
    //The var html will now have the contents of the textarea
    var html = myEditor.get('element').value;
});
 

Changing the toolbar

The default toolbar included with the editor makes every currently supported feature available by default. You can override this config before the editor is rendered by passing in an object literal of a new toolbar to the constructor.

See this example for the full toolbar config

  1. var myEditor = new YAHOO.widget.Editor('msgpost', {
  2. height: '200px',
  3. width: '385px',
  4. dompath: false,
  5. animate: true,
  6. toolbar: {
  7. titlebar: 'My Editor',
  8. buttons: [
  9. { group: 'textstyle', label: 'Font Style',
  10. buttons: [
  11. { type: 'push', label: 'Bold', value: 'bold' },
  12. { type: 'push', label: 'Italic', value: 'italic' },
  13. { type: 'push', label: 'Underline', value: 'underline' },
  14. { type: 'separator' },
  15. { type: 'select', label: 'Arial', value: 'fontname', disabled: true,
  16. menu: [
  17. { text: 'Arial', checked: true },
  18. { text: 'Arial Black' },
  19. { text: 'Comic Sans MS' },
  20. { text: 'Courier New' },
  21. { text: 'Lucida Console' },
  22. { text: 'Tahoma' },
  23. { text: 'Times New Roman' },
  24. { text: 'Trebuchet MS' },
  25. { text: 'Verdana' }
  26. ]
  27. },
  28. { type: 'spin', label: '13', value: 'fontsize', range: [ 9, 75 ], disabled: true },
  29. { type: 'separator' },
  30. { type: 'color', label: 'Font Color', value: 'forecolor', disabled: true },
  31. { type: 'color', label: 'Background Color', value: 'backcolor', disabled: true }
  32. ]
  33. }
  34. ]
  35. }
  36. });
  37. myEditor.render();
  38.  
var myEditor = new YAHOO.widget.Editor('msgpost', {
    height: '200px',
    width: '385px',
    dompath: false,
    animate: true,
    toolbar: {
        titlebar: 'My Editor',
        buttons: [
            { group: 'textstyle', label: 'Font Style',
                buttons: [
                    { type: 'push', label: 'Bold', value: 'bold' },
                    { type: 'push', label: 'Italic', value: 'italic' },
                    { type: 'push', label: 'Underline', value: 'underline' },
                    { type: 'separator' },
                    { type: 'select', label: 'Arial', value: 'fontname', disabled: true,
                        menu: [
                            { text: 'Arial', checked: true },
                            { text: 'Arial Black' },
                            { text: 'Comic Sans MS' },
                            { text: 'Courier New' },
                            { text: 'Lucida Console' },
                            { text: 'Tahoma' },
                            { text: 'Times New Roman' },
                            { text: 'Trebuchet MS' },
                            { text: 'Verdana' }
                        ]
                    },
                    { type: 'spin', label: '13', value: 'fontsize', range: [ 9, 75 ], disabled: true },
                    { type: 'separator' },
                    { type: 'color', label: 'Font Color', value: 'forecolor', disabled: true },
                    { type: 'color', label: 'Background Color', value: 'backcolor', disabled: true }
                ]
            }
        ]
    }
});
myEditor.render();
 

The Editor's Toolbar supports 2 types of buttons: advanced and basic.

Note: To use the advanced button type you will need to make sure you include the Menu and Button Controls.

The following are advanced button types:

  • Push: Push buttons are provided via the YUI Button Control.
  • Menu: Menu buttons are provided via the YUI Button Control.
  • Select: The Select button is a hybrid of the menu button that mimics an HTML <select> element.
  • Color: The Color button is another hybrid menu button that contains an interactive color picker; note that this color picker is not an implementation of the YUI Color Picker Control but rather a dedicated text-editing control optimized for styling text.
  • Spin: The Spin button is a hybrid of a Push button that adds a pair of up and down arrows to the side of the button. It is generally used to allow the user to select a value from a range of numeric values. Selecting one of the buttons causes the value to "spin" up and down the range of possible values.
  • Separator: The Separator button gives you a way to place a bar ("|") in between two buttons. The separator bar is also given a unique classname so you can use it to style the toolbar as needed.

The following are basic button types:

  • Push: Push buttons are provided via the default toolbar.
  • Menu: Menu buttons are provided via the default toolbar.
  • Select: The Select button is an HTML <select> element.
  • Color: The Color button is a hybrid menu button that contains an interactive color picker; note that this color picker is not an implementation of the YUI Color Picker Control but rather a dedicated text-editing control optimized for styling text.
  • Spin: The Spin button is a hybrid of a Push button that adds a pair of up and down arrows to the side of the button. It is generally used to allow the user to select a value from a range of numeric values. Selecting one of the buttons causes the value to "spin" up and down the range of possible values.
  • Separator: The Separator button gives you a way to place a bar ("|") in between two buttons. The separator bar is also given a unique classname so you can use it to style the toolbar as needed.

Example code for each of these button types is included in the toolbar section above. You can also see a few examples of using the different button types in the Editor's example section.

With the above code you would get an Editor that looked like this:

Rich Text Editor Screenshot

Events

The Rich Text Editor and the Toolbar are both loaded with Custom Events to which you can subscribe as you customize the editor's behavior to suit the specific needs of your application.

Some of the more common Rich Text Editor events include the following; for a full list, including the arguments passed to each event, see the API documentation for Rich Text Editor:

SimpleEditor Events

  • Editor Render Events
    • toolbarLoaded
    • afterRender
    • editorContentLoaded
  • Editor HTML Event Mapping
    • editorMouseUp
    • editorMouseDown
    • editorDoubleClick
    • editorKeyUp
    • editorKeyPress
    • editorKeyDown
  • Editor Command Execution Events
    • beforeNodeChange
    • afterNodeChange
    • beforeExecCommand
    • afterExecCommand
  • Toolbar Events (accessed via EditorObj.toolbar.on())
    • toolbarExpanded
    • toolbarCollapsed
    • colorPickerClicked
    • cmdClick (dynamic event)
    • menucmdClick (dynamic event)
    • buttonClick

Editor Events

  • Editor Render Events
    • toolbarLoaded
    • afterRender
    • editorContentLoaded
  • Editor HTML Event Mapping
    • beforeEditorMouseUp
    • editorMouseUp
    • beforeEditorMouseDown
    • editorMouseDown
    • beforeEditorClick
    • editorClick
    • beforeEditorDoubleClick
    • editorDoubleClick
    • beforeEditorKeyUp
    • editorKeyUp
    • beforeEditorKeyPress
    • editorKeyPress
    • beforeEditorKeyDown
    • editorKeyDown
  • Editor Command Execution Events
    • beforeNodeChange
    • afterNodeChange
    • beforeExecCommand
    • afterExecCommand
  • Editor Window Events
    • beforeOpenWindow
    • afterOpenWindow
    • closeWindow
    • windowCMDOpen (dynamic event)
    • windowCMDClose (dynamic event)
    • windowRender
    • windowInsertImageRender
    • windowCreateLinkRender
  • Toolbar Events (accessed via EditorObj.toolbar.on())
    • toolbarExpanded
    • toolbarCollapsed
    • colorPickerClicked
    • cmdClick (dynamic event)
    • menucmdClick (dynamic event)
    • buttonClick

Dynamic Events

Dynamic Events are special CustomEvent's that are dynamically created based on the value of a button in the Toolbar.

For example, if you had a button called "bold" you will be able to listen for the "boldClick" event or if you had a button called "foo", you would be able to listen for the "fooClick" event.

These events are best described with the following code:

  1. var myEditor = new YAHOO.widget.Editor('msgpost', {
  2. //Snippet from button config
  3. buttons: [
  4. { type: 'push', label: 'Bold', value: 'bold' },
  5. { type: 'push', label: 'My Button 1', value: 'mybutton1' },
  6. { type: 'push', label: 'My Button 2', value: 'mybutton2' }
  7. ]
  8. });
  9.  
  10. myEditor.on('toolbarLoaded', function() {
  11. //Using the Dynamic Event cmdClick where cmd is the value of the button above
  12. this.toolbar.on('boldClick', function(o) {
  13. alert('Bold Button was clicked');
  14. });
  15. //Using the Dynamic Event cmdClick where cmd is the value of the button above
  16. this.toolbar.on('mybutton1Click', function(o) {
  17. alert('mybutton1 was clicked');
  18. });
  19. //Standard Custom Event fired for all button clicks
  20. this.toolbar.on('buttonClick', function(o) {
  21. switch(o.button.value) {
  22. case 'bold':
  23. //Bold Code Here
  24. break;
  25. case 'mybutton1':
  26. //My Button 1 Code Here
  27. break;
  28. case 'mybutton2':
  29. //My Button 2 Code Here
  30. break;
  31. }
  32. });
  33. }, myEditor, true);
  34.  
  35. myEditor.render();
  36.  
var myEditor = new YAHOO.widget.Editor('msgpost', {
    //Snippet from button config
    buttons: [
        { type: 'push', label: 'Bold', value: 'bold' },
        { type: 'push', label: 'My Button 1', value: 'mybutton1' },
        { type: 'push', label: 'My Button 2', value: 'mybutton2' }
    ]
});
 
myEditor.on('toolbarLoaded', function() {
    //Using the Dynamic Event cmdClick where cmd is the value of the button above
    this.toolbar.on('boldClick', function(o) {
        alert('Bold Button was clicked');
    });
    //Using the Dynamic Event cmdClick where cmd is the value of the button above
    this.toolbar.on('mybutton1Click', function(o) {
        alert('mybutton1 was clicked');
    });
    //Standard Custom Event fired for all button clicks
    this.toolbar.on('buttonClick', function(o) {
        switch(o.button.value) {
            case 'bold':
                //Bold Code Here
                break;
            case 'mybutton1':
                //My Button 1 Code Here
                break;
            case 'mybutton2':
                //My Button 2 Code Here
                break;
        }
    });
}, myEditor, true);
 
myEditor.render();
 

Please refer to the API documentation for a full list of Custom Events that are available for the Rich Text Editor.

Plugins

The Rich Text Editor's toolbar has a flexible plugin architecture that allows you to customize the editor's behavior for the purposes of your own application.

The example below will add a new button to the default toolbar. When this custom button is clicked it will insert the following HTML: "<b>This is the text to insert.</b>" But the button will only be enabled if the user has focused a <div>, so this text will never be inserted into an element within the editor other than a <div>.

  1. //Start with the constructor for our RTE:
  2. var myEditor = new YAHOO.widget.Editor('msgpost', {
  3. height: '300px',
  4. width: '522px'
  5. });
  6.  
  7. //Use the toolbarLoaded Custom Event; when that event fires,
  8. //we will execute a function that adds or custom button:
  9. myEditor.on('toolbarLoaded', function() {
  10. //Simple button config
  11. var button = {
  12. type: 'push',
  13. label: 'My Button 3',
  14. value: 'mybutton3',
  15. disabled: false
  16. };
  17.  
  18. //Add the button to the toolbar; "this"
  19. //refers to myEditor, our RTE instance:
  20. this.toolbar.addButton(button);
  21.  
  22. //Now listen for the new buttons click and do something with it.
  23. //Note that "mybutton3Click" is an event synthesized for us
  24. //automatically because that's the value we gave our button
  25. //above:
  26. this.toolbar.on('mybutton3Click', function(o) {
  27. this.execCommand('inserthtml', '<b>This is the text to insert.</b>');
  28. }, myEditor, true);
  29.  
  30. //Setup the button to be enabled, disabled or selected
  31. this.on('afterNodeChange', function(o) {
  32. //Get the selected element
  33. var el = this._getSelectedElement();
  34.  
  35. //Get the button we want to manipulate
  36. var button = this.toolbar.getButtonByValue('mybutton3');
  37.  
  38. if (el && el.tagName == 'div') {
  39. this.toolbar.enableButton(button);
  40. }
  41. }, this, true);
  42. }, myEditor, true);
  43.  
  44. myEditor.render();
  45.  
//Start with the constructor for our RTE:
var myEditor = new YAHOO.widget.Editor('msgpost', {
    height: '300px',
    width: '522px'
});
 
//Use the toolbarLoaded Custom Event; when that event fires,
//we will execute a function that adds or custom button:
myEditor.on('toolbarLoaded', function() {
    //Simple button config
    var button = {
        type: 'push',
        label: 'My Button 3',
        value: 'mybutton3',
        disabled: false
    };
 
    //Add the button to the toolbar; "this"
    //refers to myEditor, our RTE instance:
    this.toolbar.addButton(button);
 
    //Now listen for the new buttons click and do something with it.
    //Note that "mybutton3Click" is an event synthesized for us
    //automatically because that's the value we gave our button
    //above:
    this.toolbar.on('mybutton3Click', function(o) {
        this.execCommand('inserthtml', '<b>This is the text to insert.</b>');
    }, myEditor, true);
 
    //Setup the button to be enabled, disabled or selected
    this.on('afterNodeChange', function(o) {
        //Get the selected element
        var el = this._getSelectedElement();
 
        //Get the button we want to manipulate
        var button = this.toolbar.getButtonByValue('mybutton3');
 
        if (el && el.tagName == 'div') {
            this.toolbar.enableButton(button);
        }
    }, this, true);
}, myEditor, true);
 
myEditor.render();
 

Overriding execCommands

The Rich Text Editor uses a method based approach for applying execCommand commands on selected text/elements. For example, when you call myEditor.execCommand('forecolor', 'FF0000');, the editor actually calls an internal method called cmd_forecolor. This method will then process the command and act on it. It will return an array telling the execCommand method whether it should or should not execute the document.execCommand method.

Below is an example of the cmd_forecolor method.

  1. cmd_forecolor: function(value) {
  2. var exec = true,
  3. el = this._getSelectedElement();
  4.  
  5. if (!this._isElement(el, 'body')) {
  6. Dom.setStyle(el, 'color', value);
  7. this._selectNode(el);
  8. exec = false;
  9. } else {
  10. this._createCurrentElement('span', { color: value });
  11. this._selectNode(this.currentElement[0]);
  12. exec = false;
  13. }
  14. return [exec];
  15. },
  16.  
cmd_forecolor: function(value) {
    var exec = true,
        el = this._getSelectedElement();
 
        if (!this._isElement(el, 'body')) {
            Dom.setStyle(el, 'color', value);
            this._selectNode(el);
            exec = false;
        } else {
            this._createCurrentElement('span', { color: value });
            this._selectNode(this.currentElement[0]);
            exec = false;
        }
        return [exec];
},
 

Using this technique, you can add support for your own execCommands, or change the way that the Editor handles them.

Toolbar Interactions and the nodeChange Event

If you're intereseted in extending the Toolbar with custom buttons (see the Flickr and Calendar examples that do this), the following section contains important information.

The nodeChange event is your way of knowing when an interesting moment occurs inside of the Editor. Keep in mind that the editing canvas itself (the place where the user is inputting rich text) is, under the hood, an HTML document loaded within an iframe with designMode turned on — which is to say it has a DOM full of nodes. When the user is typing, she is adding to a single DOM node. But when she mouses to a new location, selects new texts, or performs any other action that changes the cursor's current position in the DOM, the nodeChange event fires to let you know that the user appears to be performing an interesting action. Common user actions that can fire nodeChange include mousedown, mouseup, arrow keys and other keypress events.

When a nodeChange event is fired off via an internal editor event (or by manually calling myEditor.nodeChange() in your own script), all of the Toolbar's buttons need to update their status to reflect the new state of the user's editor. All of the buttons that ship with the Rich Text Editor fall into one of three groups:

  1. Can be enabled or disabled depending on the state of the editor. This group is enabled when the user has selected content in the editor and disabled when the user is merely typing.
  2. Always enabled. The "show hidden elements" button, for example, is always enabled.
  3. Always disabled. By default, there are no buttons that are always disabled; under some specific circumstances, there may be times when you want to place a custom button in this category (eg, if you've added a feature that is not always available to all users).

The Toolbar goes through the following states in updating its buttons:

  • Loop through the _disabled array (that is, the list of buttons that should be disabled when there is no selected content in the editor) and...
    1. ...if there is no selection then:
      • Disable all buttons in the array.
    2. If there is a selection then:
      • Enable each button NOT in the _alwaysDisabled object.
      • If a button is NOT in the _alwaysEnabled object, it will deselect the button.

For custom buttons that you add to the Editor, it is best practice to subscribe to the afterNodeChange event and update your button's enabled/disabled state at that time. See the Calendar example for sample code that allows you to do this.

  1. /* These are the overrides to manipulate to control the behavior of the toolbar */
  2. _disabled: [
  3. 'createlink',
  4. 'forecolor',
  5. 'backcolor',
  6. 'fontname',
  7. 'fontsize',
  8. 'superscript',
  9. 'subscript',
  10. 'removeformat',
  11. 'heading'
  12. ],
  13. _alwaysDisabled: { },
  14. _alwaysEnabled: { hiddenelements: true }
  15.  
/* These are the overrides to manipulate to control the behavior of the toolbar */
_disabled: [
    'createlink',
    'forecolor',
    'backcolor',
    'fontname', 
    'fontsize',
    'superscript',
    'subscript',
    'removeformat',
    'heading'
],
_alwaysDisabled: { },
_alwaysEnabled: { hiddenelements: true }
 

Showing and Hiding the Editor

The Rich Text Editor includes two convenience methods used when showing and hiding the editor. The methods are show() and hide().

These methods do not control the display properties of the editor. They are designed to plugin to an event given by the editor's parent container. See the Editor inside a TabView control example here for more information.

By setting the editor's container or a parent element of the editor to display none, the editor can become un-responsive. So using the show method will allow the editor to fix itself and start behaving again. On the other hand, you don't want the editor doing any processing when it is hidden. So calling the hide method will close all open editor windows and stop all background processes and timers.

A simple example of using the show and hide events on a Container Control

  1. //panel in a reference to a Container Control (Panel/Overlay/Dialog)
  2. //myEditor is a reference to your Editor instance
  3.  
  4. //Setup the show event
  5. panel.showEvent.subscribe(myEditor.show, myEditor, true);
  6.  
  7. //Setup the hide event
  8. panel.hideEvent.subscribe(myEditor.hide, myEditor, true);
  9.  
//panel in a reference to a Container Control (Panel/Overlay/Dialog)
//myEditor is a reference to your Editor instance
 
//Setup the show event
panel.showEvent.subscribe(myEditor.show, myEditor, true);
 
//Setup the hide event
panel.hideEvent.subscribe(myEditor.hide, myEditor, true);
 

Skinning the Editor

The Rich Text Editor comes with a default presentation or "skin," part of the "Sam Skin" visual treatment that accompanies most YUI controls. You can read more about the general approach to skinning YUI components in this in-depth article.

The CSS provided with the Rich Text Editor is comprised of core, functional CSS as well as the Sam Skin visual treatment.

The Rich Text Editor Control

To explore the CSS which controls the Rich Text Editor's presentation, please review the Rich Text Editor's Skinning Example wherein the full CSS for the control is displayed.

For your convenience we have provided the Rich Text Editor's sprite PSD file in a zip available here.

YUI on Mobile: Using Rich Text Editor with "A-Grade" Mobile Browsers

About this Section: YUI generally works well with mobile browsers that are based on A-Grade browser foundations. For example, Nokia's N-series phones, including the N95, use a browser based on Webkit — the same foundation shared by Apple's Safari browser, which is found on the iPhone. The fundamental challenges in developing for this emerging class of full, A-Grade-derived browsers on handheld devices are:

  • Screen size: You have a much smaller canvas;
  • Input devices: Mobile devices generally do not have mouse input, and therefore are missing some or all mouse events (like mouseover);
  • Processor power: Mobile devices have slower processors that can more easily be saturated by JavaScript and DOM interactions — and processor usage affects things like battery life in ways that don't have analogues in desktop browsers;
  • Latency: Most mobile devices have a much higher latency on the network than do terrestrially networked PCs; this can make pages with many script, css or other types of external files load much more slowly.

There are other considerations, many of them device/browser specific (for example, current versions of the iPhone's Safari browser do not support Flash). The goal of these sections on YUI User's Guides is to provide you some preliminary insights about how specific components perform on this emerging class of mobile devices. Although we have not done exhaustive testing, and although these browsers are revving quickly and present a moving target, our goal is to provide some early, provisional advice to help you get started as you contemplate how your YUI-based application will render in the mobile world.

More Information:

The YUI Rich Text Editor does not currently support the iPhone or the Nokia N95. Due to the interaction model (specifically, the inability to make a selection), the Editor will not function as expected. In our tests, it appears that the Apple and Nokia Webkit implementations don't event recognize the Editor as an editing field — meaning that these browsers are, at present, deliberately not supporting the use of an iframe in design mode.

The best way to get around this is to not render the Editor when you come across one of these browsers. Take a look at this example of browser detection in the Yahoo Global Object for ways of doing that.

Support & Community

The YUI Library and related topics are discussed on the on the YUILibrary.com forums.

Also be sure to check out YUIBlog for updates and articles about the YUI Library written by the library's developers.

Filing Bugs & Feature Requests

The YUI Library's public bug tracking and feature request repositories are located on the YUILibrary.com site. Before filing new feature requests or bug reports, please review our reporting guidelines.

Copyright © 2016 Yahoo! Inc. All rights reserved.

Privacy Policy - Copyright Policy - Job Openings