editor.js

/**
 * 公文编辑器。符合《党政机关公文格式》国家标准(GB/T 9704-2012)
 * @class DocEditor
 * @param {Element} el 要装载编辑器的Element对象
 * @param {options} [options] 公文编辑配置数据数据
 * @param {Service} [service] 公文编辑请求对象,需要调用者实现。
 *
 * @example
 * //通过script标签引用
 * //将build后的dist目录部署到服务器web目录,dist可更改名称,然后通过script标签引入
 *<html>
     <head>
         <title>docEditor</title>
         <script src="./dist/docEditor.js"></script>
     </head>
     <body>
     <div></div>
     <script>
        DocEditor.createEditor("div", {
            //此处配置所需要的参数
        }).load()
     </script>
     </body>
 </html>
 *
 * @example
 * //使用 ES Module 模块引用
 * //1、将源码包放到项目目录中。
 * //2、使用 npm install <doceditor路径> 进行安装
 * //3、打包配置,需要将doceditor下的public目录部署到输出目录,如果您使用webpack,在config中使用CopyPlugin插件:
 *  plugins: [
        new CopyPlugin({
            patterns: [
                { from: "doceditor/public", to: "doceditor/public" }
            ],
        })
    ]
 *
 * //4、在代码中使用。
 *  import DocEditor from '@o2oa/doceditor'
 *  var div = document.createElement("div");
    document.body.appendChild(div)

    const editor = DocEditor.createEditor(div, {
        'base': './doceditor/'  //我们在打包配置中将public目录输出到了 doceditor/public,所以此处需要配置为'./doceditor/' 或 'doceditor/'
        //此处配置其他所需要的参数
    });
    editor.load().then(()=>{
        //编辑器加载完成
    }));
 *
 * @example
 * //使用 CommandJS 模块引用
 * //与 ES Module 模块基本相同,只是通过require函数引入DocEditor
 *
 * const DocEditor = require('@o2oa/doceditor');
 * //后面与 ES Module 模块相同
 */


