1. 程式人生 > 其它 >WordPress編輯器支援Word文件

WordPress編輯器支援Word文件

 當前功能基於PHP,其它語言流程大抵相同。

大概流程:

1. 將docx檔案上傳到伺服器中

2. 使用PHPoffice/PHPword實現將word轉換為HTML

3. 將HTML程式碼返回並賦值到編輯器中

1 編輯器配置修改

1.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 */

1.2 修改編輯器配置檔案

1.2.1 在工具欄上新增按鈕

在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;

    };

最終樣式如下:

編輯

1.2.2 新增語言配置

在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.',

    },

1.2.3 修改過濾配置

由於匯入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

    });

……

2 新增相關功能

2.1 安裝PHPword

composer require phpoffice/phpword

1

2.2 自定義檔案轉換類

實現上傳檔案,並將檔案轉換為HTML

直接將ueditor自帶的上傳檔案"ueditor\php\Uploader.class.php"類複製到自定義類相同目錄下

自定義WordToHtmlController.class.php檔案:

<?php

class WordToHtmlController

{

    public function index()

    {

        require 'vendor/autoload.php';

        $base64 = "upload";

        $config = array(

            "pathFormat" => '/public/uploads/word/{yyyy}{mm}{dd}/{time}{rand:6}',

            "maxSize" => 102400000,

            "allowFiles" => [".docx"]

        );

        $fieldName = 'upfile';

        include 'Uploader.class.php';

        $up = new Uploader($fieldName, $config, $base64);

        $path = ltrim($up->getFileInfo()['url'], '/');

//        $phpWord = \PhpOffice\PhpWord\IOFactory::load('public/uploads/word/20211029/test.docx');

        $phpWord = \PhpOffice\PhpWord\IOFactory::load($path);

        // 直接輸出到頁面顯示

//        $phpWord->save('php://output', 'HTML');

        $xmlWriter = \PhpOffice\PhpWord\IOFactory::createWriter($phpWord, 'HTML');

        header("Content-Type:text/html; charset=utf-8");

        exit($this->replaceImageSrc($xmlWriter->getContent()));

//        exit($xmlWriter->getContent());

    }

    /**

     * 將HTML程式碼中的所有圖片地址替換

     * @param $content string 要查詢的內容

     * @return string

     */

    private function replaceImageSrc($content)

    {

        $preg = '/(\s+src\s?\=)\s?[\'|"]([^\'|"]*)/is'; // 匹配img標籤的正則表示式

        preg_match_all($preg, $content, $allImg); // 匹配所有的img

        if (!$allImg)

            return $content;

        foreach ($allImg[0] as $k => $v) {

            $old = ltrim($v, '" src=');

            preg_match('/^(data:\s*image\/(\w+);base64,)/', $old, $temp);

            $tempType = $temp[2];   // 獲取型別

            // 判斷目錄是否存在,不存在時建立

            $tempFilePath = 'public/uploads/word_images/' . date('Y-m-d', time());

            if (!file_exists($tempFilePath))

                mkdir($tempFilePath);

            // 拼接完整路徑

            $tempFileName = $tempFilePath . '/word_image_' . time() . $k . '.' . $tempType;

            $base64 = str_replace($temp[1], '', $old);

            file_put_contents($tempFileName, base64_decode($base64));

            // 替換路徑字串

            $content = str_replace($old, $tempFileName, $content);

        }

        return $content;

    }

}

2.3 編輯器實現匯入操作

在ueditor\ueditor.all.js檔案中UE.plugin.register('simpleupload', function (){})下方新增如下方法:

/**

 * @description

 * word上傳:點選按鈕,直接選擇檔案上傳

 */

