Conditionally loading MathJax with GraffitiCMS

A couple of years ago I did a series of posts about TVM, the Time Value of Money (1, 2, 3). Because they were mathematical in nature, I had to write a few math expressions and equations. Way back when I’d have written them out in the Equation Editor in Word, and taken screenshots, but this time I decided to go for a browser-based solution: MathJax. In essence, I’d write the expressions in LaTeX format, such as x = \frac {-b \pm \sqrt{b^2 - 4ac}} {2a}, and have it rendered as:

\[ x = \frac {-b \pm \sqrt{b^2 - 4ac}} {2a} \]

Writing maths on chalkboard

Eek, maths on a chalkboard!

This was a great solution, except for one thing: I didn’t really write that many mathematical expressions in my blog posts and MathJax was being loaded and executed for every single page no matter whether there were expressions to be rendered or not. In other words, the specialized infrequent need was dominating the more general use of my blog. The majority of pages were slower to load than they should be. What I wanted was a way for the page renderer to load MathJax only when it was necessary.

The first step was to be able to mark those posts that used MathJax in some way. Enter GraffitiCMS’ Custom Fields. I set up a custom checkbox field called UsesMathJax and then went back over my posts to find those that needed MathJax processing of LaTeX expressions. (It wasn’t as bad as all that: in essence I regex-searched for \[, some characters, followed by \] or the equivalent with ordinary parentheses in a loop for each post.) This post has been so marked.

Now that was done, the fun begins. I had to alter the views I use for the site so that the rendering engine (it’s NVelocity) knows to output the <script> element that references the MathJax library. I started off with a simple variable, #NeedsMathJax, that I set false at the beginning of layout.view and then was checked to be true at the end of the <body> element.

<body class="Graffiti-$where">

  <div id="wrapper">

    #set($NeedsMathJax = false)

    $childContent

    <!-- Other HTML -->

  </div><!--end of wrapper -->

  <script type="text/javascript" src="$macros.ThemeFile('minifiedBoyet.js')"></script>

  #if($NeedsMathJax == true)
  <script type="text/javascript" src="http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML"></script>
  #end

  <!-- Other scripts -->

</body>

And then, for post.view, which is loaded by $childContent, I had this at the end of the HTML:

#if($post.Custom("UsesMathJax") == "on")
  #set($NeedsMathJax = true)
#end

(Note the string value that the custom checkbox field uses: “on” . Similarly if it’s unset it defaults to “off”.)

Except … it didn’t work. After a bit of investigation, it turns out that GraffitiCMS/NVelocity first evaluates $childContent before rendering layout.view. The value of $NeedsMathJax was being reset in layout.view after it had been properly set in post.view. The solution? Easy: just don’t have that initial setting of $NeedsMathJax to false. I was a little uncertain about removing it: after all, if the post doesn’t need MathJax then the variable won’t have been declared anywhere at all (let alone set to true) and what would happen then to the if statement? Turns out, not much, NVelocity seems to take the undefined variable in its stride (no exceptions are thrown) and certainly doesn’t evaluate it to be equal to true.

So you’ll be glad – I certainly am – to know that MathJax is now only loaded when it is needed. Like for this post.

Album cover for Sleeping With the PastNow playing:
John, Elton - Stone's Throw From Hurtin'
(from Sleeping With the Past)


Loading similar posts...   Loading links to posts on similar topics...

No Responses

Feel free to add a comment...

Leave a response

Note: some MarkDown is allowed, but HTML is not. Expand to show what's available.

  •  Emphasize with italics: surround word with underscores _emphasis_
  •  Emphasize strongly: surround word with double-asterisks **strong**
  •  Link: surround text with square brackets, url with parentheses [text](url)
  •  Inline code: surround text with backticks `IEnumerable`
  •  Unordered list: start each line with an asterisk, space * an item
  •  Ordered list: start each line with a digit, period, space 1. an item
  •  Insert code block: start each line with four spaces
  •  Insert blockquote: start each line with right-angle-bracket, space > Now is the time...
Preview of response