class DocEditor{
    /**
     * 编辑器配置参数
     * @typedef {Object} options
     * @example
     * {
     *        "base": "",               //编辑器引用的基础路径。如果使用<script>标签引用,一般情况下,会自动计算引用路径,此处保持为空,就可以。
     *                                  //当使用模块化ESModule 或 CommonJS引用时, 需要将base设置为 doceditor/public目录的部署路径。
     *        "id": "documenteditor",   //编辑器标识
     *        "name": "",               //编辑器名称
     *        "readonly": false,        //是否只读
     *        "lp": "zh-cn",            //语言,目前只有zh-cn 和 en
     *        "mobile": false,          //是否时移动端展现,
     *        "defaultValue": {         //编辑器数据默认值
                "copies": "",           //份数
                "secret": "",           //密级
                "priority": "",         //紧急度
                "redHeader": "文件红头",        //文件红头,允许html
                "fileno": "[文号]",           //文号
                "signerTitle": "签发人:",      //签发人标题
                "signer": "[签发人]",             //签发人,允许文本数组
                "subject": "[文件标题]",           //文件标题
                "mainSend": "[主送单位:]",          //主送单位
                "filetext": "[请在此处编辑正文内容]", //正文
                "attachmentTitle": "附件:",           //附件说明标题
                "attachment": "",                      //附件说明列表,允许数组
                "issuanceUnit": "[发文机关]",           //发文机关
                "issuanceDate": "[成文日期]",           //成文日期
                "annotation": "",                       //附注
                "copytoTitle": "抄送:",               //抄送标题
                "copyto": "[抄送]",                       //抄送
                "copyto2Title": "发:",
                "copyto2": "[发]",
                "editionUnit": "[印发机关]",            //印发机关
                "editionDate": "[印发日期]",            //印发日期
                "meetingAttendTitle": "出席:",
                "meetingLeaveTitle": "请假:",
                "meetingSitTitle": "列席:",
                "meetingAttend": "",                    //会议出席
                "meetingLeave": "",                     //会议请假
                "meetingSit": "",                       //会议列席
                "meetingRecord": ""                     //会议记录
              },
              "documentTempleteType": "sys",            //公文模板类型,取值 "sys"或 "cus"; sys 标识系统内置模板,documentTempleteName字段生效; cus 表示自定义模板,documentTempleteUrl字段生效
              "documentTempleteName": "standard",       //内置模板名称,见 src/editor/templete.json, 模板取值:
                                                        //standard (标准公文类); meeting (纪要通报类); party-meeting (党委纪要类); letter (函类); command (命令类); party(党委纪委类); combine(联合发文类); empty (空模板(仅正文))
              "documentTempleteUrl" : "",               //自定义模板url路径

              "allowEdit": "y",                         //是否允许编辑 "y" 或 "n" 或 "s" 表示根据脚本确定
              "allowPrint": "y",                        //是否允许打印 "y" 或 "n" 或 "s" 表示根据脚本确定
              "allowHistory": "y",                      //是否允许查看痕迹 "y" 或 "n" 或 "s" 表示根据脚本确定
              "allowEditScript": null,                  //判断是否允许编辑的脚本(allowEdit为"s"时有效),一个返回boolean型的function,或者是 {"code": "return true"},这样的代码片段
              "allowPrintScript": null,                 //判断是否允许打印的脚本(allowPrint"s"时有效),一个返回boolean型的function,或者是 {"code": "return true"},这样的代码片段
              "allowHistoryScript": null,               //判断是否允许查看痕迹的脚本(allowHistory"s"时有效),一个返回boolean型的function,或者是 {"code": "return true"},这样的代码片段


              "canScale": true,                           //是否允许缩放 true 或 false
              "fullWidth": true,                         //自动将半角空格转换为全角 true 或 false
              "textIndent": true,                        //段落首行自动缩进 true 或 false
              "canFullScreen": true,                     //是否允许全屏 true 或 false
              "toWordSeal": true,                        //转换word时,是否显示图片章 true 或 false
              "firstPageNumber": true,                  //转换word,第一页是否显示页码 true 或 false
              "wordConversionEncryption": false,         //转换word,是否启用文档保护 true 或 false

              "copiesSecretPriorityShow": "y",          //份号、密级、紧急度是否显示  "y" 或 "n"

              "copiesShow": "a",                        //份号是否显示  "y":显示; "n":不显示; "a":自动(有值就显示,否则隐藏); "s": 根据脚本确定(脚本返回true显示,否则隐藏)
              "copiesShowScript": null,                 //通过脚本判断份号是否显示(copiesShow为"s"时有效),一个返回boolean型的function,或者是 {"code": "return true"},这样的代码片段
              "copiesValueType": "data",                //份号数据绑定类型,"data":绑定表单上的一个可输入字段(copiesValueData); "script":通过脚本绑定值(redHeaderValueScript)
              "copiesValueData": "",                    //份号数据绑定的表单字段选择器,如"#subject",表示id为subject的dom元素。
              "copiesValueScript": null,                //通过脚本绑定数据,copiesValueType为“script”时生效。一个function,或者是 {"code": "return '数据'"},这样的代码片段

              ...                                       //所有公文元素都有这五个字段,他们的含义都是一样的,可以看src/editor/options.json文件

              "subjectEdit" : "y",                      //份号是否允许编辑  "y"、"n" 或 "s": 根据脚本确定(脚本返回true可编辑,否则不可编辑)
              "subjectEditScript": null,                //通过脚本判断标题是否可编辑(subjectEdit"s"时有效),一个返回boolean型的function,或者是 {"code": "return true"},这样的代码片段
              "subjectFontFamily": "方正小标宋简体",     //标题字体


              "customFields": {                         //模板中自定义元素数据绑定,这个样例的意思是将自定义元素layout_opinions与表单字段#opinions的只绑定
                 "layout_opinions" : "#opinions"        //模板元素设置class为“doc_layout”,并增加属性“data-doc-layout='xxxx'”就是一个名为xxxx的自定义元素
              },                                        //这个例子中,模板中应该有一个类似 <div class='doc_layout' data-doc-layout='layout_opinions'></div>  这样的元素

              "ckeditConfigOptions"                     //ckeditor编辑器配置参数,一个返回Object类型的function,或者是 {"code": "return {}"},这样的代码片段

              "recordScale": false,                     //是否记录用户设置的缩放比例,下次打开时以这个比例显示
              "autoScale": "auto",                      //是否自动调整比例。当屏幕足够大,显示100%,当屏幕不足以显示100%比例时,自动将宽度缩小到展现文档内容
              "fullScreenDom": null,                    //全屏时参照的dom对象,为空时就是document.body
               "user": {                                //当前用户名称
                   "name": "测试"
               },
               "activity": {                            //当前活动名称
                  "name": "核稿"
               },
               "processInfo": {},                       //文档或流程相关的扩展信息

               "docId": ""                              //当前文档的唯一标识,一般情况下是流程实例的id
     * }
     */
    options;

