-
-
Notifications
You must be signed in to change notification settings - Fork 3.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Style attribute conversion does not work with attributeToAttribute() #4517
Comments
Workaround for now: editor.model.schema.extend( 'tableCell', {
allowAttributes: 'style'
} );
editor.conversion.for( 'upcast' ).attributeToAttribute( {
model: {
name: 'tableCell',
key: 'style'
},
view: 'style'
} );
editor.conversion.for( 'downcast' ).add( dispatcher => {
dispatcher.on( `attribute:style:tableCell`, ( evt, data, conversionApi ) => {
const viewElement = conversionApi.mapper.toViewElement( data.item );
conversionApi.writer.setAttribute( 'style', data.attributeNewValue, viewElement );
} );
} ); |
@Reinmar so the fix is pretty straight forward but it would need to change the way how we treat the
to at least allow passing string there as the
But OTOH just overwriting But I'm not 100% sure what's the expectation here. From one side some other converters might create styles on element but obviously such cath-all As such I'm divided on whether we should allow string for style or object only notation. |
Is there any fix for this? It outputs like this for me? style="background-color:red;0:b;1:a;2:c;3:k;4:g;5:r;6:o;7:u;8:n;9:d;10:-;11:c;12:o;13:l;14:o;15:r;16::;17:r;18:e;19:d;20:;;" Why does it add this part? |
@josueexhume This is because the Right not the solution for this is to write a bit more specialized converters for |
So there's no way to allow converting the whole style attribute?, I really need that feature for my use case. Right now i have legacy html content, and i need to preserve the style attribute as i'm slowing fading it out in preference of applying styling based on a given class. I thought maybe setting it up like this would of fixed my issue. conversion.for('upcast').attributeToAttribute({
model: {
name: 'div',
key: 'style'
},
view: 'style'
});
conversion.for('downcast').add(dispatcher => {
dispatcher.on('attribute:style:div', (evt, data, conversionApi) => {
const viewElement = conversionApi.mapper.toViewElement(data.item);
conversionApi.writer.setAttribute('style', data.attributeNewValue, viewElement);
});
}); |
You can also generalise this to all elements: dispatcher.on('attribute:style', ... ); but adding |
Did you allow editor.model.schema.extend( 'paragraph', { allowAttributes: '__style' } );
editor.conversion.for('upcast').attributeToAttribute({
model: {
key: '__style',
name: 'paragraph'
},
view: 'style'
});
editor.conversion.for('downcast').add(dispatcher => {
dispatcher.on('attribute:__style:paragraph', (evt, data, conversionApi) => {
const viewElement = conversionApi.mapper.toViewElement(data.item);
conversionApi.writer.setAttribute('style', data.attributeNewValue, viewElement);
});
}); |
@jodator thanks for the tip, i removed the @scofalik Thanks for the quick reply. I have the attribute allowed in another file, I tried your solution but it still appends a char array of the css style |
This is weird because it certainly works for me: Are you sure you don't have an old code (converter) specified somewhere? Or some custom code which could affect this too? It kind of looks like this conversion was handled twice: once correctly and once incorrectly. Try changing downcast converter to this: editor.conversion.for('downcast').add(dispatcher => {
dispatcher.on('attribute:__style:paragraph', (evt, data, conversionApi) => {
conversionApi.consumable.consume( data.item, evt.name );
const viewElement = conversionApi.mapper.toViewElement(data.item);
conversionApi.writer.setAttribute('style', data.attributeNewValue, viewElement);
}, { priority: 'highest' } );
}); And let me know if this helped. I've added higher priority (so it will be fired as a first converter) and consumed a consumable value (something you should do in order to prevent double conversion). |
@scofalik The mistake i was making was that i had i was declaring this in my widget for allowing divs. I moved it to another file (ie, plugin) where I'm enabling attributes and it worked perfectly. Just in case someone might run into the same issue here's my class. off-topic: would there be an easier way to allow all attributes besides declaring each one? import Plugin from '@ckeditor/ckeditor5-core/src/plugin';
import Div from './plugin/div/div';
import Section from './plugin/section/section';
export default class Extension extends Plugin {
static get requires() {
return [Div, Section];
}
init() {
const editor = this.editor;
let allowedAttributes = [
'width', 'style', 'target', 'class', 'id', 'name', 'title', 'type', 'olddisplay', 'align', 'lang', 'dir',
'border', 'cellspacing', 'cellpadding', 'color', 'valign', 'clear', 'src', 'height', 'shapes',
'prefix', 'tagtype', 'datetime', 'cite', 'cols', 'colspan', 'noshade',
'data-ingestor', 'shape', 'start', 'bgcolor', 'alt', 'strong', 'onclick', 'files',
'com', 'utc-timestamp', 'eastern-timestamp', 'rowspan', 'span', 'theslate', 'page', 'content',
'http-equiv', 'action', 'method', 'value', 'autofocus', 'maxlength', 'rows', 'for', 'aria-label', 'checked', 'selected',
'rel', 'scope', 'location', 'cellpacing', 'block-id', 'guid',
'data-pubtitle', 'data-paygoid', 'data-docid', 'nowrap',
'original-style', 'datatype', 'property', 'controls', 'controlslist', 'data-attr', 'poster', 'preload', 'str', 'itemprop',
'ng-repeat', 'ng-if', 'tabindex', 'role', 'aria-describedby', 'aria-disabled',
'aria-haspopup', 'onmouseover', 'onmouseout', 'onmouseup', '_cke_focus', 'hotel-location', 'office-location', 'xsd', 'xsi',
'href_cetemp', 'uie-tracker', 'uie-tracking', 'track-download', 'track-trigger', 'col',
'doc', 'attach', 'pls', 'vspace', 'hspace', 'slatepath'
];
editor.model.schema.extend('$root', { allowAttributes: allowedAttributes });
editor.model.schema.extend('$block', { allowAttributes: allowedAttributes });
editor.model.schema.extend('$text', { allowAttributes: allowedAttributes });
editor.model.schema.extend('section', { allowAttributes: allowedAttributes });
editor.model.schema.extend('div', { allowAttributes: allowedAttributes });
for (var i = 0; i < allowedAttributes.length; i++) {
editor.conversion.attributeToAttribute({ model: allowedAttributes[i], view: allowedAttributes[i] });
}
editor.model.schema.extend('paragraph', { allowAttributes: '__style' });
editor.conversion.for('upcast').attributeToAttribute({
model: {
key: '__style',
name: 'paragraph'
},
view: 'style'
});
editor.conversion.for('downcast').add(dispatcher => {
dispatcher.on('attribute:__style:paragraph', (evt, data, conversionApi) => {
conversionApi.consumable.consume(data.item, evt.name);
const viewElement = conversionApi.mapper.toViewElement(data.item);
conversionApi.writer.setAttribute('style', data.attributeNewValue, viewElement);
});
});
}
} Thank you again for all the help. Much appreciated. |
In such a case you can declare a schema rule through a callback: this.editor.model.schema.addAttributeCheck( ( context, attributeName ) => {
if ( allowedAttributes.includes( attributeName ) ) {
return false;
}
} ); The above should work. I edited the snippet cause it used the event instead of More info here: https://ckeditor.com/docs/ckeditor5/latest/api/module_engine_model_schema-Schema.html#function-addAttributeCheck |
Note about fix implementation: we might check if we can improve things with supporting catch-all converters for |
Is there a way to get it to work for textproxy items? For example, this would fail for textproxy items editor.conversion.for('downcast').add(dispatcher => {
dispatcher.on('attribute:__style:paragraph', (evt, data, conversionApi) => {
conversionApi.consumable.consume(data.item, evt.name);
// this will fail for the anchor element since the data.item is not an element but a textproxy
const viewElement = conversionApi.mapper.toViewElement(data.item);
conversionApi.writer.setAttribute('style', data.attributeNewValue, viewElement);
});
}); |
If you are dealing with those, you need to use |
I can see three solutions to this:
Treat
Downcast - requires us to export the Upcast - this is a bit trickier - we should process only non-consumed view values. I didn't research this but it might be trickier than it sounds. Also, we might not gain much implementing this other than closing this ticket.
|
ps.: this is how the parsing of if ( viewElementDefinition.styles ) {
if ( typeof viewElementDefinition.styles === 'string' ) {
const parsed = new Map();
// This util should be refactored:
parseInlineStyles( parsed, viewElementDefinition.styles );
for ( const styleKey of parsed.keys() ) {
viewWriter.setStyle( styleKey, parsed.get( styleKey ), element );
}
} else {
const keys = Object.keys( viewElementDefinition.styles );
for ( const key of keys ) {
viewWriter.setStyle( key, viewElementDefinition.styles[ key ], element );
}
}
} |
i saw all above comments they all are help me but can i apply style attribute in
and secondly how can i apply nested elements like |
A small note about this issue. I tried to add the conversion for editor.model.schema.extend( 'listItem', {
allowAttributes: 'listStyle'
} );
editor.conversion.for( 'upcast' ).attributeToAttribute( {
model: {
name: 'listItem',
key: 'listStyle'
},
view: 'style'
} );
editor.conversion.for( 'downcast' ).add( dispatcher => {
dispatcher.on('attribute:listStyle:listItem', ( evt, data, conversionApi ) => {
const viewElement = conversionApi.mapper.toViewElement( data.item );
conversionApi.writer.setAttribute( 'style', data.attributeNewValue, viewElement );
} );
}, { priority: 'highest' } ); However, it turned out that it doesn't work for editor.conversion.for( 'upcast' ).attributeToAttribute( {
model: {
name: 'listItem',
key: 'listStyle'
},
view: {
name: 'li',
key: 'style',
value: /[\s\S]+/
}
} ); |
@josueexhume Which file were you editing in your big block of code above? Is this before building the editor or do you do this in your page that creates the editor? I really want to implement this but am struggling where to put this. |
Hello! any idea if this will get fixed? For some context, I am trying to apply inline styles for images and the workarounds listed in the comments have not been working. Thanks! |
Hello! For some context, I am trying to apply inline styles for table and the workarounds listed in the comments have not been working. Thanks! |
Fix (engine): The `style` and `class` attributes conversion should work with `attributeToAttribute()`. Closes #4517. MINOR BREAKING CHANGE (engine): In the `attributeToAttribute()` upcast helper we fixed how the missing `value` of the `"class"` and `"style"` attribute conversion is handled. Now while not providing the attribute's `value` to the conversion helper accepts and consumes all values. Previously those values were not consumed and left for other converters to convert. Note that you should use the `classes`, and the `styles` fields for the fine-tuned conversion of those attributes instead of a catch-all `"style"` and `"class"` specified in the `key` field.
If you'd like to see this bug fixed sooner, add 👍 to this post.
The text was updated successfully, but these errors were encountered: