5
5
*
6
6
*/
7
7
import { basename , join } from "path/mod.ts" ;
8
+ import {
9
+ kHtmlMathMethod ,
10
+ kSelfContained ,
11
+ kSelfContainedMath ,
12
+ } from "../../config/constants.ts" ;
8
13
9
14
import {
15
+ Format ,
10
16
FormatExtras ,
11
17
FormatTemplateContext ,
12
18
Metadata ,
13
19
} from "../../config/types.ts" ;
14
20
import { copyTo } from "../../core/copy.ts" ;
15
- import { TempContext } from "../../core/temp.ts" ;
21
+ import { PandocOptions , RenderFlags } from "./types.ts" ;
22
+ import * as ld from "../../core/lodash.ts" ;
23
+ import { isHtmlDocOutput , isRevealjsOutput } from "../../config/format.ts" ;
16
24
17
25
export const kPatchedTemplateExt = ".patched" ;
18
26
export const kTemplatePartials = "template-partials" ;
@@ -25,11 +33,11 @@ export function readPartials(metadata: Metadata) {
25
33
}
26
34
27
35
export async function stageTemplate (
36
+ options : PandocOptions ,
28
37
extras : FormatExtras ,
29
- temp : TempContext ,
30
38
userContext ?: FormatTemplateContext ,
31
39
) {
32
- const stagingDir = temp . createDir ( ) ;
40
+ const stagingDir = options . temp . createDir ( ) ;
33
41
const template = "template.patched" ;
34
42
35
43
const stageContext = (
@@ -61,7 +69,14 @@ export async function stageTemplate(
61
69
) ;
62
70
const userStaged = await stageContext ( stagingDir , template , userContext ) ;
63
71
if ( formatStaged || userStaged ) {
64
- return join ( stagingDir , template ) ;
72
+ // The path to the newly staged template
73
+ const stagedTemplatePath = join ( stagingDir , template ) ;
74
+
75
+ // Apply any patches now that the template is staged
76
+ applyTemplatePatches ( stagedTemplatePath , options . format , options . flags ) ;
77
+
78
+ // Return the path to the template
79
+ return stagedTemplatePath ;
65
80
} else {
66
81
return undefined ;
67
82
}
@@ -81,3 +96,136 @@ export function cleanTemplatePartialMetadata(
81
96
}
82
97
}
83
98
}
99
+
100
+ interface TemplatePatch {
101
+ searchValue : RegExp ;
102
+ contents : string ;
103
+ }
104
+
105
+ function applyTemplatePatches (
106
+ template : string ,
107
+ format : Format ,
108
+ flags ?: RenderFlags ,
109
+ ) {
110
+ // The patches to apply
111
+ const patches : TemplatePatch [ ] = [ ] ;
112
+
113
+ // make math evade self-contained for HTML and Reveal
114
+ if ( isHtmlDocOutput ( format . pandoc ) || isRevealjsOutput ( format . pandoc ) ) {
115
+ if (
116
+ ( ( flags && flags [ kSelfContained ] ) || format . pandoc [ kSelfContained ] ) &&
117
+ ! format . render [ kSelfContainedMath ]
118
+ ) {
119
+ const math = mathConfig ( format , flags ) ;
120
+ if ( math ) {
121
+ const mathTemplate = math . method === "mathjax"
122
+ ? mathjaxScript ( math . url )
123
+ : math . method == "katex"
124
+ ? katexScript ( math . url )
125
+ : "" ;
126
+
127
+ if ( mathTemplate ) {
128
+ patches . push ( {
129
+ searchValue : / \$ m a t h \$ / ,
130
+ contents : mathTemplate ,
131
+ } ) ;
132
+ }
133
+ }
134
+ }
135
+ }
136
+
137
+ // Apply any patches
138
+ if ( patches . length ) {
139
+ let templateContents = Deno . readTextFileSync ( template ) ;
140
+ patches . forEach ( ( patch ) => {
141
+ templateContents = templateContents . replace (
142
+ patch . searchValue ,
143
+ patch . contents ,
144
+ ) ;
145
+ } ) ;
146
+ Deno . writeTextFileSync ( template , templateContents ) ;
147
+ }
148
+ }
149
+
150
+ function mathConfig ( format : Format , flags ?: RenderFlags ) {
151
+ // if any command line math flags were passed then bail
152
+ if (
153
+ flags ?. mathjax || flags ?. katex || flags ?. webtex || flags ?. gladtex ||
154
+ flags ?. mathml
155
+ ) {
156
+ return undefined ;
157
+ }
158
+
159
+ const math = format . pandoc [ kHtmlMathMethod ] ;
160
+ if ( math === undefined || math === "mathjax" ) {
161
+ return {
162
+ method : "mathjax" ,
163
+ url : "https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-chtml-full.js" ,
164
+ } ;
165
+ } else if ( math === "katex" ) {
166
+ return {
167
+ method : "katex" ,
168
+ url :
"https://cdn.jsdelivr.net/npm/[email protected] /dist/" ,
169
+ } ;
170
+ } else if ( ld . isObject ( math ) ) {
171
+ const mathMethod = math as { method : string ; url : string } ;
172
+ if (
173
+ ( mathMethod . method === "mathjax" || mathMethod . method === "katex" ) &&
174
+ typeof ( mathMethod . url ) === "string"
175
+ ) {
176
+ return mathMethod ;
177
+ }
178
+ }
179
+ }
180
+
181
+ function mathjaxScript ( url : string ) {
182
+ return `
183
+ <script>
184
+ (function () {
185
+ var script = document.createElement("script");
186
+ script.type = "text/javascript";
187
+ script.src = "${ url } ";
188
+ document.getElementsByTagName("head")[0].appendChild(script);
189
+ })();
190
+ </script>
191
+ ` ;
192
+ }
193
+
194
+ function katexScript ( url : string ) {
195
+ url = url . trim ( ) ;
196
+ if ( ! url . endsWith ( "/" ) ) {
197
+ url += "/" ;
198
+ }
199
+ return `
200
+ <script>
201
+ document.addEventListener("DOMContentLoaded", function () {
202
+ var head = document.getElementsByTagName("head")[0];
203
+ var link = document.createElement("link");
204
+ link.rel = "stylesheet";
205
+ link.href = "${ url } katex.min.css";
206
+ head.appendChild(link);
207
+
208
+ var script = document.createElement("script");
209
+ script.type = "text/javascript";
210
+ script.src = "${ url } katex.min.js";
211
+ script.async = false;
212
+ script.addEventListener('load', function() {
213
+ var mathElements = document.getElementsByClassName("math");
214
+ var macros = [];
215
+ for (var i = 0; i < mathElements.length; i++) {
216
+ var texText = mathElements[i].firstChild;
217
+ if (mathElements[i].tagName == "SPAN") {
218
+ window.katex.render(texText.data, mathElements[i], {
219
+ displayMode: mathElements[i].classList.contains('display'),
220
+ throwOnError: false,
221
+ macros: macros,
222
+ fleqn: false
223
+ });
224
+ }
225
+ }
226
+ });
227
+ head.appendChild(script);
228
+ });
229
+ </script>
230
+ ` ;
231
+ }
0 commit comments