@aprova.ch/ngx-next-pdf-viewer 20.0.8 → 20.0.10
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.
|
@@ -28,6 +28,16 @@ import * as pdfjsLib from 'pdfjs-dist';
|
|
|
28
28
|
*/
|
|
29
29
|
const NGX_PDF_WORKER_SRC = new InjectionToken('NGX_PDF_WORKER_SRC', { factory: () => 'assets/pdf.worker.min.mjs' });
|
|
30
30
|
|
|
31
|
+
// ── RSA-2048 public key (SPKI DER, base64) ────────────────────────────────
|
|
32
|
+
// Generated with api-keys/generate.js. The matching private key lives in
|
|
33
|
+
// api-keys/private.key (never ship that file with the library).
|
|
34
|
+
const API_PUBLIC_KEY_B64 = 'MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA32o40ciAzk12XQ7RQpjy' +
|
|
35
|
+
'YUa22NNDh4jlntE8UPls2PDZLcSTORMyZTASnXzzUq4RodplBaySFbQUHNwYzYYT' +
|
|
36
|
+
'H8+/GZPInigDqpVVJ+8sHiI+5jA9b4hl6alGzBmnSKaGnJYxy9DnUG/NM5cGK6+' +
|
|
37
|
+
'MaZJrnjKrrWjQ2ttkuXRmDHLwcvfva06Lv8BEBDmbt1dVnTGPjwUjJelZeu5xVZU' +
|
|
38
|
+
'gm9QlbhVR0P+vUM11jWzoq7W1bzyoDuToqZ+tQCLSVZ7Pz8FdHn3Wh/Qnw/VhqW' +
|
|
39
|
+
'IeaHTgswOB1Cti0Oh1o+tpuv3LgIeGyZxyudnWnkDInQ2LvCP9z8aLVI9io/RA3a' +
|
|
40
|
+
'PiwwIDAQAB';
|
|
31
41
|
// ──────────────────────────────────────────────
|
|
32
42
|
// Component
|
|
33
43
|
// ──────────────────────────────────────────────
|
|
@@ -55,6 +65,25 @@ class NgxNextPdfViewerComponent {
|
|
|
55
65
|
get l() {
|
|
56
66
|
return { ...NgxNextPdfViewerComponent.DEFAULT_LABELS, ...this.labels };
|
|
57
67
|
}
|
|
68
|
+
// ── One-time global CSS for the pdfjs text layer ─────────────────────────
|
|
69
|
+
static { this.textLayerStylesInjected = false; }
|
|
70
|
+
static injectTextLayerStyles() {
|
|
71
|
+
if (NgxNextPdfViewerComponent.textLayerStylesInjected)
|
|
72
|
+
return;
|
|
73
|
+
const style = document.createElement('style');
|
|
74
|
+
style.id = 'npv-text-layer-styles';
|
|
75
|
+
style.textContent =
|
|
76
|
+
'.textLayer{position:absolute;top:0;left:0;overflow:hidden;line-height:1;' +
|
|
77
|
+
'text-size-adjust:none;forced-color-adjust:none;transform-origin:0 0;z-index:0}' +
|
|
78
|
+
'.textLayer :is(span,br){color:transparent;position:absolute;white-space:pre;' +
|
|
79
|
+
'cursor:text;transform-origin:0% 0%}' +
|
|
80
|
+
'.textLayer>:not(.markedContent),' +
|
|
81
|
+
'.textLayer .markedContent span:not(.markedContent){z-index:1}' +
|
|
82
|
+
'.textLayer ::selection{background:rgba(0,120,215,.25);color:transparent}' +
|
|
83
|
+
'.textLayer br::selection{background:transparent}';
|
|
84
|
+
document.head.appendChild(style);
|
|
85
|
+
NgxNextPdfViewerComponent.textLayerStylesInjected = true;
|
|
86
|
+
}
|
|
58
87
|
constructor(cdr, zone, el, workerSrc) {
|
|
59
88
|
this.cdr = cdr;
|
|
60
89
|
this.zone = zone;
|
|
@@ -73,6 +102,18 @@ class NgxNextPdfViewerComponent {
|
|
|
73
102
|
this.initialZoom = 1.5;
|
|
74
103
|
/** Override any subset of the viewer's user-visible strings */
|
|
75
104
|
this.labels = {};
|
|
105
|
+
/** Show / hide the zoom buttons and percentage label */
|
|
106
|
+
this.showZoom = true;
|
|
107
|
+
/** Show / hide the rotate-left and rotate-right buttons */
|
|
108
|
+
this.showRotation = true;
|
|
109
|
+
/** Show / hide the previous/next page buttons and page counter */
|
|
110
|
+
this.showPageNavigation = true;
|
|
111
|
+
/** Show / hide the previous/next annotation buttons and annotation counter */
|
|
112
|
+
this.showAnnotationNavigation = true;
|
|
113
|
+
/** Show / hide the select-area / select-text toggle button */
|
|
114
|
+
this.showSelectionMode = true;
|
|
115
|
+
/** Show / hide the search button and search bar */
|
|
116
|
+
this.showSearch = true;
|
|
76
117
|
// ── Outputs ─────────────────────────────────
|
|
77
118
|
/** Fired when the user clicks a single annotation box */
|
|
78
119
|
this.boxClicked = new EventEmitter();
|
|
@@ -104,9 +145,13 @@ class NgxNextPdfViewerComponent {
|
|
|
104
145
|
// ── Loading ──────────────────────────────────
|
|
105
146
|
this.loading = false;
|
|
106
147
|
this.loadError = false;
|
|
148
|
+
// ── API-key state ────────────────────────────
|
|
149
|
+
/** True once the current apiKey has been verified against the embedded public key. */
|
|
150
|
+
this.apiKeyValid = false;
|
|
107
151
|
this.renderTasks = new Map();
|
|
108
152
|
this.textLayers = new Map();
|
|
109
153
|
pdfjsLib.GlobalWorkerOptions.workerSrc = workerSrc;
|
|
154
|
+
NgxNextPdfViewerComponent.injectTextLayerStyles();
|
|
110
155
|
}
|
|
111
156
|
ngAfterViewInit() {
|
|
112
157
|
if (typeof this.initialZoom === 'number') {
|
|
@@ -124,6 +169,15 @@ class NgxNextPdfViewerComponent {
|
|
|
124
169
|
});
|
|
125
170
|
}
|
|
126
171
|
ngOnChanges(changes) {
|
|
172
|
+
if (changes['apiKey']) {
|
|
173
|
+
this.apiKeyValid = false;
|
|
174
|
+
if (this.apiKey) {
|
|
175
|
+
this.verifyApiKey(this.apiKey).then(valid => {
|
|
176
|
+
this.apiKeyValid = valid;
|
|
177
|
+
this.cdr.detectChanges();
|
|
178
|
+
});
|
|
179
|
+
}
|
|
180
|
+
}
|
|
127
181
|
if (changes['blob'] && this.blob) {
|
|
128
182
|
console.log('load new file');
|
|
129
183
|
this.loadPdf(this.blob);
|
|
@@ -144,6 +198,54 @@ class NgxNextPdfViewerComponent {
|
|
|
144
198
|
this.pdfDoc?.destroy();
|
|
145
199
|
}
|
|
146
200
|
// ─────────────────────────────────────────────
|
|
201
|
+
// API-key verification (Web Crypto API)
|
|
202
|
+
// ─────────────────────────────────────────────
|
|
203
|
+
/** Decodes a base64url string to a Uint8Array (no external dependencies). */
|
|
204
|
+
b64urlToBytes(b64url) {
|
|
205
|
+
const b64 = b64url.replace(/-/g, '+').replace(/_/g, '/');
|
|
206
|
+
const padded = b64.padEnd(b64.length + (4 - (b64.length % 4)) % 4, '=');
|
|
207
|
+
return Uint8Array.from(atob(padded), c => c.charCodeAt(0));
|
|
208
|
+
}
|
|
209
|
+
/**
|
|
210
|
+
* Verifies an API key against the embedded RSA-2048 public key.
|
|
211
|
+
* Format: <payload_base64url>.<signature_base64url>
|
|
212
|
+
*
|
|
213
|
+
* Returns false when:
|
|
214
|
+
* - the format is invalid
|
|
215
|
+
* - the RSA signature does not match
|
|
216
|
+
* - the key type is "trial" and its expiry timestamp has passed
|
|
217
|
+
*/
|
|
218
|
+
async verifyApiKey(key) {
|
|
219
|
+
try {
|
|
220
|
+
const dotIndex = key.lastIndexOf('.');
|
|
221
|
+
if (dotIndex < 1)
|
|
222
|
+
return false;
|
|
223
|
+
const payloadB64 = key.slice(0, dotIndex);
|
|
224
|
+
const sigB64 = key.slice(dotIndex + 1);
|
|
225
|
+
// Import the embedded public key (SPKI DER, standard base64 → CryptoKey)
|
|
226
|
+
const derBytes = Uint8Array.from(atob(API_PUBLIC_KEY_B64), c => c.charCodeAt(0));
|
|
227
|
+
const cryptoKey = await crypto.subtle.importKey('spki', derBytes, { name: 'RSASSA-PKCS1-v1_5', hash: 'SHA-256' }, false, ['verify']);
|
|
228
|
+
// Verify RSA signature (computed over the UTF-8 bytes of the payload string)
|
|
229
|
+
const data = new TextEncoder().encode(payloadB64);
|
|
230
|
+
const sig = this.b64urlToBytes(sigB64);
|
|
231
|
+
const signatureValid = await crypto.subtle.verify('RSASSA-PKCS1-v1_5', cryptoKey, sig, data);
|
|
232
|
+
if (!signatureValid)
|
|
233
|
+
return false;
|
|
234
|
+
// Decode payload and check expiry for trial keys
|
|
235
|
+
const payloadJson = atob(payloadB64.replace(/-/g, '+').replace(/_/g, '/')
|
|
236
|
+
.padEnd(payloadB64.length + (4 - (payloadB64.length % 4)) % 4, '='));
|
|
237
|
+
const payload = JSON.parse(payloadJson);
|
|
238
|
+
if (payload.type === 'trial' && payload.expires != null) {
|
|
239
|
+
if (Date.now() > payload.expires)
|
|
240
|
+
return false; // trial key expired
|
|
241
|
+
}
|
|
242
|
+
return true;
|
|
243
|
+
}
|
|
244
|
+
catch {
|
|
245
|
+
return false;
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
// ─────────────────────────────────────────────
|
|
147
249
|
// PDF loading & rendering
|
|
148
250
|
// ─────────────────────────────────────────────
|
|
149
251
|
async loadPdf(blob) {
|
|
@@ -370,7 +472,9 @@ class NgxNextPdfViewerComponent {
|
|
|
370
472
|
const wasSelected = this.clickedBoxKey === key;
|
|
371
473
|
this.clickedBoxKey = wasSelected ? null : key;
|
|
372
474
|
this.cdr.detectChanges();
|
|
373
|
-
this.
|
|
475
|
+
if (this.apiKeyValid) {
|
|
476
|
+
this.boxClicked.emit({ box, selected: !wasSelected });
|
|
477
|
+
}
|
|
374
478
|
}
|
|
375
479
|
// ─────────────────────────────────────────────
|
|
376
480
|
// Drag-select
|
|
@@ -445,7 +549,9 @@ class NgxNextPdfViewerComponent {
|
|
|
445
549
|
onContextMenuAction(item) {
|
|
446
550
|
this.ctxVisible = false;
|
|
447
551
|
const selected = this.annotations.filter(b => this.multiSelectedKeys.has(this.boxKey(b)));
|
|
448
|
-
this.
|
|
552
|
+
if (this.apiKeyValid) {
|
|
553
|
+
this.boxesSelected.emit({ boxes: selected, action: item.action });
|
|
554
|
+
}
|
|
449
555
|
this.multiSelectedKeys.clear();
|
|
450
556
|
this.cdr.detectChanges();
|
|
451
557
|
}
|
|
@@ -600,7 +706,9 @@ class NgxNextPdfViewerComponent {
|
|
|
600
706
|
this.clickedBoxKey = this.boxKey(box);
|
|
601
707
|
this.cdr.detectChanges();
|
|
602
708
|
this.scrollToBox(box);
|
|
603
|
-
this.
|
|
709
|
+
if (this.apiKeyValid) {
|
|
710
|
+
this.boxClicked.emit({ box, selected: true });
|
|
711
|
+
}
|
|
604
712
|
}
|
|
605
713
|
// ─────────────────────────────────────────────
|
|
606
714
|
// Toolbar – selection mode
|
|
@@ -615,6 +723,23 @@ class NgxNextPdfViewerComponent {
|
|
|
615
723
|
}
|
|
616
724
|
this.cdr.detectChanges();
|
|
617
725
|
}
|
|
726
|
+
/**
|
|
727
|
+
* Returns the CSS matrix() transform that aligns the pdfjs text layer
|
|
728
|
+
* (always sized in *unrotated* page space) with the rotated canvas.
|
|
729
|
+
* pi.width / pi.height are the *canvas* (rotated) pixel dimensions.
|
|
730
|
+
*/
|
|
731
|
+
textLayerTransform(totalRotation, canvasW, canvasH) {
|
|
732
|
+
const norm = ((totalRotation % 360) + 360) % 360;
|
|
733
|
+
switch (norm) {
|
|
734
|
+
// 90 ° CW: (x,y) → (H−y, x) where H = canvas width after swap
|
|
735
|
+
case 90: return `matrix(0,1,-1,0,${canvasW},0)`;
|
|
736
|
+
// 180 °: (x,y) → (W−x, H−y)
|
|
737
|
+
case 180: return `matrix(-1,0,0,-1,${canvasW},${canvasH})`;
|
|
738
|
+
// 270 ° CW: (x,y) → (y, W−x) where W = canvas height after swap
|
|
739
|
+
case 270: return `matrix(0,-1,1,0,0,${canvasH})`;
|
|
740
|
+
default: return '';
|
|
741
|
+
}
|
|
742
|
+
}
|
|
618
743
|
async renderTextLayer(pageNum) {
|
|
619
744
|
if (!this.pdfDoc)
|
|
620
745
|
return;
|
|
@@ -629,9 +754,15 @@ class NgxNextPdfViewerComponent {
|
|
|
629
754
|
const totalRotation = (page.rotate + this.userRotation) % 360;
|
|
630
755
|
const viewport = page.getViewport({ scale: this.zoom, rotation: totalRotation });
|
|
631
756
|
const div = document.createElement('div');
|
|
632
|
-
|
|
633
|
-
div.
|
|
634
|
-
|
|
757
|
+
// 'textLayer' class is required for the injected pdfjs CSS rules to apply.
|
|
758
|
+
div.className = 'npv-text-layer textLayer';
|
|
759
|
+
// pdfjs sizes the container with calc(var(--scale-factor) * rawPageWidth).
|
|
760
|
+
// Without this variable every calc() is invalid → container collapses to 0.
|
|
761
|
+
div.style.setProperty('--scale-factor', String(this.zoom));
|
|
762
|
+
// pdfjs always lays text out in unrotated page space; align with rotated canvas.
|
|
763
|
+
const transform = this.textLayerTransform(totalRotation, pi.width, pi.height);
|
|
764
|
+
if (transform)
|
|
765
|
+
div.style.transform = transform;
|
|
635
766
|
wrapper.appendChild(div);
|
|
636
767
|
const textLayer = new pdfjsLib.TextLayer({
|
|
637
768
|
textContentSource: page.streamTextContent(),
|
|
@@ -642,7 +773,10 @@ class NgxNextPdfViewerComponent {
|
|
|
642
773
|
try {
|
|
643
774
|
await textLayer.render();
|
|
644
775
|
}
|
|
645
|
-
catch (
|
|
776
|
+
catch (e) {
|
|
777
|
+
if (e?.name !== 'AbortException')
|
|
778
|
+
console.error('TextLayer render error:', e);
|
|
779
|
+
}
|
|
646
780
|
page.cleanup();
|
|
647
781
|
}
|
|
648
782
|
removeTextLayer(pageNum) {
|
|
@@ -686,7 +820,7 @@ class NgxNextPdfViewerComponent {
|
|
|
686
820
|
}
|
|
687
821
|
}
|
|
688
822
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: NgxNextPdfViewerComponent, deps: [{ token: i0.ChangeDetectorRef }, { token: i0.NgZone }, { token: i0.ElementRef }, { token: NGX_PDF_WORKER_SRC }], target: i0.ɵɵFactoryTarget.Component }); }
|
|
689
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.16", type: NgxNextPdfViewerComponent, isStandalone: true, selector: "ngx-next-pdf-viewer", inputs: { blob: "blob", annotations: "annotations", contextMenuItems: "contextMenuItems", highlightingColor: "highlightingColor", selectedColor: "selectedColor", annotationStroke: "annotationStroke", initialZoom: "initialZoom", labels: "labels" }, outputs: { boxClicked: "boxClicked", boxesSelected: "boxesSelected" }, host: { listeners: { "mousemove": "onDocMouseMove($event)", "mouseup": "onDocMouseUp($event)", "document:click": "onDocClick()" } }, viewQueries: [{ propertyName: "pdfContainer", first: true, predicate: ["pdfContainer"], descendants: true }], usesOnChanges: true, ngImport: i0, template: "<div class=\"npv-root\">\n\n <!-- \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 Toolbar \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 -->\n <div class=\"npv-toolbar\">\n\n <button mat-icon-button [matTooltip]=\"l.zoomOut\" (click)=\"zoomOut()\" [disabled]=\"zoom <= 0.25\">\n <mat-icon>zoom_out</mat-icon>\n </button>\n <span class=\"npv-label\">{{ zoomPercent }}%</span>\n <button mat-icon-button [matTooltip]=\"l.zoomIn\" (click)=\"zoomIn()\" [disabled]=\"zoom >= 5\">\n <mat-icon>zoom_in</mat-icon>\n </button>\n\n <div class=\"npv-sep\"></div>\n\n <button mat-icon-button [matTooltip]=\"l.rotateLeft\" (click)=\"rotateLeft()\">\n <mat-icon>rotate_left</mat-icon>\n </button>\n <button mat-icon-button [matTooltip]=\"l.rotateRight\" (click)=\"rotateRight()\">\n <mat-icon>rotate_right</mat-icon>\n </button>\n\n <div class=\"npv-sep\"></div>\n\n <button mat-icon-button [matTooltip]=\"l.previousPage\" (click)=\"goToPrevPage()\" [disabled]=\"currentPage <= 1\">\n <mat-icon>chevron_left</mat-icon>\n </button>\n <span class=\"npv-label\">{{ currentPage }} / {{ totalPages }}</span>\n <button mat-icon-button [matTooltip]=\"l.nextPage\" (click)=\"goToNextPage()\" [disabled]=\"currentPage >= totalPages\">\n <mat-icon>chevron_right</mat-icon>\n </button>\n\n <ng-container *ngIf=\"annotations.length\">\n <div class=\"npv-sep\"></div>\n\n <button mat-icon-button [matTooltip]=\"l.previousAnnotation\" (click)=\"goToPrevAnnotation()\">\n <mat-icon>navigate_before</mat-icon>\n </button>\n <span class=\"npv-label\">\n {{ annotationIndex >= 0 ? annotationIndex + 1 : '\u2013' }} / {{ annotations.length }}\n </span>\n <button mat-icon-button [matTooltip]=\"l.nextAnnotation\" (click)=\"goToNextAnnotation()\">\n <mat-icon>navigate_next</mat-icon>\n </button>\n </ng-container>\n\n <div class=\"npv-sep\"></div>\n\n <button mat-icon-button\n [matTooltip]=\"selectionMode === 'select-area' ? l.selectText : l.selectArea\"\n (click)=\"toggleSelectionMode()\"\n [class.npv-active]=\"selectionMode === 'select-text'\">\n <mat-icon>text_fields</mat-icon>\n </button>\n\n <div class=\"npv-sep\"></div>\n\n <button mat-icon-button [matTooltip]=\"l.search\" (click)=\"toggleSearch()\" [class.npv-active]=\"searchVisible\">\n <mat-icon>search</mat-icon>\n </button>\n\n <ng-container *ngIf=\"searchVisible\">\n <input\n class=\"npv-search-input\"\n type=\"text\"\n [placeholder]=\"l.searchPlaceholder\"\n [(ngModel)]=\"searchQuery\"\n (input)=\"onSearchInput()\"\n (keydown.enter)=\"searchNext()\"\n (keydown.shift.enter)=\"searchPrev()\"\n autofocus\n />\n <button mat-icon-button [matTooltip]=\"l.previousResult\"\n (click)=\"searchPrev()\" [disabled]=\"!searchMatches.length\">\n <mat-icon>expand_less</mat-icon>\n </button>\n <button mat-icon-button [matTooltip]=\"l.nextResult\"\n (click)=\"searchNext()\" [disabled]=\"!searchMatches.length\">\n <mat-icon>expand_more</mat-icon>\n </button>\n <span class=\"npv-search-count\" *ngIf=\"searchMatches.length\">\n {{ searchIndex + 1 }} / {{ searchMatches.length }}\n </span>\n <span class=\"npv-search-count npv-no-match\" *ngIf=\"searchQuery && !searchMatches.length\">\n {{ l.noResults }}\n </span>\n </ng-container>\n\n </div>\n\n <!-- \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 Loading \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 -->\n <div class=\"npv-loading\" *ngIf=\"loading\">\n <span class=\"npv-spinner\"></span> {{ l.loading }}\n </div>\n\n <!-- \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 Scroll area \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 -->\n <div class=\"npv-scroll-area\" #pdfContainer\n (scroll)=\"onContainerScroll()\" (click)=\"ctxVisible = false\">\n <div class=\"npv-scroll-inner\">\n\n <ng-container *ngFor=\"let p of pageRange()\">\n <div class=\"npv-page-wrapper\" [id]=\"'npv-page-' + p\">\n\n <canvas [id]=\"'npv-canvas-' + p\" class=\"npv-canvas\"></canvas>\n\n <svg *ngIf=\"getPageInfo(p) as pi\"\n [id]=\"'npv-svg-' + p\"\n class=\"npv-overlay\"\n [class.npv-overlay--text-mode]=\"selectionMode === 'select-text'\"\n [attr.width]=\"pi.width\" [attr.height]=\"pi.height\"\n [attr.viewBox]=\"'0 0 ' + pi.width + ' ' + pi.height\"\n (mousedown)=\"onSvgMouseDown($event, p)\">\n\n <!-- Hit area for drag selection on empty page space -->\n <rect x=\"0\" y=\"0\" [attr.width]=\"pi.width\" [attr.height]=\"pi.height\"\n fill=\"transparent\"></rect>\n\n <!-- Annotation boxes -->\n <polygon\n *ngFor=\"let box of getBoxesForPage(p)\"\n [attr.points]=\"getSvgPoints(box, pi)\"\n class=\"npv-box\"\n [class.npv-box--clicked]=\"isClicked(box)\"\n [class.npv-box--multi]=\"isMultiSelected(box)\"\n [style.fill]=\"isClicked(box) ? highlightingColor : (isMultiSelected(box) ? selectedColor : 'transparent')\"\n [style.stroke]=\"annotationStroke\"\n (click)=\"onBoxClick($event, box)\">\n <title>{{ box.content || '' }}</title>\n </polygon>\n\n <!-- Search highlights -->\n <polygon\n *ngFor=\"let m of getSearchMatchesForPage(p); let mi = index\"\n [attr.points]=\"searchMatchPoints(m)\"\n class=\"npv-search-highlight\"\n [class.npv-search-highlight--current]=\"isCurrentSearchMatch(p, mi)\">\n </polygon>\n\n <!-- Drag selection rectangle -->\n <rect *ngIf=\"getDragRect(p) as dr\"\n [attr.x]=\"dr.x\" [attr.y]=\"dr.y\"\n [attr.width]=\"dr.w\" [attr.height]=\"dr.h\"\n class=\"npv-drag-rect\">\n </rect>\n\n </svg>\n </div>\n </ng-container>\n\n <div class=\"npv-placeholder npv-placeholder--error\" *ngIf=\"!loading && loadError\">\n {{ l.loadError }}\n </div>\n <div class=\"npv-placeholder\" *ngIf=\"!loading && !loadError && totalPages === 0\">\n {{ l.noDocument }}\n </div>\n\n </div><!-- /npv-scroll-inner -->\n </div>\n\n <!-- \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 Context menu \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 -->\n <div *ngIf=\"ctxVisible && contextMenuItems.length\"\n class=\"npv-context-menu\"\n [style.left.px]=\"ctxX\" [style.top.px]=\"ctxY\"\n (click)=\"$event.stopPropagation()\">\n <div *ngFor=\"let item of contextMenuItems\"\n class=\"npv-context-item\"\n (click)=\"onContextMenuAction(item)\">\n {{ item.label }}\n </div>\n </div>\n\n</div>\n", styles: [".npv-root{display:flex;flex-direction:column;height:100%;overflow:hidden;background:#e9ecee;position:relative;font-family:Roboto,sans-serif}.npv-toolbar{display:flex;align-items:center;gap:2px;padding:4px 8px;background:#fff;color:#000;min-height:48px;flex-shrink:0;z-index:10;box-shadow:0 2px 4px #0006}.npv-toolbar button.mat-icon-button{color:#505050}.npv-toolbar button.mat-icon-button:hover:not([disabled]){color:#fff;background:#ffffff1a}.npv-toolbar button.mat-icon-button[disabled]{opacity:.35}.npv-toolbar button.mat-icon-button.npv-active{color:#90caf9;background:#90caf91a}.npv-toolbar .npv-sep{width:1px;height:24px;background:#00000026;margin:0 4px}.npv-toolbar .npv-label{font-size:13px;min-width:50px;text-align:center;color:#505050;-webkit-user-select:none;user-select:none}.npv-toolbar .npv-search-input{background:#0000000f;border:1px solid rgba(0,0,0,.2);border-radius:4px;color:#000;font-size:13px;padding:4px 8px;outline:none;width:180px}.npv-toolbar .npv-search-input::placeholder{color:#0006}.npv-toolbar .npv-search-input:focus{border-color:#1976d2}.npv-toolbar .npv-search-count{font-size:12px;color:#607d8b;white-space:nowrap;min-width:60px}.npv-toolbar .npv-search-count.npv-no-match{color:#e53935}.npv-loading{display:flex;align-items:center;justify-content:center;gap:10px;padding:16px;color:#666;font-size:14px;flex-shrink:0}.npv-spinner{width:20px;height:20px;border:3px solid rgba(0,0,0,.1);border-top-color:#1976d2;border-radius:50%;animation:npv-spin .8s linear infinite}@keyframes npv-spin{to{transform:rotate(360deg)}}.npv-scroll-area{flex:1;overflow:auto}.npv-scroll-inner{display:flex;flex-direction:column;align-items:center;min-width:max-content;padding:16px;gap:16px}.npv-page-wrapper{position:relative;display:inline-block;box-shadow:0 4px 12px #00000080;line-height:0}.npv-canvas{display:block}.npv-overlay{position:absolute;top:0;left:0;pointer-events:all;overflow:visible;cursor:crosshair;user-select:none;-webkit-user-select:none}.npv-overlay.npv-overlay--text-mode{pointer-events:none;cursor:text}:host ::ng-deep .npv-text-layer{position:absolute;top:0;left:0;overflow:hidden;line-height:1;-webkit-text-size-adjust:none;text-size-adjust:none;forced-color-adjust:none}:host ::ng-deep .npv-text-layer span,:host ::ng-deep .npv-text-layer br{color:transparent;position:absolute;white-space:pre;cursor:text;transform-origin:0% 0%}:host ::ng-deep .npv-text-layer ::selection{background:#0078d740;color:transparent}.npv-box{pointer-events:all;stroke-width:2;fill:transparent;cursor:pointer;transition:fill .15s ease,stroke-width .15s ease}.npv-box:hover{stroke-width:3;filter:drop-shadow(0 0 3px rgba(233,115,50,.7))}.npv-box.npv-box--clicked{stroke-width:3}.npv-box.npv-box--multi{stroke-width:2.5}.npv-search-highlight{fill:#ffeb3b59;stroke:#ffc800cc;stroke-width:1.5;pointer-events:none}.npv-search-highlight.npv-search-highlight--current{fill:#ff980073;stroke:#ff6400e6;stroke-width:2}.npv-drag-rect{fill:#0078d71a;stroke:#0078d7b3;stroke-width:1.5;stroke-dasharray:5 3;pointer-events:none}.npv-placeholder{color:#aaa;font-size:14px;padding:40px;text-align:center}.npv-placeholder.npv-placeholder--error{color:#e53935}.npv-context-menu{position:fixed;z-index:9999;background:#fff;border:1px solid rgba(0,0,0,.12);border-radius:4px;box-shadow:0 4px 16px #0003;padding:4px 0;min-width:160px}.npv-context-item{padding:10px 16px;font-size:14px;cursor:pointer;color:#000000de;-webkit-user-select:none;user-select:none}.npv-context-item:hover{background:#0000000d}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i3.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i4.MatIconButton, selector: "button[mat-icon-button], a[mat-icon-button], button[matIconButton], a[matIconButton]", exportAs: ["matButton", "matAnchor"] }, { kind: "ngmodule", type: MatTooltipModule }, { kind: "directive", type: i5.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }, { kind: "ngmodule", type: MatInputModule }, { kind: "ngmodule", type: MatFormFieldModule }] }); }
|
|
823
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.16", type: NgxNextPdfViewerComponent, isStandalone: true, selector: "ngx-next-pdf-viewer", inputs: { blob: "blob", annotations: "annotations", contextMenuItems: "contextMenuItems", highlightingColor: "highlightingColor", selectedColor: "selectedColor", annotationStroke: "annotationStroke", initialZoom: "initialZoom", labels: "labels", showZoom: "showZoom", showRotation: "showRotation", showPageNavigation: "showPageNavigation", showAnnotationNavigation: "showAnnotationNavigation", showSelectionMode: "showSelectionMode", showSearch: "showSearch", apiKey: "apiKey" }, outputs: { boxClicked: "boxClicked", boxesSelected: "boxesSelected" }, host: { listeners: { "mousemove": "onDocMouseMove($event)", "mouseup": "onDocMouseUp($event)", "document:click": "onDocClick()" } }, viewQueries: [{ propertyName: "pdfContainer", first: true, predicate: ["pdfContainer"], descendants: true }], usesOnChanges: true, ngImport: i0, template: "<div class=\"npv-root\">\n\n <!-- \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 Toolbar \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 -->\n <div class=\"npv-toolbar\">\n\n <!-- Zoom -->\n <ng-container *ngIf=\"showZoom\">\n <button mat-icon-button [matTooltip]=\"l.zoomOut\" (click)=\"zoomOut()\" [disabled]=\"zoom <= 0.25\">\n <mat-icon>zoom_out</mat-icon>\n </button>\n <span class=\"npv-label\">{{ zoomPercent }}%</span>\n <button mat-icon-button [matTooltip]=\"l.zoomIn\" (click)=\"zoomIn()\" [disabled]=\"zoom >= 5\">\n <mat-icon>zoom_in</mat-icon>\n </button>\n </ng-container>\n\n <!-- Rotation -->\n <ng-container *ngIf=\"showRotation\">\n <div class=\"npv-sep\" *ngIf=\"showZoom\"></div>\n <button mat-icon-button [matTooltip]=\"l.rotateLeft\" (click)=\"rotateLeft()\">\n <mat-icon>rotate_left</mat-icon>\n </button>\n <button mat-icon-button [matTooltip]=\"l.rotateRight\" (click)=\"rotateRight()\">\n <mat-icon>rotate_right</mat-icon>\n </button>\n </ng-container>\n\n <!-- Page navigation -->\n <ng-container *ngIf=\"showPageNavigation\">\n <div class=\"npv-sep\" *ngIf=\"showZoom || showRotation\"></div>\n <button mat-icon-button [matTooltip]=\"l.previousPage\" (click)=\"goToPrevPage()\" [disabled]=\"currentPage <= 1\">\n <mat-icon>chevron_left</mat-icon>\n </button>\n <span class=\"npv-label\">{{ currentPage }} / {{ totalPages }}</span>\n <button mat-icon-button [matTooltip]=\"l.nextPage\" (click)=\"goToNextPage()\" [disabled]=\"currentPage >= totalPages\">\n <mat-icon>chevron_right</mat-icon>\n </button>\n </ng-container>\n\n <!-- Annotation navigation -->\n <ng-container *ngIf=\"showAnnotationNavigation && annotations.length\">\n <div class=\"npv-sep\" *ngIf=\"showZoom || showRotation || showPageNavigation\"></div>\n <button mat-icon-button [matTooltip]=\"l.previousAnnotation\" (click)=\"goToPrevAnnotation()\">\n <mat-icon>navigate_before</mat-icon>\n </button>\n <span class=\"npv-label\">\n {{ annotationIndex >= 0 ? annotationIndex + 1 : '\u2013' }} / {{ annotations.length }}\n </span>\n <button mat-icon-button [matTooltip]=\"l.nextAnnotation\" (click)=\"goToNextAnnotation()\">\n <mat-icon>navigate_next</mat-icon>\n </button>\n </ng-container>\n\n <!-- Selection mode toggle -->\n <ng-container *ngIf=\"showSelectionMode\">\n <div class=\"npv-sep\" *ngIf=\"showZoom || showRotation || showPageNavigation || (showAnnotationNavigation && annotations.length > 0)\"></div>\n <button mat-icon-button\n [matTooltip]=\"selectionMode === 'select-area' ? l.selectText : l.selectArea\"\n (click)=\"toggleSelectionMode()\"\n [class.npv-active]=\"selectionMode === 'select-text'\">\n <mat-icon>text_fields</mat-icon>\n </button>\n </ng-container>\n\n <!-- Search -->\n <ng-container *ngIf=\"showSearch\">\n <div class=\"npv-sep\" *ngIf=\"showZoom || showRotation || showPageNavigation || (showAnnotationNavigation && annotations.length > 0) || showSelectionMode\"></div>\n <button mat-icon-button [matTooltip]=\"l.search\" (click)=\"toggleSearch()\" [class.npv-active]=\"searchVisible\">\n <mat-icon>search</mat-icon>\n </button>\n <ng-container *ngIf=\"searchVisible\">\n <input\n class=\"npv-search-input\"\n type=\"text\"\n [placeholder]=\"l.searchPlaceholder\"\n [(ngModel)]=\"searchQuery\"\n (input)=\"onSearchInput()\"\n (keydown.enter)=\"searchNext()\"\n (keydown.shift.enter)=\"searchPrev()\"\n autofocus\n />\n <button mat-icon-button [matTooltip]=\"l.previousResult\"\n (click)=\"searchPrev()\" [disabled]=\"!searchMatches.length\">\n <mat-icon>expand_less</mat-icon>\n </button>\n <button mat-icon-button [matTooltip]=\"l.nextResult\"\n (click)=\"searchNext()\" [disabled]=\"!searchMatches.length\">\n <mat-icon>expand_more</mat-icon>\n </button>\n <span class=\"npv-search-count\" *ngIf=\"searchMatches.length\">\n {{ searchIndex + 1 }} / {{ searchMatches.length }}\n </span>\n <span class=\"npv-search-count npv-no-match\" *ngIf=\"searchQuery && !searchMatches.length\">\n {{ l.noResults }}\n </span>\n </ng-container>\n </ng-container>\n\n </div>\n\n <!-- \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 Loading \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 -->\n <div class=\"npv-loading\" *ngIf=\"loading\">\n <span class=\"npv-spinner\"></span> {{ l.loading }}\n </div>\n\n <!-- \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 Scroll area \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 -->\n <div class=\"npv-scroll-area\" #pdfContainer\n (scroll)=\"onContainerScroll()\" (click)=\"ctxVisible = false\">\n <div class=\"npv-scroll-inner\">\n\n <ng-container *ngFor=\"let p of pageRange()\">\n <div class=\"npv-page-wrapper\" [id]=\"'npv-page-' + p\">\n\n <canvas [id]=\"'npv-canvas-' + p\" class=\"npv-canvas\"></canvas>\n\n <svg *ngIf=\"getPageInfo(p) as pi\"\n [id]=\"'npv-svg-' + p\"\n class=\"npv-overlay\"\n [class.npv-overlay--text-mode]=\"selectionMode === 'select-text'\"\n [attr.width]=\"pi.width\" [attr.height]=\"pi.height\"\n [attr.viewBox]=\"'0 0 ' + pi.width + ' ' + pi.height\"\n (mousedown)=\"onSvgMouseDown($event, p)\">\n\n <!-- Hit area for drag selection on empty page space -->\n <rect x=\"0\" y=\"0\" [attr.width]=\"pi.width\" [attr.height]=\"pi.height\"\n fill=\"transparent\"></rect>\n\n <!-- Annotation boxes -->\n <polygon\n *ngFor=\"let box of getBoxesForPage(p)\"\n [attr.points]=\"getSvgPoints(box, pi)\"\n class=\"npv-box\"\n [class.npv-box--clicked]=\"isClicked(box)\"\n [class.npv-box--multi]=\"isMultiSelected(box)\"\n [style.fill]=\"isClicked(box) ? highlightingColor : (isMultiSelected(box) ? selectedColor : 'transparent')\"\n [style.stroke]=\"annotationStroke\"\n (click)=\"onBoxClick($event, box)\">\n <title>{{ box.content || '' }}</title>\n </polygon>\n\n <!-- Search highlights -->\n <polygon\n *ngFor=\"let m of getSearchMatchesForPage(p); let mi = index\"\n [attr.points]=\"searchMatchPoints(m)\"\n class=\"npv-search-highlight\"\n [class.npv-search-highlight--current]=\"isCurrentSearchMatch(p, mi)\">\n </polygon>\n\n <!-- Drag selection rectangle -->\n <rect *ngIf=\"getDragRect(p) as dr\"\n [attr.x]=\"dr.x\" [attr.y]=\"dr.y\"\n [attr.width]=\"dr.w\" [attr.height]=\"dr.h\"\n class=\"npv-drag-rect\">\n </rect>\n\n </svg>\n </div>\n </ng-container>\n\n <div class=\"npv-placeholder npv-placeholder--error\" *ngIf=\"!loading && loadError\">\n {{ l.loadError }}\n </div>\n <div class=\"npv-placeholder\" *ngIf=\"!loading && !loadError && totalPages === 0\">\n {{ l.noDocument }}\n </div>\n\n </div><!-- /npv-scroll-inner -->\n </div>\n\n <!-- \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 Context menu \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 -->\n <div *ngIf=\"ctxVisible && contextMenuItems.length\"\n class=\"npv-context-menu\"\n [style.left.px]=\"ctxX\" [style.top.px]=\"ctxY\"\n (click)=\"$event.stopPropagation()\">\n <div *ngFor=\"let item of contextMenuItems\"\n class=\"npv-context-item\"\n (click)=\"onContextMenuAction(item)\">\n {{ item.label }}\n </div>\n </div>\n\n</div>\n", styles: [".npv-root{display:flex;flex-direction:column;height:100%;overflow:hidden;background:#e9ecee;position:relative;font-family:Roboto,sans-serif}.npv-toolbar{display:flex;align-items:center;gap:2px;padding:4px 8px;background:#fff;color:#000;min-height:48px;flex-shrink:0;z-index:10;box-shadow:0 2px 4px #0006}.npv-toolbar button{color:#505050}.npv-toolbar button:hover:not([disabled]){background:#0000000f}.npv-toolbar button[disabled]{opacity:.35}.npv-toolbar button.npv-active{color:#1976d2;background:#e3f0fd;box-shadow:inset 0 2px 4px #00000026}.npv-toolbar button.npv-active:hover:not([disabled]){background:#cce0fa}.npv-toolbar .npv-sep{width:1px;height:24px;background:#00000026;margin:0 4px}.npv-toolbar .npv-label{font-size:13px;min-width:50px;text-align:center;color:#505050;-webkit-user-select:none;user-select:none}.npv-toolbar .npv-search-input{background:#0000000f;border:1px solid rgba(0,0,0,.2);border-radius:4px;color:#000;font-size:13px;padding:4px 8px;outline:none;width:180px}.npv-toolbar .npv-search-input::placeholder{color:#0006}.npv-toolbar .npv-search-input:focus{border-color:#1976d2}.npv-toolbar .npv-search-count{font-size:12px;color:#607d8b;white-space:nowrap;min-width:60px}.npv-toolbar .npv-search-count.npv-no-match{color:#e53935}.npv-loading{display:flex;align-items:center;justify-content:center;gap:10px;padding:16px;color:#666;font-size:14px;flex-shrink:0}.npv-spinner{width:20px;height:20px;border:3px solid rgba(0,0,0,.1);border-top-color:#1976d2;border-radius:50%;animation:npv-spin .8s linear infinite}@keyframes npv-spin{to{transform:rotate(360deg)}}.npv-scroll-area{flex:1;overflow:auto}.npv-scroll-inner{display:flex;flex-direction:column;align-items:center;min-width:max-content;padding:16px;gap:16px}.npv-page-wrapper{position:relative;display:inline-block;box-shadow:0 4px 12px #00000080;line-height:0}.npv-canvas{display:block}.npv-overlay{position:absolute;top:0;left:0;pointer-events:all;overflow:visible;cursor:crosshair;user-select:none;-webkit-user-select:none}.npv-overlay.npv-overlay--text-mode{pointer-events:none}.npv-box{pointer-events:all;stroke-width:2;fill:transparent;cursor:pointer;transition:fill .15s ease,stroke-width .15s ease}.npv-box:hover{stroke-width:3;filter:drop-shadow(0 0 3px rgba(233,115,50,.7))}.npv-box.npv-box--clicked{stroke-width:3}.npv-box.npv-box--multi{stroke-width:2.5}.npv-search-highlight{fill:#ffeb3b59;stroke:#ffc800cc;stroke-width:1.5;pointer-events:none}.npv-search-highlight.npv-search-highlight--current{fill:#ff980073;stroke:#ff6400e6;stroke-width:2}.npv-drag-rect{fill:#0078d71a;stroke:#0078d7b3;stroke-width:1.5;stroke-dasharray:5 3;pointer-events:none}.npv-placeholder{color:#aaa;font-size:14px;padding:40px;text-align:center}.npv-placeholder.npv-placeholder--error{color:#e53935}.npv-context-menu{position:fixed;z-index:9999;background:#fff;border:1px solid rgba(0,0,0,.12);border-radius:4px;box-shadow:0 4px 16px #0003;padding:4px 0;min-width:160px}.npv-context-item{padding:10px 16px;font-size:14px;cursor:pointer;color:#000000de;-webkit-user-select:none;user-select:none}.npv-context-item:hover{background:#0000000d}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i3.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i4.MatIconButton, selector: "button[mat-icon-button], a[mat-icon-button], button[matIconButton], a[matIconButton]", exportAs: ["matButton", "matAnchor"] }, { kind: "ngmodule", type: MatTooltipModule }, { kind: "directive", type: i5.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }, { kind: "ngmodule", type: MatInputModule }, { kind: "ngmodule", type: MatFormFieldModule }] }); }
|
|
690
824
|
}
|
|
691
825
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: NgxNextPdfViewerComponent, decorators: [{
|
|
692
826
|
type: Component,
|
|
@@ -698,7 +832,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
|
|
|
698
832
|
MatTooltipModule,
|
|
699
833
|
MatInputModule,
|
|
700
834
|
MatFormFieldModule
|
|
701
|
-
], template: "<div class=\"npv-root\">\n\n <!-- \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 Toolbar \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 -->\n <div class=\"npv-toolbar\">\n\n <button mat-icon-button [matTooltip]=\"l.zoomOut\" (click)=\"zoomOut()\" [disabled]=\"zoom <= 0.25\">\n <mat-icon>zoom_out</mat-icon>\n </button>\n <span class=\"npv-label\">{{ zoomPercent }}%</span>\n <button mat-icon-button [matTooltip]=\"l.zoomIn\" (click)=\"zoomIn()\" [disabled]=\"zoom >= 5\">\n <mat-icon>zoom_in</mat-icon>\n </button>\n\n <div class=\"npv-sep\"></div>\n\n <button mat-icon-button [matTooltip]=\"l.rotateLeft\" (click)=\"rotateLeft()\">\n <mat-icon>rotate_left</mat-icon>\n </button>\n <button mat-icon-button [matTooltip]=\"l.rotateRight\" (click)=\"rotateRight()\">\n <mat-icon>rotate_right</mat-icon>\n </button>\n\n <div class=\"npv-sep\"></div>\n\n <button mat-icon-button [matTooltip]=\"l.previousPage\" (click)=\"goToPrevPage()\" [disabled]=\"currentPage <= 1\">\n <mat-icon>chevron_left</mat-icon>\n </button>\n <span class=\"npv-label\">{{ currentPage }} / {{ totalPages }}</span>\n <button mat-icon-button [matTooltip]=\"l.nextPage\" (click)=\"goToNextPage()\" [disabled]=\"currentPage >= totalPages\">\n <mat-icon>chevron_right</mat-icon>\n </button>\n\n <ng-container *ngIf=\"annotations.length\">\n <div class=\"npv-sep\"></div>\n\n <button mat-icon-button [matTooltip]=\"l.previousAnnotation\" (click)=\"goToPrevAnnotation()\">\n <mat-icon>navigate_before</mat-icon>\n </button>\n <span class=\"npv-label\">\n {{ annotationIndex >= 0 ? annotationIndex + 1 : '\u2013' }} / {{ annotations.length }}\n </span>\n <button mat-icon-button [matTooltip]=\"l.nextAnnotation\" (click)=\"goToNextAnnotation()\">\n <mat-icon>navigate_next</mat-icon>\n </button>\n </ng-container>\n\n <div class=\"npv-sep\"></div>\n\n <button mat-icon-button\n [matTooltip]=\"selectionMode === 'select-area' ? l.selectText : l.selectArea\"\n (click)=\"toggleSelectionMode()\"\n [class.npv-active]=\"selectionMode === 'select-text'\">\n <mat-icon>text_fields</mat-icon>\n </button>\n\n <div class=\"npv-sep\"></div>\n\n <button mat-icon-button [matTooltip]=\"l.search\" (click)=\"toggleSearch()\" [class.npv-active]=\"searchVisible\">\n <mat-icon>search</mat-icon>\n </button>\n\n <ng-container *ngIf=\"searchVisible\">\n <input\n class=\"npv-search-input\"\n type=\"text\"\n [placeholder]=\"l.searchPlaceholder\"\n [(ngModel)]=\"searchQuery\"\n (input)=\"onSearchInput()\"\n (keydown.enter)=\"searchNext()\"\n (keydown.shift.enter)=\"searchPrev()\"\n autofocus\n />\n <button mat-icon-button [matTooltip]=\"l.previousResult\"\n (click)=\"searchPrev()\" [disabled]=\"!searchMatches.length\">\n <mat-icon>expand_less</mat-icon>\n </button>\n <button mat-icon-button [matTooltip]=\"l.nextResult\"\n (click)=\"searchNext()\" [disabled]=\"!searchMatches.length\">\n <mat-icon>expand_more</mat-icon>\n </button>\n <span class=\"npv-search-count\" *ngIf=\"searchMatches.length\">\n {{ searchIndex + 1 }} / {{ searchMatches.length }}\n </span>\n <span class=\"npv-search-count npv-no-match\" *ngIf=\"searchQuery && !searchMatches.length\">\n {{ l.noResults }}\n </span>\n </ng-container>\n\n </div>\n\n <!-- \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 Loading \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 -->\n <div class=\"npv-loading\" *ngIf=\"loading\">\n <span class=\"npv-spinner\"></span> {{ l.loading }}\n </div>\n\n <!-- \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 Scroll area \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 -->\n <div class=\"npv-scroll-area\" #pdfContainer\n (scroll)=\"onContainerScroll()\" (click)=\"ctxVisible = false\">\n <div class=\"npv-scroll-inner\">\n\n <ng-container *ngFor=\"let p of pageRange()\">\n <div class=\"npv-page-wrapper\" [id]=\"'npv-page-' + p\">\n\n <canvas [id]=\"'npv-canvas-' + p\" class=\"npv-canvas\"></canvas>\n\n <svg *ngIf=\"getPageInfo(p) as pi\"\n [id]=\"'npv-svg-' + p\"\n class=\"npv-overlay\"\n [class.npv-overlay--text-mode]=\"selectionMode === 'select-text'\"\n [attr.width]=\"pi.width\" [attr.height]=\"pi.height\"\n [attr.viewBox]=\"'0 0 ' + pi.width + ' ' + pi.height\"\n (mousedown)=\"onSvgMouseDown($event, p)\">\n\n <!-- Hit area for drag selection on empty page space -->\n <rect x=\"0\" y=\"0\" [attr.width]=\"pi.width\" [attr.height]=\"pi.height\"\n fill=\"transparent\"></rect>\n\n <!-- Annotation boxes -->\n <polygon\n *ngFor=\"let box of getBoxesForPage(p)\"\n [attr.points]=\"getSvgPoints(box, pi)\"\n class=\"npv-box\"\n [class.npv-box--clicked]=\"isClicked(box)\"\n [class.npv-box--multi]=\"isMultiSelected(box)\"\n [style.fill]=\"isClicked(box) ? highlightingColor : (isMultiSelected(box) ? selectedColor : 'transparent')\"\n [style.stroke]=\"annotationStroke\"\n (click)=\"onBoxClick($event, box)\">\n <title>{{ box.content || '' }}</title>\n </polygon>\n\n <!-- Search highlights -->\n <polygon\n *ngFor=\"let m of getSearchMatchesForPage(p); let mi = index\"\n [attr.points]=\"searchMatchPoints(m)\"\n class=\"npv-search-highlight\"\n [class.npv-search-highlight--current]=\"isCurrentSearchMatch(p, mi)\">\n </polygon>\n\n <!-- Drag selection rectangle -->\n <rect *ngIf=\"getDragRect(p) as dr\"\n [attr.x]=\"dr.x\" [attr.y]=\"dr.y\"\n [attr.width]=\"dr.w\" [attr.height]=\"dr.h\"\n class=\"npv-drag-rect\">\n </rect>\n\n </svg>\n </div>\n </ng-container>\n\n <div class=\"npv-placeholder npv-placeholder--error\" *ngIf=\"!loading && loadError\">\n {{ l.loadError }}\n </div>\n <div class=\"npv-placeholder\" *ngIf=\"!loading && !loadError && totalPages === 0\">\n {{ l.noDocument }}\n </div>\n\n </div><!-- /npv-scroll-inner -->\n </div>\n\n <!-- \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 Context menu \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 -->\n <div *ngIf=\"ctxVisible && contextMenuItems.length\"\n class=\"npv-context-menu\"\n [style.left.px]=\"ctxX\" [style.top.px]=\"ctxY\"\n (click)=\"$event.stopPropagation()\">\n <div *ngFor=\"let item of contextMenuItems\"\n class=\"npv-context-item\"\n (click)=\"onContextMenuAction(item)\">\n {{ item.label }}\n </div>\n </div>\n\n</div>\n", styles: [".npv-root{display:flex;flex-direction:column;height:100%;overflow:hidden;background:#e9ecee;position:relative;font-family:Roboto,sans-serif}.npv-toolbar{display:flex;align-items:center;gap:2px;padding:4px 8px;background:#fff;color:#000;min-height:48px;flex-shrink:0;z-index:10;box-shadow:0 2px 4px #0006}.npv-toolbar button.mat-icon-button{color:#505050}.npv-toolbar button.mat-icon-button:hover:not([disabled]){color:#fff;background:#ffffff1a}.npv-toolbar button.mat-icon-button[disabled]{opacity:.35}.npv-toolbar button.mat-icon-button.npv-active{color:#90caf9;background:#90caf91a}.npv-toolbar .npv-sep{width:1px;height:24px;background:#00000026;margin:0 4px}.npv-toolbar .npv-label{font-size:13px;min-width:50px;text-align:center;color:#505050;-webkit-user-select:none;user-select:none}.npv-toolbar .npv-search-input{background:#0000000f;border:1px solid rgba(0,0,0,.2);border-radius:4px;color:#000;font-size:13px;padding:4px 8px;outline:none;width:180px}.npv-toolbar .npv-search-input::placeholder{color:#0006}.npv-toolbar .npv-search-input:focus{border-color:#1976d2}.npv-toolbar .npv-search-count{font-size:12px;color:#607d8b;white-space:nowrap;min-width:60px}.npv-toolbar .npv-search-count.npv-no-match{color:#e53935}.npv-loading{display:flex;align-items:center;justify-content:center;gap:10px;padding:16px;color:#666;font-size:14px;flex-shrink:0}.npv-spinner{width:20px;height:20px;border:3px solid rgba(0,0,0,.1);border-top-color:#1976d2;border-radius:50%;animation:npv-spin .8s linear infinite}@keyframes npv-spin{to{transform:rotate(360deg)}}.npv-scroll-area{flex:1;overflow:auto}.npv-scroll-inner{display:flex;flex-direction:column;align-items:center;min-width:max-content;padding:16px;gap:16px}.npv-page-wrapper{position:relative;display:inline-block;box-shadow:0 4px 12px #00000080;line-height:0}.npv-canvas{display:block}.npv-overlay{position:absolute;top:0;left:0;pointer-events:all;overflow:visible;cursor:crosshair;user-select:none;-webkit-user-select:none}.npv-overlay.npv-overlay--text-mode{pointer-events:none;cursor:text}:host ::ng-deep .npv-text-layer{position:absolute;top:0;left:0;overflow:hidden;line-height:1;-webkit-text-size-adjust:none;text-size-adjust:none;forced-color-adjust:none}:host ::ng-deep .npv-text-layer span,:host ::ng-deep .npv-text-layer br{color:transparent;position:absolute;white-space:pre;cursor:text;transform-origin:0% 0%}:host ::ng-deep .npv-text-layer ::selection{background:#0078d740;color:transparent}.npv-box{pointer-events:all;stroke-width:2;fill:transparent;cursor:pointer;transition:fill .15s ease,stroke-width .15s ease}.npv-box:hover{stroke-width:3;filter:drop-shadow(0 0 3px rgba(233,115,50,.7))}.npv-box.npv-box--clicked{stroke-width:3}.npv-box.npv-box--multi{stroke-width:2.5}.npv-search-highlight{fill:#ffeb3b59;stroke:#ffc800cc;stroke-width:1.5;pointer-events:none}.npv-search-highlight.npv-search-highlight--current{fill:#ff980073;stroke:#ff6400e6;stroke-width:2}.npv-drag-rect{fill:#0078d71a;stroke:#0078d7b3;stroke-width:1.5;stroke-dasharray:5 3;pointer-events:none}.npv-placeholder{color:#aaa;font-size:14px;padding:40px;text-align:center}.npv-placeholder.npv-placeholder--error{color:#e53935}.npv-context-menu{position:fixed;z-index:9999;background:#fff;border:1px solid rgba(0,0,0,.12);border-radius:4px;box-shadow:0 4px 16px #0003;padding:4px 0;min-width:160px}.npv-context-item{padding:10px 16px;font-size:14px;cursor:pointer;color:#000000de;-webkit-user-select:none;user-select:none}.npv-context-item:hover{background:#0000000d}\n"] }]
|
|
835
|
+
], template: "<div class=\"npv-root\">\n\n <!-- \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 Toolbar \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 -->\n <div class=\"npv-toolbar\">\n\n <!-- Zoom -->\n <ng-container *ngIf=\"showZoom\">\n <button mat-icon-button [matTooltip]=\"l.zoomOut\" (click)=\"zoomOut()\" [disabled]=\"zoom <= 0.25\">\n <mat-icon>zoom_out</mat-icon>\n </button>\n <span class=\"npv-label\">{{ zoomPercent }}%</span>\n <button mat-icon-button [matTooltip]=\"l.zoomIn\" (click)=\"zoomIn()\" [disabled]=\"zoom >= 5\">\n <mat-icon>zoom_in</mat-icon>\n </button>\n </ng-container>\n\n <!-- Rotation -->\n <ng-container *ngIf=\"showRotation\">\n <div class=\"npv-sep\" *ngIf=\"showZoom\"></div>\n <button mat-icon-button [matTooltip]=\"l.rotateLeft\" (click)=\"rotateLeft()\">\n <mat-icon>rotate_left</mat-icon>\n </button>\n <button mat-icon-button [matTooltip]=\"l.rotateRight\" (click)=\"rotateRight()\">\n <mat-icon>rotate_right</mat-icon>\n </button>\n </ng-container>\n\n <!-- Page navigation -->\n <ng-container *ngIf=\"showPageNavigation\">\n <div class=\"npv-sep\" *ngIf=\"showZoom || showRotation\"></div>\n <button mat-icon-button [matTooltip]=\"l.previousPage\" (click)=\"goToPrevPage()\" [disabled]=\"currentPage <= 1\">\n <mat-icon>chevron_left</mat-icon>\n </button>\n <span class=\"npv-label\">{{ currentPage }} / {{ totalPages }}</span>\n <button mat-icon-button [matTooltip]=\"l.nextPage\" (click)=\"goToNextPage()\" [disabled]=\"currentPage >= totalPages\">\n <mat-icon>chevron_right</mat-icon>\n </button>\n </ng-container>\n\n <!-- Annotation navigation -->\n <ng-container *ngIf=\"showAnnotationNavigation && annotations.length\">\n <div class=\"npv-sep\" *ngIf=\"showZoom || showRotation || showPageNavigation\"></div>\n <button mat-icon-button [matTooltip]=\"l.previousAnnotation\" (click)=\"goToPrevAnnotation()\">\n <mat-icon>navigate_before</mat-icon>\n </button>\n <span class=\"npv-label\">\n {{ annotationIndex >= 0 ? annotationIndex + 1 : '\u2013' }} / {{ annotations.length }}\n </span>\n <button mat-icon-button [matTooltip]=\"l.nextAnnotation\" (click)=\"goToNextAnnotation()\">\n <mat-icon>navigate_next</mat-icon>\n </button>\n </ng-container>\n\n <!-- Selection mode toggle -->\n <ng-container *ngIf=\"showSelectionMode\">\n <div class=\"npv-sep\" *ngIf=\"showZoom || showRotation || showPageNavigation || (showAnnotationNavigation && annotations.length > 0)\"></div>\n <button mat-icon-button\n [matTooltip]=\"selectionMode === 'select-area' ? l.selectText : l.selectArea\"\n (click)=\"toggleSelectionMode()\"\n [class.npv-active]=\"selectionMode === 'select-text'\">\n <mat-icon>text_fields</mat-icon>\n </button>\n </ng-container>\n\n <!-- Search -->\n <ng-container *ngIf=\"showSearch\">\n <div class=\"npv-sep\" *ngIf=\"showZoom || showRotation || showPageNavigation || (showAnnotationNavigation && annotations.length > 0) || showSelectionMode\"></div>\n <button mat-icon-button [matTooltip]=\"l.search\" (click)=\"toggleSearch()\" [class.npv-active]=\"searchVisible\">\n <mat-icon>search</mat-icon>\n </button>\n <ng-container *ngIf=\"searchVisible\">\n <input\n class=\"npv-search-input\"\n type=\"text\"\n [placeholder]=\"l.searchPlaceholder\"\n [(ngModel)]=\"searchQuery\"\n (input)=\"onSearchInput()\"\n (keydown.enter)=\"searchNext()\"\n (keydown.shift.enter)=\"searchPrev()\"\n autofocus\n />\n <button mat-icon-button [matTooltip]=\"l.previousResult\"\n (click)=\"searchPrev()\" [disabled]=\"!searchMatches.length\">\n <mat-icon>expand_less</mat-icon>\n </button>\n <button mat-icon-button [matTooltip]=\"l.nextResult\"\n (click)=\"searchNext()\" [disabled]=\"!searchMatches.length\">\n <mat-icon>expand_more</mat-icon>\n </button>\n <span class=\"npv-search-count\" *ngIf=\"searchMatches.length\">\n {{ searchIndex + 1 }} / {{ searchMatches.length }}\n </span>\n <span class=\"npv-search-count npv-no-match\" *ngIf=\"searchQuery && !searchMatches.length\">\n {{ l.noResults }}\n </span>\n </ng-container>\n </ng-container>\n\n </div>\n\n <!-- \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 Loading \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 -->\n <div class=\"npv-loading\" *ngIf=\"loading\">\n <span class=\"npv-spinner\"></span> {{ l.loading }}\n </div>\n\n <!-- \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 Scroll area \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 -->\n <div class=\"npv-scroll-area\" #pdfContainer\n (scroll)=\"onContainerScroll()\" (click)=\"ctxVisible = false\">\n <div class=\"npv-scroll-inner\">\n\n <ng-container *ngFor=\"let p of pageRange()\">\n <div class=\"npv-page-wrapper\" [id]=\"'npv-page-' + p\">\n\n <canvas [id]=\"'npv-canvas-' + p\" class=\"npv-canvas\"></canvas>\n\n <svg *ngIf=\"getPageInfo(p) as pi\"\n [id]=\"'npv-svg-' + p\"\n class=\"npv-overlay\"\n [class.npv-overlay--text-mode]=\"selectionMode === 'select-text'\"\n [attr.width]=\"pi.width\" [attr.height]=\"pi.height\"\n [attr.viewBox]=\"'0 0 ' + pi.width + ' ' + pi.height\"\n (mousedown)=\"onSvgMouseDown($event, p)\">\n\n <!-- Hit area for drag selection on empty page space -->\n <rect x=\"0\" y=\"0\" [attr.width]=\"pi.width\" [attr.height]=\"pi.height\"\n fill=\"transparent\"></rect>\n\n <!-- Annotation boxes -->\n <polygon\n *ngFor=\"let box of getBoxesForPage(p)\"\n [attr.points]=\"getSvgPoints(box, pi)\"\n class=\"npv-box\"\n [class.npv-box--clicked]=\"isClicked(box)\"\n [class.npv-box--multi]=\"isMultiSelected(box)\"\n [style.fill]=\"isClicked(box) ? highlightingColor : (isMultiSelected(box) ? selectedColor : 'transparent')\"\n [style.stroke]=\"annotationStroke\"\n (click)=\"onBoxClick($event, box)\">\n <title>{{ box.content || '' }}</title>\n </polygon>\n\n <!-- Search highlights -->\n <polygon\n *ngFor=\"let m of getSearchMatchesForPage(p); let mi = index\"\n [attr.points]=\"searchMatchPoints(m)\"\n class=\"npv-search-highlight\"\n [class.npv-search-highlight--current]=\"isCurrentSearchMatch(p, mi)\">\n </polygon>\n\n <!-- Drag selection rectangle -->\n <rect *ngIf=\"getDragRect(p) as dr\"\n [attr.x]=\"dr.x\" [attr.y]=\"dr.y\"\n [attr.width]=\"dr.w\" [attr.height]=\"dr.h\"\n class=\"npv-drag-rect\">\n </rect>\n\n </svg>\n </div>\n </ng-container>\n\n <div class=\"npv-placeholder npv-placeholder--error\" *ngIf=\"!loading && loadError\">\n {{ l.loadError }}\n </div>\n <div class=\"npv-placeholder\" *ngIf=\"!loading && !loadError && totalPages === 0\">\n {{ l.noDocument }}\n </div>\n\n </div><!-- /npv-scroll-inner -->\n </div>\n\n <!-- \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 Context menu \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 -->\n <div *ngIf=\"ctxVisible && contextMenuItems.length\"\n class=\"npv-context-menu\"\n [style.left.px]=\"ctxX\" [style.top.px]=\"ctxY\"\n (click)=\"$event.stopPropagation()\">\n <div *ngFor=\"let item of contextMenuItems\"\n class=\"npv-context-item\"\n (click)=\"onContextMenuAction(item)\">\n {{ item.label }}\n </div>\n </div>\n\n</div>\n", styles: [".npv-root{display:flex;flex-direction:column;height:100%;overflow:hidden;background:#e9ecee;position:relative;font-family:Roboto,sans-serif}.npv-toolbar{display:flex;align-items:center;gap:2px;padding:4px 8px;background:#fff;color:#000;min-height:48px;flex-shrink:0;z-index:10;box-shadow:0 2px 4px #0006}.npv-toolbar button{color:#505050}.npv-toolbar button:hover:not([disabled]){background:#0000000f}.npv-toolbar button[disabled]{opacity:.35}.npv-toolbar button.npv-active{color:#1976d2;background:#e3f0fd;box-shadow:inset 0 2px 4px #00000026}.npv-toolbar button.npv-active:hover:not([disabled]){background:#cce0fa}.npv-toolbar .npv-sep{width:1px;height:24px;background:#00000026;margin:0 4px}.npv-toolbar .npv-label{font-size:13px;min-width:50px;text-align:center;color:#505050;-webkit-user-select:none;user-select:none}.npv-toolbar .npv-search-input{background:#0000000f;border:1px solid rgba(0,0,0,.2);border-radius:4px;color:#000;font-size:13px;padding:4px 8px;outline:none;width:180px}.npv-toolbar .npv-search-input::placeholder{color:#0006}.npv-toolbar .npv-search-input:focus{border-color:#1976d2}.npv-toolbar .npv-search-count{font-size:12px;color:#607d8b;white-space:nowrap;min-width:60px}.npv-toolbar .npv-search-count.npv-no-match{color:#e53935}.npv-loading{display:flex;align-items:center;justify-content:center;gap:10px;padding:16px;color:#666;font-size:14px;flex-shrink:0}.npv-spinner{width:20px;height:20px;border:3px solid rgba(0,0,0,.1);border-top-color:#1976d2;border-radius:50%;animation:npv-spin .8s linear infinite}@keyframes npv-spin{to{transform:rotate(360deg)}}.npv-scroll-area{flex:1;overflow:auto}.npv-scroll-inner{display:flex;flex-direction:column;align-items:center;min-width:max-content;padding:16px;gap:16px}.npv-page-wrapper{position:relative;display:inline-block;box-shadow:0 4px 12px #00000080;line-height:0}.npv-canvas{display:block}.npv-overlay{position:absolute;top:0;left:0;pointer-events:all;overflow:visible;cursor:crosshair;user-select:none;-webkit-user-select:none}.npv-overlay.npv-overlay--text-mode{pointer-events:none}.npv-box{pointer-events:all;stroke-width:2;fill:transparent;cursor:pointer;transition:fill .15s ease,stroke-width .15s ease}.npv-box:hover{stroke-width:3;filter:drop-shadow(0 0 3px rgba(233,115,50,.7))}.npv-box.npv-box--clicked{stroke-width:3}.npv-box.npv-box--multi{stroke-width:2.5}.npv-search-highlight{fill:#ffeb3b59;stroke:#ffc800cc;stroke-width:1.5;pointer-events:none}.npv-search-highlight.npv-search-highlight--current{fill:#ff980073;stroke:#ff6400e6;stroke-width:2}.npv-drag-rect{fill:#0078d71a;stroke:#0078d7b3;stroke-width:1.5;stroke-dasharray:5 3;pointer-events:none}.npv-placeholder{color:#aaa;font-size:14px;padding:40px;text-align:center}.npv-placeholder.npv-placeholder--error{color:#e53935}.npv-context-menu{position:fixed;z-index:9999;background:#fff;border:1px solid rgba(0,0,0,.12);border-radius:4px;box-shadow:0 4px 16px #0003;padding:4px 0;min-width:160px}.npv-context-item{padding:10px 16px;font-size:14px;cursor:pointer;color:#000000de;-webkit-user-select:none;user-select:none}.npv-context-item:hover{background:#0000000d}\n"] }]
|
|
702
836
|
}], ctorParameters: () => [{ type: i0.ChangeDetectorRef }, { type: i0.NgZone }, { type: i0.ElementRef }, { type: undefined, decorators: [{
|
|
703
837
|
type: Inject,
|
|
704
838
|
args: [NGX_PDF_WORKER_SRC]
|
|
@@ -718,6 +852,20 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
|
|
|
718
852
|
type: Input
|
|
719
853
|
}], labels: [{
|
|
720
854
|
type: Input
|
|
855
|
+
}], showZoom: [{
|
|
856
|
+
type: Input
|
|
857
|
+
}], showRotation: [{
|
|
858
|
+
type: Input
|
|
859
|
+
}], showPageNavigation: [{
|
|
860
|
+
type: Input
|
|
861
|
+
}], showAnnotationNavigation: [{
|
|
862
|
+
type: Input
|
|
863
|
+
}], showSelectionMode: [{
|
|
864
|
+
type: Input
|
|
865
|
+
}], showSearch: [{
|
|
866
|
+
type: Input
|
|
867
|
+
}], apiKey: [{
|
|
868
|
+
type: Input
|
|
721
869
|
}], boxClicked: [{
|
|
722
870
|
type: Output
|
|
723
871
|
}], boxesSelected: [{
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"aprova.ch-ngx-next-pdf-viewer.mjs","sources":["../../../projects/ngx-next-pdf-viewer/src/lib/tokens.ts","../../../projects/ngx-next-pdf-viewer/src/lib/ngx-next-pdf-viewer.component.ts","../../../projects/ngx-next-pdf-viewer/src/lib/ngx-next-pdf-viewer.component.html","../../../projects/ngx-next-pdf-viewer/src/aprova.ch-ngx-next-pdf-viewer.ts"],"sourcesContent":["import { InjectionToken } from '@angular/core';\n\n/**\n * URL to the PDF.js worker script.\n *\n * Default: `'assets/pdf.worker.min.mjs'`\n *\n * Override in your application by providing this token:\n * ```ts\n * providers: [\n * { provide: NGX_PDF_WORKER_SRC, useValue: 'assets/pdf.worker.min.mjs' }\n * ]\n * ```\n */\nexport const NGX_PDF_WORKER_SRC = new InjectionToken<string>(\n 'NGX_PDF_WORKER_SRC',\n { factory: () => 'assets/pdf.worker.min.mjs' }\n);\n","import {\n Component, Input, Output, EventEmitter, Inject,\n OnChanges, OnDestroy, SimpleChanges,\n ViewChild, ElementRef, ChangeDetectorRef,\n HostListener, NgZone, AfterViewInit\n} from '@angular/core';\nimport { CommonModule } from '@angular/common';\nimport { FormsModule } from '@angular/forms';\nimport { MatIconModule } from '@angular/material/icon';\nimport { MatButtonModule } from '@angular/material/button';\nimport { MatTooltipModule } from '@angular/material/tooltip';\nimport { MatInputModule } from '@angular/material/input';\nimport { MatFormFieldModule } from '@angular/material/form-field';\nimport * as pdfjsLib from 'pdfjs-dist';\nimport { PDFDocumentProxy, PDFPageProxy } from 'pdfjs-dist';\n\nimport { BoundingBox, ContextMenuItem, PdfViewerLabels, ZoomMode } from './models';\nimport { NGX_PDF_WORKER_SRC } from './tokens';\n\n// ──────────────────────────────────────────────\n// Internal helpers\n// ──────────────────────────────────────────────\n\ninterface RenderedPage {\n pageNum: number;\n width: number;\n height: number;\n rotation: number;\n}\n\ninterface DragState {\n active: boolean;\n pageNum: number;\n startX: number;\n startY: number;\n currentX: number;\n currentY: number;\n}\n\ninterface SearchMatch {\n pageNum: number;\n polygon: number[];\n}\n\n// ──────────────────────────────────────────────\n// Component\n// ──────────────────────────────────────────────\n\n@Component({\n selector: 'ngx-next-pdf-viewer',\n standalone: true,\n imports: [\n CommonModule,\n FormsModule,\n MatIconModule,\n MatButtonModule,\n MatTooltipModule,\n MatInputModule,\n MatFormFieldModule\n ],\n templateUrl: './ngx-next-pdf-viewer.component.html',\n styleUrl: './ngx-next-pdf-viewer.component.scss'\n})\nexport class NgxNextPdfViewerComponent implements OnChanges, OnDestroy, AfterViewInit {\n\n // ── Inputs ──────────────────────────────────\n /** PDF file to display */\n @Input() blob: Blob | undefined;\n /** Bounding-box annotations to overlay */\n @Input() annotations: BoundingBox[] = [];\n /** Items shown in the context menu after drag-selecting boxes */\n @Input() contextMenuItems: ContextMenuItem[] = [];\n /** Fill colour for a single-clicked box (CSS colour string) */\n @Input() highlightingColor = 'rgba(255, 200, 0, 0.35)';\n /** Fill colour for drag-selected boxes (CSS colour string) */\n @Input() selectedColor = 'rgba(0, 120, 215, 0.35)';\n /** Stroke colour for all annotation polygons */\n @Input() annotationStroke = '#e97332';\n /** Initial zoom: numeric level (1.0 = 100 %) or 'fit-to-page' | 'fit-to-width' | 'fit-to-height' */\n @Input() initialZoom: ZoomMode = 1.5;\n /** Override any subset of the viewer's user-visible strings */\n @Input() labels: Partial<PdfViewerLabels> = {};\n\n private static readonly DEFAULT_LABELS: PdfViewerLabels = {\n zoomOut: 'Zoom out',\n zoomIn: 'Zoom in',\n rotateLeft: 'Rotate left',\n rotateRight: 'Rotate right',\n previousPage: 'Previous page',\n nextPage: 'Next page',\n search: 'Search',\n previousResult: 'Previous result',\n nextResult: 'Next result',\n previousAnnotation: 'Previous annotation',\n nextAnnotation: 'Next annotation',\n selectArea: 'Select area',\n selectText: 'Select & copy text',\n searchPlaceholder: 'Search in PDF…',\n noResults: 'No results',\n loading: 'Loading PDF…',\n noDocument: 'No PDF loaded',\n loadError: 'Failed to load PDF',\n };\n\n get l(): PdfViewerLabels {\n return { ...NgxNextPdfViewerComponent.DEFAULT_LABELS, ...this.labels };\n }\n\n // ── Outputs ─────────────────────────────────\n /** Fired when the user clicks a single annotation box */\n @Output() boxClicked = new EventEmitter<{ box: BoundingBox; selected: boolean }>();\n /** Fired when the user picks a context-menu item after drag-selection */\n @Output() boxesSelected = new EventEmitter<{ boxes: BoundingBox[]; action: string }>();\n\n // ── View refs ────────────────────────────────\n @ViewChild('pdfContainer') pdfContainer!: ElementRef<HTMLDivElement>;\n\n // ── PDF state ────────────────────────────────\n pdfDoc: PDFDocumentProxy | null = null;\n renderedPages: RenderedPage[] = [];\n currentPage = 1;\n totalPages = 0;\n zoom = 1.5;\n userRotation = 0;\n\n // ── Annotation state ─────────────────────────\n clickedBoxKey: string | null = null;\n multiSelectedKeys: Set<string> = new Set();\n\n // ── Drag-select state ────────────────────────\n drag: DragState = { active: false, pageNum: 0, startX: 0, startY: 0, currentX: 0, currentY: 0 };\n\n // ── Context-menu state ───────────────────────\n ctxVisible = false;\n ctxX = 0;\n ctxY = 0;\n\n // ── Search state ─────────────────────────────\n searchVisible = false;\n searchQuery = '';\n searchMatches: SearchMatch[] = [];\n searchIndex = -1;\n\n // ── Selection mode ───────────────────────────\n selectionMode: 'select-area' | 'select-text' = 'select-area';\n\n // ── Loading ──────────────────────────────────\n loading = false;\n loadError = false;\n\n private renderTasks: Map<number, any> = new Map();\n private textLayers: Map<number, any> = new Map();\n private wheelListener?: (e: WheelEvent) => void;\n\n constructor(\n private cdr: ChangeDetectorRef,\n private zone: NgZone,\n private el: ElementRef,\n @Inject(NGX_PDF_WORKER_SRC) workerSrc: string\n ) {\n pdfjsLib.GlobalWorkerOptions.workerSrc = workerSrc;\n }\n\n ngAfterViewInit(): void {\n if (typeof this.initialZoom === 'number') {\n this.zoom = this.initialZoom;\n }\n // Ctrl+scroll zooming – requires passive:false to call preventDefault()\n this.zone.runOutsideAngular(() => {\n this.wheelListener = (e: WheelEvent) => {\n if (!e.ctrlKey) return;\n e.preventDefault();\n this.zone.run(() => e.deltaY < 0 ? this.zoomIn() : this.zoomOut());\n };\n this.el.nativeElement.addEventListener('wheel', this.wheelListener, { passive: false });\n });\n }\n\n ngOnChanges(changes: SimpleChanges): void {\n if (changes['blob'] && this.blob) {\n console.log('load new file');\n this.loadPdf(this.blob);\n }\n if (changes['annotations'] && !changes['blob']) {\n console.log('set new annotations', this.annotations.length);\n this.cdr.detectChanges();\n if (this.annotations.length === 1) {\n this.scrollToBox(this.annotations[0]);\n }\n }\n }\n\n ngOnDestroy(): void {\n if (this.wheelListener) {\n this.el.nativeElement.removeEventListener('wheel', this.wheelListener);\n }\n this.removeAllTextLayers();\n this.pdfDoc?.destroy();\n }\n\n // ─────────────────────────────────────────────\n // PDF loading & rendering\n // ─────────────────────────────────────────────\n\n private async loadPdf(blob: Blob): Promise<void> {\n this.loading = true;\n this.loadError = false;\n this.renderedPages = [];\n this.clickedBoxKey = null;\n this.multiSelectedKeys.clear();\n this.searchMatches = [];\n this.searchIndex = -1;\n this.removeAllTextLayers();\n this.cdr.detectChanges();\n\n try {\n this.pdfDoc?.destroy();\n const buf = await blob.arrayBuffer();\n this.pdfDoc = await pdfjsLib.getDocument({ data: buf }).promise;\n this.totalPages = this.pdfDoc.numPages;\n this.currentPage = 1;\n if (typeof this.initialZoom !== 'number') {\n this.zoom = await this.computeFitZoom(this.initialZoom);\n }\n this.loading = false;\n this.cdr.detectChanges();\n\n for (let p = 1; p <= this.totalPages; p++) {\n await this.renderPage(p);\n }\n\n if (this.annotations.length === 1) {\n this.scrollToBox(this.annotations[0]);\n }\n } catch {\n this.loading = false;\n this.loadError = true;\n }\n this.cdr.detectChanges();\n }\n\n private async computeFitZoom(mode: Exclude<ZoomMode, number>): Promise<number> {\n if (!this.pdfDoc) return 1;\n const page = await this.pdfDoc.getPage(1);\n const rotation = (page.rotate + this.userRotation) % 360;\n const vp = page.getViewport({ scale: 1, rotation });\n page.cleanup();\n\n const container = this.pdfContainer?.nativeElement;\n if (!container) return 1;\n\n // Subtract the 16 px padding on each side defined in npv-scroll-inner\n const availW = container.clientWidth - 32;\n const availH = container.clientHeight - 32;\n const scaleW = availW / vp.width;\n const scaleH = availH / vp.height;\n\n switch (mode) {\n case 'fit-to-width': return scaleW;\n case 'fit-to-height': return scaleH;\n case 'fit-to-page': return Math.min(scaleW, scaleH);\n }\n }\n\n private async renderPage(pageNum: number): Promise<void> {\n if (!this.pdfDoc) return;\n const page: PDFPageProxy = await this.pdfDoc.getPage(pageNum);\n const totalRotation = (page.rotate + this.userRotation) % 360;\n const viewport = page.getViewport({ scale: this.zoom, rotation: totalRotation });\n\n // HiDPI: render at physical pixel density, display at CSS size\n const dpr = window.devicePixelRatio || 1;\n const hiResViewport = page.getViewport({ scale: this.zoom * dpr, rotation: totalRotation });\n\n const canvas = document.getElementById(`npv-canvas-${pageNum}`) as HTMLCanvasElement | null;\n if (!canvas) return;\n\n canvas.width = hiResViewport.width;\n canvas.height = hiResViewport.height;\n canvas.style.width = `${viewport.width}px`;\n canvas.style.height = `${viewport.height}px`;\n\n if (this.renderTasks.has(pageNum)) {\n try { this.renderTasks.get(pageNum).cancel(); } catch (_) {}\n }\n\n const ctx = canvas.getContext('2d')!;\n const task = page.render({ canvasContext: ctx, viewport: hiResViewport });\n this.renderTasks.set(pageNum, task);\n try {\n await task.promise;\n } catch (e: any) {\n if (e?.name !== 'RenderingCancelledException') console.error(e);\n return;\n }\n this.renderTasks.delete(pageNum);\n\n const existing = this.renderedPages.find(r => r.pageNum === pageNum);\n if (existing) {\n existing.width = viewport.width;\n existing.height = viewport.height;\n existing.rotation = totalRotation;\n } else {\n this.renderedPages.push({ pageNum, width: viewport.width, height: viewport.height, rotation: totalRotation });\n }\n this.cdr.detectChanges();\n page.cleanup();\n }\n\n private async rerenderAll(): Promise<void> {\n if (!this.pdfDoc) return;\n if (this.selectionMode === 'select-text') {\n this.removeAllTextLayers();\n }\n for (let p = 1; p <= this.totalPages; p++) {\n await this.renderPage(p);\n if (this.selectionMode === 'select-text') {\n await this.renderTextLayer(p);\n }\n }\n this.cdr.detectChanges();\n }\n\n // ─────────────────────────────────────────────\n // Coordinate transformation\n // ─────────────────────────────────────────────\n\n /** Converts a polygon (y=0 at top, any consistent unit) to SVG canvas coordinates */\n transformPolygon(\n polygon: number[],\n pdfWidth: number,\n pdfHeight: number,\n canvasWidth: number,\n canvasHeight: number,\n rotation: number\n ): number[] {\n const norm = ((rotation % 360) + 360) % 360;\n const result: number[] = [];\n for (let i = 0; i < polygon.length; i += 2) {\n const px = polygon[i];\n const py = polygon[i + 1];\n let cx: number, cy: number;\n switch (norm) {\n case 90:\n cx = (pdfHeight - py) * canvasWidth / pdfHeight;\n cy = px * canvasHeight / pdfWidth;\n break;\n case 180:\n cx = (pdfWidth - px) * canvasWidth / pdfWidth;\n cy = (pdfHeight - py) * canvasHeight / pdfHeight;\n break;\n case 270:\n cx = py * canvasWidth / pdfHeight;\n cy = (pdfWidth - px) * canvasHeight / pdfWidth;\n break;\n default:\n cx = px * canvasWidth / pdfWidth;\n cy = py * canvasHeight / pdfHeight;\n }\n result.push(cx, cy);\n }\n return result;\n }\n\n getSvgPoints(box: BoundingBox, pi: RenderedPage): string {\n const pts = this.transformPolygon(\n box.polygon, box.width, box.height, pi.width, pi.height, pi.rotation\n );\n const pairs: string[] = [];\n for (let i = 0; i < pts.length; i += 2) {\n pairs.push(`${pts[i].toFixed(2)},${pts[i + 1].toFixed(2)}`);\n }\n return pairs.join(' ');\n }\n\n private polygonBBox(pts: number[]): { x: number; y: number; w: number; h: number } {\n let minX = Infinity, minY = Infinity, maxX = -Infinity, maxY = -Infinity;\n for (let i = 0; i < pts.length; i += 2) {\n minX = Math.min(minX, pts[i]); maxX = Math.max(maxX, pts[i]);\n minY = Math.min(minY, pts[i+1]); maxY = Math.max(maxY, pts[i+1]);\n }\n return { x: minX, y: minY, w: maxX - minX, h: maxY - minY };\n }\n\n private boxKey(box: BoundingBox): string {\n return JSON.stringify({ page: box.page, polygon: box.polygon });\n }\n\n // ─────────────────────────────────────────────\n // Template helpers\n // ─────────────────────────────────────────────\n\n getPageInfo(pageNum: number): RenderedPage | undefined {\n return this.renderedPages.find(r => r.pageNum === pageNum);\n }\n\n getBoxesForPage(pageNum: number): BoundingBox[] {\n return this.annotations.filter(b => b.page === pageNum);\n }\n\n isClicked(box: BoundingBox): boolean {\n return this.clickedBoxKey === this.boxKey(box);\n }\n\n isMultiSelected(box: BoundingBox): boolean {\n return this.multiSelectedKeys.has(this.boxKey(box));\n }\n\n pageRange(): number[] {\n return Array.from({ length: this.totalPages }, (_, i) => i + 1);\n }\n\n getDragRect(pageNum: number): { x: number; y: number; w: number; h: number } | null {\n if (!this.drag.active || this.drag.pageNum !== pageNum) return null;\n return {\n x: Math.min(this.drag.startX, this.drag.currentX),\n y: Math.min(this.drag.startY, this.drag.currentY),\n w: Math.abs(this.drag.currentX - this.drag.startX),\n h: Math.abs(this.drag.currentY - this.drag.startY)\n };\n }\n\n getSearchMatchesForPage(pageNum: number): SearchMatch[] {\n return this.searchMatches.filter(m => m.pageNum === pageNum);\n }\n\n getSearchIndexOffset(pageNum: number): number {\n return this.searchMatches.findIndex(m => m.pageNum === pageNum);\n }\n\n isCurrentSearchMatch(pageNum: number, localIndex: number): boolean {\n const offset = this.getSearchIndexOffset(pageNum);\n return offset >= 0 && offset + localIndex === this.searchIndex;\n }\n\n searchMatchPoints(m: SearchMatch): string {\n const pairs: string[] = [];\n for (let i = 0; i < m.polygon.length; i += 2) {\n pairs.push(`${m.polygon[i].toFixed(2)},${m.polygon[i + 1].toFixed(2)}`);\n }\n return pairs.join(' ');\n }\n\n // ─────────────────────────────────────────────\n // Box interaction\n // ─────────────────────────────────────────────\n\n onBoxClick(event: MouseEvent, box: BoundingBox): void {\n event.stopPropagation();\n this.ctxVisible = false;\n this.multiSelectedKeys.clear();\n const key = this.boxKey(box);\n const wasSelected = this.clickedBoxKey === key;\n this.clickedBoxKey = wasSelected ? null : key;\n this.cdr.detectChanges();\n this.boxClicked.emit({ box, selected: !wasSelected });\n }\n\n // ─────────────────────────────────────────────\n // Drag-select\n // ─────────────────────────────────────────────\n\n onSvgMouseDown(event: MouseEvent, pageNum: number): void {\n if (this.selectionMode === 'select-text') return;\n if (event.button !== 0) return;\n const tag = (event.target as Element).tagName?.toLowerCase();\n if (tag === 'polygon' || tag === 'title') return;\n this.ctxVisible = false;\n this.clickedBoxKey = null;\n const pt = this.svgPoint(event, pageNum);\n if (!pt) return;\n this.drag = { active: true, pageNum, startX: pt.x, startY: pt.y, currentX: pt.x, currentY: pt.y };\n }\n\n @HostListener('mousemove', ['$event'])\n onDocMouseMove(event: MouseEvent): void {\n if (!this.drag.active) return;\n const pt = this.svgPoint(event, this.drag.pageNum);\n if (!pt) return;\n this.drag.currentX = pt.x;\n this.drag.currentY = pt.y;\n this.cdr.detectChanges();\n }\n\n @HostListener('mouseup', ['$event'])\n onDocMouseUp(event: MouseEvent): void {\n if (!this.drag.active) return;\n const rect = this.getDragRect(this.drag.pageNum);\n this.drag.active = false;\n\n if (!rect || (rect.w < 5 && rect.h < 5)) { this.cdr.detectChanges(); return; }\n\n const pageInfo = this.getPageInfo(this.drag.pageNum);\n if (!pageInfo) { this.cdr.detectChanges(); return; }\n\n const hits: BoundingBox[] = [];\n for (const box of this.annotations) {\n const pts = this.transformPolygon(\n box.polygon, box.width, box.height, pageInfo.width, pageInfo.height, pageInfo.rotation\n );\n const bb = this.polygonBBox(pts);\n if (this.rectsIntersect(rect, bb)) hits.push(box);\n }\n\n this.multiSelectedKeys = new Set(hits.map(b => this.boxKey(b)));\n\n if (hits.length > 0 && this.contextMenuItems.length > 0) {\n this.ctxX = event.clientX;\n this.ctxY = event.clientY;\n this.ctxVisible = true;\n }\n this.cdr.detectChanges();\n }\n\n private svgPoint(event: MouseEvent, pageNum: number): { x: number; y: number } | null {\n const svg = document.getElementById(`npv-svg-${pageNum}`) as SVGSVGElement | null;\n if (!svg) return null;\n const r = svg.getBoundingClientRect();\n return { x: event.clientX - r.left, y: event.clientY - r.top };\n }\n\n private rectsIntersect(\n a: { x: number; y: number; w: number; h: number },\n b: { x: number; y: number; w: number; h: number }\n ): boolean {\n return !(a.x + a.w < b.x || b.x + b.w < a.x || a.y + a.h < b.y || b.y + b.h < a.y);\n }\n\n // ─────────────────────────────────────────────\n // Context menu\n // ─────────────────────────────────────────────\n\n onContextMenuAction(item: ContextMenuItem): void {\n this.ctxVisible = false;\n const selected = this.annotations.filter(b => this.multiSelectedKeys.has(this.boxKey(b)));\n this.boxesSelected.emit({ boxes: selected, action: item.action });\n this.multiSelectedKeys.clear();\n this.cdr.detectChanges();\n }\n\n @HostListener('document:click')\n onDocClick(): void {\n if (this.ctxVisible) { this.ctxVisible = false; this.cdr.detectChanges(); }\n }\n\n // ─────────────────────────────────────────────\n // Toolbar – zoom\n // ─────────────────────────────────────────────\n\n zoomIn(): void { this.zoom = Math.min(this.zoom + 0.25, 5); this.rerenderAll(); }\n zoomOut(): void { this.zoom = Math.max(this.zoom - 0.25, 0.25); this.rerenderAll(); }\n\n get zoomPercent(): number { return Math.round(this.zoom * 100); }\n\n // ─────────────────────────────────────────────\n // Toolbar – rotation\n // ─────────────────────────────────────────────\n\n rotateLeft(): void { this.userRotation = (this.userRotation + 270) % 360; this.rerenderAll(); }\n rotateRight(): void { this.userRotation = (this.userRotation + 90) % 360; this.rerenderAll(); }\n\n // ─────────────────────────────────────────────\n // Toolbar – page navigation\n // ─────────────────────────────────────────────\n\n goToPrevPage(): void { if (this.currentPage > 1) this.scrollToPageNum(this.currentPage - 1); }\n goToNextPage(): void { if (this.currentPage < this.totalPages) this.scrollToPageNum(this.currentPage + 1); }\n\n scrollToPageNum(pageNum: number): void {\n this.currentPage = pageNum;\n document.getElementById(`npv-page-${pageNum}`)?.scrollIntoView({ behavior: 'smooth', block: 'start' });\n }\n\n scrollToBox(box: BoundingBox): void {\n this.currentPage = box.page;\n console.log('scroll to page', this.currentPage)\n const pageEl = document.getElementById(`npv-page-${box.page}`);\n if (!pageEl) {\n console.log('no page element found, stop scrolling')\n return;\n }\n const pi = this.getPageInfo(box.page);\n if (!pi) {\n pageEl.scrollIntoView({ behavior: 'smooth', block: 'start' });\n console.log('scroll into view done')\n return;\n }\n const pts = this.transformPolygon(box.polygon, box.width, box.height, pi.width, pi.height, pi.rotation);\n const bb = this.polygonBBox(pts);\n const top = (pageEl as HTMLElement).offsetTop + bb.y - window.innerHeight / 2;\n this.pdfContainer?.nativeElement.scrollTo({ top, behavior: 'smooth' });\n console.log('scrolling to element done')\n }\n\n // ─────────────────────────────────────────────\n // Toolbar – search\n // ─────────────────────────────────────────────\n\n toggleSearch(): void {\n this.searchVisible = !this.searchVisible;\n if (!this.searchVisible) {\n this.searchQuery = '';\n this.searchMatches = [];\n this.searchIndex = -1;\n this.cdr.detectChanges();\n }\n }\n\n async onSearchInput(): Promise<void> {\n const q = this.searchQuery.trim().toLowerCase();\n this.searchMatches = [];\n this.searchIndex = -1;\n if (!q || !this.pdfDoc) { this.cdr.detectChanges(); return; }\n\n for (let p = 1; p <= this.totalPages; p++) {\n const pi = this.getPageInfo(p);\n if (!pi) continue;\n const page = await this.pdfDoc.getPage(p);\n const text = await page.getTextContent();\n const vp = page.getViewport({ scale: this.zoom, rotation: pi.rotation });\n\n for (const item of text.items as any[]) {\n if (!item.str) continue;\n const idx = item.str.toLowerCase().indexOf(q);\n if (idx < 0) continue;\n\n const charW = (item.width / item.str.length) || 6;\n const itemH = Math.abs(item.transform[3]) || 10;\n const x0 = item.transform[4] + idx * charW;\n const y0 = item.transform[5];\n\n const t = vp.transform;\n const applyT = (x: number, y: number): [number, number] =>\n [t[0]*x + t[2]*y + t[4], t[1]*x + t[3]*y + t[5]];\n\n const [cx0, cy0] = applyT(x0, y0 + itemH);\n const [cx1, cy1] = applyT(x0 + q.length * charW, y0);\n\n this.searchMatches.push({\n pageNum: p,\n polygon: [cx0, cy0, cx1, cy0, cx1, cy1, cx0, cy1]\n });\n }\n page.cleanup();\n }\n\n if (this.searchMatches.length > 0) {\n this.searchIndex = 0;\n this.scrollToSearchMatch(0);\n }\n this.cdr.detectChanges();\n }\n\n searchNext(): void {\n if (!this.searchMatches.length) return;\n this.searchIndex = (this.searchIndex + 1) % this.searchMatches.length;\n this.scrollToSearchMatch(this.searchIndex);\n this.cdr.detectChanges();\n }\n\n searchPrev(): void {\n if (!this.searchMatches.length) return;\n this.searchIndex = (this.searchIndex - 1 + this.searchMatches.length) % this.searchMatches.length;\n this.scrollToSearchMatch(this.searchIndex);\n this.cdr.detectChanges();\n }\n\n private scrollToSearchMatch(idx: number): void {\n const m = this.searchMatches[idx];\n if (!m) return;\n document.getElementById(`npv-page-${m.pageNum}`)?.scrollIntoView({ behavior: 'smooth', block: 'center' });\n }\n\n // ─────────────────────────────────────────────\n // Toolbar – annotation navigation\n // ─────────────────────────────────────────────\n\n get annotationIndex(): number {\n if (!this.clickedBoxKey) return -1;\n return this.annotations.findIndex(b => this.boxKey(b) === this.clickedBoxKey);\n }\n\n goToPrevAnnotation(): void {\n if (!this.annotations.length) return;\n const prev = (this.annotationIndex - 1 + this.annotations.length) % this.annotations.length;\n this.selectAnnotation(prev);\n }\n\n goToNextAnnotation(): void {\n if (!this.annotations.length) return;\n const next = (this.annotationIndex + 1) % this.annotations.length;\n this.selectAnnotation(next);\n }\n\n private selectAnnotation(index: number): void {\n const box = this.annotations[index];\n if (!box) return;\n this.multiSelectedKeys.clear();\n this.ctxVisible = false;\n this.clickedBoxKey = this.boxKey(box);\n this.cdr.detectChanges();\n this.scrollToBox(box);\n this.boxClicked.emit({ box, selected: true });\n }\n\n // ─────────────────────────────────────────────\n // Toolbar – selection mode\n // ─────────────────────────────────────────────\n\n toggleSelectionMode(): void {\n this.selectionMode = this.selectionMode === 'select-area' ? 'select-text' : 'select-area';\n if (this.selectionMode === 'select-text') {\n this.renderedPages.forEach(rp => this.renderTextLayer(rp.pageNum));\n } else {\n this.removeAllTextLayers();\n }\n this.cdr.detectChanges();\n }\n\n private async renderTextLayer(pageNum: number): Promise<void> {\n if (!this.pdfDoc) return;\n const pi = this.getPageInfo(pageNum);\n if (!pi) return;\n\n const wrapper = document.getElementById(`npv-page-${pageNum}`) as HTMLElement | null;\n if (!wrapper) return;\n\n this.removeTextLayer(pageNum);\n\n const page = await this.pdfDoc.getPage(pageNum);\n const totalRotation = (page.rotate + this.userRotation) % 360;\n const viewport = page.getViewport({ scale: this.zoom, rotation: totalRotation });\n\n const div = document.createElement('div');\n div.className = 'npv-text-layer';\n div.style.width = `${pi.width}px`;\n div.style.height = `${pi.height}px`;\n wrapper.appendChild(div);\n\n const textLayer = new (pdfjsLib as any).TextLayer({\n textContentSource: page.streamTextContent(),\n container: div,\n viewport,\n });\n\n this.textLayers.set(pageNum, textLayer);\n try {\n await textLayer.render();\n } catch (_) {}\n page.cleanup();\n }\n\n private removeTextLayer(pageNum: number): void {\n const tl = this.textLayers.get(pageNum);\n if (tl) {\n try { tl.cancel(); } catch (_) {}\n this.textLayers.delete(pageNum);\n }\n const wrapper = document.getElementById(`npv-page-${pageNum}`);\n wrapper?.querySelector('.npv-text-layer')?.remove();\n }\n\n private removeAllTextLayers(): void {\n for (const pageNum of Array.from(this.textLayers.keys())) {\n this.removeTextLayer(pageNum);\n }\n }\n\n // ─────────────────────────────────────────────\n // Scroll tracking\n // ─────────────────────────────────────────────\n\n onContainerScroll(): void {\n if (!this.pdfContainer) return;\n const top = this.pdfContainer.nativeElement.scrollTop;\n let closest = 1, minDist = Infinity;\n for (let p = 1; p <= this.totalPages; p++) {\n const el = document.getElementById(`npv-page-${p}`) as HTMLElement | null;\n if (!el) continue;\n const dist = Math.abs(el.offsetTop - top);\n if (dist < minDist) { minDist = dist; closest = p; }\n }\n if (this.currentPage !== closest) { this.currentPage = closest; this.cdr.detectChanges(); }\n }\n}\n","<div class=\"npv-root\">\n\n <!-- ─────────── Toolbar ─────────── -->\n <div class=\"npv-toolbar\">\n\n <button mat-icon-button [matTooltip]=\"l.zoomOut\" (click)=\"zoomOut()\" [disabled]=\"zoom <= 0.25\">\n <mat-icon>zoom_out</mat-icon>\n </button>\n <span class=\"npv-label\">{{ zoomPercent }}%</span>\n <button mat-icon-button [matTooltip]=\"l.zoomIn\" (click)=\"zoomIn()\" [disabled]=\"zoom >= 5\">\n <mat-icon>zoom_in</mat-icon>\n </button>\n\n <div class=\"npv-sep\"></div>\n\n <button mat-icon-button [matTooltip]=\"l.rotateLeft\" (click)=\"rotateLeft()\">\n <mat-icon>rotate_left</mat-icon>\n </button>\n <button mat-icon-button [matTooltip]=\"l.rotateRight\" (click)=\"rotateRight()\">\n <mat-icon>rotate_right</mat-icon>\n </button>\n\n <div class=\"npv-sep\"></div>\n\n <button mat-icon-button [matTooltip]=\"l.previousPage\" (click)=\"goToPrevPage()\" [disabled]=\"currentPage <= 1\">\n <mat-icon>chevron_left</mat-icon>\n </button>\n <span class=\"npv-label\">{{ currentPage }} / {{ totalPages }}</span>\n <button mat-icon-button [matTooltip]=\"l.nextPage\" (click)=\"goToNextPage()\" [disabled]=\"currentPage >= totalPages\">\n <mat-icon>chevron_right</mat-icon>\n </button>\n\n <ng-container *ngIf=\"annotations.length\">\n <div class=\"npv-sep\"></div>\n\n <button mat-icon-button [matTooltip]=\"l.previousAnnotation\" (click)=\"goToPrevAnnotation()\">\n <mat-icon>navigate_before</mat-icon>\n </button>\n <span class=\"npv-label\">\n {{ annotationIndex >= 0 ? annotationIndex + 1 : '–' }} / {{ annotations.length }}\n </span>\n <button mat-icon-button [matTooltip]=\"l.nextAnnotation\" (click)=\"goToNextAnnotation()\">\n <mat-icon>navigate_next</mat-icon>\n </button>\n </ng-container>\n\n <div class=\"npv-sep\"></div>\n\n <button mat-icon-button\n [matTooltip]=\"selectionMode === 'select-area' ? l.selectText : l.selectArea\"\n (click)=\"toggleSelectionMode()\"\n [class.npv-active]=\"selectionMode === 'select-text'\">\n <mat-icon>text_fields</mat-icon>\n </button>\n\n <div class=\"npv-sep\"></div>\n\n <button mat-icon-button [matTooltip]=\"l.search\" (click)=\"toggleSearch()\" [class.npv-active]=\"searchVisible\">\n <mat-icon>search</mat-icon>\n </button>\n\n <ng-container *ngIf=\"searchVisible\">\n <input\n class=\"npv-search-input\"\n type=\"text\"\n [placeholder]=\"l.searchPlaceholder\"\n [(ngModel)]=\"searchQuery\"\n (input)=\"onSearchInput()\"\n (keydown.enter)=\"searchNext()\"\n (keydown.shift.enter)=\"searchPrev()\"\n autofocus\n />\n <button mat-icon-button [matTooltip]=\"l.previousResult\"\n (click)=\"searchPrev()\" [disabled]=\"!searchMatches.length\">\n <mat-icon>expand_less</mat-icon>\n </button>\n <button mat-icon-button [matTooltip]=\"l.nextResult\"\n (click)=\"searchNext()\" [disabled]=\"!searchMatches.length\">\n <mat-icon>expand_more</mat-icon>\n </button>\n <span class=\"npv-search-count\" *ngIf=\"searchMatches.length\">\n {{ searchIndex + 1 }} / {{ searchMatches.length }}\n </span>\n <span class=\"npv-search-count npv-no-match\" *ngIf=\"searchQuery && !searchMatches.length\">\n {{ l.noResults }}\n </span>\n </ng-container>\n\n </div>\n\n <!-- ─────────── Loading ─────────── -->\n <div class=\"npv-loading\" *ngIf=\"loading\">\n <span class=\"npv-spinner\"></span> {{ l.loading }}\n </div>\n\n <!-- ─────────── Scroll area ─────────── -->\n <div class=\"npv-scroll-area\" #pdfContainer\n (scroll)=\"onContainerScroll()\" (click)=\"ctxVisible = false\">\n <div class=\"npv-scroll-inner\">\n\n <ng-container *ngFor=\"let p of pageRange()\">\n <div class=\"npv-page-wrapper\" [id]=\"'npv-page-' + p\">\n\n <canvas [id]=\"'npv-canvas-' + p\" class=\"npv-canvas\"></canvas>\n\n <svg *ngIf=\"getPageInfo(p) as pi\"\n [id]=\"'npv-svg-' + p\"\n class=\"npv-overlay\"\n [class.npv-overlay--text-mode]=\"selectionMode === 'select-text'\"\n [attr.width]=\"pi.width\" [attr.height]=\"pi.height\"\n [attr.viewBox]=\"'0 0 ' + pi.width + ' ' + pi.height\"\n (mousedown)=\"onSvgMouseDown($event, p)\">\n\n <!-- Hit area for drag selection on empty page space -->\n <rect x=\"0\" y=\"0\" [attr.width]=\"pi.width\" [attr.height]=\"pi.height\"\n fill=\"transparent\"></rect>\n\n <!-- Annotation boxes -->\n <polygon\n *ngFor=\"let box of getBoxesForPage(p)\"\n [attr.points]=\"getSvgPoints(box, pi)\"\n class=\"npv-box\"\n [class.npv-box--clicked]=\"isClicked(box)\"\n [class.npv-box--multi]=\"isMultiSelected(box)\"\n [style.fill]=\"isClicked(box) ? highlightingColor : (isMultiSelected(box) ? selectedColor : 'transparent')\"\n [style.stroke]=\"annotationStroke\"\n (click)=\"onBoxClick($event, box)\">\n <title>{{ box.content || '' }}</title>\n </polygon>\n\n <!-- Search highlights -->\n <polygon\n *ngFor=\"let m of getSearchMatchesForPage(p); let mi = index\"\n [attr.points]=\"searchMatchPoints(m)\"\n class=\"npv-search-highlight\"\n [class.npv-search-highlight--current]=\"isCurrentSearchMatch(p, mi)\">\n </polygon>\n\n <!-- Drag selection rectangle -->\n <rect *ngIf=\"getDragRect(p) as dr\"\n [attr.x]=\"dr.x\" [attr.y]=\"dr.y\"\n [attr.width]=\"dr.w\" [attr.height]=\"dr.h\"\n class=\"npv-drag-rect\">\n </rect>\n\n </svg>\n </div>\n </ng-container>\n\n <div class=\"npv-placeholder npv-placeholder--error\" *ngIf=\"!loading && loadError\">\n {{ l.loadError }}\n </div>\n <div class=\"npv-placeholder\" *ngIf=\"!loading && !loadError && totalPages === 0\">\n {{ l.noDocument }}\n </div>\n\n </div><!-- /npv-scroll-inner -->\n </div>\n\n <!-- ─────────── Context menu ─────────── -->\n <div *ngIf=\"ctxVisible && contextMenuItems.length\"\n class=\"npv-context-menu\"\n [style.left.px]=\"ctxX\" [style.top.px]=\"ctxY\"\n (click)=\"$event.stopPropagation()\">\n <div *ngFor=\"let item of contextMenuItems\"\n class=\"npv-context-item\"\n (click)=\"onContextMenuAction(item)\">\n {{ item.label }}\n </div>\n </div>\n\n</div>\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"aprova.ch-ngx-next-pdf-viewer.mjs","sources":["../../../projects/ngx-next-pdf-viewer/src/lib/tokens.ts","../../../projects/ngx-next-pdf-viewer/src/lib/ngx-next-pdf-viewer.component.ts","../../../projects/ngx-next-pdf-viewer/src/lib/ngx-next-pdf-viewer.component.html","../../../projects/ngx-next-pdf-viewer/src/aprova.ch-ngx-next-pdf-viewer.ts"],"sourcesContent":["import { InjectionToken } from '@angular/core';\n\n/**\n * URL to the PDF.js worker script.\n *\n * Default: `'assets/pdf.worker.min.mjs'`\n *\n * Override in your application by providing this token:\n * ```ts\n * providers: [\n * { provide: NGX_PDF_WORKER_SRC, useValue: 'assets/pdf.worker.min.mjs' }\n * ]\n * ```\n */\nexport const NGX_PDF_WORKER_SRC = new InjectionToken<string>(\n 'NGX_PDF_WORKER_SRC',\n { factory: () => 'assets/pdf.worker.min.mjs' }\n);\n","import {\n Component, Input, Output, EventEmitter, Inject,\n OnChanges, OnDestroy, SimpleChanges,\n ViewChild, ElementRef, ChangeDetectorRef,\n HostListener, NgZone, AfterViewInit\n} from '@angular/core';\nimport { CommonModule } from '@angular/common';\nimport { FormsModule } from '@angular/forms';\nimport { MatIconModule } from '@angular/material/icon';\nimport { MatButtonModule } from '@angular/material/button';\nimport { MatTooltipModule } from '@angular/material/tooltip';\nimport { MatInputModule } from '@angular/material/input';\nimport { MatFormFieldModule } from '@angular/material/form-field';\nimport * as pdfjsLib from 'pdfjs-dist';\nimport { PDFDocumentProxy, PDFPageProxy } from 'pdfjs-dist';\n\nimport { BoundingBox, ContextMenuItem, PdfViewerLabels, ZoomMode } from './models';\nimport { NGX_PDF_WORKER_SRC } from './tokens';\n\n// ── RSA-2048 public key (SPKI DER, base64) ────────────────────────────────\n// Generated with api-keys/generate.js. The matching private key lives in\n// api-keys/private.key (never ship that file with the library).\nconst API_PUBLIC_KEY_B64 =\n 'MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA32o40ciAzk12XQ7RQpjy' +\n 'YUa22NNDh4jlntE8UPls2PDZLcSTORMyZTASnXzzUq4RodplBaySFbQUHNwYzYYT' +\n 'H8+/GZPInigDqpVVJ+8sHiI+5jA9b4hl6alGzBmnSKaGnJYxy9DnUG/NM5cGK6+' +\n 'MaZJrnjKrrWjQ2ttkuXRmDHLwcvfva06Lv8BEBDmbt1dVnTGPjwUjJelZeu5xVZU' +\n 'gm9QlbhVR0P+vUM11jWzoq7W1bzyoDuToqZ+tQCLSVZ7Pz8FdHn3Wh/Qnw/VhqW' +\n 'IeaHTgswOB1Cti0Oh1o+tpuv3LgIeGyZxyudnWnkDInQ2LvCP9z8aLVI9io/RA3a' +\n 'PiwwIDAQAB';\n\n// ──────────────────────────────────────────────\n// Internal helpers\n// ──────────────────────────────────────────────\n\ninterface RenderedPage {\n pageNum: number;\n width: number;\n height: number;\n rotation: number;\n}\n\ninterface DragState {\n active: boolean;\n pageNum: number;\n startX: number;\n startY: number;\n currentX: number;\n currentY: number;\n}\n\ninterface SearchMatch {\n pageNum: number;\n polygon: number[];\n}\n\n// ──────────────────────────────────────────────\n// Component\n// ──────────────────────────────────────────────\n\n@Component({\n selector: 'ngx-next-pdf-viewer',\n standalone: true,\n imports: [\n CommonModule,\n FormsModule,\n MatIconModule,\n MatButtonModule,\n MatTooltipModule,\n MatInputModule,\n MatFormFieldModule\n ],\n templateUrl: './ngx-next-pdf-viewer.component.html',\n styleUrl: './ngx-next-pdf-viewer.component.scss'\n})\nexport class NgxNextPdfViewerComponent implements OnChanges, OnDestroy, AfterViewInit {\n\n // ── Inputs ──────────────────────────────────\n /** PDF file to display */\n @Input() blob: Blob | undefined;\n /** Bounding-box annotations to overlay */\n @Input() annotations: BoundingBox[] = [];\n /** Items shown in the context menu after drag-selecting boxes */\n @Input() contextMenuItems: ContextMenuItem[] = [];\n /** Fill colour for a single-clicked box (CSS colour string) */\n @Input() highlightingColor = 'rgba(255, 200, 0, 0.35)';\n /** Fill colour for drag-selected boxes (CSS colour string) */\n @Input() selectedColor = 'rgba(0, 120, 215, 0.35)';\n /** Stroke colour for all annotation polygons */\n @Input() annotationStroke = '#e97332';\n /** Initial zoom: numeric level (1.0 = 100 %) or 'fit-to-page' | 'fit-to-width' | 'fit-to-height' */\n @Input() initialZoom: ZoomMode = 1.5;\n /** Override any subset of the viewer's user-visible strings */\n @Input() labels: Partial<PdfViewerLabels> = {};\n /** Show / hide the zoom buttons and percentage label */\n @Input() showZoom = true;\n /** Show / hide the rotate-left and rotate-right buttons */\n @Input() showRotation = true;\n /** Show / hide the previous/next page buttons and page counter */\n @Input() showPageNavigation = true;\n /** Show / hide the previous/next annotation buttons and annotation counter */\n @Input() showAnnotationNavigation = true;\n /** Show / hide the select-area / select-text toggle button */\n @Input() showSelectionMode = true;\n /** Show / hide the search button and search bar */\n @Input() showSearch = true;\n /**\n * API key for enabling output triggers (boxClicked, boxesSelected).\n * When provided it must be a valid key generated by api-keys/generate.js.\n * Output events are silently suppressed while the key is absent or invalid.\n */\n @Input() apiKey: string | undefined;\n\n private static readonly DEFAULT_LABELS: PdfViewerLabels = {\n zoomOut: 'Zoom out',\n zoomIn: 'Zoom in',\n rotateLeft: 'Rotate left',\n rotateRight: 'Rotate right',\n previousPage: 'Previous page',\n nextPage: 'Next page',\n search: 'Search',\n previousResult: 'Previous result',\n nextResult: 'Next result',\n previousAnnotation: 'Previous annotation',\n nextAnnotation: 'Next annotation',\n selectArea: 'Select area',\n selectText: 'Select & copy text',\n searchPlaceholder: 'Search in PDF…',\n noResults: 'No results',\n loading: 'Loading PDF…',\n noDocument: 'No PDF loaded',\n loadError: 'Failed to load PDF',\n };\n\n get l(): PdfViewerLabels {\n return { ...NgxNextPdfViewerComponent.DEFAULT_LABELS, ...this.labels };\n }\n\n // ── Outputs ─────────────────────────────────\n /** Fired when the user clicks a single annotation box */\n @Output() boxClicked = new EventEmitter<{ box: BoundingBox; selected: boolean }>();\n /** Fired when the user picks a context-menu item after drag-selection */\n @Output() boxesSelected = new EventEmitter<{ boxes: BoundingBox[]; action: string }>();\n\n // ── View refs ────────────────────────────────\n @ViewChild('pdfContainer') pdfContainer!: ElementRef<HTMLDivElement>;\n\n // ── PDF state ────────────────────────────────\n pdfDoc: PDFDocumentProxy | null = null;\n renderedPages: RenderedPage[] = [];\n currentPage = 1;\n totalPages = 0;\n zoom = 1.5;\n userRotation = 0;\n\n // ── Annotation state ─────────────────────────\n clickedBoxKey: string | null = null;\n multiSelectedKeys: Set<string> = new Set();\n\n // ── Drag-select state ────────────────────────\n drag: DragState = { active: false, pageNum: 0, startX: 0, startY: 0, currentX: 0, currentY: 0 };\n\n // ── Context-menu state ───────────────────────\n ctxVisible = false;\n ctxX = 0;\n ctxY = 0;\n\n // ── Search state ─────────────────────────────\n searchVisible = false;\n searchQuery = '';\n searchMatches: SearchMatch[] = [];\n searchIndex = -1;\n\n // ── Selection mode ───────────────────────────\n selectionMode: 'select-area' | 'select-text' = 'select-area';\n\n // ── Loading ──────────────────────────────────\n loading = false;\n loadError = false;\n\n // ── API-key state ────────────────────────────\n /** True once the current apiKey has been verified against the embedded public key. */\n apiKeyValid = false;\n\n private renderTasks: Map<number, any> = new Map();\n private textLayers: Map<number, any> = new Map();\n private wheelListener?: (e: WheelEvent) => void;\n\n // ── One-time global CSS for the pdfjs text layer ─────────────────────────\n private static textLayerStylesInjected = false;\n\n private static injectTextLayerStyles(): void {\n if (NgxNextPdfViewerComponent.textLayerStylesInjected) return;\n const style = document.createElement('style');\n style.id = 'npv-text-layer-styles';\n style.textContent =\n '.textLayer{position:absolute;top:0;left:0;overflow:hidden;line-height:1;' +\n 'text-size-adjust:none;forced-color-adjust:none;transform-origin:0 0;z-index:0}' +\n '.textLayer :is(span,br){color:transparent;position:absolute;white-space:pre;' +\n 'cursor:text;transform-origin:0% 0%}' +\n '.textLayer>:not(.markedContent),' +\n '.textLayer .markedContent span:not(.markedContent){z-index:1}' +\n '.textLayer ::selection{background:rgba(0,120,215,.25);color:transparent}' +\n '.textLayer br::selection{background:transparent}';\n document.head.appendChild(style);\n NgxNextPdfViewerComponent.textLayerStylesInjected = true;\n }\n\n constructor(\n private cdr: ChangeDetectorRef,\n private zone: NgZone,\n private el: ElementRef,\n @Inject(NGX_PDF_WORKER_SRC) workerSrc: string\n ) {\n pdfjsLib.GlobalWorkerOptions.workerSrc = workerSrc;\n NgxNextPdfViewerComponent.injectTextLayerStyles();\n }\n\n ngAfterViewInit(): void {\n if (typeof this.initialZoom === 'number') {\n this.zoom = this.initialZoom;\n }\n // Ctrl+scroll zooming – requires passive:false to call preventDefault()\n this.zone.runOutsideAngular(() => {\n this.wheelListener = (e: WheelEvent) => {\n if (!e.ctrlKey) return;\n e.preventDefault();\n this.zone.run(() => e.deltaY < 0 ? this.zoomIn() : this.zoomOut());\n };\n this.el.nativeElement.addEventListener('wheel', this.wheelListener, { passive: false });\n });\n }\n\n ngOnChanges(changes: SimpleChanges): void {\n if (changes['apiKey']) {\n this.apiKeyValid = false;\n if (this.apiKey) {\n this.verifyApiKey(this.apiKey).then(valid => {\n this.apiKeyValid = valid;\n this.cdr.detectChanges();\n });\n }\n }\n if (changes['blob'] && this.blob) {\n console.log('load new file');\n this.loadPdf(this.blob);\n }\n if (changes['annotations'] && !changes['blob']) {\n console.log('set new annotations', this.annotations.length);\n this.cdr.detectChanges();\n if (this.annotations.length === 1) {\n this.scrollToBox(this.annotations[0]);\n }\n }\n }\n\n ngOnDestroy(): void {\n if (this.wheelListener) {\n this.el.nativeElement.removeEventListener('wheel', this.wheelListener);\n }\n this.removeAllTextLayers();\n this.pdfDoc?.destroy();\n }\n\n // ─────────────────────────────────────────────\n // API-key verification (Web Crypto API)\n // ─────────────────────────────────────────────\n\n /** Decodes a base64url string to a Uint8Array (no external dependencies). */\n private b64urlToBytes(b64url: string): Uint8Array {\n const b64 = b64url.replace(/-/g, '+').replace(/_/g, '/');\n const padded = b64.padEnd(b64.length + (4 - (b64.length % 4)) % 4, '=');\n return Uint8Array.from(atob(padded), c => c.charCodeAt(0));\n }\n\n /**\n * Verifies an API key against the embedded RSA-2048 public key.\n * Format: <payload_base64url>.<signature_base64url>\n *\n * Returns false when:\n * - the format is invalid\n * - the RSA signature does not match\n * - the key type is \"trial\" and its expiry timestamp has passed\n */\n private async verifyApiKey(key: string): Promise<boolean> {\n try {\n const dotIndex = key.lastIndexOf('.');\n if (dotIndex < 1) return false;\n const payloadB64 = key.slice(0, dotIndex);\n const sigB64 = key.slice(dotIndex + 1);\n\n // Import the embedded public key (SPKI DER, standard base64 → CryptoKey)\n const derBytes = Uint8Array.from(atob(API_PUBLIC_KEY_B64), c => c.charCodeAt(0));\n const cryptoKey = await crypto.subtle.importKey(\n 'spki',\n derBytes,\n { name: 'RSASSA-PKCS1-v1_5', hash: 'SHA-256' },\n false,\n ['verify']\n );\n\n // Verify RSA signature (computed over the UTF-8 bytes of the payload string)\n const data = new TextEncoder().encode(payloadB64);\n const sig = this.b64urlToBytes(sigB64);\n const signatureValid = await crypto.subtle.verify('RSASSA-PKCS1-v1_5', cryptoKey, sig, data);\n if (!signatureValid) return false;\n\n // Decode payload and check expiry for trial keys\n const payloadJson = atob(\n payloadB64.replace(/-/g, '+').replace(/_/g, '/')\n .padEnd(payloadB64.length + (4 - (payloadB64.length % 4)) % 4, '=')\n );\n const payload = JSON.parse(payloadJson) as { type?: string; expires?: number | null };\n\n if (payload.type === 'trial' && payload.expires != null) {\n if (Date.now() > payload.expires) return false; // trial key expired\n }\n\n return true;\n } catch {\n return false;\n }\n }\n\n // ─────────────────────────────────────────────\n // PDF loading & rendering\n // ─────────────────────────────────────────────\n\n private async loadPdf(blob: Blob): Promise<void> {\n this.loading = true;\n this.loadError = false;\n this.renderedPages = [];\n this.clickedBoxKey = null;\n this.multiSelectedKeys.clear();\n this.searchMatches = [];\n this.searchIndex = -1;\n this.removeAllTextLayers();\n this.cdr.detectChanges();\n\n try {\n this.pdfDoc?.destroy();\n const buf = await blob.arrayBuffer();\n this.pdfDoc = await pdfjsLib.getDocument({ data: buf }).promise;\n this.totalPages = this.pdfDoc.numPages;\n this.currentPage = 1;\n if (typeof this.initialZoom !== 'number') {\n this.zoom = await this.computeFitZoom(this.initialZoom);\n }\n this.loading = false;\n this.cdr.detectChanges();\n\n for (let p = 1; p <= this.totalPages; p++) {\n await this.renderPage(p);\n }\n\n if (this.annotations.length === 1) {\n this.scrollToBox(this.annotations[0]);\n }\n } catch {\n this.loading = false;\n this.loadError = true;\n }\n this.cdr.detectChanges();\n }\n\n private async computeFitZoom(mode: Exclude<ZoomMode, number>): Promise<number> {\n if (!this.pdfDoc) return 1;\n const page = await this.pdfDoc.getPage(1);\n const rotation = (page.rotate + this.userRotation) % 360;\n const vp = page.getViewport({ scale: 1, rotation });\n page.cleanup();\n\n const container = this.pdfContainer?.nativeElement;\n if (!container) return 1;\n\n // Subtract the 16 px padding on each side defined in npv-scroll-inner\n const availW = container.clientWidth - 32;\n const availH = container.clientHeight - 32;\n const scaleW = availW / vp.width;\n const scaleH = availH / vp.height;\n\n switch (mode) {\n case 'fit-to-width': return scaleW;\n case 'fit-to-height': return scaleH;\n case 'fit-to-page': return Math.min(scaleW, scaleH);\n }\n }\n\n private async renderPage(pageNum: number): Promise<void> {\n if (!this.pdfDoc) return;\n const page: PDFPageProxy = await this.pdfDoc.getPage(pageNum);\n const totalRotation = (page.rotate + this.userRotation) % 360;\n const viewport = page.getViewport({ scale: this.zoom, rotation: totalRotation });\n\n // HiDPI: render at physical pixel density, display at CSS size\n const dpr = window.devicePixelRatio || 1;\n const hiResViewport = page.getViewport({ scale: this.zoom * dpr, rotation: totalRotation });\n\n const canvas = document.getElementById(`npv-canvas-${pageNum}`) as HTMLCanvasElement | null;\n if (!canvas) return;\n\n canvas.width = hiResViewport.width;\n canvas.height = hiResViewport.height;\n canvas.style.width = `${viewport.width}px`;\n canvas.style.height = `${viewport.height}px`;\n\n if (this.renderTasks.has(pageNum)) {\n try { this.renderTasks.get(pageNum).cancel(); } catch (_) {}\n }\n\n const ctx = canvas.getContext('2d')!;\n const task = page.render({ canvasContext: ctx, viewport: hiResViewport });\n this.renderTasks.set(pageNum, task);\n try {\n await task.promise;\n } catch (e: any) {\n if (e?.name !== 'RenderingCancelledException') console.error(e);\n return;\n }\n this.renderTasks.delete(pageNum);\n\n const existing = this.renderedPages.find(r => r.pageNum === pageNum);\n if (existing) {\n existing.width = viewport.width;\n existing.height = viewport.height;\n existing.rotation = totalRotation;\n } else {\n this.renderedPages.push({ pageNum, width: viewport.width, height: viewport.height, rotation: totalRotation });\n }\n this.cdr.detectChanges();\n page.cleanup();\n }\n\n private async rerenderAll(): Promise<void> {\n if (!this.pdfDoc) return;\n if (this.selectionMode === 'select-text') {\n this.removeAllTextLayers();\n }\n for (let p = 1; p <= this.totalPages; p++) {\n await this.renderPage(p);\n if (this.selectionMode === 'select-text') {\n await this.renderTextLayer(p);\n }\n }\n this.cdr.detectChanges();\n }\n\n // ─────────────────────────────────────────────\n // Coordinate transformation\n // ─────────────────────────────────────────────\n\n /** Converts a polygon (y=0 at top, any consistent unit) to SVG canvas coordinates */\n transformPolygon(\n polygon: number[],\n pdfWidth: number,\n pdfHeight: number,\n canvasWidth: number,\n canvasHeight: number,\n rotation: number\n ): number[] {\n const norm = ((rotation % 360) + 360) % 360;\n const result: number[] = [];\n for (let i = 0; i < polygon.length; i += 2) {\n const px = polygon[i];\n const py = polygon[i + 1];\n let cx: number, cy: number;\n switch (norm) {\n case 90:\n cx = (pdfHeight - py) * canvasWidth / pdfHeight;\n cy = px * canvasHeight / pdfWidth;\n break;\n case 180:\n cx = (pdfWidth - px) * canvasWidth / pdfWidth;\n cy = (pdfHeight - py) * canvasHeight / pdfHeight;\n break;\n case 270:\n cx = py * canvasWidth / pdfHeight;\n cy = (pdfWidth - px) * canvasHeight / pdfWidth;\n break;\n default:\n cx = px * canvasWidth / pdfWidth;\n cy = py * canvasHeight / pdfHeight;\n }\n result.push(cx, cy);\n }\n return result;\n }\n\n getSvgPoints(box: BoundingBox, pi: RenderedPage): string {\n const pts = this.transformPolygon(\n box.polygon, box.width, box.height, pi.width, pi.height, pi.rotation\n );\n const pairs: string[] = [];\n for (let i = 0; i < pts.length; i += 2) {\n pairs.push(`${pts[i].toFixed(2)},${pts[i + 1].toFixed(2)}`);\n }\n return pairs.join(' ');\n }\n\n private polygonBBox(pts: number[]): { x: number; y: number; w: number; h: number } {\n let minX = Infinity, minY = Infinity, maxX = -Infinity, maxY = -Infinity;\n for (let i = 0; i < pts.length; i += 2) {\n minX = Math.min(minX, pts[i]); maxX = Math.max(maxX, pts[i]);\n minY = Math.min(minY, pts[i+1]); maxY = Math.max(maxY, pts[i+1]);\n }\n return { x: minX, y: minY, w: maxX - minX, h: maxY - minY };\n }\n\n private boxKey(box: BoundingBox): string {\n return JSON.stringify({ page: box.page, polygon: box.polygon });\n }\n\n // ─────────────────────────────────────────────\n // Template helpers\n // ─────────────────────────────────────────────\n\n getPageInfo(pageNum: number): RenderedPage | undefined {\n return this.renderedPages.find(r => r.pageNum === pageNum);\n }\n\n getBoxesForPage(pageNum: number): BoundingBox[] {\n return this.annotations.filter(b => b.page === pageNum);\n }\n\n isClicked(box: BoundingBox): boolean {\n return this.clickedBoxKey === this.boxKey(box);\n }\n\n isMultiSelected(box: BoundingBox): boolean {\n return this.multiSelectedKeys.has(this.boxKey(box));\n }\n\n pageRange(): number[] {\n return Array.from({ length: this.totalPages }, (_, i) => i + 1);\n }\n\n getDragRect(pageNum: number): { x: number; y: number; w: number; h: number } | null {\n if (!this.drag.active || this.drag.pageNum !== pageNum) return null;\n return {\n x: Math.min(this.drag.startX, this.drag.currentX),\n y: Math.min(this.drag.startY, this.drag.currentY),\n w: Math.abs(this.drag.currentX - this.drag.startX),\n h: Math.abs(this.drag.currentY - this.drag.startY)\n };\n }\n\n getSearchMatchesForPage(pageNum: number): SearchMatch[] {\n return this.searchMatches.filter(m => m.pageNum === pageNum);\n }\n\n getSearchIndexOffset(pageNum: number): number {\n return this.searchMatches.findIndex(m => m.pageNum === pageNum);\n }\n\n isCurrentSearchMatch(pageNum: number, localIndex: number): boolean {\n const offset = this.getSearchIndexOffset(pageNum);\n return offset >= 0 && offset + localIndex === this.searchIndex;\n }\n\n searchMatchPoints(m: SearchMatch): string {\n const pairs: string[] = [];\n for (let i = 0; i < m.polygon.length; i += 2) {\n pairs.push(`${m.polygon[i].toFixed(2)},${m.polygon[i + 1].toFixed(2)}`);\n }\n return pairs.join(' ');\n }\n\n // ─────────────────────────────────────────────\n // Box interaction\n // ─────────────────────────────────────────────\n\n onBoxClick(event: MouseEvent, box: BoundingBox): void {\n event.stopPropagation();\n this.ctxVisible = false;\n this.multiSelectedKeys.clear();\n const key = this.boxKey(box);\n const wasSelected = this.clickedBoxKey === key;\n this.clickedBoxKey = wasSelected ? null : key;\n this.cdr.detectChanges();\n if (this.apiKeyValid) {\n this.boxClicked.emit({ box, selected: !wasSelected });\n }\n }\n\n // ─────────────────────────────────────────────\n // Drag-select\n // ─────────────────────────────────────────────\n\n onSvgMouseDown(event: MouseEvent, pageNum: number): void {\n if (this.selectionMode === 'select-text') return;\n if (event.button !== 0) return;\n const tag = (event.target as Element).tagName?.toLowerCase();\n if (tag === 'polygon' || tag === 'title') return;\n this.ctxVisible = false;\n this.clickedBoxKey = null;\n const pt = this.svgPoint(event, pageNum);\n if (!pt) return;\n this.drag = { active: true, pageNum, startX: pt.x, startY: pt.y, currentX: pt.x, currentY: pt.y };\n }\n\n @HostListener('mousemove', ['$event'])\n onDocMouseMove(event: MouseEvent): void {\n if (!this.drag.active) return;\n const pt = this.svgPoint(event, this.drag.pageNum);\n if (!pt) return;\n this.drag.currentX = pt.x;\n this.drag.currentY = pt.y;\n this.cdr.detectChanges();\n }\n\n @HostListener('mouseup', ['$event'])\n onDocMouseUp(event: MouseEvent): void {\n if (!this.drag.active) return;\n const rect = this.getDragRect(this.drag.pageNum);\n this.drag.active = false;\n\n if (!rect || (rect.w < 5 && rect.h < 5)) { this.cdr.detectChanges(); return; }\n\n const pageInfo = this.getPageInfo(this.drag.pageNum);\n if (!pageInfo) { this.cdr.detectChanges(); return; }\n\n const hits: BoundingBox[] = [];\n for (const box of this.annotations) {\n const pts = this.transformPolygon(\n box.polygon, box.width, box.height, pageInfo.width, pageInfo.height, pageInfo.rotation\n );\n const bb = this.polygonBBox(pts);\n if (this.rectsIntersect(rect, bb)) hits.push(box);\n }\n\n this.multiSelectedKeys = new Set(hits.map(b => this.boxKey(b)));\n\n if (hits.length > 0 && this.contextMenuItems.length > 0) {\n this.ctxX = event.clientX;\n this.ctxY = event.clientY;\n this.ctxVisible = true;\n }\n this.cdr.detectChanges();\n }\n\n private svgPoint(event: MouseEvent, pageNum: number): { x: number; y: number } | null {\n const svg = document.getElementById(`npv-svg-${pageNum}`) as SVGSVGElement | null;\n if (!svg) return null;\n const r = svg.getBoundingClientRect();\n return { x: event.clientX - r.left, y: event.clientY - r.top };\n }\n\n private rectsIntersect(\n a: { x: number; y: number; w: number; h: number },\n b: { x: number; y: number; w: number; h: number }\n ): boolean {\n return !(a.x + a.w < b.x || b.x + b.w < a.x || a.y + a.h < b.y || b.y + b.h < a.y);\n }\n\n // ─────────────────────────────────────────────\n // Context menu\n // ─────────────────────────────────────────────\n\n onContextMenuAction(item: ContextMenuItem): void {\n this.ctxVisible = false;\n const selected = this.annotations.filter(b => this.multiSelectedKeys.has(this.boxKey(b)));\n if (this.apiKeyValid) {\n this.boxesSelected.emit({ boxes: selected, action: item.action });\n }\n this.multiSelectedKeys.clear();\n this.cdr.detectChanges();\n }\n\n @HostListener('document:click')\n onDocClick(): void {\n if (this.ctxVisible) { this.ctxVisible = false; this.cdr.detectChanges(); }\n }\n\n // ─────────────────────────────────────────────\n // Toolbar – zoom\n // ─────────────────────────────────────────────\n\n zoomIn(): void { this.zoom = Math.min(this.zoom + 0.25, 5); this.rerenderAll(); }\n zoomOut(): void { this.zoom = Math.max(this.zoom - 0.25, 0.25); this.rerenderAll(); }\n\n get zoomPercent(): number { return Math.round(this.zoom * 100); }\n\n // ─────────────────────────────────────────────\n // Toolbar – rotation\n // ─────────────────────────────────────────────\n\n rotateLeft(): void { this.userRotation = (this.userRotation + 270) % 360; this.rerenderAll(); }\n rotateRight(): void { this.userRotation = (this.userRotation + 90) % 360; this.rerenderAll(); }\n\n // ─────────────────────────────────────────────\n // Toolbar – page navigation\n // ─────────────────────────────────────────────\n\n goToPrevPage(): void { if (this.currentPage > 1) this.scrollToPageNum(this.currentPage - 1); }\n goToNextPage(): void { if (this.currentPage < this.totalPages) this.scrollToPageNum(this.currentPage + 1); }\n\n scrollToPageNum(pageNum: number): void {\n this.currentPage = pageNum;\n document.getElementById(`npv-page-${pageNum}`)?.scrollIntoView({ behavior: 'smooth', block: 'start' });\n }\n\n scrollToBox(box: BoundingBox): void {\n this.currentPage = box.page;\n console.log('scroll to page', this.currentPage)\n const pageEl = document.getElementById(`npv-page-${box.page}`);\n if (!pageEl) {\n console.log('no page element found, stop scrolling')\n return;\n }\n const pi = this.getPageInfo(box.page);\n if (!pi) {\n pageEl.scrollIntoView({ behavior: 'smooth', block: 'start' });\n console.log('scroll into view done')\n return;\n }\n const pts = this.transformPolygon(box.polygon, box.width, box.height, pi.width, pi.height, pi.rotation);\n const bb = this.polygonBBox(pts);\n const top = (pageEl as HTMLElement).offsetTop + bb.y - window.innerHeight / 2;\n this.pdfContainer?.nativeElement.scrollTo({ top, behavior: 'smooth' });\n console.log('scrolling to element done')\n }\n\n // ─────────────────────────────────────────────\n // Toolbar – search\n // ─────────────────────────────────────────────\n\n toggleSearch(): void {\n this.searchVisible = !this.searchVisible;\n if (!this.searchVisible) {\n this.searchQuery = '';\n this.searchMatches = [];\n this.searchIndex = -1;\n this.cdr.detectChanges();\n }\n }\n\n async onSearchInput(): Promise<void> {\n const q = this.searchQuery.trim().toLowerCase();\n this.searchMatches = [];\n this.searchIndex = -1;\n if (!q || !this.pdfDoc) { this.cdr.detectChanges(); return; }\n\n for (let p = 1; p <= this.totalPages; p++) {\n const pi = this.getPageInfo(p);\n if (!pi) continue;\n const page = await this.pdfDoc.getPage(p);\n const text = await page.getTextContent();\n const vp = page.getViewport({ scale: this.zoom, rotation: pi.rotation });\n\n for (const item of text.items as any[]) {\n if (!item.str) continue;\n const idx = item.str.toLowerCase().indexOf(q);\n if (idx < 0) continue;\n\n const charW = (item.width / item.str.length) || 6;\n const itemH = Math.abs(item.transform[3]) || 10;\n const x0 = item.transform[4] + idx * charW;\n const y0 = item.transform[5];\n\n const t = vp.transform;\n const applyT = (x: number, y: number): [number, number] =>\n [t[0]*x + t[2]*y + t[4], t[1]*x + t[3]*y + t[5]];\n\n const [cx0, cy0] = applyT(x0, y0 + itemH);\n const [cx1, cy1] = applyT(x0 + q.length * charW, y0);\n\n this.searchMatches.push({\n pageNum: p,\n polygon: [cx0, cy0, cx1, cy0, cx1, cy1, cx0, cy1]\n });\n }\n page.cleanup();\n }\n\n if (this.searchMatches.length > 0) {\n this.searchIndex = 0;\n this.scrollToSearchMatch(0);\n }\n this.cdr.detectChanges();\n }\n\n searchNext(): void {\n if (!this.searchMatches.length) return;\n this.searchIndex = (this.searchIndex + 1) % this.searchMatches.length;\n this.scrollToSearchMatch(this.searchIndex);\n this.cdr.detectChanges();\n }\n\n searchPrev(): void {\n if (!this.searchMatches.length) return;\n this.searchIndex = (this.searchIndex - 1 + this.searchMatches.length) % this.searchMatches.length;\n this.scrollToSearchMatch(this.searchIndex);\n this.cdr.detectChanges();\n }\n\n private scrollToSearchMatch(idx: number): void {\n const m = this.searchMatches[idx];\n if (!m) return;\n document.getElementById(`npv-page-${m.pageNum}`)?.scrollIntoView({ behavior: 'smooth', block: 'center' });\n }\n\n // ─────────────────────────────────────────────\n // Toolbar – annotation navigation\n // ─────────────────────────────────────────────\n\n get annotationIndex(): number {\n if (!this.clickedBoxKey) return -1;\n return this.annotations.findIndex(b => this.boxKey(b) === this.clickedBoxKey);\n }\n\n goToPrevAnnotation(): void {\n if (!this.annotations.length) return;\n const prev = (this.annotationIndex - 1 + this.annotations.length) % this.annotations.length;\n this.selectAnnotation(prev);\n }\n\n goToNextAnnotation(): void {\n if (!this.annotations.length) return;\n const next = (this.annotationIndex + 1) % this.annotations.length;\n this.selectAnnotation(next);\n }\n\n private selectAnnotation(index: number): void {\n const box = this.annotations[index];\n if (!box) return;\n this.multiSelectedKeys.clear();\n this.ctxVisible = false;\n this.clickedBoxKey = this.boxKey(box);\n this.cdr.detectChanges();\n this.scrollToBox(box);\n if (this.apiKeyValid) {\n this.boxClicked.emit({ box, selected: true });\n }\n }\n\n // ─────────────────────────────────────────────\n // Toolbar – selection mode\n // ─────────────────────────────────────────────\n\n toggleSelectionMode(): void {\n this.selectionMode = this.selectionMode === 'select-area' ? 'select-text' : 'select-area';\n if (this.selectionMode === 'select-text') {\n this.renderedPages.forEach(rp => this.renderTextLayer(rp.pageNum));\n } else {\n this.removeAllTextLayers();\n }\n this.cdr.detectChanges();\n }\n\n /**\n * Returns the CSS matrix() transform that aligns the pdfjs text layer\n * (always sized in *unrotated* page space) with the rotated canvas.\n * pi.width / pi.height are the *canvas* (rotated) pixel dimensions.\n */\n private textLayerTransform(totalRotation: number, canvasW: number, canvasH: number): string {\n const norm = ((totalRotation % 360) + 360) % 360;\n switch (norm) {\n // 90 ° CW: (x,y) → (H−y, x) where H = canvas width after swap\n case 90: return `matrix(0,1,-1,0,${canvasW},0)`;\n // 180 °: (x,y) → (W−x, H−y)\n case 180: return `matrix(-1,0,0,-1,${canvasW},${canvasH})`;\n // 270 ° CW: (x,y) → (y, W−x) where W = canvas height after swap\n case 270: return `matrix(0,-1,1,0,0,${canvasH})`;\n default: return '';\n }\n }\n\n private async renderTextLayer(pageNum: number): Promise<void> {\n if (!this.pdfDoc) return;\n const pi = this.getPageInfo(pageNum);\n if (!pi) return;\n\n const wrapper = document.getElementById(`npv-page-${pageNum}`) as HTMLElement | null;\n if (!wrapper) return;\n\n this.removeTextLayer(pageNum);\n\n const page = await this.pdfDoc.getPage(pageNum);\n const totalRotation = (page.rotate + this.userRotation) % 360;\n const viewport = page.getViewport({ scale: this.zoom, rotation: totalRotation });\n\n const div = document.createElement('div');\n // 'textLayer' class is required for the injected pdfjs CSS rules to apply.\n div.className = 'npv-text-layer textLayer';\n // pdfjs sizes the container with calc(var(--scale-factor) * rawPageWidth).\n // Without this variable every calc() is invalid → container collapses to 0.\n div.style.setProperty('--scale-factor', String(this.zoom));\n // pdfjs always lays text out in unrotated page space; align with rotated canvas.\n const transform = this.textLayerTransform(totalRotation, pi.width, pi.height);\n if (transform) div.style.transform = transform;\n\n wrapper.appendChild(div);\n\n const textLayer = new (pdfjsLib as any).TextLayer({\n textContentSource: page.streamTextContent(),\n container: div,\n viewport,\n });\n\n this.textLayers.set(pageNum, textLayer);\n try {\n await textLayer.render();\n } catch (e: any) {\n if (e?.name !== 'AbortException') console.error('TextLayer render error:', e);\n }\n page.cleanup();\n }\n\n private removeTextLayer(pageNum: number): void {\n const tl = this.textLayers.get(pageNum);\n if (tl) {\n try { tl.cancel(); } catch (_) {}\n this.textLayers.delete(pageNum);\n }\n const wrapper = document.getElementById(`npv-page-${pageNum}`);\n wrapper?.querySelector('.npv-text-layer')?.remove();\n }\n\n private removeAllTextLayers(): void {\n for (const pageNum of Array.from(this.textLayers.keys())) {\n this.removeTextLayer(pageNum);\n }\n }\n\n // ─────────────────────────────────────────────\n // Scroll tracking\n // ─────────────────────────────────────────────\n\n onContainerScroll(): void {\n if (!this.pdfContainer) return;\n const top = this.pdfContainer.nativeElement.scrollTop;\n let closest = 1, minDist = Infinity;\n for (let p = 1; p <= this.totalPages; p++) {\n const el = document.getElementById(`npv-page-${p}`) as HTMLElement | null;\n if (!el) continue;\n const dist = Math.abs(el.offsetTop - top);\n if (dist < minDist) { minDist = dist; closest = p; }\n }\n if (this.currentPage !== closest) { this.currentPage = closest; this.cdr.detectChanges(); }\n }\n}\n","<div class=\"npv-root\">\n\n <!-- ─────────── Toolbar ─────────── -->\n <div class=\"npv-toolbar\">\n\n <!-- Zoom -->\n <ng-container *ngIf=\"showZoom\">\n <button mat-icon-button [matTooltip]=\"l.zoomOut\" (click)=\"zoomOut()\" [disabled]=\"zoom <= 0.25\">\n <mat-icon>zoom_out</mat-icon>\n </button>\n <span class=\"npv-label\">{{ zoomPercent }}%</span>\n <button mat-icon-button [matTooltip]=\"l.zoomIn\" (click)=\"zoomIn()\" [disabled]=\"zoom >= 5\">\n <mat-icon>zoom_in</mat-icon>\n </button>\n </ng-container>\n\n <!-- Rotation -->\n <ng-container *ngIf=\"showRotation\">\n <div class=\"npv-sep\" *ngIf=\"showZoom\"></div>\n <button mat-icon-button [matTooltip]=\"l.rotateLeft\" (click)=\"rotateLeft()\">\n <mat-icon>rotate_left</mat-icon>\n </button>\n <button mat-icon-button [matTooltip]=\"l.rotateRight\" (click)=\"rotateRight()\">\n <mat-icon>rotate_right</mat-icon>\n </button>\n </ng-container>\n\n <!-- Page navigation -->\n <ng-container *ngIf=\"showPageNavigation\">\n <div class=\"npv-sep\" *ngIf=\"showZoom || showRotation\"></div>\n <button mat-icon-button [matTooltip]=\"l.previousPage\" (click)=\"goToPrevPage()\" [disabled]=\"currentPage <= 1\">\n <mat-icon>chevron_left</mat-icon>\n </button>\n <span class=\"npv-label\">{{ currentPage }} / {{ totalPages }}</span>\n <button mat-icon-button [matTooltip]=\"l.nextPage\" (click)=\"goToNextPage()\" [disabled]=\"currentPage >= totalPages\">\n <mat-icon>chevron_right</mat-icon>\n </button>\n </ng-container>\n\n <!-- Annotation navigation -->\n <ng-container *ngIf=\"showAnnotationNavigation && annotations.length\">\n <div class=\"npv-sep\" *ngIf=\"showZoom || showRotation || showPageNavigation\"></div>\n <button mat-icon-button [matTooltip]=\"l.previousAnnotation\" (click)=\"goToPrevAnnotation()\">\n <mat-icon>navigate_before</mat-icon>\n </button>\n <span class=\"npv-label\">\n {{ annotationIndex >= 0 ? annotationIndex + 1 : '–' }} / {{ annotations.length }}\n </span>\n <button mat-icon-button [matTooltip]=\"l.nextAnnotation\" (click)=\"goToNextAnnotation()\">\n <mat-icon>navigate_next</mat-icon>\n </button>\n </ng-container>\n\n <!-- Selection mode toggle -->\n <ng-container *ngIf=\"showSelectionMode\">\n <div class=\"npv-sep\" *ngIf=\"showZoom || showRotation || showPageNavigation || (showAnnotationNavigation && annotations.length > 0)\"></div>\n <button mat-icon-button\n [matTooltip]=\"selectionMode === 'select-area' ? l.selectText : l.selectArea\"\n (click)=\"toggleSelectionMode()\"\n [class.npv-active]=\"selectionMode === 'select-text'\">\n <mat-icon>text_fields</mat-icon>\n </button>\n </ng-container>\n\n <!-- Search -->\n <ng-container *ngIf=\"showSearch\">\n <div class=\"npv-sep\" *ngIf=\"showZoom || showRotation || showPageNavigation || (showAnnotationNavigation && annotations.length > 0) || showSelectionMode\"></div>\n <button mat-icon-button [matTooltip]=\"l.search\" (click)=\"toggleSearch()\" [class.npv-active]=\"searchVisible\">\n <mat-icon>search</mat-icon>\n </button>\n <ng-container *ngIf=\"searchVisible\">\n <input\n class=\"npv-search-input\"\n type=\"text\"\n [placeholder]=\"l.searchPlaceholder\"\n [(ngModel)]=\"searchQuery\"\n (input)=\"onSearchInput()\"\n (keydown.enter)=\"searchNext()\"\n (keydown.shift.enter)=\"searchPrev()\"\n autofocus\n />\n <button mat-icon-button [matTooltip]=\"l.previousResult\"\n (click)=\"searchPrev()\" [disabled]=\"!searchMatches.length\">\n <mat-icon>expand_less</mat-icon>\n </button>\n <button mat-icon-button [matTooltip]=\"l.nextResult\"\n (click)=\"searchNext()\" [disabled]=\"!searchMatches.length\">\n <mat-icon>expand_more</mat-icon>\n </button>\n <span class=\"npv-search-count\" *ngIf=\"searchMatches.length\">\n {{ searchIndex + 1 }} / {{ searchMatches.length }}\n </span>\n <span class=\"npv-search-count npv-no-match\" *ngIf=\"searchQuery && !searchMatches.length\">\n {{ l.noResults }}\n </span>\n </ng-container>\n </ng-container>\n\n </div>\n\n <!-- ─────────── Loading ─────────── -->\n <div class=\"npv-loading\" *ngIf=\"loading\">\n <span class=\"npv-spinner\"></span> {{ l.loading }}\n </div>\n\n <!-- ─────────── Scroll area ─────────── -->\n <div class=\"npv-scroll-area\" #pdfContainer\n (scroll)=\"onContainerScroll()\" (click)=\"ctxVisible = false\">\n <div class=\"npv-scroll-inner\">\n\n <ng-container *ngFor=\"let p of pageRange()\">\n <div class=\"npv-page-wrapper\" [id]=\"'npv-page-' + p\">\n\n <canvas [id]=\"'npv-canvas-' + p\" class=\"npv-canvas\"></canvas>\n\n <svg *ngIf=\"getPageInfo(p) as pi\"\n [id]=\"'npv-svg-' + p\"\n class=\"npv-overlay\"\n [class.npv-overlay--text-mode]=\"selectionMode === 'select-text'\"\n [attr.width]=\"pi.width\" [attr.height]=\"pi.height\"\n [attr.viewBox]=\"'0 0 ' + pi.width + ' ' + pi.height\"\n (mousedown)=\"onSvgMouseDown($event, p)\">\n\n <!-- Hit area for drag selection on empty page space -->\n <rect x=\"0\" y=\"0\" [attr.width]=\"pi.width\" [attr.height]=\"pi.height\"\n fill=\"transparent\"></rect>\n\n <!-- Annotation boxes -->\n <polygon\n *ngFor=\"let box of getBoxesForPage(p)\"\n [attr.points]=\"getSvgPoints(box, pi)\"\n class=\"npv-box\"\n [class.npv-box--clicked]=\"isClicked(box)\"\n [class.npv-box--multi]=\"isMultiSelected(box)\"\n [style.fill]=\"isClicked(box) ? highlightingColor : (isMultiSelected(box) ? selectedColor : 'transparent')\"\n [style.stroke]=\"annotationStroke\"\n (click)=\"onBoxClick($event, box)\">\n <title>{{ box.content || '' }}</title>\n </polygon>\n\n <!-- Search highlights -->\n <polygon\n *ngFor=\"let m of getSearchMatchesForPage(p); let mi = index\"\n [attr.points]=\"searchMatchPoints(m)\"\n class=\"npv-search-highlight\"\n [class.npv-search-highlight--current]=\"isCurrentSearchMatch(p, mi)\">\n </polygon>\n\n <!-- Drag selection rectangle -->\n <rect *ngIf=\"getDragRect(p) as dr\"\n [attr.x]=\"dr.x\" [attr.y]=\"dr.y\"\n [attr.width]=\"dr.w\" [attr.height]=\"dr.h\"\n class=\"npv-drag-rect\">\n </rect>\n\n </svg>\n </div>\n </ng-container>\n\n <div class=\"npv-placeholder npv-placeholder--error\" *ngIf=\"!loading && loadError\">\n {{ l.loadError }}\n </div>\n <div class=\"npv-placeholder\" *ngIf=\"!loading && !loadError && totalPages === 0\">\n {{ l.noDocument }}\n </div>\n\n </div><!-- /npv-scroll-inner -->\n </div>\n\n <!-- ─────────── Context menu ─────────── -->\n <div *ngIf=\"ctxVisible && contextMenuItems.length\"\n class=\"npv-context-menu\"\n [style.left.px]=\"ctxX\" [style.top.px]=\"ctxY\"\n (click)=\"$event.stopPropagation()\">\n <div *ngFor=\"let item of contextMenuItems\"\n class=\"npv-context-item\"\n (click)=\"onContextMenuAction(item)\">\n {{ item.label }}\n </div>\n </div>\n\n</div>\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"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"}
|
package/index.d.ts
CHANGED
|
@@ -97,6 +97,24 @@ declare class NgxNextPdfViewerComponent implements OnChanges, OnDestroy, AfterVi
|
|
|
97
97
|
initialZoom: ZoomMode;
|
|
98
98
|
/** Override any subset of the viewer's user-visible strings */
|
|
99
99
|
labels: Partial<PdfViewerLabels>;
|
|
100
|
+
/** Show / hide the zoom buttons and percentage label */
|
|
101
|
+
showZoom: boolean;
|
|
102
|
+
/** Show / hide the rotate-left and rotate-right buttons */
|
|
103
|
+
showRotation: boolean;
|
|
104
|
+
/** Show / hide the previous/next page buttons and page counter */
|
|
105
|
+
showPageNavigation: boolean;
|
|
106
|
+
/** Show / hide the previous/next annotation buttons and annotation counter */
|
|
107
|
+
showAnnotationNavigation: boolean;
|
|
108
|
+
/** Show / hide the select-area / select-text toggle button */
|
|
109
|
+
showSelectionMode: boolean;
|
|
110
|
+
/** Show / hide the search button and search bar */
|
|
111
|
+
showSearch: boolean;
|
|
112
|
+
/**
|
|
113
|
+
* API key for enabling output triggers (boxClicked, boxesSelected).
|
|
114
|
+
* When provided it must be a valid key generated by api-keys/generate.js.
|
|
115
|
+
* Output events are silently suppressed while the key is absent or invalid.
|
|
116
|
+
*/
|
|
117
|
+
apiKey: string | undefined;
|
|
100
118
|
private static readonly DEFAULT_LABELS;
|
|
101
119
|
get l(): PdfViewerLabels;
|
|
102
120
|
/** Fired when the user clicks a single annotation box */
|
|
@@ -129,13 +147,29 @@ declare class NgxNextPdfViewerComponent implements OnChanges, OnDestroy, AfterVi
|
|
|
129
147
|
selectionMode: 'select-area' | 'select-text';
|
|
130
148
|
loading: boolean;
|
|
131
149
|
loadError: boolean;
|
|
150
|
+
/** True once the current apiKey has been verified against the embedded public key. */
|
|
151
|
+
apiKeyValid: boolean;
|
|
132
152
|
private renderTasks;
|
|
133
153
|
private textLayers;
|
|
134
154
|
private wheelListener?;
|
|
155
|
+
private static textLayerStylesInjected;
|
|
156
|
+
private static injectTextLayerStyles;
|
|
135
157
|
constructor(cdr: ChangeDetectorRef, zone: NgZone, el: ElementRef, workerSrc: string);
|
|
136
158
|
ngAfterViewInit(): void;
|
|
137
159
|
ngOnChanges(changes: SimpleChanges): void;
|
|
138
160
|
ngOnDestroy(): void;
|
|
161
|
+
/** Decodes a base64url string to a Uint8Array (no external dependencies). */
|
|
162
|
+
private b64urlToBytes;
|
|
163
|
+
/**
|
|
164
|
+
* Verifies an API key against the embedded RSA-2048 public key.
|
|
165
|
+
* Format: <payload_base64url>.<signature_base64url>
|
|
166
|
+
*
|
|
167
|
+
* Returns false when:
|
|
168
|
+
* - the format is invalid
|
|
169
|
+
* - the RSA signature does not match
|
|
170
|
+
* - the key type is "trial" and its expiry timestamp has passed
|
|
171
|
+
*/
|
|
172
|
+
private verifyApiKey;
|
|
139
173
|
private loadPdf;
|
|
140
174
|
private computeFitZoom;
|
|
141
175
|
private renderPage;
|
|
@@ -187,12 +221,18 @@ declare class NgxNextPdfViewerComponent implements OnChanges, OnDestroy, AfterVi
|
|
|
187
221
|
goToNextAnnotation(): void;
|
|
188
222
|
private selectAnnotation;
|
|
189
223
|
toggleSelectionMode(): void;
|
|
224
|
+
/**
|
|
225
|
+
* Returns the CSS matrix() transform that aligns the pdfjs text layer
|
|
226
|
+
* (always sized in *unrotated* page space) with the rotated canvas.
|
|
227
|
+
* pi.width / pi.height are the *canvas* (rotated) pixel dimensions.
|
|
228
|
+
*/
|
|
229
|
+
private textLayerTransform;
|
|
190
230
|
private renderTextLayer;
|
|
191
231
|
private removeTextLayer;
|
|
192
232
|
private removeAllTextLayers;
|
|
193
233
|
onContainerScroll(): void;
|
|
194
234
|
static ɵfac: i0.ɵɵFactoryDeclaration<NgxNextPdfViewerComponent, never>;
|
|
195
|
-
static ɵcmp: i0.ɵɵComponentDeclaration<NgxNextPdfViewerComponent, "ngx-next-pdf-viewer", never, { "blob": { "alias": "blob"; "required": false; }; "annotations": { "alias": "annotations"; "required": false; }; "contextMenuItems": { "alias": "contextMenuItems"; "required": false; }; "highlightingColor": { "alias": "highlightingColor"; "required": false; }; "selectedColor": { "alias": "selectedColor"; "required": false; }; "annotationStroke": { "alias": "annotationStroke"; "required": false; }; "initialZoom": { "alias": "initialZoom"; "required": false; }; "labels": { "alias": "labels"; "required": false; }; }, { "boxClicked": "boxClicked"; "boxesSelected": "boxesSelected"; }, never, never, true, never>;
|
|
235
|
+
static ɵcmp: i0.ɵɵComponentDeclaration<NgxNextPdfViewerComponent, "ngx-next-pdf-viewer", never, { "blob": { "alias": "blob"; "required": false; }; "annotations": { "alias": "annotations"; "required": false; }; "contextMenuItems": { "alias": "contextMenuItems"; "required": false; }; "highlightingColor": { "alias": "highlightingColor"; "required": false; }; "selectedColor": { "alias": "selectedColor"; "required": false; }; "annotationStroke": { "alias": "annotationStroke"; "required": false; }; "initialZoom": { "alias": "initialZoom"; "required": false; }; "labels": { "alias": "labels"; "required": false; }; "showZoom": { "alias": "showZoom"; "required": false; }; "showRotation": { "alias": "showRotation"; "required": false; }; "showPageNavigation": { "alias": "showPageNavigation"; "required": false; }; "showAnnotationNavigation": { "alias": "showAnnotationNavigation"; "required": false; }; "showSelectionMode": { "alias": "showSelectionMode"; "required": false; }; "showSearch": { "alias": "showSearch"; "required": false; }; "apiKey": { "alias": "apiKey"; "required": false; }; }, { "boxClicked": "boxClicked"; "boxesSelected": "boxesSelected"; }, never, never, true, never>;
|
|
196
236
|
}
|
|
197
237
|
|
|
198
238
|
/**
|