0

Is it possible to wait for Jinja2 to finish inserting all template elements before executing a certain script? I'm attempting to render some math using KaTeX on a page, that also contains a bunch of template blocks. However, the math is rendered before all of the template blocks are rendered by Jinja2, so any math in said blocks does not render.

I could set a timeout of, say, 5 seconds and execute the rendering script then (this works), but I'd rather use a more elegant solution. Using defer inside the <script> tags as instructed here does nothing, nor does

<script>
    document.addEventListener("DOMContentLoaded", function() {
        renderMathInElement(document.body, {
            // ...options...
        });
    });
</script>

What is the event that tells the browser a templating engine such as Jinja2 has finished its work? It certainly isn't DOMContentLoaded, based on the above.

Edit

Here is an example course implemented using the A+ LMS. The troublesome template can be found in the folder _templates. The default template uses MathJax, but since that particular library has some annoying features, such as being very slow when there is a lot of math to be rendered, I decided to use KaTeX instead. Here is my version of the template:

{% extends "aplus/layout.html" %}

{% block extrahead %}

<!--  MathJax (LaTex math)
<script type="text/javascript" async src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.5/MathJax.js?config=TeX-MML-AM_CHTML" data-aplus></script>
 -->

<!--  KaTeX (LaTeX math) -->

<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/katex@0.10.2/dist/katex.min.css" integrity="sha384-yFRtMMDnQtDRO8rLpMIKrtPCD5jdktao2TV19YiZYWMDkUR5GQZR/NOVTdquEx1j" crossorigin="anonymous" data-aplus>
<script defer type="text/javascript" src="https://cdn.jsdelivr.net/npm/katex@0.10.2/dist/katex.min.js" integrity="sha384-9Nhn55MVVN0/4OFx7EE5kpFBPsEMZxKTCnA+4fqDmg12eCTqGi6+BB2LjY8brQxJ" crossorigin="anonymous"  onload="console.log('Hello, this is KaTeX!');" data-aplus></script>
  <script data-aplus>
    function render_katex() {
      if (window.katex) {
          renderMathInElement(document.body,{delimiters: [
          {left: "\\[", right: "\\]", display: true},
          {left: "\\(", right: "\\)", display: false}]}
          );
        console.log("Math rendered.");
      } else {
        console.log("KaTeX not loaded.")
      };
    };
  </script>

<script defer type="text/javascript" src="https://cdn.jsdelivr.net/npm/katex@0.10.2/dist/contrib/auto-render.min.js" integrity="sha384-kWPLUVMOks5AQFrykwIup5lo0m3iMkkHrD0uJ4H5cjeGihAutqP0yW0J6dpFiVkI" crossorigin="anonymous" onload="setTimeout(render_katex,300);" data-aplus></script>


<!-- Custom course styles -->
<link rel="stylesheet"
      href="{{ pathto('_static/course.css', 1) }}"
      type="text/css"
      data-aplus />

<link rel="stylesheet"
      href="{{ pathto('_static/active_element.css', 1) }}"
      type="text/css"
      data-aplus />

{% endblock %}

Edit 2

A link to the full source of the page on Pastebin.

