mirror of
https://github.com/Alfresco/alfresco-ng2-components.git
synced 2025-09-17 14:21:29 +00:00
new base render
This commit is contained in:
@@ -300,6 +300,7 @@
|
|||||||
</adf-info-drawer>
|
</adf-info-drawer>
|
||||||
</ng-template>
|
</ng-template>
|
||||||
|
|
||||||
|
<div *ngIf="">
|
||||||
<adf-alfresco-viewer
|
<adf-alfresco-viewer
|
||||||
(close)="onViewerVisibilityChanged()"
|
(close)="onViewerVisibilityChanged()"
|
||||||
[nodeId]="nodeId"
|
[nodeId]="nodeId"
|
||||||
|
@@ -64,11 +64,12 @@ export class FileViewComponent implements OnInit {
|
|||||||
desiredAspect: string = null;
|
desiredAspect: string = null;
|
||||||
showAspect: string = null;
|
showAspect: string = null;
|
||||||
name: string;
|
name: string;
|
||||||
|
filename: string;
|
||||||
|
|
||||||
constructor(private router: Router,
|
constructor(private router: Router,
|
||||||
private route: ActivatedRoute,
|
private route: ActivatedRoute,
|
||||||
private nodeApiService: NodesApiService,
|
private nodeApiService: NodesApiService,
|
||||||
private contentServices: ContentService,
|
private contentService: ContentService,
|
||||||
private preview: PreviewService,
|
private preview: PreviewService,
|
||||||
private notificationService: NotificationService) {
|
private notificationService: NotificationService) {
|
||||||
}
|
}
|
||||||
@@ -81,8 +82,8 @@ export class FileViewComponent implements OnInit {
|
|||||||
this.nodeApiService.getNode(id).subscribe(
|
this.nodeApiService.getNode(id).subscribe(
|
||||||
(node) => {
|
(node) => {
|
||||||
if (node && node.isFile) {
|
if (node && node.isFile) {
|
||||||
this.isCommentEnabled = this.contentServices.hasPermissions(node, PermissionsEnum.NOT_CONSUMER) ||
|
this.isCommentEnabled = this.contentService.hasPermissions(node, PermissionsEnum.NOT_CONSUMER) ||
|
||||||
this.contentServices.hasAllowableOperations(node, AllowableOperationsEnum.UPDATE);
|
this.contentService.hasAllowableOperations(node, AllowableOperationsEnum.UPDATE);
|
||||||
this.nodeId = id;
|
this.nodeId = id;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -90,6 +91,9 @@ export class FileViewComponent implements OnInit {
|
|||||||
},
|
},
|
||||||
() => this.router.navigate(['/files', id])
|
() => this.router.navigate(['/files', id])
|
||||||
);
|
);
|
||||||
|
} else{
|
||||||
|
this.urlFile = this.contentService.createTrustedUrl(this.preview.content);
|
||||||
|
this.filename = this.preview.name;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@@ -26,7 +26,6 @@ import {
|
|||||||
EventEmitter, AfterViewInit, ViewChild, HostListener, OnDestroy
|
EventEmitter, AfterViewInit, ViewChild, HostListener, OnDestroy
|
||||||
} from '@angular/core';
|
} from '@angular/core';
|
||||||
import { AppConfigService } from '../../app-config/app-config.service';
|
import { AppConfigService } from '../../app-config/app-config.service';
|
||||||
import { UrlService } from '../../services/url.service';
|
|
||||||
import Cropper from 'cropperjs';
|
import Cropper from 'cropperjs';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
@@ -47,9 +46,6 @@ export class ImgViewerComponent implements AfterViewInit, OnChanges, OnDestroy {
|
|||||||
@Input()
|
@Input()
|
||||||
urlFile: string;
|
urlFile: string;
|
||||||
|
|
||||||
@Input()
|
|
||||||
blobFile: Blob;
|
|
||||||
|
|
||||||
@Input()
|
@Input()
|
||||||
fileName: string;
|
fileName: string;
|
||||||
|
|
||||||
@@ -73,8 +69,7 @@ export class ImgViewerComponent implements AfterViewInit, OnChanges, OnDestroy {
|
|||||||
}
|
}
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private appConfigService: AppConfigService,
|
private appConfigService: AppConfigService) {
|
||||||
private urlService: UrlService) {
|
|
||||||
this.initializeScaling();
|
this.initializeScaling();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -138,12 +133,7 @@ export class ImgViewerComponent implements AfterViewInit, OnChanges, OnDestroy {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ngOnChanges(changes: SimpleChanges) {
|
ngOnChanges(changes: SimpleChanges) {
|
||||||
const blobFile = changes['blobFile'];
|
if (!this.urlFile) {
|
||||||
if (blobFile && blobFile.currentValue) {
|
|
||||||
this.urlFile = this.urlService.createTrustedUrl(this.blobFile);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (!this.urlFile && !this.blobFile) {
|
|
||||||
throw new Error('Attribute urlFile or blobFile is required');
|
throw new Error('Attribute urlFile or blobFile is required');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -16,7 +16,6 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { Component, Input, OnChanges, SimpleChanges, ViewEncapsulation, Output, EventEmitter } from '@angular/core';
|
import { Component, Input, OnChanges, SimpleChanges, ViewEncapsulation, Output, EventEmitter } from '@angular/core';
|
||||||
import { ContentService } from '../../services/content.service';
|
|
||||||
import { Track } from '../models/viewer.model';
|
import { Track } from '../models/viewer.model';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
@@ -31,9 +30,6 @@ export class MediaPlayerComponent implements OnChanges {
|
|||||||
@Input()
|
@Input()
|
||||||
urlFile: string;
|
urlFile: string;
|
||||||
|
|
||||||
@Input()
|
|
||||||
blobFile: Blob;
|
|
||||||
|
|
||||||
@Input()
|
@Input()
|
||||||
mimeType: string;
|
mimeType: string;
|
||||||
|
|
||||||
@@ -47,18 +43,11 @@ export class MediaPlayerComponent implements OnChanges {
|
|||||||
@Output()
|
@Output()
|
||||||
error = new EventEmitter<any>();
|
error = new EventEmitter<any>();
|
||||||
|
|
||||||
constructor(private contentService: ContentService) {
|
constructor() {
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnChanges(changes: SimpleChanges) {
|
ngOnChanges(changes: SimpleChanges) {
|
||||||
const blobFile = changes['blobFile'];
|
if (!this.urlFile) {
|
||||||
|
|
||||||
if (blobFile && blobFile.currentValue) {
|
|
||||||
this.urlFile = this.contentService.createTrustedUrl(this.blobFile);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!this.urlFile && !this.blobFile) {
|
|
||||||
throw new Error('Attribute urlFile or blobFile is required');
|
throw new Error('Attribute urlFile or blobFile is required');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -56,9 +56,6 @@ export class PdfViewerComponent implements OnChanges, OnDestroy {
|
|||||||
@Input()
|
@Input()
|
||||||
urlFile: string;
|
urlFile: string;
|
||||||
|
|
||||||
@Input()
|
|
||||||
blobFile: Blob;
|
|
||||||
|
|
||||||
@Input()
|
@Input()
|
||||||
fileName: string;
|
fileName: string;
|
||||||
|
|
||||||
@@ -149,21 +146,6 @@ export class PdfViewerComponent implements OnChanges, OnDestroy {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ngOnChanges(changes: SimpleChanges) {
|
ngOnChanges(changes: SimpleChanges) {
|
||||||
const blobFile = changes['blobFile'];
|
|
||||||
|
|
||||||
if (blobFile && blobFile.currentValue) {
|
|
||||||
const reader = new FileReader();
|
|
||||||
reader.onload = async () => {
|
|
||||||
const pdfSource: PDFSource = {
|
|
||||||
...this.pdfjsDefaultOptions,
|
|
||||||
data: reader.result,
|
|
||||||
withCredentials: this.appConfigService.get<boolean>('auth.withCredentials', undefined)
|
|
||||||
};
|
|
||||||
this.executePdf(pdfSource);
|
|
||||||
};
|
|
||||||
reader.readAsArrayBuffer(blobFile.currentValue);
|
|
||||||
}
|
|
||||||
|
|
||||||
const urlFile = changes['urlFile'];
|
const urlFile = changes['urlFile'];
|
||||||
if (urlFile && urlFile.currentValue) {
|
if (urlFile && urlFile.currentValue) {
|
||||||
const pdfSource: PDFSource = {
|
const pdfSource: PDFSource = {
|
||||||
@@ -179,7 +161,7 @@ export class PdfViewerComponent implements OnChanges, OnDestroy {
|
|||||||
this.executePdf(pdfSource);
|
this.executePdf(pdfSource);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!this.urlFile && !this.blobFile) {
|
if (!this.urlFile) {
|
||||||
throw new Error('Attribute urlFile or blobFile is required');
|
throw new Error('Attribute urlFile or blobFile is required');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -31,27 +31,18 @@ export class TxtViewerComponent implements OnChanges {
|
|||||||
@Input()
|
@Input()
|
||||||
urlFile: any;
|
urlFile: any;
|
||||||
|
|
||||||
@Input()
|
|
||||||
blobFile: Blob;
|
|
||||||
|
|
||||||
content: string | ArrayBuffer;
|
content: string | ArrayBuffer;
|
||||||
|
|
||||||
constructor(private http: HttpClient, private appConfigService: AppConfigService) {
|
constructor(private http: HttpClient, private appConfigService: AppConfigService) {
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnChanges(changes: SimpleChanges): Promise<void> {
|
ngOnChanges(changes: SimpleChanges): Promise<void> {
|
||||||
|
|
||||||
const blobFile = changes['blobFile'];
|
|
||||||
if (blobFile && blobFile.currentValue) {
|
|
||||||
return this.readBlob(blobFile.currentValue);
|
|
||||||
}
|
|
||||||
|
|
||||||
const urlFile = changes['urlFile'];
|
const urlFile = changes['urlFile'];
|
||||||
if (urlFile && urlFile.currentValue) {
|
if (urlFile && urlFile.currentValue) {
|
||||||
return this.getUrlContent(urlFile.currentValue);
|
return this.getUrlContent(urlFile.currentValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!this.urlFile && !this.blobFile) {
|
if (!this.urlFile) {
|
||||||
throw new Error('Attribute urlFile or blobFile is required');
|
throw new Error('Attribute urlFile or blobFile is required');
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -71,20 +62,4 @@ export class TxtViewerComponent implements OnChanges {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private readBlob(blob: Blob): Promise<void> {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
const reader = new FileReader();
|
|
||||||
|
|
||||||
reader.onload = () => {
|
|
||||||
this.content = reader.result;
|
|
||||||
resolve();
|
|
||||||
};
|
|
||||||
|
|
||||||
reader.onerror = (error: any) => {
|
|
||||||
reject(error);
|
|
||||||
};
|
|
||||||
|
|
||||||
reader.readAsText(blob);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@@ -37,7 +37,6 @@
|
|||||||
<ng-container *ngSwitchCase="'pdf'">
|
<ng-container *ngSwitchCase="'pdf'">
|
||||||
<adf-pdf-viewer [thumbnailsTemplate]="thumbnailsTemplate"
|
<adf-pdf-viewer [thumbnailsTemplate]="thumbnailsTemplate"
|
||||||
[allowThumbnails]="allowThumbnails"
|
[allowThumbnails]="allowThumbnails"
|
||||||
[blobFile]="blobFile"
|
|
||||||
[urlFile]="urlFile"
|
[urlFile]="urlFile"
|
||||||
[fileName]="internalFileName"
|
[fileName]="internalFileName"
|
||||||
[cacheType]="cacheTypeForContent"
|
[cacheType]="cacheTypeForContent"
|
||||||
@@ -51,7 +50,6 @@
|
|||||||
<adf-img-viewer [urlFile]="urlFile"
|
<adf-img-viewer [urlFile]="urlFile"
|
||||||
[readOnly]="readOnly"
|
[readOnly]="readOnly"
|
||||||
[fileName]="internalFileName"
|
[fileName]="internalFileName"
|
||||||
[blobFile]="blobFile"
|
|
||||||
(error)="onUnsupportedFile()"
|
(error)="onUnsupportedFile()"
|
||||||
(submit)="onSubmitFile($event)"
|
(submit)="onSubmitFile($event)"
|
||||||
></adf-img-viewer>
|
></adf-img-viewer>
|
||||||
@@ -62,15 +60,13 @@
|
|||||||
[urlFile]="urlFile"
|
[urlFile]="urlFile"
|
||||||
[tracks]="tracks"
|
[tracks]="tracks"
|
||||||
[mimeType]="mimeType"
|
[mimeType]="mimeType"
|
||||||
[blobFile]="blobFile"
|
|
||||||
[fileName]="internalFileName"
|
[fileName]="internalFileName"
|
||||||
(error)="onUnsupportedFile()">
|
(error)="onUnsupportedFile()">
|
||||||
</adf-media-player>
|
</adf-media-player>
|
||||||
</ng-container>
|
</ng-container>
|
||||||
|
|
||||||
<ng-container *ngSwitchCase="'text'">
|
<ng-container *ngSwitchCase="'text'">
|
||||||
<adf-txt-viewer [urlFile]="urlFile"
|
<adf-txt-viewer [urlFile]="urlFile">
|
||||||
[blobFile]="blobFile">
|
|
||||||
|
|
||||||
</adf-txt-viewer>
|
</adf-txt-viewer>
|
||||||
</ng-container>
|
</ng-container>
|
||||||
|
@@ -42,10 +42,6 @@ export class ViewerRenderComponent implements OnChanges, OnInit, OnDestroy {
|
|||||||
@Input()
|
@Input()
|
||||||
urlFile = '';
|
urlFile = '';
|
||||||
|
|
||||||
/** Loads a Blob File */
|
|
||||||
@Input()
|
|
||||||
blobFile: Blob;
|
|
||||||
|
|
||||||
/** Toggles the 'Full Screen' feature. */
|
/** Toggles the 'Full Screen' feature. */
|
||||||
@Input()
|
@Input()
|
||||||
allowFullScreen = true;
|
allowFullScreen = true;
|
||||||
@@ -144,22 +140,12 @@ export class ViewerRenderComponent implements OnChanges, OnInit, OnDestroy {
|
|||||||
ngOnChanges() {
|
ngOnChanges() {
|
||||||
this.isLoading = true;
|
this.isLoading = true;
|
||||||
|
|
||||||
if (this.blobFile) {
|
if (this.urlFile) {
|
||||||
this.setUpBlobData();
|
|
||||||
} else if (this.urlFile) {
|
|
||||||
this.setUpUrlFile();
|
this.setUpUrlFile();
|
||||||
}
|
}
|
||||||
this.isLoading = false;
|
this.isLoading = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private setUpBlobData() {
|
|
||||||
this.internalFileName = this.fileName;
|
|
||||||
this.internalViewerType = this.viewUtilService.getViewerTypeByMimeType(this.blobFile.type);
|
|
||||||
|
|
||||||
this.extensionChange.emit(this.blobFile.type);
|
|
||||||
this.scrollTop();
|
|
||||||
}
|
|
||||||
|
|
||||||
private setUpUrlFile() {
|
private setUpUrlFile() {
|
||||||
this.internalFileName = this.fileName ? this.fileName : this.viewUtilService.getFilenameFromUrl(this.urlFile);
|
this.internalFileName = this.fileName ? this.fileName : this.viewUtilService.getFilenameFromUrl(this.urlFile);
|
||||||
this.extension = this.viewUtilService.getFileExtension(this.internalFileName);
|
this.extension = this.viewUtilService.getFileExtension(this.internalFileName);
|
||||||
|
172
lib/core/src/lib/viewer/components/viewer.component.html
Normal file
172
lib/core/src/lib/viewer/components/viewer.component.html
Normal file
@@ -0,0 +1,172 @@
|
|||||||
|
<div *ngIf="showViewer"
|
||||||
|
class="adf-alfresco-viewer-container"
|
||||||
|
[class.adf-alfresco-viewer-overlay-container]="overlayMode"
|
||||||
|
[class.adf-alfresco-viewer-inline-container]="!overlayMode">
|
||||||
|
|
||||||
|
<div class="adf-alfresco-viewer-content"
|
||||||
|
fxLayout="column"
|
||||||
|
[cdkTrapFocus]="overlayMode"
|
||||||
|
cdkTrapFocusAutoCapture>
|
||||||
|
<ng-content select="adf-viewer-toolbar"></ng-content>
|
||||||
|
<ng-container *ngIf="showToolbar && !toolbar">
|
||||||
|
<adf-toolbar id="adf-alfresco-viewer-toolbar" class="adf-alfresco-viewer-toolbar">
|
||||||
|
<adf-toolbar-title>
|
||||||
|
|
||||||
|
<ng-container *ngIf="allowLeftSidebar">
|
||||||
|
<button mat-icon-button
|
||||||
|
[attr.aria-expanded]="showLeftSidebar"
|
||||||
|
[attr.aria-label]="'ADF_VIEWER.ACTIONS.INFO' | translate"
|
||||||
|
title="{{ 'ADF_VIEWER.ACTIONS.INFO' | translate }}"
|
||||||
|
data-automation-id="adf-toolbar-left-sidebar"
|
||||||
|
[color]="showLeftSidebar ? 'accent' : null"
|
||||||
|
(click)="toggleLeftSidebar()">
|
||||||
|
<mat-icon>info_outline</mat-icon>
|
||||||
|
</button>
|
||||||
|
</ng-container>
|
||||||
|
|
||||||
|
<button *ngIf="allowGoBack"
|
||||||
|
class="adf-alfresco-viewer-close-button"
|
||||||
|
data-automation-id="adf-toolbar-back"
|
||||||
|
[attr.aria-label]="'ADF_VIEWER.ACTIONS.CLOSE' | translate"
|
||||||
|
mat-icon-button
|
||||||
|
title="{{ 'ADF_VIEWER.ACTIONS.CLOSE' | translate }}"
|
||||||
|
(click)="onClose()">
|
||||||
|
<mat-icon>close</mat-icon>
|
||||||
|
</button>
|
||||||
|
</adf-toolbar-title>
|
||||||
|
|
||||||
|
<div fxFlex="1 1 auto"
|
||||||
|
class="adf-alfresco-viewer__file-title">
|
||||||
|
<button *ngIf="allowNavigate && canNavigateBefore"
|
||||||
|
data-automation-id="adf-toolbar-pref-file"
|
||||||
|
mat-icon-button
|
||||||
|
[attr.aria-label]="'ADF_VIEWER.ACTIONS.PREV_FILE' | translate"
|
||||||
|
title="{{ 'ADF_VIEWER.ACTIONS.PREV_FILE' | translate }}"
|
||||||
|
(click)="onNavigateBeforeClick($event)">
|
||||||
|
<mat-icon>navigate_before</mat-icon>
|
||||||
|
</button>
|
||||||
|
<img class="adf-alfresco-viewer__mimeicon"
|
||||||
|
[alt]="mimeType"
|
||||||
|
[src]="mimeType | adfMimeTypeIcon"
|
||||||
|
data-automation-id="adf-file-thumbnail">
|
||||||
|
<span class="adf-alfresco-viewer__display-name"
|
||||||
|
id="adf-alfresco-viewer-display-name">{{ fileName }}</span>
|
||||||
|
<button *ngIf="allowNavigate && canNavigateNext"
|
||||||
|
data-automation-id="adf-toolbar-next-file"
|
||||||
|
mat-icon-button
|
||||||
|
[attr.aria-label]="'ADF_VIEWER.ACTIONS.NEXT_FILE' | translate"
|
||||||
|
title="{{ 'ADF_VIEWER.ACTIONS.NEXT_FILE' | translate }}"
|
||||||
|
(click)="onNavigateNextClick($event)">
|
||||||
|
<mat-icon>navigate_next</mat-icon>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<ng-content select="adf-alfresco-viewer-toolbar-actions"></ng-content>
|
||||||
|
|
||||||
|
<ng-container *ngIf="mnuOpenWith"
|
||||||
|
data-automation-id='adf-toolbar-custom-btn'>
|
||||||
|
<button id="adf-alfresco-viewer-openwith"
|
||||||
|
mat-button
|
||||||
|
[matMenuTriggerFor]="mnuOpenWith"
|
||||||
|
data-automation-id="adf-toolbar-open-with">
|
||||||
|
<span>{{ 'ADF_VIEWER.ACTIONS.OPEN_WITH' | translate }}</span>
|
||||||
|
<mat-icon>arrow_drop_down</mat-icon>
|
||||||
|
</button>
|
||||||
|
<mat-menu #mnuOpenWith="matMenu"
|
||||||
|
[overlapTrigger]="false">
|
||||||
|
<ng-content select="adf-alfresco-viewer-open-with"></ng-content>
|
||||||
|
</mat-menu>
|
||||||
|
</ng-container>
|
||||||
|
|
||||||
|
<adf-toolbar-divider></adf-toolbar-divider>
|
||||||
|
|
||||||
|
<button id="adf-alfresco-viewer-fullscreen"
|
||||||
|
*ngIf="viewerType !== 'media'"
|
||||||
|
mat-icon-button
|
||||||
|
[attr.aria-label]="'ADF_VIEWER.ACTIONS.FULLSCREEN' | translate"
|
||||||
|
title="{{ 'ADF_VIEWER.ACTIONS.FULLSCREEN' | translate }}"
|
||||||
|
data-automation-id="adf-toolbar-fullscreen"
|
||||||
|
(click)="enterFullScreen()">
|
||||||
|
<mat-icon>fullscreen</mat-icon>
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<ng-container *ngIf="allowRightSidebar">
|
||||||
|
<adf-toolbar-divider></adf-toolbar-divider>
|
||||||
|
|
||||||
|
<button mat-icon-button
|
||||||
|
[attr.aria-expanded]="showRightSidebar"
|
||||||
|
[attr.aria-label]="'ADF_VIEWER.ACTIONS.INFO' | translate"
|
||||||
|
title="{{ 'ADF_VIEWER.ACTIONS.INFO' | translate }}"
|
||||||
|
data-automation-id="adf-toolbar-sidebar"
|
||||||
|
[color]="showRightSidebar ? 'accent' : null"
|
||||||
|
(click)="toggleRightSidebar()">
|
||||||
|
<mat-icon>info_outline</mat-icon>
|
||||||
|
</button>
|
||||||
|
|
||||||
|
</ng-container>
|
||||||
|
|
||||||
|
<ng-container *ngIf="mnuMoreActions">
|
||||||
|
<button id="adf-alfresco-viewer-moreactions"
|
||||||
|
mat-icon-button
|
||||||
|
[matMenuTriggerFor]="mnuMoreActions"
|
||||||
|
[attr.aria-label]="'ADF_VIEWER.ACTIONS.MORE_ACTIONS' | translate"
|
||||||
|
title="{{ 'ADF_VIEWER.ACTIONS.MORE_ACTIONS' | translate }}"
|
||||||
|
data-automation-id="adf-toolbar-more-actions">
|
||||||
|
<mat-icon>more_vert</mat-icon>
|
||||||
|
</button>
|
||||||
|
<mat-menu #mnuMoreActions="matMenu"
|
||||||
|
[overlapTrigger]="false">
|
||||||
|
<ng-content select="adf-alfresco-viewer-more-actions"></ng-content>
|
||||||
|
</mat-menu>
|
||||||
|
</ng-container>
|
||||||
|
|
||||||
|
</adf-toolbar>
|
||||||
|
</ng-container>
|
||||||
|
|
||||||
|
<div fxLayout="row"
|
||||||
|
fxFlex="1 1 auto">
|
||||||
|
|
||||||
|
<ng-container *ngIf="allowRightSidebar && showRightSidebar">
|
||||||
|
<div class="adf-alfresco-viewer__sidebar"
|
||||||
|
[ngClass]="'adf-alfresco-viewer__sidebar__right'"
|
||||||
|
fxFlexOrder="4"
|
||||||
|
id="adf-right-sidebar">
|
||||||
|
<ng-container *ngIf="sidebarRightTemplate">
|
||||||
|
<ng-container *ngTemplateOutlet="sidebarRightTemplate;context:sidebarRightTemplateContext">
|
||||||
|
</ng-container>
|
||||||
|
</ng-container>
|
||||||
|
<ng-content *ngIf="!sidebarRightTemplate"
|
||||||
|
select="adf-alfresco-viewer-sidebar"></ng-content>
|
||||||
|
</div>
|
||||||
|
</ng-container>
|
||||||
|
|
||||||
|
<ng-container *ngIf="allowLeftSidebar && showLeftSidebar">
|
||||||
|
<div class="adf-alfresco-viewer__sidebar"
|
||||||
|
[ngClass]="'adf-alfresco-viewer__sidebar__left'"
|
||||||
|
fxFlexOrder="1"
|
||||||
|
id="adf-left-sidebar">
|
||||||
|
<ng-container *ngIf="sidebarLeftTemplate">
|
||||||
|
<ng-container *ngTemplateOutlet="sidebarLeftTemplate;context:sidebarLeftTemplateContext">
|
||||||
|
</ng-container>
|
||||||
|
</ng-container>
|
||||||
|
<ng-content *ngIf="!sidebarLeftTemplate"
|
||||||
|
select="adf-alfresco-viewer-sidebar"></ng-content>
|
||||||
|
</div>
|
||||||
|
</ng-container>
|
||||||
|
|
||||||
|
<adf-viewer-render
|
||||||
|
fxFlexOrder="1"
|
||||||
|
fxFlex="1 1 auto"
|
||||||
|
(close)="onClose()"
|
||||||
|
(submitFile)="onSubmitFile($event)"
|
||||||
|
[viewerType]="viewerType"
|
||||||
|
[fileName]="fileName"
|
||||||
|
[isLoading]="isLoading"
|
||||||
|
[urlFile]="urlFile"
|
||||||
|
[tracks]="tracks"
|
||||||
|
[readOnly]="readOnly">
|
||||||
|
</adf-viewer-render>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
77
lib/core/src/lib/viewer/components/viewer.component.scss
Normal file
77
lib/core/src/lib/viewer/components/viewer.component.scss
Normal file
@@ -0,0 +1,77 @@
|
|||||||
|
/* stylelint-disable scss/at-extend-no-missing-placeholder */
|
||||||
|
.adf-full-screen {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
background-color: var(--theme-card-bg-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.adf-alfresco-viewer {
|
||||||
|
position: absolute;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
|
||||||
|
.mat-toolbar {
|
||||||
|
color: var(--theme-text-color);
|
||||||
|
|
||||||
|
.adf-toolbar-title {
|
||||||
|
width: auto;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&-main {
|
||||||
|
width: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__mimeicon {
|
||||||
|
vertical-align: middle;
|
||||||
|
height: 18px;
|
||||||
|
width: 18px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&-toolbar {
|
||||||
|
.mat-toolbar {
|
||||||
|
background-color: var(--theme-card-bg-bold-color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&__file-title {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__display-name {
|
||||||
|
font-size: var(--theme-subheading-2-font-size);
|
||||||
|
opacity: 0.87;
|
||||||
|
line-height: 1.5;
|
||||||
|
letter-spacing: -0.4px;
|
||||||
|
font-weight: normal;
|
||||||
|
font-style: normal;
|
||||||
|
font-stretch: normal;
|
||||||
|
max-width: 400px;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
overflow: hidden;
|
||||||
|
display: inline-block;
|
||||||
|
vertical-align: middle;
|
||||||
|
color: var(--theme-text-fg-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
&-inline-container {
|
||||||
|
@extend .adf-full-screen;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__sidebar {
|
||||||
|
width: 350px;
|
||||||
|
display: block;
|
||||||
|
padding: 0;
|
||||||
|
background-color: var(--theme-background-color);
|
||||||
|
box-shadow: 0 2px 4px 0 var(--theme-text-fg-shadow-color);
|
||||||
|
overflow: auto;
|
||||||
|
|
||||||
|
&__right {
|
||||||
|
border-left: 1px solid var(--theme-border-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
&__left {
|
||||||
|
border-right: 1px solid var(--theme-border-color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
944
lib/core/src/lib/viewer/components/viewer.component.spec.ts
Normal file
944
lib/core/src/lib/viewer/components/viewer.component.spec.ts
Normal file
@@ -0,0 +1,944 @@
|
|||||||
|
/*!
|
||||||
|
* @license
|
||||||
|
* Copyright 2019 Alfresco Software, Ltd.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { Location } from '@angular/common';
|
||||||
|
import { SpyLocation } from '@angular/common/testing';
|
||||||
|
import { ComponentFixture, fakeAsync, TestBed, tick } from '@angular/core/testing';
|
||||||
|
|
||||||
|
import { TranslateModule } from '@ngx-translate/core';
|
||||||
|
import { MatDialog } from '@angular/material/dialog';
|
||||||
|
import { NoopAnimationsModule } from '@angular/platform-browser/animations';
|
||||||
|
import { AppExtensionService, ViewerExtensionRef } from '@alfresco/adf-extensions';
|
||||||
|
import { MatButtonModule } from '@angular/material/button';
|
||||||
|
import { MatIconModule } from '@angular/material/icon';
|
||||||
|
import { NodeEntry, VersionEntry } from '@alfresco/js-api';
|
||||||
|
import { AlfrescoViewerComponent, RenditionViewerService } from '@alfresco/adf-content-services';
|
||||||
|
import {
|
||||||
|
AlfrescoApiService,
|
||||||
|
CoreTestingModule,
|
||||||
|
setupTestBed,
|
||||||
|
EventMock,
|
||||||
|
FileModel, UploadService
|
||||||
|
} from '@alfresco/adf-core';
|
||||||
|
import { throwError } from 'rxjs';
|
||||||
|
import { Component } from '@angular/core';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'adf-viewer-container-toolbar',
|
||||||
|
template: `
|
||||||
|
<adf-alfresco-viewer>
|
||||||
|
<adf-viewer-toolbar>
|
||||||
|
<div class="custom-toolbar-element"></div>
|
||||||
|
</adf-viewer-toolbar>
|
||||||
|
</adf-alfresco-viewer>
|
||||||
|
`
|
||||||
|
})
|
||||||
|
class ViewerWithCustomToolbarComponent {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'adf-viewer-container-toolbar-actions',
|
||||||
|
template: `
|
||||||
|
<adf-alfresco-viewer>
|
||||||
|
<adf-viewer-toolbar-actions>
|
||||||
|
<button mat-icon-button id="custom-button">
|
||||||
|
<mat-icon>alarm</mat-icon>
|
||||||
|
</button>
|
||||||
|
</adf-viewer-toolbar-actions>
|
||||||
|
</adf-alfresco-viewer>
|
||||||
|
`
|
||||||
|
})
|
||||||
|
class ViewerWithCustomToolbarActionsComponent {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'adf-viewer-container-sidebar',
|
||||||
|
template: `
|
||||||
|
<adf-alfresco-viewer>
|
||||||
|
<adf-viewer-sidebar>
|
||||||
|
<div class="custom-sidebar"></div>
|
||||||
|
</adf-viewer-sidebar>
|
||||||
|
</adf-alfresco-viewer>
|
||||||
|
`
|
||||||
|
})
|
||||||
|
class ViewerWithCustomSidebarComponent {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'adf-dialog-dummy',
|
||||||
|
template: ``
|
||||||
|
})
|
||||||
|
class DummyDialogComponent {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'adf-viewer-container-open-with',
|
||||||
|
template: `
|
||||||
|
<adf-alfresco-viewer>
|
||||||
|
<adf-viewer-open-with>
|
||||||
|
<button mat-menu-item>
|
||||||
|
<mat-icon>dialpad</mat-icon>
|
||||||
|
<span>Option 1</span>
|
||||||
|
</button>
|
||||||
|
<button mat-menu-item disabled>
|
||||||
|
<mat-icon>voicemail</mat-icon>
|
||||||
|
<span>Option 2</span>
|
||||||
|
</button>
|
||||||
|
<button mat-menu-item>
|
||||||
|
<mat-icon>notifications_off</mat-icon>
|
||||||
|
<span>Option 3</span>
|
||||||
|
</button>
|
||||||
|
</adf-viewer-open-with>
|
||||||
|
</adf-alfresco-viewer>
|
||||||
|
`
|
||||||
|
})
|
||||||
|
class ViewerWithCustomOpenWithComponent {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'adf-viewer-container-more-actions',
|
||||||
|
template: `
|
||||||
|
<adf-alfresco-viewer>
|
||||||
|
<adf-viewer-more-actions>
|
||||||
|
<button mat-menu-item>
|
||||||
|
<mat-icon>dialpad</mat-icon>
|
||||||
|
<span>Action One</span>
|
||||||
|
</button>
|
||||||
|
<button mat-menu-item disabled>
|
||||||
|
<mat-icon>voicemail</mat-icon>
|
||||||
|
<span>Action Two</span>
|
||||||
|
</button>
|
||||||
|
<button mat-menu-item>
|
||||||
|
<mat-icon>notifications_off</mat-icon>
|
||||||
|
<span>Action Three</span>
|
||||||
|
</button>
|
||||||
|
</adf-viewer-more-actions>
|
||||||
|
</adf-alfresco-viewer>
|
||||||
|
`
|
||||||
|
})
|
||||||
|
class ViewerWithCustomMoreActionsComponent {
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
describe('AlfrescoViewerComponent', () => {
|
||||||
|
|
||||||
|
let component: AlfrescoViewerComponent;
|
||||||
|
let fixture: ComponentFixture<AlfrescoViewerComponent>;
|
||||||
|
let element: HTMLElement;
|
||||||
|
|
||||||
|
let alfrescoApiService: AlfrescoApiService;
|
||||||
|
let dialog: MatDialog;
|
||||||
|
let uploadService: UploadService;
|
||||||
|
let extensionService: AppExtensionService;
|
||||||
|
|
||||||
|
setupTestBed({
|
||||||
|
imports: [
|
||||||
|
NoopAnimationsModule,
|
||||||
|
TranslateModule.forRoot(),
|
||||||
|
CoreTestingModule,
|
||||||
|
MatButtonModule,
|
||||||
|
MatIconModule
|
||||||
|
],
|
||||||
|
declarations: [
|
||||||
|
ViewerWithCustomToolbarComponent,
|
||||||
|
ViewerWithCustomSidebarComponent,
|
||||||
|
ViewerWithCustomOpenWithComponent,
|
||||||
|
ViewerWithCustomMoreActionsComponent,
|
||||||
|
ViewerWithCustomToolbarActionsComponent
|
||||||
|
],
|
||||||
|
providers: [
|
||||||
|
{
|
||||||
|
provide: RenditionViewerService, useValue: {
|
||||||
|
getNodeRendition: () => throwError('thrown')
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{provide: Location, useClass: SpyLocation},
|
||||||
|
MatDialog
|
||||||
|
]
|
||||||
|
});
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
fixture = TestBed.createComponent(AlfrescoViewerComponent);
|
||||||
|
element = fixture.nativeElement;
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
|
||||||
|
uploadService = TestBed.inject(UploadService);
|
||||||
|
alfrescoApiService = TestBed.inject(AlfrescoApiService);
|
||||||
|
dialog = TestBed.inject(MatDialog);
|
||||||
|
extensionService = TestBed.inject(AppExtensionService);
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
fixture.destroy();
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
describe('Extension Type Test', () => {
|
||||||
|
|
||||||
|
|
||||||
|
it('should use external viewer to display node by id', fakeAsync(() => {
|
||||||
|
const extension: ViewerExtensionRef = {
|
||||||
|
component: 'custom.component',
|
||||||
|
id: 'custom.component.id',
|
||||||
|
fileExtension: '*'
|
||||||
|
};
|
||||||
|
spyOn(extensionService, 'getViewerExtensions').and.returnValue([extension]);
|
||||||
|
|
||||||
|
fixture = TestBed.createComponent(AlfrescoViewerComponent);
|
||||||
|
element = fixture.nativeElement;
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
|
||||||
|
spyOn(component.nodesApi, 'getNode').and.callFake(() => Promise.resolve(new NodeEntry({entry: {}})));
|
||||||
|
|
||||||
|
component.nodeId = '37f7f34d-4e64-4db6-bb3f-5c89f7844251';
|
||||||
|
component.ngOnChanges();
|
||||||
|
|
||||||
|
fixture.detectChanges();
|
||||||
|
tick(100);
|
||||||
|
|
||||||
|
expect(component.nodesApi.getNode).toHaveBeenCalled();
|
||||||
|
expect(component.viewerType).toBe('external');
|
||||||
|
expect(component.isLoading).toBeFalsy();
|
||||||
|
expect(element.querySelector('[data-automation-id="custom.component"]')).not.toBeNull();
|
||||||
|
}));
|
||||||
|
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('MimeType handling', () => {
|
||||||
|
|
||||||
|
it('should node without content show unkonwn', (done) => {
|
||||||
|
const displayName = 'the-name';
|
||||||
|
const contentUrl = '/content/url/path';
|
||||||
|
|
||||||
|
component.nodeId = '12';
|
||||||
|
spyOn(component['nodesApi'], 'getNode').and.returnValue(Promise.resolve(new NodeEntry({
|
||||||
|
entry: {content: {name: displayName, id: '12'}}
|
||||||
|
})));
|
||||||
|
|
||||||
|
spyOn(component['contentApi'], 'getContentUrl').and.returnValue(contentUrl);
|
||||||
|
|
||||||
|
component.ngOnChanges();
|
||||||
|
fixture.whenStable().then(() => {
|
||||||
|
fixture.detectChanges();
|
||||||
|
expect(element.querySelector('adf-viewer-unknown-format')).toBeDefined();
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should change display name every time node changes', fakeAsync(() => {
|
||||||
|
spyOn(component['nodesApi'], 'getNode').and.returnValues(
|
||||||
|
Promise.resolve(new NodeEntry({entry: {name: 'file1', content: {}}})),
|
||||||
|
Promise.resolve(new NodeEntry({entry: {name: 'file2', content: {}}}))
|
||||||
|
);
|
||||||
|
|
||||||
|
component.showViewer = true;
|
||||||
|
|
||||||
|
component.nodeId = 'id1';
|
||||||
|
component.ngOnChanges();
|
||||||
|
tick();
|
||||||
|
|
||||||
|
expect(component.fileName).toBe('file1');
|
||||||
|
|
||||||
|
component.nodeId = 'id2';
|
||||||
|
component.ngOnChanges();
|
||||||
|
tick();
|
||||||
|
|
||||||
|
expect(component.fileName).toBe('file2');
|
||||||
|
}));
|
||||||
|
|
||||||
|
it('should append version of the file to the file content URL', fakeAsync(() => {
|
||||||
|
spyOn(component['nodesApi'], 'getNode').and.returnValue(
|
||||||
|
Promise.resolve(new NodeEntry({
|
||||||
|
entry: {
|
||||||
|
name: 'file1.pdf',
|
||||||
|
content: {},
|
||||||
|
properties: {'cm:versionLabel': '10'}
|
||||||
|
}
|
||||||
|
}))
|
||||||
|
);
|
||||||
|
spyOn(component['versionsApi'], 'getVersion').and.returnValue(Promise.resolve(undefined));
|
||||||
|
|
||||||
|
component.nodeId = 'id1';
|
||||||
|
component.showViewer = true;
|
||||||
|
|
||||||
|
component.versionId = null;
|
||||||
|
component.ngOnChanges();
|
||||||
|
tick();
|
||||||
|
|
||||||
|
expect(component.fileName).toBe('file1.pdf');
|
||||||
|
expect(component.urlFileContent).toContain('/public/alfresco/versions/1/nodes/id1/content?attachment=false&10');
|
||||||
|
}));
|
||||||
|
|
||||||
|
it('should change display name every time node\`s version changes', fakeAsync(() => {
|
||||||
|
spyOn(component['nodesApi'], 'getNode').and.returnValue(
|
||||||
|
Promise.resolve(new NodeEntry({entry: {name: 'node1', content: {}}}))
|
||||||
|
);
|
||||||
|
|
||||||
|
spyOn(component['versionsApi'], 'getVersion').and.returnValues(
|
||||||
|
Promise.resolve(new VersionEntry({entry: {name: 'file1', content: {}}})),
|
||||||
|
Promise.resolve(new VersionEntry({entry: {name: 'file2', content: {}}}))
|
||||||
|
);
|
||||||
|
|
||||||
|
component.nodeId = 'id1';
|
||||||
|
component.showViewer = true;
|
||||||
|
|
||||||
|
component.versionId = '1.0';
|
||||||
|
component.ngOnChanges();
|
||||||
|
tick();
|
||||||
|
|
||||||
|
expect(component.fileName).toBe('file1');
|
||||||
|
|
||||||
|
component.versionId = '1.1';
|
||||||
|
component.ngOnChanges();
|
||||||
|
tick();
|
||||||
|
|
||||||
|
expect(component.fileName).toBe('file2');
|
||||||
|
}));
|
||||||
|
|
||||||
|
it('should update node only if node name changed', fakeAsync(() => {
|
||||||
|
spyOn(component['nodesApi'], 'getNode').and.returnValues(
|
||||||
|
Promise.resolve(new NodeEntry({entry: {name: 'file1', content: {}}}))
|
||||||
|
);
|
||||||
|
|
||||||
|
component.showViewer = true;
|
||||||
|
|
||||||
|
component.nodeId = 'id1';
|
||||||
|
fixture.detectChanges();
|
||||||
|
component.ngOnChanges();
|
||||||
|
tick();
|
||||||
|
|
||||||
|
expect(component.fileName).toBe('file1');
|
||||||
|
|
||||||
|
alfrescoApiService.nodeUpdated.next({id: 'id1', name: 'file2'} as any);
|
||||||
|
fixture.detectChanges();
|
||||||
|
expect(component.fileName).toBe('file2');
|
||||||
|
|
||||||
|
alfrescoApiService.nodeUpdated.next({id: 'id1', name: 'file3'} as any);
|
||||||
|
fixture.detectChanges();
|
||||||
|
expect(component.fileName).toBe('file3');
|
||||||
|
|
||||||
|
alfrescoApiService.nodeUpdated.next({id: 'id2', name: 'file4'} as any);
|
||||||
|
fixture.detectChanges();
|
||||||
|
expect(component.fileName).toBe('file3');
|
||||||
|
expect(component.nodeId).toBe('id1');
|
||||||
|
}));
|
||||||
|
|
||||||
|
describe('Viewer Example Component Rendering', () => {
|
||||||
|
|
||||||
|
it('should use custom toolbar', (done) => {
|
||||||
|
const customFixture = TestBed.createComponent(ViewerWithCustomToolbarComponent);
|
||||||
|
const customElement: HTMLElement = customFixture.nativeElement;
|
||||||
|
|
||||||
|
customFixture.detectChanges();
|
||||||
|
fixture.whenStable().then(() => {
|
||||||
|
expect(customElement.querySelector('.custom-toolbar-element')).toBeDefined();
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should use custom toolbar actions', (done) => {
|
||||||
|
const customFixture = TestBed.createComponent(ViewerWithCustomToolbarActionsComponent);
|
||||||
|
const customElement: HTMLElement = customFixture.nativeElement;
|
||||||
|
|
||||||
|
customFixture.detectChanges();
|
||||||
|
fixture.whenStable().then(() => {
|
||||||
|
expect(customElement.querySelector('#custom-button')).toBeDefined();
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should use custom info drawer', (done) => {
|
||||||
|
const customFixture = TestBed.createComponent(ViewerWithCustomSidebarComponent);
|
||||||
|
const customElement: HTMLElement = customFixture.nativeElement;
|
||||||
|
|
||||||
|
customFixture.detectChanges();
|
||||||
|
|
||||||
|
fixture.whenStable().then(() => {
|
||||||
|
expect(customElement.querySelector('.custom-info-drawer-element')).toBeDefined();
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should use custom open with menu', (done) => {
|
||||||
|
const customFixture = TestBed.createComponent(ViewerWithCustomOpenWithComponent);
|
||||||
|
const customElement: HTMLElement = customFixture.nativeElement;
|
||||||
|
|
||||||
|
customFixture.detectChanges();
|
||||||
|
|
||||||
|
fixture.whenStable().then(() => {
|
||||||
|
expect(customElement.querySelector('.adf-viewer-container-open-with')).toBeDefined();
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should use custom more actions menu', (done) => {
|
||||||
|
const customFixture = TestBed.createComponent(ViewerWithCustomMoreActionsComponent);
|
||||||
|
const customElement: HTMLElement = customFixture.nativeElement;
|
||||||
|
|
||||||
|
customFixture.detectChanges();
|
||||||
|
|
||||||
|
fixture.whenStable().then(() => {
|
||||||
|
expect(customElement.querySelector('.adf-viewer-container-more-actions')).toBeDefined();
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('error handling', () => {
|
||||||
|
|
||||||
|
it('should show unknown view when node file not found', (done) => {
|
||||||
|
spyOn(component['nodesApi'], 'getNode')
|
||||||
|
.and.returnValue(Promise.reject({}));
|
||||||
|
|
||||||
|
component.nodeId = 'the-node-id-of-the-file-to-preview';
|
||||||
|
component.mimeType = null;
|
||||||
|
|
||||||
|
component.ngOnChanges();
|
||||||
|
fixture.whenStable().then(() => {
|
||||||
|
fixture.detectChanges();
|
||||||
|
expect(element.querySelector('adf-viewer-unknown-format')).not.toBeNull();
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should show unknown view when sharedLink file not found', (done) => {
|
||||||
|
spyOn(component['sharedLinksApi'], 'getSharedLink')
|
||||||
|
.and.returnValue(Promise.reject({}));
|
||||||
|
|
||||||
|
component.sharedLinkId = 'the-Shared-Link-id';
|
||||||
|
component.mimeType = null;
|
||||||
|
component.nodeId = null;
|
||||||
|
|
||||||
|
component.ngOnChanges();
|
||||||
|
fixture.whenStable().then(() => {
|
||||||
|
fixture.detectChanges();
|
||||||
|
expect(element.querySelector('adf-viewer-unknown-format')).not.toBeNull();
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should raise an event when the shared link is invalid', fakeAsync(() => {
|
||||||
|
spyOn(component['sharedLinksApi'], 'getSharedLink')
|
||||||
|
.and.returnValue(Promise.reject({}));
|
||||||
|
|
||||||
|
component.sharedLinkId = 'the-Shared-Link-id';
|
||||||
|
component.mimeType = null;
|
||||||
|
component.nodeId = null;
|
||||||
|
|
||||||
|
component.invalidSharedLink.subscribe((emittedValue) => {
|
||||||
|
expect(emittedValue).toBeUndefined();
|
||||||
|
});
|
||||||
|
|
||||||
|
component.ngOnChanges();
|
||||||
|
}));
|
||||||
|
//
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('Toolbar', () => {
|
||||||
|
|
||||||
|
it('should show only next file button', async () => {
|
||||||
|
component.allowNavigate = true;
|
||||||
|
component.canNavigateBefore = false;
|
||||||
|
component.canNavigateNext = true;
|
||||||
|
|
||||||
|
fixture.detectChanges();
|
||||||
|
await fixture.whenStable();
|
||||||
|
|
||||||
|
const nextButton = element.querySelector<HTMLButtonElement>('[data-automation-id="adf-toolbar-next-file"]');
|
||||||
|
expect(nextButton).not.toBeNull();
|
||||||
|
|
||||||
|
const prevButton = element.querySelector<HTMLButtonElement>('[data-automation-id="adf-toolbar-pref-file"]');
|
||||||
|
expect(prevButton).toBeNull();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should provide tooltip for next file button', async () => {
|
||||||
|
component.allowNavigate = true;
|
||||||
|
component.canNavigateBefore = false;
|
||||||
|
component.canNavigateNext = true;
|
||||||
|
|
||||||
|
fixture.detectChanges();
|
||||||
|
await fixture.whenStable();
|
||||||
|
|
||||||
|
const nextButton = element.querySelector<HTMLButtonElement>('[data-automation-id="adf-toolbar-next-file"]');
|
||||||
|
expect(nextButton.title).toBe('ADF_VIEWER.ACTIONS.NEXT_FILE');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should show only previous file button', async () => {
|
||||||
|
component.allowNavigate = true;
|
||||||
|
component.canNavigateBefore = true;
|
||||||
|
component.canNavigateNext = false;
|
||||||
|
|
||||||
|
fixture.detectChanges();
|
||||||
|
await fixture.whenStable();
|
||||||
|
|
||||||
|
const nextButton = element.querySelector<HTMLButtonElement>('[data-automation-id="adf-toolbar-next-file"]');
|
||||||
|
expect(nextButton).toBeNull();
|
||||||
|
|
||||||
|
const prevButton = element.querySelector<HTMLButtonElement>('[data-automation-id="adf-toolbar-pref-file"]');
|
||||||
|
expect(prevButton).not.toBeNull();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should provide tooltip for the previous file button', async () => {
|
||||||
|
component.allowNavigate = true;
|
||||||
|
component.canNavigateBefore = true;
|
||||||
|
component.canNavigateNext = false;
|
||||||
|
|
||||||
|
fixture.detectChanges();
|
||||||
|
await fixture.whenStable();
|
||||||
|
|
||||||
|
const prevButton = element.querySelector<HTMLButtonElement>('[data-automation-id="adf-toolbar-pref-file"]');
|
||||||
|
expect(prevButton.title).toBe('ADF_VIEWER.ACTIONS.PREV_FILE');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should show both file navigation buttons', async () => {
|
||||||
|
component.allowNavigate = true;
|
||||||
|
component.canNavigateBefore = true;
|
||||||
|
component.canNavigateNext = true;
|
||||||
|
|
||||||
|
fixture.detectChanges();
|
||||||
|
await fixture.whenStable();
|
||||||
|
|
||||||
|
const nextButton = element.querySelector<HTMLButtonElement>('[data-automation-id="adf-toolbar-next-file"]');
|
||||||
|
expect(nextButton).not.toBeNull();
|
||||||
|
|
||||||
|
const prevButton = element.querySelector<HTMLButtonElement>('[data-automation-id="adf-toolbar-pref-file"]');
|
||||||
|
expect(prevButton).not.toBeNull();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not show navigation buttons', async () => {
|
||||||
|
component.allowNavigate = false;
|
||||||
|
|
||||||
|
fixture.detectChanges();
|
||||||
|
await fixture.whenStable();
|
||||||
|
|
||||||
|
const nextButton = element.querySelector<HTMLButtonElement>('[data-automation-id="adf-toolbar-next-file"]');
|
||||||
|
expect(nextButton).toBeNull();
|
||||||
|
|
||||||
|
const prevButton = element.querySelector<HTMLButtonElement>('[data-automation-id="adf-toolbar-pref-file"]');
|
||||||
|
expect(prevButton).toBeNull();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should now show navigation buttons even if navigation enabled', async () => {
|
||||||
|
component.allowNavigate = true;
|
||||||
|
component.canNavigateBefore = false;
|
||||||
|
component.canNavigateNext = false;
|
||||||
|
|
||||||
|
fixture.detectChanges();
|
||||||
|
await fixture.whenStable();
|
||||||
|
|
||||||
|
const nextButton = element.querySelector<HTMLButtonElement>('[data-automation-id="adf-toolbar-next-file"]');
|
||||||
|
expect(nextButton).toBeNull();
|
||||||
|
|
||||||
|
const prevButton = element.querySelector<HTMLButtonElement>('[data-automation-id="adf-toolbar-pref-file"]');
|
||||||
|
expect(prevButton).toBeNull();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should render fullscreen button', () => {
|
||||||
|
expect(element.querySelector('[data-automation-id="adf-toolbar-fullscreen"]')).toBeDefined();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should render default download button', (done) => {
|
||||||
|
component.allowDownload = true;
|
||||||
|
|
||||||
|
fixture.whenStable().then(() => {
|
||||||
|
expect(element.querySelector('[data-automation-id="adf-toolbar-download"]')).toBeDefined();
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not render default download button', (done) => {
|
||||||
|
component.allowDownload = false;
|
||||||
|
fixture.detectChanges();
|
||||||
|
|
||||||
|
fixture.whenStable().then(() => {
|
||||||
|
expect(element.querySelector('[data-automation-id="adf-toolbar-download"]')).toBeNull();
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should render default print button', (done) => {
|
||||||
|
component.allowPrint = true;
|
||||||
|
fixture.detectChanges();
|
||||||
|
|
||||||
|
fixture.whenStable().then(() => {
|
||||||
|
expect(element.querySelector('[data-automation-id="adf-toolbar-print"]')).toBeDefined();
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not render default print button', (done) => {
|
||||||
|
component.allowPrint = false;
|
||||||
|
fixture.detectChanges();
|
||||||
|
|
||||||
|
fixture.whenStable().then(() => {
|
||||||
|
expect(element.querySelector('[data-automation-id="adf-toolbar-print"]')).toBeNull();
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should invoke print action with the toolbar button', (done) => {
|
||||||
|
component.allowPrint = true;
|
||||||
|
fixture.detectChanges();
|
||||||
|
|
||||||
|
spyOn(component, 'onPrintContent').and.stub();
|
||||||
|
|
||||||
|
const button: HTMLButtonElement = element.querySelector('[data-automation-id="adf-toolbar-print"]') as HTMLButtonElement;
|
||||||
|
button.click();
|
||||||
|
|
||||||
|
fixture.whenStable().then(() => {
|
||||||
|
expect(component.onPrintContent).toHaveBeenCalled();
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should get and assign node for download', (done) => {
|
||||||
|
component.nodeId = '12';
|
||||||
|
const displayName = 'the-name';
|
||||||
|
const nodeDetails = {
|
||||||
|
entry: {name: displayName, id: '12', content: {mimeType: 'txt'}}
|
||||||
|
};
|
||||||
|
|
||||||
|
const contentUrl = '/content/url/path';
|
||||||
|
|
||||||
|
const node = new NodeEntry(nodeDetails);
|
||||||
|
|
||||||
|
spyOn(component['nodesApi'], 'getNode').and.returnValue(Promise.resolve(node));
|
||||||
|
spyOn(component['contentApi'], 'getContentUrl').and.returnValue(contentUrl);
|
||||||
|
|
||||||
|
component.ngOnChanges();
|
||||||
|
fixture.whenStable().then(() => {
|
||||||
|
fixture.detectChanges();
|
||||||
|
expect(component.nodeEntry).toBe(node);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should render close viewer button if it is not a shared link', (done) => {
|
||||||
|
fixture.detectChanges();
|
||||||
|
fixture.whenStable().then(() => {
|
||||||
|
fixture.detectChanges();
|
||||||
|
expect(element.querySelector('[data-automation-id="adf-toolbar-back"]')).toBeDefined();
|
||||||
|
expect(element.querySelector('[data-automation-id="adf-toolbar-back"]')).not.toBeNull();
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not render close viewer button if it is a shared link', (done) => {
|
||||||
|
spyOn(component['sharedLinksApi'], 'getSharedLink')
|
||||||
|
.and.returnValue(Promise.reject({}));
|
||||||
|
|
||||||
|
component.sharedLinkId = 'the-Shared-Link-id';
|
||||||
|
component.mimeType = null;
|
||||||
|
|
||||||
|
component.ngOnChanges();
|
||||||
|
fixture.whenStable().then(() => {
|
||||||
|
fixture.detectChanges();
|
||||||
|
expect(element.querySelector('[data-automation-id="adf-toolbar-back"]')).toBeNull();
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('Base component', () => {
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
component.mimeType = 'application/pdf';
|
||||||
|
component.nodeId = 'id1';
|
||||||
|
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('SideBar Test', () => {
|
||||||
|
|
||||||
|
it('should NOT display sidebar if is not allowed', (done) => {
|
||||||
|
component.showRightSidebar = true;
|
||||||
|
component.allowRightSidebar = false;
|
||||||
|
fixture.detectChanges();
|
||||||
|
|
||||||
|
fixture.whenStable().then(() => {
|
||||||
|
const sidebar = element.querySelector('#adf-right-sidebar');
|
||||||
|
expect(sidebar).toBeNull();
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should display sidebar on the right side', (done) => {
|
||||||
|
component.allowRightSidebar = true;
|
||||||
|
component.showRightSidebar = true;
|
||||||
|
fixture.detectChanges();
|
||||||
|
|
||||||
|
fixture.whenStable().then(() => {
|
||||||
|
const sidebar = element.querySelector('#adf-right-sidebar');
|
||||||
|
expect(getComputedStyle(sidebar).order).toEqual('4');
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should NOT display left sidebar if is not allowed', (done) => {
|
||||||
|
component.showLeftSidebar = true;
|
||||||
|
component.allowLeftSidebar = false;
|
||||||
|
fixture.detectChanges();
|
||||||
|
|
||||||
|
fixture.whenStable().then(() => {
|
||||||
|
const sidebar = element.querySelector('#adf-left-sidebar');
|
||||||
|
expect(sidebar).toBeNull();
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should display sidebar on the left side', (done) => {
|
||||||
|
component.allowLeftSidebar = true;
|
||||||
|
component.showLeftSidebar = true;
|
||||||
|
fixture.detectChanges();
|
||||||
|
|
||||||
|
fixture.whenStable().then(() => {
|
||||||
|
const sidebar = element.querySelector('#adf-left-sidebar');
|
||||||
|
expect(getComputedStyle(sidebar).order).toEqual('1');
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('View', () => {
|
||||||
|
|
||||||
|
describe('Overlay mode true', () => {
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
component.overlayMode = true;
|
||||||
|
component.fileName = 'fake-test-file.pdf';
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should header be present if is overlay mode', () => {
|
||||||
|
expect(element.querySelector('.adf-alfresco-viewer-toolbar')).not.toBeNull();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should Name File be present if is overlay mode ', (done) => {
|
||||||
|
component.ngOnChanges();
|
||||||
|
fixture.detectChanges();
|
||||||
|
fixture.whenStable().then(() => {
|
||||||
|
fixture.detectChanges();
|
||||||
|
expect(element.querySelector('#adf-alfresco-viewer-display-name').textContent).toEqual('fake-test-file.pdf');
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should Close button be present if overlay mode', (done) => {
|
||||||
|
fixture.detectChanges();
|
||||||
|
fixture.whenStable().then(() => {
|
||||||
|
fixture.detectChanges();
|
||||||
|
expect(element.querySelector('.adf-alfresco-viewer-close-button')).not.toBeNull();
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should Click on close button hide the viewer', (done) => {
|
||||||
|
const closeButton: any = element.querySelector('.adf-alfresco-viewer-close-button');
|
||||||
|
closeButton.click();
|
||||||
|
fixture.detectChanges();
|
||||||
|
|
||||||
|
fixture.whenStable().then(() => {
|
||||||
|
expect(element.querySelector('.adf-alfresco-viewer-content')).toBeNull();
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should Esc button hide the viewer', (done) => {
|
||||||
|
EventMock.keyDown(27);
|
||||||
|
|
||||||
|
fixture.detectChanges();
|
||||||
|
|
||||||
|
fixture.whenStable().then(() => {
|
||||||
|
expect(element.querySelector('.adf-alfresco-viewer-content')).toBeNull();
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not close the viewer on Escape event if dialog was opened', (done) => {
|
||||||
|
const event = new KeyboardEvent('keydown', {
|
||||||
|
bubbles: true,
|
||||||
|
keyCode: 27
|
||||||
|
} as KeyboardEventInit);
|
||||||
|
|
||||||
|
const dialogRef = dialog.open(DummyDialogComponent);
|
||||||
|
|
||||||
|
dialogRef.afterClosed().subscribe(() => {
|
||||||
|
EventMock.keyDown(27);
|
||||||
|
fixture.detectChanges();
|
||||||
|
expect(element.querySelector('.adf-alfresco-viewer-content')).toBeNull();
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
|
||||||
|
fixture.detectChanges();
|
||||||
|
|
||||||
|
document.body.dispatchEvent(event);
|
||||||
|
fixture.detectChanges();
|
||||||
|
expect(element.querySelector('.adf-alfresco-viewer-content')).not.toBeNull();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('Overlay mode false', () => {
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
component.overlayMode = false;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should Esc button not hide the viewer if is not overlay mode', (done) => {
|
||||||
|
EventMock.keyDown(27);
|
||||||
|
|
||||||
|
fixture.detectChanges();
|
||||||
|
|
||||||
|
fixture.whenStable().then(() => {
|
||||||
|
expect(element.querySelector('.adf-alfresco-viewer-content')).not.toBeNull();
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('Attribute', () => {
|
||||||
|
|
||||||
|
it('should FileNodeId present not thrown any error ', () => {
|
||||||
|
component.showViewer = true;
|
||||||
|
component.nodeId = 'file-node-id';
|
||||||
|
|
||||||
|
expect(() => {
|
||||||
|
component.ngOnChanges();
|
||||||
|
}).not.toThrow();
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
it('should showViewer default value be true', () => {
|
||||||
|
expect(component.showViewer).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should viewer be hide if showViewer value is false', () => {
|
||||||
|
component.showViewer = false;
|
||||||
|
|
||||||
|
fixture.detectChanges();
|
||||||
|
expect(element.querySelector('.adf-alfresco-viewer-content')).toBeNull();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('Events', () => {
|
||||||
|
|
||||||
|
it('should update version when emitted by image-viewer and user has update permissions', () => {
|
||||||
|
spyOn(uploadService, 'uploadFilesInTheQueue').and.callFake(() => {
|
||||||
|
});
|
||||||
|
spyOn(uploadService, 'addToQueue');
|
||||||
|
component.readOnly = false;
|
||||||
|
component.nodeEntry = new NodeEntry({
|
||||||
|
entry: {
|
||||||
|
name: 'fakeImage.png',
|
||||||
|
id: '12',
|
||||||
|
content: {mimeType: 'img/png'}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
const data = atob('iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5ErkJggg==');
|
||||||
|
const fakeBlob = new Blob([data], {type: 'image/png'});
|
||||||
|
const newImageFile: File = new File([fakeBlob], component?.nodeEntry?.entry?.name, {type: component?.nodeEntry?.entry?.content?.mimeType});
|
||||||
|
const newFile = new FileModel(
|
||||||
|
newImageFile,
|
||||||
|
{
|
||||||
|
majorVersion: false,
|
||||||
|
newVersion: true,
|
||||||
|
parentId: component?.nodeEntry?.entry?.parentId,
|
||||||
|
nodeType: component?.nodeEntry?.entry?.content?.mimeType
|
||||||
|
},
|
||||||
|
component.nodeEntry.entry?.id
|
||||||
|
);
|
||||||
|
component.onSubmitFile(fakeBlob);
|
||||||
|
fixture.detectChanges();
|
||||||
|
|
||||||
|
expect(uploadService.addToQueue).toHaveBeenCalledWith(...[newFile]);
|
||||||
|
expect(uploadService.uploadFilesInTheQueue).toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not update version when emitted by image-viewer and user doesn`t have update permissions', () => {
|
||||||
|
spyOn(uploadService, 'uploadFilesInTheQueue').and.callFake(() => {
|
||||||
|
});
|
||||||
|
component.readOnly = true;
|
||||||
|
component.nodeEntry = new NodeEntry({
|
||||||
|
entry: {
|
||||||
|
name: 'fakeImage.png',
|
||||||
|
id: '12',
|
||||||
|
content: {mimeType: 'img/png'}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
const data = atob('iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5ErkJggg==');
|
||||||
|
const fakeBlob = new Blob([data], {type: 'image/png'});
|
||||||
|
component.onSubmitFile(fakeBlob);
|
||||||
|
fixture.detectChanges();
|
||||||
|
|
||||||
|
expect(uploadService.uploadFilesInTheQueue).not.toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('Viewer component - Full Screen Mode - Mocking fixture element', () => {
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
fixture = TestBed.createComponent(AlfrescoViewerComponent);
|
||||||
|
element = fixture.nativeElement;
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
|
||||||
|
component.showToolbar = true;
|
||||||
|
component.nodeId = 'fake-node-id';
|
||||||
|
component.mimeType = 'application/pdf';
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should use standard mode', () => {
|
||||||
|
const domElement = jasmine.createSpyObj('el', ['requestFullscreen']);
|
||||||
|
spyOn(fixture.nativeElement, 'querySelector').and.returnValue(domElement);
|
||||||
|
|
||||||
|
component.enterFullScreen();
|
||||||
|
expect(domElement.requestFullscreen).toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should use webkit prefix', () => {
|
||||||
|
const domElement = jasmine.createSpyObj('el', ['webkitRequestFullscreen']);
|
||||||
|
spyOn(fixture.nativeElement, 'querySelector').and.returnValue(domElement);
|
||||||
|
|
||||||
|
component.enterFullScreen();
|
||||||
|
expect(domElement.webkitRequestFullscreen).toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should use moz prefix', () => {
|
||||||
|
const domElement = jasmine.createSpyObj('el', ['mozRequestFullScreen']);
|
||||||
|
spyOn(fixture.nativeElement, 'querySelector').and.returnValue(domElement);
|
||||||
|
|
||||||
|
component.enterFullScreen();
|
||||||
|
expect(domElement.mozRequestFullScreen).toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should use ms prefix', () => {
|
||||||
|
const domElement = jasmine.createSpyObj('el', ['msRequestFullscreen']);
|
||||||
|
spyOn(fixture.nativeElement, 'querySelector').and.returnValue(domElement);
|
||||||
|
|
||||||
|
component.enterFullScreen();
|
||||||
|
expect(domElement.msRequestFullscreen).toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
233
lib/core/src/lib/viewer/components/viewer.component.ts
Normal file
233
lib/core/src/lib/viewer/components/viewer.component.ts
Normal file
@@ -0,0 +1,233 @@
|
|||||||
|
/*!
|
||||||
|
* @license
|
||||||
|
* Copyright 2019 Alfresco Software, Ltd.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import {
|
||||||
|
Component,
|
||||||
|
ContentChild,
|
||||||
|
ElementRef,
|
||||||
|
EventEmitter,
|
||||||
|
HostListener,
|
||||||
|
Input,
|
||||||
|
OnDestroy,
|
||||||
|
OnInit,
|
||||||
|
Output,
|
||||||
|
TemplateRef,
|
||||||
|
ViewEncapsulation
|
||||||
|
} from '@angular/core';
|
||||||
|
import { Subject } from 'rxjs';
|
||||||
|
import { MatDialog } from '@angular/material/dialog';
|
||||||
|
import { ViewUtilService } from '../services/view-util.service';
|
||||||
|
import { ViewerToolbarComponent } from './viewer-toolbar.component';
|
||||||
|
import { ViewerOpenWithComponent } from './viewer-open-with.component';
|
||||||
|
import { ViewerMoreActionsComponent } from './viewer-more-actions.component';
|
||||||
|
import { ViewerSidebarComponent } from "./viewer-sidebar.component";
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'adf-viewer',
|
||||||
|
templateUrl: './alfresco-viewer.component.html',
|
||||||
|
styleUrls: ['./alfresco-viewer.component.scss'],
|
||||||
|
host: {class: 'adf-alfresco-viewer'},
|
||||||
|
encapsulation: ViewEncapsulation.None,
|
||||||
|
providers: [ViewUtilService]
|
||||||
|
})
|
||||||
|
export class ViewerComponent implements OnInit, OnDestroy {
|
||||||
|
|
||||||
|
@ContentChild(ViewerToolbarComponent)
|
||||||
|
toolbar: ViewerToolbarComponent;
|
||||||
|
|
||||||
|
@ContentChild(ViewerSidebarComponent)
|
||||||
|
sidebar: ViewerSidebarComponent;
|
||||||
|
|
||||||
|
@ContentChild(ViewerOpenWithComponent)
|
||||||
|
mnuOpenWith: ViewerOpenWithComponent;
|
||||||
|
|
||||||
|
@ContentChild(ViewerMoreActionsComponent)
|
||||||
|
mnuMoreActions: ViewerMoreActionsComponent;
|
||||||
|
|
||||||
|
/** If you want to load an external file that does not come from ACS you
|
||||||
|
* can use this URL to specify where to load the file from.
|
||||||
|
*/
|
||||||
|
@Input()
|
||||||
|
urlFile = '';
|
||||||
|
|
||||||
|
/** Override Content filename. */
|
||||||
|
@Input()
|
||||||
|
fileName: string;
|
||||||
|
|
||||||
|
/** Hide or show the viewer */
|
||||||
|
@Input()
|
||||||
|
showViewer = true;
|
||||||
|
|
||||||
|
/** Allows `back` navigation */
|
||||||
|
@Input()
|
||||||
|
allowGoBack = true;
|
||||||
|
|
||||||
|
/** Hide or show the toolbar */
|
||||||
|
@Input()
|
||||||
|
showToolbar = true;
|
||||||
|
|
||||||
|
/** If `true` then show the Viewer as a full page over the current content.
|
||||||
|
* Otherwise fit inside the parent div.
|
||||||
|
*/
|
||||||
|
@Input()
|
||||||
|
overlayMode = false;
|
||||||
|
|
||||||
|
/** Toggles before/next navigation. You can use the arrow buttons to navigate
|
||||||
|
* between documents in the collection.
|
||||||
|
*/
|
||||||
|
@Input()
|
||||||
|
allowNavigate = false;
|
||||||
|
|
||||||
|
/** Toggles the "before" ("<") button. Requires `allowNavigate` to be enabled. */
|
||||||
|
@Input()
|
||||||
|
canNavigateBefore = true;
|
||||||
|
|
||||||
|
/** Toggles the next (">") button. Requires `allowNavigate` to be enabled. */
|
||||||
|
@Input()
|
||||||
|
canNavigateNext = true;
|
||||||
|
|
||||||
|
/** Allow the left the sidebar. */
|
||||||
|
@Input()
|
||||||
|
allowLeftSidebar = false;
|
||||||
|
|
||||||
|
/** Allow the right sidebar. */
|
||||||
|
@Input()
|
||||||
|
allowRightSidebar = false;
|
||||||
|
|
||||||
|
/** Toggles right sidebar visibility. Requires `allowRightSidebar` to be set to `true`. */
|
||||||
|
@Input()
|
||||||
|
showRightSidebar = false;
|
||||||
|
|
||||||
|
/** Toggles left sidebar visibility. Requires `allowLeftSidebar` to be set to `true`. */
|
||||||
|
@Input()
|
||||||
|
showLeftSidebar = false;
|
||||||
|
|
||||||
|
/** The template for the right sidebar. The template context contains the loaded node data. */
|
||||||
|
@Input()
|
||||||
|
sidebarRightTemplate: TemplateRef<any> = null;
|
||||||
|
|
||||||
|
/** The template for the left sidebar. The template context contains the loaded node data. */
|
||||||
|
@Input()
|
||||||
|
sidebarLeftTemplate: TemplateRef<any> = null;
|
||||||
|
|
||||||
|
/** Emitted when the shared link used is not valid. */
|
||||||
|
@Output()
|
||||||
|
invalidSharedLink = new EventEmitter();
|
||||||
|
|
||||||
|
/** Emitted when user clicks 'Navigate Before' ("<") button. */
|
||||||
|
@Output()
|
||||||
|
navigateBefore = new EventEmitter<MouseEvent | KeyboardEvent>();
|
||||||
|
|
||||||
|
/** Emitted when user clicks 'Navigate Next' (">") button. */
|
||||||
|
@Output()
|
||||||
|
navigateNext = new EventEmitter<MouseEvent | KeyboardEvent>();
|
||||||
|
|
||||||
|
/** Emitted when the viewer close */
|
||||||
|
@Output()
|
||||||
|
close = new EventEmitter<boolean>();
|
||||||
|
|
||||||
|
private onDestroy$ = new Subject<boolean>();
|
||||||
|
|
||||||
|
isLoading: boolean;
|
||||||
|
urlFileContent: string;
|
||||||
|
viewerType: any;
|
||||||
|
mimeType: string;
|
||||||
|
readOnly: boolean = true;
|
||||||
|
|
||||||
|
sidebarRightTemplateContext: { node: Node } = {node: null};
|
||||||
|
sidebarLeftTemplateContext: { node: Node } = {node: null};
|
||||||
|
|
||||||
|
constructor(private el: ElementRef,
|
||||||
|
public dialog: MatDialog) {
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
onNavigateBeforeClick(event: MouseEvent | KeyboardEvent) {
|
||||||
|
this.navigateBefore.next(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
onNavigateNextClick(event: MouseEvent | KeyboardEvent) {
|
||||||
|
this.navigateNext.next(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* close the viewer
|
||||||
|
*/
|
||||||
|
onClose() {
|
||||||
|
this.showViewer = false;
|
||||||
|
this.close.emit(this.showViewer);
|
||||||
|
}
|
||||||
|
|
||||||
|
toggleRightSidebar() {
|
||||||
|
this.showRightSidebar = !this.showRightSidebar;
|
||||||
|
}
|
||||||
|
|
||||||
|
toggleLeftSidebar() {
|
||||||
|
this.showLeftSidebar = !this.showLeftSidebar;
|
||||||
|
}
|
||||||
|
|
||||||
|
@HostListener('document:keyup', ['$event'])
|
||||||
|
handleKeyboardEvent(event: KeyboardEvent) {
|
||||||
|
if (event && event.defaultPrevented) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const key = event.keyCode;
|
||||||
|
|
||||||
|
// Left arrow
|
||||||
|
if (key === 37 && this.canNavigateBefore) {
|
||||||
|
event.preventDefault();
|
||||||
|
this.onNavigateBeforeClick(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Right arrow
|
||||||
|
if (key === 39 && this.canNavigateNext) {
|
||||||
|
event.preventDefault();
|
||||||
|
this.onNavigateNextClick(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ctrl+F
|
||||||
|
if (key === 70 && event.ctrlKey) {
|
||||||
|
event.preventDefault();
|
||||||
|
this.enterFullScreen();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Triggers full screen mode with a main content area displayed.
|
||||||
|
*/
|
||||||
|
enterFullScreen(): void {
|
||||||
|
const container = this.el.nativeElement.querySelector('.adf-viewer__fullscreen-container');
|
||||||
|
if (container) {
|
||||||
|
if (container.requestFullscreen) {
|
||||||
|
container.requestFullscreen();
|
||||||
|
} else if (container.webkitRequestFullscreen) {
|
||||||
|
container.webkitRequestFullscreen();
|
||||||
|
} else if (container.mozRequestFullScreen) {
|
||||||
|
container.mozRequestFullScreen();
|
||||||
|
} else if (container.msRequestFullscreen) {
|
||||||
|
container.msRequestFullscreen();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnDestroy() {
|
||||||
|
this.onDestroy$.next(true);
|
||||||
|
this.onDestroy$.complete();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@@ -31,6 +31,7 @@ export * from './components/viewer-sidebar.component';
|
|||||||
export * from './components/viewer-toolbar.component';
|
export * from './components/viewer-toolbar.component';
|
||||||
export * from './components/viewer-toolbar-actions.component';
|
export * from './components/viewer-toolbar-actions.component';
|
||||||
export * from './components/viewer-render.component';
|
export * from './components/viewer-render.component';
|
||||||
|
export * from './components/viewer.component';
|
||||||
|
|
||||||
export * from './directives/viewer-extension.directive';
|
export * from './directives/viewer-extension.directive';
|
||||||
|
|
||||||
|
@@ -43,6 +43,7 @@ import { ViewerExtensionDirective } from './directives/viewer-extension.directiv
|
|||||||
import { ViewerToolbarActionsComponent } from './components/viewer-toolbar-actions.component';
|
import { ViewerToolbarActionsComponent } from './components/viewer-toolbar-actions.component';
|
||||||
import { DirectiveModule } from '../directives/directive.module';
|
import { DirectiveModule } from '../directives/directive.module';
|
||||||
import { A11yModule } from '@angular/cdk/a11y';
|
import { A11yModule } from '@angular/cdk/a11y';
|
||||||
|
import { ViewerComponent } from "./components/viewer.component";
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
imports: [
|
imports: [
|
||||||
@@ -73,7 +74,8 @@ import { A11yModule } from '@angular/cdk/a11y';
|
|||||||
ViewerSidebarComponent,
|
ViewerSidebarComponent,
|
||||||
ViewerOpenWithComponent,
|
ViewerOpenWithComponent,
|
||||||
ViewerMoreActionsComponent,
|
ViewerMoreActionsComponent,
|
||||||
ViewerToolbarActionsComponent
|
ViewerToolbarActionsComponent,
|
||||||
|
ViewerComponent
|
||||||
],
|
],
|
||||||
exports: [
|
exports: [
|
||||||
ViewerRenderComponent,
|
ViewerRenderComponent,
|
||||||
@@ -90,7 +92,8 @@ import { A11yModule } from '@angular/cdk/a11y';
|
|||||||
ViewerSidebarComponent,
|
ViewerSidebarComponent,
|
||||||
ViewerOpenWithComponent,
|
ViewerOpenWithComponent,
|
||||||
ViewerMoreActionsComponent,
|
ViewerMoreActionsComponent,
|
||||||
ViewerToolbarActionsComponent
|
ViewerToolbarActionsComponent,
|
||||||
|
ViewerComponent
|
||||||
]
|
]
|
||||||
})
|
})
|
||||||
export class ViewerModule {
|
export class ViewerModule {
|
||||||
|
Reference in New Issue
Block a user