Ckeditor5: div is replaced with p

Created on 17 Oct 2018  路  21Comments  路  Source: ckeditor/ckeditor5

Is this a bug report or feature request? (choose one)

馃啎 Feature request

馃捇 Version of CKEditor

"devDependencies": {
    "@ckeditor/ckeditor5-adapter-ckfinder": "^10.0.3",
    "@ckeditor/ckeditor5-alignment": "^10.0.3",
    "@ckeditor/ckeditor5-font": "^10.0.3",
    "@ckeditor/ckeditor5-autoformat": "^10.0.3",
    "@ckeditor/ckeditor5-basic-styles": "^10.0.3",
    "@ckeditor/ckeditor5-block-quote": "^10.1.0",
    "@ckeditor/ckeditor5-dev-utils": "^11.0.1",
    "@ckeditor/ckeditor5-dev-webpack-plugin": "^7.0.1",
    "@ckeditor/ckeditor5-easy-image": "^10.0.3",
    "@ckeditor/ckeditor5-editor-classic": "^11.0.1",
    "@ckeditor/ckeditor5-essentials": "^10.1.2",
    "@ckeditor/ckeditor5-heading": "^10.1.0",
    "@ckeditor/ckeditor5-image": "^11.0.0",
    "@ckeditor/ckeditor5-link": "^10.0.4",
    "@ckeditor/ckeditor5-list": "^11.0.2",
    "@ckeditor/ckeditor5-paragraph": "^10.0.3",
    "@ckeditor/ckeditor5-theme-lark": "^11.1.0",
    "@ckeditor/ckeditor5-upload": "^10.0.3",
    "postcss-loader": "^3.0.0",
    "raw-loader": "^0.5.1",
    "style-loader": "^0.23.1",
    "uglifyjs-webpack-plugin": "^1.2.7",
    "webpack": "^4.20.2",
    "webpack-cli": "^3.1.2"
  },

I see that div is now replaced with p. Is there a way to leave div? Is there a ready plugin for this?
Also all classes from p are stripped. How to leave them? Another custom plugin?

invalid question

Most helpful comment

I'm just wondering whether a feature was ever implemented following this thread? I have a very simple case where my HTML content looks like:

```

` When I set the initial content of the editor the outer

