summaryrefslogtreecommitdiff
path: root/support/TeX4ht/source/tex4ht-mathjax.tex
blob: f4338eb6f58d979575e817d8de861f853018c1d5 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
% $Id: tex4ht-mathjax.tex 1553 2024-09-10 13:43:17Z michal_h21 $
% compile: latex tex4ht-mathjax
%
% Copyright 2018-2024 TeX Users Group
% Released under LPPL 1.3c+.
% See tex4ht-cpright.tex for license text.

\ifx \HTML\UnDef
   \def\HTML{mathjax-latex-4ht} 
   \def\CONFIG{\jobname}
   \def\MAKETITLE{\author{Michal Hoftich}}
   \def\next{\input mktex4ht.4ht  \endinput}
   \expandafter\next
\fi

\input{common-code}
\input{common}
\input{tex4ht-cpright}

\<mathjax-latex-4ht\><<<
% mathjax-latex-4ht.4ht (|version), generated from |jobname.tex
% Copyright 2018-2024 TeX Users Group
|<TeX4ht copywrite|>
|<required packages|>
|<defined commands|>
\AtBeginDocument{%
|<configurations|>
|<mhchem configurations|>
|<restore environments|>
}
\endinput
>>>

We don't require additional packages anymore, as everything necessary is included
in LaTeX kernel now.
% \RequirePackage{etoolbox,expl3,environ}
\<required packages\><<<
>>>

The \verb|\alteqtoks| command prints the used LaTeX math code to the output document in 
verbatim. 

In the past, we used \verb|\detokenize|. The side effect of this is that detokeize inserts space
after each control sequence. This is completely valid TeX code, but earlier versions of
MathJax didn't like that, rendering resulted in error.

Fortunatelly, MathJax 3 supports these spaces, so we could remove regular expressions for space handling.
The original code was this:

% % convert \ { to \:{ 
% \regex_replace_all:nnN { \x{5C} \x{20} \x{7B} } { \x{5C} \x{3A} \x{7B} } \l_tmpa_tl
% % delete spaces before left brackets
% \regex_replace_all:nnN { \x{20} \x{7B} } { \x{7B} } \l_tmpa_tl
% % replace \\:{ back to \\ { -- this can be introduced by the previous regex
% \regex_replace_all:nnN { \x{5C} \x{5C}  \x{3A} \x{7B} } { \x{5C} \x{5C} \x{20} \x{7B} } \l_tmpa_tl


In July 2024, when I researched another issue, I've found that it is actually possible to avoid these 
extra spaces using LaTeX 3 commands. The inspiration comes from 
\Link[https://tex.stackexchange.com/a/44444/2891]this Bruno Le Foch\EndLink.
One ongoing issue is that newlines are not presented. But they weren't preserved with \verb|\detokenize|
either, so it shouldn't be a problem.

In September 2024 I found that the LaTeX 3 method of preserving spaces didn't work correctly for 
code like this: \verb|$\int   A f(x)\;dx$| -- the space between \verb|\int| and \verb|A| was removed,
so it ended like command \verb|\intA|. So we are moving back to \verb|\detokenize|.

This is the code that was promising, but didn't work in the end:

\begin{verbatim}
  % save tokens, but preserve spaces
  % https://tex.stackexchange.com/a/44444/2891
  \tl_set:Nn \l_tmpa_tl {#1}
  \regex_replace_all:nnN { . } { \c{string} \0 } \l_tmpa_tl
  \tl_set:Nx \l_tmpa_tl { \l_tmpa_tl }
\end{verbatim}


We still use regular expressions to escape invalid XML characters to entities, so it works only with LaTeX.

\<defined commands\><<<
\ExplSyntaxOn
\cs_new_protected:Npn \alteqtoks #1
{
  \tl_set:Ne \l_tmpa_tl {\detokenize{#1}}
  % % replace < > and & with xml entities
  \regex_replace_all:nnN { \x{26} } { &amp; } \l_tmpa_tl
  \regex_replace_all:nnN { \x{3C} } { &lt; } \l_tmpa_tl 
  \regex_replace_all:nnN { \x{3E} } { &gt; } \l_tmpa_tl
  % replace \par command with blank lines
  \regex_replace_all:nnN { \x{5C}par\b } {\x{A}\x{A}} \l_tmpa_tl
  \tl_set:Ne \l_tmpb_tl{ \l_tmpa_tl }
  \HCode{\l_tmpb_tl}
}
\ExplSyntaxOff

>>>

Provide configuration for MathJax

\<defined commands\><<<
\NewConfigure{MathJaxConfig}{1}
>>>

The MathJaxMacros configuration includes a file with TeX macro 
definitions, and include them at the beginning of each HTML page.
MathJax then interprets them, so they are available in math. 
This is an alternative to JavaScript method using MathJaxConfig.

The file cannot contain any other commands than newcommand,
all characters that could cause issues in the HTML parsing must
be escaped, so \verb|<| should became \verb|&lt;|, for example.

\<defined commands\><<<
\NewConfigure{MathJaxMacros}[1]{%
\Configure{@BODY}{\bgroup\NoFonts\ttfamily\detokenize{\(}%
  \special{t4ht*<#1}%
\detokenize{\)}\EndNoFonts\egroup}%
}
>>>

The following commands are used for patching of the standard math commands and
environments. They will then keep the LaTeX code unchanged.

\<defined commands\><<<

\long\def\AltlMath#1\){\expandafter\alteqtoks{\(#1\)}\)}
\long\def\AltlDisplay#1\]{\alteqtoks{\[#1\]}\]}
\long\def\AltMathOne#1${\alteqtoks{\(#1\)}$}
% this seems a bit hacky -- we need to skip some code inserted at the 
% beginning of each display math
\long\def\AltlDisplayDollars#1$${\alteqtoks{\[#1\]}$$}

\newcommand\VerbMathToks[2]{%
  \alteqtoks{\begin{#2}
    #1
  \end{#2}}%
}
>>>

In pictures, we want to use the original version of the math environments. Because we use
an agressive verbatim method for the environments, we cannot use the usual \verb'\HLet' method.
Instead, we save the original meaning, and user needs to restore it manually, using
the \verb'\RestoreMathJaxEnvironments' command.

\<defined commands\><<<
\ExplSyntaxOn
\seq_new:N\:savedmathjaxenvs

\newcommand\:savemathjaxenv[1]{%
  \seq_gput_right:Nn\:savedmathjaxenvs{#1}
  \expandafter\let\csname mathjax-#1\expandafter\endcsname\csname #1\endcsname%
  \expandafter\let\csname mathjax-end#1\expandafter\endcsname\csname end#1\endcsname%
}

% we must not reintroduce the matrix environmeint in TikZ, because it interferes with the \matrix command
\newcommand\:ignoretikzmatrix{\seq_remove_all:Nn\:savedmathjaxenvs{matrix}}

\newcommand\RestoreMathJaxEnvironment[1]{%
  \expandafter\let\csname #1\expandafter\endcsname\csname mathjax-#1\endcsname%
  \expandafter\let\csname end#1\expandafter\endcsname\csname mathjax-end#1\endcsname%
}

\newcommand\RestoreMathJaxEnvironments{%
  \seq_map_function:NN\:savedmathjaxenvs\RestoreMathJaxEnvironment%
}
\ExplSyntaxOff
>>>

The \verb|\VerbMath| command redefines environments to pass their content
verbatim to the HTML output.

The optional command can contain name of the counter that should be updated.
It will also use LaTeX 3 regular expressions to search for label commands.
Thanks to that, cross-referencing to the math environments should work.
It is a bit limited, for example subequations cannot work. There can be also
issues in books, where equation numbers are based on chapters, but MathJax
numbers them consecutively. In these cases, other mechanisms may be necessary.

\<defined commands\><<<
\ExplSyntaxOn
\cs_generate_variant:Nn \regex_extract_once:nnNTF {nV}
\newcommand\VerbMath[2][]{%
  \cs_if_exist:cTF{#2}{
    \:savemathjaxenv{#2}%
    \RenewDocumentEnvironment{#2}{+!b}{%
      \NoFonts\expandafter\VerbMathToks\expandafter{\detokenize{##1}}{#2}\EndNoFonts%
      \ifx\relax#1\relax\else%
      \refstepcounter{#1}%
      \regex_extract_once:nVNTF { label\s* \x{7B}([^\x{7D}]*)\x{7D}} {\l_tmpb_tl} \l_tmp_seq {\label{\seq_item:Nn\l_tmp_seq{2}}} {}%
      \fi
    }{}
  }{}%
}
\ExplSyntaxOff
>>>

The \verb|\fixmathjaxtoc| command is used for patching commands which should
keep their verbatim appearance in the TOC

\<defined commands\><<<
\def\fixmathjaxtoc#1{\Configure{writetoc}{\def#1{\detokenize{#1}}}}
>>>

This was meant to fix some commands in sectioning commands, but it is not
a good solution. Better is to define the problematic commands as robust.

\<not defined commands\><<<
\def\fixmathjaxsec#1{\def#1{\detokenize{#1}}}
\fixmathjaxsec\right
\fixmathjaxsec\left
>>>

Require verbatim math environments.

\<configurations\><<<
\VerbMath{subarray}
\VerbMath{smallmatrix}
\VerbMath{matrix}
\VerbMath{pmatrix}
\VerbMath{bmatrix}
\VerbMath{Bmatrix}
\VerbMath{vmatrix}
\VerbMath{Vmatrix}
\VerbMath{cases}
\VerbMath{subequations}
\VerbMath{aligned}
\VerbMath{alignedat}
\VerbMath{gathered}
\VerbMath{gather}
\VerbMath{gather*}
\VerbMath{alignat}
\VerbMath{alignat*}
\VerbMath{xalignat}
\VerbMath{xalignat*}
\VerbMath{xxalignat}
\VerbMath{align}
\VerbMath{align*}
\VerbMath{flalign}
\VerbMath{flalign*}
\VerbMath{split}
\VerbMath{multline}
\VerbMath{multline*}
\VerbMath[equation]{equation}
\VerbMath{equation*}
\VerbMath{math}
\VerbMath{displaymath}
\VerbMath{eqnarray}
\VerbMath{eqnarray*}
>>>

It is necessary to reset env configurations for multiline 
environments, because default TeX4ht configurations turn
them into pictures.

\<configurations\><<<
\ConfigureEnv{gather}{}{}{}{}
\ConfigureEnv{gather*}{}{}{}{}
\ConfigureEnv{multline}{}{}{}{}
\ConfigureEnv{multline*}{}{}{}{}
>>>


Fixes for tables of contents.

\<configurations\><<<
\fixmathjaxtoc\int
\fixmathjaxtoc\,
\fixmathjaxtoc\sin
\fixmathjaxtoc\cos
\fixmathjaxtoc\tan
\fixmathjaxtoc\arcsin
\fixmathjaxtoc\arccos
\fixmathjaxtoc\arctan
\fixmathjaxtoc\csc
\fixmathjaxtoc\sec
\fixmathjaxtoc\cot
\fixmathjaxtoc\sinh
\fixmathjaxtoc\cosh
\fixmathjaxtoc\tanh
\fixmathjaxtoc\coth
\fixmathjaxtoc\log
\fixmathjaxtoc\ln
\fixmathjaxtoc\sum
\fixmathjaxtoc\(
\fixmathjaxtoc\)
\fixmathjaxtoc\begin
\fixmathjaxtoc\end
\fixmathjaxtoc\\
\fixmathjaxtoc\exp
\fixmathjaxtoc\left
\fixmathjaxtoc\right
>>>

\<mhchem configurations\><<<
\@ifpackageloaded{mhchem}{%
\def\:tempa#1{\texttt{\detokenize{\(\ce{#1}\)}}}
\HLet\ce\:tempa
}{}
>>>

Restore environments redefined to produce verbatim output to their
original meaning in the picture mode. Otherwise math cannot work
inside TikZ etc.

\<restore environments\><<<
\@ifpackageloaded{tikz}{%
\tikzset{every picture/.append code={\:ignoretikzmatrix\RestoreMathJaxEnvironments}} 
}{}
>>>

\endinput