deepresearch-flow 0.4.1__py3-none-any.whl → 0.5.0__py3-none-any.whl
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.
- deepresearch_flow/paper/db.py +34 -0
- deepresearch_flow/paper/web/app.py +106 -1
- deepresearch_flow/paper/web/constants.py +1 -0
- deepresearch_flow/paper/web/handlers/__init__.py +2 -1
- deepresearch_flow/paper/web/handlers/api.py +55 -0
- deepresearch_flow/paper/web/handlers/pages.py +105 -25
- deepresearch_flow/paper/web/markdown.py +60 -0
- deepresearch_flow/paper/web/pdfjs/web/viewer.html +57 -5
- deepresearch_flow/paper/web/pdfjs/web/viewer.js +5 -1
- deepresearch_flow/paper/web/static/js/detail.js +494 -125
- deepresearch_flow/paper/web/static/js/outline.js +48 -34
- deepresearch_flow/paper/web/static_assets.py +289 -0
- deepresearch_flow/paper/web/templates/detail.html +43 -66
- deepresearch_flow/paper/web/templates.py +7 -4
- {deepresearch_flow-0.4.1.dist-info → deepresearch_flow-0.5.0.dist-info}/METADATA +62 -2
- {deepresearch_flow-0.4.1.dist-info → deepresearch_flow-0.5.0.dist-info}/RECORD +20 -19
- {deepresearch_flow-0.4.1.dist-info → deepresearch_flow-0.5.0.dist-info}/WHEEL +0 -0
- {deepresearch_flow-0.4.1.dist-info → deepresearch_flow-0.5.0.dist-info}/entry_points.txt +0 -0
- {deepresearch_flow-0.4.1.dist-info → deepresearch_flow-0.5.0.dist-info}/licenses/LICENSE +0 -0
- {deepresearch_flow-0.4.1.dist-info → deepresearch_flow-0.5.0.dist-info}/top_level.txt +0 -0
|
@@ -8,8 +8,7 @@
|
|
|
8
8
|
|
|
9
9
|
function init() {
|
|
10
10
|
initFullscreen();
|
|
11
|
-
|
|
12
|
-
initFootnotes();
|
|
11
|
+
initMarkdownContent();
|
|
13
12
|
initBackToTop();
|
|
14
13
|
|
|
15
14
|
// View-specific initializers
|
|
@@ -28,6 +27,12 @@
|
|
|
28
27
|
// Back-to-top button
|
|
29
28
|
// ========================================
|
|
30
29
|
|
|
30
|
+
function escapeHtml(text) {
|
|
31
|
+
var div = document.createElement('div');
|
|
32
|
+
div.textContent = String(text || '');
|
|
33
|
+
return div.innerHTML;
|
|
34
|
+
}
|
|
35
|
+
|
|
31
36
|
function initBackToTop() {
|
|
32
37
|
var button = document.getElementById('backToTop');
|
|
33
38
|
if (!button) return;
|
|
@@ -81,64 +86,395 @@
|
|
|
81
86
|
}
|
|
82
87
|
|
|
83
88
|
// ========================================
|
|
84
|
-
// Markdown rendering (
|
|
89
|
+
// Markdown rendering (Marked + DOMPurify) + enhancements
|
|
85
90
|
// ========================================
|
|
86
91
|
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
92
|
+
var DOMPURIFY_CONFIG = {
|
|
93
|
+
ADD_TAGS: ['sup', 'table', 'thead', 'tbody', 'tfoot', 'tr', 'th', 'td', 'caption', 'colgroup', 'col'],
|
|
94
|
+
ADD_ATTR: ['colspan', 'rowspan', 'align'],
|
|
95
|
+
ALLOWED_URI_REGEXP: /^(?:(?:https?|mailto|tel|data:image\/)|[^a-z]|[a-z+.\-]+(?:[^a-z+.\-:]|$))/i
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
function initMarkdownContent() {
|
|
99
|
+
var content = document.getElementById('content');
|
|
100
|
+
if (!content) return;
|
|
101
|
+
|
|
102
|
+
var markdownUrl = content.dataset.markdownUrl;
|
|
103
|
+
var rawMarkdownUrl = content.dataset.rawMarkdownUrl;
|
|
104
|
+
var imagesBaseUrl = content.dataset.imagesBaseUrl || '';
|
|
105
|
+
if (!markdownUrl) {
|
|
106
|
+
var rawText = content.textContent || '';
|
|
107
|
+
if (content.children.length === 0 && rawText.trim()) {
|
|
108
|
+
var rendered = renderMarkdown(rawText, imagesBaseUrl);
|
|
109
|
+
content.innerHTML = rendered;
|
|
110
|
+
} else {
|
|
111
|
+
rewriteRenderedImages(imagesBaseUrl);
|
|
112
|
+
}
|
|
113
|
+
if (rawMarkdownUrl) {
|
|
114
|
+
var statusEl = document.getElementById('markdownStatus');
|
|
115
|
+
var rawEl = document.getElementById('rawMarkdown');
|
|
116
|
+
if (statusEl) statusEl.textContent = 'Loading raw markdown...';
|
|
117
|
+
fetch(rawMarkdownUrl).then(function(res) {
|
|
118
|
+
if (!res.ok) throw new Error('Failed to load raw markdown');
|
|
119
|
+
return res.text();
|
|
120
|
+
}).then(function(text) {
|
|
121
|
+
if (rawEl) rawEl.textContent = text;
|
|
122
|
+
if (statusEl) statusEl.remove();
|
|
123
|
+
}).catch(function() {
|
|
124
|
+
if (statusEl) statusEl.textContent = 'Failed to load raw markdown.';
|
|
107
125
|
});
|
|
108
126
|
}
|
|
127
|
+
runMarkdownEnhancements();
|
|
128
|
+
initFootnotes();
|
|
129
|
+
dispatchContentUpdated();
|
|
130
|
+
return;
|
|
131
|
+
}
|
|
109
132
|
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
133
|
+
var status = document.getElementById('markdownStatus');
|
|
134
|
+
var rawContainer = document.getElementById('rawMarkdown');
|
|
135
|
+
if (status) status.textContent = 'Loading markdown...';
|
|
136
|
+
|
|
137
|
+
fetch(markdownUrl).then(function(res) {
|
|
138
|
+
if (!res.ok) throw new Error('Failed to load markdown');
|
|
139
|
+
return res.text();
|
|
140
|
+
}).then(function(text) {
|
|
141
|
+
if (rawContainer) rawContainer.textContent = text;
|
|
142
|
+
var html = renderMarkdown(text, imagesBaseUrl);
|
|
143
|
+
content.innerHTML = html;
|
|
144
|
+
if (status) status.remove();
|
|
145
|
+
rewriteRenderedImages(imagesBaseUrl);
|
|
146
|
+
runMarkdownEnhancements();
|
|
147
|
+
initFootnotes();
|
|
148
|
+
dispatchContentUpdated();
|
|
149
|
+
}).catch(function() {
|
|
150
|
+
if (status) status.textContent = 'Failed to load markdown.';
|
|
151
|
+
});
|
|
152
|
+
}
|
|
118
153
|
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
154
|
+
function renderMarkdown(markdown, imagesBaseUrl) {
|
|
155
|
+
var normalized = normalizeFootnoteDefinitions(markdown || '');
|
|
156
|
+
var footnoteData = extractFootnotes(normalized);
|
|
157
|
+
var mathData = extractMathPlaceholders(footnoteData.markdown);
|
|
158
|
+
|
|
159
|
+
if (!window.marked) {
|
|
160
|
+
return '<pre><code>' + escapeHtml(markdown) + '</code></pre>';
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
var renderer = new window.marked.Renderer();
|
|
164
|
+
renderer.image = function(href, title, text) {
|
|
165
|
+
var src = rewriteImageUrl(href, imagesBaseUrl);
|
|
166
|
+
if (!src) return '';
|
|
167
|
+
var html = '<img src="' + escapeHtml(src) + '" alt="' + escapeHtml(text || '') + '"';
|
|
168
|
+
if (title) {
|
|
169
|
+
html += ' title="' + escapeHtml(title) + '"';
|
|
122
170
|
}
|
|
171
|
+
return html + ' />';
|
|
172
|
+
};
|
|
123
173
|
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
174
|
+
if (window.marked && window.marked.setOptions) {
|
|
175
|
+
window.marked.setOptions({ gfm: true, breaks: false });
|
|
176
|
+
}
|
|
177
|
+
var parsed = window.marked.parse(mathData.text || '', { renderer: renderer });
|
|
178
|
+
parsed = replaceMathPlaceholders(parsed, mathData.placeholders);
|
|
179
|
+
parsed = injectFootnotes(parsed, footnoteData);
|
|
180
|
+
if (window.DOMPurify) {
|
|
181
|
+
return window.DOMPurify.sanitize(parsed, DOMPURIFY_CONFIG);
|
|
182
|
+
}
|
|
183
|
+
return parsed;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
function rewriteImageUrl(url, imagesBaseUrl) {
|
|
187
|
+
if (!url) return url;
|
|
188
|
+
if (!imagesBaseUrl) return url;
|
|
189
|
+
if (isAbsoluteUrl(url)) return url;
|
|
190
|
+
|
|
191
|
+
var cleaned = String(url);
|
|
192
|
+
while (cleaned.indexOf('../') === 0) {
|
|
193
|
+
cleaned = cleaned.slice(3);
|
|
194
|
+
}
|
|
195
|
+
cleaned = cleaned.replace(/^\.\//, '');
|
|
196
|
+
cleaned = cleaned.replace(/^\/+/, '');
|
|
197
|
+
if (cleaned.indexOf('images/') === 0) {
|
|
198
|
+
cleaned = cleaned.slice('images/'.length);
|
|
199
|
+
}
|
|
200
|
+
var base = String(imagesBaseUrl).replace(/\/+$/, '');
|
|
201
|
+
return base + '/' + cleaned;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
function rewriteRenderedImages(imagesBaseUrl) {
|
|
205
|
+
if (!imagesBaseUrl) return;
|
|
206
|
+
var content = document.getElementById('content');
|
|
207
|
+
if (!content) return;
|
|
208
|
+
content.querySelectorAll('img').forEach(function(img) {
|
|
209
|
+
var src = img.getAttribute('src');
|
|
210
|
+
var rewritten = rewriteImageUrl(src, imagesBaseUrl);
|
|
211
|
+
if (rewritten && rewritten !== src) {
|
|
212
|
+
img.setAttribute('src', rewritten);
|
|
134
213
|
}
|
|
214
|
+
});
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
function isAbsoluteUrl(url) {
|
|
218
|
+
return /^(?:[a-z][a-z0-9+.\-]*:|\/\/|#)/i.test(url) || url.charAt(0) === '/';
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
function normalizeFootnoteDefinitions(text) {
|
|
222
|
+
return String(text || '').replace(/^\[\^([^\]]+)\]\s+/gm, '[^$1]: ');
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
function extractFootnotes(text) {
|
|
226
|
+
var lines = String(text || '').split(/\r?\n/);
|
|
227
|
+
var out = [];
|
|
228
|
+
var notes = {};
|
|
229
|
+
var order = [];
|
|
230
|
+
var i = 0;
|
|
231
|
+
while (i < lines.length) {
|
|
232
|
+
var line = lines[i];
|
|
233
|
+
var match = line.match(/^\[\^([^\]]+)\]:\s*(.*)$/);
|
|
234
|
+
if (!match) {
|
|
235
|
+
out.push(line);
|
|
236
|
+
i += 1;
|
|
237
|
+
continue;
|
|
238
|
+
}
|
|
239
|
+
var rawId = match[1].trim();
|
|
240
|
+
var id = sanitizeFootnoteId(rawId);
|
|
241
|
+
var content = match[2] || '';
|
|
242
|
+
var parts = [content];
|
|
243
|
+
i += 1;
|
|
244
|
+
while (i < lines.length) {
|
|
245
|
+
var next = lines[i];
|
|
246
|
+
if (/^\[\^([^\]]+)\]:\s*/.test(next)) {
|
|
247
|
+
break;
|
|
248
|
+
}
|
|
249
|
+
if (/^\s{2,}|\t/.test(next)) {
|
|
250
|
+
parts.push(next.replace(/^\s{2,}|\t/, ''));
|
|
251
|
+
i += 1;
|
|
252
|
+
continue;
|
|
253
|
+
}
|
|
254
|
+
if (next.trim() === '') {
|
|
255
|
+
parts.push('');
|
|
256
|
+
i += 1;
|
|
257
|
+
continue;
|
|
258
|
+
}
|
|
259
|
+
break;
|
|
260
|
+
}
|
|
261
|
+
if (!notes[id]) {
|
|
262
|
+
order.push(id);
|
|
263
|
+
}
|
|
264
|
+
notes[id] = parts.join('\n').trim();
|
|
135
265
|
}
|
|
266
|
+
return { markdown: out.join('\n'), notes: notes, order: order };
|
|
267
|
+
}
|
|
136
268
|
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
initRendering();
|
|
269
|
+
function injectFootnotes(html, footnoteData) {
|
|
270
|
+
if (!footnoteData || !footnoteData.order || footnoteData.order.length === 0) {
|
|
271
|
+
return html;
|
|
141
272
|
}
|
|
273
|
+
var notes = footnoteData.notes || {};
|
|
274
|
+
var order = footnoteData.order;
|
|
275
|
+
var replaced = String(html || '').replace(/\[\^([^\]]+)\]/g, function(match, rawId) {
|
|
276
|
+
var id = sanitizeFootnoteId(rawId);
|
|
277
|
+
if (!notes[id]) return match;
|
|
278
|
+
return '<sup class="footnote-ref"><a href="#fn' + id + '" id="fnref' + id + '">[' +
|
|
279
|
+
escapeHtml(rawId) + ']</a></sup>';
|
|
280
|
+
});
|
|
281
|
+
|
|
282
|
+
var items = order.map(function(id) {
|
|
283
|
+
var noteText = notes[id] || '';
|
|
284
|
+
var body = window.marked ? window.marked.parse(noteText) : '<p>' + escapeHtml(noteText) + '</p>';
|
|
285
|
+
return '<li id="fn' + id + '">' + body +
|
|
286
|
+
' <a class="footnote-backref" href="#fnref' + id + '">↩</a></li>';
|
|
287
|
+
}).join('');
|
|
288
|
+
var footnotesHtml = '<div class="footnotes"><ol>' + items + '</ol></div>';
|
|
289
|
+
return replaced + footnotesHtml;
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
function sanitizeFootnoteId(value) {
|
|
293
|
+
return String(value || '').replace(/[^a-zA-Z0-9_-]/g, '-');
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
function extractMathPlaceholders(text) {
|
|
297
|
+
var placeholders = {};
|
|
298
|
+
var out = [];
|
|
299
|
+
var idx = 0;
|
|
300
|
+
var inFence = false;
|
|
301
|
+
var fenceChar = '';
|
|
302
|
+
var fenceLen = 0;
|
|
303
|
+
var inlineDelimLen = 0;
|
|
304
|
+
|
|
305
|
+
function nextPlaceholder(value) {
|
|
306
|
+
var key = '@@MATH_' + Object.keys(placeholders).length + '@@';
|
|
307
|
+
placeholders[key] = value;
|
|
308
|
+
return key;
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
while (idx < text.length) {
|
|
312
|
+
var atLineStart = idx === 0 || text[idx - 1] === '\n';
|
|
313
|
+
if (inlineDelimLen === 0 && atLineStart) {
|
|
314
|
+
var lineEnd = text.indexOf('\n', idx);
|
|
315
|
+
if (lineEnd === -1) lineEnd = text.length;
|
|
316
|
+
var line = text.slice(idx, lineEnd);
|
|
317
|
+
var stripped = line.replace(/^[ ]+/, '');
|
|
318
|
+
var leadingSpaces = line.length - stripped.length;
|
|
319
|
+
if (leadingSpaces <= 3 && stripped) {
|
|
320
|
+
var first = stripped[0];
|
|
321
|
+
if (first === '`' || first === '~') {
|
|
322
|
+
var runLen = 0;
|
|
323
|
+
while (runLen < stripped.length && stripped[runLen] === first) {
|
|
324
|
+
runLen += 1;
|
|
325
|
+
}
|
|
326
|
+
if (runLen >= 3) {
|
|
327
|
+
if (!inFence) {
|
|
328
|
+
inFence = true;
|
|
329
|
+
fenceChar = first;
|
|
330
|
+
fenceLen = runLen;
|
|
331
|
+
} else if (first === fenceChar && runLen >= fenceLen) {
|
|
332
|
+
inFence = false;
|
|
333
|
+
fenceChar = '';
|
|
334
|
+
fenceLen = 0;
|
|
335
|
+
}
|
|
336
|
+
out.push(line);
|
|
337
|
+
idx = lineEnd;
|
|
338
|
+
continue;
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
if (inFence) {
|
|
345
|
+
out.push(text[idx]);
|
|
346
|
+
idx += 1;
|
|
347
|
+
continue;
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
if (inlineDelimLen > 0) {
|
|
351
|
+
var delim = '`'.repeat(inlineDelimLen);
|
|
352
|
+
if (text.slice(idx, idx + inlineDelimLen) === delim) {
|
|
353
|
+
out.push(delim);
|
|
354
|
+
idx += inlineDelimLen;
|
|
355
|
+
inlineDelimLen = 0;
|
|
356
|
+
continue;
|
|
357
|
+
}
|
|
358
|
+
out.push(text[idx]);
|
|
359
|
+
idx += 1;
|
|
360
|
+
continue;
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
if (text[idx] === '`') {
|
|
364
|
+
var inlineRun = 0;
|
|
365
|
+
while (idx + inlineRun < text.length && text[idx + inlineRun] === '`') {
|
|
366
|
+
inlineRun += 1;
|
|
367
|
+
}
|
|
368
|
+
inlineDelimLen = inlineRun;
|
|
369
|
+
out.push('`'.repeat(inlineRun));
|
|
370
|
+
idx += inlineRun;
|
|
371
|
+
continue;
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
if (text.slice(idx, idx + 2) === '$$' && (idx === 0 || text[idx - 1] !== '\\')) {
|
|
375
|
+
var searchFrom = idx + 2;
|
|
376
|
+
var end = text.indexOf('$$', searchFrom);
|
|
377
|
+
while (end !== -1 && text[end - 1] === '\\') {
|
|
378
|
+
searchFrom = end + 2;
|
|
379
|
+
end = text.indexOf('$$', searchFrom);
|
|
380
|
+
}
|
|
381
|
+
if (end !== -1) {
|
|
382
|
+
out.push(nextPlaceholder(text.slice(idx, end + 2)));
|
|
383
|
+
idx = end + 2;
|
|
384
|
+
continue;
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
if (text[idx] === '$' && text.slice(idx, idx + 2) !== '$$' && (idx === 0 || text[idx - 1] !== '\\')) {
|
|
389
|
+
var lineEndInline = text.indexOf('\n', idx + 1);
|
|
390
|
+
if (lineEndInline === -1) lineEndInline = text.length;
|
|
391
|
+
var searchInline = idx + 1;
|
|
392
|
+
var endInline = text.indexOf('$', searchInline);
|
|
393
|
+
while (endInline !== -1 && endInline < lineEndInline && text[endInline - 1] === '\\') {
|
|
394
|
+
searchInline = endInline + 1;
|
|
395
|
+
endInline = text.indexOf('$', searchInline);
|
|
396
|
+
}
|
|
397
|
+
if (endInline !== -1 && endInline < lineEndInline) {
|
|
398
|
+
out.push(nextPlaceholder(text.slice(idx, endInline + 1)));
|
|
399
|
+
idx = endInline + 1;
|
|
400
|
+
continue;
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
out.push(text[idx]);
|
|
405
|
+
idx += 1;
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
return { text: out.join(''), placeholders: placeholders };
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
function replaceMathPlaceholders(html, placeholders) {
|
|
412
|
+
var out = String(html || '');
|
|
413
|
+
Object.keys(placeholders || {}).forEach(function(key) {
|
|
414
|
+
var value = escapeHtml(placeholders[key]);
|
|
415
|
+
out = out.split(key).join(value);
|
|
416
|
+
});
|
|
417
|
+
return out;
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
function runMarkdownEnhancements() {
|
|
421
|
+
var content = document.getElementById('content');
|
|
422
|
+
if (!content) return;
|
|
423
|
+
|
|
424
|
+
// Markmap: convert fenced markmap blocks to svg mindmaps
|
|
425
|
+
if (window.markmap && window.markmap.Transformer && window.markmap.Markmap) {
|
|
426
|
+
var transformer = new window.markmap.Transformer();
|
|
427
|
+
document.querySelectorAll('code.language-markmap').forEach(function(code) {
|
|
428
|
+
var pre = code.parentElement;
|
|
429
|
+
if (!pre) return;
|
|
430
|
+
var svg = document.createElement('svg');
|
|
431
|
+
svg.className = 'markmap';
|
|
432
|
+
pre.replaceWith(svg);
|
|
433
|
+
try {
|
|
434
|
+
var result = transformer.transform(code.textContent || '');
|
|
435
|
+
window.markmap.Markmap.create(svg, null, result.root);
|
|
436
|
+
} catch (err) {
|
|
437
|
+
// Ignore markmap parse errors
|
|
438
|
+
}
|
|
439
|
+
});
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
// Mermaid: convert fenced code blocks to mermaid divs
|
|
443
|
+
document.querySelectorAll('code.language-mermaid').forEach(function(code) {
|
|
444
|
+
var pre = code.parentElement;
|
|
445
|
+
var div = document.createElement('div');
|
|
446
|
+
div.className = 'mermaid';
|
|
447
|
+
div.textContent = code.textContent;
|
|
448
|
+
pre.replaceWith(div);
|
|
449
|
+
});
|
|
450
|
+
|
|
451
|
+
if (window.mermaid) {
|
|
452
|
+
mermaid.initialize({ startOnLoad: false });
|
|
453
|
+
mermaid.run();
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
if (window.renderMathInElement) {
|
|
457
|
+
renderMathInElement(content, {
|
|
458
|
+
delimiters: [
|
|
459
|
+
{left: '$$', right: '$$', display: true},
|
|
460
|
+
{left: '$', right: '$', display: false},
|
|
461
|
+
{left: '\\(', right: '\\)', display: false},
|
|
462
|
+
{left: '\\[', right: '\\]', display: true}
|
|
463
|
+
],
|
|
464
|
+
throwOnError: false
|
|
465
|
+
});
|
|
466
|
+
}
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
function dispatchContentUpdated() {
|
|
470
|
+
var event;
|
|
471
|
+
try {
|
|
472
|
+
event = new CustomEvent('content:updated');
|
|
473
|
+
} catch (err) {
|
|
474
|
+
event = document.createEvent('Event');
|
|
475
|
+
event.initEvent('content:updated', true, true);
|
|
476
|
+
}
|
|
477
|
+
document.dispatchEvent(event);
|
|
142
478
|
}
|
|
143
479
|
|
|
144
480
|
// ========================================
|
|
@@ -305,92 +641,125 @@
|
|
|
305
641
|
var pdfUrl = document.body.dataset.pdfUrl;
|
|
306
642
|
if (!pdfUrl) return;
|
|
307
643
|
|
|
308
|
-
var
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
pageRendering =
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
644
|
+
var started = false;
|
|
645
|
+
var loadRequested = false;
|
|
646
|
+
|
|
647
|
+
function startPdf() {
|
|
648
|
+
if (started) return true;
|
|
649
|
+
var pdfJsLib = window.pdfjsLib;
|
|
650
|
+
if (!pdfJsLib || !pdfJsLib.getDocument) return false;
|
|
651
|
+
|
|
652
|
+
started = true;
|
|
653
|
+
pdfJsLib.GlobalWorkerOptions.workerSrc =
|
|
654
|
+
window.PDFJS_WORKER_SRC || '/pdfjs/build/pdf.worker.js';
|
|
655
|
+
|
|
656
|
+
var pdfDoc = null;
|
|
657
|
+
var pageNum = 1;
|
|
658
|
+
var pageRendering = false;
|
|
659
|
+
var pageNumPending = null;
|
|
660
|
+
var zoomLevel = 1.0;
|
|
661
|
+
var canvas = document.getElementById('the-canvas');
|
|
662
|
+
var ctx = canvas.getContext('2d');
|
|
663
|
+
|
|
664
|
+
function renderPage(num) {
|
|
665
|
+
pageRendering = true;
|
|
666
|
+
pdfDoc.getPage(num).then(function(page) {
|
|
667
|
+
var baseViewport = page.getViewport({scale: 1});
|
|
668
|
+
var containerWidth = canvas.clientWidth || baseViewport.width;
|
|
669
|
+
var fitScale = containerWidth / baseViewport.width;
|
|
670
|
+
var scale = fitScale * zoomLevel;
|
|
671
|
+
|
|
672
|
+
var viewport = page.getViewport({scale: scale});
|
|
673
|
+
var outputScale = window.devicePixelRatio || 1;
|
|
674
|
+
|
|
675
|
+
canvas.width = Math.floor(viewport.width * outputScale);
|
|
676
|
+
canvas.height = Math.floor(viewport.height * outputScale);
|
|
677
|
+
canvas.style.width = Math.floor(viewport.width) + 'px';
|
|
678
|
+
canvas.style.height = Math.floor(viewport.height) + 'px';
|
|
679
|
+
|
|
680
|
+
var transform = outputScale !== 1 ? [outputScale, 0, 0, outputScale, 0, 0] : null;
|
|
681
|
+
var renderContext = { canvasContext: ctx, viewport: viewport, transform: transform };
|
|
682
|
+
var renderTask = page.render(renderContext);
|
|
683
|
+
renderTask.promise.then(function() {
|
|
684
|
+
pageRendering = false;
|
|
685
|
+
document.getElementById('page_num').textContent = String(pageNum);
|
|
686
|
+
if (pageNumPending !== null) {
|
|
687
|
+
var next = pageNumPending;
|
|
688
|
+
pageNumPending = null;
|
|
689
|
+
renderPage(next);
|
|
690
|
+
}
|
|
691
|
+
});
|
|
348
692
|
});
|
|
349
|
-
}
|
|
350
|
-
}
|
|
693
|
+
}
|
|
351
694
|
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
695
|
+
function queueRenderPage(num) {
|
|
696
|
+
if (pageRendering) {
|
|
697
|
+
pageNumPending = num;
|
|
698
|
+
} else {
|
|
699
|
+
renderPage(num);
|
|
700
|
+
}
|
|
357
701
|
}
|
|
358
|
-
}
|
|
359
702
|
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
703
|
+
function onPrevPage() {
|
|
704
|
+
if (pageNum <= 1) return;
|
|
705
|
+
pageNum--;
|
|
706
|
+
queueRenderPage(pageNum);
|
|
707
|
+
}
|
|
365
708
|
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
709
|
+
function onNextPage() {
|
|
710
|
+
if (pageNum >= pdfDoc.numPages) return;
|
|
711
|
+
pageNum++;
|
|
712
|
+
queueRenderPage(pageNum);
|
|
713
|
+
}
|
|
371
714
|
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
715
|
+
function adjustZoom(delta) {
|
|
716
|
+
zoomLevel = Math.max(0.5, Math.min(3.0, zoomLevel + delta));
|
|
717
|
+
queueRenderPage(pageNum);
|
|
718
|
+
}
|
|
376
719
|
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
720
|
+
document.getElementById('prev').addEventListener('click', onPrevPage);
|
|
721
|
+
document.getElementById('next').addEventListener('click', onNextPage);
|
|
722
|
+
document.getElementById('zoomOut').addEventListener('click', function() { adjustZoom(-0.1); });
|
|
723
|
+
document.getElementById('zoomIn').addEventListener('click', function() { adjustZoom(0.1); });
|
|
381
724
|
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
725
|
+
pdfJsLib.getDocument(pdfUrl).promise.then(function(pdfDoc_) {
|
|
726
|
+
pdfDoc = pdfDoc_;
|
|
727
|
+
document.getElementById('page_count').textContent = String(pdfDoc.numPages);
|
|
728
|
+
renderPage(pageNum);
|
|
729
|
+
});
|
|
387
730
|
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
731
|
+
var resizeTimer = null;
|
|
732
|
+
window.addEventListener('resize', function() {
|
|
733
|
+
if (!pdfDoc) return;
|
|
734
|
+
if (resizeTimer) clearTimeout(resizeTimer);
|
|
735
|
+
resizeTimer = setTimeout(function() { queueRenderPage(pageNum); }, 150);
|
|
736
|
+
});
|
|
737
|
+
|
|
738
|
+
return true;
|
|
739
|
+
}
|
|
740
|
+
|
|
741
|
+
if (startPdf()) return;
|
|
742
|
+
|
|
743
|
+
if (!loadRequested && window.PDFJS_SCRIPT_SRC) {
|
|
744
|
+
loadRequested = true;
|
|
745
|
+
var script = document.createElement('script');
|
|
746
|
+
script.src = window.PDFJS_SCRIPT_SRC;
|
|
747
|
+
script.defer = true;
|
|
748
|
+
script.onload = function() {
|
|
749
|
+
try {
|
|
750
|
+
window.dispatchEvent(new Event('pdfjs:loaded'));
|
|
751
|
+
} catch (err) {
|
|
752
|
+
var event = document.createEvent('Event');
|
|
753
|
+
event.initEvent('pdfjs:loaded', true, true);
|
|
754
|
+
window.dispatchEvent(event);
|
|
755
|
+
}
|
|
756
|
+
};
|
|
757
|
+
document.head.appendChild(script);
|
|
758
|
+
}
|
|
759
|
+
|
|
760
|
+
window.addEventListener('pdfjs:loaded', function() {
|
|
761
|
+
startPdf();
|
|
762
|
+
}, { once: true });
|
|
394
763
|
}
|
|
395
764
|
|
|
396
765
|
// ========================================
|