Merge pull request #4338 from FinnStutzenstein/projector-message-slide
ProjectorMessageSlide and some renaming
This commit is contained in:
commit
34feac553b
@ -16,8 +16,8 @@ import {
|
|||||||
import { HttpService } from './http.service';
|
import { HttpService } from './http.service';
|
||||||
import { SlideManager } from 'app/slides/services/slide-manager.service';
|
import { SlideManager } from 'app/slides/services/slide-manager.service';
|
||||||
import { BaseModel } from 'app/shared/models/base/base-model';
|
import { BaseModel } from 'app/shared/models/base/base-model';
|
||||||
import { BaseViewModel } from 'app/site/base/base-view-model';
|
|
||||||
import { ViewModelStoreService } from './view-model-store.service';
|
import { ViewModelStoreService } from './view-model-store.service';
|
||||||
|
import { BaseProjectableViewModel } from 'app/site/base/base-projectable-view-model';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This service cares about Projectables being projected and manage all projection-related
|
* This service cares about Projectables being projected and manage all projection-related
|
||||||
@ -260,9 +260,15 @@ export class ProjectorService {
|
|||||||
* @param element The projector element
|
* @param element The projector element
|
||||||
* @returns the view model from the projector element
|
* @returns the view model from the projector element
|
||||||
*/
|
*/
|
||||||
public getViewModelFromProjectorElement<T extends BaseViewModel>(element: IdentifiableProjectorElement): T {
|
public getViewModelFromProjectorElement<T extends BaseProjectableViewModel>(
|
||||||
|
element: IdentifiableProjectorElement
|
||||||
|
): T {
|
||||||
this.assertElementIsMappable(element);
|
this.assertElementIsMappable(element);
|
||||||
return this.viewModelStore.get<T>(element.name, element.id);
|
const viewModel = this.viewModelStore.get<T>(element.name, element.id);
|
||||||
|
if (!isProjectable(viewModel)) {
|
||||||
|
console.error('The view model is not projectable', viewModel, element);
|
||||||
|
}
|
||||||
|
return viewModel;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -138,6 +138,7 @@ export class MotionRepositoryService extends BaseRepository<ViewMotion, Motion>
|
|||||||
return viewMotion.getTitle();
|
return viewMotion.getTitle();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
viewMotion.getProjectorTitle = viewMotion.getAgendaTitle;
|
||||||
viewMotion.getAgendaTitleWithType = () => {
|
viewMotion.getAgendaTitleWithType = () => {
|
||||||
// Append the verbose name only, if not the special format 'Motion <identifier>' is used.
|
// Append the verbose name only, if not the special format 'Motion <identifier>' is used.
|
||||||
if (viewMotion.identifier) {
|
if (viewMotion.identifier) {
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { TestBed, inject } from '@angular/core/testing';
|
import { TestBed, inject } from '@angular/core/testing';
|
||||||
|
|
||||||
import { E2EImportsModule } from 'e2e-imports.module';
|
import { E2EImportsModule } from 'e2e-imports.module';
|
||||||
import { ProjectorMessageRepositoryService } from './projectormessage-repository.service';
|
import { ProjectorMessageRepositoryService } from './projector-message-repository.service';
|
||||||
|
|
||||||
describe('ProjectorMessageRepositoryService', () => {
|
describe('ProjectorMessageRepositoryService', () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
@ -4,9 +4,10 @@ import { BaseRepository } from '../base-repository';
|
|||||||
import { Identifiable } from 'app/shared/models/base/identifiable';
|
import { Identifiable } from 'app/shared/models/base/identifiable';
|
||||||
import { CollectionStringMapperService } from '../../core-services/collectionStringMapper.service';
|
import { CollectionStringMapperService } from '../../core-services/collectionStringMapper.service';
|
||||||
import { ProjectorMessage } from 'app/shared/models/core/projector-message';
|
import { ProjectorMessage } from 'app/shared/models/core/projector-message';
|
||||||
import { ViewProjectorMessage } from 'app/site/projector/models/view-projectormessage';
|
import { ViewProjectorMessage } from 'app/site/projector/models/view-projector-message';
|
||||||
import { ViewModelStoreService } from 'app/core/core-services/view-model-store.service';
|
import { ViewModelStoreService } from 'app/core/core-services/view-model-store.service';
|
||||||
import { TranslateService } from '@ngx-translate/core';
|
import { TranslateService } from '@ngx-translate/core';
|
||||||
|
import { DataSendService } from 'app/core/core-services/data-send.service';
|
||||||
|
|
||||||
@Injectable({
|
@Injectable({
|
||||||
providedIn: 'root'
|
providedIn: 'root'
|
||||||
@ -16,7 +17,8 @@ export class ProjectorMessageRepositoryService extends BaseRepository<ViewProjec
|
|||||||
DS: DataStoreService,
|
DS: DataStoreService,
|
||||||
mapperService: CollectionStringMapperService,
|
mapperService: CollectionStringMapperService,
|
||||||
viewModelStoreService: ViewModelStoreService,
|
viewModelStoreService: ViewModelStoreService,
|
||||||
private translate: TranslateService
|
private translate: TranslateService,
|
||||||
|
private dataSend: DataSendService
|
||||||
) {
|
) {
|
||||||
super(DS, mapperService, viewModelStoreService, ProjectorMessage);
|
super(DS, mapperService, viewModelStoreService, ProjectorMessage);
|
||||||
}
|
}
|
||||||
@ -30,14 +32,16 @@ export class ProjectorMessageRepositoryService extends BaseRepository<ViewProjec
|
|||||||
}
|
}
|
||||||
|
|
||||||
public async create(message: ProjectorMessage): Promise<Identifiable> {
|
public async create(message: ProjectorMessage): Promise<Identifiable> {
|
||||||
throw new Error('TODO');
|
return await this.dataSend.createModel(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async update(message: Partial<ProjectorMessage>, viewMessage: ViewProjectorMessage): Promise<void> {
|
public async update(message: Partial<ProjectorMessage>, viewMessage: ViewProjectorMessage): Promise<void> {
|
||||||
throw new Error('TODO');
|
const update = viewMessage.projectormessage;
|
||||||
|
update.patchValues(message);
|
||||||
|
await this.dataSend.updateModel(update);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async delete(viewMessage: ViewProjectorMessage): Promise<void> {
|
public async delete(viewMessage: ViewProjectorMessage): Promise<void> {
|
||||||
throw new Error('TODO');
|
await this.dataSend.deleteModel(viewMessage.projectormessage);
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,13 +1,10 @@
|
|||||||
<h2 mat-dialog-title>
|
<h2 mat-dialog-title>
|
||||||
<span *ngIf="projectorElementBuildDescriptor.projectionDefaultName !== 'motions'" translate>Project {{ projectorElementBuildDescriptor.getTitle() }}?</span>
|
<span translate>Project</span> {{ projectorElementBuildDescriptor.getTitle() }}?
|
||||||
<span *ngIf="projectorElementBuildDescriptor.projectionDefaultName === 'motions'" translate>Project motion {{ projectorElementBuildDescriptor.getTitle() }}?</span>
|
|
||||||
</h2>
|
</h2>
|
||||||
<mat-dialog-content>
|
<mat-dialog-content>
|
||||||
<div
|
<div class="projectors"
|
||||||
class="projectors"
|
|
||||||
*ngFor="let projector of projectors"
|
*ngFor="let projector of projectors"
|
||||||
[ngClass]="isProjectedOn(projector) ? 'projected' : ''"
|
[ngClass]="isProjectedOn(projector) ? 'projected' : ''">
|
||||||
>
|
|
||||||
<mat-checkbox [checked]="isProjectorSelected(projector)" (change)="toggleProjector(projector)">
|
<mat-checkbox [checked]="isProjectorSelected(projector)" (change)="toggleProjector(projector)">
|
||||||
{{ projector.name | translate }}
|
{{ projector.name | translate }}
|
||||||
</mat-checkbox>
|
</mat-checkbox>
|
||||||
|
@ -13,7 +13,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div *ngFor="let slide of slides" class="content">
|
<div *ngFor="let slide of slides">
|
||||||
<os-slide-container [slideData]="slide" [scroll]="scroll" [scale]="scale"></os-slide-container>
|
<os-slide-container [slideData]="slide" [scroll]="scroll" [scale]="scale"></os-slide-container>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -51,14 +51,6 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.content {
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
position: absolute;
|
|
||||||
top: 0;
|
|
||||||
left: 50px;
|
|
||||||
right: 50px;
|
|
||||||
}
|
|
||||||
|
|
||||||
#footer {
|
#footer {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
|
@ -1 +1,6 @@
|
|||||||
<div id="slide" [ngStyle]="slideStyle"><ng-container #slide></ng-container></div>
|
<div
|
||||||
|
id="slide"
|
||||||
|
[ngClass]="{'content': slideOptions.scaleable || slideOptions.scrollable}"
|
||||||
|
[ngStyle]="slideStyle">
|
||||||
|
<ng-container #slide></ng-container>
|
||||||
|
</div>
|
||||||
|
@ -1,6 +1,14 @@
|
|||||||
#slide {
|
#slide {
|
||||||
width: calc(100% - 100px);
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
|
||||||
|
&.content {
|
||||||
|
width: calc(100% - 100px);
|
||||||
|
margin-left: 50px;
|
||||||
|
margin-right: 50px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
::ng-deep #slide {
|
::ng-deep #slide {
|
||||||
z-index: 5;
|
z-index: 5;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
@ -88,7 +88,7 @@ export class SlideContainerComponent extends BaseComponent {
|
|||||||
/**
|
/**
|
||||||
* The current slideoptions.
|
* The current slideoptions.
|
||||||
*/
|
*/
|
||||||
private slideOptions: SlideOptions = { scaleable: false, scrollable: false };
|
public slideOptions: SlideOptions = { scaleable: false, scrollable: false };
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Styles for scaling and scrolling.
|
* Styles for scaling and scrolling.
|
||||||
|
11
client/src/app/shared/utils/strip-html-tags.ts
Normal file
11
client/src/app/shared/utils/strip-html-tags.ts
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
/**
|
||||||
|
* Helper to remove html tags from a string.
|
||||||
|
* CAUTION: It is just a basic "don't show distracting html tags in a
|
||||||
|
* preview", not an actual tested sanitizer!
|
||||||
|
*
|
||||||
|
* @param inputString
|
||||||
|
*/
|
||||||
|
export function stripHtmlTags(inputString: string): string {
|
||||||
|
const regexp = new RegExp(/<[^ ][^<>]*(>|$)/g);
|
||||||
|
return inputString.replace(regexp, '').trim();
|
||||||
|
}
|
@ -10,6 +10,7 @@ import { DurationService } from 'app/core/ui-services/duration.service';
|
|||||||
import { FileExportService } from 'app/core/ui-services/file-export.service';
|
import { FileExportService } from 'app/core/ui-services/file-export.service';
|
||||||
import { itemVisibilityChoices } from 'app/shared/models/agenda/item';
|
import { itemVisibilityChoices } from 'app/shared/models/agenda/item';
|
||||||
import { ViewCreateTopic } from '../../models/view-create-topic';
|
import { ViewCreateTopic } from '../../models/view-create-topic';
|
||||||
|
import { stripHtmlTags } from 'app/shared/utils/strip-html-tags';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Component for the agenda import list view.
|
* Component for the agenda import list view.
|
||||||
@ -59,9 +60,9 @@ export class AgendaImportListComponent extends BaseImportListComponent<ViewCreat
|
|||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
if (input.length > 50) {
|
if (input.length > 50) {
|
||||||
return this.stripHtmlTags(input.substring(0, 47)) + '...';
|
return stripHtmlTags(input.substring(0, 47)) + '...';
|
||||||
}
|
}
|
||||||
return this.stripHtmlTags(input);
|
return stripHtmlTags(input);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -77,28 +78,15 @@ export class AgendaImportListComponent extends BaseImportListComponent<ViewCreat
|
|||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
if (input.length < 300) {
|
if (input.length < 300) {
|
||||||
return this.stripHtmlTags(input);
|
return stripHtmlTags(input);
|
||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
this.stripHtmlTags(input.substring(0, 147)) +
|
stripHtmlTags(input.substring(0, 147)) +
|
||||||
' [...] ' +
|
' [...] ' +
|
||||||
this.stripHtmlTags(input.substring(input.length - 150, input.length))
|
stripHtmlTags(input.substring(input.length - 150, input.length))
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Helper to remove html tags from a string.
|
|
||||||
* CAUTION: It is just a basic "don't show distracting html tags in a
|
|
||||||
* preview", not an actual tested sanitizer!
|
|
||||||
*
|
|
||||||
* @param inputString
|
|
||||||
* @returns a string without hatml tags
|
|
||||||
*/
|
|
||||||
private stripHtmlTags(inputString: string): string {
|
|
||||||
const regexp = new RegExp(/<[^ ][^<>]*(>|$)/g);
|
|
||||||
return inputString.replace(regexp, '').trim();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Triggers an example csv download
|
* Triggers an example csv download
|
||||||
*/
|
*/
|
||||||
|
@ -6,4 +6,11 @@ import { BaseViewModel } from './base-view-model';
|
|||||||
*/
|
*/
|
||||||
export abstract class BaseProjectableViewModel extends BaseViewModel implements Projectable {
|
export abstract class BaseProjectableViewModel extends BaseViewModel implements Projectable {
|
||||||
public abstract getSlide(): ProjectorElementBuildDeskriptor;
|
public abstract getSlide(): ProjectorElementBuildDeskriptor;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @returns the projector title used for managing projector elements.
|
||||||
|
*/
|
||||||
|
public getProjectorTitle = () => {
|
||||||
|
return this.getTitle();
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
@ -8,6 +8,7 @@ import { BaseImportListComponent } from 'app/site/base/base-import-list';
|
|||||||
import { MotionCsvExportService } from '../../services/motion-csv-export.service';
|
import { MotionCsvExportService } from '../../services/motion-csv-export.service';
|
||||||
import { MotionImportService } from '../../services/motion-import.service';
|
import { MotionImportService } from '../../services/motion-import.service';
|
||||||
import { ViewMotion } from '../../models/view-motion';
|
import { ViewMotion } from '../../models/view-motion';
|
||||||
|
import { stripHtmlTags } from 'app/shared/utils/strip-html-tags';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Component for the motion import list view.
|
* Component for the motion import list view.
|
||||||
@ -43,9 +44,9 @@ export class MotionImportListComponent extends BaseImportListComponent<ViewMotio
|
|||||||
*/
|
*/
|
||||||
public getShortPreview(input: string): string {
|
public getShortPreview(input: string): string {
|
||||||
if (input.length > 50) {
|
if (input.length > 50) {
|
||||||
return this.stripHtmlTags(input.substring(0, 47)) + '...';
|
return stripHtmlTags(input.substring(0, 47)) + '...';
|
||||||
}
|
}
|
||||||
return this.stripHtmlTags(input);
|
return stripHtmlTags(input);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -56,26 +57,15 @@ export class MotionImportListComponent extends BaseImportListComponent<ViewMotio
|
|||||||
*/
|
*/
|
||||||
public getLongPreview(input: string): string {
|
public getLongPreview(input: string): string {
|
||||||
if (input.length < 300) {
|
if (input.length < 300) {
|
||||||
return this.stripHtmlTags(input);
|
return stripHtmlTags(input);
|
||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
this.stripHtmlTags(input.substring(0, 147)) +
|
stripHtmlTags(input.substring(0, 147)) +
|
||||||
' [...] ' +
|
' [...] ' +
|
||||||
this.stripHtmlTags(input.substring(input.length - 150, input.length))
|
stripHtmlTags(input.substring(input.length - 150, input.length))
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Helper to remove html tags from a string.
|
|
||||||
* CAUTION: It is just a basic "don't show distracting html tags in a
|
|
||||||
* preview", not an actual tested sanitizer!
|
|
||||||
* @param inputString
|
|
||||||
*/
|
|
||||||
private stripHtmlTags(inputString: string): string {
|
|
||||||
const regexp = new RegExp(/<[^ ][^<>]*(>|$)/g);
|
|
||||||
return inputString.replace(regexp, '').trim();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Triggers an example csv download
|
* Triggers an example csv download
|
||||||
*/
|
*/
|
||||||
|
@ -7,6 +7,7 @@ import { BaseImportListComponent } from 'app/site/base/base-import-list';
|
|||||||
import { ViewStatuteParagraph } from 'app/site/motions/models/view-statute-paragraph';
|
import { ViewStatuteParagraph } from 'app/site/motions/models/view-statute-paragraph';
|
||||||
import { StatuteImportService } from 'app/site/motions/services/statute-import.service';
|
import { StatuteImportService } from 'app/site/motions/services/statute-import.service';
|
||||||
import { StatuteCsvExportService } from 'app/site/motions/services/statute-csv-export.service';
|
import { StatuteCsvExportService } from 'app/site/motions/services/statute-csv-export.service';
|
||||||
|
import { stripHtmlTags } from 'app/shared/utils/strip-html-tags';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Component for the statute paragraphs import list view.
|
* Component for the statute paragraphs import list view.
|
||||||
@ -42,9 +43,9 @@ export class StatuteImportListComponent extends BaseImportListComponent<ViewStat
|
|||||||
*/
|
*/
|
||||||
public getShortPreview(input: string): string {
|
public getShortPreview(input: string): string {
|
||||||
if (input.length > 50) {
|
if (input.length > 50) {
|
||||||
return this.stripHtmlTags(input.substring(0, 47)) + '...';
|
return stripHtmlTags(input.substring(0, 47)) + '...';
|
||||||
}
|
}
|
||||||
return this.stripHtmlTags(input);
|
return stripHtmlTags(input);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -55,26 +56,15 @@ export class StatuteImportListComponent extends BaseImportListComponent<ViewStat
|
|||||||
*/
|
*/
|
||||||
public getLongPreview(input: string): string {
|
public getLongPreview(input: string): string {
|
||||||
if (input.length < 300) {
|
if (input.length < 300) {
|
||||||
return this.stripHtmlTags(input);
|
return stripHtmlTags(input);
|
||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
this.stripHtmlTags(input.substring(0, 147)) +
|
stripHtmlTags(input.substring(0, 147)) +
|
||||||
' [...] ' +
|
' [...] ' +
|
||||||
this.stripHtmlTags(input.substring(input.length - 150, input.length))
|
stripHtmlTags(input.substring(input.length - 150, input.length))
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Helper to remove html tags from a string.
|
|
||||||
* CAUTION: It is just a basic "don't show distracting html tags in a
|
|
||||||
* preview", not an actual tested sanitizer!
|
|
||||||
* @param inputString
|
|
||||||
*/
|
|
||||||
private stripHtmlTags(inputString: string): string {
|
|
||||||
const regexp = new RegExp(/<[^ ][^<>]*(>|$)/g);
|
|
||||||
return inputString.replace(regexp, '').trim();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Triggers an example csv download
|
* Triggers an example csv download
|
||||||
*/
|
*/
|
||||||
|
@ -580,7 +580,7 @@ export class ViewMotion extends BaseAgendaViewModel implements Searchable {
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
projectionDefaultName: 'motions',
|
projectionDefaultName: 'motions',
|
||||||
getTitle: () => this.identifier
|
getTitle: this.getAgendaTitle
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
import { Component, OnInit } from '@angular/core';
|
import { Component, OnInit } from '@angular/core';
|
||||||
import { Title } from '@angular/platform-browser';
|
import { Title } from '@angular/platform-browser';
|
||||||
|
import { MatSnackBar } from '@angular/material';
|
||||||
|
import { FormGroup, FormBuilder, Validators } from '@angular/forms';
|
||||||
|
|
||||||
import { TranslateService } from '@ngx-translate/core';
|
import { TranslateService } from '@ngx-translate/core';
|
||||||
|
|
||||||
import { FormGroup, FormBuilder, Validators } from '@angular/forms';
|
|
||||||
import { PromptService } from 'app/core/ui-services/prompt.service';
|
import { PromptService } from 'app/core/ui-services/prompt.service';
|
||||||
import { BaseViewComponent } from '../../../base/base-view';
|
import { BaseViewComponent } from '../../../base/base-view';
|
||||||
import { MatSnackBar } from '@angular/material';
|
|
||||||
import { ViewCountdown } from '../../models/view-countdown';
|
import { ViewCountdown } from '../../models/view-countdown';
|
||||||
import { CountdownRepositoryService } from 'app/core/repositories/projector/countdown-repository.service';
|
import { CountdownRepositoryService } from 'app/core/repositories/projector/countdown-repository.service';
|
||||||
import { Countdown } from 'app/shared/models/core/countdown';
|
import { Countdown } from 'app/shared/models/core/countdown';
|
||||||
|
@ -7,11 +7,14 @@
|
|||||||
|
|
||||||
<div class="content-container" *ngIf="projector">
|
<div class="content-container" *ngIf="projector">
|
||||||
<div class="column-left">
|
<div class="column-left">
|
||||||
<a [routerLink]="['/projector', projector.id]">
|
<!--<a [routerLink]="['/projector', projector.id]">
|
||||||
<div id="projector">
|
<div id="projector">
|
||||||
<os-projector [projector]="projector"></os-projector>
|
<os-projector [projector]="projector"></os-projector>
|
||||||
</div>
|
</div>
|
||||||
</a>
|
</a>-->
|
||||||
|
<div id="projector">
|
||||||
|
<os-projector [projector]="projector"></os-projector>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="column-right" *osPerms="'core.can_manage_projector'">
|
<div class="column-right" *osPerms="'core.can_manage_projector'">
|
||||||
<div class="control-group">
|
<div class="control-group">
|
||||||
@ -75,7 +78,7 @@
|
|||||||
<div *ngIf="countdowns.length">
|
<div *ngIf="countdowns.length">
|
||||||
<h4>
|
<h4>
|
||||||
<span translate>Countdowns</span>
|
<span translate>Countdowns</span>
|
||||||
<button type="button" mat-icon-button disableRipple routerLink="/countdowns">
|
<button type="button" mat-icon-button disableRipple routerLink="/projectors/countdowns">
|
||||||
<mat-icon>edit</mat-icon>
|
<mat-icon>edit</mat-icon>
|
||||||
</button>
|
</button>
|
||||||
</h4>
|
</h4>
|
||||||
@ -92,16 +95,16 @@
|
|||||||
<div *ngIf="messages.length">
|
<div *ngIf="messages.length">
|
||||||
<h4>
|
<h4>
|
||||||
<span translate>Messages</span>
|
<span translate>Messages</span>
|
||||||
<button type="button" mat-icon-button disableRipple routerLink="/messages">
|
<button type="button" mat-icon-button disableRipple routerLink="/projectors/messages">
|
||||||
<mat-icon>edit</mat-icon>
|
<mat-icon>edit</mat-icon>
|
||||||
</button>
|
</button>
|
||||||
</h4>
|
</h4>
|
||||||
<mat-list>
|
<mat-list>
|
||||||
<mat-list-item *ngFor="let message of messages; let i = index" [ngClass]="{'projected': isProjected(message)}">
|
<mat-list-item *ngFor="let message of messages" [ngClass]="{'projected': isProjected(message)}">
|
||||||
<button type="button" mat-icon-button (click)="project(message)">
|
<button type="button" mat-icon-button (click)="project(message)">
|
||||||
<mat-icon>videocam</mat-icon>
|
<mat-icon>videocam</mat-icon>
|
||||||
</button>
|
</button>
|
||||||
<span translate>Message</span> {{ i + 1 }}
|
<span translate>{{ message.getPreview(40) }}</span>
|
||||||
</mat-list-item>
|
</mat-list-item>
|
||||||
</mat-list>
|
</mat-list>
|
||||||
</div>
|
</div>
|
||||||
|
@ -16,8 +16,8 @@ import { moveItemInArray, CdkDragDrop } from '@angular/cdk/drag-drop';
|
|||||||
import { ProjectorElement } from 'app/shared/models/core/projector';
|
import { ProjectorElement } from 'app/shared/models/core/projector';
|
||||||
import { SlideManager } from 'app/slides/services/slide-manager.service';
|
import { SlideManager } from 'app/slides/services/slide-manager.service';
|
||||||
import { CountdownRepositoryService } from 'app/core/repositories/projector/countdown-repository.service';
|
import { CountdownRepositoryService } from 'app/core/repositories/projector/countdown-repository.service';
|
||||||
import { ProjectorMessageRepositoryService } from 'app/core/repositories/projector/projectormessage-repository.service';
|
import { ProjectorMessageRepositoryService } from 'app/core/repositories/projector/projector-message-repository.service';
|
||||||
import { ViewProjectorMessage } from 'app/site/projector/models/view-projectormessage';
|
import { ViewProjectorMessage } from 'app/site/projector/models/view-projector-message';
|
||||||
import { ViewCountdown } from 'app/site/projector/models/view-countdown';
|
import { ViewCountdown } from 'app/site/projector/models/view-countdown';
|
||||||
import { Projectable } from 'app/site/base/projectable';
|
import { Projectable } from 'app/site/base/projectable';
|
||||||
import { CurrentListOfSpeakersSlideService } from '../../services/current-list-of-of-speakers-slide.service';
|
import { CurrentListOfSpeakersSlideService } from '../../services/current-list-of-of-speakers-slide.service';
|
||||||
@ -121,7 +121,7 @@ export class ProjectorDetailComponent extends BaseViewComponent implements OnIni
|
|||||||
const idElement = this.slideManager.getIdentifialbeProjectorElement(element);
|
const idElement = this.slideManager.getIdentifialbeProjectorElement(element);
|
||||||
const viewModel = this.projectorService.getViewModelFromProjectorElement(idElement);
|
const viewModel = this.projectorService.getViewModelFromProjectorElement(idElement);
|
||||||
if (viewModel) {
|
if (viewModel) {
|
||||||
return viewModel.getTitle();
|
return viewModel.getProjectorTitle();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -111,12 +111,12 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<mat-menu #ellipsisMenu="matMenu">
|
<mat-menu #ellipsisMenu="matMenu">
|
||||||
<button mat-menu-item routerLink="/projectors/countdowns">
|
<button type="button" mat-menu-item routerLink="/projectors/messages">
|
||||||
<mat-icon>alarm</mat-icon>
|
|
||||||
<span translate>Countdowns</span>
|
|
||||||
</button>
|
|
||||||
<button mat-menu-item>
|
|
||||||
<mat-icon>note</mat-icon>
|
<mat-icon>note</mat-icon>
|
||||||
<span translate>Projector messages</span>
|
<span translate>Projector messages</span>
|
||||||
</button>
|
</button>
|
||||||
|
<button type="button" mat-menu-item routerLink="/projectors/countdowns">
|
||||||
|
<mat-icon>alarm</mat-icon>
|
||||||
|
<span translate>Countdowns</span>
|
||||||
|
</button>
|
||||||
</mat-menu>
|
</mat-menu>
|
||||||
|
@ -0,0 +1,83 @@
|
|||||||
|
<os-head-bar [nav]="false" [goBack]="true" [mainButton]="true" (mainEvent)="onPlusButton()">
|
||||||
|
<!-- Title -->
|
||||||
|
<div class="title-slot">
|
||||||
|
<h2 translate>Messages</h2>
|
||||||
|
</div>
|
||||||
|
</os-head-bar>
|
||||||
|
|
||||||
|
<div class="head-spacer"></div>
|
||||||
|
<mat-card *ngIf="messageToCreate">
|
||||||
|
<mat-card-title translate>New message</mat-card-title>
|
||||||
|
<mat-card-content>
|
||||||
|
<form [formGroup]="createForm"
|
||||||
|
(keydown)="onKeyDownCreate($event)">
|
||||||
|
<p>
|
||||||
|
<editor formControlName="message" [init]="tinyMceSettings"></editor>
|
||||||
|
</p>
|
||||||
|
</form>
|
||||||
|
</mat-card-content>
|
||||||
|
<mat-card-actions>
|
||||||
|
<button mat-button (click)="create()">
|
||||||
|
<span translate>Save</span>
|
||||||
|
</button>
|
||||||
|
<button mat-button (click)="onCancelCreate()">
|
||||||
|
<span translate>Cancel</span>
|
||||||
|
</button>
|
||||||
|
</mat-card-actions>
|
||||||
|
</mat-card>
|
||||||
|
|
||||||
|
<mat-accordion class="os-card">
|
||||||
|
<mat-expansion-panel *ngFor="let message of messages" (opened)="openId = message.id"
|
||||||
|
(closed)="panelClosed(message)" [expanded]="openId === message.id" multiple="false">
|
||||||
|
|
||||||
|
<!-- Projector button and countdown description-->
|
||||||
|
<mat-expansion-panel-header>
|
||||||
|
<mat-panel-title>
|
||||||
|
<div class="header-container">
|
||||||
|
<div class="header-projector-button">
|
||||||
|
<os-projector-button [object]="message"></os-projector-button>
|
||||||
|
</div>
|
||||||
|
<div class="header-name">
|
||||||
|
{{ message.getPreview() }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</mat-panel-title>
|
||||||
|
</mat-expansion-panel-header>
|
||||||
|
<form [formGroup]="updateForm"
|
||||||
|
*ngIf="editId === message.id"
|
||||||
|
(keydown)="onKeyDownUpdate($event)">
|
||||||
|
<h5 translate>Edit message</h5>
|
||||||
|
<p>
|
||||||
|
<editor formControlName="message" [init]="tinyMceSettings"></editor>
|
||||||
|
</p>
|
||||||
|
</form>
|
||||||
|
<ng-container *ngIf="editId !== message.id">
|
||||||
|
<div class="message" *ngIf="message.message" [innerHTML]="getSafeMessage(message)"></div>
|
||||||
|
<div *ngIf="!message.message" class="no-content" translate>No message</div>
|
||||||
|
</ng-container>
|
||||||
|
<mat-action-row>
|
||||||
|
<button *ngIf="editId !== message.id" mat-button class="on-transition-fade" (click)="onEditButton(message)"
|
||||||
|
mat-icon-button>
|
||||||
|
<mat-icon>edit</mat-icon>
|
||||||
|
</button>
|
||||||
|
<button *ngIf="editId === message.id" mat-button class="on-transition-fade" (click)="onCancelUpdate()"
|
||||||
|
mat-icon-button>
|
||||||
|
<mat-icon>close</mat-icon>
|
||||||
|
</button>
|
||||||
|
<button *ngIf="editId === message.id" mat-button class="on-transition-fade" (click)="onSaveButton(message)"
|
||||||
|
mat-icon-button>
|
||||||
|
<mat-icon>save</mat-icon>
|
||||||
|
</button>
|
||||||
|
<button mat-button class='on-transition-fade' (click)=onDeleteButton(message) mat-icon-button>
|
||||||
|
<mat-icon>delete</mat-icon>
|
||||||
|
</button>
|
||||||
|
</mat-action-row>
|
||||||
|
</mat-expansion-panel>
|
||||||
|
</mat-accordion>
|
||||||
|
|
||||||
|
<mat-card *ngIf="messages.length === 0">
|
||||||
|
<mat-card-content>
|
||||||
|
<div class="no-content" translate>No messages</div>
|
||||||
|
</mat-card-content>
|
||||||
|
</mat-card>
|
@ -0,0 +1,42 @@
|
|||||||
|
.head-spacer {
|
||||||
|
width: 100%;
|
||||||
|
height: 60px;
|
||||||
|
line-height: 60px;
|
||||||
|
text-align: right;
|
||||||
|
background: white; /* TODO: remove this and replace with theme */
|
||||||
|
border-bottom: 1px solid rgba(0, 0, 0, 0.12);
|
||||||
|
}
|
||||||
|
|
||||||
|
mat-card {
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header-container {
|
||||||
|
display: grid;
|
||||||
|
grid-template-rows: auto;
|
||||||
|
grid-template-columns: 40px 1fr;
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
|
> div {
|
||||||
|
grid-row-start: 1;
|
||||||
|
grid-row-end: span 1;
|
||||||
|
grid-column-end: span 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header-projector-button {
|
||||||
|
grid-column-start: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header-name {
|
||||||
|
grid-column-start: 2;
|
||||||
|
padding: 10px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.message {
|
||||||
|
text-align: center;
|
||||||
|
|
||||||
|
::ng-deep p {
|
||||||
|
margin: 0 0 10px;
|
||||||
|
}
|
||||||
|
}
|
@ -1,7 +1,7 @@
|
|||||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
import { E2EImportsModule } from 'e2e-imports.module';
|
import { E2EImportsModule } from 'e2e-imports.module';
|
||||||
import { ProjectorMessageListComponent } from './projectormessage-list.component';
|
import { ProjectorMessageListComponent } from './projector-message-list.component';
|
||||||
|
|
||||||
describe('CountdownListComponent', () => {
|
describe('CountdownListComponent', () => {
|
||||||
let component: ProjectorMessageListComponent;
|
let component: ProjectorMessageListComponent;
|
@ -0,0 +1,192 @@
|
|||||||
|
import { Component, OnInit } from '@angular/core';
|
||||||
|
import { Title, SafeHtml, DomSanitizer } from '@angular/platform-browser';
|
||||||
|
import { MatSnackBar } from '@angular/material';
|
||||||
|
import { FormGroup, FormBuilder } from '@angular/forms';
|
||||||
|
|
||||||
|
import { TranslateService } from '@ngx-translate/core';
|
||||||
|
|
||||||
|
import { BaseViewComponent } from '../../../base/base-view';
|
||||||
|
import { ProjectorMessage } from 'app/shared/models/core/projector-message';
|
||||||
|
import { ViewProjectorMessage } from '../../models/view-projector-message';
|
||||||
|
import { ProjectorMessageRepositoryService } from 'app/core/repositories/projector/projector-message-repository.service';
|
||||||
|
import { PromptService } from 'app/core/ui-services/prompt.service';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* List view for the projector messages.
|
||||||
|
*/
|
||||||
|
@Component({
|
||||||
|
selector: 'os-projector-message-list',
|
||||||
|
templateUrl: './projector-message-list.component.html',
|
||||||
|
styleUrls: ['./projector-message-list.component.scss']
|
||||||
|
})
|
||||||
|
export class ProjectorMessageListComponent extends BaseViewComponent implements OnInit {
|
||||||
|
public messageToCreate: ProjectorMessage | null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Source of the Data
|
||||||
|
*/
|
||||||
|
public messages: ViewProjectorMessage[] = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The current focussed formgroup
|
||||||
|
*/
|
||||||
|
public updateForm: FormGroup;
|
||||||
|
|
||||||
|
public createForm: FormGroup;
|
||||||
|
|
||||||
|
public openId: number | null;
|
||||||
|
public editId: number | null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*/
|
||||||
|
public constructor(
|
||||||
|
titleService: Title,
|
||||||
|
translate: TranslateService,
|
||||||
|
matSnackBar: MatSnackBar,
|
||||||
|
private repo: ProjectorMessageRepositoryService,
|
||||||
|
private formBuilder: FormBuilder,
|
||||||
|
private promptService: PromptService,
|
||||||
|
private santinizer: DomSanitizer
|
||||||
|
) {
|
||||||
|
super(titleService, translate, matSnackBar);
|
||||||
|
|
||||||
|
const form = {
|
||||||
|
message: ['']
|
||||||
|
};
|
||||||
|
this.createForm = this.formBuilder.group(form);
|
||||||
|
this.updateForm = this.formBuilder.group(form);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Init function.
|
||||||
|
*
|
||||||
|
* Sets the title and gets/observes messages from DataStore
|
||||||
|
*/
|
||||||
|
public ngOnInit(): void {
|
||||||
|
super.setTitle('Messages');
|
||||||
|
this.messages = this.repo.getViewModelList();
|
||||||
|
this.repo.getViewModelListObservable().subscribe(messages => (this.messages = messages));
|
||||||
|
}
|
||||||
|
|
||||||
|
public getSafeMessage(message: ViewProjectorMessage): SafeHtml {
|
||||||
|
return this.santinizer.bypassSecurityTrustHtml(message.message);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a new message.
|
||||||
|
*/
|
||||||
|
public onPlusButton(): void {
|
||||||
|
if (!this.messageToCreate) {
|
||||||
|
this.createForm.reset();
|
||||||
|
this.createForm.setValue({
|
||||||
|
message: ''
|
||||||
|
});
|
||||||
|
this.messageToCreate = new ProjectorMessage();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handler when clicking on create to create a new statute paragraph
|
||||||
|
*/
|
||||||
|
public create(): void {
|
||||||
|
if (this.createForm.valid) {
|
||||||
|
this.messageToCreate.patchValues(this.createForm.value as ProjectorMessage);
|
||||||
|
this.repo.create(this.messageToCreate).then(() => {
|
||||||
|
this.messageToCreate = null;
|
||||||
|
}, this.raiseError);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Executed on edit button
|
||||||
|
* @param message
|
||||||
|
*/
|
||||||
|
public onEditButton(message: ViewProjectorMessage): void {
|
||||||
|
this.editId = message.id;
|
||||||
|
|
||||||
|
this.updateForm.setValue({
|
||||||
|
message: message.message
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Saves the message
|
||||||
|
* @param message The message to save
|
||||||
|
*/
|
||||||
|
public onSaveButton(message: ViewProjectorMessage): void {
|
||||||
|
if (this.updateForm.valid) {
|
||||||
|
this.repo.update(this.updateForm.value as Partial<ProjectorMessage>, message).then(() => {
|
||||||
|
this.openId = this.editId = null;
|
||||||
|
}, this.raiseError);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Is executed, when the delete button is pressed
|
||||||
|
*
|
||||||
|
* @param message The message to delete
|
||||||
|
*/
|
||||||
|
public async onDeleteButton(message: ViewProjectorMessage): Promise<void> {
|
||||||
|
const content = this.translate.instant('Delete this message?');
|
||||||
|
if (await this.promptService.open('Are you sure?', content)) {
|
||||||
|
this.repo.delete(message).then(() => (this.openId = this.editId = null), this.raiseError);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Is executed when a mat-extension-panel is closed
|
||||||
|
*
|
||||||
|
* @param message the message in the panel
|
||||||
|
*/
|
||||||
|
public panelClosed(message: ViewProjectorMessage): void {
|
||||||
|
this.openId = null;
|
||||||
|
if (this.editId) {
|
||||||
|
this.onSaveButton(message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* clicking Shift and Enter will save automatically
|
||||||
|
* clicking Escape will cancel the process
|
||||||
|
*
|
||||||
|
* @param event has the code
|
||||||
|
*/
|
||||||
|
public onKeyDownCreate(event: KeyboardEvent): void {
|
||||||
|
if (event.key === 'Enter' && event.shiftKey) {
|
||||||
|
this.create();
|
||||||
|
}
|
||||||
|
if (event.key === 'Escape') {
|
||||||
|
this.onCancelCreate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cancels the current form action
|
||||||
|
*/
|
||||||
|
public onCancelCreate(): void {
|
||||||
|
this.messageToCreate = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* clicking Shift and Enter will save automatically
|
||||||
|
* clicking Escape will cancel the process
|
||||||
|
*
|
||||||
|
* @param event has the code
|
||||||
|
*/
|
||||||
|
public onKeyDownUpdate(event: KeyboardEvent): void {
|
||||||
|
if (event.key === 'Enter' && event.shiftKey) {
|
||||||
|
const message = this.messages.find(x => x.id === this.editId);
|
||||||
|
this.onSaveButton(message);
|
||||||
|
}
|
||||||
|
if (event.key === 'Escape') {
|
||||||
|
this.onCancelUpdate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cancels the current form action
|
||||||
|
*/
|
||||||
|
public onCancelUpdate(): void {
|
||||||
|
this.editId = null;
|
||||||
|
}
|
||||||
|
}
|
@ -1,9 +0,0 @@
|
|||||||
<os-head-bar [nav]="false" [goBack]="true" [mainButton]="true" (mainEvent)="onPlusButton()">
|
|
||||||
<!-- Title -->
|
|
||||||
<div class="title-slot">
|
|
||||||
<h2 translate>Messages</h2>
|
|
||||||
</div>
|
|
||||||
</os-head-bar>
|
|
||||||
|
|
||||||
<div class="head-spacer"></div>
|
|
||||||
<p>TODO</p>
|
|
@ -1,32 +0,0 @@
|
|||||||
import { Component, OnInit } from '@angular/core';
|
|
||||||
import { Title } from '@angular/platform-browser';
|
|
||||||
|
|
||||||
import { TranslateService } from '@ngx-translate/core';
|
|
||||||
|
|
||||||
import { BaseViewComponent } from '../../../base/base-view';
|
|
||||||
import { MatSnackBar } from '@angular/material';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* List view for the projector messages.
|
|
||||||
*/
|
|
||||||
@Component({
|
|
||||||
selector: 'os-projectormessage-list',
|
|
||||||
templateUrl: './projectormessage-list.component.html',
|
|
||||||
styleUrls: ['./projectormessage-list.component.scss']
|
|
||||||
})
|
|
||||||
export class ProjectorMessageListComponent extends BaseViewComponent implements OnInit {
|
|
||||||
public constructor(titleService: Title, translate: TranslateService, matSnackBar: MatSnackBar) {
|
|
||||||
super(titleService, translate, matSnackBar);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Init function.
|
|
||||||
*
|
|
||||||
* Sets the title and gets/observes messages from DataStore
|
|
||||||
*/
|
|
||||||
public ngOnInit(): void {
|
|
||||||
super.setTitle('Messages');
|
|
||||||
}
|
|
||||||
|
|
||||||
public onPlusButton(): void {}
|
|
||||||
}
|
|
@ -2,22 +2,23 @@ import { BaseProjectableViewModel } from 'app/site/base/base-projectable-view-mo
|
|||||||
import { ProjectorElementBuildDeskriptor } from 'app/site/base/projectable';
|
import { ProjectorElementBuildDeskriptor } from 'app/site/base/projectable';
|
||||||
import { ProjectorMessage } from 'app/shared/models/core/projector-message';
|
import { ProjectorMessage } from 'app/shared/models/core/projector-message';
|
||||||
import { BaseViewModel } from 'app/site/base/base-view-model';
|
import { BaseViewModel } from 'app/site/base/base-view-model';
|
||||||
|
import { stripHtmlTags } from 'app/shared/utils/strip-html-tags';
|
||||||
|
|
||||||
export class ViewProjectorMessage extends BaseProjectableViewModel {
|
export class ViewProjectorMessage extends BaseProjectableViewModel {
|
||||||
public static COLLECTIONSTRING = ProjectorMessage.COLLECTIONSTRING;
|
public static COLLECTIONSTRING = ProjectorMessage.COLLECTIONSTRING;
|
||||||
|
|
||||||
private _message: ProjectorMessage;
|
private _message: ProjectorMessage;
|
||||||
|
|
||||||
public get projctormessage(): ProjectorMessage {
|
public get projectormessage(): ProjectorMessage {
|
||||||
return this._message;
|
return this._message;
|
||||||
}
|
}
|
||||||
|
|
||||||
public get id(): number {
|
public get id(): number {
|
||||||
return this.projctormessage.id;
|
return this.projectormessage.id;
|
||||||
}
|
}
|
||||||
|
|
||||||
public get message(): string {
|
public get message(): string {
|
||||||
return this.projctormessage.message;
|
return this.projectormessage.message;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -49,4 +50,13 @@ export class ViewProjectorMessage extends BaseProjectableViewModel {
|
|||||||
getTitle: () => this.getTitle()
|
getTitle: () => this.getTitle()
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public getPreview(maxLength: number = 100): string {
|
||||||
|
const html = stripHtmlTags(this.message);
|
||||||
|
if (html.length > maxLength) {
|
||||||
|
return html.substring(0, maxLength) + ' ...';
|
||||||
|
} else {
|
||||||
|
return html;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
@ -3,7 +3,7 @@ import { Routes, RouterModule } from '@angular/router';
|
|||||||
import { ProjectorListComponent } from './components/projector-list/projector-list.component';
|
import { ProjectorListComponent } from './components/projector-list/projector-list.component';
|
||||||
import { ProjectorDetailComponent } from './components/projector-detail/projector-detail.component';
|
import { ProjectorDetailComponent } from './components/projector-detail/projector-detail.component';
|
||||||
import { CountdownListComponent } from './components/countdown-list/countdown-list.component';
|
import { CountdownListComponent } from './components/countdown-list/countdown-list.component';
|
||||||
import { ProjectorMessageListComponent } from './components/projectormessage-list/projectormessage-list.component';
|
import { ProjectorMessageListComponent } from './components/projector-message-list/projector-message-list.component';
|
||||||
|
|
||||||
const routes: Routes = [
|
const routes: Routes = [
|
||||||
{
|
{
|
||||||
|
@ -4,10 +4,10 @@ import { Countdown } from 'app/shared/models/core/countdown';
|
|||||||
import { ProjectorMessage } from 'app/shared/models/core/projector-message';
|
import { ProjectorMessage } from 'app/shared/models/core/projector-message';
|
||||||
import { ProjectorRepositoryService } from 'app/core/repositories/projector/projector-repository.service';
|
import { ProjectorRepositoryService } from 'app/core/repositories/projector/projector-repository.service';
|
||||||
import { CountdownRepositoryService } from 'app/core/repositories/projector/countdown-repository.service';
|
import { CountdownRepositoryService } from 'app/core/repositories/projector/countdown-repository.service';
|
||||||
import { ProjectorMessageRepositoryService } from 'app/core/repositories/projector/projectormessage-repository.service';
|
import { ProjectorMessageRepositoryService } from 'app/core/repositories/projector/projector-message-repository.service';
|
||||||
import { ViewProjector } from './models/view-projector';
|
import { ViewProjector } from './models/view-projector';
|
||||||
import { ViewCountdown } from './models/view-countdown';
|
import { ViewCountdown } from './models/view-countdown';
|
||||||
import { ViewProjectorMessage } from './models/view-projectormessage';
|
import { ViewProjectorMessage } from './models/view-projector-message';
|
||||||
|
|
||||||
export const ProjectorAppConfig: AppConfig = {
|
export const ProjectorAppConfig: AppConfig = {
|
||||||
name: 'projector',
|
name: 'projector',
|
||||||
|
@ -9,7 +9,7 @@ import { ClockSlideService } from './services/clock-slide.service';
|
|||||||
import { ProjectorDataService } from './services/projector-data.service';
|
import { ProjectorDataService } from './services/projector-data.service';
|
||||||
import { CurrentListOfSpeakersSlideService } from './services/current-list-of-of-speakers-slide.service';
|
import { CurrentListOfSpeakersSlideService } from './services/current-list-of-of-speakers-slide.service';
|
||||||
import { CountdownListComponent } from './components/countdown-list/countdown-list.component';
|
import { CountdownListComponent } from './components/countdown-list/countdown-list.component';
|
||||||
import { ProjectorMessageListComponent } from './components/projectormessage-list/projectormessage-list.component';
|
import { ProjectorMessageListComponent } from './components/projector-message-list/projector-message-list.component';
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
providers: [ClockSlideService, ProjectorDataService, CurrentListOfSpeakersSlideService],
|
providers: [ClockSlideService, ProjectorDataService, CurrentListOfSpeakersSlideService],
|
||||||
|
@ -41,7 +41,7 @@ export const allSlides: SlideManifest[] = [
|
|||||||
{
|
{
|
||||||
slide: 'core/clock',
|
slide: 'core/clock',
|
||||||
path: 'core/clock',
|
path: 'core/clock',
|
||||||
loadChildren: './slides/core/clock/core-clock-slide.module#CoreClockSlideModule',
|
loadChildren: './slides/core/clock/clock-slide.module#ClockSlideModule',
|
||||||
scaleable: false,
|
scaleable: false,
|
||||||
scrollable: false,
|
scrollable: false,
|
||||||
verboseName: 'Clock',
|
verboseName: 'Clock',
|
||||||
@ -51,13 +51,23 @@ export const allSlides: SlideManifest[] = [
|
|||||||
{
|
{
|
||||||
slide: 'core/countdown',
|
slide: 'core/countdown',
|
||||||
path: 'core/countdown',
|
path: 'core/countdown',
|
||||||
loadChildren: './slides/core/countdown/core-countdown-slide.module#CoreCountdownSlideModule',
|
loadChildren: './slides/core/countdown/countdown-slide.module#CountdownSlideModule',
|
||||||
scaleable: false,
|
scaleable: false,
|
||||||
scrollable: false,
|
scrollable: false,
|
||||||
verboseName: 'Countdown',
|
verboseName: 'Countdown',
|
||||||
elementIdentifiers: ['name', 'id'],
|
elementIdentifiers: ['name', 'id'],
|
||||||
canBeMappedToModel: true
|
canBeMappedToModel: true
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
slide: 'core/projector-message',
|
||||||
|
path: 'core/projector-message',
|
||||||
|
loadChildren: './slides/core/projector-message/projector-message-slide.module#ProjectorMessageSlideModule',
|
||||||
|
scaleable: false,
|
||||||
|
scrollable: false,
|
||||||
|
verboseName: 'Message',
|
||||||
|
elementIdentifiers: ['name', 'id'],
|
||||||
|
canBeMappedToModel: true
|
||||||
|
},
|
||||||
{
|
{
|
||||||
slide: 'agenda/current-list-of-speakers',
|
slide: 'agenda/current-list-of-speakers',
|
||||||
path: 'agenda/current-list-of-speakers',
|
path: 'agenda/current-list-of-speakers',
|
||||||
@ -79,5 +89,15 @@ export const allSlides: SlideManifest[] = [
|
|||||||
verboseName: 'Current list of speakers overlay',
|
verboseName: 'Current list of speakers overlay',
|
||||||
elementIdentifiers: ['name', 'id'],
|
elementIdentifiers: ['name', 'id'],
|
||||||
canBeMappedToModel: false
|
canBeMappedToModel: false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
slide: 'assignments/assignment',
|
||||||
|
path: 'assignments/assignment',
|
||||||
|
loadChildren: './slides/assignments/assignment/assignment-slide.module#AssignmentSlideModule',
|
||||||
|
scaleable: true,
|
||||||
|
scrollable: true,
|
||||||
|
verboseName: 'Election',
|
||||||
|
elementIdentifiers: ['name', 'id'],
|
||||||
|
canBeMappedToModel: true
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
@ -0,0 +1,3 @@
|
|||||||
|
export interface AssignmentSlideData {
|
||||||
|
user: string;
|
||||||
|
}
|
@ -0,0 +1,3 @@
|
|||||||
|
<div *ngIf="data">
|
||||||
|
<h1>TODO</h1>
|
||||||
|
</div>
|
@ -1,21 +1,21 @@
|
|||||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
import { CoreCountdownSlideComponent } from './core-countdown-slide.component';
|
import { AssignmentSlideComponent } from './assignment-slide.component';
|
||||||
import { E2EImportsModule } from '../../../../e2e-imports.module';
|
import { E2EImportsModule } from '../../../../e2e-imports.module';
|
||||||
|
|
||||||
describe('CoreCountdownSlideComponent', () => {
|
describe('AssignmentSlideComponent', () => {
|
||||||
let component: CoreCountdownSlideComponent;
|
let component: AssignmentSlideComponent;
|
||||||
let fixture: ComponentFixture<CoreCountdownSlideComponent>;
|
let fixture: ComponentFixture<AssignmentSlideComponent>;
|
||||||
|
|
||||||
beforeEach(async(() => {
|
beforeEach(async(() => {
|
||||||
TestBed.configureTestingModule({
|
TestBed.configureTestingModule({
|
||||||
imports: [E2EImportsModule],
|
imports: [E2EImportsModule],
|
||||||
declarations: [CoreCountdownSlideComponent]
|
declarations: [AssignmentSlideComponent]
|
||||||
}).compileComponents();
|
}).compileComponents();
|
||||||
}));
|
}));
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
fixture = TestBed.createComponent(CoreCountdownSlideComponent);
|
fixture = TestBed.createComponent(AssignmentSlideComponent);
|
||||||
component = fixture.componentInstance;
|
component = fixture.componentInstance;
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
});
|
});
|
@ -0,0 +1,15 @@
|
|||||||
|
import { Component } from '@angular/core';
|
||||||
|
|
||||||
|
import { BaseSlideComponent } from 'app/slides/base-slide-component';
|
||||||
|
import { AssignmentSlideData } from './assignment-slide-data';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'os-assignment-slide',
|
||||||
|
templateUrl: './assignment-slide.component.html',
|
||||||
|
styleUrls: ['./assignment-slide.component.scss']
|
||||||
|
})
|
||||||
|
export class AssignmentSlideComponent extends BaseSlideComponent<AssignmentSlideData> {
|
||||||
|
public constructor() {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,13 @@
|
|||||||
|
import { AssignmentSlideModule } from './assignment-slide.module';
|
||||||
|
|
||||||
|
describe('UsersUserSlideModule', () => {
|
||||||
|
let usersUserSlideModule: AssignmentSlideModule;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
usersUserSlideModule = new AssignmentSlideModule();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create an instance', () => {
|
||||||
|
expect(usersUserSlideModule).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
@ -0,0 +1,7 @@
|
|||||||
|
import { NgModule } from '@angular/core';
|
||||||
|
|
||||||
|
import { makeSlideModule } from 'app/slides/base-slide-module';
|
||||||
|
import { AssignmentSlideComponent } from './assignment-slide.component';
|
||||||
|
|
||||||
|
@NgModule(makeSlideModule(AssignmentSlideComponent))
|
||||||
|
export class AssignmentSlideModule {}
|
@ -0,0 +1,26 @@
|
|||||||
|
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
|
import { ClockSlideComponent } from './clock-slide.component';
|
||||||
|
import { E2EImportsModule } from '../../../../e2e-imports.module';
|
||||||
|
|
||||||
|
describe('ClockSlideComponent', () => {
|
||||||
|
let component: ClockSlideComponent;
|
||||||
|
let fixture: ComponentFixture<ClockSlideComponent>;
|
||||||
|
|
||||||
|
beforeEach(async(() => {
|
||||||
|
TestBed.configureTestingModule({
|
||||||
|
imports: [E2EImportsModule],
|
||||||
|
declarations: [ClockSlideComponent]
|
||||||
|
}).compileComponents();
|
||||||
|
}));
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
fixture = TestBed.createComponent(ClockSlideComponent);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create', () => {
|
||||||
|
expect(component).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
@ -1,14 +1,16 @@
|
|||||||
import { Component, OnInit, OnDestroy } from '@angular/core';
|
import { Component, OnInit, OnDestroy } from '@angular/core';
|
||||||
import { BaseSlideComponent } from 'app/slides/base-slide-component';
|
|
||||||
import { ServertimeService } from 'app/core/core-services/servertime.service';
|
|
||||||
import { Subscription } from 'rxjs';
|
import { Subscription } from 'rxjs';
|
||||||
|
|
||||||
|
import { BaseSlideComponent } from 'app/slides/base-slide-component';
|
||||||
|
import { ServertimeService } from 'app/core/core-services/servertime.service';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'os-core-clock-slide',
|
selector: 'os-clock-slide',
|
||||||
templateUrl: './core-clock-slide.component.html',
|
templateUrl: './clock-slide.component.html',
|
||||||
styleUrls: ['./core-clock-slide.component.scss']
|
styleUrls: ['./clock-slide.component.scss']
|
||||||
})
|
})
|
||||||
export class CoreClockSlideComponent extends BaseSlideComponent<{}> implements OnInit, OnDestroy {
|
export class ClockSlideComponent extends BaseSlideComponent<{}> implements OnInit, OnDestroy {
|
||||||
public time: string;
|
public time: string;
|
||||||
|
|
||||||
private servertimeSubscription: Subscription | null = null;
|
private servertimeSubscription: Subscription | null = null;
|
13
client/src/app/slides/core/clock/clock-slide.module.spec.ts
Normal file
13
client/src/app/slides/core/clock/clock-slide.module.spec.ts
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
import { ClockSlideModule } from './clock-slide.module';
|
||||||
|
|
||||||
|
describe('ClockSlideModule', () => {
|
||||||
|
let clockSlideModule: ClockSlideModule;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
clockSlideModule = new ClockSlideModule();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create an instance', () => {
|
||||||
|
expect(clockSlideModule).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
7
client/src/app/slides/core/clock/clock-slide.module.ts
Normal file
7
client/src/app/slides/core/clock/clock-slide.module.ts
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
import { NgModule } from '@angular/core';
|
||||||
|
|
||||||
|
import { makeSlideModule } from 'app/slides/base-slide-module';
|
||||||
|
import { ClockSlideComponent } from './clock-slide.component';
|
||||||
|
|
||||||
|
@NgModule(makeSlideModule(ClockSlideComponent))
|
||||||
|
export class ClockSlideModule {}
|
@ -1,13 +0,0 @@
|
|||||||
import { CoreClockSlideModule } from './core-clock-slide.module';
|
|
||||||
|
|
||||||
describe('CoreClockSlideModule', () => {
|
|
||||||
let coreClockSlideModule: CoreClockSlideModule;
|
|
||||||
|
|
||||||
beforeEach(() => {
|
|
||||||
coreClockSlideModule = new CoreClockSlideModule();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should create an instance', () => {
|
|
||||||
expect(coreClockSlideModule).toBeTruthy();
|
|
||||||
});
|
|
||||||
});
|
|
@ -1,7 +0,0 @@
|
|||||||
import { NgModule } from '@angular/core';
|
|
||||||
|
|
||||||
import { makeSlideModule } from 'app/slides/base-slide-module';
|
|
||||||
import { CoreClockSlideComponent } from './core-clock-slide.component';
|
|
||||||
|
|
||||||
@NgModule(makeSlideModule(CoreClockSlideComponent))
|
|
||||||
export class CoreClockSlideModule {}
|
|
@ -1,3 +0,0 @@
|
|||||||
export interface CoreCountdownSlideData {
|
|
||||||
error: string;
|
|
||||||
}
|
|
@ -1,14 +0,0 @@
|
|||||||
import { Component } from '@angular/core';
|
|
||||||
import { BaseSlideComponent } from 'app/slides/base-slide-component';
|
|
||||||
import { CoreCountdownSlideData } from './core-countdown-slide-data';
|
|
||||||
|
|
||||||
@Component({
|
|
||||||
selector: 'os-core-countdown-slide',
|
|
||||||
templateUrl: './core-countdown-slide.component.html',
|
|
||||||
styleUrls: ['./core-countdown-slide.component.scss']
|
|
||||||
})
|
|
||||||
export class CoreCountdownSlideComponent extends BaseSlideComponent<CoreCountdownSlideData> {
|
|
||||||
public constructor() {
|
|
||||||
super();
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,13 +0,0 @@
|
|||||||
import { CoreCountdownSlideModule } from './core-countdown-slide.module';
|
|
||||||
|
|
||||||
describe('CoreCountdownSlideModule', () => {
|
|
||||||
let coreCountdownSlideModule: CoreCountdownSlideModule;
|
|
||||||
|
|
||||||
beforeEach(() => {
|
|
||||||
coreCountdownSlideModule = new CoreCountdownSlideModule();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should create an instance', () => {
|
|
||||||
expect(CoreCountdownSlideModule).toBeTruthy();
|
|
||||||
});
|
|
||||||
});
|
|
@ -1,7 +0,0 @@
|
|||||||
import { NgModule } from '@angular/core';
|
|
||||||
|
|
||||||
import { makeSlideModule } from 'app/slides/base-slide-module';
|
|
||||||
import { CoreCountdownSlideComponent } from './core-countdown-slide.component';
|
|
||||||
|
|
||||||
@NgModule(makeSlideModule(CoreCountdownSlideComponent))
|
|
||||||
export class CoreCountdownSlideModule {}
|
|
@ -0,0 +1,3 @@
|
|||||||
|
export interface CountdownSlideData {
|
||||||
|
error: string;
|
||||||
|
}
|
@ -1,21 +1,21 @@
|
|||||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
import { CoreClockSlideComponent } from './core-clock-slide.component';
|
import { CountdownSlideComponent } from './countdown-slide.component';
|
||||||
import { E2EImportsModule } from '../../../../e2e-imports.module';
|
import { E2EImportsModule } from '../../../../e2e-imports.module';
|
||||||
|
|
||||||
describe('CoreClockSlideComponent', () => {
|
describe('CountdownSlideComponent', () => {
|
||||||
let component: CoreClockSlideComponent;
|
let component: CountdownSlideComponent;
|
||||||
let fixture: ComponentFixture<CoreClockSlideComponent>;
|
let fixture: ComponentFixture<CountdownSlideComponent>;
|
||||||
|
|
||||||
beforeEach(async(() => {
|
beforeEach(async(() => {
|
||||||
TestBed.configureTestingModule({
|
TestBed.configureTestingModule({
|
||||||
imports: [E2EImportsModule],
|
imports: [E2EImportsModule],
|
||||||
declarations: [CoreClockSlideComponent]
|
declarations: [CountdownSlideComponent]
|
||||||
}).compileComponents();
|
}).compileComponents();
|
||||||
}));
|
}));
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
fixture = TestBed.createComponent(CoreClockSlideComponent);
|
fixture = TestBed.createComponent(CountdownSlideComponent);
|
||||||
component = fixture.componentInstance;
|
component = fixture.componentInstance;
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
});
|
});
|
@ -0,0 +1,14 @@
|
|||||||
|
import { Component } from '@angular/core';
|
||||||
|
import { BaseSlideComponent } from 'app/slides/base-slide-component';
|
||||||
|
import { CountdownSlideData } from './countdown-slide-data';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'os-countdown-slide',
|
||||||
|
templateUrl: './countdown-slide.component.html',
|
||||||
|
styleUrls: ['./countdown-slide.component.scss']
|
||||||
|
})
|
||||||
|
export class CountdownSlideComponent extends BaseSlideComponent<CountdownSlideData> {
|
||||||
|
public constructor() {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,13 @@
|
|||||||
|
import { CountdownSlideModule } from './countdown-slide.module';
|
||||||
|
|
||||||
|
describe('CountdownSlideModule', () => {
|
||||||
|
let countdownSlideModule: CountdownSlideModule;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
countdownSlideModule = new CountdownSlideModule();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create an instance', () => {
|
||||||
|
expect(countdownSlideModule).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
@ -0,0 +1,7 @@
|
|||||||
|
import { NgModule } from '@angular/core';
|
||||||
|
|
||||||
|
import { makeSlideModule } from 'app/slides/base-slide-module';
|
||||||
|
import { CountdownSlideComponent } from './countdown-slide.component';
|
||||||
|
|
||||||
|
@NgModule(makeSlideModule(CountdownSlideComponent))
|
||||||
|
export class CountdownSlideModule {}
|
@ -0,0 +1,3 @@
|
|||||||
|
export interface ProjectorMessageSlideData {
|
||||||
|
message: string;
|
||||||
|
}
|
@ -0,0 +1,5 @@
|
|||||||
|
<div id="background" *ngIf="data">
|
||||||
|
<div id="message">
|
||||||
|
<div [innerHTML]="trustHTML(data.data.message)"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
@ -0,0 +1,29 @@
|
|||||||
|
#background {
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
top: 0;
|
||||||
|
background-color: rgba($color: #000000, $alpha: 0.5);
|
||||||
|
z-index: 10;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
display: grid;
|
||||||
|
grid-template-rows: auto;
|
||||||
|
grid-template-columns: auto;
|
||||||
|
|
||||||
|
#message {
|
||||||
|
align-self: center;
|
||||||
|
width: 80%;
|
||||||
|
text-align: center;
|
||||||
|
justify-self: center;
|
||||||
|
border-radius: 0.2em;
|
||||||
|
background: #ffffff;
|
||||||
|
font-size: 2.75em;
|
||||||
|
padding: 0.2em 0;
|
||||||
|
box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05);
|
||||||
|
min-height: 20px;
|
||||||
|
|
||||||
|
::ng-deep p {
|
||||||
|
margin: 0 0 10px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,26 @@
|
|||||||
|
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
|
import { E2EImportsModule } from '../../../../e2e-imports.module';
|
||||||
|
import { ProjectorMessageSlideComponent } from './projector-message-slide.component';
|
||||||
|
|
||||||
|
describe('ProjectorMessageSlideComponent', () => {
|
||||||
|
let component: ProjectorMessageSlideComponent;
|
||||||
|
let fixture: ComponentFixture<ProjectorMessageSlideComponent>;
|
||||||
|
|
||||||
|
beforeEach(async(() => {
|
||||||
|
TestBed.configureTestingModule({
|
||||||
|
imports: [E2EImportsModule],
|
||||||
|
declarations: [ProjectorMessageSlideComponent]
|
||||||
|
}).compileComponents();
|
||||||
|
}));
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
fixture = TestBed.createComponent(ProjectorMessageSlideComponent);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create', () => {
|
||||||
|
expect(component).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
@ -0,0 +1,20 @@
|
|||||||
|
import { Component } from '@angular/core';
|
||||||
|
import { DomSanitizer, SafeHtml } from '@angular/platform-browser';
|
||||||
|
|
||||||
|
import { BaseSlideComponent } from 'app/slides/base-slide-component';
|
||||||
|
import { ProjectorMessageSlideData } from './projector-message-slide-data';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'os-projector-message-slide',
|
||||||
|
templateUrl: './projector-message-slide.component.html',
|
||||||
|
styleUrls: ['./projector-message-slide.component.scss']
|
||||||
|
})
|
||||||
|
export class ProjectorMessageSlideComponent extends BaseSlideComponent<ProjectorMessageSlideData> {
|
||||||
|
public constructor(private sanitizer: DomSanitizer) {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
public trustHTML(html: string): SafeHtml {
|
||||||
|
return this.sanitizer.bypassSecurityTrustHtml(html);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,13 @@
|
|||||||
|
import { ProjectorMessageSlideModule } from './projector-message-slide.module';
|
||||||
|
|
||||||
|
describe('ProjectormessageSlideModule', () => {
|
||||||
|
let projectorMessageSlideModule: ProjectorMessageSlideModule;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
projectorMessageSlideModule = new ProjectorMessageSlideModule();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create an instance', () => {
|
||||||
|
expect(projectorMessageSlideModule).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
@ -0,0 +1,7 @@
|
|||||||
|
import { NgModule } from '@angular/core';
|
||||||
|
|
||||||
|
import { makeSlideModule } from 'app/slides/base-slide-module';
|
||||||
|
import { ProjectorMessageSlideComponent } from './projector-message-slide.component';
|
||||||
|
|
||||||
|
@NgModule(makeSlideModule(ProjectorMessageSlideComponent))
|
||||||
|
export class ProjectorMessageSlideModule {}
|
Loading…
Reference in New Issue
Block a user