-
Notifications
You must be signed in to change notification settings - Fork 4
Expand file tree
/
Copy pathBuildSidebarJS.js
More file actions
125 lines (113 loc) · 5.38 KB
/
Copy pathBuildSidebarJS.js
File metadata and controls
125 lines (113 loc) · 5.38 KB
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
const fs = require("fs");
const { exec } = require("child_process");
const { promisify } = require("util");
const execPromise = promisify(exec);
function getMathJaxSetup() {
// REASON: MathJax has no built-in table/tabular/center/figure environments, so any
// LaTeX table hits "Unknown environment 'table'" on the client renderer, and long
// tables also fail every server renderer (the URL-encoded equation exceeds the GET
// limit) leaving users with no renderer that works (reported by a user 2026-05-16).
// The macros/environments below emulate the common text-mode constructs in math mode:
// - table/figure map to gathered and swallow the optional [h] placement arg
// (the 4th element '' marks the env's single arg as optional, per configmacros)
// - tabular maps to array, which shares the |c|l| column-spec syntax
// - caption becomes a centered text row inside the gathered; label/centering/
// noindent/vspace are display no-ops
// - toprule/midrule/bottomrule cover ChatGPT-generated booktabs tables
// configmacros (which reads 'macros'/'environments') and textmacros are already in
// tex-svg's default package set.
// REASON: preload the small upgreek, gensymb, and boldsymbol extensions. Their
// combined transfer is only a few kilobytes, and keeping the package list explicit
// is simpler and more deterministic than maintaining a second command-to-package
// autoload map. `bm` remains a compatibility spelling for the common LaTeX
// package's primary command; it delegates to MathJax's boldsymbol implementation
// rather than pretending to implement the full bm package.
//
// REASON: do not put the combined `tex-svg` component in loader.load. The component
// is loaded directly by the script tag below; asking the loader to load it again
// re-enters configuration startup. In the Google Apps Script iframe that exposed
// MathJax v3's `Package` getter collision and aborted every client render before
// tex2svgPromise existed.
return `
window.MathJax = {
loader: { load: ['[tex]/color', '[tex]/upgreek', '[tex]/gensymb', '[tex]/boldsymbol'] },
tex: {
packages: { '[+]': ['color', 'upgreek', 'gensymb', 'boldsymbol'] },
macros: {
bm: ['\\\\boldsymbol{#1}', 1],
centering: '',
caption: ['\\\\\\\\[0.5em]\\\\text{#1}', 1],
label: ['', 1],
emph: ['\\\\textit{#1}', 1],
toprule: '\\\\hline',
midrule: '\\\\hline',
bottomrule: '\\\\hline',
noindent: '',
vspace: ['', 1]
},
environments: {
table: ['\\\\begin{gathered}', '\\\\end{gathered}', 1, ''],
tabular: ['\\\\begin{array}{#1}', '\\\\end{array}', 1],
center: ['\\\\begin{gathered}', '\\\\end{gathered}'],
figure: ['\\\\begin{gathered}', '\\\\end{gathered}', 1, '']
}
},
svg: {
fontCache: 'none'
},
startup: {
typeset: false // Prevent auto-typesetting
},
options: {
enableAssistiveMml: false
}
};
`;
}
function wrapJS(sidebarJS, includeMathJax, sharedJS) {
const mathJaxSetup = includeMathJax ? getMathJaxSetup() : "";
const sharedBlock = includeMathJax && sharedJS ? `\n${sharedJS}` : "";
// REASON: pin MathJax 4.1.2. The prior v3 bundle crashes during configuration in
// Google Apps Script sidebars with "Cannot set property Package ... which has only
// a getter"; MathJax v4 fixes that exact getter-only configuration bug. Keep the
// version explicit so a future CDN release cannot silently change rendering.
//
// crossorigin="anonymous" makes the browser surface real error
// details (message/filename/lineno/stack) in window.onerror for this
// cross-origin script. Without it, every MathJax failure inside the sandboxed
// iframe gets reported as the opaque "Script error." — which dominated our
// Cloud Logging signal. The jsdelivr CDN serves the proper
// Access-Control-Allow-Origin header, so this is purely an opt-in on our side.
const mathJaxScript = includeMathJax
? '\n<script type="text/javascript" id="MathJax-script" async crossorigin="anonymous" src="https://cdn.jsdelivr.net/npm/mathjax@4.1.2/tex-svg.js"></script>'
: "";
return `<script src="//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<script>
${mathJaxSetup}${sharedBlock}
${sidebarJS}</script>${mathJaxScript}`;
}
async function compileTS() {
await execPromise("npx tsc --preserveConstEnums Sidebar.ts -t es2020 --lib es2020,dom --types google-apps-script,jquery --skipLibCheck");
}
// REASON: the MathJax equation preprocessing (depth-aware newlines, hline repair,
// gathered wrap) must behave identically in the Docs and Slides sidebars. It lives
// once in ../SidebarMathJaxShared.ts and is compiled + injected here rather than
// copy-pasted into each Sidebar.ts.
async function compileSharedTS() {
await execPromise("npx tsc --preserveConstEnums ../SidebarMathJaxShared.ts -t es2020 --lib es2020,dom --skipLibCheck");
}
async function buildSidebarJS() {
await compileTS();
const sidebarJS = fs.readFileSync("Sidebar.js", "utf8");
const sidebarHTML = fs.readFileSync("Sidebar.html", "utf8");
const includeMathJax = sidebarHTML.includes("data-mathjax-enabled");
let sharedJS = "";
if (includeMathJax) {
await compileSharedTS();
sharedJS = fs.readFileSync("../SidebarMathJaxShared.js", "utf8");
}
const wrapped = wrapJS(sidebarJS, includeMathJax, sharedJS);
// write out
fs.writeFileSync("SidebarJS.html", wrapped);
}
buildSidebarJS();