|
当前功能基于PHP,其它语言流程大致相同
1.新增上传word json配置
在ueditor\php\config.json中新增如下配置:
/* 上传word配置 */
"wordActionName": "wordupload", /* 执行上传视频的action名称 */
"wordFieldName": "upfile", /* 提交的视频表单名称 */
"wordPathFormat": "/public/uploads/word/{yyyy}{mm}{dd}/{time}{rand:6}", /* 上传保存路径,可以自定义保存路径和文件名格式 */
"wordMaxSize": 102400000, /* 上传大小限制,单位B,默认100MB */
"wordAllowFiles": [".docx"] /* 仅支持docx格式的word */
2.修改编辑器配置文件,在工具栏上新增按钮
在ueditor\ueditor.config.js文件中,新增按钮名称"wordupload",并添加鼠标悬浮提示,如下所示:
//工具栏上的所有的功能按钮和下拉框,可以在new编辑器的实例时选择自己需要的重新定义
, toolbars: [[
'fullscreen', 'source', '|', 'undo', 'redo', '|',
'bold', 'italic', 'underline', 'fontborder', 'strikethrough', 'superscript', 'subscript', 'removeformat', 'formatmatch', 'autotypeset', 'blockquote', 'pasteplain', '|', 'forecolor', 'backcolor', 'insertorderedlist', 'insertunorderedlist', 'selectall', 'cleardoc', '|',
'rowspacingtop', 'rowspacingbottom', 'lineheight', '|',
'customstyle', 'paragraph', 'fontfamily', 'fontsize', '|',
'directionalityltr', 'directionalityrtl', 'indent', '|',
'justifyleft', 'justifycenter', 'justifyright', 'justifyjustify', '|', 'touppercase', 'tolowercase', '|',
'link', 'unlink', 'anchor', '|', 'imagenone', 'imageleft', 'imageright', 'imagecenter', '|',
'simpleupload', 'insertimage', 'emotion', 'scrawl', 'insertvideo', 'music', 'attachment', 'map', 'gmap', 'insertframe', 'insertcode', 'webapp', 'pagebreak', 'template', 'background', '|',
'horizontal', 'date', 'time', 'spechars', 'snapscreen', 'wordimage', '|',
'inserttable', 'deletetable', 'insertparagraphbeforetable', 'insertrow', 'deleterow', 'insertcol', 'deletecol', 'mergecells', 'mergeright', 'mergedown', 'splittocells', 'splittorows', 'splittocols', 'charts', '|',
'print', 'preview', 'searchreplace', 'drafts', 'help', 'wordupload'
]]
//当鼠标放在工具栏上时显示的tooltip提示,留空支持自动多语言配置,否则以配置值为准
,labelMap:{
'wordupload': '上传word文件',
}
在ueditor\themes\default\images\目录下新增按钮图标"word_upload.png":
在ueditor\themes\default\css\ueditor.css文件中新增按钮样式:
.edui-for-wordupload .edui-icon {
width: 16px;
height: 16px;
background: url(../images/word_upload.png) no-repeat 2px 2px !important;
}
最后在ueditor\ueditor.all.js文件中editorui["simpleupload"] = function (editor){}后面添加如下代码:
/* word上传 */
editorui["wordupload"] = function (editor) {
var name = 'wordupload',
ui = new editorui.Button({
className:'edui-for-' + name,
title:editor.options.labelMap[name] || editor.getLang("labelMap." + name) || '',
onclick:function () {},
theme:editor.options.theme,
showText:false
});
editorui.buttons[name] = ui;
editor.addListener('ready', function() {
var b = ui.getDom('body'),
iconSpan = b.children[0];
editor.fireEvent('worduploadbtnready', iconSpan);
});
editor.addListener('selectionchange', function (type, causeByUi, uiReady) {
var state = editor.queryCommandState(name);
if (state == -1) {
ui.setDisabled(true);
ui.setChecked(false);
} else {
if (!uiReady) {
ui.setDisabled(false);
ui.setChecked(state);
}
}
});
return ui;
};
最终样式如下:

