relation lookup progress/equatable

This commit is contained in:
lotte
2019-07-16 16:37:48 +02:00
parent 65a66a104c
commit 2bfe6ceebb
9 changed files with 93 additions and 101 deletions

View File

@@ -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;
}
}

View 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);
}

View 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);
}
}

View File

@@ -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">-->
<!--&lt;!&ndash; 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.-->
<!--&ndash;&gt;-->
<!--<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>

View File

@@ -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) {

View File

@@ -1 +0,0 @@
export interface ListableObject {}

View File

@@ -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);

View File

@@ -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
}

View File

@@ -16,4 +16,7 @@ export class SearchResult<T extends DSpaceObject> implements ListableObject {
*/
hitHighlights: MetadataMap;
get id(): string {
return this.indexableObject.id;
}
}