www.gusucode.com > 可上传图片的Java版htmlarea编辑器改进版源码程序 > 可上传图片的Java版htmlarea编辑器改进版/htmleditor/htmleditor/htmleditor/WebRoot/JS/htmleditor.js
// Ext.ux.HTMLEditorToolbar // extension of Ext.Toolbar to cater for extensibility Ext.ux.HTMLEditorToolbar = Ext.extend(Ext.Toolbar, { // overrides Ext.Toolbar.initComponent // first function to be called upon creation of toolbar initComponent: function(){ // call Ext.Toolbar.initComponent Ext.ux.HTMLEditorToolbar.superclass.initComponent.call(this); // unable to use existing items collection for pre-render // configuration as it's updated by Ext.Toolbar during render this.tools = new Ext.util.MixedCollection(false, function(tool){ return tool.itemId || tool.id || Ext.id(); }); }, // add tools (pre-render) addTools: function(tools){ tools = (tools instanceof Array) ? tools : [tools]; for (var i = 0, len = tools.length; i < len; i++) { this.tools.add(tools[i]); } }, // insert tools (pre-render) insertTools: function(index, tools){ tools = (tools instanceof Array) ? tools : [tools]; for (var i = 0, len = tools.length; i < len; i++) { this.tools.insert(index + i, tools[i]); } }, // insert tools before another tool (pre-render) insertToolsBefore: function(itemId, tools){ var index = this.tools.indexOfKey(itemId); this.insertTools(index, tools); }, // insert tools after another tool (pre-render) insertToolsAfter: function(itemId, tools){ var index = this.tools.indexOfKey(itemId) + 1; this.insertTools(index, tools); }, // render tools (performed after tools/plugins have been configured/reordered) renderTool: function(tool){ // cater for new tbcombo component // created to split configuration from render if (typeof tool == "object" && tool.xtype && tool.xtype == "tbcombo") { // not catered for in Ext.Toolbar.add function // as it defaults to addField instead of addItem this.addItem(Ext.ComponentMgr.create(tool)); } else { // else use existing Ext.Toolbar.add function // to render tools this.add(tool); } }, // overrides Ext.Toolbar.onRender onRender: function(ct, position){ // call Ext.Toolbar.onRender Ext.ux.HTMLEditorToolbar.superclass.onRender.call(this, ct, position); // loop through pre-configured/reordered tools and render each accordingly this.tools.each(this.renderTool, this); } }); // Ext.ux.HTMLEditorToolbar.ComboBox // created to handle the pre-configuration of a combobox (pre-render) Ext.ux.HTMLEditorToolbar.ComboBox = function(config){ Ext.apply(this, config); // create combobox in memory before render var selEl = document.createElement("select"); selEl.className = this.cls; for (var i = 0, len = this.opts.length; i < len; i++) { var opt = this.opts[i]; var optEl = document.createElement('option'); optEl.text = opt.text; optEl.value = opt.value; if (opt.selected) { optEl.selected = true; this.defaultValue = opt.value; } selEl.options.add(optEl); } if (!this.defaultValue) { this.defaultValue = this.opts[0].value; } // call Ext.Toolbar.Item constructor passing combobox Ext.ux.HTMLEditorToolbar.ComboBox.superclass.constructor.call(this, selEl); } // Ext.ux.HTMLEditorToolbar.ComboBox // extension of Ext.Toolbar.Item Ext.extend(Ext.ux.HTMLEditorToolbar.ComboBox, Ext.Toolbar.Item, { // overrides Ext.Toolbar.Item.render render: function(td){ // call Ext.Toolbar.Item.render Ext.ux.HTMLEditorToolbar.ComboBox.superclass.render.call(this, td); // add handler for combobox change event Ext.EventManager.on(this.el, 'change', this.handler, this.scope); } }); // register Ext.ux.HTMLEditorToolbar.ComboBox as a new component Ext.ComponentMgr.registerType('tbcombo', Ext.ux.HTMLEditorToolbar.ComboBox); // Ext.ux.HTMLEditor // extends Ext.form.HtmlEditor to provide extensibility Ext.ux.HTMLEditor = Ext.extend(Ext.form.HtmlEditor, { // using the enable... flags to define content meant that items // were always added in the same order. // using the toolbarItems list instead allows the user to override // the order of items, and even exclude items not wanted. // the enable... flags are now no longer used toolbarItems: ['fonts', 'allformats', 'allfontsizes', 'allcolors', 'allalignments', 'alllinks', 'alllists', 'sourceedit'], // as an alternative, the toolbarItemExcludes list can be used to // exclude items from the toolbarItem list toolbarItemExcludes: [], // overrides Ext.form.HtmlEditor.initComponent // first function to be called upon creation of the editor initComponent: function(){ // call Ext.form.HtmlEditor.initComponent Ext.ux.HTMLEditor.superclass.initComponent.call(this); // add important event missing from Ext.form.HtmlEditor this.addEvents({ editorevent: true }); // remove any toolbarItemExcludes from the toolbarItems array for (var i = 0, iMax = this.toolbarItemExcludes.length; i < iMax; i++) { var item = this.toolbarItemExcludes[i].toLowerCase(); for (var j = 0, jMax = this.toolbarItems.length; j < jMax; j++) { if (this.toolbarItems[j] == item) { this.toolbarItems.splice(j, 1); break; } } } // create the editor toolbar this.tb = new Ext.ux.HTMLEditorToolbar(); // create the toolbar items this.createTools(this.toolbarItems); }, // overrides Ext.form.HtmlEditor.createFontOptions createFontOptions: function(){ var opts = [], ffs = this.fontFamilies, ff; for (var i = 0, len = ffs.length; i < len; i++) { ff = ffs[i]; fflc = ff.toLowerCase(); var opt = { text: ff, value: fflc }; if (fflc == this.defaultFont) opt.selected = true; opts.push(opt); } return opts; }, // create default button config btn: function(id, toggle, queryState, handler){ return { itemId: id, cls: 'x-btn-icon x-edit-' + id, enableToggle: toggle !== false, queryState: queryState !== false, handler: handler || this.relayBtnCmd, scope: this, clickEvent: 'mousedown', tooltip: this.buttonTips[id] || undefined, tabIndex: -1 }; }, // create known tools based on the passed item list (initially // from the toolbarItems list) and add it to the tools collection. // this function allows random tool allocation as opposed // to the old version that added tools sequentially createTools: function(toolbarItems){ // convert single items to a list toolbarItems = (toolbarItems instanceof Array) ? toolbarItems : [toolbarItems]; // loop through the item list for (var i = 0, len = toolbarItems.length; i < len; i++) { //add the item to the toolbar var item = toolbarItems[i]; switch (item) { // add the fonts combobox case 'fonts': if (!Ext.isSafari) { this.tb.addTools({ itemId: 'fontname', xtype: 'tbcombo', cls: 'x-font-select', opts: this.createFontOptions(), queryValue: true, handler: function(event, el){ this.relayCmd('fontname', el.value); this.deferFocus(); }, scope: this }); } break; // add the bold button case 'bold': this.tb.addTools(this.btn('bold')); break; // add the italic button case 'italic': this.tb.addTools(this.btn('italic')); break; // add the underline button case 'underline': this.tb.addTools(this.btn('underline')); break; // add all format buttons (with a leading separator) case 'allformats': this.createTools(['-', 'bold', 'italic', 'underline']); break; // add the increasefontsize button case 'increasefontsize': this.tb.addTools(this.btn('increasefontsize', false, false, this.adjustFont)); break; // add the decreasefontsize button case 'decreasefontsize': this.tb.addTools(this.btn('decreasefontsize', false, false, this.adjustFont)); break; // add both fontsize buttons (with a leading separator) case 'allfontsizes': this.createTools(['-', 'increasefontsize', 'decreasefontsize']); break; // add the forecolor button and associated menu case 'forecolor': this.tb.addTools({ itemId: 'forecolor', cls: 'x-btn-icon x-edit-forecolor', clickEvent: 'mousedown', tooltip: this.buttonTips['forecolor'], tabIndex: -1, menu: new Ext.menu.ColorMenu({ allowReselect: true, focus: Ext.emptyFn, value: '000000', plain: true, selectHandler: function(cp, color){ this.execCmd('forecolor', Ext.isSafari || Ext.isIE ? '#' + color : color); this.deferFocus(); }, scope: this, clickEvent: 'mousedown' }) }); break; // add the backcolor button and associated menu case 'backcolor': this.tb.addTools({ itemId: 'backcolor', cls: 'x-btn-icon x-edit-backcolor', clickEvent: 'mousedown', tooltip: this.buttonTips['backcolor'], tabIndex: -1, menu: new Ext.menu.ColorMenu({ focus: Ext.emptyFn, value: 'FFFFFF', plain: true, allowReselect: true, selectHandler: 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.isSafari || Ext.isIE ? '#' + color : color); this.deferFocus(); } }, scope: this, clickEvent: 'mousedown' }) }); break; // add both color buttons (with a leading separator) case 'allcolors': this.createTools(['-', 'forecolor', 'backcolor']); break; // add the justifyleft button case 'justifyleft': this.tb.addTools(this.btn('justifyleft')); break; // add the justifycenter button case 'justifycenter': this.tb.addTools(this.btn('justifycenter')); break; // add the justifyright button case 'justifyright': this.tb.addTools(this.btn('justifyright')); break; // add all alignment buttons (with a leading separator) case 'allalignments': this.createTools(['-', 'justifyleft', 'justifycenter', 'justifyright']); break; // add the link button case 'link': if (!Ext.isSafari) { this.tb.addTools(this.btn('createlink', false, false, this.createLink)); } break; // add the link button (with a leading separator) case 'alllinks': if (!Ext.isSafari) { this.createTools(['-', 'link']); } break; // add the orderedlist button case 'orderedlist': if (!Ext.isSafari) { this.tb.addTools(this.btn('insertorderedlist')); } break; // add the unorderedlist button case 'unorderedlist': if (!Ext.isSafari) { this.tb.addTools(this.btn('insertunorderedlist')); } break; // add both list buttons (with a leading separator) case 'alllists': if (!Ext.isSafari) { this.createTools(['-', 'orderedlist', 'unorderedlist']); } break; // add the sourceedit button case 'sourceedit': if (!Ext.isSafari) { this.tb.addTools(this.btn('sourceedit', true, false, function(btn){ this.toggleSourceEdit(btn.pressed); })); } break; // allows for '-', 'separator', ' ', '->', labels, or other item types default: this.tb.addTools(item); } } }, // overrides Ext.form.HtmlEditor.createToolbar // most functionality has been removed as this is called // upon render createToolbar: function(){ // render toolbar this.tb.render(this.wrap.dom.firstChild); // inherited this.tb.el.on('click', function(e){ e.preventDefault(); }); }, // overrides Ext.form.HtmlEditor.getDocMarkup // provides ability to include stylesheets in the editor document // created by bpjohnson (see http://extjs.com/forum/showthread.php?t=9588) getDocMarkup: function(){ var markup = '<html><head><style type="text/css">body{border:0;margin:0;padding:3px;height:98%;cursor:text;}</style>'; if (this.styles) { for (var i = 0; i < this.styles.length; i++) { markup = markup + '<link rel="stylesheet" type="text/css" href="' + this.styles[i] + '" />'; } } markup = markup + '</head><body></body></html>'; return markup; }, // overrides Ext.form.HtmlEditor.onEditorEvent onEditorEvent: function(e){ // call Ext.form.HtmlEditor.onEditorEvent Ext.ux.HTMLEditor.superclass.onEditorEvent.call(this, e); // fire new editorevent to tell plugins that an event occurred // in the editor. // this saves plugins from having to monitor multiple events // i.e. 'click', 'keyup', etc. this.fireEvent('editorevent', this, e); }, // overrides Ext.form.HtmlEditor.updateToolbar // does not call superclass function as much of it was no // longer needed, but duplicates some code updateToolbar: function(){ // inherited if (!this.activated) { this.onFirstFocus(); return; } // loop through toolbar items and update status based on // query values return from the browser (if configured) this.tb.items.each(function(item){ if (item.queryState) { item.toggle(this.doc.queryCommandState(item.itemId)); } else if (item.queryEnabled) { item.setDisabled(!this.doc.queryCommandEnabled(item.itemId)); } else if (item.xtype = "tbcombo" && item.queryValue) { var value = (this.doc.queryCommandValue(item.itemId) || item.defaultValue).toLowerCase(); if (value != item.el.value) { item.el.value = value; } } }, this); // inherited Ext.menu.MenuMgr.hideAll(); // inherited this.syncValue(); } });