Merge pull request #4391 from boehlke/mediafiles-projector
Show PDF, PNG and JPEG files in projector
This commit is contained in:
commit
39d77dac29
@ -51,6 +51,7 @@
|
|||||||
"ng-pick-datetime": "^7.0.0",
|
"ng-pick-datetime": "^7.0.0",
|
||||||
"ngx-file-drop": "^6.0.0",
|
"ngx-file-drop": "^6.0.0",
|
||||||
"ngx-mat-select-search": "^1.7.2",
|
"ngx-mat-select-search": "^1.7.2",
|
||||||
|
"ng2-pdf-viewer": "^5.2.3",
|
||||||
"ngx-papaparse": "^3.0.2",
|
"ngx-papaparse": "^3.0.2",
|
||||||
"pdfmake": "^0.1.53",
|
"pdfmake": "^0.1.53",
|
||||||
"po2json": "^1.0.0-alpha",
|
"po2json": "^1.0.0-alpha",
|
||||||
|
@ -5,9 +5,9 @@ import { Observable, BehaviorSubject } from 'rxjs';
|
|||||||
import { WebsocketService } from 'app/core/core-services/websocket.service';
|
import { WebsocketService } from 'app/core/core-services/websocket.service';
|
||||||
import { ProjectorElement, Projector } from 'app/shared/models/core/projector';
|
import { ProjectorElement, Projector } from 'app/shared/models/core/projector';
|
||||||
|
|
||||||
export interface SlideData<T = { error?: string }> {
|
export interface SlideData<T = { error?: string }, P extends ProjectorElement = ProjectorElement> {
|
||||||
data: T;
|
data: T;
|
||||||
element: ProjectorElement;
|
element: P;
|
||||||
error?: string;
|
error?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -186,6 +186,15 @@ export class ProjectorService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async updateElement(
|
||||||
|
projector: Projector,
|
||||||
|
obj: Projectable | ProjectorElementBuildDeskriptor | IdentifiableProjectorElement
|
||||||
|
): Promise<void> {
|
||||||
|
const element = this.getProjectorElement(obj);
|
||||||
|
projector.replaceElements(element);
|
||||||
|
await this.projectRequest(projector, projector.elements, projector.elements_preview);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Executes the request to change projector elements.
|
* Executes the request to change projector elements.
|
||||||
*
|
*
|
||||||
|
@ -10,8 +10,6 @@
|
|||||||
line-height: 1.5em;
|
line-height: 1.5em;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#slide {
|
||||||
::ng-deep #slide {
|
|
||||||
z-index: 5;
|
|
||||||
height: 100%;
|
height: 100%;
|
||||||
}
|
}
|
||||||
|
@ -71,7 +71,7 @@
|
|||||||
<ng-container matColumnDef="projector">
|
<ng-container matColumnDef="projector">
|
||||||
<mat-header-cell *matHeaderCellDef mat-sort-header>Projector</mat-header-cell>
|
<mat-header-cell *matHeaderCellDef mat-sort-header>Projector</mat-header-cell>
|
||||||
<mat-cell *matCellDef="let file">
|
<mat-cell *matCellDef="let file">
|
||||||
<os-projector-button [object]="file"></os-projector-button>
|
<os-projector-button *ngIf="file.isProjectable()" [object]="file"></os-projector-button>
|
||||||
</mat-cell>
|
</mat-cell>
|
||||||
</ng-container>
|
</ng-container>
|
||||||
|
|
||||||
|
@ -0,0 +1,13 @@
|
|||||||
|
import { ProjectorElement } from 'app/shared/models/core/projector';
|
||||||
|
|
||||||
|
export interface MediafileProjectorElement extends ProjectorElement {
|
||||||
|
// Images and Pdf
|
||||||
|
rotation?: 0 | 90 | 180 | 270;
|
||||||
|
|
||||||
|
// Images
|
||||||
|
fullscreen?: boolean;
|
||||||
|
|
||||||
|
// Pdf
|
||||||
|
page?: number;
|
||||||
|
zoom?: number; // 0 is normal, then +-1, +-2, ...
|
||||||
|
}
|
@ -7,6 +7,10 @@ import { ProjectorElementBuildDeskriptor } from 'app/site/base/projectable';
|
|||||||
import { BaseViewModelWithListOfSpeakers } from 'app/site/base/base-view-model-with-list-of-speakers';
|
import { BaseViewModelWithListOfSpeakers } from 'app/site/base/base-view-model-with-list-of-speakers';
|
||||||
import { ViewListOfSpeakers } from 'app/site/agenda/models/view-list-of-speakers';
|
import { ViewListOfSpeakers } from 'app/site/agenda/models/view-list-of-speakers';
|
||||||
|
|
||||||
|
export const IMAGE_MIMETYPES = ['image/png', 'image/jpeg', 'image/gif'];
|
||||||
|
export const FONT_MIMETYPES = ['font/ttf', 'font/woff', 'application/font-woff', 'application/font-sfnt'];
|
||||||
|
export const PDF_MIMETYPES = ['application/pdf'];
|
||||||
|
|
||||||
export interface MediafileTitleInformation {
|
export interface MediafileTitleInformation {
|
||||||
title: string;
|
title: string;
|
||||||
}
|
}
|
||||||
@ -57,6 +61,10 @@ export class ViewMediafile extends BaseViewModelWithListOfSpeakers<Mediafile>
|
|||||||
return this.mediafile.downloadUrl;
|
return this.mediafile.downloadUrl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public get pages(): number | null {
|
||||||
|
return this.mediafile.mediafile.pages;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Determines if the file has the 'hidden' attribute
|
* Determines if the file has the 'hidden' attribute
|
||||||
* @returns the hidden attribute, also 'hidden' if there is no file
|
* @returns the hidden attribute, also 'hidden' if there is no file
|
||||||
@ -96,13 +104,17 @@ export class ViewMediafile extends BaseViewModelWithListOfSpeakers<Mediafile>
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public isProjectable(): boolean {
|
||||||
|
return this.isImage() || this.isPdf();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Determine if the file is an image
|
* Determine if the file is an image
|
||||||
*
|
*
|
||||||
* @returns true or false
|
* @returns true or false
|
||||||
*/
|
*/
|
||||||
public isImage(): boolean {
|
public isImage(): boolean {
|
||||||
return ['image/png', 'image/jpeg', 'image/gif'].includes(this.type);
|
return IMAGE_MIMETYPES.includes(this.type);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -111,7 +123,7 @@ export class ViewMediafile extends BaseViewModelWithListOfSpeakers<Mediafile>
|
|||||||
* @returns true or false
|
* @returns true or false
|
||||||
*/
|
*/
|
||||||
public isFont(): boolean {
|
public isFont(): boolean {
|
||||||
return ['font/ttf', 'font/woff', 'application/font-woff', 'application/font-sfnt'].includes(this.type);
|
return FONT_MIMETYPES.includes(this.type);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -120,7 +132,7 @@ export class ViewMediafile extends BaseViewModelWithListOfSpeakers<Mediafile>
|
|||||||
* @returns true or false
|
* @returns true or false
|
||||||
*/
|
*/
|
||||||
public isPdf(): boolean {
|
public isPdf(): boolean {
|
||||||
return ['application/pdf'].includes(this.type);
|
return PDF_MIMETYPES.includes(this.type);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -0,0 +1,37 @@
|
|||||||
|
<mat-expansion-panel *ngIf="elements.length">
|
||||||
|
<mat-expansion-panel-header>
|
||||||
|
<span translate>Media file</span>
|
||||||
|
</mat-expansion-panel-header>
|
||||||
|
<div *ngFor="let element of elements">
|
||||||
|
<i>{{ getMediafile(element).getTitle() }}</i>
|
||||||
|
<div *ngIf="getMediafile(element).isImage()">
|
||||||
|
<button type="button" *ngIf="!element.fullscreen" mat-icon-button (click)="fullscreen(element)">
|
||||||
|
<mat-icon>check_box_outline_blank</mat-icon>
|
||||||
|
</button>
|
||||||
|
<button type="button" *ngIf="!!element.fullscreen" mat-icon-button (click)="fullscreen(element)">
|
||||||
|
<mat-icon>check_box</mat-icon>
|
||||||
|
</button>
|
||||||
|
<span translate>fullscreen</span>
|
||||||
|
</div>
|
||||||
|
<div *ngIf="getMediafile(element).isPdf()">
|
||||||
|
<button type="button" mat-icon-button (click)="pdfBackward(element)" [disabled]="getPage(element) <= 1">
|
||||||
|
<mat-icon>arrow_back</mat-icon>
|
||||||
|
</button>
|
||||||
|
<button type="button" mat-icon-button (click)="pdfForward(element)" [disabled]="getPage(element) >= getMediafile(element).pages">
|
||||||
|
<mat-icon>arrow_forward</mat-icon>
|
||||||
|
</button>
|
||||||
|
<!-- TODO: Use form for page number; use pdfSetPage then. -->
|
||||||
|
<span translate>Page</span> {{ getPage(element) }}/{{ getMediafile(element).pages }}
|
||||||
|
<br>
|
||||||
|
<button type="button" mat-icon-button (click)="zoom(element, 'in')">
|
||||||
|
<mat-icon>zoom_in</mat-icon>
|
||||||
|
</button>
|
||||||
|
<button type="button" mat-icon-button (click)="zoom(element, 'reset')">
|
||||||
|
<mat-icon>replay</mat-icon>
|
||||||
|
</button>
|
||||||
|
<button type="button" mat-icon-button (click)="zoom(element, 'out')">
|
||||||
|
<mat-icon>zoom_out</mat-icon>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</mat-expansion-panel>
|
@ -0,0 +1,26 @@
|
|||||||
|
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
|
import { E2EImportsModule } from '../../../../../e2e-imports.module';
|
||||||
|
import { PresentationControlComponent } from './presentation-control.component';
|
||||||
|
import { ProjectorModule } from '../../projector.module';
|
||||||
|
|
||||||
|
describe('PresentationControlComponent', () => {
|
||||||
|
let component: PresentationControlComponent;
|
||||||
|
let fixture: ComponentFixture<PresentationControlComponent>;
|
||||||
|
|
||||||
|
beforeEach(async(() => {
|
||||||
|
TestBed.configureTestingModule({
|
||||||
|
imports: [E2EImportsModule, ProjectorModule]
|
||||||
|
}).compileComponents();
|
||||||
|
}));
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
fixture = TestBed.createComponent(PresentationControlComponent);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create', () => {
|
||||||
|
expect(component).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
@ -0,0 +1,144 @@
|
|||||||
|
import { Component, Input } from '@angular/core';
|
||||||
|
import { MatSnackBar } from '@angular/material';
|
||||||
|
import { Title } from '@angular/platform-browser';
|
||||||
|
|
||||||
|
import { TranslateService } from '@ngx-translate/core';
|
||||||
|
|
||||||
|
import { BaseViewComponent } from 'app/site/base/base-view';
|
||||||
|
import { Mediafile } from 'app/shared/models/mediafiles/mediafile';
|
||||||
|
import { MediafileRepositoryService } from 'app/core/repositories/mediafiles/mediafile-repository.service';
|
||||||
|
import { ProjectorService } from 'app/core/core-services/projector.service';
|
||||||
|
import { SlideManager } from 'app/slides/services/slide-manager.service';
|
||||||
|
import { ViewMediafile } from 'app/site/mediafiles/models/view-mediafile';
|
||||||
|
import { ViewProjector } from '../../models/view-projector';
|
||||||
|
import { MediafileProjectorElement } from 'app/site/mediafiles/models/mediafile-projector-element';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The presentation controls.
|
||||||
|
*/
|
||||||
|
@Component({
|
||||||
|
selector: 'os-presentation-control',
|
||||||
|
templateUrl: './presentation-control.component.html',
|
||||||
|
styleUrls: ['./presentation-control.component.scss']
|
||||||
|
})
|
||||||
|
export class PresentationControlComponent extends BaseViewComponent {
|
||||||
|
/**
|
||||||
|
* The projector.
|
||||||
|
*/
|
||||||
|
private _projector: ViewProjector;
|
||||||
|
|
||||||
|
@Input()
|
||||||
|
public set projector(projector: ViewProjector) {
|
||||||
|
this._projector = projector;
|
||||||
|
this.updateElements();
|
||||||
|
}
|
||||||
|
|
||||||
|
public get projector(): ViewProjector {
|
||||||
|
return this._projector;
|
||||||
|
}
|
||||||
|
|
||||||
|
// All mediafile elements.
|
||||||
|
public elements: MediafileProjectorElement[] = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor
|
||||||
|
*
|
||||||
|
* @param titleService
|
||||||
|
* @param translate
|
||||||
|
* @param matSnackBar
|
||||||
|
* @param mediafileRepo
|
||||||
|
* @param slideManager
|
||||||
|
* @param projectorService
|
||||||
|
*/
|
||||||
|
public constructor(
|
||||||
|
titleService: Title,
|
||||||
|
translate: TranslateService,
|
||||||
|
matSnackBar: MatSnackBar,
|
||||||
|
private mediafileRepo: MediafileRepositoryService,
|
||||||
|
private slideManager: SlideManager,
|
||||||
|
private projectorService: ProjectorService
|
||||||
|
) {
|
||||||
|
super(titleService, translate, matSnackBar);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates incoming elements
|
||||||
|
*/
|
||||||
|
private updateElements(): void {
|
||||||
|
this.elements = this.projector.elements.filter(element => {
|
||||||
|
if (element.name !== Mediafile.COLLECTIONSTRING || !element.id) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
const mediafile = this.mediafileRepo.getViewModel(element.id);
|
||||||
|
return !!mediafile && mediafile.isProjectable();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public getMediafile(element: MediafileProjectorElement): ViewMediafile {
|
||||||
|
return this.mediafileRepo.getViewModel(element.id);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @returns the currently used page number (1 in case of unnumbered elements)
|
||||||
|
*/
|
||||||
|
public getPage(element: MediafileProjectorElement): number {
|
||||||
|
return element.page || 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* moves the projected forward by one page (if not already at end)
|
||||||
|
*
|
||||||
|
* @param element
|
||||||
|
*/
|
||||||
|
public pdfForward(element: MediafileProjectorElement): void {
|
||||||
|
if (this.getPage(element) < this.getMediafile(element).pages) {
|
||||||
|
this.pdfSetPage(element, this.getPage(element) + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* moves the projected one page backwards (if not already at beginnning)
|
||||||
|
*
|
||||||
|
* @param element
|
||||||
|
*/
|
||||||
|
public pdfBackward(element: MediafileProjectorElement): void {
|
||||||
|
if (this.getPage(element) > 1) {
|
||||||
|
this.pdfSetPage(element, this.getPage(element) - 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Moves the element to a specific given page. If the number given is greater
|
||||||
|
* than the amount of element pages, it does nothing
|
||||||
|
*
|
||||||
|
* @param element
|
||||||
|
* @param page
|
||||||
|
*/
|
||||||
|
public pdfSetPage(element: MediafileProjectorElement, page: number): void {
|
||||||
|
if (this.getMediafile(element).pages >= page) {
|
||||||
|
element.page = page;
|
||||||
|
this.updateElement(element);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public zoom(element: MediafileProjectorElement, direction: 'in' | 'out' | 'reset'): void {
|
||||||
|
if (direction === 'reset') {
|
||||||
|
element.zoom = 0;
|
||||||
|
} else if (direction === 'in') {
|
||||||
|
element.zoom = (element.zoom || 0) + 1;
|
||||||
|
} else if (direction === 'out') {
|
||||||
|
element.zoom = (element.zoom || 0) - 1;
|
||||||
|
}
|
||||||
|
this.updateElement(element);
|
||||||
|
}
|
||||||
|
|
||||||
|
public fullscreen(element: MediafileProjectorElement): void {
|
||||||
|
element.fullscreen = !element.fullscreen;
|
||||||
|
this.updateElement(element);
|
||||||
|
}
|
||||||
|
|
||||||
|
private updateElement(element: MediafileProjectorElement): void {
|
||||||
|
const idElement = this.slideManager.getIdentifialbeProjectorElement(element);
|
||||||
|
this.projectorService.updateElement(this.projector.projector, idElement).then(null, this.raiseError);
|
||||||
|
}
|
||||||
|
}
|
@ -262,6 +262,18 @@
|
|||||||
</mat-list-item>
|
</mat-list-item>
|
||||||
</mat-list>
|
</mat-list>
|
||||||
</mat-expansion-panel>
|
</mat-expansion-panel>
|
||||||
|
|
||||||
|
<!-- File display controls -->
|
||||||
|
<!--<mat-expansion-panel>
|
||||||
|
<mat-expansion-panel-header>
|
||||||
|
<span translate>Media controls</span>
|
||||||
|
</mat-expansion-panel-header>
|
||||||
|
<os-presentation-control [projector]="projector">
|
||||||
|
</os-presentation-control>
|
||||||
|
</mat-expansion-panel>-->
|
||||||
|
|
||||||
|
<os-presentation-control [projector]="projector">
|
||||||
|
</os-presentation-control>
|
||||||
</mat-accordion>
|
</mat-accordion>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,15 +1,16 @@
|
|||||||
import { NgModule } from '@angular/core';
|
|
||||||
import { CommonModule } from '@angular/common';
|
import { CommonModule } from '@angular/common';
|
||||||
|
import { NgModule } from '@angular/core';
|
||||||
|
|
||||||
import { ProjectorRoutingModule } from './projector-routing.module';
|
|
||||||
import { SharedModule } from '../../shared/shared.module';
|
|
||||||
import { ProjectorListComponent } from './components/projector-list/projector-list.component';
|
|
||||||
import { ProjectorDetailComponent } from './components/projector-detail/projector-detail.component';
|
|
||||||
import { CountdownControlsComponent } from './components/countdown-controls/countdown-controls.component';
|
import { CountdownControlsComponent } from './components/countdown-controls/countdown-controls.component';
|
||||||
import { CountdownDialogComponent } from './components/countdown-dialog/countdown-dialog.component';
|
import { CountdownDialogComponent } from './components/countdown-dialog/countdown-dialog.component';
|
||||||
import { MessageControlsComponent } from './components/message-controls/message-controls.component';
|
import { MessageControlsComponent } from './components/message-controls/message-controls.component';
|
||||||
import { MessageDialogComponent } from './components/message-dialog/message-dialog.component';
|
import { MessageDialogComponent } from './components/message-dialog/message-dialog.component';
|
||||||
|
import { PresentationControlComponent } from './components/presentation-control/presentation-control.component';
|
||||||
|
import { ProjectorDetailComponent } from './components/projector-detail/projector-detail.component';
|
||||||
|
import { ProjectorListComponent } from './components/projector-list/projector-list.component';
|
||||||
import { ProjectorListEntryComponent } from './components/projector-list-entry/projector-list-entry.component';
|
import { ProjectorListEntryComponent } from './components/projector-list-entry/projector-list-entry.component';
|
||||||
|
import { ProjectorRoutingModule } from './projector-routing.module';
|
||||||
|
import { SharedModule } from '../../shared/shared.module';
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
imports: [CommonModule, ProjectorRoutingModule, SharedModule],
|
imports: [CommonModule, ProjectorRoutingModule, SharedModule],
|
||||||
@ -20,8 +21,14 @@ import { ProjectorListEntryComponent } from './components/projector-list-entry/p
|
|||||||
CountdownControlsComponent,
|
CountdownControlsComponent,
|
||||||
CountdownDialogComponent,
|
CountdownDialogComponent,
|
||||||
MessageControlsComponent,
|
MessageControlsComponent,
|
||||||
MessageDialogComponent
|
MessageDialogComponent,
|
||||||
|
PresentationControlComponent
|
||||||
],
|
],
|
||||||
entryComponents: [CountdownDialogComponent, MessageDialogComponent]
|
entryComponents: [
|
||||||
|
CountdownDialogComponent,
|
||||||
|
MessageDialogComponent,
|
||||||
|
PresentationControlComponent,
|
||||||
|
ProjectorListEntryComponent
|
||||||
|
]
|
||||||
})
|
})
|
||||||
export class ProjectorModule {}
|
export class ProjectorModule {}
|
||||||
|
@ -2,17 +2,18 @@ import { Input } from '@angular/core';
|
|||||||
|
|
||||||
import { ViewProjector } from 'app/site/projector/models/view-projector';
|
import { ViewProjector } from 'app/site/projector/models/view-projector';
|
||||||
import { SlideData } from 'app/core/core-services/projector-data.service';
|
import { SlideData } from 'app/core/core-services/projector-data.service';
|
||||||
|
import { ProjectorElement } from 'app/shared/models/core/projector';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Every slide has to extends this base class. It forces the slides
|
* Every slide has to extends this base class. It forces the slides
|
||||||
* to have an input for the slidedata.
|
* to have an input for the slidedata.
|
||||||
*/
|
*/
|
||||||
export abstract class BaseSlideComponent<T extends object> {
|
export abstract class BaseSlideComponent<T extends object, P extends ProjectorElement = ProjectorElement> {
|
||||||
/**
|
/**
|
||||||
* Each slide must take slide data.
|
* Each slide must take slide data.
|
||||||
*/
|
*/
|
||||||
@Input()
|
@Input()
|
||||||
public data: SlideData<T>;
|
public data: SlideData<T, P>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The projector where this slide is projected on.
|
* The projector where this slide is projected on.
|
||||||
|
@ -1,5 +1,16 @@
|
|||||||
<div *ngIf="data">
|
<div *ngIf="data">
|
||||||
<p>{{ data.data.path }}</p>
|
<div *ngIf="isImage" [ngClass]="data.element.fullscreen ? 'fullscreen' : 'nofullscreen'" >
|
||||||
<p>{{ data.data.type }}</p>
|
<img [src]="url" alt="" />
|
||||||
<p>{{ data.data.media_url_prefix }}</p>
|
</div>
|
||||||
|
<div *ngIf="isPdf" class="fullscreen">
|
||||||
|
<pdf-viewer
|
||||||
|
[show-all]="false"
|
||||||
|
[original-size]="false"
|
||||||
|
[fit-to-page]="true"
|
||||||
|
[autoresize]="true"
|
||||||
|
[page]="data.element.page || 1"
|
||||||
|
[zoom]="zoom"
|
||||||
|
[src]="url"
|
||||||
|
style="display: block;"></pdf-viewer>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -0,0 +1,30 @@
|
|||||||
|
.fullscreen img,
|
||||||
|
.nofullscreen img {
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
margin: auto;
|
||||||
|
}
|
||||||
|
.fullscreen {
|
||||||
|
z-index: 100; /* TODO: find solution to overlap header/footer */
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
background-color: white;
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
|
||||||
|
img {
|
||||||
|
width: 100%;
|
||||||
|
height: auto; /* TODO: use dynamic auto width/height for landscape/portrait format */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.nofullscreen {
|
||||||
|
max-width: 100%;
|
||||||
|
max-height: 100%;
|
||||||
|
width: auto;
|
||||||
|
height: auto;
|
||||||
|
}
|
@ -2,6 +2,7 @@ import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
|||||||
|
|
||||||
import { MediafileSlideComponent } from './mediafile-slide.component';
|
import { MediafileSlideComponent } from './mediafile-slide.component';
|
||||||
import { E2EImportsModule } from '../../../../e2e-imports.module';
|
import { E2EImportsModule } from '../../../../e2e-imports.module';
|
||||||
|
import { PdfViewerModule } from 'ng2-pdf-viewer';
|
||||||
|
|
||||||
describe('MediafileSlideComponent', () => {
|
describe('MediafileSlideComponent', () => {
|
||||||
let component: MediafileSlideComponent;
|
let component: MediafileSlideComponent;
|
||||||
@ -9,7 +10,7 @@ describe('MediafileSlideComponent', () => {
|
|||||||
|
|
||||||
beforeEach(async(() => {
|
beforeEach(async(() => {
|
||||||
TestBed.configureTestingModule({
|
TestBed.configureTestingModule({
|
||||||
imports: [E2EImportsModule],
|
imports: [E2EImportsModule, PdfViewerModule],
|
||||||
declarations: [MediafileSlideComponent]
|
declarations: [MediafileSlideComponent]
|
||||||
}).compileComponents();
|
}).compileComponents();
|
||||||
}));
|
}));
|
||||||
|
@ -2,13 +2,31 @@ import { Component } from '@angular/core';
|
|||||||
|
|
||||||
import { BaseSlideComponent } from 'app/slides/base-slide-component';
|
import { BaseSlideComponent } from 'app/slides/base-slide-component';
|
||||||
import { MediafileSlideData } from './mediafile-slide-data';
|
import { MediafileSlideData } from './mediafile-slide-data';
|
||||||
|
import { IMAGE_MIMETYPES, PDF_MIMETYPES } from 'app/site/mediafiles/models/view-mediafile';
|
||||||
|
import { MediafileProjectorElement } from 'app/site/mediafiles/models/mediafile-projector-element';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'os-mediafile-slide',
|
selector: 'os-mediafile-slide',
|
||||||
templateUrl: './mediafile-slide.component.html',
|
templateUrl: './mediafile-slide.component.html',
|
||||||
styleUrls: ['./mediafile-slide.component.scss']
|
styleUrls: ['./mediafile-slide.component.scss']
|
||||||
})
|
})
|
||||||
export class MediafileSlideComponent extends BaseSlideComponent<MediafileSlideData> {
|
export class MediafileSlideComponent extends BaseSlideComponent<MediafileSlideData, MediafileProjectorElement> {
|
||||||
|
public get url(): string {
|
||||||
|
return `${this.data.data.media_url_prefix}/${this.data.data.path}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get zoom(): number {
|
||||||
|
return Math.pow(1.1, this.data.element.zoom || 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public get isImage(): boolean {
|
||||||
|
return IMAGE_MIMETYPES.includes(this.data.data.type);
|
||||||
|
}
|
||||||
|
|
||||||
|
public get isPdf(): boolean {
|
||||||
|
return PDF_MIMETYPES.includes(this.data.data.type);
|
||||||
|
}
|
||||||
|
|
||||||
public constructor() {
|
public constructor() {
|
||||||
super();
|
super();
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,16 @@
|
|||||||
import { NgModule } from '@angular/core';
|
import { NgModule } from '@angular/core';
|
||||||
|
import { CommonModule } from '@angular/common';
|
||||||
|
|
||||||
|
import { PdfViewerModule } from 'ng2-pdf-viewer';
|
||||||
|
|
||||||
import { makeSlideModule } from 'app/slides/base-slide-module';
|
|
||||||
import { MediafileSlideComponent } from './mediafile-slide.component';
|
import { MediafileSlideComponent } from './mediafile-slide.component';
|
||||||
|
import { SharedModule } from 'app/shared/shared.module';
|
||||||
|
import { SLIDE } from 'app/slides/slide-token';
|
||||||
|
|
||||||
@NgModule(makeSlideModule(MediafileSlideComponent))
|
@NgModule({
|
||||||
|
imports: [CommonModule, SharedModule, PdfViewerModule],
|
||||||
|
declarations: [MediafileSlideComponent],
|
||||||
|
providers: [{ provide: SLIDE, useValue: MediafileSlideComponent }],
|
||||||
|
entryComponents: [MediafileSlideComponent]
|
||||||
|
})
|
||||||
export class MediafileSlideModule {}
|
export class MediafileSlideModule {}
|
||||||
|
@ -54,8 +54,8 @@ export class SlideManager {
|
|||||||
return this.loadedSlideConfigurations[slideName];
|
return this.loadedSlideConfigurations[slideName];
|
||||||
}
|
}
|
||||||
|
|
||||||
public getIdentifialbeProjectorElement(element: ProjectorElement): IdentifiableProjectorElement {
|
public getIdentifialbeProjectorElement<P extends ProjectorElement>(element: P): IdentifiableProjectorElement & P {
|
||||||
const identifiableElement: IdentifiableProjectorElement = element as IdentifiableProjectorElement;
|
const identifiableElement: IdentifiableProjectorElement & P = element as IdentifiableProjectorElement & P;
|
||||||
const identifiers = this.getManifest(element.name).elementIdentifiers.map(x => x); // map to copy.
|
const identifiers = this.getManifest(element.name).elementIdentifiers.map(x => x); // map to copy.
|
||||||
identifiableElement.getIdentifiers = () => identifiers;
|
identifiableElement.getIdentifiers = () => identifiers;
|
||||||
return identifiableElement;
|
return identifiableElement;
|
||||||
|
Loading…
Reference in New Issue
Block a user