jodit富文本编辑器自定义

1. 前言

最近公司要加个在线富文本编辑的功能,选型和客制化的工作都交给我了,最后在 Jodit、Quill、TinyMCE 等等里选了 Jodit,记录一下其中一些功能客制化的过程。

2. 以不修改源代码的方式修改部分 Jodit 插件

Jodit 实例上暴露了很多非侵入式修改插件功能的方法,基本上有两种方法(需要看下源码里其他插件对此插件的依赖关系,不然可能改了没用)。

2.1. 修改Jodit config里的controls[${pluginName}].exec方法

这种方法需要插件源码包含如下代码才能修改,一般 toolbar 上的大部分按钮插件都能通过这种方法来修改:

Config.prototype.controls.[`${pluginName}`] = {
	exec: (editor) => { ... }
	...
}

print打印插件为例,原本的print在打印时会带出页眉页脚,且在文本超长不换行的情况下,打印会超出可视范围导致被截断,如图:

image-20240603170417051

image-20240603170511887

可以先去源码里把exec函数中的逻辑复制出来,放到config.controls下,然后修改需要修改的部分:

 // jodit/esm/plugins/print/print.js 源码,主要部分,其中打印内容和打印页样式是我们需要修改的地方
 
 exec: (editor) => {
     const iframe = editor.create.element('iframe');
     ...
     const myWindow = iframe.contentWindow;
     if (myWindow) {
         editor.e
             .on(myWindow, 'onbeforeunload onafterprint', afterFinishPrint)
             .on(editor.ow, 'mousemove', afterFinishPrint);
         if (editor.o.iframe) {
             editor.e.fire('generateDocumentStructure.iframe', myWindow.document, editor);
             myWindow.document.body.innerHTML = editor.value;
         }
         else {
             // 打印内容
             myWindow.document.write('<!doctype html><html lang="' +
                 defaultLanguage(editor.o.language) +
                 '"><head><title></title></head><style>' +
                 generateCriticalCSS(editor) +
                 '</style><body></body></html>');
             myWindow.document.close();
             previewBox(editor, undefined, 'px', myWindow.document.body);
         }
         const style = myWindow.document.createElement('style');
         // 打印页样式
         style.innerHTML = `@media print {
   			body {
     			-webkit-print-color-adjust: exact;
   			}
		 }`;
         myWindow.document.head.appendChild(style);
         myWindow.focus();
         myWindow.print();
     }
 }
 
 
 // config.controls.print 修改的部分,以修复无法换行、删除页眉页脚为例
 
 const config = {
     ...
     controls: {
         ...
         print: {
             exec: (editor: any) => {
 				const iframe = editor.create.element('iframe');
				...
    			const myWindow = iframe.contentWindow;
    			if (myWindow) {
        			...
        			style.innerHTML = `
            			@media print {
                			@page {
                				margin-top: 0;
                				margin-bottom: 0;
              				}
							body {
								word-break: break-word;
								-webkit-print-color-adjust: exact;
								margin: 1.6cm;
							}
			 			}
					`;
        			myWindow.document.head.appendChild(style);
        			console.log(myWindow.document.head)
        			myWindow.focus();
        			myWindow.print();
    			}
 			}
         }
     }
 }

 

这样修改完之后再打印就不会出现这个问题了:

image-20240603171910480

2.2 通过 Jodit 的PluginSystem插件系统修改

Jodit 里大部分插件(富文本编辑器运行周期只需要一个实例的插件,例如stat 文本状态统计插件)的类都被注册在 Jodit 实例的 pluginSystem上,它是一个Map(想看定义的话就自己去看源码吧,这里就不给了),因为pluginSystem是暴露的,因此可以通过重新挂载的方式来覆盖原先的plugin class 定义,以stat为例,操作如下。

原本的stat统计字符数是不计算空格的,如图:

image-20240603172936344

原因在于源代码里的这一段:

image-20240603173040853

其中SPACE_REG_EXP的定义如下,过滤了\s即空格:

export const SPACE_REG_EXP = () => /[\s\n\t\r\uFEFF\u200b]+/g;

通过覆盖pluginSystem修改的话同样先复制一份源码出来,然后把上述SPACE_REG_EXP里的\s去除,形成类似下图的文件结构(别忘了改复制出来的源码的 import 路径):

image-20240603174228214

然后在 Jodit 类引入时覆盖定义:

