nodebb-plugin-pdf-secure 1.2.21 → 1.2.23

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 (2) hide show
  1. package/package.json +1 -1
  2. package/static/viewer.html +40 -13
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nodebb-plugin-pdf-secure",
3
- "version": "1.2.21",
3
+ "version": "1.2.23",
4
4
  "description": "Secure PDF viewer plugin for NodeBB - prevents downloading, enables canvas-only rendering with Premium group support",
5
5
  "main": "library.js",
6
6
  "repository": {
@@ -1187,7 +1187,7 @@
1187
1187
  height: calc(var(--bottom-bar-height) + var(--safe-area-bottom));
1188
1188
  background: var(--bg-secondary);
1189
1189
  border-top: 1px solid var(--border-color);
1190
- z-index: 100;
1190
+ z-index: 260; /* Above backdrop (250) so dropdowns inside are clickable */
1191
1191
  padding: 0 8px;
1192
1192
  padding-bottom: var(--safe-area-bottom);
1193
1193
  /* Flex layout: scrollable tools + fixed fullscreen button */
@@ -1381,13 +1381,15 @@
1381
1381
  /* ==========================================
1382
1382
  FULLSCREEN STATE (simulated fullscreen on mobile)
1383
1383
  ========================================== */
1384
- /* Ensure bottom toolbar is visible and viewer container makes room for it */
1385
- body.viewer-fullscreen #bottomToolbar {
1386
- display: flex;
1387
- }
1384
+ /* Ensure bottom toolbar + viewerContainer adjust in fullscreen on mobile/tablet only */
1385
+ @media (max-width: 1024px) {
1386
+ body.viewer-fullscreen #bottomToolbar {
1387
+ display: flex;
1388
+ }
1388
1389
 
1389
- body.viewer-fullscreen #viewerContainer {
1390
- bottom: calc(var(--bottom-bar-height) + var(--safe-area-bottom));
1390
+ body.viewer-fullscreen #viewerContainer {
1391
+ bottom: calc(var(--bottom-bar-height) + var(--safe-area-bottom));
1392
+ }
1391
1393
  }
1392
1394
 
1393
1395
  /* ==========================================
@@ -1582,7 +1584,7 @@
1582
1584
  align-items: center;
1583
1585
  justify-content: center;
1584
1586
  background: linear-gradient(180deg, rgba(31,31,31,0.95) 0%, rgba(20,20,20,0.98) 100%);
1585
- z-index: 5;
1587
+ z-index: 15;
1586
1588
  text-align: center;
1587
1589
  padding: 20px;
1588
1590
  }
@@ -2249,8 +2251,16 @@
2249
2251
  pageEl.appendChild(overlay);
2250
2252
  }
2251
2253
 
2254
+ function isOverlayTampered(overlay) {
2255
+ var s = overlay.style;
2256
+ return s.position !== 'absolute' || s.display !== 'flex' ||
2257
+ s.zIndex !== '15' || s.opacity !== '1' ||
2258
+ s.visibility !== 'visible' || s.pointerEvents !== 'auto';
2259
+ }
2260
+
2252
2261
  function resetOverlayCSS(overlay) {
2253
- overlay.style.cssText = 'position:absolute;top:0;left:0;right:0;bottom:0;display:flex;z-index:5;opacity:1;visibility:visible;pointer-events:auto;';
2262
+ if (!isOverlayTampered(overlay)) return; // Skip if already correct (prevents observer loop)
2263
+ overlay.style.cssText = 'position:absolute;top:0;left:0;right:0;bottom:0;display:flex;z-index:15;opacity:1;visibility:visible;pointer-events:auto;';
2254
2264
  }
2255
2265
 
2256
2266
  function applyPageLocks() {
@@ -2313,9 +2323,11 @@
2313
2323
  for (var i = 0; i < mutations.length; i++) {
2314
2324
  var target = mutations[i].target;
2315
2325
  if (!target || !target.classList) continue;
2316
- // Overlay CSS tampered - reset it
2326
+ // Overlay CSS tampered - reset only if values actually differ
2317
2327
  if (target.classList.contains('page-lock-overlay')) {
2318
- resetOverlayCSS(target);
2328
+ if (isOverlayTampered(target)) {
2329
+ resetOverlayCSS(target);
2330
+ }
2319
2331
  }
2320
2332
  // Blur class removed from locked page - re-add it
2321
2333
  if (target.classList.contains('page') && !target.classList.contains('page-locked-blur')) {
@@ -2648,10 +2660,13 @@
2648
2660
  function closeAllDropdowns() {
2649
2661
  // Clean up swipe listeners
2650
2662
  if (swipeAbortController) { swipeAbortController.abort(); swipeAbortController = null; }
2651
- // Reset inline transform from swipe gesture
2663
+ // Reset inline transform and fixed positioning from dropdown
2652
2664
  [highlightDropdown, drawDropdown, shapesDropdown, overflowDropdown].forEach(dd => {
2653
2665
  dd.style.transform = '';
2654
2666
  dd.style.transition = '';
2667
+ dd.style.position = '';
2668
+ dd.style.top = '';
2669
+ dd.style.left = '';
2655
2670
  });
2656
2671
  highlightDropdown.classList.remove('visible');
2657
2672
  drawDropdown.classList.remove('visible');
@@ -2673,10 +2688,19 @@
2673
2688
  dropdown.insertBefore(handle, dropdown.firstChild);
2674
2689
  }
2675
2690
  dropdown.classList.add('visible');
2676
- // Show backdrop on mobile/tablet portrait
2677
2691
  if (useBottomSheet) {
2692
+ // Show backdrop on mobile/tablet portrait
2678
2693
  dropdownBackdrop.classList.add('visible');
2679
2694
  setupBottomSheetSwipe(dropdown);
2695
+ } else {
2696
+ // Desktop/tablet landscape: use fixed positioning to escape toolbar overflow clipping
2697
+ const wrapper = e.target.closest('.toolbarBtnWithDropdown');
2698
+ if (wrapper) {
2699
+ const rect = wrapper.getBoundingClientRect();
2700
+ dropdown.style.position = 'fixed';
2701
+ dropdown.style.top = (rect.bottom + 4) + 'px';
2702
+ dropdown.style.left = rect.left + 'px';
2703
+ }
2680
2704
  }
2681
2705
  }
2682
2706
  }
@@ -2907,6 +2931,9 @@
2907
2931
 
2908
2932
  // Annotation Layer with Persistence
2909
2933
  async function injectAnnotationLayer(pageNum) {
2934
+ // Skip annotation injection on locked pages
2935
+ if (premiumInfo && !premiumInfo.isPremium && pageNum > 1) return;
2936
+
2910
2937
  const pageView = pdfViewer.getPageView(pageNum - 1);
2911
2938
  if (!pageView?.div) return;
2912
2939