MathJax api to find math nodes prior to typesetting

37 views
Skip to first unread message

dustf...@starbucksoftware.com

unread,
Sep 22, 2016, 3:34:26 PM9/22/16
to MathJax Users
I would like to find all children of an element that contain what MathJax would see as valid math. I want to be able to call this function before any typesetting has been applied. Does MathJax support this or will I have to write my own function to do this? My preference would be to call a MathJax api since that way I could be confident that the returned nodes will be seen as math by MathJax whereas if I write my own I might potentially return nodes that MathJax does not see as math.

Thank you in advance!

Peter Krautzberger

unread,
Sep 23, 2016, 2:57:57 AM9/23/16
to mathja...@googlegroups.com
Hi,

It's not quite clear what you are after (your input, your expected result etc) but you should probably take a look at the various pre-processors, e.g., https://github.com/mathjax/MathJax/blob/master/unpacked/extensions/tex2jax.js

If all fails, you can re-use their code by extracting them from the core APIs, e.g. https://gist.github.com/pkra/1ae75a4bb86fbc3364c8d85675030223#file-tex2jax-js

Regards,
Peter.

On Thu, Sep 22, 2016 at 9:34 PM, <dustf...@starbucksoftware.com> wrote:
I would like to find all children of an element that contain what MathJax would see as valid math. I want to be able to call this function before any typesetting has been applied. Does MathJax support this or will I have to write my own function to do this? My preference would be to call a MathJax api since that way I could be confident that the returned nodes will be seen as math by MathJax whereas if I write my own I might potentially return nodes that MathJax does not see as math.

Thank you in advance!

--
You received this message because you are subscribed to the Google Groups "MathJax Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to mathjax-users+unsubscribe@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

dustf...@starbucksoftware.com

unread,
Sep 23, 2016, 1:00:06 PM9/23/16
to MathJax Users
hi Peter,

Thank you for your response. You make a good point that I did not provide any inputs or expected outputs so I will do that now.

Given this example Input:
<div id='myMathField" ng-bind-html="model">
  <p>Some latex math</p>
  <p>
    <br>
    \[x + 5 = -3 \]
  </p>
  <div>
    <math xmlns="http://www.w3.org/1998/Math/MathML">
    <infinity/>
    </math>
  </div>
</div>

I am looking for an api call that will return a collection of all the math nodes such as:
var elementsContainingMath = Math.Hub.getAllMathElements($('#myMathField')[0]);
console.log(
elementsContainingMath.length);
console.log(elementsContainingMath[0]);

Should output something like:
> 2
<p>
    <br>
    \[x + 5 = -3 \]
  </p>

My goal is to find all of the unprocessed math contained as descendants of a particular element on a page. I now that I can cook up my on regular expressions for this, which is what I am currently doing, but I would prefer to call a mathjax api to return these elements so that I am guaranteed to find exactly what mathjax would see as Math if it were processing the markup.

I will take a look at the source that you linked me and see if I can find what I am looking for there. I am just starting to look through the mathjax.js source as well.

Cheers! 
 

dustf...@starbucksoftware.com

unread,
Sep 23, 2016, 5:11:49 PM9/23/16
to MathJax Users
Hi Peter,

I took a look at the source for MathJax.Extensions.text2jax and I was able to come up with this hack for latex:
MathJax.Extension.tex2jax.isElementMath = function(element, el) { // copied and altered from MathJax.Extension.tex2jax.scanText

    if (element.nodeValue.replace(/\s+/, '') == '') {
        return element
    }
    var match, prev;
    this.search = { start: true };
    this.pattern = this.start;
    while (element) {
        this.pattern.lastIndex = 0;
        while (element && element.nodeName.toLowerCase() === '#text' &&
               (match = this.pattern.exec(element.nodeValue))) {
            if (this.search.start) {
                element = this.startMatch(match, element)
            } else {
                element = this.evalEndMatch(match, element);
                if (this.search.matched) {
                    return true;
                }
            }
        }

        if (element) {
            do {
                prev = element;
                element = element.nextSibling
            } while (element && (element.nodeName.toLowerCase() === 'br' ||
                                 element.nodeName.toLowerCase() === '#comment'));
            if (!element || element.nodeName !== '#text') {
                return false;
            }
        }
    }
    return false; //element;
};

