MathJax event just before a latex expression is typset - javascript

I have a MathJax sample at Demo sample, which works as expected. All it does is typset the latex expressions within a div having an id of mathDiv.
I need to execute some custom logic when the third latex expression is about to be typset i.e. when ${ x } ^ { 4 } = 81 $ if $ x^4 - 9 =0 $ is going to be typset.
Question
Can I execute some custom JavaScript just before the above latex expression get typset by MathJax and if yes, then how would I do it?
I was thinking there might be some event model associated with MathJax typesetting, but couldn't find any in the docs.
The same demo sample code is as below.
<h2>Math Test</h2>
<div id="mathDiv">1. Solve for x $$X^2-1 = 8$$.
<br>2. Evaluate the following limit: $$\lim_{x \rightarrow b}{ (x-10) }$$
<br>3. Is ${ x } ^ { 4 } = 81 $ if $ x^4 - 9 =0 $ ?
</div>
<script src="//ajax.googleapis.com/ajax/libs/jquery/3.1.0/jquery.min.js"></script>
<script type="text/x-mathjax-config">
MathJax.Hub.Config({tex2jax: {inlineMath: [['$','$'], ['\\(','\\)']]}});
</script>
<script type="text/javascript"
src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.5/MathJax.js?config=TeX-AMS-MML_HTMLorMML"></script>
<script>
$(document).ready(function() {
MathJax.Hub.Queue(["Typeset", MathJax.Hub, "mathDiv"]);
});
</script>

There are signals for when math is typeset (see this example), though the signals for HTML-CSS output are a bit more complicate than for the other output formats.
But there is another approach that may work better for you. You can register a preprocessor that will run after the tex2jax preprocessor has located the math in the page, and that will put your wrapper around the math at that point. Then when the math is typeset, it will be inside the wrapper automatically.
Here is one example for that:
<style>
#math0 {color:red}
#math1 {color:blue}
#math2 {color:green; font-size: 200%}
#math3 {color:purple; font-size: 75%}
</style>
<script type="text/x-mathjax-config">
MathJax.Hub.Config({
tex2jax: {inlineMath: [['$','$'], ['\\(','\\)']]}
});
MathJax.Hub.Register.PreProcessor(function (element) {
//
// Get the math scripts created by tex2jax
//
var math = element.querySelectorAll('script[type^="math/tex"]');
//
// Loop through them in reverse (since this
// is a live list)
//
for (var i = math.length - 1; i >= 0; i--) {
//
// Get the script and any preview that preceeds it
//
var script = math[i];
var preview = script.previousSibling;
if (preview && preview.className !== 'MathJax_Preview') preview = null;
//
// Create the wrapper span and give it an id
// (If you will be typesetting more than once,
// you will need to keep a global id number
// and use that rather than i)
//
var span = document.createElement('span');
span.id = 'math'+i;
//
// Insert the wrapper in place of the script
// and append the preview and script to
// the wrapper.
//
script.parentNode.replaceChild(span,script);
if (preview) span.append(preview);
span.append(script);
}
},50); // use priority 50 so it follows the standard MathJax preprocessors
</script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.5/MathJax.js?config=TeX-AMS_CHTML-full"></script>
<h2>Math Test</h2>
<div id="mathDiv">1. Solve for x $$X^2-1 = 8$$.
<br>2. Evaluate the following limit: $$\lim_{x \rightarrow b}{ (x-10) }$$
<br>3. Is ${ x } ^ { 4 } = 81 $ if $ x^4 - 9 =0 $ ?
</div>
Here, the wrappers are styled to add color, and to scale the third and fourth expressions.
I hope the comments make it clear what is happening. This preprocessor will be run any time MathJax.Hub.Typeset() is called, so you can use that as normal.
Note that if the math is in the page initially, as it is here, there is no need to queue the Typeset() call by hand (as MathJax will typeset the page initially). If you are dynamically modifying the page, then you will need to do that.

Related

Is there a way to point to document.styleSheets[].cssRules[] using a rule name?

