环境:
官网教程:
Angular 中用法
npm install @ckeditor/ckeditor5-angular@1.1.0
npm install @ckeditor/ckeditor5-build-classic@20.0.0
首先 npm 安装两个插件: ckeditor5-angular 和 ckeditor5-build-decoupled-document(以此版本为示例)。
ckeditor5-angular 经测试版本 v4.0.0 不能在 Angular4 中使用,v1.1.0 可以使用,安装此版本。
ckeditor5-build-decoupled-document 经测试版本 v34.0.0 无法在 angular4 使用,v20.0.0 可以使用,安装此版本。
查看插件版本列表命令如下:npm view @ckeditor/ckeditor5-angular versions
。
npm 慢或者报错,请使用 pnpm 或 cnpm。
首先,还是先安装 ckeditor5-angular 和 ckeditor5-build-decoupled-document 插件。
再去 ckeditor5 官网,在线构建自定义插件,地址:online-builder,按步骤创建之后下载。
将下载的压缩文件解压,找到 \build\ckeditor.js 文件,替换到项目
\node_modules@ckeditor\ckeditor5-build-decoupled-document\build 文件夹下。
此时项目中使用的 ckeditor5 插件里的功能与在线构建的功能一样。
自定义版本的插件为最新版本,需要了解与 Angular 版本是否匹配。
官方用法及 ckeditor5 详细用法不做过多介绍,详细用法请看官方文档,本文着重介绍如何自定义一个插件模块并合并到 ckeditor5。
说明:此插件只是实现在 ckeditor5 的图标栏添加剪辑图标,图标的点击事件则绑定在 Angular 中。即:此插件没有实现图标按钮的点击事件的逻辑部分。
既然是自定义,则需要下载源代码,修改后再重新编译。
npm 安装的插件中,没有源代码,如图:
\node_modules@ckeditor\ckeditor5-build-decoupled-document 文件夹显示,要使用的文件是编译过的 \build\ckeditor.js。
而官网在线构建的版本与 GitHub 地址 下载的版本与上述文件夹有区别。
在线构建的插件文件夹结构如图:
主要多了 src 文件夹和 webpack.config.js 文件,src\ckeditor.js 用来配置哪些插件最终应用到插件中,webpack.config.js
配置如何构建插件。
GitHub 下载的文件解压后,找到 packages\ckeditor5-build-decoupled-document,与上述在线构建的插件文件夹结果类似,多了 tests 文件夹和一些文件,如图:
可以复制 packages\ckeditor5-build-decoupled-document 文件夹用于开发,而不改动源文件,带有 webpack.config.js 文件的文件夹即是一个项目。
至于用以上哪种开发根据需求选择,需要自定义后再编写自己的插件就选择在线构建的插件,反之选择 GitHub 版本。
首先介绍一下开发流程:
命令行进入到 ckeditor5-build-decoupled-document(简称 document) 目录下,执行 npm install,安装开发需要的插件,
此时 document 目录下出现 node_modules 文件夹,找到 node_modules@ckeditor,里面是各种基础插件,用来开发 ckeditor5-build-decoupled-document。
将自己编辑的的插件放入里面 node_modules@ckeditor,然后在 ckeditor5-build-decoupled-document\src\ckeditor.js 配置你的插件(根据已有插件配置)。无论编辑插件还是配置都要符合 ckeditor5 的代码规则。
之后在 packages\ckeditor5-build-decoupled-document 目录下,执行 npm run build
,如图:
build 完成后, 在 packages\ckeditor5-build-decoupled-document\build 下找到 ckeditor.js,即编译好的代码,
复制放入 Angular 项目的 node_modules@ckeditor\ckeditor5-build-decoupled-document\build 中即可使用。
下面是代码的具体实现:
不知道如何开始,可以先看看内部的插件如何编写的。比较简单类似的是引用功能(block-quote),甚至可以复制一份将各种文件名,类名,参数名修改后,加入插件。
首先创建文件夹:ckeditor5-cutImage,文件夹位置与结构如图:
创建并修改 lang 下的文件,比如 block-quote 插件中的 lang 文件,此文件为语言翻译,
根据已有的,cutImage 中的 lang 文件夹中的 zh-cn.po 和 contexts.json 文件内容如下:
# Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.
#
# !!! IMPORTANT !!!
#
# Before you edit this file, please keep in mind that contributing to the project
# translations is possible ONLY via the Transifex online service.
#
# To submit your translations, visit https://www.transifex.com/ckeditor/ckeditor5.
#
# To learn more, check out the official contributor's guide:
# https://ckeditor.com/docs/ckeditor5/latest/framework/guides/contributing/contributing.html
#
msgid ""
msgstr ""
"Language-Team: Chinese (China) (https://www.transifex.com/ckeditor/teams/11143/zh_CN/)\n"
"Language: zh_CN\n"
"Plural-Forms: nplurals=1; plural=0;\n"msgctxt "Toolbar button tooltip for cutImage."
msgid "cutImage"
msgstr "截屏"
{"cutImage": "Toolbar button tooltip for cutImage."
}
theme 中的文件类似,最少需要一个 svg 类型的图标,css 则可有可无。
最重要的是 src 中的文件 ,对比 block-quote 插件,创建剪辑的文件,
对比 block-quote 插件,cutimage.js 内容为:
import Plugin from '@ckeditor/ckeditor5-core/src/plugin';import CutImageEditing from './cutimageediting.js';
import CutImageUI from './cutimageui';export default class CutImage extends Plugin {static get requires() {return [ CutImageEditing, CutImageUI ];}
}
cutimagecommand.js 内容为:
import Command from '@ckeditor/ckeditor5-core/src/command';export default class CutImageCommand extends Command {execute( { value } ) {const editor = this.editor;const selection = editor.model.document.selection;}refresh() {const model = this.editor.model;const selection = model.document.selection;const isAllowed = model.schema.checkChild( selection.focus.parent, 'cutImage' );this.isEnabled = isAllowed;}
}
cutimageediting.js 内容为:
import Plugin from '@ckeditor/ckeditor5-core/src/plugin';import { toWidget, viewToModelPositionOutsideModelElement } from '@ckeditor/ckeditor5-widget/src/utils';
import Widget from '@ckeditor/ckeditor5-widget/src/widget';export default class CutImageEditing extends Plugin {static get requires() { // ADDEDreturn [ Widget ];}init() {}
}
cutimageui.js 内容为:
import Plugin from '@ckeditor/ckeditor5-core/src/plugin';
import ButtonView from '@ckeditor/ckeditor5-ui/src/button/buttonview';import cutimageIcon from '../theme/icons/cutimage.svg';
const CUTIMAGE = 'cutImage';export default class CutImageUI extends Plugin {static get pluginName() {return 'CutImageUI';}init() {const editor = this.editor;const t = editor.t;// Add cutImage button to feature components.editor.ui.componentFactory.add( CUTIMAGE, locale => {const command = editor.commands.get(CUTIMAGE);const view = new ButtonView( locale );view.set( {label: t( 'cutImage' ),icon: cutimageIcon,tooltip: true} );return view;} );}
}
至于 package.json 可做适当修改,CHANGELOG.md、README.md 等可以忽略。
至此此插件(半成品)编辑完成。
回到 ckeditor5-build-decoupled-document\src\ckeditor.js 中配置 cutImage 插件,添加内容如图:
在 packages\ckeditor5-build-decoupled-document 目录下,执行 npm run build
构建,等待完成。
注意:ckeditor5 符合 ES6(ECMAScript 2015) 规范,在 webpack.config.js 中配置可以编译为符合 ES5 规范的文件。
由于本项目使用的是 ES5 规范,而重新编译的版本也是符合 ES6 规范的,所以需要稍作配置。
如何配置请看此链接,ES5配置
在 webpack.config.js 配置文件中,找到 module 下的 rules, 增加内容如下:
module: {rules: [{},{ // 此处为新增部分test: /(ckeditor5(?:-[^\/\\]+)?)[\/\\].+\.js$/,use: [{loader: 'babel-loader',options: {presets: [ require( '@babel/preset-env' ) ]}}]}]
}
Angular 项目中的用法如下:
组件中的 ts 文件:
import { Component, OnInit, ViewChild, ViewContainerRef } from '@angular/core';import * as DecoupledEditor from '@ckeditor/ckeditor5-build-decoupled-document';
import '@ckeditor/ckeditor5-build-decoupled-document/build/translations/zh-cn';@Component({selector: 'app-ckeditor-demo',templateUrl: './ckeditor-demo.component.html',styleUrls: ['./ckeditor-demo.component.css']
})
export class CkeditorDemoComponent implements OnInit {@ViewChild('ckeditor', { read: ViewContainerRef }) ckeditor;config = {toolbar: {items: ['bold', 'italic', 'underline', 'strikethrough', 'blockQuote', 'mediaEmbed','alignment:left', 'alignment:right', 'imageUpload', 'insertTable', 'cutImage']}}editor = null;ckeditorContent = '';decEditor = DecoupledEditor;constructor() { }ngOnInit() {}onReady(e) {this.editor = e;e.ui.getEditableElement().parentElement.insertBefore(e.ui.view.toolbar.element,e.ui.getEditableElement());this.getCutButton();}// 找到 cutImage 图标并绑定点击事件// 注意:此处通过获取 class ck-toolbar__items 最后一个子元素找到 cutImage 图标, // 是因为在类中的 config 参数配置中将 'cutImage' 放在数组 items 的最后, // 由于图标由 ckeditor 生成, 所以无法在 ckeditor 插件中赋予唯一的 id 和 classgetCutButton() {$(".ck-toolbar__items").children("button:last-child").on('click', () => {console.log('cut button clicked!');});}onChange(e) {// console.log('onchange', e);}
}
html 文件:
浏览器展示结果:
config.toolbar.items 中未添加 ‘cutImage’ 时:
config.toolbar.items 中添加 ‘cutImage’ 时:
点击图标得到的结果:
由于插件内部实现点击响应事件较为复杂,本插件内部暂时没有实现图标点击的响应事件,而是在 Angular 项目中通过 jquery 找到图标并绑定点击事件。
读者感兴趣或有能力可以尝试实现。