mirror of
https://github.com/DSpace/dspace-angular.git
synced 2025-10-07 01:54:15 +00:00
#885 add media viewer
This commit is contained in:
@@ -104,6 +104,7 @@
|
||||
"ng2-file-upload": "1.4.0",
|
||||
"ng2-nouislider": "^1.8.2",
|
||||
"ngx-bootstrap": "^5.3.2",
|
||||
"ngx-gallery": "^5.10.0",
|
||||
"ngx-infinite-scroll": "6.0.1",
|
||||
"ngx-moment": "^3.4.0",
|
||||
"ngx-pagination": "3.0.3",
|
||||
|
@@ -31,6 +31,11 @@ import { TabbedRelatedEntitiesSearchComponent } from './simple/related-entities/
|
||||
import { StatisticsModule } from '../statistics/statistics.module';
|
||||
import { AbstractIncrementalListComponent } from './simple/abstract-incremental-list/abstract-incremental-list.component';
|
||||
|
||||
import { MediaViewerComponent } from './media-viewer/media-viewer.component';
|
||||
import { MediaViewerVideoComponent } from './media-viewer/media-viewer-video/media-viewer-video.component';
|
||||
import { MediaViewerImageComponent } from './media-viewer/media-viewer-image/media-viewer-image.component';
|
||||
import { NgxGalleryModule } from 'ngx-gallery';
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
CommonModule,
|
||||
@@ -38,7 +43,8 @@ import { AbstractIncrementalListComponent } from './simple/abstract-incremental-
|
||||
ItemPageRoutingModule,
|
||||
EditItemPageModule,
|
||||
SearchPageModule,
|
||||
StatisticsModule.forRoot()
|
||||
StatisticsModule.forRoot(),
|
||||
NgxGalleryModule,
|
||||
],
|
||||
declarations: [
|
||||
ItemPageComponent,
|
||||
@@ -62,6 +68,9 @@ import { AbstractIncrementalListComponent } from './simple/abstract-incremental-
|
||||
UploadBitstreamComponent,
|
||||
TabbedRelatedEntitiesSearchComponent,
|
||||
AbstractIncrementalListComponent,
|
||||
MediaViewerComponent,
|
||||
MediaViewerVideoComponent,
|
||||
MediaViewerImageComponent,
|
||||
],
|
||||
exports: [
|
||||
ItemComponent,
|
||||
@@ -72,12 +81,8 @@ import { AbstractIncrementalListComponent } from './simple/abstract-incremental-
|
||||
RelatedItemsComponent,
|
||||
MetadataRepresentationListComponent,
|
||||
ItemPageTitleFieldComponent,
|
||||
TabbedRelatedEntitiesSearchComponent
|
||||
TabbedRelatedEntitiesSearchComponent,
|
||||
],
|
||||
entryComponents: [
|
||||
PublicationComponent
|
||||
]
|
||||
entryComponents: [PublicationComponent],
|
||||
})
|
||||
export class ItemPageModule {
|
||||
|
||||
}
|
||||
export class ItemPageModule {}
|
||||
|
@@ -0,0 +1 @@
|
||||
<ngx-gallery [options]="galleryOptions" [images]="galleryImages"></ngx-gallery>
|
@@ -0,0 +1,41 @@
|
||||
import { DebugElement } from '@angular/core';
|
||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import { By } from '@angular/platform-browser';
|
||||
|
||||
import { MediaViewerImageComponent } from './media-viewer-image.component';
|
||||
|
||||
describe('MediaViewerImageComponent', () => {
|
||||
let component: MediaViewerImageComponent;
|
||||
let fixture: ComponentFixture<MediaViewerImageComponent>;
|
||||
let debugElement: DebugElement;
|
||||
let htmlElement: HTMLElement;
|
||||
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [MediaViewerImageComponent],
|
||||
}).compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(MediaViewerImageComponent);
|
||||
component = fixture.componentInstance;
|
||||
component.galleryOptions = [
|
||||
{
|
||||
image: true,
|
||||
imageSize: 'contain',
|
||||
thumbnails: false,
|
||||
imageArrows: false,
|
||||
width: '340px',
|
||||
height: '279px',
|
||||
},
|
||||
];
|
||||
debugElement = fixture.debugElement.query(By.css('ngx-gallery'));
|
||||
htmlElement = debugElement.nativeElement;
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
|
||||
describe;
|
||||
});
|
@@ -0,0 +1,43 @@
|
||||
import { Component, Input, OnInit } from '@angular/core';
|
||||
|
||||
import { NgxGalleryOptions, NgxGalleryImage } from 'ngx-gallery';
|
||||
import { MediaViewerItem } from '../../../core/shared/media-viewer-item.model';
|
||||
|
||||
@Component({
|
||||
selector: 'ds-media-viewer-image',
|
||||
templateUrl: './media-viewer-image.component.html',
|
||||
styleUrls: ['./media-viewer-image.component.scss'],
|
||||
})
|
||||
export class MediaViewerImageComponent implements OnInit {
|
||||
@Input() images: MediaViewerItem[];
|
||||
constructor() {}
|
||||
|
||||
galleryOptions: NgxGalleryOptions[];
|
||||
galleryImages: NgxGalleryImage[];
|
||||
|
||||
ngOnInit(): void {
|
||||
this.galleryImages = new Array<NgxGalleryImage>();
|
||||
this.galleryOptions = [
|
||||
{
|
||||
image: true,
|
||||
imageSize: 'contain',
|
||||
thumbnails: false,
|
||||
imageArrows: false,
|
||||
width: '340px',
|
||||
height: '279px',
|
||||
},
|
||||
];
|
||||
for (const image of this.images) {
|
||||
this.galleryImages = [
|
||||
...this.galleryImages,
|
||||
{
|
||||
small: image.thumbnail
|
||||
? image.thumbnail
|
||||
: './assets/images/replacements_image.svg',
|
||||
medium: image.bitstream._links.content.href,
|
||||
big: image.bitstream._links.content.href,
|
||||
},
|
||||
];
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,48 @@
|
||||
<ng-container>
|
||||
<video
|
||||
#media
|
||||
[src]="medias[currentIndex].bitstream._links.content.href"
|
||||
id="singleVideo"
|
||||
[poster]="
|
||||
medias[currentIndex].thumbnail ||
|
||||
this.replacements[this.medias[this.currentIndex].format]
|
||||
"
|
||||
preload="auto"
|
||||
controls
|
||||
></video>
|
||||
<div class="buttons" *ngIf="medias?.length > 1">
|
||||
<button
|
||||
class="btn btn-primary"
|
||||
[disabled]="currentIndex === 0"
|
||||
(click)="prevMedia()"
|
||||
>
|
||||
{{ "media-viewer.previus" | translate }}
|
||||
</button>
|
||||
|
||||
<button
|
||||
class="btn btn-primary"
|
||||
[disabled]="currentIndex === medias.length - 1"
|
||||
(click)="nextMedia()"
|
||||
>
|
||||
{{ "media-viewer.next" | translate }}
|
||||
</button>
|
||||
<div ngbDropdown class="d-inline-block">
|
||||
<button
|
||||
class="btn btn-outline-primary"
|
||||
id="dropdownBasic1"
|
||||
ngbDropdownToggle
|
||||
>
|
||||
{{ "media-viewer.playlist" | translate }}
|
||||
</button>
|
||||
<div ngbDropdownMenu aria-labelledby="dropdownBasic1">
|
||||
<button
|
||||
ngbDropdownItem
|
||||
*ngFor="let item of medias; let i = index"
|
||||
(click)="selectedMedia(i)"
|
||||
>
|
||||
{{ item.bitstream.name }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</ng-container>
|
@@ -0,0 +1,4 @@
|
||||
video {
|
||||
width: 340px;
|
||||
height: 279px;
|
||||
}
|
@@ -0,0 +1,46 @@
|
||||
import { NO_ERRORS_SCHEMA } from '@angular/core';
|
||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
|
||||
import { TranslateLoader, TranslateModule } from '@ngx-translate/core';
|
||||
import { TranslateLoaderMock } from '../../../shared/mocks/translate-loader.mock';
|
||||
import { FileSizePipe } from '../../../shared/utils/file-size-pipe';
|
||||
import { VarDirective } from '../../../shared/utils/var.directive';
|
||||
import { MetadataFieldWrapperComponent } from '../../field-components/metadata-field-wrapper/metadata-field-wrapper.component';
|
||||
|
||||
import { MediaViewerVideoComponent } from './media-viewer-video.component';
|
||||
|
||||
describe('MediaViewerVideoComponent', () => {
|
||||
let component: MediaViewerVideoComponent;
|
||||
let fixture: ComponentFixture<MediaViewerVideoComponent>;
|
||||
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
imports: [
|
||||
TranslateModule.forRoot({
|
||||
loader: {
|
||||
provide: TranslateLoader,
|
||||
useClass: TranslateLoaderMock,
|
||||
},
|
||||
}),
|
||||
BrowserAnimationsModule,
|
||||
],
|
||||
declarations: [
|
||||
MediaViewerVideoComponent,
|
||||
VarDirective,
|
||||
FileSizePipe,
|
||||
MetadataFieldWrapperComponent,
|
||||
],
|
||||
schemas: [NO_ERRORS_SCHEMA],
|
||||
}).compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(MediaViewerVideoComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
@@ -0,0 +1,38 @@
|
||||
import { Component, Input, OnInit } from '@angular/core';
|
||||
import { MediaViewerItem } from '../../../core/shared/media-viewer-item.model';
|
||||
|
||||
@Component({
|
||||
selector: 'ds-media-viewer-video',
|
||||
templateUrl: './media-viewer-video.component.html',
|
||||
styleUrls: ['./media-viewer-video.component.scss'],
|
||||
})
|
||||
export class MediaViewerVideoComponent implements OnInit {
|
||||
@Input() medias: MediaViewerItem[];
|
||||
|
||||
isCollapsed: boolean;
|
||||
currentIndex = 0;
|
||||
|
||||
replacements = {
|
||||
video: './assets/images/replacement_video.svg',
|
||||
audio: './assets/images/replacement_audio.svg',
|
||||
document: './assets/images/replacement_document.svg',
|
||||
};
|
||||
|
||||
replacementThumbnail: string;
|
||||
constructor() {}
|
||||
|
||||
ngOnInit() {
|
||||
this.isCollapsed = false;
|
||||
}
|
||||
|
||||
selectedMedia(index: number) {
|
||||
console.log(index);
|
||||
this.currentIndex = index;
|
||||
}
|
||||
nextMedia() {
|
||||
this.currentIndex++;
|
||||
}
|
||||
prevMedia() {
|
||||
this.currentIndex--;
|
||||
}
|
||||
}
|
19
src/app/+item-page/media-viewer/media-viewer.component.html
Normal file
19
src/app/+item-page/media-viewer/media-viewer.component.html
Normal file
@@ -0,0 +1,19 @@
|
||||
<ng-container *ngVar="mediaList$ | async as mediaList">
|
||||
<ds-loading
|
||||
*ngIf="isLoading"
|
||||
message="{{ 'loading.default' | translate }}"
|
||||
[showMessage]="false"
|
||||
></ds-loading>
|
||||
<div class="media-viewer" *ngIf="mediaList.length > 0">
|
||||
<ng-container
|
||||
*ngIf="
|
||||
mediaList[0]?.format === 'video' || mediaList[0]?.format === 'audio'
|
||||
"
|
||||
>
|
||||
<ds-media-viewer-video [medias]="mediaList"></ds-media-viewer-video>
|
||||
</ng-container>
|
||||
<ng-container *ngIf="mediaList[0]?.format === 'image'">
|
||||
<ds-media-viewer-image [images]="mediaList"></ds-media-viewer-image>
|
||||
</ng-container>
|
||||
</div>
|
||||
</ng-container>
|
106
src/app/+item-page/media-viewer/media-viewer.component.spec.ts
Normal file
106
src/app/+item-page/media-viewer/media-viewer.component.spec.ts
Normal file
@@ -0,0 +1,106 @@
|
||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import { Bitstream } from '../../core/shared/bitstream.model';
|
||||
import { createSuccessfulRemoteDataObject$ } from '../../shared/remote-data.utils';
|
||||
import { createPaginatedList } from '../../shared/testing/utils.test';
|
||||
import { of as observableOf } from 'rxjs';
|
||||
import { By } from '@angular/platform-browser';
|
||||
import { MediaViewerComponent } from './media-viewer.component';
|
||||
import { MockBitstreamFormat1 } from '../../shared/mocks/item.mock';
|
||||
import { TranslateLoader, TranslateModule } from '@ngx-translate/core';
|
||||
import { TranslateLoaderMock } from '../../shared/mocks/translate-loader.mock';
|
||||
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
|
||||
import { BitstreamDataService } from '../../core/data/bitstream-data.service';
|
||||
import { NO_ERRORS_SCHEMA } from '@angular/core';
|
||||
import { MediaViewerItem } from '../../core/shared/media-viewer-item.model';
|
||||
import { VarDirective } from '../../shared/utils/var.directive';
|
||||
import { MetadataFieldWrapperComponent } from '../field-components/metadata-field-wrapper/metadata-field-wrapper.component';
|
||||
import { FileSizePipe } from '../../shared/utils/file-size-pipe';
|
||||
|
||||
describe('MediaViewerComponent', () => {
|
||||
let comp: MediaViewerComponent;
|
||||
let fixture: ComponentFixture<MediaViewerComponent>;
|
||||
|
||||
const bitstreamDataService = jasmine.createSpyObj('bitstreamDataService', {
|
||||
findAllByItemAndBundleName: createSuccessfulRemoteDataObject$(
|
||||
createPaginatedList([])
|
||||
),
|
||||
});
|
||||
|
||||
const mockBitstream: Bitstream = Object.assign(new Bitstream(), {
|
||||
sizeBytes: 10201,
|
||||
content:
|
||||
'https://dspace7.4science.it/dspace-spring-rest/api/core/bitstreams/cf9b0c8e-a1eb-4b65-afd0-567366448713/content',
|
||||
format: observableOf(MockBitstreamFormat1),
|
||||
bundleName: 'ORIGINAL',
|
||||
_links: {
|
||||
self: {
|
||||
href:
|
||||
'https://dspace7.4science.it/dspace-spring-rest/api/core/bitstreams/cf9b0c8e-a1eb-4b65-afd0-567366448713',
|
||||
},
|
||||
content: {
|
||||
href:
|
||||
'https://dspace7.4science.it/dspace-spring-rest/api/core/bitstreams/cf9b0c8e-a1eb-4b65-afd0-567366448713/content',
|
||||
},
|
||||
},
|
||||
id: 'cf9b0c8e-a1eb-4b65-afd0-567366448713',
|
||||
uuid: 'cf9b0c8e-a1eb-4b65-afd0-567366448713',
|
||||
type: 'bitstream',
|
||||
metadata: {
|
||||
'dc.title': [
|
||||
{
|
||||
language: null,
|
||||
value: 'test_word.docx',
|
||||
},
|
||||
],
|
||||
},
|
||||
});
|
||||
|
||||
const mockMediaViewerItem: MediaViewerItem = Object.assign(
|
||||
new MediaViewerItem(),
|
||||
{ bitstream: mockBitstream, format: 'image', thumbnail: null }
|
||||
);
|
||||
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
imports: [
|
||||
TranslateModule.forRoot({
|
||||
loader: {
|
||||
provide: TranslateLoader,
|
||||
useClass: TranslateLoaderMock,
|
||||
},
|
||||
}),
|
||||
BrowserAnimationsModule,
|
||||
],
|
||||
declarations: [
|
||||
MediaViewerComponent,
|
||||
VarDirective,
|
||||
FileSizePipe,
|
||||
MetadataFieldWrapperComponent,
|
||||
],
|
||||
providers: [
|
||||
{ provide: BitstreamDataService, useValue: bitstreamDataService },
|
||||
],
|
||||
|
||||
schemas: [NO_ERRORS_SCHEMA],
|
||||
}).compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(MediaViewerComponent);
|
||||
comp = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
describe('when the bitstreams are loading', () => {
|
||||
beforeEach(() => {
|
||||
comp.mediaList$.next([mockMediaViewerItem]);
|
||||
comp.isLoading = true;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should display a loading component', () => {
|
||||
const loading = fixture.debugElement.query(By.css('ds-loading'));
|
||||
expect(loading.nativeElement).toBeDefined();
|
||||
});
|
||||
});
|
||||
});
|
76
src/app/+item-page/media-viewer/media-viewer.component.ts
Normal file
76
src/app/+item-page/media-viewer/media-viewer.component.ts
Normal file
@@ -0,0 +1,76 @@
|
||||
import { Component, Input, OnInit } from '@angular/core';
|
||||
import { BehaviorSubject, Observable } from 'rxjs';
|
||||
import { filter, takeWhile } from 'rxjs/operators';
|
||||
import { BitstreamDataService } from '../../core/data/bitstream-data.service';
|
||||
import { BitstreamFormatDataService } from '../../core/data/bitstream-format-data.service';
|
||||
import { PaginatedList } from '../../core/data/paginated-list';
|
||||
import { RemoteData } from '../../core/data/remote-data';
|
||||
import { Bitstream } from '../../core/shared/bitstream.model';
|
||||
import { Item } from '../../core/shared/item.model';
|
||||
import { MediaViewerItem } from '../../core/shared/media-viewer-item.model';
|
||||
import { getFirstSucceededRemoteDataPayload } from '../../core/shared/operators';
|
||||
import { hasNoValue, hasValue } from '../../shared/empty.util';
|
||||
|
||||
@Component({
|
||||
selector: 'ds-media-viewer',
|
||||
templateUrl: './media-viewer.component.html',
|
||||
styleUrls: ['./media-viewer.component.scss'],
|
||||
})
|
||||
export class MediaViewerComponent implements OnInit {
|
||||
@Input() item: Item;
|
||||
|
||||
mediaList$: BehaviorSubject<MediaViewerItem[]>;
|
||||
|
||||
isLoading: boolean;
|
||||
|
||||
constructor(
|
||||
protected bitstreamDataService: BitstreamDataService,
|
||||
protected bitstreamFormatDataService: BitstreamFormatDataService
|
||||
) {}
|
||||
|
||||
ngOnInit(): void {
|
||||
this.mediaList$ = new BehaviorSubject([]);
|
||||
this.isLoading = true;
|
||||
|
||||
this.loadRemoteData('ORIGINAL').subscribe((bitstreamsRD) => {
|
||||
console.log(bitstreamsRD);
|
||||
this.loadRemoteData('THUMBNAIL').subscribe((thumbnailsRD) => {
|
||||
for (let index = 0; index < bitstreamsRD.payload.page.length; index++) {
|
||||
this.bitstreamFormatDataService
|
||||
.findByBitstream(bitstreamsRD.payload.page[index])
|
||||
.pipe(getFirstSucceededRemoteDataPayload())
|
||||
.subscribe((format) => {
|
||||
const current = this.mediaList$.getValue();
|
||||
const mediaItem = new MediaViewerItem();
|
||||
mediaItem.bitstream = bitstreamsRD.payload.page[index];
|
||||
mediaItem.format = format.mimetype.split('/')[0];
|
||||
mediaItem.thumbnail =
|
||||
thumbnailsRD.payload && thumbnailsRD.payload.page[index]
|
||||
? thumbnailsRD.payload.page[index]._links.content.href
|
||||
: null;
|
||||
this.mediaList$.next([...current, mediaItem]);
|
||||
});
|
||||
}
|
||||
this.isLoading = false;
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
loadRemoteData(
|
||||
bundleName: string
|
||||
): Observable<RemoteData<PaginatedList<Bitstream>>> {
|
||||
return this.bitstreamDataService
|
||||
.findAllByItemAndBundleName(this.item, bundleName)
|
||||
.pipe(
|
||||
filter((bitstreamsRD: RemoteData<PaginatedList<Bitstream>>) =>
|
||||
hasValue(bitstreamsRD)
|
||||
),
|
||||
takeWhile(
|
||||
(bitstreamsRD_1: RemoteData<PaginatedList<Bitstream>>) =>
|
||||
hasNoValue(bitstreamsRD_1.payload) &&
|
||||
hasNoValue(bitstreamsRD_1.error),
|
||||
true
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
@@ -3,9 +3,10 @@
|
||||
</h2>
|
||||
<div class="row">
|
||||
<div class="col-xs-12 col-md-4">
|
||||
<ds-metadata-field-wrapper>
|
||||
<!-- <ds-metadata-field-wrapper>
|
||||
<ds-thumbnail [thumbnail]="getThumbnail() | async"></ds-thumbnail>
|
||||
</ds-metadata-field-wrapper>
|
||||
</ds-metadata-field-wrapper> -->
|
||||
<ds-media-viewer [item]="object"></ds-media-viewer>
|
||||
<ds-item-page-file-section [item]="object"></ds-item-page-file-section>
|
||||
<ds-item-page-date-field [item]="object"></ds-item-page-date-field>
|
||||
<ds-item-page-author-field [item]="object"></ds-item-page-author-field>
|
||||
|
21
src/app/core/shared/media-viewer-item.model.ts
Normal file
21
src/app/core/shared/media-viewer-item.model.ts
Normal file
@@ -0,0 +1,21 @@
|
||||
import { Bitstream } from './bitstream.model';
|
||||
|
||||
/**
|
||||
* Model representing a media viewer item
|
||||
*/
|
||||
export class MediaViewerItem {
|
||||
/**
|
||||
* Incoming Bitsream
|
||||
*/
|
||||
bitstream: Bitstream;
|
||||
|
||||
/**
|
||||
* Incoming Bitsream format type
|
||||
*/
|
||||
format: string;
|
||||
|
||||
/**
|
||||
* Incoming Bitsream thumbnail
|
||||
*/
|
||||
thumbnail: string;
|
||||
}
|
@@ -2449,6 +2449,13 @@
|
||||
"publication.search.results.head": "Publication Search Results",
|
||||
|
||||
"publication.search.title": "DSpace Angular :: Publication Search",
|
||||
|
||||
|
||||
"media-viewer.next": "Next",
|
||||
|
||||
"media-viewer.previus": "Previus",
|
||||
|
||||
"media-viewer.playlist": "Playlist",
|
||||
|
||||
|
||||
"register-email.title": "New user registration",
|
||||
|
9
src/assets/images/replacement_audio.svg
Normal file
9
src/assets/images/replacement_audio.svg
Normal file
@@ -0,0 +1,9 @@
|
||||
<svg width="240" height="180" viewBox="0 0 240 180" fill="none" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<rect width="240" height="180" fill="url(#pattern0)"/>
|
||||
<defs>
|
||||
<pattern id="pattern0" patternContentUnits="objectBoundingBox" width="1" height="1">
|
||||
<use xlink:href="#image0" transform="scale(0.00416667 0.00555556)"/>
|
||||
</pattern>
|
||||
<image id="image0" width="240" height="180" xlink:href="data:image/png;base64,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"/>
|
||||
</defs>
|
||||
</svg>
|
After Width: | Height: | Size: 3.0 KiB |
9
src/assets/images/replacement_document.svg
Normal file
9
src/assets/images/replacement_document.svg
Normal file
@@ -0,0 +1,9 @@
|
||||
<svg width="240" height="180" viewBox="0 0 240 180" fill="none" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<rect width="240" height="180" fill="url(#pattern0)"/>
|
||||
<defs>
|
||||
<pattern id="pattern0" patternContentUnits="objectBoundingBox" width="1" height="1">
|
||||
<use xlink:href="#image0" transform="scale(0.00416667 0.00555556)"/>
|
||||
</pattern>
|
||||
<image id="image0" width="240" height="180" xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAPAAAAC0CAYAAACqnKHoAAAESElEQVR4nO3dX2saWQDG4dNYFzFIQ7YhVLoV8v0/z/bamxBp1yiiSEPTclyE0otl0ZiZ13ke8H5mnJ9z5s8Z3yweH38UINKFrw1yCRiCCRiCCRiCCRiCCRiCCRiCCRiCCRiCCRiCCRiCCRiCCRiCCRiCCRiCCRiCCRiCCRiCCRiCCRiCCRiCCRiCCRiCCRiCCRiCCRiCCRiCCRiCCRiCCRiCCRiCCRiCCRiCCRiCCRiCCRiCCRiCCRiCCRiCCRiCCRiCCRiCCRiCCRiCCRiCCRiCCRiCvfXltctiuSyb9bo8PT2d3boNh8MyGo3KYDBowdKchzeLx8cfXd8IbbBarcpsNivfzjDc310Oh2U8Hpd+v9+uBQsk4Bao4f4zn3dqnXsXF2UymTgaH8k5cMPqkLlr8Vbfn5/LdDo9y1OF1yTgBtWdd/bw0Nn1rxHf39+3YElyCbhB8/l8txN32XqzKdvtttPb4BgCblC9cIXtcAwBN6gLV5z/j81m0/6FbCkBQzABQzABQzABQzABQzCTGYLcvH9fbm5uWr/Af3/+3IKl6AZHYAgmYAgmYAjmHPhAdSbN+j+eIKpzXut0OTglR2AIJmAIJmAI5hw4yJevX3cf2HMEhmAChmAChmAChmAChmAChmAChmDuAwepz1fXPwhrO/eqX4+Ag9R4Eyb0C/j1GEJDMAFDMAFDMAFDMAFDMAFDMLeRgtQ/BPdPfvxKwEEWy+XuA3uG0BBMwBBMwBBMwBBMwBBMwBBMwBDMfeAgV+/elaurq5Mu8MNsVrbb7ZltufMl4CD9fv/kb+ToXRiUJfFtQTABQzABQzABQzABQzABQzC3kYIsl8uTT+h3DziLgIN8e3rafWDPEBqCCRiCCRiCCRiCCbhBJg78q07S4DD2oAYNLy87u+6/sh0OJ+AG/Xl93dl13/uj39/Nc+YwAm5Qnds7Go06u/7V7e1tC5Yil4AbNv7woQwGg06uex2BdP0H7FgCbliv1yuTT586tSPXi3fj8djR9wV4lLIFasR/ffy4e855sViU1WpVvj8/n9161vPd+kN1fX3tyvMLEXCL1HPiU7/zivNiCA3BBAzBBAzBBAzBBAzBBAzBBAzB3Ac+kfpyuOl0epbr9rvJZNKuBeoQAZ9IfZJqfeI3SIIh9IE8MUUbCPhAZtHQBgI+UJ0CeOkoTMMEfIQ6Jc57rWiSve8IdUpcvQIrYppizztSHUrf3d0ZTtMIt5FewP5IXO/91sn4p/4DMtgT8AuqR+Ouvt+KZhhCQzABQzABQzABQzABQzABQzABQzABQzABQzABQzABQzABQzABQzABQzABQzABQzABQzABQzABQzABQzABQzABQzABQzABQzABQzABQzABQzABQzABQzABQzABQzABQzABQzABQzABQzABQzABQzABQzABQzABQzABQzABQzABQzABQzABQzABQzABQ6pSyk/71rEEHrIkFQAAAABJRU5ErkJggg=="/>
|
||||
</defs>
|
||||
</svg>
|
After Width: | Height: | Size: 2.0 KiB |
9
src/assets/images/replacement_image.svg
Normal file
9
src/assets/images/replacement_image.svg
Normal file
@@ -0,0 +1,9 @@
|
||||
<svg width="240" height="180" viewBox="0 0 240 180" fill="none" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<rect width="240" height="180" fill="url(#pattern0)"/>
|
||||
<defs>
|
||||
<pattern id="pattern0" patternContentUnits="objectBoundingBox" width="1" height="1">
|
||||
<use xlink:href="#image0" transform="scale(0.00416667 0.00555556)"/>
|
||||
</pattern>
|
||||
<image id="image0" width="240" height="180" xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAPAAAAC0CAYAAACqnKHoAAAE5UlEQVR4nO3d70pbSRzH4eNaxKB06RLJ4iIVBO//hrwAqWysWOIbcZlAwLX+SeIkZ745z/OmFmoxYz6e8xsnunc7nT51QKQ/fNogl4AhmIAhmIAhmIAhmIAhmIAhmIAhmIAhmIAhmIAhmIAhmIAhmIAhmIAhmIAhmIAhmIAhmIAhmIAhmIAhmIAhmIAhmIAhmIAhmIAhmIAhmIAhmIAhmIAhmIAhmIAhmIAhmIAhmIAhmIAhmIAhmIAhmIAhmIAhmIAhmIAhmIAhmIAhmIAhmIAhmIAhmIAhmIAhmIAhmIAh2BefvM15fHzs7n/96h5ms/nbs9lsVx/q/4xGo25/f787HI2646Oj+dtshoA35Pr6uvtxczMPd2jKF62FEu/JeNxNJpPBrcM27N1Op0+7/zC3pwR7dXXVzR4ehvKQlzI6POwuLi5cjSszA1cm3teVNSlrQ10CrqjcNov3bWVtyhpRj4ArKbfOZeblfUPdF9gUAVdSNm48MT+22JmnDgFX8jCQbxHVYK3qEXAlrr70QcCVDOWQBm0RMAQTMAQTMAQTMAQTMAQTMAQTMAQTMAQTMAQTMAQTMAQTMAQTMAQTMAQTMAQTMAQTMAQTMAQTMAQTMAQTMAQTMAQTMAQTMAQTMAQTMAQTMAQTMAQTMHN/fftmIQJ9GfoC0HV/TybdZDKZ/4rUn3d3ViSIK/DA/fn16zze4uzsrDs4OBj6kkQR8ICVWEu0C/v7+9359+9DX5YoAh6oRazlz+dGo1H3z+np0JcnhoAH6vT0dB7ra8bj8fzWmvYJOMDo8LDqB1l2nD/adTYPZxBw48qV8PLyslrE5f95Pve+xTycQcANex7bxcXFp6+I8yjPz5f+9+bh9gm4USW2Eu9ik+mtTadVlPdf9YuAebhtAm7Ua5tM5e/L3P6+phzWOD4+Xut9zcPtEnCDTsbjNzeZytVw1dva54c11mEebpeAG1Pm3tMPAh2/E/hLLw9rrMs83CYBN6Rc6cpm1TJKlB/tTNeYm58zD7dHwA1ZNbaPdqbfO6yxLvNwWwTciHJ7uuom03tX2GUOa6zDPNwWATeg3JaW29N1vLYzvexhjXWZh9sh4J7ViO35zvSqhzXWZR5ug4B79PKwxmcsdqa3OaOah/sn4B7V3mQqQW3zqmge7p+Ae/LeYY0k5uF+CbgHyxzWSGIe7o+At2yVwxpJzMP9EPCW1TwZ1RLzcD/8WNktWsy89/f3O/0Y/51OG/hIhkHAW1Se2J7c1OQWGoIJGIIJGIIJuJLaL9uDZQi4kl381hDtE3Alh67AS7NW9Qi4kuOjI1fhJZQ1cuyyHgFXUp6YJ2u+KH9IrFFdAq6o/OjW2r/HaJeUtfnMj7fldwKurLxQQcS/K2uyiy/i6Nve7XT6NOwl2Izr6+vux81N9/j4uIsPb2mL0cKVdzMEvGE/7+66h9lspx/jW8pusw2rzRIwBDMDQzABQzABQzABQzABQzABQzABQzABQzABQzABQzABQzABQzABQzABQzABQzABQzABQzABQzABQzABQzABQzABQzABQzABQzABQzABQzABQzABQzABQzABQzABQzABQzABQzABQzABQzABQzABQzABQzABQzABQzABQzABQzABQzABQzABQzABQzABQzABQzABQzABQzABQ6qu6/4DYMqyrZ0wRgUAAAAASUVORK5CYII="/>
|
||||
</defs>
|
||||
</svg>
|
After Width: | Height: | Size: 2.2 KiB |
9
src/assets/images/replacement_video.svg
Normal file
9
src/assets/images/replacement_video.svg
Normal file
@@ -0,0 +1,9 @@
|
||||
<svg width="240" height="180" viewBox="0 0 240 180" fill="none" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<rect width="240" height="180" fill="url(#pattern0)"/>
|
||||
<defs>
|
||||
<pattern id="pattern0" patternContentUnits="objectBoundingBox" width="1" height="1">
|
||||
<use xlink:href="#image0" transform="scale(0.00416667 0.00555556)"/>
|
||||
</pattern>
|
||||
<image id="image0" width="240" height="180" xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAPAAAAC0CAYAAACqnKHoAAAFZ0lEQVR4nO3dbU/UWByH4QqLMRCQQBACMfL9v5JZYiRr0AkPgQwxEHTzn41GdxfsYGeYX3tdiS98Y9oDt+2ZOT19dnF+/rUBIi35sUEuAUMwAUMwAUMwAUMwAUMwAUMwAUMwAUMwAUMwAUMwAUMwAUMwAUMwAUMwAUMwAUMwAUMwAUMwAUMwAUMwAUMwAUMwAUMwAUMwAUMwAUMwAUMwAUMwAUMwAUMwAUMwAUMwAUMwAUMwAUMwAUMwAUMwAUMwAUMwAUMwAUMwAUMwAUMwAUMwAUMwAUMwAUMwAUMwAUMwAUOwP/zwHu/29ra5vLpqvtzdNZ8/f27u7u5ST2WulpeXmxcvXjRLy8vNxvp6s7KyMqCz79azi/Pzr306oXmocD+NRs3FxUX/T3YONjc3m1c7O0J+BAFPqa607969a+6+fIk67kW3vLTUHB4eTq7MtGcOPAXxzk6NaY1tjTHtCXgKf334IN4ZqrGtMaY9Abd0dXXl6jAHNcY11rQj4JYu/VLNjQ8H2xNwS9fjccRx9oE7nfYE3NLN7W3EcfaBsW7PQo6O1cKEnZ0dX4f8S11VR6ORqUjHXIE7VAsSXr9+Ld7/UWNSY1NjRHcE3JFaiLC3u9uLc5mlGqMaK7phJDtSV5ha48vDvq2DphsC7sja2lovzoMsAoZgAoZgAoZgAoZgAoZgAoZgllIGqqd1Ts/OJssTa1HE+saGLWkGSsBh6oH3Hx+3q4fg6+9Xl5fN9vZ2s7W1ZUHJgLiFDjIej+99VrZCro32jo6OPE87IAIOcn19/cuDrUfx6iptf6lhEHCQaYIcX183fx4d/bOPl/2qe8scOMhjQvxxflzPKdMvrsAD8G1+/PbtWxvG9YyAB6Tmx++Pj82Pe0TAA2R+3B/mwANmfpzPFXjgfpwfu63OI2Aman58fHzsljqMgPmuIvYpdRYB85Nbm6pHETAEEzA/WV1dNSBBBMx39dYE2+Nm8T0wE9tbW83e3p7BCCPggVtbXW0ODg7s5hFKwAP1fGWl2d/fd8scTsADU3to7bx6NbllJp+AB6SirTXP9szqDwEPgHlufwk4yLRXTvPc/hNwkHqv7mWLtcrmucMh4CC10OL09HTyCOB9zHOHRcBBag5biy1OTk7+E7F57jAJOMy35Y51K10P4Nc8t9Yvm+cOk4AD1VXW/JbGwwyQTcAQTMAQTMAQTMAQTMAdubEZHE9AwB25vbnpxXmQRcAdqfcN2ZL112qMxi1eVE47Au7Qe282eFCNTY0R3bESq0O1tLHeMVTLHdfX13tzXl2oNz7Uy9QeehCD6Qm4Y/ULenp2NvnD49TjkLRjpFqqZ3Ex1otGwC2teWPB3Ai4PQG3VC/BxlgvGgG35BG++agxtilBewKeQm1V4/Zudmpsa4xpT8BTqH2mDt+8aTZ8RdS5GtMaW3t5TefZxfn516QDXhT1vean0Wjy3S+PVx8O1pzX9+aPI+DfVKuLZhXxycePT/4fRN3W7u3uzuzfdsX9PRZy/Kb6BZzVhnKLsKChjsGGeYvLHBiCCRiCCRiCCXiBrTx//uQHtwjHwP0EvMA2X7588oNbhGPgfgJeYPXp78H+/pMd4IFXky483wMHqG1o6mH4eapNCaxJXnwChmBuoSGYgCGYgCGYgCGYgCGYgCGYgCGYgCGYgCGYgCGYgCGYgCGYgCGYgCGYgCGYgCGYgCGYgCGYgCGYgCGYgCGYgCGYgCGYgCGYgCGYgCGYgCGYgCGYgCGYgCGYgCGYgCGYgCGYgCGYgCGYgCGYgCGYgCGYgCGYgCGYgCGYgCGYgCGYgCGYgCGYgCGYgCGYgCGYgCGYgCGYgCFV0zR/A9c/gdi8GSXTAAAAAElFTkSuQmCC"/>
|
||||
</defs>
|
||||
</svg>
|
After Width: | Height: | Size: 2.3 KiB |
@@ -17,9 +17,9 @@ export const environment: GlobalConfig = {
|
||||
// The REST API server settings.
|
||||
// NOTE: these must be "synced" with the 'dspace.server.url' setting in your backend's local.cfg.
|
||||
rest: {
|
||||
ssl: true,
|
||||
host: 'dspace7.4science.cloud',
|
||||
port: 443,
|
||||
ssl: false,
|
||||
host: 'localhost',
|
||||
port: 8080,
|
||||
// NOTE: Space is capitalized because 'namespace' is a reserved string in TypeScript
|
||||
nameSpace: '/server',
|
||||
},
|
||||
|
@@ -6928,6 +6928,11 @@ ngx-bootstrap@^5.3.2:
|
||||
resolved "https://registry.yarnpkg.com/ngx-bootstrap/-/ngx-bootstrap-5.3.2.tgz#0668b01202610657e998b3ca87669645e0b31dc9"
|
||||
integrity sha512-gSMf8EXYl99Q3gqkq4RVhoTNSTYHz2Or6Cig2BJRbLJyqk15ZQE5qcq/ldHS8zzx/wgCA3HQeI63t2j2mEU9PA==
|
||||
|
||||
ngx-gallery@^5.10.0:
|
||||
version "5.10.0"
|
||||
resolved "https://registry.yarnpkg.com/ngx-gallery/-/ngx-gallery-5.10.0.tgz#21f623cb788578dbb5a3625c869712de2b95258c"
|
||||
integrity sha512-+2DnsBfkIzNQoReOHf6+OMf06+qyQQMyVVN4iQAtL0+KykjVqDZiBwLQtmwajDWMGph6O1HNKLrqTcmgqw+d2A==
|
||||
|
||||
ngx-infinite-scroll@6.0.1:
|
||||
version "6.0.1"
|
||||
resolved "https://registry.yarnpkg.com/ngx-infinite-scroll/-/ngx-infinite-scroll-6.0.1.tgz#571e54860ce32839451569bcf6e7a63cfae327bd"
|
||||
|
Reference in New Issue
Block a user