ckeditor5: элемент span со встроенным стилем не объединяется, когда имя стиля совпадает - PullRequest
1 голос
/ 29 марта 2020

Я разработал собственный плагин Border и BorderWidth для Ckeditor5.

Плагины настроены для работы с блочными и текстовыми элементами. Проблема в текстовых элементах (editor.conversion.for( 'downcast' ).attributeToElement). Будет создано два элемента span, но мне нужен только один элемент span со стилем border . Два плагина создают стиль border . Возможно, в этом проблема, почему она не объединена?

CKeditor-Version: 17.0.0

Это код для Border-Plugin для представления:

init() {
        // Allow alignment attribute on all blocks.
        editor.model.schema.extend( '$block', { allowAttributes: BORDER, BORDER_INLINE } );
        editor.model.schema.extend( '$text', { allowAttributes: BORDER, BORDER_INLINE } );
        editor.model.schema.setAttributeProperties( BORDER_INLINE, {
            isFormatting: true,
            copyOnEnter: true
        } );
        editor.model.schema.addAttributeCheck( ( context, attributeName ) => {
            if ( context.endsWith( 'table' ) || context.endsWith( 'tableRow' ) || context.endsWith( 'tableCell' ))
                return false;
            if (context.endsWith('image'))
                return true;
            // console.log('Context:', context);
        } );

        editor.conversion.for( 'downcast' ).attributeToElement( {
            model: {
                key: BORDER_INLINE
            },
            view: ( option, viewWriter ) => {
                if (option == null)
                    return viewWriter.createAttributeElement( 'span', { style: '' });

                const selectedBlocks = getSelectedBlocks( this.editor );
                const selection = this.editor.model.document.selection;
                const _value = { style: '' };
                const styleOption = option.replace( '-tablerow', '' );
                const borderStyle = selection.getAttribute( 'borderStyle' );

                const borderColor = selection.getAttribute( 'borderColor' );

                const borderWidth = selection.getAttribute( BORDER_WIDTH );

                if ( styleOption == 'no-border' )
                    return viewWriter.createAttributeElement( 'span', { style: '' });

                _value.style = 'border' + ( styleOption == 'all' ? '' : '-' + styleOption ) + ': ' +
                    ( borderWidth ? borderWidth : '1px' ) + ' ' +
                    ( borderStyle ? borderStyle : 'solid' ) + ' ' +
                    ( borderColor ? borderColor : 'black' );
                console.log('value: ', _value);

                return viewWriter.createAttributeElement( 'span', {
                    style: _value.style
                } );
            }
        } );

        editor.conversion.for( 'downcast' ).attributeToAttribute( {
            model: BORDER,
            view: function( option ) {
                const selectedBlocks = getSelectedBlocks( this.editor );
                if (option == null) {
                    return { key: 'style', value: {
                        border: {
                            width: { top: 0, right: 0, bottom: 0, left: 0},
                            color: { top: 'transparent', right: 'transparent', bottom: 'transparent', left: 'transparent'},
                            style: { top: 'none', right: 'none', bottom: 'none', left: 'none'}
                        }} };
                }


                const styleOption = option.replace( '-tablerow', '' );
                const borderStyle = selectedBlocks[0].getAttribute( 'borderStyle' );

                const borderColor = selectedBlocks[0].getAttribute( 'borderColor' );

                const borderWidth = selectedBlocks[0].getAttribute( BORDER_WIDTH );

                if ( styleOption == 'no-border' )
                    return { key: 'style', value: { border: 'none' } };

                const defaultBorderWidth = ( borderWidth ? borderWidth : '1px' );
                const defaultBorderColor = ( borderColor ? borderColor : 'black' );
                const defaultBorderStyle = ( borderStyle ? borderStyle : 'solid' );
                let _value;
                if ( styleOption == 'all') {
                    _value = { border: {
                        width: { top: defaultBorderWidth, right: defaultBorderWidth, bottom: defaultBorderWidth, left: defaultBorderWidth},
                        color: { top: defaultBorderColor, right: defaultBorderColor, bottom: defaultBorderColor, left: defaultBorderColor},
                        style: { top: defaultBorderStyle, right: defaultBorderStyle, bottom: defaultBorderStyle, left: defaultBorderStyle}
                        }};
                }
                else {
                    _value = {
                        border: {
                            width: {
                                top: styleOption == 'top' ? defaultBorderWidth : 0,
                                right: styleOption == 'right' ? defaultBorderWidth : 0,
                                bottom:  styleOption == 'bottom' ? defaultBorderWidth : 0,
                                left:  styleOption == 'left' ? defaultBorderWidth : 0
                            },
                            color: {
                                top: styleOption == 'top' ? defaultBorderColor : 'transparent',
                                right: styleOption == 'right' ? defaultBorderColor : 'transparent',
                                bottom:  styleOption == 'bottom' ? defaultBorderColor : 'transparent',
                                left:  styleOption == 'left' ? defaultBorderColor : 'transparent'
                            },
                            style: {
                                top: styleOption == 'top' ? defaultBorderStyle : 'none',
                                right: styleOption == 'right' ? defaultBorderStyle : 'none',
                                bottom:  styleOption == 'bottom' ? defaultBorderStyle : 'none',
                                left:  styleOption == 'left' ? defaultBorderStyle : 'none'
                            }
                        }};
                }
                return { key: 'style', value: _value };
            }.bind(this),
            priority: 100
        } );

        editor.commands.add( 'border', new Bordercommand( editor ) );
}

