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} \]
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.
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.
_emphasis_
**strong**
[text](url)
`IEnumerable`
* an item
1. an item
> Now is the time...
Preview of response