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'>/**
19 </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 Ext.define('Ext.form.field.HtmlEditor', {
65 extend:'Ext.Component',
67 labelable: 'Ext.form.Labelable',
68 field: 'Ext.form.field.Field'
70 alias: 'widget.htmleditor',
71 alternateClassName: 'Ext.form.HtmlEditor',
73 'Ext.tip.QuickTipManager',
76 'Ext.toolbar.Toolbar',
78 'Ext.layout.component.field.HtmlEditor'
82 '<div class="{toolbarWrapCls}"></div>',
83 '<textarea id="{id}" name="{name}" tabIndex="-1" class="{textareaCls}" ',
84 'style="{size}" autocomplete="off"></textarea>',
85 '<iframe name="{iframeName}" frameBorder="0" style="overflow:auto;{size}" src="{iframeSrc}"></iframe>',
92 <span id='Ext-form-field-HtmlEditor-cfg-enableFormat'> /**
93 </span> * @cfg {Boolean} enableFormat Enable the bold, italic and underline buttons (defaults to true)
96 <span id='Ext-form-field-HtmlEditor-cfg-enableFontSize'> /**
97 </span> * @cfg {Boolean} enableFontSize Enable the increase/decrease font size buttons (defaults to true)
99 enableFontSize : true,
100 <span id='Ext-form-field-HtmlEditor-cfg-enableColors'> /**
101 </span> * @cfg {Boolean} enableColors Enable the fore/highlight color buttons (defaults to true)
104 <span id='Ext-form-field-HtmlEditor-cfg-enableAlignments'> /**
105 </span> * @cfg {Boolean} enableAlignments Enable the left, center, right alignment buttons (defaults to true)
107 enableAlignments : true,
108 <span id='Ext-form-field-HtmlEditor-cfg-enableLists'> /**
109 </span> * @cfg {Boolean} enableLists Enable the bullet and numbered list buttons. Not available in Safari. (defaults to true)
112 <span id='Ext-form-field-HtmlEditor-cfg-enableSourceEdit'> /**
113 </span> * @cfg {Boolean} enableSourceEdit Enable the switch to source edit button. Not available in Safari. (defaults to true)
115 enableSourceEdit : true,
116 <span id='Ext-form-field-HtmlEditor-cfg-enableLinks'> /**
117 </span> * @cfg {Boolean} enableLinks Enable the create link button. Not available in Safari. (defaults to true)
120 <span id='Ext-form-field-HtmlEditor-cfg-enableFont'> /**
121 </span> * @cfg {Boolean} enableFont Enable font selection. Not available in Safari. (defaults to true)
124 <span id='Ext-form-field-HtmlEditor-cfg-createLinkText'> /**
125 </span> * @cfg {String} createLinkText The default text for the create link prompt
127 createLinkText : 'Please enter the URL for the link:',
128 <span id='Ext-form-field-HtmlEditor-cfg-defaultLinkValue'> /**
129 </span> * @cfg {String} defaultLinkValue The default value for the create link prompt (defaults to http:/ /)
131 defaultLinkValue : 'http:/'+'/',
132 <span id='Ext-form-field-HtmlEditor-cfg-fontFamilies'> /**
133 </span> * @cfg {Array} fontFamilies An array of available font families
142 defaultFont: 'tahoma',
143 <span id='Ext-form-field-HtmlEditor-cfg-defaultValue'> /**
144 </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).
146 defaultValue: (Ext.isOpera || Ext.isIE6) ? '&#160;' : '&#8203;',
148 fieldBodyCls: Ext.baseCSSPrefix + 'html-editor-wrap',
150 componentLayout: 'htmleditor',
152 // private properties
155 sourceEditMode : false,
162 initComponent : function(){
166 <span id='Ext-form-field-HtmlEditor-event-initialize'> /**
167 </span> * @event initialize
168 * Fires when the editor is fully initialized (including the iframe)
169 * @param {Ext.form.field.HtmlEditor} this
172 <span id='Ext-form-field-HtmlEditor-event-activate'> /**
173 </span> * @event activate
174 * Fires when the editor is first receives the focus. Any insertion must wait
175 * until after this event.
176 * @param {Ext.form.field.HtmlEditor} this
179 <span id='Ext-form-field-HtmlEditor-event-beforesync'> /**
180 </span> * @event beforesync
181 * Fires before the textarea is updated with content from the editor iframe. Return false
182 * to cancel the sync.
183 * @param {Ext.form.field.HtmlEditor} this
184 * @param {String} html
187 <span id='Ext-form-field-HtmlEditor-event-beforepush'> /**
188 </span> * @event beforepush
189 * Fires before the iframe editor is updated with content from the textarea. Return false
190 * to cancel the push.
191 * @param {Ext.form.field.HtmlEditor} this
192 * @param {String} html
195 <span id='Ext-form-field-HtmlEditor-event-sync'> /**
196 </span> * @event sync
197 * Fires when the textarea is updated with content from the editor iframe.
198 * @param {Ext.form.field.HtmlEditor} this
199 * @param {String} html
202 <span id='Ext-form-field-HtmlEditor-event-push'> /**
203 </span> * @event push
204 * Fires when the iframe editor is updated with content from the textarea.
205 * @param {Ext.form.field.HtmlEditor} this
206 * @param {String} html
209 <span id='Ext-form-field-HtmlEditor-event-editmodechange'> /**
210 </span> * @event editmodechange
211 * Fires when the editor switches edit modes
212 * @param {Ext.form.field.HtmlEditor} this
213 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
218 me.callParent(arguments);
226 * Protected method that will not generally be called directly. It
227 * is called when the editor creates its toolbar. Override this method if you need to
228 * add custom toolbar buttons.
229 * @param {Ext.form.field.HtmlEditor} editor
231 createToolbar : function(editor){
234 tipsEnabled = Ext.tip.QuickTipManager && Ext.tip.QuickTipManager.isEnabled(),
235 baseCSSPrefix = Ext.baseCSSPrefix,
236 fontSelectItem, toolbar, undef;
238 function btn(id, toggle, handler){
241 cls : baseCSSPrefix + 'btn-icon',
242 iconCls: baseCSSPrefix + 'edit-'+id,
243 enableToggle:toggle !== false,
245 handler:handler||editor.relayBtnCmd,
246 clickEvent:'mousedown',
247 tooltip: tipsEnabled ? editor.buttonTips[id] || undef : undef,
248 overflowText: editor.buttonTips[id].title || undef,
254 if (me.enableFont && !Ext.isSafari2) {
255 fontSelectItem = Ext.widget('component', {
257 '<select class="{cls}">',
258 '<tpl for="fonts">',
259 '<option value="{[values.toLowerCase()]}" style="font-family:{.}"<tpl if="values.toLowerCase()==parent.defaultFont"> selected</tpl>>{.}</option>',
264 cls: baseCSSPrefix + 'font-select',
265 fonts: me.fontFamilies,
266 defaultFont: me.defaultFont
271 onDisable: function() {
272 var selectEl = this.selectEl;
274 selectEl.dom.disabled = true;
276 Ext.Component.superclass.onDisable.apply(this, arguments);
278 onEnable: function() {
279 var selectEl = this.selectEl;
281 selectEl.dom.disabled = false;
283 Ext.Component.superclass.onEnable.apply(this, arguments);
293 if (me.enableFormat) {
301 if (me.enableFontSize) {
304 btn('increasefontsize', false, me.adjustFont),
305 btn('decreasefontsize', false, me.adjustFont)
309 if (me.enableColors) {
313 cls: baseCSSPrefix + 'btn-icon',
314 iconCls: baseCSSPrefix + 'edit-forecolor',
315 overflowText: editor.buttonTips.forecolor.title,
316 tooltip: tipsEnabled ? editor.buttonTips.forecolor || undef : undef,
318 menu : Ext.widget('menu', {
321 xtype: 'colorpicker',
326 clickEvent: 'mousedown',
327 handler: function(cp, color) {
328 me.execCmd('forecolor', Ext.isWebKit || Ext.isIE ? '#'+color : color);
330 this.up('menu').hide();
336 cls: baseCSSPrefix + 'btn-icon',
337 iconCls: baseCSSPrefix + 'edit-backcolor',
338 overflowText: editor.buttonTips.backcolor.title,
339 tooltip: tipsEnabled ? editor.buttonTips.backcolor || undef : undef,
341 menu : Ext.widget('menu', {
344 xtype: 'colorpicker',
349 clickEvent: 'mousedown',
350 handler: function(cp, color) {
352 me.execCmd('useCSS', false);
353 me.execCmd('hilitecolor', color);
354 me.execCmd('useCSS', true);
357 me.execCmd(Ext.isOpera ? 'hilitecolor' : 'backcolor', Ext.isWebKit || Ext.isIE ? '#'+color : color);
360 this.up('menu').hide();
368 if (me.enableAlignments) {
372 btn('justifycenter'),
377 if (!Ext.isSafari2) {
378 if (me.enableLinks) {
381 btn('createlink', false, me.createLink)
385 if (me.enableLists) {
388 btn('insertorderedlist'),
389 btn('insertunorderedlist')
392 if (me.enableSourceEdit) {
395 btn('sourceedit', true, function(btn){
396 me.toggleSourceEdit(!me.sourceEditMode);
403 toolbar = Ext.widget('toolbar', {
404 renderTo: me.toolbarWrap,
405 enableOverflow: true,
409 if (fontSelectItem) {
410 me.fontSelect = fontSelectItem.selectEl;
412 me.mon(me.fontSelect, 'change', function(){
413 me.relayCmd('fontname', me.fontSelect.dom.value);
419 me.mon(toolbar.el, 'click', function(e){
423 me.toolbar = toolbar;
426 onDisable: function() {
428 this.callParent(arguments);
431 onEnable: function() {
432 this.bodyEl.unmask();
433 this.callParent(arguments);
436 <span id='Ext-form-field-HtmlEditor-method-setReadOnly'> /**
437 </span> * Sets the read only state of this field.
438 * @param {Boolean} readOnly Whether the field should be read only.
440 setReadOnly: function(readOnly) {
442 textareaEl = me.textareaEl,
443 iframeEl = me.iframeEl,
446 me.readOnly = readOnly;
449 textareaEl.dom.readOnly = readOnly;
452 if (me.initialized) {
453 body = me.getEditorBody();
455 // Hide the iframe while setting contentEditable so it doesn't grab focus
456 iframeEl.setDisplayed(false);
457 body.contentEditable = !readOnly;
458 iframeEl.setDisplayed(true);
460 me.setDesignMode(!readOnly);
463 body.style.cursor = readOnly ? 'default' : 'text';
465 me.disableItems(readOnly);
469 <span id='Ext-form-field-HtmlEditor-method-getDocMarkup'> /**
470 </span> * Protected method that will not generally be called directly. It
471 * is called when the editor initializes the iframe with HTML contents. Override this method if you
472 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
474 * Note: IE8-Standards has unwanted scroller behavior, so the default meta tag forces IE7 compatibility.
475 * Also note that forcing IE7 mode works when the page is loaded normally, but if you are using IE's Web
476 * Developer Tools to manually set the document mode, that will take precedence and override what this
477 * code sets by default. This can be confusing when developing, but is not a user-facing issue.
479 getDocMarkup: function() {
481 h = me.iframeEl.getHeight() - me.iframePad * 2;
482 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);
486 getEditorBody: function() {
487 var doc = this.getDoc();
488 return doc.body || doc.documentElement;
493 return (!Ext.isIE && this.iframeEl.dom.contentDocument) || this.getWin().document;
498 return Ext.isIE ? this.iframeEl.dom.contentWindow : window.frames[this.iframeEl.dom.name];
502 onRender: function() {
504 renderSelectors = me.renderSelectors;
506 Ext.applyIf(renderSelectors, me.getLabelableSelectors());
508 Ext.applyIf(renderSelectors, {
509 toolbarWrap: 'div.' + Ext.baseCSSPrefix + 'html-editor-tb',
511 textareaEl: 'textarea'
514 me.callParent(arguments);
516 me.textareaEl.dom.value = me.value || '';
518 // Start polling for when the iframe document is ready to be manipulated
519 me.monitorTask = Ext.TaskManager.start({
520 run: me.checkDesignMode,
525 me.createToolbar(me);
526 me.disableItems(true);
529 initRenderTpl: function() {
531 if (!me.hasOwnProperty('renderTpl')) {
532 me.renderTpl = me.getTpl('labelableRenderTpl');
534 return me.callParent();
537 initRenderData: function() {
538 return Ext.applyIf(this.callParent(), this.getLabelableRenderData());
541 getSubTplData: function() {
542 var cssPrefix = Ext.baseCSSPrefix;
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 return this.getTpl('fieldSubTpl').apply(this.getSubTplData());
556 getBodyNaturalWidth: function() {
560 initFrameDoc: function() {
564 Ext.TaskManager.stop(me.monitorTask);
567 me.win = me.getWin();
570 doc.write(me.getDocMarkup());
573 task = { // must defer to wait for browser to be ready
575 var doc = me.getDoc();
576 if (doc.body || doc.readyState === 'complete') {
577 Ext.TaskManager.stop(task);
578 me.setDesignMode(true);
579 Ext.defer(me.initEditor, 10, me);
586 Ext.TaskManager.start(task);
589 checkDesignMode: function() {
592 if (doc && (!doc.editorInitialized || me.getDesignMode() !== 'on')) {
598 * set current design mode. To enable, mode can be true or 'on', off otherwise
600 setDesignMode: function(mode) {
607 doc.designMode = (/on|true/i).test(String(mode).toLowerCase()) ?'on':'off';
612 getDesignMode: function() {
613 var doc = this.getDoc();
614 return !doc ? '' : String(doc.designMode).toLowerCase();
617 disableItems: function(disabled) {
618 this.getToolbar().items.each(function(item){
619 if(item.getItemId() !== 'sourceedit'){
620 item.setDisabled(disabled);
625 <span id='Ext-form-field-HtmlEditor-method-toggleSourceEdit'> /**
626 </span> * Toggles the editor between standard and source edit mode.
627 * @param {Boolean} sourceEditMode (optional) True for source edit, false for standard
629 toggleSourceEdit: function(sourceEditMode) {
631 iframe = me.iframeEl,
632 textarea = me.textareaEl,
633 hiddenCls = Ext.baseCSSPrefix + 'hidden',
634 btn = me.getToolbar().getComponent('sourceedit');
636 if (!Ext.isBoolean(sourceEditMode)) {
637 sourceEditMode = !me.sourceEditMode;
639 me.sourceEditMode = sourceEditMode;
641 if (btn.pressed !== sourceEditMode) {
642 btn.toggle(sourceEditMode);
644 if (sourceEditMode) {
645 me.disableItems(true);
647 iframe.addCls(hiddenCls);
648 textarea.removeCls(hiddenCls);
649 textarea.dom.removeAttribute('tabIndex');
653 if (me.initialized) {
654 me.disableItems(me.readOnly);
657 iframe.removeCls(hiddenCls);
658 textarea.addCls(hiddenCls);
659 textarea.dom.setAttribute('tabIndex', -1);
662 me.fireEvent('editmodechange', me, sourceEditMode);
663 me.doComponentLayout();
666 // private used internally
667 createLink : function() {
668 var url = prompt(this.createLinkText, this.defaultLinkValue);
669 if (url && url !== 'http:/'+'/') {
670 this.relayCmd('createlink', url);
674 clearInvalid: Ext.emptyFn,
676 // docs inherit from Field
677 setValue: function(value) {
679 textarea = me.textareaEl;
680 me.mixins.field.setValue.call(me, value);
681 if (value === null || value === undefined) {
685 textarea.dom.value = value;
691 <span id='Ext-form-field-HtmlEditor-method-cleanHtml'> /**
692 </span> * Protected method that will not generally be called directly. If you need/want
693 * custom HTML cleanup, this is the method you should override.
694 * @param {String} html The HTML to be cleaned
695 * @return {String} The cleaned HTML
697 cleanHtml: function(html) {
699 if (Ext.isWebKit) { // strip safari nonsense
700 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
704 * Neat little hack. Strips out all the non-digit characters from the default
705 * value and compares it to the character code of the first character in the string
706 * because it can cause encoding issues when posted to the server.
708 if (html.charCodeAt(0) === this.defaultValue.replace(/\D/g, '')) {
709 html = html.substring(1);
714 <span id='Ext-form-field-HtmlEditor-method-syncValue'> /**
715 </span> * @protected method that will not generally be called directly. Syncs the contents
716 * of the editor iframe with the textarea.
718 syncValue : function(){
720 body, html, bodyStyle, match;
721 if (me.initialized) {
722 body = me.getEditorBody();
723 html = body.innerHTML;
725 bodyStyle = body.getAttribute('style'); // Safari puts text-align styles on the body element!
726 match = bodyStyle.match(/text-align:(.*?);/i);
727 if (match && match[1]) {
728 html = '<div style="' + match[0] + '">' + html + '</div>';
731 html = me.cleanHtml(html);
732 if (me.fireEvent('beforesync', me, html) !== false) {
733 me.textareaEl.dom.value = html;
734 me.fireEvent('sync', me, html);
739 //docs inherit from Field
740 getValue : function() {
743 if (!me.sourceEditMode) {
746 value = me.rendered ? me.textareaEl.dom.value : me.value;
751 <span id='Ext-form-field-HtmlEditor-method-pushValue'> /**
752 </span> * @protected method that will not generally be called directly. Pushes the value of the textarea
753 * into the iframe editor.
755 pushValue: function() {
759 v = me.textareaEl.dom.value || '';
760 if (!me.activated && v.length < 1) {
763 if (me.fireEvent('beforepush', me, v) !== false) {
764 me.getEditorBody().innerHTML = v;
766 // Gecko hack, see: https://bugzilla.mozilla.org/show_bug.cgi?id=232791#c8
767 me.setDesignMode(false); //toggle off first
768 me.setDesignMode(true);
770 me.fireEvent('push', me, v);
776 deferFocus : function(){
777 this.focus(false, true);
780 getFocusEl: function() {
783 return win && !me.sourceEditMode ? win : me.textareaEl;
787 initEditor : function(){
788 //Destroying the component during/before initEditor can cause issues.
791 dbody = me.getEditorBody(),
792 ss = me.textareaEl.getStyles('font-size', 'font-family', 'background-image', 'background-repeat', 'background-color', 'color'),
796 ss['background-attachment'] = 'fixed'; // w3c
797 dbody.bgProperties = 'fixed'; // ie
799 Ext.core.DomHelper.applyStyles(dbody, ss);
805 Ext.EventManager.removeAll(doc);
810 * We need to use createDelegate here, because when using buffer, the delayed task is added
811 * as a property to the function. When the listener is removed, the task is deleted from the function.
812 * Since onEditorEvent is shared on the prototype, if we have multiple html editors, the first time one of the editors
813 * is destroyed, it causes the fn to be deleted from the prototype, which causes errors. Essentially, we're just anonymizing the function.
815 fn = Ext.Function.bind(me.onEditorEvent, me);
816 Ext.EventManager.on(doc, {
824 // These events need to be relayed from the inner document (where they stop
825 // bubbling) up to the outer document. This has to be done at the DOM level so
826 // the event reaches listeners on elements like the document body. The effected
827 // mechanisms that depend on this bubbling behavior are listed to the right
829 fn = me.onRelayedEvent;
830 Ext.EventManager.on(doc, {
831 mousedown: fn, // menu dismisal (MenuManager) and Window onMouseDown (toFront)
832 mousemove: fn, // window resize drag detection
833 mouseup: fn, // window resize termination
834 click: fn, // not sure, but just to be safe
835 dblclick: fn, // not sure again
840 Ext.EventManager.on(doc, 'keypress', me.applyCommand, me);
843 Ext.EventManager.on(doc, 'keydown', me.fixKeys, me);
846 // We need to be sure we remove all our events from the iframe on unload or we're going to LEAK!
847 Ext.EventManager.on(window, 'unload', me.beforeDestroy, me);
848 doc.editorInitialized = true;
850 me.initialized = true;
852 me.setReadOnly(me.readOnly);
853 me.fireEvent('initialize', me);
860 beforeDestroy : function(){
862 monitorTask = me.monitorTask,
866 Ext.TaskManager.stop(monitorTask);
872 Ext.EventManager.removeAll(doc);
874 if (doc.hasOwnProperty(prop)) {
882 Ext.destroyMembers('tb', 'toolbarWrap', 'iframeEl', 'textareaEl');
888 onRelayedEvent: function (event) {
889 // relay event from the iframe's document to the document that owns the iframe...
891 var iframeEl = this.iframeEl,
892 iframeXY = iframeEl.getXY(),
893 eventXY = event.getXY();
895 // the event from the inner document has XY relative to that document's origin,
896 // so adjust it to use the origin of the iframe in the outer document:
897 event.xy = [iframeXY[0] + eventXY[0], iframeXY[1] + eventXY[1]];
899 event.injectEvent(iframeEl); // blame the iframe for the event...
901 event.xy = eventXY; // restore the original XY (just for safety)
905 onFirstFocus : function(){
909 me.disableItems(me.readOnly);
910 if (Ext.isGecko) { // prevent silly gecko errors
912 selection = me.win.getSelection();
913 if (!selection.focusNode || selection.focusNode.nodeType !== 3) {
914 range = selection.getRangeAt(0);
915 range.selectNodeContents(me.getEditorBody());
916 range.collapse(true);
920 me.execCmd('useCSS', true);
921 me.execCmd('styleWithCSS', false);
926 me.fireEvent('activate', me);
930 adjustFont: function(btn) {
931 var adjust = btn.getItemId() === 'increasefontsize' ? 1 : -1,
932 size = this.getDoc().queryCommandValue('FontSize') || '2',
933 isPxSize = Ext.isString(size) && size.indexOf('px') !== -1,
935 size = parseInt(size, 10);
938 // 1 = 10px, 2 = 13px, 3 = 16px, 4 = 18px, 5 = 24px, 6 = 32px
942 else if (size <= 13) {
945 else if (size <= 16) {
948 else if (size <= 18) {
951 else if (size <= 24) {
957 size = Ext.Number.constrain(size, 1, 6);
959 isSafari = Ext.isSafari;
960 if (isSafari) { // safari
963 size = Math.max(1, size + adjust) + (isSafari ? 'px' : 0);
965 this.execCmd('FontSize', size);
969 onEditorEvent: function(e) {
970 this.updateToolbar();
973 <span id='Ext-form-field-HtmlEditor-method-updateToolbar'> /**
974 </span> * Protected method that will not generally be called directly. It triggers
975 * a toolbar update by reading the markup state of the current selection in the editor.
977 updateToolbar: function() {
979 btns, doc, name, fontSelect;
990 btns = me.getToolbar().items.map;
993 if (me.enableFont && !Ext.isSafari2) {
994 name = (doc.queryCommandValue('FontName') || me.defaultFont).toLowerCase();
995 fontSelect = me.fontSelect.dom;
996 if (name !== fontSelect.value) {
997 fontSelect.value = name;
1001 function updateButtons() {
1002 Ext.Array.forEach(Ext.Array.toArray(arguments), function(name) {
1003 btns[name].toggle(doc.queryCommandState(name));
1006 if(me.enableFormat){
1007 updateButtons('bold', 'italic', 'underline');
1009 if(me.enableAlignments){
1010 updateButtons('justifyleft', 'justifycenter', 'justifyright');
1012 if(!Ext.isSafari2 && me.enableLists){
1013 updateButtons('insertorderedlist', 'insertunorderedlist');
1016 Ext.menu.Manager.hideAll();
1022 relayBtnCmd: function(btn) {
1023 this.relayCmd(btn.getItemId());
1026 <span id='Ext-form-field-HtmlEditor-method-relayCmd'> /**
1027 </span> * Executes a Midas editor command on the editor document and performs necessary focus and
1028 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
1029 * @param {String} cmd The Midas command
1030 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
1032 relayCmd: function(cmd, value) {
1033 Ext.defer(function() {
1036 me.execCmd(cmd, value);
1041 <span id='Ext-form-field-HtmlEditor-method-execCmd'> /**
1042 </span> * Executes a Midas editor command directly on the editor document.
1043 * For visual commands, you should use {@link #relayCmd} instead.
1044 * <b>This should only be called after the editor is initialized.</b>
1045 * @param {String} cmd The Midas command
1046 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
1048 execCmd : function(cmd, value){
1052 doc.execCommand(cmd, false, value === undef ? null : value);
1057 applyCommand : function(e){
1060 c = e.getCharCode(), cmd;
1062 c = String.fromCharCode(c);
1084 <span id='Ext-form-field-HtmlEditor-method-insertAtCursor'> /**
1085 </span> * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
1087 * @param {String} text
1089 insertAtCursor : function(text){
1096 range = me.getDoc().selection.createRange();
1098 range.pasteHTML(text);
1103 me.execCmd('InsertHTML', text);
1110 fixKeys: function() { // load time branching for fastest keydown performance
1119 range = doc.selection.createRange();
1121 range.collapse(true);
1122 range.pasteHTML('&nbsp;&nbsp;&nbsp;&nbsp;');
1126 else if (k === e.ENTER) {
1127 range = doc.selection.createRange();
1129 target = range.parentElement();
1130 if(!target || target.tagName.toLowerCase() !== 'li'){
1132 range.pasteHTML('<br />');
1133 range.collapse(false);
1144 if (e.getKey() === e.TAB) {
1147 me.execCmd('InsertHTML','&nbsp;&nbsp;&nbsp;&nbsp;');
1159 me.execCmd('InsertText','\t');
1162 else if (k === e.ENTER) {
1164 me.execCmd('InsertHtml','<br /><br />');
1170 return null; // not needed, so null
1173 <span id='Ext-form-field-HtmlEditor-method-getToolbar'> /**
1174 </span> * Returns the editor's toolbar. <b>This is only available after the editor has been rendered.</b>
1175 * @return {Ext.toolbar.Toolbar}
1177 getToolbar : function(){
1178 return this.toolbar;
1181 <span id='Ext-form-field-HtmlEditor-property-buttonTips'> /**
1182 </span> * Object collection of toolbar tooltips for the buttons in the editor. The key
1183 * is the command id associated with that button and the value is a valid QuickTips object.
1185 <pre><code>
1188 title: 'Bold (Ctrl+B)',
1189 text: 'Make the selected text bold.',
1190 cls: 'x-html-editor-tip'
1193 title: 'Italic (Ctrl+I)',
1194 text: 'Make the selected text italic.',
1195 cls: 'x-html-editor-tip'
1198 </code></pre>
1203 title: 'Bold (Ctrl+B)',
1204 text: 'Make the selected text bold.',
1205 cls: Ext.baseCSSPrefix + 'html-editor-tip'
1208 title: 'Italic (Ctrl+I)',
1209 text: 'Make the selected text italic.',
1210 cls: Ext.baseCSSPrefix + 'html-editor-tip'
1213 title: 'Underline (Ctrl+U)',
1214 text: 'Underline the selected text.',
1215 cls: Ext.baseCSSPrefix + 'html-editor-tip'
1217 increasefontsize : {
1219 text: 'Increase the font size.',
1220 cls: Ext.baseCSSPrefix + 'html-editor-tip'
1222 decreasefontsize : {
1223 title: 'Shrink Text',
1224 text: 'Decrease the font size.',
1225 cls: Ext.baseCSSPrefix + 'html-editor-tip'
1228 title: 'Text Highlight Color',
1229 text: 'Change the background color of the selected text.',
1230 cls: Ext.baseCSSPrefix + 'html-editor-tip'
1233 title: 'Font Color',
1234 text: 'Change the color of the selected text.',
1235 cls: Ext.baseCSSPrefix + 'html-editor-tip'
1238 title: 'Align Text Left',
1239 text: 'Align text to the left.',
1240 cls: Ext.baseCSSPrefix + 'html-editor-tip'
1243 title: 'Center Text',
1244 text: 'Center text in the editor.',
1245 cls: Ext.baseCSSPrefix + 'html-editor-tip'
1248 title: 'Align Text Right',
1249 text: 'Align text to the right.',
1250 cls: Ext.baseCSSPrefix + 'html-editor-tip'
1252 insertunorderedlist : {
1253 title: 'Bullet List',
1254 text: 'Start a bulleted list.',
1255 cls: Ext.baseCSSPrefix + 'html-editor-tip'
1257 insertorderedlist : {
1258 title: 'Numbered List',
1259 text: 'Start a numbered list.',
1260 cls: Ext.baseCSSPrefix + 'html-editor-tip'
1264 text: 'Make the selected text a hyperlink.',
1265 cls: Ext.baseCSSPrefix + 'html-editor-tip'
1268 title: 'Source Edit',
1269 text: 'Switch to source editing mode.',
1270 cls: Ext.baseCSSPrefix + 'html-editor-tip'
1274 // hide stuff that is not compatible
1275 <span id='Ext-form-field-HtmlEditor-event-blur'> /**
1276 </span> * @event blur
1279 <span id='Ext-form-field-HtmlEditor-event-change'> /**
1280 </span> * @event change
1283 <span id='Ext-form-field-HtmlEditor-event-focus'> /**
1284 </span> * @event focus
1287 <span id='Ext-form-field-HtmlEditor-event-specialkey'> /**
1288 </span> * @event specialkey
1291 <span id='Ext-form-field-HtmlEditor-cfg-fieldCls'> /**
1292 </span> * @cfg {String} fieldCls @hide
1294 <span id='Ext-form-field-HtmlEditor-cfg-focusCls'> /**
1295 </span> * @cfg {String} focusCls @hide
1297 <span id='Ext-form-field-HtmlEditor-cfg-autoCreate'> /**
1298 </span> * @cfg {String} autoCreate @hide
1300 <span id='Ext-form-field-HtmlEditor-cfg-inputType'> /**
1301 </span> * @cfg {String} inputType @hide
1303 <span id='Ext-form-field-HtmlEditor-cfg-invalidCls'> /**
1304 </span> * @cfg {String} invalidCls @hide
1306 <span id='Ext-form-field-HtmlEditor-cfg-invalidText'> /**
1307 </span> * @cfg {String} invalidText @hide
1309 <span id='Ext-form-field-HtmlEditor-cfg-msgFx'> /**
1310 </span> * @cfg {String} msgFx @hide
1312 <span id='Ext-form-field-HtmlEditor-cfg-allowDomMove'> /**
1313 </span> * @cfg {Boolean} allowDomMove @hide
1315 <span id='Ext-form-field-HtmlEditor-cfg-applyTo'> /**
1316 </span> * @cfg {String} applyTo @hide
1318 <span id='Ext-form-field-HtmlEditor-cfg-readOnly'> /**
1319 </span> * @cfg {String} readOnly @hide
1321 <span id='Ext-form-field-HtmlEditor-cfg-tabIndex'> /**
1322 </span> * @cfg {String} tabIndex @hide
1324 <span id='Ext-form-field-HtmlEditor-method-validate'> /**
1325 </span> * @method validate