diff --git a/projects/common/assets/playlist_remove.svg b/projects/common/assets/playlist_remove.svg new file mode 100644 index 0000000000000000000000000000000000000000..88bc9bd6e0b2de49f1a2c12c331f658d0c2ecca0 --- /dev/null +++ b/projects/common/assets/playlist_remove.svg @@ -0,0 +1 @@ +<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="white"><path d="m576-80-56-56 104-104-104-104 56-56 104 104 104-104 56 56-104 104 104 104-56 56-104-104L576-80ZM120-320v-80h280v80H120Zm0-160v-80h440v80H120Zm0-160v-80h440v80H120Z"/></svg> \ No newline at end of file diff --git a/projects/common/models/section.ts b/projects/common/models/section.ts index 9233e58ca11497b4a424b7244a6ec1a52e453913..edb66eb8852d990845e207b67b8bc8d06af6b8c4 100644 --- a/projects/common/models/section.ts +++ b/projects/common/models/section.ts @@ -27,6 +27,7 @@ export class Section { enableReHide: boolean = false; logicalConnectiveOfRules: 'disjunction' | 'conjunction' = 'disjunction'; visibilityRules: VisibilityRule[] = []; + ignoreNumbering: boolean = false; constructor(section?: SectionProperties) { if (section && isValid(section)) { @@ -44,6 +45,7 @@ export class Section { this.visibilityRules = section.visibilityRules.map(rule => ({ ...rule })); this.elements = section.elements .map(element => ElementFactory.createElement(element)) as PositionedUIElement[]; + this.ignoreNumbering = section.ignoreNumbering; } else { if (environment.strictInstantiation) { throw new InstantiationEror('Error at Section instantiation'); @@ -63,6 +65,7 @@ export class Section { this.elements = section?.elements !== undefined ? section.elements.map(element => ElementFactory.createElement(element)) as PositionedUIElement[] : []; + if (section?.ignoreNumbering !== undefined) this.ignoreNumbering = section.ignoreNumbering; } } @@ -112,6 +115,7 @@ export interface SectionProperties { enableReHide: boolean; logicalConnectiveOfRules: 'disjunction' | 'conjunction'; visibilityRules: VisibilityRule[]; + ignoreNumbering: boolean; } function isValid(blueprint?: SectionProperties): boolean { @@ -128,5 +132,6 @@ function isValid(blueprint?: SectionProperties): boolean { blueprint.animatedVisibility !== undefined && blueprint.enableReHide !== undefined && blueprint.logicalConnectiveOfRules !== undefined && - blueprint.visibilityRules !== undefined; + blueprint.visibilityRules !== undefined && + blueprint.ignoreNumbering !== undefined; } diff --git a/projects/common/models/unit.ts b/projects/common/models/unit.ts index 2606b9c5bb49e2009aaa13edf306ab7bef7d0009..c4b52e8b1ad40bc076422d545a245d50fcb9c45b 100644 --- a/projects/common/models/unit.ts +++ b/projects/common/models/unit.ts @@ -13,12 +13,16 @@ export class Unit implements UnitProperties { version: string; stateVariables: StateVariable[] = []; pages: Page[]; + enableSectionNumbering: boolean = false; + sectionNumberingPosition: 'left' | 'above' = 'left'; constructor(unit?: UnitProperties) { if (unit && isValid(unit)) { this.version = unit.version; this.stateVariables = unit.stateVariables; this.pages = unit.pages.map(page => new Page(page)); + this.enableSectionNumbering = unit.enableSectionNumbering; + this.sectionNumberingPosition = unit.sectionNumberingPosition; } else { if (environment.strictInstantiation) { throw new InstantiationEror('Error at unit instantiation'); @@ -26,6 +30,8 @@ export class Unit implements UnitProperties { this.version = VersionManager.getCurrentVersion(); if (unit?.stateVariables !== undefined) this.stateVariables = unit.stateVariables; this.pages = unit?.pages.map(page => new Page(page)) || [new Page()]; + if (unit?.enableSectionNumbering !== undefined) this.enableSectionNumbering = unit.enableSectionNumbering; + if (unit?.sectionNumberingPosition !== undefined) this.sectionNumberingPosition = unit.sectionNumberingPosition; } } @@ -46,7 +52,9 @@ function isValid(blueprint?: UnitProperties): boolean { return blueprint.version === VersionManager.getCurrentVersion() && blueprint.stateVariables !== undefined && blueprint.type !== undefined && - blueprint.pages !== undefined; + blueprint.pages !== undefined && + blueprint.enableSectionNumbering !== undefined && + blueprint.sectionNumberingPosition !== undefined; } export interface UnitProperties { @@ -54,4 +62,6 @@ export interface UnitProperties { version: string; stateVariables: StateVariable[]; pages: Page[]; + enableSectionNumbering: boolean; + sectionNumberingPosition: 'left' | 'above'; } diff --git a/projects/common/util/section-counter.ts b/projects/common/util/section-counter.ts new file mode 100644 index 0000000000000000000000000000000000000000..6b5c90d134b98a8232bca1d7086a25e378e1baee --- /dev/null +++ b/projects/common/util/section-counter.ts @@ -0,0 +1,12 @@ +export class SectionCounter { + private static counter: number = 0; + + static getNext(): number { + SectionCounter.counter += 1; + return SectionCounter.counter; + } + + static reset(): void { + SectionCounter.counter = 0; + } +} diff --git a/projects/editor/src/app/app.component.ts b/projects/editor/src/app/app.component.ts index 95ca2f6c011fc0c225146cb9812968be92b97375..b7214519ca41bb263ed8748e7031b9016b8b0985 100644 --- a/projects/editor/src/app/app.component.ts +++ b/projects/editor/src/app/app.component.ts @@ -4,6 +4,8 @@ import { registerLocaleData } from '@angular/common'; import localeDe from '@angular/common/locales/de'; import { VeronaAPIService, StartCommand } from './services/verona-api.service'; import { UnitService } from './services/unit-services/unit.service'; +import { MatIconRegistry } from '@angular/material/icon'; +import { DomSanitizer } from '@angular/platform-browser'; @Component({ selector: 'aspect-editor', @@ -25,9 +27,13 @@ export class AppComponent implements OnInit { constructor(private unitService: UnitService, private translateService: TranslateService, - private veronaApiService: VeronaAPIService) { + private veronaApiService: VeronaAPIService, + private matIconRegistry: MatIconRegistry, + private domSanitizer: DomSanitizer) { translateService.addLangs(['de']); translateService.setDefaultLang('de'); + this.matIconRegistry.addSvgIcon('playlist_remove', + this.domSanitizer.bypassSecurityTrustResourceUrl('assets/playlist_remove.svg')); } ngOnInit(): void { diff --git a/projects/editor/src/app/components/unit-view/canvas/canvas.component.html b/projects/editor/src/app/components/unit-view/canvas/canvas.component.html index 83918eca7e1f91b10371f4fae5bd630615f4a953..8924a17a847b4f767bcde0dded7e68dc60390e51 100644 --- a/projects/editor/src/app/components/unit-view/canvas/canvas.component.html +++ b/projects/editor/src/app/components/unit-view/canvas/canvas.component.html @@ -32,6 +32,7 @@ class="section drop-list" [section]="section" [sectionIndex]="i" [isSelected]="selectionService.selectedSectionIndex === i" + [ignoreSectionCounter]="!unitService.unit.enableSectionNumbering || page.alwaysVisible || section.ignoreNumbering" (elementSelected)="selectionService.selectedSectionIndex = i" (transferElement)="moveElementsBetweenSections(selectionService.getSelectedElements(), $event.previousSectionIndex, diff --git a/projects/editor/src/app/components/unit-view/canvas/canvas.component.ts b/projects/editor/src/app/components/unit-view/canvas/canvas.component.ts index b78a45ee4495018b606217efbf10cc3e342c55ac..cf02a923bdd295e7abf7e5dc32ceacb0e674c7cc 100644 --- a/projects/editor/src/app/components/unit-view/canvas/canvas.component.ts +++ b/projects/editor/src/app/components/unit-view/canvas/canvas.component.ts @@ -1,5 +1,5 @@ import { - Component, Input, QueryList, ViewChildren + Component, Input, OnDestroy, OnInit, QueryList, ViewChildren } from '@angular/core'; import { CdkDragDrop } from '@angular/cdk/drag-drop'; import { PositionedUIElement, UIElement } from 'common/models/elements/element'; @@ -12,6 +12,8 @@ import { SectionStaticComponent } from './section-static/section-static.componen import { SectionDynamicComponent } from './section-dynamic/section-dynamic.component'; import { SectionService } from 'editor/src/app/services/unit-services/section.service'; import { ElementService } from 'editor/src/app/services/unit-services/element.service'; +import { takeUntil } from 'rxjs/operators'; +import { Subject } from 'rxjs'; @Component({ selector: 'aspect-page-canvas', @@ -39,16 +41,30 @@ import { ElementService } from 'editor/src/app/services/unit-services/element.se } `] }) -export class CanvasComponent { +export class CanvasComponent implements OnInit, OnDestroy { @Input() page!: Page; @ViewChildren('sectionComponent') sectionComponents!: QueryList<SectionStaticComponent | SectionDynamicComponent>; + private ngUnsubscribe = new Subject<void>(); + constructor(public selectionService: SelectionService, public unitService: UnitService, public elementService: ElementService, public sectionService: SectionService) { } + ngOnInit(): void { + this.unitService.sectionCountUpdated + .pipe(takeUntil(this.ngUnsubscribe)) + .subscribe( + () => { + this.sectionComponents.toArray() + .filter(comp => comp instanceof SectionDynamicComponent) + .forEach(sectionComp => (sectionComp as SectionDynamicComponent).updateSectionCounter()); + } + ); + } + moveElementsBetweenSections(elements: UIElement[], previousSectionIndex: number, newSectionIndex: number): void { this.sectionService.transferElements(elements, this.page.sections[previousSectionIndex], @@ -114,4 +130,9 @@ export class CanvasComponent { } return null; } + + ngOnDestroy(): void { + this.ngUnsubscribe.next(); + this.ngUnsubscribe.complete(); + } } diff --git a/projects/editor/src/app/components/unit-view/canvas/section-dynamic/section-dynamic.component.ts b/projects/editor/src/app/components/unit-view/canvas/section-dynamic/section-dynamic.component.ts index 7f6fb03e75d09983ce2b2effeed7ace1f61b1ea4..8e98e666d5b913ac6b837394386f31cabcdce03e 100644 --- a/projects/editor/src/app/components/unit-view/canvas/section-dynamic/section-dynamic.component.ts +++ b/projects/editor/src/app/components/unit-view/canvas/section-dynamic/section-dynamic.component.ts @@ -1,8 +1,10 @@ import { Component, Input, Output, EventEmitter, - ViewChildren, QueryList, ViewChild + ViewChildren, QueryList, ViewChild, OnInit } from '@angular/core'; import { Section } from 'common/models/section'; +import { SectionCounter } from 'common/util/section-counter'; +import { UnitService } from 'editor/src/app/services/unit-services/unit.service'; import { DragNDropService } from 'editor/src/app/services/drag-n-drop.service'; import { CanvasElementOverlay } from '../canvas-element-overlay'; import { DynamicSectionHelperGridComponent } from './dynamic-section-helper-grid.component'; @@ -10,71 +12,96 @@ import { DynamicSectionHelperGridComponent } from './dynamic-section-helper-grid @Component({ selector: 'aspect-section-dynamic', template: ` - <div [style.display]="'grid'" - [style.grid-template-columns]="section.autoColumnSize ? '' : section.gridColumnSizes | measure" - [style.grid-template-rows]="section.autoRowSize ? '' : section.gridRowSizes | measure" - [style.grid-auto-columns]="'auto'" - [style.grid-auto-rows]="'auto'" - [style.border]="isSelected ? '2px solid #ff4081': '1px dotted'" - [style.min-height.px]="section.autoRowSize ? 50 : null" - [style.height.px]="section.autoRowSize ? null : section.height" - [style.background-color]="section.backgroundColor" - app-dynamic-section-helper-grid - [autoColumnSize]="section.autoColumnSize" - [autoRowSize]="section.autoRowSize" - [gridColumnSizes]="section.gridColumnSizes" - [gridRowSizes]="section.gridRowSizes" - [section]="section" - [sectionIndex]="sectionIndex" - [style.isolation]="'isolate'" - (transferElement)="transferElement.emit($event)"> + <div class="section-wrapper" + [ngClass]="unitService.unit.sectionNumberingPosition === 'left' ? 'row-align' : 'column-align'"> + <div *ngIf="unitService.unit.enableSectionNumbering" [style.min-width.px]="35" [style.font-size.px]="20"> + <b *ngIf="sectionCounter">{{sectionCounter}}.</b> + </div> + <div [style.display]="'grid'" + [style.flex-grow]="1" + [style.grid-template-columns]="section.autoColumnSize ? '' : section.gridColumnSizes | measure" + [style.grid-template-rows]="section.autoRowSize ? '' : section.gridRowSizes | measure" + [style.grid-auto-columns]="'auto'" + [style.grid-auto-rows]="'auto'" + [style.border]="isSelected ? '2px solid #ff4081': '1px dotted'" + [style.min-height.px]="section.autoRowSize ? 50 : null" + [style.height.px]="section.autoRowSize ? null : section.height" + [style.background-color]="section.backgroundColor" + app-dynamic-section-helper-grid + [autoColumnSize]="section.autoColumnSize" + [autoRowSize]="section.autoRowSize" + [gridColumnSizes]="section.gridColumnSizes" + [gridRowSizes]="section.gridRowSizes" + [section]="section" + [sectionIndex]="sectionIndex" + [style.isolation]="'isolate'" + (transferElement)="transferElement.emit($event)"> - <!-- Angular content projection is used in the helper grid component, where the following - is the content.--> - <aspect-dynamic-canvas-overlay *ngFor="let element of section.elements" - #elementComponent - [style.z-index]="element.position.zIndex" - [element]="$any(element)" - [style.margin-left]="[element.position.marginLeft] | measure" - [style.margin-right]="[element.position.marginRight] | measure" - [style.margin-top]="[element.position.marginTop] | measure" - [style.margin-bottom]="[element.position.marginBottom] | measure" - [style.grid-column-start]="element.position.gridColumn" - [style.grid-column-end]="element.position.gridColumn ? - element.position.gridColumn + element.position.gridColumnRange : - null" - [style.grid-row-start]="element.position.gridRow" - [style.grid-row-end]="element.position.gridRow ? - element.position.gridRow + element.position.gridRowRange : - null" - cdkDropList cdkDropListSortingDisabled - [cdkDropListData]="{ sectionIndex: sectionIndex }" - [cdkDropListConnectedTo]="dropListList" - [style.position]="'relative'" - [style.pointer-events]="dragNDropService.isDragInProgress && - element.type == 'frame' ? - 'none' : 'auto'" - appElementGridChangeListener - [gridColumn]="element.position.gridColumn" - [gridColumnRange]="element.position.gridColumnRange" - [gridRow]="element.position.gridRow" - [gridRowRange]="element.position.gridRowRange" - (elementSelected)="elementSelected.emit()" - (elementChanged)="helperGrid && helperGrid.refresh()"> - </aspect-dynamic-canvas-overlay> + <!-- Angular content projection is used in the helper grid component, where the following + is the content.--> + <aspect-dynamic-canvas-overlay *ngFor="let element of section.elements" + #elementComponent + [style.z-index]="element.position.zIndex" + [element]="$any(element)" + [style.margin-left]="[element.position.marginLeft] | measure" + [style.margin-right]="[element.position.marginRight] | measure" + [style.margin-top]="[element.position.marginTop] | measure" + [style.margin-bottom]="[element.position.marginBottom] | measure" + [style.grid-column-start]="element.position.gridColumn" + [style.grid-column-end]="element.position.gridColumn ? + element.position.gridColumn + element.position.gridColumnRange : + null" + [style.grid-row-start]="element.position.gridRow" + [style.grid-row-end]="element.position.gridRow ? + element.position.gridRow + element.position.gridRowRange : + null" + cdkDropList cdkDropListSortingDisabled + [cdkDropListData]="{ sectionIndex: sectionIndex }" + [cdkDropListConnectedTo]="dropListList" + [style.position]="'relative'" + [style.pointer-events]="dragNDropService.isDragInProgress && + element.type == 'frame' ? + 'none' : 'auto'" + appElementGridChangeListener + [gridColumn]="element.position.gridColumn" + [gridColumnRange]="element.position.gridColumnRange" + [gridRow]="element.position.gridRow" + [gridRowRange]="element.position.gridRowRange" + [style.align-items]="'baseline'" + (elementSelected)="elementSelected.emit()" + (elementChanged)="helperGrid && helperGrid.refresh()"> + </aspect-dynamic-canvas-overlay> + </div> </div> + `, + styles: ` + .section-wrapper {display: flex;} + .section-wrapper.row-align {flex-direction: row; align-items: baseline;} + .section-wrapper.column-align {flex-direction: column;} ` }) -export class SectionDynamicComponent { +export class SectionDynamicComponent implements OnInit { @Input() section!: Section; @Input() sectionIndex!: number; @Input() dropListList!: string[]; @Input() isSelected!: boolean; + @Input() ignoreSectionCounter: boolean = true; @Output() transferElement = new EventEmitter<{ previousSectionIndex: number, newSectionIndex: number }>(); @Output() elementSelected = new EventEmitter(); @ViewChild(DynamicSectionHelperGridComponent) helperGrid!: DynamicSectionHelperGridComponent; @ViewChildren('elementComponent') childElementComponents!: QueryList<CanvasElementOverlay>; - constructor(protected dragNDropService: DragNDropService) { } + sectionCounter: number | undefined; + + constructor(protected dragNDropService: DragNDropService, protected unitService: UnitService) { } + + ngOnInit(): void { + this.updateSectionCounter(); + } + + updateSectionCounter(): void { + this.sectionCounter = undefined; + if (!this.ignoreSectionCounter) this.sectionCounter = SectionCounter.getNext(); + } } diff --git a/projects/editor/src/app/components/unit-view/canvas/section-menu.component.ts b/projects/editor/src/app/components/unit-view/canvas/section-menu.component.ts index ef9a7d8520276aba6fed2b098f8176680f10d63c..23fbb142cf340a241ea2e065bf1f70d00e716ec5 100644 --- a/projects/editor/src/app/components/unit-view/canvas/section-menu.component.ts +++ b/projects/editor/src/app/components/unit-view/canvas/section-menu.component.ts @@ -44,6 +44,14 @@ import { SectionService } from 'editor/src/app/services/unit-services/section.se [value]="$any(section.backgroundColor)" (change)="updateModel('backgroundColor', $any($event.target).value)"> + + <button mat-mini-fab [color]="section.ignoreNumbering ? 'primary' : 'accent'" + (click)="ignoreNumbering()" + [matTooltip]="'Von der Nummerierung ausnehmen'" [matTooltipPosition]="'left'"> + <mat-icon>playlist_remove</mat-icon> + </button> + + <button mat-mini-fab (click)="showVisibilityRulesDialog()" [matTooltip]="'Sichtbarkeit'" [matTooltipPosition]="'left'"> @@ -298,4 +306,8 @@ export class SectionMenuComponent implements OnDestroy { .concat(this.unitService.unit.stateVariables .map(element => element.id)); } + + ignoreNumbering() { + this.updateModel('ignoreNumbering', !this.section.ignoreNumbering); + } } diff --git a/projects/editor/src/app/components/unit-view/page-menu.component.ts b/projects/editor/src/app/components/unit-view/page-menu.component.ts index 478aefafa628cb624d025e689d5c73e731e1fda8..17b14327fe68f2d462e9ebad675d5e65f522e621 100644 --- a/projects/editor/src/app/components/unit-view/page-menu.component.ts +++ b/projects/editor/src/app/components/unit-view/page-menu.component.ts @@ -87,6 +87,7 @@ export class PageMenu implements OnDestroy { this.movePageToFront(page); page.alwaysVisible = true; this.selectionService.selectedPageIndex = 0; + this.unitService.updateSectionCounter(); this.pageOrderChanged.emit(); } page[property] = value; diff --git a/projects/editor/src/app/components/unit-view/unit-view.component.html b/projects/editor/src/app/components/unit-view/unit-view.component.html index d543893d7833c47bd4b9b7bd7b22ba8161daec1d..66bf2e386998399a843d5258cf8c44e5fac906cf 100644 --- a/projects/editor/src/app/components/unit-view/unit-view.component.html +++ b/projects/editor/src/app/components/unit-view/unit-view.component.html @@ -72,6 +72,25 @@ </ng-template> </mat-tab> + <mat-tab disabled> + <ng-template mat-tab-label> + <button mat-icon-button [matMenuTriggerFor]="numberingMenu"> + <mat-icon>format_list_numbered</mat-icon> + </button> + <mat-menu #numberingMenu="matMenu" (click)="$event.stopPropagation()"> + <div [style.padding]="'0 20px 10px'" (click)="$event.stopPropagation()"> + <h3>Abschnittsnummerierung</h3> + <mat-checkbox #numberingInput (change)="setSectionNumbering($event)"> + Nummerierung aktivieren + </mat-checkbox> + <mat-checkbox [disabled]="!numberingInput.checked" (change)="setSectionNumberingPosition($event)"> + vertikale Ausrichtung + </mat-checkbox> + </div> + </mat-menu> + </ng-template> + </mat-tab> + </mat-tab-group> </mat-drawer-content> diff --git a/projects/editor/src/app/components/unit-view/unit-view.component.ts b/projects/editor/src/app/components/unit-view/unit-view.component.ts index 71ee86a6431a9825656de7ad1d1c02de85bdf9bc..048c6cf30c3540712f38e12935888b9fe58feb4a 100644 --- a/projects/editor/src/app/components/unit-view/unit-view.component.ts +++ b/projects/editor/src/app/components/unit-view/unit-view.component.ts @@ -4,6 +4,7 @@ import { UnitService } from '../../services/unit-services/unit.service'; import { SelectionService } from '../../services/selection.service'; import { HistoryService } from 'editor/src/app/services/history.service'; import { PageService } from 'editor/src/app/services/unit-services/page.service'; +import { MatCheckboxChange } from '@angular/material/checkbox'; @Component({ selector: 'aspect-unit-view', @@ -35,4 +36,12 @@ export class UnitViewComponent { this.pagesLoaded = true; }); } + + setSectionNumbering(event: MatCheckboxChange) { + this.unitService.setSectionNumbering(event.checked); + } + + setSectionNumberingPosition(event: MatCheckboxChange) { + this.unitService.setSectionNumberingPosition(event.checked ? 'above' : 'left'); + } } diff --git a/projects/editor/src/app/services/unit-services/page.service.ts b/projects/editor/src/app/services/unit-services/page.service.ts index 5cdea1226386bb86b3bc52382bc7d1028c38b209..477c7b497442999b95d56f159d488f816290f328 100644 --- a/projects/editor/src/app/services/unit-services/page.service.ts +++ b/projects/editor/src/app/services/unit-services/page.service.ts @@ -37,6 +37,7 @@ export class PageService { this.unitService.unregisterIDs(selectedPage.getAllElements()); const deletedpage = this.unitService.unit.pages.splice(pageIndex, 1)[0]; this.selectionService.selectPreviousPage(); + this.unitService.updateSectionCounter(); return { pageIndex, deletedpage @@ -47,6 +48,7 @@ export class PageService { rollback: (deletedData: Record<string, unknown>) => { this.unitService.registerIDs((deletedData['deletedpage'] as Page).getAllElements()); this.unitService.unit.pages.splice(deletedData['pageIndex'] as number, 0, deletedData['deletedpage'] as Page); + this.unitService.updateSectionCounter(); } }); } @@ -60,6 +62,7 @@ export class PageService { this.unitService.unit.pages, direction === 'left' ? 'up' : 'down' ); + this.unitService.updateSectionCounter(); return {direction}; }, rollback: (deletedData: Record<string, unknown>) => { @@ -68,6 +71,7 @@ export class PageService { this.unitService.unit.pages, direction === 'left' ? 'up' : 'down' ); + this.unitService.updateSectionCounter(); } }); } diff --git a/projects/editor/src/app/services/unit-services/section.service.ts b/projects/editor/src/app/services/unit-services/section.service.ts index e160aa6aec47e2497610e75ae2498ca3c8868f46..63c317ee51c253547b8a6e0b793e65980b11fbbb 100644 --- a/projects/editor/src/app/services/unit-services/section.service.ts +++ b/projects/editor/src/app/services/unit-services/section.service.ts @@ -24,6 +24,7 @@ export class SectionService { command: () => { const oldValue = section[property]; section.setProperty(property, value); + if (property === 'ignoreNumbering') this.unitService.updateSectionCounter(); this.unitService.elementPropertyUpdated.next(); return {oldValue}; }, @@ -71,6 +72,7 @@ export class SectionService { this.unitService.unit.pages[pageIndex].sections.splice(sectionIndex, 1); this.selectionService.selectedSectionIndex = Math.max(0, this.selectionService.selectedSectionIndex - 1); + this.unitService.updateSectionCounter(); return {deletedSection: sectionToDelete, pageIndex, sectionIndex}; } return {}; @@ -80,6 +82,7 @@ export class SectionService { this.unitService.unit.pages[deletedData.pageIndex as number].addSection(deletedData.deletedSection as Section, sectionIndex); this.selectionService.selectedSectionIndex = Math.max(0, this.selectionService.selectedSectionIndex - 1); + this.unitService.updateSectionCounter(); } }); } @@ -94,12 +97,14 @@ export class SectionService { }); page.addSection(newSection, sectionIndex + 1); this.selectionService.selectedSectionIndex += 1; + this.unitService.updateSectionCounter(); return {}; }, rollback: (deletedData: Record<string, unknown>) => { this.unitService.unregisterIDs(page.sections[sectionIndex + 1].getAllElements()); page.deleteSection(sectionIndex + 1); this.selectionService.selectedSectionIndex -= 1; + this.unitService.updateSectionCounter(); } }); } @@ -110,11 +115,13 @@ export class SectionService { command: () => { ArrayUtils.moveArrayItem(section, page.sections, direction); direction === 'up' ? this.selectionService.selectedSectionIndex -= 1 : this.selectionService.selectedSectionIndex += 1; + this.unitService.updateSectionCounter(); return {}; }, rollback: (deletedData: Record<string, unknown>) => { ArrayUtils.moveArrayItem(section, page.sections, direction === 'up' ? 'down' : 'up'); direction === 'up' ? this.selectionService.selectedSectionIndex += 1 : this.selectionService.selectedSectionIndex -= 1; + this.unitService.updateSectionCounter(); } }); } diff --git a/projects/editor/src/app/services/unit-services/unit.service.ts b/projects/editor/src/app/services/unit-services/unit.service.ts index 356215ca934334bc62e29a237e97422106963c77..a0b962871714270220280a150e4d14600ea9234d 100644 --- a/projects/editor/src/app/services/unit-services/unit.service.ts +++ b/projects/editor/src/app/services/unit-services/unit.service.ts @@ -19,6 +19,7 @@ import { UnitDefinitionSanitizer } from '../sanitizer'; import { HistoryService, UnitUpdateCommand } from 'editor/src/app/services/history.service'; import { Page } from 'common/models/page'; import { Section } from 'common/models/section'; +import { SectionCounter } from 'common/util/section-counter'; @Injectable({ providedIn: 'root' @@ -29,6 +30,7 @@ export class UnitService { geometryElementPropertyUpdated: Subject<string> = new Subject<string>(); mathTableElementPropertyUpdated: Subject<string> = new Subject<string>(); tablePropUpdated: Subject<string> = new Subject<string>(); + sectionCountUpdated: Subject<void> = new Subject<void>(); referenceManager: ReferenceManager; savedSectionCode: string | undefined; @@ -209,4 +211,22 @@ export class UnitService { applyTemplate(templateName: string) { // TODO } + + updateSectionCounter(): void { + SectionCounter.reset(); + // Wait for the change to propagate through the components + setTimeout(() => this.sectionCountUpdated.next()); + } + + setSectionNumbering(isEnabled: boolean) { + this.unit.enableSectionNumbering = isEnabled; + this.updateUnitDefinition(); + this.updateSectionCounter(); + } + + setSectionNumberingPosition(position: 'above' | 'left') { + this.unit.sectionNumberingPosition = position; + this.updateUnitDefinition(); + this.updateSectionCounter(); + } }