import { Jodit } from "jodit";
import './plugins-dependency';
import { stat } from './stat/stat.js'

Jodit.plugins.remove('stat')
Jodit.plugins.add('stat', stat)

export { Jodit };

image-20240603174459902

可以看见成功修改了。

3. 修改 Jodit 源代码(以增加 popup 内部 iconBtn 的 tooltip 为例)

Jodit 里在inline-popup插件构筑的 popup 内部的所有 iconBtn 是无法显示其 tooltip 的,如图:

image-20240603175152603

而正常的内置 iconBtn 都应该是有 tooltip 的,如图:

image-20240603175250175

这个插件由于在 Jodit 运行过程中生成了多次实例,而且每次实例可能由不同的插件触发,因此没有挂载在pluginSystem上,所以如果要修改就只能改源码了。首先复制一份源码出来,类似下图的文件结构(Jodit 里很多文件是用不到的,只要复制 esm 和任意一个版本的 css 文件就可以了),其中源代码都在 esm 文件夹里:

image-20240603175621461

接下来就是解析inline-popup的相关代码了,首先打开@/assets/esm/plugins/inline-popup/inline-popup.js,可以看出比较重要的是以下部分:

image-20240603175939380

可以看出inline-popup其实是一个特殊的popup,只是触发位置不在toolbar上。因此继续打开@/assets/esm/plugins/popup/popup.js,在这个文件里是没有任何关于tooltip的逻辑的,因此需要我们自己补上对应的逻辑,而正好 Jodit 里是有对应的 tooltip 组件的,位于@/assets/esm/core/ui/button/tooltip/tooltip.js中,使用方法可以参考@/assets/esm/modules/toolbar/collection/collection.js,其中主要代码如下:

image-20240604105323996

tooltip内部实现了事件监听等,在使用时我们不必关心,至于具体实现可以自己去看源码,这里就不给了。

于是我们把对用的逻辑加到popup里:

image-20240604105659403

但在重新编译后可以看出,并不生效:

image-20240604105735325

原因在于tooltip内部的实现,主要是这一块:

image-20240604105842397

可以看出这里的view只能是Jodit对象,因为只有Jodit对象有e(events)属性,而这段代码就是监听Jodit.container上鼠标移入tooltip绑定对象时触发__onMouseEnter方法显示组件,但因为popup是append 到 HTML body 上的,事件捕获不到,因此tootip显示不出,具体情况如下图:

image-20240604110525976

image-20240604110559724

因此我们可以这样改一下tooltipconstractor

// tooltip.js

constructor(view, emitter) { // 增加一个 emitter: HTMLElement 用来绑定事件
    super(view);
    this.__isOpened = false;
    this.__listenClose = false;
    this.__currentTarget = null;
    this.__delayShowTimeout = 0;
    this.__hideTimeout = 0;
    if (!view.o.textIcons &&
        view.o.showTooltip &&
        !view.o.useNativeTooltip) {
        // 存在 emitter 的情况下将事件绑定到 emitter 上
        if (emitter) {
            this.emitter = emitter
            getContainer(this.j, UITooltip_1).appendChild(this.container);
            view.e.on(emitter, 'mouseenter.tooltip', this.__onMouseEnter, {
                capture: true
            });
        }
        view.hookStatus(STATUSES.ready, () => {
            // TODO Move it inside __show method. Now it is here because testcase failed with capturing
            getContainer(this.j, UITooltip_1).appendChild(this.container);
            view.e.on(view.container, 'mouseenter.tooltip', this.__onMouseEnter, {
                capture: true
            });
        });
    }
    
    ...
    __addListenersOnEnter() {
        if (this.__listenClose) {
            return;
        }
        this.__listenClose = true;
        const view = this.j;
        // 同样的,移出事件也要绑定到 emiiter 上
        view.e
            .on(view.ow, WINDOW_EVENTS_ON_HIDE, this.__hide)
            .on(JODIT_EVENTS_ON_HIDE, this.__hide)
            .on(this.emitter ?? view.container, 'mouseleave.tooltip', this.__onMouseLeave, {
            capture: true
        });
    }
}

然后再在popup里使用:

constructor(jodit, smart = true) {
    super(jodit);
    this.smart = smart;
    this.isOpened = false;
    this.strategy = 'leftBottom';
    this.viewBound = () => ({
        left: 0,
        top: 0,
        width: this.ow.innerWidth,
        height: this.ow.innerHeight
    });
    this.__childrenPopups = new Set();
    attr(this.container, 'role', 'popup');
    this.__tooltip = new UITooltip(this.jodit, this.container); // 指定事件绑定对象为 popover 的 container
}

