ckeditor5列表项的起始编号

时间:2018-11-29 00:28:44

标签: ckeditor5

尝试构建插件以在ckEditor5中设置ol的开始属性。

据我所知,该模型包含listItems的集合。

需要在ol上设置start属性,但是,列表项的父级而不是列表项本身..有一种方法可以从模型中访问ol

我可以通过获取当前的li

first(editor.model.document.selection.getSelectedBlocks())

是否可以在ol元素上设置属性?

编辑-获取LI属性的代码:

editor.model.schema.extend('listItem', { allowAttributes: 'listStart' });

editor.conversion.attributeToAttribute({ 
  model: 'listStart', 
  view: 'start'
});

在模型中启用:<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;
}

link to source

我可以观察到一个事件吗?还是转换定义中有一种方法可以将属性定位到父级?

更新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 );
    }

这有点丑陋,因为我们正在修改源代码(用于维护的皮塔饼),并且在泛滥中,我们向模型中的每个listStart元素添加了listItem属性。.但这是一个开始

我简要地考虑了添加调度程序。例如:

data.upcastDispatcher.on( 'element:li', myCustomUpcastFunction );

但无法弄清楚如何获得对上述listItem函数中添加到模型的viewModelConverter元素的引用。

3 个答案:

答案 0 :(得分:1)

已更新: 好的,生成列表的工作方式很奇怪。这可能与列表的合并方式和更改类型有关。我必须承认我不太了解那部分的工作原理。

我无法找到一种根据需要向下转换属性的方法,因此,除非Cksource的某个人来临,否则我唯一能找到的解决方案就是修补列表代码。而且我不确定这与上播效果如何。 (仅经过轻轻测试)。

但是在文件node_modules/@ckeditor/ckeditor5-list/src/converters.js

只需尝试添加以下行:

viewWriter.setAttribute('start',model.getAttribute('listStart'),viewList);

方法

function generateLiInUl( modelItem, conversionApi ) {

在我的ckeditor版本(最新版本)中,应将其添加到第810行。

原始答案(完整但不用于列表)。

哦,是的。您对模型是正确的。但是ckeditor 5中的整个设计要点是,您不必修改现有插件即可添加属性。您可以在架构中注册额外的属性,然后在自己的插件中添加匹配的DowncastElementToElement。

这是我用来向图像类添加额外属性的代码。改为在listItems上工作应该是微不足道的。 (从代码的不同位置剪切/粘贴,所以我可能忘记了一些东西,但是请尝试一下。如果您无法使它正常工作,我将在星期一制作一个可以正常工作的示例:)

        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' }))

答案 1 :(得分:1)

对我有用的答案很简单,我觉得很早就看不到它了:使用LI value属性而不是OL start属性。

<ol>
  <li value="4">words</li>
</ol>

代替:

<ol start="4">
  <li>words</li>
</ol>

这会将属性保留在listItem上,并避免了所有麻烦(我在最初的尝试中完全错过了LI的value属性的存在):

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);
    });
  }
});

答案 2 :(得分:0)

我猜@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',
        })
    }
}