@aprova.ch/ngx-next-pdf-viewer 21.0.9 → 21.0.11

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.
package/README.md CHANGED
@@ -9,6 +9,7 @@ An Angular component for rendering PDFs with bounding-box annotations, drag-to-s
9
9
  - Single-click highlight + `boxClicked` output event
10
10
  - Drag-to-select multiple boxes + context menu + `boxesSelected` output event
11
11
  - Toolbar: zoom in/out, rotate left/right, previous/next page, text search
12
+ - Page selection mode with thumbnail sidebar + `pagesSelected` output event
12
13
  - Ctrl + scroll wheel zoom
13
14
  - Configurable worker URL via injection token
14
15
 
@@ -65,13 +66,15 @@ export class AppComponent { ... }
65
66
  | `highlightingColor`| `string` | `'rgba(255,200,0,0.35)'` | Fill color of the clicked/highlighted box |
66
67
  | `selectedColor` | `string` | `'rgba(0,120,215,0.35)'` | Fill color of multi-selected boxes |
67
68
  | `annotationStroke` | `string` | `'#e97332'` | Stroke color of annotation polygons |
68
- | `initialZoom` | `number` or `string` | `1.5` or `fit-to-width` or `fit-to-height` or `fit-to-page` | Zoom level applied when the PDF first loads |
69
+ | `initialZoom` | `number` or `string` | `1.5` or `fit-to-width` or `fit-to-height` or `fit-to-page` or `automatic` | Zoom level applied when the PDF first loads |
69
70
  | `page` | `number \| undefined` | `undefined` | When set or changed, scrolls to this page number |
71
+ | `selectPagesEnabled` | `boolean` | `false` | Enables page-selection mode with a thumbnail sidebar. Users can click thumbnails to select/deselect individual pages |
72
+ | `selectedPages` | `number[]` | `[]` | Pre-selected page numbers (1-based). Only effective when `selectPagesEnabled` is `true`. Can be updated at any time to change the selection |
70
73
  | `labels` | `Partial<PdfViewerLabels>` | see below | Override any subset of the viewer's UI strings |
71
74
 
72
75
  ## Outputs
73
76
 
74
- > **License required** — The output events (`boxClicked`, `boxesSelected`) are only available with a valid license.
77
+ > **License required** — The output events (`boxClicked`, `boxesSelected`, `pagesSelected`) are only available with a valid license.
75
78
  >
