我定义了一种新型的模型元素作为插件;让我们将其称为Foo
. 模型中的Foo
节点应转换为section
视图中的元素。到目前为止,一切都很好。我设法通过定义简单的转换规则来做到这一点。我还设法定义了一个FooCommand
将选定块转换(重命名)为Foo
.
我试图将这些Foo
模型节点上的属性转换为视图元素上的属性(反之亦然)时遇到了困难。假设 Foos 有一个名为的属性fooClass
,它应该映射到视图元素的class
属性。
<Foo fooClass="green-foo"> should map to/from <section class="green-foo">
我可以在 中成功接收参数FooCommand
,但我似乎无法在命令正在处理的块上设置它们:
execute(options = {}) {
const document = this.editor.document;
const fooClass = options.fooClass;
document.enqueueChanges(() => {
const batch = options.batch || document.batch();
const blocks = (options.selection || document.selection).getSelectedBlocks();
for (const block of blocks) {
if (!block.is('foo')) {
batch.rename(block, 'foo');
batch.setAttribute(block, 'fooClass', fooClass);
}
}
});
}
下面是插件中init
函数的代码Foo
,包括模型→视图和视图→模型转换:
init() {
const editor = this.editor;
const doc = editor.document;
const data = editor.data;
const editing = editor.editing;
editor.commands.add('foo', new FooCommand(editor));
doc.schema.registerItem('foo', '$block');
buildModelConverter().for(data.modelToView, editing.modelToView)
.fromElement('foo')
.toElement(modelElement => {
const fooClass = modelElement.item.getAttribute('fooClass'));
return new ContainerElement('section', {'class': fooClass});
});
buildViewConverter().for(data.viewToModel)
.fromElement('section')
.toElement(viewElement => {
let classes = Array.from(viewElement.getClassNames());
let modelElement = new ModelElement('foo', {'fooClass': classes[0]});
return modelElement;
});
}
当我尝试通过
editor.execute('foo', { fooClass: 'green-foo' })
我可以看到该green-foo
值可用于FooCommand
,但modelElement
在模型→视图转换中,另一方面,没有fooClass
属性。
我确定我在这里遗漏了重点并滥用了 API。如果有人能对这个问题有所了解,我将非常感激。我可以根据需要提供更多详细信息。
初步建议后的跟进
感谢@Reinmar 和@jodator 关于配置文档模式以允许自定义属性的建议。我真的以为这会解决它,但没有。无论如何这可能是一个必要的步骤,但是在模型→视图转换期间我仍然无法从模型元素中获取属性值。
首先,让我添加一条我遗漏的重要信息:我正在使用的 CKEditor5 的版本是1.0.0-alpha2。我知道一些 API 必然会发生变化,但我仍然希望使用当前版本。
模型→视图转换
如果我理解正确,可以将 astring
或 a传递function
给toElement
调用。关于使用后者的一个问题:传递给函数的参数到底是什么?我假设它将是要转换的模型元素(节点?)。是这样吗?如果是这样,为什么在请求时通过batch.setAttribute
(内部)在该节点上设置的属性不可用?document.enqueueChanges
应该是吗?
排序问题?
额外的测试似乎表明发生了某种执行顺序问题。我观察到,即使当我第一次尝试从modelElement
参数中读取该属性时该属性不可用,但如果我稍后再次读取它就会如此。让我试着说明下面的情况。首先,我将修改转换代码,使其使用一些虚拟值,以防读取时属性值不可用:
buildModelConverter().for(data.modelToView, editing.modelToView)
.fromElement('foo')
.toElement(modelElement => {
let fooClass = modelElement.item.getAttribute('fooClass') || 'naught';
let viewElement = new ContainerElement('section');
viewElement.setAttribute('class', fooClass);
return viewElement;
});
现在我重新加载页面并在控制台上执行以下指令:
c = Array.from(editor.document.getRoot().getChildren());
c[1].is('paragraph'); // true
// Changing the node from 'paragraph' to 'foo' and adding an attribute
// 'fooClass' with value 'green-foo' to it.
editor.document.enqueueChanges(() => {
const batch = editor.document.batch();
batch.rename(c[1], 'foo');
batch.setAttribute(c[1], 'fooClass', 'green-foo');
return batch;
});
c[1].is('paragraph'); // false
c[1].is('foo'); // true
c[1].hasAttribute('fooClass'); // true
c[1].getAttribute('fooClass'); // 'green-foo'
尽管看起来正在生成预期的输出,但看一眼生成的视图元素就会发现问题:
<section class="naught"/>
最后,即使我尝试重置fooClass
模型元素的属性,更改也不会反映在视图元素上。这是为什么?不应该通过更改enqueueChanges
导致视图更新吗?
对不起,很长的帖子,但我试图传达尽可能多的细节。希望有人能发现我对 CKEditor 5 的 API 实际工作方式的错误或误解。
视图不更新?
我转向Document
's events并尝试了该changesDone
事件。它成功地解决了“时间”问题,因为它只有在处理完所有更改后才会始终触发。尽管如此,视图没有响应模型变化而更新的问题仍然存在。为了清楚起见,模型确实发生了变化,但视图并未反映这一点。这是电话:
editor.document.enqueueChanges(() => editor.document.batch().setAttribute(c[1], 'fooClass', 'red-foo'));