@itellyou/itellyou-editor

2.2.18 • Public • Published

适用于 React 的富文本编辑器

ITELLYOU 官网,发布文章功能中可体验,网站已开通了普通用户协同编辑权限,注册两个账户,在两个浏览器或不同的电脑登录,可以同时编辑网站上已发布的 标签或问题 ) 在 itellyou-engine 基础上扩展编辑能力,提供更多丰富的插件

引擎(itellyou-engine

编辑器核心库,纯js编写,不依赖 React,提供编辑能力,插件接口

扩展功能

  • codeblock (代码块,需要额外引用 codemirror 对语言支持)
  • table (表格)
  • emoji (emoji 表情)
  • file (文件上传、预览 需要配合后台api处理上传)
  • label (文本状态)
  • lockedtext (加密文本 ,需要配合后台api加密)
  • mindmap (脑图)
  • diagram (文本绘图,PlantUML、Mermaid、Flowchart、Graphviz 需要后台api调用第三方库生成svg图片)
  • math (数学公式,同diagram 一样需要后台api调用第三方库生成svg图片)
  • mention (提及 @)
  • search (输入关键字可以查询编辑器中的符合条件的文字,并高亮显示,可以替换相应的文字)
  • translate (可以对编辑器中的文档翻译,并且可以替换,需要后台 提供翻译api,一般使用阿里云)
  • video (视频,需要后台上传api)
  • youku (在线视频)
  • image (图片,需要后台上传api)
  • toc (大纲)

四种满足使用环境的编辑器模式

  • FullEditor (正常完整模式,适合专业文档撰写)
  • MiniEditor (迷你模式,评论、问答等简单撰写)
  • LineEditor (行模式 适合文字评论、表情评论、图片评论)
  • MobileEditor (手机模式,适合手机h5简单撰写)
import { FullEditor , MiniEditor , LineEditor ,MobileEditor } from '@itellyou/itellyou-editor'

依赖

// 引擎
https://github.com/itellyou-com/itellyou-engine.git
// ajax 文件上传工具
https://github.com/itellyou-com/itellyou-ajax.git
// request 数据请求工具
https://github.com/itellyou-com/itellyou-request.git

本地编译(@itellyou/itellyou-ajax、@itellyou/itellyou-engine、@itellyou/itellyou-request、@itellyou/itellyou-editor 这些都是私有包,是访问不到的,需要将这4个项目在本地编译或者发布到自己的npm上)

clone https://github.com/itellyou-com/itellyou-editor.git

现在整个项目是基于 umijs.org 搭建的,主要有一些测试页面,编辑器是在 src/library 目录中 编译之前需要确认以下命令是否有全局安装,或在package.json/scripts/compile(编译脚本) 中 修改命令 主要就是先删除项目根目录下的library目录,然后将src/library中的es6代码转换成es5代码,并把转换后的代码和css复制到项目根目录下的library文件夹中

// rimraf 删除 library 目录
npm install rimraf -g
// cpr 复制资源文件
npm install cpr -g

在 itellyou-editor

// 安装模块
npm install

// 编译后链接到全局(相当于将包发布到本地)
npm link 
// 或只编译
npm run compile

编译后的文件在 itellyou-editor/library 文件夹中

npm link 使用:

首先得执行 npm link 编译后链接到全局 ,然后在您的应用程序中链接它

npm link @itellyou/itellyou-editor

Class Component

import React from 'react'
import { FullEditor } from '@itellyou/itellyou-editor'

class Editor extends React.Component {

    state = {
        content:"<p>Hello Editor</p>"
    }

    onLoad = editor => {
        console.log("编辑器加载好了,",editor)
    }

    onChange = content => {
        this.setState({
            content
        })
    }

    onSave = () => {
        console.log("我请求保存")
    }

    render(){
        const { content } = this.state
        /**
         * 
         * {
                lang,// 语言 en , zh-cn
                defaultValue, // 默认编辑器内容
                onChange, // 编辑器内容改变调用
                onLoad, //编辑器加载成功时调用
                header, // 编辑器扩展header信息,可以是 React 组件
                onSave, // 保存插件执行保存的时候调用
                onBeforeRenderImage,// 在读取图片前调用,可以在函数里面修改 图片地址
                // 表情包
                emoji: {
                    action: 'https://cdn-object.itellyou.com/emoji/',
                },
                // 加密文本插件配置,selection/locakedtext
                lockedtext: {
                    action: '/api/crypto',
                    // 参数
                    {
                        action:encrypt 加密 text 文本 ,pwd 密码,返回加密后的密文
                        action:decrypt 解密 text 加密密文 , pwd 密码,返回解密后的文本
                    }
                },
                // 图片插件配置
                image: {
                    action: '/api/upload/image',//上传地址,粘贴图片的时候传的 图片url地址,
                    //返回参数
                    {
                        result:true,
                        data:{
                            url,// 图片地址,必须
                            preview, // 预览地址
                            download,// 下载地址
                            size , // 图片大小
                            width , // 真实宽度
                            height // 真实高度
                        }
                    }
                    display: 'block',// 默认显示模式 inline 同文本一行,block ,单独占一行
                    align: 'center',// 默认位置:left 居左,center 居中,right 居右
                },
                // 文件插件配置
                file: {
                    action: '/api/upload/file',
                    //返回参数
                    {
                        result:true,
                        data:{
                            url,// 文件地址,必须
                            preview, // 预览地址,文档预览可以配合阿里云 “智能媒体管理” - “文档转换” 使用
                            download,// 下载地址
                            size , // 文件大小
                        }
                    }
                },
                // 阿里云视频上传请求,需要阿里云sdk支持 https://cdn-object.itellyou.com/ali-sdk/aliyun-oss-sdk-5.3.1.min.js , https://cdn-object.itellyou.com/ali-sdk/aliyun-upload-sdk-1.5.0.min.js,具体可查看阿里云视频点播服务
                video: {
                    action: {
                        create: '/api/upload/video',// 请求创建上传视频请求,
                        //请求参数
                        {
                            filename,//文件名
                            filesize,//文件大小
                        }
                        //后端调用 CreateUploadVideoRequest ,并返回 
                        {
                            result:true,
                            data:...
                        }

                        save: '/api/upload/video/save',// 保存上传后的信息,可根据需要保存
                        
                        query: '/api/upload/video/query',// 查询播放链接
                        //请求参数
                        {
                            video_id//视频编号
                        }
                        //后端使用 GetPlayInfoResponse 获取播放信息
                        GetPlayInfoResponse response = vodService.getPlayInfo(videoId);
                        if(response == null) return new ResultModel(0,"获取视频播放信息失败");
                        Map<String,Object> data = new HashMap<>();
                        GetPlayInfoResponse.VideoBase videoBase = response.getVideoBase();
                        data.put("video_id",videoBase.getVideoId());
                        data.put("cover_url",videoBase.getCoverURL());
                        data.put("title",videoBase.getTitle());
                        List<Map<String,Object>> playList = new ArrayList<>();
                        for (GetPlayInfoResponse.PlayInfo playInfo : response.getPlayInfoList()){
                            Map<String,Object> playData = new HashMap<>();
                            playData.put("url",playInfo.getPlayURL());
                            playData.put("format",playInfo.getFormat());
                            playData.put("width",playInfo.getWidth());
                            playData.put("height",playInfo.getHeight());
                            playData.put("size",playInfo.getSize());
                            playList.add(playData);
                        }
                        data.put("play_list",playList);
                        并返回数据
                        return {
                            result:true,
                            data:...
                        }
                    },
                },
                // 阿里云翻译请求
                translate: {
                    action: '/api/translate',
                },
                // @ 插件
                mention: {
                    action: '/api/user/search',
                    paramName: 'q',"q" // 查询参数
                    default: [],//默认可以 @ 的会员
                },
                // markdown 支持命令
                markdown: {
                    action: '/api/document/convert',// 粘贴时,识别到markdown代码,转行为编辑器数据格式请求。不提供则不检测
                    items: [
                        'codeblcok',
                        'code',
                        'mark',
                        'bold',
                        'strikethrough',
                        'italic',
                        'sup',
                        'sub',
                        'orderedlist',
                        'unorderedlist',
                        'tasklist',
                        'checkedtasklist',
                        'h1',
                        'h2',
                        'h3',
                        'h4',
                        'h5',
                        'h6',
                        'quote',
                        'link',
                    ],
                },
                // 是否启用协同编辑,需要后端做好api配合
                ot: false,
            }
         */
        return (
            <Editor 
            defaultValue={content} 
            onLoad={this.onLoad}
            onChange={this.onChange}
            onSave={this.onSave}
            />
        )
    }
}
export default Editor

Hook

export default EditorTest = () => {
    const [ content , setContent ] = useState("<p>Hello</p>")

    const onChange = value => setContent(value)

    const onLoad = editor = => {
        console.log("编辑器加载了,实例:",editor)
    }

    return <Editor defaultValue={content} onLoad={onLoad} onChange={onChange} />
}

实例方法

// 获取编辑器内容
getContent()

// 获取不包含光标信息的内容
getPureContent()

// 获取不包含光标信息的html
getPureHtml()

协同编辑

使用 ShareDB 基于 JSON 文档的操作转换 https://github.com/share/sharedb

需要配合 itellyou-editor-server 是一个nodejs项目,作为 协同 服务端

demo:

yarn start

打开两个浏览器,访问 /Collab ,自定义一个 账户 ,然后选择一个文档编辑。数据交互是基于 mock 作为演示

扩展插件

section 块

import SectionBase from '@itellyou/itellyou-editor/library/section/base'
import { Engine } from '@itellyou/itellyou-editor';

class PaidSection extends SectionBase {
    constructor(engine, contentView){
        super()
        this.section = Engine.section
        this.engine = engine
        this.contentView = contentView
    }

    render(container, value) {
        value = value || {};
        // 初始化 section 节点
        container.append(Engine.$("<div style='color:#fff;background:blue'>This is Section Plugin</div>"));
    }
}
// 块的类型 block、inline
PaidSection.type = 'block';
export default PaidSection

插件

const PLUGIN_NAME = "paid"
export default {
    initialize: function () {
        // 创建命令
        this.command.add(PLUGIN_NAME, {
            execute: () => {
                // 插入Section块,名称为 paid
                this.change.insertSection(PLUGIN_NAME)
            }
        }) 
        // 设置快捷键
        const options = this.options[PLUGIN_NAME] || {
            hotkey:'mod+shift+m'
        }
        
        if(!!options.hotkey){
            this.hotkey.set(options.hotkey, PLUGIN_NAME)
        }
    }
}

添加到引擎

import { FullEditor , Engine } from '@itellyou/itellyou-editor';
Engine.section.add('paid', PaidSection)
Engine.plugin.add('paid', PaidPlugin)

最后使用快捷键 mod+shift+m 出来插件效果,或者添加toolbar按钮执行插件

Readme

Keywords

none

Package Sidebar

Install

npm i @itellyou/itellyou-editor

Weekly Downloads

15

Version

2.2.18

License

none

Unpacked Size

2.59 MB

Total Files

231

Last publish

Collaborators

  • aomao