Maths support via MathJax

I saw some discussion on how to get Mathematics to display using Zola here. So I thought I would share my approach which may not be very “nice” but it works!

The problem with putting maths as TeX in a markdown document is that certain parts of the notation such as _ get interpreted in the markdown processor as italics instead of being left to be interpreted as maths.

My solution protect your TeX from the markdown processor by quoting it in backticks e.g. `$x^2$` or indenting it as a blockquote with double dollar signs for display maths.

$$
x^2
$$

I then use a bit of javascript to extract any maths that is stuck inside a <code> or a <pre> block and use MathJax to render it. It isn’t perfect and it works fairly well for my purposes but it does require you to use the backticks as well as dollar signs when writing your markdown files.

How to implement Add the following code to the <head> of your template. With MathJax 3 it is actually quite fast. If something as simple as protecting code between your maths markers from the markdown processing engine were built in it would be great but for now this works OK for me, I hope it might be a help to someone else in a similar situation.

		<!-- JS for MathJax -->
		<script>
		window.MathJax = {
		  tex: {
			inlineMath: [['$','$'], ['\\(','\\)']],
			displayMath: [ ['$$','$$'], ["\\[","\\]"], ]
		  },
		  startup: {
			ready: () => {
					// Function to iterate over all pre and code elements
					// if they contain TeX/LaTeX code for maths as defined
					// by the markers in tex settings above then copy their
					// textContent before them and remove the element from
					// the DOM. 
					
					// get pre and code elements
					var prelist = document.getElementsByTagName("pre");
					var codelist = document.getElementsByTagName("code");
					// get delimiters for inline and display math
					var inline = MathJax.config.tex.inlineMath;
					var display = MathJax.config.tex.displayMath;
					// start building  a RegExp for each of these math types
					var inlineRegexList = [];
					var displayRegexList =[];
					for(i=0;i<inline.length;i++) {
						// https://stackoverflow.com/questions/3446170/escape-string-for-use-in-javascript-regex
						delimLEsc = inline[i][0].replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&");
						//alert(delimLEsc);
						delimREsc = inline[i][1].replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&");
						inlineRegexList.push("("+delimLEsc+")((.|[\\r\\n\\t])*?)("+delimREsc+")");
					};
					for(i=0;i<display.length;i++) {
						// https://stackoverflow.com/questions/3446170/escape-string-for-use-in-javascript-regex
						delimLEsc = display[i][0].replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&");
						//alert(delimLEsc);
						delimREsc = display[i][1].replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&");
						displayRegexList.push("("+delimLEsc+")((.|[\\r\\n\\t])*?)("+delimREsc+")");
					};
					inlineRegExp = new RegExp(inlineRegexList.join("|"));
					displayRegExp = new RegExp(displayRegexList.join("|"));
					
					// iterate over pre elements applying RegExp
					// iterate "backwards" as we are removing elements!
					for (i=prelist.length; i>0; i--) {
						if(displayRegExp.test(prelist[i-1].textContent)) {
							var t = document.createTextNode(prelist[i-1].textContent);
							prelist[i-1].parentNode.insertBefore(t,prelist[i-1]);
							prelist[i-1].parentNode.removeChild(prelist[i-1]);
						}
					}
					// iterate over code elements applying RegExp
					// iterate "backwards" as we are removing elements!
					for (i=codelist.length; i>0; i--) {
						if(inlineRegExp.test(codelist[i-1].textContent)) {
							var t = document.createTextNode(codelist[i-1].textContent);
							codelist[i-1].parentNode.insertBefore(t,codelist[i-1]);
							codelist[i-1].parentNode.removeChild(codelist[i-1]);
						}
					}
			  // Now process the page in MathJax
			  MathJax.startup.defaultReady();
			}
		  }
		};
		</script>
		<script type="text/javascript" id="MathJax-script" async
		  src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-chtml.js">
		</script>

Actually this final script tag should be defer rather than async as the DOM needs to be loaded before all the relevant pre or code tags can be found. Funnily enough I didn’t have this problem with version 2 of MathJax because it was so much slower they DOM had always loaded when I used this method before. Now that MathJax is on version 3 is is so much faster.