mirror of
https://github.com/DSpace/dspace-angular.git
synced 2025-10-07 18:14:17 +00:00
Refactored ItemDetailPreviewComponent
This commit is contained in:
@@ -329,7 +329,10 @@
|
||||
"no-title": "No title",
|
||||
"no-authors": "No Authors",
|
||||
"no-date": "No Date",
|
||||
"no-abstract": "No Abstract"
|
||||
"no-abstract": "No Abstract",
|
||||
"no-files": "No Files",
|
||||
"no-uri": "No Uri",
|
||||
"no-collections": "No Collections"
|
||||
},
|
||||
"messages": {
|
||||
"title": "Messages",
|
||||
|
@@ -0,0 +1,10 @@
|
||||
<ds-metadata-field-wrapper [label]="label | translate">
|
||||
<ng-container *ngIf="item.hasMetadata(metadata)">
|
||||
<span *ngFor="let mdValue of allMetadataValues(metadata); let last=last;">
|
||||
{{mdValue}}<span *ngIf="!last" [innerHTML]="separator"></span>
|
||||
</span>
|
||||
</ng-container>
|
||||
<ng-container *ngIf="!item.hasMetadata(metadata)">
|
||||
<span class="text-muted">{{(placeholder | translate)}}</span>
|
||||
</ng-container>
|
||||
</ds-metadata-field-wrapper>
|
@@ -0,0 +1,98 @@
|
||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import { ChangeDetectionStrategy, NO_ERRORS_SCHEMA } from '@angular/core';
|
||||
import { NoopAnimationsModule } from '@angular/platform-browser/animations';
|
||||
|
||||
import { of as observableOf } from 'rxjs';
|
||||
import { TranslateLoader, TranslateModule } from '@ngx-translate/core';
|
||||
|
||||
import { ItemDetailPreviewFieldComponent } from './item-detail-preview-field.component';
|
||||
import { Item } from '../../../../../core/shared/item.model';
|
||||
import { TruncatePipe } from '../../../../utils/truncate.pipe';
|
||||
import { MockTranslateLoader } from '../../../../mocks/mock-translate-loader';
|
||||
import { By } from '@angular/platform-browser';
|
||||
|
||||
let component: ItemDetailPreviewFieldComponent;
|
||||
let fixture: ComponentFixture<ItemDetailPreviewFieldComponent>;
|
||||
|
||||
const mockItemWithAuthorAndDate: Item = Object.assign(new Item(), {
|
||||
bitstreams: observableOf({}),
|
||||
metadata: {
|
||||
'dc.contributor.author': [
|
||||
{
|
||||
language: 'en_US',
|
||||
value: 'Smith, Donald'
|
||||
}
|
||||
],
|
||||
'dc.date.issued': [
|
||||
{
|
||||
language: null,
|
||||
value: '2015-06-26'
|
||||
}
|
||||
],
|
||||
'dc.title': [
|
||||
{
|
||||
language: 'en_US',
|
||||
value: 'This is just another title'
|
||||
}
|
||||
],
|
||||
'dc.type': [
|
||||
{
|
||||
language: null,
|
||||
value: 'Article'
|
||||
}
|
||||
]
|
||||
}
|
||||
});
|
||||
|
||||
describe('ItemDetailPreviewFieldComponent', () => {
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
imports: [
|
||||
NoopAnimationsModule,
|
||||
TranslateModule.forRoot({
|
||||
loader: {
|
||||
provide: TranslateLoader,
|
||||
useClass: MockTranslateLoader
|
||||
}
|
||||
}),
|
||||
],
|
||||
declarations: [ItemDetailPreviewFieldComponent, TruncatePipe],
|
||||
providers: [
|
||||
{ provide: 'objectElementProvider', useValue: { mockItemWithAuthorAndDate } }
|
||||
|
||||
],
|
||||
|
||||
schemas: [NO_ERRORS_SCHEMA]
|
||||
}).overrideComponent(ItemDetailPreviewFieldComponent, {
|
||||
set: { changeDetection: ChangeDetectionStrategy.Default }
|
||||
}).compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(async(() => {
|
||||
fixture = TestBed.createComponent(ItemDetailPreviewFieldComponent);
|
||||
component = fixture.componentInstance;
|
||||
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
component.object = { hitHighlights: {} } as any;
|
||||
component.item = mockItemWithAuthorAndDate;
|
||||
component.label = 'test label';
|
||||
component.metadata = 'dc.title';
|
||||
component.placeholder = 'No title';
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should display dc.title value', () => {
|
||||
const span = fixture.debugElement.query(By.css('span'));
|
||||
expect(span.nativeElement.innerHTML).toContain('This is just another title');
|
||||
});
|
||||
|
||||
it('should display placeholder when metadata has no value', () => {
|
||||
component.metadata = 'dc.abstract';
|
||||
component.placeholder = 'No abstract';
|
||||
fixture.detectChanges();
|
||||
const span = fixture.debugElement.query(By.css('.text-muted'));
|
||||
expect(span.nativeElement.innerHTML).toContain('No abstract');
|
||||
});
|
||||
});
|
@@ -0,0 +1,55 @@
|
||||
import { Component, Input } from '@angular/core';
|
||||
|
||||
import { Metadata } from '../../../../../core/shared/metadata.utils';
|
||||
import { MyDSpaceResult } from '../../../../../+my-dspace-page/my-dspace-result.model';
|
||||
import { Item } from '../../../../../core/shared/item.model';
|
||||
|
||||
/**
|
||||
* This component show values for the given item metadata
|
||||
*/
|
||||
@Component({
|
||||
selector: 'ds-item-detail-preview-field',
|
||||
templateUrl: './item-detail-preview-field.component.html'
|
||||
})
|
||||
export class ItemDetailPreviewFieldComponent {
|
||||
|
||||
/**
|
||||
* The item to display
|
||||
*/
|
||||
@Input() item: Item;
|
||||
|
||||
/**
|
||||
* The mydspace result object
|
||||
*/
|
||||
@Input() object: MyDSpaceResult<any>;
|
||||
|
||||
/**
|
||||
* The metadata label
|
||||
*/
|
||||
@Input() label: string;
|
||||
|
||||
/**
|
||||
* The metadata to show
|
||||
*/
|
||||
@Input() metadata: string | string[];
|
||||
|
||||
/**
|
||||
* The placeholder if there are no value to show
|
||||
*/
|
||||
@Input() placeholder: string;
|
||||
|
||||
/**
|
||||
* The value's separator
|
||||
*/
|
||||
@Input() separator: string;
|
||||
|
||||
/**
|
||||
* Gets all matching metadata string values from hitHighlights or dso metadata, preferring hitHighlights.
|
||||
*
|
||||
* @param {string|string[]} keyOrKeys The metadata key(s) in scope. Wildcards are supported; see [[Metadata]].
|
||||
* @returns {string[]} the matching string values or an empty array.
|
||||
*/
|
||||
allMetadataValues(keyOrKeys: string | string[]): string[] {
|
||||
return Metadata.allValues([this.object.hitHighlights, this.item.metadata], keyOrKeys);
|
||||
}
|
||||
}
|
@@ -1,10 +1,10 @@
|
||||
<div class="item-page" @fadeInOut>
|
||||
<div *ngIf="item" class="item-page" @fadeInOut>
|
||||
<ng-container *ngIf="status">
|
||||
<ds-mydspace-item-status [status]="status"></ds-mydspace-item-status>
|
||||
</ng-container>
|
||||
<div *ngIf="item">
|
||||
<h2 class="item-page-title-field">
|
||||
<ds-metadata-values *ngIf="item.hasMetadata('dc.title')" [mdValues]="item?.allMetadata(fields)"></ds-metadata-values>
|
||||
<ds-metadata-values *ngIf="item.hasMetadata('dc.title')" [mdValues]="item?.allMetadata('dc.title')"></ds-metadata-values>
|
||||
<span class="text-muted" *ngIf="!item.hasMetadata('dc.title')">{{('mydspace.results.no-title' | translate)}}</span>
|
||||
</h2>
|
||||
<div class="row mb-1">
|
||||
@@ -12,38 +12,46 @@
|
||||
<ds-metadata-field-wrapper>
|
||||
<ds-thumbnail [thumbnail]="thumbnail$ | async"></ds-thumbnail>
|
||||
</ds-metadata-field-wrapper>
|
||||
<ds-metadata-field-wrapper [label]="'item.page.date' | translate">
|
||||
<ng-container *ngIf="item.hasMetadata('dc.date.issued')">
|
||||
<span *ngFor="let mdValue of allMetadataValues('dc.date.issued'); let last=last;">
|
||||
{{mdValue.value}}<span *ngIf="!last" [innerHTML]="separator"></span>
|
||||
</span>
|
||||
</ng-container>
|
||||
<ng-container *ngIf="!item.hasMetadata('dc.date.issued')">
|
||||
<span class="text-muted">{{('mydspace.results.no-date' | translate)}}</span>
|
||||
</ng-container>
|
||||
</ds-metadata-field-wrapper>
|
||||
<ds-metadata-field-wrapper [label]="'item.page.author' | translate">
|
||||
<ng-container *ngIf="item.hasMetadata(['dc.contributor', 'dc.creator', 'dc.contributor.*']);">
|
||||
<span *ngFor="let mdValue of allMetadataValues(['dc.contributor.author', 'dc.creator', 'dc.contributor.*']); let last=last;">
|
||||
{{mdValue.value}}<span *ngIf="!last" [innerHTML]="separator"></span>
|
||||
</span>
|
||||
</ng-container>
|
||||
<ng-container *ngIf="!item.hasMetadata(['dc.contributor', 'dc.creator', 'dc.contributor.*']);">
|
||||
<span class="text-muted">{{('mydspace.results.no-authors' | translate)}}</span>
|
||||
</ng-container>
|
||||
</ds-metadata-field-wrapper>
|
||||
<ng-container *ngVar="(bitstreams$ | async) as bitstreams">
|
||||
<ds-metadata-field-wrapper [label]="('item.page.files' | translate)">
|
||||
<div *ngIf="bitstreams?.length > 0" class="file-section">
|
||||
<a *ngFor="let file of bitstreams; let last=last;" [href]="file?.content" target="_blank" [download]="file?.name">
|
||||
<span>{{file?.name}}</span>
|
||||
<span>({{(file?.sizeBytes) | dsFileSize }})</span>
|
||||
<span *ngIf="!last" innerHTML="{{separator}}"></span>
|
||||
</a>
|
||||
</div>
|
||||
<ng-container *ngIf="bitstreams?.length === 0">
|
||||
<span class="text-muted">{{('mydspace.results.no-files' | translate)}}</span>
|
||||
</ng-container>
|
||||
</ds-metadata-field-wrapper>
|
||||
</ng-container>
|
||||
<ds-item-detail-preview-field [item]="item"
|
||||
[object]="object"
|
||||
[label]="('item.page.date' | translate)"
|
||||
[metadata]="'dc.date.issued'"
|
||||
[separator]="separator"
|
||||
[placeholder]="('mydspace.results.no-date' | translate)"></ds-item-detail-preview-field>
|
||||
<ds-item-detail-preview-field [item]="item"
|
||||
[object]="object"
|
||||
[label]="('item.page.author' | translate)"
|
||||
[metadata]="['dc.contributor', 'dc.creator', 'dc.contributor.*']"
|
||||
[separator]="separator"
|
||||
[placeholder]="('mydspace.results.no-authors' | translate)"></ds-item-detail-preview-field>
|
||||
</div>
|
||||
<div class="col-xs-12 col-md-6">
|
||||
<ds-metadata-field-wrapper [label]="'item.page.abstract' | translate">
|
||||
<ng-container *ngIf="item.hasMetadata('dc.description.abstract');">
|
||||
<span *ngFor="let mdValue of allMetadataValues('dc.description.abstract'); let last=last;">
|
||||
{{mdValue.value}}<span *ngIf="!last" [innerHTML]="separator"></span>
|
||||
</span>
|
||||
</ng-container>
|
||||
<ng-container *ngIf="!item.hasMetadata('dc.description.abstract');">
|
||||
<span class="text-muted">{{('mydspace.results.no-abstract' | translate)}}</span>
|
||||
</ng-container>
|
||||
</ds-metadata-field-wrapper>
|
||||
<ds-item-detail-preview-field [item]="item"
|
||||
[object]="object"
|
||||
[label]="('item.page.abstract' | translate)"
|
||||
[metadata]="'dc.description.abstract'"
|
||||
[separator]="separator"
|
||||
[placeholder]="('mydspace.results.no-abstract' | translate)"></ds-item-detail-preview-field>
|
||||
<ds-item-detail-preview-field [item]="item"
|
||||
[object]="object"
|
||||
[label]="('item.page.uri' | translate)"
|
||||
[metadata]="'dc.identifier.uri'"
|
||||
[separator]="separator"
|
||||
[placeholder]="('mydspace.results.no-uri' | translate)"></ds-item-detail-preview-field>
|
||||
<div>
|
||||
<ng-content></ng-content>
|
||||
</div>
|
||||
|
@@ -1,5 +1,6 @@
|
||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import { ChangeDetectionStrategy, NO_ERRORS_SCHEMA } from '@angular/core';
|
||||
import { NoopAnimationsModule } from '@angular/platform-browser/animations';
|
||||
|
||||
import { of as observableOf } from 'rxjs';
|
||||
import { TranslateLoader, TranslateModule } from '@ngx-translate/core';
|
||||
@@ -8,13 +9,15 @@ import { TruncatePipe } from '../../../utils/truncate.pipe';
|
||||
import { Item } from '../../../../core/shared/item.model';
|
||||
import { ItemDetailPreviewComponent } from './item-detail-preview.component';
|
||||
import { MockTranslateLoader } from '../../../mocks/mock-translate-loader';
|
||||
import { NoopAnimationsModule } from '@angular/platform-browser/animations';
|
||||
import { ItemDetailPreviewFieldComponent } from './item-detail-preview-field/item-detail-preview-field.component';
|
||||
import { FileSizePipe } from '../../../utils/file-size-pipe';
|
||||
import { VarDirective } from '../../../utils/var.directive';
|
||||
|
||||
let component: ItemDetailPreviewComponent;
|
||||
let fixture: ComponentFixture<ItemDetailPreviewComponent>;
|
||||
|
||||
const mockItemWithAuthorAndDate: Item = Object.assign(new Item(), {
|
||||
bitstreams: observableOf({}),
|
||||
const mockItem: Item = Object.assign(new Item(), {
|
||||
bitstreams: observableOf([]),
|
||||
metadata: {
|
||||
'dc.contributor.author': [
|
||||
{
|
||||
@@ -27,12 +30,7 @@ const mockItemWithAuthorAndDate: Item = Object.assign(new Item(), {
|
||||
language: null,
|
||||
value: '2015-06-26'
|
||||
}
|
||||
]
|
||||
}
|
||||
});
|
||||
const mockItemWithoutAuthorAndDate: Item = Object.assign(new Item(), {
|
||||
bitstreams: observableOf({}),
|
||||
metadata: {
|
||||
],
|
||||
'dc.title': [
|
||||
{
|
||||
language: 'en_US',
|
||||
@@ -60,12 +58,7 @@ describe('ItemDetailPreviewComponent', () => {
|
||||
}
|
||||
}),
|
||||
],
|
||||
declarations: [ItemDetailPreviewComponent, TruncatePipe],
|
||||
providers: [
|
||||
{ provide: 'objectElementProvider', useValue: { mockItemWithAuthorAndDate } }
|
||||
|
||||
],
|
||||
|
||||
declarations: [ItemDetailPreviewComponent, ItemDetailPreviewFieldComponent, TruncatePipe, FileSizePipe, VarDirective],
|
||||
schemas: [NO_ERRORS_SCHEMA]
|
||||
}).overrideComponent(ItemDetailPreviewComponent, {
|
||||
set: { changeDetection: ChangeDetectionStrategy.Default }
|
||||
@@ -75,16 +68,16 @@ describe('ItemDetailPreviewComponent', () => {
|
||||
beforeEach(async(() => {
|
||||
fixture = TestBed.createComponent(ItemDetailPreviewComponent);
|
||||
component = fixture.componentInstance;
|
||||
component.object = { hitHighlights: {} } as any;
|
||||
component.item = mockItem;
|
||||
component.separator = ', ';
|
||||
spyOn(component.item, 'getFiles').and.returnValue(mockItem.bitstreams);
|
||||
fixture.detectChanges();
|
||||
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
component.object = { hitHighlights: {} };
|
||||
component.item = mockItemWithAuthorAndDate;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should init thumbnail on init', () => {
|
||||
it('should init thumbnail and bitstreams on init', () => {
|
||||
expect(component.thumbnail$).toBeDefined();
|
||||
expect(component.bitstreams$).toBeDefined();
|
||||
});
|
||||
});
|
||||
|
@@ -6,7 +6,7 @@ import { Item } from '../../../../core/shared/item.model';
|
||||
import { MyDspaceItemStatusType } from '../../../object-collection/shared/mydspace-item-status/my-dspace-item-status-type';
|
||||
import { fadeInOut } from '../../../animations/fade';
|
||||
import { Bitstream } from '../../../../core/shared/bitstream.model';
|
||||
import { Metadata } from '../../../../core/shared/metadata.utils';
|
||||
import { MyDSpaceResult } from '../../../../+my-dspace-page/my-dspace-result.model';
|
||||
|
||||
/**
|
||||
* This component show metadata for the given item object in the detail view.
|
||||
@@ -27,7 +27,7 @@ export class ItemDetailPreviewComponent {
|
||||
/**
|
||||
* The mydspace result object
|
||||
*/
|
||||
@Input() object: any;
|
||||
@Input() object: MyDSpaceResult<any>;
|
||||
|
||||
/**
|
||||
* Represent item's status
|
||||
@@ -42,23 +42,24 @@ export class ItemDetailPreviewComponent {
|
||||
/**
|
||||
* The item's thumbnail
|
||||
*/
|
||||
public thumbnail$: Observable<Bitstream>;
|
||||
public bitstreams$: Observable<Bitstream[]>;
|
||||
|
||||
/**
|
||||
* Gets all matching metadata string values from hitHighlights or dso metadata, preferring hitHighlights.
|
||||
*
|
||||
* @param {string|string[]} keyOrKeys The metadata key(s) in scope. Wildcards are supported; see [[Metadata]].
|
||||
* @returns {string[]} the matching string values or an empty array.
|
||||
* The value's separator
|
||||
*/
|
||||
allMetadataValues(keyOrKeys: string | string[]): string[] {
|
||||
return Metadata.allValues([this.object.hitHighlights, this.item.metadata], keyOrKeys);
|
||||
}
|
||||
public separator = ', ';
|
||||
|
||||
/**
|
||||
* The item's thumbnail
|
||||
*/
|
||||
public thumbnail$: Observable<Bitstream>;
|
||||
|
||||
/**
|
||||
* Initialize all instance variables
|
||||
*/
|
||||
ngOnInit() {
|
||||
this.thumbnail$ = this.item.getThumbnail();
|
||||
this.bitstreams$ = this.item.getFiles();
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -78,7 +78,7 @@ describe('ItemListPreviewComponent', () => {
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
component.object = { hitHighlights: {} };
|
||||
component.object = { hitHighlights: {} } as any;
|
||||
});
|
||||
|
||||
describe('When the item has an author', () => {
|
||||
|
@@ -4,6 +4,7 @@ import { Item } from '../../../../core/shared/item.model';
|
||||
import { fadeInOut } from '../../../animations/fade';
|
||||
import { MyDspaceItemStatusType } from '../../../object-collection/shared/mydspace-item-status/my-dspace-item-status-type';
|
||||
import { Metadata } from '../../../../core/shared/metadata.utils';
|
||||
import { MyDSpaceResult } from '../../../../+my-dspace-page/my-dspace-result.model';
|
||||
|
||||
/**
|
||||
* This component show metadata for the given item object in the list view.
|
||||
@@ -24,7 +25,7 @@ export class ItemListPreviewComponent {
|
||||
/**
|
||||
* The mydspace result object
|
||||
*/
|
||||
@Input() object: any;
|
||||
@Input() object: MyDSpaceResult<any>;
|
||||
|
||||
/**
|
||||
* Represent item's status
|
||||
|
@@ -130,6 +130,7 @@ import { MetadataValuesComponent } from '../+item-page/field-components/metadata
|
||||
import { RoleDirective } from './roles/role.directive';
|
||||
import { UserMenuComponent } from './auth-nav-menu/user-menu/user-menu.component';
|
||||
import { ClaimedTaskActionsReturnToPoolComponent } from './mydspace-actions/claimed-task/return-to-pool/claimed-task-actions-return-to-pool.component';
|
||||
import { ItemDetailPreviewFieldComponent } from './object-detail/my-dspace-result-detail-element/item-detail-preview/item-detail-preview-field/item-detail-preview-field.component';
|
||||
|
||||
const MODULES = [
|
||||
// Do NOT include UniversalModule, HttpModule, or JsonpModule here
|
||||
@@ -219,6 +220,7 @@ const COMPONENTS = [
|
||||
MyDSpaceItemStatusComponent,
|
||||
ItemSubmitterComponent,
|
||||
ItemDetailPreviewComponent,
|
||||
ItemDetailPreviewFieldComponent,
|
||||
ClaimedTaskActionsComponent,
|
||||
ClaimedTaskActionsApproveComponent,
|
||||
ClaimedTaskActionsRejectComponent,
|
||||
|
Reference in New Issue
Block a user