ngx-doc-viewer
Version:
Angular document viewer.
518 lines (513 loc) • 37.6 kB
JavaScript
import * as i0 from '@angular/core';
import { EventEmitter, TemplateRef, ViewChildren, ContentChild, Input, Output, Component, NgModule } from '@angular/core';
import * as i2 from '@angular/common';
import { CommonModule } from '@angular/common';
import { getViewerDetails, isLocalFile, replaceLocalUrl, getDocxToHtml, googleCheckSubscription, getViewerRecoveryPlan, iframeIsLoaded } from 'docviewhelper';
export * from 'docviewhelper';
import * as i1 from '@angular/platform-browser';
class NgxDocViewerComponent {
domSanitizer;
ngZone;
cdr;
loaded = new EventEmitter();
loading = new EventEmitter();
error = new EventEmitter();
phaseChange = new EventEmitter();
url = '';
queryParams = '';
viewerUrl = '';
googleCheckInterval = 3000;
googleMaxChecks = 5;
googleFinalRetryDelay = 0;
disableContent = 'none';
googleCheckContentLoaded = true;
viewer = 'google';
overrideLocalhost = '';
loadingText = 'Loading document...';
errorTextOverride = '';
retryButtonText = 'Retry';
officeAutoRetry = false;
officeRetryDelay = 3000;
officeReloadButtonText = '↻';
officeReloadButtonTitle = 'Reload document';
secondaryActionText = '';
secondaryActionMode = 'open';
loadingTemplate;
errorTemplate;
errorActionsTemplate;
officeReloadTemplate;
iframes = undefined;
fullUrl = undefined;
externalViewer = false;
docHtml = '';
configuredViewer = 'google';
showIframe = true;
renderPhase = 'idle';
errorText = '';
failedUrl = '';
retryNonce = 0;
loadingTemplateContext = this.createTemplateContext();
errorTemplateContext = this.createTemplateContext();
checkIFrameSubscription = undefined;
loadVersion = 0;
externalLoadTimeoutId = undefined;
googleFinalRetryTimeoutId = undefined;
googleFinalRetriedSourceKey = undefined;
currentGoogleSourceKey = undefined;
officeRetryTimeoutId = undefined;
officeAutoRetriedSourceKey = undefined;
currentOfficeSourceKey = undefined;
lastEmittedPhase = undefined;
constructor(domSanitizer, ngZone, cdr) {
this.domSanitizer = domSanitizer;
this.ngZone = ngZone;
this.cdr = cdr;
}
ngOnDestroy() {
this.clearExternalLoadTimeout();
this.clearGoogleFinalRetry();
this.clearOfficeRetry();
if (this.checkIFrameSubscription) {
this.checkIFrameSubscription.unsubscribe();
}
}
async ngOnChanges(changes) {
if (changes &&
changes['retryNonce'] &&
changes['retryNonce'].firstChange) {
return;
}
if (changes &&
changes['viewer'] &&
(changes['viewer'].firstChange ||
changes['viewer'].currentValue !== changes['viewer'].previousValue)) {
if (this.viewer !== 'google' &&
this.viewer !== 'office' &&
this.viewer !== 'mammoth' &&
this.viewer !== 'pdf' &&
this.viewer !== 'url') {
console.error(`Unsupported viewer: '${this.viewer}'. Supported viewers: google, office, mammoth and pdf`);
}
this.configuredViewer = this.viewer;
this.updateTemplateContexts();
}
if ((changes['url'] &&
changes['url'].currentValue !== changes['url'].previousValue) ||
(changes['viewer'] &&
changes['viewer'].currentValue !== changes['viewer'].previousValue) ||
(changes['viewerUrl'] &&
changes['viewerUrl'].currentValue !==
changes['viewerUrl'].previousValue)) {
let viewerDetails = getViewerDetails(this.url, this.configuredViewer, this.queryParams, this.viewerUrl);
const loadVersion = ++this.loadVersion;
this.clearExternalLoadTimeout();
this.externalViewer = viewerDetails.externalViewer;
if (viewerDetails.externalViewer &&
this.overrideLocalhost &&
isLocalFile(this.url)) {
const newUrl = replaceLocalUrl(this.url, this.overrideLocalhost);
viewerDetails = getViewerDetails(newUrl, this.configuredViewer, this.queryParams, this.viewerUrl);
}
const officeSourceKey = this.configuredViewer === 'office' ? viewerDetails.url : undefined;
if (officeSourceKey !== this.currentOfficeSourceKey) {
this.officeAutoRetriedSourceKey = undefined;
}
this.currentOfficeSourceKey = officeSourceKey;
const googleSourceKey = this.configuredViewer === 'google' ? viewerDetails.url : undefined;
if (googleSourceKey !== this.currentGoogleSourceKey) {
this.googleFinalRetriedSourceKey = undefined;
}
this.currentGoogleSourceKey = googleSourceKey;
this.docHtml = '';
this.errorText = '';
this.failedUrl = this.url;
this.clearGoogleFinalRetry();
this.clearOfficeRetry();
this.updateTemplateContexts();
if (this.checkIFrameSubscription) {
this.checkIFrameSubscription.unsubscribe();
}
if (!this.url) {
this.fullUrl = undefined;
this.showIframe = false;
this.externalViewer = false;
this.setRenderPhase('idle');
this.updateTemplateContexts();
}
else if (viewerDetails.externalViewer ||
this.configuredViewer === 'url' ||
this.configuredViewer === 'pdf') {
this.setRenderPhase('loading');
const iframeUrl = this.domSanitizer.bypassSecurityTrustResourceUrl(viewerDetails.url);
this.fullUrl = undefined;
this.showIframe = false;
this.cdr.detectChanges();
this.fullUrl = iframeUrl;
this.showIframe = true;
this.updateTemplateContexts();
this.scheduleExternalLoadTimeout(loadVersion);
this.cdr.detectChanges();
this.scheduleViewerRecovery();
}
else if (this.configuredViewer === 'mammoth') {
this.setRenderPhase('loading');
this.externalViewer = false;
this.fullUrl = undefined;
this.showIframe = false;
try {
const docHtml = await getDocxToHtml(this.url);
if (loadVersion !== this.loadVersion) {
return;
}
this.ngZone.run(() => {
this.docHtml = docHtml;
this.setRenderPhase('ready');
this.updateTemplateContexts();
this.cdr.detectChanges();
});
}
catch (error) {
if (loadVersion !== this.loadVersion) {
return;
}
this.ngZone.run(() => {
this.errorText =
error instanceof Error ? error.message : 'Unable to load document.';
this.setRenderPhase('error');
this.updateTemplateContexts();
this.cdr.detectChanges();
});
}
}
}
}
retryLoad() {
this.retryNonce += 1;
const retryVersion = ++this.loadVersion;
this.clearExternalLoadTimeout();
this.clearGoogleFinalRetry();
this.clearOfficeRetry();
this.errorText = '';
this.setRenderPhase(this.url ? 'loading' : 'idle');
this.updateTemplateContexts();
if (!this.url) {
return;
}
if (this.configuredViewer === 'mammoth') {
this.docHtml = '';
void this.reloadMammoth(retryVersion);
return;
}
if (this.configuredViewer === 'google' ||
this.configuredViewer === 'office' ||
this.configuredViewer === 'url' ||
this.configuredViewer === 'pdf') {
const details = getViewerDetails(this.url, this.configuredViewer, this.queryParams, this.viewerUrl);
const finalUrl = details.externalViewer && this.overrideLocalhost && isLocalFile(this.url)
? getViewerDetails(replaceLocalUrl(this.url, this.overrideLocalhost), this.configuredViewer, this.queryParams, this.viewerUrl).url
: details.url;
this.fullUrl = undefined;
this.showIframe = false;
this.cdr.detectChanges();
this.fullUrl =
this.domSanitizer.bypassSecurityTrustResourceUrl(finalUrl);
this.showIframe = true;
this.scheduleExternalLoadTimeout(retryVersion);
this.scheduleViewerRecovery();
this.updateTemplateContexts();
this.cdr.detectChanges();
}
}
reloadIframe(iframe) {
this.checkIFrameSubscription = googleCheckSubscription();
this.checkIFrameSubscription.subscribe(iframe, this.googleCheckInterval, this.googleMaxChecks);
}
scheduleViewerRecovery() {
const recoveryPlan = getViewerRecoveryPlan({
viewer: this.configuredViewer,
googleCheckContentLoaded: this.googleCheckContentLoaded,
googleFinalRetryDelay: this.googleFinalRetryDelay,
officeAutoRetry: this.officeAutoRetry,
});
for (const mode of recoveryPlan.modes) {
if (mode === 'google-probe') {
this.scheduleGoogleRecovery();
}
if (mode === 'google-final-retry') {
continue;
}
if (mode === 'office-auto-retry') {
this.scheduleOfficeRetry();
}
}
}
scheduleGoogleRecovery() {
if (this.configuredViewer !== 'google' ||
!this.googleCheckContentLoaded) {
return;
}
// see:
// https://stackoverflow.com/questions/40414039/google-docs-viewer-returning-204-responses-no-longer-working-alternatives
// hack to reload iframe if it's not loaded.
this.ngZone.runOutsideAngular(() => {
window.setTimeout(() => {
const iframe = this.iframes?.first?.nativeElement;
if (iframe) {
this.reloadIframe(iframe);
}
}, 0);
});
}
iframeLoaded() {
const iframe = this.iframes?.first?.nativeElement;
if (iframe && iframeIsLoaded(iframe)) {
this.clearExternalLoadTimeout();
this.clearGoogleFinalRetry();
this.clearOfficeRetry();
this.setRenderPhase('ready');
this.updateTemplateContexts();
this.loaded.emit(undefined);
if (this.checkIFrameSubscription) {
this.checkIFrameSubscription.unsubscribe();
}
}
}
objectLoaded() {
this.clearExternalLoadTimeout();
this.clearGoogleFinalRetry();
this.clearOfficeRetry();
this.setRenderPhase('ready');
this.updateTemplateContexts();
}
async reloadMammoth(loadVersion) {
this.externalViewer = false;
this.fullUrl = undefined;
this.showIframe = false;
try {
const docHtml = await getDocxToHtml(this.url);
if (loadVersion !== this.loadVersion) {
return;
}
this.ngZone.run(() => {
this.docHtml = docHtml;
this.setRenderPhase('ready');
this.updateTemplateContexts();
this.cdr.detectChanges();
});
}
catch (error) {
if (loadVersion !== this.loadVersion) {
return;
}
this.ngZone.run(() => {
this.errorText =
error instanceof Error ? error.message : 'Unable to load document.';
this.setRenderPhase('error');
this.updateTemplateContexts();
this.cdr.detectChanges();
});
}
}
scheduleExternalLoadTimeout(loadVersion) {
this.clearExternalLoadTimeout();
const timeoutMs = this.configuredViewer === 'google'
? Math.max(this.googleCheckInterval * this.googleMaxChecks + 2000, 15000)
: 15000;
this.externalLoadTimeoutId = window.setTimeout(() => {
if (loadVersion !== this.loadVersion || this.renderPhase !== 'loading') {
return;
}
if (this.scheduleGoogleFinalRetry()) {
return;
}
this.ngZone.run(() => {
this.errorText = `The ${this.configuredViewer} viewer did not finish loading in time.`;
this.setRenderPhase('error');
this.updateTemplateContexts();
this.cdr.detectChanges();
});
}, timeoutMs);
}
clearExternalLoadTimeout() {
if (this.externalLoadTimeoutId) {
window.clearTimeout(this.externalLoadTimeoutId);
this.externalLoadTimeoutId = undefined;
}
}
clearGoogleFinalRetry() {
if (this.googleFinalRetryTimeoutId) {
window.clearTimeout(this.googleFinalRetryTimeoutId);
this.googleFinalRetryTimeoutId = undefined;
}
}
clearOfficeRetry() {
if (this.officeRetryTimeoutId) {
window.clearTimeout(this.officeRetryTimeoutId);
this.officeRetryTimeoutId = undefined;
}
}
scheduleOfficeRetry() {
if (this.configuredViewer !== 'office' ||
!this.officeAutoRetry ||
!this.currentOfficeSourceKey ||
this.officeAutoRetriedSourceKey === this.currentOfficeSourceKey) {
return;
}
this.clearOfficeRetry();
this.officeRetryTimeoutId = window.setTimeout(() => {
if (!this.currentOfficeSourceKey ||
this.officeAutoRetriedSourceKey === this.currentOfficeSourceKey) {
return;
}
this.officeAutoRetriedSourceKey = this.currentOfficeSourceKey;
this.ngZone.run(() => this.retryLoad());
}, this.officeRetryDelay);
}
scheduleGoogleFinalRetry() {
const recoveryPlan = getViewerRecoveryPlan({
viewer: this.configuredViewer,
googleCheckContentLoaded: this.googleCheckContentLoaded,
googleFinalRetryDelay: this.googleFinalRetryDelay,
officeAutoRetry: this.officeAutoRetry,
});
if (!recoveryPlan.modes.includes('google-final-retry') ||
!this.currentGoogleSourceKey ||
this.googleFinalRetriedSourceKey === this.currentGoogleSourceKey) {
return false;
}
this.clearGoogleFinalRetry();
this.googleFinalRetryTimeoutId = window.setTimeout(() => {
if (!this.currentGoogleSourceKey ||
this.googleFinalRetriedSourceKey === this.currentGoogleSourceKey) {
return;
}
this.googleFinalRetriedSourceKey = this.currentGoogleSourceKey;
this.ngZone.run(() => this.retryLoad());
}, this.googleFinalRetryDelay);
return true;
}
get displayedErrorText() {
return this.errorTextOverride || this.errorText || 'Unable to load document.';
}
updateTemplateContexts() {
const state = this.createStateContext();
this.loadingTemplateContext = { $implicit: state, state };
this.errorTemplateContext = { $implicit: state, state };
}
createTemplateContext() {
const state = this.createStateContext();
return { $implicit: state, state };
}
createStateContext() {
return {
viewer: this.configuredViewer,
url: this.failedUrl || this.url,
phase: this.renderPhase,
errorText: this.displayedErrorText,
retry: () => this.retryLoad(),
actionUrl: this.failedUrl || this.url,
};
}
setRenderPhase(phase) {
this.renderPhase = phase;
this.emitLifecycleIfNeeded();
}
emitLifecycleIfNeeded() {
if (this.lastEmittedPhase === this.renderPhase) {
return;
}
this.lastEmittedPhase = this.renderPhase;
const state = this.createStateContext();
this.phaseChange.emit(state);
if (this.renderPhase === 'loading') {
this.loading.emit(state);
}
if (this.renderPhase === 'error') {
this.error.emit(state);
}
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: NgxDocViewerComponent, deps: [{ token: i1.DomSanitizer }, { token: i0.NgZone }, { token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component });
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.2.4", type: NgxDocViewerComponent, isStandalone: true, selector: "ngx-doc-viewer", inputs: { url: "url", queryParams: "queryParams", viewerUrl: "viewerUrl", googleCheckInterval: "googleCheckInterval", googleMaxChecks: "googleMaxChecks", googleFinalRetryDelay: "googleFinalRetryDelay", disableContent: "disableContent", googleCheckContentLoaded: "googleCheckContentLoaded", viewer: "viewer", overrideLocalhost: "overrideLocalhost", loadingText: "loadingText", errorTextOverride: "errorTextOverride", retryButtonText: "retryButtonText", officeAutoRetry: "officeAutoRetry", officeRetryDelay: "officeRetryDelay", officeReloadButtonText: "officeReloadButtonText", officeReloadButtonTitle: "officeReloadButtonTitle", secondaryActionText: "secondaryActionText", secondaryActionMode: "secondaryActionMode" }, outputs: { loaded: "loaded", loading: "loading", error: "error", phaseChange: "phaseChange" }, queries: [{ propertyName: "loadingTemplate", first: true, predicate: ["loadingContent"], descendants: true, read: TemplateRef }, { propertyName: "errorTemplate", first: true, predicate: ["errorContent"], descendants: true, read: TemplateRef }, { propertyName: "errorActionsTemplate", first: true, predicate: ["errorActions"], descendants: true, read: TemplateRef }, { propertyName: "officeReloadTemplate", first: true, predicate: ["officeReloadContent"], descendants: true, read: TemplateRef }], viewQueries: [{ propertyName: "iframes", predicate: ["iframe"], descendants: true }], usesOnChanges: true, ngImport: i0, template: "<div class=\"container\">\n <div *ngIf=\"renderPhase === 'loading'\" class=\"loading-overlay\">\n <ng-container *ngIf=\"loadingTemplate; else defaultLoadingTemplate\">\n <ng-container *ngTemplateOutlet=\"loadingTemplate; context: loadingTemplateContext\"></ng-container>\n </ng-container>\n <ng-template #defaultLoadingTemplate>{{ loadingText }}</ng-template>\n </div>\n <div *ngIf=\"renderPhase === 'error'\" class=\"error-overlay\">\n <ng-container *ngIf=\"errorTemplate; else defaultErrorTemplate\">\n <ng-container *ngTemplateOutlet=\"errorTemplate; context: errorTemplateContext\"></ng-container>\n </ng-container>\n <ng-template #defaultErrorTemplate>\n <div>\n <div>{{ displayedErrorText }}</div>\n <div *ngIf=\"configuredViewer\" style=\"margin-top: 8px; color: #475569;\">\n Viewer: {{ configuredViewer }}\n </div>\n <div *ngIf=\"failedUrl\" style=\"margin-top: 4px; color: #64748b; font-size: 12px; word-break: break-word;\">\n {{ failedUrl }}\n </div>\n <ng-container *ngIf=\"errorActionsTemplate; else defaultErrorActions\">\n <ng-container *ngTemplateOutlet=\"errorActionsTemplate; context: errorTemplateContext\"></ng-container>\n </ng-container>\n <ng-template #defaultErrorActions>\n <div style=\"margin-top: 14px; display: flex; gap: 8px; justify-content: center; flex-wrap: wrap;\">\n <button\n type=\"button\"\n (click)=\"retryLoad()\"\n style=\"border: 1px solid #fecaca; background: #fff; color: #991b1b; border-radius: 999px; padding: 8px 14px; font: inherit; cursor: pointer;\"\n >\n {{ retryButtonText }}\n </button>\n <a\n *ngIf=\"secondaryActionText && failedUrl\"\n [href]=\"failedUrl\"\n [attr.target]=\"secondaryActionMode === 'open' ? '_blank' : null\"\n [attr.rel]=\"secondaryActionMode === 'open' ? 'noreferrer' : null\"\n [attr.download]=\"secondaryActionMode === 'download' ? '' : null\"\n style=\"border: 1px solid #cbd5e1; background: #fff; color: #334155; border-radius: 999px; padding: 8px 14px; text-decoration: none; font: inherit;\"\n >\n {{ secondaryActionText }}\n </a>\n </div>\n </ng-template>\n </div>\n </ng-template>\n </div>\n\n <ng-container *ngIf=\"!externalViewer\">\n <div *ngIf=\"configuredViewer !== 'pdf'\" class=\"inline-document-shell\">\n <div class=\"inline-document-page\" [innerHTML]=\"docHtml\"></div>\n </div>\n <object\n (load)=\"objectLoaded()\"\n *ngIf=\"fullUrl && configuredViewer === 'pdf'\"\n [data]=\"fullUrl\"\n type=\"application/pdf\"\n width=\"100%\"\n height=\"100%\"\n >\n <p>\n Your browser does not support PDFs.\n <a [href]=\"fullUrl\">Download the PDF</a>.\n </p>\n </object>\n </ng-container>\n\n <button\n *ngIf=\"configuredViewer === 'office' && renderPhase === 'ready'\"\n class=\"office-reload-btn\"\n type=\"button\"\n [attr.title]=\"officeReloadButtonTitle\"\n (click)=\"retryLoad()\"\n >\n <ng-container *ngIf=\"officeReloadTemplate; else defaultOfficeReloadTemplate\">\n <ng-container *ngTemplateOutlet=\"officeReloadTemplate; context: errorTemplateContext\"></ng-container>\n </ng-container>\n <ng-template #defaultOfficeReloadTemplate>{{ officeReloadButtonText }}</ng-template>\n </button>\n\n <ng-container *ngIf=\"externalViewer\">\n <iframe\n (load)=\"iframeLoaded()\"\n *ngIf=\"fullUrl && showIframe && disableContent === 'none'\"\n #iframe\n id=\"iframe-doc-viewer\"\n frameBorder=\"0\"\n allow=\"clipboard-read; clipboard-write\"\n [src]=\"fullUrl\"\n ></iframe>\n <div class=\"container\" *ngIf=\"disableContent !== 'none'\">\n <div\n [class.overlay-full]=\"disableContent === 'all'\"\n [class.overlay-popout-google]=\"\n configuredViewer === 'google' &&\n (disableContent === 'popout' || disableContent === 'popout-hide')\n \"\n [class.overlay-popout-office]=\"\n configuredViewer === 'office' &&\n (disableContent === 'popout' || disableContent === 'popout-hide')\n \"\n [style.background-color]=\"\n disableContent === 'popout-hide' ? '#fff' : 'transparent'\n \"\n ></div>\n <iframe\n (load)=\"iframeLoaded()\"\n *ngIf=\"fullUrl && showIframe\"\n #iframe\n id=\"iframe\"\n frameBorder=\"0\"\n allow=\"clipboard-read; clipboard-write\"\n [src]=\"fullUrl\"\n ></iframe>\n </div>\n </ng-container>\n</div>\n", styles: [":host{display:block}.container{width:100%;height:100%;position:relative}.inline-document-shell{width:100%;height:100%;overflow:auto;background:linear-gradient(180deg,#eef2f7,#f8fafc);padding:24px}.inline-document-page{max-width:900px;min-height:100%;margin:0 auto;background:#fff;border:1px solid #dbe4f0;border-radius:18px;box-shadow:0 18px 40px -24px #0f172a4d,0 6px 18px -10px #0f172a2e;padding:40px 48px}.inline-document-page,.inline-document-page *{box-sizing:border-box}.inline-document-page{color:#1e293b;font-family:Georgia,Cambria,Times New Roman,Times,serif;font-size:18px;line-height:1.7}.inline-document-page p,.inline-document-page ul,.inline-document-page ol,.inline-document-page blockquote,.inline-document-page table{margin:0 0 1.1em}.inline-document-page h1,.inline-document-page h2,.inline-document-page h3,.inline-document-page h4,.inline-document-page h5,.inline-document-page h6{margin:1.4em 0 .65em;color:#0f172a;line-height:1.25}.inline-document-page h1:first-child,.inline-document-page h2:first-child,.inline-document-page h3:first-child,.inline-document-page p:first-child{margin-top:0}.inline-document-page table{width:100%;border-collapse:collapse}.inline-document-page td,.inline-document-page th{padding:6px 10px;vertical-align:top}.inline-document-page img{max-width:100%;height:auto}.inline-document-page hr{border:0;border-top:1px solid #dbe4f0;margin:1.5em 0}.loading-overlay{position:absolute;inset:0;z-index:1001;display:flex;align-items:center;justify-content:center;background:#ffffffe0;color:#475569;font-size:14px;font-weight:600;letter-spacing:.02em;text-align:center;padding:16px}.error-overlay{position:absolute;inset:0;z-index:1001;display:flex;align-items:center;justify-content:center;background:#fffffff0;color:#991b1b;font-size:14px;font-weight:600;letter-spacing:.02em;text-align:center;padding:16px}.overlay-popout-google{width:40px;height:40px;right:26px;top:11.5px;position:absolute;z-index:1000}.overlay-popout-office{width:100px;height:20px;right:0;bottom:0;position:absolute;z-index:1000}.office-reload-btn{position:absolute;top:8px;right:8px;z-index:1001;width:32px;height:32px;border-radius:50%;border:1px solid rgba(0,0,0,.12);background:#ffffffd9;color:#475569;font-size:16px;line-height:1;cursor:pointer;display:flex;align-items:center;justify-content:center;opacity:.5;transition:opacity .15s;padding:0}.office-reload-btn:hover{opacity:1}.overlay-full{width:100%;height:100%;right:0;top:0;position:absolute;z-index:1000}iframe{width:100%;height:100%}@media(max-width:768px){.inline-document-shell{padding:12px}.inline-document-page{border-radius:12px;padding:22px 18px}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i2.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }] });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: NgxDocViewerComponent, decorators: [{
type: Component,
args: [{ selector: 'ngx-doc-viewer', standalone: true, imports: [CommonModule], template: "<div class=\"container\">\n <div *ngIf=\"renderPhase === 'loading'\" class=\"loading-overlay\">\n <ng-container *ngIf=\"loadingTemplate; else defaultLoadingTemplate\">\n <ng-container *ngTemplateOutlet=\"loadingTemplate; context: loadingTemplateContext\"></ng-container>\n </ng-container>\n <ng-template #defaultLoadingTemplate>{{ loadingText }}</ng-template>\n </div>\n <div *ngIf=\"renderPhase === 'error'\" class=\"error-overlay\">\n <ng-container *ngIf=\"errorTemplate; else defaultErrorTemplate\">\n <ng-container *ngTemplateOutlet=\"errorTemplate; context: errorTemplateContext\"></ng-container>\n </ng-container>\n <ng-template #defaultErrorTemplate>\n <div>\n <div>{{ displayedErrorText }}</div>\n <div *ngIf=\"configuredViewer\" style=\"margin-top: 8px; color: #475569;\">\n Viewer: {{ configuredViewer }}\n </div>\n <div *ngIf=\"failedUrl\" style=\"margin-top: 4px; color: #64748b; font-size: 12px; word-break: break-word;\">\n {{ failedUrl }}\n </div>\n <ng-container *ngIf=\"errorActionsTemplate; else defaultErrorActions\">\n <ng-container *ngTemplateOutlet=\"errorActionsTemplate; context: errorTemplateContext\"></ng-container>\n </ng-container>\n <ng-template #defaultErrorActions>\n <div style=\"margin-top: 14px; display: flex; gap: 8px; justify-content: center; flex-wrap: wrap;\">\n <button\n type=\"button\"\n (click)=\"retryLoad()\"\n style=\"border: 1px solid #fecaca; background: #fff; color: #991b1b; border-radius: 999px; padding: 8px 14px; font: inherit; cursor: pointer;\"\n >\n {{ retryButtonText }}\n </button>\n <a\n *ngIf=\"secondaryActionText && failedUrl\"\n [href]=\"failedUrl\"\n [attr.target]=\"secondaryActionMode === 'open' ? '_blank' : null\"\n [attr.rel]=\"secondaryActionMode === 'open' ? 'noreferrer' : null\"\n [attr.download]=\"secondaryActionMode === 'download' ? '' : null\"\n style=\"border: 1px solid #cbd5e1; background: #fff; color: #334155; border-radius: 999px; padding: 8px 14px; text-decoration: none; font: inherit;\"\n >\n {{ secondaryActionText }}\n </a>\n </div>\n </ng-template>\n </div>\n </ng-template>\n </div>\n\n <ng-container *ngIf=\"!externalViewer\">\n <div *ngIf=\"configuredViewer !== 'pdf'\" class=\"inline-document-shell\">\n <div class=\"inline-document-page\" [innerHTML]=\"docHtml\"></div>\n </div>\n <object\n (load)=\"objectLoaded()\"\n *ngIf=\"fullUrl && configuredViewer === 'pdf'\"\n [data]=\"fullUrl\"\n type=\"application/pdf\"\n width=\"100%\"\n height=\"100%\"\n >\n <p>\n Your browser does not support PDFs.\n <a [href]=\"fullUrl\">Download the PDF</a>.\n </p>\n </object>\n </ng-container>\n\n <button\n *ngIf=\"configuredViewer === 'office' && renderPhase === 'ready'\"\n class=\"office-reload-btn\"\n type=\"button\"\n [attr.title]=\"officeReloadButtonTitle\"\n (click)=\"retryLoad()\"\n >\n <ng-container *ngIf=\"officeReloadTemplate; else defaultOfficeReloadTemplate\">\n <ng-container *ngTemplateOutlet=\"officeReloadTemplate; context: errorTemplateContext\"></ng-container>\n </ng-container>\n <ng-template #defaultOfficeReloadTemplate>{{ officeReloadButtonText }}</ng-template>\n </button>\n\n <ng-container *ngIf=\"externalViewer\">\n <iframe\n (load)=\"iframeLoaded()\"\n *ngIf=\"fullUrl && showIframe && disableContent === 'none'\"\n #iframe\n id=\"iframe-doc-viewer\"\n frameBorder=\"0\"\n allow=\"clipboard-read; clipboard-write\"\n [src]=\"fullUrl\"\n ></iframe>\n <div class=\"container\" *ngIf=\"disableContent !== 'none'\">\n <div\n [class.overlay-full]=\"disableContent === 'all'\"\n [class.overlay-popout-google]=\"\n configuredViewer === 'google' &&\n (disableContent === 'popout' || disableContent === 'popout-hide')\n \"\n [class.overlay-popout-office]=\"\n configuredViewer === 'office' &&\n (disableContent === 'popout' || disableContent === 'popout-hide')\n \"\n [style.background-color]=\"\n disableContent === 'popout-hide' ? '#fff' : 'transparent'\n \"\n ></div>\n <iframe\n (load)=\"iframeLoaded()\"\n *ngIf=\"fullUrl && showIframe\"\n #iframe\n id=\"iframe\"\n frameBorder=\"0\"\n allow=\"clipboard-read; clipboard-write\"\n [src]=\"fullUrl\"\n ></iframe>\n </div>\n </ng-container>\n</div>\n", styles: [":host{display:block}.container{width:100%;height:100%;position:relative}.inline-document-shell{width:100%;height:100%;overflow:auto;background:linear-gradient(180deg,#eef2f7,#f8fafc);padding:24px}.inline-document-page{max-width:900px;min-height:100%;margin:0 auto;background:#fff;border:1px solid #dbe4f0;border-radius:18px;box-shadow:0 18px 40px -24px #0f172a4d,0 6px 18px -10px #0f172a2e;padding:40px 48px}.inline-document-page,.inline-document-page *{box-sizing:border-box}.inline-document-page{color:#1e293b;font-family:Georgia,Cambria,Times New Roman,Times,serif;font-size:18px;line-height:1.7}.inline-document-page p,.inline-document-page ul,.inline-document-page ol,.inline-document-page blockquote,.inline-document-page table{margin:0 0 1.1em}.inline-document-page h1,.inline-document-page h2,.inline-document-page h3,.inline-document-page h4,.inline-document-page h5,.inline-document-page h6{margin:1.4em 0 .65em;color:#0f172a;line-height:1.25}.inline-document-page h1:first-child,.inline-document-page h2:first-child,.inline-document-page h3:first-child,.inline-document-page p:first-child{margin-top:0}.inline-document-page table{width:100%;border-collapse:collapse}.inline-document-page td,.inline-document-page th{padding:6px 10px;vertical-align:top}.inline-document-page img{max-width:100%;height:auto}.inline-document-page hr{border:0;border-top:1px solid #dbe4f0;margin:1.5em 0}.loading-overlay{position:absolute;inset:0;z-index:1001;display:flex;align-items:center;justify-content:center;background:#ffffffe0;color:#475569;font-size:14px;font-weight:600;letter-spacing:.02em;text-align:center;padding:16px}.error-overlay{position:absolute;inset:0;z-index:1001;display:flex;align-items:center;justify-content:center;background:#fffffff0;color:#991b1b;font-size:14px;font-weight:600;letter-spacing:.02em;text-align:center;padding:16px}.overlay-popout-google{width:40px;height:40px;right:26px;top:11.5px;position:absolute;z-index:1000}.overlay-popout-office{width:100px;height:20px;right:0;bottom:0;position:absolute;z-index:1000}.office-reload-btn{position:absolute;top:8px;right:8px;z-index:1001;width:32px;height:32px;border-radius:50%;border:1px solid rgba(0,0,0,.12);background:#ffffffd9;color:#475569;font-size:16px;line-height:1;cursor:pointer;display:flex;align-items:center;justify-content:center;opacity:.5;transition:opacity .15s;padding:0}.office-reload-btn:hover{opacity:1}.overlay-full{width:100%;height:100%;right:0;top:0;position:absolute;z-index:1000}iframe{width:100%;height:100%}@media(max-width:768px){.inline-document-shell{padding:12px}.inline-document-page{border-radius:12px;padding:22px 18px}}\n"] }]
}], ctorParameters: () => [{ type: i1.DomSanitizer }, { type: i0.NgZone }, { type: i0.ChangeDetectorRef }], propDecorators: { loaded: [{
type: Output
}], loading: [{
type: Output
}], error: [{
type: Output
}], phaseChange: [{
type: Output
}], url: [{
type: Input
}], queryParams: [{
type: Input
}], viewerUrl: [{
type: Input
}], googleCheckInterval: [{
type: Input
}], googleMaxChecks: [{
type: Input
}], googleFinalRetryDelay: [{
type: Input
}], disableContent: [{
type: Input
}], googleCheckContentLoaded: [{
type: Input
}], viewer: [{
type: Input
}], overrideLocalhost: [{
type: Input
}], loadingText: [{
type: Input
}], errorTextOverride: [{
type: Input
}], retryButtonText: [{
type: Input
}], officeAutoRetry: [{
type: Input
}], officeRetryDelay: [{
type: Input
}], officeReloadButtonText: [{
type: Input
}], officeReloadButtonTitle: [{
type: Input
}], secondaryActionText: [{
type: Input
}], secondaryActionMode: [{
type: Input
}], loadingTemplate: [{
type: ContentChild,
args: ['loadingContent', { read: TemplateRef }]
}], errorTemplate: [{
type: ContentChild,
args: ['errorContent', { read: TemplateRef }]
}], errorActionsTemplate: [{
type: ContentChild,
args: ['errorActions', { read: TemplateRef }]
}], officeReloadTemplate: [{
type: ContentChild,
args: ['officeReloadContent', { read: TemplateRef }]
}], iframes: [{
type: ViewChildren,
args: ['iframe']
}] } });
class NgxDocViewerModule {
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: NgxDocViewerModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
static ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "21.2.4", ngImport: i0, type: NgxDocViewerModule, imports: [CommonModule, NgxDocViewerComponent], exports: [NgxDocViewerComponent] });
static ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: NgxDocViewerModule, imports: [CommonModule, NgxDocViewerComponent] });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: NgxDocViewerModule, decorators: [{
type: NgModule,
args: [{
imports: [CommonModule, NgxDocViewerComponent],
exports: [NgxDocViewerComponent],
}]
}] });
/**
* Generated bundle index. Do not edit.
*/
export { NgxDocViewerComponent, NgxDocViewerModule };
//# sourceMappingURL=ngx-doc-viewer.mjs.map