3 This file is part of Ext JS 4
5 Copyright (c) 2011 Sencha Inc
7 Contact: http://www.sencha.com/contact
9 GNU General Public License Usage
10 This file may be used under the terms of the GNU General Public License version 3.0 as published by the Free Software Foundation and appearing in the file LICENSE included in the packaging of this file. Please review the following information to ensure the GNU General Public License version 3.0 requirements will be met: http://www.gnu.org/copyleft/gpl.html.
12 If you are unsure which license is appropriate for your use, please contact the sales department at http://www.sencha.com/contact.
16 * @class Ext.form.field.HtmlEditor
17 * @extends Ext.Component
19 * Provides a lightweight HTML Editor component. Some toolbar features are not supported by Safari and will be
20 * automatically hidden when needed. These are noted in the config options where appropriate.
22 * The editor's toolbar buttons have tooltips defined in the {@link #buttonTips} property, but they are not
23 * enabled by default unless the global {@link Ext.tip.QuickTipManager} singleton is {@link Ext.tip.QuickTipManager#init initialized}.
25 * An Editor is a sensitive component that can't be used in all spots standard fields can be used. Putting an Editor within
26 * any element that has display set to 'none' can cause problems in Safari and Firefox due to their default iframe reloading bugs.
28 * {@img Ext.form.HtmlEditor/Ext.form.HtmlEditor1.png Ext.form.HtmlEditor component}
32 * {@img Ext.form.HtmlEditor/Ext.form.HtmlEditor2.png Ext.form.HtmlEditor component}
34 * // Simple example rendered with default options:
35 * Ext.tip.QuickTips.init(); // enable tooltips
36 * Ext.create('Ext.form.HtmlEditor', {
39 * renderTo: Ext.getBody()
42 * {@img Ext.form.HtmlEditor/Ext.form.HtmlEditor2.png Ext.form.HtmlEditor component}
44 * // Passed via xtype into a container and with custom options:
45 * Ext.tip.QuickTips.init(); // enable tooltips
46 * new Ext.panel.Panel({
47 * title: 'HTML Editor',
48 * renderTo: Ext.getBody(),
54 * xtype: 'htmleditor',
55 * enableColors: false,
56 * enableAlignments: false
61 Ext.define('Ext.form.field.HtmlEditor', {
62 extend:'Ext.Component',
64 labelable: 'Ext.form.Labelable',
65 field: 'Ext.form.field.Field'
67 alias: 'widget.htmleditor',
68 alternateClassName: 'Ext.form.HtmlEditor',
70 'Ext.tip.QuickTipManager',
73 'Ext.toolbar.Toolbar',
75 'Ext.layout.component.field.HtmlEditor'
79 '<div class="{toolbarWrapCls}"></div>',
80 '<textarea id="{id}" name="{name}" tabIndex="-1" class="{textareaCls}" ',
81 'style="{size}" autocomplete="off"></textarea>',
82 '<iframe name="{iframeName}" frameBorder="0" style="overflow:auto;{size}" src="{iframeSrc}"></iframe>',
90 * @cfg {Boolean} enableFormat Enable the bold, italic and underline buttons (defaults to true)
94 * @cfg {Boolean} enableFontSize Enable the increase/decrease font size buttons (defaults to true)
96 enableFontSize : true,
98 * @cfg {Boolean} enableColors Enable the fore/highlight color buttons (defaults to true)
102 * @cfg {Boolean} enableAlignments Enable the left, center, right alignment buttons (defaults to true)
104 enableAlignments : true,
106 * @cfg {Boolean} enableLists Enable the bullet and numbered list buttons. Not available in Safari. (defaults to true)
110 * @cfg {Boolean} enableSourceEdit Enable the switch to source edit button. Not available in Safari. (defaults to true)
112 enableSourceEdit : true,
114 * @cfg {Boolean} enableLinks Enable the create link button. Not available in Safari. (defaults to true)
118 * @cfg {Boolean} enableFont Enable font selection. Not available in Safari. (defaults to true)
122 * @cfg {String} createLinkText The default text for the create link prompt
124 createLinkText : 'Please enter the URL for the link:',
126 * @cfg {String} defaultLinkValue The default value for the create link prompt (defaults to http:/ /)
128 defaultLinkValue : 'http:/'+'/',
130 * @cfg {Array} fontFamilies An array of available font families
139 defaultFont: 'tahoma',
141 * @cfg {String} defaultValue A default value to be put into the editor to resolve focus issues (defaults to   (Non-breaking space) in Opera and IE6, ​ (Zero-width space) in all other browsers).
143 defaultValue: (Ext.isOpera || Ext.isIE6) ? ' ' : '​',
145 fieldBodyCls: Ext.baseCSSPrefix + 'html-editor-wrap',
147 componentLayout: 'htmleditor',
149 // private properties
152 sourceEditMode : false,
159 initComponent : function(){
165 * Fires when the editor is fully initialized (including the iframe)
166 * @param {Ext.form.field.HtmlEditor} this
171 * Fires when the editor is first receives the focus. Any insertion must wait
172 * until after this event.
173 * @param {Ext.form.field.HtmlEditor} this
178 * Fires before the textarea is updated with content from the editor iframe. Return false
179 * to cancel the sync.
180 * @param {Ext.form.field.HtmlEditor} this
181 * @param {String} html
186 * Fires before the iframe editor is updated with content from the textarea. Return false
187 * to cancel the push.
188 * @param {Ext.form.field.HtmlEditor} this
189 * @param {String} html
194 * Fires when the textarea is updated with content from the editor iframe.
195 * @param {Ext.form.field.HtmlEditor} this
196 * @param {String} html
201 * Fires when the iframe editor is updated with content from the textarea.
202 * @param {Ext.form.field.HtmlEditor} this
203 * @param {String} html
207 * @event editmodechange
208 * Fires when the editor switches edit modes
209 * @param {Ext.form.field.HtmlEditor} this
210 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
215 me.callParent(arguments);
223 * Protected method that will not generally be called directly. It
224 * is called when the editor creates its toolbar. Override this method if you need to
225 * add custom toolbar buttons.
226 * @param {Ext.form.field.HtmlEditor} editor
228 createToolbar : function(editor){
231 tipsEnabled = Ext.tip.QuickTipManager && Ext.tip.QuickTipManager.isEnabled(),
232 baseCSSPrefix = Ext.baseCSSPrefix,
233 fontSelectItem, toolbar, undef;
235 function btn(id, toggle, handler){
238 cls : baseCSSPrefix + 'btn-icon',
239 iconCls: baseCSSPrefix + 'edit-'+id,
240 enableToggle:toggle !== false,
242 handler:handler||editor.relayBtnCmd,
243 clickEvent:'mousedown',
244 tooltip: tipsEnabled ? editor.buttonTips[id] || undef : undef,
245 overflowText: editor.buttonTips[id].title || undef,
251 if (me.enableFont && !Ext.isSafari2) {
252 fontSelectItem = Ext.widget('component', {
254 '<select class="{cls}">',
256 '<option value="{[values.toLowerCase()]}" style="font-family:{.}"<tpl if="values.toLowerCase()==parent.defaultFont"> selected</tpl>>{.}</option>',
261 cls: baseCSSPrefix + 'font-select',
262 fonts: me.fontFamilies,
263 defaultFont: me.defaultFont
268 onDisable: function() {
269 var selectEl = this.selectEl;
271 selectEl.dom.disabled = true;
273 Ext.Component.superclass.onDisable.apply(this, arguments);
275 onEnable: function() {
276 var selectEl = this.selectEl;
278 selectEl.dom.disabled = false;
280 Ext.Component.superclass.onEnable.apply(this, arguments);
290 if (me.enableFormat) {
298 if (me.enableFontSize) {
301 btn('increasefontsize', false, me.adjustFont),
302 btn('decreasefontsize', false, me.adjustFont)
306 if (me.enableColors) {
310 cls: baseCSSPrefix + 'btn-icon',
311 iconCls: baseCSSPrefix + 'edit-forecolor',
312 overflowText: editor.buttonTips.forecolor.title,
313 tooltip: tipsEnabled ? editor.buttonTips.forecolor || undef : undef,
315 menu : Ext.widget('menu', {
318 xtype: 'colorpicker',
323 clickEvent: 'mousedown',
324 handler: function(cp, color) {
325 me.execCmd('forecolor', Ext.isWebKit || Ext.isIE ? '#'+color : color);
327 this.up('menu').hide();
333 cls: baseCSSPrefix + 'btn-icon',
334 iconCls: baseCSSPrefix + 'edit-backcolor',
335 overflowText: editor.buttonTips.backcolor.title,
336 tooltip: tipsEnabled ? editor.buttonTips.backcolor || undef : undef,
338 menu : Ext.widget('menu', {
341 xtype: 'colorpicker',
346 clickEvent: 'mousedown',
347 handler: function(cp, color) {
349 me.execCmd('useCSS', false);
350 me.execCmd('hilitecolor', color);
351 me.execCmd('useCSS', true);
354 me.execCmd(Ext.isOpera ? 'hilitecolor' : 'backcolor', Ext.isWebKit || Ext.isIE ? '#'+color : color);
357 this.up('menu').hide();
365 if (me.enableAlignments) {
369 btn('justifycenter'),
374 if (!Ext.isSafari2) {
375 if (me.enableLinks) {
378 btn('createlink', false, me.createLink)
382 if (me.enableLists) {
385 btn('insertorderedlist'),
386 btn('insertunorderedlist')
389 if (me.enableSourceEdit) {
392 btn('sourceedit', true, function(btn){
393 me.toggleSourceEdit(!me.sourceEditMode);
400 toolbar = Ext.widget('toolbar', {
401 renderTo: me.toolbarWrap,
402 enableOverflow: true,
406 if (fontSelectItem) {
407 me.fontSelect = fontSelectItem.selectEl;
409 me.mon(me.fontSelect, 'change', function(){
410 me.relayCmd('fontname', me.fontSelect.dom.value);
416 me.mon(toolbar.el, 'click', function(e){
420 me.toolbar = toolbar;
423 onDisable: function() {
425 this.callParent(arguments);
428 onEnable: function() {
429 this.bodyEl.unmask();
430 this.callParent(arguments);
434 * Sets the read only state of this field.
435 * @param {Boolean} readOnly Whether the field should be read only.
437 setReadOnly: function(readOnly) {
439 textareaEl = me.textareaEl,
440 iframeEl = me.iframeEl,
443 me.readOnly = readOnly;
446 textareaEl.dom.readOnly = readOnly;
449 if (me.initialized) {
450 body = me.getEditorBody();
452 // Hide the iframe while setting contentEditable so it doesn't grab focus
453 iframeEl.setDisplayed(false);
454 body.contentEditable = !readOnly;
455 iframeEl.setDisplayed(true);
457 me.setDesignMode(!readOnly);
460 body.style.cursor = readOnly ? 'default' : 'text';
462 me.disableItems(readOnly);
467 * Protected method that will not generally be called directly. It
468 * is called when the editor initializes the iframe with HTML contents. Override this method if you
469 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
471 * Note: IE8-Standards has unwanted scroller behavior, so the default meta tag forces IE7 compatibility.
472 * Also note that forcing IE7 mode works when the page is loaded normally, but if you are using IE's Web
473 * Developer Tools to manually set the document mode, that will take precedence and override what this
474 * code sets by default. This can be confusing when developing, but is not a user-facing issue.
476 getDocMarkup: function() {
478 h = me.iframeEl.getHeight() - me.iframePad * 2;
479 return Ext.String.format('<html><head><style type="text/css">body{border:0;margin:0;padding:{0}px;height:{1}px;box-sizing: border-box; -moz-box-sizing: border-box; -webkit-box-sizing: border-box;cursor:text}</style></head><body></body></html>', me.iframePad, h);
483 getEditorBody: function() {
484 var doc = this.getDoc();
485 return doc.body || doc.documentElement;
490 return (!Ext.isIE && this.iframeEl.dom.contentDocument) || this.getWin().document;
495 return Ext.isIE ? this.iframeEl.dom.contentWindow : window.frames[this.iframeEl.dom.name];
499 onRender: function() {
501 renderSelectors = me.renderSelectors;
503 Ext.applyIf(renderSelectors, me.getLabelableSelectors());
505 Ext.applyIf(renderSelectors, {
506 toolbarWrap: 'div.' + Ext.baseCSSPrefix + 'html-editor-tb',
508 textareaEl: 'textarea'
511 me.callParent(arguments);
513 me.textareaEl.dom.value = me.value || '';
515 // Start polling for when the iframe document is ready to be manipulated
516 me.monitorTask = Ext.TaskManager.start({
517 run: me.checkDesignMode,
522 me.createToolbar(me);
523 me.disableItems(true);
526 initRenderTpl: function() {
528 if (!me.hasOwnProperty('renderTpl')) {
529 me.renderTpl = me.getTpl('labelableRenderTpl');
531 return me.callParent();
534 initRenderData: function() {
535 return Ext.applyIf(this.callParent(), this.getLabelableRenderData());
538 getSubTplData: function() {
539 var cssPrefix = Ext.baseCSSPrefix;
541 toolbarWrapCls: cssPrefix + 'html-editor-tb',
542 textareaCls: cssPrefix + 'hidden',
543 iframeName: Ext.id(),
544 iframeSrc: Ext.SSL_SECURE_URL,
545 size: 'height:100px;'
549 getSubTplMarkup: function() {
550 return this.getTpl('fieldSubTpl').apply(this.getSubTplData());
553 getBodyNaturalWidth: function() {
557 initFrameDoc: function() {
561 Ext.TaskManager.stop(me.monitorTask);
564 me.win = me.getWin();
567 doc.write(me.getDocMarkup());
570 task = { // must defer to wait for browser to be ready
572 var doc = me.getDoc();
573 if (doc.body || doc.readyState === 'complete') {
574 Ext.TaskManager.stop(task);
575 me.setDesignMode(true);
576 Ext.defer(me.initEditor, 10, me);
583 Ext.TaskManager.start(task);
586 checkDesignMode: function() {
589 if (doc && (!doc.editorInitialized || me.getDesignMode() !== 'on')) {
595 * set current design mode. To enable, mode can be true or 'on', off otherwise
597 setDesignMode: function(mode) {
604 doc.designMode = (/on|true/i).test(String(mode).toLowerCase()) ?'on':'off';
609 getDesignMode: function() {
610 var doc = this.getDoc();
611 return !doc ? '' : String(doc.designMode).toLowerCase();
614 disableItems: function(disabled) {
615 this.getToolbar().items.each(function(item){
616 if(item.getItemId() !== 'sourceedit'){
617 item.setDisabled(disabled);
623 * Toggles the editor between standard and source edit mode.
624 * @param {Boolean} sourceEditMode (optional) True for source edit, false for standard
626 toggleSourceEdit: function(sourceEditMode) {
628 iframe = me.iframeEl,
629 textarea = me.textareaEl,
630 hiddenCls = Ext.baseCSSPrefix + 'hidden',
631 btn = me.getToolbar().getComponent('sourceedit');
633 if (!Ext.isBoolean(sourceEditMode)) {
634 sourceEditMode = !me.sourceEditMode;
636 me.sourceEditMode = sourceEditMode;
638 if (btn.pressed !== sourceEditMode) {
639 btn.toggle(sourceEditMode);
641 if (sourceEditMode) {
642 me.disableItems(true);
644 iframe.addCls(hiddenCls);
645 textarea.removeCls(hiddenCls);
646 textarea.dom.removeAttribute('tabIndex');
650 if (me.initialized) {
651 me.disableItems(me.readOnly);
654 iframe.removeCls(hiddenCls);
655 textarea.addCls(hiddenCls);
656 textarea.dom.setAttribute('tabIndex', -1);
659 me.fireEvent('editmodechange', me, sourceEditMode);
660 me.doComponentLayout();
663 // private used internally
664 createLink : function() {
665 var url = prompt(this.createLinkText, this.defaultLinkValue);
666 if (url && url !== 'http:/'+'/') {
667 this.relayCmd('createlink', url);
671 clearInvalid: Ext.emptyFn,
673 // docs inherit from Field
674 setValue: function(value) {
676 textarea = me.textareaEl;
677 me.mixins.field.setValue.call(me, value);
678 if (value === null || value === undefined) {
682 textarea.dom.value = value;
689 * Protected method that will not generally be called directly. If you need/want
690 * custom HTML cleanup, this is the method you should override.
691 * @param {String} html The HTML to be cleaned
692 * @return {String} The cleaned HTML
694 cleanHtml: function(html) {
696 if (Ext.isWebKit) { // strip safari nonsense
697 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
701 * Neat little hack. Strips out all the non-digit characters from the default
702 * value and compares it to the character code of the first character in the string
703 * because it can cause encoding issues when posted to the server.
705 if (html.charCodeAt(0) === this.defaultValue.replace(/\D/g, '')) {
706 html = html.substring(1);
712 * @protected method that will not generally be called directly. Syncs the contents
713 * of the editor iframe with the textarea.
715 syncValue : function(){
717 body, html, bodyStyle, match;
718 if (me.initialized) {
719 body = me.getEditorBody();
720 html = body.innerHTML;
722 bodyStyle = body.getAttribute('style'); // Safari puts text-align styles on the body element!
723 match = bodyStyle.match(/text-align:(.*?);/i);
724 if (match && match[1]) {
725 html = '<div style="' + match[0] + '">' + html + '</div>';
728 html = me.cleanHtml(html);
729 if (me.fireEvent('beforesync', me, html) !== false) {
730 me.textareaEl.dom.value = html;
731 me.fireEvent('sync', me, html);
736 //docs inherit from Field
737 getValue : function() {
740 if (!me.sourceEditMode) {
743 value = me.rendered ? me.textareaEl.dom.value : me.value;
749 * @protected method that will not generally be called directly. Pushes the value of the textarea
750 * into the iframe editor.
752 pushValue: function() {
756 v = me.textareaEl.dom.value || '';
757 if (!me.activated && v.length < 1) {
760 if (me.fireEvent('beforepush', me, v) !== false) {
761 me.getEditorBody().innerHTML = v;
763 // Gecko hack, see: https://bugzilla.mozilla.org/show_bug.cgi?id=232791#c8
764 me.setDesignMode(false); //toggle off first
765 me.setDesignMode(true);
767 me.fireEvent('push', me, v);
773 deferFocus : function(){
774 this.focus(false, true);
777 getFocusEl: function() {
780 return win && !me.sourceEditMode ? win : me.textareaEl;
784 initEditor : function(){
785 //Destroying the component during/before initEditor can cause issues.
788 dbody = me.getEditorBody(),
789 ss = me.textareaEl.getStyles('font-size', 'font-family', 'background-image', 'background-repeat', 'background-color', 'color'),
793 ss['background-attachment'] = 'fixed'; // w3c
794 dbody.bgProperties = 'fixed'; // ie
796 Ext.core.DomHelper.applyStyles(dbody, ss);
802 Ext.EventManager.removeAll(doc);
807 * We need to use createDelegate here, because when using buffer, the delayed task is added
808 * as a property to the function. When the listener is removed, the task is deleted from the function.
809 * Since onEditorEvent is shared on the prototype, if we have multiple html editors, the first time one of the editors
810 * is destroyed, it causes the fn to be deleted from the prototype, which causes errors. Essentially, we're just anonymizing the function.
812 fn = Ext.Function.bind(me.onEditorEvent, me);
813 Ext.EventManager.on(doc, {
821 // These events need to be relayed from the inner document (where they stop
822 // bubbling) up to the outer document. This has to be done at the DOM level so
823 // the event reaches listeners on elements like the document body. The effected
824 // mechanisms that depend on this bubbling behavior are listed to the right
826 fn = me.onRelayedEvent;
827 Ext.EventManager.on(doc, {
828 mousedown: fn, // menu dismisal (MenuManager) and Window onMouseDown (toFront)
829 mousemove: fn, // window resize drag detection
830 mouseup: fn, // window resize termination
831 click: fn, // not sure, but just to be safe
832 dblclick: fn, // not sure again
837 Ext.EventManager.on(doc, 'keypress', me.applyCommand, me);
840 Ext.EventManager.on(doc, 'keydown', me.fixKeys, me);
843 // We need to be sure we remove all our events from the iframe on unload or we're going to LEAK!
844 Ext.EventManager.on(window, 'unload', me.beforeDestroy, me);
845 doc.editorInitialized = true;
847 me.initialized = true;
849 me.setReadOnly(me.readOnly);
850 me.fireEvent('initialize', me);
857 beforeDestroy : function(){
859 monitorTask = me.monitorTask,
863 Ext.TaskManager.stop(monitorTask);
869 Ext.EventManager.removeAll(doc);
871 if (doc.hasOwnProperty(prop)) {
879 Ext.destroyMembers('tb', 'toolbarWrap', 'iframeEl', 'textareaEl');
885 onRelayedEvent: function (event) {
886 // relay event from the iframe's document to the document that owns the iframe...
888 var iframeEl = this.iframeEl,
889 iframeXY = iframeEl.getXY(),
890 eventXY = event.getXY();
892 // the event from the inner document has XY relative to that document's origin,
893 // so adjust it to use the origin of the iframe in the outer document:
894 event.xy = [iframeXY[0] + eventXY[0], iframeXY[1] + eventXY[1]];
896 event.injectEvent(iframeEl); // blame the iframe for the event...
898 event.xy = eventXY; // restore the original XY (just for safety)
902 onFirstFocus : function(){
906 me.disableItems(me.readOnly);
907 if (Ext.isGecko) { // prevent silly gecko errors
909 selection = me.win.getSelection();
910 if (!selection.focusNode || selection.focusNode.nodeType !== 3) {
911 range = selection.getRangeAt(0);
912 range.selectNodeContents(me.getEditorBody());
913 range.collapse(true);
917 me.execCmd('useCSS', true);
918 me.execCmd('styleWithCSS', false);
923 me.fireEvent('activate', me);
927 adjustFont: function(btn) {
928 var adjust = btn.getItemId() === 'increasefontsize' ? 1 : -1,
929 size = this.getDoc().queryCommandValue('FontSize') || '2',
930 isPxSize = Ext.isString(size) && size.indexOf('px') !== -1,
932 size = parseInt(size, 10);
935 // 1 = 10px, 2 = 13px, 3 = 16px, 4 = 18px, 5 = 24px, 6 = 32px
939 else if (size <= 13) {
942 else if (size <= 16) {
945 else if (size <= 18) {
948 else if (size <= 24) {
954 size = Ext.Number.constrain(size, 1, 6);
956 isSafari = Ext.isSafari;
957 if (isSafari) { // safari
960 size = Math.max(1, size + adjust) + (isSafari ? 'px' : 0);
962 this.execCmd('FontSize', size);
966 onEditorEvent: function(e) {
967 this.updateToolbar();
971 * Protected method that will not generally be called directly. It triggers
972 * a toolbar update by reading the markup state of the current selection in the editor.
974 updateToolbar: function() {
976 btns, doc, name, fontSelect;
987 btns = me.getToolbar().items.map;
990 if (me.enableFont && !Ext.isSafari2) {
991 name = (doc.queryCommandValue('FontName') || me.defaultFont).toLowerCase();
992 fontSelect = me.fontSelect.dom;
993 if (name !== fontSelect.value) {
994 fontSelect.value = name;
998 function updateButtons() {
999 Ext.Array.forEach(Ext.Array.toArray(arguments), function(name) {
1000 btns[name].toggle(doc.queryCommandState(name));
1003 if(me.enableFormat){
1004 updateButtons('bold', 'italic', 'underline');
1006 if(me.enableAlignments){
1007 updateButtons('justifyleft', 'justifycenter', 'justifyright');
1009 if(!Ext.isSafari2 && me.enableLists){
1010 updateButtons('insertorderedlist', 'insertunorderedlist');
1013 Ext.menu.Manager.hideAll();
1019 relayBtnCmd: function(btn) {
1020 this.relayCmd(btn.getItemId());
1024 * Executes a Midas editor command on the editor document and performs necessary focus and
1025 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
1026 * @param {String} cmd The Midas command
1027 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
1029 relayCmd: function(cmd, value) {
1030 Ext.defer(function() {
1033 me.execCmd(cmd, value);
1039 * Executes a Midas editor command directly on the editor document.
1040 * For visual commands, you should use {@link #relayCmd} instead.
1041 * <b>This should only be called after the editor is initialized.</b>
1042 * @param {String} cmd The Midas command
1043 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
1045 execCmd : function(cmd, value){
1049 doc.execCommand(cmd, false, value === undef ? null : value);
1054 applyCommand : function(e){
1057 c = e.getCharCode(), cmd;
1059 c = String.fromCharCode(c);
1082 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
1084 * @param {String} text
1086 insertAtCursor : function(text){
1093 range = me.getDoc().selection.createRange();
1095 range.pasteHTML(text);
1100 me.execCmd('InsertHTML', text);
1107 fixKeys: function() { // load time branching for fastest keydown performance
1116 range = doc.selection.createRange();
1118 range.collapse(true);
1119 range.pasteHTML(' ');
1123 else if (k === e.ENTER) {
1124 range = doc.selection.createRange();
1126 target = range.parentElement();
1127 if(!target || target.tagName.toLowerCase() !== 'li'){
1129 range.pasteHTML('<br />');
1130 range.collapse(false);
1141 if (e.getKey() === e.TAB) {
1144 me.execCmd('InsertHTML',' ');
1156 me.execCmd('InsertText','\t');
1159 else if (k === e.ENTER) {
1161 me.execCmd('InsertHtml','<br /><br />');
1167 return null; // not needed, so null
1171 * Returns the editor's toolbar. <b>This is only available after the editor has been rendered.</b>
1172 * @return {Ext.toolbar.Toolbar}
1174 getToolbar : function(){
1175 return this.toolbar;
1179 * Object collection of toolbar tooltips for the buttons in the editor. The key
1180 * is the command id associated with that button and the value is a valid QuickTips object.
1185 title: 'Bold (Ctrl+B)',
1186 text: 'Make the selected text bold.',
1187 cls: 'x-html-editor-tip'
1190 title: 'Italic (Ctrl+I)',
1191 text: 'Make the selected text italic.',
1192 cls: 'x-html-editor-tip'
1200 title: 'Bold (Ctrl+B)',
1201 text: 'Make the selected text bold.',
1202 cls: Ext.baseCSSPrefix + 'html-editor-tip'
1205 title: 'Italic (Ctrl+I)',
1206 text: 'Make the selected text italic.',
1207 cls: Ext.baseCSSPrefix + 'html-editor-tip'
1210 title: 'Underline (Ctrl+U)',
1211 text: 'Underline the selected text.',
1212 cls: Ext.baseCSSPrefix + 'html-editor-tip'
1214 increasefontsize : {
1216 text: 'Increase the font size.',
1217 cls: Ext.baseCSSPrefix + 'html-editor-tip'
1219 decreasefontsize : {
1220 title: 'Shrink Text',
1221 text: 'Decrease the font size.',
1222 cls: Ext.baseCSSPrefix + 'html-editor-tip'
1225 title: 'Text Highlight Color',
1226 text: 'Change the background color of the selected text.',
1227 cls: Ext.baseCSSPrefix + 'html-editor-tip'
1230 title: 'Font Color',
1231 text: 'Change the color of the selected text.',
1232 cls: Ext.baseCSSPrefix + 'html-editor-tip'
1235 title: 'Align Text Left',
1236 text: 'Align text to the left.',
1237 cls: Ext.baseCSSPrefix + 'html-editor-tip'
1240 title: 'Center Text',
1241 text: 'Center text in the editor.',
1242 cls: Ext.baseCSSPrefix + 'html-editor-tip'
1245 title: 'Align Text Right',
1246 text: 'Align text to the right.',
1247 cls: Ext.baseCSSPrefix + 'html-editor-tip'
1249 insertunorderedlist : {
1250 title: 'Bullet List',
1251 text: 'Start a bulleted list.',
1252 cls: Ext.baseCSSPrefix + 'html-editor-tip'
1254 insertorderedlist : {
1255 title: 'Numbered List',
1256 text: 'Start a numbered list.',
1257 cls: Ext.baseCSSPrefix + 'html-editor-tip'
1261 text: 'Make the selected text a hyperlink.',
1262 cls: Ext.baseCSSPrefix + 'html-editor-tip'
1265 title: 'Source Edit',
1266 text: 'Switch to source editing mode.',
1267 cls: Ext.baseCSSPrefix + 'html-editor-tip'
1271 // hide stuff that is not compatible
1289 * @cfg {String} fieldCls @hide
1292 * @cfg {String} focusCls @hide
1295 * @cfg {String} autoCreate @hide
1298 * @cfg {String} inputType @hide
1301 * @cfg {String} invalidCls @hide
1304 * @cfg {String} invalidText @hide
1307 * @cfg {String} msgFx @hide
1310 * @cfg {Boolean} allowDomMove @hide
1313 * @cfg {String} applyTo @hide
1316 * @cfg {String} readOnly @hide
1319 * @cfg {String} tabIndex @hide