use placeholder area for d&d

pull/6834/head
Jens Ulferts 6 years ago
parent c95dc496c6
commit a8a91eda05
No known key found for this signature in database
GPG Key ID: 3CAA4B1182CF5308
  1. 33
      frontend/src/app/modules/grids/grid.component.html
  2. 179
      frontend/src/app/modules/grids/grid.component.ts

@ -25,12 +25,13 @@
cdkDropList cdkDropList
[id]="gridAreaId(area) + '-widgeted-' + area.guid" [id]="gridAreaId(area) + '-widgeted-' + area.guid"
[cdkDropListData]="area" [cdkDropListData]="area"
[cdkDropListConnectedTo]="gridAreaDropIdsWithoutSelf(area)"> [cdkDropListConnectedTo]="gridAreaDropIds">
<div class="widget-box" <div class="widget-box"
cdkDrag cdkDrag
(cdkDragStarted)="dragStart(area)" (cdkDragStarted)="dragStart(area)"
(cdkDragEnded)="dragStop()" (cdkDragEnded)="dragStop(area, $event)"
style="height: 100%"> style="height: 100%">
<div *cdkDragPlaceholder></div>
<div class="grid--widget-remove" <div class="grid--widget-remove"
(click)="removeWidget(area)"> (click)="removeWidget(area)">
</div> </div>
@ -48,7 +49,7 @@
<!-- One grid area per cell (row x columns) --> <!-- One grid area per cell (row x columns) -->
<div *ngFor="let area of gridAreas; trackBy: identifyGridArea;" <div *ngFor="let area of gridAreas; trackBy: identifyGridArea;"
class="grid--area" class="grid--area"
[ngClass] = "{'-drop-target': currentlyDragging && gridAreaDropIds.indexOf(gridAreaId(area)) >= 0, [ngClass] = "{'-drop-target': currentlyDragging,
'-resize-target': isResizeTarget(area), '-resize-target': isResizeTarget(area),
'-addable': isAddable(area) }" '-addable': isAddable(area) }"
[style.grid-row-start]="area.startRow" [style.grid-row-start]="area.startRow"
@ -61,6 +62,7 @@
[cdkDropListData]="area" [cdkDropListData]="area"
(cdkDropListDropped)="drop($event)" (cdkDropListDropped)="drop($event)"
(cdkDropListEntered)="dragEntered($event)" (cdkDropListEntered)="dragEntered($event)"
(cdkDropListExited)="dragExited($event)"
[cdkDropListConnectedTo]="gridAreaDropIds"> [cdkDropListConnectedTo]="gridAreaDropIds">
<div class="grid--widget-add" <div class="grid--widget-add"
*ngIf="isAddable(area)" *ngIf="isAddable(area)"
@ -70,10 +72,25 @@
<!-- Grid area to visualize resizing --> <!-- Grid area to visualize resizing -->
<div class="grid--area -resizing" <div class="grid--area -resizing"
*ngIf="resizeArea" *ngIf="resizePlaceholderArea"
[style.grid-row-start]="resizeArea.startRow" [style.grid-row-start]="resizePlaceholderArea.startRow"
[style.grid-row-end]="resizeArea.endRow" [style.grid-row-end]="resizePlaceholderArea.endRow"
[style.grid-column-start]="resizeArea.startColumn" [style.grid-column-start]="resizePlaceholderArea.startColumn"
[style.grid-column-end]="resizeArea.endColumn"> [style.grid-column-end]="resizePlaceholderArea.endColumn">
</div>
<!-- Grid area used as a placeholder while dragging -->
<div *ngIf="dragPlaceholderArea"
class="grid--area -widgeted"
[style.grid-row-start]="dragPlaceholderArea.startRow"
[style.grid-row-end]="dragPlaceholderArea.endRow"
[style.grid-column-start]="dragPlaceholderArea.startColumn"
[style.grid-column-end]="dragPlaceholderArea.endColumn">
<div class="widget-box"
style="height: 100%">
<ndc-dynamic [ndcDynamicComponent]="widgetComponent(dragPlaceholderArea.widget)"
[ndcDynamicOutputs]="{}">
</ndc-dynamic>
</div>
</div> </div>
</div> </div>

