mirror of
https://github.com/DSpace/dspace-angular.git
synced 2025-10-18 07:23:03 +00:00
Merge pull request #88 from LotteHofstede/w2p-40416_simple-item-page
Simple Item View Page
This commit is contained in:
@@ -11,6 +11,17 @@
|
|||||||
"link.duraspace": "DuraSpace"
|
"link.duraspace": "DuraSpace"
|
||||||
},
|
},
|
||||||
|
|
||||||
|
"item": {
|
||||||
|
"page": {
|
||||||
|
"author": "Author",
|
||||||
|
"abstract": "Abstract",
|
||||||
|
"date": "Date",
|
||||||
|
"uri": "URI",
|
||||||
|
"files": "Files",
|
||||||
|
"collections": "Collections"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
"nav": {
|
"nav": {
|
||||||
"home": "Home"
|
"home": "Home"
|
||||||
},
|
},
|
||||||
|
@@ -2,6 +2,7 @@ import { NgModule } from '@angular/core';
|
|||||||
|
|
||||||
import { CoreModule } from './core/core.module';
|
import { CoreModule } from './core/core.module';
|
||||||
import { HomeModule } from './home/home.module';
|
import { HomeModule } from './home/home.module';
|
||||||
|
import { ItemPageModule } from './item-page/item-page.module';
|
||||||
|
|
||||||
import { SharedModule } from './shared/shared.module';
|
import { SharedModule } from './shared/shared.module';
|
||||||
|
|
||||||
@@ -10,15 +11,17 @@ import { AppComponent } from './app.component';
|
|||||||
import { HeaderComponent } from './header/header.component';
|
import { HeaderComponent } from './header/header.component';
|
||||||
import { PageNotFoundComponent } from './pagenotfound/pagenotfound.component';
|
import { PageNotFoundComponent } from './pagenotfound/pagenotfound.component';
|
||||||
|
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
declarations: [
|
declarations: [
|
||||||
AppComponent,
|
AppComponent,
|
||||||
HeaderComponent,
|
HeaderComponent,
|
||||||
PageNotFoundComponent
|
PageNotFoundComponent,
|
||||||
],
|
],
|
||||||
imports: [
|
imports: [
|
||||||
SharedModule,
|
SharedModule,
|
||||||
HomeModule,
|
HomeModule,
|
||||||
|
ItemPageModule,
|
||||||
CoreModule.forRoot(),
|
CoreModule.forRoot(),
|
||||||
AppRoutingModule,
|
AppRoutingModule,
|
||||||
],
|
],
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
import { inheritSerialization } from "cerialize";
|
import { inheritSerialization, autoserialize } from "cerialize";
|
||||||
import { NormalizedDSpaceObject } from "./normalized-dspace-object.model";
|
import { NormalizedDSpaceObject } from "./normalized-dspace-object.model";
|
||||||
import { Bitstream } from "../../shared/bitstream.model";
|
import { Bitstream } from "../../shared/bitstream.model";
|
||||||
import { mapsTo } from "../builders/build-decorators";
|
import { mapsTo } from "../builders/build-decorators";
|
||||||
@@ -10,6 +10,7 @@ export class NormalizedBitstream extends NormalizedDSpaceObject {
|
|||||||
/**
|
/**
|
||||||
* The size of this bitstream in bytes(?)
|
* The size of this bitstream in bytes(?)
|
||||||
*/
|
*/
|
||||||
|
@autoserialize
|
||||||
size: number;
|
size: number;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -36,4 +37,7 @@ export class NormalizedBitstream extends NormalizedDSpaceObject {
|
|||||||
* The Bundle that owns this Bitstream
|
* The Bundle that owns this Bitstream
|
||||||
*/
|
*/
|
||||||
owner: string;
|
owner: string;
|
||||||
|
|
||||||
|
@autoserialize
|
||||||
|
retrieve: string;
|
||||||
}
|
}
|
||||||
|
@@ -42,6 +42,7 @@ export abstract class NormalizedDSpaceObject implements CacheableObject {
|
|||||||
/**
|
/**
|
||||||
* An array of DSpaceObjects that are direct parents of this DSpaceObject
|
* An array of DSpaceObjects that are direct parents of this DSpaceObject
|
||||||
*/
|
*/
|
||||||
|
@autoserialize
|
||||||
parents: Array<string>;
|
parents: Array<string>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@@ -32,6 +32,8 @@ export class NormalizedItem extends NormalizedDSpaceObject {
|
|||||||
/**
|
/**
|
||||||
* An array of Collections that are direct parents of this Item
|
* An array of Collections that are direct parents of this Item
|
||||||
*/
|
*/
|
||||||
|
@autoserialize
|
||||||
|
@relationship(NormalizedDSOType.NormalizedCollection)
|
||||||
parents: Array<string>;
|
parents: Array<string>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@@ -1,5 +1,6 @@
|
|||||||
import { DSpaceObject } from "./dspace-object.model";
|
import { DSpaceObject } from "./dspace-object.model";
|
||||||
import { Bundle } from "./bundle.model";
|
import { Bundle } from "./bundle.model";
|
||||||
|
import { RemoteData } from "../data/remote-data";
|
||||||
|
|
||||||
export class Bitstream extends DSpaceObject {
|
export class Bitstream extends DSpaceObject {
|
||||||
|
|
||||||
@@ -26,10 +27,16 @@ export class Bitstream extends DSpaceObject {
|
|||||||
/**
|
/**
|
||||||
* An array of Bundles that are direct parents of this Bitstream
|
* An array of Bundles that are direct parents of this Bitstream
|
||||||
*/
|
*/
|
||||||
parents: Array<Bundle>;
|
parents: Array<RemoteData<Bundle>>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The Bundle that owns this Bitstream
|
* The Bundle that owns this Bitstream
|
||||||
*/
|
*/
|
||||||
owner: Bundle;
|
owner: Bundle;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The Bundle that owns this Bitstream
|
||||||
|
*/
|
||||||
|
retrieve: string;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -12,7 +12,7 @@ export class Bundle extends DSpaceObject {
|
|||||||
/**
|
/**
|
||||||
* An array of Items that are direct parents of this Bundle
|
* An array of Items that are direct parents of this Bundle
|
||||||
*/
|
*/
|
||||||
parents: Array<Item>;
|
parents: Array<RemoteData<Item>>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The Item that owns this Bundle
|
* The Item that owns this Bundle
|
||||||
|
@@ -58,7 +58,7 @@ export class Collection extends DSpaceObject {
|
|||||||
/**
|
/**
|
||||||
* An array of Collections that are direct parents of this Collection
|
* An array of Collections that are direct parents of this Collection
|
||||||
*/
|
*/
|
||||||
parents: Array<Collection>;
|
parents: Array<RemoteData<Collection>>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The Collection that owns this Collection
|
* The Collection that owns this Collection
|
||||||
|
@@ -2,76 +2,94 @@ import { autoserialize, autoserializeAs } from "cerialize";
|
|||||||
import { Metadatum } from "./metadatum.model"
|
import { Metadatum } from "./metadatum.model"
|
||||||
import { isEmpty, isNotEmpty } from "../../shared/empty.util";
|
import { isEmpty, isNotEmpty } from "../../shared/empty.util";
|
||||||
import { CacheableObject } from "../cache/object-cache.reducer";
|
import { CacheableObject } from "../cache/object-cache.reducer";
|
||||||
|
import { RemoteData } from "../data/remote-data";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An abstract model class for a DSpaceObject.
|
* An abstract model class for a DSpaceObject.
|
||||||
*/
|
*/
|
||||||
export abstract class DSpaceObject implements CacheableObject {
|
export abstract class DSpaceObject implements CacheableObject {
|
||||||
|
|
||||||
@autoserialize
|
@autoserialize
|
||||||
self: string;
|
self: string;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The human-readable identifier of this DSpaceObject
|
* The human-readable identifier of this DSpaceObject
|
||||||
*/
|
*/
|
||||||
@autoserialize
|
@autoserialize
|
||||||
id: string;
|
id: string;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The universally unique identifier of this DSpaceObject
|
* The universally unique identifier of this DSpaceObject
|
||||||
*/
|
*/
|
||||||
@autoserialize
|
@autoserialize
|
||||||
uuid: string;
|
uuid: string;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A string representing the kind of DSpaceObject, e.g. community, item, …
|
* A string representing the kind of DSpaceObject, e.g. community, item, …
|
||||||
*/
|
*/
|
||||||
type: string;
|
type: string;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The name for this DSpaceObject
|
* The name for this DSpaceObject
|
||||||
*/
|
*/
|
||||||
@autoserialize
|
@autoserialize
|
||||||
name: string;
|
name: string;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An array containing all metadata of this DSpaceObject
|
* An array containing all metadata of this DSpaceObject
|
||||||
*/
|
*/
|
||||||
@autoserializeAs(Metadatum)
|
@autoserializeAs(Metadatum)
|
||||||
metadata: Array<Metadatum>;
|
metadata: Array<Metadatum>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An array of DSpaceObjects that are direct parents of this DSpaceObject
|
* An array of DSpaceObjects that are direct parents of this DSpaceObject
|
||||||
*/
|
*/
|
||||||
parents: Array<DSpaceObject>;
|
parents: Array<RemoteData<DSpaceObject>>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The DSpaceObject that owns this DSpaceObject
|
* The DSpaceObject that owns this DSpaceObject
|
||||||
*/
|
*/
|
||||||
owner: DSpaceObject;
|
owner: DSpaceObject;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Find a metadata field by key and language
|
* Find a metadata field by key and language
|
||||||
*
|
*
|
||||||
* This method returns the value of the first element
|
* This method returns the value of the first element
|
||||||
* in the metadata array that matches the provided
|
* in the metadata array that matches the provided
|
||||||
* key and language
|
* key and language
|
||||||
*
|
*
|
||||||
* @param key
|
* @param key
|
||||||
* @param language
|
* @param language
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
findMetadata(key: string, language?: string): string {
|
findMetadata(key: string, language?: string): string {
|
||||||
const metadatum = this.metadata
|
const metadatum = this.metadata
|
||||||
.find((metadatum: Metadatum) => {
|
.find((metadatum: Metadatum) => {
|
||||||
return metadatum.key === key &&
|
return metadatum.key === key &&
|
||||||
(isEmpty(language) || metadatum.language === language)
|
(isEmpty(language) || metadatum.language === language)
|
||||||
});
|
});
|
||||||
if (isNotEmpty(metadatum)) {
|
if (isNotEmpty(metadatum)) {
|
||||||
return metadatum.value;
|
return metadatum.value;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
return undefined;
|
/**
|
||||||
|
* Find metadata by an array of keys
|
||||||
|
*
|
||||||
|
* This method returns the values of the element
|
||||||
|
* in the metadata array that match the provided
|
||||||
|
* key(s)
|
||||||
|
*
|
||||||
|
* @param key(s)
|
||||||
|
* @return Array<Metadatum>
|
||||||
|
*/
|
||||||
|
filterMetadata(keys: string[]): Array<Metadatum> {
|
||||||
|
return this.metadata
|
||||||
|
.filter((metadatum: Metadatum) => {
|
||||||
|
return keys.some(key => key === metadatum.key);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@@ -2,39 +2,79 @@ import { DSpaceObject } from "./dspace-object.model";
|
|||||||
import { Collection } from "./collection.model";
|
import { Collection } from "./collection.model";
|
||||||
import { RemoteData } from "../data/remote-data";
|
import { RemoteData } from "../data/remote-data";
|
||||||
import { Bundle } from "./bundle.model";
|
import { Bundle } from "./bundle.model";
|
||||||
|
import { Bitstream } from "./bitstream.model";
|
||||||
|
import { Observable } from "rxjs";
|
||||||
|
|
||||||
export class Item extends DSpaceObject {
|
export class Item extends DSpaceObject {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A string representing the unique handle of this Item
|
* A string representing the unique handle of this Item
|
||||||
*/
|
*/
|
||||||
handle: string;
|
handle: string;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The Date of the last modification of this Item
|
* The Date of the last modification of this Item
|
||||||
*/
|
*/
|
||||||
lastModified: Date;
|
lastModified: Date;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A boolean representing if this Item is currently archived or not
|
* A boolean representing if this Item is currently archived or not
|
||||||
*/
|
*/
|
||||||
isArchived: boolean;
|
isArchived: boolean;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A boolean representing if this Item is currently withdrawn or not
|
* A boolean representing if this Item is currently withdrawn or not
|
||||||
*/
|
*/
|
||||||
isWithdrawn: boolean;
|
isWithdrawn: boolean;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An array of Collections that are direct parents of this Item
|
* An array of Collections that are direct parents of this Item
|
||||||
*/
|
*/
|
||||||
parents: Array<Collection>;
|
parents: Array<RemoteData<Collection>>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The Collection that owns this Item
|
* The Collection that owns this Item
|
||||||
*/
|
*/
|
||||||
owner: Collection;
|
owner: Collection;
|
||||||
|
|
||||||
bundles: Array<RemoteData<Bundle>>
|
bundles: Array<RemoteData<Bundle>>;
|
||||||
|
|
||||||
|
getThumbnail(): Observable<Bitstream> {
|
||||||
|
const bundle: Observable<Bundle> = this.getBundle("THUMBNAIL");
|
||||||
|
return bundle.flatMap(
|
||||||
|
bundle => {
|
||||||
|
if (bundle != null) {
|
||||||
|
return bundle.primaryBitstream.payload;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return Observable.of(undefined);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
getFiles(): Observable<Array<Observable<Bitstream>>> {
|
||||||
|
const bundle: Observable <Bundle> = this.getBundle("ORIGINAL");
|
||||||
|
return bundle.map(bundle => {
|
||||||
|
if (bundle != null) {
|
||||||
|
return bundle.bitstreams.map(bitstream => bitstream.payload)
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
getBundle(name: String): Observable<Bundle> {
|
||||||
|
return Observable.combineLatest(
|
||||||
|
...this.bundles.map(b => b.payload),
|
||||||
|
(...bundles: Array<Bundle>) => bundles)
|
||||||
|
.map(bundles => {
|
||||||
|
return bundles.find((bundle: Bundle) => {
|
||||||
|
return bundle.name === name
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
getCollections(): Array<Observable<Collection>> {
|
||||||
|
return this.parents.map(collection => collection.payload.map(parent => parent));
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
7
src/app/item-page/collections/collections.component.html
Normal file
7
src/app/item-page/collections/collections.component.html
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
<ds-metadata-field-wrapper [label]="label | translate">
|
||||||
|
<div class="collections">
|
||||||
|
<a *ngFor="let collection of collections; let last=last;" [href]="(collection | async)?.self">
|
||||||
|
<span>{{(collection | async)?.name}}</span><span *ngIf="!last" [innerHTML]="separator"></span>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</ds-metadata-field-wrapper>
|
34
src/app/item-page/collections/collections.component.ts
Normal file
34
src/app/item-page/collections/collections.component.ts
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
import { Component, Input, OnInit } from '@angular/core';
|
||||||
|
import { Collection } from "../../core/shared/collection.model";
|
||||||
|
import { Observable } from "rxjs";
|
||||||
|
import { Item } from "../../core/shared/item.model";
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'ds-item-page-collections',
|
||||||
|
templateUrl: './collections.component.html'
|
||||||
|
})
|
||||||
|
export class CollectionsComponent implements OnInit {
|
||||||
|
|
||||||
|
@Input() item: Item;
|
||||||
|
|
||||||
|
label : string = "item.page.collections";
|
||||||
|
|
||||||
|
separator: string = "<br/>"
|
||||||
|
|
||||||
|
collections: Array<Observable<Collection>>;
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
this.universalInit();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
universalInit() {
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnInit(): void {
|
||||||
|
this.collections = this.item.getCollections();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
@@ -0,0 +1,9 @@
|
|||||||
|
<ds-metadata-field-wrapper [label]="label | translate">
|
||||||
|
<div class="file-section">
|
||||||
|
<a *ngFor="let file of (files | async); let last=last;" [href]="(file | async)?.retrieve">
|
||||||
|
<span>{{(file | async)?.name}}</span>
|
||||||
|
<span>({{((file | async)?.size) | dsFileSize }})</span>
|
||||||
|
<span *ngIf="!last" innerHTML="{{separator}}"></span>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</ds-metadata-field-wrapper>
|
33
src/app/item-page/file-section/file-section.component.ts
Normal file
33
src/app/item-page/file-section/file-section.component.ts
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
import { Component, Input, OnInit } from '@angular/core';
|
||||||
|
import { Bitstream } from "../../core/shared/bitstream.model";
|
||||||
|
import { Item } from "../../core/shared/item.model";
|
||||||
|
import { Observable } from "rxjs";
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'ds-item-page-file-section',
|
||||||
|
templateUrl: './file-section.component.html'
|
||||||
|
})
|
||||||
|
export class FileSectionComponent implements OnInit {
|
||||||
|
|
||||||
|
@Input() item: Item;
|
||||||
|
|
||||||
|
label : string = "item.page.files";
|
||||||
|
|
||||||
|
separator: string = "<br/>"
|
||||||
|
|
||||||
|
files: Observable<Array<Observable<Bitstream>>>;
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
this.universalInit();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
universalInit() {
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnInit(): void {
|
||||||
|
this.files = this.item.getFiles();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
14
src/app/item-page/item-page-routing.module.ts
Normal file
14
src/app/item-page/item-page-routing.module.ts
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
import { NgModule } from '@angular/core';
|
||||||
|
import { RouterModule } from '@angular/router';
|
||||||
|
|
||||||
|
import { ItemPageComponent } from './item-page.component';
|
||||||
|
|
||||||
|
@NgModule({
|
||||||
|
imports: [
|
||||||
|
RouterModule.forChild([
|
||||||
|
{ path: 'items/:id', pathMatch: 'full', component: ItemPageComponent },
|
||||||
|
])
|
||||||
|
]
|
||||||
|
})
|
||||||
|
export class ItemPageRoutingModule {
|
||||||
|
}
|
19
src/app/item-page/item-page.component.html
Normal file
19
src/app/item-page/item-page.component.html
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
<div class="item-page" *ngIf="item.hasSucceeded | async">
|
||||||
|
<ds-item-page-title-field [item]="item.payload | async"></ds-item-page-title-field>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-xs-12 col-md-4">
|
||||||
|
<ds-metadata-field-wrapper>
|
||||||
|
<ds-thumbnail [thumbnail]="thumbnail | async"></ds-thumbnail>
|
||||||
|
</ds-metadata-field-wrapper>
|
||||||
|
<ds-item-page-file-section [item]="item.payload | async"></ds-item-page-file-section>
|
||||||
|
<ds-item-page-date-field [item]="item.payload | async"></ds-item-page-date-field>
|
||||||
|
<ds-item-page-author-field [item]="item.payload | async"></ds-item-page-author-field>
|
||||||
|
</div>
|
||||||
|
<div class="col-xs-12 col-md-6">
|
||||||
|
<ds-item-page-abstract-field
|
||||||
|
[item]="item.payload | async"></ds-item-page-abstract-field>
|
||||||
|
<ds-item-page-uri-field [item]="item.payload | async"></ds-item-page-uri-field>
|
||||||
|
<ds-item-page-collections [item]="item.payload | async"></ds-item-page-collections>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
1
src/app/item-page/item-page.component.scss
Normal file
1
src/app/item-page/item-page.component.scss
Normal file
@@ -0,0 +1 @@
|
|||||||
|
@import '../../styles/variables.scss';
|
41
src/app/item-page/item-page.component.ts
Normal file
41
src/app/item-page/item-page.component.ts
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
import { Component, OnInit } from '@angular/core';
|
||||||
|
import { ActivatedRoute } from '@angular/router';
|
||||||
|
import { Item } from "../core/shared/item.model";
|
||||||
|
import { ItemDataService } from "../core/data/item-data.service";
|
||||||
|
import { RemoteData } from "../core/data/remote-data";
|
||||||
|
import { Observable } from "rxjs";
|
||||||
|
import { Bitstream } from "../core/shared/bitstream.model";
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'ds-item-page',
|
||||||
|
styleUrls: ['./item-page.component.css'],
|
||||||
|
templateUrl: './item-page.component.html',
|
||||||
|
})
|
||||||
|
export class ItemPageComponent implements OnInit {
|
||||||
|
|
||||||
|
id: number;
|
||||||
|
|
||||||
|
private sub: any;
|
||||||
|
|
||||||
|
item: RemoteData<Item>;
|
||||||
|
|
||||||
|
thumbnail: Observable<Bitstream>;
|
||||||
|
|
||||||
|
constructor(private route: ActivatedRoute, private items: ItemDataService) {
|
||||||
|
this.universalInit();
|
||||||
|
}
|
||||||
|
|
||||||
|
universalInit() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnInit(): void {
|
||||||
|
this.sub = this.route.params.subscribe(params => {
|
||||||
|
this.id = +params['id'];
|
||||||
|
this.item = this.items.findById(params['id']);
|
||||||
|
this.thumbnail = this.item.payload.flatMap(i => i.getThumbnail());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
40
src/app/item-page/item-page.module.ts
Normal file
40
src/app/item-page/item-page.module.ts
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
import { NgModule } from '@angular/core';
|
||||||
|
import { CommonModule } from '@angular/common';
|
||||||
|
import { ItemPageComponent } from './item-page.component';
|
||||||
|
import { ItemPageRoutingModule } from './item-page-routing.module';
|
||||||
|
import { MetadataValuesComponent } from './metadata-values/metadata-values.component';
|
||||||
|
import { MetadataUriValuesComponent } from './metadata-uri-values/metadata-uri-values.component';
|
||||||
|
import { MetadataFieldWrapperComponent } from './metadata-field-wrapper/metadata-field-wrapper.component';
|
||||||
|
import { ItemPageAuthorFieldComponent } from './specific-field/author/item-page-author-field.component';
|
||||||
|
import { ItemPageDateFieldComponent } from './specific-field/date/item-page-date-field.component';
|
||||||
|
import { ItemPageAbstractFieldComponent } from './specific-field/abstract/item-page-abstract-field.component';
|
||||||
|
import { ItemPageUriFieldComponent } from './specific-field/uri/item-page-uri-field.component';
|
||||||
|
import { ItemPageTitleFieldComponent } from './specific-field/title/item-page-title-field.component';
|
||||||
|
import { ItemPageSpecificFieldComponent } from './specific-field/item-page-specific-field.component';
|
||||||
|
import { SharedModule } from './../shared/shared.module';
|
||||||
|
import { FileSectionComponent } from "./file-section/file-section.component";
|
||||||
|
import { CollectionsComponent } from "./collections/collections.component";
|
||||||
|
|
||||||
|
@NgModule({
|
||||||
|
declarations: [
|
||||||
|
ItemPageComponent,
|
||||||
|
MetadataValuesComponent,
|
||||||
|
MetadataUriValuesComponent,
|
||||||
|
MetadataFieldWrapperComponent,
|
||||||
|
ItemPageAuthorFieldComponent,
|
||||||
|
ItemPageDateFieldComponent,
|
||||||
|
ItemPageAbstractFieldComponent,
|
||||||
|
ItemPageUriFieldComponent,
|
||||||
|
ItemPageTitleFieldComponent,
|
||||||
|
ItemPageSpecificFieldComponent,
|
||||||
|
FileSectionComponent,
|
||||||
|
CollectionsComponent
|
||||||
|
],
|
||||||
|
imports: [
|
||||||
|
ItemPageRoutingModule,
|
||||||
|
CommonModule,
|
||||||
|
SharedModule
|
||||||
|
]
|
||||||
|
})
|
||||||
|
export class ItemPageModule {
|
||||||
|
}
|
@@ -0,0 +1,6 @@
|
|||||||
|
<div class="simple-view-element">
|
||||||
|
<h5 class="simple-view-element-header" *ngIf="label">{{ label }}</h5>
|
||||||
|
<div class="simple-view-element-body">
|
||||||
|
<ng-content></ng-content>
|
||||||
|
</div>
|
||||||
|
</div>
|
@@ -0,0 +1,6 @@
|
|||||||
|
@import '../../../styles/variables.scss';
|
||||||
|
:host {
|
||||||
|
.simple-view-element {
|
||||||
|
margin-bottom: 15px;
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,21 @@
|
|||||||
|
import { Component, Input } from '@angular/core';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'ds-metadata-field-wrapper',
|
||||||
|
styleUrls: ['./metadata-field-wrapper.component.css'],
|
||||||
|
templateUrl: './metadata-field-wrapper.component.html'
|
||||||
|
})
|
||||||
|
export class MetadataFieldWrapperComponent {
|
||||||
|
|
||||||
|
@Input() label: string;
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
this.universalInit();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
universalInit() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@@ -0,0 +1,5 @@
|
|||||||
|
<ds-metadata-field-wrapper [label]="label | translate">
|
||||||
|
<a *ngFor="let metadatum of values; let last=last;" [href]="metadatum.value">
|
||||||
|
{{ linktext || metadatum.value }}<span *ngIf="!last" [innerHTML]="separator"></span>
|
||||||
|
</a>
|
||||||
|
</ds-metadata-field-wrapper>
|
@@ -0,0 +1 @@
|
|||||||
|
@import '../../../styles/variables.scss';
|
@@ -0,0 +1,18 @@
|
|||||||
|
import { Component, Input } from '@angular/core';
|
||||||
|
import { MetadataValuesComponent } from "../metadata-values/metadata-values.component";
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'ds-metadata-uri-values',
|
||||||
|
styleUrls: ['./metadata-uri-values.component.css'],
|
||||||
|
templateUrl: './metadata-uri-values.component.html'
|
||||||
|
})
|
||||||
|
export class MetadataUriValuesComponent extends MetadataValuesComponent {
|
||||||
|
|
||||||
|
@Input() linktext: any;
|
||||||
|
|
||||||
|
@Input() values: any;
|
||||||
|
|
||||||
|
@Input() separator: string;
|
||||||
|
|
||||||
|
@Input() label: string;
|
||||||
|
}
|
@@ -0,0 +1,5 @@
|
|||||||
|
<ds-metadata-field-wrapper [label]="label | translate">
|
||||||
|
<span *ngFor="let metadatum of values; let last=last;">
|
||||||
|
{{metadatum.value}}<span *ngIf="!last" [innerHTML]="separator"></span>
|
||||||
|
</span>
|
||||||
|
</ds-metadata-field-wrapper>
|
@@ -0,0 +1 @@
|
|||||||
|
@import '../../../styles/variables.scss';
|
@@ -0,0 +1,25 @@
|
|||||||
|
import { Component, Input } from '@angular/core';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'ds-metadata-values',
|
||||||
|
styleUrls: ['./metadata-values.component.css'],
|
||||||
|
templateUrl: './metadata-values.component.html'
|
||||||
|
})
|
||||||
|
export class MetadataValuesComponent {
|
||||||
|
|
||||||
|
@Input() values: any;
|
||||||
|
|
||||||
|
@Input() separator: string;
|
||||||
|
|
||||||
|
@Input() label: string;
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
this.universalInit();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
universalInit() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@@ -0,0 +1,21 @@
|
|||||||
|
import { Component, OnInit, Input } from '@angular/core';
|
||||||
|
import { Item } from "../../../core/shared/item.model";
|
||||||
|
import { ItemPageSpecificFieldComponent } from "../item-page-specific-field.component";
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'ds-item-page-abstract-field',
|
||||||
|
templateUrl: './../item-page-specific-field.component.html'
|
||||||
|
})
|
||||||
|
export class ItemPageAbstractFieldComponent extends ItemPageSpecificFieldComponent {
|
||||||
|
|
||||||
|
@Input() item: Item;
|
||||||
|
|
||||||
|
separator : string;
|
||||||
|
|
||||||
|
fields : string[] = [
|
||||||
|
"dc.description.abstract"
|
||||||
|
];
|
||||||
|
|
||||||
|
label : string = "item.page.abstract";
|
||||||
|
|
||||||
|
}
|
@@ -0,0 +1,23 @@
|
|||||||
|
import { Component, OnInit, Input } from '@angular/core';
|
||||||
|
import { Item } from "../../../core/shared/item.model";
|
||||||
|
import { ItemPageSpecificFieldComponent } from "../item-page-specific-field.component";
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'ds-item-page-author-field',
|
||||||
|
templateUrl: './../item-page-specific-field.component.html'
|
||||||
|
})
|
||||||
|
export class ItemPageAuthorFieldComponent extends ItemPageSpecificFieldComponent {
|
||||||
|
|
||||||
|
@Input() item: Item;
|
||||||
|
|
||||||
|
separator : string;
|
||||||
|
|
||||||
|
fields : string[] = [
|
||||||
|
"dc.contributor.author",
|
||||||
|
"dc.creator",
|
||||||
|
"dc.contributor"
|
||||||
|
];
|
||||||
|
|
||||||
|
label : string = "item.page.author";
|
||||||
|
|
||||||
|
}
|
@@ -0,0 +1,21 @@
|
|||||||
|
import { Component, OnInit, Input } from '@angular/core';
|
||||||
|
import { Item } from "../../../core/shared/item.model";
|
||||||
|
import { ItemPageSpecificFieldComponent } from "../item-page-specific-field.component";
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'ds-item-page-date-field',
|
||||||
|
templateUrl: './../item-page-specific-field.component.html'
|
||||||
|
})
|
||||||
|
export class ItemPageDateFieldComponent extends ItemPageSpecificFieldComponent {
|
||||||
|
|
||||||
|
@Input() item: Item;
|
||||||
|
|
||||||
|
separator : string = ", ";
|
||||||
|
|
||||||
|
fields : string[] = [
|
||||||
|
"dc.date.issued"
|
||||||
|
];
|
||||||
|
|
||||||
|
label : string = "item.page.date";
|
||||||
|
|
||||||
|
}
|
@@ -0,0 +1,3 @@
|
|||||||
|
<div class="item-page-specific-field">
|
||||||
|
<ds-metadata-values [values]="item?.filterMetadata(fields)" [separator]="separator" [label]="label"></ds-metadata-values>
|
||||||
|
</div>
|
@@ -0,0 +1,24 @@
|
|||||||
|
import { Component, OnInit, Input } from '@angular/core';
|
||||||
|
import { Item } from "../../core/shared/item.model";
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
templateUrl: './item-page-specific-field.component.html'
|
||||||
|
})
|
||||||
|
export class ItemPageSpecificFieldComponent {
|
||||||
|
|
||||||
|
@Input() item: Item;
|
||||||
|
|
||||||
|
fields : string[];
|
||||||
|
|
||||||
|
label : string;
|
||||||
|
|
||||||
|
separator : string = "<br/>";
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
this.universalInit();
|
||||||
|
}
|
||||||
|
|
||||||
|
universalInit() {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,3 @@
|
|||||||
|
<h2 class="item-page-title-field">
|
||||||
|
<ds-metadata-values [values]="item?.filterMetadata(fields)"></ds-metadata-values>
|
||||||
|
</h2>
|
@@ -0,0 +1,19 @@
|
|||||||
|
import { Component, OnInit, Input } from '@angular/core';
|
||||||
|
import { Item } from "../../../core/shared/item.model";
|
||||||
|
import { ItemPageSpecificFieldComponent } from "../item-page-specific-field.component";
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'ds-item-page-title-field',
|
||||||
|
templateUrl: './item-page-title-field.component.html'
|
||||||
|
})
|
||||||
|
export class ItemPageTitleFieldComponent extends ItemPageSpecificFieldComponent {
|
||||||
|
|
||||||
|
@Input() item: Item;
|
||||||
|
|
||||||
|
separator : string;
|
||||||
|
|
||||||
|
fields : string[] = [
|
||||||
|
"dc.title"
|
||||||
|
];
|
||||||
|
|
||||||
|
}
|
@@ -0,0 +1,3 @@
|
|||||||
|
<div class="item-page-specific-field">
|
||||||
|
<ds-metadata-uri-values [values]="item?.filterMetadata(fields)" [separator]="separator" [label]="label"></ds-metadata-uri-values>
|
||||||
|
</div>
|
@@ -0,0 +1,21 @@
|
|||||||
|
import { Component, OnInit, Input } from '@angular/core';
|
||||||
|
import { Item } from "../../../core/shared/item.model";
|
||||||
|
import { ItemPageSpecificFieldComponent } from "../item-page-specific-field.component";
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'ds-item-page-uri-field',
|
||||||
|
templateUrl: './item-page-uri-field.component.html'
|
||||||
|
})
|
||||||
|
export class ItemPageUriFieldComponent extends ItemPageSpecificFieldComponent {
|
||||||
|
|
||||||
|
@Input() item: Item;
|
||||||
|
|
||||||
|
separator : string;
|
||||||
|
|
||||||
|
fields : string[] = [
|
||||||
|
"dc.identifier.uri"
|
||||||
|
];
|
||||||
|
|
||||||
|
label : string = "item.page.uri";
|
||||||
|
|
||||||
|
}
|
@@ -7,6 +7,9 @@ import { NgbModule } from '@ng-bootstrap/ng-bootstrap';
|
|||||||
import { TranslateModule } from 'ng2-translate/ng2-translate';
|
import { TranslateModule } from 'ng2-translate/ng2-translate';
|
||||||
|
|
||||||
import { ApiService } from './api.service';
|
import { ApiService } from './api.service';
|
||||||
|
import { FileSizePipe } from "./utils/file-size-pipe";
|
||||||
|
import { ThumbnailComponent } from "../thumbnail/thumbnail.component";
|
||||||
|
import { SafeUrlPipe } from "./utils/safe-url-pipe";
|
||||||
|
|
||||||
const MODULES = [
|
const MODULES = [
|
||||||
// Do NOT include UniversalModule, HttpModule, or JsonpModule here
|
// Do NOT include UniversalModule, HttpModule, or JsonpModule here
|
||||||
@@ -19,10 +22,13 @@ const MODULES = [
|
|||||||
];
|
];
|
||||||
|
|
||||||
const PIPES = [
|
const PIPES = [
|
||||||
|
FileSizePipe,
|
||||||
|
SafeUrlPipe
|
||||||
// put pipes here
|
// put pipes here
|
||||||
];
|
];
|
||||||
|
|
||||||
const COMPONENTS = [
|
const COMPONENTS = [
|
||||||
|
ThumbnailComponent
|
||||||
// put shared components here
|
// put shared components here
|
||||||
];
|
];
|
||||||
|
|
||||||
|
36
src/app/shared/utils/file-size-pipe.ts
Normal file
36
src/app/shared/utils/file-size-pipe.ts
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
import { Pipe, PipeTransform } from '@angular/core';
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Convert bytes into largest possible unit.
|
||||||
|
* Takes an precision argument that defaults to 2.
|
||||||
|
* Usage:
|
||||||
|
* bytes | fileSize:precision
|
||||||
|
* Example:
|
||||||
|
* {{ 1024 | fileSize}}
|
||||||
|
* formats to: 1 KB
|
||||||
|
*/
|
||||||
|
@Pipe({name: 'dsFileSize'})
|
||||||
|
export class FileSizePipe implements PipeTransform {
|
||||||
|
|
||||||
|
private units = [
|
||||||
|
'bytes',
|
||||||
|
'KiB',
|
||||||
|
'MiB',
|
||||||
|
'GiB',
|
||||||
|
'TiB',
|
||||||
|
'PiB'
|
||||||
|
];
|
||||||
|
|
||||||
|
transform(bytes: number = 0, precision: number = 2 ) : string {
|
||||||
|
if ( isNaN( parseFloat( String(bytes) )) || ! isFinite( bytes ) ) return '?';
|
||||||
|
|
||||||
|
let unit = 0;
|
||||||
|
|
||||||
|
while ( bytes >= 1024 ) {
|
||||||
|
bytes /= 1024;
|
||||||
|
unit ++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return bytes.toFixed( + precision ) + ' ' + this.units[ unit ];
|
||||||
|
}
|
||||||
|
}
|
10
src/app/shared/utils/safe-url-pipe.ts
Normal file
10
src/app/shared/utils/safe-url-pipe.ts
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
import { Pipe, PipeTransform } from '@angular/core';
|
||||||
|
import { DomSanitizer } from '@angular/platform-browser';
|
||||||
|
|
||||||
|
@Pipe({name: 'dsSafeUrl'})
|
||||||
|
export class SafeUrlPipe implements PipeTransform {
|
||||||
|
constructor(private domSanitizer: DomSanitizer) {}
|
||||||
|
transform(url) {
|
||||||
|
return this.domSanitizer.bypassSecurityTrustResourceUrl(url);
|
||||||
|
}
|
||||||
|
}
|
4
src/app/thumbnail/thumbnail.component.html
Normal file
4
src/app/thumbnail/thumbnail.component.html
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
<div class="thumbnail">
|
||||||
|
<img *ngIf="thumbnail" [src]="thumbnail.retrieve"/>
|
||||||
|
<img *ngIf="!thumbnail" [src]="holderSource | dsSafeUrl"/>
|
||||||
|
</div>
|
1
src/app/thumbnail/thumbnail.component.scss
Normal file
1
src/app/thumbnail/thumbnail.component.scss
Normal file
@@ -0,0 +1 @@
|
|||||||
|
@import '../../styles/variables.scss';
|
28
src/app/thumbnail/thumbnail.component.ts
Normal file
28
src/app/thumbnail/thumbnail.component.ts
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
import { Component, Input, OnInit } from '@angular/core';
|
||||||
|
import { Bitstream } from "../core/shared/bitstream.model";
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'ds-thumbnail',
|
||||||
|
styleUrls: ['./thumbnail.component.css'],
|
||||||
|
templateUrl: './thumbnail.component.html'
|
||||||
|
})
|
||||||
|
export class ThumbnailComponent {
|
||||||
|
|
||||||
|
@Input() thumbnail: Bitstream;
|
||||||
|
|
||||||
|
data: any = {};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The default 'holder.js' image
|
||||||
|
*/
|
||||||
|
holderSource: string = "data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2293%22%20height%3D%22120%22%20viewBox%3D%220%200%2093%20120%22%20preserveAspectRatio%3D%22none%22%3E%3C!--%0ASource%20URL%3A%20holder.js%2F93x120%3Ftext%3DNo%20Thumbnail%0ACreated%20with%20Holder.js%202.8.2.%0ALearn%20more%20at%20http%3A%2F%2Fholderjs.com%0A(c)%202012-2015%20Ivan%20Malopinsky%20-%20http%3A%2F%2Fimsky.co%0A--%3E%3Cdefs%3E%3Cstyle%20type%3D%22text%2Fcss%22%3E%3C!%5BCDATA%5B%23holder_1543e460b05%20text%20%7B%20fill%3A%23AAAAAA%3Bfont-weight%3Abold%3Bfont-family%3AArial%2C%20Helvetica%2C%20Open%20Sans%2C%20sans-serif%2C%20monospace%3Bfont-size%3A10pt%20%7D%20%5D%5D%3E%3C%2Fstyle%3E%3C%2Fdefs%3E%3Cg%20id%3D%22holder_1543e460b05%22%3E%3Crect%20width%3D%2293%22%20height%3D%22120%22%20fill%3D%22%23EEEEEE%22%2F%3E%3Cg%3E%3Ctext%20x%3D%2235.6171875%22%20y%3D%2257%22%3ENo%3C%2Ftext%3E%3Ctext%20x%3D%2210.8125%22%20y%3D%2272%22%3EThumbnail%3C%2Ftext%3E%3C%2Fg%3E%3C%2Fg%3E%3C%2Fsvg%3E";
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
this.universalInit();
|
||||||
|
}
|
||||||
|
|
||||||
|
universalInit() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@@ -4,7 +4,7 @@ export const ITEMS = [
|
|||||||
"self": {
|
"self": {
|
||||||
"href": "/items/8871"
|
"href": "/items/8871"
|
||||||
},
|
},
|
||||||
"collections": [
|
"parents": [
|
||||||
{
|
{
|
||||||
"href": "/collections/5179"
|
"href": "/collections/5179"
|
||||||
},
|
},
|
||||||
@@ -16,9 +16,9 @@ export const ITEMS = [
|
|||||||
{
|
{
|
||||||
"href": "/bundles/2355"
|
"href": "/bundles/2355"
|
||||||
},
|
},
|
||||||
{
|
// {
|
||||||
"href": "/bundles/5687"
|
// "href": "/bundles/5687"
|
||||||
}
|
// }
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"id": "8871",
|
"id": "8871",
|
||||||
@@ -96,7 +96,7 @@ export const ITEMS = [
|
|||||||
"self": {
|
"self": {
|
||||||
"href": "/items/9978"
|
"href": "/items/9978"
|
||||||
},
|
},
|
||||||
"collections": [
|
"parents": [
|
||||||
{
|
{
|
||||||
"href": "/collections/5179"
|
"href": "/collections/5179"
|
||||||
},
|
},
|
||||||
@@ -108,9 +108,9 @@ export const ITEMS = [
|
|||||||
{
|
{
|
||||||
"href": "/bundles/2355"
|
"href": "/bundles/2355"
|
||||||
},
|
},
|
||||||
{
|
// {
|
||||||
"href": "/bundles/5687"
|
// "href": "/bundles/5687"
|
||||||
}
|
// }
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"id": "9978",
|
"id": "9978",
|
||||||
|
@@ -10,5 +10,5 @@
|
|||||||
* ];
|
* ];
|
||||||
**/
|
**/
|
||||||
export const routes: string[] = [
|
export const routes: string[] = [
|
||||||
'home', '**'
|
'home', 'items/:id' , '**'
|
||||||
];
|
];
|
||||||
|
Reference in New Issue
Block a user