使用协作功能中的上下文
The Context
class 将多个编辑器组织成一个环境。这样,您可以初始化某些功能,这些功能不是针对单个编辑器,而是针对其可供多个编辑器访问的上下文。
# 上下文简介
# 协作功能和多个编辑器
大多数应用程序每个网页或表单只使用一个编辑器实例。在这些集成中,编辑器是最顶层的实体,它初始化功能并协调其工作。协作功能(如边栏或状态列表)与这个单个编辑器实例相关联,并且只处理发生在这个编辑器实例中的更改。
然而,对于需要在一个网页上显示多个编辑器的应用程序来说,这并不能创造良好的用户体验。在这种情况下,每个编辑器实例都有自己的边栏和状态列表。此外,还需要处理多个独立的连接来进行数据交换。
The Context
class 的引入是为了解决这些问题。它将多个编辑器组织成一个环境。一些功能,而不是为单个编辑器初始化,可以为整个上下文初始化。然后,每个编辑器都可以使用该功能的同一个实例,这意味着可以有一个通用的状态列表或边栏与多个编辑器链接。
请注意,只有选定的插件准备作为上下文插件使用。请参阅协作功能的 API 文档,了解哪些插件可以作为上下文插件使用。
此外,在使用 Context
和多个编辑器实例的集成中,每个编辑器实例只会在评论存档面板中显示“它自己”的评论线程。
# 协作功能和无编辑器
添加到上下文的上下文插件在上下文创建后即可使用。这允许在没有创建编辑器的情况下使用上下文插件!
因此,您可以提供诸如 非编辑器表单字段上的评论 之类的功能,这些功能不再仅仅是编辑器功能,而是与您的应用程序深度集成。
# 频道 ID
频道 ID 用于标识给定编辑器或上下文应连接到的协作功能的数据存储。如果您使用多个编辑器,则每个编辑器必须使用不同的频道 ID 来连接到特定文档。此外,上下文本身也需要指定自己的唯一频道 ID。
要设置频道 ID,请使用 config.collaboration.channelId
配置属性。请参见下面的代码片段。
频道 ID 通常在 评论 API 中用作参数或数据属性。如果您正在准备使用评论 API 的自定义集成,您可以使用频道 ID 来识别评论是添加到编辑器实例还是上下文。
如果您遇到由于 _CKEditorCloudServicesServerError: cloud-services-server-error: Validation failed.
错误导致编辑器初始化失败的问题,这可能与缺少 config.collaboration.channelId
配置有关。
# 开始之前
作为本指南的补充,我们提供了一个 现成的示例.
您可以将其用作示例或作为您自己的集成的起点。
# 使用上下文准备自定义编辑器设置
上下文可以与独立协作功能和实时协作功能一起使用。以下是一个使用实时协作的示例。
我们建议您阅读 实时协作功能集成 指南中有关准备自定义编辑器设置的内容。以下示例将基于本指南。
要使用 Context
,请将其添加到您的编辑器设置中
import {
/* ... */
CloudServices,
Context
} from 'ckeditor5';
import {
/* ... */
// Context plugins:
CommentsRepository,
NarrowSidebar,
WideSidebar,
CloudServicesCommentsAdapter,
PresenceList
} from 'ckeditor5-premium-features';
// The context's configuration.
const contextConfig = {
// Plugins specific for the context:
plugins: [
CloudServices,
CloudServicesCommentsAdapter,
CommentsRepository,
NarrowSidebar,
PresenceList,
WideSidebar
],
// Sidebar and presence list's shared locations:
sidebar: {
container: document.querySelector( '#editor-annotations' )
},
presenceList: {
container: document.querySelector( '#editor-presence' )
},
// Default configuration of the comments feature needs to be specified on the
// context as it is a context plugin:
comments: {
editorConfig: {
extraPlugins: [ Autoformat, Bold, Italic, List, Mention ],
mention: {
feeds: [
{
marker: '@',
feed: [
/* See: https://ckeditor.npmjs.net.cn/docs/ckeditor5/latest/features/mentions.html#comments-with-mentions */
]
}
]
}
}
},
// Real-time features configuration:
// NOTE: PROVIDE CORRECT VALUES HERE.
cloudServices: {
tokenUrl: 'https://example.com/cs-token-endpoint',
uploadUrl: 'https://your-organization-id.cke-cs.com/easyimage/upload/',
webSocketUrl: 'your-organization-id.cke-cs.com/ws/'
},
collaboration: {
channelId: 'channel-id'
}
};
// Template of a specific editor configuration.
const editorConfig = {
/*
Assuming that you based your setup on the configuration produced by the Builder (https://ckeditor.npmjs.net.cn/ckeditor-5/builder),
now you can comment out (remove) a couple of properties that were specified on the context level
and do not need to be customized per editor instance:
*/
// comments: ...
// sidebar: ...
// presenceList: ...
// cloudServices: ...
/* The channelId property will be specified later so you can remove it too: */
// collaboration: { channelId: ... }
};
# 在集成中使用上下文
编辑器设置准备就绪后,您需要配置和初始化上下文和编辑器。
如果您使用 Builder 生成的 HTML,您只需要将 .editor-container__editor
容器的内容更新为以下内容
<div class="editor-container__editor">
<div id="editor1" class="editor"></div>
<div id="editor2" class="editor"></div>
<div id="editor3" class="editor"></div>
</div>
现在,我们可以在这三个元素上设置三个编辑器实例,共享一个上下文
// An example of initialization of the context and multiple editors:
Context.create( contextConfig ).then( context => {
// After the context is ready, initialize an editor on all elements in the DOM with the `.editor` class:
for ( const editorElement of document.querySelectorAll( '.editor' ) ) {
// Create current editor's config based on the earlier defined template.
const currentEditorConfig = Object.assign( editorConfig, {
// Pass the context to the editor.
context,
// Each editor should connect to its document.
// Create a unique channel ID for an editor (document).
collaboration: {
channelId: 'channel-id-' + editorElement.id
}
} );
DecoupledEditor.create( editorElement, currentEditorConfig ).then( editor => {
// Insert the toolbar of this editor right above its editing area.
document.querySelector( '.editor-container__editor' )
.insertBefore( editor.ui.view.toolbar.element, editor.ui.view.editable.element );
// You can do something with the editor instance after it was initialized.
// ...
} );
}
} );
演示将依次渲染三个编辑器实例。由于它们共享一个上下文,您将能够观察到
- 成员列表在它们之间共享(并且它们使用一个协作会话)。
- 带有评论的侧边栏也在它们之间共享。
由 Builder 提出的 HTML 可能不适合这种修改后的设置。使用 Context 配置完整设置需要进一步的自定义。
# 上下文和看门狗
类似于编辑器实例,上下文可以与看门狗集成,以处理编辑器或上下文功能中可能发生的错误。请参考 看门狗文档 了解如何使用上下文看门狗。
# 最小实现
以下是展示上下文和看门狗与实时协作功能一起使用的代码片段。
main.js
文件
import {
ClassicEditor,
// Import the context, its watchdog and plugins:
ContextWatchdog,
Context,
CloudServices,
// Editor plugins:
Bold, Italic, Essentials, Heading, Paragraph
} from 'ckeditor5';
// Real-time collaboration plugins are editor plugins:
import {
RealTimeCollaborativeComments,
RealTimeCollaborativeEditing,
RealTimeCollaborativeTrackChanges,
Comments,
TrackChanges,
// Context plugins:
CommentsRepository,
NarrowSidebar,
WideSidebar,
CloudServicesCommentsAdapter,
PresenceList
} from 'ckeditor5-premium-features';
import 'ckeditor5/ckeditor5.css';
import 'ckeditor5-premium-features/ckeditor5-premium-features.css';
const channelId = 'channel-id';
// The context's configuration.
const contextConfig = {
// Plugins to include in the context.
plugins: [
CloudServices,
CloudServicesCommentsAdapter,
CommentsRepository,
NarrowSidebar,
WideSidebar,
PresenceList
],
// Default configuration for the context plugins:
sidebar: {
container: document.querySelector( '#sidebar' )
},
presenceList: {
container: document.querySelector( '#presence-list-container' )
},
// The configuration shared between the editors:
toolbar: {
items: [
'bold', 'italic', '|', 'undo', 'redo', '|',
'comment', 'commentsArchive', 'trackChanges'
]
},
comments: {
editorConfig: {
plugins: [ Essentials, Paragraph, Bold, Italic ]
}
},
// The configuration for real-time collaboration features, shared between the editors:
cloudServices: {
// PROVIDE CORRECT VALUES HERE:
tokenUrl: 'https://example.com/cs-token-endpoint',
uploadUrl: 'https://your-organization-id.cke-cs.com/easyimage/upload/',
webSocketUrl: 'your-organization-id.cke-cs.com/ws/'
},
// Collaboration configuration for the context:
collaboration: {
channelId
}
};
// Template of a specific editor configuration.
const editorConfig = {
// Plugins to include in the editor:
plugins: [
Essentials, Paragraph, Bold, Italic, Heading,
// Real-time collaboration plugins are editor plugins:
RealTimeCollaborativeEditing,
RealTimeCollaborativeComments,
RealTimeCollaborativeTrackChanges,
Comments,
TrackChanges
],
};
const watchdog = new ContextWatchdog( Context );
await watchdog.create( contextConfig );
for ( const editorElement of document.querySelectorAll( '.editor' ) ) {
// Create current editor's configuration based on the template defined earlier.
const currentEditorConfig = Object.assign( editorConfig, {
collaboration: {
// Create a unique channel ID for an editor (document).
channelId: channelId + '-' + editorElement.id
}
// You do not need to pass the context to the configuration
// if you are using the context watchdog.
} );
await watchdog.add( {
id: editorElement.id,
type: 'editor',
sourceElementOrData: editorElement,
config: currentEditorConfig,
creator: ( element, config ) => ClassicEditor.create( element, config )
} );
}
HTML 文件
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>CKEditor 5 Collaboration – Hello World!</title>
<style type="text/css">
#presence-list-container {
width: 800px;
margin: 0 auto;
}
#container {
display: flex;
position: relative;
width: 800px;
margin: 0 auto;
}
.form {
width: 500px;
}
#container .ck.ck-editor {
width: 100%;
}
#sidebar {
width: 300px;
padding: 0 10px;
}
</style>
</head>
<body>
<div id="presence-list-container"></div>
<div id="container">
<div class="form">
<div class="editor" id="editor-1">
<h2>Editor 1</h2>
<p>Foo bar baz</p>
</div>
<div class="editor" id="editor-2">
<h2>Editor 2</h2>
<p>Foo bar baz</p>
</div>
</div>
<div id="sidebar"></div>
</div>
<script type="module" src="./main.js"></script>
</body>
</html>
# 演示
与您的同事分享此页面的完整 URL,以便实时协作!
双语人格障碍
这可能是您第一次听说这种虚构的疾病,但实际上它并不遥远。正如最近的研究表明,您使用的语言对您的影响比您意识到的更大。研究表明,一个人的语言会影响他们的认知、行为、情绪,进而影响他们的性格。
研究
这并不令人惊讶 因为我们已经知道 大脑的不同区域会根据活动变得更加活跃。语言的结构、信息,尤其是 **文化** 差异很大,一个人使用的语言是日常生活中的一个重要元素。
我们每天都在努力使我们的文档完整。您是否发现过时的信息?是否缺少什么?请通过我们的 问题跟踪器 报告。
随着 42.0.0 版的发布,我们重写了大部分文档,以反映新的导入路径和功能。我们感谢您的反馈,帮助我们确保其准确性和完整性。