I want to change a specific class-property-value using Javascript, but by the class-name itself and not with any integer as a pointer (cssRules[i]) or looping all classes to find the matching "selectorText" value.
This is for changing the readable on-screen language within the page.
<style id="languages" class="languages" title="languages">
<!--
/* ... more styles ... */
.lang-ita { display : none; }
.lang-eng { display : none; }
/* ... more styles ... */
-->
</style>
<script language="javascript">
<!--
function fxSwitchLanguage(i)
{
/* ... more code ... */
document.getElementById('languages').sheet.cssRules[i].style.setProperty('display','block');
/* ... more code ... */
}
-->
</script>
<button onClick="fxSwitchLanguage(0);">ITA</button>
<button onClick="fxSwitchLanguage(1);">ENG</button>
<br>
<div class="lang-ita">CIAO!</div>
<div class="lang-eng">HELLO!</div>
Of course I set the previous language "display" to "none" before showing only the new selected one.
I would like to have ".cssRules['.lang-eng']" instead of ".cssRules[i]".
Since this document is shared and may be changed by someone else, I really DO prefer to point the class using its name and not any hard-coded integer for obvious stability reasons, moreover I do not want to use a "for" cycle to test the "selectorText" property of each written class (can be easily thousands).
I don't mind any Browsers differences (.cssRules or .rules).
I just want to know if it is possible to have it in the way I'd prefer to.
No, there is no CSSOM API to get a rule (or list of rules) by its selector string. Iterating them to find one is the only way. Of course you wouldn't do this in the fxSwitchLanguage function, everytime it is called, but outside of it, only once when the script is loaded. Then just store references to the relevant rules in a few constants, or a data structure.
But since your goal is to manipulate the rules by JavaScript, I'd go even further and also create them using javascript. That way, you can easily store a reference to them without iteration.
const {sheet} = document.getElementById('languages');
const rules = new Map(['eng', 'ita', 'esp'].map(lang => {
const rule = sheet.cssRules[sheet.insertRule(`.lang-${lang} {
display: none;
}`)]; // yes, it's weird, `insertRule` returns an index
return [lang, rule];
}));
let active = null;
function fxSwitchLanguage(l) {
if (active) rules.get(active).style.display = 'none';
rules.get(l).style.display = 'block';
active = l;
} // or build a toggle or whatever
<style id="languages">
</style>
<button onClick="fxSwitchLanguage('ita');">ITA</button>
<button onClick="fxSwitchLanguage('eng');">ENG</button>
<button onClick="fxSwitchLanguage('esp');">ESP</button>
<br>
<div class="lang-ita">CIAO!</div>
<div class="lang-eng">HELLO!</div>
<div class="lang-esp">HOLA!</div>
from comment here is the idea :
function fxSwitchLanguage(varlang) {
//* test if already created and remove it before update*/
if (document.contains(document.getElementById("langSetting"))) {
document.getElementById("langSetting").remove();
}
//* update language chosen*/
var newStyle = document.createElement("style");
newStyle.setAttribute("id", "langSetting"); //* put a mark on it */
var addContent = ".lang-" + varlang + "{display:block;}";
newStyle.appendChild(document.createTextNode(addContent));
var head = document.getElementsByTagName("head")[0];
head.appendChild(newStyle);
}
[class^='lang'] {display:none;}
<button onClick="fxSwitchLanguage('ita');">ITA</button>
<button onClick="fxSwitchLanguage('eng');">ENG</button>
<hr>
<p class="lang-ita">CIAO!</p>
<div class="lang-eng">HELLO!</div>

How being able to recognize javascript in codemirror?

