Navada25 commited on
Commit
bd43db3
·
verified ·
1 Parent(s): a85cab8

Update public/split_screen.js for document viewer

Browse files
Files changed (1) hide show
  1. public/split_screen.js +612 -0
public/split_screen.js ADDED
@@ -0,0 +1,612 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // Split Screen Document Viewer for Chainlit
2
+ (function() {
3
+ 'use strict';
4
+
5
+ let documentViewer = null;
6
+ let documents = [];
7
+ let activeDocIndex = 0;
8
+ let viewerActive = false;
9
+
10
+ // Create the document viewer panel (hidden by default)
11
+ function createDocumentViewer() {
12
+ if (document.getElementById('document-viewer')) {
13
+ return document.getElementById('document-viewer');
14
+ }
15
+
16
+ const viewer = document.createElement('div');
17
+ viewer.id = 'document-viewer';
18
+ viewer.className = ''; // Start without 'active' class
19
+
20
+ // Create header
21
+ const header = document.createElement('div');
22
+ header.className = 'document-header';
23
+ header.innerHTML = `
24
+ <h3>Document Viewer</h3>
25
+ <div style="display: flex; gap: 10px;">
26
+ <button class="document-pin" title="Pin document">📌 Pin</button>
27
+ <button class="document-close-btn">Close</button>
28
+ </div>
29
+ `;
30
+ viewer.appendChild(header);
31
+
32
+ // Create tabs container
33
+ const tabsContainer = document.createElement('div');
34
+ tabsContainer.className = 'document-tabs';
35
+ viewer.appendChild(tabsContainer);
36
+
37
+ // Create content area
38
+ const contentArea = document.createElement('div');
39
+ contentArea.id = 'document-content';
40
+ contentArea.innerHTML = `
41
+ <div class="document-empty-state">
42
+ <h4>No Document Selected</h4>
43
+ <p>Click on any document, image, or file in the chat to view it here</p>
44
+ </div>
45
+ `;
46
+ viewer.appendChild(contentArea);
47
+
48
+ // Add close functionality
49
+ header.querySelector('.document-close-btn').addEventListener('click', () => {
50
+ hideDocumentViewer();
51
+ });
52
+
53
+ // Add pin functionality
54
+ const pinBtn = header.querySelector('.document-pin');
55
+ pinBtn.addEventListener('click', () => {
56
+ pinBtn.classList.toggle('pinned');
57
+ const isPinned = pinBtn.classList.contains('pinned');
58
+ pinBtn.textContent = isPinned ? '📍 Pinned' : '📌 Pin';
59
+ });
60
+
61
+ return viewer;
62
+ }
63
+
64
+ // Show document viewer
65
+ function showDocumentViewer() {
66
+ if (!documentViewer) {
67
+ documentViewer = createDocumentViewer();
68
+ document.body.appendChild(documentViewer);
69
+ }
70
+
71
+ // Add active classes
72
+ documentViewer.classList.add('active');
73
+ document.body.classList.add('document-viewer-active');
74
+
75
+ // Adjust main container
76
+ const mainContainer = document.querySelector('#root > div');
77
+ if (mainContainer) {
78
+ mainContainer.classList.add('split-active');
79
+ }
80
+
81
+ viewerActive = true;
82
+ console.log('Document viewer shown');
83
+ }
84
+
85
+ // Hide document viewer
86
+ function hideDocumentViewer() {
87
+ if (documentViewer) {
88
+ documentViewer.classList.remove('active');
89
+ document.body.classList.remove('document-viewer-active');
90
+
91
+ const mainContainer = document.querySelector('#root > div');
92
+ if (mainContainer) {
93
+ mainContainer.classList.remove('split-active');
94
+ }
95
+ }
96
+ viewerActive = false;
97
+ console.log('Document viewer hidden');
98
+ }
99
+
100
+ // Display document in viewer
101
+ function displayDocument(content, title = 'Document', type = 'text') {
102
+ console.log('Displaying document:', title, type);
103
+
104
+ // Show viewer if not visible
105
+ if (!viewerActive) {
106
+ showDocumentViewer();
107
+ }
108
+
109
+ const contentArea = document.getElementById('document-content');
110
+ const tabsContainer = documentViewer.querySelector('.document-tabs');
111
+
112
+ // Check if document already exists
113
+ const existingIndex = documents.findIndex(doc => doc.title === title);
114
+ if (existingIndex !== -1) {
115
+ // Switch to existing tab
116
+ activeDocIndex = existingIndex;
117
+ updateTabs();
118
+ displayContent(documents[existingIndex]);
119
+ return;
120
+ }
121
+
122
+ // Add to documents array
123
+ const docIndex = documents.length;
124
+ documents.push({ content, title, type });
125
+
126
+ // Create tab
127
+ const tab = document.createElement('button');
128
+ tab.className = 'document-tab';
129
+ tab.textContent = title.length > 20 ? title.substring(0, 20) + '...' : title;
130
+ tab.title = title;
131
+ tab.dataset.docIndex = docIndex;
132
+
133
+ tab.addEventListener('click', () => {
134
+ activeDocIndex = parseInt(tab.dataset.docIndex);
135
+ updateTabs();
136
+ displayContent(documents[activeDocIndex]);
137
+ });
138
+
139
+ // Add close button to tab
140
+ const closeTab = document.createElement('span');
141
+ closeTab.innerHTML = ' ×';
142
+ closeTab.style.cssText = 'margin-left: 8px; font-weight: bold; color: #888;';
143
+ closeTab.onclick = (e) => {
144
+ e.stopPropagation();
145
+ removeDocument(docIndex);
146
+ };
147
+ tab.appendChild(closeTab);
148
+
149
+ tabsContainer.appendChild(tab);
150
+
151
+ // Display content
152
+ activeDocIndex = docIndex;
153
+ updateTabs();
154
+ displayContent({ content, title, type });
155
+ }
156
+
157
+ // Update active tab styling
158
+ function updateTabs() {
159
+ const tabs = documentViewer.querySelectorAll('.document-tab');
160
+ tabs.forEach((tab, index) => {
161
+ if (parseInt(tab.dataset.docIndex) === activeDocIndex) {
162
+ tab.classList.add('active');
163
+ } else {
164
+ tab.classList.remove('active');
165
+ }
166
+ });
167
+ }
168
+
169
+ // Remove document and tab
170
+ function removeDocument(index) {
171
+ documents.splice(index, 1);
172
+
173
+ // Rebuild tabs
174
+ const tabsContainer = documentViewer.querySelector('.document-tabs');
175
+ tabsContainer.innerHTML = '';
176
+
177
+ documents.forEach((doc, i) => {
178
+ const tab = document.createElement('button');
179
+ tab.className = 'document-tab';
180
+ tab.textContent = doc.title.length > 20 ? doc.title.substring(0, 20) + '...' : doc.title;
181
+ tab.title = doc.title;
182
+ tab.dataset.docIndex = i;
183
+
184
+ if (i === activeDocIndex) {
185
+ tab.classList.add('active');
186
+ }
187
+
188
+ tab.addEventListener('click', () => {
189
+ activeDocIndex = i;
190
+ updateTabs();
191
+ displayContent(documents[i]);
192
+ });
193
+
194
+ const closeTab = document.createElement('span');
195
+ closeTab.innerHTML = ' ×';
196
+ closeTab.style.cssText = 'margin-left: 8px; font-weight: bold; color: #888;';
197
+ closeTab.onclick = (e) => {
198
+ e.stopPropagation();
199
+ removeDocument(i);
200
+ };
201
+ tab.appendChild(closeTab);
202
+
203
+ tabsContainer.appendChild(tab);
204
+ });
205
+
206
+ // If no documents left, show empty state
207
+ if (documents.length === 0) {
208
+ const contentArea = document.getElementById('document-content');
209
+ contentArea.innerHTML = `
210
+ <div class="document-empty-state">
211
+ <h4>No Document Selected</h4>
212
+ <p>Click on any document, image, or file in the chat to view it here</p>
213
+ </div>
214
+ `;
215
+ // Hide viewer if not pinned
216
+ const pinBtn = documentViewer.querySelector('.document-pin');
217
+ if (!pinBtn.classList.contains('pinned')) {
218
+ hideDocumentViewer();
219
+ }
220
+ } else {
221
+ // Adjust active index if needed
222
+ if (activeDocIndex >= documents.length) {
223
+ activeDocIndex = documents.length - 1;
224
+ }
225
+ displayContent(documents[activeDocIndex]);
226
+ }
227
+ }
228
+
229
+ // Display content based on type
230
+ function displayContent(doc) {
231
+ const contentArea = document.getElementById('document-content');
232
+
233
+ switch (doc.type) {
234
+ case 'image':
235
+ contentArea.innerHTML = `
236
+ <div class="document-content">
237
+ <img src="${doc.content}" alt="${doc.title}" class="document-image">
238
+ </div>
239
+ `;
240
+ break;
241
+ case 'pdf':
242
+ contentArea.innerHTML = `
243
+ <iframe src="${doc.content}" class="pdf-viewer"></iframe>
244
+ `;
245
+ break;
246
+ case 'code':
247
+ contentArea.innerHTML = `
248
+ <div class="document-code">
249
+ <pre><code>${escapeHtml(doc.content)}</code></pre>
250
+ </div>
251
+ `;
252
+ break;
253
+ case 'html':
254
+ contentArea.innerHTML = `
255
+ <div class="document-content">
256
+ ${doc.content}
257
+ </div>
258
+ `;
259
+ break;
260
+ default:
261
+ contentArea.innerHTML = `
262
+ <div class="document-content">
263
+ ${escapeHtml(doc.content)}
264
+ </div>
265
+ `;
266
+ }
267
+ }
268
+
269
+ // Escape HTML for safe display
270
+ function escapeHtml(text) {
271
+ const div = document.createElement('div');
272
+ div.textContent = text;
273
+ return div.innerHTML;
274
+ }
275
+
276
+ // Add "View in Document Viewer" buttons to file elements
277
+ function addViewerButtons() {
278
+ console.log('Scanning for file elements to add viewer buttons...');
279
+
280
+ // Enhanced file element selectors
281
+ const fileSelectors = [
282
+ '[data-testid*="element"]',
283
+ '[data-testid*="file"]',
284
+ '[data-testid*="pdf"]',
285
+ '.cl-file',
286
+ '.cl-pdf',
287
+ '[class*="file"]',
288
+ '[class*="pdf"]',
289
+ 'a[href$=".pdf"]',
290
+ 'a[download]',
291
+ 'div[class*="MuiPaper-root"]:has(a[download])',
292
+ '.message-content a',
293
+ '[title*=".pdf"]',
294
+ '[title*="PDF"]'
295
+ ];
296
+
297
+ let foundElements = 0;
298
+
299
+ fileSelectors.forEach(selector => {
300
+ try {
301
+ const elements = document.querySelectorAll(selector);
302
+ elements.forEach(element => {
303
+ if (element.querySelector('.viewer-button') || element.closest('#document-viewer')) {
304
+ return; // Already has button or is in viewer
305
+ }
306
+
307
+ // Skip if element is too small or hidden
308
+ const rect = element.getBoundingClientRect();
309
+ if (rect.width < 10 || rect.height < 10) {
310
+ return;
311
+ }
312
+
313
+ // Check if element is actually visible
314
+ const style = window.getComputedStyle(element);
315
+ if (style.display === 'none' || style.visibility === 'hidden' || style.opacity === '0') {
316
+ return;
317
+ }
318
+
319
+ foundElements++;
320
+ console.log(`Adding viewer button to element:`, element, `(selector: ${selector})`);
321
+
322
+ // Create viewer button
323
+ const viewerBtn = document.createElement('button');
324
+ viewerBtn.className = 'viewer-button';
325
+ viewerBtn.innerHTML = '👁️ View';
326
+ viewerBtn.title = 'Open in Document Viewer';
327
+
328
+ // Force button visibility with inline styles
329
+ viewerBtn.style.cssText = `
330
+ position: absolute !important;
331
+ top: 5px !important;
332
+ right: 5px !important;
333
+ padding: 6px 12px !important;
334
+ background: #ff4757 !important;
335
+ color: white !important;
336
+ border: none !important;
337
+ border-radius: 6px !important;
338
+ font-size: 12px !important;
339
+ font-weight: 500 !important;
340
+ cursor: pointer !important;
341
+ z-index: 9999 !important;
342
+ display: block !important;
343
+ visibility: visible !important;
344
+ opacity: 1 !important;
345
+ min-width: 60px !important;
346
+ text-align: center !important;
347
+ box-shadow: 0 2px 8px rgba(255, 71, 87, 0.3) !important;
348
+ `;
349
+
350
+ // Position the parent element if needed
351
+ const computedStyle = window.getComputedStyle(element);
352
+ if (computedStyle.position === 'static') {
353
+ element.style.position = 'relative';
354
+ }
355
+
356
+ viewerBtn.addEventListener('click', (e) => {
357
+ e.preventDefault();
358
+ e.stopPropagation();
359
+
360
+ console.log('Viewer button clicked for element:', element);
361
+
362
+ // Find download link or href
363
+ let link = element.href ||
364
+ element.getAttribute('href') ||
365
+ element.querySelector('a[href]')?.href ||
366
+ element.querySelector('[href]')?.getAttribute('href');
367
+
368
+ let fileName = element.textContent?.trim() ||
369
+ element.getAttribute('title') ||
370
+ element.querySelector('[title]')?.title ||
371
+ element.querySelector('a')?.textContent?.trim() ||
372
+ `Document ${documents.length + 1}`;
373
+
374
+ console.log('Found link:', link, 'fileName:', fileName);
375
+
376
+ if (link) {
377
+ if (link.endsWith('.pdf') || link.includes('pdf') || fileName.toLowerCase().includes('pdf')) {
378
+ displayDocument(link, fileName, 'pdf');
379
+ } else if (link.match(/\.(jpg|jpeg|png|gif|webp)$/i)) {
380
+ displayDocument(link, fileName, 'image');
381
+ } else {
382
+ // Try to fetch content
383
+ fetch(link)
384
+ .then(res => res.text())
385
+ .then(content => {
386
+ const type = link.endsWith('.html') ? 'html' : 'text';
387
+ displayDocument(content, fileName, type);
388
+ })
389
+ .catch(err => {
390
+ console.error('Error loading document:', err);
391
+ displayDocument('Error loading document content', fileName, 'text');
392
+ });
393
+ }
394
+ } else {
395
+ // If no link, display the element's content
396
+ const content = element.textContent || element.innerHTML;
397
+ displayDocument(content, fileName, 'html');
398
+ }
399
+ });
400
+
401
+ element.appendChild(viewerBtn);
402
+ });
403
+ } catch (error) {
404
+ console.warn(`Error processing selector ${selector}:`, error);
405
+ }
406
+ });
407
+
408
+ console.log(`Added viewer buttons to ${foundElements} elements`);
409
+ }
410
+
411
+ // Attach click handlers to documents
412
+ function attachDocumentHandlers() {
413
+ document.addEventListener('click', (e) => {
414
+ const target = e.target;
415
+
416
+ // Don't process clicks on viewer buttons
417
+ if (target.classList.contains('viewer-button')) {
418
+ return;
419
+ }
420
+
421
+ console.log('Click detected on:', target.tagName, target.className, target);
422
+
423
+ // Enhanced detection for Chainlit file elements
424
+ const fileSelectors = [
425
+ '[data-testid*="element"]',
426
+ '[data-testid*="file"]',
427
+ '[data-testid*="pdf"]',
428
+ '.cl-file',
429
+ '.cl-pdf',
430
+ '[class*="file"]',
431
+ '[class*="pdf"]',
432
+ 'a[href$=".pdf"]',
433
+ 'a[download]'
434
+ ];
435
+
436
+ let fileElement = null;
437
+ for (const selector of fileSelectors) {
438
+ fileElement = target.closest(selector);
439
+ if (fileElement && !fileElement.closest('#document-viewer')) {
440
+ break;
441
+ }
442
+ }
443
+
444
+ if (fileElement) {
445
+ console.log('File element detected:', fileElement);
446
+ e.preventDefault();
447
+ e.stopPropagation();
448
+
449
+ // Try to find the download link within the element
450
+ const downloadLink = fileElement.href ||
451
+ fileElement.querySelector('a[href]')?.href ||
452
+ fileElement.querySelector('[href]')?.getAttribute('href');
453
+
454
+ if (downloadLink) {
455
+ const fileName = fileElement.textContent ||
456
+ fileElement.querySelector('[title]')?.title ||
457
+ fileElement.getAttribute('title') ||
458
+ 'Document ' + (documents.length + 1);
459
+
460
+ console.log('Opening document:', fileName, downloadLink);
461
+
462
+ if (downloadLink.endsWith('.pdf')) {
463
+ displayDocument(downloadLink, fileName, 'pdf');
464
+ } else {
465
+ // Try to fetch and display content
466
+ fetch(downloadLink)
467
+ .then(res => res.text())
468
+ .then(content => {
469
+ const type = downloadLink.endsWith('.html') ? 'html' : 'text';
470
+ displayDocument(content, fileName, type);
471
+ })
472
+ .catch(err => {
473
+ console.error('Error loading document:', err);
474
+ displayDocument('Error loading document content', fileName, 'text');
475
+ });
476
+ }
477
+ }
478
+ return;
479
+ }
480
+
481
+ // Check for images
482
+ if (target.tagName === 'IMG' && target.src && !target.closest('#document-viewer')) {
483
+ e.preventDefault();
484
+ e.stopPropagation();
485
+ const title = target.alt || 'Image ' + (documents.length + 1);
486
+ displayDocument(target.src, title, 'image');
487
+ return;
488
+ }
489
+
490
+ // Check for code blocks
491
+ const codeBlock = target.closest('pre');
492
+ if (codeBlock && !codeBlock.closest('#document-viewer')) {
493
+ e.preventDefault();
494
+ e.stopPropagation();
495
+ const content = codeBlock.textContent;
496
+ const title = 'Code Block ' + (documents.length + 1);
497
+ displayDocument(content, title, 'code');
498
+ return;
499
+ }
500
+ }, true);
501
+ }
502
+
503
+ // Periodically scan for new file elements and add viewer buttons
504
+ function scanForNewElements() {
505
+ addViewerButtons();
506
+ }
507
+
508
+ // Initialize when DOM is ready
509
+ function initialize() {
510
+ console.log('Initializing Chainlit Split Screen Document Viewer');
511
+
512
+ // Add a global helper function to manually open documents
513
+ window.openInDocumentViewer = function(url, title, type = 'pdf') {
514
+ console.log('Manual document viewer open called:', url, title, type);
515
+ displayDocument(url, title, type);
516
+ };
517
+
518
+ // Create viewer but keep it hidden
519
+ documentViewer = createDocumentViewer();
520
+ document.body.appendChild(documentViewer);
521
+
522
+ // Attach handlers
523
+ attachDocumentHandlers();
524
+
525
+ // Add initial viewer buttons
526
+ addViewerButtons();
527
+
528
+ // Scan for new elements periodically (more frequently for better responsiveness)
529
+ setInterval(scanForNewElements, 1000);
530
+
531
+ // Also scan when new messages are added
532
+ const observer = new MutationObserver((mutations) => {
533
+ let shouldScan = false;
534
+ mutations.forEach((mutation) => {
535
+ if (mutation.type === 'childList' && mutation.addedNodes.length > 0) {
536
+ mutation.addedNodes.forEach((node) => {
537
+ if (node.nodeType === Node.ELEMENT_NODE) {
538
+ // Check if new element contains file-like content
539
+ if (node.querySelector && (
540
+ node.querySelector('a[download]') ||
541
+ node.querySelector('[class*="file"]') ||
542
+ node.querySelector('[data-testid*="file"]') ||
543
+ node.textContent?.toLowerCase().includes('pdf')
544
+ )) {
545
+ shouldScan = true;
546
+ }
547
+ }
548
+ });
549
+ }
550
+ });
551
+ if (shouldScan) {
552
+ console.log('New content detected, scanning for file elements...');
553
+ setTimeout(addViewerButtons, 500); // Small delay to let DOM settle
554
+ }
555
+ });
556
+
557
+ observer.observe(document.body, {
558
+ childList: true,
559
+ subtree: true
560
+ });
561
+
562
+ // Add mobile toggle button if needed
563
+ if (window.innerWidth <= 768) {
564
+ const toggleBtn = document.createElement('button');
565
+ toggleBtn.className = 'mobile-doc-toggle';
566
+ toggleBtn.innerHTML = '📄';
567
+ toggleBtn.style.display = viewerActive ? 'flex' : 'none';
568
+ toggleBtn.addEventListener('click', () => {
569
+ if (viewerActive) {
570
+ hideDocumentViewer();
571
+ toggleBtn.style.display = 'none';
572
+ } else {
573
+ showDocumentViewer();
574
+ }
575
+ });
576
+ document.body.appendChild(toggleBtn);
577
+ }
578
+
579
+ console.log('Document Viewer initialized (hidden by default)');
580
+ }
581
+
582
+ // Wait for DOM to be ready
583
+ if (document.readyState === 'loading') {
584
+ document.addEventListener('DOMContentLoaded', initialize);
585
+ } else {
586
+ // Delay initialization to ensure Chainlit is fully loaded
587
+ setTimeout(initialize, 1000);
588
+
589
+ // Additional initialization after a longer delay
590
+ setTimeout(() => {
591
+ console.log('Additional document viewer initialization...');
592
+ addViewerButtons();
593
+
594
+ // Force scan every few seconds in case elements are missed
595
+ setInterval(() => {
596
+ console.log('Force scanning for new elements...');
597
+ addViewerButtons();
598
+ }, 3000);
599
+ }, 3000);
600
+ }
601
+
602
+ // Export functions for external use
603
+ window.ChainlitDocumentViewer = {
604
+ displayDocument,
605
+ showDocumentViewer,
606
+ hideDocumentViewer,
607
+ addViewerButtons,
608
+ openInDocumentViewer: function(url, title, type = 'pdf') {
609
+ displayDocument(url, title, type);
610
+ }
611
+ };
612
+ })();