``` tags are stripped. I have no other requirement regarding allowing/disallowing content but I do need to disable the editor from removing those tags, I have 30,000+ HTML snippets that I am migrating and I was surprised to run into this issue! Is a custom plugin really the only option for something so simple?

All 21 comments

Hello,

any block elements (like <div>) that are not recognized by any feature are converted to <p>s. Unrecognized are stripped too.

Maybe some time in a future we will provide some kind of "AllowElements" plugin that would provide a simple 1-to-1 conversion for tags specified in its configuration. For now, I'd advise adding your own plugin for divs. It should be relatively easy to do. Add a new entry in Schema and then provide conversion. Maybe that will be enough:

model.schema.register( 'div', { inheritAllFrom: '$block' } );
editor.conversion.elementToElement( { model: 'div', view: 'div' } );

Allowing attributes on those divs (or ps) is easy too. I can imagine "ClassAttributePlugin" that enables that for specified elements. However in that case it might conflict with other features which manages strictly their classes, so instead you might want to convert an exact class names.

Here are Schema docs: https://ckeditor.com/docs/ckeditor5/latest/api/module_engine_model_schema-Schema.html

Here are conversion docs. See examples in the methods descriptions, there are lots of them and they might prove helpful:
https://ckeditor.com/docs/ckeditor5/latest/api/module_engine_conversion_conversion-Conversion.html
https://ckeditor.com/docs/ckeditor5/latest/api/module_engine_conversion_downcast-converters.html
https://ckeditor.com/docs/ckeditor5/latest/api/module_engine_conversion_upcast-converters.html

You'd be interested in attribute-to-attribute conversion.

@scofalik Thanks for guidness.
Here what I have:

editor.model.schema.register('div', {
            inheritAllFrom: '$block',
            allowAttributes: ['id', 'class'],
            isBlock: true,
        });
        editor.conversion.elementToElement({model: 'div', view: 'div'});

As You can see id and class attributes are allowed on div but ckeditor strips them anyway. Is it happening during conversion? How to fix it?

They are stripped because you didn't specify conversion for them. For the simplest solution, see documentation for Conversion#attributeToAttribute. https://ckeditor.com/docs/ckeditor5/latest/api/module_engine_conversion_conversion-Conversion.html#function-attributeToAttribute

I think that { model: { name: 'div', key: 'id' }, view: 'id' } should work. (same for class). Try that.

@scofalik thanks again.
One more issue though.
I want to create button that inserts <div id="myDiv"></div>. This has to be strict html.
As I can see in plugin example, I need to execute something like this:

            view.on('execute', () => {
                // editor.execute('div');
                editor.model.change(writer => {
                    const divEl = writer.createElement('div', {
                        id: 'myDiv',
                    });

                    editor.model.insertContent(divEl);
                });
            });

But I don't have creator command for div, so I need to add one? Or maybe there is a way to add plain html text <div id="myDiv"></div>?

@scofalik Back to topic....

I must advice CkEditor is very complicated now :/
In ck4 I had very simple plugin that adds div to editor - nothing more.
Here it is:

CKEDITOR.plugins.add('if_karetka_maila', {
    requires: ['button'], //, 'styles' ],
    init: function (editor) {
        var pluginDirectory = this.path;
        editor.addContentsCss(pluginDirectory + 'styles.css');

        editor.ui.addButton('karetka', {
            label: 'Wstaw znacznik tre艣ci',
            title: 'Zaznacz gdzie rozpoczyna si臋 tre艣膰 emaila',
            className: 'cke_button_tylkoTekst',
            command: 'insertKaretka'
        });

        editor.addCommand('insertKaretka', {
            exec: function (editor) {
                editor.insertHtml('<div id=\"karetka_papeterii\"><p></p></div>');
            }
        });
    }
}); 

But now it is almost impossible to make it:/
I suppose that div is translated to paragraph and there are no nested paragraphs, so I cannot create <div><p></p></div>.
So I think I have to create new ckElement, or maybe there is a generic one?
How to create ckElement that only inserts tag, without checking other and so on?

PS. Maybe You could create some facade classes that helps with most common plugin tasks ??

@scofalik any help with it?

If you need a <div><p></p></div> structure you need to allow paragraph in div using Schema. Something like model.schema.extend( 'paragraph', allowIn: [ 'div' ] ). However, keep in mind that this means that you are starting to fiddle with an aribtrary nested-blocks structure. This is not something that we developed a lot. As of now, only Blockquote features allows for having paragraph in other block and AFAIR it required some additional code to work correctly. You might have some problems with Enter key functioning.

We will work in future on having the editor work correctly for such structures as we need it for a few features (like for example lists containing structured content). But it is not our priority right now.

Can You guess timeframe? days, month, six months?
I have to admit I'll need it within max 3 months, so I'd be forced to use other library :/ (which I don't want to)

Since block quotes work already, I'd guess that such divs may work as well. If anything, minor tweaks should be enough, so I'd recommend just checking if it works.

What @scofalik meant are some more complex structures and arbitrary HTML. But as long as your feature defines proper converters and schema and you don't make the structure too complicated it should work well.

I think that problem is that div and p are both 'paragraphs' so I cannot place <div><p></p></div> It is replaced with <p> or <div>

Here are my plugins:

    export class Div extends Plugin {
        init() {
            console.log('Div was initialized');
            const editor = this.editor;

            editor.model.schema.register('div', {
                inheritAllFrom: '$block',
                allowAttributes: ['id', 'class'],
                isBlock: true,
            });
            editor.conversion.elementToElement({model: 'div', view: 'div'});
            editor.conversion.attributeToAttribute({model: 'class', view: 'class'});
            editor.conversion.attributeToAttribute({model: {name: 'div', key: 'id'}, view: 'id'});
        }
    }


    export class KaretkaPapeterii extends Plugin {
        init() {
            console.log('Karetka papeterii was initialized');
            const editor = this.editor;

            editor.ui.componentFactory.add('karetkaPapeterii', locale => {
                const view = new ButtonView(locale);

                view.set({
                    label: 'Karetka papeterii',
                    // icon: imageIcon,
                    tooltip: true,
                    withText: true,
                });

                // Callback executed once the image is clicked.
                view.on('execute', () => {
                    const htmlDP = new HtmlDataProcessor();

                    const viewFragment = htmlDP.toView('<div id="karetka_papeterii"><p>&nbsp;</p></div>');
                    const modelFragment = editor.data.toModel(viewFragment);
                    editor.model.insertContent(modelFragment);
                });

                return view;
            });
        }
    }

@Reinmar @scofalik Is there any example of enhancing ckeditor 5 to accept input and select tags and may be some custom controls like datepickers. It would be of great help if you can point us to similar example. (running code preferred)

I must say that I fall back to ckeditor 4. Creating custom funcs is very difficult right now. You need to make soma improvements.

did you get any luck with rendering div instead of p tag using custom js plugin?? not with the doc frag.
Or may be you can guide me how can i make one.

@Kushan- I gave up

If you want <p> inside of <div> apart from what I've already wrote, you can check out Blockquote feature for help. It works for Blockquote, so it should be a good starting point. Check how schema is defined for blockquote element and allow paragraph in blockquote.

If you want <div> instead of <p> and no <p>s whatsoever in your content, you can simply overwrite conversion for paragraph model element. I've just answered similar question regarding <b> and <strong>: https://stackoverflow.com/questions/53899331/elegant-way-to-change-view-schema-in-ckeditor5/54094675#54094675. In your case, elementToElement converter will need to be used. Also, in your case you might need to also define upcasting (but maybe autoparagrapher will do the work for you).

If you want mixed content, so that all following are fine:
<p>Foo</p>
<div>Foo</div>
<div><p>Foo</p></div>
Then you are in the shady territory of source view and "allow any HTML". We think how to enable it and did some research (and also loosen our point of view on that subject) but it is not possible to do that without running into some bugs (mostly with Enter behavior) ATM.

I've also seen that you want to enable arbitrary ids and classes in your divs. AFAIK id should work for you, but class is a bit of a special attribute (like style). It's conversion is a little more different, we treat each class name and style declaration as single, convertible entity (instead of converting whole attribute). This way different features can add different classes and can co-exist. But I didn't run your code, so maybe it works for you. If anything, I'd recommend class attribute conversion only for divs (as you did with id).

My use case is, while rendering raw html like <div><ul><li>foo</li></ul></div> , setData() is eliminating div and rendering p instead (i know the reason why it's happening), but how can i prevent it from eliminating the div tag. On using docFrag method i need to parse the whole structure (i tried to did that but cke5 is not rendering ul, li as expected tagName = writer.createElement( "unordered" ); tagName = writer.createElement( "list" );) and createElement which is tedious. Is there is any way i can do that??

This is blockquote-like structure. You could base on blockquote plugin to write your own plugin for div elements. Since blockquote has more things to it (to make it work correctly in any case and also to prevent blockquotes in blockquotes) you can simply do the easier part. But don't expect it will work flawlessly.

// Enable "div" element in schema.
editor.model.schema.register( 'div', {
    allowWhere: '$block',
    allowContentOf: '$root'
} );

// Specify conversion for "div" element.
editor.conversion.elementToElement( { model: 'div', view: 'div' } );

Once again, do note that you might run into some problems with this as "custom nested" structures is not the topic we have been focused on yet.

I'm closing it due to a lack of activity.

I think support for div's to behave the same way as ck4 is a needed feature. I tried implemented what was suggested, it provides me with some of the functionalities but I still run into issues, such as deleting contents from one div to merge into another div.

Currently it throws the error:


ckeditorerror.js:66 Uncaught CKEditorError: move-operation-node-into-itself: Trying to move a range of nodes into one of nodes from that range

Is there a way to get the deletion functionality working, ie.
Before:
```html

columns one text

  • list 1
  • list 2

text that needs to be deleted and merged into the previous column

  • list 1
  • list 2

**After**
``` html
<div class="col">
    <p>columns one text</p>
    <ul>
        <li>list 1</li>
        <li>list 2</li>
    </ul>
    <p>text that needs to be deleted and merged into the previous column</p>
</div>

<div class="col">
    <ul>
        <li>list 1</li>
        <li>list 2</li>
    </ul>
</div>

I'm just wondering whether a feature was ever implemented following this thread? I have a very simple case where my HTML content looks like:

```

` When I set the initial content of the editor the outer

``` tags are stripped. I have no other requirement regarding allowing/disallowing content but I do need to disable the editor from removing those tags, I have 30,000+ HTML snippets that I am migrating and I was surprised to run into this issue! Is a custom plugin really the only option for something so simple?

Was this page helpful?
0 / 5 - 0 ratings