ckeditor5 列表项起始编号
ckeditor5 list item start number
正在尝试构建插件以在 ckEditor5 中为 ol
设置启动属性。
据我所知,model 包含 listItems
的集合。
需要在 ol
上设置 start 属性,但是,列表项的父项,而不是列表项本身。有没有办法从 ol
访问model?
我可以用
得到当前的li
first(editor.model.document.selection.getSelectedBlocks())
有没有办法在 ol
元素上设置属性?
编辑——获取 LI 属性的代码:
editor.model.schema.extend('listItem', { allowAttributes: 'listStart' });
editor.conversion.attributeToAttribute({
model: 'listStart',
view: 'start'
});
在 model 中启用:<listItem type="numbered" listStart="4">
,这将在视图中转换为:
<ol>
<li start="4">words</li>
</ol>
我想要实现的是
<ol start="4">
<li>words</li>
</ol>
当我检查源代码时,它看起来好像 ol
(或 ul
)是在此处自动创建的:
function generateLiInUl( modelItem, conversionApi ) {
const mapper = conversionApi.mapper;
const viewWriter = conversionApi.writer;
const listType = modelItem.getAttribute( 'listType' ) == 'numbered' ? 'ol' : 'ul';
const viewItem = createViewListItemElement( viewWriter );
// ** OL or UL created here -->
const viewList = viewWriter.createContainerElement( listType, null );
viewWriter.insert( ViewPosition.createAt( viewList ), viewItem );
mapper.bindElements( modelItem, viewItem );
return viewItem;
}
有没有我可以观察的事件?或者在转换定义中是否有一种方法可以将属性定位到父级?
更新 2
如果我们要 mod 来源,我们可以通过将此添加到 generateLiInUl
函数来拦截向下转换(感谢 MTilsted):
const listStart = modelItem.getAttribute('listStart');
if (listStart) {
viewWriter.setAttribute('start', listStart, viewList);
}
为了便于向上转换,将其添加到 viewModelConverter
函数
const listStart = data.viewItem.parent.getAttribute('start');
if (listStart) {
writer.setAttribute( 'listStart', listStart, listItem );
}
这有点难看,因为我们正在 mod 化源代码,这是维护的皮塔饼,并且在向上转换时,我们将 listStart
属性添加到每个 listItem
元素model.. 但这是一个开始。
我简要地查看了添加调度程序.. 例如:
data.upcastDispatcher.on( 'element:li', myCustomUpcastFunction );
但无法弄清楚如何获取对添加到上述 viewModelConverter
函数中的 model 的 listItem
元素的引用。
更新:
好的,生成列表的工作方式很奇怪。这可能与列表合并和更改类型的方式有关。我必须承认我真的不明白那部分是如何工作的。
我找不到根据需要向下转换属性的方法,所以除非来自 Cksource 的人出现,否则我能找到的唯一解决方案是修补列表代码。而且我不确定它与 upcast 的配合情况如何。 (仅进行了轻微测试)。
但是在文件中node_modules/@ckeditor/ckeditor5-list/src/converters.js
只需尝试添加这一行:
viewWriter.setAttribute('start',model.getAttribute('listStart'),viewList);
到方法
function generateLiInUl( modelItem, conversionApi ) {
在我的ckeditor版本中(最新的)它应该被添加到第810行。
原始答案(有用但不适用于列表)。
哦,是的。你对模型是正确的。但 ckeditor 5 中的整个设计要点是您不必修改现有插件即可添加属性。您可以使用架构注册额外的属性,然后在您自己的插件中添加匹配的 DowncastElementToElement。
这是我用来向图像添加额外属性的代码 class。更改为在 listItems 上工作应该是微不足道的。 (Cut/Pasted 来自我代码中的不同位置,所以我可能忘记了一些东西,但请尝试一下。如果你不能让它工作,我将在星期一制作一个完整的示例 :)
model.schema.extend('image', {
allowAttributes: ['displaywidth','ignorecolumns','fullpagepicture']
} );
editor.conversion.for('upcast')
.add(upcastAttributeToAttribute( { model: 'isvisible', view: 'isvisible' }))
.add(upcastAttributeToAttribute( { model: 'displaywidth', view: 'displaywidth' }))
.add(upcastAttributeToAttribute( { model: 'fullpagepicture', view: 'fullpagepicture' }))
editor.conversion.for('downcast')
.add(downcastAttributeToAttribute( { model: 'isvisible', view: 'isvisible' }))
.add(downcastAttributeToAttribute( { model: 'displaywidth', view: 'displaywidth' }))
.add(downcastAttributeToAttribute( { model: 'fullpagepicture', view: 'fullpagepicture' }))
对我有用的答案非常简单,我觉得没有早点看到它有点傻:使用 LI value
属性而不是 OL start
属性。
<ol>
<li value="4">words</li>
</ol>
而不是:
<ol start="4">
<li>words</li>
</ol>
这将属性保留在 listItem 上并避免了所有的复杂化(我在最初的尝试中完全错过了 LI 的值属性的存在):
editor.model.schema.extend('listItem', { allowAttributes: 'value' });
editor.conversion.attributeToAttribute({
model: 'value',
view: 'value'
});
应用值的命令:
execute(arg) {
let val = arg.value;
const model = this.editor.model;
const block = first(model.document.selection.getSelectedBlocks());
model.change(writer => {
if (+val) {
writer.setAttribute('value', val, block);
} else {
writer.removeAttribute('value', block);
}
});
}
并防止在输入时将该值复制到下一个 LI:
editor.commands.get('enter').on('afterExecute', () => {
const block = first(editor.model.document.selection.getSelectedBlocks());
if ( block.name == 'listItem' && block.hasAttribute('value')) {
editor.model.change( writer => {
writer.removeAttribute('value', block);
});
}
});
我想@Steve 已经解决了他的问题,但他的问题帮助我理解了我自己的问题。因此,我想帮助像我一样需要帮助的人。
首先,我注意到按照之前的建议更改内置插件是不正常的。 CKEditor 的创建者鼓励我们使用我们的自定义插件来覆盖内置逻辑。所以,使用 CKEditor API 来改变编辑器的行为。
我的解决方案是
// @ckeditor/ckeditor5-core@25.0.0
import Plugin from '@ckeditor/ckeditor5-core/src/plugin'
export class ListStartAttribute extends Plugin {
init() {
console.log('ListStartAttribute is init')
const editor = this.editor
// 1.extend schema
editor.model.schema.extend('listItem', { allowAttributes: 'start' })
// 2.set conversion up/down
editor.conversion.for('downcast').add(dispatcher => {
dispatcher.on('attribute', (evt, data, conversionApi) => {
if (data.item.name != 'listItem') {
return
}
const viewWriter = conversionApi.writer
const viewElement = conversionApi.mapper.toViewElement(
data.item
)
const containerElement = viewElement.parent
if (
data.attributeNewValue &&
!containerElement.getAttribute('start')
) {
viewWriter.setAttribute(
data.attributeKey,
data.attributeNewValue,
containerElement
)
}
})
})
editor.conversion.for('upcast').attributeToAttribute({
model: {
name: 'listItem',
key: 'start',
},
view: {
name: 'ol',
key: 'start',
},
converterPriority: 'low',
})
}
}
正在尝试构建插件以在 ckEditor5 中为 ol
设置启动属性。
据我所知,model 包含 listItems
的集合。
需要在 ol
上设置 start 属性,但是,列表项的父项,而不是列表项本身。有没有办法从 ol
访问model?
我可以用
得到当前的li
first(editor.model.document.selection.getSelectedBlocks())
有没有办法在 ol
元素上设置属性?
编辑——获取 LI 属性的代码:
editor.model.schema.extend('listItem', { allowAttributes: 'listStart' });
editor.conversion.attributeToAttribute({
model: 'listStart',
view: 'start'
});
在 model 中启用:<listItem type="numbered" listStart="4">
,这将在视图中转换为:
<ol>
<li start="4">words</li>
</ol>
我想要实现的是
<ol start="4">
<li>words</li>
</ol>
当我检查源代码时,它看起来好像 ol
(或 ul
)是在此处自动创建的:
function generateLiInUl( modelItem, conversionApi ) {
const mapper = conversionApi.mapper;
const viewWriter = conversionApi.writer;
const listType = modelItem.getAttribute( 'listType' ) == 'numbered' ? 'ol' : 'ul';
const viewItem = createViewListItemElement( viewWriter );
// ** OL or UL created here -->
const viewList = viewWriter.createContainerElement( listType, null );
viewWriter.insert( ViewPosition.createAt( viewList ), viewItem );
mapper.bindElements( modelItem, viewItem );
return viewItem;
}
有没有我可以观察的事件?或者在转换定义中是否有一种方法可以将属性定位到父级?
更新 2
如果我们要 mod 来源,我们可以通过将此添加到 generateLiInUl
函数来拦截向下转换(感谢 MTilsted):
const listStart = modelItem.getAttribute('listStart');
if (listStart) {
viewWriter.setAttribute('start', listStart, viewList);
}
为了便于向上转换,将其添加到 viewModelConverter
函数
const listStart = data.viewItem.parent.getAttribute('start');
if (listStart) {
writer.setAttribute( 'listStart', listStart, listItem );
}
这有点难看,因为我们正在 mod 化源代码,这是维护的皮塔饼,并且在向上转换时,我们将 listStart
属性添加到每个 listItem
元素model.. 但这是一个开始。
我简要地查看了添加调度程序.. 例如:
data.upcastDispatcher.on( 'element:li', myCustomUpcastFunction );
但无法弄清楚如何获取对添加到上述 viewModelConverter
函数中的 model 的 listItem
元素的引用。
更新: 好的,生成列表的工作方式很奇怪。这可能与列表合并和更改类型的方式有关。我必须承认我真的不明白那部分是如何工作的。
我找不到根据需要向下转换属性的方法,所以除非来自 Cksource 的人出现,否则我能找到的唯一解决方案是修补列表代码。而且我不确定它与 upcast 的配合情况如何。 (仅进行了轻微测试)。
但是在文件中node_modules/@ckeditor/ckeditor5-list/src/converters.js
只需尝试添加这一行:
viewWriter.setAttribute('start',model.getAttribute('listStart'),viewList);
到方法
function generateLiInUl( modelItem, conversionApi ) {
在我的ckeditor版本中(最新的)它应该被添加到第810行。
原始答案(有用但不适用于列表)。
哦,是的。你对模型是正确的。但 ckeditor 5 中的整个设计要点是您不必修改现有插件即可添加属性。您可以使用架构注册额外的属性,然后在您自己的插件中添加匹配的 DowncastElementToElement。
这是我用来向图像添加额外属性的代码 class。更改为在 listItems 上工作应该是微不足道的。 (Cut/Pasted 来自我代码中的不同位置,所以我可能忘记了一些东西,但请尝试一下。如果你不能让它工作,我将在星期一制作一个完整的示例 :)
model.schema.extend('image', {
allowAttributes: ['displaywidth','ignorecolumns','fullpagepicture']
} );
editor.conversion.for('upcast')
.add(upcastAttributeToAttribute( { model: 'isvisible', view: 'isvisible' }))
.add(upcastAttributeToAttribute( { model: 'displaywidth', view: 'displaywidth' }))
.add(upcastAttributeToAttribute( { model: 'fullpagepicture', view: 'fullpagepicture' }))
editor.conversion.for('downcast')
.add(downcastAttributeToAttribute( { model: 'isvisible', view: 'isvisible' }))
.add(downcastAttributeToAttribute( { model: 'displaywidth', view: 'displaywidth' }))
.add(downcastAttributeToAttribute( { model: 'fullpagepicture', view: 'fullpagepicture' }))
对我有用的答案非常简单,我觉得没有早点看到它有点傻:使用 LI value
属性而不是 OL start
属性。
<ol>
<li value="4">words</li>
</ol>
而不是:
<ol start="4">
<li>words</li>
</ol>
这将属性保留在 listItem 上并避免了所有的复杂化(我在最初的尝试中完全错过了 LI 的值属性的存在):
editor.model.schema.extend('listItem', { allowAttributes: 'value' });
editor.conversion.attributeToAttribute({
model: 'value',
view: 'value'
});
应用值的命令:
execute(arg) {
let val = arg.value;
const model = this.editor.model;
const block = first(model.document.selection.getSelectedBlocks());
model.change(writer => {
if (+val) {
writer.setAttribute('value', val, block);
} else {
writer.removeAttribute('value', block);
}
});
}
并防止在输入时将该值复制到下一个 LI:
editor.commands.get('enter').on('afterExecute', () => {
const block = first(editor.model.document.selection.getSelectedBlocks());
if ( block.name == 'listItem' && block.hasAttribute('value')) {
editor.model.change( writer => {
writer.removeAttribute('value', block);
});
}
});
我想@Steve 已经解决了他的问题,但他的问题帮助我理解了我自己的问题。因此,我想帮助像我一样需要帮助的人。
首先,我注意到按照之前的建议更改内置插件是不正常的。 CKEditor 的创建者鼓励我们使用我们的自定义插件来覆盖内置逻辑。所以,使用 CKEditor API 来改变编辑器的行为。
我的解决方案是
// @ckeditor/ckeditor5-core@25.0.0
import Plugin from '@ckeditor/ckeditor5-core/src/plugin'
export class ListStartAttribute extends Plugin {
init() {
console.log('ListStartAttribute is init')
const editor = this.editor
// 1.extend schema
editor.model.schema.extend('listItem', { allowAttributes: 'start' })
// 2.set conversion up/down
editor.conversion.for('downcast').add(dispatcher => {
dispatcher.on('attribute', (evt, data, conversionApi) => {
if (data.item.name != 'listItem') {
return
}
const viewWriter = conversionApi.writer
const viewElement = conversionApi.mapper.toViewElement(
data.item
)
const containerElement = viewElement.parent
if (
data.attributeNewValue &&
!containerElement.getAttribute('start')
) {
viewWriter.setAttribute(
data.attributeKey,
data.attributeNewValue,
containerElement
)
}
})
})
editor.conversion.for('upcast').attributeToAttribute({
model: {
name: 'listItem',
key: 'start',
},
view: {
name: 'ol',
key: 'start',
},
converterPriority: 'low',
})
}
}