Xzya/django-web-components

modify the slot render method, e.g. using markdownify

Closed this issue · 4 comments

Hi Xzya, thanks for this wonderful piece of software. I have an idea, and would like to hear if you'd find this useful, I did not find a way of achieving it.

Would it be possible to modify the rendering for each block in dwc? In short, I'd like to have the inner_block of a component render Markdown, e.g. using the markdownify filter. I think this must somehow be done in the render_slot method.

Would it be possible to add a customization there somehow?

I think this would be a helpful addon. It would enable component slots to be written in Markdown, uppercase etc.

Or am I overlooking something completely and it is easy to do?

Hello,

If I understand correctly, you want to have a component who's content (inner_block) should be converted from markdown to HTML (or the other way around), e.g.

{% some_component %}
	**This is bold text**

	*This is italic text*
{% endsome_component %}

<!-- Will be turned into this -->
<strong>This is bold text</strong>
<em>This is italic text</em>

My initial thought is that this can be easily achieved without the need of components, by creating a custom Django template tag, e.g.

# templatetags/app_tags.py
from django import template
from django.utils.safestring import mark_safe
import markdown
import textwrap

register = template.Library()


class MarkdownNode(template.Node):
    def __init__(self, nodelist):
        self.nodelist = nodelist

    def render(self, context):
        content = self.nodelist.render(context)
        content = textwrap.dedent(content)
        return mark_safe(markdown.markdown(content))


@register.tag(name="markdown")
def do_markdown(parser, token):
    nodelist = parser.parse(("endmarkdown",))
    parser.delete_first_token()
    return MarkdownNode(nodelist)
{% load app_tags %}

{% markdown %}
	**This is bold text**

	*This is italic text*
{% endmarkdown %}

<!-- Will be turned into this -->
<strong>This is bold text</strong>
<em>This is italic text</em>

This can then be used inside any Django template, including with components, e.g.

{% some_component %}
	{% markdown %}
		**This is bold text**
	
		*This is italic text*
	{% endmarkdown %}
{% endsome_component %}

Does this make sense? Or am I misunderstanding your use case?

Yes, this would be possible, but adds visual clutter. I'd like to have a component where the inner_block, or the header or foo slot is rendered in a special way. Markdown would be one (but very common) one.

I think this would be good to implement in a more generic way than just inner_block -> markdown...

With your example, I would have to write the templatetags again and again in each component's render tags, so this is not DRY.

Xzya commented

Hello,

You could also wrap the render_slot tag with the markdown block inside the component:

@component.register
def some_component(context):
    return CachedTemplate(
        """
        {% load app_tags %}

        <div>
            {% markdown %}
                {% render_slot slots.inner_block %}
            {% endmarkdown %}
        </div>
        """,
        name="some_component",
    ).render(context)

Now you can use the component without explicitly wrapping it in the markdown block:

{% some_component %}
	**This is bold text**

	*This is italic text*  
{% endsome_component%}

This should work with any slots, not just the inner_block.

Now that's a good idea. Thanks, for helping me out from being a blockhead. No need to do more.
There is no markdown/endmarkdown templatetag yet, but that would be easy to achieve.
I opened an issue at markdownify.