Grapesjs: A component that inserts editable HTML

Created on 24 Nov 2017  路  11Comments  路  Source: artf/grapesjs

Would it be possible to create a block that allowed the user to write in responsive HTML either directly on to the template or on the side in the style/layout manager?

outdated

Most helpful comment

@chiqui3d Change the isComponent function to this to prevent the initial internal html from getting parsed by grapesjs into components:

isComponent: function(el) {
    if (el.hasAttribute && el.hasAttribute("data-html-code")) {
        return {
            type: 'html-code',
            content: el.innerHTML,
            components: []
        };
    }
}

The other code I posted should prevent grapesjs from parsing the html after editing through the modal. The key to both is that you need to set the internal html into the content property instead of components.

All 11 comments

Hi @NorthstarTech,

I just created a plugin (very early, could use some more work) that you may find helpful: https://github.com/ryandeba/grapesjs-html-block.

You should just be able to include that file in your project and include the plugin in your grapesjs init config:
grapesjs.init({ ..., plugins: ['html-block'] })

After doing that, you should see a new "HTML Code" block. Drag and drop it somewhere, select the element, and you should see a "code" button in the toolbar. Click the code button and you should get a modal that lets you edit the HTML content.

Let me know if you run into any issues.

I believe this issue has been resolved and could be closed based on the first comment here: https://github.com/ryandeba/grapesjs-html-block/issues/1. @NorthstarTech could you confirm or reply with additional details if you want to keep this issue open?

Its working fine after adding this plugin. Issue resolved.
Thank u so much @ryandeba

@ryandeba I have a problem, I'm doing when they click on the component also opens the modal to edit the html, but when I add paragraphs, header or another type of component this is superimposed on the html-block, it's possible to block that the inner components are not selected?

@chiqui3d You could replace this with the following code:

saveButton.onclick = function() {
    component.components(""); // you really shouldn't need this... try removing it and see if it causes any issues
    component.set("content", codeViewer.editor.getValue());
    editor.Modal.close();
};

FYI - commenting on closed issues like this one can make easy for me to completely miss your message. Luckily I got an email notification since you tagged me and had free time to respond, but in the future it would be best to open a new issue.

thanks @ryandeba,

I have additionally added the following to your code.

isComponent: function(el) {
                    if (el.hasAttribute && el.hasAttribute("data-html-code")) {
                        return { type: "html-code", components: el.innerHTML };
                    }
                }
            }),
            view: defaultType.view.extend({
                events: {
                    click: 'handleClick',
                },
                handleClick: function(e) {
                    editor.runCommand("open-html-code-editor");
                },
                render: function() {
                    defaultType.view.prototype.render.apply(this, arguments);
                    return this;
                },
            }),
        });

The problem I have is when I edit that html in the Modal and I add a paragraph, it shows me the badge text and selects the text, when I want it in this case I select the html-code component, , all the internal code of this component could only edit through the Modal, that is possible to do it?

And that way i'll have to avoid clicking arrow to move a component up and avoid confusion

@chiqui3d Change the isComponent function to this to prevent the initial internal html from getting parsed by grapesjs into components:

isComponent: function(el) {
    if (el.hasAttribute && el.hasAttribute("data-html-code")) {
        return {
            type: 'html-code',
            content: el.innerHTML,
            components: []
        };
    }
}

The other code I posted should prevent grapesjs from parsing the html after editing through the modal. The key to both is that you need to set the internal html into the content property instead of components.

@ryandeba awesome, works well. I have already understood a little more. Thank you very much :)

Hello again @ryandeba @artf
This is crazy, now when I save in the database and reload the page I can't select the component, and actually component has been saved correctly with the div and with data-html-code attribute.

The full plugin code is:

grapesjs.plugins.add('html-block', function(editor, options) {
    options = options || {};

    addHTMLCodeEditor();
    addHTMLCodeComponent();
    addHTMLCodeBlock();

    function addHTMLCodeEditor() {
        editor.Commands.add("open-html-code-editor", {
            run: function(editor, sender, data) {

                var codeViewer = editor.CodeManager.getViewer("CodeMirror").clone();
                codeViewer.set({
                    codeName: "htmlmixed",
                    theme: "hopscotch",
                    readOnly: false
                });

                var modalContent = document.createElement("div");

                var editorTextArea = document.createElement("textarea");

                var saveButton = document.createElement("button");
                saveButton.innerHTML = "Save";
                saveButton.className = "gjs-btn-prim";
                saveButton.style = "margin-top: 8px;";
                saveButton.onclick = function() {
                    var content = codeViewer.editor.getValue();
                    editor.getSelected().set("content", content);
                    editor.Modal.close();
                };

                modalContent.appendChild(editorTextArea);
                modalContent.appendChild(saveButton);

                codeViewer.init(editorTextArea);

                var htmlContent = document.createElement("div");
                htmlContent.innerHTML = editor.getSelected().toHTML();
                htmlContent = htmlContent.firstChild.innerHTML;
                codeViewer.setContent(htmlContent);

                editor.Modal
                    .setTitle("Edit HTML")
                    .setContent(modalContent)
                    .open();

                codeViewer.editor.refresh();
            }
        });
    };
    //inner components not selectable
    function addHTMLCodeComponent() {
        var defaultType = editor.DomComponents.getType('default');

        var _initToolbar = defaultType.model.prototype.initToolbar;

        editor.DomComponents.addType('html-code', {
            model: defaultType.model.extend({
                defaults: Object.assign({}, defaultType.model.prototype.defaults, {
                    'custom-name': "HTML CODE",
                    classes: ["container-html"]
                }),
                initToolbar(args) {
                    _initToolbar.apply(this, args);

                    var toolbar = this.get("toolbar");
                    toolbar.push({
                        attributes: {
                            "class": "fa fa-code"
                        },
                        command: "open-html-code-editor",
                    });
                    this.set("toolbar", toolbar);
                }
            }, {
                isComponent: function(el) {
                    if (el.hasAttribute && el.hasAttribute("data-html-code")) {
                        return {
                            type: "html-code",
                            content: el.innerHTML,
                            components: []
                        };
                    }
                }
            }),
            view: defaultType.view.extend({
                events: {
                    dblclick: 'handleClick',
                },
                handleClick: function(e) {
                    e.preventDefault();
                    editor.runCommand("open-html-code-editor");
                },
                render: function() {
                    defaultType.view.prototype.render.apply(this, arguments);
                    return this;
                },
            }),
        });

    };

    function addHTMLCodeBlock() {
        editor.BlockManager.add("html-code", {
            attributes: { class: "fa fa-code" },
            label: "HTML Code",
            content: `<div data-html-code>Click To Edit The HTML Code</div>`
        });
    };

});

Besides, if I remove from the function isComponent() components: [], it duplicates the content by two, I can't find the meaning, but in this case lets me edit the component.

Can you help me please?

I feel like I've ran into that issue before, but I don't remember what the solution was. I'll try to look into it soon. Would you mind creating a new issue here to for this problem? https://github.com/ryandeba/grapesjs-html-block/issues

This thread has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

mathiasbc picture mathiasbc  路  3Comments

Snarkly picture Snarkly  路  3Comments

kickbk picture kickbk  路  3Comments

kosirm picture kosirm  路  3Comments

ionic666 picture ionic666  路  3Comments