X-Git-Url: http://git.ithinksw.org/extjs.git/blobdiff_plain/25ef3491bd9ae007ff1fc2b0d7943e6eaaccf775..b37ceabb82336ee82757cd32efe353cfab8ec267:/docs/source/HtmlEditor.html?ds=sidebyside diff --git a/docs/source/HtmlEditor.html b/docs/source/HtmlEditor.html index 2aaa0637..2010253c 100644 --- a/docs/source/HtmlEditor.html +++ b/docs/source/HtmlEditor.html @@ -1,1181 +1,1277 @@
+/*! - * Ext JS Library 3.0.3 - * Copyright(c) 2006-2009 Ext JS, LLC + * Ext JS Library 3.2.2 + * Copyright(c) 2006-2010 Ext JS, Inc. * licensing@extjs.com * http://www.extjs.com/license */ -/** - * @class Ext.form.HtmlEditor - * @extends Ext.form.Field - * Provides a lightweight HTML Editor component. Some toolbar features are not supported by Safari and will be - * automatically hidden when needed. These are noted in the config options where appropriate. - *+/** + * @class Ext.form.HtmlEditor + * @extends Ext.form.Field + * Provides a lightweight HTML Editor component. Some toolbar features are not supported by Safari and will be + * automatically hidden when needed. These are noted in the config options where appropriate. + *
The editor's toolbar buttons have tooltips defined in the {@link #buttonTips} property, but they are not - * enabled by default unless the global {@link Ext.QuickTips} singleton is {@link Ext.QuickTips#init initialized}. - *
Note: The focus/blur and validation marking functionality inherited from Ext.form.Field is NOT - * supported by this editor. - *
An Editor is a sensitive component that can't be used in all spots standard fields can be used. Putting an Editor within - * any element that has display set to 'none' can cause problems in Safari and Firefox due to their default iframe reloading bugs. - *
Example usage: - *- * @constructor - * Create a new HtmlEditor - * @param {Object} config - * @xtype htmleditor - */ - -Ext.form.HtmlEditor = Ext.extend(Ext.form.Field, { - /** - * @cfg {Boolean} enableFormat Enable the bold, italic and underline buttons (defaults to true) - */ - enableFormat : true, - /** - * @cfg {Boolean} enableFontSize Enable the increase/decrease font size buttons (defaults to true) - */ - enableFontSize : true, - /** - * @cfg {Boolean} enableColors Enable the fore/highlight color buttons (defaults to true) - */ - enableColors : true, - /** - * @cfg {Boolean} enableAlignments Enable the left, center, right alignment buttons (defaults to true) - */ - enableAlignments : true, - /** - * @cfg {Boolean} enableLists Enable the bullet and numbered list buttons. Not available in Safari. (defaults to true) - */ - enableLists : true, - /** - * @cfg {Boolean} enableSourceEdit Enable the switch to source edit button. Not available in Safari. (defaults to true) - */ - enableSourceEdit : true, - /** - * @cfg {Boolean} enableLinks Enable the create link button. Not available in Safari. (defaults to true) - */ - enableLinks : true, - /** - * @cfg {Boolean} enableFont Enable font selection. Not available in Safari. (defaults to true) - */ - enableFont : true, - /** - * @cfg {String} createLinkText The default text for the create link prompt - */ - createLinkText : 'Please enter the URL for the link:', - /** - * @cfg {String} defaultLinkValue The default value for the create link prompt (defaults to http:/ /) - */ - defaultLinkValue : 'http:/'+'/', - /** - * @cfg {Array} fontFamilies An array of available font families - */ - fontFamilies : [ - 'Arial', - 'Courier New', - 'Tahoma', - 'Times New Roman', - 'Verdana' - ], - defaultFont: 'tahoma', - /** - * @cfg {String} defaultValue A default value to be put into the editor to resolve focus issues (defaults to (Zero-width space), (Non-breaking space) in Opera and IE6). - */ - defaultValue: (Ext.isOpera || Ext.isIE6) ? ' ' : '', - - // private properties - actionMode: 'wrap', - validationEvent : false, - deferHeight: true, - initialized : false, - activated : false, - sourceEditMode : false, - onFocus : Ext.emptyFn, - iframePad:3, - hideMode:'offsets', - defaultAutoCreate : { - tag: "textarea", - style:"width:500px;height:300px;", - autocomplete: "off" - }, - - // private - initComponent : function(){ - this.addEvents( - /** - * @event initialize - * Fires when the editor is fully initialized (including the iframe) - * @param {HtmlEditor} this - */ - 'initialize', - /** - * @event activate - * Fires when the editor is first receives the focus. Any insertion must wait - * until after this event. - * @param {HtmlEditor} this - */ - 'activate', - /** - * @event beforesync - * Fires before the textarea is updated with content from the editor iframe. Return false - * to cancel the sync. - * @param {HtmlEditor} this - * @param {String} html - */ - 'beforesync', - /** - * @event beforepush - * Fires before the iframe editor is updated with content from the textarea. Return false - * to cancel the push. - * @param {HtmlEditor} this - * @param {String} html - */ - 'beforepush', - /** - * @event sync - * Fires when the textarea is updated with content from the editor iframe. - * @param {HtmlEditor} this - * @param {String} html - */ - 'sync', - /** - * @event push - * Fires when the iframe editor is updated with content from the textarea. - * @param {HtmlEditor} this - * @param {String} html - */ - 'push', - /** - * @event editmodechange - * Fires when the editor switches edit modes - * @param {HtmlEditor} this - * @param {Boolean} sourceEdit True if source edit, false if standard editing. - */ - 'editmodechange' - ) - }, - - // private - createFontOptions : function(){ - var buf = [], fs = this.fontFamilies, ff, lc; - for(var i = 0, len = fs.length; i< len; i++){ - ff = fs[i]; - lc = ff.toLowerCase(); - buf.push( - '' - ); - } - return buf.join(''); - }, - - /* - * Protected method that will not generally be called directly. It - * is called when the editor creates its toolbar. Override this method if you need to - * add custom toolbar buttons. - * @param {HtmlEditor} editor - */ - createToolbar : function(editor){ - - var tipsEnabled = Ext.QuickTips && Ext.QuickTips.isEnabled(); - - function btn(id, toggle, handler){ - return { - itemId : id, - cls : 'x-btn-icon', - iconCls: 'x-edit-'+id, - enableToggle:toggle !== false, - scope: editor, - handler:handler||editor.relayBtnCmd, - clickEvent:'mousedown', - tooltip: tipsEnabled ? editor.buttonTips[id] || undefined : undefined, - overflowText: editor.buttonTips[id].title || undefined, - tabIndex:-1 - }; - } - - // build the toolbar - var tb = new Ext.Toolbar({ - renderTo:this.wrap.dom.firstChild - }); - - // stop form submits - this.mon(tb.el, 'click', function(e){ - e.preventDefault(); - }); - - if(this.enableFont && !Ext.isSafari2){ - this.fontSelect = tb.el.createChild({ - tag:'select', - cls:'x-font-select', - html: this.createFontOptions() - }); - this.mon(this.fontSelect, 'change', function(){ - var font = this.fontSelect.dom.value; - this.relayCmd('fontname', font); - this.deferFocus(); - }, this); - - tb.add( - this.fontSelect.dom, - '-' - ); - } - - if(this.enableFormat){ - tb.add( - btn('bold'), - btn('italic'), - btn('underline') - ); - } - - if(this.enableFontSize){ - tb.add( - '-', - btn('increasefontsize', false, this.adjustFont), - btn('decreasefontsize', false, this.adjustFont) - ); - } - - if(this.enableColors){ - tb.add( - '-', { - itemId:'forecolor', - cls:'x-btn-icon', - iconCls: 'x-edit-forecolor', - clickEvent:'mousedown', - tooltip: tipsEnabled ? editor.buttonTips.forecolor || undefined : undefined, - tabIndex:-1, - menu : new Ext.menu.ColorMenu({ - allowReselect: true, - focus: Ext.emptyFn, - value:'000000', - plain:true, - listeners: { - scope: this, - select: function(cp, color){ - this.execCmd('forecolor', Ext.isWebKit || Ext.isIE ? '#'+color : color); - this.deferFocus(); - } - }, - clickEvent:'mousedown' - }) - }, { - itemId:'backcolor', - cls:'x-btn-icon', - iconCls: 'x-edit-backcolor', - clickEvent:'mousedown', - tooltip: tipsEnabled ? editor.buttonTips.backcolor || undefined : undefined, - tabIndex:-1, - menu : new Ext.menu.ColorMenu({ - focus: Ext.emptyFn, - value:'FFFFFF', - plain:true, - allowReselect: true, - listeners: { - scope: this, - select: function(cp, color){ - if(Ext.isGecko){ - this.execCmd('useCSS', false); - this.execCmd('hilitecolor', color); - this.execCmd('useCSS', true); - this.deferFocus(); - }else{ - this.execCmd(Ext.isOpera ? 'hilitecolor' : 'backcolor', Ext.isWebKit || Ext.isIE ? '#'+color : color); - this.deferFocus(); - } - } - }, - clickEvent:'mousedown' - }) - } - ); - } - - if(this.enableAlignments){ - tb.add( - '-', - btn('justifyleft'), - btn('justifycenter'), - btn('justifyright') - ); - } - - if(!Ext.isSafari2){ - if(this.enableLinks){ - tb.add( - '-', - btn('createlink', false, this.createLink) - ); - } - - if(this.enableLists){ - tb.add( - '-', - btn('insertorderedlist'), - btn('insertunorderedlist') - ); - } - if(this.enableSourceEdit){ - tb.add( - '-', - btn('sourceedit', true, function(btn){ - this.toggleSourceEdit(!this.sourceEditMode); - }) - ); - } - } - - this.tb = tb; - }, - - /** - * Protected method that will not generally be called directly. It - * is called when the editor initializes the iframe with HTML contents. Override this method if you - * want to change the initialization markup of the iframe (e.g. to add stylesheets). - */ - getDocMarkup : function(){ - return ''; - }, - - // private - getEditorBody : function(){ - return this.doc.body || this.doc.documentElement; - }, - - // private - getDoc : function(){ - return Ext.isIE ? this.getWin().document : (this.iframe.contentDocument || this.getWin().document); - }, - - // private - getWin : function(){ - return Ext.isIE ? this.iframe.contentWindow : window.frames[this.iframe.name]; - }, - - // private - onRender : function(ct, position){ - Ext.form.HtmlEditor.superclass.onRender.call(this, ct, position); - this.el.dom.style.border = '0 none'; - this.el.dom.setAttribute('tabIndex', -1); - this.el.addClass('x-hidden'); - if(Ext.isIE){ // fix IE 1px bogus margin - this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;') - } - this.wrap = this.el.wrap({ - cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'} - }); - - this.createToolbar(this); - - this.disableItems(true); - // is this needed? - // this.tb.doLayout(); - - this.createIFrame(); - - if(!this.width){ - var sz = this.el.getSize(); - this.setSize(sz.width, this.height || sz.height); - } - this.resizeEl = this.positionEl = this.wrap; - }, - - createIFrame: function(){ - var iframe = document.createElement('iframe'); - iframe.name = Ext.id(); - iframe.frameBorder = '0'; - iframe.src = Ext.SSL_SECURE_URL; - this.wrap.dom.appendChild(iframe); - - this.iframe = iframe; - - this.monitorTask = Ext.TaskMgr.start({ - run: this.checkDesignMode, - scope: this, - interval:100 - }); - }, - - initFrame : function(){ - Ext.TaskMgr.stop(this.monitorTask); - this.doc = this.getDoc(); - this.win = this.getWin(); - - this.doc.open(); - this.doc.write(this.getDocMarkup()); - this.doc.close(); - - var task = { // must defer to wait for browser to be ready - run : function(){ - if(this.doc.body || this.doc.readyState == 'complete'){ - Ext.TaskMgr.stop(task); - this.doc.designMode="on"; - this.initEditor.defer(10, this); - } - }, - interval : 10, - duration:10000, - scope: this - }; - Ext.TaskMgr.start(task); - }, - - - checkDesignMode : function(){ - if(this.wrap && this.wrap.dom.offsetWidth){ - var doc = this.getDoc(); - if(!doc){ - return; - } - if(!doc.editorInitialized || String(doc.designMode).toLowerCase() != 'on'){ - this.initFrame(); - } - } - }, - - disableItems: function(disabled){ - if(this.fontSelect){ - this.fontSelect.dom.disabled = disabled; - } - this.tb.items.each(function(item){ - if(item.getItemId() != 'sourceedit'){ - item.setDisabled(disabled); - } - }); - }, - - // private - onResize : function(w, h){ - Ext.form.HtmlEditor.superclass.onResize.apply(this, arguments); - if(this.el && this.iframe){ - if(Ext.isNumber(w)){ - var aw = w - this.wrap.getFrameWidth('lr'); - this.el.setWidth(aw); - this.tb.setWidth(aw); - this.iframe.style.width = Math.max(aw, 0) + 'px'; - } - if(Ext.isNumber(h)){ - var ah = h - this.wrap.getFrameWidth('tb') - this.tb.el.getHeight(); - this.el.setHeight(ah); - this.iframe.style.height = Math.max(ah, 0) + 'px'; - if(this.doc){ - this.getEditorBody().style.height = Math.max((ah - (this.iframePad*2)), 0) + 'px'; - } - } - } - }, - - /** - * Toggles the editor between standard and source edit mode. - * @param {Boolean} sourceEdit (optional) True for source edit, false for standard - */ - toggleSourceEdit : function(sourceEditMode){ - if(sourceEditMode === undefined){ - sourceEditMode = !this.sourceEditMode; - } - this.sourceEditMode = sourceEditMode === true; - var btn = this.tb.items.get('sourceedit'); - if(btn.pressed !== this.sourceEditMode){ - btn.toggle(this.sourceEditMode); - if(!btn.xtbHidden){ - return; - } - } - if(this.sourceEditMode){ - this.disableItems(true); - this.syncValue(); - this.iframe.className = 'x-hidden'; - this.el.removeClass('x-hidden'); - this.el.dom.removeAttribute('tabIndex'); - this.el.focus(); - }else{ - if(this.initialized){ - this.disableItems(false); - } - this.pushValue(); - this.iframe.className = ''; - this.el.addClass('x-hidden'); - this.el.dom.setAttribute('tabIndex', -1); - this.deferFocus(); - } - var lastSize = this.lastSize; - if(lastSize){ - delete this.lastSize; - this.setSize(lastSize); - } - this.fireEvent('editmodechange', this, this.sourceEditMode); - }, - - // private used internally - createLink : function(){ - var url = prompt(this.createLinkText, this.defaultLinkValue); - if(url && url != 'http:/'+'/'){ - this.relayCmd('createlink', url); - } - }, - - // private - initEvents : function(){ - this.originalValue = this.getValue(); - }, - - /** - * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide - * @method - */ - markInvalid : Ext.emptyFn, - - /** - * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide - * @method - */ - clearInvalid : Ext.emptyFn, - - // docs inherit from Field - setValue : function(v){ - Ext.form.HtmlEditor.superclass.setValue.call(this, v); - this.pushValue(); - return this; - }, - - /** - * Protected method that will not generally be called directly. If you need/want - * custom HTML cleanup, this is the method you should override. - * @param {String} html The HTML to be cleaned - * @return {String} The cleaned HTML - */ - cleanHtml: function(html) { - html = String(html); - if(Ext.isWebKit){ // strip safari nonsense - html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, ''); - } - - /* - * Neat little hack. Strips out all the non-digit characters from the default - * value and compares it to the character code of the first character in the string - * because it can cause encoding issues when posted to the server. - */ - if(html.charCodeAt(0) == this.defaultValue.replace(/\D/g, '')){ - html = html.substring(1); - } - return html; - }, - - /** - * Protected method that will not generally be called directly. Syncs the contents - * of the editor iframe with the textarea. - */ - syncValue : function(){ - if(this.initialized){ - var bd = this.getEditorBody(); - var html = bd.innerHTML; - if(Ext.isWebKit){ - var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element! - var m = bs.match(/text-align:(.*?);/i); - if(m && m[1]){ - html = '-// Simple example rendered with default options: -Ext.QuickTips.init(); // enable tooltips -new Ext.form.HtmlEditor({ - renderTo: Ext.getBody(), - width: 800, - height: 300 -}); - -// Passed via xtype into a container and with custom options: -Ext.QuickTips.init(); // enable tooltips -new Ext.Panel({ - title: 'HTML Editor', - renderTo: Ext.getBody(), - width: 600, - height: 300, - frame: true, - layout: 'fit', - items: { - xtype: 'htmleditor', - enableColors: false, - enableAlignments: false - } -}); -
' + html + ''; - } - } - html = this.cleanHtml(html); - if(this.fireEvent('beforesync', this, html) !== false){ - this.el.dom.value = html; - this.fireEvent('sync', this, html); - } - } - }, - - //docs inherit from Field - getValue : function() { - this[this.sourceEditMode ? 'pushValue' : 'syncValue'](); - return Ext.form.HtmlEditor.superclass.getValue.call(this); - }, - - /** - * Protected method that will not generally be called directly. Pushes the value of the textarea - * into the iframe editor. - */ - pushValue : function(){ - if(this.initialized){ - var v = this.el.dom.value; - if(!this.activated && v.length < 1){ - v = this.defaultValue; - } - if(this.fireEvent('beforepush', this, v) !== false){ - this.getEditorBody().innerHTML = v; - if(Ext.isGecko){ - // Gecko hack, see: https://bugzilla.mozilla.org/show_bug.cgi?id=232791#c8 - var d = this.doc, - mode = d.designMode.toLowerCase(); - - d.designMode = mode.toggle('on', 'off'); - d.designMode = mode; - } - this.fireEvent('push', this, v); - } - } - }, - - // private - deferFocus : function(){ - this.focus.defer(10, this); - }, - - // docs inherit from Field - focus : function(){ - if(this.win && !this.sourceEditMode){ - this.win.focus(); - }else{ - this.el.focus(); - } - }, - - // private - initEditor : function(){ - //Destroying the component during/before initEditor can cause issues. - try{ - var dbody = this.getEditorBody(); - var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat'); - ss['background-attachment'] = 'fixed'; // w3c - dbody.bgProperties = 'fixed'; // ie - - Ext.DomHelper.applyStyles(dbody, ss); - - if(this.doc){ - try{ - Ext.EventManager.removeAll(this.doc); - }catch(e){} - } - - this.doc = this.getDoc(); - - Ext.EventManager.on(this.doc, { - 'mousedown': this.onEditorEvent, - 'dblclick': this.onEditorEvent, - 'click': this.onEditorEvent, - 'keyup': this.onEditorEvent, - buffer:100, - scope: this - }); - - if(Ext.isGecko){ - Ext.EventManager.on(this.doc, 'keypress', this.applyCommand, this); - } - if(Ext.isIE || Ext.isWebKit || Ext.isOpera){ - Ext.EventManager.on(this.doc, 'keydown', this.fixKeys, this); - } - this.initialized = true; - this.fireEvent('initialize', this); - this.doc.editorInitialized = true; - this.pushValue(); - }catch(e){} - }, - - // private - onDestroy : function(){ - if(this.monitorTask){ - Ext.TaskMgr.stop(this.monitorTask); - } - if(this.rendered){ - Ext.destroy(this.tb); - if(this.wrap){ - this.wrap.dom.innerHTML = ''; - this.wrap.remove(); - } - } - if(this.el){ - this.el.removeAllListeners(); - this.el.remove(); - } - - if(this.doc){ - try{ - Ext.EventManager.removeAll(this.doc); - for (var prop in this.doc){ - delete this.doc[prop]; - } - }catch(e){} - } - this.purgeListeners(); - }, - - // private - onFirstFocus : function(){ - this.activated = true; - this.disableItems(false); - if(Ext.isGecko){ // prevent silly gecko errors - this.win.focus(); - var s = this.win.getSelection(); - if(!s.focusNode || s.focusNode.nodeType != 3){ - var r = s.getRangeAt(0); - r.selectNodeContents(this.getEditorBody()); - r.collapse(true); - this.deferFocus(); - } - try{ - this.execCmd('useCSS', true); - this.execCmd('styleWithCSS', false); - }catch(e){} - } - this.fireEvent('activate', this); - }, - - // private - adjustFont: function(btn){ - var adjust = btn.getItemId() == 'increasefontsize' ? 1 : -1; - - var v = parseInt(this.doc.queryCommandValue('FontSize') || 2, 10); - if((Ext.isSafari && !Ext.isSafari2) || Ext.isChrome || Ext.isAir){ - // Safari 3 values - // 1 = 10px, 2 = 13px, 3 = 16px, 4 = 18px, 5 = 24px, 6 = 32px - if(v <= 10){ - v = 1 + adjust; - }else if(v <= 13){ - v = 2 + adjust; - }else if(v <= 16){ - v = 3 + adjust; - }else if(v <= 18){ - v = 4 + adjust; - }else if(v <= 24){ - v = 5 + adjust; - }else { - v = 6 + adjust; - } - v = v.constrain(1, 6); - }else{ - if(Ext.isSafari){ // safari - adjust *= 2; - } - v = Math.max(1, v+adjust) + (Ext.isSafari ? 'px' : 0); - } - this.execCmd('FontSize', v); - }, - - // private - onEditorEvent : function(e){ - this.updateToolbar(); - }, - - - /** - * Protected method that will not generally be called directly. It triggers - * a toolbar update by reading the markup state of the current selection in the editor. - */ - updateToolbar: function(){ - - if(!this.activated){ - this.onFirstFocus(); - return; - } - - var btns = this.tb.items.map, doc = this.doc; - - if(this.enableFont && !Ext.isSafari2){ - var name = (this.doc.queryCommandValue('FontName')||this.defaultFont).toLowerCase(); - if(name != this.fontSelect.dom.value){ - this.fontSelect.dom.value = name; - } - } - if(this.enableFormat){ - btns.bold.toggle(doc.queryCommandState('bold')); - btns.italic.toggle(doc.queryCommandState('italic')); - btns.underline.toggle(doc.queryCommandState('underline')); - } - if(this.enableAlignments){ - btns.justifyleft.toggle(doc.queryCommandState('justifyleft')); - btns.justifycenter.toggle(doc.queryCommandState('justifycenter')); - btns.justifyright.toggle(doc.queryCommandState('justifyright')); - } - if(!Ext.isSafari2 && this.enableLists){ - btns.insertorderedlist.toggle(doc.queryCommandState('insertorderedlist')); - btns.insertunorderedlist.toggle(doc.queryCommandState('insertunorderedlist')); - } - - Ext.menu.MenuMgr.hideAll(); - - this.syncValue(); - }, - - // private - relayBtnCmd : function(btn){ - this.relayCmd(btn.getItemId()); - }, - - /** - * Executes a Midas editor command on the editor document and performs necessary focus and - * toolbar updates. This should only be called after the editor is initialized. - * @param {String} cmd The Midas command - * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null) - */ - relayCmd : function(cmd, value){ - (function(){ - this.focus(); - this.execCmd(cmd, value); - this.updateToolbar(); - }).defer(10, this); - }, - - /** - * Executes a Midas editor command directly on the editor document. - * For visual commands, you should use {@link #relayCmd} instead. - * This should only be called after the editor is initialized. - * @param {String} cmd The Midas command - * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null) - */ - execCmd : function(cmd, value){ - this.doc.execCommand(cmd, false, value === undefined ? null : value); - this.syncValue(); - }, - - // private - applyCommand : function(e){ - if(e.ctrlKey){ - var c = e.getCharCode(), cmd; - if(c > 0){ - c = String.fromCharCode(c); - switch(c){ - case 'b': - cmd = 'bold'; - break; - case 'i': - cmd = 'italic'; - break; - case 'u': - cmd = 'underline'; - break; - } - if(cmd){ - this.win.focus(); - this.execCmd(cmd); - this.deferFocus(); - e.preventDefault(); - } - } - } - }, - - /** - * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated - * to insert text. - * @param {String} text - */ - insertAtCursor : function(text){ - if(!this.activated){ - return; - } - if(Ext.isIE){ - this.win.focus(); - var r = this.doc.selection.createRange(); - if(r){ - r.collapse(true); - r.pasteHTML(text); - this.syncValue(); - this.deferFocus(); - } - }else{ - this.win.focus(); - this.execCmd('InsertHTML', text); - this.deferFocus(); - } - }, - - // private - fixKeys : function(){ // load time branching for fastest keydown performance - if(Ext.isIE){ - return function(e){ - var k = e.getKey(), r; - if(k == e.TAB){ - e.stopEvent(); - r = this.doc.selection.createRange(); - if(r){ - r.collapse(true); - r.pasteHTML(' '); - this.deferFocus(); - } - }else if(k == e.ENTER){ - r = this.doc.selection.createRange(); - if(r){ - var target = r.parentElement(); - if(!target || target.tagName.toLowerCase() != 'li'){ - e.stopEvent(); - r.pasteHTML('
'); - r.collapse(false); - r.select(); - } - } - } - }; - }else if(Ext.isOpera){ - return function(e){ - var k = e.getKey(); - if(k == e.TAB){ - e.stopEvent(); - this.win.focus(); - this.execCmd('InsertHTML',' '); - this.deferFocus(); - } - }; - }else if(Ext.isWebKit){ - return function(e){ - var k = e.getKey(); - if(k == e.TAB){ - e.stopEvent(); - this.execCmd('InsertText','\t'); - this.deferFocus(); - }else if(k == e.ENTER){ - e.stopEvent(); - this.execCmd('InsertHtml','
'); - this.deferFocus(); - } - }; - } - }(), - - /** - * Returns the editor's toolbar. This is only available after the editor has been rendered. - * @return {Ext.Toolbar} - */ - getToolbar : function(){ - return this.tb; - }, - - /** - * Object collection of toolbar tooltips for the buttons in the editor. The key - * is the command id associated with that button and the value is a valid QuickTips object. - * For example: -- * @type Object - */ - buttonTips : { - bold : { - title: 'Bold (Ctrl+B)', - text: 'Make the selected text bold.', - cls: 'x-html-editor-tip' - }, - italic : { - title: 'Italic (Ctrl+I)', - text: 'Make the selected text italic.', - cls: 'x-html-editor-tip' - }, - underline : { - title: 'Underline (Ctrl+U)', - text: 'Underline the selected text.', - cls: 'x-html-editor-tip' - }, - increasefontsize : { - title: 'Grow Text', - text: 'Increase the font size.', - cls: 'x-html-editor-tip' - }, - decreasefontsize : { - title: 'Shrink Text', - text: 'Decrease the font size.', - cls: 'x-html-editor-tip' - }, - backcolor : { - title: 'Text Highlight Color', - text: 'Change the background color of the selected text.', - cls: 'x-html-editor-tip' - }, - forecolor : { - title: 'Font Color', - text: 'Change the color of the selected text.', - cls: 'x-html-editor-tip' - }, - justifyleft : { - title: 'Align Text Left', - text: 'Align text to the left.', - cls: 'x-html-editor-tip' - }, - justifycenter : { - title: 'Center Text', - text: 'Center text in the editor.', - cls: 'x-html-editor-tip' - }, - justifyright : { - title: 'Align Text Right', - text: 'Align text to the right.', - cls: 'x-html-editor-tip' - }, - insertunorderedlist : { - title: 'Bullet List', - text: 'Start a bulleted list.', - cls: 'x-html-editor-tip' - }, - insertorderedlist : { - title: 'Numbered List', - text: 'Start a numbered list.', - cls: 'x-html-editor-tip' - }, - createlink : { - title: 'Hyperlink', - text: 'Make the selected text a hyperlink.', - cls: 'x-html-editor-tip' - }, - sourceedit : { - title: 'Source Edit', - text: 'Switch to source editing mode.', - cls: 'x-html-editor-tip' - } - } - - // hide stuff that is not compatible - /** - * @event blur - * @hide - */ - /** - * @event change - * @hide - */ - /** - * @event focus - * @hide - */ - /** - * @event specialkey - * @hide - */ - /** - * @cfg {String} fieldClass @hide - */ - /** - * @cfg {String} focusClass @hide - */ - /** - * @cfg {String} autoCreate @hide - */ - /** - * @cfg {String} inputType @hide - */ - /** - * @cfg {String} invalidClass @hide - */ - /** - * @cfg {String} invalidText @hide - */ - /** - * @cfg {String} msgFx @hide - */ - /** - * @cfg {String} validateOnBlur @hide - */ - /** - * @cfg {Boolean} allowDomMove @hide - */ - /** - * @cfg {String} applyTo @hide - */ - /** - * @cfg {String} autoHeight @hide - */ - /** - * @cfg {String} autoWidth @hide - */ - /** - * @cfg {String} cls @hide - */ - /** - * @cfg {String} disabled @hide - */ - /** - * @cfg {String} disabledClass @hide - */ - /** - * @cfg {String} msgTarget @hide - */ - /** - * @cfg {String} readOnly @hide - */ - /** - * @cfg {String} style @hide - */ - /** - * @cfg {String} validationDelay @hide - */ - /** - * @cfg {String} validationEvent @hide - */ - /** - * @cfg {String} tabIndex @hide - */ - /** - * @property disabled - * @hide - */ - /** - * @method applyToMarkup - * @hide - */ - /** - * @method disable - * @hide - */ - /** - * @method enable - * @hide - */ - /** - * @method validate - * @hide - */ - /** - * @event valid - * @hide - */ - /** - * @method setDisabled - * @hide - */ - /** - * @cfg keys - * @hide - */ -}); -Ext.reg('htmleditor', Ext.form.HtmlEditor);-{ - bold : { - title: 'Bold (Ctrl+B)', - text: 'Make the selected text bold.', - cls: 'x-html-editor-tip' - }, - italic : { - title: 'Italic (Ctrl+I)', - text: 'Make the selected text italic.', - cls: 'x-html-editor-tip' - }, - ... -
+// Simple example rendered with default options:
+Ext.QuickTips.init(); // enable tooltips
+new Ext.form.HtmlEditor({
+ renderTo: Ext.getBody(),
+ width: 800,
+ height: 300
+});
+
+// Passed via xtype into a container and with custom options:
+Ext.QuickTips.init(); // enable tooltips
+new Ext.Panel({
+ title: 'HTML Editor',
+ renderTo: Ext.getBody(),
+ width: 600,
+ height: 300,
+ frame: true,
+ layout: 'fit',
+ items: {
+ xtype: 'htmleditor',
+ enableColors: false,
+ enableAlignments: false
+ }
+});
+
+ * @constructor
+ * Create a new HtmlEditor
+ * @param {Object} config
+ * @xtype htmleditor
+ */
+
+Ext.form.HtmlEditor = Ext.extend(Ext.form.Field, {
+ /**
+ * @cfg {Boolean} enableFormat Enable the bold, italic and underline buttons (defaults to true)
+ */
+ enableFormat : true,
+ /**
+ * @cfg {Boolean} enableFontSize Enable the increase/decrease font size buttons (defaults to true)
+ */
+ enableFontSize : true,
+ /**
+ * @cfg {Boolean} enableColors Enable the fore/highlight color buttons (defaults to true)
+ */
+ enableColors : true,
+ /**
+ * @cfg {Boolean} enableAlignments Enable the left, center, right alignment buttons (defaults to true)
+ */
+ enableAlignments : true,
+ /**
+ * @cfg {Boolean} enableLists Enable the bullet and numbered list buttons. Not available in Safari. (defaults to true)
+ */
+ enableLists : true,
+ /**
+ * @cfg {Boolean} enableSourceEdit Enable the switch to source edit button. Not available in Safari. (defaults to true)
+ */
+ enableSourceEdit : true,
+ /**
+ * @cfg {Boolean} enableLinks Enable the create link button. Not available in Safari. (defaults to true)
+ */
+ enableLinks : true,
+ /**
+ * @cfg {Boolean} enableFont Enable font selection. Not available in Safari. (defaults to true)
+ */
+ enableFont : true,
+ /**
+ * @cfg {String} createLinkText The default text for the create link prompt
+ */
+ createLinkText : 'Please enter the URL for the link:',
+ /**
+ * @cfg {String} defaultLinkValue The default value for the create link prompt (defaults to http:/ /)
+ */
+ defaultLinkValue : 'http:/'+'/',
+ /**
+ * @cfg {Array} fontFamilies An array of available font families
+ */
+ fontFamilies : [
+ 'Arial',
+ 'Courier New',
+ 'Tahoma',
+ 'Times New Roman',
+ 'Verdana'
+ ],
+ defaultFont: 'tahoma',
+ /**
+ * @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).
+ */
+ defaultValue: (Ext.isOpera || Ext.isIE6) ? ' ' : '',
+
+ // private properties
+ actionMode: 'wrap',
+ validationEvent : false,
+ deferHeight: true,
+ initialized : false,
+ activated : false,
+ sourceEditMode : false,
+ onFocus : Ext.emptyFn,
+ iframePad:3,
+ hideMode:'offsets',
+ defaultAutoCreate : {
+ tag: "textarea",
+ style:"width:500px;height:300px;",
+ autocomplete: "off"
+ },
+
+ // private
+ initComponent : function(){
+ this.addEvents(
+ /**
+ * @event initialize
+ * Fires when the editor is fully initialized (including the iframe)
+ * @param {HtmlEditor} this
+ */
+ 'initialize',
+ /**
+ * @event activate
+ * Fires when the editor is first receives the focus. Any insertion must wait
+ * until after this event.
+ * @param {HtmlEditor} this
+ */
+ 'activate',
+ /**
+ * @event beforesync
+ * Fires before the textarea is updated with content from the editor iframe. Return false
+ * to cancel the sync.
+ * @param {HtmlEditor} this
+ * @param {String} html
+ */
+ 'beforesync',
+ /**
+ * @event beforepush
+ * Fires before the iframe editor is updated with content from the textarea. Return false
+ * to cancel the push.
+ * @param {HtmlEditor} this
+ * @param {String} html
+ */
+ 'beforepush',
+ /**
+ * @event sync
+ * Fires when the textarea is updated with content from the editor iframe.
+ * @param {HtmlEditor} this
+ * @param {String} html
+ */
+ 'sync',
+ /**
+ * @event push
+ * Fires when the iframe editor is updated with content from the textarea.
+ * @param {HtmlEditor} this
+ * @param {String} html
+ */
+ 'push',
+ /**
+ * @event editmodechange
+ * Fires when the editor switches edit modes
+ * @param {HtmlEditor} this
+ * @param {Boolean} sourceEdit True if source edit, false if standard editing.
+ */
+ 'editmodechange'
+ );
+ },
+
+ // private
+ createFontOptions : function(){
+ var buf = [], fs = this.fontFamilies, ff, lc;
+ for(var i = 0, len = fs.length; i< len; i++){
+ ff = fs[i];
+ lc = ff.toLowerCase();
+ buf.push(
+ ''
+ );
+ }
+ return buf.join('');
+ },
+
+ /*
+ * Protected method that will not generally be called directly. It
+ * is called when the editor creates its toolbar. Override this method if you need to
+ * add custom toolbar buttons.
+ * @param {HtmlEditor} editor
+ */
+ createToolbar : function(editor){
+ var items = [];
+ var tipsEnabled = Ext.QuickTips && Ext.QuickTips.isEnabled();
+
+
+ function btn(id, toggle, handler){
+ return {
+ itemId : id,
+ cls : 'x-btn-icon',
+ iconCls: 'x-edit-'+id,
+ enableToggle:toggle !== false,
+ scope: editor,
+ handler:handler||editor.relayBtnCmd,
+ clickEvent:'mousedown',
+ tooltip: tipsEnabled ? editor.buttonTips[id] || undefined : undefined,
+ overflowText: editor.buttonTips[id].title || undefined,
+ tabIndex:-1
+ };
+ }
+
+
+ if(this.enableFont && !Ext.isSafari2){
+ var fontSelectItem = new Ext.Toolbar.Item({
+ autoEl: {
+ tag:'select',
+ cls:'x-font-select',
+ html: this.createFontOptions()
+ }
+ });
+
+ items.push(
+ fontSelectItem,
+ '-'
+ );
+ }
+
+ if(this.enableFormat){
+ items.push(
+ btn('bold'),
+ btn('italic'),
+ btn('underline')
+ );
+ }
+
+ if(this.enableFontSize){
+ items.push(
+ '-',
+ btn('increasefontsize', false, this.adjustFont),
+ btn('decreasefontsize', false, this.adjustFont)
+ );
+ }
+
+ if(this.enableColors){
+ items.push(
+ '-', {
+ itemId:'forecolor',
+ cls:'x-btn-icon',
+ iconCls: 'x-edit-forecolor',
+ clickEvent:'mousedown',
+ tooltip: tipsEnabled ? editor.buttonTips.forecolor || undefined : undefined,
+ tabIndex:-1,
+ menu : new Ext.menu.ColorMenu({
+ allowReselect: true,
+ focus: Ext.emptyFn,
+ value:'000000',
+ plain:true,
+ listeners: {
+ scope: this,
+ select: function(cp, color){
+ this.execCmd('forecolor', Ext.isWebKit || Ext.isIE ? '#'+color : color);
+ this.deferFocus();
+ }
+ },
+ clickEvent:'mousedown'
+ })
+ }, {
+ itemId:'backcolor',
+ cls:'x-btn-icon',
+ iconCls: 'x-edit-backcolor',
+ clickEvent:'mousedown',
+ tooltip: tipsEnabled ? editor.buttonTips.backcolor || undefined : undefined,
+ tabIndex:-1,
+ menu : new Ext.menu.ColorMenu({
+ focus: Ext.emptyFn,
+ value:'FFFFFF',
+ plain:true,
+ allowReselect: true,
+ listeners: {
+ scope: this,
+ select: function(cp, color){
+ if(Ext.isGecko){
+ this.execCmd('useCSS', false);
+ this.execCmd('hilitecolor', color);
+ this.execCmd('useCSS', true);
+ this.deferFocus();
+ }else{
+ this.execCmd(Ext.isOpera ? 'hilitecolor' : 'backcolor', Ext.isWebKit || Ext.isIE ? '#'+color : color);
+ this.deferFocus();
+ }
+ }
+ },
+ clickEvent:'mousedown'
+ })
+ }
+ );
+ }
+
+ if(this.enableAlignments){
+ items.push(
+ '-',
+ btn('justifyleft'),
+ btn('justifycenter'),
+ btn('justifyright')
+ );
+ }
+
+ if(!Ext.isSafari2){
+ if(this.enableLinks){
+ items.push(
+ '-',
+ btn('createlink', false, this.createLink)
+ );
+ }
+
+ if(this.enableLists){
+ items.push(
+ '-',
+ btn('insertorderedlist'),
+ btn('insertunorderedlist')
+ );
+ }
+ if(this.enableSourceEdit){
+ items.push(
+ '-',
+ btn('sourceedit', true, function(btn){
+ this.toggleSourceEdit(!this.sourceEditMode);
+ })
+ );
+ }
+ }
+
+ // build the toolbar
+ var tb = new Ext.Toolbar({
+ renderTo: this.wrap.dom.firstChild,
+ items: items
+ });
+
+ if (fontSelectItem) {
+ this.fontSelect = fontSelectItem.el;
+
+ this.mon(this.fontSelect, 'change', function(){
+ var font = this.fontSelect.dom.value;
+ this.relayCmd('fontname', font);
+ this.deferFocus();
+ }, this);
+ }
+
+ // stop form submits
+ this.mon(tb.el, 'click', function(e){
+ e.preventDefault();
+ });
+
+ this.tb = tb;
+ this.tb.doLayout();
+ },
+
+ onDisable: function(){
+ this.wrap.mask();
+ Ext.form.HtmlEditor.superclass.onDisable.call(this);
+ },
+
+ onEnable: function(){
+ this.wrap.unmask();
+ Ext.form.HtmlEditor.superclass.onEnable.call(this);
+ },
+
+ setReadOnly: function(readOnly){
+
+ Ext.form.HtmlEditor.superclass.setReadOnly.call(this, readOnly);
+ if(this.initialized){
+ if(Ext.isIE){
+ this.getEditorBody().contentEditable = !readOnly;
+ }else{
+ this.setDesignMode(!readOnly);
+ }
+ var bd = this.getEditorBody();
+ if(bd){
+ bd.style.cursor = this.readOnly ? 'default' : 'text';
+ }
+ this.disableItems(readOnly);
+ }
+ },
+
+ /**
+ * Protected method that will not generally be called directly. It
+ * is called when the editor initializes the iframe with HTML contents. Override this method if you
+ * want to change the initialization markup of the iframe (e.g. to add stylesheets).
+ *
+ * Note: IE8-Standards has unwanted scroller behavior, so the default meta tag forces IE7 compatibility
+ */
+ getDocMarkup : function(){
+ var h = Ext.fly(this.iframe).getHeight() - this.iframePad * 2;
+ return String.format('', this.iframePad, h);
+ },
+
+ // private
+ getEditorBody : function(){
+ var doc = this.getDoc();
+ return doc.body || doc.documentElement;
+ },
+
+ // private
+ getDoc : function(){
+ return Ext.isIE ? this.getWin().document : (this.iframe.contentDocument || this.getWin().document);
+ },
+
+ // private
+ getWin : function(){
+ return Ext.isIE ? this.iframe.contentWindow : window.frames[this.iframe.name];
+ },
+
+ // private
+ onRender : function(ct, position){
+ Ext.form.HtmlEditor.superclass.onRender.call(this, ct, position);
+ this.el.dom.style.border = '0 none';
+ this.el.dom.setAttribute('tabIndex', -1);
+ this.el.addClass('x-hidden');
+ if(Ext.isIE){ // fix IE 1px bogus margin
+ this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;');
+ }
+ this.wrap = this.el.wrap({
+ cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
+ });
+
+ this.createToolbar(this);
+
+ this.disableItems(true);
+
+ this.tb.doLayout();
+
+ this.createIFrame();
+
+ if(!this.width){
+ var sz = this.el.getSize();
+ this.setSize(sz.width, this.height || sz.height);
+ }
+ this.resizeEl = this.positionEl = this.wrap;
+ },
+
+ createIFrame: function(){
+ var iframe = document.createElement('iframe');
+ iframe.name = Ext.id();
+ iframe.frameBorder = '0';
+ iframe.style.overflow = 'auto';
+
+ this.wrap.dom.appendChild(iframe);
+ this.iframe = iframe;
+
+ this.monitorTask = Ext.TaskMgr.start({
+ run: this.checkDesignMode,
+ scope: this,
+ interval:100
+ });
+ },
+
+ initFrame : function(){
+ Ext.TaskMgr.stop(this.monitorTask);
+ var doc = this.getDoc();
+ this.win = this.getWin();
+
+ doc.open();
+ doc.write(this.getDocMarkup());
+ doc.close();
+
+ var task = { // must defer to wait for browser to be ready
+ run : function(){
+ var doc = this.getDoc();
+ if(doc.body || doc.readyState == 'complete'){
+ Ext.TaskMgr.stop(task);
+ this.setDesignMode(true);
+ this.initEditor.defer(10, this);
+ }
+ },
+ interval : 10,
+ duration:10000,
+ scope: this
+ };
+ Ext.TaskMgr.start(task);
+ },
+
+
+ checkDesignMode : function(){
+ if(this.wrap && this.wrap.dom.offsetWidth){
+ var doc = this.getDoc();
+ if(!doc){
+ return;
+ }
+ if(!doc.editorInitialized || this.getDesignMode() != 'on'){
+ this.initFrame();
+ }
+ }
+ },
+
+ /* private
+ * set current design mode. To enable, mode can be true or 'on', off otherwise
+ */
+ setDesignMode : function(mode){
+ var doc ;
+ if(doc = this.getDoc()){
+ if(this.readOnly){
+ mode = false;
+ }
+ doc.designMode = (/on|true/i).test(String(mode).toLowerCase()) ?'on':'off';
+ }
+
+ },
+
+ // private
+ getDesignMode : function(){
+ var doc = this.getDoc();
+ if(!doc){ return ''; }
+ return String(doc.designMode).toLowerCase();
+
+ },
+
+ disableItems: function(disabled){
+ if(this.fontSelect){
+ this.fontSelect.dom.disabled = disabled;
+ }
+ this.tb.items.each(function(item){
+ if(item.getItemId() != 'sourceedit'){
+ item.setDisabled(disabled);
+ }
+ });
+ },
+
+ // private
+ onResize : function(w, h){
+ Ext.form.HtmlEditor.superclass.onResize.apply(this, arguments);
+ if(this.el && this.iframe){
+ if(Ext.isNumber(w)){
+ var aw = w - this.wrap.getFrameWidth('lr');
+ this.el.setWidth(aw);
+ this.tb.setWidth(aw);
+ this.iframe.style.width = Math.max(aw, 0) + 'px';
+ }
+ if(Ext.isNumber(h)){
+ var ah = h - this.wrap.getFrameWidth('tb') - this.tb.el.getHeight();
+ this.el.setHeight(ah);
+ this.iframe.style.height = Math.max(ah, 0) + 'px';
+ var bd = this.getEditorBody();
+ if(bd){
+ bd.style.height = Math.max((ah - (this.iframePad*2)), 0) + 'px';
+ }
+ }
+ }
+ },
+
+ /**
+ * Toggles the editor between standard and source edit mode.
+ * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
+ */
+ toggleSourceEdit : function(sourceEditMode){
+ var iframeHeight,
+ elHeight;
+
+ if (sourceEditMode === undefined) {
+ sourceEditMode = !this.sourceEditMode;
+ }
+ this.sourceEditMode = sourceEditMode === true;
+ var btn = this.tb.getComponent('sourceedit');
+
+ if (btn.pressed !== this.sourceEditMode) {
+ btn.toggle(this.sourceEditMode);
+ if (!btn.xtbHidden) {
+ return;
+ }
+ }
+ if (this.sourceEditMode) {
+ // grab the height of the containing panel before we hide the iframe
+ this.previousSize = this.getSize();
+
+ iframeHeight = Ext.get(this.iframe).getHeight();
+
+ this.disableItems(true);
+ this.syncValue();
+ this.iframe.className = 'x-hidden';
+ this.el.removeClass('x-hidden');
+ this.el.dom.removeAttribute('tabIndex');
+ this.el.focus();
+ this.el.dom.style.height = iframeHeight + 'px';
+ }
+ else {
+ elHeight = parseInt(this.el.dom.style.height, 10);
+ if (this.initialized) {
+ this.disableItems(this.readOnly);
+ }
+ this.pushValue();
+ this.iframe.className = '';
+ this.el.addClass('x-hidden');
+ this.el.dom.setAttribute('tabIndex', -1);
+ this.deferFocus();
+
+ this.setSize(this.previousSize);
+ delete this.previousSize;
+ this.iframe.style.height = elHeight + 'px';
+ }
+ this.fireEvent('editmodechange', this, this.sourceEditMode);
+ },
+
+ // private used internally
+ createLink : function() {
+ var url = prompt(this.createLinkText, this.defaultLinkValue);
+ if(url && url != 'http:/'+'/'){
+ this.relayCmd('createlink', url);
+ }
+ },
+
+ // private
+ initEvents : function(){
+ this.originalValue = this.getValue();
+ },
+
+ /**
+ * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
+ * @method
+ */
+ markInvalid : Ext.emptyFn,
+
+ /**
+ * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
+ * @method
+ */
+ clearInvalid : Ext.emptyFn,
+
+ // docs inherit from Field
+ setValue : function(v){
+ Ext.form.HtmlEditor.superclass.setValue.call(this, v);
+ this.pushValue();
+ return this;
+ },
+
+ /**
+ * Protected method that will not generally be called directly. If you need/want
+ * custom HTML cleanup, this is the method you should override.
+ * @param {String} html The HTML to be cleaned
+ * @return {String} The cleaned HTML
+ */
+ cleanHtml: function(html) {
+ html = String(html);
+ if(Ext.isWebKit){ // strip safari nonsense
+ html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
+ }
+
+ /*
+ * Neat little hack. Strips out all the non-digit characters from the default
+ * value and compares it to the character code of the first character in the string
+ * because it can cause encoding issues when posted to the server.
+ */
+ if(html.charCodeAt(0) == this.defaultValue.replace(/\D/g, '')){
+ html = html.substring(1);
+ }
+ return html;
+ },
+
+ /**
+ * Protected method that will not generally be called directly. Syncs the contents
+ * of the editor iframe with the textarea.
+ */
+ syncValue : function(){
+ if(this.initialized){
+ var bd = this.getEditorBody();
+ var html = bd.innerHTML;
+ if(Ext.isWebKit){
+ var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
+ var m = bs.match(/text-align:(.*?);/i);
+ if(m && m[1]){
+ html = '
+{
+ bold : {
+ title: 'Bold (Ctrl+B)',
+ text: 'Make the selected text bold.',
+ cls: 'x-html-editor-tip'
+ },
+ italic : {
+ title: 'Italic (Ctrl+I)',
+ text: 'Make the selected text italic.',
+ cls: 'x-html-editor-tip'
+ },
+ ...
+
+ * @type Object
+ */
+ buttonTips : {
+ bold : {
+ title: 'Bold (Ctrl+B)',
+ text: 'Make the selected text bold.',
+ cls: 'x-html-editor-tip'
+ },
+ italic : {
+ title: 'Italic (Ctrl+I)',
+ text: 'Make the selected text italic.',
+ cls: 'x-html-editor-tip'
+ },
+ underline : {
+ title: 'Underline (Ctrl+U)',
+ text: 'Underline the selected text.',
+ cls: 'x-html-editor-tip'
+ },
+ increasefontsize : {
+ title: 'Grow Text',
+ text: 'Increase the font size.',
+ cls: 'x-html-editor-tip'
+ },
+ decreasefontsize : {
+ title: 'Shrink Text',
+ text: 'Decrease the font size.',
+ cls: 'x-html-editor-tip'
+ },
+ backcolor : {
+ title: 'Text Highlight Color',
+ text: 'Change the background color of the selected text.',
+ cls: 'x-html-editor-tip'
+ },
+ forecolor : {
+ title: 'Font Color',
+ text: 'Change the color of the selected text.',
+ cls: 'x-html-editor-tip'
+ },
+ justifyleft : {
+ title: 'Align Text Left',
+ text: 'Align text to the left.',
+ cls: 'x-html-editor-tip'
+ },
+ justifycenter : {
+ title: 'Center Text',
+ text: 'Center text in the editor.',
+ cls: 'x-html-editor-tip'
+ },
+ justifyright : {
+ title: 'Align Text Right',
+ text: 'Align text to the right.',
+ cls: 'x-html-editor-tip'
+ },
+ insertunorderedlist : {
+ title: 'Bullet List',
+ text: 'Start a bulleted list.',
+ cls: 'x-html-editor-tip'
+ },
+ insertorderedlist : {
+ title: 'Numbered List',
+ text: 'Start a numbered list.',
+ cls: 'x-html-editor-tip'
+ },
+ createlink : {
+ title: 'Hyperlink',
+ text: 'Make the selected text a hyperlink.',
+ cls: 'x-html-editor-tip'
+ },
+ sourceedit : {
+ title: 'Source Edit',
+ text: 'Switch to source editing mode.',
+ cls: 'x-html-editor-tip'
+ }
+ }
+
+ // hide stuff that is not compatible
+ /**
+ * @event blur
+ * @hide
+ */
+ /**
+ * @event change
+ * @hide
+ */
+ /**
+ * @event focus
+ * @hide
+ */
+ /**
+ * @event specialkey
+ * @hide
+ */
+ /**
+ * @cfg {String} fieldClass @hide
+ */
+ /**
+ * @cfg {String} focusClass @hide
+ */
+ /**
+ * @cfg {String} autoCreate @hide
+ */
+ /**
+ * @cfg {String} inputType @hide
+ */
+ /**
+ * @cfg {String} invalidClass @hide
+ */
+ /**
+ * @cfg {String} invalidText @hide
+ */
+ /**
+ * @cfg {String} msgFx @hide
+ */
+ /**
+ * @cfg {String} validateOnBlur @hide
+ */
+ /**
+ * @cfg {Boolean} allowDomMove @hide
+ */
+ /**
+ * @cfg {String} applyTo @hide
+ */
+ /**
+ * @cfg {String} autoHeight @hide
+ */
+ /**
+ * @cfg {String} autoWidth @hide
+ */
+ /**
+ * @cfg {String} cls @hide
+ */
+ /**
+ * @cfg {String} disabled @hide
+ */
+ /**
+ * @cfg {String} disabledClass @hide
+ */
+ /**
+ * @cfg {String} msgTarget @hide
+ */
+ /**
+ * @cfg {String} readOnly @hide
+ */
+ /**
+ * @cfg {String} style @hide
+ */
+ /**
+ * @cfg {String} validationDelay @hide
+ */
+ /**
+ * @cfg {String} validationEvent @hide
+ */
+ /**
+ * @cfg {String} tabIndex @hide
+ */
+ /**
+ * @property disabled
+ * @hide
+ */
+ /**
+ * @method applyToMarkup
+ * @hide
+ */
+ /**
+ * @method disable
+ * @hide
+ */
+ /**
+ * @method enable
+ * @hide
+ */
+ /**
+ * @method validate
+ * @hide
+ */
+ /**
+ * @event valid
+ * @hide
+ */
+ /**
+ * @method setDisabled
+ * @hide
+ */
+ /**
+ * @cfg keys
+ * @hide
+ */
+});
+Ext.reg('htmleditor', Ext.form.HtmlEditor);
+
\ No newline at end of file