Ext4 HtmlEditor富文本加入固定表情panel

来源:岁月联盟 编辑:exp 时间:2012-08-14

感谢Ext社区的外国朋友提供一个现成的插件,我在当中加入一个表情panel,希望给大家在用Ext的时候也方便一些.做个例子让大家继续扩展.


Ext.ux.form.plugin.HtmlEditor.js
[javascript] 
/**
* @class Ext.ux.form.plugin.HtmlEditor
* @author Adrian Teodorescu (ateodorescu@gmail.com; http://www.mzsolutions.eu)
* @docauthor Adrian Teodorescu (ateodorescu@gmail.com; http://www.mzsolutions.eu)
* @version 1.1

* Provides plugins for the HtmlEditor. Many thanks to [Shea Frederick][1] as I was inspired by his [work][2].

* [1]: http://www.vinylfox.com
* [2]: http://www.vinylfox.com/plugin-set-for-additional-extjs-htmleditor-buttons/

* The plugin buttons have tooltips defined in the {@link #buttonTips} property, but they are not
* enabled by default unless the global {@link Ext.tip.QuickTipManager} singleton is {@link Ext.tip.QuickTipManager#init initialized}.
*


#Example usage:#
 
{@img Ext.ux.form.plugin.HtmlEditor.png Ext.ux.form.plugin.HtmlEditor plugins}
 
     var top = Ext.create('Ext.form.Panel', {
        frame:true,
        title:          'HtmlEditor plugins',
        bodyStyle:      'padding:5px 5px 0',
        width:          '80%',
        fieldDefaults: {
            labelAlign:     'top',
            msgTarget:      'side'
        },
 
        items: [{
            xtype:          'htmleditor',
            fieldLabel:     'Text editor',
            height:         300,
            plugins: [
                Ext.create('Ext.ux.form.plugin.HtmlEditor',{
                    enableAll:  true
                })
            ],
            anchor:         '100%'
        }],
 
        buttons: [{
            text: 'Save'
        },{
            text: 'Cancel'
        }]
    });
 
    top.render(document.body);
 
*/ 
Ext.define('Ext.ux.form.plugin.HtmlEditor', { 
    mixins: { 
        observable: 'Ext.util.Observable' 
    }, 
    alternateClassName: 'Ext.form.plugin.HtmlEditor', 
    requires: [ 
        'Ext.tip.QuickTipManager', 
        'Ext.form.field.HtmlEditor' 
    ], 
     
    /**
    * @cfg {Boolean} enableAll Enable all available plugins
    */ 
    enableAll:              false, 
    /**
    * @cfg {Boolean} enableUndoRedo Enable "undo" and "redo" plugins
    */ 
    enableUndoRedo:         false, 
    /**
    * @cfg {Boolean} enableRemoveHtml Enable the plugin "remove html" which is removing all html entities from the entire text
    */ 
    enableRemoveHtml:       false, 
    /**
    * @cfg {Boolean} enableRemoveFormatting Enable "remove format" plugin
    */ 
    enableRemoveFormatting: false, 
    /**
    * @cfg {Boolean} enableIndenting Enable "indent" and "outdent" plugins
    */ 
    enableIndenting:        false, 
    /**
    * @cfg {Boolean} enableSmallLetters Enable "superscript" and "subscript" plugins
    */ 
    enableSmallLetters:     false, 
    /**
    * @cfg {Boolean} enableHorizontalRule Enable "horizontal rule" plugin
    */ 
    enableHorizontalRule:   false, 
    /**
    * @cfg {Boolean} enableSpecialChars Enable "special chars" plugin
    */ 
    enableSpecialChars:     false, 
    /**
    * @cfg {Boolean} enableWordPaste Enable "word paste" plugin which is cleaning the pasted text that is coming from MS Word
    */ 
    enableWordPaste:        false, 
    /**
    * @cfg {Boolean} enableFormatBlocks Enable "format blocks" plugin which allows to insert formatting tags.
    */ 
    enableFormatBlocks:     false, 
    /**
    * @cfg {Boolean} defaultFormatBlock Set the default block format.
    */ 
    defaultFormatBlock:     'p', 
    /**
     * 表情
     */ 
    enableFaceImages:     false, 
     
    enableInsertTable:      false, 
     
    wordPasteEnabled:       false, 
     
    /**
     * @cfg {Array} specialChars
     * An array of additional characters to display for user selection.  Uses numeric portion of the ASCII HTML Character Code only. For example, to use the Copyright symbol, which is © we would just specify <tt>169</tt> (ie: <tt>specialChars:[169]</tt>).
     */ 
    specialChars: [], 
     
    /**
     * 表情
     */ 
    faceImages: [], 
    /**
     * @cfg {Array} charRange
     * Two numbers specifying a range of ASCII HTML Characters to display for user selection. Defaults to <tt>[160, 256]</tt>.
     */ 
    charRange: [160, 256], 
    /**
     * @cfg {Array} listFormatBlocks Array of available format blocks.
     */ 
    listFormatBlocks: ["p", "h1", "h2", "h3", "h4", "h5", "h6", "address", "pre"], 
     
    constructor: function(config) { 
        Ext.apply(this, config); 
    }, 
         
    init: function(editor){ 
        var me = this; 
        me.editor = editor; 
        me.mon(editor, 'initialize', me.onInitialize, me); 
    }, 
     
    onInitialize: function(){ 
        var me = this, undef, 
            items = [], 
            baseCSSPrefix = Ext.baseCSSPrefix, 
            tipsEnabled = Ext.tip.QuickTipManager && Ext.tip.QuickTipManager.isEnabled(); 
         
        function btn(id, toggle, handler){ 
            return { 
                itemId : id, 
                cls : baseCSSPrefix + 'btn-icon', 
                iconCls: baseCSSPrefix + 'edit-'+id, 
                enableToggle:toggle !== false, 
                scope: me, 
                handler:handler||me.relayBtnCmd, 
                clickEvent:'mousedown', 
                tooltip: tipsEnabled ? me.buttonTips[id] || undef : undef, 
                overflowText: me.buttonTips[id].title || undef, 
                tabIndex:-1 
            }; 
        } 
        /**
        if(me.enableFormatBlocks || me.enableAll){
            var i, listFormatBlocks = new Array();
            for(i=0; i < me.listFormatBlocks.length; i++){
                listFormatBlocks.push({
                    value:      me.listFormatBlocks[i].toLowerCase(),
                    caption:    me.buttonTips.listFormatBlocks[me.listFormatBlocks[i]]
                });
            }
            formatBlockSelectItem = Ext.widget('component', {
                renderTpl: [
                    '<select class="{cls}">',
                        '<tpl for="formats">',
                            '<option value="<{value}>" <tpl if="values.toLowerCase()==parent.defaultFormatBlock"> selected</tpl>>{caption}</option>',
                        '</tpl>',
                    '</select>'
                ],
                renderData: {
                    cls:                    baseCSSPrefix + 'font-select',
                    formats:                listFormatBlocks,
                    defaultFormatBlock:     me.defaultFormatBlock
                },
                renderSelectors: {
                    selectEl: 'select'
                },
                onDisable: function() {
                    var selectEl = this.selectEl;
                    if (selectEl) {
                        selectEl.dom.disabled = true;
                    }
                    Ext.Component.superclass.onDisable.apply(this, arguments);
                },
                onEnable: function() {
                    var selectEl = this.selectEl;
                    if (selectEl) {
                        selectEl.dom.disabled = false;
                    }
                    Ext.Component.superclass.onEnable.apply(this, arguments);
                }
            });
 
            items.push(
                '-',
                formatBlockSelectItem
            );
        }
        */ 
        if(me.enableRemoveHtml || me.enableAll){ 
            items.push(btn('removehtml', false, me.doRemoveHtml)); 
        } 
        if(me.enableRemoveFormatting || me.enableAll){ 
            items.push(btn('removeformat', false)); 
        } 
        if(me.enableUndoRedo || me.enableAll){ 
            items.push('-'); 
            items.push(btn('undo', false)); 
            items.push(btn('redo', false)); 
        } 
        /*if(me.enableInsertTable || me.enableAll){
            items.push('-');
            items.push(btn('inserttable', false, me.doInsertTable));
        }*/ 
        if(me.enableIndenting || me.enableAll){ 
            items.push('-'); 
            items.push(btn('indent', false)); 
            items.push(btn('outdent', false)); 
        } 
        if(me.enableSmallLetters || me.enableAll){ 
            items.push('-'); 
            items.push(btn('superscript')); 
            items.push(btn('subscript')); 
        } 
        if(me.enableHorizontalRule || me.enableAll){ 
            items.push(btn('inserthorizontalrule', false)); 
        } 
        if(me.enableSpecialChars || me.enableAll){ 
            items.push(btn('chars', false, me.doSpecialChars)); 
        } 
        if(me.enableFaceImages || me.enableAll){ 
            items.push('-'); 
            var faceImagesBtn = btn('faceImages', false, me.doFaceImages); 
            faceImagesBtn.iconCls = 'employee-add'; 
            items.push(faceImagesBtn); 
        } 
         
        /**
        if(me.enableWordPaste || me.enableAll){
            items.push('-');
            items.push(btn('wordpaste', true, me.doWordPaste));
            me.wordPasteEnabled = true;
        }else{
            me.wordPasteEnabled = false;
        }
        */ 
         
        /*if(me.enableImages){
            items.push(btn('images', false, me.doImages));
        }*/ 
        if(items.length > 0){ 
            me.editor.getToolbar().add(items); 
            fn = Ext.Function.bind(me.onEditorEvent, me); 
            Ext.EventManager.on(me.editor.getDoc(), { 
                mousedown: fn, 
                dblclick: fn, 
                click: fn, 
                keyup: fn, 
                buffer:100 
            }); 
             
            if(formatBlockSelectItem){ 
                me.formatBlockSelect = formatBlockSelectItem.selectEl; 
 
                me.mon(me.formatBlockSelect, 'change', function(){ 
                    me.relayCmd('formatblock', me.formatBlockSelect.dom.value); 
                    me.editor.deferFocus(); 
                });                 
            } 
             
        } 
    }, 
     
    onEditorEvent: function(e){ 
        var me = this, 
            diffAt = 0; 
         
        me.updateToolbar(); 
         
        me.curLength = me.editor.getValue().length; 
         
        if (e.ctrlKey) { 
            var c = e.getCharCode(); 
            if (c > 0) { 
                c = String.fromCharCode(c); 
                if(c.toLowerCase() == 'v' && me.wordPasteEnabled){ 
                    me.cleanWordPaste(); 
                } 
            } 
        } 
         
        me.lastLength = me.editor.getValue().length; 
        me.lastValue = me.editor.getValue(); 
 
    }, 
     
    updateToolbar: function(){ 
        var me = this, 
            btns, doc; 
         
        if(me.editor.readOnly){ 
            return; 
        } 
         
        btns = me.editor.getToolbar().items.map; 
        doc = me.editor.getDoc(); 
         
        function updateButtons() { 
            Ext.Array.forEach(Ext.Array.toArray(arguments), function(name) { 
                btns[name].toggle(doc.queryCommandState(name)); 
            }); 
        } 
         
        if(me.enableSmallLetters || me.enableAll){ 
            updateButtons('superscript', 'subscript'); 
        } 
        /**
        if(me.enableWordPaste || me.enableAll){
            btns['wordpaste'].toggle(me.wordPasteEnabled);
        }
        
        if(me.enableFormatBlocks || me.enableAll){
            this.checkSelectionFormatBlock();
        }
        */ 
    }, 
     
    doRemoveHtml: function() { 
        Ext.defer(function() { 
            var me = this; 
            me.editor.focus(); 
            var tmp = document.createElement("DIV"); 
            tmp.innerHTML = me.editor.getValue(); 
            me.editor.setValue(tmp.textContent||tmp.innerText); 
        }, 10, this); 
    }, 
     
    doInsertTable: function(){ 
         
    }, 
     
    doFaceImages: function(){ 
        //表情列表     
        var faceImages = [ 
            ["001"],["002"],["003"],["004"],["005"] 
        ]; 
        //表情集合 
        var faceImagesStore = new Ext.data.ArrayStore({ 
            fields: ['name'], 
            data: faceImages 
        }); 
        //表情窗口 
        this.faceImagesWindow = Ext.create('Ext.Window', { 
            title:          this.buttonTips.faceImages.text, 
            width:          500, 
            height :        400, 
            autoShow:       true, 
            layout:         'fit', 
            items: [{ 
                itemId:         'idDataView', 
                xtype:          'dataview', 
                store:          faceImagesStore, 
                autoHeight:     true, 
                multiSelect:    true,   
                tpl: new Ext.XTemplate('<tpl for="."><div class="char-item"><img src="images/face/{name}.gif" title="{name}"></div></tpl>'), 
                overItemCls:    'char-over', 
                trackOver:      true, 
                itemSelector:   'div.char-item', 
                listeners: { 
                    itemdblclick: function(t, record, item, index, e, eOpts ){ 
                         
                        var c = '<img src="images/face/'+ record.get('name') + '.gif" title="' + record.get('name') + '">'; 
                        if(this.editor.getValue() == null || this.editor.getValue() == ""){ 
                            this.editor.setValue(c); 
                            this.editor.focus(true,true); 
                        }else{ 
                            this.editor.focus(); 
                            this.editor.insertAtCursor(c); 
                        } 
                        this.faceImagesWindow.close(); 
                    }, 
                    scope: this 
                } 
            }] 
        }); 
        this.faceImagesWindow.show(); 
    }, 
     
    doSpecialChars: function(){ 
        var specialChars = []; 
        if (this.specialChars.length) { 
            Ext.each(this.specialChars, function(c, i){ 
                specialChars[i] = ['&#' + c + ';']; 
            }, this); 
        } 
        for (i = this.charRange[0]; i < this.charRange[1]; i++) { 
            specialChars.push(['&#' + i + ';']); 
        } 
        var charStore = new Ext.data.ArrayStore({ 
            fields: ['char'], 
            data: specialChars 
        }); 
        this.charWindow = Ext.create('Ext.Window', { 
            title:          this.buttonTips.chars.text, 
            width:          436, 
            autoHeight:     true, 
            layout:         'fit', 
            items: [{ 
                itemId:         'idDataView', 
                xtype:          'dataview', 
                store:          charStore, 
                autoHeight:     true, 
                multiSelect:    true, 
                tpl: new Ext.XTemplate('<tpl for="."><div class="char-item" style="width: 20px; height: 20px; ">{char}</div></tpl><div class="x-clear"></div>'), 
                overItemCls:    'char-over', 
                trackOver:      true, 
                itemSelector:   'div.char-item', 
                listeners: { 
                    itemdblclick: function(t, i, n, e){ 
                        if(this.editor.getValue() == null || this.editor.getValue() == ""){ 
                            this.editor.setValue(i.get('char')); 
                        }else{ 
                            this.editor.focus(); 
                            this.editor.insertAtCursor(i.get('char')); 
                        } 
                        this.charWindow.close(); 
                    }, 
                    scope: this 
                } 
            }] 
        }); 
        this.charWindow.show(); 
    }, 
     
    doWordPaste: function(){ 
        this.wordPasteEnabled = !this.wordPasteEnabled; 
    }, 
     
    cleanWordPaste: function(){ 
        this.editor.suspendEvents(); 
         
        diffAt = this.findValueDiffAt(this.editor.getValue()); 
        var parts = [ 
            this.editor.getValue().substr(0, diffAt), 
            this.fixWordPaste(this.editor.getValue().substr(diffAt, (this.curLength - this.lastLength))), 
            this.editor.getValue().substr((this.curLength - this.lastLength)+diffAt, this.curLength) 
        ]; 
        this.editor.setValue(parts.join('')); 
         
        this.editor.resumeEvents();         
    }, 
     
    findValueDiffAt: function(val){ 
         
        for (i=0;i<this.curLength;i++){ 
            if (this.lastValue[i] != val[i]){ 
                return i;             
            } 
        } 
         
    }, 
 
    fixWordPaste: function(wordPaste) { 
        var removals = [/ /ig, /[/r/n]/g, /<(xml|style)[^>]*>.*?<///1>/ig, /<//?(meta|object|span)[^>]*>/ig, 
            /<//?[A-Z0-9]*:[A-Z]*[^>]*>/ig, /(lang|class|type|href|name|title|id|clear)=/"[^/"]*/"/ig, /style=(/'/'|/"/")/ig, /<![/[-].*?-*>/g,  
            /MsoNormal/g, /<//?/?xml[^>]*>/g, /<//?o:p[^>]*>/g, /<//?v:[^>]*>/g, /<//?o:[^>]*>/g, /<//?st1:[^>]*>/g, / /g,  
            /<//?SPAN[^>]*>/g, /<//?FONT[^>]*>/g, /<//?STRONG[^>]*>/g, /<//?H1[^>]*>/g, /<//?H2[^>]*>/g, /<//?H3[^>]*>/g, /<//?H4[^>]*>/g,  
            /<//?H5[^>]*>/g, /<//?H6[^>]*>/g, /<//?P[^>]*><//P>/g, /<!--(.*)-->/g, /<!--(.*)>/g, /<!(.*)-->/g, /<//?/?xml[^>]*>/g,  
            /<//?o:p[^>]*>/g, /<//?v:[^>]*>/g, /<//?o:[^>]*>/g, /<//?st1:[^>]*>/g, /style=/"[^/"]*/"/g, /style=/'[^/"]*/'/g, /lang=/"[^/"]*/"/g,  
            /lang=/'[^/"]*/'/g, /class=/"[^/"]*/"/g, /class=/'[^/"]*/'/g, /type=/"[^/"]*/"/g, /type=/'[^/"]*/'/g, /href=/'#[^/"]*/'/g,  
            /href=/"#[^/"]*/"/g, /name=/"[^/"]*/"/g, /name=/'[^/"]*/'/g, / clear=/"all/"/g, /id=/"[^/"]*/"/g, /title=/"[^/"]*/"/g,  
            /<span[^>]*>/g, /<//?span[^>]*>/g, /class=/g]; 
                     
        Ext.each(removals, function(s){ 
            wordPaste = wordPaste.replace(s, ""); 
        }); 
         
        // keep the divs in paragraphs 
        wordPaste = wordPaste.replace(/<div[^>]*>/g, "<p>"); 
        wordPaste = wordPaste.replace(/<//?div[^>]*>/g, "</p>"); 
        return wordPaste; 
         
    }, 
     
    getSelectedNode: function(){ 
        try{ 
            if (this.editor.getWin().getSelection) { 
                var currNode = this.editor.getWin().getSelection().focusNode; 
            } else if (this.editor.getDoc().getSelection) { 
                var currNode = this.editor.getDoc().getSelection().focusNode; 
            } else if (this.editor.getDoc().selection) { 
                var currNode = this.editor.getDoc().selection.createRange().parentElement(); 
            } 
        }catch(err){} 
        if(currNode){ 
            if(currNode.nodeName == "#text") currNode = currNode.parentNode; 
        } 
        return currNode; 
    }, 
     
    /**
    checkSelectionFormatBlock: function(){
        currNode = this.getSelectedNode();
        var index = -1;
        try{
            var currTag = currNode;
            var prevTagName = currNode.tagName;
            if (prevTagName) prevTagName = prevTagName.toLowerCase();
 
            while(prevTagName != "html"){
                if (prevTagName == "paragraph"){
                    index = this.listFormatBlocks.indexOf('p')
                }else{
                    index = this.listFormatBlocks.indexOf(prevTagName);
                }
                if (index >= 0) break;
                
                currTag = currTag.parentNode;
                prevTagName = currTag.tagName;
                if (prevTagName) prevTagName = prevTagName.toLowerCase();
            }
        }catch(err){}
 
        this.formatBlockSelect.dom.selectedIndex = index;
        return index;
    },
    */ 
     
    relayBtnCmd: function(btn){ 
        this.relayCmd(btn.getItemId()); 
    }, 
     
    relayCmd: function(cmd, value) { 
        Ext.defer(function() { 
            var me = this; 
            me.editor.focus(); 
            me.editor.execCmd(cmd, value); 
        }, 10, this); 
    }, 
 
    buttonTips : { 
        undo : { 
            title: 'Undo', 
            text: 'Undo the last action.', 
            cls: Ext.baseCSSPrefix + 'html-editor-tip' 
        }, 
        redo : { 
            title: 'Redo', 
            text: 'Redo the last action.', 
            cls: Ext.baseCSSPrefix + 'html-editor-tip' 
        }, 
        removehtml : { 
            title: 'Remove html', 
            text: 'Remove html from the entire text.', 
            cls: Ext.baseCSSPrefix + 'html-editor-tip' 
        }, 
        removeformat : { 
            title: 'Remove formatting', 
            text: 'Remove formatting for the selected area.', 
            cls: Ext.baseCSSPrefix + 'html-editor-tip' 
        }, 
        inserttable : { 
            title: 'Insert table', 
            text: 'Insert table at the cursor.', 
            cls: Ext.baseCSSPrefix + 'html-editor-tip' 
        }, 
        indent : { 
            title: 'Indent', 
            text: 'Indent paragraph.', 
            cls: Ext.baseCSSPrefix + 'html-editor-tip' 
        }, 
        outdent : { 
            title: 'Outdent', 
            text: 'Outdent paragraph.', 
            cls: Ext.baseCSSPrefix + 'html-editor-tip' 
        }, 
        superscript : { 
            title: 'Superscript', 
            text: 'Change font size to superscript.', 
            cls: Ext.baseCSSPrefix + 'html-editor-tip' 
        }, 
        subscript : { 
            title: 'Subscript', 
            text: 'Change font size to subscript.', 
            cls: Ext.baseCSSPrefix + 'html-editor-tip' 
        }, 
        inserthorizontalrule : { 
            title: 'Insert horizontal rule', 
            text: 'Insert horizontal rule at the cursor.', 
            cls: Ext.baseCSSPrefix + 'html-editor-tip' 
        }, 
        chars : { 
            title: 'Special chars', 
            text: 'Insert special characters.', 
            cls: Ext.baseCSSPrefix + 'html-editor-tip' 
        }, 
         
        faceImages : { 
            title: 'Face images', 
            text: 'Insert Face Images.', 
            cls: Ext.baseCSSPrefix + 'html-editor-tip' 
        }, 
         
        wordpaste : { 
            title: 'Word paste', 
            text: 'Clean the pasted text.', 
            cls: Ext.baseCSSPrefix + 'html-editor-tip' 
        }, 
        images : { 
            title: 'Images', 
            text: 'Insert images.', 
            cls: Ext.baseCSSPrefix + 'html-editor-tip' 
        }, 
        listFormatBlocks: { 
            p:          "Paragraph",  
            h1:         "Header 1",  
            h2:         "Header 2",  
            h3:         "Header 3",  
            h4:         "Header 4",  
            h5:         "Header 5",  
            h6:         "Header 6",  
            address:    "Address",  
            pre:        "Formatted" 
        } 
    } 
     
}) 
 
