欢迎各位兄弟 发布技术文章

这里的技术是共享的

You are here

让UEditor编辑器 百度编辑器 可以直接WORD图文复制粘贴 剪切板 剪贴板 有大用 有大大用 有大大大用 有大大大大用

为什么以前对企业微信的复制粘贴的图文起作用,现在不起作用了,难道以前企业微信是rtf格式的数据,现在是html格式的数据了

对于企业微信我的处理方法是

1) 本地一个apache服务器, my.qyweixin.com,路径指向企业微信的图像的路径, C:\Users\16666739\Documents\WXWork

2) sites\all\libraries\ueditor\ueditor.all.js 里面  

me.addListener('beforepaste', function (cmd, html) { 

 这个函数里面的最后 约 20452行,加上两行代码

html.html =  html.html.replaceAll('file:///C:/Users/16666739/Documents/WXWork','http://my.qyweixin.com:82');    //替换为apache服务器的网站路径
html.html = html.html.replaceAll('<img','<br style="height:1px" /><img style="max-width:520px;" '); //把图像设为最宽520px

3) 使用 get_images模块,见 /node-admin/1134

此时 就可以复制企业微信的图文了,剪切的含图片的内容就可以直接转变成服务器上的图了,哎,真搞不懂!




见附件,自己改写的 对 word 和 wps 的图像的粘贴, 对拖拽(拖拉)图片,QQ截图剪切板图像都起作用,已应用于 aaaa (本身这个js是可以取imgurl(远程url图像)保存到服务器的,但是aaaa的网站的后如因为限制了跟外网的链接,所以无法取外网的imgurl保存起来)

ueditor.all-for-word-and-wps-img-paste-ok---from-imgurl-ok---drag-img-ok.js.txt  #包括wps  自然在aaaa用的是它

ueditor.all-for-word-img-paste-ok---from-imgurl-ok---drag-img-ok.js.txt  #除了wps 

上面两个文件的区别仅仅在 约 7543 行 

即把  const regexPictureHeader = /{\\pict[\s\S]+?\\bliptag-?\d+(\\blipupi-?\d+)?({\\\*\\blipuid\s?[\da-fA-F]+)?[\s}]*?/;     

改成了  const regexPictureHeader = /{\\pict[\s\S]+?({\\\*\\blipuid\s?[\da-fA-F]+)[\s}]*/;


前言

UE编辑器本身就集成了WORD图文粘贴,可惜由于年代久远,官方放弃了维护且现代浏览器不在需要毒瘤flash了,所以UE编辑器就用不了word图文粘贴。

浏览器技术也在不断改进,要解决word图文粘贴有几种做法:

  1. 浏览器控件(扩展)。

让用户的浏览器安装控件,直接读取word保存在硬盘的临时图片。但是这个体验不够好。

  1. 先将word文件上传到服务器后端,后端解析word文件后,再回调到前端编辑器。

比较常见的实现方法,但是对于纯前端来说,我觉得这种做法通用性低,仅适用公司自用。

  1. 纯前端解决。本次实现的方式。

解决思路

首先UE本身已经实现WORD的图文粘贴,只是图片转换没有做解决方案,会用一张临时图片顶替。因此本次任务就是去解决前人遗留的问题。

众所周知,复制整份图文word文档,在浏览器中粘贴,你通过监听剪切板内容,会发现图片标签都是以 file:/// 开头的。 由于浏览器安全机制,他会阻止你加载本地资源。所以摆在我眼前的问题就成了:如何将file:/// 开头的图片,转换为base64。 找到了目标后,就很好办了。

错误的思路

尽管找到了目标,但是要将本地图片转换为base64不是一个容易的事情。不过这些小困难想难倒一个拥有10多年面向搜索引擎开发经验的程序员来说,只是一个易事。

皇天不负有心人,我想到了用过JS FileReader来转换base64 。思路:

  1. 读取剪切板所有本地图片地址。

  2. 手动追加 <input type="file"> 并将本地图片地址进行手动模拟。

我就把时间花在如何将图片地址添加到input file中,且是模式用户的。 几小时过去,我认为这个思路是错误的。

站在巨人之上去解决问题

正当我一筹莫展的时候,我想起了知名的富文本编辑器——CK5。CK5已经实现了word图文粘贴,遂到官网一试,看看源码,CK5成功将图片转换为base64了。果断下载CK5源码到本地一探究竟。

在CK5源码的packages库中,可以找到一个名为ckeditor5-paste-from-office目录。大概看了一下里面的源码,然而我也看不懂。

再后来,我忘记我搜索什么关键词了依次在掘金找到juejin.cn/post/701372… ,  /node-admin/17946  通过CK5和RTF关键词,找到一篇别人写的文章:blog.csdn.net/Jioho_chen/…    /node-admin/19460

通过站在巨人之上,整个解决方案就出来了。

实现方案

由于篇幅和时间限制,如何整合到UE的思路我就不叙述了,直接来实现的方案:打开UE的核心文件ueditor.all.js

首先,在核心文件开头附近,声明一个数组,用于存放转换好的图片。大概30行附近左右,添加

var wordImg = [];
复制代码


找到_initEvents: function () {,大概7454行,这里大概就是UE初始化的代码,在这里可以监听到当前UE编辑器的DOM。 接下来将整个_initEvents覆盖如下代码即可,如果你有对比器,可以根据我这部分获取差异。

/**
 * 初始化UE事件及部分事件代理
 * @method _initEvents
 * @private
 */
_initEvents: function () {
    var me = this,
        doc = me.document,
        win = me.window;

    //监听word复制粘贴功能
    doc.addEventListener("paste", function (e) {

        if (!(e.clipboardData && e.clipboardData.items)) {
            return;
        }

        const clipboardData = e.clipboardData;

        //粘贴板中的HTML文本
        let copyStr = clipboardData.getData('text/html');

        //粘贴板中的RTF数据
        let rtf = clipboardData.getData('text/rtf');

        //获取粘贴板中图片的数量
        let imgs = me.findAllImageElementsWithLocalSource(copyStr);

        me.replaceImagesFileSourceWithInlineRepresentation(imgs, me.extractImageDataFromRtf(rtf))

    })

    me._proxyDomEvent = utils.bind(me._proxyDomEvent, me);
    domUtils.on(doc, ['click', 'contextmenu', 'mousedown', 'keydown', 'keyup', 'keypress', 'mouseup', 'mouseover', 'mouseout', 'selectstart'], me._proxyDomEvent);
    domUtils.on(win, ['focus', 'blur'], me._proxyDomEvent);
    domUtils.on(me.body,'drop',function(e){
        //阻止ff下默认的弹出新页面打开图片
        if(browser.gecko && e.stopPropagation) { e.stopPropagation(); }
        me.fireEvent('contentchange')
    });
    domUtils.on(doc, ['mouseup', 'keydown'], function (evt) {
        //特殊键不触发selectionchange
        if (evt.type == 'keydown' && (evt.ctrlKey || evt.metaKey || evt.shiftKey || evt.altKey)) {
            return;
        }
        if (evt.button == 2)return;
        me._selectionChange(250, evt);
    });
},

复制代码


接着在后面添加如下代码

//获取粘贴板中图片数量
findAllImageElementsWithLocalSource:function(copyStr){
    let imgs = $(copyStr).find('img');
    return imgs;
},

//处理图片信息
extractImageDataFromRtf:function(rtfData){
    if (!rtfData) {
        return [];
    }

    const regexPictureHeader = /{\pict[\s\S]+?\bliptag-?\d+(\blipupi-?\d+)?({\*\blipuid\s?[\da-fA-F]+)?[\s}]*?/;
    const regexPicture = new RegExp('(?:(' + regexPictureHeader.source + '))([\da-fA-F\s]+)\}', 'g');
    const images = rtfData.match(regexPicture);
    const result = [];

    if (images) {
        for (const image of images) {
            let imageType = false;

            if (image.includes('\pngblip')) {
                imageType = 'image/png';
            } else if (image.includes('\jpegblip')) {
                imageType = 'image/jpeg';
            }

            if (imageType) {
                result.push({
                    hex: image.replace(regexPictureHeader, '').replace(/[^\da-fA-F]/g, ''),
                    type: imageType
                });
            }
        }
    }

    return result;
},

//16进制转换为base64
_convertHexToBase64:function(hexString){
    return btoa(hexString.match(/\w{2}/g).map(char => {
        return String.fromCharCode(parseInt(char, 16));
    }).join(''));
},

//存储图片资源
replaceImagesFileSourceWithInlineRepresentation:function(imageElements, imagesHexSources){
    // Assume there is an equal amount of image elements and images HEX sources so they can be matched accordingly based on existing order.
    if (imageElements.length === imagesHexSources.length) {
        for (let i = 0; i < imageElements.length; i++) {
            const newSrc = `data:${imagesHexSources[i].type};base64,${this._convertHexToBase64(imagesHexSources[i].hex)}`;

            wordImg.push(newSrc);

            // writer.setAttribute('src', newSrc, imageElements[i]);
        }
    }

    console.dir(wordImg)

},
复制代码


上述代码作用是监控粘贴板,并将转换好的图片保存在wordImg数组中。

接下来在文件搜索//todo base64暂时去掉,后边做远程图片上传后,干掉这个 将下方的代码去除。最终样子大概如下:

    case 'img':
        //todo base64暂时去掉,后边做远程图片上传后,干掉这个
        if (val = node.getAttr('src')) {

        }
        node.setAttr('_src', node.getAttr('src'));
        break;
复制代码


最后,定位到 UE.plugin.register('wordimage',function(){ 大概13990行。直接将inputRule : function (root) { 覆盖替换如下代码

inputRule : function (root) {
    utils.each(root.getNodesByTagName('img'), function (img, key) {
        var attrs = img.attrs,
            flag = parseInt(attrs.width) < 128 || parseInt(attrs.height) < 43,
            opt = me.options,
            src = opt.UEDITOR_HOME_URL + 'themes/default/images/spacer.gif';
        if (attrs['src'] && /^(?:(file:\/+))/.test(attrs['src'])) {
            img.setAttr({
                width:attrs.width,
                height:attrs.height,
                alt:attrs.alt,
                src:wordImg[key],
                'style':'background:url(' + ( flag ? opt.themePath + opt.theme + '/images/word.gif' : opt.langPath + opt.lang + '/images/localimage.png') + ') no-repeat center center;border:1px solid #ddd'
            })
        }
    })
    //清空调用记录
    wordImg = [];

}
复制代码


至此,整个UE编辑器可以支持word图文粘贴了。需要注意的是:本次修改没有将图片上传到后端服务器。具体的逻辑请大家自行修改了。x

效果图:



09523179279d4e9887d04200c3af4bd8_tplv-k3u1fbpfcp-zoom-in-crop-mark_1512_0_0_0 (2).gif





对了,RTF目前还是实验性功能,可能随着浏览器的升级,这次修改又双叒叕失效。

整合代码

考虑到上面代码有些分散,可以直接查看我的GITEE 本次代码的提交:gitee.com/fallBirds/P…


打个小广告,如果大家对文档编辑有需求,可以使用我编写的文档管理:PESCMS DOC gitee.com/fallBirds/P…


作者:天机星
链接:https://juejin.cn/post/7096322277641289735
来源:稀土掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

我之前从tinymce里扣了一段代码出来,又改了下,就是解析rtf,抽出里面图片的hex,转成blob上传。不过蛋疼的,wps里面跟word还有区别
1
1
(作者)
[我想静静]wps我没试。迟点有需求再改了
点赞
回复
特蕾丝汀的头像
古铜军团指挥官 @ 石堂城
收藏



来自  https://juejin.cn/post/7096322277641289735



普通分类: