-
-
Notifications
You must be signed in to change notification settings - Fork 1.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
toggle not working after re-filling the parent div's innerHTML #2594
Comments
The It would be better to implement a version of Here is one such implementation: <script>
MathJax = {
loader: {load: ['[tex]/tagformat']},
tex: {
packages: {'[+]': ['tagformat', 'external-eqref']},
tagformat: {
//
// If the ID is already a URL, use it, otherwise construct the url as usual
//
url: (id, base) => (id.indexOf('#') >= 0 ? id : base + '#' + encodeURIComponent(id))
}
},
startup: {
ready() {
//
// These would be replaced by import commands if you wanted to make
// a proper extension.
//
const Configuration = MathJax._.input.tex.Configuration.Configuration;
const CommandMap = MathJax._.input.tex.SymbolMap.CommandMap;
const Label = MathJax._.input.tex.Tags.Label;
const BaseMethods = MathJax._.input.tex.base.BaseMethods.default;
//
// Create a command map to override \ref and \eqref
//
new CommandMap('external-eqref', {
ref: ['HandleRef', false],
eqref: ['HandleRef', true]
}, {
HandleRef(parser, name, eqref) {
//
// Get the label parameter (keeping parse position as it is)
//
const i = parser.i;
const label = parser.GetArgument(name);
parser.i = i;
//
// If the label is of the form url#tag and the label doesn't already exist
// split the url and tag
// create a label using the tag and a proper URL for the link
//
if (label.indexOf('#') >= 0 && !(parser.tags.allLabels[label] || parser.tags.labels[label])) {
const [url, tag] = label.split(/#/);
const id = parser.tags.formatId(tag);
parser.tags.labels[label] = new Label(tag, parser.tags.formatUrl(id, url));
}
//
// Call the original function to perform the reference
//
BaseMethods.HandleRef(parser, name, eqref);
}
});
//
// Create the package for the overridden macros
//
Configuration.create('external-eqref', {
handler: {macro: ['external-eqref']}
});
MathJax.startup.defaultReady();
}
}
}
</script> This could be made into a proper TeX extension that lives in its own file, if you wish. |
@dvpc, thanks a lot, var eqsLabelsArrayPerPage=[];
for(pageNum=0; pageNum<totalPageNumber; pageNum++){
var jax = MathJax.getAllJax("resultPage-"+pageNum);
var neWLabelsInPage=[];
for (var i=0, l=jax.length; i<l; i++) {
//alert(jax[i].math);
jax[i].math.replace(/\\label\{([^\}]+)\}/g, function(x,y){
neWLabelsInPage.push(y);
return false;
});
}
eqsLabelsArrayPerPage.push(neWLabelsInPage);
}
var eqOnWPVar;
result.innerHTML=result.innerHTML.replace(/(href\=\"\#mjx\-eqn\-([^\"]*)\")/g, function(x,y1,y2){
eqOnWPVar=eqsLabelsArrayPerPage.findIndex(function(x) {
return x.indexOf(y2) !== -1;
});
return y1+" onclick=\"currentPage="+eqOnWPVar+"; changePage();\"";
}); the second part of which is now replaced by var eqCitations=[];
result.innerHTML.replace(/(href\=\"\#mjx\-eqn\-([^\"]*)\")/g, function(x,y1,y2){
eqCitations=document.querySelectorAll("mrow[href='#mjx-eqn-"+y2+"']");
for(var i=0, len=eqCitations.length; i<len; i++){
eqCitations[i].parentNode.parentNode.parentNode.onclick=function(){
currentPage=eqsLabelsArrayPerPage.findIndex(function(subArray){
return subArray.indexOf(y2) !== -1;
});
changePage();
};
}
return false;
}); It is not efficient to re-evaluate the Thanks again, I very much appreciate the time you put in such conversations |
Well, here is a possible approach that might do what you are looking for with minimal overhead. It is all done within MathJax, so doesn't need to have extra code like what you have given above, but it does take a little bit of setup to make it work. There are three main components: a subclass of the standard tagging class that keeps track of the page that each labeled equation is on, a TeX configuration that overrides the I think that should do what you want (or at least give a framework for it). Here is a complete file that has several labeled equations with links to them in different pages. <!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta content="width=device-width, initial-scale=1" name="viewport"/>
<title>Page switching \eqref links</title>
<script src="https://polyfill.io/v3/polyfill.min.js?features=es6"></script>
<script>
let currentPage = 1;
MathJax = {
startup: {
ready() {
//
// These would be replaced by import commands if you wanted to make
// a proper extension.
//
const TagsFactory = MathJax._.input.tex.Tags.TagsFactory;
const AmsTags = MathJax._.input.tex.ams.AmsConfiguration.AmsTags;
//
// Subclass the AmsTags object to track page information
//
class PageTags extends AmsTags {
constructor() {
super();
this.page = null; // the div for the last page where we found an equation
this.pageNo = ""; // the number of that page
this.math = null; // the MathItem for the current equation
}
//
// Save the MathItem and do the usual startup.
//
startEquation(math) {
this.math = math;
super.startEquation(math);
}
//
// Check if there are labels for this equation.
// If so, find the page for this MathItem
// and save the page with the label information.
// The do the usual finishing up.
//
finishEquation(math) {
const labels = Object.keys(this.labels);
if (labels.length) {
const page = this.getPage();
labels.map((label) => {this.labels[label].page = page});
}
super.finishEquation(math);
}
//
// If there is a cached page div and this MathItem is in it, return its page number.
// Otherwise, look through the parents of the math until you find its page.
// If you found a page, cache it and get its number.
// Return the page number.
//
getPage() {
let node = this.math.start.node;
if (this.page && this.page.contains(node)) return this.pageNo;
while (node && (!node.id || node.id.substr(0,11) !== 'resultPage-')) {
node = node.parentNode;
}
if (node) {
this.page = node;
this.pageNo = node.id.substr(11);
}
return this.pageNo;
}
}
//
// These would be replaced by import commands if you wanted to make
// a proper extension.
//
const Configuration = MathJax._.input.tex.Configuration.Configuration;
const CommandMap = MathJax._.input.tex.SymbolMap.CommandMap;
const Label = MathJax._.input.tex.Tags.Label;
const ParseUtil = MathJax._.input.tex.ParseUtil.default;
//
// Create a command map to override \ref and \eqref to handle page changes.
//
new CommandMap('page-eqref', {
ref: ['HandleRef', false],
eqref: ['HandleRef', true]
}, {
//
// Copied from BaseMethods.HandleRef, and modified to add page information.
//
HandleRef(parser, name, eqref) {
//
// Get the label name and look up its data.
//
const label = parser.GetArgument(name);
let ref = parser.tags.allLabels[label] || parser.tags.labels[label];
//
// If none, then reprocess this item, if we are on the first pass,
// and use a blank label.
//
if (!ref) {
if (!parser.tags.refUpdate) {
parser.tags.redo = true;
}
ref = new Label();
}
//
// Get the tag string.
//
const tag = (eqref ? parser.tags.formatTag(ref.tag) : ref.tag);
//
// Create an mrow with the parsed tags contents and href link.
//
const node = parser.create('node', 'mrow', ParseUtil.internalMath(parser, tag), {
href: parser.tags.formatUrl(ref.id, parser.options.baseURL), 'class': 'MathJax_ref'
});
//
// If the page of the linked quation is not the same as our own equation,
// Add a page attribute to the mrow.
//
if (ref.page !== parser.tags.getPage()) {
node.attributes.set('data-page', ref.page);
}
parser.Push(node);
}
});
//
// Create the package for the overridden macros
//
Configuration.create('page-eqref', {
handler: {macro: ['page-eqref']},
tags: {page: PageTags}
});
//
// Do the normal setup (create the input and output jax and other objects)
//
MathJax.startup.defaultReady();
//
// The listener function for when a link goes to a different page:
// Unhide the linked page and hide the current one.
// Save the current page as the linked one.
//
const listener = function (event) {
const n = this.getAttribute('data-page');
document.getElementById('resultPage-' + n).classList.remove('hidden');
document.getElementById('resultPage-' + currentPage).classList.add('hidden');
currentPage = n;
};
//
// Add a post-filter to the output jax to look for links that are to different
// pages, add the event listener to the <a> element for the link, and
// propagate the page to the anchor where the listener can find it.
//
MathJax.startup.output.postFilters.add(({data}) => {
for (const link of data.querySelectorAll('[data-page]')) {
link.parentNode.addEventListener('click', listener, true);
link.parentNode.setAttribute('data-page', link.getAttribute('data-page'));
}
});
}
},
tex: {
packages: {'[+]': ['page-eqref']},
tags: 'page'
}
}
</script>
<script id="MathJax-script" async src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-svg.js"></script>
<style>
div {
border: 1px solid grey;
padding: .5em;
}
h1 {
font-size: 130%;
margin-top: 0;
}
.hidden {
display: none;
}
.spacer {
height: 40em;
width: 1em;
background-color: red;
margin: 1em 0;
border: none;
}
</style>
</head>
<body>
<div class="spacer"></div>
<div id="resultPage-1">
<h1>Page 1</h1>
A math formula:
$$E = mc^2. \tag{1}\label{eq1}$$
That is the formula.
We link to \eqref{eq3}.
</div>
<div id="resultPage-2" class="hidden">
<h1>Page 2</h1>
This page has a different formula:
$$x = {-b \pm \sqrt{b^2-4ac} \over 2a}. \tag{2}\label{eq2}$$
And a second one:
$$\frac{x+1}{x-1}. \tag{2.1}\label{eq2.1}$$
We link to \eqref{eq1}.
</div>
<div id="resultPage-3" class="hidden">
<h1>Page 3</h1>
This one has yet another formula:
$$f(a) = \frac{1}{2\pi i} \oint\frac{f(z)}{z-a}dz. \tag{3}\label{eq3}$$
We link to \eqref{eq2}, and \eqref{eq3}.
</div>
<div class="spacer"></div>
</body>
</html> The red bars above and below the math are just to make the page large enough to scroll so that you can see that the proper equation is being targeted. Note, however, that different browsers handle the scrolling to SVG positions slightly differently. I'm looking into improving the targeting so that it is more consistent, but that isn't yet ready. CommonHTML does better with that. In any case, see if that gets you more like what you want. |
I cannot appreciate enough the time and energy you put in answering the questions. I just saw your answer, sounds so amazing. It would take me some times, though, before I can apply the code you provided into my app. Thank you very much. |
No problem. It was an interesting project, and worth working out how it could be done, for future reference by others. |
I have a multi-page markdown editor which benefits the usage of Mathjax. For it being multi-page, the cross referencing of equations failed to work as expected automatically until I modified the code for \eqref{}, after being processed by Mathjax, so that in action it will first set the correct value to the target page, divert to the new page, then the reference works as expected. This works very well, but just recently I have discovered that the mouse pointer over the term to be toggled is changed as on a clickable area, whereas, clicking over it will cause nothing to happen.
this is a minimal example to reproduce it:
The problem arises because of the line:
result.innerHTML=result.innerHTML;
. It is now a trivial statement left for the sake of bug reproducibility, while in the real code I have something non-trivial of the kind:result.innerHTML=result.innerHTML.replace();
. I assumed it be a bug as everything else seemingly work as far as I have checked, except for the \toggle command.Thank you
The text was updated successfully, but these errors were encountered: