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 { SlideManager } from 'app/slides/services/slide-manager.service';
|
||||
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 { BaseProjectableViewModel } from 'app/site/base/base-projectable-view-model';
|
||||
|
||||
/**
|
||||
* This service cares about Projectables being projected and manage all projection-related
|
||||
@ -260,9 +260,15 @@ export class ProjectorService {
|
||||
* @param element 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);
|
||||
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();
|
||||
}
|
||||
};
|
||||
viewMotion.getProjectorTitle = viewMotion.getAgendaTitle;
|
||||
viewMotion.getAgendaTitleWithType = () => {
|
||||
// Append the verbose name only, if not the special format 'Motion <identifier>' is used.
|
||||
if (viewMotion.identifier) {
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { TestBed, inject } from '@angular/core/testing';
|
||||
|
||||
import { E2EImportsModule } from 'e2e-imports.module';
|
||||
import { ProjectorMessageRepositoryService } from './projectormessage-repository.service';
|
||||
import { ProjectorMessageRepositoryService } from './projector-message-repository.service';
|
||||
|
||||
describe('ProjectorMessageRepositoryService', () => {
|
||||
beforeEach(() => {
|
@ -4,9 +4,10 @@ import { BaseRepository } from '../base-repository';
|
||||
import { Identifiable } from 'app/shared/models/base/identifiable';
|
||||
import { CollectionStringMapperService } from '../../core-services/collectionStringMapper.service';
|
||||
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 { TranslateService } from '@ngx-translate/core';
|
||||
import { DataSendService } from 'app/core/core-services/data-send.service';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
@ -16,7 +17,8 @@ export class ProjectorMessageRepositoryService extends BaseRepository<ViewProjec
|
||||
DS: DataStoreService,
|
||||
mapperService: CollectionStringMapperService,
|
||||
viewModelStoreService: ViewModelStoreService,
|
||||
private translate: TranslateService
|
||||
private translate: TranslateService,
|
||||
private dataSend: DataSendService
|
||||
) {
|
||||
super(DS, mapperService, viewModelStoreService, ProjectorMessage);
|
||||
}
|
||||
@ -30,14 +32,16 @@ export class ProjectorMessageRepositoryService extends BaseRepository<ViewProjec
|
||||
}
|
||||
|
||||
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> {
|
||||
throw new Error('TODO');
|
||||
const update = viewMessage.projectormessage;
|
||||
update.patchValues(message);
|
||||
await this.dataSend.updateModel(update);
|
||||
}
|
||||
|
||||
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>
|
||||
<span *ngIf="projectorElementBuildDescriptor.projectionDefaultName !== 'motions'" translate>Project {{ projectorElementBuildDescriptor.getTitle() }}?</span>
|
||||
<span *ngIf="projectorElementBuildDescriptor.projectionDefaultName === 'motions'" translate>Project motion {{ projectorElementBuildDescriptor.getTitle() }}?</span>
|
||||
<span translate>Project</span> {{ projectorElementBuildDescriptor.getTitle() }}?
|
||||
</h2>
|
||||
<mat-dialog-content>
|
||||
<div
|
||||
class="projectors"
|
||||
<div class="projectors"
|
||||
*ngFor="let projector of projectors"
|
||||
[ngClass]="isProjectedOn(projector) ? 'projected' : ''"
|
||||
>
|
||||
[ngClass]="isProjectedOn(projector) ? 'projected' : ''">
|
||||
<mat-checkbox [checked]="isProjectorSelected(projector)" (change)="toggleProjector(projector)">
|
||||
{{ projector.name | translate }}
|
||||
</mat-checkbox>
|
||||
|
@ -13,7 +13,7 @@
|
||||
</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>
|
||||
</div>
|
||||
|
||||
|
@ -51,14 +51,6 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
.content {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 50px;
|
||||
right: 50px;
|
||||
}
|
||||
|
||||
#footer {
|
||||
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 {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
|
||||
&.content {
|
||||
width: calc(100% - 100px);
|
||||
margin-left: 50px;
|
||||
margin-right: 50px;
|
||||
}
|
||||
}
|
||||
|
||||
::ng-deep #slide {
|
||||
z-index: 5;
|
||||
height: 100%;
|
||||
|
@ -88,7 +88,7 @@ export class SlideContainerComponent extends BaseComponent {
|
||||
/**
|
||||
* The current slideoptions.
|
||||
*/
|
||||
private slideOptions: SlideOptions = { scaleable: false, scrollable: false };
|
||||
public slideOptions: SlideOptions = { scaleable: false, scrollable: false };
|
||||
|
||||
/**
|
||||
* 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 { itemVisibilityChoices } from 'app/shared/models/agenda/item';
|
||||
import { ViewCreateTopic } from '../../models/view-create-topic';
|
||||
import { stripHtmlTags } from 'app/shared/utils/strip-html-tags';
|
||||
|
||||
/**
|
||||
* Component for the agenda import list view.
|
||||
@ -59,9 +60,9 @@ export class AgendaImportListComponent extends BaseImportListComponent<ViewCreat
|
||||
return '';
|
||||
}
|
||||
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 '';
|
||||
}
|
||||
if (input.length < 300) {
|
||||
return this.stripHtmlTags(input);
|
||||
return stripHtmlTags(input);
|
||||
}
|
||||
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
|
||||
*/
|
||||
|
@ -6,4 +6,11 @@ import { BaseViewModel } from './base-view-model';
|
||||
*/
|
||||
export abstract class BaseProjectableViewModel extends BaseViewModel implements Projectable {
|
||||
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 { MotionImportService } from '../../services/motion-import.service';
|
||||
import { ViewMotion } from '../../models/view-motion';
|
||||
import { stripHtmlTags } from 'app/shared/utils/strip-html-tags';
|
||||
|
||||
/**
|
||||
* Component for the motion import list view.
|
||||
@ -43,9 +44,9 @@ export class MotionImportListComponent extends BaseImportListComponent<ViewMotio
|
||||
*/
|
||||
public getShortPreview(input: string): string {
|
||||
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 {
|
||||
if (input.length < 300) {
|
||||
return this.stripHtmlTags(input);
|
||||
return stripHtmlTags(input);
|
||||
}
|
||||
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
|
||||
*/
|
||||
|
@ -7,6 +7,7 @@ import { BaseImportListComponent } from 'app/site/base/base-import-list';
|
||||
import { ViewStatuteParagraph } from 'app/site/motions/models/view-statute-paragraph';
|
||||
import { StatuteImportService } from 'app/site/motions/services/statute-import.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.
|
||||
@ -42,9 +43,9 @@ export class StatuteImportListComponent extends BaseImportListComponent<ViewStat
|
||||
*/
|
||||
public getShortPreview(input: string): string {
|
||||
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 {
|
||||
if (input.length < 300) {
|
||||
return this.stripHtmlTags(input);
|
||||
return stripHtmlTags(input);
|
||||
}
|
||||
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
|
||||
*/
|
||||
|
@ -580,7 +580,7 @@ export class ViewMotion extends BaseAgendaViewModel implements Searchable {
|
||||
}
|
||||
],
|
||||
projectionDefaultName: 'motions',
|
||||
getTitle: () => this.identifier
|
||||
getTitle: this.getAgendaTitle
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -1,12 +1,12 @@
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
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 { FormGroup, FormBuilder, Validators } from '@angular/forms';
|
||||
import { PromptService } from 'app/core/ui-services/prompt.service';
|
||||
import { BaseViewComponent } from '../../../base/base-view';
|
||||
import { MatSnackBar } from '@angular/material';
|
||||
import { ViewCountdown } from '../../models/view-countdown';
|
||||
import { CountdownRepositoryService } from 'app/core/repositories/projector/countdown-repository.service';
|
||||
import { Countdown } from 'app/shared/models/core/countdown';
|
||||
|
@ -7,11 +7,14 @@
|
||||
|
||||
<div class="content-container" *ngIf="projector">
|
||||
<div class="column-left">
|
||||
<a [routerLink]="['/projector', projector.id]">
|
||||
<!--<a [routerLink]="['/projector', projector.id]">
|
||||
<div id="projector">
|
||||
<os-projector [projector]="projector"></os-projector>
|
||||
</div>
|
||||
</a>-->
|
||||
<div id="projector">
|
||||
<os-projector [projector]="projector"></os-projector>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
<div class="column-right" *osPerms="'core.can_manage_projector'">
|
||||
<div class="control-group">
|
||||
@ -75,7 +78,7 @@
|
||||
<div *ngIf="countdowns.length">
|
||||
<h4>
|
||||
<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>
|
||||
</button>
|
||||
</h4>
|
||||
@ -92,16 +95,16 @@
|
||||
<div *ngIf="messages.length">
|
||||
<h4>
|
||||
<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>
|
||||
</button>
|
||||
</h4>
|
||||
<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)">
|
||||
<mat-icon>videocam</mat-icon>
|
||||
</button>
|
||||
<span translate>Message</span> {{ i + 1 }}
|
||||
<span translate>{{ message.getPreview(40) }}</span>
|
||||
</mat-list-item>
|
||||
</mat-list>
|
||||
</div>
|
||||
|
@ -16,8 +16,8 @@ import { moveItemInArray, CdkDragDrop } from '@angular/cdk/drag-drop';
|
||||
import { ProjectorElement } from 'app/shared/models/core/projector';
|
||||
import { SlideManager } from 'app/slides/services/slide-manager.service';
|
||||
import { CountdownRepositoryService } from 'app/core/repositories/projector/countdown-repository.service';
|
||||
import { ProjectorMessageRepositoryService } from 'app/core/repositories/projector/projectormessage-repository.service';
|
||||
import { ViewProjectorMessage } from 'app/site/projector/models/view-projectormessage';
|
||||
import { ProjectorMessageRepositoryService } from 'app/core/repositories/projector/projector-message-repository.service';
|
||||
import { ViewProjectorMessage } from 'app/site/projector/models/view-projector-message';
|
||||
import { ViewCountdown } from 'app/site/projector/models/view-countdown';
|
||||
import { Projectable } from 'app/site/base/projectable';
|
||||
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 viewModel = this.projectorService.getViewModelFromProjectorElement(idElement);
|
||||
if (viewModel) {
|
||||
return viewModel.getTitle();
|
||||
return viewModel.getProjectorTitle();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -111,12 +111,12 @@
|
||||
</div>
|
||||
|
||||
<mat-menu #ellipsisMenu="matMenu">
|
||||
<button mat-menu-item routerLink="/projectors/countdowns">
|
||||
<mat-icon>alarm</mat-icon>
|
||||
<span translate>Countdowns</span>
|
||||
</button>
|
||||
<button mat-menu-item>
|
||||
<button type="button" mat-menu-item routerLink="/projectors/messages">
|
||||
<mat-icon>note</mat-icon>
|
||||
<span translate>Projector messages</span>
|
||||
</button>
|
||||
<button type="button" mat-menu-item routerLink="/projectors/countdowns">
|
||||
<mat-icon>alarm</mat-icon>
|
||||
<span translate>Countdowns</span>
|
||||
</button>
|
||||
</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 { E2EImportsModule } from 'e2e-imports.module';
|
||||
import { ProjectorMessageListComponent } from './projectormessage-list.component';
|
||||
import { ProjectorMessageListComponent } from './projector-message-list.component';
|
||||
|
||||
describe('CountdownListComponent', () => {
|
||||
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 { ProjectorMessage } from 'app/shared/models/core/projector-message';
|
||||
import { BaseViewModel } from 'app/site/base/base-view-model';
|
||||
import { stripHtmlTags } from 'app/shared/utils/strip-html-tags';
|
||||
|
||||
export class ViewProjectorMessage extends BaseProjectableViewModel {
|
||||
public static COLLECTIONSTRING = ProjectorMessage.COLLECTIONSTRING;
|
||||
|
||||
private _message: ProjectorMessage;
|
||||
|
||||
public get projctormessage(): ProjectorMessage {
|
||||
public get projectormessage(): ProjectorMessage {
|
||||
return this._message;
|
||||
}
|
||||
|
||||
public get id(): number {
|
||||
return this.projctormessage.id;
|
||||
return this.projectormessage.id;
|
||||
}
|
||||
|
||||
public get message(): string {
|
||||
return this.projctormessage.message;
|
||||
return this.projectormessage.message;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -49,4 +50,13 @@ export class ViewProjectorMessage extends BaseProjectableViewModel {
|
||||
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 { ProjectorDetailComponent } from './components/projector-detail/projector-detail.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 = [
|
||||
{
|
||||
|
@ -4,10 +4,10 @@ import { Countdown } from 'app/shared/models/core/countdown';
|
||||
import { ProjectorMessage } from 'app/shared/models/core/projector-message';
|
||||
import { ProjectorRepositoryService } from 'app/core/repositories/projector/projector-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 { ViewCountdown } from './models/view-countdown';
|
||||
import { ViewProjectorMessage } from './models/view-projectormessage';
|
||||
import { ViewProjectorMessage } from './models/view-projector-message';
|
||||
|
||||
export const ProjectorAppConfig: AppConfig = {
|
||||
name: 'projector',
|
||||
|
@ -9,7 +9,7 @@ import { ClockSlideService } from './services/clock-slide.service';
|
||||
import { ProjectorDataService } from './services/projector-data.service';
|
||||
import { CurrentListOfSpeakersSlideService } from './services/current-list-of-of-speakers-slide.service';
|
||||
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({
|
||||
providers: [ClockSlideService, ProjectorDataService, CurrentListOfSpeakersSlideService],
|
||||
|
@ -41,7 +41,7 @@ export const allSlides: SlideManifest[] = [
|
||||
{
|
||||
slide: 'core/clock',
|
||||
path: 'core/clock',
|
||||
loadChildren: './slides/core/clock/core-clock-slide.module#CoreClockSlideModule',
|
||||
loadChildren: './slides/core/clock/clock-slide.module#ClockSlideModule',
|
||||
scaleable: false,
|
||||
scrollable: false,
|
||||
verboseName: 'Clock',
|
||||
@ -51,13 +51,23 @@ export const allSlides: SlideManifest[] = [
|
||||
{
|
||||
slide: 'core/countdown',
|
||||
path: 'core/countdown',
|
||||
loadChildren: './slides/core/countdown/core-countdown-slide.module#CoreCountdownSlideModule',
|
||||
loadChildren: './slides/core/countdown/countdown-slide.module#CountdownSlideModule',
|
||||
scaleable: false,
|
||||
scrollable: false,
|
||||
verboseName: 'Countdown',
|
||||
elementIdentifiers: ['name', 'id'],
|
||||
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',
|
||||
path: 'agenda/current-list-of-speakers',
|
||||
@ -79,5 +89,15 @@ export const allSlides: SlideManifest[] = [
|
||||
verboseName: 'Current list of speakers overlay',
|
||||
elementIdentifiers: ['name', 'id'],
|
||||
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 { CoreCountdownSlideComponent } from './core-countdown-slide.component';
|
||||
import { AssignmentSlideComponent } from './assignment-slide.component';
|
||||
import { E2EImportsModule } from '../../../../e2e-imports.module';
|
||||
|
||||
describe('CoreCountdownSlideComponent', () => {
|
||||
let component: CoreCountdownSlideComponent;
|
||||
let fixture: ComponentFixture<CoreCountdownSlideComponent>;
|
||||
describe('AssignmentSlideComponent', () => {
|
||||
let component: AssignmentSlideComponent;
|
||||
let fixture: ComponentFixture<AssignmentSlideComponent>;
|
||||
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
imports: [E2EImportsModule],
|
||||
declarations: [CoreCountdownSlideComponent]
|
||||
declarations: [AssignmentSlideComponent]
|
||||
}).compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(CoreCountdownSlideComponent);
|
||||
fixture = TestBed.createComponent(AssignmentSlideComponent);
|
||||
component = fixture.componentInstance;
|
||||
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 { BaseSlideComponent } from 'app/slides/base-slide-component';
|
||||
import { ServertimeService } from 'app/core/core-services/servertime.service';
|
||||
|
||||
import { Subscription } from 'rxjs';
|
||||
|
||||
import { BaseSlideComponent } from 'app/slides/base-slide-component';
|
||||
import { ServertimeService } from 'app/core/core-services/servertime.service';
|
||||
|
||||
@Component({
|
||||
selector: 'os-core-clock-slide',
|
||||
templateUrl: './core-clock-slide.component.html',
|
||||
styleUrls: ['./core-clock-slide.component.scss']
|
||||
selector: 'os-clock-slide',
|
||||
templateUrl: './clock-slide.component.html',
|
||||
styleUrls: ['./clock-slide.component.scss']
|
||||
})
|
||||
export class CoreClockSlideComponent extends BaseSlideComponent<{}> implements OnInit, OnDestroy {
|
||||
export class ClockSlideComponent extends BaseSlideComponent<{}> implements OnInit, OnDestroy {
|
||||
public time: string;
|
||||
|
||||
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 { CoreClockSlideComponent } from './core-clock-slide.component';
|
||||
import { CountdownSlideComponent } from './countdown-slide.component';
|
||||
import { E2EImportsModule } from '../../../../e2e-imports.module';
|
||||
|
||||
describe('CoreClockSlideComponent', () => {
|
||||
let component: CoreClockSlideComponent;
|
||||
let fixture: ComponentFixture<CoreClockSlideComponent>;
|
||||
describe('CountdownSlideComponent', () => {
|
||||
let component: CountdownSlideComponent;
|
||||
let fixture: ComponentFixture<CountdownSlideComponent>;
|
||||
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
imports: [E2EImportsModule],
|
||||
declarations: [CoreClockSlideComponent]
|
||||
declarations: [CountdownSlideComponent]
|
||||
}).compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(CoreClockSlideComponent);
|
||||
fixture = TestBed.createComponent(CountdownSlideComponent);
|
||||
component = fixture.componentInstance;
|
||||
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