pageproof 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (68) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +90 -0
  3. package/THIRD_PARTY_NOTICES.md +74 -0
  4. package/assets/SKILL.md +58 -0
  5. package/assets/_paged.css +82 -0
  6. package/assets/chicago.csl +6006 -0
  7. package/assets/default.html +496 -0
  8. package/assets/doublespaced.css +8 -0
  9. package/assets/european-journal-of-international-law.csl +404 -0
  10. package/assets/favicon.svg +5 -0
  11. package/assets/footnotes-inline.lua +56 -0
  12. package/assets/latex.css +142 -0
  13. package/assets/msword.css +100 -0
  14. package/assets/numbered.css +75 -0
  15. package/assets/vendor/mathjax/LICENSE +202 -0
  16. package/assets/vendor/mathjax/sre/mathmaps/af.json +146 -0
  17. package/assets/vendor/mathjax/sre/mathmaps/base.json +140 -0
  18. package/assets/vendor/mathjax/sre/mathmaps/ca.json +140 -0
  19. package/assets/vendor/mathjax/sre/mathmaps/da.json +140 -0
  20. package/assets/vendor/mathjax/sre/mathmaps/de.json +146 -0
  21. package/assets/vendor/mathjax/sre/mathmaps/en.json +158 -0
  22. package/assets/vendor/mathjax/sre/mathmaps/es.json +140 -0
  23. package/assets/vendor/mathjax/sre/mathmaps/euro.json +32 -0
  24. package/assets/vendor/mathjax/sre/mathmaps/fr.json +146 -0
  25. package/assets/vendor/mathjax/sre/mathmaps/hi.json +146 -0
  26. package/assets/vendor/mathjax/sre/mathmaps/it.json +146 -0
  27. package/assets/vendor/mathjax/sre/mathmaps/ko.json +146 -0
  28. package/assets/vendor/mathjax/sre/mathmaps/nb.json +146 -0
  29. package/assets/vendor/mathjax/sre/mathmaps/nemeth.json +125 -0
  30. package/assets/vendor/mathjax/sre/mathmaps/nn.json +146 -0
  31. package/assets/vendor/mathjax/sre/mathmaps/sv.json +146 -0
  32. package/assets/vendor/mathjax/sre/speech-worker.js +1 -0
  33. package/assets/vendor/mathjax/tex-mml-chtml-nofont.js +18 -0
  34. package/assets/vendor/mathjax-fonts/LICENSE +202 -0
  35. package/assets/vendor/mathjax-fonts/mathjax-tex-font/chtml/woff2/mjx-tex-b.woff2 +0 -0
  36. package/assets/vendor/mathjax-fonts/mathjax-tex-font/chtml/woff2/mjx-tex-bi.woff2 +0 -0
  37. package/assets/vendor/mathjax-fonts/mathjax-tex-font/chtml/woff2/mjx-tex-brk.woff2 +0 -0
  38. package/assets/vendor/mathjax-fonts/mathjax-tex-font/chtml/woff2/mjx-tex-c.woff2 +0 -0
  39. package/assets/vendor/mathjax-fonts/mathjax-tex-font/chtml/woff2/mjx-tex-cb.woff2 +0 -0
  40. package/assets/vendor/mathjax-fonts/mathjax-tex-font/chtml/woff2/mjx-tex-f.woff2 +0 -0
  41. package/assets/vendor/mathjax-fonts/mathjax-tex-font/chtml/woff2/mjx-tex-fb.woff2 +0 -0
  42. package/assets/vendor/mathjax-fonts/mathjax-tex-font/chtml/woff2/mjx-tex-i.woff2 +0 -0
  43. package/assets/vendor/mathjax-fonts/mathjax-tex-font/chtml/woff2/mjx-tex-lo.woff2 +0 -0
  44. package/assets/vendor/mathjax-fonts/mathjax-tex-font/chtml/woff2/mjx-tex-m.woff2 +0 -0
  45. package/assets/vendor/mathjax-fonts/mathjax-tex-font/chtml/woff2/mjx-tex-mi.woff2 +0 -0
  46. package/assets/vendor/mathjax-fonts/mathjax-tex-font/chtml/woff2/mjx-tex-n.woff2 +0 -0
  47. package/assets/vendor/mathjax-fonts/mathjax-tex-font/chtml/woff2/mjx-tex-ob.woff2 +0 -0
  48. package/assets/vendor/mathjax-fonts/mathjax-tex-font/chtml/woff2/mjx-tex-os.woff2 +0 -0
  49. package/assets/vendor/mathjax-fonts/mathjax-tex-font/chtml/woff2/mjx-tex-s3.woff2 +0 -0
  50. package/assets/vendor/mathjax-fonts/mathjax-tex-font/chtml/woff2/mjx-tex-s4.woff2 +0 -0
  51. package/assets/vendor/mathjax-fonts/mathjax-tex-font/chtml/woff2/mjx-tex-so.woff2 +0 -0
  52. package/assets/vendor/mathjax-fonts/mathjax-tex-font/chtml/woff2/mjx-tex-ss.woff2 +0 -0
  53. package/assets/vendor/mathjax-fonts/mathjax-tex-font/chtml/woff2/mjx-tex-ssb.woff2 +0 -0
  54. package/assets/vendor/mathjax-fonts/mathjax-tex-font/chtml/woff2/mjx-tex-ssi.woff2 +0 -0
  55. package/assets/vendor/mathjax-fonts/mathjax-tex-font/chtml/woff2/mjx-tex-v.woff2 +0 -0
  56. package/assets/vendor/mathjax-fonts/mathjax-tex-font/chtml/woff2/mjx-tex-zero.woff2 +0 -0
  57. package/assets/vendor/mathjax-fonts/mathjax-tex-font/chtml.js +1 -0
  58. package/assets/vendor/mathjax-fonts/mathjax-tex-font/package.json +88 -0
  59. package/assets/vendor/paged.polyfill.js +33251 -0
  60. package/bin/mdpreview.js +8 -0
  61. package/bin/pageproof.js +8 -0
  62. package/package.json +42 -0
  63. package/src/assets.js +246 -0
  64. package/src/cli.js +166 -0
  65. package/src/lifecycle.js +445 -0
  66. package/src/pandoc.js +346 -0
  67. package/src/server.js +228 -0
  68. package/src/util.js +43 -0
