mirror of
https://github.com/Alfresco/alfresco-ng2-components.git
synced 2025-06-30 18:15:11 +00:00
[ADF-1412] Viewer enhancements (#2873)
* collection navigation support for Viewer * code cleanup * full screen mode support * keyboard shortcuts * zooming scale label * layout fixes * test fixes * image toolbar with basic tranformations * test fixes * test fixes
This commit is contained in:
parent
d2d635b94d
commit
08f2cc9236
@ -65,6 +65,10 @@ Using with file url:
|
||||
| showSidebar | boolean | false | Toggles sidebar visibility. Requires `allowSidebar` to be set to `true`. |
|
||||
| sidebarPosition | string | right | The position of the sidebar. Can be `left` or `right`. |
|
||||
| sidebarTemplate | TemplateRef<any> | null | The template intended to be used as a sidebar. The template context contains the loaded node data. |
|
||||
| allowNavigate | boolean | false | Toggle before/next navigation, arrow buttons to navigate between multiple documents in the collection. |
|
||||
| canNavigateBefore | boolean | true | Toggle the "before" ("<") button. Requires `allowNavigate` to be enabled. |
|
||||
| canNavigateNext | boolean | true | Toggle the next (">") button. Requires `allowNavigate` to be enabled.|
|
||||
| allowFullScreen | boolean | true | Toggle the 'Full Screen' feature. |
|
||||
|
||||
### Events
|
||||
|
||||
@ -74,6 +78,17 @@ Using with file url:
|
||||
| download | any | Yes | Raised when user clicks the 'Download' button. |
|
||||
| print | any | Yes | Raised when user clicks the 'Print' button. |
|
||||
| share | any | Yes | Raised when user clicks the 'Share' button. |
|
||||
| navigateBefore | any | No | Raised when user clicks 'Navigate Before' ("<") button. |
|
||||
| navigateNext | any | No | Raised when user clicks 'Navigate Next' (">") button. |
|
||||
|
||||
### Keyboard shortcuts
|
||||
|
||||
| Name | Description |
|
||||
| --- | --- |
|
||||
| Esc | Close the viewer (overlay mode only). |
|
||||
| Left | Invoke 'Navigate before' action. |
|
||||
| Right | Invoke 'Navigate next' action. |
|
||||
| Ctrl+F | Activate full-screen mode. |
|
||||
|
||||
## Details
|
||||
|
||||
|
@ -187,7 +187,8 @@
|
||||
"PRINT": "Print",
|
||||
"SHARE": "Share",
|
||||
"MORE_ACTIONS": "More actions",
|
||||
"INFO": "Info"
|
||||
"INFO": "Info",
|
||||
"FULLSCREEN": "Activate full-screen mode"
|
||||
},
|
||||
"ARIA": {
|
||||
"PREVIOUS_PAGE": "Previous page",
|
||||
|
@ -24,6 +24,13 @@ export class EventMock {
|
||||
document.dispatchEvent(event);
|
||||
}
|
||||
|
||||
static keyUp(key: any) {
|
||||
let event: any = document.createEvent('Event');
|
||||
event.keyCode = key;
|
||||
event.initEvent('keyup');
|
||||
document.dispatchEvent(event);
|
||||
}
|
||||
|
||||
static resizeMobileView() {
|
||||
// todo: no longer compiles with TS 2.0.2 as innerWidth/innerHeight are readonly fields
|
||||
/*
|
||||
|
@ -17,9 +17,11 @@
|
||||
@import '../toolbar/toolbar.component';
|
||||
@import '../userinfo/components/user-info.component';
|
||||
@import '../viewer/components/viewer.component';
|
||||
@import '../viewer/components/pdfViewer.component';
|
||||
@import '../viewer/components/txtViewer.component';
|
||||
@import '../viewer/components/imgViewer.component';
|
||||
@import '../form/components/form.component';
|
||||
@import '../sidebar/sidebar-action-menu.component';
|
||||
@import '../viewer/components/pdfViewer.component';
|
||||
|
||||
@mixin adf-core-theme($theme) {
|
||||
@include adf-colors-theme($theme);
|
||||
@ -40,6 +42,8 @@
|
||||
@include adf-userinfo-theme($theme);
|
||||
@include adf-viewer-theme($theme);
|
||||
@include adf-pdf-viewer-theme($theme);
|
||||
@include adf-image-viewer-theme($theme);
|
||||
@include adf-text-viewer-theme($theme);
|
||||
@include adf-form-component-theme($theme);
|
||||
@include adf-sidebar-action-menu-theme($theme);
|
||||
}
|
||||
|
@ -1,3 +1,27 @@
|
||||
<div class="image-container">
|
||||
<div class="image-container" [ngStyle]="{ transform: transform }">
|
||||
<img id="viewer-image" [src]="urlFile" [alt]="nameFile" />
|
||||
</div>
|
||||
|
||||
<div class="adf-image-viewer__toolbar" *ngIf="showToolbar">
|
||||
<adf-toolbar>
|
||||
<button mat-icon-button (click)="zoomIn()">
|
||||
<mat-icon>zoom_in</mat-icon>
|
||||
</button>
|
||||
|
||||
<button mat-icon-button (click)="zoomOut()">
|
||||
<mat-icon>zoom_out</mat-icon>
|
||||
</button>
|
||||
|
||||
<button mat-icon-button (click)="rotateLeft()">
|
||||
<mat-icon>rotate_left</mat-icon>
|
||||
</button>
|
||||
|
||||
<button mat-icon-button (click)="rotateRight()">
|
||||
<mat-icon>rotate_right</mat-icon>
|
||||
</button>
|
||||
|
||||
<button mat-icon-button (click)="flip()">
|
||||
<mat-icon>flip</mat-icon>
|
||||
</button>
|
||||
</adf-toolbar>
|
||||
</div>
|
||||
|
@ -1,14 +1,33 @@
|
||||
.adf-img-viewer {
|
||||
.image-container {
|
||||
display: flex;
|
||||
flex: 1;
|
||||
text-align: center;
|
||||
flex-direction: row;
|
||||
justify-content: center;
|
||||
height: 90vh;
|
||||
img {
|
||||
width: 100%;
|
||||
object-fit: contain;
|
||||
@mixin adf-image-viewer-theme($theme) {
|
||||
.adf-image-viewer {
|
||||
.image-container {
|
||||
display: flex;
|
||||
flex: 1;
|
||||
text-align: center;
|
||||
flex-direction: row;
|
||||
justify-content: center;
|
||||
height: 90vh;
|
||||
img {
|
||||
width: 100%;
|
||||
object-fit: contain;
|
||||
}
|
||||
}
|
||||
|
||||
&__toolbar {
|
||||
position: absolute;
|
||||
bottom: 5px;
|
||||
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
|
||||
.adf-toolbar .mat-toolbar {
|
||||
max-height: 48px;
|
||||
background-color: mat-color($primary, default-contrast, 1);
|
||||
border-width: 0;
|
||||
border-radius: 2px;
|
||||
box-shadow: 0 2px 2px 0 rgba(0, 0, 0, 0.24), 0 0 2px 0 rgba(0, 0, 0, 0.12);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -21,6 +21,8 @@ import { AlfrescoApiService } from '../../services/alfresco-api.service';
|
||||
import { AuthenticationService } from '../../services/authentication.service';
|
||||
import { ContentService } from '../../services/content.service';
|
||||
import { SettingsService } from '../../services/settings.service';
|
||||
import { MaterialModule } from '../../material.module';
|
||||
import { ToolbarModule } from '../../toolbar/toolbar.module';
|
||||
|
||||
import { ImgViewerComponent } from './imgViewer.component';
|
||||
|
||||
@ -38,7 +40,10 @@ describe('Test Img viewer component ', () => {
|
||||
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
|
||||
imports: [
|
||||
MaterialModule,
|
||||
ToolbarModule
|
||||
],
|
||||
declarations: [ImgViewerComponent],
|
||||
providers: [
|
||||
SettingsService,
|
||||
|
@ -22,11 +22,14 @@ import { ContentService } from '../../services/content.service';
|
||||
selector: 'adf-img-viewer',
|
||||
templateUrl: './imgViewer.component.html',
|
||||
styleUrls: ['./imgViewer.component.scss'],
|
||||
host: { 'class': 'adf-img-viewer' },
|
||||
host: { 'class': 'adf-image-viewer' },
|
||||
encapsulation: ViewEncapsulation.None
|
||||
})
|
||||
export class ImgViewerComponent implements OnChanges {
|
||||
|
||||
@Input()
|
||||
showToolbar = true;
|
||||
|
||||
@Input()
|
||||
urlFile: string;
|
||||
|
||||
@ -36,6 +39,14 @@ export class ImgViewerComponent implements OnChanges {
|
||||
@Input()
|
||||
nameFile: string;
|
||||
|
||||
rotate: number = 0;
|
||||
scaleX: number = 1.0;
|
||||
scaleY: number = 1.0;
|
||||
|
||||
get transform(): string {
|
||||
return `scale(${this.scaleX}, ${this.scaleY}) rotate(${this.rotate}deg)`
|
||||
}
|
||||
|
||||
constructor(private contentService: ContentService) {}
|
||||
|
||||
ngOnChanges(changes: SimpleChanges) {
|
||||
@ -48,4 +59,31 @@ export class ImgViewerComponent implements OnChanges {
|
||||
throw new Error('Attribute urlFile or blobFile is required');
|
||||
}
|
||||
}
|
||||
|
||||
zoomIn() {
|
||||
const ratio = +((this.scaleX + 0.2).toFixed(1));
|
||||
this.scaleX = this.scaleY = ratio;
|
||||
}
|
||||
|
||||
zoomOut() {
|
||||
let ratio = +((this.scaleX - 0.2).toFixed(1));
|
||||
if (ratio < 0.2) {
|
||||
ratio = 0.2;
|
||||
}
|
||||
this.scaleX = this.scaleY = ratio;
|
||||
}
|
||||
|
||||
rotateLeft() {
|
||||
const angle = this.rotate - 90;
|
||||
this.rotate = Math.abs(angle) < 360 ? angle : 0;
|
||||
}
|
||||
|
||||
rotateRight() {
|
||||
const angle = this.rotate + 90;
|
||||
this.rotate = Math.abs(angle) < 360 ? angle : 0;
|
||||
}
|
||||
|
||||
flip() {
|
||||
this.scaleX *= -1;
|
||||
}
|
||||
}
|
||||
|
@ -44,7 +44,9 @@
|
||||
<span>{{ 'ADF_VIEWER.PAGE_LABEL.OF' | translate }} {{ totalPages }}</span>
|
||||
</div>
|
||||
|
||||
<adf-toolbar-divider></adf-toolbar-divider>
|
||||
<div class="adf-pdf-viewer__toolbar-page-scale">
|
||||
{{ currentScaleText }}
|
||||
</div>
|
||||
|
||||
<button
|
||||
id="viewer-zoom-in-button"
|
||||
|
@ -1,4 +1,6 @@
|
||||
@mixin adf-pdf-viewer-theme($theme) {
|
||||
$foreground: map-get($theme, foreground);
|
||||
|
||||
.adf-pdf-viewer {
|
||||
.loader-container {
|
||||
display: -webkit-box; /* OLD - iOS 6-, Safari 3.1-6 */
|
||||
@ -39,8 +41,11 @@
|
||||
font-size: 14px;
|
||||
|
||||
& > input {
|
||||
border: 1px solid mat-color($foreground, text, 0.07);
|
||||
font-size: 14px;
|
||||
padding: 4px 0;
|
||||
padding: 0;
|
||||
height: 24px;
|
||||
line-height: 24px;
|
||||
text-align: right;
|
||||
width: 33px;
|
||||
margin-right: 4px;
|
||||
@ -48,6 +53,18 @@
|
||||
outline-color: gray;
|
||||
}
|
||||
}
|
||||
|
||||
&-page-scale {
|
||||
cursor: default;
|
||||
width: 79px;
|
||||
height: 24px;
|
||||
font-size: 14px;
|
||||
border: 1px solid mat-color($foreground, text, 0.07);
|
||||
text-align: center;
|
||||
line-height: 24px;
|
||||
margin-left: 4px;
|
||||
margin-right: 4px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -56,13 +56,17 @@ export class PdfViewerComponent implements OnChanges, OnDestroy {
|
||||
loadingPercent: number;
|
||||
pdfViewer: any;
|
||||
currentScaleMode: string = 'auto';
|
||||
currentScale: number;
|
||||
currentScale: number = 1;
|
||||
|
||||
MAX_AUTO_SCALE: number = 1.25;
|
||||
DEFAULT_SCALE_DELTA: number = 1.1;
|
||||
MIN_SCALE: number = 0.25;
|
||||
MAX_SCALE: number = 10.0;
|
||||
|
||||
get currentScaleText(): string {
|
||||
return Math.round(this.currentScale * 100) + '%';
|
||||
}
|
||||
|
||||
constructor(private renderingQueueServices: RenderingQueueServices,
|
||||
private logService: LogService) {
|
||||
// needed to preserve "this" context when setting as a global document event listener
|
||||
@ -163,21 +167,21 @@ export class PdfViewerComponent implements OnChanges, OnDestroy {
|
||||
let documentContainer = document.getElementById('viewer-pdf-container');
|
||||
|
||||
let widthContainer;
|
||||
let heigthContainer;
|
||||
let heightContainer;
|
||||
|
||||
if (viewerContainer && viewerContainer.clientWidth <= documentContainer.clientWidth) {
|
||||
widthContainer = viewerContainer.clientWidth;
|
||||
heigthContainer = viewerContainer.clientHeight;
|
||||
heightContainer = viewerContainer.clientHeight;
|
||||
} else {
|
||||
widthContainer = documentContainer.clientWidth;
|
||||
heigthContainer = documentContainer.clientHeight;
|
||||
heightContainer = documentContainer.clientHeight;
|
||||
}
|
||||
|
||||
let currentPage = this.pdfViewer._pages[this.pdfViewer._currentPageNumber - 1];
|
||||
|
||||
let padding = 20;
|
||||
let pageWidthScale = (widthContainer - padding) / currentPage.width * currentPage.scale;
|
||||
let pageHeightScale = (heigthContainer - padding) / currentPage.width * currentPage.scale;
|
||||
let pageHeightScale = (heightContainer - padding) / currentPage.width * currentPage.scale;
|
||||
|
||||
let scale;
|
||||
|
||||
@ -231,7 +235,7 @@ export class PdfViewerComponent implements OnChanges, OnDestroy {
|
||||
}
|
||||
|
||||
/**
|
||||
* method to check if the request scale of the page is the same for avoid unuseful re-rendering
|
||||
* Check if the request scale of the page is the same for avoid useless re-rendering
|
||||
*
|
||||
* @param {number} oldScale - old scale page
|
||||
* @param {number} newScale - new scale page
|
||||
@ -243,7 +247,7 @@ export class PdfViewerComponent implements OnChanges, OnDestroy {
|
||||
}
|
||||
|
||||
/**
|
||||
* method to check if is a land scape view
|
||||
* Check if is a land scape view
|
||||
*
|
||||
* @param {number} width
|
||||
* @param {number} height
|
||||
|
@ -1,6 +1,9 @@
|
||||
.adf-txt-viewer {
|
||||
background-color: white;
|
||||
width: 100vw;
|
||||
overflow: hidden;
|
||||
overflow-y: scroll;
|
||||
@mixin adf-text-viewer-theme($theme) {
|
||||
$background: map-get($theme, background);
|
||||
|
||||
.adf-txt-viewer {
|
||||
background-color: mat-color($background, background);
|
||||
overflow: hidden;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
}
|
||||
|
@ -63,6 +63,15 @@
|
||||
<mat-icon>share</mat-icon>
|
||||
</button>
|
||||
|
||||
<button
|
||||
*ngIf="allowFullScreen"
|
||||
mat-icon-button
|
||||
matTooltip="{{ 'ADF_VIEWER.ACTIONS.FULLSCREEN' | translate }}"
|
||||
data-automation-id="toolbar-fullscreen"
|
||||
(click)="enterFullScreen()">
|
||||
<mat-icon>fullscreen</mat-icon>
|
||||
</button>
|
||||
|
||||
<ng-container *ngIf="mnuMoreActions">
|
||||
<button
|
||||
mat-icon-button
|
||||
@ -104,7 +113,7 @@
|
||||
<div *ngIf="!isLoading" fxLayout="row" fxFlex="1 1 auto">
|
||||
|
||||
<ng-container *ngIf="allowSidebar && showSidebar">
|
||||
<div class="adf-viewer__sidebar" fxFlexOrder="{{sidebarPosition === 'left'? 1: 2 }}">
|
||||
<div class="adf-viewer__sidebar" fxFlexOrder="{{sidebarPosition === 'left'? 1 : 4 }}">
|
||||
<ng-container *ngIf="sidebarTemplate">
|
||||
<ng-container *ngTemplateOutlet="sidebarTemplate;context:sidebarTemplateContext"></ng-container>
|
||||
</ng-container>
|
||||
@ -112,10 +121,17 @@
|
||||
</div>
|
||||
</ng-container>
|
||||
|
||||
<div fxFlexOrder="{{sidebarPosition !== 'left'? 1: 2}}" fxFlex="1 1 auto">
|
||||
<div class="adf-viewer-layout-content">
|
||||
<div class="adf-viewer-content-container" [ngSwitch]="viewerType">
|
||||
<ng-container *ngIf="allowNavigate && canNavigateBefore">
|
||||
<div class="navigate-before">
|
||||
<button mat-mini-fab color="primary" (click)="onNavigateBeforeClick()">
|
||||
<mat-icon>navigate_before</mat-icon>
|
||||
</button>
|
||||
</div>
|
||||
</ng-container>
|
||||
|
||||
<div class="adf-viewer-main" fxFlexOrder="{{sidebarPosition !== 'left'? 1 : 4}}" fxFlex="1 1 auto">
|
||||
<div class="adf-viewer-layout-content adf-viewer__fullscreen-container">
|
||||
<div class="adf-viewer-content-container" [ngSwitch]="viewerType">
|
||||
<ng-container *ngSwitchCase="'pdf'">
|
||||
<adf-pdf-viewer [blobFile]="blobFile" [urlFile]="urlFileContent" [nameFile]="displayName"></adf-pdf-viewer>
|
||||
</ng-container>
|
||||
@ -142,10 +158,17 @@
|
||||
<ng-container *ngSwitchDefault>
|
||||
<adf-viewer-unknown-format></adf-viewer-unknown-format>
|
||||
</ng-container>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<ng-container *ngIf="allowNavigate && canNavigateNext">
|
||||
<div class="navigate-next" fxFlexOrder="{{sidebarPosition !== 'left' ? 3 : 4}}">
|
||||
<button mat-mini-fab color="primary" (click)="onNavigateNextClick()">
|
||||
<mat-icon>navigate_next</mat-icon>
|
||||
</button>
|
||||
</div>
|
||||
</ng-container>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -11,6 +11,30 @@
|
||||
|
||||
.adf-viewer {
|
||||
|
||||
.navigate-before {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
order: 1;
|
||||
padding-left: 2px;
|
||||
padding-right: 4px;
|
||||
background-color: mat-color($background, background);
|
||||
}
|
||||
|
||||
&-main {
|
||||
width: 0;
|
||||
}
|
||||
|
||||
.navigate-next {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
order: 3;
|
||||
padding-left: 4px;
|
||||
padding-right: 2px;
|
||||
background-color: mat-color($background, background);
|
||||
}
|
||||
|
||||
&__mimeicon {
|
||||
vertical-align: middle;
|
||||
height: 18px;
|
||||
@ -19,7 +43,7 @@
|
||||
|
||||
&-toolbar {
|
||||
.mat-toolbar {
|
||||
background-color: mat-color($primary, default-contrast)
|
||||
background-color: mat-color($primary, default-contrast);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -232,7 +232,7 @@ describe('ViewerComponent', () => {
|
||||
component.sidebarPosition = 'right';
|
||||
fixture.detectChanges();
|
||||
let sidebar = element.querySelector('.adf-viewer__sidebar');
|
||||
expect(getComputedStyle(sidebar).order).toEqual('2');
|
||||
expect(getComputedStyle(sidebar).order).toEqual('4');
|
||||
});
|
||||
|
||||
it('should display sidebar on the right side as fallback', () => {
|
||||
@ -241,11 +241,71 @@ describe('ViewerComponent', () => {
|
||||
component.sidebarPosition = 'unknown-value';
|
||||
fixture.detectChanges();
|
||||
let sidebar = element.querySelector('.adf-viewer__sidebar');
|
||||
expect(getComputedStyle(sidebar).order).toEqual('2');
|
||||
expect(getComputedStyle(sidebar).order).toEqual('4');
|
||||
});
|
||||
|
||||
describe('Full Screen Mode', () => {
|
||||
|
||||
it('should request only if enabled', () => {
|
||||
const domElement = jasmine.createSpyObj('el', ['requestFullscreen']);
|
||||
spyOn(fixture.nativeElement, 'querySelector').and.returnValue(domElement);
|
||||
|
||||
component.allowFullScreen = false;
|
||||
component.enterFullScreen();
|
||||
|
||||
expect(domElement.requestFullscreen).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
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();
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('Toolbar', () => {
|
||||
|
||||
it('should render fullscreen button', () => {
|
||||
component.allowFullScreen = true;
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(element.querySelector('[data-automation-id="toolbar-fullscreen"]')).toBeDefined();
|
||||
});
|
||||
|
||||
it('should not render fullscreen button', () => {
|
||||
component.allowFullScreen = false;
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(element.querySelector('[data-automation-id="toolbar-fullscreen"]')).toBeNull();
|
||||
});
|
||||
|
||||
it('should render default download button', () => {
|
||||
component.allowDownload = true;
|
||||
fixture.detectChanges();
|
||||
@ -397,7 +457,7 @@ describe('ViewerComponent', () => {
|
||||
});
|
||||
|
||||
it('should Esc button hide the viewer', () => {
|
||||
EventMock.keyDown(27);
|
||||
EventMock.keyUp(27);
|
||||
fixture.detectChanges();
|
||||
expect(element.querySelector('.adf-viewer-content')).toBeNull();
|
||||
});
|
||||
|
@ -17,7 +17,7 @@
|
||||
|
||||
import { Location } from '@angular/common';
|
||||
import {
|
||||
Component, ContentChild, EventEmitter, HostListener,
|
||||
Component, ContentChild, EventEmitter, HostListener, ElementRef,
|
||||
Input, OnChanges, Output, SimpleChanges, TemplateRef, ViewEncapsulation
|
||||
} from '@angular/core';
|
||||
import { MinimalNodeEntryEntity } from 'alfresco-js-api';
|
||||
@ -90,6 +90,18 @@ export class ViewerComponent implements OnChanges {
|
||||
@Input()
|
||||
allowShare = false;
|
||||
|
||||
@Input()
|
||||
allowFullScreen = true;
|
||||
|
||||
@Input()
|
||||
allowNavigate = false;
|
||||
|
||||
@Input()
|
||||
canNavigateBefore = true;
|
||||
|
||||
@Input()
|
||||
canNavigateNext = true;
|
||||
|
||||
@Input()
|
||||
allowSidebar = false;
|
||||
|
||||
@ -129,6 +141,12 @@ export class ViewerComponent implements OnChanges {
|
||||
@Output()
|
||||
extensionChange = new EventEmitter<string>();
|
||||
|
||||
@Output()
|
||||
navigateBefore = new EventEmitter();
|
||||
|
||||
@Output()
|
||||
navigateNext = new EventEmitter();
|
||||
|
||||
viewerType = 'unknown';
|
||||
isLoading = false;
|
||||
node: MinimalNodeEntryEntity;
|
||||
@ -143,7 +161,7 @@ export class ViewerComponent implements OnChanges {
|
||||
private extensions = {
|
||||
image: ['png', 'jpg', 'jpeg', 'gif', 'bpm'],
|
||||
media: ['wav', 'mp4', 'mp3', 'webm', 'ogg'],
|
||||
text: ['txt', 'xml', 'js', 'html', 'json'],
|
||||
text: ['txt', 'xml', 'js', 'html', 'json', 'ts'],
|
||||
pdf: ['pdf']
|
||||
};
|
||||
|
||||
@ -155,7 +173,8 @@ export class ViewerComponent implements OnChanges {
|
||||
constructor(private apiService: AlfrescoApiService,
|
||||
private logService: LogService,
|
||||
private location: Location,
|
||||
private renditionService: RenditionsService) {
|
||||
private renditionService: RenditionsService,
|
||||
private el: ElementRef) {
|
||||
}
|
||||
|
||||
isSourceDefined(): boolean {
|
||||
@ -354,6 +373,14 @@ export class ViewerComponent implements OnChanges {
|
||||
}
|
||||
}
|
||||
|
||||
onNavigateBeforeClick() {
|
||||
this.navigateBefore.next();
|
||||
}
|
||||
|
||||
onNavigateNextClick() {
|
||||
this.navigateNext.next();
|
||||
}
|
||||
|
||||
/**
|
||||
* close the viewer
|
||||
*/
|
||||
@ -409,15 +436,35 @@ export class ViewerComponent implements OnChanges {
|
||||
}
|
||||
|
||||
/**
|
||||
* Litener Keyboard Event
|
||||
* Keyboard event listener
|
||||
* @param {KeyboardEvent} event
|
||||
*/
|
||||
@HostListener('document:keydown', ['$event'])
|
||||
@HostListener('document:keyup', ['$event'])
|
||||
handleKeyboardEvent(event: KeyboardEvent) {
|
||||
let key = event.keyCode;
|
||||
const key = event.keyCode;
|
||||
|
||||
// Esc
|
||||
if (key === 27 && this.overlayMode) { // esc
|
||||
this.close();
|
||||
}
|
||||
|
||||
// Left arrow
|
||||
if (key === 37 && this.canNavigateBefore) {
|
||||
event.preventDefault();
|
||||
this.onNavigateBeforeClick();
|
||||
}
|
||||
|
||||
// Right arrow
|
||||
if (key === 39 && this.canNavigateNext) {
|
||||
event.preventDefault();
|
||||
this.onNavigateNextClick();
|
||||
}
|
||||
|
||||
// Ctrl+F
|
||||
if (key === 70 && event.ctrlKey) {
|
||||
event.preventDefault();
|
||||
this.enterFullScreen();
|
||||
}
|
||||
}
|
||||
|
||||
downloadContent() {
|
||||
@ -453,6 +500,26 @@ export class ViewerComponent implements OnChanges {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Triggers full screen mode with a main content area displayed.
|
||||
*/
|
||||
enterFullScreen(): void {
|
||||
if (this.allowFullScreen) {
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private async displayNodeRendition(nodeId: string) {
|
||||
this.isLoading = true;
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user