refactor part 2

This commit is contained in:
eromano
2022-11-22 22:38:53 +01:00
committed by Amedeo Lepore
parent 36ee8c8e34
commit 9b6daeedb7
12 changed files with 306 additions and 108 deletions

View File

@@ -178,13 +178,16 @@
<adf-viewer-render <adf-viewer-render
fxFlexOrder="1" fxFlexOrder="1"
fxFlex="1 1 auto" fxFlex="1 1 auto"
(close)="onClose()"
(submitFile)="onSubmitFile($event)" (submitFile)="onSubmitFile($event)"
[viewerType]="viewerType" [viewerType]="viewerType"
[fileName]="fileName" [fileName]="fileName"
[isLoading]="isLoading" [isLoading]="isLoading"
[allowGoBack]="allowGoBack" [allowGoBack]="allowGoBack"
[urlFile]="urlFileContent" [urlFile]="urlFileContent"
></adf-viewer-render> [tracks]="tracks"
[readOnly]="readOnly">
</adf-viewer-render>
</div> </div>
</div> </div>

View File

@@ -58,10 +58,6 @@
@extend .adf-full-screen; @extend .adf-full-screen;
} }
&-custom-content {
width: 100vw;
}
&__sidebar { &__sidebar {
width: 350px; width: 350px;
display: block; display: block;

View File

@@ -1,30 +1,58 @@
/*!
* @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 { import {
ChangeDetectorRef, ChangeDetectorRef,
Component, ContentChild, Component,
EventEmitter, HostListener, ContentChild,
ElementRef,
EventEmitter,
HostListener,
Input, Input,
Output, Output,
ViewEncapsulation, TemplateRef,
ElementRef, ViewEncapsulation
TemplateRef } from '@angular/core';
} from "@angular/core";
import { ViewUtilService } from "../../../../../core/src/lib/viewer/services/view-util.service";
import { import {
ContentApi, Node, AlfrescoApiService, ContentService,
FileModel,
LogService, Track,
UploadService,
ViewerMoreActionsComponent,
ViewerOpenWithComponent,
ViewerSidebarComponent,
ViewerToolbarComponent,
ViewUtilService
} from "@alfresco/adf-core";
import { fromEvent, Subject } from "rxjs";
import {
ContentApi,
Node,
NodeEntry, NodeEntry,
NodesApi, RenditionEntry, NodesApi,
SharedLinkEntry, RenditionEntry,
SharedlinksApi, Version, SharedlinksApi,
Version,
VersionEntry, VersionEntry,
VersionsApi VersionsApi
} from "@alfresco/js-api"; } from "@alfresco/js-api";
import { AlfrescoApiService, LogService, UploadService } from "../../../../../core/src/lib/services"; import { RenditionViewerService } from "../services/rendition-viewer.service";
import { MatDialog } from "@angular/material/dialog"; import { MatDialog } from "@angular/material/dialog";
import { filter, skipWhile, takeUntil } from "rxjs/operators"; import { filter, skipWhile, takeUntil } from "rxjs/operators";
import { FileModel } from "../../../../../core/src/lib/models";
import { fromEvent, Subject } from "rxjs";
import { RenditionViewerService } from "../services/rendition-viewer.service";
import { ViewerToolbarComponent,ViewerSidebarComponent, ViewerOpenWithComponent,ViewerMoreActionsComponent } from "@alfresco/adf-core";
@Component({ @Component({
selector: 'adf-alfresco-viewer', selector: 'adf-alfresco-viewer',
@@ -159,6 +187,8 @@ export class AlfrescoViewerComponent {
fileName: string; fileName: string;
mimeType: string; mimeType: string;
nodeEntry: NodeEntry; nodeEntry: NodeEntry;
tracks: Track[] = [];
readOnly: boolean = true;
sidebarRightTemplateContext: { node: Node } = {node: null}; sidebarRightTemplateContext: { node: Node } = {node: null};
sidebarLeftTemplateContext: { node: Node } = {node: null}; sidebarLeftTemplateContext: { node: Node } = {node: null};
@@ -191,6 +221,7 @@ export class AlfrescoViewerComponent {
private renditionViewerService: RenditionViewerService, private renditionViewerService: RenditionViewerService,
private viewUtilService: ViewUtilService, private viewUtilService: ViewUtilService,
private logService: LogService, private logService: LogService,
private contentService: ContentService,
private el: ElementRef, private el: ElementRef,
private uploadService: UploadService, private uploadService: UploadService,
public dialog: MatDialog, public dialog: MatDialog,
@@ -199,14 +230,6 @@ export class AlfrescoViewerComponent {
} }
onNavigateBeforeClick(event: MouseEvent | KeyboardEvent) {
this.navigateBefore.next(event);
}
onNavigateNextClick(event: MouseEvent | KeyboardEvent) {
this.navigateNext.next(event);
}
ngOnInit() { ngOnInit() {
this.apiService.nodeUpdated.pipe( this.apiService.nodeUpdated.pipe(
filter((node) => node && node.id === this.nodeId && filter((node) => node && node.id === this.nodeId &&
@@ -241,22 +264,13 @@ export class AlfrescoViewerComponent {
}); });
} }
/** private async onNodeUpdated(node: Node) {
* close the viewer
*/
onClose() {
this.showViewer = false;
this.close.emit(this.showViewer);
}
private onNodeUpdated(node: Node) {
if (node && node.id === this.nodeId) { if (node && node.id === this.nodeId) {
// this.cacheTypeForContent = 'no-cache';
this.generateCacheBusterNumber(); this.generateCacheBusterNumber();
this.isLoading = true; this.isLoading = true;
this.setUpNodeFile(node).then(() => {
await this.setUpNodeFile(node)
this.isLoading = false; this.isLoading = false;
});
} }
} }
@@ -264,52 +278,42 @@ export class AlfrescoViewerComponent {
return node?.properties['cm:versionLabel'] ?? ''; return node?.properties['cm:versionLabel'] ?? '';
} }
private setupSharedLink() { private async setupSharedLink() {
this.allowGoBack = false; this.allowGoBack = false;
this.sharedLinksApi.getSharedLink(this.sharedLinkId).then( try {
(sharedLinkEntry: SharedLinkEntry) => { const sharedLinkEntry = await this.sharedLinksApi.getSharedLink(this.sharedLinkId);
this.setUpSharedLinkFile(sharedLinkEntry); await this.setUpSharedLinkFile(sharedLinkEntry);
this.isLoading = false; this.isLoading = false;
}, } catch (error) {
() => {
this.isLoading = false; this.isLoading = false;
this.logService.error('This sharedLink does not exist'); this.logService.error('This sharedLink does not exist');
this.invalidSharedLink.next(); this.invalidSharedLink.next();
}); }
} }
private setupNode() { private async setupNode() {
this.nodesApi.getNode(this.nodeId, {include: ['allowableOperations']}).then( try {
(node: NodeEntry) => { this.nodeEntry = await this.nodesApi.getNode(this.nodeId, {include: ['allowableOperations']});
this.nodeEntry = node;
if (this.versionId) { if (this.versionId) {
this.versionsApi.getVersion(this.nodeId, this.versionId).then( this.versionEntry = await this.versionsApi.getVersion(this.nodeId, this.versionId);
(version: VersionEntry) => { await this.setUpNodeFile(this.nodeEntry.entry, this.versionEntry.entry);
this.versionEntry = version;
this.setUpNodeFile(node.entry, version.entry).then(() => {
this.isLoading = false; this.isLoading = false;
});
}
);
} else { } else {
this.setUpNodeFile(node.entry).then(() => { await this.setUpNodeFile(this.nodeEntry.entry);
this.isLoading = false; this.isLoading = false;
this.cdr.detectChanges(); this.cdr.detectChanges();
});
} }
}, } catch (error) {
() => {
this.isLoading = false; this.isLoading = false;
this.logService.error('This node does not exist'); this.logService.error('This node does not exist');
} }
);
} }
private async setUpNodeFile(nodeData: Node, versionData?: Version): Promise<void> { private async setUpNodeFile(nodeData: Node, versionData?: Version): Promise<void> {
this.isLoading = true; this.isLoading = true;
// this.readOnly = !this.contentService.hasAllowableOperations(nodeData, 'update'); this.readOnly = !this.contentService.hasAllowableOperations(nodeData, 'update');
if (versionData && versionData.content) { if (versionData && versionData.content) {
this.mimeType = versionData.content.mimeType; this.mimeType = versionData.content.mimeType;
@@ -341,7 +345,10 @@ export class AlfrescoViewerComponent {
viewerType: this.viewerType viewerType: this.viewerType
} = await this.renditionViewerService.getNodeRendition(nodeData.id)); } = await this.renditionViewerService.getNodeRendition(nodeData.id));
} }
} else if (this.viewerType === 'media') {
this.tracks = await this.renditionViewerService.generateMediaTracksRendition(this.nodeId);
} }
this.isLoading = false; this.isLoading = false;
this.sidebarRightTemplateContext.node = nodeData; this.sidebarRightTemplateContext.node = nodeData;
@@ -363,14 +370,6 @@ export class AlfrescoViewerComponent {
} }
} }
onPrintContent(event: MouseEvent) {
if (this.allowPrint) {
if (!event.defaultPrevented) {
this.viewUtilService.printFileGeneric(this.nodeId, this.mimeType);
}
}
}
private async getSharedLinkRendition(sharedId: string): Promise<{ url: string, viewerType: string }> { private async getSharedLinkRendition(sharedId: string): Promise<{ url: string, viewerType: string }> {
try { try {
const rendition: RenditionEntry = await this.sharedLinksApi.getSharedLinkRendition(sharedId, 'pdf'); const rendition: RenditionEntry = await this.sharedLinksApi.getSharedLinkRendition(sharedId, 'pdf');
@@ -400,8 +399,32 @@ export class AlfrescoViewerComponent {
this.cacheBusterNumber = Date.now(); this.cacheBusterNumber = Date.now();
} }
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);
}
onPrintContent(event: MouseEvent) {
if (this.allowPrint) {
if (!event.defaultPrevented) {
this.viewUtilService.printFileGeneric(this.nodeId, this.mimeType);
}
}
}
onSubmitFile(newImageBlob: Blob) { onSubmitFile(newImageBlob: Blob) {
if (this?.nodeEntry?.entry?.id) { // && !this.readOnly) { if (this?.nodeEntry?.entry?.id && !this.readOnly) {
const newImageFile: File = new File([newImageBlob], this?.nodeEntry?.entry?.name, {type: this?.nodeEntry?.entry?.content?.mimeType}); const newImageFile: File = new File([newImageBlob], this?.nodeEntry?.entry?.name, {type: this?.nodeEntry?.entry?.content?.mimeType});
const newFile = new FileModel( const newFile = new FileModel(
newImageFile, newImageFile,

View File

@@ -39,10 +39,8 @@ export class MediaPlayerComponent implements OnChanges {
@Input() @Input()
fileName: string; fileName: string;
//
// @Input()
// nodeId: string;
/** media subtitles for the media player*/
@Input() @Input()
tracks: Track[] = []; tracks: Track[] = [];
@@ -54,17 +52,12 @@ export class MediaPlayerComponent implements OnChanges {
ngOnChanges(changes: SimpleChanges) { ngOnChanges(changes: SimpleChanges) {
const blobFile = changes['blobFile']; const blobFile = changes['blobFile'];
// const nodeId = changes['nodeId'];
if (blobFile && blobFile.currentValue) { if (blobFile && blobFile.currentValue) {
this.urlFile = this.contentService.createTrustedUrl(this.blobFile); this.urlFile = this.contentService.createTrustedUrl(this.blobFile);
return; return;
} }
// if (nodeId && nodeId.currentValue) {
// this.viewUtils.generateMediaTracksRendition(this.nodeId).then((tracks) => this.tracks = tracks);
// }
if (!this.urlFile && !this.blobFile) { if (!this.urlFile && !this.blobFile) {
throw new Error('Attribute urlFile or blobFile is required'); throw new Error('Attribute urlFile or blobFile is required');
} }

View File

@@ -80,6 +80,9 @@ export class PdfViewerComponent implements OnChanges, OnDestroy {
@Output() @Output()
error = new EventEmitter<any>(); error = new EventEmitter<any>();
@Output()
close = new EventEmitter<any>();
page: number; page: number;
displayPage: number; displayPage: number;
totalPages: number; totalPages: number;
@@ -511,6 +514,8 @@ export class PdfViewerComponent implements OnChanges, OnDestroy {
.afterClosed().subscribe((password) => { .afterClosed().subscribe((password) => {
if (password) { if (password) {
callback(password); callback(password);
} else {
this.close.emit();
} }
}); });
} }

View File

@@ -1,5 +1,7 @@
<div *ngIf="isLoading" <div *ngIf="isLoading"
class="adf-viewer-main"> class="adf-viewer-render-main"
fxFlexOrder="1"
fxFlex="1 1 auto">
<div class="adf-viewer-render-layout-content adf-viewer__fullscreen-container"> <div class="adf-viewer-render-layout-content adf-viewer__fullscreen-container">
<div class="adf-viewer-render-content-container"> <div class="adf-viewer-render-content-container">
<ng-container *ngIf="isLoading"> <ng-container *ngIf="isLoading">
@@ -17,7 +19,9 @@
</div> </div>
<div *ngIf="!isLoading" <div *ngIf="!isLoading"
class="adf-viewer-main"> class="adf-viewer-render-main"
fxFlexOrder="1"
fxFlex="1 1 auto">
<div class="adf-viewer-render-layout-content adf-viewer__fullscreen-container"> <div class="adf-viewer-render-layout-content adf-viewer__fullscreen-container">
<div class="adf-viewer-render-content-container" [ngSwitch]="viewerType"> <div class="adf-viewer-render-content-container" [ngSwitch]="viewerType">
<ng-container *ngSwitchCase="'external'"> <ng-container *ngSwitchCase="'external'">
@@ -37,6 +41,7 @@
[urlFile]="urlFile" [urlFile]="urlFile"
[fileName]="fileName" [fileName]="fileName"
[cacheType]="cacheTypeForContent" [cacheType]="cacheTypeForContent"
(close)="onClose()"
(error)="onUnsupportedFile()"> (error)="onUnsupportedFile()">
</adf-pdf-viewer> </adf-pdf-viewer>
@@ -44,6 +49,7 @@
<ng-container *ngSwitchCase="'image'"> <ng-container *ngSwitchCase="'image'">
<adf-img-viewer [urlFile]="urlFile" <adf-img-viewer [urlFile]="urlFile"
[readOnly]="readOnly"
[fileName]="fileName" [fileName]="fileName"
[blobFile]="blobFile" [blobFile]="blobFile"
(error)="onUnsupportedFile()" (error)="onUnsupportedFile()"
@@ -54,6 +60,7 @@
<ng-container *ngSwitchCase="'media'"> <ng-container *ngSwitchCase="'media'">
<adf-media-player id="adf-mdedia-player" <adf-media-player id="adf-mdedia-player"
[urlFile]="urlFile" [urlFile]="urlFile"
[tracks]="tracks"
[mimeType]="mimeType" [mimeType]="mimeType"
[blobFile]="blobFile" [blobFile]="blobFile"
[fileName]="fileName" [fileName]="fileName"

View File

@@ -16,7 +16,7 @@
justify-content: center; justify-content: center;
} }
.adf-viewer-render-layout-content { &-layout-content {
@extend .adf-full-screen; @extend .adf-full-screen;
position: relative; position: relative;

View File

@@ -15,18 +15,8 @@
* limitations under the License. * limitations under the License.
*/ */
//TODO BETTER APPROACH FOR IMG EXTENSION submit
//TODO uncomment readOnly
//TODO TO UNDERSTAND THE LEFT AND RIGHT SIDEBAR
//TODO uncomment media load subtitle
//TODO rename allowGoBack allow close button
//TODO prevent momentous unknown format
//TODO null propagation
//TODO viewer widget specialization in process service cloud
//TODO Test close dialog password scenario
//TODO Remove unused CSS
//TODO FIX documentation //TODO FIX documentation
//TODO Fix core viewer widget //TODO FIX unit test
import { import {
Component, EventEmitter, Component, EventEmitter,
@@ -37,6 +27,7 @@ import { Subject } from 'rxjs';
import { ViewUtilService } from '../services/view-util.service'; import { ViewUtilService } from '../services/view-util.service';
import { AppExtensionService, ViewerExtensionRef } from '@alfresco/adf-extensions'; import { AppExtensionService, ViewerExtensionRef } from '@alfresco/adf-extensions';
import { MatDialog } from '@angular/material/dialog'; import { MatDialog } from '@angular/material/dialog';
import { Track } from "../models/viewer.model";
@Component({ @Component({
selector: 'adf-viewer-render', selector: 'adf-viewer-render',
@@ -99,6 +90,14 @@ export class ViewerRenderComponent implements OnChanges, OnInit, OnDestroy {
@Input() @Input()
isLoading = false; isLoading = false;
/** Enable when where is possible the editing functionalities */
@Input()
readOnly = true;
/** media subtitles for the media player*/
@Input()
tracks: Track[] = [];
/** Emitted when the filename extension changes. */ /** Emitted when the filename extension changes. */
@Output() @Output()
extensionChange = new EventEmitter<string>(); extensionChange = new EventEmitter<string>();
@@ -107,6 +106,10 @@ export class ViewerRenderComponent implements OnChanges, OnInit, OnDestroy {
@Output() @Output()
submitFile = new EventEmitter<Blob>(); submitFile = new EventEmitter<Blob>();
/** Emitted when the img is submitted in the img viewer. */
@Output()
close = new EventEmitter<boolean>();
extensionTemplates: { template: TemplateRef<any>; isVisible: boolean }[] = []; extensionTemplates: { template: TemplateRef<any>; isVisible: boolean }[] = [];
extension: string; extension: string;
@@ -200,4 +203,8 @@ export class ViewerRenderComponent implements OnChanges, OnInit, OnDestroy {
this.viewerType = 'unknown'; this.viewerType = 'unknown';
} }
onClose() {
this.close.next(true);
}
} }

View File

@@ -0,0 +1,7 @@
<div class="adf-file-viewer-widget {{field.className}}" [class.adf-invalid]="!field.isValid"
[class.adf-readonly]="field.readOnly">
<label class="adf-label" [attr.for]="field.id">{{field.name | translate }}<span class="adf-asterisk"
*ngIf="isRequired()">*</span></label>
<adf-viewer [overlayMode]="false" [nodeId]="field.value" [showViewer]="field.value" [allowGoBack]="false"></adf-viewer>
<error-widget [error]="field.validationSummary"></error-widget>
</div>

View File

@@ -0,0 +1,19 @@
file-viewer-widget {
height: 100%;
width: 100%;
.adf-file-viewer-widget {
height: 100%;
width: 100%;
adf-viewer.adf-viewer {
position: relative;
.adf-viewer-container {
.adf-viewer-content > div {
height: 90vh;
}
}
}
}
}

View File

@@ -0,0 +1,83 @@
/*!
* @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 { FormModel } from '../core/form.model';
import { TranslateModule } from '@ngx-translate/core';
import { FormFieldModel } from '../core/form-field.model';
import { FormService } from '../../../services/form.service';
import { FileViewerWidgetComponent } from './file-viewer.widget';
import { ComponentFixture, TestBed } from '@angular/core/testing';
describe('FileViewerWidgetComponent', () => {
const fakeForm = new FormModel();
let widget: FileViewerWidgetComponent;
let formServiceStub: Partial<FormService>;
let fixture: ComponentFixture<FileViewerWidgetComponent>;
const fakePngAnswer: any = {
id: '1933',
link: false,
isExternal: false,
relatedContent: false,
contentAvailable: true,
name: 'a_png_file.png',
simpleType: 'image',
mimeType: 'image/png',
previewStatus: 'queued',
thumbnailStatus: 'queued',
created: '2022-10-14T17:17:37.099Z',
createdBy: { id: 1001, firstName: 'Admin', lastName: 'admin', email: 'admin@example.com' }
};
beforeEach(() => {
TestBed.configureTestingModule({
imports: [
TranslateModule.forRoot()
],
declarations: [ FileViewerWidgetComponent ],
providers: [ { provide: FormService, useValue: formServiceStub } ]
});
formServiceStub = TestBed.inject(FormService);
fixture = TestBed.createComponent(FileViewerWidgetComponent);
widget = fixture.componentInstance;
});
it('should set the file id corretly when the field value is an array', (done) => {
const fakeField = new FormFieldModel(fakeForm, { id: 'fakeField', value: [fakePngAnswer] });
widget.field = fakeField;
fixture.detectChanges();
fixture.whenStable().then(() => {
expect(widget.field.value).toBe('1933');
done();
});
});
it('should set the file id corretly when the field value is a string', (done) => {
const fakeField = new FormFieldModel(fakeForm, { id: 'fakeField', value: 'fakeValue' });
widget.field = fakeField;
fixture.detectChanges();
fixture.whenStable().then(() => {
expect(widget.field.value).toBe('fakeValue');
done();
});
});
});

View File

@@ -0,0 +1,55 @@
/*!
* @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, OnInit, ViewEncapsulation } from '@angular/core';
import { FormService } from '../../../services/form.service';
import { WidgetComponent } from '../widget.component';
/* eslint-disable @angular-eslint/component-selector */
@Component({
selector: 'file-viewer-widget',
templateUrl: './file-viewer.widget.html',
styleUrls: ['./file-viewer.widget.scss'],
host: {
'(click)': 'event($event)',
'(blur)': 'event($event)',
'(change)': 'event($event)',
'(focus)': 'event($event)',
'(focusin)': 'event($event)',
'(focusout)': 'event($event)',
'(input)': 'event($event)',
'(invalid)': 'event($event)',
'(select)': 'event($event)'
},
encapsulation: ViewEncapsulation.None
})
export class FileViewerWidgetComponent extends WidgetComponent implements OnInit {
constructor(formService: FormService) {
super(formService);
}
ngOnInit(): void {
if (this.field &&
this.field.value &&
Array.isArray(this.field.value) &&
this.field.value.length) {
const file = this.field.value[0];
this.field.value = file.id;
}
}
}