sesodesa
  • 1,473
  • 2
  • 15
  • 24
  • The order is: 1. Jinja2 renders the template 2. the resulting document is sent from server to client (browser) 3. client-side JavaScript starts to run - Whatever the issue is, it needs to be fixed server-side. Can you post Jinja2 template code that reproduces the issue? –  Jun 04 '19 at 11:48
  • @ChrisG I've edited my question and added relevant links + my version of the template causing issues. – sesodesa Jun 04 '19 at 12:06
  • Are you getting any console errors when you observe that not all math blocks are rendered? –  Jun 04 '19 at 12:20
  • None whatsoever. Just two few deprecation warnings concerning `onmozfullscreenchange` and `onmozfullxcreenerror` issued by `translate.js`. But like I said, there seems to be no issue, if I wait for at least a second (or ten on huge pages with lots of elements). – sesodesa Jun 04 '19 at 12:24
  • Can you look at the source in the browser (Ctrl+U) and paste it on pastebin or the like? The problem with your question is that it doesn't really contain code that reproduces the issue, which means debugging it is not possible. –  Jun 04 '19 at 12:51
  • @ChrisG Done. Put it on pastebin. – sesodesa Jun 04 '19 at 12:56
  • Got it, which math blocks don't render for you? –  Jun 04 '19 at 13:01
  • Looks like they're the ones inside the `exercise`-class `div`s. If there is no timeout set on autorender, only the very first integral outside of those `div`s in the page renders. – sesodesa Jun 04 '19 at 13:07
  • Ok, so like Question 1's `(x+1)³ = 27`? Because it does for me. –  Jun 04 '19 at 13:09
  • Well it works for me as well, as long as I'm loading the page directly with my browser, and not pushing it through the testing environment run on Docker Containers. When I do that, as in use the system as it's supposed to be used, the timeout required seems to be dependent on the number of `exercise` class `div`s on the page. – sesodesa Jun 04 '19 at 13:12
  • One thing I've noticed is that the source code contains lots of URLs correctly starting with `/static/...` which will most likely always work but also URLs starting with `http://localhost:8080/static/` which won't work on anything other than `localhost:8080` obviously. Not sure if that's the cause of the issue but probably worth looking into. –  Jun 04 '19 at 14:51

1 Answers1

-1

Okay, so I've come to the conclusion that the best option is to simply wait for the template to pass through Jinja2. How long should one wait? Well, that depends on how many exercises there are on a single page:

<!--  KaTeX (LaTeX math) -->

<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/katex@0.10.2/dist/katex.min.css" integrity="sha384-yFRtMMDnQtDRO8rLpMIKrtPCD5jdktao2TV19YiZYWMDkUR5GQZR/NOVTdquEx1j" crossorigin="anonymous" data-aplus>
<script defer type="text/javascript" src="https://cdn.jsdelivr.net/npm/katex@0.10.2/dist/katex.min.js" integrity="sha384-9Nhn55MVVN0/4OFx7EE5kpFBPsEMZxKTCnA+4fqDmg12eCTqGi6+BB2LjY8brQxJ" crossorigin="anonymous"  onload="console.log('Hello, this is KaTeX!');" data-aplus></script>
<script defer type="text/javascript" src="https://cdn.jsdelivr.net/npm/katex@0.10.2/dist/contrib/auto-render.min.js" integrity="sha384-kWPLUVMOks5AQFrykwIup5lo0m3iMkkHrD0uJ4H5cjeGihAutqP0yW0J6dpFiVkI" crossorigin="anonymous" data-aplus></script>

<script data-aplus>
  document.addEventListener("DOMContentLoaded", function() {

    const n_of_exercises = $(".exercise").length;
    // Using "let" here so that math would render also the first time a page is loaded
    const ms = 300;
    const render_time = n_of_exercises * ms;
    const minimum_render_time = 1200;

    if (render_time >= minimum_render_time) {

      setTimeout(function() {
        renderMathInElement(document.body,{delimiters: [
          {left: "\\[", right: "\\]", display: true},
          {left: "\\(", right: "\\)", display: false}]}
        );
      }, render_time);

    } else {

      setTimeout(function() {
        renderMathInElement(document.body,{delimiters: [
          {left: "\\[", right: "\\]", display: true},
          {left: "\\(", right: "\\)", display: false}]}
        );
      }, minimum_render_time);

    };

    console.log("Number of .exercise divs:" + n_of_exercises);
    console.log("Render time:" + render_time);


  });
</script>

It turns out that no matter how many exercises there are on a page, it still takes some minimum amount of time for things to happen. That is why there is a minimum_render_time specified. This was only tested on this particular page, so values might need to be moved around a bit in the future.

sesodesa
  • 1,473
  • 2
  • 15
  • 24
  • Again: you don't have to "wait for the template to pass through Jinja2". Any client-side JavaScript code cannot possibly start to execute before Jinja2 is finished rendering the template. This answer is a workaround at best, and doesn't solve the issue. –  Jun 06 '19 at 08:16