diff --git a/projects/editor/src/app/app.module.ts b/projects/editor/src/app/app.module.ts index 85d091859c7d188029b6d35e21826da82a409f2f..101598cd1ba642d196ce2fd96b0437419ad1c565 100644 --- a/projects/editor/src/app/app.module.ts +++ b/projects/editor/src/app/app.module.ts @@ -26,8 +26,6 @@ import { } from './dialog.service'; import { EditorTranslateLoader } from './editor-translate-loader'; import { ElementPropertiesComponent } from './components/unit-view/page-view/properties/element-properties.component'; -import { StaticViewOnlyElementOverlayComponent } from './components/unit-view/page-view/canvas/static-view-only-element-overlay.component'; -import { DynamicViewOnlyElementOverlayComponent } from './components/unit-view/page-view/canvas/dynamic-view-only-element-overlay.component'; import { SectionMenuComponent } from './components/unit-view/page-view/canvas/section-menu.component'; @NgModule({ @@ -46,8 +44,6 @@ import { SectionMenuComponent } from './components/unit-view/page-view/canvas/se MultilineTextEditDialog, RichTextEditDialogTinyMCE, ElementPropertiesComponent, - StaticViewOnlyElementOverlayComponent, - DynamicViewOnlyElementOverlayComponent, SectionMenuComponent ], imports: [ diff --git a/projects/editor/src/app/components/unit-view/page-view/canvas/dynamic-view-only-element-overlay.component.ts b/projects/editor/src/app/components/unit-view/page-view/canvas/dynamic-view-only-element-overlay.component.ts deleted file mode 100644 index bca827160168f009ae15449939236b2d68ca672b..0000000000000000000000000000000000000000 --- a/projects/editor/src/app/components/unit-view/page-view/canvas/dynamic-view-only-element-overlay.component.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { Component } from '@angular/core'; -import { CanvasElementOverlay } from './canvas-element-overlay'; - -@Component({ - selector: 'app-dynamic-view-only-element-overlay', - template: ` - <div #draggableElement [style.height.%]="100"> - <ng-template #elementContainer></ng-template> - </div> - ` -}) -export class DynamicViewOnlyElementOverlayComponent extends CanvasElementOverlay { } diff --git a/projects/editor/src/app/components/unit-view/page-view/canvas/page-canvas.component.html b/projects/editor/src/app/components/unit-view/page-view/canvas/page-canvas.component.html index 8157d92fec826f40a8ce869b9f609482ebcee2f4..724bc0dbf70ce3d60bde1e60b5f961a78948b4e2 100644 --- a/projects/editor/src/app/components/unit-view/page-view/canvas/page-canvas.component.html +++ b/projects/editor/src/app/components/unit-view/page-view/canvas/page-canvas.component.html @@ -1,15 +1,19 @@ -<mat-slide-toggle (change)="toggleSectionEditMode($event)"> - Abschnitte verwalten -</mat-slide-toggle> - <div class="canvasBackground" fxFlex> - <div *ngIf="!sectionEditMode" - class="canvasFrame" + <div class="canvasFrame" [style.width.px]="page.maxWidth" [style.padding.px]="page.margin" [style.background-color]="page.backgroundColor"> <div cdkDropListGroup> - <ng-container *ngFor="let section of page.sections; let i = index"> + <div *ngFor="let section of page.sections; let i = index" [style.position]="'relative'"> + <app-section-menu [class.open]="hoveredSection === i" class="section-menu" fxLayout="column" + [style.left.px]="-45" [style.z-index]="1" [style.position]="'absolute'" + [section]="section" + [allowMoveUp]="i != 0" + [allowMoveDown]="i < page.sections.length - 1" + [allowDelete]="page.sections.length > 1" + (moveSection)="unitService.moveSection(section, page, $event)" + (mouseover)="hoveredSection = i" (mouseleave)="hoveredSection = -1"> <!-- keep menu open--> + </app-section-menu> <!-- TODO split section into static and dynamic--> <div *ngIf="!section.dynamicPositioning" app-canvas-section class="section drop-list" id="section-{{i}}" @@ -17,7 +21,8 @@ cdkDropList cdkDropListSortingDisabled [cdkDropListData]="{ sectionIndex: i }" (cdkDropListDropped)="elementDropped($event)" - [cdkDropListConnectedTo]="dropListList"> + [cdkDropListConnectedTo]="dropListList" + (mouseover)="hoveredSection = i" (mouseleave)="hoveredSection = -1"> </div> <div *ngIf="section.dynamicPositioning" app-canvas-section class="section drop-list" @@ -25,28 +30,8 @@ [dropListList]="dropListList" (transferElement)="moveElementBetweenSections($event.element, $event.previousSectionIndex, - $event.newSectionIndex)"> - </div> - </ng-container> - </div> - </div> - - <div *ngIf="sectionEditMode" class="drop-list" - [style.width.px]="page.maxWidth" [style.padding.px]="page.margin" - cdkDropList (cdkDropListDropped)="sectionDrop($event)" [cdkDropListData]="page.sections"> - <div *ngFor="let section of page.sections; let i = index" [style.position]="'relative'"> - <button mat-fab class="add-section-button" - (click)="addSection(i)"> - <mat-icon>add</mat-icon> - </button> - <div> - <app-section-menu class="button-panel" fxLayout="column" - [style.left.px]="-42" [style.z-index]="1" [style.position]="'absolute'" - [section]="section" [allowDelete]="page.sections.length > 1"> - </app-section-menu> - <div app-canvas-section class="section" - [section]="section" [sectionEditMode]="sectionEditMode" - cdkDrag cdkDragLockAxis="y"> + $event.newSectionIndex)" + (mouseover)="hoveredSection = i" (mouseleave)="hoveredSection = -1"> </div> </div> </div> diff --git a/projects/editor/src/app/components/unit-view/page-view/canvas/page-canvas.component.ts b/projects/editor/src/app/components/unit-view/page-view/canvas/page-canvas.component.ts index 5d5a8af05f66a806725c8ff95c08eca414276e55..0c285290a0491651c3543639c97248b170045afe 100644 --- a/projects/editor/src/app/components/unit-view/page-view/canvas/page-canvas.component.ts +++ b/projects/editor/src/app/components/unit-view/page-view/canvas/page-canvas.component.ts @@ -4,7 +4,6 @@ import { import { CdkDragDrop, moveItemInArray } from '@angular/cdk/drag-drop'; import { Subject } from 'rxjs'; import { takeUntil } from 'rxjs/operators'; -import { MatSlideToggleChange } from '@angular/material/slide-toggle'; import { UnitPage, UnitPageSection, UnitUIElement } from '../../../../../../../common/unit'; import { UnitService } from '../../../../unit.service'; import { SelectionService } from '../../../../selection.service'; @@ -17,13 +16,15 @@ import { SelectionService } from '../../../../selection.service'; '.canvasBackground {background-color: lightgrey; padding: 20px 50px; height: 100%; overflow: auto;}', '.add-section-button {width: 100%; height: 25px; background-color: #BABABA; margin: 15px 0; border-radius: 10%}', '::ng-deep .add-section-button span.mat-button-wrapper {padding: 0}', - '::ng-deep .add-section-button span.mat-button-wrapper mat-icon {vertical-align: unset}' + '::ng-deep .add-section-button span.mat-button-wrapper mat-icon {vertical-align: unset}', + '.section-menu {opacity:0; transition: opacity 0.5s linear; transition-delay:1s;}', + '.section-menu.open {opacity:1; transition-delay:0s;}' ] }) export class PageCanvasComponent implements OnInit, OnDestroy { @Input() page!: UnitPage; - sectionEditMode: boolean = false; dropListList: string[] = []; + hoveredSection: number = -1; private ngUnsubscribe = new Subject<void>(); constructor(private selectionService: SelectionService, public unitService: UnitService) { } @@ -104,10 +105,6 @@ export class PageCanvasComponent implements OnInit, OnDestroy { return this.page.sections.reduce(reduceFct, 0); } - toggleSectionEditMode(event: MatSlideToggleChange): void { - this.sectionEditMode = event.checked; - } - addSection(index: number | null = null): void { this.unitService.addSection(this.page, index); } diff --git a/projects/editor/src/app/components/unit-view/page-view/canvas/section-menu.component.ts b/projects/editor/src/app/components/unit-view/page-view/canvas/section-menu.component.ts index cac9bd4993da4e7852997b3a28cfe07902a78f46..45d4b92d97569a0dc11c221f4957c0060c4545b8 100644 --- a/projects/editor/src/app/components/unit-view/page-view/canvas/section-menu.component.ts +++ b/projects/editor/src/app/components/unit-view/page-view/canvas/section-menu.component.ts @@ -1,9 +1,12 @@ import { - Component, OnInit, Input, + Component, OnInit, OnDestroy, Input, Output, EventEmitter, ViewChild, ElementRef } from '@angular/core'; +import { Subject } from 'rxjs'; +import { takeUntil } from 'rxjs/operators'; import { UnitPageSection } from '../../../../../../../common/unit'; import { UnitService } from '../../../../unit.service'; +import { DialogService } from '../../../../dialog.service'; @Component({ selector: 'app-section-menu', @@ -91,6 +94,14 @@ import { UnitService } from '../../../../unit.service'; </div> </mat-menu> + <button *ngIf="allowMoveUp" mat-mini-fab + (click)="this.moveSection.emit('up')"> + <mat-icon>north</mat-icon> + </button> + <button *ngIf="allowMoveDown" mat-mini-fab + (click)="this.moveSection.emit('down')"> + <mat-icon>south</mat-icon> + </button> <button *ngIf="allowDelete" mat-mini-fab (click)="deleteSection()"> <mat-icon>clear</mat-icon> @@ -103,16 +114,20 @@ import { UnitService } from '../../../../unit.service'; '::ng-deep .layoutMenu {width: 200px; padding: 0 15px}' ] }) -export class SectionMenuComponent implements OnInit { +export class SectionMenuComponent implements OnInit, OnDestroy { @Input() section!: UnitPageSection; + @Input() allowMoveUp!: boolean; + @Input() allowMoveDown!: boolean; @Input() allowDelete!: boolean; + @Output() moveSection = new EventEmitter<'up' | 'down'>(); @ViewChild('colorPicker') colorPicker!: ElementRef; - columnSizes: { value: string, unit: string }[] = []; rowSizes: { value: string, unit: string }[] = []; + private ngUnsubscribe = new Subject<void>(); - constructor(private unitService: UnitService) { } + constructor(public unitService: UnitService, + private dialogService: DialogService) { } ngOnInit(): void { this.updateGridSizes(); @@ -123,7 +138,13 @@ export class SectionMenuComponent implements OnInit { } deleteSection(): void { - this.unitService.deleteSection(this.section); + this.dialogService.showConfirmDialog('Abschnitt löschen?') + .pipe(takeUntil(this.ngUnsubscribe)) + .subscribe((result: boolean) => { + if (result) { + this.unitService.deleteSection(this.section); + } + }); } /* Initialize internal array of grid sizes. Where value and unit are put, split up, in an array. */ @@ -176,4 +197,9 @@ export class SectionMenuComponent implements OnInit { openColorPicker() { this.colorPicker.nativeElement.click(); } + + ngOnDestroy(): void { + this.ngUnsubscribe.next(); + this.ngUnsubscribe.complete(); + } } diff --git a/projects/editor/src/app/components/unit-view/page-view/canvas/section.component.ts b/projects/editor/src/app/components/unit-view/page-view/canvas/section.component.ts index 2b85712f1a57d1752c0a50f824140962c22d12fa..fbb5c42f7bc2f240e80e4de562f5c62e3705bdde 100644 --- a/projects/editor/src/app/components/unit-view/page-view/canvas/section.component.ts +++ b/projects/editor/src/app/components/unit-view/page-view/canvas/section.component.ts @@ -10,8 +10,7 @@ import { DragItemData, DropListData } from './page-canvas.component'; @Component({ selector: '[app-canvas-section]', template: ` - <div *ngIf="!sectionEditMode" - #sectionElement class="section-wrapper" + <div #sectionElement class="section-wrapper" [style.border]="selected ? '1px solid': '1px dotted'" [style.height.px]="section.height" [style.background-color]="section.backgroundColor" @@ -71,53 +70,6 @@ import { DragItemData, DropListData } from './page-canvas.component'; </app-dynamic-canvas-overlay> </div> </div> - - <div *ngIf="sectionEditMode" - #sectionElement class="section-wrapper" - [style.border]="selected ? '1px solid': '1px dotted'" - [style.height.px]="section.height" - [style.background-color]="section.backgroundColor" - (click)="selectionService.selectSection(this)"> - <div *ngIf="!section.dynamicPositioning"> - <app-view-only-element-overlay *ngFor="let element of section.elements" [element]="$any(element)"> - </app-view-only-element-overlay> - </div> - - <div *ngIf="section.dynamicPositioning" - [style.display]="'grid'" - [style.grid-template-columns]="section.gridColumnSizes" - [style.grid-template-rows]="section.gridRowSizes" - [style.height.%]="100"> - <!-- Dynamic sections have the droplists for the grid cells next to the actual elements. Elements can not - be children of the grid cells because they can span over multiple cells. --> - <ng-container *ngFor="let column of this.section.gridColumnSizes.split(' '); let x = index"> - <ng-container *ngFor="let row of this.section.gridRowSizes.split(' '); let y = index"> - <div class="grid-placeholder" - [style.grid-column-start]="x + 1" - [style.grid-column-end]="x + 1" - [style.grid-row-start]="y + 1" - [style.grid-row-end]="y + 1"> - {{x + 1}} / {{y + 1}} - </div> - </ng-container> - </ng-container> - - <app-dynamic-view-only-element-overlay *ngFor="let element of section.elements" - [element]="$any(element)" - [style.min-width.px]="element.width" - [style.min-height.px]="element.height" - [style.margin-left.px]="element.marginLeft" - [style.margin-right.px]="element.marginRight" - [style.margin-top.px]="element.marginTop" - [style.margin-bottom.px]="element.marginBottom" - [style.grid-column-start]="element.gridColumnStart" - [style.grid-column-end]="element.gridColumnEnd" - [style.grid-row-start]="element.gridRowStart" - [style.grid-row-end]="element.gridRowEnd"> - </app-dynamic-view-only-element-overlay> - </div> - - </div> `, styles: [ '.section-wrapper {width: 100%}', @@ -126,7 +78,6 @@ import { DragItemData, DropListData } from './page-canvas.component'; }) export class SectionComponent { @Input() section!: UnitPageSection; - @Input() sectionEditMode: boolean = false; @Input() sectionIndex!: number; @Input() dropListList!: string[]; @Output() transferElement = new EventEmitter<{ element: UnitUIElement, diff --git a/projects/editor/src/app/components/unit-view/page-view/canvas/static-view-only-element-overlay.component.ts b/projects/editor/src/app/components/unit-view/page-view/canvas/static-view-only-element-overlay.component.ts deleted file mode 100644 index 08a4b89b4f1f85a6fe9d7339107a5fb9eaaad1f3..0000000000000000000000000000000000000000 --- a/projects/editor/src/app/components/unit-view/page-view/canvas/static-view-only-element-overlay.component.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { Component } from '@angular/core'; -import { CanvasElementOverlay } from './canvas-element-overlay'; - -@Component({ - selector: 'app-view-only-element-overlay', - template: ` - <div [style.position]="'absolute'" - [style.width.px]="element.width" - [style.height.px]="element.height" - [style.left.px]="element.xPosition" - [style.top.px]="element.yPosition" - [style.z-index]="element.zIndex"> - <ng-template #elementContainer></ng-template> - </div> - ` -}) -export class StaticViewOnlyElementOverlayComponent extends CanvasElementOverlay { - -} diff --git a/projects/editor/src/app/dialog.service.ts b/projects/editor/src/app/dialog.service.ts index 51593f4299f0a8281e77d3de00cb46a1ef5686cb..60931f3062b7cda46ff1698c2e3f654e2ee78054 100644 --- a/projects/editor/src/app/dialog.service.ts +++ b/projects/editor/src/app/dialog.service.ts @@ -9,8 +9,12 @@ import { MAT_DIALOG_DATA, MatDialog } from '@angular/material/dialog'; export class DialogService { constructor(private dialog: MatDialog) { } - showConfirmDialog(): Observable<boolean> { - const dialogRef = this.dialog.open(ConfirmationDialog); + showConfirmDialog(text: string): Observable<boolean> { + const dialogRef = this.dialog.open(ConfirmationDialog, { + data: { + text: text + } + }); return dialogRef.afterClosed(); } @@ -49,7 +53,7 @@ export class DialogService { selector: 'app-confirmation-dialog', template: ` <mat-dialog-content> - Seite wirklich löschen? + {{data.text}} </mat-dialog-content> <mat-dialog-actions> <button mat-button [mat-dialog-close]="true">Okay</button> @@ -57,7 +61,9 @@ export class DialogService { </mat-dialog-actions> ` }) -export class ConfirmationDialog {} +export class ConfirmationDialog { + constructor(@Inject(MAT_DIALOG_DATA) public data: { text: string }) { } +} @Component({ selector: 'app-text-edit-dialog', diff --git a/projects/editor/src/app/unit.service.ts b/projects/editor/src/app/unit.service.ts index 001d9a8efca6979805cabee676f12b0d4dd21109..e7551a4b61321d104a8fed56c9e446642507cfeb 100644 --- a/projects/editor/src/app/unit.service.ts +++ b/projects/editor/src/app/unit.service.ts @@ -58,22 +58,18 @@ export class UnitService { this.veronaApiService.sendVoeDefinitionChangedNotification(); } - /* reorder page in page array */ + /* Reorder page in page array. + * Checks first that the page can not be moved in front of the always visible page. */ movePage(selectedPage: UnitPage, direction: 'up' | 'down'): void { - const oldPageIndex = this._unit.value.pages.indexOf(selectedPage); - if ((this._unit.value.pages.length > 1) && - !(direction === 'down' && oldPageIndex + 1 === this._unit.value.pages.length) && // dont allow last page down - !(direction === 'up' && oldPageIndex === 0) && // dotn allow first page up - // dont allow second page to go before always shown page - !(direction === 'up' && oldPageIndex === 1 && this._unit.value.pages[0].alwaysVisible) && - !(selectedPage.alwaysVisible)) { - const newPageIndex = direction === 'up' ? oldPageIndex - 1 : oldPageIndex + 1; - const page = this._unit.value.pages.splice(oldPageIndex, 1); - this._unit.value.pages.splice(newPageIndex, 0, page[0]); - this._unit.next(this._unit.value); - this.pageMoved.next(); - this.veronaApiService.sendVoeDefinitionChangedNotification(); + if (direction === 'up' && + this._unit.value.pages.indexOf(selectedPage) === 1 && + this._unit.value.pages[0].alwaysVisible) { + return; } + UnitService.moveArrayItem(selectedPage, this._unit.value.pages, direction); + this._unit.next(this._unit.value); + this.pageMoved.next(); + this.veronaApiService.sendVoeDefinitionChangedNotification(); } updatePageProperty(page: UnitPage, property: string, value: number | boolean): void { @@ -119,6 +115,12 @@ export class UnitService { } } + moveSection(section: UnitPageSection, page: UnitPage, direction: 'up' | 'down'): void { + UnitService.moveArrayItem(section, page.sections, direction); + this._unit.next(this._unit.value); + this.veronaApiService.sendVoeDefinitionChangedNotification(); + } + setPageSections(page: UnitPage, sections: UnitPageSection[]): void { this._unit.value.pages[this.selectedPageIndex].sections = sections; this.veronaApiService.sendVoeDefinitionChangedNotification(); @@ -325,4 +327,16 @@ export class UnitService { // no default } } + + private static moveArrayItem(item: unknown, array: unknown[], direction: 'up' | 'down'): void { + const oldIndex = array.indexOf(item); + + if ((array.length > 1) && + !(direction === 'down' && oldIndex + 1 === array.length) && // dont allow last element down + !(direction === 'up' && oldIndex === 0)) { // dont allow first element up + const newIndex = direction === 'up' ? oldIndex - 1 : oldIndex + 1; + const elements = array.splice(oldIndex, 1); + array.splice(newIndex, 0, elements[0]); + } + } }