mirror of
https://github.com/DSpace/dspace-angular.git
synced 2025-10-07 10:04:11 +00:00
93747: Edit metadata redesign - drag to reorder pt1
This commit is contained in:
@@ -0,0 +1,33 @@
|
|||||||
|
import { MetadataPatchOperation } from './metadata-patch-operation.model';
|
||||||
|
import { Operation } from 'fast-json-patch';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wrapper object for a metadata patch move Operation
|
||||||
|
*/
|
||||||
|
export class MetadataPatchMoveOperation extends MetadataPatchOperation {
|
||||||
|
static operationType = 'move';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The original place of the metadata value to move
|
||||||
|
*/
|
||||||
|
from: number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The new place to move the metadata value to
|
||||||
|
*/
|
||||||
|
to: number;
|
||||||
|
|
||||||
|
constructor(field: string, from: number, to: number) {
|
||||||
|
super(MetadataPatchMoveOperation.operationType, field);
|
||||||
|
this.from = from;
|
||||||
|
this.to = to;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Transform the MetadataPatchOperation into a fast-json-patch Operation by constructing its path and other properties
|
||||||
|
* using the information provided.
|
||||||
|
*/
|
||||||
|
toOperation(): Operation {
|
||||||
|
return { op: this.op as any, from: `/metadata/${this.field}/${this.from}`, path: `/metadata/${this.field}/${this.to}` };
|
||||||
|
}
|
||||||
|
}
|
@@ -1,4 +1,4 @@
|
|||||||
<div class="flex-grow-1 ds-drop-list h-100">
|
<div class="flex-grow-1 ds-drop-list h-100" [class.disabled]="(draggingMdField$ | async) && (draggingMdField$ | async) !== mdField" cdkDropList (cdkDropListDropped)="drop($event)">
|
||||||
<ds-dso-edit-metadata-value *ngFor="let mdValue of form.fields[mdField]; let idx = index"
|
<ds-dso-edit-metadata-value *ngFor="let mdValue of form.fields[mdField]; let idx = index"
|
||||||
[dso]="dso"
|
[dso]="dso"
|
||||||
[mdValue]="mdValue"
|
[mdValue]="mdValue"
|
||||||
@@ -8,6 +8,7 @@
|
|||||||
(edit)="mdValue.editing = true"
|
(edit)="mdValue.editing = true"
|
||||||
(confirm)="mdValue.confirmChanges($event); form.resetReinstatable(); valueSaved.emit()"
|
(confirm)="mdValue.confirmChanges($event); form.resetReinstatable(); valueSaved.emit()"
|
||||||
(remove)="mdValue.change = DsoEditMetadataChangeTypeEnum.REMOVE; form.resetReinstatable(); valueSaved.emit()"
|
(remove)="mdValue.change = DsoEditMetadataChangeTypeEnum.REMOVE; form.resetReinstatable(); valueSaved.emit()"
|
||||||
(undo)="mdValue.change === DsoEditMetadataChangeTypeEnum.ADD ? form.remove(mdField, idx) : mdValue.discard(); valueSaved.emit()">
|
(undo)="mdValue.change === DsoEditMetadataChangeTypeEnum.ADD ? form.remove(mdField, idx) : mdValue.discard(); valueSaved.emit()"
|
||||||
|
(dragging)="$event ? draggingMdField$.next(mdField) : draggingMdField$.next(null)">
|
||||||
</ds-dso-edit-metadata-value>
|
</ds-dso-edit-metadata-value>
|
||||||
</div>
|
</div>
|
||||||
|
@@ -1,3 +1,7 @@
|
|||||||
.ds-drop-list {
|
.ds-drop-list {
|
||||||
background-color: var(--bs-gray-500);
|
background-color: var(--bs-gray-500);
|
||||||
|
|
||||||
|
&.disabled {
|
||||||
|
opacity: 0.3;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,7 +1,9 @@
|
|||||||
import { Component, EventEmitter, Input, Output } from '@angular/core';
|
import { Component, EventEmitter, Input, Output } from '@angular/core';
|
||||||
import { DsoEditMetadataChangeType, DsoEditMetadataForm } from '../dso-edit-metadata-form';
|
import { DsoEditMetadataChangeType, DsoEditMetadataForm, DsoEditMetadataValue } from '../dso-edit-metadata-form';
|
||||||
import { Observable } from 'rxjs/internal/Observable';
|
import { Observable } from 'rxjs/internal/Observable';
|
||||||
import { DSpaceObject } from '../../../core/shared/dspace-object.model';
|
import { DSpaceObject } from '../../../core/shared/dspace-object.model';
|
||||||
|
import { BehaviorSubject } from 'rxjs/internal/BehaviorSubject';
|
||||||
|
import { CdkDragDrop, moveItemInArray } from '@angular/cdk/drag-drop';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'ds-dso-edit-metadata-field-values',
|
selector: 'ds-dso-edit-metadata-field-values',
|
||||||
@@ -38,6 +40,12 @@ export class DsoEditMetadataFieldValuesComponent {
|
|||||||
*/
|
*/
|
||||||
@Input() saving$: Observable<boolean>;
|
@Input() saving$: Observable<boolean>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tracks for which metadata-field a drag operation is taking place
|
||||||
|
* Null when no drag is currently happening for any field
|
||||||
|
*/
|
||||||
|
@Input() draggingMdField$: BehaviorSubject<string>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Emit when the value has been saved within the form
|
* Emit when the value has been saved within the form
|
||||||
*/
|
*/
|
||||||
@@ -48,4 +56,26 @@ export class DsoEditMetadataFieldValuesComponent {
|
|||||||
* @type {DsoEditMetadataChangeType}
|
* @type {DsoEditMetadataChangeType}
|
||||||
*/
|
*/
|
||||||
public DsoEditMetadataChangeTypeEnum = DsoEditMetadataChangeType;
|
public DsoEditMetadataChangeTypeEnum = DsoEditMetadataChangeType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Drop a value into a new position
|
||||||
|
* Update the form's value array for the current field to match the dropped position
|
||||||
|
* Update the values their place property to match the new order
|
||||||
|
* Send an update to the parent
|
||||||
|
* @param event
|
||||||
|
*/
|
||||||
|
drop(event: CdkDragDrop<any>) {
|
||||||
|
const dragIndex = event.previousIndex;
|
||||||
|
const dropIndex = event.currentIndex;
|
||||||
|
// Move the value within its field
|
||||||
|
moveItemInArray(this.form.fields[this.mdField], dragIndex, dropIndex);
|
||||||
|
// Update all the values in this field their place property
|
||||||
|
this.form.fields[this.mdField].forEach((value: DsoEditMetadataValue, index: number) => {
|
||||||
|
value.newValue.place = index;
|
||||||
|
value.confirmChanges();
|
||||||
|
});
|
||||||
|
// Update the form statuses
|
||||||
|
this.form.resetReinstatable();
|
||||||
|
this.valueSaved.emit();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,10 +1,11 @@
|
|||||||
import { MetadataMap, MetadataValue } from '../../core/shared/metadata.models';
|
import { MetadataMap, MetadataValue } from '../../core/shared/metadata.models';
|
||||||
import { hasNoValue, hasValue, isEmpty, isNotEmpty } from '../../shared/empty.util';
|
import { hasNoValue, hasValue, isEmpty, isNotEmpty } from '../../shared/empty.util';
|
||||||
import { Operation } from 'fast-json-patch';
|
import { MoveOperation, Operation } from 'fast-json-patch';
|
||||||
import { MetadataPatchReplaceOperation } from '../../core/data/object-updates/patch-operation-service/operations/metadata/metadata-patch-replace-operation.model';
|
import { MetadataPatchReplaceOperation } from '../../core/data/object-updates/patch-operation-service/operations/metadata/metadata-patch-replace-operation.model';
|
||||||
import { MetadataPatchRemoveOperation } from '../../core/data/object-updates/patch-operation-service/operations/metadata/metadata-patch-remove-operation.model';
|
import { MetadataPatchRemoveOperation } from '../../core/data/object-updates/patch-operation-service/operations/metadata/metadata-patch-remove-operation.model';
|
||||||
import { MetadataPatchAddOperation } from '../../core/data/object-updates/patch-operation-service/operations/metadata/metadata-patch-add-operation.model';
|
import { MetadataPatchAddOperation } from '../../core/data/object-updates/patch-operation-service/operations/metadata/metadata-patch-add-operation.model';
|
||||||
import { MetadataPatchOperation } from '../../core/data/object-updates/patch-operation-service/operations/metadata/metadata-patch-operation.model';
|
import { ArrayMoveChangeAnalyzer } from '../../core/data/array-move-change-analyzer.service';
|
||||||
|
import { MetadataPatchMoveOperation } from '../../core/data/object-updates/patch-operation-service/operations/metadata/metadata-patch-move-operation.model';
|
||||||
|
|
||||||
/* tslint:disable:max-classes-per-file */
|
/* tslint:disable:max-classes-per-file */
|
||||||
|
|
||||||
@@ -69,7 +70,7 @@ export class DsoEditMetadataValue {
|
|||||||
*/
|
*/
|
||||||
confirmChanges(finishEditing = false) {
|
confirmChanges(finishEditing = false) {
|
||||||
if (hasNoValue(this.change) || this.change === DsoEditMetadataChangeType.UPDATE) {
|
if (hasNoValue(this.change) || this.change === DsoEditMetadataChangeType.UPDATE) {
|
||||||
if ((this.originalValue.value !== this.newValue.value || this.originalValue.language !== this.newValue.language)) {
|
if ((this.originalValue.value !== this.newValue.value || this.originalValue.language !== this.newValue.language || this.originalValue.place !== this.newValue.place)) {
|
||||||
this.change = DsoEditMetadataChangeType.UPDATE;
|
this.change = DsoEditMetadataChangeType.UPDATE;
|
||||||
} else {
|
} else {
|
||||||
this.change = undefined;
|
this.change = undefined;
|
||||||
@@ -187,7 +188,7 @@ export class DsoEditMetadataForm {
|
|||||||
Object.entries(metadata).forEach(([mdField, values]: [string, MetadataValue[]]) => {
|
Object.entries(metadata).forEach(([mdField, values]: [string, MetadataValue[]]) => {
|
||||||
this.originalFieldKeys.push(mdField);
|
this.originalFieldKeys.push(mdField);
|
||||||
this.fieldKeys.push(mdField);
|
this.fieldKeys.push(mdField);
|
||||||
this.fields[mdField] = values.map((value: MetadataValue) => new DsoEditMetadataValue(value));
|
this.setValuesForFieldSorted(mdField, values.map((value: MetadataValue) => new DsoEditMetadataValue(value)));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -208,6 +209,10 @@ export class DsoEditMetadataForm {
|
|||||||
setMetadataField(mdField: string): void {
|
setMetadataField(mdField: string): void {
|
||||||
this.newValue.editing = false;
|
this.newValue.editing = false;
|
||||||
this.addValueToField(this.newValue, mdField);
|
this.addValueToField(this.newValue, mdField);
|
||||||
|
// Set the place property to match the new value's position within its field
|
||||||
|
const place = this.fields[mdField].length - 1;
|
||||||
|
this.fields[mdField][place].originalValue.place = place;
|
||||||
|
this.fields[mdField][place].newValue.place = place;
|
||||||
this.newValue = undefined;
|
this.newValue = undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -253,6 +258,7 @@ export class DsoEditMetadataForm {
|
|||||||
*/
|
*/
|
||||||
discard(): void {
|
discard(): void {
|
||||||
this.resetReinstatable();
|
this.resetReinstatable();
|
||||||
|
// Discard changes from each value from each field
|
||||||
Object.entries(this.fields).forEach(([field, values]: [string, DsoEditMetadataValue[]]) => {
|
Object.entries(this.fields).forEach(([field, values]: [string, DsoEditMetadataValue[]]) => {
|
||||||
let removeFromIndex = -1;
|
let removeFromIndex = -1;
|
||||||
values.forEach((value: DsoEditMetadataValue, index: number) => {
|
values.forEach((value: DsoEditMetadataValue, index: number) => {
|
||||||
@@ -272,25 +278,39 @@ export class DsoEditMetadataForm {
|
|||||||
this.fields[field].splice(removeFromIndex, this.fields[field].length - removeFromIndex);
|
this.fields[field].splice(removeFromIndex, this.fields[field].length - removeFromIndex);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
// Delete new metadata fields
|
||||||
this.fieldKeys.forEach((field: string) => {
|
this.fieldKeys.forEach((field: string) => {
|
||||||
if (this.originalFieldKeys.indexOf(field) < 0) {
|
if (this.originalFieldKeys.indexOf(field) < 0) {
|
||||||
delete this.fields[field];
|
delete this.fields[field];
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
this.fieldKeys = [...this.originalFieldKeys];
|
this.fieldKeys = [...this.originalFieldKeys];
|
||||||
|
// Reset the order of values within their fields to match their place property
|
||||||
|
this.fieldKeys.forEach((field: string) => {
|
||||||
|
this.setValuesForFieldSorted(field, this.fields[field]);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Undo any previously discarded changes
|
||||||
|
*/
|
||||||
reinstate(): void {
|
reinstate(): void {
|
||||||
|
// Reinstate each value
|
||||||
Object.values(this.fields).forEach((values: DsoEditMetadataValue[]) => {
|
Object.values(this.fields).forEach((values: DsoEditMetadataValue[]) => {
|
||||||
values.forEach((value: DsoEditMetadataValue) => {
|
values.forEach((value: DsoEditMetadataValue) => {
|
||||||
value.reinstate();
|
value.reinstate();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
// Re-add new values
|
||||||
Object.entries(this.reinstatableNewValues).forEach(([field, values]: [string, DsoEditMetadataValue[]]) => {
|
Object.entries(this.reinstatableNewValues).forEach(([field, values]: [string, DsoEditMetadataValue[]]) => {
|
||||||
values.forEach((value: DsoEditMetadataValue) => {
|
values.forEach((value: DsoEditMetadataValue) => {
|
||||||
this.addValueToField(value, field);
|
this.addValueToField(value, field);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
// Reset the order of values within their fields to match their place property
|
||||||
|
this.fieldKeys.forEach((field: string) => {
|
||||||
|
this.setValuesForFieldSorted(field, this.fields[field]);
|
||||||
|
});
|
||||||
this.reinstatableNewValues = {};
|
this.reinstatableNewValues = {};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -317,34 +337,73 @@ export class DsoEditMetadataForm {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the json PATCH operations for the current changes within this form
|
* Set the values of a metadata field and sort them by their newValue's place property
|
||||||
|
* @param mdField
|
||||||
|
* @param values
|
||||||
*/
|
*/
|
||||||
getOperations(): Operation[] {
|
private setValuesForFieldSorted(mdField: string, values: DsoEditMetadataValue[]) {
|
||||||
|
this.fields[mdField] = values.sort((a: DsoEditMetadataValue, b: DsoEditMetadataValue) => a.newValue.place - b.newValue.place);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the json PATCH operations for the current changes within this form
|
||||||
|
* For each metadata field, it'll return operations in the following order: replace, remove (from last to first place), add and move
|
||||||
|
* This order is important, as each operation is executed in succession of the previous one
|
||||||
|
*/
|
||||||
|
getOperations(moveAnalyser: ArrayMoveChangeAnalyzer<number>): Operation[] {
|
||||||
const operations: Operation[] = [];
|
const operations: Operation[] = [];
|
||||||
Object.entries(this.fields).forEach(([field, values]: [string, DsoEditMetadataValue[]]) => {
|
Object.entries(this.fields).forEach(([field, values]: [string, DsoEditMetadataValue[]]) => {
|
||||||
values.forEach((value: DsoEditMetadataValue, place: number) => {
|
const replaceOperations: MetadataPatchReplaceOperation[] = [];
|
||||||
|
const removeOperations: MetadataPatchRemoveOperation[] = [];
|
||||||
|
const addOperations: MetadataPatchAddOperation[] = [];
|
||||||
|
values
|
||||||
|
.sort((a: DsoEditMetadataValue, b: DsoEditMetadataValue) => a.originalValue.place - b.originalValue.place)
|
||||||
|
.forEach((value: DsoEditMetadataValue) => {
|
||||||
if (value.hasChanges()) {
|
if (value.hasChanges()) {
|
||||||
let operation: MetadataPatchOperation;
|
|
||||||
if (value.change === DsoEditMetadataChangeType.UPDATE) {
|
if (value.change === DsoEditMetadataChangeType.UPDATE) {
|
||||||
operation = new MetadataPatchReplaceOperation(field, place, {
|
// Only changes to value or language are considered "replace" operations. Changes to place are considered "move", which is processed below.
|
||||||
|
if (value.originalValue.value !== value.newValue.value || value.originalValue.language !== value.newValue.language) {
|
||||||
|
replaceOperations.push(new MetadataPatchReplaceOperation(field, value.originalValue.place, {
|
||||||
value: value.newValue.value,
|
value: value.newValue.value,
|
||||||
language: value.newValue.language,
|
language: value.newValue.language,
|
||||||
});
|
}));
|
||||||
|
}
|
||||||
} else if (value.change === DsoEditMetadataChangeType.REMOVE) {
|
} else if (value.change === DsoEditMetadataChangeType.REMOVE) {
|
||||||
operation = new MetadataPatchRemoveOperation(field, place);
|
removeOperations.push(new MetadataPatchRemoveOperation(field, value.originalValue.place));
|
||||||
} else if (value.change === DsoEditMetadataChangeType.ADD) {
|
} else if (value.change === DsoEditMetadataChangeType.ADD) {
|
||||||
operation = new MetadataPatchAddOperation(field, {
|
addOperations.push(new MetadataPatchAddOperation(field, {
|
||||||
value: value.newValue.value,
|
value: value.newValue.value,
|
||||||
language: value.newValue.language,
|
language: value.newValue.language,
|
||||||
});
|
}));
|
||||||
} else {
|
} else {
|
||||||
console.warn('Illegal metadata change state detected for', value);
|
console.warn('Illegal metadata change state detected for', value);
|
||||||
}
|
}
|
||||||
if (hasValue(operation)) {
|
|
||||||
operations.push(operation.toOperation());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
operations.push(...replaceOperations
|
||||||
|
.map((operation: MetadataPatchReplaceOperation) => operation.toOperation()));
|
||||||
|
operations.push(...removeOperations
|
||||||
|
// Sort remove operations backwards first, because they get executed in order. This avoids one removal affecting the next.
|
||||||
|
.sort((a: MetadataPatchRemoveOperation, b: MetadataPatchRemoveOperation) => b.place - a.place)
|
||||||
|
.map((operation: MetadataPatchRemoveOperation) => operation.toOperation()));
|
||||||
|
operations.push(...addOperations
|
||||||
|
.map((operation: MetadataPatchAddOperation) => operation.toOperation()));
|
||||||
|
});
|
||||||
|
// Calculate and add the move operations that need to happen in order to move value from their old place to their new within the field
|
||||||
|
// This uses an ArrayMoveChangeAnalyzer
|
||||||
|
Object.entries(this.fields).forEach(([field, values]: [string, DsoEditMetadataValue[]]) => {
|
||||||
|
// Exclude values marked for removal, because operations are executed in order (remove first, then move)
|
||||||
|
const valuesWithoutRemoved = values.filter((value: DsoEditMetadataValue) => value.change !== DsoEditMetadataChangeType.REMOVE);
|
||||||
|
const moveOperations = moveAnalyser
|
||||||
|
.diff(
|
||||||
|
valuesWithoutRemoved
|
||||||
|
.map((value: DsoEditMetadataValue) => value.originalValue.place),
|
||||||
|
valuesWithoutRemoved
|
||||||
|
.sort((a: DsoEditMetadataValue, b: DsoEditMetadataValue) => a.newValue.place - b.newValue.place)
|
||||||
|
.map((value: DsoEditMetadataValue) => value.originalValue.place))
|
||||||
|
.map((operation: MoveOperation) => new MetadataPatchMoveOperation(field, +operation.from.substr(1), +operation.path.substr(1)).toOperation());
|
||||||
|
operations.push(...moveOperations);
|
||||||
});
|
});
|
||||||
return operations;
|
return operations;
|
||||||
}
|
}
|
||||||
|
@@ -1,4 +1,5 @@
|
|||||||
<div class="d-flex flex-row ds-value-row" *ngVar="mdValue.newValue.isVirtual as isVirtual"
|
<div class="d-flex flex-row ds-value-row" *ngVar="mdValue.newValue.isVirtual as isVirtual"
|
||||||
|
cdkDrag (cdkDragStarted)="dragging.emit(true)" (cdkDragEnded)="dragging.emit(false)"
|
||||||
[ngClass]="{ 'ds-warning': mdValue.change === DsoEditMetadataChangeTypeEnum.UPDATE, 'ds-danger': mdValue.change === DsoEditMetadataChangeTypeEnum.REMOVE, 'ds-success': mdValue.change === DsoEditMetadataChangeTypeEnum.ADD, 'h-100': isOnlyValue }">
|
[ngClass]="{ 'ds-warning': mdValue.change === DsoEditMetadataChangeTypeEnum.UPDATE, 'ds-danger': mdValue.change === DsoEditMetadataChangeTypeEnum.REMOVE, 'ds-success': mdValue.change === DsoEditMetadataChangeTypeEnum.ADD, 'h-100': isOnlyValue }">
|
||||||
<div class="flex-grow-1 ds-flex-cell ds-value-cell d-flex align-items-center" *ngVar="(mdRepresentation$ | async) as mdRepresentation">
|
<div class="flex-grow-1 ds-flex-cell ds-value-cell d-flex align-items-center" *ngVar="(mdRepresentation$ | async) as mdRepresentation">
|
||||||
<div class="dont-break-out preserve-line-breaks" *ngIf="!mdValue.editing && !mdRepresentation">{{ mdValue.newValue.value }}</div>
|
<div class="dont-break-out preserve-line-breaks" *ngIf="!mdValue.editing && !mdRepresentation">{{ mdValue.newValue.value }}</div>
|
||||||
@@ -34,8 +35,7 @@
|
|||||||
<i class="fas fa-undo-alt fa-fw"></i>
|
<i class="fas fa-undo-alt fa-fw"></i>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<!-- TODO: Enable drag -->
|
<button class="btn btn-outline-secondary ds-drag-handle btn-sm" cdkDragHandle
|
||||||
<button class="btn btn-outline-secondary ds-drag-handle btn-sm"
|
|
||||||
[ngClass]="{'disabled': isOnlyValue || (saving$ | async)}" ngbTooltip="{{ dsoType + '.edit.metadata.edit.buttons.drag' | translate }}" [disabled]="isOnlyValue || (saving$ | async)">
|
[ngClass]="{'disabled': isOnlyValue || (saving$ | async)}" ngbTooltip="{{ dsoType + '.edit.metadata.edit.buttons.drag' | translate }}" [disabled]="isOnlyValue || (saving$ | async)">
|
||||||
<i class="fas fa-grip-vertical fa-fw"></i>
|
<i class="fas fa-grip-vertical fa-fw"></i>
|
||||||
</button>
|
</button>
|
||||||
|
@@ -10,3 +10,7 @@
|
|||||||
::ng-deep .tooltip-inner {
|
::ng-deep .tooltip-inner {
|
||||||
min-width: var(--ds-dso-edit-virtual-tooltip-min-width);
|
min-width: var(--ds-dso-edit-virtual-tooltip-min-width);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.cdk-drag-placeholder {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
@@ -71,6 +71,11 @@ export class DsoEditMetadataValueComponent implements OnInit {
|
|||||||
*/
|
*/
|
||||||
@Output() undo: EventEmitter<any> = new EventEmitter<any>();
|
@Output() undo: EventEmitter<any> = new EventEmitter<any>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Emits true when the user starts dragging a value, false when the user stops dragging
|
||||||
|
*/
|
||||||
|
@Output() dragging: EventEmitter<boolean> = new EventEmitter<boolean>();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The DsoEditMetadataChangeType enumeration for access in the component's template
|
* The DsoEditMetadataChangeType enumeration for access in the component's template
|
||||||
* @type {DsoEditMetadataChangeType}
|
* @type {DsoEditMetadataChangeType}
|
||||||
|
@@ -48,6 +48,7 @@
|
|||||||
[form]="form"
|
[form]="form"
|
||||||
[dsoType]="dsoType"
|
[dsoType]="dsoType"
|
||||||
[saving$]="saving$"
|
[saving$]="saving$"
|
||||||
|
[draggingMdField$]="draggingMdField$"
|
||||||
[mdField]="mdField"
|
[mdField]="mdField"
|
||||||
(valueSaved)="onValueSaved()">
|
(valueSaved)="onValueSaved()">
|
||||||
</ds-dso-edit-metadata-field-values>
|
</ds-dso-edit-metadata-field-values>
|
||||||
|
@@ -19,6 +19,7 @@ import { NotificationsService } from '../../shared/notifications/notifications.s
|
|||||||
import { TranslateService } from '@ngx-translate/core';
|
import { TranslateService } from '@ngx-translate/core';
|
||||||
import { MetadataFieldSelectorComponent } from './metadata-field-selector/metadata-field-selector.component';
|
import { MetadataFieldSelectorComponent } from './metadata-field-selector/metadata-field-selector.component';
|
||||||
import { Observable } from 'rxjs/internal/Observable';
|
import { Observable } from 'rxjs/internal/Observable';
|
||||||
|
import { ArrayMoveChangeAnalyzer } from '../../core/data/array-move-change-analyzer.service';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'ds-dso-edit-metadata',
|
selector: 'ds-dso-edit-metadata',
|
||||||
@@ -72,6 +73,13 @@ export class DsoEditMetadataComponent implements OnInit, OnDestroy {
|
|||||||
*/
|
*/
|
||||||
saving$: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false);
|
saving$: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tracks for which metadata-field a drag operation is taking place
|
||||||
|
* Null when no drag is currently happening for any field
|
||||||
|
* This is a BehaviorSubject that is passed down to child components, to give them the power to alter the state
|
||||||
|
*/
|
||||||
|
draggingMdField$: BehaviorSubject<string> = new BehaviorSubject<string>(null);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whether or not the metadata field is currently being validated
|
* Whether or not the metadata field is currently being validated
|
||||||
*/
|
*/
|
||||||
@@ -98,7 +106,8 @@ export class DsoEditMetadataComponent implements OnInit, OnDestroy {
|
|||||||
constructor(protected route: ActivatedRoute,
|
constructor(protected route: ActivatedRoute,
|
||||||
protected notificationsService: NotificationsService,
|
protected notificationsService: NotificationsService,
|
||||||
protected translateService: TranslateService,
|
protected translateService: TranslateService,
|
||||||
protected parentInjector: Injector) {
|
protected parentInjector: Injector,
|
||||||
|
protected arrayMoveChangeAnalyser: ArrayMoveChangeAnalyzer<number>) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -167,7 +176,7 @@ export class DsoEditMetadataComponent implements OnInit, OnDestroy {
|
|||||||
*/
|
*/
|
||||||
submit(): void {
|
submit(): void {
|
||||||
this.saving$.next(true);
|
this.saving$.next(true);
|
||||||
this.updateDataService.patch(this.dso, this.form.getOperations()).pipe(
|
this.updateDataService.patch(this.dso, this.form.getOperations(this.arrayMoveChangeAnalyser)).pipe(
|
||||||
getFirstCompletedRemoteData()
|
getFirstCompletedRemoteData()
|
||||||
).subscribe((rd: RemoteData<DSpaceObject>) => {
|
).subscribe((rd: RemoteData<DSpaceObject>) => {
|
||||||
this.saving$.next(false);
|
this.saving$.next(false);
|
||||||
|
Reference in New Issue
Block a user