nodebb-plugin-pdf-secure2 1.2.38 → 1.3.1

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.
Binary file
@@ -1,161 +0,0 @@
1
- import { getDocument, GlobalWorkerOptions } from './pdf.min.mjs';
2
-
3
- GlobalWorkerOptions.workerSrc = new URL('./pdf.worker.min.mjs', import.meta.url).href;
4
-
5
- // Listen for NodeBB SPA navigations (jQuery event)
6
- $(window).on('action:ajaxify.end', function () {
7
- interceptPdfLinks();
8
- });
9
-
10
- // Also run immediately for the current page
11
- interceptPdfLinks();
12
-
13
- function interceptPdfLinks() {
14
- var postContents = document.querySelectorAll('[component="post/content"]');
15
-
16
- postContents.forEach(function (content, idx) {
17
- var pdfLinks = content.querySelectorAll('a[href$=".pdf"], a[href$=".PDF"]');
18
-
19
- pdfLinks.forEach(function (link) {
20
- if (link.dataset.pdfSecure) return;
21
- link.dataset.pdfSecure = 'true';
22
-
23
- var href = link.getAttribute('href');
24
- var parts = href.split('/');
25
- var filename = parts[parts.length - 1];
26
-
27
- var container = document.createElement('div');
28
- container.className = 'pdf-secure-inline';
29
- container.innerHTML =
30
- '<div class="pdf-secure-inline-header">' +
31
- '<i class="fa fa-file-pdf-o"></i> ' +
32
- '<span class="pdf-secure-filename">' + escapeHtml(link.textContent || filename) + '</span>' +
33
- '</div>' +
34
- '<div class="pdf-secure-inline-body">' +
35
- '<div class="pdf-secure-loading">Loading PDF...</div>' +
36
- '<div class="pdf-secure-error"></div>' +
37
- '<canvas class="pdf-secure-canvas"></canvas>' +
38
- '</div>' +
39
- '<div class="pdf-secure-inline-footer">' +
40
- '<button class="pdf-secure-prev" disabled>&#8249; Prev</button>' +
41
- '<span class="pdf-secure-page-info"></span>' +
42
- '<button class="pdf-secure-next" disabled>Next &#8250;</button>' +
43
- '</div>';
44
-
45
- link.replaceWith(container);
46
-
47
- loadPdf(container, filename);
48
- });
49
- });
50
- }
51
-
52
- async function loadPdf(container, filename) {
53
- var loadingEl = container.querySelector('.pdf-secure-loading');
54
- var errorEl = container.querySelector('.pdf-secure-error');
55
- var canvas = container.querySelector('.pdf-secure-canvas');
56
- var footer = container.querySelector('.pdf-secure-inline-footer');
57
- var prevBtn = container.querySelector('.pdf-secure-prev');
58
- var nextBtn = container.querySelector('.pdf-secure-next');
59
- var pageInfo = container.querySelector('.pdf-secure-page-info');
60
- var bodyEl = container.querySelector('.pdf-secure-inline-body');
61
-
62
- function showError(msg) {
63
- loadingEl.style.display = 'none';
64
- canvas.style.display = 'none';
65
- errorEl.style.display = 'flex';
66
- errorEl.textContent = msg;
67
- }
68
-
69
- try {
70
- // Step 1: Fetch nonce
71
- var nonceUrl = config.relative_path + '/api/v3/plugins/pdf-secure/nonce?file=' + encodeURIComponent(filename);
72
-
73
- var nonceRes = await fetch(nonceUrl, {
74
- credentials: 'same-origin',
75
- headers: { 'x-csrf-token': config.csrf_token },
76
- });
77
-
78
- if (!nonceRes.ok) {
79
- showError(nonceRes.status === 401 ? 'Log in to view this PDF.' : 'Failed to load PDF (' + nonceRes.status + ')');
80
- return;
81
- }
82
-
83
- var result = await nonceRes.json();
84
- var nonce = result.response.nonce;
85
-
86
- // Step 2: Fetch PDF binary
87
- var pdfUrl = config.relative_path + '/api/v3/plugins/pdf-secure/pdf-data?nonce=' + encodeURIComponent(nonce);
88
-
89
- var pdfRes = await fetch(pdfUrl, { credentials: 'same-origin' });
90
-
91
- if (!pdfRes.ok) {
92
- showError('Failed to load PDF data (' + pdfRes.status + ')');
93
- return;
94
- }
95
-
96
- var pdfArrayBuffer = await pdfRes.arrayBuffer();
97
-
98
- // Step 3: Render PDF
99
- var pdfDoc = await getDocument({ data: new Uint8Array(pdfArrayBuffer) }).promise;
100
- var totalPages = pdfDoc.numPages;
101
-
102
- loadingEl.style.display = 'none';
103
- canvas.style.display = 'block';
104
-
105
- // Security: scoped to container
106
- container.addEventListener('contextmenu', function (e) { e.preventDefault(); });
107
- container.addEventListener('dragstart', function (e) { e.preventDefault(); });
108
- container.addEventListener('selectstart', function (e) { e.preventDefault(); });
109
-
110
- var ctx = canvas.getContext('2d');
111
- var currentPage = 1;
112
- var rendering = false;
113
-
114
- async function renderPage(pageNum) {
115
- if (rendering) return;
116
- rendering = true;
117
-
118
- try {
119
- var page = await pdfDoc.getPage(pageNum);
120
- var containerWidth = bodyEl.clientWidth - 20;
121
- var vp = page.getViewport({ scale: 1 });
122
- var scale = Math.min(containerWidth / vp.width, 2.0);
123
- var scaled = page.getViewport({ scale: scale });
124
-
125
- canvas.width = scaled.width;
126
- canvas.height = scaled.height;
127
-
128
- await page.render({ canvasContext: ctx, viewport: scaled }).promise;
129
-
130
- currentPage = pageNum;
131
- pageInfo.textContent = currentPage + ' / ' + totalPages;
132
- prevBtn.disabled = currentPage <= 1;
133
- nextBtn.disabled = currentPage >= totalPages;
134
- } catch (err) {
135
- showError('Error rendering page.');
136
- }
137
- rendering = false;
138
- }
139
-
140
- await renderPage(1);
141
-
142
- if (totalPages > 1) {
143
- footer.style.display = 'flex';
144
- prevBtn.addEventListener('click', function () {
145
- if (currentPage > 1) renderPage(currentPage - 1);
146
- });
147
- nextBtn.addEventListener('click', function () {
148
- if (currentPage < totalPages) renderPage(currentPage + 1);
149
- });
150
- }
151
-
152
- } catch (err) {
153
- showError('Failed to load PDF.');
154
- }
155
- }
156
-
157
- function escapeHtml(str) {
158
- var d = document.createElement('div');
159
- d.textContent = str;
160
- return d.innerHTML;
161
- }