tinymce / tinymce

The world's #1 JavaScript library for rich text editing. Available for React, Vue and Angular
https://www.tiny.cloud
Other
15k stars 2.24k forks source link

Custom style formats : span tag keeps getting wrapped into p tags #8664

Closed 1019-h closed 1 year ago

1019-h commented 1 year ago

What is the current behavior? Describe the bug Hi ! Sorry if my question is dumb, I'm not really a professionnal dev yet. I have customised style_formats to have the kind of headings and blocks I want my users to use :

style_formats: [
        { title: 'Headings', items: [
                        { title: 'Titre principal', block: 'span', attributes: {'class' : 'title'}, wrapper: true },
                        { title: 'Titre alternatif', block: 'span', attributes: {'class' : 'title-alt'}, wrapper: true },
                        { title: 'Titre alternatif (gris)', block: 'span', attributes: {'class' : 'title-alt grey'}, wrapper: true },
                        { title: 'Titre informatif', block: 'span', attributes: {'class' : 'title-alt infos'}, wrapper: true },
                        { title: 'Sous-titre', block: 'span', attributes: {'class' : 'subtitle'}, wrapper: true },
                        { title: 'Petit titre', block: 'span', styles: { color: 'var(--violet)', fontFamily: 'var(--playfair)', fontWeight: 'bold' }, wrapper: true }
        ]},
        { title: 'Blocks', items: [
                        { title: 'Paragraph', format: 'p' },
                        { title: 'Blockquote', format: 'blockquote' },
                        { title: 'Cadre gris', block: 'div', classes: ['cadre-admin'], wrapper: true },
                        { title: 'Cadre de titre (au-dessus d\'un cadre gris)', block: 'div', classes: ['cadre-admin-title'], styles: { '--url': 'url(\'https://i.imgur.com/P02IE2L.png\')'}, wrapper: true },
                        { title: 'Cadre dégradé (dans cadre gris)', block: 'div', classes: ['admin-image'], wrapper: true },
                        { title: 'Cadre gris avec ombre portée', block: 'div', classes: ['cadre-admin-alt', 'container', 'grey', 'shadow'], wrapper: true },
                        { title: 'Bloc clair (dans cadre gris)', block: 'div', classes: ['admin-content'], wrapper: true },
                        { title: 'Bloc clair avec lettrine (dans cadre gris)', block: 'div', classes: ['admin-content', 'first-letter'], wrapper: true },
                        { title: 'Cadre dégradé', block: 'div', classes: ['cadre-admin-alt', 'container', 'important'], wrapper: true },
                        { title: 'Bloc blanc (dans cadre dégradé)', block: 'div', classes: ['bloc'], wrapper: true },
                        { title: 'Bloc d\'informations', block: 'div', classes: ['bloc-interieur'], wrapper: true }
        ]}
]

I want my custom headings to have the same kind of behaviour that the "vanilla" headings have : replacing the p tag in which the text is wrapped by the tag they chose (without customisation, it would be h1, h2, h3,... etc).

But here, when they choose a heading, it doesn't replace the p tag by the span tag. It does this :

<p>
<span class="title">
Title
</span>
</p>

When I change the span inside style_formats by div, it does this :

<div class="title">
<p>
Title
</p>
</div>

Demo : https://fiddle.tiny.cloud/I5iaab

What is the expected behavior? I want that, when the users chose a heading, it replaces the p tag in which the text is wrapped. Like this :

<span class="title">
Title
</span>

Is there anything I missed inside the style_formats options ?

Thank you.

Which versions of TinyMCE, and which browser / OS are affected by this issue? Did this work in previous versions of TinyMCE? TinyMCE 6, on Chrome / Windows 10.

spocke commented 1 year ago

The blocks option should have a block element name that is normally things like div or p etc. span however is a inline element. So tinymce will wrap any inline elements at root level in default paragraph blocks. If you want custom headings I suggest using semantic elements like block: 'h1' then custom classes on that using attributes: { 'class': 'someclass' }.