@ -9,7 +9,7 @@ import {GridWidgetResource} from "app/modules/hal/resources/grid-widget-resource
import {HookService} from "app/modules/plugins/hook-service"; import {HookService} from "app/modules/plugins/hook-service";
import {debugLog} from "app/helpers/debug_output"; import {debugLog} from "app/helpers/debug_output";
import {DomSanitizer} from "@angular/platform-browser"; import {DomSanitizer} from "@angular/platform-browser";
import {CdkDragDrop, CdkDragEnter} from "@angular/cdk/drag-drop"; import {CdkDragDrop, CdkDragEnter, CdkDragExit, CdkDragEnd} from "@angular/cdk/drag-drop";
import {ResizeDelta} from "../common/resizer/resizer.component"; import {ResizeDelta} from "../common/resizer/resizer.component";
import {GridWidgetsService} from "core-app/modules/grids/widgets/widgets.service"; import {GridWidgetsService} from "core-app/modules/grids/widgets/widgets.service";
import {AddGridWidgetService} from "core-app/modules/grids/widgets/add/add.service"; import {AddGridWidgetService} from "core-app/modules/grids/widgets/add/add.service";
@ -37,11 +37,13 @@ export class GridComponent implements OnDestroy, OnInit {
public gridWidgetAreas:GridWidgetArea[]; public gridWidgetAreas:GridWidgetArea[];
public gridAreaDropIds:string[]; public gridAreaDropIds:string[];
public draggedArea:GridWidgetArea|null; public draggedArea:GridWidgetArea|null;
public dragPlaceholderArea:GridWidgetArea|null;
public GRID_AREA_HEIGHT = 100; public GRID_AREA_HEIGHT = 100;
private schema:SchemaResource; private schema:SchemaResource;
public resizeArea:GridArea|null; public resizePlaceholderArea:GridWidgetArea|null;
private resizedArea:GridWidgetArea|null;
public resizeAreaTargetIds:string[]; public resizeAreaTargetIds:string[];
private mousedOverArea:GridArea|null; private mousedOverArea:GridArea|null;
@ -104,74 +106,110 @@ export class GridComponent implements OnDestroy, OnInit {
public dragStart(area:GridWidgetArea) { public dragStart(area:GridWidgetArea) {
this.draggedArea = area; this.draggedArea = area;
this.dragPlaceholderArea = new GridWidgetArea(area.widget);
} }
public dragStop() { public dragStop(area:GridWidgetArea, event:CdkDragEnd) {
if (!this.draggedArea) {
return;
}
let dropArea = event.source.dropContainer.data;
// Handle special case of user starting to move the widget but then deciding to
// move it back to the original area.
if (this.draggedArea.startColumn === dropArea.startColumn &&
this.draggedArea.startRow === dropArea.startRow) {
this.resetAreasOnDragging();
}
this.draggedArea = null; this.draggedArea = null;
this.dragPlaceholderArea = null;
} }
public drop(event:CdkDragDrop<GridArea>) { public drop(event:CdkDragDrop<GridArea>) {
// this.draggedArea is already reset to null at this point // this.draggedArea is already reset to null at this point
if (event.previousContainer !== event.container) { let dropArea = event.container.data;
let dropArea = event.container.data; let draggedArea = event.previousContainer.data as GridWidgetArea;
let draggedArea = event.previousContainer.data as GridWidgetArea;
// Set the draggedArea's startRow/startColumn properties
// Set the draggedArea's startRow/startColumn properties // to the drop zone ones.
// to the drop zone ones. // The dragged Area should keep it's height and width normally but will
// The dragged Area should keep it's height and width normally but will // shrink if the area would otherwise end outside the grid.
// shrink if the area would otherwise end outside the grid. draggedArea.startRow = dropArea.startRow;
draggedArea.startRow = dropArea.startRow; if (dropArea.startRow + draggedArea.widget.height > this.numRows + 1) {
if (dropArea.startRow + draggedArea.widget.height > this.numRows + 1) { draggedArea.endRow = this.numRows + 1;
draggedArea.endRow = this.numRows + 1; } else {
} else { draggedArea.endRow = dropArea.startRow + draggedArea.widget.height;
draggedArea.endRow = dropArea.startRow + draggedArea.widget.height; }
}
draggedArea.startColumn = dropArea.startColumn; draggedArea.startColumn = dropArea.startColumn;
if (dropArea.startColumn + draggedArea.widget.width > this.numColumns + 1) { if (dropArea.startColumn + draggedArea.widget.width > this.numColumns + 1) {
draggedArea.endColumn = this.numColumns + 1; draggedArea.endColumn = this.numColumns + 1;
} else { } else {
draggedArea.endColumn = dropArea.startColumn + draggedArea.widget.width; draggedArea.endColumn = dropArea.startColumn + draggedArea.widget.width;
} }
// persist all changes to the areas caused by dragging this.writeAreaChangesToWidgets();
// to the widget this.buildAreas();
this.gridWidgetAreas.forEach((area) => { }
area.widget.startRow = area.startRow;
area.widget.endRow = area.endRow;
area.widget.startColumn = area.startColumn;
area.widget.endColumn = area.endColumn;
});
this.buildAreas(); // persist all changes to the areas caused by dragging/resizing
} // to the widget
private writeAreaChangesToWidgets() {
this.gridWidgetAreas.forEach((area) => {
area.widget.startRow = area.startRow;
area.widget.endRow = area.endRow;
area.widget.startColumn = area.startColumn;
area.widget.endColumn = area.endColumn;
});
} }
public dragEntered(event:CdkDragEnter<GridArea>) { public dragEntered(event:CdkDragEnter<GridArea>) {
if (this.draggedArea) { if (this.draggedArea) {
let dropArea = event.container.data; let dropArea = event.container.data;
this.resetAreasOnDragging(); this.resetAreasOnDragging(this.draggedArea);
this.moveAreasOnDragging(dropArea); this.moveAreasOnDragging(dropArea);
} }
} }
public dragExited(event:CdkDragExit<GridArea>) {
// prevent flickering when dragging within the area spanned
// by the dragged element. Otherwise, cdk drag fire an entered event on every
// move.
if (this.draggedArea) {
this.draggedArea.endRow = this.draggedArea.startRow + 1;
this.draggedArea.endColumn = this.draggedArea.startColumn + 1;
}
}
private moveAreasOnDragging(dropArea:GridArea) { private moveAreasOnDragging(dropArea:GridArea) {
if (!this.dragPlaceholderArea) {
return;
}
let widgetArea = this.draggedArea!; let widgetArea = this.draggedArea!;
// we cannot use the widget's original area as moving it while dragging confuses cdkDrag // we cannot use the widget's original area as moving it while dragging confuses cdkDrag
let widget = widgetArea.widget; this.dragPlaceholderArea.startRow = dropArea.startRow;
let placeholderArea = new GridWidgetArea(widget); if (this.dragPlaceholderArea.startRow + this.dragPlaceholderArea.widget.height > this.numRows + 1) {
this.dragPlaceholderArea.endRow = this.numRows + 1;
} else {
this.dragPlaceholderArea.endRow = dropArea.startRow + this.dragPlaceholderArea.widget.height;
}
placeholderArea.startRow = dropArea.startRow; this.dragPlaceholderArea.startColumn = dropArea.startColumn;
placeholderArea.endRow = placeholderArea.startRow + widget.height; if (this.dragPlaceholderArea.startColumn + this.dragPlaceholderArea.widget.height > this.numColumns + 1) {
placeholderArea.startColumn = dropArea.startColumn; this.dragPlaceholderArea.endColumn = this.numColumns + 1;
placeholderArea.endColumn = placeholderArea.startColumn + widget.width; } else {
this.dragPlaceholderArea.endColumn = dropArea.startColumn + this.dragPlaceholderArea.widget.height;
}
this.moveAreasDown(placeholderArea, widgetArea); this.moveAreasDown(this.dragPlaceholderArea, widgetArea);
} }
private resetAreasOnDragging() { private resetAreasOnDragging(ignoredArea:GridWidgetArea|null = null) {
this.gridWidgetAreas.forEach((area) => { this.gridWidgetAreas.filter((area) => {
return !ignoredArea || area.guid !== ignoredArea.guid;
}).forEach((area) => {
area.startRow = area.widget.startRow; area.startRow = area.widget.startRow;
area.endRow = area.widget.endRow; area.endRow = area.widget.endRow;
area.startColumn = area.widget.startColumn; area.startColumn = area.widget.startColumn;
@ -183,39 +221,28 @@ export class GridComponent implements OnDestroy, OnInit {
} }
public resize(area:GridWidgetArea, deltas:ResizeDelta) { public resize(area:GridWidgetArea, deltas:ResizeDelta) {
if (!this.resizeArea) { if (!this.resizePlaceholderArea ||
!this.resizedArea) {
return; return;
} }
let widget = area.widget; this.resizedArea.endRow = this.resizePlaceholderArea.endRow;
this.resizedArea.endColumn = this.resizePlaceholderArea.endColumn;
widget.endRow = this.resizeArea.endRow;
widget.endColumn = this.resizeArea.endColumn;
this.writeAreaChangesToWidgets();
this.buildAreas(); this.buildAreas();
return this.resizeArea = null; this.resizedArea = null;
this.resizePlaceholderArea = null;
} }
public resizeStart(resizedArea:GridWidgetArea) { public resizeStart(resizedArea:GridWidgetArea) {
this.resizeArea = new GridArea(resizedArea.startRow, this.resizePlaceholderArea = new GridWidgetArea(resizedArea.widget);
resizedArea.endRow, this.resizedArea = resizedArea;
resizedArea.startColumn,
resizedArea.endColumn);
let blockableWidgetAreas = this.gridWidgetAreas.filter((widgetArea) => {
return resizedArea.guid !== widgetArea.guid &&
widgetArea.startRow >= resizedArea.startRow &&
widgetArea.startColumn >= resizedArea.startColumn;
}) as GridWidgetArea[];
let resizeTargets = this.gridAreas.filter((area) => { let resizeTargets = this.gridAreas.filter((area) => {
return area.startRow >= this.resizeArea!.startRow && return area.startRow >= this.resizePlaceholderArea!.startRow &&
area.startColumn >= this.resizeArea!.startColumn && area.startColumn >= this.resizePlaceholderArea!.startColumn; //&&
!blockableWidgetAreas.some((widgetArea) => {
return area.startRow >= widgetArea.startRow &&
area.startColumn >= widgetArea.startColumn;
});
}); });
this.resizeAreaTargetIds = resizeTargets.map((area) => { this.resizeAreaTargetIds = resizeTargets.map((area) => {
@ -224,20 +251,24 @@ export class GridComponent implements OnDestroy, OnInit {
} }
public resizeMove(deltas:ResizeDelta) { public resizeMove(deltas:ResizeDelta) {
if (!this.resizeArea || if (!this.resizePlaceholderArea ||
!this.mousedOverArea || !this.mousedOverArea ||
!this.resizeAreaTargetIds.includes(this.gridAreaId(this.mousedOverArea))) { !this.resizeAreaTargetIds.includes(this.gridAreaId(this.mousedOverArea))) {
return; return;
} }
this.resizeArea.endRow = this.mousedOverArea.endRow; this.resetAreasOnDragging();
this.resizeArea.endColumn = this.mousedOverArea.endColumn;
this.resizePlaceholderArea.endRow = this.mousedOverArea.endRow;
this.resizePlaceholderArea.endColumn = this.mousedOverArea.endColumn;
this.moveAreasDown(this.resizePlaceholderArea, this.resizedArea);
} }
public isResizeTarget(area:GridArea) { public isResizeTarget(area:GridArea) {
let areaId = this.gridAreaId(area); let areaId = this.gridAreaId(area);
return this.resizeArea && this.resizeAreaTargetIds.includes(areaId); return this.resizePlaceholderArea && this.resizeAreaTargetIds.includes(areaId);
} }
public isAddable(area:GridArea) { public isAddable(area:GridArea) {
@ -248,7 +279,7 @@ export class GridComponent implements OnDestroy, OnInit {
} }
public get currentlyResizing() { public get currentlyResizing() {
return this.resizeArea; return this.resizePlaceholderArea;
} }
public setMousedOverArea(area:GridArea) { public setMousedOverArea(area:GridArea) {
@ -438,14 +469,6 @@ export class GridComponent implements OnDestroy, OnInit {
return `gridArea ${cell.guid}`; return `gridArea ${cell.guid}`;
} }
private gridAreaDropIdsWithoutSelf(area:GridArea) {
let selfId = this.gridAreaId(area);
return this.gridAreaDropIds.filter((areaId) => {
return selfId !== areaId;
});
}
private buildGridAreaDropIds() { private buildGridAreaDropIds() {
let ids:string[] = []; let ids:string[] = [];

Loading…
Cancel
Save