I am creating a website in which I am trying to embed code blocks. Someone referred me to the CodeMirror library and thereafter I am trying to have some Javascript code in a code block .
I have incorporated the CodeMirror CSS and JS libraries into my HTMl
file and have created an instance of CodeMirror.
I managed to create a code block. But the code block doesn't apply any formatting/styling to the text in regards to whether it is Javascript or not
It just shows a code block with plain text. I have till now implemented the following code.
At the beginning I defined the following lines:
<link rel="stylesheet" href="codemirror-5.47.0/lib/codemirror.css">
<script src="codemirror-5.47.0/lib/codemirror.js"></script>
<script type="text/javascript" language="javascript">
window.load = function () {
var myCodeMirror = CodeMirror.fromTextArea(document.getElementById("codeeditor"), {
mode: "javascript",
lineNumbers: true
});
myCodeMirror.setSize(500, 300);
}
</script>
<textarea id="codeeditor" rows="20" cols="100">
var GetArray = function (Feature) {var dic = { "Bedrijfsvestigingen": ["bedrijfsvestigingen_Sbi2008_BedrijfsvestigingenNaarActiviteit_ALandbouw_BosbouwEnVisserij", "bedrijfsvestigingen_Sbi2008_BedrijfsvestigingenNaarActiviteit_B-fNijverheidEnEnergie", "bedrijfsvestigingen_Sbi2008_BedrijfsvestigingenNaarActiviteit_G_p_IHandelEnHoreca", "bedrijfsvestigingen_Sbi2008_BedrijfsvestigingenNaarActiviteit_H_p_JVervoer_InformatieEnCommunicatie", "bedrijfsvestigingen_Sbi2008_BedrijfsvestigingenNaarActiviteit_K-lFinancieleDiensten_OnroerendGoed", "bedrijfsvestigingen_Sbi2008_BedrijfsvestigingenNaarActiviteit_M-nZakelijkeDienstverlening", "bedrijfsvestigingen_Sbi2008_BedrijfsvestigingenNaarActiviteit_R-uCultuur_Recreatie_OverigeDiensten", "bedrijfsvestigingen_Sbi2008_BedrijfsvestigingenTotaal"]};
</textarea>
The result is thus a code block with plain text and thus not formatting have been applied on JavaScript code. In case someone knows a solution to this problem, it would be nice to have a pure Javascript solution, since for example I am not familiar with jQuery for example.
You seem to have forgotten to import the "mode"-file; and probably some addons.
var myCodeMirror = CodeMirror.fromTextArea(document.getElementById("codeeditor"), {
mode: "javascript",
lineNumbers: true
});
//myCodeMirror.setSize(500, 300);
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.47.0/codemirror.min.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.47.0/codemirror.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.47.0/mode/javascript/javascript.min.js"></script>
<textarea id="codeeditor" rows="20" cols="100">
var GetArray = function(Feature) {
var dic = {
"Bedrijfsvestigingen": [
"bedrijfsvestigingen_Sbi2008_BedrijfsvestigingenNaarActiviteit_ALandbouw_BosbouwEnVisserij",
"bedrijfsvestigingen_Sbi2008_BedrijfsvestigingenNaarActiviteit_B-fNijverheidEnEnergie",
"bedrijfsvestigingen_Sbi2008_BedrijfsvestigingenNaarActiviteit_G_p_IHandelEnHoreca",
"bedrijfsvestigingen_Sbi2008_BedrijfsvestigingenNaarActiviteit_H_p_JVervoer_InformatieEnCommunicatie",
"bedrijfsvestigingen_Sbi2008_BedrijfsvestigingenNaarActiviteit_K-lFinancieleDiensten_OnroerendGoed",
"bedrijfsvestigingen_Sbi2008_BedrijfsvestigingenNaarActiviteit_M-nZakelijkeDienstverlening",
"bedrijfsvestigingen_Sbi2008_BedrijfsvestigingenNaarActiviteit_R-uCultuur_Recreatie_OverigeDiensten",
"bedrijfsvestigingen_Sbi2008_BedrijfsvestigingenTotaal"
]
};
}
</textarea>

What is the aspect of Javascript and DOM scoping and assignment rules which prevent the code from working on the second block of html?

The html code is below is exported form orgmode and the Javascript function is meant to transform the <pre class="src src-emacs-lisp"> block to <pre><code class="lisp"> for it to be syntax-highlighted by highlightjs.
For some Javascript quirk I don't understand the function doesn't work on the second block. I thought it was the syntax of the html code in it, but when I rearrange the blocks, the fault always happens on the second. There must be something about the scoping rules of Javascript that I don't understand. The code to locate the blocks works fine and if I print them out without processing it works they all show up. It is when I apply the transformations that things go wrong. What feature of Javascript am I not comprehending?
The code which just prints them out works fine. They are all detected.
document.addEventListener('DOMContentLoaded', (event) => {
var lispBlocks = document.getElementsByClassName('src src-emacs-lisp');
alert(lispBlocks.length);
for (i=0;i<lispBlocks.length;i++){
var iHtml = lispBlocks[i].outerHTML;
//alert(lispBlocks[i].outerHTML);
alert(iHtml);
};
});
With the code that transforms them, things go south
document.addEventListener('DOMContentLoaded', (event) => {
var lispBlocks = document.getElementsByClassName('src src-emacs-lisp');
alert(lispBlocks.length);
var iHtml;
var lBlockText;
for (i=0;i<lispBlocks.length;i++){
//lispBlocks[i].className = '';
iHtml = lispBlocks[i].innerHTML;
alert(lispBlocks[i].innerHTML);
alert(lispBlocks[i].outerHTML);
lBlockText = '<pre><code class="lisp">' + iHtml + '</code></pre>';
alert(lBlockText);
lispBlocks[i].outerHTML = lBlockText;
//alert(lispBlocks[i].outerHTML);
//hljs.highlightBlock(lispBlocks[i]);
};
});
<!-- language: lang-html -->
<div class="org-src-container">
<pre class="src src-emacs-lisp">;; after splitting a frame automatically, switch to the new window (unless we
;; were in the minibuffer)
(setq split-window-preferred-function 'my/split-window-func)
(defun my/split-window-func (&optional window)
(let ((new-window (split-window-sensibly window)))
(if (not (active-minibuffer-window))
(select-window new-window))))
</pre>
</div>
<div class="org-src-container">
<pre class="src src-emacs-lisp"> (defun split-window--select-window (orig-func &rest args)
"Switch to the other window after a `split-window'"
(let ((cur-window (selected-window))
(new-window (apply orig-func args)))
(when (equal (window-buffer cur-window) (window-buffer new-window))
(select-window new-window))
new-window))
(advice-add 'split-window :around #'split-window--select-window)
</pre>
</div>
<div class="org-src-container">
<pre class="src src-emacs-lisp">;; settings for default frames
(add-to-list 'default-frame-alist '(font . FONT ))
;;or
;; set-face-atribute, ='default nil= for all existing frames and new frames
;; ='default t= for new frames only
;; function sets a number of attributes besides :font see docs
(set-face-attribute 'default nil :font FONT )
;;set frame font
(set-frame-font FONT nil t)
</pre>
</div>
The problem is that getElementsByClassName returns a live list
Therefore, when changing the outerHTML you change the list, because you've changed the class of the element that is in the live list
In the example, you'd have a list of elements, [a, b, c], and i == 0
You change a such that it disappears from the list, now the list is [b, c] but i increments to 1, so the next iteration changes c, skipping b
use
var lispBlocks = document.querySelectorAll('.src.src-emacs-lisp');
instead
Alternatively you could use a while loop
while(lispBlocks.length) {
iHtml = lispBlocks[0].innerHTML; // note, the hard coded `0` here
// etc
}

MathJax equation containing multiple summations with index

Background:
Here is how I am including the MathJax library in my page:
<script src='https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.4/MathJax.js?config=TeX-MML-AM_CHTML' async></script>
Problem:
The MathJax string (that I believe) will display what I want:
$$\sum_{s=1}^{1000} p_s \sum_{c=1}^{4} x_c$$
The closest MathJax string that I can get to work (display correctly):
$$\sum_{s=1}^{1000} p_s \sum_c^{4} x_c$$
As part of debugging, I have simplified the second summation down to 'x_c' but it still does not work. This leads me to believe that the problem is caused by the second summation index definition. When I try to add the 'c=1' bit to the second summation notation, it seems MathJax will no longer render the equation at all. This behavior seems strange since the first summation can have the defined index (e.g., 'i=1'). Any thoughts appreciated at this point.
As #Peter_Krautzberger has noted it looks like the Markdown parser has converted some text to italics. Which could be causing the issue.
The below snippet is to verify that the issue is not with MathJax.
<script async src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.5/MathJax.js?config=TeX-MML-AM_CHTML-full&latest"></script>
$$\sum_{s=1}^{1000} p_s \sum_{c=1}^{4} x_c$$
According to https://divadnojnarg.github.io/blog/mathjax/ MathJax \sum_ does not work correctly in markdown and you have to use \sum\_.
Latex rendering errors
There are some differences with classical Latex expressions and the syntax to use in a markdown document. For example, \sum_ does not render with Hugo and you should use \sum_ instead (notice the second backslash before the underscore).
Try escaping the underscores.
Either:
$$\sum\_{s=1}^{1000} p\_s \sum\_{c=1}^{4} x\_c$$
or
$$\sum\_{s=1}^{1000} p_s \sum\_{c=1}^{4} x_c$$
Might do the trick.
There is also some additional config mentioned in the article that may be required:
<script type="text/javascript" async
src="https://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML">
MathJax.Hub.Config({
tex2jax: {
inlineMath: [['$','$'], ['\\(','\\)']],
displayMath: [['$$','$$']],
processEscapes: true,
processEnvironments: true,
skipTags: ['script', 'noscript', 'style', 'textarea', 'pre'],
TeX: { equationNumbers: { autoNumber: "AMS" },
extensions: ["AMSmath.js", "AMSsymbols.js"] }
}
});
MathJax.Hub.Queue(function() {
// https://github.com/mojombo/jekyll/issues/199
var all = MathJax.Hub.getAllJax(), i;
for(i = 0; i < all.length; i += 1) {
all[i].SourceElement().parentNode.className += ' has-jax';
}
});
MathJax.Hub.Config({
// Autonumbering by mathjax
TeX: { equationNumbers: { autoNumber: "AMS" } }
});
</script>

How to call external javascript from URL inside function

I'm will try to make my previous question a little more clearer.
So I have to CPA offer from my CPA network using tag.
<script type="text/javascript" src="https://megadownloder.com/script_include.php?id=372715"></script>
and
<script type="text/javascript" src="https://megadownloder.com/script_include.php?id=372716"></script>
Now, I want it to randomly call and choose between the two when the user click the download button.
Example scenario:
When a user clicked download button, the <script type="text/javascript" src="https://megadownloder.com/script_include.php?id=372715"></script> will be called.
When a new user clicked download again the <script type="text/javascript" src="https://megadownloder.com/script_include.php?id=372716"></script> will show.
In ramdom manners.
I hope I make my question clear and you guys can help me. Thank you very much.
Just give your script tag an id and then read the src attribute.
With slice cut of the last character, and add 5 + (0 or 1 random) to the string again.
So the result will be 372715 or 372716 as the id.
If there is no JS active, the src is still valid, but only with this id: 372715
As a side note:
This won't work in your case. The time you manipulate the script src attribute, the script was already loaded. So you should do this on server side.
var dlScr = document.getElementById('dl-script');
dlScr.src = dlScr.src.slice(0, -1) + (5+Math.round(Math.random()));
<script id="dl-script" type="text/javascript" src="https://megadownloder.com/script_include.php?id=372715"></script>
You just need to round it up using Math.round. Math.random will give you a number between 0 and 1. Rounding it will ensure it will be 0 or 1. After that you can use it strait in the if statement, because 0 is false, and 1 - and everything not 0 actually - is true, in case of numbers. By negating you could get true/false instead: !(Math.round(Math.random())), of course in reverse order, but because it's random, it does not matter. But if that bothers you just add extra ! to negate it again like: !!(Math.round(Math.random())).
But if you need more than two outcomes, just multiply Math.random by the number of outcomes minus one. For example for a three way you could use: Math.round(Math.random() * 2). But then you'll have to use if statement like in your example.
In case you need 1 or 2 as outcomes, just add one to the random number like: Math.round(Math.random() + 1). This will return 1 or 2.
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>
<script>
function chose() {
// Rounding up like: Math.round(Math.random()).
// Will return 0 or 1.
// By negating you could get true/false instead:
// !(Math.round(Math.random()))
// !0 > true
// !1 > false
// For a three way (or more) random switch use:
// Math.round(Math.random() * [ways - 1]).
// Will return 0, 1 or 2.
// For a case where you want 1 or 2 as results:
// Math.round(Math.random() + 1).
// Will return 1 or 2.
return Math.round(Math.random() + 1);
}
function GetResult() {
if ( chose() === 1 ) {
OfferOne();
} else {
OfferTwo();
}
}
function loadScript ( id ) {
$('<scr'+'ipt type="text/javascript" src="https://megadownloder.com/script_include.php?id=' + id +'"></scr'+'ipt>').appendTo(document.head);
}
function OfferOne() {
loadScript(1000000);
}
function OfferTwo() {
loadScript(2000000);
}
</script>
If your code uses document.write() and you do not want it to overwrite the whole page if called after DOMReady, to be safe put the whole script above into the <head>, and use this loadScript function instead, to ensure synchronicity!
<script>
function loadScript ( id ) {
document.write('<scr'+'ipt type="text/javascript" src="https://megadownloder.com/script_include.php?id=' + id +'"></scr'+'ipt>');
}
</script>

Categories

Resources