mirror of
https://github.com/DSpace/dspace-angular.git
synced 2025-10-13 04:53:06 +00:00
relation lookup progress/equatable
This commit is contained in:
@@ -1,8 +1,8 @@
|
||||
import { autoserialize, autoserializeAs } from 'cerialize';
|
||||
import { ListableObject } from '../../shared/object-collection/shared/listable-object.model';
|
||||
|
||||
export class BrowseEntry implements ListableObject {
|
||||
import { Equatable } from '../utilities/equatable';
|
||||
import { hasValue } from '../../shared/empty.util';
|
||||
|
||||
export class BrowseEntry implements Equatable<BrowseEntry> {
|
||||
@autoserialize
|
||||
type: string;
|
||||
|
||||
@@ -15,7 +15,15 @@ export class BrowseEntry implements ListableObject {
|
||||
@autoserializeAs('valueLang')
|
||||
language: string;
|
||||
|
||||
@excludeFromEquals
|
||||
@autoserialize
|
||||
count: number;
|
||||
|
||||
equals(other: BrowseEntry): boolean {
|
||||
if (hasValue(other)) {
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
39
src/app/core/utilities/equals.decorators.ts
Normal file
39
src/app/core/utilities/equals.decorators.ts
Normal file
@@ -0,0 +1,39 @@
|
||||
import { isEmpty } from '../../shared/empty.util';
|
||||
|
||||
const excludedFromEquals = new Map();
|
||||
const fieldsForEqualsMap = new Map();
|
||||
|
||||
export function excludeFromEquals(object: any, propertyName: string): any {
|
||||
if (!object) {
|
||||
return;
|
||||
}
|
||||
let list = excludedFromEquals.get(object.constructor);
|
||||
if (isEmpty(list)) {
|
||||
list = [];
|
||||
}
|
||||
excludedFromEquals.set(object.constructor, [...list, propertyName]);
|
||||
}
|
||||
|
||||
export function getExcludedFromEqualsFor(constructor: Function) {
|
||||
return excludedFromEquals.get(constructor) || [];
|
||||
}
|
||||
|
||||
export function fieldsForEquals(...fields: string[]): any {
|
||||
return function i(object: any, propertyName: string): any {
|
||||
if (!object) {
|
||||
return;
|
||||
}
|
||||
let fieldMap = fieldsForEqualsMap.get(object.constructor);
|
||||
if (isEmpty(fieldMap)) {
|
||||
fieldMap = new Map();
|
||||
}
|
||||
fieldMap.set(propertyName, fields);
|
||||
fieldsForEqualsMap.set(object.constructor, fieldMap);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export function getFieldsForEquals(constructor: Function, field: string) {
|
||||
const fieldMap = excludedFromEquals.get(constructor) || new Map();
|
||||
return fieldMap.get(field);
|
||||
}
|
33
src/app/core/utilities/equatable.ts
Normal file
33
src/app/core/utilities/equatable.ts
Normal file
@@ -0,0 +1,33 @@
|
||||
import { getExcludedFromEqualsFor, getFieldsForEquals } from './equals.decorators';
|
||||
import { hasNoValue, hasValue } from '../../shared/empty.util';
|
||||
|
||||
function equalsByFields(object1, object2, fieldList): boolean {
|
||||
const unequalProperty = fieldList.find((key) => {
|
||||
if (object1[key] === object2[key]) {
|
||||
return false;
|
||||
}
|
||||
if (hasNoValue(object1[key]) && hasNoValue(object2[key])) {
|
||||
return false;
|
||||
}
|
||||
if (hasNoValue(object1[key]) || hasNoValue(object2[key])) {
|
||||
return true;
|
||||
}
|
||||
const mapping = getFieldsForEquals(this.constructor, key);
|
||||
if (hasValue(mapping)) {
|
||||
return !equalsByFields(object1[key], object2[key], mapping);
|
||||
}
|
||||
if (this[key] instanceof EquatableObject) {
|
||||
return !object1[key].equals(object2[key]);
|
||||
}
|
||||
return object1[key] !== object2[key];
|
||||
});
|
||||
return hasNoValue(unequalProperty);
|
||||
}
|
||||
|
||||
export abstract class EquatableObject<T> {
|
||||
equals(other: T): boolean {
|
||||
const excludedKeys = getExcludedFromEqualsFor(this.constructor);
|
||||
const keys = Object.keys(this).filter((key) => excludedKeys.findIndex((excludedKey) => key === excludedKey) < 0);
|
||||
return equalsByFields(this, other, keys);
|
||||
}
|
||||
}
|
@@ -24,95 +24,6 @@
|
||||
[selectable]="true"
|
||||
[selectionConfig]="{ repeatable: repeatable, listId: listId }">
|
||||
</ds-search-results>
|
||||
<!--<ds-loading *ngIf="!resultsRD || resultsRD.isLoading"></ds-loading>-->
|
||||
<!--<div *ngIf="resultsRD?.hasSucceeded && resultsRD.payload.page.length > 0">-->
|
||||
<!--<div *ngIf="repeatable">-->
|
||||
<!--<div class="input-group mb-3">-->
|
||||
<!--<div class="input-group-prepend">-->
|
||||
<!--<div class="input-group-text">-->
|
||||
<!--<!– In theory we don't need separate checkboxes for this,-->
|
||||
<!--but I wasn't able to get this to work correctly without them.-->
|
||||
<!--Checkboxes that are in the indeterminate state always switch to checked when clicked-->
|
||||
<!--This seemed like the cleanest and clearest solution to solve this issue for now.-->
|
||||
<!--–>-->
|
||||
<!--<input *ngIf="!isAllSelected() && !isSomeSelected()"-->
|
||||
<!--type="checkbox"-->
|
||||
<!--[indeterminate]="false"-->
|
||||
<!--(change)="selectAll()">-->
|
||||
<!--<input *ngIf="!isAllSelected() && isSomeSelected()"-->
|
||||
<!--type="checkbox"-->
|
||||
<!--[indeterminate]="true"-->
|
||||
<!--(change)="deselectAll()">-->
|
||||
<!--<input *ngIf="isAllSelected()" type="checkbox"-->
|
||||
<!--[checked]="true"-->
|
||||
<!--(change)="deselectAll()">-->
|
||||
<!--</div>-->
|
||||
<!--</div>-->
|
||||
<!--<button *ngIf="selectAllLoading" type="button"-->
|
||||
<!--class="btn btn-outline-secondary">-->
|
||||
<!--<span class="spinner-border spinner-border-sm" role="status"-->
|
||||
<!--aria-hidden="true"></span>-->
|
||||
<!--<span class="sr-only">Loading...</span>-->
|
||||
<!--</button>-->
|
||||
<!--<div ngbDropdown class="input-group-append">-->
|
||||
<!--<button *ngIf="!selectAllLoading" id="resultdropdown" type="button"-->
|
||||
<!--ngbDropdownToggle-->
|
||||
<!--class="btn btn-outline-secondary dropdown-toggle-split"-->
|
||||
<!--data-toggle="dropdown" aria-haspopup="true"-->
|
||||
<!--aria-expanded="false">-->
|
||||
<!--<span class="sr-only">Toggle Dropdown</span>-->
|
||||
<!--</button>-->
|
||||
|
||||
<!--<div ngbDropdownMenu aria-labelledby="resultdropdown">-->
|
||||
<!--<button class="dropdown-item"-->
|
||||
<!--(click)="selectPage(resultsRD?.payload?.page)">Select-->
|
||||
<!--page-->
|
||||
<!--</button>-->
|
||||
<!--<button class="dropdown-item"-->
|
||||
<!--(click)="deselectPage(resultsRD?.payload?.page)">-->
|
||||
<!--Deselect-->
|
||||
<!--page-->
|
||||
<!--</button>-->
|
||||
<!--<button class="dropdown-item" (click)="selectAll()">Select all-->
|
||||
<!--</button>-->
|
||||
<!--<button class="dropdown-item" (click)="deselectAll()">Deselect-->
|
||||
<!--all-->
|
||||
<!--</button>-->
|
||||
<!--</div>-->
|
||||
<!--</div>-->
|
||||
<!--</div>-->
|
||||
<!--</div>-->
|
||||
<!--<ds-pagination-->
|
||||
<!--[paginationOptions]="searchConfig.pagination"-->
|
||||
<!--[collectionSize]="resultsRD?.payload?.totalElements"-->
|
||||
<!--[sortOptions]="searchConfig.sort"-->
|
||||
<!--[hideGear]="true"-->
|
||||
<!--[hidePagerWhenSinglePage]="true"-->
|
||||
<!--(paginationChange)="onPaginationChange($event.pagination)">-->
|
||||
<!--<div class="form-check"-->
|
||||
<!--*ngFor="let result of resultsRD?.payload?.page; let i = index">-->
|
||||
<!--<input *ngIf="repeatable" class="form-check-input" type="checkbox"-->
|
||||
<!--[name]="'checkbox' + i"-->
|
||||
<!--[id]="'object'+i"-->
|
||||
<!--[checked]="isSelected(result.indexableObject)"-->
|
||||
<!--[disabled]="isDisabled(result.indexableObject)"-->
|
||||
<!--(change)="selectCheckbox($event.currentTarget.checked, result.indexableObject)">-->
|
||||
<!--<input *ngIf="!repeatable" class="form-check-input" type="radio"-->
|
||||
<!--[name]="'radio' + i"-->
|
||||
<!--[id]="'object'+i"-->
|
||||
<!--[checked]="isSelected(result.indexableObject)"-->
|
||||
<!--(change)="selectRadio($event.currentTarget.checked, result.indexableObject)">-->
|
||||
<!--<label class="form-check-label" [for]="'object'+i">-->
|
||||
<!--<ds-wrapper-list-element class="result-list-element"-->
|
||||
<!--[object]="result"-->
|
||||
<!--[index]="i"></ds-wrapper-list-element>-->
|
||||
<!--</label>-->
|
||||
<!--</div>-->
|
||||
<!--</ds-pagination>-->
|
||||
<!--</div>-->
|
||||
<!--<div *ngIf="resultsRD?.hasSucceeded && resultsRD.payload.page.length === 0">-->
|
||||
<!--{{ 'form.no-results' | translate}}-->
|
||||
<!--</div>-->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@@ -52,7 +52,7 @@ export class DsDynamicLookupRelationModalComponent implements OnInit {
|
||||
ngOnInit(): void {
|
||||
this.resetRoute();
|
||||
this.onPaginationChange(this.initialPagination);
|
||||
this.selectableListService.getSelectableList(this.listId).pipe(map((listState: SelectableListState) => hasValue(listState) && hasValue(listState.selection) ? listState.selection : []));
|
||||
this.selection = this.selectableListService.getSelectableList(this.listId).pipe(map((listState: SelectableListState) => hasValue(listState) && hasValue(listState.selection) ? listState.selection : []));
|
||||
}
|
||||
|
||||
search(query: string) {
|
||||
|
@@ -1 +0,0 @@
|
||||
export interface ListableObject {}
|
@@ -68,7 +68,7 @@ export class SelectableListDeselectAction extends SelectableListAction {
|
||||
}
|
||||
|
||||
export class SelectableListSetSelectionAction extends SelectableListAction {
|
||||
payload: ListableObject;
|
||||
payload: ListableObject[];
|
||||
|
||||
constructor(id: string, objects: ListableObject[]) {
|
||||
super(SelectableListActionTypes.SET_SELECTION, id);
|
||||
|
@@ -71,7 +71,7 @@ function select(state: SelectableListState, action: SelectableListSelectAction)
|
||||
|
||||
function selectSingle(state: SelectableListState, action: SelectableListSelectSingleAction) {
|
||||
let newSelection;
|
||||
if (action.payload.multipleSelectionsAllowed && !isObjectInSelection(state.selection, action.payload)) {
|
||||
if (action.payload.multipleSelectionsAllowed && !isObjectInSelection(state.selection, action.payload.object)) {
|
||||
newSelection = [...state.selection, action.payload.object];
|
||||
} else {
|
||||
newSelection = [action.payload.object];
|
||||
@@ -80,20 +80,19 @@ function selectSingle(state: SelectableListState, action: SelectableListSelectSi
|
||||
}
|
||||
|
||||
function deselect(state: SelectableListState, action: SelectableListDeselectAction) {
|
||||
const newSelection = state.selection.filter((selected) => hasNoValue(action.payload.find((object) => object === selected)));
|
||||
const newSelection = state.selection.filter((selected) => hasNoValue(action.payload.find((object) => object.uuid === selected.uuid)));
|
||||
return Object.assign({}, state, { selection: newSelection });
|
||||
}
|
||||
|
||||
function deselectSingle(state: SelectableListState, action: SelectableListDeselectSingleAction) {
|
||||
const newSelection = state.selection.filter((selected) => {
|
||||
return selected !== action.payload
|
||||
return selected.uuid !== action.payload.uuid
|
||||
});
|
||||
return Object.assign({}, state, { selection: newSelection });
|
||||
}
|
||||
|
||||
function setList(state: SelectableListState, action: SelectableListSetSelectionAction) {
|
||||
const newSelection = [...state.selection, action.payload];
|
||||
return Object.assign({}, state, { selection: newSelection });
|
||||
return Object.assign({}, state, { selection: action.payload });
|
||||
}
|
||||
|
||||
function clearSelection(id: string) {
|
||||
@@ -102,5 +101,5 @@ function clearSelection(id: string) {
|
||||
|
||||
|
||||
function isObjectInSelection(selection: ListableObject[], object: ListableObject) {
|
||||
return selection.findIndex((selected) => selected === object) >= 0
|
||||
return selection.findIndex((selected) => selected.uuid === object.uuid) >= 0
|
||||
}
|
||||
|
@@ -16,4 +16,7 @@ export class SearchResult<T extends DSpaceObject> implements ListableObject {
|
||||
*/
|
||||
hitHighlights: MetadataMap;
|
||||
|
||||
get id(): string {
|
||||
return this.indexableObject.id;
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user