deepresearch-flow 0.4.0__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.
Files changed (25) hide show
  1. deepresearch_flow/paper/db.py +34 -0
  2. deepresearch_flow/paper/web/app.py +106 -1
  3. deepresearch_flow/paper/web/constants.py +5 -4
  4. deepresearch_flow/paper/web/handlers/__init__.py +2 -1
  5. deepresearch_flow/paper/web/handlers/api.py +55 -0
  6. deepresearch_flow/paper/web/handlers/pages.py +105 -25
  7. deepresearch_flow/paper/web/markdown.py +60 -0
  8. deepresearch_flow/paper/web/pdfjs/web/viewer.html +57 -5
  9. deepresearch_flow/paper/web/pdfjs/web/viewer.js +5 -1
  10. deepresearch_flow/paper/web/static/js/detail.js +494 -125
  11. deepresearch_flow/paper/web/static/js/outline.js +48 -34
  12. deepresearch_flow/paper/web/static_assets.py +289 -0
  13. deepresearch_flow/paper/web/templates/detail.html +46 -69
  14. deepresearch_flow/paper/web/templates/index.html +3 -3
  15. deepresearch_flow/paper/web/templates.py +7 -4
  16. deepresearch_flow/recognize/cli.py +805 -26
  17. deepresearch_flow/recognize/katex_check.js +29 -0
  18. deepresearch_flow/recognize/math.py +719 -0
  19. deepresearch_flow/recognize/mermaid.py +690 -0
  20. {deepresearch_flow-0.4.0.dist-info → deepresearch_flow-0.5.0.dist-info}/METADATA +117 -4
  21. {deepresearch_flow-0.4.0.dist-info → deepresearch_flow-0.5.0.dist-info}/RECORD +25 -21
  22. {deepresearch_flow-0.4.0.dist-info → deepresearch_flow-0.5.0.dist-info}/WHEEL +0 -0
  23. {deepresearch_flow-0.4.0.dist-info → deepresearch_flow-0.5.0.dist-info}/entry_points.txt +0 -0
  24. {deepresearch_flow-0.4.0.dist-info → deepresearch_flow-0.5.0.dist-info}/licenses/LICENSE +0 -0
  25. {deepresearch_flow-0.4.0.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
- initMarkdownRendering();
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 (Mermaid + KaTeX)
89
+ // Markdown rendering (Marked + DOMPurify) + enhancements
85
90
  // ========================================
86
91
 
87
- function initMarkdownRendering() {
88
- // Only run if we have content with mermaid/katex
89
- if (!document.getElementById('content')) return;
90
-
91
- function initRendering() {
92
- // Markmap: convert fenced markmap blocks to svg mindmaps
93
- if (window.markmap && window.markmap.Transformer && window.markmap.Markmap) {
94
- var transformer = new window.markmap.Transformer();
95
- document.querySelectorAll('code.language-markmap').forEach(function(code) {
96
- var pre = code.parentElement;
97
- if (!pre) return;
98
- var svg = document.createElement('svg');
99
- svg.className = 'markmap';
100
- pre.replaceWith(svg);
101
- try {
102
- var result = transformer.transform(code.textContent || '');
103
- window.markmap.Markmap.create(svg, null, result.root);
104
- } catch (err) {
105
- // Ignore markmap parse errors
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
- // Mermaid: convert fenced code blocks to mermaid divs
111
- document.querySelectorAll('code.language-mermaid').forEach(function(code) {
112
- var pre = code.parentElement;
113
- var div = document.createElement('div');
114
- div.className = 'mermaid';
115
- div.textContent = code.textContent;
116
- pre.replaceWith(div);
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
- if (window.mermaid) {
120
- mermaid.initialize({ startOnLoad: false });
121
- mermaid.run();
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
- if (window.renderMathInElement) {
125
- renderMathInElement(document.getElementById('content'), {
126
- delimiters: [
127
- {left: '$$', right: '$$', display: true},
128
- {left: '$', right: '$', display: false},
129
- {left: '\\(', right: '\\)', display: false},
130
- {left: '\\[', right: '\\]', display: true}
131
- ],
132
- throwOnError: false
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
- if (document.readyState === 'loading') {
138
- document.addEventListener('DOMContentLoaded', initRendering);
139
- } else {
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 pdfJsLib = window.pdfjsLib;
309
- if (!pdfJsLib) return;
310
-
311
- pdfJsLib.GlobalWorkerOptions.workerSrc = 'https://cdnjs.cloudflare.com/ajax/libs/pdf.js/4.0.379/pdf.worker.min.js';
312
-
313
- var pdfDoc = null;
314
- var pageNum = 1;
315
- var pageRendering = false;
316
- var pageNumPending = null;
317
- var zoomLevel = 1.0;
318
- var canvas = document.getElementById('the-canvas');
319
- var ctx = canvas.getContext('2d');
320
-
321
- function renderPage(num) {
322
- pageRendering = true;
323
- pdfDoc.getPage(num).then(function(page) {
324
- var baseViewport = page.getViewport({scale: 1});
325
- var containerWidth = canvas.clientWidth || baseViewport.width;
326
- var fitScale = containerWidth / baseViewport.width;
327
- var scale = fitScale * zoomLevel;
328
-
329
- var viewport = page.getViewport({scale: scale});
330
- var outputScale = window.devicePixelRatio || 1;
331
-
332
- canvas.width = Math.floor(viewport.width * outputScale);
333
- canvas.height = Math.floor(viewport.height * outputScale);
334
- canvas.style.width = Math.floor(viewport.width) + 'px';
335
- canvas.style.height = Math.floor(viewport.height) + 'px';
336
-
337
- var transform = outputScale !== 1 ? [outputScale, 0, 0, outputScale, 0, 0] : null;
338
- var renderContext = { canvasContext: ctx, viewport: viewport, transform: transform };
339
- var renderTask = page.render(renderContext);
340
- renderTask.promise.then(function() {
341
- pageRendering = false;
342
- document.getElementById('page_num').textContent = String(pageNum);
343
- if (pageNumPending !== null) {
344
- var next = pageNumPending;
345
- pageNumPending = null;
346
- renderPage(next);
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
- function queueRenderPage(num) {
353
- if (pageRendering) {
354
- pageNumPending = num;
355
- } else {
356
- renderPage(num);
695
+ function queueRenderPage(num) {
696
+ if (pageRendering) {
697
+ pageNumPending = num;
698
+ } else {
699
+ renderPage(num);
700
+ }
357
701
  }
358
- }
359
702
 
360
- function onPrevPage() {
361
- if (pageNum <= 1) return;
362
- pageNum--;
363
- queueRenderPage(pageNum);
364
- }
703
+ function onPrevPage() {
704
+ if (pageNum <= 1) return;
705
+ pageNum--;
706
+ queueRenderPage(pageNum);
707
+ }
365
708
 
366
- function onNextPage() {
367
- if (pageNum >= pdfDoc.numPages) return;
368
- pageNum++;
369
- queueRenderPage(pageNum);
370
- }
709
+ function onNextPage() {
710
+ if (pageNum >= pdfDoc.numPages) return;
711
+ pageNum++;
712
+ queueRenderPage(pageNum);
713
+ }
371
714
 
372
- function adjustZoom(delta) {
373
- zoomLevel = Math.max(0.5, Math.min(3.0, zoomLevel + delta));
374
- queueRenderPage(pageNum);
375
- }
715
+ function adjustZoom(delta) {
716
+ zoomLevel = Math.max(0.5, Math.min(3.0, zoomLevel + delta));
717
+ queueRenderPage(pageNum);
718
+ }
376
719
 
377
- document.getElementById('prev').addEventListener('click', onPrevPage);
378
- document.getElementById('next').addEventListener('click', onNextPage);
379
- document.getElementById('zoomOut').addEventListener('click', function() { adjustZoom(-0.1); });
380
- document.getElementById('zoomIn').addEventListener('click', function() { adjustZoom(0.1); });
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
- pdfJsLib.getDocument(pdfUrl).promise.then(function(pdfDoc_) {
383
- pdfDoc = pdfDoc_;
384
- document.getElementById('page_count').textContent = String(pdfDoc.numPages);
385
- renderPage(pageNum);
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
- var resizeTimer = null;
389
- window.addEventListener('resize', function() {
390
- if (!pdfDoc) return;
391
- if (resizeTimer) clearTimeout(resizeTimer);
392
- resizeTimer = setTimeout(function() { queueRenderPage(pageNum); }, 150);
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
  // ========================================