76
79
  > - **30-day trial:** Contact the Telegram bot [@AprovaLicenceBot](https://t.me/AprovaLicenceBot)
77
80
  > - **Permanent license:** Email [licence@aprova.ch](mailto:licence@aprova.ch)
@@ -80,6 +83,7 @@ export class AppComponent { ... }
80
83
  |-----------------|--------------------------------------------------------|-------------------------------------------------------|
81
84
  | `boxClicked` | `EventEmitter<{ box: BoundingBox; selected: boolean }>` | Emitted when a box is clicked (select or deselect) |
82
85
  | `boxesSelected` | `EventEmitter<{ boxes: BoundingBox[]; action: string }>` | Emitted when drag-select + context menu action chosen |
86
+ | `pagesSelected` | `EventEmitter<number[]>` | Emitted when pages are selected/deselected in the thumbnail sidebar. Contains sorted array of selected page numbers (e.g. `[1, 3, 5]`) |
83
87
 
84
88
  ## Configuring the worker URL
85
89
 
@@ -54,6 +54,7 @@ class NgxNextPdfViewerComponent {
54
54
  nextAnnotation: 'Next annotation',
55
55
  selectArea: 'Select area',
56
56
  selectText: 'Select & copy text',
57
+ selectPages: 'Select pages',
57
58
  searchPlaceholder: 'Search in PDF…',
58
59
  noResults: 'No results',
59
60
  loading: 'Loading PDF…',
@@ -96,7 +97,7 @@ class NgxNextPdfViewerComponent {
96
97
  this.selectedColor = 'rgba(0, 120, 215, 0.35)';
97
98
  /** Stroke colour for all annotation polygons */
98
99
  this.annotationStroke = '#e97332';
99
- /** Initial zoom: numeric level (1.0 = 100 %) or 'fit-to-page' | 'fit-to-width' | 'fit-to-height' */
100
+ /** Initial zoom: numeric level (1.0 = 100 %) or 'fit-to-page' | 'fit-to-width' | 'fit-to-height' | 'automatic' */
100
101
  this.initialZoom = 1.5;
101
102
  /** Override any subset of the viewer's user-visible strings */
102
103
  this.labels = {};
@@ -112,11 +113,17 @@ class NgxNextPdfViewerComponent {
112
113
  this.showSelectionMode = true;
113
114
  /** Show / hide the search button and search bar */
114
115
  this.showSearch = true;
116
+ /** Enable page-selection mode: shows a thumbnail sidebar where users can select/deselect pages */
117
+ this.selectPagesEnabled = false;
118
+ /** Pre-selected page numbers (1-based). Only effective when selectPagesEnabled is true */
119
+ this.selectedPages = [];
115
120
  // ── Outputs ─────────────────────────────────
116
121
  /** Fired when the user clicks a single annotation box */
117
122
  this.boxClicked = new EventEmitter();
118
123
  /** Fired when the user picks a context-menu item after drag-selection */
119
124
  this.boxesSelected = new EventEmitter();
125
+ /** Fired when the user selects or deselects pages in the thumbnail sidebar (requires valid apiKey) */
126
+ this.pagesSelected = new EventEmitter();
120
127
  // ── PDF state ────────────────────────────────
121
128
  this.pdfDoc = null;
122
129
  this.renderedPages = [];
@@ -140,6 +147,9 @@ class NgxNextPdfViewerComponent {
140
147
  this.searchIndex = -1;
141
148
  // ── Selection mode ───────────────────────────
142
149
  this.selectionMode = 'select-area';
150
+ // ── Page selection state ────────────────────
151
+ this.sidebarOpen = false;
152
+ this.selectedPagesSet = new Set();
143
153
  // ── Loading ──────────────────────────────────
144
154
  this.loading = false;
145
155
  this.loadError = false;
@@ -191,6 +201,18 @@ class NgxNextPdfViewerComponent {
191
201
  console.log('scroll to page', this.page);
192
202
  this.scrollToPageNum(this.page);
193
203
  }
204
+ if (changes['selectPagesEnabled']) {
205
+ this.sidebarOpen = this.selectPagesEnabled && this.totalPages > 0;
206
+ this.selectedPagesSet = new Set(this.selectedPages);
207
+ if (this.sidebarOpen) {
208
+ this.cdr.detectChanges();
209
+ this.renderAllThumbnails();
210
+ }
211
+ }
212
+ if (changes['selectedPages'] && !changes['selectPagesEnabled']) {
213
+ this.selectedPagesSet = new Set(this.selectedPages);
214
+ this.cdr.detectChanges();
215
+ }
194
216
  }
195
217
  ngOnDestroy() {
196
218
  if (this.wheelListener) {
@@ -279,6 +301,12 @@ class NgxNextPdfViewerComponent {
279
301
  for (let p = 1; p <= this.totalPages; p++) {
280
302
  await this.renderPage(p);
281
303
  }
304
+ if (this.selectPagesEnabled) {
305
+ this.sidebarOpen = true;
306
+ this.selectedPagesSet = new Set(this.selectedPages);
307
+ this.cdr.detectChanges();
308
+ this.renderAllThumbnails();
309
+ }
282
310
  if (this.page != null) {
283
311
  this.scrollToPageNum(this.page);
284
312
  }
@@ -311,6 +339,7 @@ class NgxNextPdfViewerComponent {
311
339
  case 'fit-to-width': return scaleW;
312
340
  case 'fit-to-height': return scaleH;
313
341
  case 'fit-to-page': return Math.min(scaleW, scaleH);
342
+ case 'automatic': return scaleW <= scaleH ? scaleW : Math.min(scaleW, scaleH);
314
343
  }
315
344
  }
316
345
  async renderPage(pageNum) {
@@ -485,6 +514,9 @@ class NgxNextPdfViewerComponent {
485
514
  if (this.apiKeyValid) {
486
515
  this.boxClicked.emit({ box, selected: !wasSelected });
487
516
  }
517
+ else {
518
+ console.warn('[ngx-next-pdf-viewer] boxClicked event suppressed — provide a valid apiKey to enable licensed features.');
519
+ }
488
520
  }
489
521
  // ─────────────────────────────────────────────
490
522
  // Drag-select
@@ -562,6 +594,9 @@ class NgxNextPdfViewerComponent {
562
594
  if (this.apiKeyValid) {
563
595
  this.boxesSelected.emit({ boxes: selected, action: item.action });
564
596
  }
597
+ else {
598
+ console.warn('[ngx-next-pdf-viewer] boxesSelected event suppressed — provide a valid apiKey to enable licensed features.');
599
+ }
565
600
  this.multiSelectedKeys.clear();
566
601
  this.cdr.detectChanges();
567
602
  }
@@ -719,6 +754,9 @@ class NgxNextPdfViewerComponent {
719
754
  if (this.apiKeyValid) {
720
755
  this.boxClicked.emit({ box, selected: true });
721
756
  }
757
+ else {
758
+ console.warn('[ngx-next-pdf-viewer] boxClicked event suppressed — provide a valid apiKey to enable licensed features.');
759
+ }
722
760
  }
723
761
  // ─────────────────────────────────────────────
724
762
  // Toolbar – selection mode
@@ -807,6 +845,58 @@ class NgxNextPdfViewerComponent {
807
845
  }
808
846
  }
809
847
  // ─────────────────────────────────────────────
848
+ // Page selection (thumbnail sidebar)
849
+ // ─────────────────────────────────────────────
850
+ toggleSidebar() {
851
+ this.sidebarOpen = !this.sidebarOpen;
852
+ if (this.sidebarOpen) {
853
+ this.cdr.detectChanges();
854
+ this.renderAllThumbnails();
855
+ }
856
+ }
857
+ togglePageSelection(pageNum) {
858
+ if (this.selectedPagesSet.has(pageNum)) {
859
+ this.selectedPagesSet.delete(pageNum);
860
+ }
861
+ else {
862
+ this.selectedPagesSet.add(pageNum);
863
+ }
864
+ this.cdr.detectChanges();
865
+ if (this.apiKeyValid) {
866
+ this.pagesSelected.emit(Array.from(this.selectedPagesSet).sort((a, b) => a - b));
867
+ }
868
+ else {
869
+ console.warn('[ngx-next-pdf-viewer] pagesSelected event suppressed — provide a valid apiKey to enable licensed features.');
870
+ }
871
+ }
872
+ isPageSelected(pageNum) {
873
+ return this.selectedPagesSet.has(pageNum);
874
+ }
875
+ async renderAllThumbnails() {
876
+ if (!this.pdfDoc)
877
+ return;
878
+ for (let p = 1; p <= this.totalPages; p++) {
879
+ await this.renderThumbnail(p);
880
+ }
881
+ }
882
+ async renderThumbnail(pageNum) {
883
+ if (!this.pdfDoc)
884
+ return;
885
+ const canvas = document.getElementById(`npv-thumb-${pageNum}`);
886
+ if (!canvas)
887
+ return;
888
+ const page = await this.pdfDoc.getPage(pageNum);
889
+ const totalRotation = (page.rotate + this.userRotation) % 360;
890
+ const viewport = page.getViewport({ scale: 1, rotation: totalRotation });
891
+ const thumbScale = 150 / viewport.width;
892
+ const thumbViewport = page.getViewport({ scale: thumbScale, rotation: totalRotation });
893
+ canvas.width = thumbViewport.width;
894
+ canvas.height = thumbViewport.height;
895
+ const ctx = canvas.getContext('2d');
896
+ await page.render({ canvasContext: ctx, viewport: thumbViewport }).promise;
897
+ page.cleanup();
898
+ }
899
+ // ─────────────────────────────────────────────
810
900
  // Scroll tracking
811
901
  // ─────────────────────────────────────────────
812
902
  onContainerScroll() {
@@ -830,7 +920,7 @@ class NgxNextPdfViewerComponent {
830
920
  }
831
921
  }
832
922
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.1", ngImport: i0, type: NgxNextPdfViewerComponent, deps: [{ token: i0.ChangeDetectorRef }, { token: i0.NgZone }, { token: i0.ElementRef }, { token: NGX_PDF_WORKER_SRC }], target: i0.ɵɵFactoryTarget.Component }); }
833
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.1", 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", page: "page" }, 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 @if (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 }\n\n <!-- Rotation -->\n @if (showRotation) {\n @if (showZoom) {\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\n <!-- Page navigation -->\n @if (showPageNavigation) {\n @if (showZoom || showRotation) {\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\n <!-- Annotation navigation -->\n @if (showAnnotationNavigation && annotations.length) {\n @if (showZoom || showRotation || showPageNavigation) {\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 }\n\n <!-- Selection mode toggle -->\n @if (showSelectionMode) {\n @if (showZoom || showRotation || showPageNavigation || (showAnnotationNavigation && annotations.length > 0)) {\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\n <!-- Search -->\n @if (showSearch) {\n @if (showZoom || showRotation || showPageNavigation || (showAnnotationNavigation && annotations.length > 0) || showSelectionMode) {\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 @if (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 @if (searchMatches.length) {\n <span class=\"npv-search-count\">\n {{ searchIndex + 1 }} / {{ searchMatches.length }}\n </span>\n }\n @if (searchQuery && !searchMatches.length) {\n <span class=\"npv-search-count npv-no-match\">\n {{ l.noResults }}\n </span>\n }\n }\n }\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 @if (loading) {\n <div class=\"npv-loading\">\n <span class=\"npv-spinner\"></span> {{ l.loading }}\n </div>\n }\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 @for (p of pageRange(); track p) {\n <div class=\"npv-page-wrapper\" [id]=\"'npv-page-' + p\">\n <canvas [id]=\"'npv-canvas-' + p\" class=\"npv-canvas\"></canvas>\n @if (getPageInfo(p); as pi) {\n <svg\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 <!-- 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 <!-- Annotation boxes -->\n @for (box of getBoxesForPage(p); track box) {\n <polygon\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 @for (m of getSearchMatchesForPage(p); track m; let mi = $index) {\n <polygon\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 @if (getDragRect(p); as dr) {\n <rect\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 }\n </div>\n }\n\n @if (!loading && loadError) {\n <div class=\"npv-placeholder npv-placeholder--error\">\n {{ l.loadError }}\n </div>\n }\n @if (!loading && !loadError && totalPages === 0) {\n <div class=\"npv-placeholder\">\n {{ l.noDocument }}\n </div>\n }\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 @if (ctxVisible && contextMenuItems.length) {\n <div\n class=\"npv-context-menu\"\n [style.left.px]=\"ctxX\" [style.top.px]=\"ctxY\"\n (click)=\"$event.stopPropagation()\">\n @for (item of contextMenuItems; track item) {\n <div\n class=\"npv-context-item\"\n (click)=\"onContextMenuAction(item)\">\n {{ item.label }}\n </div>\n }\n </div>\n }\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: FormsModule }, { kind: "directive", type: i1.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: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i2.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i3.MatIconButton, selector: "button[mat-icon-button], a[mat-icon-button], button[matIconButton], a[matIconButton]", exportAs: ["matButton", "matAnchor"] }, { kind: "ngmodule", type: MatTooltipModule }, { kind: "directive", type: i4.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }, { kind: "ngmodule", type: MatInputModule }, { kind: "ngmodule", type: MatFormFieldModule }] }); }
923
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.1", 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", page: "page", selectPagesEnabled: "selectPagesEnabled", selectedPages: "selectedPages" }, outputs: { boxClicked: "boxClicked", boxesSelected: "boxesSelected", pagesSelected: "pagesSelected" }, 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 @if (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 }\n\n <!-- Rotation -->\n @if (showRotation) {\n @if (showZoom) {\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\n <!-- Page navigation -->\n @if (showPageNavigation) {\n @if (showZoom || showRotation) {\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\n <!-- Annotation navigation -->\n @if (showAnnotationNavigation && annotations.length) {\n @if (showZoom || showRotation || showPageNavigation) {\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 }\n\n <!-- Selection mode toggle -->\n @if (showSelectionMode) {\n @if (showZoom || showRotation || showPageNavigation || (showAnnotationNavigation && annotations.length > 0)) {\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\n <!-- Page selection toggle -->\n @if (selectPagesEnabled) {\n @if (showZoom || showRotation || showPageNavigation || (showAnnotationNavigation && annotations.length > 0) || showSelectionMode) {\n <div class=\"npv-sep\"></div>\n }\n <button mat-icon-button\n [matTooltip]=\"l.selectPages\"\n (click)=\"toggleSidebar()\"\n [class.npv-active]=\"sidebarOpen\">\n <mat-icon>view_sidebar</mat-icon>\n </button>\n }\n\n <!-- Search -->\n @if (showSearch) {\n @if (showZoom || showRotation || showPageNavigation || (showAnnotationNavigation && annotations.length > 0) || showSelectionMode || selectPagesEnabled) {\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 @if (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 @if (searchMatches.length) {\n <span class=\"npv-search-count\">\n {{ searchIndex + 1 }} / {{ searchMatches.length }}\n </span>\n }\n @if (searchQuery && !searchMatches.length) {\n <span class=\"npv-search-count npv-no-match\">\n {{ l.noResults }}\n </span>\n }\n }\n }\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 @if (loading) {\n <div class=\"npv-loading\">\n <span class=\"npv-spinner\"></span> {{ l.loading }}\n </div>\n }\n\n <!-- \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 Content area (sidebar + scroll) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 -->\n <div class=\"npv-content-area\">\n\n <!-- \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 Thumbnail sidebar \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 -->\n @if (sidebarOpen) {\n <div class=\"npv-sidebar\">\n @for (p of pageRange(); track p) {\n <div class=\"npv-thumb-wrapper\"\n [class.npv-thumb-wrapper--selected]=\"isPageSelected(p)\"\n (click)=\"togglePageSelection(p)\">\n <canvas [id]=\"'npv-thumb-' + p\" class=\"npv-thumb-canvas\"></canvas>\n <span class=\"npv-thumb-label\">{{ p }}</span>\n </div>\n }\n </div>\n }\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 @for (p of pageRange(); track p) {\n <div class=\"npv-page-wrapper\" [id]=\"'npv-page-' + p\">\n <canvas [id]=\"'npv-canvas-' + p\" class=\"npv-canvas\"></canvas>\n @if (getPageInfo(p); as pi) {\n <svg\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 <!-- 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 <!-- Annotation boxes -->\n @for (box of getBoxesForPage(p); track box) {\n <polygon\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 @for (m of getSearchMatchesForPage(p); track m; let mi = $index) {\n <polygon\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 @if (getDragRect(p); as dr) {\n <rect\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 }\n </div>\n }\n\n @if (!loading && loadError) {\n <div class=\"npv-placeholder npv-placeholder--error\">\n {{ l.loadError }}\n </div>\n }\n @if (!loading && !loadError && totalPages === 0) {\n <div class=\"npv-placeholder\">\n {{ l.noDocument }}\n </div>\n }\n\n </div><!-- /npv-scroll-inner -->\n </div>\n\n </div><!-- /npv-content-area -->\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 @if (ctxVisible && contextMenuItems.length) {\n <div\n class=\"npv-context-menu\"\n [style.left.px]=\"ctxX\" [style.top.px]=\"ctxY\"\n (click)=\"$event.stopPropagation()\">\n @for (item of contextMenuItems; track item) {\n <div\n class=\"npv-context-item\"\n (click)=\"onContextMenuAction(item)\">\n {{ item.label }}\n </div>\n }\n </div>\n }\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-content-area{display:flex;flex:1;overflow:hidden}.npv-sidebar{width:200px;flex-shrink:0;overflow-y:auto;background:#dcdfe2;border-right:1px solid rgba(0,0,0,.15);padding:12px 8px;display:flex;flex-direction:column;align-items:center;gap:12px;z-index:5}.npv-thumb-wrapper{display:flex;flex-direction:column;align-items:center;cursor:pointer;border:3px solid transparent;border-radius:4px;padding:4px;transition:border-color .15s ease,background .15s ease}.npv-thumb-wrapper:hover{background:#0000000f;border-color:#0003}.npv-thumb-wrapper.npv-thumb-wrapper--selected{border-color:#1976d2;background:#1976d214}.npv-thumb-wrapper.npv-thumb-wrapper--selected .npv-thumb-label{color:#1976d2;font-weight:600}.npv-thumb-canvas{max-width:150px;display:block;box-shadow:0 2px 6px #0000004d}.npv-thumb-label{margin-top:4px;font-size:12px;color:#505050;-webkit-user-select:none;user-select:none}.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: FormsModule }, { kind: "directive", type: i1.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: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i2.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i3.MatIconButton, selector: "button[mat-icon-button], a[mat-icon-button], button[matIconButton], a[matIconButton]", exportAs: ["matButton", "matAnchor"] }, { kind: "ngmodule", type: MatTooltipModule }, { kind: "directive", type: i4.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }, { kind: "ngmodule", type: MatInputModule }, { kind: "ngmodule", type: MatFormFieldModule }] }); }
834
924
  }
835
925
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.1", ngImport: i0, type: NgxNextPdfViewerComponent, decorators: [{
836
926
  type: Component,
@@ -841,7 +931,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.1", ngImpor
841
931
  MatTooltipModule,
842
932
  MatInputModule,
843
933
  MatFormFieldModule
844
- ], 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 @if (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 }\n\n <!-- Rotation -->\n @if (showRotation) {\n @if (showZoom) {\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\n <!-- Page navigation -->\n @if (showPageNavigation) {\n @if (showZoom || showRotation) {\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\n <!-- Annotation navigation -->\n @if (showAnnotationNavigation && annotations.length) {\n @if (showZoom || showRotation || showPageNavigation) {\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 }\n\n <!-- Selection mode toggle -->\n @if (showSelectionMode) {\n @if (showZoom || showRotation || showPageNavigation || (showAnnotationNavigation && annotations.length > 0)) {\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\n <!-- Search -->\n @if (showSearch) {\n @if (showZoom || showRotation || showPageNavigation || (showAnnotationNavigation && annotations.length > 0) || showSelectionMode) {\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 @if (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 @if (searchMatches.length) {\n <span class=\"npv-search-count\">\n {{ searchIndex + 1 }} / {{ searchMatches.length }}\n </span>\n }\n @if (searchQuery && !searchMatches.length) {\n <span class=\"npv-search-count npv-no-match\">\n {{ l.noResults }}\n </span>\n }\n }\n }\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 @if (loading) {\n <div class=\"npv-loading\">\n <span class=\"npv-spinner\"></span> {{ l.loading }}\n </div>\n }\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 @for (p of pageRange(); track p) {\n <div class=\"npv-page-wrapper\" [id]=\"'npv-page-' + p\">\n <canvas [id]=\"'npv-canvas-' + p\" class=\"npv-canvas\"></canvas>\n @if (getPageInfo(p); as pi) {\n <svg\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 <!-- 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 <!-- Annotation boxes -->\n @for (box of getBoxesForPage(p); track box) {\n <polygon\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 @for (m of getSearchMatchesForPage(p); track m; let mi = $index) {\n <polygon\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 @if (getDragRect(p); as dr) {\n <rect\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 }\n </div>\n }\n\n @if (!loading && loadError) {\n <div class=\"npv-placeholder npv-placeholder--error\">\n {{ l.loadError }}\n </div>\n }\n @if (!loading && !loadError && totalPages === 0) {\n <div class=\"npv-placeholder\">\n {{ l.noDocument }}\n </div>\n }\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 @if (ctxVisible && contextMenuItems.length) {\n <div\n class=\"npv-context-menu\"\n [style.left.px]=\"ctxX\" [style.top.px]=\"ctxY\"\n (click)=\"$event.stopPropagation()\">\n @for (item of contextMenuItems; track item) {\n <div\n class=\"npv-context-item\"\n (click)=\"onContextMenuAction(item)\">\n {{ item.label }}\n </div>\n }\n </div>\n }\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"] }]
934
+ ], 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 @if (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 }\n\n <!-- Rotation -->\n @if (showRotation) {\n @if (showZoom) {\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\n <!-- Page navigation -->\n @if (showPageNavigation) {\n @if (showZoom || showRotation) {\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\n <!-- Annotation navigation -->\n @if (showAnnotationNavigation && annotations.length) {\n @if (showZoom || showRotation || showPageNavigation) {\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 }\n\n <!-- Selection mode toggle -->\n @if (showSelectionMode) {\n @if (showZoom || showRotation || showPageNavigation || (showAnnotationNavigation && annotations.length > 0)) {\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\n <!-- Page selection toggle -->\n @if (selectPagesEnabled) {\n @if (showZoom || showRotation || showPageNavigation || (showAnnotationNavigation && annotations.length > 0) || showSelectionMode) {\n <div class=\"npv-sep\"></div>\n }\n <button mat-icon-button\n [matTooltip]=\"l.selectPages\"\n (click)=\"toggleSidebar()\"\n [class.npv-active]=\"sidebarOpen\">\n <mat-icon>view_sidebar</mat-icon>\n </button>\n }\n\n <!-- Search -->\n @if (showSearch) {\n @if (showZoom || showRotation || showPageNavigation || (showAnnotationNavigation && annotations.length > 0) || showSelectionMode || selectPagesEnabled) {\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 @if (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 @if (searchMatches.length) {\n <span class=\"npv-search-count\">\n {{ searchIndex + 1 }} / {{ searchMatches.length }}\n </span>\n }\n @if (searchQuery && !searchMatches.length) {\n <span class=\"npv-search-count npv-no-match\">\n {{ l.noResults }}\n </span>\n }\n }\n }\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 @if (loading) {\n <div class=\"npv-loading\">\n <span class=\"npv-spinner\"></span> {{ l.loading }}\n </div>\n }\n\n <!-- \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 Content area (sidebar + scroll) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 -->\n <div class=\"npv-content-area\">\n\n <!-- \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 Thumbnail sidebar \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 -->\n @if (sidebarOpen) {\n <div class=\"npv-sidebar\">\n @for (p of pageRange(); track p) {\n <div class=\"npv-thumb-wrapper\"\n [class.npv-thumb-wrapper--selected]=\"isPageSelected(p)\"\n (click)=\"togglePageSelection(p)\">\n <canvas [id]=\"'npv-thumb-' + p\" class=\"npv-thumb-canvas\"></canvas>\n <span class=\"npv-thumb-label\">{{ p }}</span>\n </div>\n }\n </div>\n }\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 @for (p of pageRange(); track p) {\n <div class=\"npv-page-wrapper\" [id]=\"'npv-page-' + p\">\n <canvas [id]=\"'npv-canvas-' + p\" class=\"npv-canvas\"></canvas>\n @if (getPageInfo(p); as pi) {\n <svg\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 <!-- 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 <!-- Annotation boxes -->\n @for (box of getBoxesForPage(p); track box) {\n <polygon\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 @for (m of getSearchMatchesForPage(p); track m; let mi = $index) {\n <polygon\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 @if (getDragRect(p); as dr) {\n <rect\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 }\n </div>\n }\n\n @if (!loading && loadError) {\n <div class=\"npv-placeholder npv-placeholder--error\">\n {{ l.loadError }}\n </div>\n }\n @if (!loading && !loadError && totalPages === 0) {\n <div class=\"npv-placeholder\">\n {{ l.noDocument }}\n </div>\n }\n\n </div><!-- /npv-scroll-inner -->\n </div>\n\n </div><!-- /npv-content-area -->\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 @if (ctxVisible && contextMenuItems.length) {\n <div\n class=\"npv-context-menu\"\n [style.left.px]=\"ctxX\" [style.top.px]=\"ctxY\"\n (click)=\"$event.stopPropagation()\">\n @for (item of contextMenuItems; track item) {\n <div\n class=\"npv-context-item\"\n (click)=\"onContextMenuAction(item)\">\n {{ item.label }}\n </div>\n }\n </div>\n }\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-content-area{display:flex;flex:1;overflow:hidden}.npv-sidebar{width:200px;flex-shrink:0;overflow-y:auto;background:#dcdfe2;border-right:1px solid rgba(0,0,0,.15);padding:12px 8px;display:flex;flex-direction:column;align-items:center;gap:12px;z-index:5}.npv-thumb-wrapper{display:flex;flex-direction:column;align-items:center;cursor:pointer;border:3px solid transparent;border-radius:4px;padding:4px;transition:border-color .15s ease,background .15s ease}.npv-thumb-wrapper:hover{background:#0000000f;border-color:#0003}.npv-thumb-wrapper.npv-thumb-wrapper--selected{border-color:#1976d2;background:#1976d214}.npv-thumb-wrapper.npv-thumb-wrapper--selected .npv-thumb-label{color:#1976d2;font-weight:600}.npv-thumb-canvas{max-width:150px;display:block;box-shadow:0 2px 6px #0000004d}.npv-thumb-label{margin-top:4px;font-size:12px;color:#505050;-webkit-user-select:none;user-select:none}.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"] }]
845
935
  }], ctorParameters: () => [{ type: i0.ChangeDetectorRef }, { type: i0.NgZone }, { type: i0.ElementRef }, { type: undefined, decorators: [{
846
936
  type: Inject,
847
937
  args: [NGX_PDF_WORKER_SRC]
@@ -877,10 +967,16 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.1", ngImpor
877
967
  type: Input
878
968
  }], page: [{
879
969
  type: Input
970
+ }], selectPagesEnabled: [{
971
+ type: Input
972
+ }], selectedPages: [{
973
+ type: Input
880
974
  }], boxClicked: [{
881
975
  type: Output
882
976
  }], boxesSelected: [{
883
977
  type: Output
978
+ }], pagesSelected: [{
979
+ type: Output
884
980
  }], pdfContainer: [{
885
981
  type: ViewChild,
886
982
  args: ['pdfContainer']
@@ -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';\n\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 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 /** When set or changed, scrolls to this page number */\n @Input() page: number | 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 if (changes['page'] && this.page != null && !changes['blob']) {\n console.log('scroll to page', this.page)\n this.scrollToPageNum(this.page);\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<ArrayBuffer> {\n const b64 = b64url.replace(/-/g, '+').replace(/_/g, '/');\n const padded = b64.padEnd(b64.length + (4 - (b64.length % 4)) % 4, '=');\n const raw = atob(padded);\n const buf = new ArrayBuffer(raw.length);\n const arr = new Uint8Array(buf);\n for (let i = 0; i < raw.length; i++) arr[i] = raw.charCodeAt(i);\n return arr;\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.page != null) {\n this.scrollToPageNum(this.page);\n } else 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 @if (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 }\n\n <!-- Rotation -->\n @if (showRotation) {\n @if (showZoom) {\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\n <!-- Page navigation -->\n @if (showPageNavigation) {\n @if (showZoom || showRotation) {\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\n <!-- Annotation navigation -->\n @if (showAnnotationNavigation && annotations.length) {\n @if (showZoom || showRotation || showPageNavigation) {\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 }\n\n <!-- Selection mode toggle -->\n @if (showSelectionMode) {\n @if (showZoom || showRotation || showPageNavigation || (showAnnotationNavigation && annotations.length > 0)) {\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\n <!-- Search -->\n @if (showSearch) {\n @if (showZoom || showRotation || showPageNavigation || (showAnnotationNavigation && annotations.length > 0) || showSelectionMode) {\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 @if (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 @if (searchMatches.length) {\n <span class=\"npv-search-count\">\n {{ searchIndex + 1 }} / {{ searchMatches.length }}\n </span>\n }\n @if (searchQuery && !searchMatches.length) {\n <span class=\"npv-search-count npv-no-match\">\n {{ l.noResults }}\n </span>\n }\n }\n }\n\n </div>\n\n <!-- ─────────── Loading ─────────── -->\n @if (loading) {\n <div class=\"npv-loading\">\n <span class=\"npv-spinner\"></span> {{ l.loading }}\n </div>\n }\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 @for (p of pageRange(); track p) {\n <div class=\"npv-page-wrapper\" [id]=\"'npv-page-' + p\">\n <canvas [id]=\"'npv-canvas-' + p\" class=\"npv-canvas\"></canvas>\n @if (getPageInfo(p); as pi) {\n <svg\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 <!-- 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 <!-- Annotation boxes -->\n @for (box of getBoxesForPage(p); track box) {\n <polygon\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 @for (m of getSearchMatchesForPage(p); track m; let mi = $index) {\n <polygon\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 @if (getDragRect(p); as dr) {\n <rect\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 }\n </div>\n }\n\n @if (!loading && loadError) {\n <div class=\"npv-placeholder npv-placeholder--error\">\n {{ l.loadError }}\n </div>\n }\n @if (!loading && !loadError && totalPages === 0) {\n <div class=\"npv-placeholder\">\n {{ l.noDocument }}\n </div>\n }\n\n </div><!-- /npv-scroll-inner -->\n </div>\n\n <!-- ─────────── Context menu ─────────── -->\n @if (ctxVisible && contextMenuItems.length) {\n <div\n class=\"npv-context-menu\"\n [style.left.px]=\"ctxX\" [style.top.px]=\"ctxY\"\n (click)=\"$event.stopPropagation()\">\n @for (item of contextMenuItems; track item) {\n <div\n class=\"npv-context-item\"\n (click)=\"onContextMenuAction(item)\">\n {{ item.label }}\n </div>\n }\n </div>\n }\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';\n\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 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' | 'automatic' */\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 /** When set or changed, scrolls to this page number */\n @Input() page: number | undefined;\n /** Enable page-selection mode: shows a thumbnail sidebar where users can select/deselect pages */\n @Input() selectPagesEnabled = false;\n /** Pre-selected page numbers (1-based). Only effective when selectPagesEnabled is true */\n @Input() selectedPages: number[] = [];\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 selectPages: 'Select pages',\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 /** Fired when the user selects or deselects pages in the thumbnail sidebar (requires valid apiKey) */\n @Output() pagesSelected = new EventEmitter<number[]>();\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 // ── Page selection state ────────────────────\n sidebarOpen = false;\n selectedPagesSet: Set<number> = new Set();\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 if (changes['page'] && this.page != null && !changes['blob']) {\n console.log('scroll to page', this.page)\n this.scrollToPageNum(this.page);\n }\n if (changes['selectPagesEnabled']) {\n this.sidebarOpen = this.selectPagesEnabled && this.totalPages > 0;\n this.selectedPagesSet = new Set(this.selectedPages);\n if (this.sidebarOpen) {\n this.cdr.detectChanges();\n this.renderAllThumbnails();\n }\n }\n if (changes['selectedPages'] && !changes['selectPagesEnabled']) {\n this.selectedPagesSet = new Set(this.selectedPages);\n this.cdr.detectChanges();\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<ArrayBuffer> {\n const b64 = b64url.replace(/-/g, '+').replace(/_/g, '/');\n const padded = b64.padEnd(b64.length + (4 - (b64.length % 4)) % 4, '=');\n const raw = atob(padded);\n const buf = new ArrayBuffer(raw.length);\n const arr = new Uint8Array(buf);\n for (let i = 0; i < raw.length; i++) arr[i] = raw.charCodeAt(i);\n return arr;\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.selectPagesEnabled) {\n this.sidebarOpen = true;\n this.selectedPagesSet = new Set(this.selectedPages);\n this.cdr.detectChanges();\n this.renderAllThumbnails();\n }\n\n if (this.page != null) {\n this.scrollToPageNum(this.page);\n } else 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 case 'automatic': return scaleW <= scaleH ? scaleW : 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 } else {\n console.warn('[ngx-next-pdf-viewer] boxClicked event suppressed — provide a valid apiKey to enable licensed features.');\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 } else {\n console.warn('[ngx-next-pdf-viewer] boxesSelected event suppressed — provide a valid apiKey to enable licensed features.');\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 } else {\n console.warn('[ngx-next-pdf-viewer] boxClicked event suppressed — provide a valid apiKey to enable licensed features.');\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 // Page selection (thumbnail sidebar)\n // ─────────────────────────────────────────────\n\n toggleSidebar(): void {\n this.sidebarOpen = !this.sidebarOpen;\n if (this.sidebarOpen) {\n this.cdr.detectChanges();\n this.renderAllThumbnails();\n }\n }\n\n togglePageSelection(pageNum: number): void {\n if (this.selectedPagesSet.has(pageNum)) {\n this.selectedPagesSet.delete(pageNum);\n } else {\n this.selectedPagesSet.add(pageNum);\n }\n this.cdr.detectChanges();\n if (this.apiKeyValid) {\n this.pagesSelected.emit(Array.from(this.selectedPagesSet).sort((a, b) => a - b));\n } else {\n console.warn('[ngx-next-pdf-viewer] pagesSelected event suppressed — provide a valid apiKey to enable licensed features.');\n }\n }\n\n isPageSelected(pageNum: number): boolean {\n return this.selectedPagesSet.has(pageNum);\n }\n\n private async renderAllThumbnails(): Promise<void> {\n if (!this.pdfDoc) return;\n for (let p = 1; p <= this.totalPages; p++) {\n await this.renderThumbnail(p);\n }\n }\n\n private async renderThumbnail(pageNum: number): Promise<void> {\n if (!this.pdfDoc) return;\n const canvas = document.getElementById(`npv-thumb-${pageNum}`) as HTMLCanvasElement | null;\n if (!canvas) return;\n const page = await this.pdfDoc.getPage(pageNum);\n const totalRotation = (page.rotate + this.userRotation) % 360;\n const viewport = page.getViewport({ scale: 1, rotation: totalRotation });\n const thumbScale = 150 / viewport.width;\n const thumbViewport = page.getViewport({ scale: thumbScale, rotation: totalRotation });\n canvas.width = thumbViewport.width;\n canvas.height = thumbViewport.height;\n const ctx = canvas.getContext('2d')!;\n await page.render({ canvasContext: ctx, viewport: thumbViewport }).promise;\n page.cleanup();\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 @if (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 }\n\n <!-- Rotation -->\n @if (showRotation) {\n @if (showZoom) {\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\n <!-- Page navigation -->\n @if (showPageNavigation) {\n @if (showZoom || showRotation) {\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\n <!-- Annotation navigation -->\n @if (showAnnotationNavigation && annotations.length) {\n @if (showZoom || showRotation || showPageNavigation) {\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 }\n\n <!-- Selection mode toggle -->\n @if (showSelectionMode) {\n @if (showZoom || showRotation || showPageNavigation || (showAnnotationNavigation && annotations.length > 0)) {\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\n <!-- Page selection toggle -->\n @if (selectPagesEnabled) {\n @if (showZoom || showRotation || showPageNavigation || (showAnnotationNavigation && annotations.length > 0) || showSelectionMode) {\n <div class=\"npv-sep\"></div>\n }\n <button mat-icon-button\n [matTooltip]=\"l.selectPages\"\n (click)=\"toggleSidebar()\"\n [class.npv-active]=\"sidebarOpen\">\n <mat-icon>view_sidebar</mat-icon>\n </button>\n }\n\n <!-- Search -->\n @if (showSearch) {\n @if (showZoom || showRotation || showPageNavigation || (showAnnotationNavigation && annotations.length > 0) || showSelectionMode || selectPagesEnabled) {\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 @if (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 @if (searchMatches.length) {\n <span class=\"npv-search-count\">\n {{ searchIndex + 1 }} / {{ searchMatches.length }}\n </span>\n }\n @if (searchQuery && !searchMatches.length) {\n <span class=\"npv-search-count npv-no-match\">\n {{ l.noResults }}\n </span>\n }\n }\n }\n\n </div>\n\n <!-- ─────────── Loading ─────────── -->\n @if (loading) {\n <div class=\"npv-loading\">\n <span class=\"npv-spinner\"></span> {{ l.loading }}\n </div>\n }\n\n <!-- ─────────── Content area (sidebar + scroll) ─────────── -->\n <div class=\"npv-content-area\">\n\n <!-- ─────────── Thumbnail sidebar ─────────── -->\n @if (sidebarOpen) {\n <div class=\"npv-sidebar\">\n @for (p of pageRange(); track p) {\n <div class=\"npv-thumb-wrapper\"\n [class.npv-thumb-wrapper--selected]=\"isPageSelected(p)\"\n (click)=\"togglePageSelection(p)\">\n <canvas [id]=\"'npv-thumb-' + p\" class=\"npv-thumb-canvas\"></canvas>\n <span class=\"npv-thumb-label\">{{ p }}</span>\n </div>\n }\n </div>\n }\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 @for (p of pageRange(); track p) {\n <div class=\"npv-page-wrapper\" [id]=\"'npv-page-' + p\">\n <canvas [id]=\"'npv-canvas-' + p\" class=\"npv-canvas\"></canvas>\n @if (getPageInfo(p); as pi) {\n <svg\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 <!-- 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 <!-- Annotation boxes -->\n @for (box of getBoxesForPage(p); track box) {\n <polygon\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 @for (m of getSearchMatchesForPage(p); track m; let mi = $index) {\n <polygon\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 @if (getDragRect(p); as dr) {\n <rect\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 }\n </div>\n }\n\n @if (!loading && loadError) {\n <div class=\"npv-placeholder npv-placeholder--error\">\n {{ l.loadError }}\n </div>\n }\n @if (!loading && !loadError && totalPages === 0) {\n <div class=\"npv-placeholder\">\n {{ l.noDocument }}\n </div>\n }\n\n </div><!-- /npv-scroll-inner -->\n </div>\n\n </div><!-- /npv-content-area -->\n\n <!-- ─────────── Context menu ─────────── -->\n @if (ctxVisible && contextMenuItems.length) {\n <div\n class=\"npv-context-menu\"\n [style.left.px]=\"ctxX\" [style.top.px]=\"ctxY\"\n (click)=\"$event.stopPropagation()\">\n @for (item of contextMenuItems; track item) {\n <div\n class=\"npv-context-item\"\n (click)=\"onContextMenuAction(item)\">\n {{ item.label }}\n </div>\n }\n </div>\n }\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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aprova.ch/ngx-next-pdf-viewer",
3
- "version": "21.0.9",
3
+ "version": "21.0.11",
4
4
  "description": "Angular PDF viewer with bounding-box annotations, search, zoom and page rotation",
5
5
  "keywords": [
6
6
  "angular",
@@ -29,7 +29,7 @@ interface BoundingBox {
29
29
  [key: string]: any;
30
30
  }
31
31
  /** Numeric zoom level (1.0 = 100 %) or a fit mode applied when the PDF first loads */
32
- type ZoomMode = number | 'fit-to-page' | 'fit-to-width' | 'fit-to-height';
32
+ type ZoomMode = number | 'fit-to-page' | 'fit-to-width' | 'fit-to-height' | 'automatic';
33
33
  /** All user-visible strings rendered by the viewer. Pass a partial object to override any subset. */
34
34
  interface PdfViewerLabels {
35
35
  zoomOut: string;
@@ -45,6 +45,7 @@ interface PdfViewerLabels {
45
45
  nextAnnotation: string;
46
46
  selectArea: string;
47
47
  selectText: string;
48
+ selectPages: string;
48
49
  searchPlaceholder: string;
49
50
  noResults: string;
50
51
  loading: string;
@@ -93,7 +94,7 @@ declare class NgxNextPdfViewerComponent implements OnChanges, OnDestroy, AfterVi
93
94
  selectedColor: string;
94
95
  /** Stroke colour for all annotation polygons */
95
96
  annotationStroke: string;
96
- /** Initial zoom: numeric level (1.0 = 100 %) or 'fit-to-page' | 'fit-to-width' | 'fit-to-height' */
97
+ /** Initial zoom: numeric level (1.0 = 100 %) or 'fit-to-page' | 'fit-to-width' | 'fit-to-height' | 'automatic' */
97
98
  initialZoom: ZoomMode;
98
99
  /** Override any subset of the viewer's user-visible strings */
99
100
  labels: Partial<PdfViewerLabels>;
@@ -117,6 +118,10 @@ declare class NgxNextPdfViewerComponent implements OnChanges, OnDestroy, AfterVi
117
118
  apiKey: string | undefined;
118
119
  /** When set or changed, scrolls to this page number */
119
120
  page: number | undefined;
121
+ /** Enable page-selection mode: shows a thumbnail sidebar where users can select/deselect pages */
122
+ selectPagesEnabled: boolean;
123
+ /** Pre-selected page numbers (1-based). Only effective when selectPagesEnabled is true */
124
+ selectedPages: number[];
120
125
  private static readonly DEFAULT_LABELS;
121
126
  get l(): PdfViewerLabels;
122
127
  /** Fired when the user clicks a single annotation box */
@@ -129,6 +134,8 @@ declare class NgxNextPdfViewerComponent implements OnChanges, OnDestroy, AfterVi
129
134
  boxes: BoundingBox[];
130
135
  action: string;
131
136
  }>;
137
+ /** Fired when the user selects or deselects pages in the thumbnail sidebar (requires valid apiKey) */
138
+ pagesSelected: EventEmitter<number[]>;
132
139
  pdfContainer: ElementRef<HTMLDivElement>;
133
140
  pdfDoc: PDFDocumentProxy | null;
134
141
  renderedPages: RenderedPage[];
@@ -147,6 +154,8 @@ declare class NgxNextPdfViewerComponent implements OnChanges, OnDestroy, AfterVi
147
154
  searchMatches: SearchMatch[];
148
155
  searchIndex: number;
149
156
  selectionMode: 'select-area' | 'select-text';
157
+ sidebarOpen: boolean;
158
+ selectedPagesSet: Set<number>;
150
159
  loading: boolean;
151
160
  loadError: boolean;
152
161
  /** True once the current apiKey has been verified against the embedded public key. */
@@ -232,9 +241,14 @@ declare class NgxNextPdfViewerComponent implements OnChanges, OnDestroy, AfterVi
232
241
  private renderTextLayer;
233
242
  private removeTextLayer;
234
243
  private removeAllTextLayers;
244
+ toggleSidebar(): void;
245
+ togglePageSelection(pageNum: number): void;
246
+ isPageSelected(pageNum: number): boolean;
247
+ private renderAllThumbnails;
248
+ private renderThumbnail;
235
249
  onContainerScroll(): void;
236
250
  static ɵfac: i0.ɵɵFactoryDeclaration<NgxNextPdfViewerComponent, never>;
237
- 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; }; "page": { "alias": "page"; "required": false; }; }, { "boxClicked": "boxClicked"; "boxesSelected": "boxesSelected"; }, never, never, true, never>;
251
+ 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; }; "page": { "alias": "page"; "required": false; }; "selectPagesEnabled": { "alias": "selectPagesEnabled"; "required": false; }; "selectedPages": { "alias": "selectedPages"; "required": false; }; }, { "boxClicked": "boxClicked"; "boxesSelected": "boxesSelected"; "pagesSelected": "pagesSelected"; }, never, never, true, never>;
238
252
  }
239
253
 
240
254
  /**