MathJax TypeSetting - mathjax

I'm using MathJax for my personal blog (hosted on Github using Jekyll).
I notice that MathJax equations flicker when I refresh the page, the font was originally relatively small, and it looks thin, and less than half a second later, it would refresh and become much bolder.
I think I like the thin font style and smaller equations (that look much better inline with text) than the bolder version, so I try to configure it but failed. This is the documentation I'm looking at right now: http://docs.mathjax.org/en/latest/options/output-processors/HTML-CSS.html#configure-html-css
Here is my set up that's not working:
<script type="text/x-mathjax-config">
MathJax.Hub.Config({
tex2jax: {
inlineMath: [['$','$'], ['\\(','\\)']],
displayMath: [['$$','$$']],
processEscapes: true,
skipTags: ["script","noscript","style","textarea"],
preferredFont: "TeX",
scale: 90,
EqnChunkFactor: 1,
EqnChunk: 1,
EqnChunkDelay: 10
}
});
</script>
<script
type="text/javascript"
charset="utf-8"
src="https://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML">
</script>
<script
type="text/javascript"
charset="utf-8"
src="https://vincenttam.github.io/javascripts/MathJaxLocal.js">
</script>
On the side note, I also have this annoying error message MathJaxLocal.js:1 Uncaught ReferenceError: MathJax is not defined.
Would really appreciate if someone answers this question!!

