@caribeng/ui 22.2.0 → 22.5.0
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 +311 -231
- package/fesm2022/caribeng-ui-accordion.mjs +2 -2
- package/fesm2022/caribeng-ui-account-picker.mjs +533 -0
- package/fesm2022/caribeng-ui-aging.mjs +488 -0
- package/fesm2022/{caribeng-ui-caribe-alert.mjs → caribeng-ui-alert.mjs} +45 -45
- package/fesm2022/caribeng-ui-amount.mjs +249 -0
- package/fesm2022/caribeng-ui-anchor.mjs +2 -2
- package/fesm2022/{caribeng-ui-caribe-animation-lottie.mjs → caribeng-ui-animation-lottie.mjs} +41 -41
- package/fesm2022/caribeng-ui-audit-log.mjs +323 -0
- package/fesm2022/caribeng-ui-avatar.mjs +4 -4
- package/fesm2022/caribeng-ui-badge.mjs +8 -2
- package/fesm2022/caribeng-ui-breadcrumb.mjs +26 -9
- package/fesm2022/{caribeng-ui-caribe-button-group.mjs → caribeng-ui-button-group.mjs} +15 -15
- package/fesm2022/caribeng-ui-button.mjs +2 -2
- package/fesm2022/{caribeng-ui-caribe-card-content.mjs → caribeng-ui-card-content.mjs} +39 -39
- package/fesm2022/{caribeng-ui-caribe-card-move.mjs → caribeng-ui-card-move.mjs} +65 -65
- package/fesm2022/{caribeng-ui-caribe-card-primary.mjs → caribeng-ui-card-primary.mjs} +31 -31
- package/fesm2022/{caribeng-ui-caribe-card-select.mjs → caribeng-ui-card-select.mjs} +67 -67
- package/fesm2022/caribeng-ui-carousel.mjs +2 -2
- package/fesm2022/caribeng-ui-cascadeselect.mjs +45 -9
- package/fesm2022/caribeng-ui-chart.mjs +8 -5
- package/fesm2022/caribeng-ui-chat.mjs +1303 -0
- package/fesm2022/{caribeng-ui-caribe-coachmark.mjs → caribeng-ui-coachmark.mjs} +85 -85
- package/fesm2022/caribeng-ui-code-block.mjs +332 -0
- package/fesm2022/caribeng-ui-colorpicker.mjs +99 -5
- package/fesm2022/caribeng-ui-command-palette.mjs +476 -0
- package/fesm2022/caribeng-ui-comments.mjs +864 -0
- package/fesm2022/caribeng-ui-confirmdialog.mjs +78 -13
- package/fesm2022/caribeng-ui-confirmpopup.mjs +91 -16
- package/fesm2022/caribeng-ui-contextmenu.mjs +8 -4
- package/fesm2022/caribeng-ui-copy-button.mjs +230 -0
- package/fesm2022/caribeng-ui-datagrid.mjs +1635 -0
- package/fesm2022/caribeng-ui-dataview.mjs +6 -3
- package/fesm2022/caribeng-ui-datepicker.mjs +2 -2
- package/fesm2022/caribeng-ui-dock.mjs +52 -12
- package/fesm2022/caribeng-ui-document.mjs +495 -0
- package/fesm2022/{caribeng-ui-caribe-dots-indicator.mjs → caribeng-ui-dots-indicator.mjs} +41 -41
- package/fesm2022/caribeng-ui-drawer.mjs +9 -4
- package/fesm2022/caribeng-ui-dynamic-form.mjs +1581 -0
- package/fesm2022/caribeng-ui-editor.mjs +2324 -1311
- package/fesm2022/{caribeng-ui-caribe-expansion-panel.mjs → caribeng-ui-expansion-panel.mjs} +39 -39
- package/fesm2022/{caribeng-ui-caribe-fab-menu.mjs → caribeng-ui-fab-menu.mjs} +75 -75
- package/fesm2022/caribeng-ui-fieldset.mjs +2 -2
- package/fesm2022/caribeng-ui-file-card.mjs +134 -17
- package/fesm2022/{caribeng-ui-caribe-file-download.mjs → caribeng-ui-file-download.mjs} +63 -63
- package/fesm2022/caribeng-ui-financial-report.mjs +380 -0
- package/fesm2022/{caribeng-ui-caribe-float-menu.mjs → caribeng-ui-float-menu.mjs} +31 -31
- package/fesm2022/caribeng-ui-floatlabel.mjs +2 -2
- package/fesm2022/caribeng-ui-flow.mjs +1508 -0
- package/fesm2022/caribeng-ui-folder-card.mjs +122 -12
- package/fesm2022/{caribeng-ui-caribe-footer.mjs → caribeng-ui-footer.mjs} +19 -19
- package/fesm2022/caribeng-ui-gantt.mjs +1094 -0
- package/fesm2022/{caribeng-ui-caribe-header.mjs → caribeng-ui-header.mjs} +49 -49
- package/fesm2022/{caribeng-ui-caribe-icon-button.mjs → caribeng-ui-icon-button.mjs} +23 -23
- package/fesm2022/caribeng-ui-image-cropper.mjs +671 -0
- package/fesm2022/caribeng-ui-import-wizard.mjs +746 -0
- package/fesm2022/caribeng-ui-infinite-scroll.mjs +226 -0
- package/fesm2022/caribeng-ui-inlinemessage.mjs +2 -2
- package/fesm2022/caribeng-ui-input-number.mjs +22 -6
- package/fesm2022/{caribeng-ui-caribe-input-search.mjs → caribeng-ui-input-search.mjs} +65 -65
- package/fesm2022/{caribeng-ui-caribe-input-token.mjs → caribeng-ui-input-token.mjs} +59 -59
- package/fesm2022/caribeng-ui-inputmask.mjs +8 -2
- package/fesm2022/caribeng-ui-inputotp.mjs +2 -2
- package/fesm2022/caribeng-ui-journal-entry.mjs +340 -0
- package/fesm2022/caribeng-ui-kanban.mjs +4612 -0
- package/fesm2022/caribeng-ui-kbd.mjs +122 -0
- package/fesm2022/caribeng-ui-kpi.mjs +189 -0
- package/fesm2022/{caribeng-ui-caribe-link.mjs → caribeng-ui-link.mjs} +37 -37
- package/fesm2022/caribeng-ui-masonry.mjs +93 -0
- package/fesm2022/caribeng-ui-media-player.mjs +821 -0
- package/fesm2022/caribeng-ui-megamenu.mjs +13 -9
- package/fesm2022/caribeng-ui-mentions.mjs +495 -0
- package/fesm2022/caribeng-ui-menu.mjs +8 -4
- package/fesm2022/caribeng-ui-menubar.mjs +9 -5
- package/fesm2022/caribeng-ui-message.mjs +6 -3
- package/fesm2022/caribeng-ui-notification-center.mjs +636 -0
- package/fesm2022/{caribeng-ui-caribe-off-canvas.mjs → caribeng-ui-off-canvas.mjs} +55 -55
- package/fesm2022/{caribeng-ui-caribe-onboarding.mjs → caribeng-ui-onboarding.mjs} +105 -105
- package/fesm2022/caribeng-ui-orderlist.mjs +2 -2
- package/fesm2022/caribeng-ui-organizationchart.mjs +6 -10
- package/fesm2022/caribeng-ui-panel.mjs +6 -6
- package/fesm2022/caribeng-ui-panelmenu.mjs +9 -6
- package/fesm2022/caribeng-ui-pdfviewer.mjs +1755 -25
- package/fesm2022/caribeng-ui-period-picker.mjs +637 -0
- package/fesm2022/caribeng-ui-phone-input.mjs +688 -0
- package/fesm2022/caribeng-ui-picklist.mjs +2 -2
- package/fesm2022/caribeng-ui-pivot.mjs +419 -0
- package/fesm2022/caribeng-ui-pricing.mjs +263 -69
- package/fesm2022/caribeng-ui-qrcode.mjs +564 -0
- package/fesm2022/caribeng-ui-rating.mjs +14 -17
- package/fesm2022/caribeng-ui-reconciliation.mjs +386 -0
- package/fesm2022/caribeng-ui-ripple.mjs +2 -0
- package/fesm2022/caribeng-ui-scheduler.mjs +1027 -0
- package/fesm2022/caribeng-ui-scrolltop.mjs +3 -1
- package/fesm2022/caribeng-ui-select.mjs +2 -2
- package/fesm2022/{caribeng-ui-caribe-shortcut.mjs → caribeng-ui-shortcut.mjs} +29 -29
- package/fesm2022/caribeng-ui-sidebar.mjs +573 -0
- package/fesm2022/caribeng-ui-signature-pad.mjs +654 -0
- package/fesm2022/{caribeng-ui-caribe-status.mjs → caribeng-ui-status.mjs} +11 -11
- package/fesm2022/{caribeng-ui-caribe-step-indicator.mjs → caribeng-ui-step-indicator.mjs} +53 -53
- package/fesm2022/caribeng-ui-stepper.mjs +12 -5
- package/fesm2022/caribeng-ui-steps.mjs +2 -2
- package/fesm2022/caribeng-ui-table.mjs +333 -19
- package/fesm2022/caribeng-ui-tabmenu.mjs +10 -6
- package/fesm2022/caribeng-ui-tabs.mjs +2 -2
- package/fesm2022/{caribeng-ui-caribe-tag-button.mjs → caribeng-ui-tag-button.mjs} +25 -25
- package/fesm2022/caribeng-ui-tag.mjs +2 -2
- package/fesm2022/caribeng-ui-tieredmenu.mjs +111 -21
- package/fesm2022/{caribeng-ui-caribe-tracker.mjs → caribeng-ui-tracker.mjs} +29 -29
- package/fesm2022/{caribeng-ui-caribe-transaction-status.mjs → caribeng-ui-transaction-status.mjs} +11 -11
- package/fesm2022/caribeng-ui-treeselect.mjs +44 -9
- package/fesm2022/caribeng-ui-treetable.mjs +236 -17
- package/fesm2022/{caribeng-ui-caribe-voucher.mjs → caribeng-ui-voucher.mjs} +45 -45
- package/fesm2022/caribeng-ui-xlsx.mjs +486 -0
- package/fesm2022/caribeng-ui.mjs +1568 -1
- package/package.json +258 -178
- package/schematics/collection.json +5 -0
- package/schematics/migrate-from-primeng/core-icons.json +1 -0
- package/schematics/migrate-from-primeng/icons.js +269 -0
- package/schematics/migrate-from-primeng/index.js +290 -0
- package/schematics/migrate-from-primeng/mappings/button.js +93 -0
- package/schematics/migrate-from-primeng/mappings/card.js +33 -0
- package/schematics/migrate-from-primeng/mappings/checkbox.js +44 -0
- package/schematics/migrate-from-primeng/mappings/confirm.js +221 -0
- package/schematics/migrate-from-primeng/mappings/datepicker.js +121 -0
- package/schematics/migrate-from-primeng/mappings/dialog.js +84 -0
- package/schematics/migrate-from-primeng/mappings/index.js +88 -0
- package/schematics/migrate-from-primeng/mappings/inputnumber.js +62 -0
- package/schematics/migrate-from-primeng/mappings/inputtext.js +60 -0
- package/schematics/migrate-from-primeng/mappings/menu.js +468 -0
- package/schematics/migrate-from-primeng/mappings/multiselect.js +49 -0
- package/schematics/migrate-from-primeng/mappings/radiobutton.js +22 -0
- package/schematics/migrate-from-primeng/mappings/rules.js +206 -0
- package/schematics/migrate-from-primeng/mappings/select.js +97 -0
- package/schematics/migrate-from-primeng/mappings/service-calls.js +100 -0
- package/schematics/migrate-from-primeng/mappings/table.js +613 -0
- package/schematics/migrate-from-primeng/mappings/tabs.js +225 -0
- package/schematics/migrate-from-primeng/mappings/tag.js +29 -0
- package/schematics/migrate-from-primeng/mappings/textarea.js +44 -0
- package/schematics/migrate-from-primeng/mappings/toast.js +173 -0
- package/schematics/migrate-from-primeng/mappings/toggleswitch.js +37 -0
- package/schematics/migrate-from-primeng/mappings/tooltip.js +44 -0
- package/schematics/migrate-from-primeng/mappings/types.js +10 -0
- package/schematics/migrate-from-primeng/report.js +79 -0
- package/schematics/migrate-from-primeng/schema.js +2 -0
- package/schematics/migrate-from-primeng/schema.json +34 -0
- package/schematics/migrate-from-primeng/template.js +387 -0
- package/schematics/migrate-from-primeng/todo.js +5 -0
- package/schematics/migrate-from-primeng/typescript.js +442 -0
- package/schematics/migrate-from-primeng/workspace.js +117 -0
- package/schematics/ng-add/index.js +16 -1
- package/types/caribeng-ui-account-picker.d.ts +142 -0
- package/types/caribeng-ui-aging.d.ts +123 -0
- package/types/{caribeng-ui-caribe-alert.d.ts → caribeng-ui-alert.d.ts} +2 -2
- package/types/caribeng-ui-amount.d.ts +82 -0
- package/types/{caribeng-ui-caribe-animation-lottie.d.ts → caribeng-ui-animation-lottie.d.ts} +2 -2
- package/types/caribeng-ui-audit-log.d.ts +86 -0
- package/types/caribeng-ui-badge.d.ts +3 -1
- package/types/caribeng-ui-breadcrumb.d.ts +9 -1
- package/types/{caribeng-ui-caribe-button-group.d.ts → caribeng-ui-button-group.d.ts} +2 -2
- package/types/{caribeng-ui-caribe-card-content.d.ts → caribeng-ui-card-content.d.ts} +2 -2
- package/types/{caribeng-ui-caribe-card-move.d.ts → caribeng-ui-card-move.d.ts} +1 -1
- package/types/{caribeng-ui-caribe-card-primary.d.ts → caribeng-ui-card-primary.d.ts} +2 -2
- package/types/{caribeng-ui-caribe-card-select.d.ts → caribeng-ui-card-select.d.ts} +2 -2
- package/types/caribeng-ui-cascadeselect.d.ts +6 -0
- package/types/caribeng-ui-chart.d.ts +3 -1
- package/types/caribeng-ui-chat.d.ts +299 -0
- package/types/{caribeng-ui-caribe-coachmark.d.ts → caribeng-ui-coachmark.d.ts} +2 -2
- package/types/caribeng-ui-code-block.d.ts +65 -0
- package/types/caribeng-ui-colorpicker.d.ts +5 -1
- package/types/caribeng-ui-command-palette.d.ts +133 -0
- package/types/caribeng-ui-comments.d.ts +214 -0
- package/types/caribeng-ui-confirmdialog.d.ts +34 -2
- package/types/caribeng-ui-confirmpopup.d.ts +39 -2
- package/types/caribeng-ui-contextmenu.d.ts +7 -0
- package/types/caribeng-ui-copy-button.d.ts +90 -0
- package/types/caribeng-ui-datagrid.d.ts +269 -0
- package/types/caribeng-ui-dataview.d.ts +2 -0
- package/types/caribeng-ui-dock.d.ts +13 -1
- package/types/caribeng-ui-document.d.ts +138 -0
- package/types/{caribeng-ui-caribe-dots-indicator.d.ts → caribeng-ui-dots-indicator.d.ts} +2 -2
- package/types/caribeng-ui-drawer.d.ts +3 -1
- package/types/caribeng-ui-dynamic-form.d.ts +409 -0
- package/types/caribeng-ui-editor.d.ts +110 -12
- package/types/{caribeng-ui-caribe-expansion-panel.d.ts → caribeng-ui-expansion-panel.d.ts} +1 -1
- package/types/{caribeng-ui-caribe-fab-menu.d.ts → caribeng-ui-fab-menu.d.ts} +2 -2
- package/types/caribeng-ui-file-card.d.ts +27 -2
- package/types/{caribeng-ui-caribe-file-download.d.ts → caribeng-ui-file-download.d.ts} +1 -1
- package/types/caribeng-ui-financial-report.d.ts +102 -0
- package/types/{caribeng-ui-caribe-float-menu.d.ts → caribeng-ui-float-menu.d.ts} +2 -2
- package/types/caribeng-ui-flow.d.ts +228 -0
- package/types/caribeng-ui-folder-card.d.ts +27 -5
- package/types/{caribeng-ui-caribe-footer.d.ts → caribeng-ui-footer.d.ts} +2 -2
- package/types/caribeng-ui-gantt.d.ts +244 -0
- package/types/{caribeng-ui-caribe-header.d.ts → caribeng-ui-header.d.ts} +2 -2
- package/types/{caribeng-ui-caribe-icon-button.d.ts → caribeng-ui-icon-button.d.ts} +2 -2
- package/types/{caribeng-ui-caribe-illustration.d.ts → caribeng-ui-illustration.d.ts} +1 -1
- package/types/caribeng-ui-image-cropper.d.ts +169 -0
- package/types/caribeng-ui-import-wizard.d.ts +149 -0
- package/types/caribeng-ui-infinite-scroll.d.ts +75 -0
- package/types/caribeng-ui-input-number.d.ts +1 -1
- package/types/{caribeng-ui-caribe-input-search.d.ts → caribeng-ui-input-search.d.ts} +2 -2
- package/types/{caribeng-ui-caribe-input-token.d.ts → caribeng-ui-input-token.d.ts} +2 -2
- package/types/caribeng-ui-inputmask.d.ts +3 -1
- package/types/caribeng-ui-journal-entry.d.ts +110 -0
- package/types/caribeng-ui-kanban.d.ts +783 -0
- package/types/caribeng-ui-kbd.d.ts +36 -0
- package/types/caribeng-ui-kpi.d.ts +64 -0
- package/types/{caribeng-ui-caribe-link.d.ts → caribeng-ui-link.d.ts} +2 -2
- package/types/{caribeng-ui-caribe-logo.d.ts → caribeng-ui-logo.d.ts} +1 -1
- package/types/caribeng-ui-masonry.d.ts +32 -0
- package/types/caribeng-ui-media-player.d.ts +140 -0
- package/types/caribeng-ui-megamenu.d.ts +11 -0
- package/types/caribeng-ui-mentions.d.ts +127 -0
- package/types/caribeng-ui-menu.d.ts +7 -0
- package/types/caribeng-ui-menubar.d.ts +7 -0
- package/types/caribeng-ui-message.d.ts +2 -0
- package/types/caribeng-ui-notification-center.d.ts +153 -0
- package/types/{caribeng-ui-caribe-off-canvas.d.ts → caribeng-ui-off-canvas.d.ts} +2 -2
- package/types/{caribeng-ui-caribe-onboarding.d.ts → caribeng-ui-onboarding.d.ts} +2 -2
- package/types/caribeng-ui-panelmenu.d.ts +7 -0
- package/types/caribeng-ui-pdfviewer.d.ts +245 -5
- package/types/caribeng-ui-period-picker.d.ts +148 -0
- package/types/caribeng-ui-phone-input.d.ts +168 -0
- package/types/caribeng-ui-pivot.d.ts +116 -0
- package/types/caribeng-ui-pricing.d.ts +41 -4
- package/types/caribeng-ui-qrcode.d.ts +88 -0
- package/types/caribeng-ui-reconciliation.d.ts +109 -0
- package/types/caribeng-ui-scheduler.d.ts +188 -0
- package/types/{caribeng-ui-caribe-shortcut.d.ts → caribeng-ui-shortcut.d.ts} +2 -2
- package/types/caribeng-ui-sidebar.d.ts +167 -0
- package/types/caribeng-ui-signature-pad.d.ts +151 -0
- package/types/{caribeng-ui-caribe-status.d.ts → caribeng-ui-status.d.ts} +2 -2
- package/types/{caribeng-ui-caribe-step-indicator.d.ts → caribeng-ui-step-indicator.d.ts} +2 -2
- package/types/caribeng-ui-stepper.d.ts +2 -0
- package/types/caribeng-ui-table.d.ts +67 -3
- package/types/caribeng-ui-tabmenu.d.ts +7 -0
- package/types/{caribeng-ui-caribe-tag-button.d.ts → caribeng-ui-tag-button.d.ts} +2 -2
- package/types/caribeng-ui-tieredmenu.d.ts +17 -1
- package/types/{caribeng-ui-caribe-tracker.d.ts → caribeng-ui-tracker.d.ts} +2 -2
- package/types/{caribeng-ui-caribe-transaction-status.d.ts → caribeng-ui-transaction-status.d.ts} +2 -2
- package/types/caribeng-ui-treeselect.d.ts +6 -0
- package/types/caribeng-ui-treetable.d.ts +67 -2
- package/types/{caribeng-ui-caribe-voucher.d.ts → caribeng-ui-voucher.d.ts} +2 -2
- package/types/caribeng-ui-xlsx.d.ts +79 -0
- package/types/caribeng-ui.d.ts +985 -2
- package/fesm2022/caribeng-ui-caribe-calendar.mjs +0 -92
- package/fesm2022/caribeng-ui-caribe-circle-loading.mjs +0 -130
- package/fesm2022/caribeng-ui-caribe-data-table.mjs +0 -94
- package/fesm2022/caribeng-ui-caribe-file-select.mjs +0 -88
- package/fesm2022/caribeng-ui-caribe-inline-alert.mjs +0 -100
- package/fesm2022/caribeng-ui-caribe-input-date.mjs +0 -138
- package/fesm2022/caribeng-ui-caribe-input-select.mjs +0 -154
- package/fesm2022/caribeng-ui-caribe-loader.mjs +0 -48
- package/fesm2022/caribeng-ui-caribe-modal.mjs +0 -119
- package/fesm2022/caribeng-ui-caribe-pictogram.mjs +0 -52
- package/fesm2022/caribeng-ui-caribe-pop-over.mjs +0 -104
- package/fesm2022/caribeng-ui-caribe-preloader.mjs +0 -57
- package/fesm2022/caribeng-ui-caribe-progress-bar.mjs +0 -84
- package/fesm2022/caribeng-ui-caribe-stroke.mjs +0 -69
- package/fesm2022/caribeng-ui-caribe-switch.mjs +0 -182
- package/styles/caribeng.css +0 -380
- package/styles/scss/_mixins.scss +0 -46
- package/styles/scss/_overlay.scss +0 -15
- package/styles/scss/_tokens.scss +0 -267
- package/styles/scss/_utilities.scss +0 -73
- package/styles/scss/_variables.scss +0 -33
- package/styles/scss/index.scss +0 -16
- package/types/caribeng-ui-caribe-calendar.d.ts +0 -27
- package/types/caribeng-ui-caribe-circle-loading.d.ts +0 -28
- package/types/caribeng-ui-caribe-data-table.d.ts +0 -26
- package/types/caribeng-ui-caribe-file-select.d.ts +0 -31
- package/types/caribeng-ui-caribe-inline-alert.d.ts +0 -28
- package/types/caribeng-ui-caribe-input-date.d.ts +0 -40
- package/types/caribeng-ui-caribe-input-select.d.ts +0 -47
- package/types/caribeng-ui-caribe-loader.d.ts +0 -22
- package/types/caribeng-ui-caribe-modal.d.ts +0 -21
- package/types/caribeng-ui-caribe-pictogram.d.ts +0 -15
- package/types/caribeng-ui-caribe-pop-over.d.ts +0 -17
- package/types/caribeng-ui-caribe-preloader.d.ts +0 -24
- package/types/caribeng-ui-caribe-progress-bar.d.ts +0 -28
- package/types/caribeng-ui-caribe-stroke.d.ts +0 -17
- package/types/caribeng-ui-caribe-switch.d.ts +0 -55
- /package/fesm2022/{caribeng-ui-caribe-illustration.mjs → caribeng-ui-illustration.mjs} +0 -0
- /package/fesm2022/{caribeng-ui-caribe-logo.mjs → caribeng-ui-logo.mjs} +0 -0
|
@@ -1,11 +1,337 @@
|
|
|
1
|
-
import { DOCUMENT, isPlatformBrowser } from '@angular/common';
|
|
1
|
+
import { DOCUMENT, isPlatformBrowser, NgTemplateOutlet } from '@angular/common';
|
|
2
2
|
import * as i0 from '@angular/core';
|
|
3
|
-
import { InjectionToken, makeEnvironmentProviders, inject, Injectable, input, booleanAttribute, model, output, Injector, PLATFORM_ID, signal, viewChild, viewChildren, computed, effect, untracked, afterNextRender, DestroyRef, isDevMode, ViewEncapsulation, ChangeDetectionStrategy, Component } from '@angular/core';
|
|
3
|
+
import { InjectionToken, makeEnvironmentProviders, inject, Injectable, input, booleanAttribute, model, output, Injector, ElementRef, PLATFORM_ID, signal, viewChild, viewChildren, computed, effect, untracked, afterNextRender, DestroyRef, isDevMode, ViewEncapsulation, ChangeDetectionStrategy, Component } from '@angular/core';
|
|
4
4
|
import { injectCbTranslation, cbFormat } from '@caribeng/ui';
|
|
5
|
+
import { CbDialog } from '@caribeng/ui/dialog';
|
|
5
6
|
import { CbIconRegistry, CbIcon } from '@caribeng/ui/icon';
|
|
6
|
-
import { panelLeft, printer, zoomOut, zoomIn } from '@caribeng/ui/icons';
|
|
7
|
+
import { signature, penLine, stickyNote, highlighter, panelLeft, printer, zoomOut, zoomIn } from '@caribeng/ui/icons';
|
|
8
|
+
import { CbSignaturePad } from '@caribeng/ui/signature-pad';
|
|
7
9
|
import { CbSpinner } from '@caribeng/ui/spinner';
|
|
8
10
|
|
|
11
|
+
const CB_PDF_COLORS = {
|
|
12
|
+
yellow: { light: '#fde047', dark: '#a16207' },
|
|
13
|
+
green: { light: '#86efac', dark: '#15803d' },
|
|
14
|
+
blue: { light: '#93c5fd', dark: '#1d4ed8' },
|
|
15
|
+
red: { light: '#fca5a5', dark: '#b91c1c' },
|
|
16
|
+
};
|
|
17
|
+
/** Punto PDF → píxeles CSS dentro de la página dibujada. */
|
|
18
|
+
function pdfToView(geom, view, x, y) {
|
|
19
|
+
const f = view.factor;
|
|
20
|
+
const u = (x - geom.x0) * geom.userUnit * f;
|
|
21
|
+
const v = (geom.height - (y - geom.y0) * geom.userUnit) * f;
|
|
22
|
+
const w = geom.width * f;
|
|
23
|
+
const h = geom.height * f;
|
|
24
|
+
switch (normalize(view.rotation)) {
|
|
25
|
+
case 90:
|
|
26
|
+
return [h - v, u];
|
|
27
|
+
case 180:
|
|
28
|
+
return [w - u, h - v];
|
|
29
|
+
case 270:
|
|
30
|
+
return [v, w - u];
|
|
31
|
+
default:
|
|
32
|
+
return [u, v];
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
/** Píxeles CSS dentro de la página dibujada → punto PDF. */
|
|
36
|
+
function viewToPdf(geom, view, px, py) {
|
|
37
|
+
const f = view.factor;
|
|
38
|
+
const w = geom.width * f;
|
|
39
|
+
const h = geom.height * f;
|
|
40
|
+
let u;
|
|
41
|
+
let v;
|
|
42
|
+
switch (normalize(view.rotation)) {
|
|
43
|
+
case 90:
|
|
44
|
+
[u, v] = [py, h - px];
|
|
45
|
+
break;
|
|
46
|
+
case 180:
|
|
47
|
+
[u, v] = [w - px, h - py];
|
|
48
|
+
break;
|
|
49
|
+
case 270:
|
|
50
|
+
[u, v] = [w - py, px];
|
|
51
|
+
break;
|
|
52
|
+
default:
|
|
53
|
+
[u, v] = [px, py];
|
|
54
|
+
}
|
|
55
|
+
return [geom.x0 + u / (geom.userUnit * f), geom.y0 + (geom.height - v / f) / geom.userUnit];
|
|
56
|
+
}
|
|
57
|
+
/** Rectángulo PDF → caja CSS (`left`, `top`, `width`, `height`) en la página dibujada. */
|
|
58
|
+
function rectToView(geom, view, rect) {
|
|
59
|
+
const [ax, ay] = pdfToView(geom, view, rect[0], rect[1]);
|
|
60
|
+
const [bx, by] = pdfToView(geom, view, rect[2], rect[3]);
|
|
61
|
+
return { left: Math.min(ax, bx), top: Math.min(ay, by), width: Math.abs(bx - ax), height: Math.abs(by - ay) };
|
|
62
|
+
}
|
|
63
|
+
/** Caja CSS en la página dibujada → rectángulo PDF normalizado (x1 < x2, y1 < y2). */
|
|
64
|
+
function viewToRect(geom, view, left, top, width, height) {
|
|
65
|
+
const [ax, ay] = viewToPdf(geom, view, left, top);
|
|
66
|
+
const [bx, by] = viewToPdf(geom, view, left + width, top + height);
|
|
67
|
+
return [round(Math.min(ax, bx)), round(Math.min(ay, by)), round(Math.max(ax, bx)), round(Math.max(ay, by))];
|
|
68
|
+
}
|
|
69
|
+
/** Desplaza un rectángulo `dx`, `dy` puntos sin salirse de la página. */
|
|
70
|
+
function moveRect(geom, rect, dx, dy) {
|
|
71
|
+
const w = rect[2] - rect[0];
|
|
72
|
+
const h = rect[3] - rect[1];
|
|
73
|
+
const maxX = geom.x0 + geom.width / geom.userUnit - w;
|
|
74
|
+
const maxY = geom.y0 + geom.height / geom.userUnit - h;
|
|
75
|
+
const x = clamp$1(rect[0] + dx, geom.x0, Math.max(geom.x0, maxX));
|
|
76
|
+
const y = clamp$1(rect[1] + dy, geom.y0, Math.max(geom.y0, maxY));
|
|
77
|
+
return [round(x), round(y), round(x + w), round(y + h)];
|
|
78
|
+
}
|
|
79
|
+
/** Escala un rectángulo desde su esquina superior izquierda (en el PDF, x1 e y2 se quedan). */
|
|
80
|
+
function scaleRect(rect, factor, minWidth = 24) {
|
|
81
|
+
const w = rect[2] - rect[0];
|
|
82
|
+
const h = rect[3] - rect[1];
|
|
83
|
+
const k = Math.max(factor, minWidth / Math.max(1, w));
|
|
84
|
+
return [rect[0], round(rect[3] - h * k), round(rect[0] + w * k), rect[3]];
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Une los rectángulos de una selección de texto (`getClientRects()`, ya relativos a la página) en
|
|
88
|
+
* uno por línea: los que se solapan en vertical y se tocan en horizontal.
|
|
89
|
+
*/
|
|
90
|
+
function mergeLineRects(rects) {
|
|
91
|
+
const sorted = rects.filter((r) => r.width > 0.5 && r.height > 0.5).sort((a, b) => a.top - b.top || a.left - b.left);
|
|
92
|
+
const lines = [];
|
|
93
|
+
for (const r of sorted) {
|
|
94
|
+
const right = r.left + r.width;
|
|
95
|
+
const bottom = r.top + r.height;
|
|
96
|
+
const line = lines.find((l) => {
|
|
97
|
+
const overlap = Math.min(l.bottom, bottom) - Math.max(l.top, r.top);
|
|
98
|
+
return overlap > Math.min(l.bottom - l.top, r.height) / 2 && r.left <= l.right + r.height && right >= l.left - r.height;
|
|
99
|
+
});
|
|
100
|
+
if (line) {
|
|
101
|
+
line.left = Math.min(line.left, r.left);
|
|
102
|
+
line.top = Math.min(line.top, r.top);
|
|
103
|
+
line.right = Math.max(line.right, right);
|
|
104
|
+
line.bottom = Math.max(line.bottom, bottom);
|
|
105
|
+
}
|
|
106
|
+
else {
|
|
107
|
+
lines.push({ left: r.left, top: r.top, right, bottom });
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
return lines.map((l) => ({ left: l.left, top: l.top, width: l.right - l.left, height: l.bottom - l.top }));
|
|
111
|
+
}
|
|
112
|
+
/** Rectángulo que contiene a todos. */
|
|
113
|
+
function boundsOf(rects) {
|
|
114
|
+
return [
|
|
115
|
+
Math.min(...rects.map((r) => r[0])),
|
|
116
|
+
Math.min(...rects.map((r) => r[1])),
|
|
117
|
+
Math.max(...rects.map((r) => r[2])),
|
|
118
|
+
Math.max(...rects.map((r) => r[3])),
|
|
119
|
+
];
|
|
120
|
+
}
|
|
121
|
+
/** Caja de un dibujo, con medio grosor de margen. */
|
|
122
|
+
function inkBounds(ink) {
|
|
123
|
+
const xs = [];
|
|
124
|
+
const ys = [];
|
|
125
|
+
for (const path of ink.paths) {
|
|
126
|
+
for (let i = 0; i + 1 < path.length; i += 2) {
|
|
127
|
+
xs.push(path[i]);
|
|
128
|
+
ys.push(path[i + 1]);
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
const m = ink.thickness / 2 + 1;
|
|
132
|
+
return [round(Math.min(...xs) - m), round(Math.min(...ys) - m), round(Math.max(...xs) + m), round(Math.max(...ys) + m)];
|
|
133
|
+
}
|
|
134
|
+
/** Quita puntos casi alineados de un trazo (Ramer–Douglas–Peucker), con tolerancia en las mismas unidades. */
|
|
135
|
+
function simplifyPath(points, tolerance) {
|
|
136
|
+
if (points.length <= 4)
|
|
137
|
+
return [...points];
|
|
138
|
+
const n = points.length / 2;
|
|
139
|
+
const keep = new Uint8Array(n);
|
|
140
|
+
keep[0] = keep[n - 1] = 1;
|
|
141
|
+
const stack = [[0, n - 1]];
|
|
142
|
+
while (stack.length) {
|
|
143
|
+
const [a, b] = stack.pop();
|
|
144
|
+
const [ax, ay, bx, by] = [points[a * 2], points[a * 2 + 1], points[b * 2], points[b * 2 + 1]];
|
|
145
|
+
const len = Math.hypot(bx - ax, by - ay) || 1;
|
|
146
|
+
let max = 0;
|
|
147
|
+
let at = -1;
|
|
148
|
+
for (let i = a + 1; i < b; i++) {
|
|
149
|
+
const d = Math.abs((by - ay) * points[i * 2] - (bx - ax) * points[i * 2 + 1] + bx * ay - by * ax) / len;
|
|
150
|
+
if (d > max)
|
|
151
|
+
[max, at] = [d, i];
|
|
152
|
+
}
|
|
153
|
+
if (at !== -1 && max > tolerance) {
|
|
154
|
+
keep[at] = 1;
|
|
155
|
+
stack.push([a, at], [at, b]);
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
const out = [];
|
|
159
|
+
for (let i = 0; i < n; i++)
|
|
160
|
+
if (keep[i])
|
|
161
|
+
out.push(points[i * 2], points[i * 2 + 1]);
|
|
162
|
+
return out;
|
|
163
|
+
}
|
|
164
|
+
/** Prefijo que pdf.js reconoce como anotación nueva al guardar o imprimir. */
|
|
165
|
+
const PDFJS_EDITOR_PREFIX = 'pdfjs_internal_editor_';
|
|
166
|
+
/** Tipos de anotación nueva de pdf.js (`AnnotationEditorType`). */
|
|
167
|
+
const EDITOR_TYPE = { freeText: 3, highlight: 9, stamp: 13, ink: 15 };
|
|
168
|
+
/**
|
|
169
|
+
* La anotación en el formato que pdf.js escribe en el PDF al guardar (`saveDocument`) o imprimir.
|
|
170
|
+
* La firma necesita su imagen como `ImageBitmap` (`bitmap`): pdf.js la transfiere al worker, así
|
|
171
|
+
* que hay que crear una nueva cada vez.
|
|
172
|
+
*/
|
|
173
|
+
function toPdfJsAnnotation(annotation, pageRotation, bitmap) {
|
|
174
|
+
const base = {
|
|
175
|
+
pageIndex: annotation.page - 1,
|
|
176
|
+
rotation: normalize(pageRotation),
|
|
177
|
+
user: annotation.author || undefined,
|
|
178
|
+
date: annotation.date ? new Date(annotation.date) : new Date(),
|
|
179
|
+
structTreeParentId: null,
|
|
180
|
+
};
|
|
181
|
+
switch (annotation.type) {
|
|
182
|
+
case 'highlight': {
|
|
183
|
+
if (!annotation.rects.length)
|
|
184
|
+
return null;
|
|
185
|
+
const rect = boundsOf(annotation.rects);
|
|
186
|
+
return {
|
|
187
|
+
...base,
|
|
188
|
+
annotationType: EDITOR_TYPE.highlight,
|
|
189
|
+
color: hexToRgb(CB_PDF_COLORS[annotation.color].light),
|
|
190
|
+
opacity: 1,
|
|
191
|
+
rect,
|
|
192
|
+
quadPoints: annotation.rects.flatMap(([x1, y1, x2, y2]) => [x1, y2, x2, y2, x1, y1, x2, y1]),
|
|
193
|
+
outlines: annotation.rects.map(([x1, y1, x2, y2]) => [x1, y1, x2, y1, x2, y2, x1, y2]),
|
|
194
|
+
popup: annotation.comment ? { contents: annotation.comment, rect: [rect[2], rect[3] - 60, rect[2] + 160, rect[3]] } : undefined,
|
|
195
|
+
};
|
|
196
|
+
}
|
|
197
|
+
case 'note':
|
|
198
|
+
return {
|
|
199
|
+
...base,
|
|
200
|
+
annotationType: EDITOR_TYPE.freeText,
|
|
201
|
+
color: hexToRgb(CB_PDF_COLORS[annotation.color].dark),
|
|
202
|
+
fontSize: annotation.fontSize ?? 12,
|
|
203
|
+
value: annotation.text,
|
|
204
|
+
rect: [...annotation.rect],
|
|
205
|
+
};
|
|
206
|
+
case 'ink': {
|
|
207
|
+
const paths = annotation.paths.filter((p) => p.length >= 2);
|
|
208
|
+
if (!paths.length)
|
|
209
|
+
return null;
|
|
210
|
+
return {
|
|
211
|
+
...base,
|
|
212
|
+
annotationType: EDITOR_TYPE.ink,
|
|
213
|
+
color: hexToRgb(CB_PDF_COLORS[annotation.color].dark),
|
|
214
|
+
thickness: annotation.thickness,
|
|
215
|
+
opacity: 1,
|
|
216
|
+
rect: [...inkBounds({ paths, thickness: annotation.thickness })],
|
|
217
|
+
// pdf.js escribe cada trazo como segmentos: NaN×4 indica "línea recta hasta x, y".
|
|
218
|
+
paths: {
|
|
219
|
+
lines: paths.map((p) => {
|
|
220
|
+
const line = [Number.NaN, Number.NaN, Number.NaN, Number.NaN, p[0], p[1]];
|
|
221
|
+
for (let i = 2; i + 1 < p.length; i += 2)
|
|
222
|
+
line.push(Number.NaN, Number.NaN, Number.NaN, Number.NaN, p[i], p[i + 1]);
|
|
223
|
+
return line;
|
|
224
|
+
}),
|
|
225
|
+
points: paths.map((p) => [...p]),
|
|
226
|
+
},
|
|
227
|
+
};
|
|
228
|
+
}
|
|
229
|
+
case 'signature':
|
|
230
|
+
if (!bitmap)
|
|
231
|
+
return null;
|
|
232
|
+
return {
|
|
233
|
+
...base,
|
|
234
|
+
annotationType: EDITOR_TYPE.stamp,
|
|
235
|
+
bitmapId: `cb_sig_${annotation.id}`,
|
|
236
|
+
bitmap,
|
|
237
|
+
isSvg: false,
|
|
238
|
+
rect: [...annotation.rect],
|
|
239
|
+
};
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
/**
|
|
243
|
+
* Recorta el margen transparente de una firma (el área de `cb-signature-pad` suele estar casi
|
|
244
|
+
* vacía) y da su tamaño en píxeles. Sin canvas, la devuelve tal cual.
|
|
245
|
+
*/
|
|
246
|
+
async function trimSignature(dataUrl, doc) {
|
|
247
|
+
const img = await loadImage(dataUrl, doc);
|
|
248
|
+
const fallback = { url: dataUrl, width: img?.naturalWidth || 300, height: img?.naturalHeight || 100 };
|
|
249
|
+
if (!img?.naturalWidth)
|
|
250
|
+
return fallback;
|
|
251
|
+
const canvas = doc.createElement('canvas');
|
|
252
|
+
canvas.width = img.naturalWidth;
|
|
253
|
+
canvas.height = img.naturalHeight;
|
|
254
|
+
let ctx = null;
|
|
255
|
+
try {
|
|
256
|
+
ctx = canvas.getContext('2d', { willReadFrequently: true });
|
|
257
|
+
}
|
|
258
|
+
catch {
|
|
259
|
+
ctx = null;
|
|
260
|
+
}
|
|
261
|
+
if (!ctx)
|
|
262
|
+
return fallback;
|
|
263
|
+
ctx.drawImage(img, 0, 0);
|
|
264
|
+
const { data, width, height } = ctx.getImageData(0, 0, canvas.width, canvas.height);
|
|
265
|
+
let [minX, minY, maxX, maxY] = [width, height, -1, -1];
|
|
266
|
+
for (let y = 0; y < height; y++) {
|
|
267
|
+
for (let x = 0; x < width; x++) {
|
|
268
|
+
if (data[(y * width + x) * 4 + 3] > 16) {
|
|
269
|
+
if (x < minX)
|
|
270
|
+
minX = x;
|
|
271
|
+
if (x > maxX)
|
|
272
|
+
maxX = x;
|
|
273
|
+
if (y < minY)
|
|
274
|
+
minY = y;
|
|
275
|
+
if (y > maxY)
|
|
276
|
+
maxY = y;
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
if (maxX < 0)
|
|
281
|
+
return fallback;
|
|
282
|
+
const pad = 4;
|
|
283
|
+
const x = Math.max(0, minX - pad);
|
|
284
|
+
const y = Math.max(0, minY - pad);
|
|
285
|
+
const w = Math.min(width, maxX + pad + 1) - x;
|
|
286
|
+
const h = Math.min(height, maxY + pad + 1) - y;
|
|
287
|
+
const out = doc.createElement('canvas');
|
|
288
|
+
out.width = w;
|
|
289
|
+
out.height = h;
|
|
290
|
+
out.getContext('2d')?.drawImage(canvas, x, y, w, h, 0, 0, w, h);
|
|
291
|
+
return { url: out.toDataURL('image/png'), width: w, height: h };
|
|
292
|
+
}
|
|
293
|
+
/** La imagen de una firma como `ImageBitmap`, para que pdf.js la escriba en el PDF. */
|
|
294
|
+
async function imageToBitmap(dataUrl) {
|
|
295
|
+
if (typeof createImageBitmap !== 'function')
|
|
296
|
+
return undefined;
|
|
297
|
+
try {
|
|
298
|
+
const blob = await (await fetch(dataUrl)).blob();
|
|
299
|
+
return await createImageBitmap(blob);
|
|
300
|
+
}
|
|
301
|
+
catch {
|
|
302
|
+
return undefined;
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
function loadImage(src, doc) {
|
|
306
|
+
return new Promise((resolve) => {
|
|
307
|
+
const img = doc.createElement('img');
|
|
308
|
+
const timer = setTimeout(() => resolve(null), 3000);
|
|
309
|
+
img.onload = () => {
|
|
310
|
+
clearTimeout(timer);
|
|
311
|
+
resolve(img);
|
|
312
|
+
};
|
|
313
|
+
img.onerror = () => {
|
|
314
|
+
clearTimeout(timer);
|
|
315
|
+
resolve(null);
|
|
316
|
+
};
|
|
317
|
+
img.src = src;
|
|
318
|
+
});
|
|
319
|
+
}
|
|
320
|
+
/** `#rrggbb` → `[r, g, b]` (0–255), como los colores de pdf.js. */
|
|
321
|
+
function hexToRgb(hex) {
|
|
322
|
+
const m = /^#?([\da-f]{2})([\da-f]{2})([\da-f]{2})$/i.exec(hex);
|
|
323
|
+
return m ? [parseInt(m[1], 16), parseInt(m[2], 16), parseInt(m[3], 16)] : [0, 0, 0];
|
|
324
|
+
}
|
|
325
|
+
function normalize(rotation) {
|
|
326
|
+
return ((Math.round(rotation / 90) * 90) % 360 + 360) % 360;
|
|
327
|
+
}
|
|
328
|
+
function clamp$1(value, min, max) {
|
|
329
|
+
return Math.min(max, Math.max(min, value));
|
|
330
|
+
}
|
|
331
|
+
function round(value) {
|
|
332
|
+
return Math.round(value * 100) / 100;
|
|
333
|
+
}
|
|
334
|
+
|
|
9
335
|
const CB_PDF_VIEWER_OPTIONS = new InjectionToken('CB_PDF_VIEWER_OPTIONS');
|
|
10
336
|
/**
|
|
11
337
|
* Configura el visor de PDF (worker, recursos y carga de pdf.js).
|
|
@@ -79,8 +405,11 @@ const PRINT_DPI = 150;
|
|
|
79
405
|
* Imprime el documento: rasteriza cada página a {@link PRINT_DPI} ppp en un
|
|
80
406
|
* `<iframe>` oculto y abre el diálogo de impresión del navegador (así se
|
|
81
407
|
* imprime el PDF y no la página de la aplicación).
|
|
408
|
+
*
|
|
409
|
+
* `printStorage` es una copia de los campos y anotaciones nuevas (`annotationStorage.print`): se
|
|
410
|
+
* toma una vez para todas las páginas, porque al copiarla pdf.js transfiere las imágenes al worker.
|
|
82
411
|
*/
|
|
83
|
-
async function printPdfDocument(pdf, document, onProgress, rotation = 0) {
|
|
412
|
+
async function printPdfDocument(pdf, document, onProgress, rotation = 0, printStorage = pdf.annotationStorage.print) {
|
|
84
413
|
const urls = [];
|
|
85
414
|
const frame = document.createElement('iframe');
|
|
86
415
|
frame.setAttribute('aria-hidden', 'true');
|
|
@@ -96,7 +425,8 @@ async function printPdfDocument(pdf, document, onProgress, rotation = 0) {
|
|
|
96
425
|
const canvas = document.createElement('canvas');
|
|
97
426
|
canvas.width = Math.floor(viewport.width);
|
|
98
427
|
canvas.height = Math.floor(viewport.height);
|
|
99
|
-
|
|
428
|
+
// AnnotationMode.ENABLE_STORAGE (3): los campos se imprimen con lo escrito y con las anotaciones nuevas.
|
|
429
|
+
await page.render({ canvas, viewport, intent: 'print', annotationMode: 3, printAnnotationStorage: printStorage }).promise;
|
|
100
430
|
const blob = await new Promise((resolve) => canvas.toBlob(resolve, 'image/png'));
|
|
101
431
|
if (blob)
|
|
102
432
|
urls.push(URL.createObjectURL(blob));
|
|
@@ -245,11 +575,18 @@ const PAGE_GAP = 16;
|
|
|
245
575
|
/** Píxeles máximos de un canvas (evita agotar la memoria en zoom alto). */
|
|
246
576
|
const MAX_CANVAS_PIXELS = 2 ** 24;
|
|
247
577
|
const THUMB_WIDTH = 112;
|
|
578
|
+
let nextAnnotationId = 0;
|
|
579
|
+
/** Esquemas que se abren desde los enlaces del documento. */
|
|
580
|
+
const SAFE_URL = /^(https?:|mailto:|tel:)/i;
|
|
248
581
|
const PDF_ICONS = {
|
|
249
582
|
'zoom-in': zoomIn,
|
|
250
583
|
'zoom-out': zoomOut,
|
|
251
584
|
printer,
|
|
252
585
|
'panel-left': panelLeft,
|
|
586
|
+
highlighter,
|
|
587
|
+
'sticky-note': stickyNote,
|
|
588
|
+
'pen-line': penLine,
|
|
589
|
+
signature,
|
|
253
590
|
};
|
|
254
591
|
/**
|
|
255
592
|
* Visor de PDF sobre [pdf.js](https://mozilla.github.io/pdf.js/) (`pdfjs-dist`,
|
|
@@ -257,7 +594,9 @@ const PDF_ICONS = {
|
|
|
257
594
|
*
|
|
258
595
|
* Renderiza las páginas a medida que se ven, con texto seleccionable y
|
|
259
596
|
* legible por lectores de pantalla, búsqueda (ignora tildes y mayúsculas),
|
|
260
|
-
* miniaturas,
|
|
597
|
+
* miniaturas, índice (marcadores), enlaces internos y externos, formularios
|
|
598
|
+
* rellenables (se descargan e imprimen con lo escrito), zoom, giro, descarga,
|
|
599
|
+
* impresión y documentos con contraseña.
|
|
261
600
|
*
|
|
262
601
|
* @example
|
|
263
602
|
* ```html
|
|
@@ -299,16 +638,49 @@ class CbPdfViewer {
|
|
|
299
638
|
this.showRotate = input(true, { ...(ngDevMode ? { debugName: "showRotate" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
300
639
|
this.downloadable = input(true, { ...(ngDevMode ? { debugName: "downloadable" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
301
640
|
this.printable = input(true, { ...(ngDevMode ? { debugName: "printable" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
641
|
+
/** Pestaña Índice en el panel lateral (si el documento tiene marcadores). */
|
|
642
|
+
this.showOutline = input(true, { ...(ngDevMode ? { debugName: "showOutline" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
643
|
+
/** Campos de formulario rellenables (si no, se pintan como imagen). */
|
|
644
|
+
this.forms = input(true, { ...(ngDevMode ? { debugName: "forms" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
645
|
+
/** Enlaces externos del documento: se abren en otra pestaña. `false` los desactiva. */
|
|
646
|
+
this.externalLinks = input(true, { ...(ngDevMode ? { debugName: "externalLinks" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
647
|
+
/** Vista del panel lateral. */
|
|
648
|
+
this.sidebarView = model('thumbnails', /* @ts-ignore */
|
|
649
|
+
...(ngDevMode ? [{ debugName: "sidebarView" }] : /* istanbul ignore next */ []));
|
|
302
650
|
/** Nombre accesible del visor (por defecto, "Visor de PDF"). */
|
|
303
651
|
this.ariaLabel = input('', /* @ts-ignore */
|
|
304
652
|
...(ngDevMode ? [{ debugName: "ariaLabel" }] : /* istanbul ignore next */ []));
|
|
653
|
+
/** Herramientas para resaltar, poner notas, dibujar y firmar (y la pestaña Anotaciones). */
|
|
654
|
+
this.annotatable = input(false, { ...(ngDevMode ? { debugName: "annotatable" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
655
|
+
/**
|
|
656
|
+
* Anotaciones del usuario, en puntos PDF. Se ven siempre; con `annotatable` se crean, mueven y
|
|
657
|
+
* borran. Al descargar o imprimir se escriben en el PDF como anotaciones estándar.
|
|
658
|
+
*/
|
|
659
|
+
this.annotations = model([], /* @ts-ignore */
|
|
660
|
+
...(ngDevMode ? [{ debugName: "annotations" }] : /* istanbul ignore next */ []));
|
|
661
|
+
/** Herramienta activa (`none`, `highlight`, `note`, `ink`). Escape vuelve a `none`. */
|
|
662
|
+
this.tool = model('none', /* @ts-ignore */
|
|
663
|
+
...(ngDevMode ? [{ debugName: "tool" }] : /* istanbul ignore next */ []));
|
|
664
|
+
/** Color de las anotaciones nuevas. */
|
|
665
|
+
this.annotationColor = model('yellow', /* @ts-ignore */
|
|
666
|
+
...(ngDevMode ? [{ debugName: "annotationColor" }] : /* istanbul ignore next */ []));
|
|
667
|
+
/** Autor de las anotaciones nuevas (se guarda en el PDF). */
|
|
668
|
+
this.author = input('', /* @ts-ignore */
|
|
669
|
+
...(ngDevMode ? [{ debugName: "author" }] : /* istanbul ignore next */ []));
|
|
305
670
|
/** Documento abierto. */
|
|
306
671
|
this.loaded = output();
|
|
307
672
|
/** No se pudo abrir el documento. */
|
|
308
673
|
this.loadError = output();
|
|
674
|
+
/** El usuario cambió un campo del formulario (los valores, con `getFormData()`). */
|
|
675
|
+
this.formChange = output();
|
|
676
|
+
/** El usuario creó una anotación. */
|
|
677
|
+
this.annotationAdd = output();
|
|
678
|
+
/** El usuario borró una anotación. */
|
|
679
|
+
this.annotationRemove = output();
|
|
309
680
|
this.engine = inject(CbPdfEngine);
|
|
310
681
|
this.document = inject(DOCUMENT);
|
|
311
682
|
this.injector = inject(Injector);
|
|
683
|
+
this.host = inject(ElementRef);
|
|
312
684
|
this.isBrowser = isPlatformBrowser(inject(PLATFORM_ID));
|
|
313
685
|
this.uid = `cb-pdf-${++nextUid}`;
|
|
314
686
|
this.state = signal('idle', /* @ts-ignore */
|
|
@@ -334,6 +706,35 @@ class CbPdfViewer {
|
|
|
334
706
|
this.searching = signal(false, /* @ts-ignore */
|
|
335
707
|
...(ngDevMode ? [{ debugName: "searching" }] : /* istanbul ignore next */ []));
|
|
336
708
|
this.zoomLevels = ZOOM_LEVELS;
|
|
709
|
+
/** Índice del documento (vacío si no tiene). */
|
|
710
|
+
this.outline = signal([], /* @ts-ignore */
|
|
711
|
+
...(ngDevMode ? [{ debugName: "outline" }] : /* istanbul ignore next */ []));
|
|
712
|
+
/** Algún campo del formulario cambió desde que se abrió. */
|
|
713
|
+
this.formModified = signal(false, /* @ts-ignore */
|
|
714
|
+
...(ngDevMode ? [{ debugName: "formModified" }] : /* istanbul ignore next */ []));
|
|
715
|
+
this.collapsed = signal(new Set(), /* @ts-ignore */
|
|
716
|
+
...(ngDevMode ? [{ debugName: "collapsed" }] : /* istanbul ignore next */ []));
|
|
717
|
+
/** Enlaces del documento (lo que la capa de anotaciones de pdf.js necesita). */
|
|
718
|
+
this.linkService = {
|
|
719
|
+
externalLinkEnabled: true,
|
|
720
|
+
eventBus: null,
|
|
721
|
+
addLinkAttributes: (link, url, newWindow) => {
|
|
722
|
+
if (!this.externalLinks() || !SAFE_URL.test(url)) {
|
|
723
|
+
link.removeAttribute('href');
|
|
724
|
+
return;
|
|
725
|
+
}
|
|
726
|
+
link.href = url;
|
|
727
|
+
link.title = url;
|
|
728
|
+
link.rel = 'noopener noreferrer nofollow';
|
|
729
|
+
if (newWindow !== false)
|
|
730
|
+
link.target = '_blank';
|
|
731
|
+
},
|
|
732
|
+
getDestinationHash: () => '#',
|
|
733
|
+
getAnchorUrl: (hash) => `#${hash}`,
|
|
734
|
+
goToDestination: (dest) => void this.goToDestination(dest),
|
|
735
|
+
executeNamedAction: (action) => this.namedAction(action),
|
|
736
|
+
executeSetOCGState: () => undefined,
|
|
737
|
+
};
|
|
337
738
|
this.viewport = viewChild('viewport', /* @ts-ignore */
|
|
338
739
|
...(ngDevMode ? [{ debugName: "viewport" }] : /* istanbul ignore next */ []));
|
|
339
740
|
this.pageEls = viewChildren('pageEl', /* @ts-ignore */
|
|
@@ -344,6 +745,8 @@ class CbPdfViewer {
|
|
|
344
745
|
...(ngDevMode ? [{ debugName: "searchInput" }] : /* istanbul ignore next */ []));
|
|
345
746
|
this.passwordInput = viewChild('passwordInput', /* @ts-ignore */
|
|
346
747
|
...(ngDevMode ? [{ debugName: "passwordInput" }] : /* istanbul ignore next */ []));
|
|
748
|
+
this.cardText = viewChild('cardText', /* @ts-ignore */
|
|
749
|
+
...(ngDevMode ? [{ debugName: "cardText" }] : /* istanbul ignore next */ []));
|
|
347
750
|
/** Factor de zoom efectivo (1 = 100 %). */
|
|
348
751
|
this.scale = computed(() => {
|
|
349
752
|
const zoom = this.zoom();
|
|
@@ -393,6 +796,79 @@ class CbPdfViewer {
|
|
|
393
796
|
return this.searching() ? this.t().searching : this.t().noResults;
|
|
394
797
|
}, /* @ts-ignore */
|
|
395
798
|
...(ngDevMode ? [{ debugName: "searchStatus" }] : /* istanbul ignore next */ []));
|
|
799
|
+
// --- Anotaciones -------------------------------------------------------------
|
|
800
|
+
this.colors = CB_PDF_COLORS;
|
|
801
|
+
this.colorNames = Object.keys(CB_PDF_COLORS);
|
|
802
|
+
this.selectedId = signal(null, /* @ts-ignore */
|
|
803
|
+
...(ngDevMode ? [{ debugName: "selectedId" }] : /* istanbul ignore next */ []));
|
|
804
|
+
/** Anotación con el editor (texto de la nota o comentario del resaltado) abierto. */
|
|
805
|
+
this.editingId = signal(null, /* @ts-ignore */
|
|
806
|
+
...(ngDevMode ? [{ debugName: "editingId" }] : /* istanbul ignore next */ []));
|
|
807
|
+
/** Anotación mientras se arrastra o cambia de tamaño (se confirma al soltar). */
|
|
808
|
+
this.dragPreview = signal(null, /* @ts-ignore */
|
|
809
|
+
...(ngDevMode ? [{ debugName: "dragPreview" }] : /* istanbul ignore next */ []));
|
|
810
|
+
/** Trazo que se está dibujando, en píxeles de la página. */
|
|
811
|
+
this.stroke = signal(null, /* @ts-ignore */
|
|
812
|
+
...(ngDevMode ? [{ debugName: "stroke" }] : /* istanbul ignore next */ []));
|
|
813
|
+
this.announcement = signal('', /* @ts-ignore */
|
|
814
|
+
...(ngDevMode ? [{ debugName: "announcement" }] : /* istanbul ignore next */ []));
|
|
815
|
+
this.announceFlip = false;
|
|
816
|
+
this.signing = signal(false, /* @ts-ignore */
|
|
817
|
+
...(ngDevMode ? [{ debugName: "signing" }] : /* istanbul ignore next */ []));
|
|
818
|
+
this.signatureValue = signal('', /* @ts-ignore */
|
|
819
|
+
...(ngDevMode ? [{ debugName: "signatureValue" }] : /* istanbul ignore next */ []));
|
|
820
|
+
this.pendingFocus = null;
|
|
821
|
+
this.shownAnnotations = computed(() => {
|
|
822
|
+
const preview = this.dragPreview();
|
|
823
|
+
const list = this.annotations();
|
|
824
|
+
return preview ? list.map((a) => (a.id === preview.id ? preview : a)) : list;
|
|
825
|
+
}, /* @ts-ignore */
|
|
826
|
+
...(ngDevMode ? [{ debugName: "shownAnnotations" }] : /* istanbul ignore next */ []));
|
|
827
|
+
/** Anotaciones de cada página, ya colocadas con el zoom y el giro actuales. */
|
|
828
|
+
this.marks = computed(() => {
|
|
829
|
+
const sizes = this.sizes();
|
|
830
|
+
const pages = sizes.map(() => []);
|
|
831
|
+
for (const a of this.shownAnnotations()) {
|
|
832
|
+
const size = sizes[a.page - 1];
|
|
833
|
+
if (!size)
|
|
834
|
+
continue;
|
|
835
|
+
pages[a.page - 1].push(this.toMark(a, size));
|
|
836
|
+
}
|
|
837
|
+
return pages;
|
|
838
|
+
}, /* @ts-ignore */
|
|
839
|
+
...(ngDevMode ? [{ debugName: "marks" }] : /* istanbul ignore next */ []));
|
|
840
|
+
this.editingMark = computed(() => {
|
|
841
|
+
const id = this.editingId();
|
|
842
|
+
if (!id)
|
|
843
|
+
return null;
|
|
844
|
+
for (const page of this.marks())
|
|
845
|
+
for (const m of page)
|
|
846
|
+
if (m.a.id === id)
|
|
847
|
+
return m;
|
|
848
|
+
return null;
|
|
849
|
+
}, /* @ts-ignore */
|
|
850
|
+
...(ngDevMode ? [{ debugName: "editingMark" }] : /* istanbul ignore next */ []));
|
|
851
|
+
this.sortedAnnotations = computed(() => [...this.annotations()].sort((a, b) => a.page - b.page || this.topOf(b) - this.topOf(a)), /* @ts-ignore */
|
|
852
|
+
...(ngDevMode ? [{ debugName: "sortedAnnotations" }] : /* istanbul ignore next */ []));
|
|
853
|
+
this.sidebarTabs = computed(() => {
|
|
854
|
+
const tabs = ['thumbnails'];
|
|
855
|
+
if (this.outline().length && this.showOutline())
|
|
856
|
+
tabs.push('outline');
|
|
857
|
+
if (this.annotatable())
|
|
858
|
+
tabs.push('annotations');
|
|
859
|
+
return tabs;
|
|
860
|
+
}, /* @ts-ignore */
|
|
861
|
+
...(ngDevMode ? [{ debugName: "sidebarTabs" }] : /* istanbul ignore next */ []));
|
|
862
|
+
this.activeView = computed(() => (this.sidebarTabs().includes(this.sidebarView()) ? this.sidebarView() : 'thumbnails'), /* @ts-ignore */
|
|
863
|
+
...(ngDevMode ? [{ debugName: "activeView" }] : /* istanbul ignore next */ []));
|
|
864
|
+
this.toolHint = computed(() => {
|
|
865
|
+
if (!this.annotatable())
|
|
866
|
+
return '';
|
|
867
|
+
const tool = this.tool();
|
|
868
|
+
const t = this.t();
|
|
869
|
+
return tool === 'highlight' ? t.pdfHighlightHint : tool === 'note' ? t.pdfNoteHint : tool === 'ink' ? t.pdfDrawHint : '';
|
|
870
|
+
}, /* @ts-ignore */
|
|
871
|
+
...(ngDevMode ? [{ debugName: "toolHint" }] : /* istanbul ignore next */ []));
|
|
396
872
|
this.loadToken = 0;
|
|
397
873
|
this.searchToken = 0;
|
|
398
874
|
this.pages = new Map();
|
|
@@ -533,12 +1009,79 @@ class CbPdfViewer {
|
|
|
533
1009
|
if (total)
|
|
534
1010
|
this.selectMatch((this.matchIndex() - 1 + total) % total);
|
|
535
1011
|
}
|
|
536
|
-
/**
|
|
1012
|
+
/** Lleva a un destino del documento (nombre o destino explícito), con su posición en la página. */
|
|
1013
|
+
async goToDestination(dest) {
|
|
1014
|
+
const pdf = this.pdf;
|
|
1015
|
+
if (!pdf || !dest)
|
|
1016
|
+
return;
|
|
1017
|
+
const explicit = typeof dest === 'string' ? await pdf.getDestination(dest).catch(() => null) : dest;
|
|
1018
|
+
if (!Array.isArray(explicit) || pdf !== this.pdf)
|
|
1019
|
+
return;
|
|
1020
|
+
const ref = explicit[0];
|
|
1021
|
+
let page;
|
|
1022
|
+
try {
|
|
1023
|
+
page = typeof ref === 'object' && ref ? (await pdf.getPageIndex(ref)) + 1 : Number.isInteger(ref) ? ref + 1 : NaN;
|
|
1024
|
+
}
|
|
1025
|
+
catch {
|
|
1026
|
+
return;
|
|
1027
|
+
}
|
|
1028
|
+
if (!Number.isFinite(page) || page < 1 || page > this.numPages())
|
|
1029
|
+
return;
|
|
1030
|
+
// XYZ y FitH/FitBH dan la altura (en puntos, desde abajo) a la que se ve el destino.
|
|
1031
|
+
const kind = explicit[1]?.name;
|
|
1032
|
+
const top = kind === 'XYZ' ? explicit[3] : kind === 'FitH' || kind === 'FitBH' ? explicit[2] : null;
|
|
1033
|
+
this.goToPage(page);
|
|
1034
|
+
if (typeof top === 'number')
|
|
1035
|
+
afterNextRender(() => this.scrollToPoint(page, top), { injector: this.injector });
|
|
1036
|
+
}
|
|
1037
|
+
/** Valores actuales del formulario, por nombre de campo. */
|
|
1038
|
+
async getFormData() {
|
|
1039
|
+
const pdf = this.pdf;
|
|
1040
|
+
if (!pdf)
|
|
1041
|
+
return {};
|
|
1042
|
+
const fields = (await Promise.resolve(pdf.getFieldObjects?.()).catch(() => null));
|
|
1043
|
+
const storage = pdf.annotationStorage;
|
|
1044
|
+
const data = {};
|
|
1045
|
+
if (!fields || !storage)
|
|
1046
|
+
return data;
|
|
1047
|
+
for (const [name, widgets] of fields) {
|
|
1048
|
+
for (const widget of widgets) {
|
|
1049
|
+
if (!widget.id)
|
|
1050
|
+
continue;
|
|
1051
|
+
const stored = storage.getValue(widget.id, { value: widget.value }).value;
|
|
1052
|
+
if (widget.type === 'checkbox' || widget.type === 'radiobutton') {
|
|
1053
|
+
const checked = stored === true || (typeof stored === 'string' && stored !== 'Off' && stored !== '');
|
|
1054
|
+
if (widget.type === 'checkbox')
|
|
1055
|
+
data[name] = checked;
|
|
1056
|
+
else if (checked)
|
|
1057
|
+
data[name] = widget.exportValues ?? String(stored);
|
|
1058
|
+
else
|
|
1059
|
+
data[name] ??= null;
|
|
1060
|
+
}
|
|
1061
|
+
else {
|
|
1062
|
+
data[name] = Array.isArray(stored) ? stored.map(String) : stored == null ? null : String(stored);
|
|
1063
|
+
}
|
|
1064
|
+
}
|
|
1065
|
+
}
|
|
1066
|
+
return data;
|
|
1067
|
+
}
|
|
1068
|
+
/** El PDF con lo escrito en el formulario y las anotaciones (o el original si no hay cambios). */
|
|
1069
|
+
async save() {
|
|
1070
|
+
const pdf = this.pdf;
|
|
1071
|
+
if (!pdf)
|
|
1072
|
+
return null;
|
|
1073
|
+
const changed = this.formModified() || this.annotations().length > 0;
|
|
1074
|
+
const bytes = changed ? await this.withAnnotations(() => pdf.saveDocument()) : await pdf.getData();
|
|
1075
|
+
return new Blob([bytes], { type: 'application/pdf' });
|
|
1076
|
+
}
|
|
1077
|
+
/** Descarga el documento (con los datos del formulario y las anotaciones, si los hay). */
|
|
537
1078
|
async download() {
|
|
538
1079
|
if (!this.pdf)
|
|
539
1080
|
return;
|
|
540
1081
|
const src = this.src();
|
|
541
|
-
const blob = src instanceof Blob
|
|
1082
|
+
const blob = src instanceof Blob && !this.formModified() && !this.annotations().length ? src : await this.save();
|
|
1083
|
+
if (!blob)
|
|
1084
|
+
return;
|
|
542
1085
|
const url = URL.createObjectURL(blob);
|
|
543
1086
|
const a = this.document.createElement('a');
|
|
544
1087
|
a.href = url;
|
|
@@ -555,7 +1098,10 @@ class CbPdfViewer {
|
|
|
555
1098
|
return;
|
|
556
1099
|
this.printProgress.set({ done: 0, total: this.numPages() });
|
|
557
1100
|
try {
|
|
558
|
-
|
|
1101
|
+
const pdf = this.pdf;
|
|
1102
|
+
// La copia para imprimir se toma con las anotaciones escritas; después se quitan.
|
|
1103
|
+
const storage = await this.withAnnotations(async () => pdf.annotationStorage.print);
|
|
1104
|
+
await printPdfDocument(pdf, this.document, (done, total) => this.printProgress.set({ done, total }), this.rotation(), storage);
|
|
559
1105
|
}
|
|
560
1106
|
finally {
|
|
561
1107
|
this.printProgress.set(null);
|
|
@@ -604,6 +1150,14 @@ class CbPdfViewer {
|
|
|
604
1150
|
return;
|
|
605
1151
|
}
|
|
606
1152
|
this.pdf = pdf;
|
|
1153
|
+
this.formModified.set(false);
|
|
1154
|
+
// pdf.js tipa estos ganchos como `null`, pero los llama si se les asigna una función.
|
|
1155
|
+
const storage = pdf.annotationStorage;
|
|
1156
|
+
if (storage) {
|
|
1157
|
+
storage.onSetModified = () => this.formModified.set(true);
|
|
1158
|
+
storage.onResetModified = () => this.formModified.set(false);
|
|
1159
|
+
}
|
|
1160
|
+
void this.loadOutline(pdf, token);
|
|
607
1161
|
// Mide el área antes del primer render para que "ajustar al ancho" no renderice dos veces.
|
|
608
1162
|
this.observeResize();
|
|
609
1163
|
const first = sizeOf(await this.getPage(1));
|
|
@@ -632,6 +1186,14 @@ class CbPdfViewer {
|
|
|
632
1186
|
this.loadError.emit(error);
|
|
633
1187
|
}
|
|
634
1188
|
}
|
|
1189
|
+
async loadOutline(pdf, token) {
|
|
1190
|
+
const raw = await Promise.resolve(pdf.getOutline?.()).catch(() => null);
|
|
1191
|
+
if (token !== this.loadToken)
|
|
1192
|
+
return;
|
|
1193
|
+
const map = (items) => (items ?? []).map((i) => ({ title: i.title, dest: i.dest, url: i.url, bold: !!i.bold, italic: !!i.italic, items: map(i.items) }));
|
|
1194
|
+
this.outline.set(map(raw));
|
|
1195
|
+
this.collapsed.set(new Set());
|
|
1196
|
+
}
|
|
635
1197
|
submitPassword(event, value) {
|
|
636
1198
|
event.preventDefault();
|
|
637
1199
|
if (!this.passwordCallback)
|
|
@@ -681,6 +1243,12 @@ class CbPdfViewer {
|
|
|
681
1243
|
this.searching.set(false);
|
|
682
1244
|
this.numPages.set(0);
|
|
683
1245
|
this.sizes.set([]);
|
|
1246
|
+
this.outline.set([]);
|
|
1247
|
+
this.formModified.set(false);
|
|
1248
|
+
this.selectedId.set(null);
|
|
1249
|
+
this.editingId.set(null);
|
|
1250
|
+
this.stroke.set(null);
|
|
1251
|
+
this.dragPreview.set(null);
|
|
684
1252
|
}
|
|
685
1253
|
getPage(n) {
|
|
686
1254
|
let page = this.pages.get(n);
|
|
@@ -770,12 +1338,15 @@ class CbPdfViewer {
|
|
|
770
1338
|
canvas.width = Math.floor(viewport.width * ratio);
|
|
771
1339
|
canvas.height = Math.floor(viewport.height * ratio);
|
|
772
1340
|
canvas.setAttribute('aria-hidden', 'true');
|
|
773
|
-
|
|
1341
|
+
// Con formularios HTML, el canvas no dibuja los campos (AnnotationMode.ENABLE_FORMS).
|
|
1342
|
+
const annotationMode = this.forms() ? (this.pdfjs?.AnnotationMode?.ENABLE_FORMS ?? 2) : (this.pdfjs?.AnnotationMode?.ENABLE ?? 1);
|
|
1343
|
+
const task = page.render({ canvas, viewport, annotationMode, transform: ratio === 1 ? undefined : [ratio, 0, 0, ratio, 0, 0] });
|
|
774
1344
|
renderTask = task;
|
|
775
1345
|
await task.promise;
|
|
776
1346
|
if (cancelled)
|
|
777
1347
|
return;
|
|
778
1348
|
el.querySelector('.cb-pdf__canvas')?.replaceChildren(canvas);
|
|
1349
|
+
void this.renderAnnotations(page, viewport, el, () => cancelled);
|
|
779
1350
|
const textEl = el.querySelector('.cb-pdf__text');
|
|
780
1351
|
if (!textEl || !this.pdfjs?.TextLayer)
|
|
781
1352
|
return;
|
|
@@ -805,6 +1376,54 @@ class CbPdfViewer {
|
|
|
805
1376
|
const el = this.pageEl(n);
|
|
806
1377
|
el?.querySelector('.cb-pdf__canvas')?.replaceChildren();
|
|
807
1378
|
el?.querySelector('.cb-pdf__text')?.replaceChildren();
|
|
1379
|
+
el?.querySelector('.cb-pdf__annotations')?.replaceChildren();
|
|
1380
|
+
}
|
|
1381
|
+
/** Enlaces y campos de formulario de la página (capa de anotaciones de pdf.js). */
|
|
1382
|
+
async renderAnnotations(page, viewport, el, cancelled) {
|
|
1383
|
+
const div = el.querySelector('.cb-pdf__annotations');
|
|
1384
|
+
const Layer = this.pdfjs?.AnnotationLayer;
|
|
1385
|
+
const pdf = this.pdf;
|
|
1386
|
+
if (!div || !Layer || !pdf)
|
|
1387
|
+
return;
|
|
1388
|
+
try {
|
|
1389
|
+
const annotations = await page.getAnnotations({ intent: 'display' });
|
|
1390
|
+
if (cancelled() || !annotations.length)
|
|
1391
|
+
return;
|
|
1392
|
+
const fieldObjects = this.forms() ? await pdf.getFieldObjects().catch(() => null) : null;
|
|
1393
|
+
if (cancelled())
|
|
1394
|
+
return;
|
|
1395
|
+
div.replaceChildren();
|
|
1396
|
+
const layerViewport = viewport.clone({ dontFlip: true });
|
|
1397
|
+
const layer = new Layer({
|
|
1398
|
+
div,
|
|
1399
|
+
page,
|
|
1400
|
+
viewport: layerViewport,
|
|
1401
|
+
linkService: this.linkService,
|
|
1402
|
+
annotationStorage: pdf.annotationStorage,
|
|
1403
|
+
accessibilityManager: null,
|
|
1404
|
+
annotationCanvasMap: null,
|
|
1405
|
+
annotationEditorUIManager: null,
|
|
1406
|
+
structTreeLayer: null,
|
|
1407
|
+
commentManager: null,
|
|
1408
|
+
});
|
|
1409
|
+
await layer.render({
|
|
1410
|
+
viewport: layerViewport,
|
|
1411
|
+
div,
|
|
1412
|
+
annotations,
|
|
1413
|
+
page,
|
|
1414
|
+
linkService: this.linkService,
|
|
1415
|
+
annotationStorage: pdf.annotationStorage,
|
|
1416
|
+
renderForms: this.forms(),
|
|
1417
|
+
enableScripting: false,
|
|
1418
|
+
hasJSActions: false,
|
|
1419
|
+
fieldObjects,
|
|
1420
|
+
});
|
|
1421
|
+
if (cancelled())
|
|
1422
|
+
div.replaceChildren();
|
|
1423
|
+
}
|
|
1424
|
+
catch {
|
|
1425
|
+
// Anotaciones dañadas: la página se ve igual, sin enlaces ni campos.
|
|
1426
|
+
}
|
|
808
1427
|
}
|
|
809
1428
|
observeThumbs() {
|
|
810
1429
|
const root = this.document.getElementById(`${this.uid}-thumbs`);
|
|
@@ -949,6 +1568,16 @@ class CbPdfViewer {
|
|
|
949
1568
|
this.visiblePage = n;
|
|
950
1569
|
root.scrollTop = el.offsetTop - PAGE_GAP;
|
|
951
1570
|
}
|
|
1571
|
+
/** Desplaza hasta la altura `top` (puntos PDF, desde abajo) de la página `n`. */
|
|
1572
|
+
scrollToPoint(n, top) {
|
|
1573
|
+
const root = this.viewport()?.nativeElement;
|
|
1574
|
+
const el = this.pageEl(n);
|
|
1575
|
+
const size = this.sizes()[n - 1];
|
|
1576
|
+
if (!root || !el || !size || (size.rotate + this.rotation()) % 360 !== 0)
|
|
1577
|
+
return;
|
|
1578
|
+
const factor = this.scale() * CSS_UNITS;
|
|
1579
|
+
root.scrollTop = el.offsetTop + Math.max(0, (size.height - top) * factor) - PAGE_GAP;
|
|
1580
|
+
}
|
|
952
1581
|
readAnchor() {
|
|
953
1582
|
const root = this.viewport()?.nativeElement;
|
|
954
1583
|
const el = this.pageEl(this.visiblePage);
|
|
@@ -976,7 +1605,571 @@ class CbPdfViewer {
|
|
|
976
1605
|
pageEl(n) {
|
|
977
1606
|
return this.pageEls()[n - 1]?.nativeElement;
|
|
978
1607
|
}
|
|
1608
|
+
// --- Anotaciones -------------------------------------------------------------
|
|
1609
|
+
toggleTool(tool) {
|
|
1610
|
+
this.tool.set(this.tool() === tool ? 'none' : tool);
|
|
1611
|
+
}
|
|
1612
|
+
/** Con texto seleccionado lo resalta al momento; si no, activa la herramienta. */
|
|
1613
|
+
onHighlightTool() {
|
|
1614
|
+
if (this.tool() !== 'highlight' && this.highlightSelection())
|
|
1615
|
+
return;
|
|
1616
|
+
this.toggleTool('highlight');
|
|
1617
|
+
}
|
|
1618
|
+
/** Con el teclado (sin puntero) la nota se pone directamente en la página que se ve. */
|
|
1619
|
+
onNoteTool(event) {
|
|
1620
|
+
if (event.detail === 0 && this.tool() !== 'note') {
|
|
1621
|
+
const page = this.page();
|
|
1622
|
+
const spot = this.visibleSpot(page);
|
|
1623
|
+
if (spot)
|
|
1624
|
+
this.addNote(page, spot.x - 80, spot.y - 20);
|
|
1625
|
+
return;
|
|
1626
|
+
}
|
|
1627
|
+
this.toggleTool('note');
|
|
1628
|
+
}
|
|
1629
|
+
openSignature() {
|
|
1630
|
+
this.tool.set('none');
|
|
1631
|
+
this.signatureValue.set('');
|
|
1632
|
+
this.signing.set(true);
|
|
1633
|
+
}
|
|
1634
|
+
async insertSignature() {
|
|
1635
|
+
const value = this.signatureValue();
|
|
1636
|
+
if (!value)
|
|
1637
|
+
return;
|
|
1638
|
+
const page = this.page();
|
|
1639
|
+
const size = this.sizes()[page - 1];
|
|
1640
|
+
const spot = this.visibleSpot(page);
|
|
1641
|
+
this.signing.set(false);
|
|
1642
|
+
if (!size || !spot)
|
|
1643
|
+
return;
|
|
1644
|
+
const { url, width, height } = await trimSignature(value, this.document);
|
|
1645
|
+
const view = this.viewOf(size);
|
|
1646
|
+
const pageWidth = this.pageBoxes()[page - 1]?.width ?? 400;
|
|
1647
|
+
// 180 pt de ancho como máximo (algo menos que media página A4), con la proporción de la firma.
|
|
1648
|
+
const w = Math.min(pageWidth * 0.45, 180 * view.factor);
|
|
1649
|
+
const h = (w * height) / Math.max(1, width);
|
|
1650
|
+
const rect = viewToRect(this.geomOf(size), view, spot.x - w / 2, spot.y - h / 2, w, h);
|
|
1651
|
+
const id = this.addAnnotation({ ...this.newBase(page), type: 'signature', rect, image: url });
|
|
1652
|
+
this.pendingFocus = id;
|
|
1653
|
+
}
|
|
1654
|
+
/** El foco vuelve tras cerrar el diálogo: entonces se lleva a la firma recién puesta. */
|
|
1655
|
+
onSignatureHide() {
|
|
1656
|
+
const id = this.pendingFocus;
|
|
1657
|
+
this.pendingFocus = null;
|
|
1658
|
+
if (id)
|
|
1659
|
+
setTimeout(() => this.focusMark(id));
|
|
1660
|
+
}
|
|
1661
|
+
/** Resalta el texto seleccionado en el documento (una anotación por página). */
|
|
1662
|
+
highlightSelection() {
|
|
1663
|
+
const selection = this.document.getSelection();
|
|
1664
|
+
if (!selection || selection.isCollapsed || !selection.rangeCount)
|
|
1665
|
+
return false;
|
|
1666
|
+
let created = 0;
|
|
1667
|
+
for (const [index, ref] of this.pageEls().entries()) {
|
|
1668
|
+
const pageEl = ref.nativeElement;
|
|
1669
|
+
const textEl = pageEl.querySelector('.cb-pdf__text');
|
|
1670
|
+
const size = this.sizes()[index];
|
|
1671
|
+
if (!textEl || !size)
|
|
1672
|
+
continue;
|
|
1673
|
+
const boxes = [];
|
|
1674
|
+
let text = '';
|
|
1675
|
+
for (let k = 0; k < selection.rangeCount; k++) {
|
|
1676
|
+
const range = selection.getRangeAt(k);
|
|
1677
|
+
if (!range.intersectsNode(textEl))
|
|
1678
|
+
continue;
|
|
1679
|
+
const part = range.cloneRange();
|
|
1680
|
+
if (!textEl.contains(part.startContainer))
|
|
1681
|
+
part.setStart(textEl, 0);
|
|
1682
|
+
if (!textEl.contains(part.endContainer))
|
|
1683
|
+
part.setEnd(textEl, textEl.childNodes.length);
|
|
1684
|
+
const origin = pageEl.getBoundingClientRect();
|
|
1685
|
+
for (const r of Array.from(part.getClientRects())) {
|
|
1686
|
+
boxes.push({ left: r.left - origin.left, top: r.top - origin.top, width: r.width, height: r.height });
|
|
1687
|
+
}
|
|
1688
|
+
text += part.toString();
|
|
1689
|
+
}
|
|
1690
|
+
const lines = mergeLineRects(withoutTallRects(boxes));
|
|
1691
|
+
if (!lines.length)
|
|
1692
|
+
continue;
|
|
1693
|
+
const geom = this.geomOf(size);
|
|
1694
|
+
const view = this.viewOf(size);
|
|
1695
|
+
const rects = lines.map((l) => viewToRect(geom, view, l.left, l.top, l.width, l.height));
|
|
1696
|
+
this.addAnnotation({ ...this.newBase(index + 1), type: 'highlight', rects, color: this.annotationColor(), text: text.replace(/\s+/g, ' ').trim() });
|
|
1697
|
+
created++;
|
|
1698
|
+
}
|
|
1699
|
+
if (created)
|
|
1700
|
+
selection.removeAllRanges();
|
|
1701
|
+
return created > 0;
|
|
1702
|
+
}
|
|
1703
|
+
onPagesPointerUp() {
|
|
1704
|
+
// La selección termina de fijarse después del pointerup.
|
|
1705
|
+
if (this.annotatable() && this.tool() === 'highlight')
|
|
1706
|
+
setTimeout(() => this.highlightSelection());
|
|
1707
|
+
}
|
|
1708
|
+
onMarksPointerDown(event, page) {
|
|
1709
|
+
if (!this.annotatable() || event.button !== 0)
|
|
1710
|
+
return;
|
|
1711
|
+
const layer = event.currentTarget;
|
|
1712
|
+
const origin = layer.getBoundingClientRect();
|
|
1713
|
+
const tool = this.tool();
|
|
1714
|
+
if (tool === 'note') {
|
|
1715
|
+
event.preventDefault();
|
|
1716
|
+
this.addNote(page, event.clientX - origin.left, event.clientY - origin.top);
|
|
1717
|
+
}
|
|
1718
|
+
else if (tool === 'ink') {
|
|
1719
|
+
event.preventDefault();
|
|
1720
|
+
layer.setPointerCapture?.(event.pointerId);
|
|
1721
|
+
this.stroke.set({ page, points: [event.clientX - origin.left, event.clientY - origin.top] });
|
|
1722
|
+
const move = (e) => {
|
|
1723
|
+
const s = this.stroke();
|
|
1724
|
+
if (s)
|
|
1725
|
+
this.stroke.set({ page, points: [...s.points, e.clientX - origin.left, e.clientY - origin.top] });
|
|
1726
|
+
};
|
|
1727
|
+
const end = () => {
|
|
1728
|
+
layer.removeEventListener('pointermove', move);
|
|
1729
|
+
layer.removeEventListener('pointerup', end);
|
|
1730
|
+
layer.removeEventListener('pointercancel', end);
|
|
1731
|
+
this.finishStroke();
|
|
1732
|
+
};
|
|
1733
|
+
layer.addEventListener('pointermove', move);
|
|
1734
|
+
layer.addEventListener('pointerup', end);
|
|
1735
|
+
layer.addEventListener('pointercancel', end);
|
|
1736
|
+
}
|
|
1737
|
+
else if (tool === 'none') {
|
|
1738
|
+
this.closeEditor(false);
|
|
1739
|
+
this.selectedId.set(null);
|
|
1740
|
+
}
|
|
1741
|
+
}
|
|
1742
|
+
finishStroke() {
|
|
1743
|
+
const s = this.stroke();
|
|
1744
|
+
this.stroke.set(null);
|
|
1745
|
+
const size = s && this.sizes()[s.page - 1];
|
|
1746
|
+
if (!s || !size)
|
|
1747
|
+
return;
|
|
1748
|
+
const points = s.points.length === 2 ? [...s.points, s.points[0] + 0.5, s.points[1] + 0.5] : s.points;
|
|
1749
|
+
const geom = this.geomOf(size);
|
|
1750
|
+
const view = this.viewOf(size);
|
|
1751
|
+
const pdf = [];
|
|
1752
|
+
for (let i = 0; i + 1 < points.length; i += 2)
|
|
1753
|
+
pdf.push(...viewToPdf(geom, view, points[i], points[i + 1]));
|
|
1754
|
+
const path = simplifyPath(pdf, 0.4).map((v) => Math.round(v * 100) / 100);
|
|
1755
|
+
this.addAnnotation({ ...this.newBase(s.page), type: 'ink', paths: [path], color: this.annotationColor(), thickness: 2 }, false);
|
|
1756
|
+
}
|
|
1757
|
+
addNote(page, x, y) {
|
|
1758
|
+
const size = this.sizes()[page - 1];
|
|
1759
|
+
if (!size)
|
|
1760
|
+
return;
|
|
1761
|
+
const view = this.viewOf(size);
|
|
1762
|
+
const box = this.pageBoxes()[page - 1];
|
|
1763
|
+
const w = 160 * view.factor;
|
|
1764
|
+
const h = 12 * 1.5 * view.factor;
|
|
1765
|
+
const left = clamp(x, 0, Math.max(0, (box?.width ?? w) - w));
|
|
1766
|
+
const top = clamp(y, 0, Math.max(0, (box?.height ?? h) - h));
|
|
1767
|
+
const rect = viewToRect(this.geomOf(size), view, left, top, w, h);
|
|
1768
|
+
const id = this.addAnnotation({ ...this.newBase(page), type: 'note', rect, text: '', color: this.annotationColor() }, false);
|
|
1769
|
+
this.tool.set('none');
|
|
1770
|
+
this.openEditor(id);
|
|
1771
|
+
}
|
|
1772
|
+
/** Añade una anotación, la anuncia y la selecciona. Devuelve su `id`. */
|
|
1773
|
+
addAnnotation(annotation, focus = true) {
|
|
1774
|
+
this.annotations.update((list) => [...list, annotation]);
|
|
1775
|
+
this.annotationAdd.emit(annotation);
|
|
1776
|
+
this.announce(cbFormat(this.t().pdfAnnotationAdded, this.nounOf(annotation), annotation.page));
|
|
1777
|
+
this.selectedId.set(annotation.id);
|
|
1778
|
+
if (focus)
|
|
1779
|
+
afterNextRender(() => this.focusMark(annotation.id), { injector: this.injector });
|
|
1780
|
+
return annotation.id;
|
|
1781
|
+
}
|
|
1782
|
+
/** Borra una anotación y deja el foco en la siguiente de la página (o en el documento). */
|
|
1783
|
+
removeAnnotation(annotation) {
|
|
1784
|
+
const list = this.annotations();
|
|
1785
|
+
const index = list.findIndex((a) => a.id === annotation.id);
|
|
1786
|
+
if (index === -1)
|
|
1787
|
+
return;
|
|
1788
|
+
const samePage = list.filter((a) => a.page === annotation.page && a.id !== annotation.id);
|
|
1789
|
+
const hadFocus = this.host.nativeElement.contains(this.document.activeElement);
|
|
1790
|
+
this.annotations.set(list.filter((a) => a.id !== annotation.id));
|
|
1791
|
+
if (this.editingId() === annotation.id)
|
|
1792
|
+
this.editingId.set(null);
|
|
1793
|
+
if (this.selectedId() === annotation.id)
|
|
1794
|
+
this.selectedId.set(null);
|
|
1795
|
+
this.annotationRemove.emit(annotation);
|
|
1796
|
+
this.announce(this.t().pdfAnnotationRemoved);
|
|
1797
|
+
if (!hadFocus || this.activeView() === 'annotations' && this.sidebar())
|
|
1798
|
+
return;
|
|
1799
|
+
const next = samePage[0]?.id;
|
|
1800
|
+
afterNextRender(() => (next ? this.focusMark(next) : this.viewport()?.nativeElement.focus()), { injector: this.injector });
|
|
1801
|
+
}
|
|
1802
|
+
replaceAnnotation(annotation) {
|
|
1803
|
+
this.annotations.update((list) => list.map((a) => (a.id === annotation.id ? annotation : a)));
|
|
1804
|
+
}
|
|
1805
|
+
select(id) {
|
|
1806
|
+
if (this.editingId() && this.editingId() !== id)
|
|
1807
|
+
this.closeEditor(false);
|
|
1808
|
+
this.selectedId.set(id);
|
|
1809
|
+
}
|
|
1810
|
+
/** Lleva a la anotación (desde la lista del panel) y le da el foco. */
|
|
1811
|
+
revealAnnotation(annotation) {
|
|
1812
|
+
this.goToPage(annotation.page);
|
|
1813
|
+
this.selectedId.set(annotation.id);
|
|
1814
|
+
afterNextRender(() => this.focusMark(annotation.id, true), { injector: this.injector });
|
|
1815
|
+
}
|
|
1816
|
+
focusMark(id, scroll = false) {
|
|
1817
|
+
const el = this.host.nativeElement.querySelector(`.cb-pdf__mark[data-id="${id}"]`);
|
|
1818
|
+
if (!el)
|
|
1819
|
+
return;
|
|
1820
|
+
el.focus({ preventScroll: !scroll });
|
|
1821
|
+
if (scroll)
|
|
1822
|
+
el.scrollIntoView?.({ block: 'center', inline: 'nearest' });
|
|
1823
|
+
}
|
|
1824
|
+
openEditor(id) {
|
|
1825
|
+
const annotation = this.annotations().find((a) => a.id === id);
|
|
1826
|
+
if (!annotation || (annotation.type !== 'note' && annotation.type !== 'highlight'))
|
|
1827
|
+
return;
|
|
1828
|
+
this.selectedId.set(id);
|
|
1829
|
+
this.editingId.set(id);
|
|
1830
|
+
afterNextRender(() => {
|
|
1831
|
+
const textarea = this.cardText()?.nativeElement;
|
|
1832
|
+
if (!textarea)
|
|
1833
|
+
return;
|
|
1834
|
+
textarea.value = annotation.type === 'note' ? annotation.text : (annotation.comment ?? '');
|
|
1835
|
+
textarea.focus();
|
|
1836
|
+
}, { injector: this.injector });
|
|
1837
|
+
}
|
|
1838
|
+
onCardInput(value) {
|
|
1839
|
+
const annotation = this.annotations().find((a) => a.id === this.editingId());
|
|
1840
|
+
if (annotation?.type === 'note')
|
|
1841
|
+
this.replaceAnnotation({ ...annotation, text: value });
|
|
1842
|
+
else if (annotation?.type === 'highlight')
|
|
1843
|
+
this.replaceAnnotation({ ...annotation, comment: value || undefined });
|
|
1844
|
+
}
|
|
1845
|
+
onCardKeydown(event) {
|
|
1846
|
+
event.stopPropagation();
|
|
1847
|
+
if (event.key === 'Escape' || (event.key === 'Enter' && (event.ctrlKey || event.metaKey))) {
|
|
1848
|
+
event.preventDefault();
|
|
1849
|
+
this.closeEditor(true);
|
|
1850
|
+
}
|
|
1851
|
+
}
|
|
1852
|
+
/** Cierra el editor: una nota vacía se borra y una con texto ajusta su caja a lo escrito. */
|
|
1853
|
+
closeEditor(refocus) {
|
|
1854
|
+
const id = this.editingId();
|
|
1855
|
+
if (!id)
|
|
1856
|
+
return;
|
|
1857
|
+
this.editingId.set(null);
|
|
1858
|
+
const annotation = this.annotations().find((a) => a.id === id);
|
|
1859
|
+
if (annotation?.type === 'note') {
|
|
1860
|
+
if (!annotation.text.trim()) {
|
|
1861
|
+
this.annotations.update((list) => list.filter((a) => a.id !== id));
|
|
1862
|
+
this.selectedId.set(null);
|
|
1863
|
+
if (refocus)
|
|
1864
|
+
this.viewport()?.nativeElement.focus();
|
|
1865
|
+
return;
|
|
1866
|
+
}
|
|
1867
|
+
this.measureNote(annotation);
|
|
1868
|
+
}
|
|
1869
|
+
if (refocus)
|
|
1870
|
+
afterNextRender(() => this.focusMark(id), { injector: this.injector });
|
|
1871
|
+
}
|
|
1872
|
+
/** La caja de la nota en el PDF es la que ocupa su texto en pantalla. */
|
|
1873
|
+
measureNote(note) {
|
|
1874
|
+
const el = this.host.nativeElement.querySelector(`.cb-pdf__mark[data-id="${note.id}"]`);
|
|
1875
|
+
const size = this.sizes()[note.page - 1];
|
|
1876
|
+
if (!el || !size || !el.offsetWidth)
|
|
1877
|
+
return;
|
|
1878
|
+
const rect = viewToRect(this.geomOf(size), this.viewOf(size), el.offsetLeft, el.offsetTop, el.offsetWidth, el.offsetHeight);
|
|
1879
|
+
if (rect.some((v, i) => Math.abs(v - note.rect[i]) > 0.5))
|
|
1880
|
+
this.replaceAnnotation({ ...note, rect });
|
|
1881
|
+
}
|
|
1882
|
+
onMarkPointerDown(event, annotation) {
|
|
1883
|
+
event.stopPropagation();
|
|
1884
|
+
const el = event.currentTarget;
|
|
1885
|
+
if (!this.annotatable() || event.button !== 0)
|
|
1886
|
+
return;
|
|
1887
|
+
if (annotation.type === 'highlight') {
|
|
1888
|
+
this.select(annotation.id);
|
|
1889
|
+
return;
|
|
1890
|
+
}
|
|
1891
|
+
// Sin el default no empieza una selección de texto al arrastrar; el foco se da a mano.
|
|
1892
|
+
event.preventDefault();
|
|
1893
|
+
el.focus({ preventScroll: true });
|
|
1894
|
+
this.trackPointer(event, el, (dx, dy) => this.translated(annotation, dx, dy), () => {
|
|
1895
|
+
if (annotation.type === 'note' && this.editingId() !== annotation.id)
|
|
1896
|
+
this.openEditor(annotation.id);
|
|
1897
|
+
});
|
|
1898
|
+
}
|
|
1899
|
+
onResizePointerDown(event, annotation) {
|
|
1900
|
+
event.stopPropagation();
|
|
1901
|
+
event.preventDefault();
|
|
1902
|
+
if (annotation.type !== 'signature')
|
|
1903
|
+
return;
|
|
1904
|
+
const size = this.sizes()[annotation.page - 1];
|
|
1905
|
+
if (!size)
|
|
1906
|
+
return;
|
|
1907
|
+
const width = rectToView(this.geomOf(size), this.viewOf(size), annotation.rect).width;
|
|
1908
|
+
this.trackPointer(event, event.currentTarget, (dx) => ({ ...annotation, rect: scaleRect(annotation.rect, (width + dx) / Math.max(1, width)) }));
|
|
1909
|
+
}
|
|
1910
|
+
/** Arrastre con vista previa: se confirma al soltar; sin moverse es un clic (`onClick`). */
|
|
1911
|
+
trackPointer(event, el, update, onClick) {
|
|
1912
|
+
el.setPointerCapture?.(event.pointerId);
|
|
1913
|
+
const [x, y] = [event.clientX, event.clientY];
|
|
1914
|
+
let moved = false;
|
|
1915
|
+
const move = (e) => {
|
|
1916
|
+
const [dx, dy] = [e.clientX - x, e.clientY - y];
|
|
1917
|
+
if (!moved && Math.hypot(dx, dy) < 3)
|
|
1918
|
+
return;
|
|
1919
|
+
moved = true;
|
|
1920
|
+
this.dragPreview.set(update(dx, dy));
|
|
1921
|
+
};
|
|
1922
|
+
const end = () => {
|
|
1923
|
+
el.removeEventListener('pointermove', move);
|
|
1924
|
+
el.removeEventListener('pointerup', end);
|
|
1925
|
+
el.removeEventListener('pointercancel', end);
|
|
1926
|
+
const preview = this.dragPreview();
|
|
1927
|
+
this.dragPreview.set(null);
|
|
1928
|
+
if (moved && preview)
|
|
1929
|
+
this.replaceAnnotation(preview);
|
|
1930
|
+
else
|
|
1931
|
+
onClick?.();
|
|
1932
|
+
};
|
|
1933
|
+
el.addEventListener('pointermove', move);
|
|
1934
|
+
el.addEventListener('pointerup', end);
|
|
1935
|
+
el.addEventListener('pointercancel', end);
|
|
1936
|
+
}
|
|
1937
|
+
onMarkKeydown(event, rendered) {
|
|
1938
|
+
if (!this.annotatable() || event.ctrlKey || event.metaKey || event.altKey)
|
|
1939
|
+
return;
|
|
1940
|
+
// La de la plantilla puede ser de antes del último repintado (tecla mantenida): se usa la actual.
|
|
1941
|
+
const annotation = this.annotations().find((a) => a.id === rendered.id) ?? rendered;
|
|
1942
|
+
const step = event.shiftKey ? 20 : 4;
|
|
1943
|
+
const arrows = { ArrowLeft: [-step, 0], ArrowRight: [step, 0], ArrowUp: [0, -step], ArrowDown: [0, step] };
|
|
1944
|
+
if (event.key === 'Delete' || event.key === 'Backspace') {
|
|
1945
|
+
this.removeAnnotation(annotation);
|
|
1946
|
+
}
|
|
1947
|
+
else if (event.key === 'Enter' || event.key === ' ') {
|
|
1948
|
+
if (annotation.type !== 'note' && annotation.type !== 'highlight')
|
|
1949
|
+
return;
|
|
1950
|
+
this.openEditor(annotation.id);
|
|
1951
|
+
}
|
|
1952
|
+
else if (arrows[event.key] && annotation.type !== 'highlight') {
|
|
1953
|
+
const moved = this.translated(annotation, ...arrows[event.key]);
|
|
1954
|
+
this.replaceAnnotation(moved);
|
|
1955
|
+
this.announcePosition(moved);
|
|
1956
|
+
}
|
|
1957
|
+
else if ((event.key === '+' || event.key === '=' || event.key === '-') && (annotation.type === 'signature' || annotation.type === 'note')) {
|
|
1958
|
+
const grow = event.key !== '-';
|
|
1959
|
+
if (annotation.type === 'signature') {
|
|
1960
|
+
const rect = scaleRect(annotation.rect, grow ? 1.1 : 1 / 1.1);
|
|
1961
|
+
const pageWidth = (this.sizes()[annotation.page - 1]?.width ?? 1) / (this.sizes()[annotation.page - 1]?.userUnit ?? 1);
|
|
1962
|
+
this.replaceAnnotation({ ...annotation, rect });
|
|
1963
|
+
this.announce(cbFormat(this.t().pdfSignatureResized, Math.round(((rect[2] - rect[0]) / pageWidth) * 100)));
|
|
1964
|
+
}
|
|
1965
|
+
else {
|
|
1966
|
+
const fontSize = clamp((annotation.fontSize ?? 12) + (grow ? 1 : -1), 6, 48);
|
|
1967
|
+
this.replaceAnnotation({ ...annotation, fontSize });
|
|
1968
|
+
this.announce(cbFormat(this.t().pdfNoteResized, fontSize));
|
|
1969
|
+
afterNextRender(() => this.measureNote({ ...annotation, fontSize }), { injector: this.injector });
|
|
1970
|
+
}
|
|
1971
|
+
}
|
|
1972
|
+
else {
|
|
1973
|
+
return;
|
|
1974
|
+
}
|
|
1975
|
+
event.preventDefault();
|
|
1976
|
+
event.stopPropagation();
|
|
1977
|
+
}
|
|
1978
|
+
/** Desplaza `dx`, `dy` píxeles de pantalla (con el giro, en el sentido en que se ven). */
|
|
1979
|
+
translated(annotation, dx, dy) {
|
|
1980
|
+
const size = this.sizes()[annotation.page - 1];
|
|
1981
|
+
if (!size || annotation.type === 'highlight')
|
|
1982
|
+
return annotation;
|
|
1983
|
+
const geom = this.geomOf(size);
|
|
1984
|
+
const view = this.viewOf(size);
|
|
1985
|
+
const [ax, ay] = viewToPdf(geom, view, 0, 0);
|
|
1986
|
+
const [bx, by] = viewToPdf(geom, view, dx, dy);
|
|
1987
|
+
const [px, py] = [bx - ax, by - ay];
|
|
1988
|
+
if (annotation.type === 'ink') {
|
|
1989
|
+
return { ...annotation, paths: annotation.paths.map((p) => p.map((v, i) => Math.round((v + (i % 2 ? py : px)) * 100) / 100)) };
|
|
1990
|
+
}
|
|
1991
|
+
return { ...annotation, rect: moveRect(geom, annotation.rect, px, py) };
|
|
1992
|
+
}
|
|
1993
|
+
announcePosition(annotation) {
|
|
1994
|
+
const box = this.marks()[annotation.page - 1]?.find((m) => m.a.id === annotation.id)?.box;
|
|
1995
|
+
const page = this.pageBoxes()[annotation.page - 1];
|
|
1996
|
+
if (!box || !page)
|
|
1997
|
+
return;
|
|
1998
|
+
this.announce(cbFormat(this.t().pdfAnnotationMoved, Math.round((box.left / page.width) * 100), Math.round((box.top / page.height) * 100)));
|
|
1999
|
+
}
|
|
2000
|
+
announce(text) {
|
|
2001
|
+
// Un espacio duro alterno hace que se repita aunque el texto sea el mismo.
|
|
2002
|
+
this.announceFlip = !this.announceFlip;
|
|
2003
|
+
this.announcement.set(this.announceFlip ? text : `${text} `);
|
|
2004
|
+
}
|
|
2005
|
+
/** Centro de la parte visible de la página `n`, en píxeles de la página. */
|
|
2006
|
+
visibleSpot(n) {
|
|
2007
|
+
const root = this.viewport()?.nativeElement;
|
|
2008
|
+
const el = this.pageEl(n);
|
|
2009
|
+
if (!root || !el)
|
|
2010
|
+
return null;
|
|
2011
|
+
const top = Math.max(0, root.scrollTop - el.offsetTop);
|
|
2012
|
+
const bottom = Math.min(el.offsetHeight, root.scrollTop + root.clientHeight - el.offsetTop);
|
|
2013
|
+
const y = bottom > top ? (top + bottom) / 2 : el.offsetHeight / 3;
|
|
2014
|
+
return { x: (el.offsetWidth || this.pageBoxes()[n - 1]?.width || 0) / 2, y };
|
|
2015
|
+
}
|
|
2016
|
+
toMark(a, size) {
|
|
2017
|
+
const geom = this.geomOf(size);
|
|
2018
|
+
const view = this.viewOf(size);
|
|
2019
|
+
const color = CB_PDF_COLORS[a.type === 'signature' ? 'blue' : a.color];
|
|
2020
|
+
const base = { a, light: color.light, dark: color.dark, label: this.labelOf(a) };
|
|
2021
|
+
switch (a.type) {
|
|
2022
|
+
case 'highlight': {
|
|
2023
|
+
const boxes = a.rects.map((r) => rectToView(geom, view, r));
|
|
2024
|
+
const box = unionBox(boxes);
|
|
2025
|
+
return { ...base, box, rects: boxes.map((b) => ({ ...b, left: b.left - box.left, top: b.top - box.top })) };
|
|
2026
|
+
}
|
|
2027
|
+
case 'note':
|
|
2028
|
+
return { ...base, box: rectToView(geom, view, a.rect), fontPx: (a.fontSize ?? 12) * view.factor * geom.userUnit };
|
|
2029
|
+
case 'ink': {
|
|
2030
|
+
const pad = (a.thickness / 2 + 1) * view.factor;
|
|
2031
|
+
const points = a.paths.map((p) => {
|
|
2032
|
+
const out = [];
|
|
2033
|
+
for (let i = 0; i + 1 < p.length; i += 2)
|
|
2034
|
+
out.push(pdfToView(geom, view, p[i], p[i + 1]));
|
|
2035
|
+
return out;
|
|
2036
|
+
});
|
|
2037
|
+
const flat = points.flat();
|
|
2038
|
+
const left = Math.min(...flat.map((p) => p[0])) - pad;
|
|
2039
|
+
const top = Math.min(...flat.map((p) => p[1])) - pad;
|
|
2040
|
+
const width = Math.max(...flat.map((p) => p[0])) + pad - left;
|
|
2041
|
+
const height = Math.max(...flat.map((p) => p[1])) + pad - top;
|
|
2042
|
+
const d = points.map((p) => p.map(([x, y], i) => `${i ? 'L' : 'M'}${round2(x - left)} ${round2(y - top)}`).join(' ')).join(' ');
|
|
2043
|
+
return { ...base, box: { left, top, width, height }, d, strokePx: a.thickness * view.factor };
|
|
2044
|
+
}
|
|
2045
|
+
case 'signature':
|
|
2046
|
+
return { ...base, box: rectToView(geom, view, a.rect) };
|
|
2047
|
+
}
|
|
2048
|
+
}
|
|
2049
|
+
labelOf(a) {
|
|
2050
|
+
const t = this.t();
|
|
2051
|
+
switch (a.type) {
|
|
2052
|
+
case 'highlight': {
|
|
2053
|
+
const label = cbFormat(t.pdfHighlightOf, truncate(a.text, 80));
|
|
2054
|
+
return a.comment ? `${label}. ${t.pdfComment}: ${truncate(a.comment, 120)}` : label;
|
|
2055
|
+
}
|
|
2056
|
+
case 'note':
|
|
2057
|
+
return cbFormat(t.pdfNoteOf, a.text.trim() ? truncate(a.text, 120) : t.pdfEmptyNote);
|
|
2058
|
+
case 'ink':
|
|
2059
|
+
return t.pdfInkOf;
|
|
2060
|
+
case 'signature':
|
|
2061
|
+
return t.pdfSignatureOf;
|
|
2062
|
+
}
|
|
2063
|
+
}
|
|
2064
|
+
nounOf(a) {
|
|
2065
|
+
const t = this.t();
|
|
2066
|
+
return a.type === 'highlight' ? t.pdfHighlightNoun : a.type === 'note' ? t.pdfNote : a.type === 'ink' ? t.pdfInkOf : t.pdfSignatureOf;
|
|
2067
|
+
}
|
|
2068
|
+
swatchOf(a) {
|
|
2069
|
+
if (a.type === 'signature')
|
|
2070
|
+
return CB_PDF_COLORS.blue.dark;
|
|
2071
|
+
return a.type === 'highlight' ? CB_PDF_COLORS[a.color].light : CB_PDF_COLORS[a.color].dark;
|
|
2072
|
+
}
|
|
2073
|
+
colorLabel(color) {
|
|
2074
|
+
const t = this.t();
|
|
2075
|
+
return { yellow: t.pdfColorYellow, green: t.pdfColorGreen, blue: t.pdfColorBlue, red: t.pdfColorRed }[color];
|
|
2076
|
+
}
|
|
2077
|
+
/** Posición del editor: bajo la anotación, sin salirse de la página. */
|
|
2078
|
+
cardLeft(m, pageWidth) {
|
|
2079
|
+
return clamp(m.box.left, 0, Math.max(0, pageWidth - 260));
|
|
2080
|
+
}
|
|
2081
|
+
noteHeight(m) {
|
|
2082
|
+
if (m.a.type !== 'note')
|
|
2083
|
+
return m.box.height;
|
|
2084
|
+
const lines = Math.max(1, m.a.text.split('\n').length);
|
|
2085
|
+
return Math.max(m.box.height, lines * (m.fontPx ?? 16) * 1.25 + 8);
|
|
2086
|
+
}
|
|
2087
|
+
newBase(page) {
|
|
2088
|
+
const author = this.author();
|
|
2089
|
+
return { id: `cb-annot-${Date.now().toString(36)}-${++nextAnnotationId}`, page, ...(author ? { author } : {}), date: new Date().toISOString() };
|
|
2090
|
+
}
|
|
2091
|
+
geomOf(size) {
|
|
2092
|
+
return { x0: size.x0, y0: size.y0, width: size.width, height: size.height, userUnit: size.userUnit };
|
|
2093
|
+
}
|
|
2094
|
+
viewOf(size) {
|
|
2095
|
+
return { factor: this.scale() * CSS_UNITS, rotation: (size.rotate + this.rotation()) % 360 };
|
|
2096
|
+
}
|
|
2097
|
+
/** Altura (para ordenar de arriba abajo en el panel). */
|
|
2098
|
+
topOf(a) {
|
|
2099
|
+
if (a.type === 'highlight')
|
|
2100
|
+
return Math.max(...a.rects.map((r) => r[3]));
|
|
2101
|
+
if (a.type === 'ink')
|
|
2102
|
+
return Math.max(...a.paths.flatMap((p) => p.filter((_, i) => i % 2)));
|
|
2103
|
+
return a.rect[3];
|
|
2104
|
+
}
|
|
2105
|
+
/**
|
|
2106
|
+
* Escribe las anotaciones en el `annotationStorage` de pdf.js mientras dura `run` (guardar o
|
|
2107
|
+
* tomar la copia para imprimir) y las quita después, sin marcar el formulario como cambiado.
|
|
2108
|
+
*/
|
|
2109
|
+
async withAnnotations(run) {
|
|
2110
|
+
const pdf = this.pdf;
|
|
2111
|
+
const list = this.annotations();
|
|
2112
|
+
if (!pdf || !list.length)
|
|
2113
|
+
return run();
|
|
2114
|
+
const storage = pdf.annotationStorage;
|
|
2115
|
+
const hook = storage.onSetModified;
|
|
2116
|
+
storage.onSetModified = null;
|
|
2117
|
+
const keys = [];
|
|
2118
|
+
try {
|
|
2119
|
+
for (const a of list) {
|
|
2120
|
+
const size = this.sizes()[a.page - 1];
|
|
2121
|
+
if (!size)
|
|
2122
|
+
continue;
|
|
2123
|
+
const bitmap = a.type === 'signature' ? await imageToBitmap(a.image) : undefined;
|
|
2124
|
+
const value = toPdfJsAnnotation(a, size.rotate, bitmap);
|
|
2125
|
+
if (!value)
|
|
2126
|
+
continue;
|
|
2127
|
+
const key = `${PDFJS_EDITOR_PREFIX}${a.id}`;
|
|
2128
|
+
storage.setValue(key, value);
|
|
2129
|
+
keys.push(key);
|
|
2130
|
+
}
|
|
2131
|
+
return await run();
|
|
2132
|
+
}
|
|
2133
|
+
finally {
|
|
2134
|
+
for (const key of keys)
|
|
2135
|
+
storage.remove(key);
|
|
2136
|
+
storage.onSetModified = hook;
|
|
2137
|
+
}
|
|
2138
|
+
}
|
|
979
2139
|
// --- Barra y teclado -------------------------------------------------------------
|
|
2140
|
+
isCollapsed(path) {
|
|
2141
|
+
return this.collapsed().has(path);
|
|
2142
|
+
}
|
|
2143
|
+
toggleOutline(path) {
|
|
2144
|
+
this.collapsed.update((set) => {
|
|
2145
|
+
const next = new Set(set);
|
|
2146
|
+
if (next.has(path))
|
|
2147
|
+
next.delete(path);
|
|
2148
|
+
else
|
|
2149
|
+
next.add(path);
|
|
2150
|
+
return next;
|
|
2151
|
+
});
|
|
2152
|
+
}
|
|
2153
|
+
openOutlineItem(item) {
|
|
2154
|
+
if (item.dest)
|
|
2155
|
+
void this.goToDestination(item.dest);
|
|
2156
|
+
else if (item.url && this.externalLinks() && SAFE_URL.test(item.url))
|
|
2157
|
+
globalThis.open?.(item.url, '_blank', 'noopener,noreferrer');
|
|
2158
|
+
}
|
|
2159
|
+
/** Acciones con nombre de los enlaces (NextPage, PrevPage, FirstPage, LastPage). */
|
|
2160
|
+
namedAction(action) {
|
|
2161
|
+
if (action === 'NextPage')
|
|
2162
|
+
this.nextPage();
|
|
2163
|
+
else if (action === 'PrevPage')
|
|
2164
|
+
this.previousPage();
|
|
2165
|
+
else if (action === 'FirstPage')
|
|
2166
|
+
this.goToPage(1);
|
|
2167
|
+
else if (action === 'LastPage')
|
|
2168
|
+
this.goToPage(this.numPages());
|
|
2169
|
+
}
|
|
2170
|
+
onFormInput() {
|
|
2171
|
+
this.formChange.emit();
|
|
2172
|
+
}
|
|
980
2173
|
onPageInput(event) {
|
|
981
2174
|
const input = event.target;
|
|
982
2175
|
const value = Number.parseInt(input.value, 10);
|
|
@@ -995,6 +2188,11 @@ class CbPdfViewer {
|
|
|
995
2188
|
this.thumbEls()[next - 1]?.nativeElement.focus();
|
|
996
2189
|
}
|
|
997
2190
|
onHostKeydown(event) {
|
|
2191
|
+
if (event.key === 'Escape' && this.tool() !== 'none') {
|
|
2192
|
+
this.tool.set('none');
|
|
2193
|
+
event.preventDefault();
|
|
2194
|
+
return;
|
|
2195
|
+
}
|
|
998
2196
|
if (this.state() !== 'ready' || !(event.ctrlKey || event.metaKey) || event.altKey)
|
|
999
2197
|
return;
|
|
1000
2198
|
const key = event.key.toLowerCase();
|
|
@@ -1045,7 +2243,7 @@ class CbPdfViewer {
|
|
|
1045
2243
|
return (size.rotate + this.rotation()) % 180 === 0 ? [size.width, size.height] : [size.height, size.width];
|
|
1046
2244
|
}
|
|
1047
2245
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.5", ngImport: i0, type: CbPdfViewer, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
1048
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.5", type: CbPdfViewer, isStandalone: true, selector: "cb-pdf-viewer", inputs: { src: { classPropertyName: "src", publicName: "src", isSignal: true, isRequired: false, transformFunction: null }, fileName: { classPropertyName: "fileName", publicName: "fileName", isSignal: true, isRequired: false, transformFunction: null }, password: { classPropertyName: "password", publicName: "password", isSignal: true, isRequired: false, transformFunction: null }, withCredentials: { classPropertyName: "withCredentials", publicName: "withCredentials", isSignal: true, isRequired: false, transformFunction: null }, httpHeaders: { classPropertyName: "httpHeaders", publicName: "httpHeaders", isSignal: true, isRequired: false, transformFunction: null }, page: { classPropertyName: "page", publicName: "page", isSignal: true, isRequired: false, transformFunction: null }, zoom: { classPropertyName: "zoom", publicName: "zoom", isSignal: true, isRequired: false, transformFunction: null }, rotation: { classPropertyName: "rotation", publicName: "rotation", isSignal: true, isRequired: false, transformFunction: null }, sidebar: { classPropertyName: "sidebar", publicName: "sidebar", isSignal: true, isRequired: false, transformFunction: null }, showToolbar: { classPropertyName: "showToolbar", publicName: "showToolbar", isSignal: true, isRequired: false, transformFunction: null }, showSearch: { classPropertyName: "showSearch", publicName: "showSearch", isSignal: true, isRequired: false, transformFunction: null }, showThumbnails: { classPropertyName: "showThumbnails", publicName: "showThumbnails", isSignal: true, isRequired: false, transformFunction: null }, showRotate: { classPropertyName: "showRotate", publicName: "showRotate", isSignal: true, isRequired: false, transformFunction: null }, downloadable: { classPropertyName: "downloadable", publicName: "downloadable", isSignal: true, isRequired: false, transformFunction: null }, printable: { classPropertyName: "printable", publicName: "printable", isSignal: true, isRequired: false, transformFunction: null }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "ariaLabel", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { page: "pageChange", zoom: "zoomChange", rotation: "rotationChange", sidebar: "sidebarChange", loaded: "loaded", loadError: "loadError" }, host: { attributes: { "role": "region" }, listeners: { "keydown": "onHostKeydown($event)" }, properties: { "attr.aria-label": "ariaLabel() || t().pdfViewer" }, classAttribute: "cb-pdf-viewer" }, viewQueries: [{ propertyName: "viewport", first: true, predicate: ["viewport"], descendants: true, isSignal: true }, { propertyName: "pageEls", predicate: ["pageEl"], descendants: true, isSignal: true }, { propertyName: "thumbEls", predicate: ["thumbEl"], descendants: true, isSignal: true }, { propertyName: "searchInput", first: true, predicate: ["searchInput"], descendants: true, isSignal: true }, { propertyName: "passwordInput", first: true, predicate: ["passwordInput"], descendants: true, isSignal: true }], ngImport: i0, template: `
|
|
2246
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.5", type: CbPdfViewer, isStandalone: true, selector: "cb-pdf-viewer", inputs: { src: { classPropertyName: "src", publicName: "src", isSignal: true, isRequired: false, transformFunction: null }, fileName: { classPropertyName: "fileName", publicName: "fileName", isSignal: true, isRequired: false, transformFunction: null }, password: { classPropertyName: "password", publicName: "password", isSignal: true, isRequired: false, transformFunction: null }, withCredentials: { classPropertyName: "withCredentials", publicName: "withCredentials", isSignal: true, isRequired: false, transformFunction: null }, httpHeaders: { classPropertyName: "httpHeaders", publicName: "httpHeaders", isSignal: true, isRequired: false, transformFunction: null }, page: { classPropertyName: "page", publicName: "page", isSignal: true, isRequired: false, transformFunction: null }, zoom: { classPropertyName: "zoom", publicName: "zoom", isSignal: true, isRequired: false, transformFunction: null }, rotation: { classPropertyName: "rotation", publicName: "rotation", isSignal: true, isRequired: false, transformFunction: null }, sidebar: { classPropertyName: "sidebar", publicName: "sidebar", isSignal: true, isRequired: false, transformFunction: null }, showToolbar: { classPropertyName: "showToolbar", publicName: "showToolbar", isSignal: true, isRequired: false, transformFunction: null }, showSearch: { classPropertyName: "showSearch", publicName: "showSearch", isSignal: true, isRequired: false, transformFunction: null }, showThumbnails: { classPropertyName: "showThumbnails", publicName: "showThumbnails", isSignal: true, isRequired: false, transformFunction: null }, showRotate: { classPropertyName: "showRotate", publicName: "showRotate", isSignal: true, isRequired: false, transformFunction: null }, downloadable: { classPropertyName: "downloadable", publicName: "downloadable", isSignal: true, isRequired: false, transformFunction: null }, printable: { classPropertyName: "printable", publicName: "printable", isSignal: true, isRequired: false, transformFunction: null }, showOutline: { classPropertyName: "showOutline", publicName: "showOutline", isSignal: true, isRequired: false, transformFunction: null }, forms: { classPropertyName: "forms", publicName: "forms", isSignal: true, isRequired: false, transformFunction: null }, externalLinks: { classPropertyName: "externalLinks", publicName: "externalLinks", isSignal: true, isRequired: false, transformFunction: null }, sidebarView: { classPropertyName: "sidebarView", publicName: "sidebarView", isSignal: true, isRequired: false, transformFunction: null }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "ariaLabel", isSignal: true, isRequired: false, transformFunction: null }, annotatable: { classPropertyName: "annotatable", publicName: "annotatable", isSignal: true, isRequired: false, transformFunction: null }, annotations: { classPropertyName: "annotations", publicName: "annotations", isSignal: true, isRequired: false, transformFunction: null }, tool: { classPropertyName: "tool", publicName: "tool", isSignal: true, isRequired: false, transformFunction: null }, annotationColor: { classPropertyName: "annotationColor", publicName: "annotationColor", isSignal: true, isRequired: false, transformFunction: null }, author: { classPropertyName: "author", publicName: "author", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { page: "pageChange", zoom: "zoomChange", rotation: "rotationChange", sidebar: "sidebarChange", sidebarView: "sidebarViewChange", annotations: "annotationsChange", tool: "toolChange", annotationColor: "annotationColorChange", loaded: "loaded", loadError: "loadError", formChange: "formChange", annotationAdd: "annotationAdd", annotationRemove: "annotationRemove" }, host: { attributes: { "role": "region" }, listeners: { "keydown": "onHostKeydown($event)" }, properties: { "attr.aria-label": "ariaLabel() || t().pdfViewer" }, classAttribute: "cb-pdf-viewer" }, viewQueries: [{ propertyName: "viewport", first: true, predicate: ["viewport"], descendants: true, isSignal: true }, { propertyName: "pageEls", predicate: ["pageEl"], descendants: true, isSignal: true }, { propertyName: "thumbEls", predicate: ["thumbEl"], descendants: true, isSignal: true }, { propertyName: "searchInput", first: true, predicate: ["searchInput"], descendants: true, isSignal: true }, { propertyName: "passwordInput", first: true, predicate: ["passwordInput"], descendants: true, isSignal: true }, { propertyName: "cardText", first: true, predicate: ["cardText"], descendants: true, isSignal: true }], ngImport: i0, template: `
|
|
1049
2247
|
@if (showToolbar()) {
|
|
1050
2248
|
<div class="cb-pdf__toolbar">
|
|
1051
2249
|
@if (showThumbnails()) {
|
|
@@ -1128,6 +2326,70 @@ class CbPdfViewer {
|
|
|
1128
2326
|
}
|
|
1129
2327
|
</div>
|
|
1130
2328
|
|
|
2329
|
+
@if (annotatable()) {
|
|
2330
|
+
<div class="cb-pdf__group" role="group" [attr.aria-label]="t().pdfAnnotate">
|
|
2331
|
+
<!-- mousedown sin default: pulsar la herramienta no quita la selección de texto. -->
|
|
2332
|
+
<button
|
|
2333
|
+
type="button"
|
|
2334
|
+
class="cb-pdf__tool"
|
|
2335
|
+
[attr.aria-label]="t().pdfHighlight"
|
|
2336
|
+
[attr.aria-pressed]="tool() === 'highlight'"
|
|
2337
|
+
[attr.title]="t().pdfHighlight"
|
|
2338
|
+
[disabled]="state() !== 'ready'"
|
|
2339
|
+
(mousedown)="$event.preventDefault()"
|
|
2340
|
+
(click)="onHighlightTool()"
|
|
2341
|
+
>
|
|
2342
|
+
<cb-icon name="highlighter" [size]="18" aria-hidden="true" />
|
|
2343
|
+
</button>
|
|
2344
|
+
<button
|
|
2345
|
+
type="button"
|
|
2346
|
+
class="cb-pdf__tool"
|
|
2347
|
+
[attr.aria-label]="t().pdfNote"
|
|
2348
|
+
[attr.aria-pressed]="tool() === 'note'"
|
|
2349
|
+
[attr.title]="t().pdfNote"
|
|
2350
|
+
[disabled]="state() !== 'ready'"
|
|
2351
|
+
(click)="onNoteTool($event)"
|
|
2352
|
+
>
|
|
2353
|
+
<cb-icon name="sticky-note" [size]="18" aria-hidden="true" />
|
|
2354
|
+
</button>
|
|
2355
|
+
<button
|
|
2356
|
+
type="button"
|
|
2357
|
+
class="cb-pdf__tool"
|
|
2358
|
+
[attr.aria-label]="t().pdfDraw"
|
|
2359
|
+
[attr.aria-pressed]="tool() === 'ink'"
|
|
2360
|
+
[attr.title]="t().pdfDraw"
|
|
2361
|
+
[disabled]="state() !== 'ready'"
|
|
2362
|
+
(click)="toggleTool('ink')"
|
|
2363
|
+
>
|
|
2364
|
+
<cb-icon name="pen-line" [size]="18" aria-hidden="true" />
|
|
2365
|
+
</button>
|
|
2366
|
+
<button
|
|
2367
|
+
type="button"
|
|
2368
|
+
class="cb-pdf__tool"
|
|
2369
|
+
aria-haspopup="dialog"
|
|
2370
|
+
[attr.aria-label]="t().pdfSign"
|
|
2371
|
+
[attr.title]="t().pdfSign"
|
|
2372
|
+
[disabled]="state() !== 'ready'"
|
|
2373
|
+
(click)="openSignature()"
|
|
2374
|
+
>
|
|
2375
|
+
<cb-icon name="signature" [size]="18" aria-hidden="true" />
|
|
2376
|
+
</button>
|
|
2377
|
+
<span class="cb-pdf__color">
|
|
2378
|
+
<span class="cb-pdf__swatch" aria-hidden="true" [style.background]="colors[annotationColor()].light" [style.border-color]="colors[annotationColor()].dark"></span>
|
|
2379
|
+
<select
|
|
2380
|
+
class="cb-pdf__field cb-pdf__color-select"
|
|
2381
|
+
[attr.aria-label]="t().pdfColor"
|
|
2382
|
+
[disabled]="state() !== 'ready'"
|
|
2383
|
+
(change)="annotationColor.set($any($event.target).value)"
|
|
2384
|
+
>
|
|
2385
|
+
@for (c of colorNames; track c) {
|
|
2386
|
+
<option [value]="c" [selected]="annotationColor() === c">{{ colorLabel(c) }}</option>
|
|
2387
|
+
}
|
|
2388
|
+
</select>
|
|
2389
|
+
</span>
|
|
2390
|
+
</div>
|
|
2391
|
+
}
|
|
2392
|
+
|
|
1131
2393
|
<span class="cb-pdf__spacer"></span>
|
|
1132
2394
|
|
|
1133
2395
|
@if (showSearch()) {
|
|
@@ -1158,7 +2420,14 @@ class CbPdfViewer {
|
|
|
1158
2420
|
@if (downloadable() || printable()) {
|
|
1159
2421
|
<div class="cb-pdf__group">
|
|
1160
2422
|
@if (downloadable()) {
|
|
1161
|
-
<button
|
|
2423
|
+
<button
|
|
2424
|
+
type="button"
|
|
2425
|
+
class="cb-pdf__tool"
|
|
2426
|
+
[attr.aria-label]="annotations().length ? t().pdfDownloadAnnotated : formModified() ? t().pdfDownloadFilled : t().download"
|
|
2427
|
+
[attr.title]="annotations().length ? t().pdfDownloadAnnotated : formModified() ? t().pdfDownloadFilled : null"
|
|
2428
|
+
[disabled]="state() !== 'ready'"
|
|
2429
|
+
(click)="download()"
|
|
2430
|
+
>
|
|
1162
2431
|
<cb-icon name="download" [size]="18" aria-hidden="true" />
|
|
1163
2432
|
</button>
|
|
1164
2433
|
}
|
|
@@ -1180,7 +2449,51 @@ class CbPdfViewer {
|
|
|
1180
2449
|
|
|
1181
2450
|
<div class="cb-pdf__body">
|
|
1182
2451
|
@if (state() === 'ready' && sidebar() && showThumbnails()) {
|
|
1183
|
-
<
|
|
2452
|
+
<div
|
|
2453
|
+
class="cb-pdf__sidebar"
|
|
2454
|
+
[class.cb-pdf__sidebar--tabs]="sidebarTabs().length > 1"
|
|
2455
|
+
[class.cb-pdf__sidebar--outline]="activeView() !== 'thumbnails' || sidebarTabs().length > 2"
|
|
2456
|
+
[id]="uid + '-thumbs'"
|
|
2457
|
+
>
|
|
2458
|
+
@if (sidebarTabs().length > 1) {
|
|
2459
|
+
<div class="cb-pdf__views" role="group" [attr.aria-label]="t().pdfSidebarView">
|
|
2460
|
+
@for (view of sidebarTabs(); track view) {
|
|
2461
|
+
<button type="button" class="cb-pdf__view" [attr.aria-pressed]="activeView() === view" (click)="sidebarView.set(view)">
|
|
2462
|
+
{{ view === 'outline' ? t().pdfOutline : view === 'annotations' ? t().pdfAnnotations : t().thumbnails }}
|
|
2463
|
+
</button>
|
|
2464
|
+
}
|
|
2465
|
+
</div>
|
|
2466
|
+
}
|
|
2467
|
+
@if (activeView() === 'outline') {
|
|
2468
|
+
<nav class="cb-pdf__outline" [attr.aria-label]="t().pdfOutline">
|
|
2469
|
+
<ng-container *ngTemplateOutlet="outlineList; context: { $implicit: outline(), path: '' }" />
|
|
2470
|
+
</nav>
|
|
2471
|
+
} @else if (activeView() === 'annotations') {
|
|
2472
|
+
<section class="cb-pdf__notes-panel" [attr.aria-label]="t().pdfAnnotations">
|
|
2473
|
+
@if (!sortedAnnotations().length) {
|
|
2474
|
+
<p class="cb-pdf__notes-empty">{{ t().pdfNoAnnotations }}</p>
|
|
2475
|
+
} @else {
|
|
2476
|
+
<ul class="cb-pdf__notes-list">
|
|
2477
|
+
@for (a of sortedAnnotations(); track a.id) {
|
|
2478
|
+
<li class="cb-pdf__notes-item">
|
|
2479
|
+
<button type="button" class="cb-pdf__notes-link" (click)="revealAnnotation(a)">
|
|
2480
|
+
<span class="cb-pdf__notes-swatch" aria-hidden="true" [style.background]="swatchOf(a)"></span>
|
|
2481
|
+
<span class="cb-pdf__notes-text">
|
|
2482
|
+
<!-- La coma oculta separa la página del texto en el nombre del botón. -->
|
|
2483
|
+
<span class="cb-pdf__notes-page">{{ format(t().pageOf, a.page, numPages()) }}<span class="cb-pdf__sr">, </span></span>
|
|
2484
|
+
<span class="cb-pdf__notes-label">{{ labelOf(a) }}</span>
|
|
2485
|
+
</span>
|
|
2486
|
+
</button>
|
|
2487
|
+
<button type="button" class="cb-pdf__notes-remove" [attr.aria-label]="t().pdfDeleteAnnotation + ': ' + labelOf(a)" (click)="removeAnnotation(a)">
|
|
2488
|
+
<cb-icon name="trash" [size]="14" aria-hidden="true" />
|
|
2489
|
+
</button>
|
|
2490
|
+
</li>
|
|
2491
|
+
}
|
|
2492
|
+
</ul>
|
|
2493
|
+
}
|
|
2494
|
+
</section>
|
|
2495
|
+
} @else {
|
|
2496
|
+
<nav class="cb-pdf__thumbs" [attr.aria-label]="t().thumbnails">
|
|
1184
2497
|
@for (thumb of thumbBoxes(); track $index; let i = $index) {
|
|
1185
2498
|
<button
|
|
1186
2499
|
#thumbEl
|
|
@@ -1197,7 +2510,9 @@ class CbPdfViewer {
|
|
|
1197
2510
|
<span class="cb-pdf__thumb-label" aria-hidden="true">{{ i + 1 }}</span>
|
|
1198
2511
|
</button>
|
|
1199
2512
|
}
|
|
1200
|
-
|
|
2513
|
+
</nav>
|
|
2514
|
+
}
|
|
2515
|
+
</div>
|
|
1201
2516
|
}
|
|
1202
2517
|
|
|
1203
2518
|
<div
|
|
@@ -1243,7 +2558,10 @@ class CbPdfViewer {
|
|
|
1243
2558
|
</form>
|
|
1244
2559
|
}
|
|
1245
2560
|
@case ('ready') {
|
|
1246
|
-
|
|
2561
|
+
@if (toolHint(); as hint) {
|
|
2562
|
+
<div class="cb-pdf__hint">{{ hint }}</div>
|
|
2563
|
+
}
|
|
2564
|
+
<div class="cb-pdf__pages" (pointerup)="onPagesPointerUp()">
|
|
1247
2565
|
@for (box of pageBoxes(); track $index; let i = $index) {
|
|
1248
2566
|
<div
|
|
1249
2567
|
#pageEl
|
|
@@ -1258,6 +2576,97 @@ class CbPdfViewer {
|
|
|
1258
2576
|
>
|
|
1259
2577
|
<div class="cb-pdf__canvas"></div>
|
|
1260
2578
|
<div class="cb-pdf__text"></div>
|
|
2579
|
+
<div class="cb-pdf__annotations" (input)="onFormInput()" (change)="onFormInput()"></div>
|
|
2580
|
+
@if (annotatable() || marks()[i]?.length) {
|
|
2581
|
+
<div
|
|
2582
|
+
class="cb-pdf__marks"
|
|
2583
|
+
[class.cb-pdf__marks--capture]="annotatable() && (tool() === 'ink' || tool() === 'note')"
|
|
2584
|
+
[class.cb-pdf__marks--ink]="tool() === 'ink'"
|
|
2585
|
+
[class.cb-pdf__marks--pass]="tool() === 'highlight'"
|
|
2586
|
+
(pointerdown)="onMarksPointerDown($event, i + 1)"
|
|
2587
|
+
>
|
|
2588
|
+
@for (m of marks()[i]; track m.a.id) {
|
|
2589
|
+
<div
|
|
2590
|
+
class="cb-pdf__mark"
|
|
2591
|
+
[class]="'cb-pdf__mark cb-pdf__mark--' + m.a.type"
|
|
2592
|
+
[class.cb-is-selected]="selectedId() === m.a.id"
|
|
2593
|
+
[attr.data-id]="m.a.id"
|
|
2594
|
+
[attr.tabindex]="annotatable() ? 0 : null"
|
|
2595
|
+
[attr.role]="annotatable() ? 'button' : 'img'"
|
|
2596
|
+
[attr.aria-label]="m.label"
|
|
2597
|
+
[attr.aria-describedby]="annotatable() ? uid + '-mark-hint' : null"
|
|
2598
|
+
[attr.aria-expanded]="annotatable() && (m.a.type === 'note' || m.a.type === 'highlight') ? editingId() === m.a.id : null"
|
|
2599
|
+
[style.left.px]="m.box.left"
|
|
2600
|
+
[style.top.px]="m.box.top"
|
|
2601
|
+
[style.width.px]="m.a.type === 'note' ? null : m.box.width"
|
|
2602
|
+
[style.height.px]="m.a.type === 'note' ? null : m.box.height"
|
|
2603
|
+
[style.--cb-pdf-mark-light]="m.light"
|
|
2604
|
+
[style.--cb-pdf-mark-dark]="m.dark"
|
|
2605
|
+
(pointerdown)="onMarkPointerDown($event, m.a)"
|
|
2606
|
+
(keydown)="onMarkKeydown($event, m.a)"
|
|
2607
|
+
(focus)="select(m.a.id)"
|
|
2608
|
+
>
|
|
2609
|
+
@switch (m.a.type) {
|
|
2610
|
+
@case ('highlight') {
|
|
2611
|
+
@for (r of m.rects; track $index) {
|
|
2612
|
+
<span class="cb-pdf__hl-rect" [style.left.px]="r.left" [style.top.px]="r.top" [style.width.px]="r.width" [style.height.px]="r.height"></span>
|
|
2613
|
+
}
|
|
2614
|
+
@if (m.a.comment) {
|
|
2615
|
+
<span class="cb-pdf__hl-badge" aria-hidden="true"></span>
|
|
2616
|
+
}
|
|
2617
|
+
}
|
|
2618
|
+
@case ('note') {
|
|
2619
|
+
<span class="cb-pdf__note-text" [style.font-size.px]="m.fontPx" [style.min-width.px]="m.box.width">{{ m.a.text || ' ' }}</span>
|
|
2620
|
+
}
|
|
2621
|
+
@case ('ink') {
|
|
2622
|
+
<svg class="cb-pdf__ink" [attr.viewBox]="'0 0 ' + m.box.width + ' ' + m.box.height" aria-hidden="true">
|
|
2623
|
+
<path [attr.d]="m.d" [attr.stroke-width]="m.strokePx" />
|
|
2624
|
+
</svg>
|
|
2625
|
+
}
|
|
2626
|
+
@case ('signature') {
|
|
2627
|
+
<img class="cb-pdf__sig" [src]="m.a.image" alt="" draggable="false" />
|
|
2628
|
+
@if (annotatable() && selectedId() === m.a.id) {
|
|
2629
|
+
<span class="cb-pdf__resize" aria-hidden="true" (pointerdown)="onResizePointerDown($event, m.a)"></span>
|
|
2630
|
+
}
|
|
2631
|
+
}
|
|
2632
|
+
}
|
|
2633
|
+
</div>
|
|
2634
|
+
}
|
|
2635
|
+
@if (stroke(); as s) {
|
|
2636
|
+
@if (s.page === i + 1) {
|
|
2637
|
+
<svg class="cb-pdf__stroke" aria-hidden="true" [style.--cb-pdf-mark-dark]="colors[annotationColor()].dark">
|
|
2638
|
+
<polyline [attr.points]="s.points.join(' ')" [attr.stroke-width]="2 * box.scaleFactor" />
|
|
2639
|
+
</svg>
|
|
2640
|
+
}
|
|
2641
|
+
}
|
|
2642
|
+
@if (editingMark(); as e) {
|
|
2643
|
+
@if (e.a.page === i + 1) {
|
|
2644
|
+
<div
|
|
2645
|
+
class="cb-pdf__card"
|
|
2646
|
+
role="group"
|
|
2647
|
+
[attr.aria-label]="e.label"
|
|
2648
|
+
[style.left.px]="cardLeft(e, box.width)"
|
|
2649
|
+
[style.top.px]="e.box.top + (e.a.type === 'note' ? noteHeight(e) : e.box.height) + 6"
|
|
2650
|
+
(pointerdown)="$event.stopPropagation()"
|
|
2651
|
+
(keydown)="onCardKeydown($event)"
|
|
2652
|
+
>
|
|
2653
|
+
<label class="cb-pdf__card-label" [for]="uid + '-card'">{{ e.a.type === 'note' ? t().pdfNoteText : t().pdfComment }}</label>
|
|
2654
|
+
<textarea
|
|
2655
|
+
#cardText
|
|
2656
|
+
class="cb-pdf__field cb-pdf__card-text"
|
|
2657
|
+
rows="3"
|
|
2658
|
+
[id]="uid + '-card'"
|
|
2659
|
+
(input)="onCardInput($any($event.target).value)"
|
|
2660
|
+
></textarea>
|
|
2661
|
+
<div class="cb-pdf__card-actions">
|
|
2662
|
+
<button type="button" class="cb-pdf__card-btn" (click)="removeAnnotation(e.a)">{{ t().pdfDeleteAnnotation }}</button>
|
|
2663
|
+
<button type="button" class="cb-pdf__card-btn cb-pdf__card-btn--primary" (click)="closeEditor(true)">{{ t().pdfDone }}</button>
|
|
2664
|
+
</div>
|
|
2665
|
+
</div>
|
|
2666
|
+
}
|
|
2667
|
+
}
|
|
2668
|
+
</div>
|
|
2669
|
+
}
|
|
1261
2670
|
</div>
|
|
1262
2671
|
}
|
|
1263
2672
|
</div>
|
|
@@ -1266,14 +2675,60 @@ class CbPdfViewer {
|
|
|
1266
2675
|
</div>
|
|
1267
2676
|
</div>
|
|
1268
2677
|
|
|
2678
|
+
@if (annotatable()) {
|
|
2679
|
+
<span class="cb-pdf__sr" [id]="uid + '-mark-hint'">{{ t().pdfAnnotationHint }}</span>
|
|
2680
|
+
<span class="cb-pdf__sr" aria-live="polite">{{ announcement() }}</span>
|
|
2681
|
+
<cb-dialog [(visible)]="signing" [header]="t().pdfSignTitle" width="34rem" (onHide)="onSignatureHide()">
|
|
2682
|
+
<cb-signature-pad [(value)]="signatureValue" background="transparent" [ariaLabel]="t().pdfSignTitle" />
|
|
2683
|
+
<div cb-dialog-footer class="cb-pdf__sign-actions">
|
|
2684
|
+
<button type="button" class="cb-pdf__card-btn" (click)="signing.set(false)">{{ t().pdfCancel }}</button>
|
|
2685
|
+
<button type="button" class="cb-pdf__card-btn cb-pdf__card-btn--primary" [disabled]="!signatureValue()" (click)="insertSignature()">
|
|
2686
|
+
{{ t().pdfInsertSignature }}
|
|
2687
|
+
</button>
|
|
2688
|
+
</div>
|
|
2689
|
+
</cb-dialog>
|
|
2690
|
+
}
|
|
2691
|
+
|
|
2692
|
+
<ng-template #outlineList let-items let-path="path">
|
|
2693
|
+
<ul class="cb-pdf__outline-list" [attr.role]="path ? 'group' : null">
|
|
2694
|
+
@for (item of items; track $index; let i = $index) {
|
|
2695
|
+
<li class="cb-pdf__outline-item">
|
|
2696
|
+
@if (item.items.length) {
|
|
2697
|
+
<button
|
|
2698
|
+
type="button"
|
|
2699
|
+
class="cb-pdf__outline-toggle"
|
|
2700
|
+
[attr.aria-expanded]="!isCollapsed(path + i)"
|
|
2701
|
+
[attr.aria-label]="format(isCollapsed(path + i) ? t().pdfExpandItem : t().pdfCollapseItem, item.title)"
|
|
2702
|
+
(click)="toggleOutline(path + i)"
|
|
2703
|
+
>
|
|
2704
|
+
<cb-icon [name]="isCollapsed(path + i) ? 'chevron-right' : 'chevron-down'" [size]="14" aria-hidden="true" />
|
|
2705
|
+
</button>
|
|
2706
|
+
}
|
|
2707
|
+
<button
|
|
2708
|
+
type="button"
|
|
2709
|
+
class="cb-pdf__outline-link"
|
|
2710
|
+
[class.cb-pdf__outline-link--bold]="item.bold"
|
|
2711
|
+
[class.cb-pdf__outline-link--italic]="item.italic"
|
|
2712
|
+
(click)="openOutlineItem(item)"
|
|
2713
|
+
>
|
|
2714
|
+
{{ item.title }}
|
|
2715
|
+
</button>
|
|
2716
|
+
@if (item.items.length && !isCollapsed(path + i)) {
|
|
2717
|
+
<ng-container *ngTemplateOutlet="outlineList; context: { $implicit: item.items, path: path + i + '.' }" />
|
|
2718
|
+
}
|
|
2719
|
+
</li>
|
|
2720
|
+
}
|
|
2721
|
+
</ul>
|
|
2722
|
+
</ng-template>
|
|
2723
|
+
|
|
1269
2724
|
@if (printProgress(); as p) {
|
|
1270
2725
|
<div class="cb-pdf__toast" role="status">{{ format(t().preparingPrint, p.done, p.total) }}</div>
|
|
1271
2726
|
}
|
|
1272
|
-
`, isInline: true, styles: [":host{position:relative;display:flex;flex-direction:column;box-sizing:border-box;width:100%;height:var(--cb-pdf-viewer-height, 40rem);min-height:16rem;overflow:hidden;border:var(--cb-border-width, 1px) solid var(--cb-color-border);border-radius:var(--cb-radius-lg);background:var(--cb-color-surface);color:var(--cb-color-text);font-family:var(--cb-font-sans);font-size:var(--cb-text-sm);container-type:inline-size}.cb-pdf__toolbar{display:flex;flex-wrap:wrap;align-items:center;gap:var(--cb-space-2);padding:var(--cb-space-2) var(--cb-space-3);border-bottom:var(--cb-border-width, 1px) solid var(--cb-color-border);background:var(--cb-color-surface)}.cb-pdf__group{display:inline-flex;align-items:center;gap:var(--cb-space-1)}.cb-pdf__spacer{flex:1}.cb-pdf__tool{display:inline-flex;align-items:center;justify-content:center;width:2.25rem;height:2.25rem;padding:0;border:none;border-radius:var(--cb-radius-md);background:transparent;color:var(--cb-color-text);cursor:pointer;transition:background-color var(--cb-duration-fast) var(--cb-ease)}.cb-pdf__tool:hover:not(:disabled){background:var(--cb-color-surface-hover)}.cb-pdf__tool[aria-expanded=true]{background:var(--cb-color-surface-hover);color:var(--cb-color-primary-600)}.cb-pdf__tool:disabled{opacity:var(--cb-opacity-disabled, .5);cursor:default}.cb-pdf__tool:focus-visible,.cb-pdf__field:focus-visible,.cb-pdf__thumb:focus-visible,.cb-pdf__submit:focus-visible,.cb-pdf__viewport:focus-visible{outline:2px solid var(--cb-color-focus-ring);outline-offset:2px}.cb-pdf__field{height:2.25rem;padding:0 var(--cb-space-2);border:var(--cb-border-width, 1px) solid var(--cb-color-border-strong);border-radius:var(--cb-radius-md);background:var(--cb-color-surface);color:var(--cb-color-text);font:inherit}.cb-pdf__field:disabled{opacity:var(--cb-opacity-disabled, .5)}.cb-pdf__page-input{width:3.25rem;text-align:center}.cb-pdf__total{min-width:2.5rem;color:var(--cb-color-text-muted);white-space:nowrap}.cb-pdf__zoom{width:9.5rem}.cb-pdf__search{position:relative}.cb-pdf__search-icon{position:absolute;left:.625rem;color:var(--cb-color-text-muted);pointer-events:none}.cb-pdf__search-input{width:14rem;padding-left:2rem}.cb-pdf__status{min-width:4.5rem;color:var(--cb-color-text-muted);font-size:var(--cb-text-xs);text-align:center;white-space:nowrap}@container (max-width: 40rem){.cb-pdf__zoom,.cb-pdf__status{display:none}.cb-pdf__search-input{width:9rem}}.cb-pdf__body{display:flex;flex:1;min-height:0}.cb-pdf__sidebar{display:flex;flex-direction:column;align-items:center;gap:var(--cb-space-3);flex:none;width:10rem;padding:var(--cb-space-3) 0;overflow-y:auto;border-right:var(--cb-border-width, 1px) solid var(--cb-color-border);background:var(--cb-color-surface)}.cb-pdf__thumb{display:flex;flex-direction:column;align-items:center;gap:var(--cb-space-1);padding:var(--cb-space-1);border:2px solid transparent;border-radius:var(--cb-radius-md);background:transparent;color:var(--cb-color-text-muted);font:inherit;font-size:var(--cb-text-xs);cursor:pointer}.cb-pdf__thumb:hover{background:var(--cb-color-surface-hover)}.cb-pdf__thumb.cb-is-active{border-color:var(--cb-color-primary-500);color:var(--cb-color-text-strong);font-weight:var(--cb-font-weight-semibold)}.cb-pdf__thumb-canvas{display:block;background:#fff;box-shadow:0 1px 3px #0f172a33}:host ::ng-deep .cb-pdf__thumb-canvas canvas{display:block;width:100%;height:100%}.cb-pdf__viewport{position:relative;flex:1;min-width:0;overflow:auto;background:var(--cb-color-surface-subtle)}.cb-pdf__pages{display:flex;flex-direction:column;align-items:center;gap:16px;padding:16px;width:max-content;min-width:100%;box-sizing:border-box}.cb-pdf__page{--user-unit: 1;--total-scale-factor: calc(var(--scale-factor) * var(--user-unit));--scale-round-x: 1px;--scale-round-y: 1px;position:relative;flex:none;background:#fff;box-shadow:0 1px 3px #0f172a2e,0 4px 12px #0f172a14;direction:ltr}.cb-pdf__canvas,:host ::ng-deep .cb-pdf__canvas canvas{position:absolute;inset:0;width:100%;height:100%}.cb-pdf__text{position:absolute;inset:0;overflow:clip;opacity:1;line-height:1;text-align:initial;letter-spacing:normal;word-spacing:normal;-webkit-text-size-adjust:none;text-size-adjust:none;forced-color-adjust:none;transform-origin:0 0;caret-color:CanvasText;z-index:0;--min-font-size: 1;--text-scale-factor: calc(var(--total-scale-factor) * var(--min-font-size));--min-font-size-inv: calc(1 / var(--min-font-size))}.cb-pdf__text[data-main-rotation=\"90\"]{transform:rotate(90deg) translateY(-100%)}.cb-pdf__text[data-main-rotation=\"180\"]{transform:rotate(180deg) translate(-100%,-100%)}.cb-pdf__text[data-main-rotation=\"270\"]{transform:rotate(270deg) translate(-100%)}:host ::ng-deep .cb-pdf__text :is(span,br){position:absolute;color:transparent;white-space:pre;cursor:text;transform-origin:0% 0%;-webkit-user-select:text;user-select:text}:host ::ng-deep .cb-pdf__text>:not(.markedContent),:host ::ng-deep .cb-pdf__text .markedContent span:not(.markedContent){--font-height: 0;--scale-x: 1;--rotate: 0deg;z-index:1;font-size:calc(var(--text-scale-factor) * var(--font-height));transform:rotate(var(--rotate)) scaleX(var(--scale-x)) scale(var(--min-font-size-inv))}:host ::ng-deep .cb-pdf__text .markedContent{display:contents}:host ::ng-deep .cb-pdf__text span[role=img]{-webkit-user-select:none;user-select:none;cursor:default}:host ::ng-deep .cb-pdf__text ::selection{background:color-mix(in srgb,var(--cb-color-primary-500) 35%,transparent);color:transparent}:host ::ng-deep .cb-pdf__text .cb-pdf__hl{position:relative;margin:-1px;padding:1px;border-radius:3px;background:#facc1573;font-size:inherit;transform:none}:host ::ng-deep .cb-pdf__text .cb-pdf__hl.cb-is-selected{background:#f973168c;outline:2px solid rgb(234 88 12)}@media(forced-colors:active){:host ::ng-deep .cb-pdf__text .cb-pdf__hl{background:transparent;outline:1px solid Highlight}:host ::ng-deep .cb-pdf__text .cb-pdf__hl.cb-is-selected{outline:3px solid Highlight}}.cb-pdf__message{display:flex;flex-direction:column;align-items:center;justify-content:center;gap:var(--cb-space-3);height:100%;padding:var(--cb-space-6);color:var(--cb-color-text-muted);text-align:center}.cb-pdf__message--error{color:var(--cb-color-danger)}.cb-pdf__password{display:flex;flex-direction:column;align-items:center;gap:var(--cb-space-2);max-width:24rem;margin:var(--cb-space-6) auto;padding:var(--cb-space-6);border:var(--cb-border-width, 1px) solid var(--cb-color-border);border-radius:var(--cb-radius-lg);background:var(--cb-color-surface);text-align:center}.cb-pdf__password-text{margin:0}.cb-pdf__password-label{align-self:flex-start;font-weight:var(--cb-font-weight-medium)}.cb-pdf__password-row{display:flex;gap:var(--cb-space-2);width:100%}.cb-pdf__password-row .cb-pdf__field{flex:1;min-width:0}.cb-pdf__password-error{margin:0;color:var(--cb-color-danger)}.cb-pdf__submit{height:2.25rem;padding:0 var(--cb-space-4);border:none;border-radius:var(--cb-radius-md);background:var(--cb-color-primary-500);color:var(--cb-color-primary-contrast);font:inherit;font-weight:var(--cb-font-weight-semibold);cursor:pointer}.cb-pdf__submit:hover{background:var(--cb-color-primary-600)}.cb-pdf__toast{position:absolute;left:50%;bottom:var(--cb-space-4);transform:translate(-50%);padding:var(--cb-space-2) var(--cb-space-4);border-radius:var(--cb-radius-full);background:var(--cb-color-surface-950);color:#fff;box-shadow:var(--cb-shadow-md)}\n"], dependencies: [{ kind: "component", type: CbIcon, selector: "cb-icon", inputs: ["name", "size", "spin", "ariaLabel"] }, { kind: "component", type: CbSpinner, selector: "cb-spinner", inputs: ["size", "strokeWidth", "severity", "ariaLabel"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
2727
|
+
`, isInline: true, styles: [":host{position:relative;display:flex;flex-direction:column;box-sizing:border-box;width:100%;height:var(--cb-pdf-viewer-height, 40rem);min-height:16rem;overflow:hidden;border:var(--cb-border-width, 1px) solid var(--cb-color-border);border-radius:var(--cb-radius-lg);background:var(--cb-color-surface);color:var(--cb-color-text);font-family:var(--cb-font-sans);font-size:var(--cb-text-sm);container-type:inline-size}.cb-pdf__toolbar{display:flex;flex-wrap:wrap;align-items:center;gap:var(--cb-space-2);padding:var(--cb-space-2) var(--cb-space-3);border-bottom:var(--cb-border-width, 1px) solid var(--cb-color-border);background:var(--cb-color-surface)}.cb-pdf__group{display:inline-flex;align-items:center;gap:var(--cb-space-1)}.cb-pdf__spacer{flex:1}.cb-pdf__tool{display:inline-flex;align-items:center;justify-content:center;width:2.25rem;height:2.25rem;padding:0;border:none;border-radius:var(--cb-radius-md);background:transparent;color:var(--cb-color-text);cursor:pointer;transition:background-color var(--cb-duration-fast) var(--cb-ease)}.cb-pdf__tool:hover:not(:disabled){background:var(--cb-color-surface-hover)}.cb-pdf__tool[aria-expanded=true]{background:var(--cb-color-surface-hover);color:var(--cb-color-primary-text)}.cb-pdf__tool:disabled{opacity:var(--cb-opacity-disabled, .5);cursor:default}.cb-pdf__tool:focus-visible,.cb-pdf__field:focus-visible,.cb-pdf__thumb:focus-visible,.cb-pdf__submit:focus-visible,.cb-pdf__viewport:focus-visible{outline:2px solid var(--cb-color-focus-ring);outline-offset:2px}.cb-pdf__field{height:2.25rem;padding:0 var(--cb-space-2);border:var(--cb-border-width, 1px) solid var(--cb-color-border-strong);border-radius:var(--cb-radius-md);background:var(--cb-color-surface);color:var(--cb-color-text);font:inherit}.cb-pdf__field:disabled{opacity:var(--cb-opacity-disabled, .5)}.cb-pdf__page-input{width:3.25rem;text-align:center}.cb-pdf__total{min-width:2.5rem;color:var(--cb-color-text-muted);white-space:nowrap}.cb-pdf__zoom{width:9.5rem}.cb-pdf__search{position:relative}.cb-pdf__search-icon{position:absolute;left:.625rem;color:var(--cb-color-text-muted);pointer-events:none}.cb-pdf__search-input{width:14rem;padding-left:2rem}.cb-pdf__status{min-width:4.5rem;color:var(--cb-color-text-muted);font-size:var(--cb-text-xs);text-align:center;white-space:nowrap}@container (max-width: 40rem){.cb-pdf__zoom,.cb-pdf__status{display:none}.cb-pdf__search-input{width:9rem}}.cb-pdf__body{display:flex;flex:1;min-height:0}.cb-pdf__sidebar{display:flex;flex-direction:column;gap:var(--cb-space-3);flex:none;width:10rem;padding:var(--cb-space-3) 0;overflow-y:auto;border-right:var(--cb-border-width, 1px) solid var(--cb-color-border);background:var(--cb-color-surface)}.cb-pdf__sidebar--tabs{width:12rem}.cb-pdf__sidebar--outline{width:16rem}.cb-pdf__thumbs{display:flex;flex-direction:column;align-items:center;gap:var(--cb-space-3)}.cb-pdf__views{display:flex;gap:2px;margin:0 var(--cb-space-2);padding:2px;border-radius:var(--cb-radius-md);background:var(--cb-color-surface-hover)}.cb-pdf__view{flex:1;min-width:0;padding:.25rem .375rem;border:0;border-radius:calc(var(--cb-radius-md) - 2px);background:transparent;color:var(--cb-color-text-muted);font:inherit;font-size:var(--cb-text-xs);font-weight:var(--cb-font-weight-medium);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;cursor:pointer}.cb-pdf__view[aria-pressed=true]{background:var(--cb-color-surface-raised);color:var(--cb-color-text-strong);box-shadow:0 1px 2px #0f172a1f}.cb-pdf__view:focus-visible,.cb-pdf__outline-link:focus-visible,.cb-pdf__outline-toggle:focus-visible{outline:2px solid var(--cb-color-focus-ring);outline-offset:1px}.cb-pdf__outline{padding:0 var(--cb-space-2)}.cb-pdf__outline-list{margin:0;padding:0;list-style:none}.cb-pdf__outline-list .cb-pdf__outline-list{padding-left:1rem}.cb-pdf__outline-item{display:flex;flex-wrap:wrap;align-items:flex-start}.cb-pdf__outline-item>.cb-pdf__outline-list{flex-basis:100%}.cb-pdf__outline-toggle{display:inline-flex;flex:none;align-items:center;justify-content:center;width:1.5rem;height:1.75rem;padding:0;border:0;border-radius:var(--cb-radius-sm);background:transparent;color:var(--cb-color-text-muted);cursor:pointer}.cb-pdf__outline-link{flex:1;min-width:0;padding:.3rem .375rem;border:0;border-radius:var(--cb-radius-sm);background:transparent;color:var(--cb-color-text);font:inherit;font-size:var(--cb-text-sm);line-height:1.3;text-align:start;cursor:pointer}.cb-pdf__outline-item>.cb-pdf__outline-link:first-child{margin-left:1.5rem}.cb-pdf__outline-link:hover,.cb-pdf__outline-toggle:hover{background:var(--cb-color-surface-hover)}.cb-pdf__outline-link--bold{font-weight:var(--cb-font-weight-semibold)}.cb-pdf__outline-link--italic{font-style:italic}.cb-pdf__thumb{display:flex;flex-direction:column;align-items:center;gap:var(--cb-space-1);padding:var(--cb-space-1);border:2px solid transparent;border-radius:var(--cb-radius-md);background:transparent;color:var(--cb-color-text-muted);font:inherit;font-size:var(--cb-text-xs);cursor:pointer}.cb-pdf__thumb:hover{background:var(--cb-color-surface-hover)}.cb-pdf__thumb.cb-is-active{border-color:var(--cb-color-primary-500);color:var(--cb-color-text-strong);font-weight:var(--cb-font-weight-semibold)}.cb-pdf__thumb-canvas{display:block;background:#fff;box-shadow:0 1px 3px #0f172a33}:host ::ng-deep .cb-pdf__thumb-canvas canvas{display:block;width:100%;height:100%}.cb-pdf__viewport{position:relative;flex:1;min-width:0;overflow:auto;background:var(--cb-color-surface-subtle)}.cb-pdf__pages{display:flex;flex-direction:column;align-items:center;gap:16px;padding:16px;width:max-content;min-width:100%;box-sizing:border-box}.cb-pdf__page{--user-unit: 1;--total-scale-factor: calc(var(--scale-factor) * var(--user-unit));--scale-round-x: 1px;--scale-round-y: 1px;position:relative;flex:none;background:#fff;box-shadow:0 1px 3px #0f172a2e,0 4px 12px #0f172a14;direction:ltr}.cb-pdf__canvas,:host ::ng-deep .cb-pdf__canvas canvas{position:absolute;inset:0;width:100%;height:100%}.cb-pdf__text{position:absolute;inset:0;overflow:clip;opacity:1;line-height:1;text-align:initial;letter-spacing:normal;word-spacing:normal;-webkit-text-size-adjust:none;text-size-adjust:none;forced-color-adjust:none;transform-origin:0 0;caret-color:CanvasText;z-index:0;--min-font-size: 1;--text-scale-factor: calc(var(--total-scale-factor) * var(--min-font-size));--min-font-size-inv: calc(1 / var(--min-font-size))}.cb-pdf__text[data-main-rotation=\"90\"]{transform:rotate(90deg) translateY(-100%)}.cb-pdf__text[data-main-rotation=\"180\"]{transform:rotate(180deg) translate(-100%,-100%)}.cb-pdf__text[data-main-rotation=\"270\"]{transform:rotate(270deg) translate(-100%)}.cb-pdf__annotations{position:absolute;inset:0;z-index:1;transform-origin:0 0;pointer-events:none}.cb-pdf__annotations[data-main-rotation=\"90\"]{transform:rotate(90deg) translateY(-100%)}.cb-pdf__annotations[data-main-rotation=\"180\"]{transform:rotate(180deg) translate(-100%,-100%)}.cb-pdf__annotations[data-main-rotation=\"270\"]{transform:rotate(270deg) translate(-100%)}:host ::ng-deep .cb-pdf__annotations section{position:absolute;box-sizing:border-box;text-align:initial;transform-origin:0 0;pointer-events:auto}:host ::ng-deep .cb-pdf__annotations [hidden]{display:none!important}:host ::ng-deep .cb-pdf__annotations .linkAnnotation>a{position:absolute;inset:0;border-radius:2px}:host ::ng-deep .cb-pdf__annotations .linkAnnotation>a:hover{background:#0e74901f}:host ::ng-deep .cb-pdf__annotations .linkAnnotation>a:focus-visible{outline:2px solid var(--cb-color-focus-ring);outline-offset:1px}:host ::ng-deep .cb-pdf__annotations :is(.textWidgetAnnotation,.choiceWidgetAnnotation) :is(input,textarea,select){width:100%;height:100%;box-sizing:border-box;margin:0;padding:0 calc(2px * var(--total-scale-factor));border:1px solid transparent;border-radius:0;background:#2563eb1a;color:#111827;font-family:Helvetica,Arial,sans-serif;font-size:calc(9px * var(--total-scale-factor));vertical-align:top}:host ::ng-deep .cb-pdf__annotations .textWidgetAnnotation textarea{padding-top:calc(2px * var(--total-scale-factor));resize:none}:host ::ng-deep .cb-pdf__annotations :is(.textWidgetAnnotation,.choiceWidgetAnnotation) :is(input,textarea,select):hover{border-color:#2563eb99}:host ::ng-deep .cb-pdf__annotations :is(input,textarea,select):focus{border-color:transparent;outline:2px solid var(--cb-color-focus-ring);outline-offset:0;background:#2563eb0a}:host ::ng-deep .cb-pdf__annotations :is(input,textarea,select):disabled{background:transparent}:host ::ng-deep .cb-pdf__annotations .buttonWidgetAnnotation :is(.checkBox,.radioButton) input{width:100%;height:100%;margin:0;accent-color:var(--cb-color-primary-600, #0e7490);cursor:pointer}:host ::ng-deep .cb-pdf__annotations .buttonWidgetAnnotation.checkBox input,:host ::ng-deep .cb-pdf__annotations .buttonWidgetAnnotation.radioButton input{width:100%;height:100%;margin:0;accent-color:var(--cb-color-primary-600, #0e7490);cursor:pointer}:host ::ng-deep .cb-pdf__text :is(span,br){position:absolute;color:transparent;white-space:pre;cursor:text;transform-origin:0% 0%;-webkit-user-select:text;user-select:text}:host ::ng-deep .cb-pdf__text>:not(.markedContent),:host ::ng-deep .cb-pdf__text .markedContent span:not(.markedContent){--font-height: 0;--scale-x: 1;--rotate: 0deg;z-index:1;font-size:calc(var(--text-scale-factor) * var(--font-height));transform:rotate(var(--rotate)) scaleX(var(--scale-x)) scale(var(--min-font-size-inv))}:host ::ng-deep .cb-pdf__text .markedContent{display:contents}:host ::ng-deep .cb-pdf__text span[role=img]{-webkit-user-select:none;user-select:none;cursor:default}:host ::ng-deep .cb-pdf__text ::selection{background:color-mix(in srgb,var(--cb-color-primary-500) 35%,transparent);color:transparent}:host ::ng-deep .cb-pdf__text .cb-pdf__hl{position:relative;margin:-1px;padding:1px;border-radius:3px;background:#facc1573;font-size:inherit;transform:none}:host ::ng-deep .cb-pdf__text .cb-pdf__hl.cb-is-selected{background:#f973168c;outline:2px solid rgb(234 88 12)}@media(forced-colors:active){:host ::ng-deep .cb-pdf__text .cb-pdf__hl{background:transparent;outline:1px solid Highlight}:host ::ng-deep .cb-pdf__text .cb-pdf__hl.cb-is-selected{outline:3px solid Highlight}}.cb-pdf__message{display:flex;flex-direction:column;align-items:center;justify-content:center;gap:var(--cb-space-3);height:100%;padding:var(--cb-space-6);color:var(--cb-color-text-muted);text-align:center}.cb-pdf__message--error{color:var(--cb-color-danger)}.cb-pdf__password{display:flex;flex-direction:column;align-items:center;gap:var(--cb-space-2);max-width:24rem;margin:var(--cb-space-6) auto;padding:var(--cb-space-6);border:var(--cb-border-width, 1px) solid var(--cb-color-border);border-radius:var(--cb-radius-lg);background:var(--cb-color-surface);text-align:center}.cb-pdf__password-text{margin:0}.cb-pdf__password-label{align-self:flex-start;font-weight:var(--cb-font-weight-medium)}.cb-pdf__password-row{display:flex;gap:var(--cb-space-2);width:100%}.cb-pdf__password-row .cb-pdf__field{flex:1;min-width:0}.cb-pdf__password-error{margin:0;color:var(--cb-color-danger)}.cb-pdf__submit{height:2.25rem;padding:0 var(--cb-space-4);border:none;border-radius:var(--cb-radius-md);background:var(--cb-color-primary-500);color:var(--cb-color-primary-contrast);font:inherit;font-weight:var(--cb-font-weight-semibold);cursor:pointer}.cb-pdf__submit:hover{background:var(--cb-color-primary-600)}.cb-pdf__toast{position:absolute;left:50%;bottom:var(--cb-space-4);transform:translate(-50%);padding:var(--cb-space-2) var(--cb-space-4);border-radius:var(--cb-radius-full);background:var(--cb-color-surface-950);color:#fff;box-shadow:var(--cb-shadow-md)}.cb-pdf__tool[aria-pressed=true]{background:color-mix(in srgb,var(--cb-color-primary-500) 16%,transparent);color:var(--cb-color-primary-700)}:host-context([data-theme=\"dark\"]) .cb-pdf__tool[aria-pressed=true]{color:var(--cb-color-primary-300)}.cb-pdf__color{position:relative;display:inline-flex;align-items:center}.cb-pdf__swatch{position:absolute;left:.625rem;width:.875rem;height:.875rem;border:2px solid;border-radius:var(--cb-radius-full);pointer-events:none}.cb-pdf__color-select{padding-left:1.875rem}.cb-pdf__hint{position:sticky;top:var(--cb-space-2);z-index:4;box-sizing:border-box;width:max-content;max-width:calc(100% - 2rem);height:2rem;margin:var(--cb-space-2) auto calc(-2rem - var(--cb-space-2));padding:0 var(--cb-space-3);overflow:hidden;border-radius:var(--cb-radius-full);background:var(--cb-color-surface-950, #0f172a);color:#fff;font-size:var(--cb-text-xs);line-height:2rem;text-overflow:ellipsis;white-space:nowrap;box-shadow:var(--cb-shadow-md)}.cb-pdf__marks{position:absolute;inset:0;z-index:2;pointer-events:none}.cb-pdf__marks--capture{pointer-events:auto;cursor:cell;touch-action:none}.cb-pdf__marks--ink{cursor:crosshair}.cb-pdf__mark{position:absolute;box-sizing:border-box;pointer-events:auto;border-radius:2px;outline-offset:2px;touch-action:none}.cb-pdf__mark:focus-visible,.cb-pdf__mark.cb-is-selected{outline:2px solid var(--cb-color-focus-ring)}.cb-pdf__marks--pass .cb-pdf__mark--highlight{pointer-events:none}.cb-pdf__mark--highlight{cursor:pointer}.cb-pdf__hl-rect{position:absolute;background:color-mix(in srgb,var(--cb-pdf-mark-light) 55%,transparent)}.cb-pdf__hl-badge{position:absolute;top:-.35rem;right:-.35rem;width:.625rem;height:.625rem;border:2px solid #fff;border-radius:var(--cb-radius-full);background:var(--cb-pdf-mark-dark)}.cb-pdf__mark--note,.cb-pdf__mark--signature,.cb-pdf__mark--ink{cursor:move}.cb-pdf__note-text{display:block;box-sizing:border-box;padding:.1em .3em;border:1px dashed color-mix(in srgb,var(--cb-pdf-mark-dark) 45%,transparent);border-radius:2px;background:transparent;color:var(--cb-pdf-mark-dark);font-family:Helvetica,Arial,sans-serif;line-height:1.2;white-space:pre}.cb-pdf__ink,.cb-pdf__stroke{position:absolute;inset:0;width:100%;height:100%;overflow:visible;pointer-events:none}.cb-pdf__ink path,.cb-pdf__stroke polyline{fill:none;stroke:var(--cb-pdf-mark-dark);stroke-linecap:round;stroke-linejoin:round}.cb-pdf__sig{display:block;width:100%;height:100%;-webkit-user-select:none;user-select:none;-webkit-user-drag:none}.cb-pdf__resize{position:absolute;right:-.4rem;bottom:-.4rem;width:.8rem;height:.8rem;border:2px solid #fff;border-radius:2px;background:var(--cb-color-focus-ring);cursor:nwse-resize}.cb-pdf__card{position:absolute;z-index:3;display:flex;flex-direction:column;gap:var(--cb-space-2);box-sizing:border-box;width:16rem;padding:var(--cb-space-3);border:var(--cb-border-width, 1px) solid var(--cb-color-border);border-radius:var(--cb-radius-md);background:var(--cb-color-surface-raised, var(--cb-color-surface));color:var(--cb-color-text);font-size:var(--cb-text-sm);box-shadow:var(--cb-shadow-lg);pointer-events:auto;cursor:auto}.cb-pdf__card-label{font-weight:var(--cb-font-weight-medium)}.cb-pdf__card-text{height:auto;min-height:4.5rem;padding:var(--cb-space-2);resize:vertical}.cb-pdf__card-actions,.cb-pdf__sign-actions{display:flex;justify-content:flex-end;gap:var(--cb-space-2)}.cb-pdf__card-btn{height:2rem;padding:0 var(--cb-space-3);border:var(--cb-border-width, 1px) solid var(--cb-color-border-strong);border-radius:var(--cb-radius-md);background:transparent;color:var(--cb-color-text);font:inherit;cursor:pointer}.cb-pdf__card-btn:hover:not(:disabled){background:var(--cb-color-surface-hover)}.cb-pdf__card-btn--primary{border-color:var(--cb-color-primary-500);background:var(--cb-color-primary-500);color:var(--cb-color-primary-contrast);font-weight:var(--cb-font-weight-semibold)}.cb-pdf__card-btn--primary:hover:not(:disabled){background:var(--cb-color-primary-600)}.cb-pdf__card-btn:disabled{opacity:var(--cb-opacity-disabled, .5);cursor:default}.cb-pdf__card-btn:focus-visible,.cb-pdf__card-text:focus-visible,.cb-pdf__notes-link:focus-visible,.cb-pdf__notes-remove:focus-visible{outline:2px solid var(--cb-color-focus-ring);outline-offset:2px}.cb-pdf__notes-panel{padding:0 var(--cb-space-2)}.cb-pdf__notes-empty{margin:0;padding:var(--cb-space-2);color:var(--cb-color-text-muted)}.cb-pdf__notes-list{display:flex;flex-direction:column;gap:2px;margin:0;padding:0;list-style:none}.cb-pdf__notes-item{display:flex;align-items:flex-start;gap:2px}.cb-pdf__notes-link{display:flex;flex:1;align-items:flex-start;gap:var(--cb-space-2);min-width:0;padding:var(--cb-space-2);border:0;border-radius:var(--cb-radius-md);background:transparent;color:var(--cb-color-text);font:inherit;text-align:left;cursor:pointer}.cb-pdf__notes-link:hover,.cb-pdf__notes-remove:hover{background:var(--cb-color-surface-hover)}.cb-pdf__notes-swatch{flex:none;width:.625rem;height:.625rem;margin-top:.3rem;border-radius:var(--cb-radius-full)}.cb-pdf__notes-text{display:flex;flex-direction:column;min-width:0}.cb-pdf__notes-page{color:var(--cb-color-text-muted);font-size:var(--cb-text-xs)}.cb-pdf__notes-label{overflow:hidden;display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:3;overflow-wrap:anywhere}.cb-pdf__notes-remove{display:inline-flex;flex:none;align-items:center;justify-content:center;width:2rem;height:2rem;border:0;border-radius:var(--cb-radius-md);background:transparent;color:var(--cb-color-text-muted);cursor:pointer}.cb-pdf__sr{position:absolute;width:1px;height:1px;margin:-1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap;border:0}@media(forced-colors:active){.cb-pdf__hl-rect{background:transparent;outline:2px solid Mark}.cb-pdf__note-text{border-color:CanvasText}}\n"], dependencies: [{ kind: "component", type: CbDialog, selector: "cb-dialog", inputs: ["visible", "header", "closable", "dismissableMask", "closeOnEscape", "width", "ariaLabel"], outputs: ["visibleChange", "onHide", "onShow"] }, { kind: "component", type: CbIcon, selector: "cb-icon", inputs: ["name", "size", "spin", "ariaLabel"] }, { kind: "component", type: CbSignaturePad, selector: "cb-signature-pad", inputs: ["value", "format", "mode", "typing", "penColor", "background", "minWidth", "maxWidth", "height", "font", "placeholder", "disabled", "readonly", "invalid", "ariaLabel"], outputs: ["valueChange", "modeChange", "signStart", "signEnd", "cleared"] }, { kind: "component", type: CbSpinner, selector: "cb-spinner", inputs: ["size", "strokeWidth", "severity", "ariaLabel"] }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
1273
2728
|
}
|
|
1274
2729
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.5", ngImport: i0, type: CbPdfViewer, decorators: [{
|
|
1275
2730
|
type: Component,
|
|
1276
|
-
args: [{ selector: 'cb-pdf-viewer', changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.Emulated, imports: [CbIcon, CbSpinner], host: {
|
|
2731
|
+
args: [{ selector: 'cb-pdf-viewer', changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.Emulated, imports: [CbDialog, CbIcon, CbSignaturePad, CbSpinner, NgTemplateOutlet], host: {
|
|
1277
2732
|
class: 'cb-pdf-viewer',
|
|
1278
2733
|
role: 'region',
|
|
1279
2734
|
'[attr.aria-label]': 'ariaLabel() || t().pdfViewer',
|
|
@@ -1361,6 +2816,70 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.5", ngImpor
|
|
|
1361
2816
|
}
|
|
1362
2817
|
</div>
|
|
1363
2818
|
|
|
2819
|
+
@if (annotatable()) {
|
|
2820
|
+
<div class="cb-pdf__group" role="group" [attr.aria-label]="t().pdfAnnotate">
|
|
2821
|
+
<!-- mousedown sin default: pulsar la herramienta no quita la selección de texto. -->
|
|
2822
|
+
<button
|
|
2823
|
+
type="button"
|
|
2824
|
+
class="cb-pdf__tool"
|
|
2825
|
+
[attr.aria-label]="t().pdfHighlight"
|
|
2826
|
+
[attr.aria-pressed]="tool() === 'highlight'"
|
|
2827
|
+
[attr.title]="t().pdfHighlight"
|
|
2828
|
+
[disabled]="state() !== 'ready'"
|
|
2829
|
+
(mousedown)="$event.preventDefault()"
|
|
2830
|
+
(click)="onHighlightTool()"
|
|
2831
|
+
>
|
|
2832
|
+
<cb-icon name="highlighter" [size]="18" aria-hidden="true" />
|
|
2833
|
+
</button>
|
|
2834
|
+
<button
|
|
2835
|
+
type="button"
|
|
2836
|
+
class="cb-pdf__tool"
|
|
2837
|
+
[attr.aria-label]="t().pdfNote"
|
|
2838
|
+
[attr.aria-pressed]="tool() === 'note'"
|
|
2839
|
+
[attr.title]="t().pdfNote"
|
|
2840
|
+
[disabled]="state() !== 'ready'"
|
|
2841
|
+
(click)="onNoteTool($event)"
|
|
2842
|
+
>
|
|
2843
|
+
<cb-icon name="sticky-note" [size]="18" aria-hidden="true" />
|
|
2844
|
+
</button>
|
|
2845
|
+
<button
|
|
2846
|
+
type="button"
|
|
2847
|
+
class="cb-pdf__tool"
|
|
2848
|
+
[attr.aria-label]="t().pdfDraw"
|
|
2849
|
+
[attr.aria-pressed]="tool() === 'ink'"
|
|
2850
|
+
[attr.title]="t().pdfDraw"
|
|
2851
|
+
[disabled]="state() !== 'ready'"
|
|
2852
|
+
(click)="toggleTool('ink')"
|
|
2853
|
+
>
|
|
2854
|
+
<cb-icon name="pen-line" [size]="18" aria-hidden="true" />
|
|
2855
|
+
</button>
|
|
2856
|
+
<button
|
|
2857
|
+
type="button"
|
|
2858
|
+
class="cb-pdf__tool"
|
|
2859
|
+
aria-haspopup="dialog"
|
|
2860
|
+
[attr.aria-label]="t().pdfSign"
|
|
2861
|
+
[attr.title]="t().pdfSign"
|
|
2862
|
+
[disabled]="state() !== 'ready'"
|
|
2863
|
+
(click)="openSignature()"
|
|
2864
|
+
>
|
|
2865
|
+
<cb-icon name="signature" [size]="18" aria-hidden="true" />
|
|
2866
|
+
</button>
|
|
2867
|
+
<span class="cb-pdf__color">
|
|
2868
|
+
<span class="cb-pdf__swatch" aria-hidden="true" [style.background]="colors[annotationColor()].light" [style.border-color]="colors[annotationColor()].dark"></span>
|
|
2869
|
+
<select
|
|
2870
|
+
class="cb-pdf__field cb-pdf__color-select"
|
|
2871
|
+
[attr.aria-label]="t().pdfColor"
|
|
2872
|
+
[disabled]="state() !== 'ready'"
|
|
2873
|
+
(change)="annotationColor.set($any($event.target).value)"
|
|
2874
|
+
>
|
|
2875
|
+
@for (c of colorNames; track c) {
|
|
2876
|
+
<option [value]="c" [selected]="annotationColor() === c">{{ colorLabel(c) }}</option>
|
|
2877
|
+
}
|
|
2878
|
+
</select>
|
|
2879
|
+
</span>
|
|
2880
|
+
</div>
|
|
2881
|
+
}
|
|
2882
|
+
|
|
1364
2883
|
<span class="cb-pdf__spacer"></span>
|
|
1365
2884
|
|
|
1366
2885
|
@if (showSearch()) {
|
|
@@ -1391,7 +2910,14 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.5", ngImpor
|
|
|
1391
2910
|
@if (downloadable() || printable()) {
|
|
1392
2911
|
<div class="cb-pdf__group">
|
|
1393
2912
|
@if (downloadable()) {
|
|
1394
|
-
<button
|
|
2913
|
+
<button
|
|
2914
|
+
type="button"
|
|
2915
|
+
class="cb-pdf__tool"
|
|
2916
|
+
[attr.aria-label]="annotations().length ? t().pdfDownloadAnnotated : formModified() ? t().pdfDownloadFilled : t().download"
|
|
2917
|
+
[attr.title]="annotations().length ? t().pdfDownloadAnnotated : formModified() ? t().pdfDownloadFilled : null"
|
|
2918
|
+
[disabled]="state() !== 'ready'"
|
|
2919
|
+
(click)="download()"
|
|
2920
|
+
>
|
|
1395
2921
|
<cb-icon name="download" [size]="18" aria-hidden="true" />
|
|
1396
2922
|
</button>
|
|
1397
2923
|
}
|
|
@@ -1413,7 +2939,51 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.5", ngImpor
|
|
|
1413
2939
|
|
|
1414
2940
|
<div class="cb-pdf__body">
|
|
1415
2941
|
@if (state() === 'ready' && sidebar() && showThumbnails()) {
|
|
1416
|
-
<
|
|
2942
|
+
<div
|
|
2943
|
+
class="cb-pdf__sidebar"
|
|
2944
|
+
[class.cb-pdf__sidebar--tabs]="sidebarTabs().length > 1"
|
|
2945
|
+
[class.cb-pdf__sidebar--outline]="activeView() !== 'thumbnails' || sidebarTabs().length > 2"
|
|
2946
|
+
[id]="uid + '-thumbs'"
|
|
2947
|
+
>
|
|
2948
|
+
@if (sidebarTabs().length > 1) {
|
|
2949
|
+
<div class="cb-pdf__views" role="group" [attr.aria-label]="t().pdfSidebarView">
|
|
2950
|
+
@for (view of sidebarTabs(); track view) {
|
|
2951
|
+
<button type="button" class="cb-pdf__view" [attr.aria-pressed]="activeView() === view" (click)="sidebarView.set(view)">
|
|
2952
|
+
{{ view === 'outline' ? t().pdfOutline : view === 'annotations' ? t().pdfAnnotations : t().thumbnails }}
|
|
2953
|
+
</button>
|
|
2954
|
+
}
|
|
2955
|
+
</div>
|
|
2956
|
+
}
|
|
2957
|
+
@if (activeView() === 'outline') {
|
|
2958
|
+
<nav class="cb-pdf__outline" [attr.aria-label]="t().pdfOutline">
|
|
2959
|
+
<ng-container *ngTemplateOutlet="outlineList; context: { $implicit: outline(), path: '' }" />
|
|
2960
|
+
</nav>
|
|
2961
|
+
} @else if (activeView() === 'annotations') {
|
|
2962
|
+
<section class="cb-pdf__notes-panel" [attr.aria-label]="t().pdfAnnotations">
|
|
2963
|
+
@if (!sortedAnnotations().length) {
|
|
2964
|
+
<p class="cb-pdf__notes-empty">{{ t().pdfNoAnnotations }}</p>
|
|
2965
|
+
} @else {
|
|
2966
|
+
<ul class="cb-pdf__notes-list">
|
|
2967
|
+
@for (a of sortedAnnotations(); track a.id) {
|
|
2968
|
+
<li class="cb-pdf__notes-item">
|
|
2969
|
+
<button type="button" class="cb-pdf__notes-link" (click)="revealAnnotation(a)">
|
|
2970
|
+
<span class="cb-pdf__notes-swatch" aria-hidden="true" [style.background]="swatchOf(a)"></span>
|
|
2971
|
+
<span class="cb-pdf__notes-text">
|
|
2972
|
+
<!-- La coma oculta separa la página del texto en el nombre del botón. -->
|
|
2973
|
+
<span class="cb-pdf__notes-page">{{ format(t().pageOf, a.page, numPages()) }}<span class="cb-pdf__sr">, </span></span>
|
|
2974
|
+
<span class="cb-pdf__notes-label">{{ labelOf(a) }}</span>
|
|
2975
|
+
</span>
|
|
2976
|
+
</button>
|
|
2977
|
+
<button type="button" class="cb-pdf__notes-remove" [attr.aria-label]="t().pdfDeleteAnnotation + ': ' + labelOf(a)" (click)="removeAnnotation(a)">
|
|
2978
|
+
<cb-icon name="trash" [size]="14" aria-hidden="true" />
|
|
2979
|
+
</button>
|
|
2980
|
+
</li>
|
|
2981
|
+
}
|
|
2982
|
+
</ul>
|
|
2983
|
+
}
|
|
2984
|
+
</section>
|
|
2985
|
+
} @else {
|
|
2986
|
+
<nav class="cb-pdf__thumbs" [attr.aria-label]="t().thumbnails">
|
|
1417
2987
|
@for (thumb of thumbBoxes(); track $index; let i = $index) {
|
|
1418
2988
|
<button
|
|
1419
2989
|
#thumbEl
|
|
@@ -1430,7 +3000,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.5", ngImpor
|
|
|
1430
3000
|
<span class="cb-pdf__thumb-label" aria-hidden="true">{{ i + 1 }}</span>
|
|
1431
3001
|
</button>
|
|
1432
3002
|
}
|
|
1433
|
-
|
|
3003
|
+
</nav>
|
|
3004
|
+
}
|
|
3005
|
+
</div>
|
|
1434
3006
|
}
|
|
1435
3007
|
|
|
1436
3008
|
<div
|
|
@@ -1476,7 +3048,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.5", ngImpor
|
|
|
1476
3048
|
</form>
|
|
1477
3049
|
}
|
|
1478
3050
|
@case ('ready') {
|
|
1479
|
-
|
|
3051
|
+
@if (toolHint(); as hint) {
|
|
3052
|
+
<div class="cb-pdf__hint">{{ hint }}</div>
|
|
3053
|
+
}
|
|
3054
|
+
<div class="cb-pdf__pages" (pointerup)="onPagesPointerUp()">
|
|
1480
3055
|
@for (box of pageBoxes(); track $index; let i = $index) {
|
|
1481
3056
|
<div
|
|
1482
3057
|
#pageEl
|
|
@@ -1491,6 +3066,97 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.5", ngImpor
|
|
|
1491
3066
|
>
|
|
1492
3067
|
<div class="cb-pdf__canvas"></div>
|
|
1493
3068
|
<div class="cb-pdf__text"></div>
|
|
3069
|
+
<div class="cb-pdf__annotations" (input)="onFormInput()" (change)="onFormInput()"></div>
|
|
3070
|
+
@if (annotatable() || marks()[i]?.length) {
|
|
3071
|
+
<div
|
|
3072
|
+
class="cb-pdf__marks"
|
|
3073
|
+
[class.cb-pdf__marks--capture]="annotatable() && (tool() === 'ink' || tool() === 'note')"
|
|
3074
|
+
[class.cb-pdf__marks--ink]="tool() === 'ink'"
|
|
3075
|
+
[class.cb-pdf__marks--pass]="tool() === 'highlight'"
|
|
3076
|
+
(pointerdown)="onMarksPointerDown($event, i + 1)"
|
|
3077
|
+
>
|
|
3078
|
+
@for (m of marks()[i]; track m.a.id) {
|
|
3079
|
+
<div
|
|
3080
|
+
class="cb-pdf__mark"
|
|
3081
|
+
[class]="'cb-pdf__mark cb-pdf__mark--' + m.a.type"
|
|
3082
|
+
[class.cb-is-selected]="selectedId() === m.a.id"
|
|
3083
|
+
[attr.data-id]="m.a.id"
|
|
3084
|
+
[attr.tabindex]="annotatable() ? 0 : null"
|
|
3085
|
+
[attr.role]="annotatable() ? 'button' : 'img'"
|
|
3086
|
+
[attr.aria-label]="m.label"
|
|
3087
|
+
[attr.aria-describedby]="annotatable() ? uid + '-mark-hint' : null"
|
|
3088
|
+
[attr.aria-expanded]="annotatable() && (m.a.type === 'note' || m.a.type === 'highlight') ? editingId() === m.a.id : null"
|
|
3089
|
+
[style.left.px]="m.box.left"
|
|
3090
|
+
[style.top.px]="m.box.top"
|
|
3091
|
+
[style.width.px]="m.a.type === 'note' ? null : m.box.width"
|
|
3092
|
+
[style.height.px]="m.a.type === 'note' ? null : m.box.height"
|
|
3093
|
+
[style.--cb-pdf-mark-light]="m.light"
|
|
3094
|
+
[style.--cb-pdf-mark-dark]="m.dark"
|
|
3095
|
+
(pointerdown)="onMarkPointerDown($event, m.a)"
|
|
3096
|
+
(keydown)="onMarkKeydown($event, m.a)"
|
|
3097
|
+
(focus)="select(m.a.id)"
|
|
3098
|
+
>
|
|
3099
|
+
@switch (m.a.type) {
|
|
3100
|
+
@case ('highlight') {
|
|
3101
|
+
@for (r of m.rects; track $index) {
|
|
3102
|
+
<span class="cb-pdf__hl-rect" [style.left.px]="r.left" [style.top.px]="r.top" [style.width.px]="r.width" [style.height.px]="r.height"></span>
|
|
3103
|
+
}
|
|
3104
|
+
@if (m.a.comment) {
|
|
3105
|
+
<span class="cb-pdf__hl-badge" aria-hidden="true"></span>
|
|
3106
|
+
}
|
|
3107
|
+
}
|
|
3108
|
+
@case ('note') {
|
|
3109
|
+
<span class="cb-pdf__note-text" [style.font-size.px]="m.fontPx" [style.min-width.px]="m.box.width">{{ m.a.text || ' ' }}</span>
|
|
3110
|
+
}
|
|
3111
|
+
@case ('ink') {
|
|
3112
|
+
<svg class="cb-pdf__ink" [attr.viewBox]="'0 0 ' + m.box.width + ' ' + m.box.height" aria-hidden="true">
|
|
3113
|
+
<path [attr.d]="m.d" [attr.stroke-width]="m.strokePx" />
|
|
3114
|
+
</svg>
|
|
3115
|
+
}
|
|
3116
|
+
@case ('signature') {
|
|
3117
|
+
<img class="cb-pdf__sig" [src]="m.a.image" alt="" draggable="false" />
|
|
3118
|
+
@if (annotatable() && selectedId() === m.a.id) {
|
|
3119
|
+
<span class="cb-pdf__resize" aria-hidden="true" (pointerdown)="onResizePointerDown($event, m.a)"></span>
|
|
3120
|
+
}
|
|
3121
|
+
}
|
|
3122
|
+
}
|
|
3123
|
+
</div>
|
|
3124
|
+
}
|
|
3125
|
+
@if (stroke(); as s) {
|
|
3126
|
+
@if (s.page === i + 1) {
|
|
3127
|
+
<svg class="cb-pdf__stroke" aria-hidden="true" [style.--cb-pdf-mark-dark]="colors[annotationColor()].dark">
|
|
3128
|
+
<polyline [attr.points]="s.points.join(' ')" [attr.stroke-width]="2 * box.scaleFactor" />
|
|
3129
|
+
</svg>
|
|
3130
|
+
}
|
|
3131
|
+
}
|
|
3132
|
+
@if (editingMark(); as e) {
|
|
3133
|
+
@if (e.a.page === i + 1) {
|
|
3134
|
+
<div
|
|
3135
|
+
class="cb-pdf__card"
|
|
3136
|
+
role="group"
|
|
3137
|
+
[attr.aria-label]="e.label"
|
|
3138
|
+
[style.left.px]="cardLeft(e, box.width)"
|
|
3139
|
+
[style.top.px]="e.box.top + (e.a.type === 'note' ? noteHeight(e) : e.box.height) + 6"
|
|
3140
|
+
(pointerdown)="$event.stopPropagation()"
|
|
3141
|
+
(keydown)="onCardKeydown($event)"
|
|
3142
|
+
>
|
|
3143
|
+
<label class="cb-pdf__card-label" [for]="uid + '-card'">{{ e.a.type === 'note' ? t().pdfNoteText : t().pdfComment }}</label>
|
|
3144
|
+
<textarea
|
|
3145
|
+
#cardText
|
|
3146
|
+
class="cb-pdf__field cb-pdf__card-text"
|
|
3147
|
+
rows="3"
|
|
3148
|
+
[id]="uid + '-card'"
|
|
3149
|
+
(input)="onCardInput($any($event.target).value)"
|
|
3150
|
+
></textarea>
|
|
3151
|
+
<div class="cb-pdf__card-actions">
|
|
3152
|
+
<button type="button" class="cb-pdf__card-btn" (click)="removeAnnotation(e.a)">{{ t().pdfDeleteAnnotation }}</button>
|
|
3153
|
+
<button type="button" class="cb-pdf__card-btn cb-pdf__card-btn--primary" (click)="closeEditor(true)">{{ t().pdfDone }}</button>
|
|
3154
|
+
</div>
|
|
3155
|
+
</div>
|
|
3156
|
+
}
|
|
3157
|
+
}
|
|
3158
|
+
</div>
|
|
3159
|
+
}
|
|
1494
3160
|
</div>
|
|
1495
3161
|
}
|
|
1496
3162
|
</div>
|
|
@@ -1499,15 +3165,62 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.5", ngImpor
|
|
|
1499
3165
|
</div>
|
|
1500
3166
|
</div>
|
|
1501
3167
|
|
|
3168
|
+
@if (annotatable()) {
|
|
3169
|
+
<span class="cb-pdf__sr" [id]="uid + '-mark-hint'">{{ t().pdfAnnotationHint }}</span>
|
|
3170
|
+
<span class="cb-pdf__sr" aria-live="polite">{{ announcement() }}</span>
|
|
3171
|
+
<cb-dialog [(visible)]="signing" [header]="t().pdfSignTitle" width="34rem" (onHide)="onSignatureHide()">
|
|
3172
|
+
<cb-signature-pad [(value)]="signatureValue" background="transparent" [ariaLabel]="t().pdfSignTitle" />
|
|
3173
|
+
<div cb-dialog-footer class="cb-pdf__sign-actions">
|
|
3174
|
+
<button type="button" class="cb-pdf__card-btn" (click)="signing.set(false)">{{ t().pdfCancel }}</button>
|
|
3175
|
+
<button type="button" class="cb-pdf__card-btn cb-pdf__card-btn--primary" [disabled]="!signatureValue()" (click)="insertSignature()">
|
|
3176
|
+
{{ t().pdfInsertSignature }}
|
|
3177
|
+
</button>
|
|
3178
|
+
</div>
|
|
3179
|
+
</cb-dialog>
|
|
3180
|
+
}
|
|
3181
|
+
|
|
3182
|
+
<ng-template #outlineList let-items let-path="path">
|
|
3183
|
+
<ul class="cb-pdf__outline-list" [attr.role]="path ? 'group' : null">
|
|
3184
|
+
@for (item of items; track $index; let i = $index) {
|
|
3185
|
+
<li class="cb-pdf__outline-item">
|
|
3186
|
+
@if (item.items.length) {
|
|
3187
|
+
<button
|
|
3188
|
+
type="button"
|
|
3189
|
+
class="cb-pdf__outline-toggle"
|
|
3190
|
+
[attr.aria-expanded]="!isCollapsed(path + i)"
|
|
3191
|
+
[attr.aria-label]="format(isCollapsed(path + i) ? t().pdfExpandItem : t().pdfCollapseItem, item.title)"
|
|
3192
|
+
(click)="toggleOutline(path + i)"
|
|
3193
|
+
>
|
|
3194
|
+
<cb-icon [name]="isCollapsed(path + i) ? 'chevron-right' : 'chevron-down'" [size]="14" aria-hidden="true" />
|
|
3195
|
+
</button>
|
|
3196
|
+
}
|
|
3197
|
+
<button
|
|
3198
|
+
type="button"
|
|
3199
|
+
class="cb-pdf__outline-link"
|
|
3200
|
+
[class.cb-pdf__outline-link--bold]="item.bold"
|
|
3201
|
+
[class.cb-pdf__outline-link--italic]="item.italic"
|
|
3202
|
+
(click)="openOutlineItem(item)"
|
|
3203
|
+
>
|
|
3204
|
+
{{ item.title }}
|
|
3205
|
+
</button>
|
|
3206
|
+
@if (item.items.length && !isCollapsed(path + i)) {
|
|
3207
|
+
<ng-container *ngTemplateOutlet="outlineList; context: { $implicit: item.items, path: path + i + '.' }" />
|
|
3208
|
+
}
|
|
3209
|
+
</li>
|
|
3210
|
+
}
|
|
3211
|
+
</ul>
|
|
3212
|
+
</ng-template>
|
|
3213
|
+
|
|
1502
3214
|
@if (printProgress(); as p) {
|
|
1503
3215
|
<div class="cb-pdf__toast" role="status">{{ format(t().preparingPrint, p.done, p.total) }}</div>
|
|
1504
3216
|
}
|
|
1505
|
-
`, styles: [":host{position:relative;display:flex;flex-direction:column;box-sizing:border-box;width:100%;height:var(--cb-pdf-viewer-height, 40rem);min-height:16rem;overflow:hidden;border:var(--cb-border-width, 1px) solid var(--cb-color-border);border-radius:var(--cb-radius-lg);background:var(--cb-color-surface);color:var(--cb-color-text);font-family:var(--cb-font-sans);font-size:var(--cb-text-sm);container-type:inline-size}.cb-pdf__toolbar{display:flex;flex-wrap:wrap;align-items:center;gap:var(--cb-space-2);padding:var(--cb-space-2) var(--cb-space-3);border-bottom:var(--cb-border-width, 1px) solid var(--cb-color-border);background:var(--cb-color-surface)}.cb-pdf__group{display:inline-flex;align-items:center;gap:var(--cb-space-1)}.cb-pdf__spacer{flex:1}.cb-pdf__tool{display:inline-flex;align-items:center;justify-content:center;width:2.25rem;height:2.25rem;padding:0;border:none;border-radius:var(--cb-radius-md);background:transparent;color:var(--cb-color-text);cursor:pointer;transition:background-color var(--cb-duration-fast) var(--cb-ease)}.cb-pdf__tool:hover:not(:disabled){background:var(--cb-color-surface-hover)}.cb-pdf__tool[aria-expanded=true]{background:var(--cb-color-surface-hover);color:var(--cb-color-primary-600)}.cb-pdf__tool:disabled{opacity:var(--cb-opacity-disabled, .5);cursor:default}.cb-pdf__tool:focus-visible,.cb-pdf__field:focus-visible,.cb-pdf__thumb:focus-visible,.cb-pdf__submit:focus-visible,.cb-pdf__viewport:focus-visible{outline:2px solid var(--cb-color-focus-ring);outline-offset:2px}.cb-pdf__field{height:2.25rem;padding:0 var(--cb-space-2);border:var(--cb-border-width, 1px) solid var(--cb-color-border-strong);border-radius:var(--cb-radius-md);background:var(--cb-color-surface);color:var(--cb-color-text);font:inherit}.cb-pdf__field:disabled{opacity:var(--cb-opacity-disabled, .5)}.cb-pdf__page-input{width:3.25rem;text-align:center}.cb-pdf__total{min-width:2.5rem;color:var(--cb-color-text-muted);white-space:nowrap}.cb-pdf__zoom{width:9.5rem}.cb-pdf__search{position:relative}.cb-pdf__search-icon{position:absolute;left:.625rem;color:var(--cb-color-text-muted);pointer-events:none}.cb-pdf__search-input{width:14rem;padding-left:2rem}.cb-pdf__status{min-width:4.5rem;color:var(--cb-color-text-muted);font-size:var(--cb-text-xs);text-align:center;white-space:nowrap}@container (max-width: 40rem){.cb-pdf__zoom,.cb-pdf__status{display:none}.cb-pdf__search-input{width:9rem}}.cb-pdf__body{display:flex;flex:1;min-height:0}.cb-pdf__sidebar{display:flex;flex-direction:column;align-items:center;gap:var(--cb-space-3);flex:none;width:10rem;padding:var(--cb-space-3) 0;overflow-y:auto;border-right:var(--cb-border-width, 1px) solid var(--cb-color-border);background:var(--cb-color-surface)}.cb-pdf__thumb{display:flex;flex-direction:column;align-items:center;gap:var(--cb-space-1);padding:var(--cb-space-1);border:2px solid transparent;border-radius:var(--cb-radius-md);background:transparent;color:var(--cb-color-text-muted);font:inherit;font-size:var(--cb-text-xs);cursor:pointer}.cb-pdf__thumb:hover{background:var(--cb-color-surface-hover)}.cb-pdf__thumb.cb-is-active{border-color:var(--cb-color-primary-500);color:var(--cb-color-text-strong);font-weight:var(--cb-font-weight-semibold)}.cb-pdf__thumb-canvas{display:block;background:#fff;box-shadow:0 1px 3px #0f172a33}:host ::ng-deep .cb-pdf__thumb-canvas canvas{display:block;width:100%;height:100%}.cb-pdf__viewport{position:relative;flex:1;min-width:0;overflow:auto;background:var(--cb-color-surface-subtle)}.cb-pdf__pages{display:flex;flex-direction:column;align-items:center;gap:16px;padding:16px;width:max-content;min-width:100%;box-sizing:border-box}.cb-pdf__page{--user-unit: 1;--total-scale-factor: calc(var(--scale-factor) * var(--user-unit));--scale-round-x: 1px;--scale-round-y: 1px;position:relative;flex:none;background:#fff;box-shadow:0 1px 3px #0f172a2e,0 4px 12px #0f172a14;direction:ltr}.cb-pdf__canvas,:host ::ng-deep .cb-pdf__canvas canvas{position:absolute;inset:0;width:100%;height:100%}.cb-pdf__text{position:absolute;inset:0;overflow:clip;opacity:1;line-height:1;text-align:initial;letter-spacing:normal;word-spacing:normal;-webkit-text-size-adjust:none;text-size-adjust:none;forced-color-adjust:none;transform-origin:0 0;caret-color:CanvasText;z-index:0;--min-font-size: 1;--text-scale-factor: calc(var(--total-scale-factor) * var(--min-font-size));--min-font-size-inv: calc(1 / var(--min-font-size))}.cb-pdf__text[data-main-rotation=\"90\"]{transform:rotate(90deg) translateY(-100%)}.cb-pdf__text[data-main-rotation=\"180\"]{transform:rotate(180deg) translate(-100%,-100%)}.cb-pdf__text[data-main-rotation=\"270\"]{transform:rotate(270deg) translate(-100%)}:host ::ng-deep .cb-pdf__text :is(span,br){position:absolute;color:transparent;white-space:pre;cursor:text;transform-origin:0% 0%;-webkit-user-select:text;user-select:text}:host ::ng-deep .cb-pdf__text>:not(.markedContent),:host ::ng-deep .cb-pdf__text .markedContent span:not(.markedContent){--font-height: 0;--scale-x: 1;--rotate: 0deg;z-index:1;font-size:calc(var(--text-scale-factor) * var(--font-height));transform:rotate(var(--rotate)) scaleX(var(--scale-x)) scale(var(--min-font-size-inv))}:host ::ng-deep .cb-pdf__text .markedContent{display:contents}:host ::ng-deep .cb-pdf__text span[role=img]{-webkit-user-select:none;user-select:none;cursor:default}:host ::ng-deep .cb-pdf__text ::selection{background:color-mix(in srgb,var(--cb-color-primary-500) 35%,transparent);color:transparent}:host ::ng-deep .cb-pdf__text .cb-pdf__hl{position:relative;margin:-1px;padding:1px;border-radius:3px;background:#facc1573;font-size:inherit;transform:none}:host ::ng-deep .cb-pdf__text .cb-pdf__hl.cb-is-selected{background:#f973168c;outline:2px solid rgb(234 88 12)}@media(forced-colors:active){:host ::ng-deep .cb-pdf__text .cb-pdf__hl{background:transparent;outline:1px solid Highlight}:host ::ng-deep .cb-pdf__text .cb-pdf__hl.cb-is-selected{outline:3px solid Highlight}}.cb-pdf__message{display:flex;flex-direction:column;align-items:center;justify-content:center;gap:var(--cb-space-3);height:100%;padding:var(--cb-space-6);color:var(--cb-color-text-muted);text-align:center}.cb-pdf__message--error{color:var(--cb-color-danger)}.cb-pdf__password{display:flex;flex-direction:column;align-items:center;gap:var(--cb-space-2);max-width:24rem;margin:var(--cb-space-6) auto;padding:var(--cb-space-6);border:var(--cb-border-width, 1px) solid var(--cb-color-border);border-radius:var(--cb-radius-lg);background:var(--cb-color-surface);text-align:center}.cb-pdf__password-text{margin:0}.cb-pdf__password-label{align-self:flex-start;font-weight:var(--cb-font-weight-medium)}.cb-pdf__password-row{display:flex;gap:var(--cb-space-2);width:100%}.cb-pdf__password-row .cb-pdf__field{flex:1;min-width:0}.cb-pdf__password-error{margin:0;color:var(--cb-color-danger)}.cb-pdf__submit{height:2.25rem;padding:0 var(--cb-space-4);border:none;border-radius:var(--cb-radius-md);background:var(--cb-color-primary-500);color:var(--cb-color-primary-contrast);font:inherit;font-weight:var(--cb-font-weight-semibold);cursor:pointer}.cb-pdf__submit:hover{background:var(--cb-color-primary-600)}.cb-pdf__toast{position:absolute;left:50%;bottom:var(--cb-space-4);transform:translate(-50%);padding:var(--cb-space-2) var(--cb-space-4);border-radius:var(--cb-radius-full);background:var(--cb-color-surface-950);color:#fff;box-shadow:var(--cb-shadow-md)}\n"] }]
|
|
1506
|
-
}], ctorParameters: () => [], propDecorators: { src: [{ type: i0.Input, args: [{ isSignal: true, alias: "src", required: false }] }], fileName: [{ type: i0.Input, args: [{ isSignal: true, alias: "fileName", required: false }] }], password: [{ type: i0.Input, args: [{ isSignal: true, alias: "password", required: false }] }], withCredentials: [{ type: i0.Input, args: [{ isSignal: true, alias: "withCredentials", required: false }] }], httpHeaders: [{ type: i0.Input, args: [{ isSignal: true, alias: "httpHeaders", required: false }] }], page: [{ type: i0.Input, args: [{ isSignal: true, alias: "page", required: false }] }, { type: i0.Output, args: ["pageChange"] }], zoom: [{ type: i0.Input, args: [{ isSignal: true, alias: "zoom", required: false }] }, { type: i0.Output, args: ["zoomChange"] }], rotation: [{ type: i0.Input, args: [{ isSignal: true, alias: "rotation", required: false }] }, { type: i0.Output, args: ["rotationChange"] }], sidebar: [{ type: i0.Input, args: [{ isSignal: true, alias: "sidebar", required: false }] }, { type: i0.Output, args: ["sidebarChange"] }], showToolbar: [{ type: i0.Input, args: [{ isSignal: true, alias: "showToolbar", required: false }] }], showSearch: [{ type: i0.Input, args: [{ isSignal: true, alias: "showSearch", required: false }] }], showThumbnails: [{ type: i0.Input, args: [{ isSignal: true, alias: "showThumbnails", required: false }] }], showRotate: [{ type: i0.Input, args: [{ isSignal: true, alias: "showRotate", required: false }] }], downloadable: [{ type: i0.Input, args: [{ isSignal: true, alias: "downloadable", required: false }] }], printable: [{ type: i0.Input, args: [{ isSignal: true, alias: "printable", required: false }] }], ariaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "ariaLabel", required: false }] }], loaded: [{ type: i0.Output, args: ["loaded"] }], loadError: [{ type: i0.Output, args: ["loadError"] }], viewport: [{ type: i0.ViewChild, args: ['viewport', { isSignal: true }] }], pageEls: [{ type: i0.ViewChildren, args: ['pageEl', { isSignal: true }] }], thumbEls: [{ type: i0.ViewChildren, args: ['thumbEl', { isSignal: true }] }], searchInput: [{ type: i0.ViewChild, args: ['searchInput', { isSignal: true }] }], passwordInput: [{ type: i0.ViewChild, args: ['passwordInput', { isSignal: true }] }] } });
|
|
3217
|
+
`, styles: [":host{position:relative;display:flex;flex-direction:column;box-sizing:border-box;width:100%;height:var(--cb-pdf-viewer-height, 40rem);min-height:16rem;overflow:hidden;border:var(--cb-border-width, 1px) solid var(--cb-color-border);border-radius:var(--cb-radius-lg);background:var(--cb-color-surface);color:var(--cb-color-text);font-family:var(--cb-font-sans);font-size:var(--cb-text-sm);container-type:inline-size}.cb-pdf__toolbar{display:flex;flex-wrap:wrap;align-items:center;gap:var(--cb-space-2);padding:var(--cb-space-2) var(--cb-space-3);border-bottom:var(--cb-border-width, 1px) solid var(--cb-color-border);background:var(--cb-color-surface)}.cb-pdf__group{display:inline-flex;align-items:center;gap:var(--cb-space-1)}.cb-pdf__spacer{flex:1}.cb-pdf__tool{display:inline-flex;align-items:center;justify-content:center;width:2.25rem;height:2.25rem;padding:0;border:none;border-radius:var(--cb-radius-md);background:transparent;color:var(--cb-color-text);cursor:pointer;transition:background-color var(--cb-duration-fast) var(--cb-ease)}.cb-pdf__tool:hover:not(:disabled){background:var(--cb-color-surface-hover)}.cb-pdf__tool[aria-expanded=true]{background:var(--cb-color-surface-hover);color:var(--cb-color-primary-text)}.cb-pdf__tool:disabled{opacity:var(--cb-opacity-disabled, .5);cursor:default}.cb-pdf__tool:focus-visible,.cb-pdf__field:focus-visible,.cb-pdf__thumb:focus-visible,.cb-pdf__submit:focus-visible,.cb-pdf__viewport:focus-visible{outline:2px solid var(--cb-color-focus-ring);outline-offset:2px}.cb-pdf__field{height:2.25rem;padding:0 var(--cb-space-2);border:var(--cb-border-width, 1px) solid var(--cb-color-border-strong);border-radius:var(--cb-radius-md);background:var(--cb-color-surface);color:var(--cb-color-text);font:inherit}.cb-pdf__field:disabled{opacity:var(--cb-opacity-disabled, .5)}.cb-pdf__page-input{width:3.25rem;text-align:center}.cb-pdf__total{min-width:2.5rem;color:var(--cb-color-text-muted);white-space:nowrap}.cb-pdf__zoom{width:9.5rem}.cb-pdf__search{position:relative}.cb-pdf__search-icon{position:absolute;left:.625rem;color:var(--cb-color-text-muted);pointer-events:none}.cb-pdf__search-input{width:14rem;padding-left:2rem}.cb-pdf__status{min-width:4.5rem;color:var(--cb-color-text-muted);font-size:var(--cb-text-xs);text-align:center;white-space:nowrap}@container (max-width: 40rem){.cb-pdf__zoom,.cb-pdf__status{display:none}.cb-pdf__search-input{width:9rem}}.cb-pdf__body{display:flex;flex:1;min-height:0}.cb-pdf__sidebar{display:flex;flex-direction:column;gap:var(--cb-space-3);flex:none;width:10rem;padding:var(--cb-space-3) 0;overflow-y:auto;border-right:var(--cb-border-width, 1px) solid var(--cb-color-border);background:var(--cb-color-surface)}.cb-pdf__sidebar--tabs{width:12rem}.cb-pdf__sidebar--outline{width:16rem}.cb-pdf__thumbs{display:flex;flex-direction:column;align-items:center;gap:var(--cb-space-3)}.cb-pdf__views{display:flex;gap:2px;margin:0 var(--cb-space-2);padding:2px;border-radius:var(--cb-radius-md);background:var(--cb-color-surface-hover)}.cb-pdf__view{flex:1;min-width:0;padding:.25rem .375rem;border:0;border-radius:calc(var(--cb-radius-md) - 2px);background:transparent;color:var(--cb-color-text-muted);font:inherit;font-size:var(--cb-text-xs);font-weight:var(--cb-font-weight-medium);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;cursor:pointer}.cb-pdf__view[aria-pressed=true]{background:var(--cb-color-surface-raised);color:var(--cb-color-text-strong);box-shadow:0 1px 2px #0f172a1f}.cb-pdf__view:focus-visible,.cb-pdf__outline-link:focus-visible,.cb-pdf__outline-toggle:focus-visible{outline:2px solid var(--cb-color-focus-ring);outline-offset:1px}.cb-pdf__outline{padding:0 var(--cb-space-2)}.cb-pdf__outline-list{margin:0;padding:0;list-style:none}.cb-pdf__outline-list .cb-pdf__outline-list{padding-left:1rem}.cb-pdf__outline-item{display:flex;flex-wrap:wrap;align-items:flex-start}.cb-pdf__outline-item>.cb-pdf__outline-list{flex-basis:100%}.cb-pdf__outline-toggle{display:inline-flex;flex:none;align-items:center;justify-content:center;width:1.5rem;height:1.75rem;padding:0;border:0;border-radius:var(--cb-radius-sm);background:transparent;color:var(--cb-color-text-muted);cursor:pointer}.cb-pdf__outline-link{flex:1;min-width:0;padding:.3rem .375rem;border:0;border-radius:var(--cb-radius-sm);background:transparent;color:var(--cb-color-text);font:inherit;font-size:var(--cb-text-sm);line-height:1.3;text-align:start;cursor:pointer}.cb-pdf__outline-item>.cb-pdf__outline-link:first-child{margin-left:1.5rem}.cb-pdf__outline-link:hover,.cb-pdf__outline-toggle:hover{background:var(--cb-color-surface-hover)}.cb-pdf__outline-link--bold{font-weight:var(--cb-font-weight-semibold)}.cb-pdf__outline-link--italic{font-style:italic}.cb-pdf__thumb{display:flex;flex-direction:column;align-items:center;gap:var(--cb-space-1);padding:var(--cb-space-1);border:2px solid transparent;border-radius:var(--cb-radius-md);background:transparent;color:var(--cb-color-text-muted);font:inherit;font-size:var(--cb-text-xs);cursor:pointer}.cb-pdf__thumb:hover{background:var(--cb-color-surface-hover)}.cb-pdf__thumb.cb-is-active{border-color:var(--cb-color-primary-500);color:var(--cb-color-text-strong);font-weight:var(--cb-font-weight-semibold)}.cb-pdf__thumb-canvas{display:block;background:#fff;box-shadow:0 1px 3px #0f172a33}:host ::ng-deep .cb-pdf__thumb-canvas canvas{display:block;width:100%;height:100%}.cb-pdf__viewport{position:relative;flex:1;min-width:0;overflow:auto;background:var(--cb-color-surface-subtle)}.cb-pdf__pages{display:flex;flex-direction:column;align-items:center;gap:16px;padding:16px;width:max-content;min-width:100%;box-sizing:border-box}.cb-pdf__page{--user-unit: 1;--total-scale-factor: calc(var(--scale-factor) * var(--user-unit));--scale-round-x: 1px;--scale-round-y: 1px;position:relative;flex:none;background:#fff;box-shadow:0 1px 3px #0f172a2e,0 4px 12px #0f172a14;direction:ltr}.cb-pdf__canvas,:host ::ng-deep .cb-pdf__canvas canvas{position:absolute;inset:0;width:100%;height:100%}.cb-pdf__text{position:absolute;inset:0;overflow:clip;opacity:1;line-height:1;text-align:initial;letter-spacing:normal;word-spacing:normal;-webkit-text-size-adjust:none;text-size-adjust:none;forced-color-adjust:none;transform-origin:0 0;caret-color:CanvasText;z-index:0;--min-font-size: 1;--text-scale-factor: calc(var(--total-scale-factor) * var(--min-font-size));--min-font-size-inv: calc(1 / var(--min-font-size))}.cb-pdf__text[data-main-rotation=\"90\"]{transform:rotate(90deg) translateY(-100%)}.cb-pdf__text[data-main-rotation=\"180\"]{transform:rotate(180deg) translate(-100%,-100%)}.cb-pdf__text[data-main-rotation=\"270\"]{transform:rotate(270deg) translate(-100%)}.cb-pdf__annotations{position:absolute;inset:0;z-index:1;transform-origin:0 0;pointer-events:none}.cb-pdf__annotations[data-main-rotation=\"90\"]{transform:rotate(90deg) translateY(-100%)}.cb-pdf__annotations[data-main-rotation=\"180\"]{transform:rotate(180deg) translate(-100%,-100%)}.cb-pdf__annotations[data-main-rotation=\"270\"]{transform:rotate(270deg) translate(-100%)}:host ::ng-deep .cb-pdf__annotations section{position:absolute;box-sizing:border-box;text-align:initial;transform-origin:0 0;pointer-events:auto}:host ::ng-deep .cb-pdf__annotations [hidden]{display:none!important}:host ::ng-deep .cb-pdf__annotations .linkAnnotation>a{position:absolute;inset:0;border-radius:2px}:host ::ng-deep .cb-pdf__annotations .linkAnnotation>a:hover{background:#0e74901f}:host ::ng-deep .cb-pdf__annotations .linkAnnotation>a:focus-visible{outline:2px solid var(--cb-color-focus-ring);outline-offset:1px}:host ::ng-deep .cb-pdf__annotations :is(.textWidgetAnnotation,.choiceWidgetAnnotation) :is(input,textarea,select){width:100%;height:100%;box-sizing:border-box;margin:0;padding:0 calc(2px * var(--total-scale-factor));border:1px solid transparent;border-radius:0;background:#2563eb1a;color:#111827;font-family:Helvetica,Arial,sans-serif;font-size:calc(9px * var(--total-scale-factor));vertical-align:top}:host ::ng-deep .cb-pdf__annotations .textWidgetAnnotation textarea{padding-top:calc(2px * var(--total-scale-factor));resize:none}:host ::ng-deep .cb-pdf__annotations :is(.textWidgetAnnotation,.choiceWidgetAnnotation) :is(input,textarea,select):hover{border-color:#2563eb99}:host ::ng-deep .cb-pdf__annotations :is(input,textarea,select):focus{border-color:transparent;outline:2px solid var(--cb-color-focus-ring);outline-offset:0;background:#2563eb0a}:host ::ng-deep .cb-pdf__annotations :is(input,textarea,select):disabled{background:transparent}:host ::ng-deep .cb-pdf__annotations .buttonWidgetAnnotation :is(.checkBox,.radioButton) input{width:100%;height:100%;margin:0;accent-color:var(--cb-color-primary-600, #0e7490);cursor:pointer}:host ::ng-deep .cb-pdf__annotations .buttonWidgetAnnotation.checkBox input,:host ::ng-deep .cb-pdf__annotations .buttonWidgetAnnotation.radioButton input{width:100%;height:100%;margin:0;accent-color:var(--cb-color-primary-600, #0e7490);cursor:pointer}:host ::ng-deep .cb-pdf__text :is(span,br){position:absolute;color:transparent;white-space:pre;cursor:text;transform-origin:0% 0%;-webkit-user-select:text;user-select:text}:host ::ng-deep .cb-pdf__text>:not(.markedContent),:host ::ng-deep .cb-pdf__text .markedContent span:not(.markedContent){--font-height: 0;--scale-x: 1;--rotate: 0deg;z-index:1;font-size:calc(var(--text-scale-factor) * var(--font-height));transform:rotate(var(--rotate)) scaleX(var(--scale-x)) scale(var(--min-font-size-inv))}:host ::ng-deep .cb-pdf__text .markedContent{display:contents}:host ::ng-deep .cb-pdf__text span[role=img]{-webkit-user-select:none;user-select:none;cursor:default}:host ::ng-deep .cb-pdf__text ::selection{background:color-mix(in srgb,var(--cb-color-primary-500) 35%,transparent);color:transparent}:host ::ng-deep .cb-pdf__text .cb-pdf__hl{position:relative;margin:-1px;padding:1px;border-radius:3px;background:#facc1573;font-size:inherit;transform:none}:host ::ng-deep .cb-pdf__text .cb-pdf__hl.cb-is-selected{background:#f973168c;outline:2px solid rgb(234 88 12)}@media(forced-colors:active){:host ::ng-deep .cb-pdf__text .cb-pdf__hl{background:transparent;outline:1px solid Highlight}:host ::ng-deep .cb-pdf__text .cb-pdf__hl.cb-is-selected{outline:3px solid Highlight}}.cb-pdf__message{display:flex;flex-direction:column;align-items:center;justify-content:center;gap:var(--cb-space-3);height:100%;padding:var(--cb-space-6);color:var(--cb-color-text-muted);text-align:center}.cb-pdf__message--error{color:var(--cb-color-danger)}.cb-pdf__password{display:flex;flex-direction:column;align-items:center;gap:var(--cb-space-2);max-width:24rem;margin:var(--cb-space-6) auto;padding:var(--cb-space-6);border:var(--cb-border-width, 1px) solid var(--cb-color-border);border-radius:var(--cb-radius-lg);background:var(--cb-color-surface);text-align:center}.cb-pdf__password-text{margin:0}.cb-pdf__password-label{align-self:flex-start;font-weight:var(--cb-font-weight-medium)}.cb-pdf__password-row{display:flex;gap:var(--cb-space-2);width:100%}.cb-pdf__password-row .cb-pdf__field{flex:1;min-width:0}.cb-pdf__password-error{margin:0;color:var(--cb-color-danger)}.cb-pdf__submit{height:2.25rem;padding:0 var(--cb-space-4);border:none;border-radius:var(--cb-radius-md);background:var(--cb-color-primary-500);color:var(--cb-color-primary-contrast);font:inherit;font-weight:var(--cb-font-weight-semibold);cursor:pointer}.cb-pdf__submit:hover{background:var(--cb-color-primary-600)}.cb-pdf__toast{position:absolute;left:50%;bottom:var(--cb-space-4);transform:translate(-50%);padding:var(--cb-space-2) var(--cb-space-4);border-radius:var(--cb-radius-full);background:var(--cb-color-surface-950);color:#fff;box-shadow:var(--cb-shadow-md)}.cb-pdf__tool[aria-pressed=true]{background:color-mix(in srgb,var(--cb-color-primary-500) 16%,transparent);color:var(--cb-color-primary-700)}:host-context([data-theme=\"dark\"]) .cb-pdf__tool[aria-pressed=true]{color:var(--cb-color-primary-300)}.cb-pdf__color{position:relative;display:inline-flex;align-items:center}.cb-pdf__swatch{position:absolute;left:.625rem;width:.875rem;height:.875rem;border:2px solid;border-radius:var(--cb-radius-full);pointer-events:none}.cb-pdf__color-select{padding-left:1.875rem}.cb-pdf__hint{position:sticky;top:var(--cb-space-2);z-index:4;box-sizing:border-box;width:max-content;max-width:calc(100% - 2rem);height:2rem;margin:var(--cb-space-2) auto calc(-2rem - var(--cb-space-2));padding:0 var(--cb-space-3);overflow:hidden;border-radius:var(--cb-radius-full);background:var(--cb-color-surface-950, #0f172a);color:#fff;font-size:var(--cb-text-xs);line-height:2rem;text-overflow:ellipsis;white-space:nowrap;box-shadow:var(--cb-shadow-md)}.cb-pdf__marks{position:absolute;inset:0;z-index:2;pointer-events:none}.cb-pdf__marks--capture{pointer-events:auto;cursor:cell;touch-action:none}.cb-pdf__marks--ink{cursor:crosshair}.cb-pdf__mark{position:absolute;box-sizing:border-box;pointer-events:auto;border-radius:2px;outline-offset:2px;touch-action:none}.cb-pdf__mark:focus-visible,.cb-pdf__mark.cb-is-selected{outline:2px solid var(--cb-color-focus-ring)}.cb-pdf__marks--pass .cb-pdf__mark--highlight{pointer-events:none}.cb-pdf__mark--highlight{cursor:pointer}.cb-pdf__hl-rect{position:absolute;background:color-mix(in srgb,var(--cb-pdf-mark-light) 55%,transparent)}.cb-pdf__hl-badge{position:absolute;top:-.35rem;right:-.35rem;width:.625rem;height:.625rem;border:2px solid #fff;border-radius:var(--cb-radius-full);background:var(--cb-pdf-mark-dark)}.cb-pdf__mark--note,.cb-pdf__mark--signature,.cb-pdf__mark--ink{cursor:move}.cb-pdf__note-text{display:block;box-sizing:border-box;padding:.1em .3em;border:1px dashed color-mix(in srgb,var(--cb-pdf-mark-dark) 45%,transparent);border-radius:2px;background:transparent;color:var(--cb-pdf-mark-dark);font-family:Helvetica,Arial,sans-serif;line-height:1.2;white-space:pre}.cb-pdf__ink,.cb-pdf__stroke{position:absolute;inset:0;width:100%;height:100%;overflow:visible;pointer-events:none}.cb-pdf__ink path,.cb-pdf__stroke polyline{fill:none;stroke:var(--cb-pdf-mark-dark);stroke-linecap:round;stroke-linejoin:round}.cb-pdf__sig{display:block;width:100%;height:100%;-webkit-user-select:none;user-select:none;-webkit-user-drag:none}.cb-pdf__resize{position:absolute;right:-.4rem;bottom:-.4rem;width:.8rem;height:.8rem;border:2px solid #fff;border-radius:2px;background:var(--cb-color-focus-ring);cursor:nwse-resize}.cb-pdf__card{position:absolute;z-index:3;display:flex;flex-direction:column;gap:var(--cb-space-2);box-sizing:border-box;width:16rem;padding:var(--cb-space-3);border:var(--cb-border-width, 1px) solid var(--cb-color-border);border-radius:var(--cb-radius-md);background:var(--cb-color-surface-raised, var(--cb-color-surface));color:var(--cb-color-text);font-size:var(--cb-text-sm);box-shadow:var(--cb-shadow-lg);pointer-events:auto;cursor:auto}.cb-pdf__card-label{font-weight:var(--cb-font-weight-medium)}.cb-pdf__card-text{height:auto;min-height:4.5rem;padding:var(--cb-space-2);resize:vertical}.cb-pdf__card-actions,.cb-pdf__sign-actions{display:flex;justify-content:flex-end;gap:var(--cb-space-2)}.cb-pdf__card-btn{height:2rem;padding:0 var(--cb-space-3);border:var(--cb-border-width, 1px) solid var(--cb-color-border-strong);border-radius:var(--cb-radius-md);background:transparent;color:var(--cb-color-text);font:inherit;cursor:pointer}.cb-pdf__card-btn:hover:not(:disabled){background:var(--cb-color-surface-hover)}.cb-pdf__card-btn--primary{border-color:var(--cb-color-primary-500);background:var(--cb-color-primary-500);color:var(--cb-color-primary-contrast);font-weight:var(--cb-font-weight-semibold)}.cb-pdf__card-btn--primary:hover:not(:disabled){background:var(--cb-color-primary-600)}.cb-pdf__card-btn:disabled{opacity:var(--cb-opacity-disabled, .5);cursor:default}.cb-pdf__card-btn:focus-visible,.cb-pdf__card-text:focus-visible,.cb-pdf__notes-link:focus-visible,.cb-pdf__notes-remove:focus-visible{outline:2px solid var(--cb-color-focus-ring);outline-offset:2px}.cb-pdf__notes-panel{padding:0 var(--cb-space-2)}.cb-pdf__notes-empty{margin:0;padding:var(--cb-space-2);color:var(--cb-color-text-muted)}.cb-pdf__notes-list{display:flex;flex-direction:column;gap:2px;margin:0;padding:0;list-style:none}.cb-pdf__notes-item{display:flex;align-items:flex-start;gap:2px}.cb-pdf__notes-link{display:flex;flex:1;align-items:flex-start;gap:var(--cb-space-2);min-width:0;padding:var(--cb-space-2);border:0;border-radius:var(--cb-radius-md);background:transparent;color:var(--cb-color-text);font:inherit;text-align:left;cursor:pointer}.cb-pdf__notes-link:hover,.cb-pdf__notes-remove:hover{background:var(--cb-color-surface-hover)}.cb-pdf__notes-swatch{flex:none;width:.625rem;height:.625rem;margin-top:.3rem;border-radius:var(--cb-radius-full)}.cb-pdf__notes-text{display:flex;flex-direction:column;min-width:0}.cb-pdf__notes-page{color:var(--cb-color-text-muted);font-size:var(--cb-text-xs)}.cb-pdf__notes-label{overflow:hidden;display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:3;overflow-wrap:anywhere}.cb-pdf__notes-remove{display:inline-flex;flex:none;align-items:center;justify-content:center;width:2rem;height:2rem;border:0;border-radius:var(--cb-radius-md);background:transparent;color:var(--cb-color-text-muted);cursor:pointer}.cb-pdf__sr{position:absolute;width:1px;height:1px;margin:-1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap;border:0}@media(forced-colors:active){.cb-pdf__hl-rect{background:transparent;outline:2px solid Mark}.cb-pdf__note-text{border-color:CanvasText}}\n"] }]
|
|
3218
|
+
}], ctorParameters: () => [], propDecorators: { src: [{ type: i0.Input, args: [{ isSignal: true, alias: "src", required: false }] }], fileName: [{ type: i0.Input, args: [{ isSignal: true, alias: "fileName", required: false }] }], password: [{ type: i0.Input, args: [{ isSignal: true, alias: "password", required: false }] }], withCredentials: [{ type: i0.Input, args: [{ isSignal: true, alias: "withCredentials", required: false }] }], httpHeaders: [{ type: i0.Input, args: [{ isSignal: true, alias: "httpHeaders", required: false }] }], page: [{ type: i0.Input, args: [{ isSignal: true, alias: "page", required: false }] }, { type: i0.Output, args: ["pageChange"] }], zoom: [{ type: i0.Input, args: [{ isSignal: true, alias: "zoom", required: false }] }, { type: i0.Output, args: ["zoomChange"] }], rotation: [{ type: i0.Input, args: [{ isSignal: true, alias: "rotation", required: false }] }, { type: i0.Output, args: ["rotationChange"] }], sidebar: [{ type: i0.Input, args: [{ isSignal: true, alias: "sidebar", required: false }] }, { type: i0.Output, args: ["sidebarChange"] }], showToolbar: [{ type: i0.Input, args: [{ isSignal: true, alias: "showToolbar", required: false }] }], showSearch: [{ type: i0.Input, args: [{ isSignal: true, alias: "showSearch", required: false }] }], showThumbnails: [{ type: i0.Input, args: [{ isSignal: true, alias: "showThumbnails", required: false }] }], showRotate: [{ type: i0.Input, args: [{ isSignal: true, alias: "showRotate", required: false }] }], downloadable: [{ type: i0.Input, args: [{ isSignal: true, alias: "downloadable", required: false }] }], printable: [{ type: i0.Input, args: [{ isSignal: true, alias: "printable", required: false }] }], showOutline: [{ type: i0.Input, args: [{ isSignal: true, alias: "showOutline", required: false }] }], forms: [{ type: i0.Input, args: [{ isSignal: true, alias: "forms", required: false }] }], externalLinks: [{ type: i0.Input, args: [{ isSignal: true, alias: "externalLinks", required: false }] }], sidebarView: [{ type: i0.Input, args: [{ isSignal: true, alias: "sidebarView", required: false }] }, { type: i0.Output, args: ["sidebarViewChange"] }], ariaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "ariaLabel", required: false }] }], annotatable: [{ type: i0.Input, args: [{ isSignal: true, alias: "annotatable", required: false }] }], annotations: [{ type: i0.Input, args: [{ isSignal: true, alias: "annotations", required: false }] }, { type: i0.Output, args: ["annotationsChange"] }], tool: [{ type: i0.Input, args: [{ isSignal: true, alias: "tool", required: false }] }, { type: i0.Output, args: ["toolChange"] }], annotationColor: [{ type: i0.Input, args: [{ isSignal: true, alias: "annotationColor", required: false }] }, { type: i0.Output, args: ["annotationColorChange"] }], author: [{ type: i0.Input, args: [{ isSignal: true, alias: "author", required: false }] }], loaded: [{ type: i0.Output, args: ["loaded"] }], loadError: [{ type: i0.Output, args: ["loadError"] }], formChange: [{ type: i0.Output, args: ["formChange"] }], annotationAdd: [{ type: i0.Output, args: ["annotationAdd"] }], annotationRemove: [{ type: i0.Output, args: ["annotationRemove"] }], viewport: [{ type: i0.ViewChild, args: ['viewport', { isSignal: true }] }], pageEls: [{ type: i0.ViewChildren, args: ['pageEl', { isSignal: true }] }], thumbEls: [{ type: i0.ViewChildren, args: ['thumbEl', { isSignal: true }] }], searchInput: [{ type: i0.ViewChild, args: ['searchInput', { isSignal: true }] }], passwordInput: [{ type: i0.ViewChild, args: ['passwordInput', { isSignal: true }] }], cardText: [{ type: i0.ViewChild, args: ['cardText', { isSignal: true }] }] } });
|
|
1507
3219
|
function sizeOf(page) {
|
|
1508
3220
|
const viewport = page.getViewport({ scale: 1, rotation: 0 });
|
|
1509
3221
|
const userUnit = page.userUnit || 1;
|
|
1510
|
-
|
|
3222
|
+
const [x0 = 0, y0 = 0] = page.view ?? [];
|
|
3223
|
+
return { x0, y0, width: viewport.width, height: viewport.height, rotate: page.rotate || 0, userUnit };
|
|
1511
3224
|
}
|
|
1512
3225
|
/** Bytes del documento si no es una URL (copiados: pdf.js transfiere el buffer al worker). */
|
|
1513
3226
|
async function toData(src) {
|
|
@@ -1541,6 +3254,23 @@ function clamp(value, min, max) {
|
|
|
1541
3254
|
function round2(value) {
|
|
1542
3255
|
return Math.round(value * 100) / 100;
|
|
1543
3256
|
}
|
|
3257
|
+
/** Quita de una selección las cajas mucho más altas que una línea (contenedores, fin de contenido). */
|
|
3258
|
+
function withoutTallRects(rects) {
|
|
3259
|
+
if (rects.length < 2)
|
|
3260
|
+
return rects;
|
|
3261
|
+
const heights = rects.map((r) => r.height).sort((a, b) => a - b);
|
|
3262
|
+
const median = heights[Math.floor(heights.length / 2)];
|
|
3263
|
+
return rects.filter((r) => r.height <= median * 2.5);
|
|
3264
|
+
}
|
|
3265
|
+
function unionBox(boxes) {
|
|
3266
|
+
const left = Math.min(...boxes.map((b) => b.left));
|
|
3267
|
+
const top = Math.min(...boxes.map((b) => b.top));
|
|
3268
|
+
return { left, top, width: Math.max(...boxes.map((b) => b.left + b.width)) - left, height: Math.max(...boxes.map((b) => b.top + b.height)) - top };
|
|
3269
|
+
}
|
|
3270
|
+
function truncate(text, max) {
|
|
3271
|
+
const clean = text.replace(/\s+/g, ' ').trim();
|
|
3272
|
+
return clean.length > max ? `${clean.slice(0, max - 1)}…` : clean;
|
|
3273
|
+
}
|
|
1544
3274
|
|
|
1545
3275
|
/*
|
|
1546
3276
|
* Public API Surface de @caribeng/ui/pdfviewer
|
|
@@ -1550,4 +3280,4 @@ function round2(value) {
|
|
|
1550
3280
|
* Generated bundle index. Do not edit.
|
|
1551
3281
|
*/
|
|
1552
3282
|
|
|
1553
|
-
export { CB_PDF_VIEWER_OPTIONS, CbPdfEngine, CbPdfViewer, provideCbPdfViewer };
|
|
3283
|
+
export { CB_PDF_COLORS, CB_PDF_VIEWER_OPTIONS, CbPdfEngine, CbPdfViewer, provideCbPdfViewer };
|