Ext.define('saas.override.form.field.HtmlEditor', { override: 'Ext.form.field.HtmlEditor', fontFamilies: [{ name: '微软雅黑', value: 'Microsoft YaHei' }, { name: '宋体', value: 'SimSun' }, { name: '新宋体', value: 'NSimSun' }, { name: '仿宋', value: 'FangSong' }, { name: '楷体', value: 'KaiTi' }, { name: '黑体', value: 'SimHei' }, 'Arial', 'Arial Black', 'Courier New', 'Tahoma', 'Times New Roman', 'Verdana'], headers: [{ block: false, name: '普通文本', size: '14px', color: 'rgb(57, 57, 57)' }, { block: true, name: '标题', size: '32px', color: 'rgb(57, 57, 57)', bold: true }, { block: true, name: '副标题', size: '18px', color: 'rgb(89, 89, 89)', bold: true }, { block: true, name: '标题1', size: '28px', color: 'rgb(57, 57, 57)', bold: true }, { block: true, name: '标题2', size: '20px', color: 'rgb(57, 57, 57)', bold: true }, { block: true, name: '标题3', size: '16px', color: 'rgb(57, 57, 57)', bold: true }, { block: true, name: '标题4', size: '14px', color: 'rgb(57, 57, 57)', bold: true }], blocks: [{ class: 'doc-block', name: '带背景内容' }, { class: 'doc-tip doc-tip-info', name: '提示内容' }, { class: 'doc-tip doc-tip-warn', name: '警告内容' }, { class: 'doc-tip doc-tip-error', name: '错误内容' }, { class: 'doc-quote', name: '引用内容' }, { class: 'doc-line', html: '
' }], enableHeaders: true, enableFontSize: false, enableUpload: true, enableSourceEdit: false, enableBlocks: true, publishes: { textValue: 1 }, initComponent: function () { var me = this; me.callParent(); // 用于获取innerText me.on('change', function () { me.publishState('textValue', me.getTextValue()); }); }, initEditor: function () { var me = this; me.callParent(); /** * 扩展监听事件 */ var doc = me.getDoc(), docEl = Ext.get(doc); if (docEl) { docEl.on({ mousedown: '_onMouseDown', keyup: '_onKeyup', scope: me, delegated: false }); } }, _onMouseDown: function (e) { var target = e.parentEvent.target; if (target.nodeName == 'IMG') { e.preventDefault(); this.resizeImage(target); } }, _onKeyup: function (e) { if (e.keyCode == e.ENTER && e.ctrlKey) { e.preventDefault(); // 换行 // this.insertAtCursor('
'); this.execCmd('insertHTML', '

'); } }, getDocMarkup: function () { // 添加额外样式、脚本 var me = this, h = me.iframeEl.getHeight() - me.iframePad * 2, extraCss = Ext.getResourcePath('css/htmleditor.css'); return Ext.String.format('' + '', me.iframePad, h, me.defaultFont); }, initDefaultFont: function () { var me = this, selIdx = 0, fonts, font, select, option, i, len, fontName, fontValue; if (!me.defaultFont) { fonts = Ext.Array.clone(me.fontFamilies); select = me.down('#fontSelect').selectEl.dom; for (i = 0, len = fonts.length; i < len; ++i) { font = fonts[i]; if (Ext.isString(font)) { fontName = font; fontValue = font.toLowerCase(); } else { fontName = font.name; fontValue = font.value.toLowerCase(); } option = new Option(fontName, fontValue); if (i == selIdx) { me.defaultFont = fontName; } option.style.fontFamily = fontValue; if (Ext.isIE) { select.add(option); } else { select.options.add(option); } } // Old IE versions have a problem if we set the selected property // in the loop, so set it after. select.options[selIdx].selected = true; } }, getToolbarCfg: function () { var me = this, cfg = me.callParent(); // 选择标题样式 if (me.enableHeaders) { cfg.items.splice(0, 0, '-'); cfg.items.splice(0, 0, me.getHeadersBtn()); } // 上传图片 if (me.enableUpload) { cfg.items.push('-', Ext.merge({ xtype: 'fileuploadfield', name: 'file', allowBlank: false, buttonOnly: true, hideLabel: true, itemId: 'insertImage', buttonText: '', ui: 'plain', margin: 0, buttonConfig: { ui: 'plain-toolbar', cls: 'x-btn-icon', iconCls: 'x-fa fa-upload', accept: 'image/*' }, scope: me, listeners: { change: function (field) { if (!field.getValue()) { return; } var fileEl = field.fileInputEl.dom; me.saveImage(fileEl.files[0]); field.reset(); } }, clickEvent: 'mousedown', tooltip: '插入图片', tabIndex: -1 }, me.buttonDefaults)); cfg.listeners.click = function (e) { if (!e.getTarget('.x-form-file-input')) { e.preventDefault(); } } } // 自定义语句块 if (me.enableBlocks) { cfg.items.push('-', Ext.merge(me.getBlocks(), me.buttonDefaults)); } return cfg; }, /** * 保存图片方式一 - 服务端保存 * @param {*} file */ saveImage: function (file) { var me = this, data = new FormData(); data.append('file', file); Ext.Ajax.request({ url: '/api/file/upload', cors: true, useDefaultXhrHeader: false, method: 'post', headers: { 'Content-Type': null }, rawData: data, success: function (response) { var res = Ext.decode(response.responseText); if (res.success) { if (!me.activated) { me.onFirstFocus(); } me.insertAtCursor(''); me.syncValue(); } else { saas.util.BaseUtil.showErrorToast('上传失败: ' + res.message); } }, failure: function () { saas.util.BaseUtil.showErrorToast('上传失败'); } }); }, /** * 保存图片方式二 - base64格式 * 这样保证文档删除时附件一并删除 * 截屏直接粘贴的图片均为base64格式 * @param {*} file */ saveBase64Image: function (file) { var me = this, reader = new FileReader(); reader.readAsDataURL(file); reader.onload = function () { if (!me.activated) { me.onFirstFocus(); } me.insertAtCursor(''); me.syncValue(); } }, /** * 选择标题 */ getHeadersBtn: function () { var me = this, items = me.headers.map(h => { var style = `color:${h.color};font-size:${h.size};font-weight:` + (h.bold ? 'bold' : 'normal'), text = `${h.name}`, value = Ext.clone(h); return { text: text, value, handler: function (item) { var val = item.value; me.execHeaderStyle(val); item.ownerCt.ownerCmp.setText(val.name); } } }); return { itemId: 'headers', width: 90, padding: '7 0', text: items[0].text, tabIndex: -1, menu: Ext.widget('menu', { plain: true, items }) }; }, /** * 选择语句块 */ getBlocks: function () { var me = this, items = me.blocks.map(h => { var text = h.html || `
${h.name}
`, value = Ext.clone(h); return { text: text, value, handler: function (item) { var val = item.value; me.execBlockStyle(val); } } }); return { itemId: 'blocks', iconCls: 'x-fa fa-ellipsis-v', tooltip: '插入块', tabIndex: -1, arrowVisible: false, menuAlign: 'tr-br?', menu: Ext.widget('menu', { plain: true, cls: 'doc-blocks__ex', width: 180, items }) }; }, /** * 解决fontSize只支持 1 - 7 的问题 */ execHeaderStyle: function (header) { var me = this, win = me.getWin(), doc = me.getDoc(), text = win.getSelection() || me.defaultValue; if (!me.destroyed) { var span = doc.createElement('span'); span.innerHTML = text; span.style.fontSize = header.size; span.style.color = header.color; span.style.fontWeight = header.bold ? 'bold' : 'normal'; win.focus(); me.execCmd('insertHTML', '
' + span.outerHTML + '
'); } }, /** * 特殊样式的语句块 */ execBlockStyle: function (block) { var me = this, win = me.getWin(), text = win.getSelection() || '
', html = block.html; if (!me.destroyed) { win.focus(); if (!html) { html = `
${text}
`; } me.execCmd('insertHTML', `
${html}
`); } }, setTextValue: function () { }, getTextValue: function () { return this.getEditorBody().innerText; }, /** * 调整图片大小 * @param {*} target */ resizeImage: function (target) { var me = this, el = Ext.fly(target), padding = 73, width = el.getWidth(), maxWidth = Math.min(window.innerWidth, 880), widthPerc = width / maxWidth, height = el.getHeight(), maxHeight = window.innerHeight - padding, heightPerc = height / maxHeight, perc = Math.max(widthPerc, heightPerc); if (perc > 1) { width = width / perc; height = height / perc + padding; } else { height += padding; } var win = Ext.create('Ext.window.Window', { modal: true, autoShow: true, ui: 'simple', title: '拖动改变图片大小', maxWidth: maxWidth, width, height, tabIndex: -1, layout: 'fit', items: { itemId: 'image', xtype: 'image', src: target.src }, buttons: [{ text: '确定', ui: 'primary', handler: function () { var image = win.child('#image'); if (!target.getAttribute('data-original-width')) { target.setAttribute('data-original-width', width); target.setAttribute('data-original-height', height); } target.setAttribute('width', image.getWidth()); target.setAttribute('height', image.getHeight()); me.syncValue(); win.close(); } }, { text: '取消', ui: 'simple', handler: function () { win.close(); } }] }); win.focus(); } });