diff --git a/src/app/core/breadcrumbs/dso-name.service.ts b/src/app/core/breadcrumbs/dso-name.service.ts
index d56f4a00eb..64f37baa65 100644
--- a/src/app/core/breadcrumbs/dso-name.service.ts
+++ b/src/app/core/breadcrumbs/dso-name.service.ts
@@ -2,6 +2,7 @@ import { Injectable } from '@angular/core';
import { hasValue, isEmpty } from '../../shared/empty.util';
import { DSpaceObject } from '../shared/dspace-object.model';
import { TranslateService } from '@ngx-translate/core';
+import { Metadata } from '../shared/metadata.utils';
/**
* Returns a name for a {@link DSpaceObject} based
@@ -67,4 +68,45 @@ export class DSONameService {
return name;
}
+ /**
+ * Gets the Hit highlight
+ *
+ * @param object
+ * @param dso
+ *
+ * @returns {string} html embedded hit highlight.
+ */
+ getHitHighlights(object: any, dso: DSpaceObject): string {
+ const types = dso.getRenderTypes();
+ const entityType = types
+ .filter((type) => typeof type === 'string')
+ .find((type: string) => (['Person', 'OrgUnit']).includes(type)) as string;
+ if (entityType === 'Person') {
+ const familyName = this.firstMetadataValue(object, dso, 'person.familyName');
+ const givenName = this.firstMetadataValue(object, dso, 'person.givenName');
+ if (isEmpty(familyName) && isEmpty(givenName)) {
+ return this.firstMetadataValue(object, dso, 'dc.title') || dso.name;
+ } else if (isEmpty(familyName) || isEmpty(givenName)) {
+ return familyName || givenName;
+ }
+ return `${familyName}, ${givenName}`;
+ } else if (entityType === 'OrgUnit') {
+ return this.firstMetadataValue(object, dso, 'organization.legalName');
+ }
+ return this.firstMetadataValue(object, dso, 'dc.title') || dso.name || this.translateService.instant('dso.name.untitled');
+ }
+
+ /**
+ * Gets the first matching metadata string value from hitHighlights or dso metadata, preferring hitHighlights.
+ *
+ * @param object
+ * @param dso
+ * @param {string|string[]} keyOrKeys The metadata key(s) in scope. Wildcards are supported; see [[Metadata]].
+ *
+ * @returns {string} the first matching string value, or `undefined`.
+ */
+ firstMetadataValue(object: any, dso: DSpaceObject, keyOrKeys: string | string[]): string {
+ return Metadata.firstValue([object.hitHighlights, dso.metadata], keyOrKeys);
+ }
+
}
diff --git a/src/app/entity-groups/research-entities/submission/item-list-elements/org-unit/org-unit-search-result-list-submission-element.component.ts b/src/app/entity-groups/research-entities/submission/item-list-elements/org-unit/org-unit-search-result-list-submission-element.component.ts
index 7a38a02cf4..954f7bc591 100644
--- a/src/app/entity-groups/research-entities/submission/item-list-elements/org-unit/org-unit-search-result-list-submission-element.component.ts
+++ b/src/app/entity-groups/research-entities/submission/item-list-elements/org-unit/org-unit-search-result-list-submission-element.component.ts
@@ -61,7 +61,7 @@ export class OrgUnitSearchResultListSubmissionElementComponent extends SearchRes
this.useNameVariants = this.context === Context.EntitySearchModalWithNameVariants;
if (this.useNameVariants) {
- const defaultValue = this.dsoTitle;
+ const defaultValue = this.dso ? this.dsoNameService.getName(this.dso) : undefined;
const alternatives = this.allMetadataValues(this.alternativeField);
this.allSuggestions = [defaultValue, ...alternatives];
diff --git a/src/app/entity-groups/research-entities/submission/item-list-elements/person/person-search-result-list-submission-element.component.ts b/src/app/entity-groups/research-entities/submission/item-list-elements/person/person-search-result-list-submission-element.component.ts
index 7d761c42dd..305407f8d2 100644
--- a/src/app/entity-groups/research-entities/submission/item-list-elements/person/person-search-result-list-submission-element.component.ts
+++ b/src/app/entity-groups/research-entities/submission/item-list-elements/person/person-search-result-list-submission-element.component.ts
@@ -55,7 +55,7 @@ export class PersonSearchResultListSubmissionElementComponent extends SearchResu
ngOnInit() {
super.ngOnInit();
- const defaultValue = this.dsoTitle;
+ const defaultValue = this.dso ? this.dsoNameService.getName(this.dso) : undefined;
const alternatives = this.allMetadataValues(this.alternativeField);
this.allSuggestions = [defaultValue, ...alternatives];
diff --git a/src/app/shared/mocks/dso-name.service.mock.ts b/src/app/shared/mocks/dso-name.service.mock.ts
index f4947cc860..cf3cf5466b 100644
--- a/src/app/shared/mocks/dso-name.service.mock.ts
+++ b/src/app/shared/mocks/dso-name.service.mock.ts
@@ -6,4 +6,23 @@ export class DSONameServiceMock {
public getName(dso: DSpaceObject) {
return UNDEFINED_NAME;
}
+
+ public getHitHighlights(object: any, dso: DSpaceObject) {
+ if (object.hitHighlights && object.hitHighlights['dc.title']) {
+ return object.hitHighlights['dc.title'][0].value;
+ } else if (object.hitHighlights && object.hitHighlights['organization.legalName']) {
+ return object.hitHighlights['organization.legalName'][0].value;
+ } else if (object.hitHighlights && (object.hitHighlights['person.familyName'] || object.hitHighlights['person.givenName'])) {
+ if (object.hitHighlights['person.familyName'] && object.hitHighlights['person.givenName']) {
+ return `${object.hitHighlights['person.familyName'][0].value}, ${object.hitHighlights['person.givenName'][0].value}`;
+ }
+ if (object.hitHighlights['person.familyName']) {
+ return `${object.hitHighlights['person.familyName'][0].value}`;
+ }
+ if (object.hitHighlights['person.givenName']) {
+ return `${object.hitHighlights['person.givenName'][0].value}`;
+ }
+ }
+ return UNDEFINED_NAME;
+ }
}
diff --git a/src/app/shared/object-grid/search-result-grid-element/item-search-result/item/item-search-result-grid-element.component.spec.ts b/src/app/shared/object-grid/search-result-grid-element/item-search-result/item/item-search-result-grid-element.component.spec.ts
index 57b863a1b1..dc42b033d8 100644
--- a/src/app/shared/object-grid/search-result-grid-element/item-search-result/item/item-search-result-grid-element.component.spec.ts
+++ b/src/app/shared/object-grid/search-result-grid-element/item-search-result/item/item-search-result-grid-element.component.spec.ts
@@ -28,13 +28,19 @@ import { ItemSearchResultGridElementComponent } from './item-search-result-grid-
const mockItemWithMetadata: ItemSearchResult = new ItemSearchResult();
mockItemWithMetadata.hitHighlights = {};
+const dcTitle = 'This is just another title';
mockItemWithMetadata.indexableObject = Object.assign(new Item(), {
+ hitHighlights: {
+ 'dc.title': [{
+ value: dcTitle
+ }],
+ },
bundles: createSuccessfulRemoteDataObject$(buildPaginatedList(new PageInfo(), [])),
metadata: {
'dc.title': [
{
language: 'en_US',
- value: 'This is just another title'
+ value: dcTitle
}
],
'dc.contributor.author': [
@@ -57,6 +63,114 @@ mockItemWithMetadata.indexableObject = Object.assign(new Item(), {
]
}
});
+const mockPerson: ItemSearchResult = Object.assign(new ItemSearchResult(), {
+ hitHighlights: {
+ 'person.familyName': [{
+ value: 'Michel'
+ }],
+ },
+ indexableObject:
+ Object.assign(new Item(), {
+ bundles: createSuccessfulRemoteDataObject$(buildPaginatedList(new PageInfo(), [])),
+ entityType: 'Person',
+ metadata: {
+ 'dc.title': [
+ {
+ language: 'en_US',
+ value: 'This is just another title'
+ }
+ ],
+ 'dc.contributor.author': [
+ {
+ language: 'en_US',
+ value: 'Smith, Donald'
+ }
+ ],
+ 'dc.publisher': [
+ {
+ language: 'en_US',
+ value: 'a publisher'
+ }
+ ],
+ 'dc.date.issued': [
+ {
+ language: 'en_US',
+ value: '2015-06-26'
+ }
+ ],
+ 'dc.description.abstract': [
+ {
+ language: 'en_US',
+ value: 'This is the abstract'
+ }
+ ],
+ 'dspace.entity.type': [
+ {
+ value: 'Person'
+ }
+ ],
+ 'person.familyName': [
+ {
+ value: 'Michel'
+ }
+ ]
+ }
+ })
+});
+const mockOrgUnit: ItemSearchResult = Object.assign(new ItemSearchResult(), {
+ hitHighlights: {
+ 'organization.legalName': [{
+ value: 'Science'
+ }],
+ },
+ indexableObject:
+ Object.assign(new Item(), {
+ bundles: createSuccessfulRemoteDataObject$(buildPaginatedList(new PageInfo(), [])),
+ entityType: 'OrgUnit',
+ metadata: {
+ 'dc.title': [
+ {
+ language: 'en_US',
+ value: 'This is just another title'
+ }
+ ],
+ 'dc.contributor.author': [
+ {
+ language: 'en_US',
+ value: 'Smith, Donald'
+ }
+ ],
+ 'dc.publisher': [
+ {
+ language: 'en_US',
+ value: 'a publisher'
+ }
+ ],
+ 'dc.date.issued': [
+ {
+ language: 'en_US',
+ value: '2015-06-26'
+ }
+ ],
+ 'dc.description.abstract': [
+ {
+ language: 'en_US',
+ value: 'This is the abstract'
+ }
+ ],
+ 'organization.legalName': [
+ {
+ value: 'Science'
+ }
+ ],
+ 'dspace.entity.type': [
+ {
+ value: 'OrgUnit'
+ }
+ ]
+ }
+ })
+});
const mockItemWithoutMetadata: ItemSearchResult = new ItemSearchResult();
mockItemWithoutMetadata.hitHighlights = {};
@@ -154,6 +268,41 @@ export function getEntityGridElementTestComponent(component, searchResultWithMet
expect(itemAuthorField).toBeNull();
});
});
+
+ describe('When the item has title', () => {
+ beforeEach(() => {
+ comp.object = mockItemWithMetadata;
+ fixture.detectChanges();
+ });
+ it('should show highlighted title', () => {
+ const titleField = fixture.debugElement.query(By.css('.card-title'));
+ expect(titleField.nativeNode.innerHTML).toEqual(dcTitle);
+ });
+ });
+
+ describe('When the item is Person and has title', () => {
+ beforeEach(() => {
+ comp.object = mockPerson;
+ fixture.detectChanges();
+ });
+
+ it('should show highlighted title', () => {
+ const titleField = fixture.debugElement.query(By.css('.card-title'));
+ expect(titleField.nativeNode.innerHTML).toEqual('Michel');
+ });
+ });
+
+ describe('When the item is orgUnit and has title', () => {
+ beforeEach(() => {
+ comp.object = mockOrgUnit;
+ fixture.detectChanges();
+ });
+
+ it('should show highlighted title', () => {
+ const titleField = fixture.debugElement.query(By.css('.card-title'));
+ expect(titleField.nativeNode.innerHTML).toEqual('Science');
+ });
+ });
});
};
}
diff --git a/src/app/shared/object-grid/search-result-grid-element/item-search-result/item/item-search-result-grid-element.component.ts b/src/app/shared/object-grid/search-result-grid-element/item-search-result/item/item-search-result-grid-element.component.ts
index b5f9c016e4..303e4681a2 100644
--- a/src/app/shared/object-grid/search-result-grid-element/item-search-result/item/item-search-result-grid-element.component.ts
+++ b/src/app/shared/object-grid/search-result-grid-element/item-search-result/item/item-search-result-grid-element.component.ts
@@ -42,6 +42,6 @@ export class ItemSearchResultGridElementComponent extends SearchResultGridElemen
ngOnInit(): void {
super.ngOnInit();
this.itemPageRoute = getItemPageRoute(this.dso);
- this.dsoTitle = this.dsoNameService.getName(this.dso);
+ this.dsoTitle = this.dsoNameService.getHitHighlights(this.object, this.dso);
}
}
diff --git a/src/app/shared/object-list/my-dspace-result-list-element/item-list-preview/item-list-preview.component.ts b/src/app/shared/object-list/my-dspace-result-list-element/item-list-preview/item-list-preview.component.ts
index 04f1e24d7b..6b40678ded 100644
--- a/src/app/shared/object-list/my-dspace-result-list-element/item-list-preview/item-list-preview.component.ts
+++ b/src/app/shared/object-list/my-dspace-result-list-element/item-list-preview/item-list-preview.component.ts
@@ -55,7 +55,7 @@ export class ItemListPreviewComponent implements OnInit {
ngOnInit(): void {
this.showThumbnails = this.appConfig.browseBy.showThumbnails;
- this.dsoTitle = this.dsoNameService.getName(this.item);
+ this.dsoTitle = this.dsoNameService.getHitHighlights(this.object, this.item);
}
diff --git a/src/app/shared/object-list/search-result-list-element/item-search-result/item-types/item/item-search-result-list-element.component.spec.ts b/src/app/shared/object-list/search-result-list-element/item-search-result/item-types/item/item-search-result-list-element.component.spec.ts
index d1e6c27ba4..7665b7d64e 100644
--- a/src/app/shared/object-list/search-result-list-element/item-search-result/item-types/item/item-search-result-list-element.component.spec.ts
+++ b/src/app/shared/object-list/search-result-list-element/item-search-result/item-types/item/item-search-result-list-element.component.spec.ts
@@ -13,8 +13,13 @@ import { APP_CONFIG } from '../../../../../../../config/app-config.interface';
let publicationListElementComponent: ItemSearchResultListElementComponent;
let fixture: ComponentFixture;
-
+const dcTitle = 'This is just another title';
const mockItemWithMetadata: ItemSearchResult = Object.assign(new ItemSearchResult(), {
+ hitHighlights: {
+ 'dc.title': [{
+ value: dcTitle
+ }],
+ },
indexableObject:
Object.assign(new Item(), {
bundles: observableOf({}),
@@ -22,7 +27,7 @@ const mockItemWithMetadata: ItemSearchResult = Object.assign(new ItemSearchResul
'dc.title': [
{
language: 'en_US',
- value: 'This is just another title'
+ value: dcTitle
}
],
'dc.contributor.author': [
@@ -59,7 +64,114 @@ const mockItemWithoutMetadata: ItemSearchResult = Object.assign(new ItemSearchRe
metadata: {}
})
});
-
+const mockPerson: ItemSearchResult = Object.assign(new ItemSearchResult(), {
+ hitHighlights: {
+ 'person.familyName': [{
+ value: 'Michel'
+ }],
+ },
+ indexableObject:
+ Object.assign(new Item(), {
+ bundles: observableOf({}),
+ entityType: 'Person',
+ metadata: {
+ 'dc.title': [
+ {
+ language: 'en_US',
+ value: 'This is just another title'
+ }
+ ],
+ 'dc.contributor.author': [
+ {
+ language: 'en_US',
+ value: 'Smith, Donald'
+ }
+ ],
+ 'dc.publisher': [
+ {
+ language: 'en_US',
+ value: 'a publisher'
+ }
+ ],
+ 'dc.date.issued': [
+ {
+ language: 'en_US',
+ value: '2015-06-26'
+ }
+ ],
+ 'dc.description.abstract': [
+ {
+ language: 'en_US',
+ value: 'This is the abstract'
+ }
+ ],
+ 'person.familyName': [
+ {
+ value: 'Michel'
+ }
+ ],
+ 'dspace.entity.type': [
+ {
+ value: 'Person'
+ }
+ ]
+ }
+ })
+});
+const mockOrgUnit: ItemSearchResult = Object.assign(new ItemSearchResult(), {
+ hitHighlights: {
+ 'organization.legalName': [{
+ value: 'Science'
+ }],
+ },
+ indexableObject:
+ Object.assign(new Item(), {
+ bundles: observableOf({}),
+ entityType: 'OrgUnit',
+ metadata: {
+ 'dc.title': [
+ {
+ language: 'en_US',
+ value: 'This is just another title'
+ }
+ ],
+ 'dc.contributor.author': [
+ {
+ language: 'en_US',
+ value: 'Smith, Donald'
+ }
+ ],
+ 'dc.publisher': [
+ {
+ language: 'en_US',
+ value: 'a publisher'
+ }
+ ],
+ 'dc.date.issued': [
+ {
+ language: 'en_US',
+ value: '2015-06-26'
+ }
+ ],
+ 'dc.description.abstract': [
+ {
+ language: 'en_US',
+ value: 'This is the abstract'
+ }
+ ],
+ 'organization.legalName': [
+ {
+ value: 'Science'
+ }
+ ],
+ 'dspace.entity.type': [
+ {
+ value: 'OrgUnit'
+ }
+ ]
+ }
+ })
+});
const environmentUseThumbs = {
browseBy: {
showThumbnails: true
@@ -205,6 +317,42 @@ describe('ItemSearchResultListElementComponent', () => {
});
});
+ describe('When the item has title', () => {
+ beforeEach(() => {
+ publicationListElementComponent.object = mockItemWithMetadata;
+ fixture.detectChanges();
+ });
+
+ it('should show highlighted title', () => {
+ const titleField = fixture.debugElement.query(By.css('.item-list-title'));
+ expect(titleField.nativeNode.innerHTML).toEqual(dcTitle);
+ });
+ });
+
+ describe('When the item is Person and has title', () => {
+ beforeEach(() => {
+ publicationListElementComponent.object = mockPerson;
+ fixture.detectChanges();
+ });
+
+ it('should show highlighted title', () => {
+ const titleField = fixture.debugElement.query(By.css('.item-list-title'));
+ expect(titleField.nativeNode.innerHTML).toEqual('Michel');
+ });
+ });
+
+ describe('When the item is orgUnit and has title', () => {
+ beforeEach(() => {
+ publicationListElementComponent.object = mockOrgUnit;
+ fixture.detectChanges();
+ });
+
+ it('should show highlighted title', () => {
+ const titleField = fixture.debugElement.query(By.css('.item-list-title'));
+ expect(titleField.nativeNode.innerHTML).toEqual('Science');
+ });
+ });
+
describe('When the item has no title', () => {
beforeEach(() => {
publicationListElementComponent.object = mockItemWithoutMetadata;
diff --git a/src/app/shared/object-list/search-result-list-element/search-result-list-element.component.ts b/src/app/shared/object-list/search-result-list-element/search-result-list-element.component.ts
index 72120a6b68..e56b7e970a 100644
--- a/src/app/shared/object-list/search-result-list-element/search-result-list-element.component.ts
+++ b/src/app/shared/object-list/search-result-list-element/search-result-list-element.component.ts
@@ -33,7 +33,7 @@ export class SearchResultListElementComponent, K exten
ngOnInit(): void {
if (hasValue(this.object)) {
this.dso = this.object.indexableObject;
- this.dsoTitle = this.dsoNameService.getName(this.dso);
+ this.dsoTitle = this.dsoNameService.getHitHighlights(this.object, this.dso);
}
}