在模型更改时刷新 CKEditor5 小部件
Refreshing a CKEditor5 widget upon model changes
我有一个带有文本属性节点的自定义架构元素,该元素呈现为 editingDowncast
:
的小部件
conversion.for( 'editingDowncast' )
.add( downcastElementToElement({
model: 'myModelElement',
view: (modelElement, viewWriter) => {
return createMyModelWidget( modelElement, viewWriter, 'Label' );
}
} )
);
function createMyModelWidget( modelElement, writer, label ) {
const content = modelElement.getAttribute('content')
const placeholder = writer.createText( content );
const container = writer.createContainerElement( 'div', { class: 'my-model-element--widget' } );
writer.insert( ViewPosition.createAt( container ), placeholder );
return toWidget( container, writer, label );
}
通过一些外部事件(例如,来自配置小部件的外部模式的结果),使用 model.change
.
更新属性
model.change(writer => {
writer.setAttribute( 'attribute', 'whatever', widget );
writer.setAttribute( 'content', 'new content', widget );
});
既然它的属性发生了变化,我希望小部件能够重新呈现,但事实并非如此。如何手动触发刷新以确保它是最新的?
模型更改时视图小部件的刷新由向下转换处理。我可以看到您想将模型属性转换为 <div>
的文本内容。我假设 "attribute" 属性是一个 <div>
s 元素属性(如 data-attribute
)。在这种情况下,您需要一组转换器:
- 上行
- 一个 element to element upcast converter 将创建
myModelElement
模型元素实例。
- 垂头丧气
- 一个 element to element downcast converter 将为新插入的
myModelElment
创建 div
到模型
- 自定义 attribute converter 将更新
div
属性 content
更改的内容
- 一个双向转换器,将涵盖简单的 attribute to attribute 转换(向上转换和向下转换)。
ps.: 我使用 "downcast" 而不是 "editingDowncast" 来不分别定义 "editingDowncast" 和 "dataDowncast" 的向下转换。
// Required imports:
// import { toWidget } from '@ckeditor/ckeditor5-widget/src/utils';
// import { downcastElementToElement } from '@ckeditor/ckeditor5-engine/src/conversion/downcast-converters';
// import { upcastElementToElement } from '@ckeditor/ckeditor5-engine/src/conversion/upcast-converters';
// import ViewPosition from '@ckeditor/ckeditor5-engine/src/view/position';
// import ViewRange from '@ckeditor/ckeditor5-engine/src/view/range';
const conversion = editor.conversion;
const model = editor.model;
const schema = model.schema;
// Define model element and allow attributes on it.
schema.register( 'myModelElement', {
allowWhere: '$block',
allowAttributes: [ 'content', 'attribute' ],
isObject: true
} );
// Simple attribute to attribute converter two-way converter
// - for upcast it will read "data-attribute" property of div and put it into model's "attribute" attribute
// - for downcast it will update "data-attribute" on changes in "attribute".
conversion.attributeToAttribute( {
model: {
name: 'myModelElement',
key: 'attribute'
},
view: {
key: 'data-attribute'
}
} );
// Define upcast conversion:
conversion.for( 'upcast' ).add( upcastElementToElement( {
model: ( viewElement, modelWriter ) => {
const firstChild = viewElement.getChild( 0 );
const text = firstChild.is( 'text' ) ? firstChild.data : '(empty)';
return modelWriter.createElement( 'myModelElement', { content: text } );
},
view: {
name: 'div',
classes: 'my-model-element--widget'
}
} ) );
// Define downcast conversion:
conversion.for( 'downcast' )
.add( downcastElementToElement( {
model: 'myModelElement',
view: ( modelElement, viewWriter ) => {
return createMyModelWidget( modelElement, viewWriter, 'Label' );
}
} ) )
// Special conversion of attribute "content":
.add( dispatcher => dispatcher.on( 'attribute:content', ( evt, data, conversionApi ) => {
const myModelElement = data.item;
// Mark element as consumed by conversion.
conversionApi.consumable.consume( data.item, evt.name );
// Get mapped view element to update.
const viewElement = conversionApi.mapper.toViewElement( myModelElement );
// Remove current <div> element contents.
conversionApi.writer.remove( ViewRange.createOn( viewElement.getChild( 0 ) ) );
// Set current content
setContent( conversionApi.writer, data.attributeNewValue, viewElement );
} ) );
function createMyModelWidget( modelElement, writer, label ) {
const content = modelElement.getAttribute( 'content' );
const container = writer.createContainerElement( 'div', { class: 'my-model-element--widget' } );
setContent( writer, content, container );
return toWidget( container, writer, label );
}
function setContent( writer, content, container ) {
const placeholder = writer.createText( content || '' );
writer.insert( ViewPosition.createAt( container ), placeholder );
}
我有一个带有文本属性节点的自定义架构元素,该元素呈现为 editingDowncast
:
conversion.for( 'editingDowncast' )
.add( downcastElementToElement({
model: 'myModelElement',
view: (modelElement, viewWriter) => {
return createMyModelWidget( modelElement, viewWriter, 'Label' );
}
} )
);
function createMyModelWidget( modelElement, writer, label ) {
const content = modelElement.getAttribute('content')
const placeholder = writer.createText( content );
const container = writer.createContainerElement( 'div', { class: 'my-model-element--widget' } );
writer.insert( ViewPosition.createAt( container ), placeholder );
return toWidget( container, writer, label );
}
通过一些外部事件(例如,来自配置小部件的外部模式的结果),使用 model.change
.
model.change(writer => {
writer.setAttribute( 'attribute', 'whatever', widget );
writer.setAttribute( 'content', 'new content', widget );
});
既然它的属性发生了变化,我希望小部件能够重新呈现,但事实并非如此。如何手动触发刷新以确保它是最新的?
模型更改时视图小部件的刷新由向下转换处理。我可以看到您想将模型属性转换为 <div>
的文本内容。我假设 "attribute" 属性是一个 <div>
s 元素属性(如 data-attribute
)。在这种情况下,您需要一组转换器:
- 上行
- 一个 element to element upcast converter 将创建
myModelElement
模型元素实例。
- 一个 element to element upcast converter 将创建
- 垂头丧气
- 一个 element to element downcast converter 将为新插入的
myModelElment
创建div
到模型 - 自定义 attribute converter 将更新
div
属性content
更改的内容
- 一个 element to element downcast converter 将为新插入的
- 一个双向转换器,将涵盖简单的 attribute to attribute 转换(向上转换和向下转换)。
ps.: 我使用 "downcast" 而不是 "editingDowncast" 来不分别定义 "editingDowncast" 和 "dataDowncast" 的向下转换。
// Required imports:
// import { toWidget } from '@ckeditor/ckeditor5-widget/src/utils';
// import { downcastElementToElement } from '@ckeditor/ckeditor5-engine/src/conversion/downcast-converters';
// import { upcastElementToElement } from '@ckeditor/ckeditor5-engine/src/conversion/upcast-converters';
// import ViewPosition from '@ckeditor/ckeditor5-engine/src/view/position';
// import ViewRange from '@ckeditor/ckeditor5-engine/src/view/range';
const conversion = editor.conversion;
const model = editor.model;
const schema = model.schema;
// Define model element and allow attributes on it.
schema.register( 'myModelElement', {
allowWhere: '$block',
allowAttributes: [ 'content', 'attribute' ],
isObject: true
} );
// Simple attribute to attribute converter two-way converter
// - for upcast it will read "data-attribute" property of div and put it into model's "attribute" attribute
// - for downcast it will update "data-attribute" on changes in "attribute".
conversion.attributeToAttribute( {
model: {
name: 'myModelElement',
key: 'attribute'
},
view: {
key: 'data-attribute'
}
} );
// Define upcast conversion:
conversion.for( 'upcast' ).add( upcastElementToElement( {
model: ( viewElement, modelWriter ) => {
const firstChild = viewElement.getChild( 0 );
const text = firstChild.is( 'text' ) ? firstChild.data : '(empty)';
return modelWriter.createElement( 'myModelElement', { content: text } );
},
view: {
name: 'div',
classes: 'my-model-element--widget'
}
} ) );
// Define downcast conversion:
conversion.for( 'downcast' )
.add( downcastElementToElement( {
model: 'myModelElement',
view: ( modelElement, viewWriter ) => {
return createMyModelWidget( modelElement, viewWriter, 'Label' );
}
} ) )
// Special conversion of attribute "content":
.add( dispatcher => dispatcher.on( 'attribute:content', ( evt, data, conversionApi ) => {
const myModelElement = data.item;
// Mark element as consumed by conversion.
conversionApi.consumable.consume( data.item, evt.name );
// Get mapped view element to update.
const viewElement = conversionApi.mapper.toViewElement( myModelElement );
// Remove current <div> element contents.
conversionApi.writer.remove( ViewRange.createOn( viewElement.getChild( 0 ) ) );
// Set current content
setContent( conversionApi.writer, data.attributeNewValue, viewElement );
} ) );
function createMyModelWidget( modelElement, writer, label ) {
const content = modelElement.getAttribute( 'content' );
const container = writer.createContainerElement( 'div', { class: 'my-model-element--widget' } );
setContent( writer, content, container );
return toWidget( container, writer, label );
}
function setContent( writer, content, container ) {
const placeholder = writer.createText( content || '' );
writer.insert( ViewPosition.createAt( container ), placeholder );
}