Skip to content

Instantly share code, notes, and snippets.

@pkra
Last active May 27, 2016 12:00
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save pkra/d633ca37c0eb644db83efc7af840273f to your computer and use it in GitHub Desktop.
Save pkra/d633ca37c0eb644db83efc7af840273f to your computer and use it in GitHub Desktop.
Quick MathJax-node wrapper for xhtml files containig MathML
'use strict';
var mjAPI = require('mathjax-node/lib/mj-single');
var typeset = mjAPI.typeset;
var fs = require('fs');
var libxmljs = require('libxmljs');
var argv = require('yargs')
.strict()
.usage('Usage: jats -i input.html -o output.html -f HTML', {
i: {
describe: 'specify input file',
alias: ('i', 'input')
},
o: {
describe: 'specify output file',
alias: ('o', 'output')
},
f: {
default: 'HTML',
describe: 'output format to generate -- HTML or SVG'
},
})
.demand(['i'])
.argv;
var inputFile = fs.readFileSync(argv.i);
var outputFile = argv.o
var xmlDocument = libxmljs.parseXmlString(inputFile);
mjAPI.config({
MathJax: {
menuSettings: {
semantics: true,
},
'displayAlign': 'left',
TeX: {
TagSide: 'left',
Macros: {
bigsqcap: '\\mmlToken{mo}{\u2a05}',
lefteqn: ['\\rlap{\\displaystyle{#1}}', 1]
// btran 8
}
}
}
});
mjAPI.start();
var mathNodes = xmlDocument.find('//*[name() = "math"]'); // cf. http://stackoverflow.com/a/10990253
// For TeX or ascii input, this might be
// var texMathNodes = xmlDocument.find('.//*[name()="span"][@class="math"]');
// For TeX, you'd need some delimiter handling
// e.g., use class="math block" without delimiters or use delimiters and check innerHTML for them.
var state = {}; // shared state among typeset requests (SVG <defs> for global sprite are stored here); cf useGlobalCache
for (var i = 0; i < mathNodes.length; i++) {
let index = i;
let element = mathNodes[index];
mjAPI.typeset({
math: element.toString(),
format: 'MathML',
svg: (argv.f === 'SVG'),
useGlobalCache: true,
state: state,
html: (argv.f === 'HTML'),
speakText: true
// TODO: handle state
}, function(data) {
if (data.errors) {
throw data.errors;
}
if (data.svg) {
console.log("Hello" + index);
var svgNode = libxmljs.parseXmlString(data.svg);
element.replace(svgNode.root());
}
if (data.html) {
var htmlNode = libxmljs.parseHtmlString(data.html);
element.replace(htmlNode.root());
}
// wrap up at end of loop
// (typesetting is async but guaranteed to be in series.)
if ((index + 1) === mathNodes.length) {
if (data.svg) {
var body = xmlDocument.find('//*[name() = "body"]')[0];
var globalSVG = libxmljs.parseXmlString("<svg style='display:none'>" + state.defs.outerHTML + "</svg>"); // the SVG sprite
body.addChild(globalSVG.root());
}
fs.writeFile(outputFile, xmlDocument, function(err) {
if (err) {
throw err;
} else {
console.log("It\'s saved!");
}
});
}
});
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment