Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How to declare twig markup for a custom node or mark? #291

Open
tomkiss opened this issue Mar 18, 2024 · 1 comment
Open

How to declare twig markup for a custom node or mark? #291

tomkiss opened this issue Mar 18, 2024 · 1 comment

Comments

@tomkiss
Copy link

tomkiss commented Mar 18, 2024

Question

I've read through the user guides for custom nodes and marks, but I am left wondering - is it possible to declare custom twig markup for a mark, without getting caught up in repetition in twig?
I have some very twig specific shared code that I'd like to use in my custom mark output (in a different manner to the editor).

For example, here I can render my custom mark with whatever twig code I like:

  {% for node in vizyBlocks %}
      {% if node.type == 'paragraph' %}
        <p>
          {% for nodeContent in node.content %}
            {% if nodeContent.type == "customMark" %}
              {# Some very twig specific markup here #}
            {% else %}
              {{ nodeContent.renderHtml() }}
            {% endif %}
          {% endfor %}
        </p>
      {% else %}
        {{ node.renderHtml() }}
      {% endif %}    
  {% endfor %}

Some markup like that would work fine, until I use the mark in a listItem, at which point I would need to add another place to parse it:

  {% for node in vizyBlocks %}
      {% if node.type == 'paragraph' %}
        <p>
          {% for nodeContent in node.content %}
            {% if nodeContent.type == "customMark" %}
              {# My very twig-specific markup here #}
            {% else %}
              {{ nodeContent.renderHtml() }}
            {% endif %}
          {% endfor %}
        </p>
      {% elseif node.type == 'orderedList' or node.type == 'bulletList' %}
        {{ node.type == 'orderedList' ? "<ol>" : "<ul>" }}
          {% for nodeContent in node.content %}
            {% if nodeContent.type == "listItem" %}
              <li>
              {% for nestedNodeContent in nodeContent.content %}
                {% if nestedNodeContent.type == "customMark" %}
                  {# My very-twig specific markup here #}
                {% else %}
                  {{ nestedNodeContent.renderHtml() }}
                {% endif %}
              {% endfor %}
              </li>
            {% else %}
              {{ nodeContent.renderHtml() }}
            {% endif %}
          {% endfor %}
          {{ node.type == 'orderedList' ? "</ol>" : "</ul>" }}
      {% else %}
        {{ node.renderHtml() }}
      {% endif %}    
  {% endfor %}

And then suddenly we have repetition, not to mention some horrible conditional markup. Plus, there will be other nested occurances of the mark where even further checking is required (table cell or similar elements).

Would there be a cleaner way to achieve this?

Additional context

No response

@engram-design
Copy link
Member

The short answer is - not really. That's because of how the ProseMirror schema and structure works for nodes and marks. They aren't self-contained, as they need to factor in multiple marks.

Conceptually, you have a Node (paragraph) with text, and multiple marks (bold and italic). You need to wrap the text with both bold and italic tags, which are then wrapped with a paragraph. For example

So while it would be neat to be able to provide a Twig template for just the modular mark or node, that's not currently possible until I can come up with a nice way to handle things.

Now technically, a mark doesn't have content, it's the parent node that has the content, so you can handle things somewhat, it depends on how custom you want to go with your content in your comment below. Maybe it's a better case for a Node over a Mark?

This will allow you to ditch the:

{% if nodeContent.type == "customMark" %}
  {# My very twig-specific markup here #}
{% else %}
  {{ nodeContent.renderHtml() }}
{% endif %}

And just use:

{{ nodeContent.renderHtml() }}

This can be achieved by overriding the getTag() function for a node/mark

You could also use the renderOpeningTag() and renderClosingTag() for more flexibility (just in case you want to add multiple tags, static content, any HTML you require).

It's on my list to improve the modularity of templates for nodes and marks, and make things a little more Craft-friendly, so you don't have to worry about the intricacies of dealing with ProseMirror's schema for this sort of thing.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants