Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions cms-ui/apps/editor-ui/src/app/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { HashLocationStrategy, LocationStrategy } from '@angular/common';
import { NgModule } from '@angular/core';
import { PreloadAllModules, RouterModule } from '@angular/router';
import { KeycloakService } from '@gentics/cms-components';
import { PiktidModule } from '@gentics/picktid-editor';
import { AppComponent } from './app.component';
import { APP_ROUTES } from './app.routes';
import { CoreModule } from './core/core.module';
Expand All @@ -15,6 +16,7 @@ const PROVIDERS: any[] = [
@NgModule({
imports: [
CoreModule,
PiktidModule,
RouterModule.forRoot(APP_ROUTES, {
preloadingStrategy: PreloadAllModules,
enableTracing: false,
Expand Down
2 changes: 1 addition & 1 deletion cms-ui/apps/editor-ui/src/app/app.routes.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import { Route } from '@angular/router';
import { EditorOutlet } from './common/models';
import { NoNodesComponent, TagEditorRouteComponent } from './core/components';
import { ProjectEditorComponent } from './core/components/project-editor/project-editor.component';
import { AuthGuard } from './core/providers/guards/auth-guard';
import { OpenModalGuard } from './core/providers/guards/open-modal-guard';
import { ToolOverviewComponent } from './embedded-tools/components/tool-overview/tool-overview.component';
import { ToolProxyComponent } from './embedded-tools/components/tool-proxy/tool-proxy.component';
import { ProxyRouteComponent, RessourceProxyComponent } from './shared/components';
import { EditorOutlet } from './common/models';

export const APP_ROUTES: Route[] = [
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {
Input,
OnChanges,
OnDestroy,
OnInit,
Output,
SimpleChanges,
ViewChild,
Expand All @@ -19,7 +20,7 @@ import {
RotateParameters,
User,
} from '@gentics/cms-models';
import { ProgressBarComponent } from '@gentics/ui-core';
import { ModalService, ProgressBarComponent } from '@gentics/ui-core';
import { Observable, Subscription, of } from 'rxjs';
import { map, publishReplay, refCount, startWith, switchMap } from 'rxjs/operators';
import { getFileExtension } from '../../../common/utils/get-file-extension';
Expand All @@ -30,14 +31,15 @@ import { NavigationService } from '../../../core/providers/navigation/navigation
import { PermissionService } from '../../../core/providers/permissions/permission.service';
import { ResourceUrlBuilder } from '../../../core/providers/resource-url-builder/resource-url-builder';
import { ApplicationStateService, ApplyImageDimensionsAction, FolderActionsService } from '../../../state';
import { ImageAnonymizeModal } from '../image-anonymize-modal/image-anonymize-modal.component';

@Component({
selector: 'file-preview',
templateUrl: './file-preview.tpl.html',
styleUrls: ['./file-preview.scss'],
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class FilePreviewComponent implements OnChanges, OnDestroy {
export class FilePreviewComponent implements OnInit, OnChanges, OnDestroy {

@Input()
public file: FileModel | ImageModel;
Expand All @@ -53,11 +55,12 @@ export class FilePreviewComponent implements OnChanges, OnDestroy {
fileExtension: string;
keepFileName = true;
nodeId: number;
private maxImageFullsizeDimensions = this.calculateMaxImageDimensions();
private subscriptions = new Subscription();
isEditableImage = isEditableImage;
hasFileEditPermission$: Observable<boolean>;

private maxImageFullsizeDimensions = this.calculateMaxImageDimensions();
private subscriptions: Subscription[] = [];

get displayDimensions(): any {
return (this.file.type === 'image' && this.file.sizeX !== 0 && this.file.sizeY !== 0) ?
{ width: this.file.sizeX, height: this.file.sizeY } :
Expand All @@ -68,35 +71,42 @@ export class FilePreviewComponent implements OnChanges, OnDestroy {

private dismissErrorMessage(): void {}

constructor(private resourceUrlBuilder: ResourceUrlBuilder,
constructor(
private resourceUrlBuilder: ResourceUrlBuilder,
private navigationService: NavigationService,
private appState: ApplicationStateService,
public permissions: PermissionService,
private entityResolver: EntityResolver,
private notification: I18nNotification,
private folderActions: FolderActionsService) {
this.subscriptions.add(
this.appState.select(state => state.entities).subscribe(entities => {
this.hasFileEditPermission$ = this.appState.select(() =>
this.file.type === 'file' ? entities.file[this.file.id].folderId : entities.image[this.file.id].folderId)
.pipe(
switchMap(folderId => this.appState.select(state => state.entities.folder[folderId])),
switchMap((folder: Folder) => {
if (folder) {
const permissionsMap = folder.permissionsMap;
const isFile = this.file.type === 'file';
if (!permissionsMap) {
return this.permissions.getFolderPermissionMap(folder.id).pipe(
map((permissionsMap: PermissionsMapCollection) => {
return this.hasEditPermission(permissionsMap, isFile);
}),
);
}
return of(this.hasEditPermission(permissionsMap, isFile));
}
return of(false);
}),
);
private folderActions: FolderActionsService,
private modalService: ModalService,
) {}

ngOnInit(): void {
this.hasFileEditPermission$ = this.appState.select(state => state.entities).pipe(
map(entities => {
const folderId = this.file.type === 'file'
? entities.file[this.file.id].folderId
: entities.image[this.file.id].folderId;

return entities.folder[folderId];
}),
switchMap((folder: Folder) => {
if (!folder) {
return of(false);
}

const permissionsMap = folder.permissionsMap;
const isFile = this.file.type === 'file';
if (permissionsMap) {
return of(this.hasEditPermission(permissionsMap, isFile));
}

return this.permissions.getFolderPermissionMap(folder.id).pipe(
map((permissionsMap: PermissionsMapCollection) => {
return this.hasEditPermission(permissionsMap, isFile);
}),
);
}),
);
}
Expand Down Expand Up @@ -124,7 +134,20 @@ export class FilePreviewComponent implements OnChanges, OnDestroy {

ngOnDestroy(): void {
this.dismissErrorMessage();
this.subscriptions.unsubscribe();
this.subscriptions.forEach(s => s.unsubscribe());
}

anonymizeImage(): void {
const nodeId = this.appState.now.editor.nodeId;

this.modalService.fromComponent(ImageAnonymizeModal, {
closeOnEscape: false,
closeOnOverlayClick: false,
width: '100%',
}, {
imageId: this.file.id,
nodeId,
}).then(comp => comp.open());
}

editImage(): void {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ $file-color: $gcms-color-file;
:host {
display: flex;
flex-direction: column;
max-height: 100%;
min-height: 1px;
}

.preview-pane {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
<div class="preview-pane" [ngClass]="file.type || ''">
<div class="file-preview" *ngIf="file.type === 'file'">
<div class="file-icon" [ngClass]="fileExtension || ''">
<i class="material-icons" [attr.translate]="'no'">insert_drive_file</i>
<span class="extension" *ngIf="fileExtension"
[ngClass]="'len-' + fileExtension?.length">
<icon>insert_drive_file</icon>
<span
*ngIf="fileExtension"
class="extension"
[ngClass]="'len-' + fileExtension?.length"
>
{{ fileExtension | uppercase }}
</span>
</div>
Expand All @@ -16,77 +19,121 @@
<div class="image-preview" *ngIf="file.type === 'image'">
<div class="filename">{{ file.name }}</div>
<div class="thumbnail" [class.loading]="imageLoading | async">
<img class="previewed-image" [src]="imageUrl"
[width]="displayDimensions.width" [height]="displayDimensions.height"
(load)="onImageLoadSuccess()"
(error)="onImageLoadError($event)"
#thumbnailImage>
<div class="size-double"
[style.width.px]="displayDimensions.width"
[style.padding-bottom.%]="100 * displayDimensions.height / displayDimensions.width"></div>
<img
#thumbnailImage
class="previewed-image"
[src]="imageUrl"
[width]="displayDimensions.width"
[height]="displayDimensions.height"
(load)="onImageLoadSuccess()"
(error)="onImageLoadError($event)"
/>
<div
class="size-double"
[style.width.px]="displayDimensions.width"
[style.padding-bottom.%]="100 * displayDimensions.height / displayDimensions.width"
></div>
</div>
<div class="image-details">
<span class="dimensions">{{ { width: file.sizeX, height: file.sizeY } | imagedimensions | i18n }}</span>
<span class="separator"> - </span>
<span class="filesize">{{ file.fileSize | filesize }}</span>
</div>
</div>

<div class="author-details">
<div class="created" *ngIf="creator"
[innerHTML]="'editor.file_preview_creator_label' | i18n:{
name: creator.firstName + ' ' + creator.lastName,
date: (file.cdate | i18nDate),
time: (file.cdate | i18nDate:'time')
}"></div>
<div class="edited"
*ngIf="file.cdate !== file.edate && editor"
[innerHTML]="'editor.file_preview_editor_label' | i18n:{
name: editor.firstName + ' ' + editor.lastName,
date: (file.edate | i18nDate),
time: (file.edate | i18nDate:'time')
}"></div>
<div
*ngIf="creator"
class="created"
[innerHTML]="'editor.file_preview_creator_label' | i18n:{
name: creator.firstName + ' ' + creator.lastName,
date: (file.cdate | i18nDate),
time: (file.cdate | i18nDate:'time')
}"
></div>

<div
*ngIf="file.cdate !== file.edate && editor"
class="edited"
[innerHTML]="'editor.file_preview_editor_label' | i18n:{
name: editor.firstName + ' ' + editor.lastName,
date: (file.edate | i18nDate),
time: (file.edate | i18nDate:'time')
}"
></div>
</div>
<div class="actions">
<div class="action-rotate-left" *ngIf="file.type === 'image'">
<gtx-button flat (click)="rotateImage('ccw')" [disabled]="!isEditableImage(file)">
<i class="material-icons left">rotate_left</i> {{ 'editor.rotate_image_left_button' | i18n }}

<div *ngIf="file.type === 'image'" class="actions">
<div class="action-rotate-left">
<gtx-button
flat
[disabled]="!isEditableImage(file)"
(click)="rotateImage('ccw')"
>
<icon left>rotate_left</icon> {{ 'editor.rotate_image_left_button' | i18n }}
</gtx-button>
</div>
<div class="action-rotate-right" *ngIf="file.type === 'image'">
<gtx-button flat (click)="rotateImage('cw')" [disabled]="!isEditableImage(file)">
<i class="material-icons left">rotate_right</i> {{ 'editor.rotate_image_right_button' | i18n }}
<div class="action-rotate-right">
<gtx-button
flat
[disabled]="!isEditableImage(file)"
(click)="rotateImage('cw')"
>
<icon left>rotate_right</icon> {{ 'editor.rotate_image_right_button' | i18n }}
</gtx-button>
</div>
</div>

<div class="actions">
<div class="action-edit" *ngIf="file.type === 'image'">
<gtx-button flat (click)="editImage()" [disabled]="!isEditableImage(file)">
<i class="material-icons left" [attr.translate]="'no'">edit</i> {{ 'editor.edit_image_button' | i18n }}
</gtx-button>
</div>
<div class="action-download" *ngIf="file.type === 'file'">
<ng-container *ngIf="file.type === 'image'">
<div class="action-anonymize">
<gtx-button flat (click)="anonymizeImage()" [disabled]="!isEditableImage(file)">
<icon left>theater_comedy</icon> {{ 'editor.anonymize_people_button' | i18n }}
</gtx-button>
</div>

<div class="action-edit">
<gtx-button flat (click)="editImage()" [disabled]="!isEditableImage(file)">
<icon left>edit</icon> {{ 'editor.edit_image_button' | i18n }}
</gtx-button>
</div>
</ng-container>

<div *ngIf="file.type === 'file'" class="action-download">
<a [href]="downloadUrl" [download]="file.name" target="_blank">
<gtx-button flat>
<i class="material-icons left" [attr.translate]="'no'">file_download</i> {{ 'editor.download_file_button' | i18n }}
<icon left>file_download</icon> {{ 'editor.download_file_button' | i18n }}
</gtx-button>
</a>
</div>
<div class="action-replace"
*ngIf="hasFileEditPermission$ | async"
[overrideSlot]="file.type === 'image' ? 'replaceImageButton' : 'replaceFileButton'">

<div
*ngIf="hasFileEditPermission$ | async"
class="action-replace"
[overrideSlot]="file.type === 'image' ? 'replaceImageButton' : 'replaceFileButton'"
>
<gtx-progress-bar #uploadBar></gtx-progress-bar>
<gtx-file-picker flat
[overrideSlot]="file.type === 'image' ? 'replaceImageButton' : 'replaceFileButton'"
[overrideParams]="{ FOLDERID: file.folderId, NODEID: nodeId }"
[accept]="acceptedFiles()"
(fileSelect)="replaceFile($event, uploadBar)"
(fileSelectReject)="replaceFile($event, uploadBar)">

<gtx-file-picker
flat
[overrideSlot]="file.type === 'image' ? 'replaceImageButton' : 'replaceFileButton'"
[overrideParams]="{ FOLDERID: file.folderId, NODEID: nodeId }"
[accept]="acceptedFiles()"
(fileSelect)="replaceFile($event, uploadBar)"
(fileSelectReject)="replaceFile($event, uploadBar)"
>
<icon left>file_upload</icon>
<span *ngIf="file.type === 'image'">{{ 'editor.upload_new_image_button' | i18n }}</span>
<span *ngIf="file.type === 'file'">{{ 'editor.upload_new_file_button' | i18n }}</span>
<span *ngIf="">{{ (file.type === 'image'
? 'editor.upload_new_image_button'
: 'editor.upload_new_file_button'
) | i18n }}</span>
</gtx-file-picker>

<div class="keep-filename">
<gtx-checkbox [(ngModel)]="keepFileName" [label]="'editor.keep_filename_label' | i18n"></gtx-checkbox>
<gtx-checkbox
[label]="'editor.keep_filename_label' | i18n"
[(ngModel)]="keepFileName"
></gtx-checkbox>
</div>
</div>
</div>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<div class="modal-title">
<h5>{{ 'modal.anonymize_image_title' | i18n }}</h5>
</div>

<div class="modal-content">
<gtxpict-editor
*ngIf="imageBlob"
[imageBlob]="imageBlob"
[disabled]="loading"
(imageUpload)="updateImageId($event)"
(confirmChange)="updateConfirmation($event)"
></gtxpict-editor>
</div>

<div class="modal-footer">
<gtx-button
type="secondary"
flat
(click)="cancelFn()"
>{{ 'common.cancel_button' | i18n }}</gtx-button>

<gtx-button
type="primary"
[disabled]="!piktidImageId || confirmedIds?.length === 0"
(click)="processImage()"
>{{ 'common.confirm_button' }}</gtx-button>
</div>

Loading