mathjax / MathJax-node

MathJax for Node
Apache License 2.0
614 stars 96 forks source link

Using useGlobalCache how am I supposed to append defs to the DOM? #431

Closed MatTheCat closed 5 years ago

MatTheCat commented 5 years ago

I have the following code which processes a HTML file to replace math expressions using MathJax:

const fs = require("fs")
const { JSDOM } = require("jsdom")
const mathjax = require("mathjax-node")

let dom = new JSDOM(fs.readFileSync(`source/${file}`, { encoding: 'utf8' }))
let document = dom.window.document

let state = {}

Promise.all(Array.from(document.querySelectorAll('.math')).map((mathNode) => {
  return new Promise((resolve) => {
    mathjax.typeset({
      format: 'inline-TeX',
      math: mathNode.innerHTML,
      state: state,
      svg: true,
      useFontCache: true,
      useGlobalCache: true,
    }, (data) => {
      mathNode.innerHTML = data.svg
      resolve()
    })
  })
})).then(() => {
  if (state.defs) {
    // what now?
  }

  fs.writeFile(`public/${file}`, dom.serialize(), (err) => {
    if (err) throw err
  })
})

console.dir tells me state.defs is a SVGElement but if I try to append it somewhere I get

TypeError: Failed to execute 'appendChild' on 'Node': parameter 1 is not of type 'Node'.

How am I supposed to include defs to the DOM?

pkra commented 5 years ago

IIRC you'll have to serialize it to transfer it from one jsdom instance to the other.

MatTheCat commented 5 years ago

Oh that makes sense. Will try and update thanks @pkra

dpvc commented 5 years ago

You may be able to use importNode() to make a copy of state.defs into the new document. E.g., something like

document.body.appendChild(document.importNode(state.defs, true));

might work. I haven't actually tried it, though.

MatTheCat commented 5 years ago
document.body.appendChild(document.importNode(state.defs, true));

throws

TypeError: Failed to execute 'importNode' on 'Document': parameter 1 is not of type 'Node'.

But

let svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg')
svg.innerHTML = state.defs.outerHTML
document.body.appendChild(svg)

does the trick.

Thanks for the insight!