Skip to content
Snippets Groups Projects
Commit abc380f9 authored by rhenck's avatar rhenck
Browse files

[editor] Add section edit mode

In this mode sections can be inserted, reordered and deleted with 
buttons directly on the canvas.
parent 06069278
No related branches found
No related tags found
No related merge requests found
......@@ -6,6 +6,7 @@ import { createCustomElement } from '@angular/elements';
import { TranslateLoader, TranslateModule } from '@ngx-translate/core';
import { MatButtonToggleModule } from '@angular/material/button-toggle';
import { MatSlideToggleModule } from '@angular/material/slide-toggle';
import { AppComponent } from './app.component';
import { ToolbarComponent } from './components/toolbar/toolbar.component';
......@@ -23,6 +24,8 @@ import { EditorTranslateLoader } from './editor-translate-loader';
import { PagePropertiesComponent } from './components/unit-view/page-view/properties/page-properties.component';
import { SectionPropertiesComponent } from './components/unit-view/page-view/properties/section-properties.component';
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';
@NgModule({
declarations: [
......@@ -41,7 +44,9 @@ import { ElementPropertiesComponent } from './components/unit-view/page-view/pro
MultilineTextEditDialog,
PagePropertiesComponent,
SectionPropertiesComponent,
ElementPropertiesComponent
ElementPropertiesComponent,
StaticViewOnlyElementOverlayComponent,
DynamicViewOnlyElementOverlayComponent
],
imports: [
BrowserModule,
......@@ -49,6 +54,7 @@ import { ElementPropertiesComponent } from './components/unit-view/page-view/pro
CommonModule,
SharedModule,
MatButtonToggleModule,
MatSlideToggleModule,
TranslateModule.forRoot({
loader: {
provide: TranslateLoader,
......
......@@ -17,6 +17,7 @@ import { SelectionService } from '../../../../selection.service';
@Directive()
export abstract class CanvasElementOverlay {
@Input() element!: UnitUIElement;
@Input() viewMode: boolean = false;
@ViewChild('elementContainer', { read: ViewContainerRef, static: true }) private elementContainer!: ViewContainerRef;
selected = false;
protected childComponent!: ComponentRef<ElementComponent>;
......
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 { }
<mat-slide-toggle (change)="toggleSectionEditMode($event)">
Abschnitte verwalten
</mat-slide-toggle>
<div class="canvasBackground" fxFlex>
<div class="canvasFrame" [style.width.px]="page.width"
<div *ngIf="!sectionEditMode"
class="canvasFrame"
[style.width.px]="page.width"
[style.padding.px]="page.margin"
[style.background-color]="page.backgroundColor">
<div cdkDropListGroup class="section-list">
<div #section_component app-canvas-section class="section"
<div cdkDropListGroup>
<div app-canvas-section class="section"
*ngFor="let section of page.sections; let i = index"
[section]="section" [sectionIndex]="i"
cdkDropList cdkDropListSortingDisabled
......@@ -11,4 +17,26 @@
</div>
</div>
</div>
<div *ngIf="sectionEditMode"
[style.width.px]="page.width" [style.padding.px]="page.margin"
cdkDropList (cdkDropListDropped)="sectionDrop($event)" [cdkDropListData]="page.sections">
<ng-container *ngFor="let section of page.sections; let i = index">
<button mat-fab class="add-section-button"
(click)="addSection(i)">
<mat-icon>add</mat-icon>
</button>
<div app-canvas-section class="section"
[section]="section" [sectionEditMode]="sectionEditMode"
(deleteSection)="deleteSection($event)"
cdkDrag>
</div>
</ng-container>
</div>
<button mat-fab class="add-section-button" [style.width.px]="page.width" [style.margin.px]="page.margin"
(click)="addSection()">
<mat-icon>add</mat-icon>
</button>
</div>
import {
Component, Input, QueryList, ViewChildren
} from '@angular/core';
import { CdkDragDrop, transferArrayItem } from '@angular/cdk/drag-drop';
import { Component, Input } from '@angular/core';
import { CdkDragDrop, moveItemInArray, transferArrayItem } from '@angular/cdk/drag-drop';
import { MatSlideToggleChange } from '@angular/material/slide-toggle';
import { UnitPage, UnitPageSection } from '../../../../../../../common/unit';
import { UnitService } from '../../../../unit.service';
import { SectionComponent } from './section.component';
import { SelectionService } from '../../../../selection.service';
@Component({
......@@ -12,12 +10,15 @@ import { SelectionService } from '../../../../selection.service';
templateUrl: './page-canvas.component.html',
styles: [
'.section {position: relative}',
'.canvasBackground {background-color: lightgrey; padding:20px; height: 100%; overflow: auto;}'
'.canvasBackground {background-color: lightgrey; padding: 20px; 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}'
]
})
export class PageCanvasComponent {
@Input() page!: UnitPage;
@ViewChildren('section_component') canvasSections!: QueryList<SectionComponent>;
sectionEditMode: boolean = false;
constructor(private selectionService: SelectionService, public unitService: UnitService) { }
......@@ -54,4 +55,21 @@ export class PageCanvasComponent {
const reduceFct = (accumulator: number, currentValue: UnitPageSection) => accumulator + currentValue.height;
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);
}
deleteSection(index: number): void {
this.unitService.deleteSection(this.page.sections[index]);
}
sectionDrop(event: CdkDragDrop<UnitPageSection[]>): void {
moveItemInArray(this.page.sections, event.previousIndex, event.currentIndex);
this.unitService.setSections(this.page, this.page.sections);
}
}
import { Component, Input } from '@angular/core';
import {
Component, EventEmitter, Input, Output
} from '@angular/core';
import { CdkDragDrop } from '@angular/cdk/drag-drop/drag-events';
import { UnitPageSection } from '../../../../../../../common/unit';
import { UnitService } from '../../../../unit.service';
......@@ -7,7 +9,8 @@ import { SelectionService } from '../../../../selection.service';
@Component({
selector: '[app-canvas-section]',
template: `
<div class="section-wrapper"
<div *ngIf="!sectionEditMode"
#sectionElement class="section-wrapper"
[style.border]="selected ? '1px solid': '1px dotted'"
[style.height.px]="section.height"
[style.background-color]="section.backgroundColor"
......@@ -59,33 +62,57 @@ import { SelectionService } from '../../../../selection.service';
[style.height.px]="dragging ? draggingElementHeight : null">
</app-dynamic-canvas-overlay>
</div>
</div>
<div class="sectionMenu" fxLayout="column">
<button mat-mini-fab color="accent"
(click)="unitService.moveSection(sectionIndex, 'up')">
<mat-icon inline>arrow_upward</mat-icon>
</button>
<button mat-mini-fab color="accent"
(click)="unitService.moveSection(sectionIndex, 'down')">
<mat-icon inline>arrow_downward</mat-icon>
</button>
<div *ngIf="sectionEditMode"
#sectionElement class="section-wrapper"
[style.border]="selected ? '1px solid': '1px dotted'"
[style.height.px]="section.height"
[style.background-color]="section.backgroundColor"
[style.cursor]="'move'"
(click)="selectionService.selectSection(this)">
<button mat-mini-fab class="delete-section-button"
(click)="deleteSection.emit(sectionIndex)">
<mat-icon>clear</mat-icon>
</button>
<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">
<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: [
'.sectionMenu {visibility: hidden; transition: 0.2s 0.7s;}',
'.section-wrapper {width: 100%}',
'.section-wrapper:hover .sectionMenu {visibility: visible; transition-delay: 0s;}',
'.sectionMenu {position: absolute; left: -29px; top: 0}',
'.sectionMenu button {width: 28px; height: 28px}',
'.sectionMenu .mat-mini-fab {line-height: 0;}',
'::ng-deep .sectionMenu .mat-mini-fab .mat-button-wrapper {line-height: 0;}',
'.grid-placeholder {border: 25px inset aliceblue; text-align: center;}'
'.grid-placeholder {border: 25px inset aliceblue; text-align: center;}',
'.delete-section-button {position: absolute; right: -18px; top: -18px}'
]
})
export class SectionComponent {
@Input() section!: UnitPageSection;
@Input() sectionIndex!: number;
@Input() sectionEditMode: boolean = false;
@Output() deleteSection = new EventEmitter<number>();
selected = true;
dragging = false;
draggingElementWidth: number | undefined = 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 {
}
......@@ -73,8 +73,12 @@ export class UnitService {
return this._unit.value.pages.length > 1 && this._unit.value.pages.find(page => page.alwaysVisible) === undefined;
}
addSection(page: UnitPage): void {
page.sections.push(UnitFactory.createUnitPageSection());
addSection(page: UnitPage, index: number | null = null): void {
if (index != null) {
page.sections.splice(index, 0, UnitFactory.createUnitPageSection());
} else {
page.sections.push(UnitFactory.createUnitPageSection());
}
this._unit.next(this._unit.value);
this.veronaApiService.sendVoeDefinitionChangedNotification();
}
......@@ -92,14 +96,8 @@ export class UnitService {
}
}
moveSection(sectionIndex: number, direction: 'up' | 'down'): void {
const movedElement = this._unit.value.pages[this.selectedPageIndex].sections[sectionIndex];
this._unit.value.pages[this.selectedPageIndex].sections.splice(sectionIndex, 1);
if (direction === 'up') {
this._unit.value.pages[this.selectedPageIndex].sections.splice(sectionIndex - 1, 0, movedElement);
} else {
this._unit.value.pages[this.selectedPageIndex].sections.splice(sectionIndex + 1, 0, movedElement);
}
setPageSections(page: UnitPage, sections: UnitPageSection[]): void {
this._unit.value.pages[this.selectedPageIndex].sections = sections;
this.veronaApiService.sendVoeDefinitionChangedNotification();
}
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment