Я разработал собственный плагин 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.
Кто-нибудь может мне помочь, пожалуйста?