From efeea398da3e4a2c3cd91c1eb31eede548074eb0 Mon Sep 17 00:00:00 2001 From: Sofia Papacharalampous Date: Tue, 30 Apr 2024 14:25:54 +0300 Subject: [PATCH] fixed toc drag and drop on description template type editor --- .../description-template.module.ts | 5 +- .../description-template-table-of-contents.ts | 1067 +++++++++++------ 2 files changed, 726 insertions(+), 346 deletions(-) diff --git a/dmp-frontend/src/app/ui/admin/description-template/description-template.module.ts b/dmp-frontend/src/app/ui/admin/description-template/description-template.module.ts index 27ae25a54..6508d5949 100644 --- a/dmp-frontend/src/app/ui/admin/description-template/description-template.module.ts +++ b/dmp-frontend/src/app/ui/admin/description-template/description-template.module.ts @@ -32,6 +32,7 @@ import { ImportDescriptionTemplateDialogComponent } from './listing/import-descr import { DescriptionTemplateEditorReferenceTypeFieldComponent } from './editor/components/field-type/reference-type/description-template-editor-reference-type-field.component'; import { DescriptionFormModule } from '@app/ui/description/editor/description-form/description-form.module'; import { FinalPreviewComponent } from './editor/components/final-preview/final-preview.component'; +import { DragulaModule } from 'ng2-dragula'; @NgModule({ imports: [ @@ -47,8 +48,8 @@ import { FinalPreviewComponent } from './editor/components/final-preview/final-p UserSettingsModule, CommonFormattingModule, RichTextEditorModule, - - DescriptionFormModule + DescriptionFormModule, + DragulaModule.forRoot(), ], declarations: [ DescriptionTemplateEditorComponent, diff --git a/dmp-frontend/src/app/ui/admin/description-template/editor/table-of-contents/description-template-table-of-contents.ts b/dmp-frontend/src/app/ui/admin/description-template/editor/table-of-contents/description-template-table-of-contents.ts index 66ea13348..3f6f4313e 100644 --- a/dmp-frontend/src/app/ui/admin/description-template/editor/table-of-contents/description-template-table-of-contents.ts +++ b/dmp-frontend/src/app/ui/admin/description-template/editor/table-of-contents/description-template-table-of-contents.ts @@ -1,11 +1,11 @@ import { DOCUMENT } from '@angular/common'; -import { AfterViewInit, Component, EventEmitter, Inject, Input, OnInit, Output } from '@angular/core'; +import { AfterViewInit, Component, EventEmitter, Inject, Input, OnDestroy, OnInit, Output } from '@angular/core'; import { UntypedFormArray } from '@angular/forms'; import { MatSnackBar, MatSnackBarConfig } from '@angular/material/snack-bar'; import { BaseComponent } from '@common/base/base.component'; import { TranslateService } from '@ngx-translate/core'; import { DragulaService } from 'ng2-dragula'; -import { interval } from 'rxjs'; +import { Subscription, interval } from 'rxjs'; import { filter, takeUntil } from 'rxjs/operators'; import { NewEntryType, TableUpdateInfo, ToCEntry, ToCEntryType } from './description-template-table-of-contents-entry'; @@ -13,9 +13,9 @@ import { NewEntryType, TableUpdateInfo, ToCEntry, ToCEntryType } from './descrip @Component({ selector: 'description-template-table-of-contents', styleUrls: ['./description-template-table-of-contents.scss'], - templateUrl: './description-template-table-of-contents.html' + templateUrl: './description-template-table-of-contents.html', }) -export class DescriptionTemplateTableOfContents extends BaseComponent implements OnInit, AfterViewInit { +export class DescriptionTemplateTableOfContents extends BaseComponent implements OnInit, AfterViewInit, OnDestroy { @Input() links: ToCEntry[]; @Input() itemSelected: ToCEntry; @@ -31,7 +31,8 @@ export class DescriptionTemplateTableOfContents extends BaseComponent implements isDragging: boolean = false; draggingItemId: string = null; tocEntryType = ToCEntryType; - + dragSubscriptions: Subscription[] = []; + DRAG_GROUP: string = "TABLEDRAG"; DRAGULA_ITEM_ID_PREFIX = "table_item_id_"; ROOT_ID: string = "ROOT_ID";//no special meaning private _dragStartedAt; @@ -51,396 +52,778 @@ export class DescriptionTemplateTableOfContents extends BaseComponent implements ) { super(); - if (this.dragulaService.find('TABLEDRAG')) { - this.dragulaService.destroy('TABLEDRAG'); - } + this.dragSubscriptions.push( + dragulaService.drag(this.DRAG_GROUP).subscribe(({ el }) => { + this._dragStartedAt = new Date().getTime(); + // console.log('drag fired'); + this.isDragging = true; + this.draggingItemId = (el.id as string).replace(this.DRAGULA_ITEM_ID_PREFIX, ''); + }) + ); - const dragula = this.dragulaService.createGroup('TABLEDRAG', {}); + this.dragSubscriptions.push( + dragulaService.drop(this.DRAG_GROUP).subscribe(({ el, target, source, sibling }) => { + if (this._dragStartedAt) { + const timeNow = new Date().getTime(); - const drake = dragula.drake; - - drake.on('drop', (el, target, source, sibling) => { - - if (this._dragStartedAt) { - const timeNow = new Date().getTime(); - - if (timeNow - this._dragStartedAt > this.VALID_DROP_TIME) { - // console.log('timenow: ', timeNow); - // console.log('timestarted', this._dragStartedAt); - this._dragStartedAt = null; + if (timeNow - this._dragStartedAt > this.VALID_DROP_TIME) { + // console.log('timenow: ', timeNow); + // console.log('timestarted', this._dragStartedAt); + this._dragStartedAt = null; + } else { + this.dataNeedsRefresh.emit();// even though the data is not changed the TABLE DRAG may has changed + return; + } } else { this.dataNeedsRefresh.emit();// even though the data is not changed the TABLE DRAG may has changed return; } - } else { - this.dataNeedsRefresh.emit();// even though the data is not changed the TABLE DRAG may has changed - return; - } - - const elementId = (el.id as string).replace(this.DRAGULA_ITEM_ID_PREFIX, ''); - const targetId = target.id as string; - const sourceId = source.id as string; + const elementId = (el.id as string).replace(this.DRAGULA_ITEM_ID_PREFIX, ''); + const targetId = target.id as string; + const sourceId = source.id as string; - if (!(elementId && targetId && sourceId)) { - console.info('Elements do not have an id'); - this.dataNeedsRefresh.emit(); - return; - } + if (!(elementId && targetId && sourceId)) { + console.info('Elements do not have an id'); + this.dataNeedsRefresh.emit(); + return; + } + + const element: ToCEntry = this._findTocEntryById(elementId, this.links); + const targetContainer: ToCEntry = this._findTocEntryById(targetId, this.links); + const sourceContainer: ToCEntry = this._findTocEntryById(sourceId, this.links); + + if (!(element && (targetContainer || ((element.type === ToCEntryType.Page) && (targetId === this.ROOT_ID))) && (sourceContainer || ((element.type === ToCEntryType.Page) && (sourceId === this.ROOT_ID))))) { + // console.info('Could not find elements'); + this.dataNeedsRefresh.emit(); + //TODO: angular update //drake.cancel(true); + return; + } - const element: ToCEntry = this._findTocEntryById(elementId, this.links); - const targetContainer: ToCEntry = this._findTocEntryById(targetId, this.links); - const sourceContainer: ToCEntry = this._findTocEntryById(sourceId, this.links); - - if (!(element && (targetContainer || ((element.type === ToCEntryType.Page) && (targetId === this.ROOT_ID))) && (sourceContainer || ((element.type === ToCEntryType.Page) && (sourceId === this.ROOT_ID))))) { - // console.info('Could not find elements'); - this.dataNeedsRefresh.emit(); - //TODO: angular update //drake.cancel(true); - return; - } - - - switch (element.type) { - case ToCEntryType.FieldSet: { - if (targetContainer.type != this.tocEntryType.Section) { - // const message = 'Fieldset can only be child of Subsections'; - const message = this.language.instant('DESCRIPTION-TEMPLATE-EDITOR.STEPS.FORM.TABLE-OF-CONTENTS.ERROR-MESSAGES.FIELDSET-MUST-HAVE-PARENT-SECTION'); - // console.error(message); - this.notifyUser(message) - this.dataNeedsRefresh.emit(); - return; - } - - //check if target container has no sections - if ((targetContainer.form.get('sections') as UntypedFormArray).length) { - // const message = 'Cannot have inputs and sections on the same level'; - const message = this.language.instant('DESCRIPTION-TEMPLATE-EDITOR.STEPS.FORM.TABLE-OF-CONTENTS.ERROR-MESSAGES.INPUT-SECTION-SAME-LEVEL'); - this.notifyUser(message); - // console.error(message); - this.dataNeedsRefresh.emit(); - return; - } - - const fieldsetForm = element.form; - const targetFieldsets = targetContainer.form.get('fieldSets') as UntypedFormArray; - const sourceFieldsets = sourceContainer.form.get('fieldSets') as UntypedFormArray; - - if (!targetFieldsets) { - console.info('Not target fieldsets container found'); - this.dataNeedsRefresh.emit(); - return; - } - - let sourceOrdinal = -1; - let idx = -1; - sourceFieldsets.controls.forEach((elem, index) => { - if (elem.get('id').value === elementId) { - sourceOrdinal = elem.get('ordinal').value; - idx = index + switch (element.type) { + case ToCEntryType.FieldSet: { + if (targetContainer.type != this.tocEntryType.Section) { + // const message = 'Fieldset can only be child of Subsections'; + const message = this.language.instant('DESCRIPTION-TEMPLATE-EDITOR.STEPS.FORM.TABLE-OF-CONTENTS.ERROR-MESSAGES.FIELDSET-MUST-HAVE-PARENT-SECTION'); + // console.error(message); + this.notifyUser(message) + this.dataNeedsRefresh.emit(); + return; } - }); - if (sourceOrdinal >= 0 && idx >= 0) { - sourceFieldsets.removeAt(idx); + //check if target container has no sections + if ((targetContainer.form.get('sections') as UntypedFormArray).length) { + // const message = 'Cannot have inputs and sections on the same level'; + const message = this.language.instant('DESCRIPTION-TEMPLATE-EDITOR.STEPS.FORM.TABLE-OF-CONTENTS.ERROR-MESSAGES.INPUT-SECTION-SAME-LEVEL'); + this.notifyUser(message); + // console.error(message); + this.dataNeedsRefresh.emit(); + return; + } - sourceFieldsets.controls.forEach(control => { - const ordinal = control.get('ordinal'); - if ((ordinal.value >= sourceOrdinal) && sourceOrdinal > 0) { - const updatedOrdinalVal = ordinal.value - 1; - ordinal.setValue(updatedOrdinalVal); + const fieldsetForm = element.form; + const targetFieldsets = targetContainer.form.get('fieldSets') as UntypedFormArray; + const sourceFieldsets = sourceContainer.form.get('fieldSets') as UntypedFormArray; + + if (!targetFieldsets) { + console.info('Not target fieldsets container found'); + this.dataNeedsRefresh.emit(); + return; + } + + let sourceOrdinal = -1; + let idx = -1; + sourceFieldsets.controls.forEach((elem, index) => { + if (elem.get('id').value === elementId) { + sourceOrdinal = elem.get('ordinal').value; + idx = index } }); - sourceFieldsets.controls.sort(this._compareOrdinals); - } - let position: number = targetFieldsets.length; + if (sourceOrdinal >= 0 && idx >= 0) { + sourceFieldsets.removeAt(idx); - if (!sibling || !sibling.id) { - console.info('No sibling Id found'); - } else { - const siblingId = (sibling.id as string).replace(this.DRAGULA_ITEM_ID_PREFIX, ''); - let siblingIndex = -1; - targetFieldsets.controls.forEach((e, idx) => { - if (e.get('id').value === siblingId) { - siblingIndex = idx; - position = e.get('ordinal').value; - } - - }); - - if (siblingIndex >= 0) { //sibling found - - targetFieldsets.controls.filter(control => control.get('ordinal').value >= position).forEach(control => { + sourceFieldsets.controls.forEach(control => { const ordinal = control.get('ordinal'); - const updatedOrdinalVal = ordinal.value + 1; + if ((ordinal.value >= sourceOrdinal) && sourceOrdinal > 0) { + const updatedOrdinalVal = ordinal.value - 1; + ordinal.setValue(updatedOrdinalVal); + } + }); + sourceFieldsets.controls.sort(this._compareOrdinals); + } + + let position: number = targetFieldsets.length; + + if (!sibling || !sibling.id) { + console.info('No sibling Id found'); + } else { + const siblingId = (sibling.id as string).replace(this.DRAGULA_ITEM_ID_PREFIX, ''); + let siblingIndex = -1; + targetFieldsets.controls.forEach((e, idx) => { + if (e.get('id').value === siblingId) { + siblingIndex = idx; + position = e.get('ordinal').value; + } + + }); + + if (siblingIndex >= 0) { //sibling found + + targetFieldsets.controls.filter(control => control.get('ordinal').value >= position).forEach(control => { + const ordinal = control.get('ordinal'); + const updatedOrdinalVal = ordinal.value + 1; + ordinal.setValue(updatedOrdinalVal); + }) + } + + } + + + fieldsetForm.get('ordinal').setValue(position); + targetFieldsets.insert(position, fieldsetForm); + targetFieldsets.controls.sort(this._compareOrdinals); + this.dataNeedsRefresh.emit({ draggedItemId: elementId }); + + break; + } + case ToCEntryType.Section: { + + if (targetContainer.type == ToCEntryType.Section) { + if ((targetContainer.form.get('fieldSets') as UntypedFormArray).length) { + // const message = 'Cannot have inputs and sections on the same level'; + const message = this.language.instant('DESCRIPTION-TEMPLATE-EDITOR.STEPS.FORM.TABLE-OF-CONTENTS.ERROR-MESSAGES.INPUT-SECTION-SAME-LEVEL');; + this.notifyUser(message); + // console.info(message); + this.dataNeedsRefresh.emit(); + return; + } + + const targetSections = targetContainer.form.get('sections') as UntypedFormArray; + const elementSectionForm = element.form; + const sourceSections = elementSectionForm.parent as UntypedFormArray; + + if (!(targetSections && sourceSections && elementSectionForm)) { + console.info('Could not load sections'); + this.dataNeedsRefresh.emit(); + return; + } + + let idx = -1; + sourceSections.controls.forEach((section, i) => { + if (section.get('id').value === elementId) { + idx = i; + } + }); + + if (!(idx >= 0)) { + console.info('Could not find element in Parent container'); + this.dataNeedsRefresh.emit(); + return; + } + + sourceSections.controls.filter(control => control.get('ordinal').value >= elementSectionForm.get('ordinal').value).forEach(control => { + const ordinal = control.get('ordinal'); + const updatedOrdinalVal = ordinal.value ? ordinal.value - 1 : 0; + ordinal.setValue(updatedOrdinalVal); + }); + + + sourceSections.removeAt(idx); + + let targetOrdinal = targetSections.length; + + if (sibling && sibling.id) { + const siblingId = sibling.id.replace(this.DRAGULA_ITEM_ID_PREFIX, ''); + + targetSections.controls.forEach((section, i) => { + if (section.get('id').value === siblingId) { + targetOrdinal = section.get('ordinal').value; + } + }) + + targetSections.controls.filter(control => control.get('ordinal').value >= targetOrdinal).forEach(control => { + const ordinal = control.get('ordinal'); + const updatedOrdinalVal = ordinal.value + 1; + ordinal.setValue(updatedOrdinalVal); + }); + + } else { + console.info('no siblings found'); + } + elementSectionForm.get('ordinal').setValue(targetOrdinal); + targetSections.insert(targetOrdinal, elementSectionForm); + + } else if (targetContainer.type === ToCEntryType.Page) { + + const rootform = targetContainer.form.root; + const sectionForm = element.form; + const parentSections = sectionForm.parent as UntypedFormArray; + + let parentIndex = -1; + parentSections.controls.forEach((section, i) => { + if (section.get('id').value === elementId) { + parentIndex = i + } + }) + + + if (parentIndex < 0) { + console.info('could not locate section in parents array'); + this.dataNeedsRefresh.emit(); + return; + } + + //update parent sections ordinal + parentSections.controls.filter(section => section.get('ordinal').value >= sectionForm.get('ordinal').value).forEach(section => { + const ordinal = section.get('ordinal'); + const updatedOrdinalVal = ordinal.value ? ordinal.value - 1 : 0; ordinal.setValue(updatedOrdinalVal); }) - } - } + parentSections.removeAt(parentIndex); - fieldsetForm.get('ordinal').setValue(position); - targetFieldsets.insert(position, fieldsetForm); - targetFieldsets.controls.sort(this._compareOrdinals); - this.dataNeedsRefresh.emit({ draggedItemId: elementId }); - break; - } - case ToCEntryType.Section: { + let position = 0; + if (targetContainer.subEntries) { + position = targetContainer.subEntries.length; + } + //populate sections + const targetSectionsArray = rootform.get('sections') as UntypedFormArray; - if (targetContainer.type == ToCEntryType.Section) { - if ((targetContainer.form.get('fieldSets') as UntypedFormArray).length) { - // const message = 'Cannot have inputs and sections on the same level'; - const message = this.language.instant('DESCRIPTION-TEMPLATE-EDITOR.STEPS.FORM.TABLE-OF-CONTENTS.ERROR-MESSAGES.INPUT-SECTION-SAME-LEVEL');; + + if (sibling && sibling.id) { + const siblingId = sibling.id.replace(this.DRAGULA_ITEM_ID_PREFIX, ''); + let indx = -1; + + targetContainer.subEntries.forEach((e, i) => { + if (e.form.get('id').value === siblingId) { + indx = i; + position = e.form.get('ordinal').value; + } + }); + if (indx >= 0) { + + // e.form.get('ordinal').setValue(i+1); + targetContainer.subEntries.filter(e => e.form.get('ordinal').value >= position).forEach(e => { + const ordinal = e.form.get('ordinal'); + const updatedOrdinalVal = ordinal.value + 1; + ordinal.setValue(updatedOrdinalVal); + }); + } + + } else { + console.info('No sibling found'); + } + + sectionForm.get('ordinal').setValue(position); + sectionForm.get('page').setValue(targetContainer.id); + targetSectionsArray.push(sectionForm); + + } else { + // const message = 'Drag not support to specific container'; + const message = this.language.instant('DESCRIPTION-TEMPLATE-EDITOR.STEPS.FORM.TABLE-OF-CONTENTS.ERROR-MESSAGES.DRAG-NOT-SUPPORTED'); this.notifyUser(message); // console.info(message); this.dataNeedsRefresh.emit(); return; } - const targetSections = targetContainer.form.get('sections') as UntypedFormArray; - const elementSectionForm = element.form; - const sourceSections = elementSectionForm.parent as UntypedFormArray; - if (!(targetSections && sourceSections && elementSectionForm)) { - console.info('Could not load sections'); + + this.dataNeedsRefresh.emit({ draggedItemId: elementId }); + break; + } + case ToCEntryType.Page: { + if (targetId != this.ROOT_ID) { + // const message = 'A page element can only be at top level'; + const message = this.language.instant('DESCRIPTION-TEMPLATE-EDITOR.STEPS.FORM.TABLE-OF-CONTENTS.ERROR-MESSAGES.PAGE-ELEMENT-ONLY-TOP-LEVEL'); + this.notifyUser(message); + // console.info(message); this.dataNeedsRefresh.emit(); return; } - let idx = -1; - sourceSections.controls.forEach((section, i) => { - if (section.get('id').value === elementId) { - idx = i; - } - }); - - if (!(idx >= 0)) { - console.info('Could not find element in Parent container'); + const rootForm = element.form.root; + if (!rootForm) { + console.info('Could not find root!') this.dataNeedsRefresh.emit(); return; } - sourceSections.controls.filter(control => control.get('ordinal').value >= elementSectionForm.get('ordinal').value).forEach(control => { - const ordinal = control.get('ordinal'); - const updatedOrdinalVal = ordinal.value ? ordinal.value - 1 : 0; - ordinal.setValue(updatedOrdinalVal); - }); + const pages = rootForm.get('pages') as UntypedFormArray; + const pageForm = element.form; - sourceSections.removeAt(idx); - - let targetOrdinal = targetSections.length; - - if (sibling && sibling.id) { - const siblingId = sibling.id.replace(this.DRAGULA_ITEM_ID_PREFIX, ''); - - targetSections.controls.forEach((section, i) => { - if (section.get('id').value === siblingId) { - targetOrdinal = section.get('ordinal').value; - } - }) - - targetSections.controls.filter(control => control.get('ordinal').value >= targetOrdinal).forEach(control => { - const ordinal = control.get('ordinal'); - const updatedOrdinalVal = ordinal.value + 1; - ordinal.setValue(updatedOrdinalVal); - }); - - } else { - console.info('no siblings found'); - } - elementSectionForm.get('ordinal').setValue(targetOrdinal); - targetSections.insert(targetOrdinal, elementSectionForm); - - } else if (targetContainer.type === ToCEntryType.Page) { - - const rootform = targetContainer.form.root; - const sectionForm = element.form; - const parentSections = sectionForm.parent as UntypedFormArray; - - let parentIndex = -1; - parentSections.controls.forEach((section, i) => { - if (section.get('id').value === elementId) { - parentIndex = i - } - }) - - - if (parentIndex < 0) { - console.info('could not locate section in parents array'); - this.dataNeedsRefresh.emit(); - return; - } - - //update parent sections ordinal - parentSections.controls.filter(section => section.get('ordinal').value >= sectionForm.get('ordinal').value).forEach(section => { - const ordinal = section.get('ordinal'); - const updatedOrdinalVal = ordinal.value ? ordinal.value - 1 : 0; - ordinal.setValue(updatedOrdinalVal); - }) - - parentSections.removeAt(parentIndex); - - - - let position = 0; - if (targetContainer.subEntries) { - position = targetContainer.subEntries.length; - } - //populate sections - const targetSectionsArray = rootform.get('sections') as UntypedFormArray; - - - if (sibling && sibling.id) { - const siblingId = sibling.id.replace(this.DRAGULA_ITEM_ID_PREFIX, ''); - let indx = -1; - - targetContainer.subEntries.forEach((e, i) => { - if (e.form.get('id').value === siblingId) { - indx = i; - position = e.form.get('ordinal').value; - } - }); - if (indx >= 0) { - - // e.form.get('ordinal').setValue(i+1); - targetContainer.subEntries.filter(e => e.form.get('ordinal').value >= position).forEach(e => { - const ordinal = e.form.get('ordinal'); - const updatedOrdinalVal = ordinal.value + 1; - ordinal.setValue(updatedOrdinalVal); - }); - } - - } else { - console.info('No sibling found'); - } - - sectionForm.get('ordinal').setValue(position); - sectionForm.get('page').setValue(targetContainer.id); - targetSectionsArray.push(sectionForm); - - } else { - // const message = 'Drag not support to specific container'; - const message = this.language.instant('DESCRIPTION-TEMPLATE-EDITOR.STEPS.FORM.TABLE-OF-CONTENTS.ERROR-MESSAGES.DRAG-NOT-SUPPORTED'); - this.notifyUser(message); - // console.info(message); - this.dataNeedsRefresh.emit(); - return; - } - - - - this.dataNeedsRefresh.emit({ draggedItemId: elementId }); - break; - } - case ToCEntryType.Page: { - if (targetId != this.ROOT_ID) { - // const message = 'A page element can only be at top level'; - const message = this.language.instant('DESCRIPTION-TEMPLATE-EDITOR.STEPS.FORM.TABLE-OF-CONTENTS.ERROR-MESSAGES.PAGE-ELEMENT-ONLY-TOP-LEVEL'); - this.notifyUser(message); - // console.info(message); - this.dataNeedsRefresh.emit(); - return; - } - - const rootForm = element.form.root; - if (!rootForm) { - console.info('Could not find root!') - this.dataNeedsRefresh.emit(); - return; - } - - - const pages = rootForm.get('pages') as UntypedFormArray; - const pageForm = element.form; - - let index = -1; - - pages.controls.forEach((page, i) => { - if (page.get('id').value === elementId) { - index = i; - } - }); - - if (index < 0) { - console.info('Could not locate page on pages'); - this.dataNeedsRefresh.emit(); - return; - } - - - //ordinality - pages.controls.filter(page => page.get('ordinal').value >= pageForm.get('ordinal').value).forEach(page => { - const ordinal = page.get('ordinal'); - const ordinalVal = ordinal.value ? ordinal.value - 1 : 0; - ordinal.setValue(ordinalVal); - }); - - pages.removeAt(index); - - let targetPosition = pages.length; - - if (sibling) { - const siblingId = sibling.id.replace(this.DRAGULA_ITEM_ID_PREFIX, ''); + let index = -1; pages.controls.forEach((page, i) => { - if (page.get('id').value === siblingId) { - targetPosition = page.get('ordinal').value; + if (page.get('id').value === elementId) { + index = i; } }); + + if (index < 0) { + console.info('Could not locate page on pages'); + this.dataNeedsRefresh.emit(); + return; + } + + + //ordinality + pages.controls.filter(page => page.get('ordinal').value >= pageForm.get('ordinal').value).forEach(page => { + const ordinal = page.get('ordinal'); + const ordinalVal = ordinal.value ? ordinal.value - 1 : 0; + ordinal.setValue(ordinalVal); + }); + + pages.removeAt(index); + + let targetPosition = pages.length; + + if (sibling) { + const siblingId = sibling.id.replace(this.DRAGULA_ITEM_ID_PREFIX, ''); + + pages.controls.forEach((page, i) => { + if (page.get('id').value === siblingId) { + targetPosition = page.get('ordinal').value; + } + }); + } + pageForm.get('ordinal').setValue(targetPosition); + + //update ordinality + pages.controls.filter(page => page.get('ordinal').value >= targetPosition).forEach(page => { + const ordinal = page.get('ordinal'); + const ordinalVal = ordinal.value + 1; + ordinal.setValue(ordinalVal); + }); + + + pages.insert(targetPosition, pageForm); + this.dataNeedsRefresh.emit({ draggedItemId: elementId }); + break; } - pageForm.get('ordinal').setValue(targetPosition); + default: - //update ordinality - pages.controls.filter(page => page.get('ordinal').value >= targetPosition).forEach(page => { - const ordinal = page.get('ordinal'); - const ordinalVal = ordinal.value + 1; - ordinal.setValue(ordinalVal); - }); + console.info('Could not support moving objects for specific type of element'); + this.dataNeedsRefresh.emit(); + return; - - pages.insert(targetPosition, pageForm); - this.dataNeedsRefresh.emit({ draggedItemId: elementId }); - break; } - default: + }) + ); - console.info('Could not support moving objects for specific type of element'); - this.dataNeedsRefresh.emit(); - return; - - } - }); - - - drake.on('drag', (el, source) => { - this._dragStartedAt = new Date().getTime(); - // console.log('drag fired'); - this.isDragging = true; - this.draggingItemId = (el.id as string).replace(this.DRAGULA_ITEM_ID_PREFIX, ''); - }); - drake.on('over', (el, container, source) => { - try { - this.overcontainer = container.id; - } catch (error) { + this.dragSubscriptions.push( + dragulaService.over(this.DRAG_GROUP).subscribe(( {el, container, source }) => { + try { + this.overcontainer = container.id; + } catch (error) { + this.overcontainer = null; + } + }) + ); + + this.dragSubscriptions.push( + dragulaService.dragend(this.DRAG_GROUP).subscribe(({ el }) => { + this.isDragging = false; + this.draggingItemId = null; this.overcontainer = null; - } - }); - drake.on('dragend', (el) => { - this.isDragging = false; - this.draggingItemId = null; - this.overcontainer = null; - }); + }) + ); + // if (this.dragulaService.find('TABLEDRAG')) { + // this.dragulaService.destroy('TABLEDRAG'); + // } + + // const dragula = this.dragulaService.createGroup('TABLEDRAG', {}); + + // const drake = dragula.drake; + + // drake.on('drop', (el, target, source, sibling) => { + + // if (this._dragStartedAt) { + // const timeNow = new Date().getTime(); + + // if (timeNow - this._dragStartedAt > this.VALID_DROP_TIME) { + // // console.log('timenow: ', timeNow); + // // console.log('timestarted', this._dragStartedAt); + // this._dragStartedAt = null; + + // } else { + // this.dataNeedsRefresh.emit();// even though the data is not changed the TABLE DRAG may has changed + // return; + // } + // } else { + // this.dataNeedsRefresh.emit();// even though the data is not changed the TABLE DRAG may has changed + // return; + + // } + + // const elementId = (el.id as string).replace(this.DRAGULA_ITEM_ID_PREFIX, ''); + // const targetId = target.id as string; + // const sourceId = source.id as string; + + + // if (!(elementId && targetId && sourceId)) { + // console.info('Elements do not have an id'); + // this.dataNeedsRefresh.emit(); + // return; + // } + + + // const element: ToCEntry = this._findTocEntryById(elementId, this.links); + // const targetContainer: ToCEntry = this._findTocEntryById(targetId, this.links); + // const sourceContainer: ToCEntry = this._findTocEntryById(sourceId, this.links); + + // if (!(element && (targetContainer || ((element.type === ToCEntryType.Page) && (targetId === this.ROOT_ID))) && (sourceContainer || ((element.type === ToCEntryType.Page) && (sourceId === this.ROOT_ID))))) { + // // console.info('Could not find elements'); + // this.dataNeedsRefresh.emit(); + // //TODO: angular update //drake.cancel(true); + // return; + // } + + + // switch (element.type) { + // case ToCEntryType.FieldSet: { + // if (targetContainer.type != this.tocEntryType.Section) { + // // const message = 'Fieldset can only be child of Subsections'; + // const message = this.language.instant('DESCRIPTION-TEMPLATE-EDITOR.STEPS.FORM.TABLE-OF-CONTENTS.ERROR-MESSAGES.FIELDSET-MUST-HAVE-PARENT-SECTION'); + // // console.error(message); + // this.notifyUser(message) + // this.dataNeedsRefresh.emit(); + // return; + // } + + // //check if target container has no sections + // if ((targetContainer.form.get('sections') as UntypedFormArray).length) { + // // const message = 'Cannot have inputs and sections on the same level'; + // const message = this.language.instant('DESCRIPTION-TEMPLATE-EDITOR.STEPS.FORM.TABLE-OF-CONTENTS.ERROR-MESSAGES.INPUT-SECTION-SAME-LEVEL'); + // this.notifyUser(message); + // // console.error(message); + // this.dataNeedsRefresh.emit(); + // return; + // } + + // const fieldsetForm = element.form; + // const targetFieldsets = targetContainer.form.get('fieldSets') as UntypedFormArray; + // const sourceFieldsets = sourceContainer.form.get('fieldSets') as UntypedFormArray; + + // if (!targetFieldsets) { + // console.info('Not target fieldsets container found'); + // this.dataNeedsRefresh.emit(); + // return; + // } + + // let sourceOrdinal = -1; + // let idx = -1; + // sourceFieldsets.controls.forEach((elem, index) => { + // if (elem.get('id').value === elementId) { + // sourceOrdinal = elem.get('ordinal').value; + // idx = index + // } + // }); + + // if (sourceOrdinal >= 0 && idx >= 0) { + // sourceFieldsets.removeAt(idx); + + // sourceFieldsets.controls.forEach(control => { + // const ordinal = control.get('ordinal'); + // if ((ordinal.value >= sourceOrdinal) && sourceOrdinal > 0) { + // const updatedOrdinalVal = ordinal.value - 1; + // ordinal.setValue(updatedOrdinalVal); + // } + // }); + // sourceFieldsets.controls.sort(this._compareOrdinals); + // } + + // let position: number = targetFieldsets.length; + + // if (!sibling || !sibling.id) { + // console.info('No sibling Id found'); + // } else { + // const siblingId = (sibling.id as string).replace(this.DRAGULA_ITEM_ID_PREFIX, ''); + // let siblingIndex = -1; + // targetFieldsets.controls.forEach((e, idx) => { + // if (e.get('id').value === siblingId) { + // siblingIndex = idx; + // position = e.get('ordinal').value; + // } + + // }); + + // if (siblingIndex >= 0) { //sibling found + + // targetFieldsets.controls.filter(control => control.get('ordinal').value >= position).forEach(control => { + // const ordinal = control.get('ordinal'); + // const updatedOrdinalVal = ordinal.value + 1; + // ordinal.setValue(updatedOrdinalVal); + // }) + // } + + // } + + + // fieldsetForm.get('ordinal').setValue(position); + // targetFieldsets.insert(position, fieldsetForm); + // targetFieldsets.controls.sort(this._compareOrdinals); + // this.dataNeedsRefresh.emit({ draggedItemId: elementId }); + + // break; + // } + // case ToCEntryType.Section: { + + // if (targetContainer.type == ToCEntryType.Section) { + // if ((targetContainer.form.get('fieldSets') as UntypedFormArray).length) { + // // const message = 'Cannot have inputs and sections on the same level'; + // const message = this.language.instant('DESCRIPTION-TEMPLATE-EDITOR.STEPS.FORM.TABLE-OF-CONTENTS.ERROR-MESSAGES.INPUT-SECTION-SAME-LEVEL');; + // this.notifyUser(message); + // // console.info(message); + // this.dataNeedsRefresh.emit(); + // return; + // } + + // const targetSections = targetContainer.form.get('sections') as UntypedFormArray; + // const elementSectionForm = element.form; + // const sourceSections = elementSectionForm.parent as UntypedFormArray; + + // if (!(targetSections && sourceSections && elementSectionForm)) { + // console.info('Could not load sections'); + // this.dataNeedsRefresh.emit(); + // return; + // } + + // let idx = -1; + // sourceSections.controls.forEach((section, i) => { + // if (section.get('id').value === elementId) { + // idx = i; + // } + // }); + + // if (!(idx >= 0)) { + // console.info('Could not find element in Parent container'); + // this.dataNeedsRefresh.emit(); + // return; + // } + + // sourceSections.controls.filter(control => control.get('ordinal').value >= elementSectionForm.get('ordinal').value).forEach(control => { + // const ordinal = control.get('ordinal'); + // const updatedOrdinalVal = ordinal.value ? ordinal.value - 1 : 0; + // ordinal.setValue(updatedOrdinalVal); + // }); + + + // sourceSections.removeAt(idx); + + // let targetOrdinal = targetSections.length; + + // if (sibling && sibling.id) { + // const siblingId = sibling.id.replace(this.DRAGULA_ITEM_ID_PREFIX, ''); + + // targetSections.controls.forEach((section, i) => { + // if (section.get('id').value === siblingId) { + // targetOrdinal = section.get('ordinal').value; + // } + // }) + + // targetSections.controls.filter(control => control.get('ordinal').value >= targetOrdinal).forEach(control => { + // const ordinal = control.get('ordinal'); + // const updatedOrdinalVal = ordinal.value + 1; + // ordinal.setValue(updatedOrdinalVal); + // }); + + // } else { + // console.info('no siblings found'); + // } + // elementSectionForm.get('ordinal').setValue(targetOrdinal); + // targetSections.insert(targetOrdinal, elementSectionForm); + + // } else if (targetContainer.type === ToCEntryType.Page) { + + // const rootform = targetContainer.form.root; + // const sectionForm = element.form; + // const parentSections = sectionForm.parent as UntypedFormArray; + + // let parentIndex = -1; + // parentSections.controls.forEach((section, i) => { + // if (section.get('id').value === elementId) { + // parentIndex = i + // } + // }) + + + // if (parentIndex < 0) { + // console.info('could not locate section in parents array'); + // this.dataNeedsRefresh.emit(); + // return; + // } + + // //update parent sections ordinal + // parentSections.controls.filter(section => section.get('ordinal').value >= sectionForm.get('ordinal').value).forEach(section => { + // const ordinal = section.get('ordinal'); + // const updatedOrdinalVal = ordinal.value ? ordinal.value - 1 : 0; + // ordinal.setValue(updatedOrdinalVal); + // }) + + // parentSections.removeAt(parentIndex); + // let position = 0; + // if (targetContainer.subEntries) { + // position = targetContainer.subEntries.length; + // } + // //populate sections + // const targetSectionsArray = rootform.get('sections') as UntypedFormArray; + + // if (sibling && sibling.id) { + // const siblingId = sibling.id.replace(this.DRAGULA_ITEM_ID_PREFIX, ''); + // let indx = -1; + + // targetContainer.subEntries.forEach((e, i) => { + // if (e.form.get('id').value === siblingId) { + // indx = i; + // position = e.form.get('ordinal').value; + // } + // }); + // if (indx >= 0) { + + // // e.form.get('ordinal').setValue(i+1); + // targetContainer.subEntries.filter(e => e.form.get('ordinal').value >= position).forEach(e => { + // const ordinal = e.form.get('ordinal'); + // const updatedOrdinalVal = ordinal.value + 1; + // ordinal.setValue(updatedOrdinalVal); + // }); + // } + + // } else { + // console.info('No sibling found'); + // } + + // sectionForm.get('ordinal').setValue(position); + // sectionForm.get('page').setValue(targetContainer.id); + // targetSectionsArray.push(sectionForm); + + // } else { + // // const message = 'Drag not support to specific container'; + // const message = this.language.instant('DESCRIPTION-TEMPLATE-EDITOR.STEPS.FORM.TABLE-OF-CONTENTS.ERROR-MESSAGES.DRAG-NOT-SUPPORTED'); + // this.notifyUser(message); + // // console.info(message); + // this.dataNeedsRefresh.emit(); + // return; + // } + + + + // this.dataNeedsRefresh.emit({ draggedItemId: elementId }); + // break; + // } + // case ToCEntryType.Page: { + // if (targetId != this.ROOT_ID) { + // // const message = 'A page element can only be at top level'; + // const message = this.language.instant('DESCRIPTION-TEMPLATE-EDITOR.STEPS.FORM.TABLE-OF-CONTENTS.ERROR-MESSAGES.PAGE-ELEMENT-ONLY-TOP-LEVEL'); + // this.notifyUser(message); + // // console.info(message); + // this.dataNeedsRefresh.emit(); + // return; + // } + + // const rootForm = element.form.root; + // if (!rootForm) { + // console.info('Could not find root!') + // this.dataNeedsRefresh.emit(); + // return; + // } + + + // const pages = rootForm.get('pages') as UntypedFormArray; + // const pageForm = element.form; + + // let index = -1; + + // pages.controls.forEach((page, i) => { + // if (page.get('id').value === elementId) { + // index = i; + // } + // }); + + // if (index < 0) { + // console.info('Could not locate page on pages'); + // this.dataNeedsRefresh.emit(); + // return; + // } + + + // //ordinality + // pages.controls.filter(page => page.get('ordinal').value >= pageForm.get('ordinal').value).forEach(page => { + // const ordinal = page.get('ordinal'); + // const ordinalVal = ordinal.value ? ordinal.value - 1 : 0; + // ordinal.setValue(ordinalVal); + // }); + + // pages.removeAt(index); + + // let targetPosition = pages.length; + + // if (sibling) { + // const siblingId = sibling.id.replace(this.DRAGULA_ITEM_ID_PREFIX, ''); + + // pages.controls.forEach((page, i) => { + // if (page.get('id').value === siblingId) { + // targetPosition = page.get('ordinal').value; + // } + // }); + // } + // pageForm.get('ordinal').setValue(targetPosition); + + // //update ordinality + // pages.controls.filter(page => page.get('ordinal').value >= targetPosition).forEach(page => { + // const ordinal = page.get('ordinal'); + // const ordinalVal = ordinal.value + 1; + // ordinal.setValue(ordinalVal); + // }); + + + // pages.insert(targetPosition, pageForm); + // this.dataNeedsRefresh.emit({ draggedItemId: elementId }); + // break; + // } + // default: + + // console.info('Could not support moving objects for specific type of element'); + // this.dataNeedsRefresh.emit(); + // return; + + // } + // }); + + + // drake.on('drag', (el, source) => { + // this._dragStartedAt = new Date().getTime(); + // // console.log('drag fired'); + // this.isDragging = true; + // this.draggingItemId = (el.id as string).replace(this.DRAGULA_ITEM_ID_PREFIX, ''); + // }); + // drake.on('over', (el, container, source) => { + // try { + // this.overcontainer = container.id; + // } catch (error) { + // this.overcontainer = null; + // } + // }); + // drake.on('dragend', (el) => { + // this.isDragging = false; + // this.draggingItemId = null; + // this.overcontainer = null; + // }); } + + ngOnInit(): void {} + ngAfterViewInit(): void { const top = document.querySelector('.top-scroller'); @@ -490,6 +873,10 @@ export class DescriptionTemplateTableOfContents extends BaseComponent implements } + ngOnDestroy(): void { + this.dragSubscriptions.forEach(subscription => subscription.unsubscribe()) + } + private _scrollIntoDragginItem(id: string) { // const table = document.getElementById('tocentrytable'); @@ -548,12 +935,6 @@ export class DescriptionTemplateTableOfContents extends BaseComponent implements return tocEntryFound ? tocEntryFound : null; } - ngOnInit(): void { - - - } - - itemClicked(item: ToCEntry) { //leaf node this.itemClick.emit(item); @@ -585,6 +966,4 @@ export class DescriptionTemplateTableOfContents extends BaseComponent implements return aValue - bValue; } - - }