Issue #774Opened January 18, 2018by ryandeba0 reactions

Mimic customRTE behavior when parsing content

Question

Hi @artf,

I'd like to replicate this behavior when calling editor.setComponents("<div>This is a text component. <span style='font-size: 20px;'>This is a nested element that I don't want get parsed out.</span></div>"). In that example, I would want the nested span to not get parsed as its own component so that I cannot select it or interact with it in any way (much the same as if I had enabled/disabled a customRTE on the div).

I'm seeing 2 options here:

  1. After calling editor.setComponents, programmatically enable and disable RTE on outer div so that the child elements & text are treated as content on the div. I'm pretty sure this would work without making any changes to grapesjs core...haven't tested it out just yet.
  2. Modify the behavior of ParseHtml.parseNode to somehow identify that the div should not parse out its child elements/text. Maybe something like this using a a new property returned from isComponent:
var defaultType = editor.DomComponents.getType("default");

editor.DomComponents.addType('some-custom-component-type', {
  model: defaultType.model.extend(
    {
    },
    {
      isComponent: function(el) {
        if(el.hasAttribute && el.hasAttribute("data-some-custom-component-type")){
          return {
            type: 'some-custom-component-type',
            parseChildContent: false // new property that will tell the parser not to bother with parsing the children
          };
        }
      }
    }
  ),
  view: defaultType.view
});

... // changes to ParseHtml.parseNode() below
if (nodeChild === 1 && firstChild.nodeType === 3) {
  !model.type && (model.type = 'text');
  model.content = firstChild.nodeValue;
} else if (model.hasOwnProperty("parseChildContent") && !model.parseChildContent) { // check for the new property to prevent the default node parsing behavior
  model.content = node.innerHTML;
} else {
  model.components = this.parseNode(node);
}
...

editor.setComponents("<div data-some-custom-component-type>This is a text component. <span style='font-size: 20px;'>This is a nested element that I don't want get parsed out.</span></div>")

Any thoughts on exploring option 2? Would you consider accepting a pull request that adds that new functionality to the parser? It wouldn't necessarily need to be driven by a custom component...I think a property like data-parse-child-content="false" could also be an option, or perhaps simply recognizing that a customRTE is being used and just check for model.type === "text" instead of parseChildContent.

My use case for this is that I'm going to be using a customRTE, but there's a good chance that the content that initially gets set into the editor will have a lot of nested text components which I'd like to treat as a single component.

Answers (3)

ryandebaJanuary 18, 20180 reactions

Now that I think through this a bit more, option 1 wouldn't really work for me since I want to prevent any inline styles from getting removed, as well as preventing any id's/classes/attributes from getting added to the child elements. So I guess that leaves option 2 or maybe another solution that I haven't thought of.

artfJanuary 19, 20180 reactions

Hey Ryan what about this custom component

	const domc = editor.DomComponents;
    const textType = domc.getType('text');

    domc.addType('raw-text', {
      model: textType.model.extend({
        },{
          isComponent: function(el) {
            if (el.hasAttribute && el.hasAttribute('data-raw-text')) {
              return {
                type: 'raw-text',
                content: el.innerHTML,
                components: [] // this will avoid parsing children
              };
            }
          }
        }
      ),
      view: textType.view.extend({
        disableEditing() {
          const model = this.model;
          const rte = this.rte;

          if (rte && model.get('editable')) {
            rte.disable(this, this.activeRte);
            model.set('content', this.getChildrenContainer().innerHTML)
            .trigger('change:content', model);
          }

          this.rteEnabled = 0;
          this.toggleEvents();
        },
      })
    });
ryandebaJanuary 19, 20180 reactions

Thanks @artf! I bet your suggestion will work for me - I'll test it out in the next few hours.

Related Questions and Answers

Continue research with similar issue discussions.

Paid Plugins That Match This Issue

Curated by issue keywords and label relevance to help you ship faster.

View all plugins

Loading paid plugin recommendations...

Browse Plugin Categories

Jump directly to plugin category pages on the marketplace.