@@ -0,0 +1,496 @@
1
+ <!doctype html>
2
+ <html>
3
+ <head>
4
+ <meta charset="utf-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1">
6
+ <title>MDPREVIEW_BROWSER_TITLE</title>
7
+ <link rel="icon" href="favicon.svg" type="image/svg+xml">
8
+ $for(css)$
9
+ <link rel="stylesheet" href="$css$">
10
+ $endfor$
11
+ <style data-pagedjs-ignore>
12
+ .mdpreview-diagnostics-widget {
13
+ position: fixed;
14
+ top: 12pt;
15
+ right: 12pt;
16
+ z-index: 10000;
17
+ font-family: Calibri, Arial, sans-serif;
18
+ }
19
+
20
+ .mdpreview-diagnostics-details {
21
+ position: relative;
22
+ }
23
+
24
+ .mdpreview-diagnostics-button {
25
+ display: grid;
26
+ width: 24pt;
27
+ height: 24pt;
28
+ border: 1pt solid #b5475a;
29
+ border-radius: 50%;
30
+ background: #fff7f8;
31
+ color: #8f2638;
32
+ place-items: center;
33
+ font-family: Calibri, Arial, sans-serif;
34
+ font-size: 15pt;
35
+ font-weight: bold;
36
+ line-height: 1;
37
+ box-shadow: 0 1.5pt 5pt rgba(0, 0, 0, 0.18);
38
+ cursor: pointer;
39
+ list-style: none;
40
+ user-select: none;
41
+ -webkit-user-select: none;
42
+ }
43
+
44
+ .mdpreview-diagnostics-button::-webkit-details-marker {
45
+ display: none;
46
+ }
47
+
48
+ .mdpreview-diagnostics-panel {
49
+ box-sizing: border-box;
50
+ position: absolute;
51
+ top: 30pt;
52
+ right: 0;
53
+ width: min(330pt, calc(100vw - 24pt));
54
+ max-height: calc(100vh - 54pt);
55
+ overflow: auto;
56
+ padding: 12pt 14pt;
57
+ border-top: 4px solid #b5475a;
58
+ background: #fff7f8;
59
+ color: black;
60
+ font-family: Calibri, Arial, sans-serif;
61
+ font-size: 10.5pt;
62
+ line-height: 1.45;
63
+ box-shadow: 0 3pt 12pt rgba(0, 0, 0, 0.22);
64
+ }
65
+
66
+ .mdpreview-diagnostics-panel h2 {
67
+ margin: 0 0 8pt;
68
+ font-family: Calibri, Arial, sans-serif;
69
+ font-size: 13pt;
70
+ font-weight: bold;
71
+ color: black;
72
+ }
73
+
74
+ /* The diagnostics drawer is chrome and must not carry document heading
75
+ numbers, regardless of which user style file is in effect. Neutralise
76
+ any counter side-effects on chrome headings and suppress generated
77
+ numbering content. The empty custom property mirrors the trick used
78
+ in numbered.css: Paged.js's CSS preprocessor scans counter-increment /
79
+ counter-reset for bare identifiers, but leaves var() functions alone,
80
+ so the rule survives pagination without polluting Paged.js's counter
81
+ registry. */
82
+
83
+ .mdpreview-diagnostics-widget {
84
+ --mdpreview-no-counter: ;
85
+ }
86
+
87
+ .mdpreview-diagnostics-widget h1, .mdpreview-diagnostics-widget h2,
88
+ .mdpreview-diagnostics-widget h3, .mdpreview-diagnostics-widget h4 {
89
+ counter-increment: var(--mdpreview-no-counter) !important;
90
+ counter-reset: var(--mdpreview-no-counter) !important;
91
+ }
92
+
93
+ .mdpreview-diagnostics-widget h1::before, .mdpreview-diagnostics-widget h2::before,
94
+ .mdpreview-diagnostics-widget h3::before, .mdpreview-diagnostics-widget h4::before {
95
+ content: none !important;
96
+ }
97
+
98
+ .mdpreview-diagnostics-panel p {
99
+ margin: 0 0 8pt;
100
+ }
101
+
102
+ .mdpreview-diagnostics-panel ul {
103
+ margin: 0 0 8pt;
104
+ padding-left: 16pt;
105
+ }
106
+
107
+ .mdpreview-diagnostics-panel details {
108
+ margin-top: 8pt;
109
+ }
110
+
111
+ .mdpreview-diagnostics-panel summary {
112
+ cursor: pointer;
113
+ }
114
+
115
+ .mdpreview-diagnostics-panel pre {
116
+ max-height: 160pt;
117
+ overflow: auto;
118
+ margin: 0;
119
+ padding: 0;
120
+ background: transparent;
121
+ font-size: 8.5pt;
122
+ white-space: pre-wrap;
123
+ }
124
+
125
+ body.mdpreview-disconnected {
126
+ background: #737373 !important;
127
+ }
128
+
129
+ body.mdpreview-disconnected .pagedjs_pages {
130
+ opacity: 0.55;
131
+ filter: grayscale(1);
132
+ }
133
+
134
+ body.mdpreview-disconnected .mdpreview-empty-preview {
135
+ opacity: 0.55;
136
+ }
137
+
138
+ body.mdpreview-disconnected .mdpreview-diagnostics-button {
139
+ border-color: #3f3f3f;
140
+ background: #5b5b5b;
141
+ color: #f2f2f2;
142
+ }
143
+
144
+ body.mdpreview-disconnected .mdpreview-disconnect-null {
145
+ position: relative;
146
+ font-size: 0;
147
+ }
148
+
149
+ body.mdpreview-disconnected .mdpreview-disconnect-null::before,
150
+ body.mdpreview-disconnected .mdpreview-disconnect-null::after {
151
+ content: "";
152
+ position: absolute;
153
+ top: 50%;
154
+ left: 50%;
155
+ transform-origin: center;
156
+ }
157
+
158
+ body.mdpreview-disconnected .mdpreview-disconnect-null::before {
159
+ box-sizing: border-box;
160
+ width: 12pt;
161
+ height: 12pt;
162
+ border: 2pt solid currentColor;
163
+ border-radius: 50%;
164
+ transform: translate(-50%, -50%);
165
+ }
166
+
167
+ body.mdpreview-disconnected .mdpreview-disconnect-null::after {
168
+ width: 14pt;
169
+ height: 2pt;
170
+ border-radius: 1pt;
171
+ background: currentColor;
172
+ transform: translate(-50%, -50%) rotate(-45deg);
173
+ }
174
+
175
+ body.mdpreview-disconnected .mdpreview-diagnostics-panel {
176
+ border-top-color: #3f3f3f;
177
+ background: #ededed;
178
+ }
179
+
180
+ .pagedjs_area [data-footnote-call].mdpreview-metadata-footnote {
181
+ counter-increment: mdpreview-metadata-footnote !important;
182
+ }
183
+
184
+ [data-footnote-marker].mdpreview-metadata-footnote:not([data-split-from]) {
185
+ counter-increment: mdpreview-metadata-footnote-marker !important;
186
+ }
187
+
188
+ @media print {
189
+ :root,
190
+ body {
191
+ background: white !important;
192
+ }
193
+
194
+ .pagedjs_pages {
195
+ gap: 0 !important;
196
+ padding: 0 !important;
197
+ margin: 0 !important;
198
+ }
199
+
200
+ .pagedjs_page {
201
+ box-shadow: none !important;
202
+ }
203
+
204
+ #mdpreview-chrome,
205
+ [data-mdpreview-chrome],
206
+ .mdpreview-diagnostics-widget {
207
+ display: none !important;
208
+ }
209
+ }
210
+ </style>
211
+ $if(math)$
212
+ <script>
213
+ window.PagedConfig = { auto: false };
214
+ window.MathJax = {
215
+ output: {
216
+ font: 'mathjax-tex',
217
+ fontPath: '/mathjax-fonts/%%FONT%%-font'
218
+ }
219
+ };
220
+ </script>
221
+ $endif$
222
+ $math$
223
+ </head>
224
+ <body$if(mdpreview-has-diagnostics)$ class="mdpreview-has-diagnostics"$endif$>
225
+ <div id="mdpreview-chrome">
226
+ <!-- MDPREVIEW_DIAGNOSTICS -->
227
+ </div>
228
+ <div id="mdpreview-pages" aria-label="Paginated preview"></div>
229
+ <main id="mdpreview-source" class="mdpreview-document">
230
+ $if(title)$
231
+ <header>
232
+ <div class="document-title">$title$</div>
233
+ $for(author)$
234
+ <div class="document-author">$author$</div>
235
+ $endfor$
236
+ $if(date)$
237
+ <div class="document-date">$date$</div>
238
+ $endif$
239
+ </header>
240
+ $else$
241
+ $if(author)$
242
+ <header>
243
+ $for(author)$
244
+ <div class="document-author">$author$</div>
245
+ $endfor$
246
+ $if(date)$
247
+ <div class="document-date">$date$</div>
248
+ $endif$
249
+ </header>
250
+ $else$
251
+ $if(date)$
252
+ <header>
253
+ <div class="document-date">$date$</div>
254
+ </header>
255
+ $endif$
256
+ $endif$
257
+ $endif$
258
+ $body$
259
+ </main>
260
+ <script>
261
+ window.mdpreviewBrowserDebug = false;
262
+ window.mdpreviewBuildId = 0;
263
+ window.mdpreviewBrowserLogErrors = [];
264
+ window.mdpreviewSourceSnapshot = { text: '', html: '' };
265
+
266
+ const mdpreviewRecordBrowserError = (message, source, line, column) => {
267
+ window.mdpreviewBrowserLogErrors.push({
268
+ message: String(message || 'Unknown browser error'),
269
+ source: source || undefined,
270
+ line: line || undefined,
271
+ column: column || undefined
272
+ });
273
+ };
274
+
275
+ window.addEventListener('error', (event) => {
276
+ mdpreviewRecordBrowserError(event.message, event.filename, event.lineno, event.colno);
277
+ setTimeout(() => window.mdpreviewReportBrowserRender?.(false, { phase: 'browser-error' }), 0);
278
+ });
279
+
280
+ window.addEventListener('unhandledrejection', (event) => {
281
+ mdpreviewRecordBrowserError(event.reason?.message || event.reason || 'Unhandled promise rejection');
282
+ setTimeout(() => window.mdpreviewReportBrowserRender?.(false, { phase: 'browser-unhandled-rejection' }), 0);
283
+ });
284
+
285
+ const mdpreviewTextHead = (value) => String(value || '').replace(/\s+/g, ' ').trim().slice(0, 500);
286
+ const mdpreviewTextTail = (value) => String(value || '').replace(/\s+/g, ' ').trim().slice(-500);
287
+
288
+ window.mdpreviewPostBrowserLog = (payload) => {
289
+ const body = JSON.stringify(payload);
290
+ if (!window.mdpreviewBrowserDebug && navigator.sendBeacon) {
291
+ const sent = navigator.sendBeacon('/__browser-log', new Blob([body], { type: 'application/json' }));
292
+ if (sent) return;
293
+ }
294
+ fetch('/__browser-log', {
295
+ method: 'POST',
296
+ headers: { 'content-type': 'application/json' },
297
+ body,
298
+ keepalive: !window.mdpreviewBrowserDebug
299
+ }).catch(() => {});
300
+ };
301
+
302
+ window.mdpreviewReportBrowserRender = (ok, extra = {}) => {
303
+ const pages = document.querySelector('#mdpreview-pages');
304
+ const source = extra.sourceNode || document.querySelector('#mdpreview-source') || window.PagedConfig?.content;
305
+ const renderedText = pages?.innerText || pages?.textContent || '';
306
+ const sourceText = window.mdpreviewSourceSnapshot.text || source?.innerText || source?.textContent || '';
307
+ const payload = {
308
+ type: 'browser-rendered',
309
+ buildId: window.mdpreviewBuildId,
310
+ phase: extra.phase || 'paged-rendered',
311
+ ok,
312
+ url: location.href,
313
+ pageCount: document.querySelectorAll('.pagedjs_page').length,
314
+ renderedTextLength: renderedText.length,
315
+ sourceTextLength: sourceText.length,
316
+ renderedTextTail: mdpreviewTextTail(renderedText),
317
+ errors: window.mdpreviewBrowserLogErrors.slice(-20)
318
+ };
319
+ if (extra.error) payload.error = String(extra.error?.message || extra.error);
320
+ if (window.mdpreviewBrowserDebug) {
321
+ payload.renderedTextHead = mdpreviewTextHead(renderedText);
322
+ payload.documentHtml = document.documentElement.outerHTML;
323
+ payload.pagesHtml = pages?.outerHTML || '';
324
+ payload.sourceHtml = window.mdpreviewSourceSnapshot.html || source?.outerHTML || '';
325
+ }
326
+ window.mdpreviewPostBrowserLog(payload);
327
+ };
328
+
329
+ const mdpreviewPagedTargets = () => {
330
+ const source = document.querySelector('#mdpreview-source');
331
+ return {
332
+ content: source,
333
+ renderTo: document.querySelector('#mdpreview-pages'),
334
+ sourceNode: source
335
+ };
336
+ };
337
+
338
+ const mdpreviewPreparePagedTargets = () => {
339
+ const { sourceNode, renderTo } = mdpreviewPagedTargets();
340
+ const content = document.createDocumentFragment();
341
+ if (sourceNode) {
342
+ window.mdpreviewSourceSnapshot = {
343
+ text: sourceNode.innerText || sourceNode.textContent || '',
344
+ html: sourceNode.outerHTML || ''
345
+ };
346
+ while (sourceNode.firstChild) {
347
+ content.appendChild(sourceNode.firstChild);
348
+ }
349
+ sourceNode.remove();
350
+ }
351
+ return { content, renderTo };
352
+ };
353
+
354
+ const mdpreviewAutoPaginate = !window.PagedConfig || window.PagedConfig.auto !== false;
355
+ window.PagedConfig = {
356
+ ...window.PagedConfig,
357
+ ...(mdpreviewAutoPaginate ? mdpreviewPreparePagedTargets() : mdpreviewPagedTargets()),
358
+ ...(mdpreviewAutoPaginate
359
+ ? { after: (flow) => {
360
+ window.mdpreviewReportBrowserRender(true, {
361
+ phase: 'paged-rendered'
362
+ });
363
+ return flow;
364
+ } }
365
+ : {})
366
+ };
367
+
368
+ window.mdpreviewRenderPages = () => {
369
+ const { content, renderTo } = mdpreviewPreparePagedTargets();
370
+ if (!content?.childNodes?.length || !renderTo) {
371
+ const error = new Error('mdpreview pagination targets are missing');
372
+ window.mdpreviewReportBrowserRender(false, { phase: 'paged-failed', error });
373
+ return Promise.reject(error);
374
+ }
375
+ return Promise.resolve(window.PagedPolyfill.preview(content, undefined, renderTo))
376
+ .then((flow) => {
377
+ window.mdpreviewReportBrowserRender(true, {
378
+ phase: 'paged-rendered'
379
+ });
380
+ return flow;
381
+ }, (error) => {
382
+ window.mdpreviewReportBrowserRender(false, {
383
+ phase: 'paged-failed',
384
+ error
385
+ });
386
+ throw error;
387
+ });
388
+ };
389
+ </script>
390
+ <script src="/paged.polyfill.js"></script>
391
+ $if(math)$
392
+ <script>
393
+ const runPagedAfterMath = () => {
394
+ const mathReady = window.MathJax && window.MathJax.startup
395
+ ? window.MathJax.startup.promise
396
+ : Promise.resolve();
397
+
398
+ mathReady.catch((error) => {
399
+ mdpreviewRecordBrowserError(error?.message || error || 'MathJax failed before pagination');
400
+ console.error('MathJax failed before pagination', error);
401
+ })
402
+ .then(() => window.mdpreviewRenderPages());
403
+ };
404
+
405
+ if (document.readyState === 'loading') {
406
+ document.addEventListener('DOMContentLoaded', runPagedAfterMath, { once: true });
407
+ } else {
408
+ runPagedAfterMath();
409
+ }
410
+ </script>
411
+ $endif$
412
+ <script>
413
+ const mdpreviewDisconnectedTitle = 'Preview disconnected';
414
+
415
+ const mdpreviewEnsureDiagnosticsWidget = () => {
416
+ let widget = document.querySelector('.mdpreview-diagnostics-widget');
417
+ if (widget) return widget;
418
+ const chrome = document.querySelector('#mdpreview-chrome') || document.body;
419
+ widget = document.createElement('aside');
420
+ widget.className = 'mdpreview-diagnostics-widget';
421
+ widget.dataset.mdpreviewChrome = '';
422
+ widget.dataset.mdpreviewCreatedForDisconnect = 'true';
423
+ widget.setAttribute('aria-live', 'polite');
424
+ const details = document.createElement('details');
425
+ details.className = 'mdpreview-diagnostics-details';
426
+ const button = document.createElement('summary');
427
+ button.className = 'mdpreview-diagnostics-button';
428
+ button.setAttribute('title', mdpreviewDisconnectedTitle);
429
+ button.setAttribute('aria-label', mdpreviewDisconnectedTitle);
430
+ const panel = document.createElement('section');
431
+ panel.className = 'mdpreview-diagnostics-panel';
432
+ details.append(button, panel);
433
+ widget.append(details);
434
+ chrome.prepend(widget);
435
+ return widget;
436
+ };
437
+
438
+ const mdpreviewMarkDisconnected = () => {
439
+ document.body.classList.add('mdpreview-disconnected');
440
+ const widget = mdpreviewEnsureDiagnosticsWidget();
441
+ const button = widget.querySelector('.mdpreview-diagnostics-button');
442
+ if (button && !button.dataset.mdpreviewOriginalText) {
443
+ button.dataset.mdpreviewOriginalText = button.textContent;
444
+ button.dataset.mdpreviewOriginalTitle = button.getAttribute('title') || '';
445
+ button.dataset.mdpreviewOriginalAriaLabel = button.getAttribute('aria-label') || '';
446
+ }
447
+ if (button) {
448
+ button.textContent = '';
449
+ button.classList.add('mdpreview-disconnect-null');
450
+ button.setAttribute('title', mdpreviewDisconnectedTitle);
451
+ button.setAttribute('aria-label', mdpreviewDisconnectedTitle);
452
+ }
453
+ const panel = widget.querySelector('.mdpreview-diagnostics-panel');
454
+ if (panel && !panel.querySelector('[data-mdpreview-disconnected-title]')) {
455
+ const message = document.createElement('h2');
456
+ message.dataset.mdpreviewDisconnectedTitle = '';
457
+ message.textContent = mdpreviewDisconnectedTitle;
458
+ panel.prepend(message);
459
+ }
460
+ };
461
+
462
+ const mdpreviewClearDisconnected = () => {
463
+ document.body.classList.remove('mdpreview-disconnected');
464
+ const widget = document.querySelector('.mdpreview-diagnostics-widget');
465
+ if (!widget) return;
466
+ if (widget.dataset.mdpreviewCreatedForDisconnect === 'true') {
467
+ widget.remove();
468
+ return;
469
+ }
470
+ const button = widget.querySelector('.mdpreview-diagnostics-button');
471
+ if (button?.dataset.mdpreviewOriginalText !== undefined) {
472
+ button.textContent = button.dataset.mdpreviewOriginalText;
473
+ button.classList.remove('mdpreview-disconnect-null');
474
+ button.setAttribute('title', button.dataset.mdpreviewOriginalTitle || '');
475
+ button.setAttribute('aria-label', button.dataset.mdpreviewOriginalAriaLabel || '');
476
+ delete button.dataset.mdpreviewOriginalText;
477
+ delete button.dataset.mdpreviewOriginalTitle;
478
+ delete button.dataset.mdpreviewOriginalAriaLabel;
479
+ }
480
+ widget.querySelector('[data-mdpreview-disconnected-title]')?.remove();
481
+ };
482
+
483
+ let mdpreviewDisconnectTimer;
484
+ const events = new EventSource('/events');
485
+ events.addEventListener('open', () => {
486
+ clearTimeout(mdpreviewDisconnectTimer);
487
+ mdpreviewClearDisconnected();
488
+ });
489
+ events.addEventListener('error', () => {
490
+ clearTimeout(mdpreviewDisconnectTimer);
491
+ mdpreviewDisconnectTimer = setTimeout(mdpreviewMarkDisconnected, 2500);
492
+ });
493
+ events.addEventListener('reload', () => location.reload());
494
+ </script>
495
+ </body>
496
+ </html>
@@ -0,0 +1,8 @@
1
+ /* mdpreview-style: Double-spaced text override for manuscript drafts. */
2
+ html {
3
+ line-height: 2;
4
+ }
5
+
6
+ p {
7
+ margin-bottom: 0;
8
+ }