MathJax.Extension.tex2jax.evalEndMatch = function (match,element) { //copied and altered from MathJax.Extension.tex2jax.endMath
    var search = this.search;
    if (match[0] == search.end) {
        if (!search.close || search.pcount === 0) {
            search.close = element;
            search.cpos = this.pattern.lastIndex;
            search.clen = (search.isBeginEnd ? 0 : match[0].length);
        }
        if (search.pcount === 0) {
            search.matched = true;
            this.switchPattern(this.start);
        }
    }
    else if (match[0] === "{") {search.pcount++}
    else if (match[0] === "}" && search.pcount) {search.pcount--}
    return element;
}

var getTextNodesIn = function (el) {
    return $(el).find(":not(iframe)").addBack().contents().filter(function () {
        return this.nodeType == 3;
    });
};

var getMathNodesIn = function(el) {
    var nodes = getTextNodesIn(el);
    var mathNodes = [];
    if (MathJax.Extension.tex2jax.createPatterns()) {
        _.forEach(nodes, function (node) {
            if (MathJax.Extension.tex2jax.isElementMath(node)) {
                mathNodes.push(node);
            }
        });
    }
    return mathNodes;
}


Then I can get all of my mathNodes like so:
var mathNodes = getMathNodesIn(($('#myMathField')[0]);

I should be able to come up with a similar solution for mathml. It is too bad that this functionality was not already part of mathjax because it would be nice to have a layer of abstraction from the extensions and simply call:
var mathNodes = MathJax.Hub.getMathNodesIn(($('#myMathField')[0]); //returns any type of math nodes depending on the loaded extensions. i.e. presentation mathml, content mathml, latex and possibly others.

Thank you for your direction!

Peter Krautzberger

unread,
Sep 24, 2016, 7:02:05 AM9/24/16
to mathja...@googlegroups.com
Hi,

Glad you could get something working. The reason the pre-processors do not provide such an API is relatively simple: they are pre-processors. The idea is that they make something easily findable (for MathJax itself). They genreate custom-type script tags, so the "usual" approach would be to run the pre-processor and simply querySelect for the script tags the pre-processor generates. But as before, whether that helps depends on whatever problem you are trying to solve.

Regards,
Peter

dustf...@starbucksoftware.com

unread,
Sep 28, 2016, 9:02:01 AM9/28/16
to MathJax Users
Hi,

My goal was to find all of the math nodes in a field before the containing element is rendered to the page then hide those nodes, place a loading spinner where the math was, and finally once each math node is typeset remove the loading spinner and display the math. I have it all working now, but I had to extend MathJax.Extension.mml2jax and MathJax.Extension.tex2jax to find the nodes. I watched MathJax.isReady to know when to search for math nodes to hide, I used MathJax.Hub.Register.MessageHook("New Math") to know when to remove the spinner and make the math node visible and finally I used MathJax.Hub.Register.MessageHook("End Process") to know when to broadcast to the rest of the application that all the math nodes in all of the elements on the page have been processed. It works well.

Thank you for your feedback Peter.

To unsubscribe from this group and stop receiving emails from it, send an email to mathjax-user...@googlegroups.com.

Peter Krautzberger

unread,
Sep 28, 2016, 9:20:12 AM9/28/16
to mathja...@googlegroups.com
Hi,

Thanks for the feedback. If you have the time, it would be great to hear why the `preview` configuration option of the pre-processors (which allows you to specify HTML snippets for a preview) was insufficient.

Best regards,
Peter.

To unsubscribe from this group and stop receiving emails from it, send an email to mathjax-users+unsubscribe@googlegroups.com.
Reply all
Reply to author
Forward
0 new messages