4 <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
5 <title>The source code</title>
6 <link href="../prettify/prettify.css" type="text/css" rel="stylesheet" />
7 <script type="text/javascript" src="../prettify/prettify.js"></script>
8 <style type="text/css">
9 .highlight { display: block; background-color: #ddd; }
11 <script type="text/javascript">
12 function highlight() {
13 document.getElementById(location.hash.replace(/#/, "")).className = "highlight";
17 <body onload="prettyPrint(); highlight();">
18 <pre class="prettyprint lang-js"><span id='Ext-form-field-HtmlEditor-method-constructor'><span id='Ext-form-field-HtmlEditor'>/**
19 </span></span> * @class Ext.form.field.HtmlEditor
20 * @extends Ext.Component
22 * Provides a lightweight HTML Editor component. Some toolbar features are not supported by Safari and will be
23 * automatically hidden when needed. These are noted in the config options where appropriate.
25 * The editor's toolbar buttons have tooltips defined in the {@link #buttonTips} property, but they are not
26 * enabled by default unless the global {@link Ext.tip.QuickTipManager} singleton is {@link Ext.tip.QuickTipManager#init initialized}.
28 * An Editor is a sensitive component that can't be used in all spots standard fields can be used. Putting an Editor within
29 * any element that has display set to 'none' can cause problems in Safari and Firefox due to their default iframe reloading bugs.
31 * {@img Ext.form.HtmlEditor/Ext.form.HtmlEditor1.png Ext.form.HtmlEditor component}
35 * {@img Ext.form.HtmlEditor/Ext.form.HtmlEditor2.png Ext.form.HtmlEditor component}
37 * // Simple example rendered with default options:
38 * Ext.tip.QuickTips.init(); // enable tooltips
39 * Ext.create('Ext.form.HtmlEditor', {
42 * renderTo: Ext.getBody()
45 * {@img Ext.form.HtmlEditor/Ext.form.HtmlEditor2.png Ext.form.HtmlEditor component}
47 * // Passed via xtype into a container and with custom options:
48 * Ext.tip.QuickTips.init(); // enable tooltips
49 * new Ext.panel.Panel({
50 * title: 'HTML Editor',
51 * renderTo: Ext.getBody(),
57 * xtype: 'htmleditor',
58 * enableColors: false,
59 * enableAlignments: false
64 * Create a new HtmlEditor
65 * @param {Object} config
68 Ext.define('Ext.form.field.HtmlEditor', {
69 extend:'Ext.Component',
71 labelable: 'Ext.form.Labelable',
72 field: 'Ext.form.field.Field'
74 alias: 'widget.htmleditor',
75 alternateClassName: 'Ext.form.HtmlEditor',
77 'Ext.tip.QuickTipManager',
80 'Ext.toolbar.Toolbar',
82 'Ext.layout.component.field.HtmlEditor'
86 '<div class="{toolbarWrapCls}"></div>',
87 '<textarea id="{id}" name="{name}" tabIndex="-1" class="{textareaCls}" ',
88 'style="{size}" autocomplete="off"></textarea>',
89 '<iframe name="{iframeName}" frameBorder="0" style="overflow:auto;{size}" src="{iframeSrc}"></iframe>',
96 <span id='Ext-form-field-HtmlEditor-cfg-enableFormat'> /**
97 </span> * @cfg {Boolean} enableFormat Enable the bold, italic and underline buttons (defaults to true)
100 <span id='Ext-form-field-HtmlEditor-cfg-enableFontSize'> /**
101 </span> * @cfg {Boolean} enableFontSize Enable the increase/decrease font size buttons (defaults to true)
103 enableFontSize : true,
104 <span id='Ext-form-field-HtmlEditor-cfg-enableColors'> /**
105 </span> * @cfg {Boolean} enableColors Enable the fore/highlight color buttons (defaults to true)
108 <span id='Ext-form-field-HtmlEditor-cfg-enableAlignments'> /**
109 </span> * @cfg {Boolean} enableAlignments Enable the left, center, right alignment buttons (defaults to true)
111 enableAlignments : true,
112 <span id='Ext-form-field-HtmlEditor-cfg-enableLists'> /**
113 </span> * @cfg {Boolean} enableLists Enable the bullet and numbered list buttons. Not available in Safari. (defaults to true)
116 <span id='Ext-form-field-HtmlEditor-cfg-enableSourceEdit'> /**
117 </span> * @cfg {Boolean} enableSourceEdit Enable the switch to source edit button. Not available in Safari. (defaults to true)
119 enableSourceEdit : true,
120 <span id='Ext-form-field-HtmlEditor-cfg-enableLinks'> /**
121 </span> * @cfg {Boolean} enableLinks Enable the create link button. Not available in Safari. (defaults to true)
124 <span id='Ext-form-field-HtmlEditor-cfg-enableFont'> /**
125 </span> * @cfg {Boolean} enableFont Enable font selection. Not available in Safari. (defaults to true)
128 <span id='Ext-form-field-HtmlEditor-cfg-createLinkText'> /**
129 </span> * @cfg {String} createLinkText The default text for the create link prompt
131 createLinkText : 'Please enter the URL for the link:',
132 <span id='Ext-form-field-HtmlEditor-cfg-defaultLinkValue'> /**
133 </span> * @cfg {String} defaultLinkValue The default value for the create link prompt (defaults to http:/ /)
135 defaultLinkValue : 'http:/'+'/',
136 <span id='Ext-form-field-HtmlEditor-cfg-fontFamilies'> /**
137 </span> * @cfg {Array} fontFamilies An array of available font families
146 defaultFont: 'tahoma',
147 <span id='Ext-form-field-HtmlEditor-cfg-defaultValue'> /**
148 </span> * @cfg {String} defaultValue A default value to be put into the editor to resolve focus issues (defaults to &#160; (Non-breaking space) in Opera and IE6, &#8203; (Zero-width space) in all other browsers).
150 defaultValue: (Ext.isOpera || Ext.isIE6) ? '&#160;' : '&#8203;',
152 fieldBodyCls: Ext.baseCSSPrefix + 'html-editor-wrap',
154 componentLayout: 'htmleditor',
156 // private properties
159 sourceEditMode : false,
166 initComponent : function(){
170 <span id='Ext-form-field-HtmlEditor-event-initialize'> /**
171 </span> * @event initialize
172 * Fires when the editor is fully initialized (including the iframe)
173 * @param {Ext.form.field.HtmlEditor} this
176 <span id='Ext-form-field-HtmlEditor-event-activate'> /**
177 </span> * @event activate
178 * Fires when the editor is first receives the focus. Any insertion must wait
179 * until after this event.
180 * @param {Ext.form.field.HtmlEditor} this
183 <span id='Ext-form-field-HtmlEditor-event-beforesync'> /**
184 </span> * @event beforesync
185 * Fires before the textarea is updated with content from the editor iframe. Return false
186 * to cancel the sync.
187 * @param {Ext.form.field.HtmlEditor} this
188 * @param {String} html
191 <span id='Ext-form-field-HtmlEditor-event-beforepush'> /**
192 </span> * @event beforepush
193 * Fires before the iframe editor is updated with content from the textarea. Return false
194 * to cancel the push.
195 * @param {Ext.form.field.HtmlEditor} this
196 * @param {String} html
199 <span id='Ext-form-field-HtmlEditor-event-sync'> /**
200 </span> * @event sync
201 * Fires when the textarea is updated with content from the editor iframe.
202 * @param {Ext.form.field.HtmlEditor} this
203 * @param {String} html
206 <span id='Ext-form-field-HtmlEditor-event-push'> /**
207 </span> * @event push
208 * Fires when the iframe editor is updated with content from the textarea.
209 * @param {Ext.form.field.HtmlEditor} this
210 * @param {String} html
213 <span id='Ext-form-field-HtmlEditor-event-editmodechange'> /**
214 </span> * @event editmodechange
215 * Fires when the editor switches edit modes
216 * @param {Ext.form.field.HtmlEditor} this
217 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
222 me.callParent(arguments);
230 * Protected method that will not generally be called directly. It
231 * is 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
235 createToolbar : function(editor){
238 tipsEnabled = Ext.tip.QuickTipManager && Ext.tip.QuickTipManager.isEnabled(),
239 baseCSSPrefix = Ext.baseCSSPrefix,
240 fontSelectItem, toolbar, undef;
242 function btn(id, toggle, handler){
245 cls : baseCSSPrefix + 'btn-icon',
246 iconCls: baseCSSPrefix + 'edit-'+id,
247 enableToggle:toggle !== false,
249 handler:handler||editor.relayBtnCmd,
250 clickEvent:'mousedown',
251 tooltip: tipsEnabled ? editor.buttonTips[id] || undef : undef,
252 overflowText: editor.buttonTips[id].title || undef,
258 if (me.enableFont && !Ext.isSafari2) {
259 fontSelectItem = Ext.widget('component', {
261 '<select class="{cls}">',
262 '<tpl for="fonts">',
263 '<option value="{[values.toLowerCase()]}" style="font-family:{.}"<tpl if="values.toLowerCase()==parent.defaultFont"> selected</tpl>>{.}</option>',
268 cls: baseCSSPrefix + 'font-select',
269 fonts: me.fontFamilies,
270 defaultFont: me.defaultFont
275 onDisable: function() {
276 var selectEl = this.selectEl;
278 selectEl.dom.disabled = true;
280 Ext.Component.superclass.onDisable.apply(this, arguments);
282 onEnable: function() {
283 var selectEl = this.selectEl;
285 selectEl.dom.disabled = false;
287 Ext.Component.superclass.onEnable.apply(this, arguments);
297 if (me.enableFormat) {
305 if (me.enableFontSize) {
308 btn('increasefontsize', false, me.adjustFont),
309 btn('decreasefontsize', false, me.adjustFont)
313 if (me.enableColors) {
317 cls: baseCSSPrefix + 'btn-icon',
318 iconCls: baseCSSPrefix + 'edit-forecolor',
319 overflowText: editor.buttonTips.forecolor.title,
320 tooltip: tipsEnabled ? editor.buttonTips.forecolor || undef : undef,
322 menu : Ext.widget('menu', {
325 xtype: 'colorpicker',
330 clickEvent: 'mousedown',
331 handler: function(cp, color) {
332 me.execCmd('forecolor', Ext.isWebKit || Ext.isIE ? '#'+color : color);
334 this.up('menu').hide();
340 cls: baseCSSPrefix + 'btn-icon',
341 iconCls: baseCSSPrefix + 'edit-backcolor',
342 overflowText: editor.buttonTips.backcolor.title,
343 tooltip: tipsEnabled ? editor.buttonTips.backcolor || undef : undef,
345 menu : Ext.widget('menu', {
348 xtype: 'colorpicker',
353 clickEvent: 'mousedown',
354 handler: function(cp, color) {
356 me.execCmd('useCSS', false);
357 me.execCmd('hilitecolor', color);
358 me.execCmd('useCSS', true);
361 me.execCmd(Ext.isOpera ? 'hilitecolor' : 'backcolor', Ext.isWebKit || Ext.isIE ? '#'+color : color);
364 this.up('menu').hide();
372 if (me.enableAlignments) {
376 btn('justifycenter'),
381 if (!Ext.isSafari2) {
382 if (me.enableLinks) {
385 btn('createlink', false, me.createLink)
389 if (me.enableLists) {
392 btn('insertorderedlist'),
393 btn('insertunorderedlist')
396 if (me.enableSourceEdit) {
399 btn('sourceedit', true, function(btn){
400 me.toggleSourceEdit(!me.sourceEditMode);
407 toolbar = Ext.widget('toolbar', {
408 renderTo: me.toolbarWrap,
409 enableOverflow: true,
413 if (fontSelectItem) {
414 me.fontSelect = fontSelectItem.selectEl;
416 me.mon(me.fontSelect, 'change', function(){
417 me.relayCmd('fontname', me.fontSelect.dom.value);
423 me.mon(toolbar.el, 'click', function(e){
427 me.toolbar = toolbar;
430 onDisable: function() {
432 this.callParent(arguments);
435 onEnable: function() {
436 this.bodyEl.unmask();
437 this.callParent(arguments);
440 <span id='Ext-form-field-HtmlEditor-method-setReadOnly'> /**
441 </span> * Sets the read only state of this field.
442 * @param {Boolean} readOnly Whether the field should be read only.
444 setReadOnly: function(readOnly) {
446 textareaEl = me.textareaEl,
447 iframeEl = me.iframeEl,
450 me.readOnly = readOnly;
453 textareaEl.dom.readOnly = readOnly;
456 if (me.initialized) {
457 body = me.getEditorBody();
459 // Hide the iframe while setting contentEditable so it doesn't grab focus
460 iframeEl.setDisplayed(false);
461 body.contentEditable = !readOnly;
462 iframeEl.setDisplayed(true);
464 me.setDesignMode(!readOnly);
467 body.style.cursor = readOnly ? 'default' : 'text';
469 me.disableItems(readOnly);
473 <span id='Ext-form-field-HtmlEditor-method-getDocMarkup'> /**
474 </span> * Protected method that will not generally be called directly. It
475 * is called when the editor initializes the iframe with HTML contents. Override this method if you
476 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
478 * Note: IE8-Standards has unwanted scroller behavior, so the default meta tag forces IE7 compatibility.
479 * Also note that forcing IE7 mode works when the page is loaded normally, but if you are using IE's Web
480 * Developer Tools to manually set the document mode, that will take precedence and override what this
481 * code sets by default. This can be confusing when developing, but is not a user-facing issue.
483 getDocMarkup: function() {
485 h = me.iframeEl.getHeight() - me.iframePad * 2;
486 return Ext.String.format('<html><head><style type="text/css">body{border:0;margin:0;padding:{0}px;height:{1}px;cursor:text}</style></head><body></body></html>', me.iframePad, h);
490 getEditorBody: function() {
491 var doc = this.getDoc();
492 return doc.body || doc.documentElement;
497 return (!Ext.isIE && this.iframeEl.dom.contentDocument) || this.getWin().document;
502 return Ext.isIE ? this.iframeEl.dom.contentWindow : window.frames[this.iframeEl.dom.name];
506 onRender: function() {
508 renderSelectors = me.renderSelectors;
510 Ext.applyIf(renderSelectors, me.getLabelableSelectors());
512 Ext.applyIf(renderSelectors, {
513 toolbarWrap: 'div.' + Ext.baseCSSPrefix + 'html-editor-tb',
515 textareaEl: 'textarea'
518 me.callParent(arguments);
520 me.textareaEl.dom.value = me.value || '';
522 // Start polling for when the iframe document is ready to be manipulated
523 me.monitorTask = Ext.TaskManager.start({
524 run: me.checkDesignMode,
529 me.createToolbar(me);
530 me.disableItems(true);
533 initRenderTpl: function() {
535 if (!me.hasOwnProperty('renderTpl')) {
536 me.renderTpl = me.getTpl('labelableRenderTpl');
538 return me.callParent();
541 initRenderData: function() {
542 return Ext.applyIf(this.callParent(), this.getLabelableRenderData());
545 getSubTplData: function() {
546 var cssPrefix = Ext.baseCSSPrefix;
548 toolbarWrapCls: cssPrefix + 'html-editor-tb',
549 textareaCls: cssPrefix + 'hidden',
550 iframeName: Ext.id(),
551 iframeSrc: Ext.SSL_SECURE_URL,
552 size: 'height:100px;'
556 getSubTplMarkup: function() {
557 return this.getTpl('fieldSubTpl').apply(this.getSubTplData());
560 getBodyNaturalWidth: function() {
564 initFrameDoc: function() {
568 Ext.TaskManager.stop(me.monitorTask);
571 me.win = me.getWin();
574 doc.write(me.getDocMarkup());
577 task = { // must defer to wait for browser to be ready
579 var doc = me.getDoc();
580 if (doc.body || doc.readyState === 'complete') {
581 Ext.TaskManager.stop(task);
582 me.setDesignMode(true);
583 Ext.defer(me.initEditor, 10, me);
590 Ext.TaskManager.start(task);
593 checkDesignMode: function() {
596 if (doc && (!doc.editorInitialized || me.getDesignMode() !== 'on')) {
602 * set current design mode. To enable, mode can be true or 'on', off otherwise
604 setDesignMode: function(mode) {
611 doc.designMode = (/on|true/i).test(String(mode).toLowerCase()) ?'on':'off';
616 getDesignMode: function() {
617 var doc = this.getDoc();
618 return !doc ? '' : String(doc.designMode).toLowerCase();
621 disableItems: function(disabled) {
622 this.getToolbar().items.each(function(item){
623 if(item.getItemId() !== 'sourceedit'){
624 item.setDisabled(disabled);
629 <span id='Ext-form-field-HtmlEditor-method-toggleSourceEdit'> /**
630 </span> * Toggles the editor between standard and source edit mode.
631 * @param {Boolean} sourceEditMode (optional) True for source edit, false for standard
633 toggleSourceEdit: function(sourceEditMode) {
635 iframe = me.iframeEl,
636 textarea = me.textareaEl,
637 hiddenCls = Ext.baseCSSPrefix + 'hidden',
638 btn = me.getToolbar().getComponent('sourceedit');
640 if (!Ext.isBoolean(sourceEditMode)) {
641 sourceEditMode = !me.sourceEditMode;
643 me.sourceEditMode = sourceEditMode;
645 if (btn.pressed !== sourceEditMode) {
646 btn.toggle(sourceEditMode);
648 if (sourceEditMode) {
649 me.disableItems(true);
651 iframe.addCls(hiddenCls);
652 textarea.removeCls(hiddenCls);
653 textarea.dom.removeAttribute('tabIndex');
657 if (me.initialized) {
658 me.disableItems(me.readOnly);
661 iframe.removeCls(hiddenCls);
662 textarea.addCls(hiddenCls);
663 textarea.dom.setAttribute('tabIndex', -1);
666 me.fireEvent('editmodechange', me, sourceEditMode);
667 me.doComponentLayout();
670 // private used internally
671 createLink : function() {
672 var url = prompt(this.createLinkText, this.defaultLinkValue);
673 if (url && url !== 'http:/'+'/') {
674 this.relayCmd('createlink', url);
678 clearInvalid: Ext.emptyFn,
680 // docs inherit from Field
681 setValue: function(value) {
683 textarea = me.textareaEl;
684 me.mixins.field.setValue.call(me, value);
685 if (value === null || value === undefined) {
689 textarea.dom.value = value;
695 <span id='Ext-form-field-HtmlEditor-method-cleanHtml'> /**
696 </span> * Protected method that will not generally be called directly. If you need/want
697 * custom HTML cleanup, this is the method you should override.
698 * @param {String} html The HTML to be cleaned
699 * @return {String} The cleaned HTML
701 cleanHtml: function(html) {
703 if (Ext.isWebKit) { // strip safari nonsense
704 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
708 * Neat little hack. Strips out all the non-digit characters from the default
709 * value and compares it to the character code of the first character in the string
710 * because it can cause encoding issues when posted to the server.
712 if (html.charCodeAt(0) === this.defaultValue.replace(/\D/g, '')) {
713 html = html.substring(1);
718 <span id='Ext-form-field-HtmlEditor-method-syncValue'> /**
719 </span> * @protected method that will not generally be called directly. Syncs the contents
720 * of the editor iframe with the textarea.
722 syncValue : function(){
724 body, html, bodyStyle, match;
725 if (me.initialized) {
726 body = me.getEditorBody();
727 html = body.innerHTML;
729 bodyStyle = body.getAttribute('style'); // Safari puts text-align styles on the body element!
730 match = bodyStyle.match(/text-align:(.*?);/i);
731 if (match && match[1]) {
732 html = '<div style="' + match[0] + '">' + html + '</div>';
735 html = me.cleanHtml(html);
736 if (me.fireEvent('beforesync', me, html) !== false) {
737 me.textareaEl.dom.value = html;
738 me.fireEvent('sync', me, html);
743 //docs inherit from Field
744 getValue : function() {
747 if (!me.sourceEditMode) {
750 value = me.rendered ? me.textareaEl.dom.value : me.value;
755 <span id='Ext-form-field-HtmlEditor-method-pushValue'> /**
756 </span> * @protected method that will not generally be called directly. Pushes the value of the textarea
757 * into the iframe editor.
759 pushValue: function() {
763 v = me.textareaEl.dom.value || '';
764 if (!me.activated && v.length < 1) {
767 if (me.fireEvent('beforepush', me, v) !== false) {
768 me.getEditorBody().innerHTML = v;
770 // Gecko hack, see: https://bugzilla.mozilla.org/show_bug.cgi?id=232791#c8
771 me.setDesignMode(false); //toggle off first
772 me.setDesignMode(true);
774 me.fireEvent('push', me, v);
780 deferFocus : function(){
781 this.focus(false, true);
784 getFocusEl: function() {
787 return win && !me.sourceEditMode ? win : me.textareaEl;
791 initEditor : function(){
792 //Destroying the component during/before initEditor can cause issues.
795 dbody = me.getEditorBody(),
796 ss = me.textareaEl.getStyles('font-size', 'font-family', 'background-image', 'background-repeat', 'background-color', 'color'),
800 ss['background-attachment'] = 'fixed'; // w3c
801 dbody.bgProperties = 'fixed'; // ie
803 Ext.core.DomHelper.applyStyles(dbody, ss);
809 Ext.EventManager.removeAll(doc);
814 * We need to use createDelegate here, because when using buffer, the delayed task is added
815 * as a property to the function. When the listener is removed, the task is deleted from the function.
816 * Since onEditorEvent is shared on the prototype, if we have multiple html editors, the first time one of the editors
817 * is destroyed, it causes the fn to be deleted from the prototype, which causes errors. Essentially, we're just anonymizing the function.
819 fn = Ext.Function.bind(me.onEditorEvent, me);
820 Ext.EventManager.on(doc, {
828 // These events need to be relayed from the inner document (where they stop
829 // bubbling) up to the outer document. This has to be done at the DOM level so
830 // the event reaches listeners on elements like the document body. The effected
831 // mechanisms that depend on this bubbling behavior are listed to the right
833 fn = me.onRelayedEvent;
834 Ext.EventManager.on(doc, {
835 mousedown: fn, // menu dismisal (MenuManager) and Window onMouseDown (toFront)
836 mousemove: fn, // window resize drag detection
837 mouseup: fn, // window resize termination
838 click: fn, // not sure, but just to be safe
839 dblclick: fn, // not sure again
844 Ext.EventManager.on(doc, 'keypress', me.applyCommand, me);
847 Ext.EventManager.on(doc, 'keydown', me.fixKeys, me);
850 // We need to be sure we remove all our events from the iframe on unload or we're going to LEAK!
851 Ext.EventManager.on(window, 'unload', me.beforeDestroy, me);
852 doc.editorInitialized = true;
854 me.initialized = true;
856 me.setReadOnly(me.readOnly);
857 me.fireEvent('initialize', me);
864 beforeDestroy : function(){
866 monitorTask = me.monitorTask,
870 Ext.TaskManager.stop(monitorTask);
876 Ext.EventManager.removeAll(doc);
878 if (doc.hasOwnProperty(prop)) {
886 Ext.destroyMembers('tb', 'toolbarWrap', 'iframeEl', 'textareaEl');
892 onRelayedEvent: function (event) {
893 // relay event from the iframe's document to the document that owns the iframe...
895 var iframeEl = this.iframeEl,
896 iframeXY = iframeEl.getXY(),
897 eventXY = event.getXY();
899 // the event from the inner document has XY relative to that document's origin,
900 // so adjust it to use the origin of the iframe in the outer document:
901 event.xy = [iframeXY[0] + eventXY[0], iframeXY[1] + eventXY[1]];
903 event.injectEvent(iframeEl); // blame the iframe for the event...
905 event.xy = eventXY; // restore the original XY (just for safety)
909 onFirstFocus : function(){
913 me.disableItems(me.readOnly);
914 if (Ext.isGecko) { // prevent silly gecko errors
916 selection = me.win.getSelection();
917 if (!selection.focusNode || selection.focusNode.nodeType !== 3) {
918 range = selection.getRangeAt(0);
919 range.selectNodeContents(me.getEditorBody());
920 range.collapse(true);
924 me.execCmd('useCSS', true);
925 me.execCmd('styleWithCSS', false);
930 me.fireEvent('activate', me);
934 adjustFont: function(btn) {
935 var adjust = btn.getItemId() === 'increasefontsize' ? 1 : -1,
936 size = this.getDoc().queryCommandValue('FontSize') || '2',
937 isPxSize = Ext.isString(size) && size.indexOf('px') !== -1,
939 size = parseInt(size, 10);
942 // 1 = 10px, 2 = 13px, 3 = 16px, 4 = 18px, 5 = 24px, 6 = 32px
946 else if (size <= 13) {
949 else if (size <= 16) {
952 else if (size <= 18) {
955 else if (size <= 24) {
961 size = Ext.Number.constrain(size, 1, 6);
963 isSafari = Ext.isSafari;
964 if (isSafari) { // safari
967 size = Math.max(1, size + adjust) + (isSafari ? 'px' : 0);
969 this.execCmd('FontSize', size);
973 onEditorEvent: function(e) {
974 this.updateToolbar();
977 <span id='Ext-form-field-HtmlEditor-method-updateToolbar'> /**
978 </span> * Protected method that will not generally be called directly. It triggers
979 * a toolbar update by reading the markup state of the current selection in the editor.
981 updateToolbar: function() {
983 btns, doc, name, fontSelect;
994 btns = me.getToolbar().items.map;
997 if (me.enableFont && !Ext.isSafari2) {
998 name = (doc.queryCommandValue('FontName') || me.defaultFont).toLowerCase();
999 fontSelect = me.fontSelect.dom;
1000 if (name !== fontSelect.value) {
1001 fontSelect.value = name;
1005 function updateButtons() {
1006 Ext.Array.forEach(Ext.Array.toArray(arguments), function(name) {
1007 btns[name].toggle(doc.queryCommandState(name));
1010 if(me.enableFormat){
1011 updateButtons('bold', 'italic', 'underline');
1013 if(me.enableAlignments){
1014 updateButtons('justifyleft', 'justifycenter', 'justifyright');
1016 if(!Ext.isSafari2 && me.enableLists){
1017 updateButtons('insertorderedlist', 'insertunorderedlist');
1020 Ext.menu.Manager.hideAll();
1026 relayBtnCmd: function(btn) {
1027 this.relayCmd(btn.getItemId());
1030 <span id='Ext-form-field-HtmlEditor-method-relayCmd'> /**
1031 </span> * Executes a Midas editor command on the editor document and performs necessary focus and
1032 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
1033 * @param {String} cmd The Midas command
1034 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
1036 relayCmd: function(cmd, value) {
1037 Ext.defer(function() {
1040 me.execCmd(cmd, value);
1045 <span id='Ext-form-field-HtmlEditor-method-execCmd'> /**
1046 </span> * Executes a Midas editor command directly on the editor document.
1047 * For visual commands, you should use {@link #relayCmd} instead.
1048 * <b>This should only be called after the editor is initialized.</b>
1049 * @param {String} cmd The Midas command
1050 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
1052 execCmd : function(cmd, value){
1056 doc.execCommand(cmd, false, value === undef ? null : value);
1061 applyCommand : function(e){
1064 c = e.getCharCode(), cmd;
1066 c = String.fromCharCode(c);
1088 <span id='Ext-form-field-HtmlEditor-method-insertAtCursor'> /**
1089 </span> * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
1091 * @param {String} text
1093 insertAtCursor : function(text){
1100 range = me.getDoc().selection.createRange();
1102 range.pasteHTML(text);
1107 me.execCmd('InsertHTML', text);
1114 fixKeys: function() { // load time branching for fastest keydown performance
1123 range = doc.selection.createRange();
1125 range.collapse(true);
1126 range.pasteHTML('&nbsp;&nbsp;&nbsp;&nbsp;');
1130 else if (k === e.ENTER) {
1131 range = doc.selection.createRange();
1133 target = range.parentElement();
1134 if(!target || target.tagName.toLowerCase() !== 'li'){
1136 range.pasteHTML('<br />');
1137 range.collapse(false);
1148 if (e.getKey() === e.TAB) {
1151 me.execCmd('InsertHTML','&nbsp;&nbsp;&nbsp;&nbsp;');
1163 me.execCmd('InsertText','\t');
1166 else if (k === e.ENTER) {
1168 me.execCmd('InsertHtml','<br /><br />');
1174 return null; // not needed, so null
1177 <span id='Ext-form-field-HtmlEditor-method-getToolbar'> /**
1178 </span> * Returns the editor's toolbar. <b>This is only available after the editor has been rendered.</b>
1179 * @return {Ext.toolbar.Toolbar}
1181 getToolbar : function(){
1182 return this.toolbar;
1185 <span id='Ext-form-field-HtmlEditor-property-buttonTips'> /**
1186 </span> * Object collection of toolbar tooltips for the buttons in the editor. The key
1187 * is the command id associated with that button and the value is a valid QuickTips object.
1189 <pre><code>
1192 title: 'Bold (Ctrl+B)',
1193 text: 'Make the selected text bold.',
1194 cls: 'x-html-editor-tip'
1197 title: 'Italic (Ctrl+I)',
1198 text: 'Make the selected text italic.',
1199 cls: 'x-html-editor-tip'
1202 </code></pre>
1207 title: 'Bold (Ctrl+B)',
1208 text: 'Make the selected text bold.',
1209 cls: Ext.baseCSSPrefix + 'html-editor-tip'
1212 title: 'Italic (Ctrl+I)',
1213 text: 'Make the selected text italic.',
1214 cls: Ext.baseCSSPrefix + 'html-editor-tip'
1217 title: 'Underline (Ctrl+U)',
1218 text: 'Underline the selected text.',
1219 cls: Ext.baseCSSPrefix + 'html-editor-tip'
1221 increasefontsize : {
1223 text: 'Increase the font size.',
1224 cls: Ext.baseCSSPrefix + 'html-editor-tip'
1226 decreasefontsize : {
1227 title: 'Shrink Text',
1228 text: 'Decrease the font size.',
1229 cls: Ext.baseCSSPrefix + 'html-editor-tip'
1232 title: 'Text Highlight Color',
1233 text: 'Change the background color of the selected text.',
1234 cls: Ext.baseCSSPrefix + 'html-editor-tip'
1237 title: 'Font Color',
1238 text: 'Change the color of the selected text.',
1239 cls: Ext.baseCSSPrefix + 'html-editor-tip'
1242 title: 'Align Text Left',
1243 text: 'Align text to the left.',
1244 cls: Ext.baseCSSPrefix + 'html-editor-tip'
1247 title: 'Center Text',
1248 text: 'Center text in the editor.',
1249 cls: Ext.baseCSSPrefix + 'html-editor-tip'
1252 title: 'Align Text Right',
1253 text: 'Align text to the right.',
1254 cls: Ext.baseCSSPrefix + 'html-editor-tip'
1256 insertunorderedlist : {
1257 title: 'Bullet List',
1258 text: 'Start a bulleted list.',
1259 cls: Ext.baseCSSPrefix + 'html-editor-tip'
1261 insertorderedlist : {
1262 title: 'Numbered List',
1263 text: 'Start a numbered list.',
1264 cls: Ext.baseCSSPrefix + 'html-editor-tip'
1268 text: 'Make the selected text a hyperlink.',
1269 cls: Ext.baseCSSPrefix + 'html-editor-tip'
1272 title: 'Source Edit',
1273 text: 'Switch to source editing mode.',
1274 cls: Ext.baseCSSPrefix + 'html-editor-tip'
1278 // hide stuff that is not compatible
1279 <span id='Ext-form-field-HtmlEditor-event-blur'> /**
1280 </span> * @event blur
1283 <span id='Ext-form-field-HtmlEditor-event-change'> /**
1284 </span> * @event change
1287 <span id='Ext-form-field-HtmlEditor-event-focus'> /**
1288 </span> * @event focus
1291 <span id='Ext-form-field-HtmlEditor-event-specialkey'> /**
1292 </span> * @event specialkey
1295 <span id='Ext-form-field-HtmlEditor-cfg-fieldCls'> /**
1296 </span> * @cfg {String} fieldCls @hide
1298 <span id='Ext-form-field-HtmlEditor-cfg-focusCls'> /**
1299 </span> * @cfg {String} focusCls @hide
1301 <span id='Ext-form-field-HtmlEditor-cfg-autoCreate'> /**
1302 </span> * @cfg {String} autoCreate @hide
1304 <span id='Ext-form-field-HtmlEditor-cfg-inputType'> /**
1305 </span> * @cfg {String} inputType @hide
1307 <span id='Ext-form-field-HtmlEditor-cfg-invalidCls'> /**
1308 </span> * @cfg {String} invalidCls @hide
1310 <span id='Ext-form-field-HtmlEditor-cfg-invalidText'> /**
1311 </span> * @cfg {String} invalidText @hide
1313 <span id='Ext-form-field-HtmlEditor-cfg-msgFx'> /**
1314 </span> * @cfg {String} msgFx @hide
1316 <span id='Ext-form-field-HtmlEditor-cfg-allowDomMove'> /**
1317 </span> * @cfg {Boolean} allowDomMove @hide
1319 <span id='Ext-form-field-HtmlEditor-cfg-applyTo'> /**
1320 </span> * @cfg {String} applyTo @hide
1322 <span id='Ext-form-field-HtmlEditor-cfg-readOnly'> /**
1323 </span> * @cfg {String} readOnly @hide
1325 <span id='Ext-form-field-HtmlEditor-cfg-tabIndex'> /**
1326 </span> * @cfg {String} tabIndex @hide
1328 <span id='Ext-form-field-HtmlEditor-method-validate'> /**
1329 </span> * @method validate