Search code examples
javascriptwagtaildraftjs

How to excute JS on Wagtail's richtext field


This question follows a previous post on the issue.

If I correctly understood it from a previous post on the issue, it possible to execute JS script on richtext field/block as long as it isn't import content from external source, i.e. doesn't raises a security issue.

I tried to execute the following script on a richtextfield and/or richtextblock. This script runs on charblock and richtextfield, but without the richtext filter.

I feed the data through my Admin and the script fails to run. I wondered if executing JS on richtext is possible at all, and if so how should I define the settings so when it passed to Draft.JS it isn't blocked due to security considerations.

<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<script>
    $(document).ready(function() {
  $(".show-hide-btn").click(function() {
    var id = $(this).data("id");
    $("#half-" + id).toggle();//hide/show..
    $("#full-" + id).toggle();
  })
})
</script>



{% with text=page.intro %}
        {% if text|wordcount > 10 %}
    <p class="half-content" id="half-{{page.id}}">{{text|richtext|truncatewords:10}}<a data-id="{{page.id}}" href="javascript:void();" class="show-hide-btn"><br>Read more</a></p>
    <p class="full-content" id="full-{{page.id}}" style="display: none;">{{ text|richtext }}<a data-id="{{page.id}}" href="javascript:void();" class="show-hide-btn">Read less</a></p>
    {% else %}
        <p>
    {{ text }}
    </p>
    {% endif %}
    {% endwith %}

Solution

  • Wagtail intentionally filters out Javascript from rich text content to prevent users with limited permissions from inserting malicious code, but I don't think that's the issue here, since the Javascript code exists in the template and is being applied to a container element around the rich text content - it's not part of the rich text content itself.

    I think the problem is that rich text content contains <p> elements of its own. In HTML it's not valid to nest <p> elements inside other <p> elements, so when the browser encounters the first <p> element of the rich text content, it'll treat that as closing the <p class="half-content"> element and starting a new paragraph. As a result, your Javascript code will be showing and hiding an empty element, while the actual text content exists outside of that element.

    Changing the <p class="half-content"> and <p class="full-content"> elements to something like a <div> - which can contain <p> elements - should fix this.