You're asking two fairly different questions but let me wrap them together anyway.
flickering
The "flickering" is (probably) the PreviewHTML output )docs). This may be surprising but comes from the fact that the combined configuration file you're loading (TeX-AMS-MML_HTMLorMML) MathJax will run the PreviewHTML output first, then the HTML-CSS output (cf. the combined config docs and the fastpreview extension docs.
You can use the PreviewHTML output like any other output manually but keep in mind that it is a far less complete (but faster) output processor which does not require webfonts (but uses whatever Times-like fonts the system has).
So following the configuration docs, something like
MathJax.Hub.Config({
messageStyle: "none",
extensions: ["tex2jax.js"],
jax: ["input/TeX", "output/PreviewHTML"],
tex2jax: {
inlineMath: [ ['$','$'], ["\\(","\\)"] ],
displayMath: [ ['$$','$$'], ["\\[","\\]"] ],
processEscapes: true
skipTags: ["script","noscript","style","textarea"]
}
TeX: {
// whatever is in MathJaxlocal.js
}
});
MathJax not defined
The error is due to the fact that all scripts on the page are loaded asynchronously. Very likely, MathJaxlocal.js will load and execute before MathJax.js (since it's on the same domain).
You'll need to ensure that the configuration is loaded before MathJax is. Luckily, MathJax can do that for you cf the docs.
Put your configuration in MathJaxLocal.js and then only load
<script src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.5/MathJax.js?config=https://vincenttam.github.io/javascripts/MathJaxLocal.js"></script>
See the link on how to add other configuration files, including combined ones from the CDN - which would make sense if you want to go back to a full output processor as the combined configurations are packaged more efficiently.

Related

Typesetting MathJax in a string of HTML server-side

I was pretty easily able to get npm's mathjax-full working, for parsing TeX to CommonHTML:
const MathJax = await require("mathjax-full").init({
options: {
enableAssistiveMml: true
},
loader: {
source: {},
load: ["adaptors/liteDOM", "tex-chtml"]
},
tex: {
packages: ["base", "ams", "newcommand"]
},
chtml: {
fontURL: "https://cdn.jsdelivr.net/npm/mathjax#3/es5/output/chtml/fonts/woff-v2"
},
startup: {
typeset: false
}
});
MathJax.tex2chtmlPromise("x^2-2x+1", {
display: true,
em: 16,
ex: 8
}).then((node) => {
var adaptor = MathJax.startup.adaptor;
console.log(adaptor.outerHTML(node));
});
However, unlike typeset/typesetPromise, rather than a DOM node or string of HTML, this works with the TeX directly. Of course I could parse the page myself, finding MathJax delimiters (outside of code blocks) and passing the contents to tex2chtmlPromise, but this would have the potential of bugs or differences in behavior between a client-side preview using MathJax's typeset and the server-side rendered version.
I've looked around in the internals of the liteDOM adaptor quite a bit, but can't seem to find any way of setting the innerHTML of its body, if that would be the correct approach (which would allow me to just use typesetPromise normally).
Is there a recommended way to do what I'm trying to do, namely, take some HTML, and typeset it with MathJax without parsing for the delimiters myself?
The MathJax node demos repository includes examples of how to process an HTML page that should give you what you need. There are several different ways to load and call mathJax, so there are separate directories that illustrate each of them. You are using the "simple" approach, but may also want to look at the "component" and "direct" approaches. Look for files that end in -page.
The main idea for the simple case is to use the document option in the startup section of your MathJax configuration. This allows you to provide a serialized HTML string to be used as the document to be processed. So in your case, you could change
startup: {
typeset: false
}
to
startup: {
typeset: false,
document: html
}
where html is the HTML string to be processed. E.g.,
html = `
<!DOCTYPE html>
<html>
<head>
<title>My Document</title>
</head>
<body>
<p>
Some math: \(E = mc^2\).
</p>
</body>
</html>
`;
If you want the same invocation of your node app to be able to process multiple pages, then you will need to use the "direct" approach, as illustrated in direct/tex2chtml-page, and do these lines for each html file you want to process. You can reuse the same output jax, but should create a new InputJax and MathDocument for each page you process.

CSP script-src strict-dynamic with hash is blocking host domain

I have a react (create-react-app, not ejected) front end, node/express back end with the following csp config:
app.use(
helmet.contentSecurityPolicy({
directives: {
'script-src': [
"'self'",
"'sha256-47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU='",
"'sha256-10e801rrdN2Gq8YctvySwnSlugHJX+Xjgx1mhmij72w='",
"'sha256-e89fobGAetuB/6VgXYgfYEJo7toSqmridYOdrJoE6LU='",
"'strict-dynamic'",
'http:',
'https:',
"'unsafe-inline'",
],
'object-src': ["'none'"],
'base-uri': ["'none'"],
},
})
)
The hashes you see there were provided in previous csp errors. I located the three scripts, and used a hash tool and verified that the hashes in the above directives belong to those three scripts.
When I publish to heroku with this configuration, I test the url with https://csp-evaluator.withgoogle.com/ and it says everything is A-ok.
But my site will not render, and in chrome devtools I get the following CSP error, "Content Security Policy of your site blocks some resources":
As you can see, it's blocking resources from the host url, not 3rd party.
The scripts from the errors look like this, in index.html:
<script src="/static/js/runtime-main.11477cd6.js"></script>
<script src="/static/js/7.e1d80075.chunk.js"></script>
<script src="/static/js/main.c7392c1f.chunk.js"></script>
I visited the link provided with the error, "See how to set a strict CSP" and followed their instructions (to the letter) for hash based CSP, and only when that did not work, I added 'self', 'http:', 'https:', and 'unsafe-inline'. I think those are ok to leave there, they don't seem to be causing any problem. I even tried adding the actual domain, but nothing changed.
I have set the INLINE_RUNTIME_CHUNK=false environment variable, needed for CRA apps (in heroku config as well) which fixed some previous (different) problems, but now this is happening.
I thought maybe the problem was that the hash was made from the path to the script, literally src="/path/file.js" and not the actual script in that file, so I hashed those three scripts and added those hashes to the directives. Still not working.
Additionally, I noticed that with nonces, the examples show the script tag with an added nonce property, like <script src="something.js" nonce="noncerandom"></script> so, I tried to use 'integrity' with the hashes of the scripts, (not the file paths.) Now, there are no errors whatsoever, but also, nothing is rendering. There is nothing inside the root <div>s.
I give up! Please help. I have read at least 50 related questions on stackoverflow, followed every link recommended in the comments & answers, re-written and re-deployed 106 times according to heroku. (None of the problems happen on localhost, so I have to republish every time.)
Turns out, the script-src hashes AND the <script> tag integrity values must both be added, even when using middleware like helmet. I got the wrong impression that you didn't need to bother updating <script> tags unless you were setting your headers in a <meta> tag, but in fact, they are required in any case.
That means you have to manually replace all those hashes after every front end build, as those scripts will change. Not a big deal imo, just an extra manual chore during development. There's probably a package for that somewhere.
Here's what my helmet config ended up looking like:
app.use(
helmet.contentSecurityPolicy({
directives: {
'img-src': [
"'self'",
'data:',
'flagcdn.com',
'upload.wikimedia.org',
'openweathermap.org',
'hereapi.com',
'js.api.here.com',
],
'default-src': ["'none'"],
'script-src': [
"'sha256-gpDxdDuBGxxl88r6aymWROliaETfsyODwU6dpFZyIUU='",
"'sha256-33dcmxHc726AphEOtauUa39NPzHtsEPzEAX8PKd8NU0='",
"'sha256-vqol01UCQbQtIbFsadt22MWtP/EzXBhlXJVTdE3Z0Nk='",
"'sha256-vnJfeIr7hNIEwFqAV/GfKdJDn1SeGTUHl87WXU7cOxA='",
"'strict-dynamic'",
],
'object-src': ["'none'"],
'base-uri': ["'none'"],
'connect-src': [
'sheltered-scrubland-08732.herokuapp.com',
'https://*.here.com:*',
'https://*.hereapi.com:*',
'blob:',
],
'worker-src': ["'self'", 'blob:'],
'manifest-src': ['https://sheltered-scrubland-08732.herokuapp.com'],
// 'require-trusted-types-for': [`'script'`], // cannot use. 'script' value requires further specifications which are a mystery to solve some other time.
},
})
)
And here's the <script> tags in index.html:
<script
src="/static/js/runtime-main.11477cd6.js"
integrity="sha256-gpDxdDuBGxxl88r6aymWROliaETfsyODwU6dpFZyIUU="
></script>
<script
src="/static/js/7.e1d80075.chunk.js"
integrity="sha256-33dcmxHc726AphEOtauUa39NPzHtsEPzEAX8PKd8NU0="
></script>
<script
src="/static/js/main.c7392c1f.chunk.js"
integrity="sha256-vqol01UCQbQtIbFsadt22MWtP/EzXBhlXJVTdE3Z0Nk="
></script>
To get those hashes, I copied and pasted the actual source code from runtime-main.11477cd6.js etc., into https://report-uri.com/home/hash. This is something I never read about ANYwhere, but it did not make sense to me to make a hash out of <script> tags with file paths. What would be the point of hashing a file path??? And in more than one article, they actually suggested using the hashes provided in the devtools csp error messages, which I discovered were made from the file path script tags, which is probably why nothing was working at first. smh.

Can MathJax just leave the page blank when it fails to parse math instead of showing it red?

When MathJax fails to recognize a symbol (like \lightning) it displays the contents in red.
Is there a possibility to just leave the tag blank instead?
The errorSettings block controls the error messages produced when there is an internal error in MathJax (the "Math Processing Error"). TeX parsing errors are controlled by the TeX noErrors and noUndefined extensions. You can change the color from red to black, for example, using the options for noUndefined. Place
<script type="text/x-mathjax-config">
MathJax.Hub.Config({
TeX: {noUndefined: {attribtues: {mathcolor: "black"}}}
});
</script>
in your HTML file before the script that loads MathJax.js itself.
Alternatively, if you really want unknown macros to be ignored completely, then you could use
<script type="text/x-mathjax-config">
MathJax.Hub.Register.StartupHook("TeX Jax Ready",function () {
MathJax.InputJax.TeX.Parse.Augment({csUndefined: function () {}});
},20);
</script>
to replace the function that handles undefined control sequences by one that does nothing.
See MathJax The Core Configuration Options. The errorSettings options describe how to change the responds to error.
After couple of hours I have found the solution:
For the debuggind step, you must register signals listener like this:
MathJax.Hub.signal.Interest(
function (message) {console.log(message)}
);
This listener listen on all signal, so you must find specyffic signal. In my case it was:
MathML Jax - parse error
When you have your signal you can register listener for that one, for eg.:
MathJax.Hub.Register.MessageHook("MathML Jax - parse error",function (message) {
console.log('error listener');
});

Behavior when async: false and true

I am using AMD way of coding and when I make async:false I don't see any difference in execution behavior i.e. making async true or false I see no difference.
Please have a look at code snippet below:
<html>
<script type="text/javascript" src="../../dojoroot/dojo/dojo.js" data-dojo-config="async:true, parseOnLoad:true"></script>
<script type="text/javascript">
require(["dojo/domReady!"], function(){
alert("I am inside DOM ready");
});
require(["dojo/ready"], function(ready){
ready(function(){
alert("I am inside ready");
});
});
</script>
<body>
some div's here
</body>
</html>
OUTPUT:
In both the case i see first "I am inside DOM ready" and then "I am inside ready" alert next.
Could you please explain what is the difference if I add async : true and async:false?
Thanks.
To answer your question, if async is set to a truthy value (true, 1, etc.), dojo/domReady and dojo/ready will be loaded when require is called. If async is not set, these modules are loaded immediately when dojo.js is loaded. So there is no impact on how your code executes, it’s just about when those modules become available for use.
This is snippet from Dojo AMD description:
For backwards-compatibility, the loader starts up in synchronous mode by default, which loads the Dojo base API automatically:
<script src="path/to/dojo/dojo.js"></script>
<script>
// the dojo base API is available here
</script>
To put the loader in the AMD mode, set the async configuration variable to truthy:
<script data-dojo-config="async: 1" src="path/to/dojo/dojo.js"></script>
<script>
// ATTENTION: nothing but the AMD API is available here
</script>
Note that you can only set the async flag before dojo.js is loaded, and that in AMD mode, neither Dojo Base nor any other library is automatically loaded - it is entirely up to the application to decide which modules/libraries to load.

Chrome Extension: Using addEventListener()

In the tutorial for migrating a Google Chrome Extension to Manifest Version 2, I am directed to Remove inline event handlers (like onclick, etc) from the HTML code, move them into an external JS file and use addEventListener() instead.
OK, I currently have a background.html page that looks like this…
<html>
<script type="text/javascript">
// Lots of script code here, snipped
…
</script>
<body onload="checkInMyNPAPIPlugin('pluginId');">
<object type="application/x-mynpapiplugin" id="pluginId">
</body>
</html>
Following another directive, I've moved that Lots of script code into a separate .js file, and following this directive, I need to remove the onload= from the body tag, and instead cal addEventListener() in my script code. I've tried several approaches, but am apparently guessing wrong. What will that code look like? In particular, upon what object do I invoke addEventListener()?
Thanks!
I normally use this for body onload event...
document.addEventListener('DOMContentLoaded', function () {
// My code here.. ( Your code here )
});
For somethings it is working.. but really, I think we should use..
window.addEventListener('load', function () {
document.getElementById("#Our_DOM_Element").addEventListener('change - or - click..', function(){
// code..
});
});

Resources