mirror of
https://github.com/DSpace/dspace-angular.git
synced 2025-10-07 01:54:15 +00:00
Merge pull request #1973 from 4Science/CST-7604
Restored highlighting of title in search results
This commit is contained in:
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -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];
|
||||
|
||||
|
@@ -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];
|
||||
|
||||
|
@@ -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;
|
||||
}
|
||||
}
|
||||
|
@@ -28,13 +28,19 @@ import { ItemSearchResultGridElementComponent } from './item-search-result-grid-
|
||||
|
||||
const mockItemWithMetadata: ItemSearchResult = new ItemSearchResult();
|
||||
mockItemWithMetadata.hitHighlights = {};
|
||||
const dcTitle = 'This is just another <em>title</em>';
|
||||
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: '<em>Michel</em>'
|
||||
}],
|
||||
},
|
||||
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: '<em>Science</em>'
|
||||
}],
|
||||
},
|
||||
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('<em>Michel</em>');
|
||||
});
|
||||
});
|
||||
|
||||
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('<em>Science</em>');
|
||||
});
|
||||
});
|
||||
});
|
||||
};
|
||||
}
|
||||
|
@@ -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);
|
||||
}
|
||||
}
|
||||
|
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
@@ -13,8 +13,13 @@ import { APP_CONFIG } from '../../../../../../../config/app-config.interface';
|
||||
|
||||
let publicationListElementComponent: ItemSearchResultListElementComponent;
|
||||
let fixture: ComponentFixture<ItemSearchResultListElementComponent>;
|
||||
|
||||
const dcTitle = 'This is just another <em>title</em>';
|
||||
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: '<em>Michel</em>'
|
||||
}],
|
||||
},
|
||||
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: '<em>Science</em>'
|
||||
}],
|
||||
},
|
||||
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('<em>Michel</em>');
|
||||
});
|
||||
});
|
||||
|
||||
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('<em>Science</em>');
|
||||
});
|
||||
});
|
||||
|
||||
describe('When the item has no title', () => {
|
||||
beforeEach(() => {
|
||||
publicationListElementComponent.object = mockItemWithoutMetadata;
|
||||
|
@@ -33,7 +33,7 @@ export class SearchResultListElementComponent<T extends SearchResult<K>, 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);
|
||||
}
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user