diff --git a/projects/editor/src/app/app.module.ts b/projects/editor/src/app/app.module.ts index 58cc15c18317fff70e6bad8215789525d0a40b44..605bbb69eaa6b5a75852a5986f79959678306e6e 100644 --- a/projects/editor/src/app/app.module.ts +++ b/projects/editor/src/app/app.module.ts @@ -70,6 +70,7 @@ import { ImagePropertiesComponent } from './components/properties-panel/model-pr import { DropListPropertiesComponent } from './components/properties-panel/model-properties-tab/input-groups/drop-list-properties.component'; import { RichTextEditorSimpleComponent } from './text-editor-simple/rich-text-editor-simple.component'; import { RichTextSimpleEditDialogComponent } from './components/dialogs/rich-text-simple-edit-dialog.component'; +import { SectionInsertDialogComponent } from 'editor/src/app/components/dialogs/section-insert-dialog.component'; @NgModule({ declarations: [ @@ -111,7 +112,8 @@ import { RichTextSimpleEditDialogComponent } from './components/dialogs/rich-tex ImagePropertiesComponent, DropListPropertiesComponent, RichTextEditorSimpleComponent, - RichTextSimpleEditDialogComponent + RichTextSimpleEditDialogComponent, + SectionInsertDialogComponent ], imports: [ BrowserModule, diff --git a/projects/editor/src/app/components/canvas/section-menu.component.ts b/projects/editor/src/app/components/canvas/section-menu.component.ts index 638b05422369b5acd27cd37b00bebe30673471f1..b3ce0f25425cdfaa65f000d18d65ec4176607c73 100644 --- a/projects/editor/src/app/components/canvas/section-menu.component.ts +++ b/projects/editor/src/app/components/canvas/section-menu.component.ts @@ -23,7 +23,7 @@ import { Section } from 'common/models/section'; <mat-menu #elementListMenu="matMenu" class="layoutMenu" xPosition="before"> <mat-action-list> <ng-container *ngIf="section.elements.length === 0"> - Keine Elemente im Abschnitt + Keine Elemente im Abschnitt </ng-container> <mat-list-item *ngFor="let element of section.elements" (click)="selectElement(element)"> @@ -68,7 +68,7 @@ import { Section } from 'common/models/section'; <ng-container *ngIf="!section.dynamicPositioning"> <mat-form-field appearance="fill"> <mat-label>{{'section-menu.height' | translate }}</mat-label> - <input matInput type="number" + <input matInput type="number" [value]="$any(section.height)" (click)="$any($event).stopPropagation()" (change)="updateModel('height', $any($event.target).value)"> @@ -163,22 +163,15 @@ import { Section } from 'common/models/section'; </div> </mat-menu> - <button mat-mini-fab + <button mat-mini-fab [matTooltip]="'Abschnitt kopieren'" [matTooltipPosition]="'left'" (click)="copySectionToClipboard()"> <mat-icon>content_copy</mat-icon> </button> - - <button mat-mini-fab [matMenuTriggerFor]="pasteSectionMenu"> + <button mat-mini-fab + [matTooltip]="'Abschnitt einfügen'" [matTooltipPosition]="'left'" + (click)="showSectionInsertDialog()"> <mat-icon>content_paste</mat-icon> </button> - <mat-menu #pasteSectionMenu="matMenu" xPosition="before"> - <mat-form-field appearance="fill" (click)="$any($event).stopPropagation()"> -<!-- <mat-label>{{'section-menu.activeAfterID' | translate }}</mat-label>--> - <input matInput (click)="$any($event).stopPropagation()" - (paste)="pasteSectionFromClipboard($event);"> - </mat-form-field> - </mat-menu> - <button *ngIf="allowMoveUp" mat-mini-fab [matTooltip]="'Nach oben verschieben'" [matTooltipPosition]="'left'" (click)="this.moveSection.emit('up')"> @@ -311,23 +304,17 @@ export class SectionMenuComponent implements OnInit, OnDestroy { copySectionToClipboard() { this.clipboard.copy(JSON.stringify(this.section)); - console.log('bla', navigator.clipboard); + this.messageService.showSuccess('Abschnitt in Zwischenablage kopiert'); } - pasteSectionFromClipboard(event: ClipboardEvent) { - console.log('paste', event); - console.log('paste2', event.clipboardData?.getData('Text')); - const pastedText = event.clipboardData?.getData('Text'); - // TODO try catch - if (!pastedText) return; - try { - const newSection = new Section(JSON.parse(pastedText) as Section); - this.unitService.replaceSection(this.selectionService.selectedPageIndex, this.sectionIndex, newSection); - } catch (e) { - this.messageService.showError('Fehler beim Lesen der Sektion'); - } - // console.log('evvv', event.target); - // (event.target as HTMLInputElement).value = 'abc'; - event.stopPropagation(); + showSectionInsertDialog(): void { + this.dialogService.showSectionInsertDialog(this.section) + .pipe(takeUntil(this.ngUnsubscribe)) + .subscribe((newSection: Section) => { + if (newSection) { + this.unitService.replaceSection(this.selectionService.selectedPageIndex, this.sectionIndex, newSection); + } + }); } + } diff --git a/projects/editor/src/app/components/dialogs/section-insert-dialog.component.ts b/projects/editor/src/app/components/dialogs/section-insert-dialog.component.ts new file mode 100644 index 0000000000000000000000000000000000000000..89384e45cc02aa54b3400d2e019738e5b480d0e0 --- /dev/null +++ b/projects/editor/src/app/components/dialogs/section-insert-dialog.component.ts @@ -0,0 +1,83 @@ +import { Component, Inject } from '@angular/core'; +import { Section } from 'common/models/section'; +import { MessageService } from 'common/services/message.service'; +import { MAT_DIALOG_DATA } from '@angular/material/dialog'; +import { Subject } from 'rxjs'; +import { UIElement } from 'common/models/elements/element'; +import { IDManager } from 'common/util/id-manager'; +import { TranslateService } from '@ngx-translate/core'; + +@Component({ + selector: 'app-section-insert-dialog', + template: ` + <mat-dialog-content> + <div (mouseenter)="hovered = true;" (mouseleave)="hovered = false;"> + <div class="paste-area" contenteditable="true" *ngIf="isPastedTextPresent === false" + (paste)="pasteSectionFromClipboard($event)"> + </div> + <div *ngIf="!hovered || isPastedTextPresent" class="message-area" [style.background-color]="operationStatus"> + {{operationStatusText}} + </div> + </div> + </mat-dialog-content> + <mat-dialog-actions> + <button mat-button *ngIf="operationStatus === 'green' || operationStatus === 'yellow'" + [mat-dialog-close]="newSection"> + {{'confirm' | translate }} + </button> + <button mat-button mat-dialog-close>{{'cancel' | translate }}</button> + </mat-dialog-actions> + `, + styles: [ + '.mat-dialog-content {width: 400px; height: 200px;}', + '.paste-area {position: absolute; width: 400px; height: 200px; border: 1px solid; overflow: hidden}', + '.message-area {position: absolute; width: 400px; height: 200px; text-align: center; font-size: large;}' + ] +}) +export class SectionInsertDialogComponent { + private ngUnsubscribe = new Subject<void>(); + + operationStatus: 'red' | 'yellow' | 'green' | 'none' = 'none'; + operationStatusText: string = this.translateService.instant('Bitte kopierten Abschnitt einfügen'); + hovered = false; + isPastedTextPresent = false; + newSection: Section | null = null; + + constructor(@Inject(MAT_DIALOG_DATA) public data: { existingSection: Section }, + private messageService: MessageService, + private translateService: TranslateService) { } + + + pasteSectionFromClipboard(event: ClipboardEvent) { + this.isPastedTextPresent = true; + const pastedText = event.clipboardData?.getData('Text'); + if (!pastedText) { + this.operationStatusText = this.translateService.instant('Fehler beim Lesen des Abschnitts!'); + return; + } + try { + this.newSection = new Section(JSON.parse(pastedText)); + + if (this.findElementsWithDuplicateID(this.newSection.getAllChildElements()).length > 0) { + this.operationStatusText = + this.translateService.instant('Doppelte IDs festgestellt. Weiter mit neu generierten IDs?'); + this.operationStatus = 'yellow'; + } else { + this.operationStatusText = this.translateService.instant('Abschnitt wurde erfolgreich gelesen.'); + this.operationStatus = 'green'; + } + } catch (e) { + this.operationStatusText = this.translateService.instant('Fehler beim Lesen des Abschnitts!'); + this.operationStatus = 'red'; + } + } + + private findElementsWithDuplicateID(elements: UIElement[]): UIElement[] { + return elements.filter(element => !IDManager.getInstance().isIdAvailable(element.id)); + } + + ngOnDestroy(): void { + this.ngUnsubscribe.next(); + this.ngUnsubscribe.complete(); + } +} diff --git a/projects/editor/src/app/services/dialog.service.ts b/projects/editor/src/app/services/dialog.service.ts index 8ae192880047efc0e200186bdd7832442028c708..86f6863805a82d8287a9e5e7224da278ae976c6d 100644 --- a/projects/editor/src/app/services/dialog.service.ts +++ b/projects/editor/src/app/services/dialog.service.ts @@ -13,6 +13,8 @@ import { RichTextSimpleEditDialogComponent } from '../components/dialogs/rich-te import { DragNDropValueObject, PlayerProperties, TextImageLabel } from 'common/models/elements/element'; import { ClozeDocument } from 'common/models/elements/compound-elements/cloze/cloze'; import { LikertRowElement } from 'common/models/elements/compound-elements/likert/likert-row'; +import { SectionInsertDialogComponent } from 'editor/src/app/components/dialogs/section-insert-dialog.component'; +import { Section } from 'common/models/section'; @Injectable({ providedIn: 'root' @@ -99,4 +101,11 @@ export class DialogService { }); return dialogRef.afterClosed(); } + + showSectionInsertDialog(section: Section): Observable<Section> { + const dialogRef = this.dialog.open(SectionInsertDialogComponent, { + data: { section } + }); + return dialogRef.afterClosed(); + } } diff --git a/projects/editor/src/assets/i18n/de.json b/projects/editor/src/assets/i18n/de.json index a84f5751780bee5847474ebba1d275dd819f73ea..96577f79d0b8d6bca5fab3b9f7f844ab14f17538 100644 --- a/projects/editor/src/assets/i18n/de.json +++ b/projects/editor/src/assets/i18n/de.json @@ -215,5 +215,9 @@ "fraction": "Anteile", "pixel": "Bildpunkte", "activeAfterID": "Sichtbar nach A/V-ID" - } + }, + "Bitte kopierten Abschnitt einfügen": "Bitte kopierten Abschnitt einfügen", + "Doppelte IDs festgestellt. Weiter mit neu generierten IDs?": "Doppelte IDs festgestellt. Weiter mit neu generierten IDs?", + "Abschnitt wurde erfolgreich gelesen.": "Abschnitt wurde erfolgreich gelesen.", + "Fehler beim Lesen des Abschnitts!": "Fehler beim Lesen des Abschnitts!" }