3. 新增语言配置
在ueditor\lang\zh-cn\zh-cn.js文件中在"simpleupload"配置下方新增以下配置:
'simpleupload':{
'exceedSizeError': '文件大小超出限制',
'exceedTypeError': '文件格式不允许',
'jsonEncodeError': '服务器返回格式错误',
'loading':"正在上传...",
'loadError':"上传错误",
'errorLoadConfig': '后端配置项没有正常加载,上传插件不能正常使用!'
},
'wordupload':{
'exceedSizeError': '文件大小超出限制',
'exceedTypeError': '文件格式不允许',
'jsonEncodeError': '服务器返回格式错误',
'loading':"正在上传...",
'loadError':"上传错误",
'errorLoadConfig': '后端配置项没有正常加载,上传插件不能正常使用!'
},
在ueditor\lang\zh-cn\en.js文件中在"simpleupload"配置下方新增以下配置:
'simpleupload':{
'exceedSizeError': 'File Size Exceed',
'exceedTypeError': 'File Type Not Allow',
'jsonEncodeError': 'Server Return Format Error',
'loading':"loading...",
'loadError':"load error",
'errorLoadConfig': 'Server config not loaded, upload can not work.',
},
'wordupload':{
'exceedSizeError': 'File Size Exceed',
'exceedTypeError': 'File Type Not Allow',
'jsonEncodeError': 'Server Return Format Error',
'loading':"loading...",
'loadError':"load error",
'errorLoadConfig': 'Server config not loaded, upload can not work.',
},
4.修改过滤配置
由于导入word时,编辑器会自动过滤掉图片等样式,所以需取消过滤
在ueditor\ueditor.config.js文件中修改如下配置:
// xss 过滤是否开启,inserthtml等操作
,xssFilterRules: false
//input xss过滤
,inputXssFilter: false
//output xss过滤
,outputXssFilter: false
在ueditor\ueditor.all.js文件中,修改UE.plugins[‘defaultfilter’],新增return ;如下所示:
// plugins/defaultfilter.js
///import core
///plugin 编辑器默认的过滤转换机制
UE.plugins['defaultfilter'] = function () {
return;
var me = this;
me.setOpt({
'allowDivTransToP':true,
'disabledTableInTable':true
});
……
5.安装PHPword
composer require phpoffice/phpword
6.自定义文件转换类
实现上传文件,并将文件转换为HTML
直接将ueditor自带的上传文件"ueditor\php\Uploader.class.php"类内容直接复制到自定义WordToHtmlController.class.php文件中
<?php
class WordToHtmlController
{
public function index()
{
require &#39;vendor/autoload.php&#39;;
$base64 = &#34;upload&#34;;
$config = array(
&#34;pathFormat&#34; => &#39;/public/uploads/word/{yyyy}{mm}{dd}/{time}{rand:6}&#39;,
&#34;maxSize&#34; => 102400000,
&#34;allowFiles&#34; => [&#34;.docx&#34;]
);
$fieldName = &#39;upfile&#39;;
include &#39;Uploader.class.php&#39;;
$up = new Uploader($fieldName, $config, $base64);
$path = ltrim($up->getFileInfo()[&#39;url&#39;], &#39;/&#39;);
// $phpWord = \PhpOffice\PhpWord\IOFactory::load(&#39;public/uploads/word/20211029/test.docx&#39;);
$phpWord = \PhpOffice\PhpWord\IOFactory::load($path);
// 直接输出到页面显示
// $phpWord->save(&#39;php://output&#39;, &#39;HTML&#39;);
$xmlWriter = \PhpOffice\PhpWord\IOFactory::createWriter($phpWord, &#39;HTML&#39;);
header(&#34;Content-Type:text/html; charset=utf-8&#34;);
exit($this->replaceImageSrc($xmlWriter->getContent()));
// exit($xmlWriter->getContent());
}
/**
* 将HTML代码中的所有图片地址替换
* @param $content string 要查找的内容
* @return string
*/
private function replaceImageSrc($content)
{
$preg = &#39;/(\s+src\s?\=)\s?[\&#39;|&#34;]([^\&#39;|&#34;]*)/is&#39;; // 匹配img标签的正则表达式
preg_match_all($preg, $content, $allImg); // 匹配所有的img
if (!$allImg)
return $content;
foreach ($allImg[0] as $k => $v) {
$old = ltrim($v, &#39;&#34; src=&#39;);
preg_match(&#39;/^(data:\s*image\/(\w+);base64,)/&#39;, $old, $temp);
$tempType = $temp[2]; // 获取类型
// 判断目录是否存在,不存在时创建
$tempFilePath = &#39;public/uploads/word_images/&#39; . date(&#39;Y-m-d&#39;, time());
if (!file_exists($tempFilePath))
mkdir($tempFilePath);
// 拼接完整路径
$tempFileName = $tempFilePath . &#39;/word_image_&#39; . time() . $k . &#39;.&#39; . $tempType;
$base64 = str_replace($temp[1], &#39;&#39;, $old);
file_put_contents($tempFileName, base64_decode($base64));
// 替换路径字符串
$content = str_replace($old, $tempFileName, $content);
}
return $content;
}
}
7.编辑器实现导入操作
在ueditor\ueditor.all.js文件中UE.plugin.register(&#39;simpleupload&#39;, function (){})下方新增如下方法
/**
* @description
* word上传:点击按钮,直接选择文件上传
*/
UE.plugin.register(&#39;wordupload&#39;, function (){
var me = this,
isLoaded = false,
containerBtn;
function initUploadBtn(){
var w = containerBtn.offsetWidth || 20,
h = containerBtn.offsetHeight || 20,
btnIframe = document.createElement(&#39;iframe&#39;),
btnStyle = &#39;display:block;width:&#39; + w + &#39;px;height:&#39; + h + &#39;px;overflow:hidden;border:0;margin:0;padding:0;position:absolute;top:0;left:0;filter:alpha(opacity=0);-moz-opacity:0;-khtml-opacity: 0;opacity: 0;cursor:pointer;&#39;;
domUtils.on(btnIframe, &#39;load&#39;, function(){
var timestrap = (+new Date()).toString(36),
wrapper,
btnIframeDoc,
btnIframeBody;
btnIframeDoc = (btnIframe.contentDocument || btnIframe.contentWindow.document);
btnIframeBody = btnIframeDoc.body;
wrapper = btnIframeDoc.createElement(&#39;div&#39;);
wrapper.innerHTML = &#39;<form id=&#34;edui_form_&#39; + timestrap + &#39;&#34; target=&#34;edui_iframe_&#39; + timestrap + &#39;&#34; method=&#34;POST&#34; enctype=&#34;multipart/form-data&#34; action=&#34;&#39; + me.getOpt(&#39;serverUrl&#39;) + &#39;&#34; &#39; +
&#39;style=&#34;&#39; + btnStyle + &#39;&#34;>&#39; +
&#39;<input id=&#34;edui_input_&#39; + timestrap + &#39;&#34; type=&#34;file&#34; accept=&#34;application/msword&#34; name=&#34;&#39; + me.options.wordFieldName + &#39;&#34; &#39; +
&#39;style=&#34;&#39; + btnStyle + &#39;&#34;>&#39; +
&#39;</form>&#39; +
&#39;<iframe id=&#34;edui_iframe_&#39; + timestrap + &#39;&#34; name=&#34;edui_iframe_&#39; + timestrap + &#39;&#34; style=&#34;display:none;width:0;height:0;border:0;margin:0;padding:0;position:absolute;&#34;></iframe>&#39;;
wrapper.className = &#39;edui-&#39; + me.options.theme;
wrapper.id = me.ui.id + &#39;_iframeupload&#39;;
btnIframeBody.style.cssText = btnStyle;
btnIframeBody.style.width = w + &#39;px&#39;;
btnIframeBody.style.height = h + &#39;px&#39;;
btnIframeBody.appendChild(wrapper);
if (btnIframeBody.parentNode) {
btnIframeBody.parentNode.style.width = w + &#39;px&#39;;
btnIframeBody.parentNode.style.height = w + &#39;px&#39;;
}
var form = btnIframeDoc.getElementById(&#39;edui_form_&#39; + timestrap);
var input = btnIframeDoc.getElementById(&#39;edui_input_&#39; + timestrap);
var iframe = btnIframeDoc.getElementById(&#39;edui_iframe_&#39; + timestrap);
domUtils.on(input, &#39;change&#39;, function(){
if(!input.value) return;
var loadingId = &#39;loading_&#39; + (+new Date()).toString(36);
var allowFiles = me.getOpt(&#39;wordAllowFiles&#39;);
me.focus();
me.execCommand(&#39;inserthtml&#39;, &#39;<img class=&#34;loadingclass&#34; id=&#34;&#39; + loadingId + &#39;&#34; src=&#34;&#39; + me.options.themePath + me.options.theme +&#39;/images/spacer.gif&#34; title=&#34;&#39; + (me.getLang(&#39;wordupload.loading&#39;) || &#39;&#39;) + &#39;&#34; >&#39;);
function callback(){
try{
// 获取到内容
var body = (iframe.contentDocument || iframe.contentWindow.document).body;
// 获取加载中图片并关闭
var loader = me.document.getElementById(loadingId);
loader.removeAttribute(&#39;id&#39;);
domUtils.removeClasses(loader, &#39;loadingclass&#39;);
// 向编辑器赋值
me.setContent(body.innerHTML, false);
// me.execCommand(&#39;insertHtml&#39;, body.innerHTML);
}catch(er){
showErrorLoader && showErrorLoader(me.getLang(&#39;wordupload.loadError&#39;));
}
form.reset();
domUtils.un(iframe, &#39;load&#39;, callback);
}
function showErrorLoader(title){
if(loadingId) {
var loader = me.document.getElementById(loadingId);
loader && domUtils.remove(loader);
me.fireEvent(&#39;showmessage&#39;, {
&#39;id&#39;: loadingId,
&#39;content&#39;: title,
&#39;type&#39;: &#39;error&#39;,
&#39;timeout&#39;: 4000
});
}
}
/* 判断后端配置是否没有加载成功 */
if (!me.getOpt(&#39;wordActionName&#39;)) {
errorHandler(me.getLang(&#39;autoupload.errorLoadConfig&#39;));
return;
}
// 判断文件格式是否错误
var filename = input.value,
fileext = filename ? filename.substr(filename.lastIndexOf(&#39;.&#39;)):&#39;&#39;;
if (!fileext || (allowFiles && (allowFiles.join(&#39;&#39;) + &#39;.&#39;).indexOf(fileext.toLowerCase() + &#39;.&#39;) == -1)) {
showErrorLoader(me.getLang(&#39;wordupload.exceedTypeError&#39;));
return;
}
domUtils.on(iframe, &#39;load&#39;, callback);
// 上传操作
// form.action = utils.formatUrl(imageActionUrl + (imageActionUrl.indexOf(&#39;?&#39;) == -1 ? &#39;?&#39;:&#39;&&#39;) + params);
// 替换请求地址为框架后台地址
form.action = &#34;/admin.php?m=fwordToHtml&a=index&#34;//这个地址依据自己系统而定
form.method = &#34;post&#34;
form.submit();
});
var stateTimer;
me.addListener(&#39;selectionchange&#39;, function () {
clearTimeout(stateTimer);
stateTimer = setTimeout(function() {
var state = me.queryCommandState(&#39;wordupload&#39;);
if (state == -1) {
input.disabled = &#39;disabled&#39;;
} else {
input.disabled = false;
}
}, 400);
});
isLoaded = true;
});
btnIframe.style.cssText = btnStyle;
containerBtn.appendChild(btnIframe);
}
return {
bindEvents:{
&#39;ready&#39;: function() {
//设置loading的样式
utils.cssRule(&#39;loading&#39;,
&#39;.loadingclass{display:inline-block;cursor:default;background: url(\&#39;&#39;
+ this.options.themePath
+ this.options.theme +&#39;/images/loading.gif\&#39;) no-repeat center center transparent;border:1px solid #cccccc;margin-right:1px;height: 22px;width: 22px;}\n&#39; +
&#39;.loaderrorclass{display:inline-block;cursor:default;background: url(\&#39;&#39;
+ this.options.themePath
+ this.options.theme +&#39;/images/loaderror.png\&#39;) no-repeat center center transparent;border:1px solid #cccccc;margin-right:1px;height: 22px;width: 22px;&#39; +
&#39;}&#39;,
this.document);
},
/* 初始化word上传按钮 */
&#39;worduploadbtnready&#39;: function(type, container) {
containerBtn = container;
me.afterConfigReady(initUploadBtn);
}
},
outputRule: function(root){
utils.each(root.getNodesByTagName(&#39;img&#39;),function(n){
if (/\b(loaderrorclass)|(bloaderrorclass)\b/.test(n.getAttr(&#39;class&#39;))) {
n.parentNode.removeChild(n);
}
});
},
commands: {
&#39;wordupload&#39;: {
queryCommandState: function () {
return isLoaded ? 0:-1;
}
}
}
}
});
然后在同文件下的btnCmds变量中添加上自定义的按钮:
//为工具栏添加按钮,以下都是统一的按钮触发命令,所以写在一起
var btnCmds = [&#39;undo&#39;, &#39;redo&#39;, &#39;formatmatch&#39;,
&#39;bold&#39;, &#39;italic&#39;, &#39;underline&#39;, &#39;fontborder&#39;, &#39;touppercase&#39;, &#39;tolowercase&#39;,
&#39;strikethrough&#39;, &#39;subscript&#39;, &#39;superscript&#39;, &#39;source&#39;, &#39;indent&#39;, &#39;outdent&#39;,
&#39;blockquote&#39;, &#39;pasteplain&#39;, &#39;pagebreak&#39;,
&#39;selectall&#39;, &#39;print&#39;,&#39;horizontal&#39;, &#39;removeformat&#39;, &#39;time&#39;, &#39;date&#39;, &#39;unlink&#39;,
&#39;insertparagraphbeforetable&#39;, &#39;insertrow&#39;, &#39;insertcol&#39;, &#39;mergeright&#39;, &#39;mergedown&#39;, &#39;deleterow&#39;,
&#39;deletecol&#39;, &#39;splittorows&#39;, &#39;splittocols&#39;, &#39;splittocells&#39;, &#39;mergecells&#39;, &#39;deletetable&#39;, &#39;drafts&#39;, &#39;wordupload&#39;];
至此,配置完成,结果示意图:


更多详细资料可以参考这篇文章:
http://blog.ncmem.com/wordpress/2019/08/12/ueditor-word%E5%9B%BE%E7%89%87%E8%BD%AC%E5%AD%98%E4%BA%A4%E4%BA%92/
技术交流可以入群一起讨论:223813913 |
|