    /**
     * 编辑器加载前触发。
     * @event DocEditor#beforeLoad
     */
    /**
     * 编辑器加载前触发。
     * @event DocEditor#queryLoad
     */
    /**
     * 编辑器加载后触发。
     * @event DocEditor#postLoad
     */
    /**
     * 编辑器加载后触发。
     * @event DocEditor#load
     */
    /**
     * 公文页面被重画后触发。
     * @event DocEditor#loadPage
     */
    /**
     * 正文中粘贴内容时触发
     * @event DocEditor#paste
     */
    /**
     * 正文改变后触发。
     * @event DocEditor#change
     */
    /**
     * 正文编辑器获得焦点时触发。
     * @event DocEditor#focus
     */
    /**
     * 正文编辑器失去焦点时触发。
     * @event DocEditor#blur
     */
    /**
     * 正文编辑器加载完成时触发。
     * @event DocEditor#loaded
     */
    /**
     * 正文中粘贴内容后触发。
     * @event DocEditor#afterPaste
     */
    /**
     * 全屏展示时触发。
     * @event DocEditor#fullScreen
     */
    /**
     * 显示痕迹时触发。
     * @event DocEditor#showHistory
     */
    /**
     * 保存痕迹之前触发。
     * @event DocEditor#beforeSaveHistory
     */
    /**
     * 保存痕迹之后触发。
     * @event DocEditor#afterSaveHistory
     */
    /**
     * 保存编辑器数据之前触发。
     * @event DocEditor#beforeSave
     */
    /**
     * 保存编辑器数据之后触发。
     * @event DocEditor#afterSave
     */
    #eventList = {
        'beforeLoad': [],
        'queryLoad': [],
        'postLoad': [],
        'load': [],
        'loadPage': [],
        'paste': [],
        'change': [],
        'focus': [],
        'blur': [],
        'loaded': [],
        'afterPaste': [],
        'fullScreen': [],
        'showHistory': [],
        'beforeSaveHistory': [],
        'afterSaveHistory': [],
        'beforeSave': [],
        'afterSave': []
    };

    /**
     * @summary 创建编辑器
     * @param {Element} el 要装载编辑器的Element对象
     * @param {options} options 公文编辑配置数据数据
     * @param {Service} service 公文编辑请求对象,需要调用者实现。
     * @example
     * const editor = DocEditor.createEditor(node);
     * editor.load().then(()=>{
     *  //...
     * });
     */
    constructor(el, options, service){}

    /**
     * @summary 载入公文编辑器
     * @param {Object} data 公文编辑数据
     * @example
     * const editor = DocEditor.createEditor(node);
     * editor.load().then(()=>{
     *  //...
     * });
     */
    async load(data){};

    /**
     * @summary 重新载入公文编辑器
     * @param {Object} options 公文编辑配置数据数据
     * @param {Object} data 公文编辑数据
     * @example
     * const editor = DocEditor.createEditor(node);
     * editor.reload().then(()=>{
     *  //...
     * });
     */
    async reload(options, data){};

    /**
     * @summary 重新计算公文要素显示
     * @example
     * editor.redisplay();
     */
    redisplay(){}

    /**对正文进行模拟盖章(模板中必须有class为“doc_layout_seal”的img对象)
     * @summary 对正文进行模拟盖章,此方法只是进行模拟盖章,通过图片显示,并非专业盖章,不具备法律效应。
     * @param src{String} 盖章图片的url.
     * @param position{integer} 要盖章的位置, 默认为0.
     * @example
     *  editor.seal("../custom/img/seal.png", 0); //在第一个盖章位置进行模拟盖章
     */
    seal(src, position){};

    /**
     * @summary 设置公文编辑器数据
     * @param {Object} data 公文编辑数据
     * @example
     * const data = editor.getData();
     * data.filetext = "测试内容";
     * editor.setData(data);
     */
    setData(data){};

    /**
     * @summary 获取公文编辑器数据
     * @return {Object} 公文编辑器的数据
     * @example
     * const data = editor.getData();
     */
    getData(){};

    /**
     * @summary 重新设置公文编辑器数据和展现
     * @example
     * const data = editor.resetData();
     */
    resetData(){};

    /**
     * @summary 公文编辑器放大显示 5%(0.05)
     * @example
     * editor.zoomIn();
     */
    zoomIn(){};
    /**
     * @summary 公文编辑器缩小显示 5%(0.05)
     * @example
     * editor.zoomOut();
     */
    zoomOut(){};

    /**设公文编辑器缩放
     * @param {number} scale 缩放比例(0.5 - 2)
     * @param {boolean} temporary 可选 是否是临时缩放(默认false)
     * @example
     * editor.zoom(1.3);
     */
    zoom(scale, temporary){};

    /**
     * @summary 根据屏幕自动缩放正文大小
     * @param {boolean} temporary 可选 是否是临时缩放(默认false)
     * @example
     * editor.autoZoom();
     */
    autoZoom(temporary){};

    /**
     * @summary 进入阅读状态,正文不能编辑
     * @example
     * editor.readFiletext();
     */
    readFiletext(){};

    /**
     * @summary 进入编辑状态,正文可编辑
     * @example
     * editor.editFiletext();
     */
    editFiletext(){};


    /**
     * @summary 保存正文数据 (需要实现service.saveData方法来完成与服务器的交互)
     * @example
     * editor.save();
     */
    save(){};

    /**
     * @summary 保存修订痕迹数据。会计算正文内容与上一次保存或第一次打开时的差异,生成修订痕迹,并请求保存。(需要实现service.saveHistory方法来完成与服务器的交互)
     * @example
     * editor.saveHistory();
     */
    saveHistory(){}

    /**
     * @summary 全屏显示
     * @example
     * editor.fullScreen();
     */
    fullScreen(){};

    /**将公文编辑器内容以html形式输出
     * @return {String}
     * @example
     * var html = editor.getDocumentHtml();
     */
    getDocumentHtml(){};

    /**
     * @summary 将公文转换为word
     * @return {Promise} revole了word文件的Blob数据。
     * @example
     * editor.toWord();
     */
    toWord(){};

    /**
     * @summary 将公文编辑转换为word文件,并下载
     * @example
     * editor.printDoc();
     */
    async printDoc(e){};

    /**
     * @summary 进入痕迹查看状态
     * @example
     * editor.historyDoc();
     */
    historyDoc(){};

    /**
     * @summary 退出痕迹查看状态
     * @example
     * editor.exitHistoryDoc();
     */
    exitHistoryDoc(){};

    /**
     * @summary 为编辑器注入service对象,用于请求编辑器数据和保存数据等服务,
     * @param {Object} obj 要注入到编辑器的对象
     * @example
     * import DocEditor from '@o2oa/doceditor';
     * const node = document.querySelector('div');
     * const editor = DocEditor.createEditor(node);
     *
     * class MyService extends DocEditor.Service{
     *        async listHistory() {
     *            //获取正文痕迹列表
     *        }
     *        async getHistory(id){
     *            //获取指定的正文痕迹比较数据
     *        }
     *        async saveHistory(data){
     *            //保存正文痕迹比较数据
     *        }
     *        async getData(){
     *            //获取编辑器数据
     *        }
     *        async saveData(data){
     *            //保存编辑器数据
     *        }
     * }
     * const service = new MyService();
     *
     * editor.provide({service});
     *
     * editor.load().then(()=>{
     *  //...
     * });
     */
    provide(service){};


    /**
     * @summary 监听编辑器事件,
     * @param {String} type 编辑器事件名称,可以是dom原生事件,这会将事件绑定到editorNode上
     * @param {Functioin} listener 事件出发时执行函数
     * @example
     * editor.on('loadPage', (e)=>{
     *     //e.editor 编辑器对象
     * });
     */
    on(type, listener){};

    /**
     * @summary 删除编辑器事件监听
     * @param {String} type 编辑器事件名称
     * @param {Functioin} listener 需要从目标事件移除的 listener 函数。
     * @example
     * const listener = (e)=>{
     *     //e.editor 编辑器对象
     * }
     * editor.on('loadPage', listener); //监听编辑器事件
     * editor.off('loadPage', listener); //删除编辑器事件监听
     */
    off(type, listener){};
}
export default DocEditor;