А теперь код для Border-Width-Plugin для представления (редактирование):

init() {
        const editor = this.editor;
        const schema = editor.model.schema;

        // Filter out unsupported options.
        const enabledOptions = editor.config.get( 'borderWidth.options' ).filter( isSupported );

        // Allow alignment attribute on all blocks.
        editor.model.schema.extend( '$block', { allowAttributes: BORDER_WIDTH, BORDER_WIDTH_INLINE } );
        editor.model.schema.extend( '$text', { allowAttributes: BORDER_WIDTH, BORDER_WIDTH_INLINE } );
        editor.model.schema.setAttributeProperties( BORDER_INLINE, {
            isFormatting: true,
            copyOnEnter: true
        } );
        editor.model.schema.addAttributeCheck( ( context, attributeName ) => {
            if (context.endsWith( 'table' ) || context.endsWith( 'tableRow' ) || context.endsWith( 'tableCell' )) {
                return false;
                if (context.endsWith( 'image' )) {
                    return true;
                }
            }
        } );
        const definition = _buildDefinition( enabledOptions.filter( option => !isDefault( option ) ) );
        editor.conversion.attributeToAttribute( definition );

        // editor.conversion.for( 'downcast' ).attributeToElement( {
        //  model: {
        //      key: BORDER_WIDTH_INLINE
        //  },
        //  view: ( option, viewWriter ) => {
        //      if (option == null)
        //          return viewWriter.createAttributeElement( 'span', { style: '' });
        //
        //      const selection = this.editor.model.document.selection;
        //      const border = selection.getAttribute( BORDER_INLINE );
        //      const borderStyle = selection.getAttribute( 'borderStyle' );
        //      const borderColor = selection.getAttribute( 'borderColor' );
        //
        //      const style = 'border' + ( !border || border == 'all' ? '' : '-' + border ) + ': ' +
        //          option + ' ' +
        //          ( borderStyle ? borderStyle : 'solid' ) + ' ' +
        //          ( borderColor ? borderColor : 'black' );
        //
        //      const element = viewWriter.createAttributeElement( 'span', {
        //          style: style });
        //
        //      return element;
        //  }
        // } );

        editor.conversion.for( 'downcast' ).add( dispatcher => {
            dispatcher.on( 'attribute:' + BORDER_WIDTH_INLINE, ( evt, data, conversionApi ) => {
                // Step 1 - check consumables (check if the attribute wasn't handled already).
                // if ( conversionApi.consumable.consume( data.item, evt.name ) ) {
                //  return;
                // }

                const viewWriter = conversionApi.writer;
                const viewElement = conversionApi.mapper.toViewElement( data.item );
                const viewRange = conversionApi.mapper.toViewRange( data.range );

                const option = data.attributeNewValue;
                if (option == null) {
                    return viewWriter.createAttributeElement( 'span', { style: '' } );

                }
                const selection = this.editor.model.document.selection;
                const border = selection.getAttribute( BORDER_INLINE );
                const borderStyle = selection.getAttribute( 'borderStyle' );

                const borderColor = selection.getAttribute( 'borderColor' );

                const style = 'border' + ( !border || border == 'all' ? '' : '-' + border ) + ': ' +
                    option + ' ' +
                    ( borderStyle ? borderStyle : 'solid' ) + ' ' +
                    ( borderColor ? borderColor : 'black' );

                const element = viewWriter.createAttributeElement( 'span', {
                    style: style
                } );
                viewWriter.wrap( viewRange, element );
                evt.stop();
            } );
        } );

        editor.commands.add( 'borderwidth', new BorderWidthCommand( editor ) );
    }

Функция getSelectedBlocks (editor):

export function getSelectedBlocks( editor ) {
    let blocks;
    const doc = editor.model.document;
    const selectedElement = doc.selection.getSelectedElement();
    if (selectedElement == null)
        blocks = Array.from( doc.selection.getSelectedBlocks() ).filter( block => canBeBordered( editor, block ) ).slice( 0, doc.selection.getSelectedBlocks().length )
    else {
        blocks = [ selectedElement ];
        if (selectedElement.name == "table") {
            var children = selectedElement.getChildren();
            console.log( 'Selected Element Children', children );
            var out = [];
            for (var child of children) {
                console.log( child );
                if (child.getChildren) {
                    const children2 = child.getChildren();
                    for (var child2 of children2) {
                        console.log( child2 );
                        out[out.length] = child2;
                    }
                } else {
                    out[out.length] = child;
                }
            }
            blocks = out;
        }
    }

    return blocks;
}

В результате получается, что два span-элементы созданы. Но я хочу, чтобы это было объединено с одним элементом span. Ckeditor Inspektor

Кто-нибудь может мне помочь, пожалуйста?

...