/**
*   This override is required to make the formatBlock plugin to work in IE and WebKit browsers.
*   The default behaviour was to insert <br> tags when Enter was pressed. We have to let the browser insert a new paragraph
*   to be able to change the format.
*/ 
if(Ext.isIE || Ext.isWebKit){ 
    Ext.override(Ext.form.field.HtmlEditor, { 
        fixKeys: function() {  
            if (Ext.isIE) { 
                return function(e){ 
                    var me = this, 
                        k = e.getKey(), 
                        doc = me.getDoc(), 
                        range, target; 
                    if (k === e.TAB) { 
                        e.stopEvent(); 
                        range = doc.selection.createRange(); 
                        if(range){ 
                            range.collapse(true); 
                            range.pasteHTML('    '); 
                            me.deferFocus(); 
                        } 
                    } 
                }; 
            } 
 
            if (Ext.isOpera) { 
                return function(e){ 
                    var me = this; 
                    if (e.getKey() === e.TAB) { 
                        e.stopEvent(); 
                        me.win.focus(); 
                        me.execCmd('InsertHTML','    '); 
                        me.deferFocus(); 
                    } 
                }; 
            } 
 
            if (Ext.isWebKit) { 
                return function(e){ 
                    var me = this, 
                        k = e.getKey(); 
                    if (k === e.TAB) { 
                        e.stopEvent(); 
                        me.execCmd('InsertText','/t'); 
                        me.deferFocus(); 
                    } 
                }; 
            } 
 
            return null;  
        }() 
         
    }) 

ux-all.css
[css]
/* Ext.ux.form.plugins.HtmlEditor */ 
.x-html-editor-tb .x-edit-removehtml, .x-menu-item img.x-edit-removehtml { 
    background-image: url("../themes/images/default/editor/tb-plugins.gif"); 
    background-position: 0 0; 

.x-html-editor-tb .x-edit-removeformat, .x-menu-item img.x-edit-removeformat { 
    background-image: url("../themes/images/default/editor/tb-plugins.gif"); 
    background-position: -16px 0; 

.x-html-editor-tb .x-edit-inserttable, .x-menu-item img.x-edit-inserttable { 
    background-image: url("../themes/images/default/editor/tb-plugins.gif"); 
    background-position: -32px 0; 

.x-html-editor-tb .x-edit-indent, .x-menu-item img.x-edit-indent { 
    background-image: url("../themes/images/default/editor/tb-plugins.gif"); 
    background-position: -48px 0; 

.x-html-editor-tb .x-edit-outdent, .x-menu-item img.x-edit-outdent { 
    background-image: url("../themes/images/default/editor/tb-plugins.gif"); 
    background-position: -64px 0; 

.x-html-editor-tb .x-edit-superscript, .x-menu-item img.x-edit-superscript { 
    background-image: url("../themes/images/default/editor/tb-plugins.gif"); 
    background-position: -80px 0; 

.x-html-editor-tb .x-edit-subscript, .x-menu-item img.x-edit-subscript { 
    background-image: url("../themes/images/default/editor/tb-plugins.gif"); 
    background-position: -96px 0; 

.x-html-editor-tb .x-edit-inserthorizontalrule, .x-menu-item img.x-edit-inserthorizontalrule { 
    background-image: url("../themes/images/default/editor/tb-plugins.gif"); 
    background-position: -112px 0; 

.x-html-editor-tb .x-edit-chars, .x-menu-item img.x-edit-chars { 
    background-image: url("../themes/images/default/editor/tb-plugins.gif"); 
    background-position: -128px 0; 

.x-html-editor-tb .x-edit-wordpaste, .x-menu-item img.x-edit-wordpaste { 
    background-image: url("../themes/images/default/editor/tb-plugins.gif"); 
    background-position: -144px 0; 

.x-html-editor-tb .x-edit-images, .x-menu-item img.x-edit-images { 
    background-image: url("../themes/images/default/editor/tb-plugins.gif"); 
    background-position: -160px 0; 

.x-html-editor-tb .x-edit-undo, .x-menu-item img.x-edit-undo { 
    background-image: url("../themes/images/default/editor/tb-plugins.gif"); 
    background-position: -176px 0; 

.x-html-editor-tb .x-edit-redo, .x-menu-item img.x-edit-redo { 
    background-image: url("../themes/images/default/editor/tb-plugins.gif"); 
    background-position: -192px 0; 

 
.char-item { 
    float: left;  
    border: 1px solid #99BBE8;  
    margin: 3px;  
    text-align: center;  
    vertical-align: middle;  
    font-size: 14px; 
    color: #15428B; 
    cursor: pointer; 

 
.char-item.x-item-selected { 
    background-color: #777; 

 
.char-over { 
    border: 1px solid #15428B; 
    background-color:#d0def0; 

使用
<script type="text/javascript" src="scripts/plugins/htmleditor/js/Ext.ux.form.plugin.HtmlEditor.js"></script>
<link rel="stylesheet" href="scripts/plugins/htmleditor/css/ux-all.css" type="text/css"></link>
[javascript] view plaincopy

    xtype: 'htmleditor', 
    name: 'bio', 
    id: 'bio', 
    plugins: [ 
        Ext.create('Ext.ux.form.plugin.HtmlEditor',{ 
            enableAll:  true 
        }) 
    ], 
    fieldLabel: 'Biography', 
    height: 200, 
    anchor: '100%' 

 

作者:caodegao