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 * Provides a lightweight HTML Editor component. Some toolbar features are not supported by Safari and will be
17 * automatically hidden when needed. These are noted in the config options where appropriate.
19 * The editor's toolbar buttons have tooltips defined in the {@link #buttonTips} property, but they are not
20 * enabled by default unless the global {@link Ext.tip.QuickTipManager} singleton is
21 * {@link Ext.tip.QuickTipManager#init initialized}.
23 * An Editor is a sensitive component that can't be used in all spots standard fields can be used. Putting an
24 * Editor within any element that has display set to 'none' can cause problems in Safari and Firefox due to their
25 * default iframe reloading bugs.
29 * Simple example rendered with default options:
32 * Ext.tip.QuickTipManager.init(); // enable tooltips
33 * Ext.create('Ext.form.HtmlEditor', {
36 * renderTo: Ext.getBody()
39 * Passed via xtype into a container and with custom options:
42 * Ext.tip.QuickTipManager.init(); // enable tooltips
43 * new Ext.panel.Panel({
44 * title: 'HTML Editor',
45 * renderTo: Ext.getBody(),
51 * xtype: 'htmleditor',
52 * enableColors: false,
53 * enableAlignments: false
57 Ext.define('Ext.form.field.HtmlEditor', {
58 extend:'Ext.Component',
60 labelable: 'Ext.form.Labelable',
61 field: 'Ext.form.field.Field'
63 alias: 'widget.htmleditor',
64 alternateClassName: 'Ext.form.HtmlEditor',
66 'Ext.tip.QuickTipManager',
69 'Ext.toolbar.Toolbar',
71 'Ext.layout.component.field.HtmlEditor'
75 '<div id="{cmpId}-toolbarWrap" class="{toolbarWrapCls}"></div>',
76 '<textarea id="{cmpId}-textareaEl" name="{name}" tabIndex="-1" class="{textareaCls}" ',
77 'style="{size}" autocomplete="off"></textarea>',
78 '<iframe id="{cmpId}-iframeEl" name="{iframeName}" frameBorder="0" style="overflow:auto;{size}" src="{iframeSrc}"></iframe>',
86 * @cfg {Boolean} enableFormat
87 * Enable the bold, italic and underline buttons
91 * @cfg {Boolean} enableFontSize
92 * Enable the increase/decrease font size buttons
94 enableFontSize : true,
96 * @cfg {Boolean} enableColors
97 * Enable the fore/highlight color buttons
101 * @cfg {Boolean} enableAlignments
102 * Enable the left, center, right alignment buttons
104 enableAlignments : true,
106 * @cfg {Boolean} enableLists
107 * Enable the bullet and numbered list buttons. Not available in Safari.
111 * @cfg {Boolean} enableSourceEdit
112 * Enable the switch to source edit button. Not available in Safari.
114 enableSourceEdit : true,
116 * @cfg {Boolean} enableLinks
117 * Enable the create link button. Not available in Safari.
121 * @cfg {Boolean} enableFont
122 * Enable font selection. Not available in Safari.
126 * @cfg {String} createLinkText
127 * The default text for the create link prompt
129 createLinkText : 'Please enter the URL for the link:',
131 * @cfg {String} [defaultLinkValue='http://']
132 * The default value for the create link prompt
134 defaultLinkValue : 'http:/'+'/',
136 * @cfg {String[]} fontFamilies
137 * An array of available font families
146 defaultFont: 'tahoma',
148 * @cfg {String} defaultValue
149 * A default value to be put into the editor to resolve focus issues (defaults to (Non-breaking space) in Opera
150 * and IE6, (Zero-width space) in all other browsers).
152 defaultValue: (Ext.isOpera || Ext.isIE6) ? ' ' : '​',
154 fieldBodyCls: Ext.baseCSSPrefix + 'html-editor-wrap',
156 componentLayout: 'htmleditor',
158 // private properties
161 sourceEditMode : false,
168 initComponent : function(){
174 * Fires when the editor is fully initialized (including the iframe)
175 * @param {Ext.form.field.HtmlEditor} this
180 * Fires when the editor is first receives the focus. Any insertion must wait until after this event.
181 * @param {Ext.form.field.HtmlEditor} this
186 * Fires before the textarea is updated with content from the editor iframe. Return false to cancel the
188 * @param {Ext.form.field.HtmlEditor} this
189 * @param {String} html
194 * Fires before the iframe editor is updated with content from the textarea. Return false to cancel the
196 * @param {Ext.form.field.HtmlEditor} this
197 * @param {String} html
202 * Fires when the textarea is updated with content from the editor iframe.
203 * @param {Ext.form.field.HtmlEditor} this
204 * @param {String} html
209 * Fires when the iframe editor is updated with content from the textarea.
210 * @param {Ext.form.field.HtmlEditor} this
211 * @param {String} html
215 * @event editmodechange
216 * Fires when the editor switches edit modes
217 * @param {Ext.form.field.HtmlEditor} this
218 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
223 me.callParent(arguments);
231 * Called when the editor creates its toolbar. Override this method if you need to
232 * add custom toolbar buttons.
233 * @param {Ext.form.field.HtmlEditor} editor
236 createToolbar : function(editor){
239 tipsEnabled = Ext.tip.QuickTipManager && Ext.tip.QuickTipManager.isEnabled(),
240 baseCSSPrefix = Ext.baseCSSPrefix,
241 fontSelectItem, toolbar, undef;
243 function btn(id, toggle, handler){
246 cls : baseCSSPrefix + 'btn-icon',
247 iconCls: baseCSSPrefix + 'edit-'+id,
248 enableToggle:toggle !== false,
250 handler:handler||editor.relayBtnCmd,
251 clickEvent:'mousedown',
252 tooltip: tipsEnabled ? editor.buttonTips[id] || undef : undef,
253 overflowText: editor.buttonTips[id].title || undef,
259 if (me.enableFont && !Ext.isSafari2) {
260 fontSelectItem = Ext.widget('component', {
262 '<select id="{id}-selectEl" class="{cls}">',
264 '<option value="{[values.toLowerCase()]}" style="font-family:{.}"<tpl if="values.toLowerCase()==parent.defaultFont"> selected</tpl>>{.}</option>',
269 cls: baseCSSPrefix + 'font-select',
270 fonts: me.fontFamilies,
271 defaultFont: me.defaultFont
273 childEls: ['selectEl'],
274 onDisable: function() {
275 var selectEl = this.selectEl;
277 selectEl.dom.disabled = true;
279 Ext.Component.superclass.onDisable.apply(this, arguments);
281 onEnable: function() {
282 var selectEl = this.selectEl;
284 selectEl.dom.disabled = false;
286 Ext.Component.superclass.onEnable.apply(this, arguments);
296 if (me.enableFormat) {
304 if (me.enableFontSize) {
307 btn('increasefontsize', false, me.adjustFont),
308 btn('decreasefontsize', false, me.adjustFont)
312 if (me.enableColors) {
316 cls: baseCSSPrefix + 'btn-icon',
317 iconCls: baseCSSPrefix + 'edit-forecolor',
318 overflowText: editor.buttonTips.forecolor.title,
319 tooltip: tipsEnabled ? editor.buttonTips.forecolor || undef : undef,
321 menu : Ext.widget('menu', {
324 xtype: 'colorpicker',
329 clickEvent: 'mousedown',
330 handler: function(cp, color) {
331 me.execCmd('forecolor', Ext.isWebKit || Ext.isIE ? '#'+color : color);
333 this.up('menu').hide();
339 cls: baseCSSPrefix + 'btn-icon',
340 iconCls: baseCSSPrefix + 'edit-backcolor',
341 overflowText: editor.buttonTips.backcolor.title,
342 tooltip: tipsEnabled ? editor.buttonTips.backcolor || undef : undef,
344 menu : Ext.widget('menu', {
347 xtype: 'colorpicker',
352 clickEvent: 'mousedown',
353 handler: function(cp, color) {
355 me.execCmd('useCSS', false);
356 me.execCmd('hilitecolor', color);
357 me.execCmd('useCSS', true);
360 me.execCmd(Ext.isOpera ? 'hilitecolor' : 'backcolor', Ext.isWebKit || Ext.isIE ? '#'+color : color);
363 this.up('menu').hide();
371 if (me.enableAlignments) {
375 btn('justifycenter'),
380 if (!Ext.isSafari2) {
381 if (me.enableLinks) {
384 btn('createlink', false, me.createLink)
388 if (me.enableLists) {
391 btn('insertorderedlist'),
392 btn('insertunorderedlist')
395 if (me.enableSourceEdit) {
398 btn('sourceedit', true, function(btn){
399 me.toggleSourceEdit(!me.sourceEditMode);
406 toolbar = Ext.widget('toolbar', {
407 renderTo: me.toolbarWrap,
408 enableOverflow: true,
412 if (fontSelectItem) {
413 me.fontSelect = fontSelectItem.selectEl;
415 me.mon(me.fontSelect, 'change', function(){
416 me.relayCmd('fontname', me.fontSelect.dom.value);
422 me.mon(toolbar.el, 'click', function(e){
426 me.toolbar = toolbar;
429 onDisable: function() {
431 this.callParent(arguments);
434 onEnable: function() {
435 this.bodyEl.unmask();
436 this.callParent(arguments);
440 * Sets the read only state of this field.
441 * @param {Boolean} readOnly Whether the field should be read only.
443 setReadOnly: function(readOnly) {
445 textareaEl = me.textareaEl,
446 iframeEl = me.iframeEl,
449 me.readOnly = readOnly;
452 textareaEl.dom.readOnly = readOnly;
455 if (me.initialized) {
456 body = me.getEditorBody();
458 // Hide the iframe while setting contentEditable so it doesn't grab focus
459 iframeEl.setDisplayed(false);
460 body.contentEditable = !readOnly;
461 iframeEl.setDisplayed(true);
463 me.setDesignMode(!readOnly);
466 body.style.cursor = readOnly ? 'default' : 'text';
468 me.disableItems(readOnly);
473 * Called when the editor initializes the iframe with HTML contents. Override this method if you
474 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
476 * **Note:** IE8-Standards has unwanted scroller behavior, so the default meta tag forces IE7 compatibility.
477 * Also note that forcing IE7 mode works when the page is loaded normally, but if you are using IE's Web
478 * Developer Tools to manually set the document mode, that will take precedence and override what this
479 * code sets by default. This can be confusing when developing, but is not a user-facing issue.
482 getDocMarkup: function() {
484 h = me.iframeEl.getHeight() - me.iframePad * 2;
485 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);
489 getEditorBody: function() {
490 var doc = this.getDoc();
491 return doc.body || doc.documentElement;
496 return (!Ext.isIE && this.iframeEl.dom.contentDocument) || this.getWin().document;
501 return Ext.isIE ? this.iframeEl.dom.contentWindow : window.frames[this.iframeEl.dom.name];
505 onRender: function() {
508 me.onLabelableRender();
510 me.addChildEls('toolbarWrap', 'iframeEl', 'textareaEl');
512 me.callParent(arguments);
514 me.textareaEl.dom.value = me.value || '';
516 // Start polling for when the iframe document is ready to be manipulated
517 me.monitorTask = Ext.TaskManager.start({
518 run: me.checkDesignMode,
523 me.createToolbar(me);
524 me.disableItems(true);
527 initRenderTpl: function() {
529 if (!me.hasOwnProperty('renderTpl')) {
530 me.renderTpl = me.getTpl('labelableRenderTpl');
532 return me.callParent();
535 initRenderData: function() {
536 return Ext.applyIf(this.callParent(), this.getLabelableRenderData());
539 getSubTplData: function() {
540 var cssPrefix = Ext.baseCSSPrefix;
543 id: this.getInputId(),
544 toolbarWrapCls: cssPrefix + 'html-editor-tb',
545 textareaCls: cssPrefix + 'hidden',
546 iframeName: Ext.id(),
547 iframeSrc: Ext.SSL_SECURE_URL,
548 size: 'height:100px;'
552 getSubTplMarkup: function() {
553 var data = this.getSubTplData();
554 return this.getTpl('fieldSubTpl').apply(data);
557 getBodyNaturalWidth: function() {
561 initFrameDoc: function() {
565 Ext.TaskManager.stop(me.monitorTask);
568 me.win = me.getWin();
571 doc.write(me.getDocMarkup());
574 task = { // must defer to wait for browser to be ready
576 var doc = me.getDoc();
577 if (doc.body || doc.readyState === 'complete') {
578 Ext.TaskManager.stop(task);
579 me.setDesignMode(true);
580 Ext.defer(me.initEditor, 10, me);
587 Ext.TaskManager.start(task);
590 checkDesignMode: function() {
593 if (doc && (!doc.editorInitialized || me.getDesignMode() !== 'on')) {
600 * Sets current design mode. To enable, mode can be true or 'on', off otherwise
602 setDesignMode: function(mode) {
609 doc.designMode = (/on|true/i).test(String(mode).toLowerCase()) ?'on':'off';
614 getDesignMode: function() {
615 var doc = this.getDoc();
616 return !doc ? '' : String(doc.designMode).toLowerCase();
619 disableItems: function(disabled) {
620 this.getToolbar().items.each(function(item){
621 if(item.getItemId() !== 'sourceedit'){
622 item.setDisabled(disabled);
628 * Toggles the editor between standard and source edit mode.
629 * @param {Boolean} sourceEditMode (optional) True for source edit, false for standard
631 toggleSourceEdit: function(sourceEditMode) {
633 iframe = me.iframeEl,
634 textarea = me.textareaEl,
635 hiddenCls = Ext.baseCSSPrefix + 'hidden',
636 btn = me.getToolbar().getComponent('sourceedit');
638 if (!Ext.isBoolean(sourceEditMode)) {
639 sourceEditMode = !me.sourceEditMode;
641 me.sourceEditMode = sourceEditMode;
643 if (btn.pressed !== sourceEditMode) {
644 btn.toggle(sourceEditMode);
646 if (sourceEditMode) {
647 me.disableItems(true);
649 iframe.addCls(hiddenCls);
650 textarea.removeCls(hiddenCls);
651 textarea.dom.removeAttribute('tabIndex');
655 if (me.initialized) {
656 me.disableItems(me.readOnly);
659 iframe.removeCls(hiddenCls);
660 textarea.addCls(hiddenCls);
661 textarea.dom.setAttribute('tabIndex', -1);
664 me.fireEvent('editmodechange', me, sourceEditMode);
665 me.doComponentLayout();
668 // private used internally
669 createLink : function() {
670 var url = prompt(this.createLinkText, this.defaultLinkValue);
671 if (url && url !== 'http:/'+'/') {
672 this.relayCmd('createlink', url);
676 clearInvalid: Ext.emptyFn,
678 // docs inherit from Field
679 setValue: function(value) {
681 textarea = me.textareaEl;
682 me.mixins.field.setValue.call(me, value);
683 if (value === null || value === undefined) {
687 textarea.dom.value = value;
694 * If you need/want custom HTML cleanup, this is the method you should override.
695 * @param {String} html The HTML to be cleaned
696 * @return {String} The cleaned HTML
699 cleanHtml: function(html) {
701 if (Ext.isWebKit) { // strip safari nonsense
702 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
706 * Neat little hack. Strips out all the non-digit characters from the default
707 * value and compares it to the character code of the first character in the string
708 * because it can cause encoding issues when posted to the server.
710 if (html.charCodeAt(0) === this.defaultValue.replace(/\D/g, '')) {
711 html = html.substring(1);
717 * Syncs the contents of the editor iframe with the textarea.
720 syncValue : function(){
722 body, html, bodyStyle, match;
723 if (me.initialized) {
724 body = me.getEditorBody();
725 html = body.innerHTML;
727 bodyStyle = body.getAttribute('style'); // Safari puts text-align styles on the body element!
728 match = bodyStyle.match(/text-align:(.*?);/i);
729 if (match && match[1]) {
730 html = '<div style="' + match[0] + '">' + html + '</div>';
733 html = me.cleanHtml(html);
734 if (me.fireEvent('beforesync', me, html) !== false) {
735 me.textareaEl.dom.value = html;
736 me.fireEvent('sync', me, html);
741 //docs inherit from Field
742 getValue : function() {
745 if (!me.sourceEditMode) {
748 value = me.rendered ? me.textareaEl.dom.value : me.value;
754 * Pushes the value of the textarea into the iframe editor.
757 pushValue: function() {
761 v = me.textareaEl.dom.value || '';
762 if (!me.activated && v.length < 1) {
765 if (me.fireEvent('beforepush', me, v) !== false) {
766 me.getEditorBody().innerHTML = v;
768 // Gecko hack, see: https://bugzilla.mozilla.org/show_bug.cgi?id=232791#c8
769 me.setDesignMode(false); //toggle off first
770 me.setDesignMode(true);
772 me.fireEvent('push', me, v);
778 deferFocus : function(){
779 this.focus(false, true);
782 getFocusEl: function() {
785 return win && !me.sourceEditMode ? win : me.textareaEl;
789 initEditor : function(){
790 //Destroying the component during/before initEditor can cause issues.
793 dbody = me.getEditorBody(),
794 ss = me.textareaEl.getStyles('font-size', 'font-family', 'background-image', 'background-repeat', 'background-color', 'color'),
798 ss['background-attachment'] = 'fixed'; // w3c
799 dbody.bgProperties = 'fixed'; // ie
801 Ext.DomHelper.applyStyles(dbody, ss);
807 Ext.EventManager.removeAll(doc);
812 * We need to use createDelegate here, because when using buffer, the delayed task is added
813 * as a property to the function. When the listener is removed, the task is deleted from the function.
814 * Since onEditorEvent is shared on the prototype, if we have multiple html editors, the first time one of the editors
815 * is destroyed, it causes the fn to be deleted from the prototype, which causes errors. Essentially, we're just anonymizing the function.
817 fn = Ext.Function.bind(me.onEditorEvent, me);
818 Ext.EventManager.on(doc, {
826 // These events need to be relayed from the inner document (where they stop
827 // bubbling) up to the outer document. This has to be done at the DOM level so
828 // the event reaches listeners on elements like the document body. The effected
829 // mechanisms that depend on this bubbling behavior are listed to the right
831 fn = me.onRelayedEvent;
832 Ext.EventManager.on(doc, {
833 mousedown: fn, // menu dismisal (MenuManager) and Window onMouseDown (toFront)
834 mousemove: fn, // window resize drag detection
835 mouseup: fn, // window resize termination
836 click: fn, // not sure, but just to be safe
837 dblclick: fn, // not sure again
842 Ext.EventManager.on(doc, 'keypress', me.applyCommand, me);
845 Ext.EventManager.on(doc, 'keydown', me.fixKeys, me);
848 // We need to be sure we remove all our events from the iframe on unload or we're going to LEAK!
849 Ext.EventManager.on(window, 'unload', me.beforeDestroy, me);
850 doc.editorInitialized = true;
852 me.initialized = true;
854 me.setReadOnly(me.readOnly);
855 me.fireEvent('initialize', me);
862 beforeDestroy : function(){
864 monitorTask = me.monitorTask,
868 Ext.TaskManager.stop(monitorTask);
874 Ext.EventManager.removeAll(doc);
876 if (doc.hasOwnProperty(prop)) {
884 Ext.destroyMembers(me, 'tb', 'toolbarWrap', 'iframeEl', 'textareaEl');
890 onRelayedEvent: function (event) {
891 // relay event from the iframe's document to the document that owns the iframe...
893 var iframeEl = this.iframeEl,
894 iframeXY = iframeEl.getXY(),
895 eventXY = event.getXY();
897 // the event from the inner document has XY relative to that document's origin,
898 // so adjust it to use the origin of the iframe in the outer document:
899 event.xy = [iframeXY[0] + eventXY[0], iframeXY[1] + eventXY[1]];
901 event.injectEvent(iframeEl); // blame the iframe for the event...
903 event.xy = eventXY; // restore the original XY (just for safety)
907 onFirstFocus : function(){
911 me.disableItems(me.readOnly);
912 if (Ext.isGecko) { // prevent silly gecko errors
914 selection = me.win.getSelection();
915 if (!selection.focusNode || selection.focusNode.nodeType !== 3) {
916 range = selection.getRangeAt(0);
917 range.selectNodeContents(me.getEditorBody());
918 range.collapse(true);
922 me.execCmd('useCSS', true);
923 me.execCmd('styleWithCSS', false);
928 me.fireEvent('activate', me);
932 adjustFont: function(btn) {
933 var adjust = btn.getItemId() === 'increasefontsize' ? 1 : -1,
934 size = this.getDoc().queryCommandValue('FontSize') || '2',
935 isPxSize = Ext.isString(size) && size.indexOf('px') !== -1,
937 size = parseInt(size, 10);
940 // 1 = 10px, 2 = 13px, 3 = 16px, 4 = 18px, 5 = 24px, 6 = 32px
944 else if (size <= 13) {
947 else if (size <= 16) {
950 else if (size <= 18) {
953 else if (size <= 24) {
959 size = Ext.Number.constrain(size, 1, 6);
961 isSafari = Ext.isSafari;
962 if (isSafari) { // safari
965 size = Math.max(1, size + adjust) + (isSafari ? 'px' : 0);
967 this.execCmd('FontSize', size);
971 onEditorEvent: function(e) {
972 this.updateToolbar();
976 * Triggers a toolbar update by reading the markup state of the current selection in the editor.
979 updateToolbar: function() {
981 btns, doc, name, fontSelect;
992 btns = me.getToolbar().items.map;
995 if (me.enableFont && !Ext.isSafari2) {
996 name = (doc.queryCommandValue('FontName') || me.defaultFont).toLowerCase();
997 fontSelect = me.fontSelect.dom;
998 if (name !== fontSelect.value) {
999 fontSelect.value = name;
1003 function updateButtons() {
1004 Ext.Array.forEach(Ext.Array.toArray(arguments), function(name) {
1005 btns[name].toggle(doc.queryCommandState(name));
1008 if(me.enableFormat){
1009 updateButtons('bold', 'italic', 'underline');
1011 if(me.enableAlignments){
1012 updateButtons('justifyleft', 'justifycenter', 'justifyright');
1014 if(!Ext.isSafari2 && me.enableLists){
1015 updateButtons('insertorderedlist', 'insertunorderedlist');
1018 Ext.menu.Manager.hideAll();
1024 relayBtnCmd: function(btn) {
1025 this.relayCmd(btn.getItemId());
1029 * Executes a Midas editor command on the editor document and performs necessary focus and toolbar updates.
1030 * **This should only be called after the editor is initialized.**
1031 * @param {String} cmd The Midas command
1032 * @param {String/Boolean} [value=null] The value to pass to the command
1034 relayCmd: function(cmd, value) {
1035 Ext.defer(function() {
1038 me.execCmd(cmd, value);
1044 * Executes a Midas editor command directly on the editor document. For visual commands, you should use
1045 * {@link #relayCmd} instead. **This should only be called after the editor is initialized.**
1046 * @param {String} cmd The Midas command
1047 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
1049 execCmd : function(cmd, value){
1053 doc.execCommand(cmd, false, value === undef ? null : value);
1058 applyCommand : function(e){
1061 c = e.getCharCode(), cmd;
1063 c = String.fromCharCode(c);
1086 * Inserts the passed text at the current cursor position.
1087 * Note: the editor must be initialized and activated to insert text.
1088 * @param {String} text
1090 insertAtCursor : function(text){
1097 range = me.getDoc().selection.createRange();
1099 range.pasteHTML(text);
1104 me.execCmd('InsertHTML', text);
1111 fixKeys: function() { // load time branching for fastest keydown performance
1120 range = doc.selection.createRange();
1122 range.collapse(true);
1123 range.pasteHTML(' ');
1127 else if (k === e.ENTER) {
1128 range = doc.selection.createRange();
1130 target = range.parentElement();
1131 if(!target || target.tagName.toLowerCase() !== 'li'){
1133 range.pasteHTML('<br />');
1134 range.collapse(false);
1145 if (e.getKey() === e.TAB) {
1148 me.execCmd('InsertHTML',' ');
1160 me.execCmd('InsertText','\t');
1163 else if (k === e.ENTER) {
1165 me.execCmd('InsertHtml','<br /><br />');
1171 return null; // not needed, so null
1175 * Returns the editor's toolbar. **This is only available after the editor has been rendered.**
1176 * @return {Ext.toolbar.Toolbar}
1178 getToolbar : function(){
1179 return this.toolbar;
1183 * @property {Object} buttonTips
1184 * Object collection of toolbar tooltips for the buttons in the editor. The key is the command id associated with
1185 * that button and the value is a valid QuickTips object. For example:
1189 * title: 'Bold (Ctrl+B)',
1190 * text: 'Make the selected text bold.',
1191 * cls: 'x-html-editor-tip'
1194 * title: 'Italic (Ctrl+I)',
1195 * text: 'Make the selected text italic.',
1196 * cls: 'x-html-editor-tip'
1202 title: 'Bold (Ctrl+B)',
1203 text: 'Make the selected text bold.',
1204 cls: Ext.baseCSSPrefix + 'html-editor-tip'
1207 title: 'Italic (Ctrl+I)',
1208 text: 'Make the selected text italic.',
1209 cls: Ext.baseCSSPrefix + 'html-editor-tip'
1212 title: 'Underline (Ctrl+U)',
1213 text: 'Underline the selected text.',
1214 cls: Ext.baseCSSPrefix + 'html-editor-tip'
1216 increasefontsize : {
1218 text: 'Increase the font size.',
1219 cls: Ext.baseCSSPrefix + 'html-editor-tip'
1221 decreasefontsize : {
1222 title: 'Shrink Text',
1223 text: 'Decrease the font size.',
1224 cls: Ext.baseCSSPrefix + 'html-editor-tip'
1227 title: 'Text Highlight Color',
1228 text: 'Change the background color of the selected text.',
1229 cls: Ext.baseCSSPrefix + 'html-editor-tip'
1232 title: 'Font Color',
1233 text: 'Change the color of the selected text.',
1234 cls: Ext.baseCSSPrefix + 'html-editor-tip'
1237 title: 'Align Text Left',
1238 text: 'Align text to the left.',
1239 cls: Ext.baseCSSPrefix + 'html-editor-tip'
1242 title: 'Center Text',
1243 text: 'Center text in the editor.',
1244 cls: Ext.baseCSSPrefix + 'html-editor-tip'
1247 title: 'Align Text Right',
1248 text: 'Align text to the right.',
1249 cls: Ext.baseCSSPrefix + 'html-editor-tip'
1251 insertunorderedlist : {
1252 title: 'Bullet List',
1253 text: 'Start a bulleted list.',
1254 cls: Ext.baseCSSPrefix + 'html-editor-tip'
1256 insertorderedlist : {
1257 title: 'Numbered List',
1258 text: 'Start a numbered list.',
1259 cls: Ext.baseCSSPrefix + 'html-editor-tip'
1263 text: 'Make the selected text a hyperlink.',
1264 cls: Ext.baseCSSPrefix + 'html-editor-tip'
1267 title: 'Source Edit',
1268 text: 'Switch to source editing mode.',
1269 cls: Ext.baseCSSPrefix + 'html-editor-tip'
1273 // hide stuff that is not compatible
1291 * @cfg {String} fieldCls @hide
1294 * @cfg {String} focusCls @hide
1297 * @cfg {String} autoCreate @hide
1300 * @cfg {String} inputType @hide
1303 * @cfg {String} invalidCls @hide
1306 * @cfg {String} invalidText @hide
1309 * @cfg {String} msgFx @hide
1312 * @cfg {Boolean} allowDomMove @hide
1315 * @cfg {String} applyTo @hide
1318 * @cfg {String} readOnly @hide
1321 * @cfg {String} tabIndex @hide