The problem is that TeX4ht doesn't have access to values saved by \label
inside math in the MathJax mode. All math contents are passed literally to MathJax, no expansion happens. Without label values, you cannot support \eqref
.
One way how to work around this issue is to reuse values from normal LaTeX run. They are stored in the .aux
file, and we can extract them and transform to some usable form. We can use the information form aux
files created by LaTeX in a make4ht
build file. We can post-process the generated HTML files using Lua filters, and insert link destinations for equations, and hyperlinks pointing to them instead of \eqref
.
I've created a Lua script that transform aux
files into Lua module that can be loaded from the make4ht
build file, getlabels.lua
:
-- execute by:
-- texlua getlabels.lua *.aux > labelmapping.lua
-- note that these aux files need to be produced by pdflatex,
-- as we need preserved value of referenced counters
-- this will contain all labels, their values and files where they were used
local map = {}
--
local function load_file(filename)
local f = io.open(filename, "r")
if not f then return nil, "cannot open file " .. filename end
local content = f:read("*all")
f:close()
return content
end
local function parse_aux(aux_filename)
local content, msg = load_file(aux_filename)
if not content then
print("Error: " .. msg)
return nil
end
local jobname = aux_filename:gsub(".aux$", "")
-- parse aux file for saved \newlabel
for label, refs in content:gmatch("\\newlabel{(.-)}(%b{})") do
-- get the first value in brackets. it holds the referenced counter.
local value = refs:match("{{([^{]-)}")
-- save mapping between label and correspoing value and file where it was used
if value then
map[label] = {value = value, jobname = jobname}
end
-- local
end
end
for _, filename in ipairs(arg) do
-- process all aux files and create mapping
parse_aux(filename)
end
-- print the mapping table in the form that is suitable for
-- loading by Lua's `require` statement
print "return {"
for label, properties in pairs(map) do
print(' ["' .. label .. '"] = {')
print(' value = "' .. properties.value .. '",')
print(' jobname = "' .. properties.jobname .. '"')
print(" },")
end
print "}"
It should be used like this:
pdflatex foo
pdflatex bar
texlua getlabels.lua *.aux > labelmapping.lua
This script transforms information from aux
files into Lua library, labelmapping.lua
:
return {
["truth"] = {
value = "1",
jobname = "sample"
},
}
The make4ht
build file, build.lua
then can use this new module:
local filter = require "make4ht-filter"
-- the labelmapping.lua file should be produced using:
-- texlua getlabels.lua *.aux > labelmapping.lua
-- it is necessary that this command is executed on files
-- produced by pdflatex (or lualatex or xelatex).
local mapping = require "labelmapping"
local process = filter {
-- add link destinations for \label
function(content, par)
-- it inserts destination after the nearest HTML tag that precedes \label
return content:gsub(">([^>]+)\\label%s*{(.-)}", function(start, label)
return "><a id='" .. label .. "'></a>" .. start .. "\\label{" .. label .."}"
end)
end,
--- handle \eqref
function(content, par)
local function handle_eqref(content, pattern)
-- this function loops for all \eqref commands and replaces them with
-- hyperlinks to the correct location. Hyperlink text is the counter value
-- as saved by latex.
return content:gsub(pattern, function(label)
local map = mapping[label]
-- don't process eqrefs that are not in the mapping table
if not map then return nil end
local htmlfile = map.jobname .. ".html"
-- don't use path to the html file if the link points inside the same file
if map.jobname == par.input then htmlfile = "" end
return string.format('(<a href="%s#%s">%s</a>)', htmlfile, label, map.value)
end)
end
-- \(\eqref{label}\)
local content = handle_eqref(content, "\\%(%s*\\eqref%s*{(.-)}%s*\\%)")
-- $\eqref{label}$
local content = handle_eqref(content,"%$%s*\\eqref%s*{(.-)}%s*%$")
return content
end
}
-- execute the filter chain for all generated HTML files
Make:match("html$", process)
It basically uses Lua gsub
function to insert link destinations to \label
and to replace \eqref
with correct value of the label and link to it.
Compile to HTML using:
make4ht -e build.lua foo "mathjax"
make4ht -e build.lua bar "mathjax"
The resulting foo.html
:
<p class='noindent'><a id='truth'></a>\begin {equation} \label{truth} 1 + 1 = 2 \end {equation}
</p><!-- l. 10 --><p class='noindent'>(<a href='#truth'>1</a>) refers to an obvious truth.
</p>
and bar.html
:
<p class='noindent'>(<a href='sample.html#truth'>1</a>) refers to an obvious truth. </p>
tex4ht
resolves the label text and the linked document throughxr-hyper
, constructs an html hyperlink, then generates the MathJax code for the label text, and outputs this together (something like<a href="foo.html#x1-2r1">[MathJax code for (1)]</a>
? Of course this would require that the user addsxr-hyper
and\externaldocument
, as in regular LaTeX.