帮助与文档 > 产品文档 > 多文本编辑器 > JS SDK 文档

有道智云编辑器 web SDK 文档

有道智云编辑器 SDK 简介

有道编辑器SDK是有道开放平台提供的云服务之一,是有道编辑器接口的一种实现。拥有多年产品化实践经验,服务于有道云笔记千万用户。

通过SDK接入优势:

  1. 支持常用的编辑功能,满足绝大多数的内容编辑场景
  2. 支持iOS、Android和桌面端WebKit内核的浏览器
  3. 自由格式的文档结构定义

集成前提

开始集成SDK之前开发者需要登录有道开放平台(http://ai.youdao.com),创建应用获取应用ID(或者通过运营人员获取应用ID),以便使用编辑器服务。

编辑器web sdk由如下几个文件组成:

文件说明
bulb.min.css编辑器样式文件(必选)
bulb.min.js编辑器核心库(必选)

SDK集成步骤

1. SDK库引入

方法一
<script> 引入

<link rel="stylesheet" href="/path/to/bulb.min.css">
<script type="text/javascript" src="/path/to/bulb.min.js"></script>

方法二
Module

import '/path/to/bulb.min.css'
import BulbEditor from '/path/to/bulb.min.js'

2. 权限添加

import '/path/to/bulb.min.css'
import BulbEditor from '/path/to/bulb.min.js'

(authBulbEditor({
    url: 'http://updateinfo.youdao.com/editorapi',
    pkn: 'com.youdao.com',
    appKey: appKey,
    version: 'v1',
    sdkVersion: 'v1',
    appSecret: appSecret,
})).then((BulbEditor) => {
    editor = new BulbEditor({
        el: document.getElementById('editor-container'),
    });
})

Web SDK API

BulbEditor配置项说明

BulbEditor可以通过在编辑器实例化时定制编辑器的特性

  • el {HTML element} [必须] 设置编辑器的挂载对象
  • disableContextMenu {Boolean} [默认值:false] 是否禁止编辑器默认右键菜单操作
  • disableAttachDownload {Boolean} [默认值:false] 是否禁止编辑器默认附件下载操作
  • disableImageDownload {Boolean} [默认值:false] 是否禁止编辑器默认图片下载操作
  • disableOpenLink {Boolean} [默认值:false] 是否禁止编辑器默认打开链接操作
  • disableInsertLink {Boolean} [默认值:false] 是否禁止编辑器默认插入超链接窗口
  • disableClipError {Boolean} [默认值:false] 是否禁止编辑器默认剪切板错误提醒
  • toolbarParentEl {HTML element} [默认值:undefined] 设置编辑器工具栏的挂载对象
  • toolbarItems {String[]} [默认值:undefined] 编辑器工具条配置,见以下节详细说明

方法

1. getContent(options)

用于获取编辑器内容

参数

  • options <Object>

    • type <String> json | xml | plain | html 表示要获取哪种格式的内容,默认 xml
    • [async] <Boolean> 默认 false

返回值

asynctrue时返回 <Promise> 其他情况返回 <String>

实例

editor
.getContent({
    type: 'json',
    async: true,
})
.then(json => {
    console.log(json)
})

2. setContent(content, options)

用于设置编辑器内容,也会将编辑状态重置

参数

  • content <String | Object>
  • options <Object>

    • type <String> json | xml 表示要设置哪种格式的内容,默认 xml
    • [async] <Boolean> 默认 false

返回值

asynctrue时返回 <Promise> 其他情况无返回值

实例

const xml = editor.getContent()

editor
.setContent(xml, {
    async: true,
})
.then(() => {
    console.log('done')
})

3. insertAttachment(options)

用于插入附件操作

参数

  • options <Object>

    • resource <String> 附件资源的地址,一般用于附件的下载
    • fileName <String> 附件名
    • fileLength <Number> 附件大小,数量级比特
    • [src] <String> 附件缩略图地址,编辑器会自行绘制附件缩略图,该值暂无实际用处

实例

editor.insertAttachment({
    resource: 'http://path.ext',
    src: 'http://thumbnail.jpg',
    fileName: '文件名',
    fileLength: 1024,
})

4. insertImage(options)

用于插入图片操作

参数

  • options <Object>

    • src <String> 图片的地址

实例

editor.insertImage({
    src: 'http://image.jpg',
})

5. insertMacro(options)

用于插入宏操作

参数

  • options <Object>

    • name <String> 宏的名字
    • content <String> 宏的内容
    • version <String> 宏的版本

实例

editor.insertMacro({
    name: 'test_macro',
    content: 'this is content of test macro',
    version: '1.0.0'
})

5. registerMacroConfig(macroConfig)

用于将宏配置实例注册到编辑器

参数

  • macroConfig <Object> 宏配置的实例

实例

editor.registerMacroConfig(new TestMacroConfig());

事件

1. before-download-attachment
当用户点击附件下载按钮或其他请求下载附件之前触发

提供参数

  • result <Object>

    • url <String> 附件的下载链接地址
    • name <String> 附件的名称

实例

editor.on('before-download-attachment', (result) => {
    console.log(result.url, result.name)
})

2. before-download-image
当用户点击下载图片按钮或其他请求下载图片之前触发

提供参数

  • result <Object>

    • url <String> 附件的下载链接地址

实例

editor.on('before-download-image', (result) => {
    console.log(result.url)
})

3. before-insert-link
当用户点击插入链接按钮或其他修改链接按钮之前触发

提供参数

  • originUrl <String> 原链接地址
  • next <Function> 回调函数,如需要自定义插入或修改链接窗口,传入需要插入的url

实例

editor.on('before-insert-link', (originUrl, next) => {
    console.log(originUrl)
    var url = 'note.youdao.com';
    next(url);
})

4. before-open-link
当用户点击链接或其他请求打开链接之前触发

提供参数

  • result <Object>

    • href <Sring> 链接的地址

实例

editor.on('before-open-link', (result) => {
    console.log(result.href)
})

5. clipboard-error
通过右键菜单或其他情况非快捷键触发粘贴、复制、剪切操作失败时触发,目前由于浏览器安全策略粘贴操作一定会失败

提供参数

  • type <String> cut | copy | paste 出错的操作类型
  • next <Function> 如果需要在提示完成后恢复编辑器焦点,可以调用该方法

实例

editor.on('clipboard-error', (type, next) => {
    alert('复制粘贴错误类型:' + type)
    next()
})

6. content-change
当文件内容发生变化时触发

提供参数

实例

editor.on('content-change', () => {
    console.log('Content change!')
})

7. context-menu
当需要显示右键菜单时触发

提供参数

  • options <Object>

    • left 相对于窗口的距离
    • top 同上
    • items <Array> 菜单列表, 内含多个菜单信息的<Object>

      • <Object>

        • index <String> 功能序列号
        • label <String> 菜单别名
        • name <String> 菜单名
        • type <Number> 0:普通菜单 2:子菜单 3:分隔符
  • next <Function> 回调函数,需要传入点击的菜单的序号,如第一个菜单则在用户点击后执行 next(items[0].index)

实例

editor.on('before-context-menu', (options, next) => {
    // do something...
    next(item[0].index)
})

8. require-attachment
请求插入附件时触发

提供参数

  • next <Function> 作为回调函数接收<Object>类型附件信息

    • <Object>

      • resource <String> 附件的下载地址
      • [fileName] <String> 附件名
      • [fileLength] <Number> 附件大小
      • [src] <String> 附件缩略图地址

实例

editor.on('require-attachment', (next) => {
    // do something...
    next({
        resource: 'http://path.ext',
        fileName: '文件名',
        fileLength: 1024,
        src: 'http://thumbnail.jpg',
    })
})

9. require-image
请求插入图片操作时触发

提供参数

  • <Function> 作为回调函数接收<Object>类型图片信息

    • <Object>

      • src <String> 图片地址

实例

editor.on('require-image', (next) => {
    // do something...
    next({
        src: 'http://image.jpg',
    })
})

10. preview-image
双击图片触发图片预览

提供参数

  • options <Object>

    • curIndex <Number> 当前图片在所有图片资源的位置索引
    • items <Object> 所有图片的信息

      • index <Number> 图片位置索引
      • name <String> 图片标题
      • src <String> 图片URL

实例

editor.on('preview-image', (options) => {
    // do something...
    console.log('preview-image', options)
})

11. insert-macro-clicked
点击工具栏上的插入宏按钮

提供参数

  • macroOptions <Object> 需要放到插入宏弹窗中显示的宏配置的数组

    • key <String> 返回macro的macroName
    • value <any> 返回macro对应的customOptions
  • <Function> 作为回调函数接收<String>类型MacroName信息

    • macroName <String> 点击的macro的名字,会弹出改macro的插入窗口

实例

editor.on('yne-insert-macro-clicked', (macroOptions, next) => {
    this.trigger('insert-macro-clicked', macroOptions, (macroName) => {
        next(macroName);
    });
});

自定义工具栏

符号 ^ 表示将一个item置顶

toolbarItems:['^bold', '^color']            // 显示默认所有图标,置顶bold和color  

符号 ! 表示将一个item从默认列表移除

toolbarItems:['!bold', '!color']            // 显示默认所有图标,移除bold和color  

符号 | 表示插入一个分割线

toolbarItems:['^bold', '|', '|', '^color']       // 显示默认所有图标,置顶bold和color,并在bold和color间插入两个分割线  

不使用默认的所有图标

toolbarItems: ['undo', 'redo', 'bold', 'color']  // 只显示自定的4个图标 

同时使用置顶和移除

toolbarItems:['^bold', '^underline', '!color']   // 显示默认所有图标,移除color,置顶bold和underline 

其余特例及显示结果

toolbarItems:['color', 'undo', '^redo']          // **不推荐的写法**,效果等同写['redo', 'color', 'undo']
toolbarItems:['color', 'undo', '!redo']          // **不推荐的写法**,效果等同写[color', 'undo']
toolbarItems:['!undo', '|', '!redo']             // **不推荐的写法**,显示默认所有图标,移除了undo和redo
toolbarItems:['|', '|', '|']                     // **不推荐的写法**

附录A: 工具栏项

|                   | 分割线(仅UI)
undo                | 撤销
redo                | 重做
remove-format       | 清除格式
format-painter      | 格式刷
heading             | 标题
font-family         | 字体
font-size           | 字号
bold                | 加粗
italic              | 斜体
underline           | 下划线
strike              | 删除线
color               | 文字颜色
back-color          | 背景色
unordered-list      | 无序列表
ordered-list        | 项目编号
todo                | 待办
indent              | 增加缩进
outdent             | 减少缩进
line-height         | 行高
table-justify       | 对齐(仅表格)
table-merge         | 合并单元格(仅表格)
table-split         | 分割单元格(仅表格)
table-operate       | 操作表格(仅表格)
table-wrap          | 自动换行(仅表格)
table               | 插入表格
hr                  | 插入水平线
link                | 插入链接
img                 | 插入图片
attachment          | 插入附件
catalogue           | 插入目录    

编辑器宏开发及使用

宏段落
宏段落为存储格式,生成的XML格式如下所示

<macro>
  <name>mymacro</name>
  <content>this is a macro</content>
  <version>1.0.0</version>
</macro>

宏段落数据定义
name: 宏名称字段,具有唯一性

content: 宏内容,可以是任意格式的数据,根据宏配置自行做消费

version: 宏版本,用于同名称宏的新旧版本的兼容与转换

宏配置
宏配置为宏的配置文件,包含宏的显示与修改逻辑。宏段落与宏配置通过唯一的名称字段做绑定。宏配置的接口如下所示:

interface IMacroToolbarOptions {
    label: string;
    icon: string;
}

interface IMacroConfig {
    macroName: string;
    version: string;
    toolbarOptions?: IMacroToolbarOptions;
    customOptions?: any;
    getReadView(macroContent: string, macroVersion?: string): Promise<any>;
    getEditView(macroContent: string, macroVersion?: string): Promise<any>;
    getEditDialog(macroContent: string, macroVersion?: string): Promise<string>;
    getInsertDialog(): Promise<string>;
}

宏配置接口定义
macroName: 宏配置名称,与宏段落的名称一致

version: 宏配置的版本信息,当出现宏段落的版本与宏配置的版本不一致时,需要做兼容性处理。

toolbarOptions: 渲染编辑器内的工具栏时,所需要的配置,遵循IMacroToolbarOptions格式:

  1. label 宏配置的标签,用于工具栏按钮的浮动提示
  2. icon 宏配置的图标,用于工具栏按钮的图标,格式为base64的图片字符串,支持图片格式及svg。

customOptions: 用户自定义配置,编辑器不做处理,会在insert-macro-clicked等事件中,返回给宏开发者

getReadView: 获取阅读模式下的视图渲染,返回值为Promise对象。相关参数为:

  1. macroContent 必要参数,宏段落的数据
  2. macroVersion 可选参数,需要处理的宏段落版本信息

getEditView: 获取编辑模式下的视图渲染,返回值为Promise对象。相关参数为:

  1. macroContent 必要参数,宏段落的数据
  2. macroVersion 可选参数,需要处理的宏段落版本信息

getInertDialog: 获取插入时的弹框视图,返回值为Promise对象。相关参数为:

  1. macroContent 必要参数,宏段落的数据,一般为空值

宏配置例子

import $ = require('jquery');
import csjs = require('csjs');
import { IMacroConfig } from 'common/core/MacroConfigInterface';
import AttachmentParse = require('common/util/attachmentParse');

class AttachmentMacro implements IMacroConfig {
    macroName = 'attachment_macro';
    version = '1.0.0';

    toolbarOptions = {
        label: '宏附件',
        // tslint:disable-next-line
        icon: 'data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+DQo8c3ZnIHdpZHRoPSIxOHB4IiBoZWlnaHQ9IjE4cHgiIHZpZXdCb3g9IjAgMCAxOCAxOCIgdmVyc2lvbj0iMS4xIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB4bWxuczpza2V0Y2g9Imh0dHA6Ly93d3cuYm9oZW1pYW5jb2RpbmcuY29tL3NrZXRjaC9ucyI+DQogICAgPCEtLSBHZW5lcmF0b3I6IFNrZXRjaCAzLjUuMSAoMjUyMzQpIC0gaHR0cDovL3d3dy5ib2hlbWlhbmNvZGluZy5jb20vc2tldGNoIC0tPg0KICAgIDx0aXRsZT7pmYTku7Y8L3RpdGxlPg0KICAgIDxkZXNjPkNyZWF0ZWQgd2l0aCBTa2V0Y2guPC9kZXNjPg0KICAgIDxkZWZzPjwvZGVmcz4NCiAgICA8ZyBpZD0iUGFnZS0xIiBzdHJva2U9Im5vbmUiIHN0cm9rZS13aWR0aD0iMSIgZmlsbD0ibm9uZSIgZmlsbC1ydWxlPSJldmVub2RkIiBza2V0Y2g6dHlwZT0iTVNQYWdlIj4NCiAgICAgICAgPGcgaWQ9InN2ZyIgc2tldGNoOnR5cGU9Ik1TQXJ0Ym9hcmRHcm91cCIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoLTY0LjAwMDAwMCwgLTc4LjAwMDAwMCkiPg0KICAgICAgICAgICAgPHBhdGggZD0iTTcyLjEwOTM3MzEsOTUuODM0MDgzMSBMNzIuMTAwNzEwNSw5NS44MzQwODMxIEM3MC40MDQ3NTY3LDk1LjgzMDIzMyA2OS4wMjQ1MDgzLDk0LjQ0NjEzNDUgNjkuMDI0NTA4Myw5Mi43NDkyMTgyIEw2OS4wMjQ1MDgzLDg0LjU5MDkyOTcgQzY5LjAyNDUwODMsODIuMjM4NTM5OCA3MC44NzYzODk3LDgwLjMyNDA5NDggNzMuMTUyNzQwOSw4MC4zMjQwOTQ4IEM3NS40MDMxMDQxLDgwLjMyNDA5NDggNzcuMjMzODEwMSw4Mi4yMzg1Mzk4IDc3LjIzMzgxMDEsODQuNTkwOTI5NyBMNzcuMjMzODEwMSw5MC41MzI1NDMxIEM3Ny4yMzM4MTAxLDkwLjc5OTE2MDEgNzcuMDE4MjA2NSw5MS4wMTM4MDEzIDc2Ljc1MjU1Miw5MS4wMTM4MDEzIEM3Ni40ODU5MzQ5LDkxLjAxMzgwMTMgNzYuMjcxMjkzOCw5MC43OTkxNjAxIDc2LjI3MTI5MzgsOTAuNTMyNTQzMSBMNzYuMjcxMjkzOCw4NC41OTA5Mjk3IEM3Ni4yNzEyOTM4LDgyLjczODA4NTggNzQuOTAxNjMzLDgxLjI4NjYxMTEgNzMuMTUyNzQwOSw4MS4yODY2MTExIEM3MS40MDc2OTg3LDgxLjI4NjYxMTEgNjkuOTg3MDI0Niw4Mi43Njg4ODYzIDY5Ljk4NzAyNDYsODQuNTkwOTI5NyBMNjkuOTg3MDI0Niw5Mi43NDkyMTgyIEM2OS45ODcwMjQ2LDkzLjkxNjc1MDYgNzAuOTM3MDI4Miw5NC44Njg2NzkyIDcyLjEwMzU5OCw5NC44NzE1NjY4IEw3Mi4xMDkzNzMxLDk0Ljg3MTU2NjggQzcyLjY3OTE4MjgsOTQuODcxNTY2OCA3My4yMTcyMjk0LDk0LjY0ODI2MyA3My42MjM0MTEzLDk0LjI0MzA0MzYgQzc0LjAzMTUxODMsOTMuODM1ODk5MiA3NC4yNTU3ODQ2LDkzLjI5Njg5IDc0LjI1NTc4NDYsOTIuNzI1MTU1MyBMNzQuMjU1Nzg0Niw4NC41OTg2Mjk5IEM3NC4yNTU3ODQ2LDg0LjI4OTY2MjEgNzQuMTM1NDcsODMuOTk5OTQ0NyA3My45MTY5Nzg4LDgzLjc4MjQxNiBDNzMuNjk5NDUwMSw4My41NjM5MjQ4IDczLjQxMDY5NTIsODMuNDQ0NTcyOCA3My4xMDI2OSw4My40NDQ1NzI4IEw3My4wOTk4MDI1LDgzLjQ0NDU3MjggQzcyLjc5MTc5NzIsODMuNDQ1NTM1MyA3Mi41MDMwNDIzLDgzLjU2NjgxMjMgNzIuMjg1NTEzNiw4My43ODUzMDM1IEM3Mi4wNjc5ODQ5LDg0LjAwMzc5NDggNzEuOTQ4NjMyOSw4NC4yOTM1MTIyIDcxLjk0OTU5NTQsODQuNjAyNDc5OSBMNzEuOTY5ODA4Myw5MS4xNTQzMjg3IEM3MS45NzA3NzA4LDkxLjQyMDk0NTcgNzEuNzU0MjA0Niw5MS42MzE3MzY4IDcxLjQ4ODU1MDEsOTEuNjM2NTQ5MyBDNzEuMjIzODU4MSw5MS42MzY1NDkzIDcxLjAwODI1NDQsOTEuNDIxOTA4MiA3MS4wMDcyOTE5LDkxLjE1NzIxNjIgTDcwLjk4NzA3OTEsODQuNjA0NDA1IEM3MC45ODUxNTQxLDg0LjAzOTQwNzkgNzEuMjAzNjQ1Myw4My41MDcxMzYzIDcxLjYwMzA4OTUsODMuMTA1NzY3IEM3Mi4wMDE1NzEzLDgyLjcwNTM2MDIgNzIuNTMxOTE3OCw4Mi40ODM5ODE1IDczLjA5Nzg3NzQsODIuNDgyMDU2NCBMNzMuMTAyNjksODIuNDgyMDU2NCBDNzMuNjY2NzI0Niw4Mi40ODIwNTY0IDc0LjE5NzA3MTEsODIuNzAxNTEwMSA3NC41OTY1MTU0LDgzLjEwMDk1NDQgQzc0Ljk5Nzg4NDcsODMuNTAwMzk4NyA3NS4yMTgzMDA5LDg0LjAzMjY3MDIgNzUuMjE4MzAwOSw4NC41OTg2Mjk5IEw3NS4yMTgzMDA5LDkyLjcyNTE1NTMgQzc1LjIxODMwMDksOTMuNTUzODgxOSA3NC44OTM5MzI5LDk0LjMzNTQ0NTIgNzQuMzAyOTQ3OSw5NC45MjQ1MDUyIEM3My43MTQ4NTA0LDk1LjUxMTY0MDEgNzIuOTM2MTc0Nyw5NS44MzQwODMxIDcyLjEwOTM3MzEsOTUuODM0MDgzMSIgaWQ9IumZhOS7tiIgZmlsbD0iIzUyNUM2RiIgc2tldGNoOnR5cGU9Ik1TU2hhcGVHcm91cCIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoNzMuMTI5MTU5LCA4OC4wNzkwODkpIHJvdGF0ZSgtMzIwLjAwMDAwMCkgdHJhbnNsYXRlKC03My4xMjkxNTksIC04OC4wNzkwODkpICI+PC9wYXRoPg0KICAgICAgICAgICAgPGcgaWQ9IuWIh+WbviIgc2tldGNoOnR5cGU9Ik1TTGF5ZXJHcm91cCIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoMzIuMDAwMDAwLCAxNi4wMDAwMDApIj48L2c+DQogICAgICAgIDwvZz4NCiAgICA8L2c+DQo8L3N2Zz4='
    };

    private styles = csjs`
.container {
    display: inline-block;
    position: relative;
    outline: none;
    width: 280px;
    height: 64px;
    border-radius: 4px;
    background-color: #ffffff !important;
    border: solid 1px #e0e1e5;
    vertical-align: middle;
}

.download {
    position: absolute;
    right: 0;
    z-index: 100;
    margin-top: -26px;
    margin-right: 22px;
    cursor: pointer;
    display: none;
}

.history {
    position: absolute;
    right: 0;
    z-index: 100;
    margin-top: -26px;
    margin-right: 44px;
    cursor: pointer;
    display: none;
}

.container:hover .download,
.container:hover .history{
    display: block;
}

.icon {
    margin: 13px 17px 15px 15px;
    float: left;
    -webkit-print-color-adjust: exact;
}

.title {
    height: 18px;
    font-size: 12px;
    font-weight: 500;
    font-style: normal;
    font-stretch: normal;
    text-align: justify;
    color: #393939;
    margin-top: 16px;
    width: 166px;
    text-overflow: ellipsis;
    white-space: nowrap;
    overflow: hidden;
    cursor: default;
}

.name {
    max-width: 115px;
    display: inline-block;
    text-overflow: ellipsis;
    white-space: nowrap;
    overflow: hidden;
    margin: 0;
}

.type {
    display: inline-block;
    text-overflow: ellipsis;
    white-space: nowrap;
    overflow: hidden;
    margin: 0;
}

.size {
    font-size: 12px;
    font-weight: normal;
    font-style: normal;
    font-stretch: normal;
    text-align: justify;
    color: #797979;
    cursor: default;
    height: 14px;
    -webkit-touch-callout: none;
    -webkit-user-select: none;
    -khtml-user-select: none;
    -moz-user-select: none;
    -ms-user-select: none;
    user-select: none;
}
    `;

    private resource = 'http://note.youdao.com/styles/images/02e7cce7.appstore.png';
    private name = '我是新版附件';

    constructor() {
        this.downloadAttachment = this.downloadAttachment.bind(this);
    }

    renderView(macroContent: string): Promise<HTMLElement> {
        return new Promise((resolve, reject) => {
            let attachment;
            try {
                attachment = JSON.parse(macroContent);
            } catch (e) {
                reject('parse macro content failed');
            }

            if (!attachment) {
                reject('macro content is empty');
            }

            // let src = attachment.source;
            const fileName = attachment.fileName;
            const fileSize = attachment.fileLength;
            const fileType = AttachmentParse.getFileType(fileName);
            let fileIcon;

            if (!fileType) {
                fileIcon = 'bulb__svg--type_other_large';
            } else {
                fileIcon = 'bulb__svg--type_' + fileType + '_large';
            }

            const size = typeof(fileSize) === 'undefined' ?
                    '未知大小' : AttachmentParse.getSizeString(fileSize);

            const splitFileName = AttachmentParse.splitFileFullName(fileName);

            const template = $(
    `

<div class="${this.styles.container}" title="${fileName}">
    <style>
    $\{csjs.getCss(this.styles)\}
    </style>
    <div class="${this.styles.icon} bulb__svg-common ${fileIcon}"></div>
    <div class="${this.styles.title}">
        <p class="${this.styles.name}">${splitFileName.fileName}</p>
        <p class="${this.styles.type}">${splitFileName.fileType}</p>
    </div>
    <div class="${this.styles.size}">${size}</div>
    <div class="${this.styles.download} bulb__svg--attacthment_download bulb__svg-common"></div>
    <div class="${this.styles.history} bulb__svg--attacthment_download bulb__svg-common"></div>
</div>
    `);

            if (template) {
                const $download: JQuery = template.find('.' + this.styles.download);
    $download.click\(this.downloadAttachment\);
            }

            if (template && template.get(0)) {
                resolve(template.get(0));
            } else {
                reject('render html failed');
            }
        });
    }

    getReadView(macroContent: string): Promise<HTMLElement> {
        return this.renderView(macroContent);
    }

    getEditView(macroContent: string): Promise<HTMLElement> {
        return this.renderView(macroContent);
    }

    getEditDialog(macroContent: string): Promise<string> {
        return new Promise((resolve, reject) => {
            let attachment;
            try {
                attachment = JSON.parse(macroContent);
            } catch (e) {
                reject('parse macro content failed');
            }

            if (!attachment) {
                reject('macro content is empty');
            }

            const fileName = window.prompt('请输入附件名称', attachment.fileName);
            if (fileName !== null) {
                attachment.fileName = fileName;
            }
            resolve(JSON.stringify(attachment));
        });
    }

    getInsertDialog(): Promise<string> {
        return Promise.resolve(JSON.stringify({
            fileName: '附件',
            fileLength: '20',
            source: 'http://www.baidu.com',
        }));
    }

    private downloadAttachment() {
        const node = document.createElement('a');
        node.setAttribute('href', this.resource);
        node.setAttribute('download', this.name);
        node.click();
    }
}

export = AttachmentMacro;

常见问题及注意事项

1. 编辑器无法加载?

检查下编辑器授权接口回调的错误信息,保证申请的appKey是有效且提前绑定了。

  • 返回110

应用没有绑定服务实例,可以新建服务实例,绑定服务实例。

  • 返回108

appKey无效,注册账号, 登录后台创建应用和实例并完成绑定, 可获得应用ID和密钥等信息,其中应用ID就是appKey( 注意不是应用密钥)

错误码

错误码含义
101缺少必填的参数,出现这个情况还可能是et的值和实际加密方式不对应
102不支持的语言类型
103翻译文本过长
104不支持的API类型
105不支持的签名类型
106不支持的响应类型
107不支持的传输加密类型
108appKey无效,注册账号, 登录后台创建应用和实例并完成绑定, 可获得应用ID和密钥等信息,其中应用ID就是appKey( 注意不是应用密钥)
109batchLog格式不正确
110无相关服务的有效实例
111开发者账号无效
113q不能为空
201解密失败,可能为DES,BASE64,URLDecode的错误
202签名检验失败
203访问IP地址不在可访问IP列表
301辞典查询失败
302翻译查询失败
303服务端的其它异常
401账户已经欠费停

版本更新记录

上线日期版本号更新内容
20180209v1.0.0有道编辑器SDK Web版上线,支持富文本编辑
20181109v1.1.0添加html和纯文本格式输出,添加宏配置,添加工具栏定制
文档是否有帮助解决问题?

如有其它疑问,可在此提交意见和反馈
详细描述(选填)
联系邮箱(选填)
 
有道智云平台介绍
网易有道旗下一个为开发者、企业和政府机构等提供自然语言翻译、文字识别OCR等服务以及行业解决方案的云服务平台,致力于提供安全、可靠和高效的云服务。
联系方式
联系电话:010-8255-8901
商务合作:
投诉反馈:
地址:北京市海淀区西北旺东路10号院 中关村软件园二期西区7号 网易(北京)公司
微信公众号
微信小程序
 
 
 
©2017 网易公司 京ICP证080268号