...

destruct() {
    this.close();
    this.__tooltip?.destruct();
    this.__tooltip = null;
    return super.destruct();
}

这样就大功告成了:

image-20240604111522824

  • 28
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
### 回答1: OnlyOffice是一种强大的在线协作软件,专为企业和个人设计。它提供了一个一体化工作环境,包括文档编辑、协作、项目管理、邮件、日历等功能,使您能够跨平台、跨设备、跨时区的进行高效的工作和协作。 Java是一种流行的编程语言,也可以与OnlyOffice集成,使其更加灵活和强大。以下是一些Java OnlyOffice的例子: 1、OnlyOffice SDK for Java: 这是一个Java开发人员可以使用的OnlyOffice SDK,它使您能够轻松地将OnlyOffice文档编辑器集成到您的Java应用程序中。它提供了许多有用的工具和API,帮助您更好地管理和处理文档编辑器。 2、Jodit:一个基于JavaScript富文本编辑器,它也支持OnlyOffice文档编辑器。您可以轻松使用Jodit编辑器将OnlyOffice集成到您的Java应用程序中,让您的用户能够更方便地编辑和共享文档。 3、文档管理系统:OneDrive中提供了一个OnlyOffice文档编辑器,您可以使用Java编写的文档管理系统将其集成到您的应用程序中。当用户上传或创建新文件时,只需将其保存在OneDrive中,用户便可以使用OnlyOffice文档编辑器在线编辑并保存。 Java OnlyOffice的使用可以帮助您在您的应用程序中实现更好的文档协作和管理,提高您和您的用户的工作效率。 ### 回答2: Java OnlyOffice 是一种基于 Java 语言的 OnlyOffice 集成库,可以帮助开发者在 Java 应用中轻松集成 OnlyOffice 功能。具体来说,Java OnlyOffice 提供了一系列 API 接口,包括文档编辑、文档阅读、文档注释等,使得开发者可以在 Java 项目中直接调用 OnlyOffice 功能,进一步丰富了应用的功能和用户体验。 Java OnlyOffice 的使用非常简单,只需要在项目中引入相应的依赖,调用相应的 API 接口即可。在具体实现上,Java OnlyOffice 可以与不同的 Java 框架集成,例如 Spring、Struts 等,灵活性很高。此外,Java OnlyOffice 还提供了详细的文档和示例代码,方便开发者学习和使用。 作为一种集成库,Java OnlyOffice 实现了使用 OnlyOffice 功能的细节,简化了开发者的开发工作,提高了应用的可靠性和稳定性。此外,OnlyOffice 支持多语言,因此开发者可以根据不同的语言环境自定义界面,提高应用的易用性。 总的来说,Java OnlyOffice 是一个极具价值的开发工具,可以帮助开发者在 Java 应用中实现 OnlyOffice 功能。如果您需要在 Java 项目中实现文档编辑、阅读或注释等功能,Java OnlyOffice 是您的最佳选择。 ### 回答3: Java OnlyOffice 是一种使用Java语言编写的开源的文档编辑器,它是OnlyOffice开源文档编辑器的一部分。通过它,用户可以轻松地在云端创建、编辑和处理各种文档格式,例如Microsoft Office文档、OpenDocument格式、PDF文档和HTML等。 Java OnlyOffice 提供了完整的文档编辑功能,包括字体、样式、段落、表格、图片、公式、图形等。它还可以实时协作文档,允许多个用户同时编辑同一个文档,以达到更好的团队协作效果。 Java OnlyOffice 同时支持在不同设备之间同步和共享文档。这种特性使用户可以在任何地方、任何时候、任何设备上访问和编辑他们的文档,提高了生产力和工作效率。 Java OnlyOffice 同时提供了强大的API,允许开发人员在自己的应用程序中集成文档编辑和管理功能。这意味着Java OnlyOffice可以在各种不同的应用程序中使用,包括商务管理应用程序、在线教育平台、协作工具等等。 总之,Java OnlyOffice是一个功能强大、易于使用、可在云端或本地部署、多平台支持和开放源代码的文档编辑器,它为用户和开发人员提供了一系列的好处和工具,可以帮助他们管理和编辑各种文档格式

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值