UNPKG

ngx-doc-viewer

Version:
407 lines (400 loc) 17.1 kB
import { __awaiter } from 'tslib'; import { EventEmitter, Component, NgZone, Output, Input, ViewChildren, NgModule } from '@angular/core'; import { DomSanitizer } from '@angular/platform-browser'; import { CommonModule } from '@angular/common'; const fileToArray = (url) => { return new Promise((resolve, reject) => { try { const request = new XMLHttpRequest(); request.open('GET', url, true); request.responseType = 'blob'; request.onload = () => { const reader = new FileReader(); reader.readAsArrayBuffer(request.response); reader.onloadend = () => { resolve(reader.result); }; }; request.send(); } catch (_a) { reject(`error while retrieving file ${url}.`); } }); }; const reloadIFrame = (iframe) => { if (iframe) { console.log('reloading..'); // eslint-disable-next-line no-self-assign iframe.src = iframe.src; } }; const ɵ0$1 = reloadIFrame; // eslint-disable-next-line @typescript-eslint/no-explicit-any const handleFileUpload = (fileInput) => { return new Promise((resolve, reject) => { if (fileInput.target.files && fileInput.target.files[0]) { const reader = new FileReader(); // eslint-disable-next-line @typescript-eslint/no-explicit-any reader.onload = (e) => { resolve(e.target.result); }; reader.readAsDataURL(fileInput.target.files[0]); } else { reject('no files selected'); } }); }; const getbaseUrl = () => { const pathArray = window.location.href.split('/'); const protocol = pathArray[0]; const host = pathArray[2]; return protocol + '//' + host; }; const getLocation = (href) => { const match = href.match(/^(https?\:)\/\/(([^:\/?#]*)(?:\:([0-9]+))?)([\/]{0,1}[^?#]*)(\?[^#]*|)(#.*|)$/); return match && { href, protocol: match[1], host: match[2], hostname: match[3], port: match[4], pathname: match[5], search: match[6], hash: match[7] }; }; const getDocxToHtml = (url) => __awaiter(void 0, void 0, void 0, function* () { if (!mammoth) { console.error('Please install mammoth and make sure mammoth.browser.min.js is loaded.'); } const arrayBuffer = yield fileToArray(url); const resultObject = yield mammoth.convertToHtml({ arrayBuffer }); return resultObject.value; }); const googleCheckSubscription = () => { let subscription = null; let checkCount = 0; return { subscribe: (iframe, interval = 3000, maxChecks = 5) => { if (!iframeIsLoaded(iframe)) { subscription = setInterval(() => { checkCount++; if (checkCount >= maxChecks) { clearInterval(subscription); } reloadIFrame(iframe); }, interval); return subscription; } else { if (subscription) { clearInterval(subscription); } } }, unsubscribe: () => { if (subscription) { clearInterval(subscription); } }, }; }; const iframeIsLoaded = (iframe) => { var _a; // its #document <html><head></head><body></body></html> when google is returning a 204 // so if contentDocument = null then it's loaded. let isLoaded = false; try { if (!internetExplorer()) { isLoaded = !(iframe === null || iframe === void 0 ? void 0 : iframe.contentDocument); } else { isLoaded = !((_a = iframe === null || iframe === void 0 ? void 0 : iframe.contentWindow) === null || _a === void 0 ? void 0 : _a.document); } } catch (_b) { // ignore message Blocked a frame with origin "http://..." from accessing a cross-origin frame. } return isLoaded; }; const internetExplorer = () => (/MSIE (\d+\.\d+);/.test(navigator.userAgent) || navigator.userAgent.indexOf("Trident/") > -1); const ɵ1 = internetExplorer; const getViewerDetails = (url, configuredViewer = 'google', queryParams = '', viewerUrl = '') => { switch (configuredViewer) { case 'google': viewerUrl = `https://docs.google.com/gview?url=%URL%&embedded=true`; break; case 'office': { viewerUrl = `https://view.officeapps.live.com/op/embed.aspx?src=%URL%`; break; } case 'pdf': { viewerUrl = ''; break; } } const externalViewer = configuredViewer === 'google' || configuredViewer === 'office' || configuredViewer === 'url'; const u = url.indexOf('/') ? encodeURIComponent(url) : url; let fullUrl = viewerUrl ? viewerUrl.replace('%URL%', u) : url; if (queryParams && externalViewer && configuredViewer !== 'url') { const start = queryParams.startsWith('&') ? '' : '&'; fullUrl = `${fullUrl}${start}${queryParams}`; } return { url: fullUrl, externalViewer, }; }; const replaceLocalUrl = (url, overrideLocalhost) => { const loc = getLocation(url); const locReplace = getLocation(overrideLocalhost); if (loc && locReplace) { return url.replace(loc.port ? `${loc.hostname}:${loc.port}` : loc.hostname, locReplace.port ? `${locReplace.hostname}:${locReplace.port}` : locReplace.hostname); } return url; }; const getBlobFromUrl = (url) => { return new Promise((resolve, reject) => { let request = new XMLHttpRequest(); request.open('GET', url, true); request.responseType = 'blob'; request.onload = () => { resolve(request.response); }; request.onerror = reject; request.send(); }); }; const ɵ2 = getBlobFromUrl; const uploadToCloud = (fileUrl, api) => new Promise((resolve, reject) => { getBlobFromUrl(fileUrl).then(blob => { var _a, _b; const loc = getLocation(fileUrl); const name = (loc === null || loc === void 0 ? void 0 : loc.pathname) ? (_a = loc === null || loc === void 0 ? void 0 : loc.pathname) === null || _a === void 0 ? void 0 : _a.split('/')[((_b = loc === null || loc === void 0 ? void 0 : loc.pathname) === null || _b === void 0 ? void 0 : _b.split('/').length) - 1] : ''; const formData = new FormData(); const request = new XMLHttpRequest(); formData.append('file', blob, name); request.onreadystatechange = e => { if (request.readyState === XMLHttpRequest.DONE) { if (request.status === 200) { resolve(request.responseText); } else { reject(request.responseText); } } }; request.onerror = reject; request.open('post', api, true); request.send(formData); }); }); const isLocalFile = (file) => { const loc = getLocation(file); const hostname = (loc === null || loc === void 0 ? void 0 : loc.hostname) || ''; return ((['localhost', '127.0.0.1', '', '::1'].includes(hostname)) || (hostname.startsWith('192.168.')) || (hostname.startsWith('10.0.')) || (hostname.endsWith('.local'))); }; class NgxDocViewerComponent { constructor(domSanitizer, ngZone) { this.domSanitizer = domSanitizer; this.ngZone = ngZone; this.loaded = new EventEmitter(); this.url = ''; this.queryParams = ''; this.viewerUrl = ''; this.googleCheckInterval = 3000; this.googleMaxChecks = 5; this.disableContent = 'none'; this.googleCheckContentLoaded = true; this.fullUrl = null; this.externalViewer = false; this.docHtml = ''; this.configuredViewer = 'google'; this.shouldCheckIframe = false; } ngAfterViewInit() { var _a, _b; if (this.shouldCheckIframe) { const iframe = (_b = (_a = this.iframes) === null || _a === void 0 ? void 0 : _a.first) === null || _b === void 0 ? void 0 : _b.nativeElement; if (iframe) { this.shouldCheckIframe = false; this.reloadIframe(iframe); } } } ngOnDestroy() { if (this.checkIFrameSubscription) { this.checkIFrameSubscription.unsubscribe(); } } ngOnChanges(changes) { return __awaiter(this, void 0, void 0, function* () { if (changes && changes.viewer && (changes.viewer.isFirstChange || 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; } 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); 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); } this.docHtml = ''; if (this.checkIFrameSubscription) { this.checkIFrameSubscription.unsubscribe(); } if (!this.url) { this.fullUrl = null; } else if (viewerDetails.externalViewer || this.configuredViewer === 'url') { this.fullUrl = this.domSanitizer.bypassSecurityTrustResourceUrl(viewerDetails.url); // 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. // would maybe be better to use view.officeapps.live.com but seems not to work with sas token. if (this.configuredViewer === 'google' && this.googleCheckContentLoaded) { this.ngZone.runOutsideAngular(() => { var _a, _b; // if it's not loaded after the googleIntervalCheck, then open load again. const iframe = (_b = (_a = this.iframes) === null || _a === void 0 ? void 0 : _a.first) === null || _b === void 0 ? void 0 : _b.nativeElement; if (iframe) { this.reloadIframe(iframe); } else { this.shouldCheckIframe = true; } }); } } else if (this.configuredViewer === 'mammoth') { this.docHtml = yield getDocxToHtml(this.url); } } }); } reloadIframe(iframe) { this.checkIFrameSubscription = googleCheckSubscription(); this.checkIFrameSubscription.subscribe(iframe, this.googleCheckInterval, this.googleMaxChecks); } iframeLoaded() { var _a, _b; const iframe = (_b = (_a = this.iframes) === null || _a === void 0 ? void 0 : _a.first) === null || _b === void 0 ? void 0 : _b.nativeElement; if (iframe && iframeIsLoaded(iframe)) { this.loaded.emit(null); if (this.checkIFrameSubscription) { this.checkIFrameSubscription.unsubscribe(); } } } } NgxDocViewerComponent.decorators = [ { type: Component, args: [{ // eslint-disable-next-line @angular-eslint/component-selector selector: 'ngx-doc-viewer', template: "<ng-container *ngIf=\"!externalViewer\">\r\n <div *ngIf=\"configuredViewer !== 'pdf'\" [innerHtml]=\"docHtml\"></div>\r\n <object\r\n *ngIf=\"fullUrl && configuredViewer === 'pdf'\"\r\n [data]=\"fullUrl\"\r\n type=\"application/pdf\"\r\n width=\"100%\"\r\n height=\"100%\"\r\n >\r\n <p>\r\n Your browser does not support PDFs.\r\n <a [href]=\"fullUrl\">Download the PDF</a>.\r\n </p>\r\n </object>\r\n</ng-container>\r\n<ng-container *ngIf=\"externalViewer\">\r\n <iframe\r\n (load)=\"iframeLoaded()\"\r\n *ngIf=\"fullUrl && disableContent === 'none'\"\r\n #iframe\r\n id=\"iframe-doc-viewer\"\r\n frameBorder=\"0\"\r\n [src]=\"fullUrl\"\r\n ></iframe>\r\n <div class=\"container\" *ngIf=\"disableContent !== 'none'\">\r\n <div\r\n [class.overlay-full]=\"disableContent === 'all'\"\r\n [class.overlay-popout-google]=\"\r\n configuredViewer === 'google' &&\r\n (disableContent === 'popout' || disableContent === 'popout-hide')\r\n \"\r\n [class.overlay-popout-office]=\"\r\n configuredViewer === 'office' &&\r\n (disableContent === 'popout' || disableContent === 'popout-hide')\r\n \"\r\n [style.background-color]=\"\r\n disableContent === 'popout-hide' ? '#fff' : 'transparent'\r\n \"\r\n ></div>\r\n <iframe\r\n (load)=\"iframeLoaded()\"\r\n *ngIf=\"fullUrl\"\r\n #iframe\r\n id=\"iframe\"\r\n frameBorder=\"0\"\r\n [src]=\"fullUrl\"\r\n ></iframe>\r\n </div>\r\n</ng-container>\r\n", styles: [` :host { display: block; } .container { width: 100%; height: 100%; position: relative; } .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; } .overlay-full { width: 100%; height: 100%; right: 0; top: 0; position: absolute; z-index: 1000; } iframe { width: 100%; height: 100%; } `] },] } ]; NgxDocViewerComponent.ctorParameters = () => [ { type: DomSanitizer }, { type: NgZone } ]; NgxDocViewerComponent.propDecorators = { loaded: [{ type: Output }], url: [{ type: Input }], queryParams: [{ type: Input }], viewerUrl: [{ type: Input }], googleCheckInterval: [{ type: Input }], googleMaxChecks: [{ type: Input }], disableContent: [{ type: Input }], googleCheckContentLoaded: [{ type: Input }], viewer: [{ type: Input }], overrideLocalhost: [{ type: Input }], iframes: [{ type: ViewChildren, args: ['iframe',] }] }; class NgxDocViewerModule { } NgxDocViewerModule.decorators = [ { type: NgModule, args: [{ imports: [CommonModule], declarations: [NgxDocViewerComponent], exports: [NgxDocViewerComponent], },] } ]; const ɵ0 = () => { }; const defaultProps = { // eslint-disable-next-line @typescript-eslint/no-empty-function loaded: ɵ0, disableContent: 'none', googleCheckContentLoaded: true, googleCheckInterval: 3000, queryParams: '', url: '', viewer: 'google', viewerUrl: '', }; /** * Generated bundle index. Do not edit. */ export { NgxDocViewerComponent, NgxDocViewerModule, defaultProps, fileToArray, getDocxToHtml, getLocation, getViewerDetails, getbaseUrl, googleCheckSubscription, handleFileUpload, iframeIsLoaded, isLocalFile, replaceLocalUrl, uploadToCloud, ɵ0$1 as ɵ0, ɵ1, ɵ2 }; //# sourceMappingURL=ngx-doc-viewer.js.map