I'm going to close this since I don't think it's a bug and more of a configuration issue.

1019-h commented 1 year ago

The blocks option should have a block element name that is normally things like div or p etc. span however is a inline element. So tinymce will wrap any inline elements at root level in default paragraph blocks. If you want custom headings I suggest using semantic elements like block: 'h1' then custom classes on that using attributes: { 'class': 'someclass' }.

I'm going to close this since I don't think it's a bug and more of a configuration issue.

Hi ! The thing is : it does this even when it's not at root level. Even wrapped in a div, it still wrap the span element with a p.

It does this even when I'm using a div, as I explained : it wraps the selection in a div and adds a p inside.

spocke commented 1 year ago

block: 'span' is not valid config it needs to be a block element name like p or h1

Here is a updated config were I removed the wrapper and changed the block configs to valid element names.

style_formats: [
      { title: 'Headings', items: [
                      { title: 'Titre principal', block: 'h1', attributes: {'class' : 'title'} },
                      { title: 'Titre alternatif', block: 'h2', attributes: {'class' : 'title-alt'} },
                      { title: 'Titre alternatif (gris)', block: 'h3', attributes: {'class' : 'title-alt grey'} },
                      { title: 'Titre informatif', block: 'h4', attributes: {'class' : 'title-alt infos'} },
                      { title: 'Sous-titre', block: 'h5', attributes: {'class' : 'subtitle'} },
                      { title: 'Petit titre', block: 'h6', styles: { color: 'var(--violet)', fontFamily: 'var(--playfair)', fontWeight: 'bold' } }
      ]},
      { title: 'Blocks', items: [
                      { title: 'Paragraph', format: 'p' },
                      { title: 'Blockquote', format: 'blockquote' },
                      { title: 'Cadre gris', block: 'div', classes: ['cadre-admin'], wrapper: true },
                      { title: 'Cadre de titre (au-dessus d\'un cadre gris)', block: 'div', classes: ['cadre-admin-title'], styles: { '--url': 'url(\'https://i.imgur.com/P02IE2L.png\')'}, wrapper: true },
                      { title: 'Cadre dégradé (dans cadre gris)', block: 'div', classes: ['admin-image'], wrapper: true },
                      { title: 'Cadre gris avec ombre portée', block: 'div', classes: ['cadre-admin-alt', 'container', 'grey', 'shadow'], wrapper: true },
                      { title: 'Bloc clair (dans cadre gris)', block: 'div', classes: ['admin-content'], wrapper: true },
                      { title: 'Bloc clair avec lettrine (dans cadre gris)', block: 'div', classes: ['admin-content', 'first-letter'], wrapper: true },
                      { title: 'Cadre dégradé', block: 'div', classes: ['cadre-admin-alt', 'container', 'important'], wrapper: true },
                      { title: 'Bloc blanc (dans cadre dégradé)', block: 'div', classes: ['bloc'], wrapper: true },
                      { title: 'Bloc d\'informations', block: 'div', classes: ['bloc-interieur'], wrapper: true }
      ]}
]

Wrapper formats are more like divs and blockquotes where you want to wrap other block elements. H1 can't contain things like P elements and spans can't contain blocks like p or h1 since they are blocks and span is inline.

1019-h commented 1 year ago

Yes, I do understand. But I have the same problem when I use "div" instead of "span" as shown here :

When I change the span inside style_formats by div, it does this :

<div class="title">
<p>
Title
</p>
</div>

I want it to replace the p I'm currently selecting. I want the result to be :

<div class="title">
Title
</div>

I'm sorry if my english isn't clear. It isn't my first language.

spocke commented 1 year ago

If you use wrapper: true and block: 'div' it will wrap things but if you don't have wrapper: true then it will replace the current block like p with the div and the specified class.