verbb / vizy

A flexible visual editor for Craft CMS
Other
43 stars 8 forks source link

An easier way to get all the content from a node #218

Closed jan-dh closed 1 year ago

jan-dh commented 1 year ago

What are you trying to do?

Currently, when I check for a node with the type heading, and that node looks like this in raw HTML: "hello this is a title", I get back the an array of 3 content nodes again. I get that this gives you ultimate flexibility, but it also very cumbersome to work with. If I you want to loop over an array of headings & output the actual heading, I always have to loop over the different content nodes again, merge them into 1 string & voila, now I have 1 single string. Having the option to output this as 1 string would make it easier to work with. You can always strip html tags etc. using |raw. or |striptag or making a custom twig filter.

What's your proposed solution?

Maybe add the raw content as a node property or provide a function to get it.

Additional context

No response

engram-design commented 1 year ago

This is really down to how ProseMirror's schema is structured. A heading (node) can contain multiple nested nodes, which themselves can contain multiple nested marks. Think bold or italic text within a heading. As such, it needs to be stored in a structured manner to help express this.

That's why the "content" of a heading isn't simple - it's not always just text that's there. By the way, I'm not quite sure I follow your example. Here's what a plain heading node looks like in its raw form:

[
   {
      "type":"heading",
      "attrs":{
         "level":1
      },
      "content":[
         {
            "type":"text",
            "text":"hello this is a title"
         }
      ]
   }
]

If you want just the text, you can access it through content[0].text. But as I've illustrated, this shouldn't really be relied on, for if I introduced some bold text, it will split the text.

[
   {
      "type":"heading",
      "attrs":{
         "level":1
      },
      "content":[
         {
            "type":"text",
            "text":"hello "
         },
         {
            "type":"text",
            "marks":[
               {
                  "type":"bold"
               }
            ],
            "text":"this"
         },
         {
            "type":"text",
            "text":" is a title"
         }
      ]
   }
]

In these scenarios, its far better to use node.renderHtml() which will render nested content for a node, rather than you having to loop through content

jan-dh commented 1 year ago

Ok, using the node.renderHtml()|striptags|raw does work. Thanks for the insights!