@yelon/abc
Version:
Common business components of ng-yunzai.
506 lines (499 loc) • 18.9 kB
JavaScript
import { __decorate } from 'tslib';
import { Platform } from '@angular/cdk/platform';
import { DOCUMENT, CommonModule } from '@angular/common';
import * as i0 from '@angular/core';
import { inject, ElementRef, ChangeDetectorRef, NgZone, DestroyRef, EventEmitter, numberAttribute, booleanAttribute, Output, Input, ViewEncapsulation, ChangeDetectionStrategy, Component, NgModule } from '@angular/core';
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
import { timer, fromEvent, debounceTime, filter } from 'rxjs';
import { YunzaiConfigService } from '@yelon/util/config';
import { ZoneOutside } from '@yelon/util/decorator';
import { LazyService } from '@yelon/util/other';
import { NzSkeletonComponent, NzSkeletonModule } from 'ng-zorro-antd/skeleton';
const PDF_DEFULAT_CONFIG = {
lib: `https://cdn.jsdelivr.net/npm/pdfjs-dist@3.6.x/`,
showAll: true,
renderText: true,
showBorders: false,
originalSize: true,
fitToPage: false,
autoReSize: true
};
// import type { PDFDocumentProxy } from 'pdfjs-dist';
var PdfTextLayerMode;
(function (PdfTextLayerMode) {
PdfTextLayerMode[PdfTextLayerMode["DISABLE"] = 0] = "DISABLE";
PdfTextLayerMode[PdfTextLayerMode["ENABLE"] = 1] = "ENABLE";
PdfTextLayerMode[PdfTextLayerMode["ENABLE_ENHANCE"] = 2] = "ENABLE_ENHANCE";
})(PdfTextLayerMode || (PdfTextLayerMode = {}));
var PdfExternalLinkTarget;
(function (PdfExternalLinkTarget) {
PdfExternalLinkTarget[PdfExternalLinkTarget["NONE"] = 0] = "NONE";
PdfExternalLinkTarget[PdfExternalLinkTarget["SELF"] = 1] = "SELF";
PdfExternalLinkTarget[PdfExternalLinkTarget["BLANK"] = 2] = "BLANK";
PdfExternalLinkTarget[PdfExternalLinkTarget["PARENT"] = 3] = "PARENT";
PdfExternalLinkTarget[PdfExternalLinkTarget["TOP"] = 4] = "TOP";
})(PdfExternalLinkTarget || (PdfExternalLinkTarget = {}));
const CSS_UNITS = 96.0 / 72.0;
const BORDER_WIDTH = 9;
class PdfComponent {
lazySrv = inject(LazyService);
platform = inject(Platform);
_el = inject(ElementRef).nativeElement;
doc = inject(DOCUMENT);
cdr = inject(ChangeDetectorRef);
ngZone = inject(NgZone);
destroy$ = inject(DestroyRef);
cogSrv = inject(YunzaiConfigService);
inited = false;
lib = '';
_pdf;
loadingTask;
_src;
lastSrc;
_pi = 1;
_total = 0;
_showAll = true;
_rotation = 0;
_zoom = 1;
_renderText = true;
_loading = false;
multiPageViewer;
multiPageLinkService;
multiPageFindController;
singlePageViewer;
singlePageLinkService;
singlePageFindController;
_eventBus;
set src(dataOrBuffer) {
this._src = dataOrBuffer;
this.load();
}
set pi(val) {
this._pi = this.getValidPi(val);
if (this.pageViewer) {
this.pageViewer.scrollPageIntoView({ pageNumber: this._pi });
}
}
set showAll(val) {
this._showAll = val;
this.resetDoc();
}
set renderText(val) {
this._renderText = val;
if (this.pageViewer) {
this.resetDoc();
}
}
textLayerMode = PdfTextLayerMode.ENABLE;
showBorders = false;
stickToPage = false;
originalSize = true;
fitToPage = false;
set zoom(val) {
if (val <= 0)
return;
this._zoom = val;
}
zoomScale = 'page-width';
set rotation(val) {
if (val % 90 !== 0) {
console.warn(`Invalid rotation angle, shoule be divisible by 90.`);
return;
}
this._rotation = val;
}
autoReSize = true;
externalLinkTarget = PdfExternalLinkTarget.BLANK;
delay;
change = new EventEmitter();
get loading() {
return this._loading;
}
get pdf() {
return this._pdf;
}
get findController() {
return this._showAll ? this.multiPageFindController : this.singlePageFindController;
}
get pageViewer() {
return this._showAll ? this.multiPageViewer : this.singlePageViewer;
}
get linkService() {
return this._showAll ? this.multiPageLinkService : this.singlePageLinkService;
}
get eventBus() {
return this._eventBus;
}
get _textLayerMode() {
return this._renderText ? this.textLayerMode : PdfTextLayerMode.DISABLE;
}
get win() {
return this.doc.defaultView || window;
}
get el() {
return this._el.querySelector('.pdf-container');
}
constructor() {
const cog = this.cogSrv.merge('pdf', PDF_DEFULAT_CONFIG);
Object.assign(this, cog);
const lib = cog.lib;
this.lib = lib.endsWith('/') ? lib : `${lib}/`;
}
getValidPi(pi) {
if (pi < 1)
return 1;
const pdf = this._pdf;
return pdf && pi > pdf.numPages ? pdf.numPages : pi;
}
emit(type, opt) {
this.ngZone.run(() => this.change.emit({
type,
pdf: this._pdf,
pi: this._pi,
total: this._total,
...opt
}));
}
initDelay() {
if (!this.win.pdfjsLib) {
throw new Error(`No window.pdfjsLib found, please make sure that cdn or local path exists, the current referenced path is: ${JSON.stringify(this.lib)}`);
}
this.inited = true;
this.cdr.detectChanges();
this.win.pdfjsLib.GlobalWorkerOptions.workerSrc = `${this.lib}build/pdf.worker.min.js`;
timer(this.delay ?? 0)
.pipe(takeUntilDestroyed(this.destroy$))
.subscribe(() => this.load());
}
setLoading(status) {
this.ngZone.run(() => {
this._loading = status;
this.cdr.detectChanges();
});
}
load() {
const { _src } = this;
if (!this.inited || !_src) {
return;
}
if (this.lastSrc === _src) {
this.render();
return;
}
this.destroy();
this.ngZone.run(() => {
this._loading = true;
this.cdr.detectChanges();
});
this.setLoading(true);
const loadingTask = (this.loadingTask = this.win.pdfjsLib.getDocument(_src));
loadingTask.onProgress = (progress) => this.emit('load-progress', { progress });
loadingTask.promise
.then(pdf => {
this._pdf = pdf;
this.lastSrc = _src;
this._total = pdf.numPages;
this.emit('loaded');
if (!this.pageViewer) {
this.setupPageViewer();
}
this.resetDoc();
this.render();
}, error => this.emit('error', { error }))
.then(() => this.setLoading(false));
}
resetDoc() {
const pdf = this._pdf;
if (!pdf) {
return;
}
this.cleanDoc();
this.findController.setDocument(pdf);
this.pageViewer.setDocument(pdf);
this.linkService.setDocument(pdf, null);
}
cleanDoc() {
this.multiPageViewer.setDocument(null);
this.singlePageViewer.setDocument(null);
this.multiPageLinkService.setDocument(null, null);
this.singlePageLinkService.setDocument(null, null);
this.multiPageFindController.setDocument(null);
this.singlePageFindController.setDocument(null);
}
render() {
const currentViewer = this.pageViewer;
if (!currentViewer) {
return;
}
if (this._rotation !== 0 || currentViewer.pagesRotation !== this._rotation) {
this.timeExec(() => {
currentViewer.pagesRotation = this._rotation;
});
}
if (this.stickToPage) {
this.timeExec(() => {
currentViewer.currentPageNumber = this._pi;
});
}
this.updateSize();
}
timeExec(fn) {
this.ngZone.runOutsideAngular(() => {
timer(0)
.pipe(takeUntilDestroyed(this.destroy$))
.subscribe(() => this.ngZone.runOutsideAngular(() => fn()));
});
}
updateSize() {
const currentViewer = this.pageViewer;
if (!currentViewer)
return;
this._pdf.getPage(currentViewer.currentPageNumber).then((page) => {
const { _rotation, _zoom } = this;
const rotation = _rotation || page.rotate;
const viewportWidth = page.getViewport({
scale: _zoom,
rotation
}).width * CSS_UNITS;
let scale = _zoom;
// Scale the document when it shouldn't be in original size or doesn't fit into the viewport
if (!this.originalSize || (this.fitToPage && viewportWidth > this.el.clientWidth)) {
const viewPort = page.getViewport({ scale: 1, rotation });
scale = this.getScale(viewPort.width, viewPort.height);
}
currentViewer.currentScale = scale;
});
}
getScale(viewportWidth, viewportHeight) {
const borderSize = this.showBorders ? 2 * BORDER_WIDTH : 0;
const el = this.el;
const containerWidth = el.clientWidth - borderSize;
const containerHeight = el.clientHeight - borderSize;
if (containerHeight === 0 || viewportHeight === 0 || containerWidth === 0 || viewportWidth === 0) {
return 1;
}
let ratio = 1;
switch (this.zoomScale) {
case 'page-fit':
ratio = Math.min(containerHeight / viewportHeight, containerWidth / viewportWidth);
break;
case 'page-height':
ratio = containerHeight / viewportHeight;
break;
case 'page-width':
default:
ratio = containerWidth / viewportWidth;
break;
}
return (this._zoom * ratio) / CSS_UNITS;
}
destroy() {
const { loadingTask } = this;
if (loadingTask && !loadingTask.destroyed) {
loadingTask.destroy();
}
if (this._pdf) {
this._pdf.destroy();
this._pdf = null;
this.cleanDoc();
}
}
setupPageViewer() {
this.win.pdfjsLib.disableTextLayer = !this._renderText;
this.win.pdfjsLib.externalLinkTarget = this.externalLinkTarget;
this.setupMultiPageViewer();
this.setupSinglePageViewer();
}
createEventBus() {
const eventBus = new this.win.pdfjsViewer.EventBus();
eventBus.on(`pagesinit`, (ev) => {
this.emit('pages-init', { ev });
});
eventBus.on(`pagerendered`, (ev) => {
this.emit('page-rendered', { ev });
});
eventBus.on(`pagechanging`, (ev) => {
const nowPi = ev.pageNumber;
if (nowPi !== this._pi) {
this._pi = nowPi;
this.emit('pi', { ev });
}
});
eventBus.on(`textlayerrendered`, (ev) => {
this.emit('text-layer-rendered', { ev });
});
return eventBus;
}
setupMultiPageViewer() {
const VIEWER = this.win.pdfjsViewer;
const eventBus = (this._eventBus = this.createEventBus());
const linkService = (this.multiPageLinkService = new VIEWER.PDFLinkService({
eventBus
}));
const findController = (this.multiPageFindController = new VIEWER.PDFFindController({
eventBus,
linkService
}));
const viewer = (this.multiPageViewer = new VIEWER.PDFViewer({
eventBus,
container: this.el,
removePageBorders: !this.showBorders,
textLayerMode: this._textLayerMode,
linkService,
findController
}));
linkService.setViewer(viewer);
}
setupSinglePageViewer() {
const VIEWER = this.win.pdfjsViewer;
const eventBus = this.createEventBus();
const linkService = (this.singlePageLinkService = new VIEWER.PDFLinkService({
eventBus
}));
const findController = (this.singlePageFindController = new VIEWER.PDFFindController({
eventBus,
linkService
}));
const pageViewer = (this.singlePageViewer = new VIEWER.PDFSinglePageViewer({
eventBus,
container: this.el,
removePageBorders: !this.showBorders,
textLayerMode: this._textLayerMode,
linkService,
findController
}));
linkService.setViewer(pageViewer);
pageViewer._currentPageNumber = this._pi;
}
ngAfterViewInit() {
if (!this.platform.isBrowser) {
return;
}
if (this.win.pdfjsLib) {
this.initDelay();
return;
}
const { lib } = this;
this.lazySrv
.load(`${lib}build/pdf.min.js`)
.then(() => this.lazySrv.load([`${lib}web/pdf_viewer.js`, `${lib}web/pdf_viewer.css`]))
.then(() => this.initDelay());
this.ngZone.runOutsideAngular(() => this.initResize());
}
initResize() {
fromEvent(this.win, 'resize')
.pipe(debounceTime(100), filter(() => this.autoReSize && this._pdf != null), takeUntilDestroyed(this.destroy$))
.subscribe(() => this.updateSize());
}
ngOnChanges(changes) {
if (this.inited && !changes.src) {
this.render();
}
}
ngOnDestroy() {
this.destroy();
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.3", ngImport: i0, type: PdfComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.1.3", type: PdfComponent, isStandalone: true, selector: "pdf", inputs: { src: "src", pi: ["pi", "pi", numberAttribute], showAll: ["showAll", "showAll", booleanAttribute], renderText: ["renderText", "renderText", booleanAttribute], textLayerMode: "textLayerMode", showBorders: ["showBorders", "showBorders", booleanAttribute], stickToPage: ["stickToPage", "stickToPage", booleanAttribute], originalSize: ["originalSize", "originalSize", booleanAttribute], fitToPage: ["fitToPage", "fitToPage", booleanAttribute], zoom: ["zoom", "zoom", numberAttribute], zoomScale: "zoomScale", rotation: ["rotation", "rotation", numberAttribute], autoReSize: ["autoReSize", "autoReSize", booleanAttribute], externalLinkTarget: "externalLinkTarget", delay: ["delay", "delay", numberAttribute] }, outputs: { change: "change" }, host: { properties: { "class.d-block": "true" } }, exportAs: ["pdf"], usesOnChanges: true, ngImport: i0, template: `
(!inited || loading) {
<nz-skeleton />
}
<div class="pdf-container">
<div class="pdfViewer"></div>
</div>
`, isInline: true, dependencies: [{ kind: "component", type: NzSkeletonComponent, selector: "nz-skeleton", inputs: ["nzActive", "nzLoading", "nzRound", "nzTitle", "nzAvatar", "nzParagraph"], exportAs: ["nzSkeleton"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
}
__decorate([
ZoneOutside()
], PdfComponent.prototype, "load", null);
__decorate([
ZoneOutside()
], PdfComponent.prototype, "resetDoc", null);
__decorate([
ZoneOutside()
], PdfComponent.prototype, "updateSize", null);
__decorate([
ZoneOutside()
], PdfComponent.prototype, "destroy", null);
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.3", ngImport: i0, type: PdfComponent, decorators: [{
type: Component,
args: [{
selector: 'pdf',
exportAs: 'pdf',
template: `
(!inited || loading) {
<nz-skeleton />
}
<div class="pdf-container">
<div class="pdfViewer"></div>
</div>
`,
host: {
'[class.d-block]': `true`
},
changeDetection: ChangeDetectionStrategy.OnPush,
encapsulation: ViewEncapsulation.None,
imports: [NzSkeletonComponent]
}]
}], ctorParameters: () => [], propDecorators: { src: [{
type: Input
}], pi: [{
type: Input,
args: [{ transform: numberAttribute }]
}], showAll: [{
type: Input,
args: [{ transform: booleanAttribute }]
}], renderText: [{
type: Input,
args: [{ transform: booleanAttribute }]
}], textLayerMode: [{
type: Input
}], showBorders: [{
type: Input,
args: [{ transform: booleanAttribute }]
}], stickToPage: [{
type: Input,
args: [{ transform: booleanAttribute }]
}], originalSize: [{
type: Input,
args: [{ transform: booleanAttribute }]
}], fitToPage: [{
type: Input,
args: [{ transform: booleanAttribute }]
}], zoom: [{
type: Input,
args: [{ transform: numberAttribute }]
}], zoomScale: [{
type: Input
}], rotation: [{
type: Input,
args: [{ transform: numberAttribute }]
}], autoReSize: [{
type: Input,
args: [{ transform: booleanAttribute }]
}], externalLinkTarget: [{
type: Input
}], delay: [{
type: Input,
args: [{ transform: numberAttribute }]
}], change: [{
type: Output
}], load: [], resetDoc: [], updateSize: [], destroy: [] } });
const COMPONENTS = [PdfComponent];
class PdfModule {
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.3", ngImport: i0, type: PdfModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
static ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "20.1.3", ngImport: i0, type: PdfModule, imports: [CommonModule, NzSkeletonModule, PdfComponent], exports: [PdfComponent] });
static ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "20.1.3", ngImport: i0, type: PdfModule, imports: [CommonModule, NzSkeletonModule, COMPONENTS] });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.3", ngImport: i0, type: PdfModule, decorators: [{
type: NgModule,
args: [{
imports: [CommonModule, NzSkeletonModule, ...COMPONENTS],
exports: COMPONENTS
}]
}] });
/**
* Generated bundle index. Do not edit.
*/
export { PDF_DEFULAT_CONFIG, PdfComponent, PdfExternalLinkTarget, PdfModule, PdfTextLayerMode };
//# sourceMappingURL=pdf.mjs.map