UE.plugin.register('wordupload', function (){

    var me = this,

        isLoaded = false,

        containerBtn;

    function initUploadBtn(){

        var w = containerBtn.offsetWidth || 20,

            h = containerBtn.offsetHeight || 20,

            btnIframe = document.createElement('iframe'),

            btnStyle = 'display:block;width:' + w + 'px;height:' + h + '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;';

        domUtils.on(btnIframe, 'load', function(){

            var timestrap = (+new Date()).toString(36),

                wrapper,

                btnIframeDoc,

                btnIframeBody;

            btnIframeDoc = (btnIframe.contentDocument || btnIframe.contentWindow.document);

            btnIframeBody = btnIframeDoc.body;

            wrapper = btnIframeDoc.createElement('div');

            wrapper.innerHTML = '<form id="edui_form_' + timestrap + '" target="edui_iframe_' + timestrap + '" method="POST" enctype="multipart/form-data" action="' + me.getOpt('serverUrl') + '" ' +

                'style="' + btnStyle + '">' +

                '<input id="edui_input_' + timestrap + '" type="file" accept="application/msword" name="' + me.options.wordFieldName + '" ' +

                'style="' + btnStyle + '">' +

                '</form>' +

                '<iframe id="edui_iframe_' + timestrap + '" name="edui_iframe_' + timestrap + '" style="display:none;width:0;height:0;border:0;margin:0;padding:0;position:absolute;"></iframe>';

            wrapper.className = 'edui-' + me.options.theme;

            wrapper.id = me.ui.id + '_iframeupload';

            btnIframeBody.style.cssText = btnStyle;

            btnIframeBody.style.width = w + 'px';

            btnIframeBody.style.height = h + 'px';

            btnIframeBody.appendChild(wrapper);

            if (btnIframeBody.parentNode) {

                btnIframeBody.parentNode.style.width = w + 'px';

                btnIframeBody.parentNode.style.height = w + 'px';

            }

            var form = btnIframeDoc.getElementById('edui_form_' + timestrap);

            var input = btnIframeDoc.getElementById('edui_input_' + timestrap);

            var iframe = btnIframeDoc.getElementById('edui_iframe_' + timestrap);

            domUtils.on(input, 'change', function(){

                if(!input.value) return;

                var loadingId = 'loading_' + (+new Date()).toString(36);

                var allowFiles = me.getOpt('wordAllowFiles');

                me.focus();

                me.execCommand('inserthtml', '<img class="loadingclass" id="' + loadingId + '" src="' + me.options.themePath + me.options.theme +'/images/spacer.gif" title="' + (me.getLang('wordupload.loading') || '') + '" >');

                function callback(){

                    try{

                        // 獲取到內容

                        var body = (iframe.contentDocument || iframe.contentWindow.document).body;

                        // 獲取載入中圖片並關閉

                        var loader = me.document.getElementById(loadingId);

                        loader.removeAttribute('id');

                        domUtils.removeClasses(loader, 'loadingclass');

                        // 向編輯器賦值

                        me.setContent(body.innerHTML, false);

                        // me.execCommand('insertHtml', body.innerHTML);

                    }catch(er){

                        showErrorLoader && showErrorLoader(me.getLang('wordupload.loadError'));

                    }

                    form.reset();

                    domUtils.un(iframe, 'load', callback);

                }

                function showErrorLoader(title){

                    if(loadingId) {

                        var loader = me.document.getElementById(loadingId);

                        loader && domUtils.remove(loader);

                        me.fireEvent('showmessage', {

                            'id': loadingId,

                            'content': title,

                            'type': 'error',

                            'timeout': 4000

                        });

                    }

                }

                /* 判斷後端配置是否沒有載入成功 */

                if (!me.getOpt('wordActionName')) {

                    errorHandler(me.getLang('autoupload.errorLoadConfig'));

                    return;

                }

                // 判斷檔案格式是否錯誤

                var filename = input.value,

                    fileext = filename ? filename.substr(filename.lastIndexOf('.')):'';

                if (!fileext || (allowFiles && (allowFiles.join('') + '.').indexOf(fileext.toLowerCase() + '.') == -1)) {

                    showErrorLoader(me.getLang('wordupload.exceedTypeError'));

                    return;

                }

                domUtils.on(iframe, 'load', callback);

                // 上傳操作

                // form.action = utils.formatUrl(imageActionUrl + (imageActionUrl.indexOf('?') == -1 ? '?':'&') + params);

                // 替換請求地址為框架後臺地址

                form.action = "/admin.php?m=fwordToHtml&a=index"

                form.method = "post"

                form.submit();

            });

            var stateTimer;

            me.addListener('selectionchange', function () {

                clearTimeout(stateTimer);

                stateTimer = setTimeout(function() {

                    var state = me.queryCommandState('wordupload');

                    if (state == -1) {

                        input.disabled = 'disabled';

                    } else {

                        input.disabled = false;

                    }

                }, 400);

            });

            isLoaded = true;

        });

        btnIframe.style.cssText = btnStyle;

        containerBtn.appendChild(btnIframe);

    }

    return {

        bindEvents:{

            'ready': function() {

                //設定loading的樣式

                utils.cssRule('loading',

                    '.loadingclass{display:inline-block;cursor:default;background: url(\''

                    + this.options.themePath

                    + this.options.theme +'/images/loading.gif\') no-repeat center center transparent;border:1px solid #cccccc;margin-right:1px;height: 22px;width: 22px;}\n' +

                    '.loaderrorclass{display:inline-block;cursor:default;background: url(\''

                    + this.options.themePath

                    + this.options.theme +'/images/loaderror.png\') no-repeat center center transparent;border:1px solid #cccccc;margin-right:1px;height: 22px;width: 22px;' +

                    '}',

                    this.document);

            },

            /* 初始化word上傳按鈕 */

            'worduploadbtnready': function(type, container) {

                containerBtn = container;

                me.afterConfigReady(initUploadBtn);

            }

        },

        outputRule: function(root){

            utils.each(root.getNodesByTagName('img'),function(n){

                if (/\b(loaderrorclass)|(bloaderrorclass)\b/.test(n.getAttr('class'))) {

                    n.parentNode.removeChild(n);

                }

            });

        },

        commands: {

            'wordupload': {

                queryCommandState: function () {

                    return isLoaded ? 0:-1;

                }

            }

        }

    }

});

然後在同文件下的btnCmds變數中新增上自定義的按鈕:

    //為工具欄新增按鈕,以下都是統一的按鈕觸發命令,所以寫在一起

    var btnCmds = ['undo', 'redo', 'formatmatch',

        'bold', 'italic', 'underline', 'fontborder', 'touppercase', 'tolowercase',

        'strikethrough', 'subscript', 'superscript', 'source', 'indent', 'outdent',

        'blockquote', 'pasteplain', 'pagebreak',

        'selectall', 'print','horizontal', 'removeformat', 'time', 'date', 'unlink',

        'insertparagraphbeforetable', 'insertrow', 'insertcol', 'mergeright', 'mergedown', 'deleterow',

        'deletecol', 'splittorows', 'splittocols', 'splittocells', 'mergecells', 'deletetable', 'drafts', 'wordupload'];

至此,配置完成,結果示意圖:

編輯

編輯

編輯

更多詳細資料可以參考這篇文章:

詳細思路及原始碼

示例下載,下載前選擇合適的語言版本:

wordpaster-vue3-cli-ueditor1.5wordpaster-vue-ueditor1.5wordpaster-asp.net-ueditor1.5xwordpaster-php-ueditor1xwordpaster-jsp-ueditor1x​