Allow formats and style_formats to remove conflicting formats/classes #7581
Replies: 6 comments 1 reply
-
@colethorsen Did you happen to find a workaround for this issue? I'm dealing with the same thing |
Beta Was this translation helpful? Give feedback.
-
Hey, I didn't but I haven't really looked into it beyond this post. I'm sure it could be created as a plugin.
|
Beta Was this translation helpful? Give feedback.
-
Could you setup a fiddle where this is happening since I have troubles reproducing this issue. The alignment buttons first remove all the other alignments before applying a new one so you would never end up with two alignment classes at the same time. Use the alignment buttons here and notice that the class of the previous alignment is removed https://fiddle.tiny.cloud/Fkiaab. If you are using the formatting apis directly I suggest instead using the commands to align things the commands are: But having a |
Beta Was this translation helpful? Give feedback.
-
@spocke use this fiddle and try using the style select dropdown instead https://fiddle.tiny.cloud/Fkiaab/1 Also there are many cases where this could be useful beyond justification. For instance we use a number of sizing styles to allow for the scale up or scale down of text, they're roughly named The TinyMCE "solution" to this is basically to use styles so the color would be set as a hard coded value, or the size would be set in px, em, rem, etc. This isn't really suitable as its much more effective to abstract the styling to classes as they can then be globally controlled, and effected by other factors, such as device, other elements this content may be nested in, etc. There are also numerous more abstract situations where this would be helpful, like having several different styling options set up for text where they are direct replacements for each other and wouldn't be used in combination, like say pullquote styling, often we provide several different complimentary style options for this, but you'd never want to combine the styles for them, picking a different class just adds it, which can cause all sorts of crazy unintended consequences for users. A clearer example (give that the formatting does seem to work in your example, just not in mine when implemented in a different way) would probably be:
|
Beta Was this translation helpful? Give feedback.
-
OMG, just found this https://stackoverflow.com/a/56224417/527689
Using But still it would be great to not have to do a workaround like this. |
Beta Was this translation helpful? Give feedback.
-
Thats a good solution. I ended up writing a solution for this too which basically solves the problem exactly as initially described, on the surface the above solution looks like it relies on the nesting of menus, this one just uses the prefix of the formats regardless of where they are applied from. It takes the approach of defaulting to toggling, and then utilizing a const config = {
formats: {
align_left : { selector : 'p,h1,h2,h3,h4,h5,h6,td,th,div,ul,ol,li,table', classes : '' },
align_center : { selector : 'p,h1,h2,h3,h4,h5,h6,td,th,div,ul,ol,li,table', classes : 'text_center' },
align_right : { selector : 'p,h1,h2,h3,h4,h5,h6,td,th,div,ul,ol,li,table', classes : 'text_right' },
h1 : { block : 'h1', classes : 'bold' },
h2 : { block : 'h2', classes : 'bold' },
h3 : { block : 'h3', classes : 'bold' },
h4 : { block : 'h4', classes : 'bold' },
h5 : { block : 'h5', classes : 'bold' },
h6 : { block : 'h6', classes : 'bold' },
header_sm : { selector : 'h1,h2,h3,h4,h5,h6', classes : 'header_sm' },
header_md : { selector : 'h1,h2,h3,h4,h5,h6', classes : 'header_md' },
header_lg : { selector : 'h1,h2,h3,h4,h5,h6', classes : 'header_lg' },
header_xl : { selector : 'h1,h2,h3,h4,h5,h6', classes : 'header_xl' },
color_primary : { inline : 'span', classes : 'text_primary' },
color_secondary : { inline : 'span', classes : 'text_secondary' },
},
style_formats : [
{ title : "Headers", items : [
{ title : "Header 1", format : "h1" },
{ title : "Header 2", format : "h2" },
{ title : "Header 3", format : "h3" },
{ title : "Header 4", format : "h4" },
{ title : "Header 5", format : "h5" },
{ title : "Header - XL", format : "header_xl" },
{ title : "Header - Large", format : "header_lg" },
{ title : "Header - Medium", format : "header_md" },
{ title : "Header - Small", format : "header_sm" }
] },
{ title : "Inline", items : [
{ title : 'Left', icon : 'align-left', format : 'align_left' },
{ title : 'Center', icon : 'align-center', format : 'align_center' },
{ title : 'Right', icon : 'align-right', format : 'align_right' },
{ title : 'Uppercase', inline : 'span', classes : 'uppercase' },
] },
{ title : "Colours", items : [
{ title : 'Primary', format : 'color_primary' },
{ title : 'Secondary', format : 'color_secondary' },
] },
],
setup : function (ed) {
//allows us to have "toggleable" formats for instance with the header sizes and aligns.
ed.on('ExecCommand', function checkListNodes (evt) {
if (evt.command == 'mceToggleFormat') {
//don't do anything for custom.
if (evt.value.startsWith('custom-'))
return true;
//detect if the current format is already applied or not. so we can know
//whether or not to re-apply it at the end.
//
//We strip off all of the formats and then re-add the selected format if it
//wasn't being toggled off this way if formats share CSS classes they won't
//get accidentally removed when we remove the other matching formats.
const formatAdded = this.formatter.match(evt.value);
//applying this format before adding/removing others ensures that the
//element is not rolled up into its parent.
this.formatter.apply('toggle_fix');
//deal with header formats as separately as they don't have an underscore in
//them but still need to be removed in case they have classes associated
//with them
const headers = ['h1', 'h2', 'h3', 'h4', 'h5', 'h6'];
if (headers.includes(evt.value)) {
headers.forEach((format) => {
if (format != evt.value) {
//since we've already changed the tag, the format is considered
//removed even though the classes weren't removed. So we have
//to re-apply them before removing them.
this.formatter.apply(format);
this.formatter.remove(format);
}
});
} else {
const currentFormat = evt.value.split('_');
if (currentFormat.length < 2)
return true;
//iterate over all the formats.
Object.entries(wysiwyg_formats).forEach(([format, formatInfo]) => {
//identify the formats that have the same prefix as the format that
//was just set, but aren't the one that was just set.
if (format.startsWith(currentFormat[0] + '_') && format != evt.value) {
//remove formats that have the same prefix.
this.formatter.remove(format);
}
});
}
if (formatAdded)
this.formatter.apply(evt.value);
//remove the toggle fix as its no longer necessary.
this.formatter.remove('toggle_fix');
}
});
},
} |
Beta Was this translation helpful? Give feedback.
-
I have a regular use case where we use our own classes, rather than setting explicit styles for various different use cases, this allows us to globally adjust the class styles at any point and not have to worry about any specific styles applied via formats in legacy content.
This however leads to an irritant when adding conflicting formats such as text alignment to an selector.
In the default tinymce way of handling this the
text-align: left;
would be replaced bytext-align: right
if you were to apply right alignment after left alignment, however with classes they just stack so you could end up withclass="left right"
, depending on the order of your styles in your stylesheet it basically makes an arbitrary looking choice. So, in order to change fromleft
toright
you actually have to click offleft
and then click onright
. This can compound further into a mess likeclass="left center right full"
What if there was an ability to set either
remove_classes
as part of a format or aremove
object that potentially containsclasses
,styles
, or eventformats
. I'm not immediately sure on what the use case for explicitly being able to remove styles would be but it would provide more flexibility.For example:
or
Beta Was this translation helpful? Give feedback.
All reactions