Merge pull request #4334 from emanuelschuetze/slides

Topic slide
This commit is contained in:
Finn Stutzenstein 2019-02-14 10:10:53 +01:00 committed by GitHub
commit 9785f67562
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
18 changed files with 155 additions and 28 deletions

View File

@ -36,7 +36,6 @@ export class ProjectionDialogService {
} else { } else {
descriptor = obj; descriptor = obj;
} }
const dialogRef = this.dialog.open< const dialogRef = this.dialog.open<
ProjectionDialogComponent, ProjectionDialogComponent,
ProjectorElementBuildDeskriptor, ProjectorElementBuildDeskriptor,

View File

@ -5,8 +5,13 @@ mat-dialog-content {
div.projectors { div.projectors {
padding: 15px 0; padding: 15px 0;
mat-checkbox {
padding: 0 10px;
}
.right { .right {
float: right; float: right;
padding-right: 10px;
} }
} }
} }

View File

@ -24,7 +24,7 @@ export class ProjectorButtonComponent implements OnInit {
/** /**
* The object to project. * The object to project.
*/ */
private _object: Projectable | ProjectorElementBuildDeskriptor; private _object: Projectable | ProjectorElementBuildDeskriptor | null;
public get object(): Projectable | ProjectorElementBuildDeskriptor { public get object(): Projectable | ProjectorElementBuildDeskriptor {
return this._object; return this._object;
@ -35,10 +35,7 @@ export class ProjectorButtonComponent implements OnInit {
if (isProjectable(obj) || isProjectorElementBuildDeskriptor(obj)) { if (isProjectable(obj) || isProjectorElementBuildDeskriptor(obj)) {
this._object = obj; this._object = obj;
} else { } else {
console.error( this.object = null;
'Your model for the projectorbutton is not projectable and not' + 'a projectorElementBuildDescriptor!',
obj
);
} }
} }
@ -62,7 +59,9 @@ export class ProjectorButtonComponent implements OnInit {
*/ */
public onClick(event: Event): void { public onClick(event: Event): void {
event.stopPropagation(); event.stopPropagation();
this.projectionDialogService.openProjectDialogFor(this.object); if (this.object) {
this.projectionDialogService.openProjectDialogFor(this.object);
}
} }
/** /**

View File

@ -28,6 +28,16 @@
</mat-cell> </mat-cell>
</ng-container> </ng-container>
<!-- Projector column -->
<ng-container matColumnDef="projector">
<mat-header-cell *matHeaderCellDef mat-sort-header>Projector</mat-header-cell>
<mat-cell *matCellDef="let item">
<div *ngIf="item.contentObject">
<os-projector-button [object]="item.contentObject"></os-projector-button>
</div>
</mat-cell>
</ng-container>
<!-- title column --> <!-- title column -->
<ng-container matColumnDef="title"> <ng-container matColumnDef="title">
<mat-header-cell *matHeaderCellDef mat-sort-header>Topic</mat-header-cell> <mat-header-cell *matHeaderCellDef mat-sort-header>Topic</mat-header-cell>

View File

@ -54,6 +54,7 @@ export class AgendaListComponent extends ListViewBaseComponent<ViewItem> impleme
* @param titleService Setting the browser tab title * @param titleService Setting the browser tab title
* @param translate translations * @param translate translations
* @param matSnackBar Shows errors and messages * @param matSnackBar Shows errors and messages
* @param operator The current user
* @param route Angulars ActivatedRoute * @param route Angulars ActivatedRoute
* @param router Angulars router * @param router Angulars router
* @param repo the agenda repository, * @param repo the agenda repository,
@ -66,12 +67,12 @@ export class AgendaListComponent extends ListViewBaseComponent<ViewItem> impleme
* @param filterService: service for filtering data * @param filterService: service for filtering data
* @param agendaPdfService: service for preparing a pdf of the agenda * @param agendaPdfService: service for preparing a pdf of the agenda
* @param pdfService: Service for exporting a pdf * @param pdfService: Service for exporting a pdf
* @param operator the current user
*/ */
public constructor( public constructor(
titleService: Title, titleService: Title,
translate: TranslateService, translate: TranslateService,
matSnackBar: MatSnackBar, matSnackBar: MatSnackBar,
private operator: OperatorService,
private route: ActivatedRoute, private route: ActivatedRoute,
private router: Router, private router: Router,
private repo: ItemRepositoryService, private repo: ItemRepositoryService,
@ -83,8 +84,7 @@ export class AgendaListComponent extends ListViewBaseComponent<ViewItem> impleme
private csvExport: AgendaCsvExportService, private csvExport: AgendaCsvExportService,
public filterService: AgendaFilterListService, public filterService: AgendaFilterListService,
private agendaPdfService: AgendaPdfService, private agendaPdfService: AgendaPdfService,
private pdfService: PdfDocumentService, private pdfService: PdfDocumentService
private operator: OperatorService
) { ) {
super(titleService, translate, matSnackBar); super(titleService, translate, matSnackBar);
@ -238,11 +238,14 @@ export class AgendaListComponent extends ListViewBaseComponent<ViewItem> impleme
* @returns an array of strings with the dialogs to show * @returns an array of strings with the dialogs to show
*/ */
public getColumnDefinition(): string[] { public getColumnDefinition(): string[] {
const list = this.vp.isMobile ? this.displayedColumnsMobile : this.displayedColumnsDesktop; let columns = this.vp.isMobile ? this.displayedColumnsMobile : this.displayedColumnsDesktop;
if (this.isMultiSelect) { if (this.operator.hasPerms('core.can_manage_projector')) {
return ['selector'].concat(list); columns = ['projector'].concat(columns);
} }
return list; if (this.isMultiSelect) {
columns = ['selector'].concat(columns);
}
return columns;
} }
/** /**

View File

@ -96,7 +96,16 @@ export class ViewTopic extends BaseAgendaViewModel {
} }
public getSlide(): ProjectorElementBuildDeskriptor { public getSlide(): ProjectorElementBuildDeskriptor {
throw new Error('TODO'); return {
getBasicProjectorElement: () => ({
name: Topic.COLLECTIONSTRING,
id: this.id,
getIdentifiers: () => ['name', 'id']
}),
slideOptions: [],
projectionDefaultName: 'topics',
getTitle: () => this.getTitle()
};
} }
public hasAttachments(): boolean { public hasAttachments(): boolean {

View File

@ -80,6 +80,15 @@ export class ViewAssignment extends BaseAgendaViewModel {
} }
public getSlide(): ProjectorElementBuildDeskriptor { public getSlide(): ProjectorElementBuildDeskriptor {
throw new Error('TODO'); return {
getBasicProjectorElement: () => ({
name: Assignment.COLLECTIONSTRING,
id: this.id,
getIdentifiers: () => ['name', 'id']
}),
slideOptions: [],
projectionDefaultName: 'assignments',
getTitle: () => this.getTitle()
};
} }
} }

View File

@ -5,6 +5,7 @@ import { SlideOptions } from './slide-options';
export function isProjectorElementBuildDeskriptor(obj: any): obj is ProjectorElementBuildDeskriptor { export function isProjectorElementBuildDeskriptor(obj: any): obj is ProjectorElementBuildDeskriptor {
const deskriptor = <ProjectorElementBuildDeskriptor>obj; const deskriptor = <ProjectorElementBuildDeskriptor>obj;
return ( return (
!!deskriptor &&
deskriptor.slideOptions !== undefined && deskriptor.slideOptions !== undefined &&
deskriptor.getBasicProjectorElement !== undefined && deskriptor.getBasicProjectorElement !== undefined &&
deskriptor.getTitle !== undefined deskriptor.getTitle !== undefined
@ -23,7 +24,11 @@ export interface ProjectorElementBuildDeskriptor {
} }
export function isProjectable(obj: any): obj is Projectable { export function isProjectable(obj: any): obj is Projectable {
return (<Projectable>obj).getSlide !== undefined; if (obj) {
return (<Projectable>obj).getSlide !== undefined;
} else {
return false;
}
} }
/** /**

View File

@ -0,0 +1,4 @@
export interface TopicsTopicSlideData {
title: string;
text: string;
}

View File

@ -0,0 +1,5 @@
<div *ngIf="data">
<h1>{{ data.data.title }}</h1>
<div [innerHTML]="data.data.text"></div>
</div>

View File

@ -0,0 +1,26 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { TopicsTopicSlideComponent } from './topics-topic-slide.component';
import { E2EImportsModule } from 'e2e-imports.module';
describe('TopicsTopicSlideComponent', () => {
let component: TopicsTopicSlideComponent;
let fixture: ComponentFixture<TopicsTopicSlideComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
imports: [E2EImportsModule],
declarations: [TopicsTopicSlideComponent]
}).compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(TopicsTopicSlideComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@ -0,0 +1,14 @@
import { Component } from '@angular/core';
import { BaseSlideComponent } from 'app/slides/base-slide-component';
import { TopicsTopicSlideData } from './topics-topic-slide-data';
@Component({
selector: 'os-topic-slide',
templateUrl: './topics-topic-slide.component.html',
styleUrls: ['./topics-topic-slide.component.scss']
})
export class TopicsTopicSlideComponent extends BaseSlideComponent<TopicsTopicSlideData> {
public constructor() {
super();
}
}

View File

@ -0,0 +1,13 @@
import { TopicsTopicSlideModule } from './topics-topic-slide.module';
describe('TopicsTopicSlideModule', () => {
let topicsTopicSlideModule: TopicsTopicSlideModule;
beforeEach(() => {
topicsTopicSlideModule = new TopicsTopicSlideModule();
});
it('should create an instance', () => {
expect(topicsTopicSlideModule).toBeTruthy();
});
});

View File

@ -0,0 +1,7 @@
import { NgModule } from '@angular/core';
import { makeSlideModule } from 'app/slides/base-slide-module';
import { TopicsTopicSlideComponent } from './topics-topic-slide.component';
@NgModule(makeSlideModule(TopicsTopicSlideComponent))
export class TopicsTopicSlideModule {}

View File

@ -8,6 +8,16 @@ import { SlideManifest } from './slide-manifest';
* is no such thing as "dynamic update" in this case.. * is no such thing as "dynamic update" in this case..
*/ */
export const allSlides: SlideManifest[] = [ export const allSlides: SlideManifest[] = [
{
slide: 'topics/topic',
path: 'topics/topic',
loadChildren: './slides/agenda/topic/topics-topic-slide.module#TopicsTopicSlideModule',
scaleable: true,
scrollable: true,
verboseName: 'Topic',
elementIdentifiers: ['name', 'id'],
canBeMappedToModel: true
},
{ {
slide: 'motions/motion', slide: 'motions/motion',
path: 'motions/motion', path: 'motions/motion',

View File

@ -1,9 +0,0 @@
#outer {
position: absolute;
right: 0;
top: 0;
background-color: green;
height: 30px;
margin: 10px;
z-index: 2;
}

View File

@ -1,6 +1,10 @@
from typing import Any, Dict from typing import Any, Dict
from ..utils.projector import AllData, register_projector_slide from ..utils.projector import (
AllData,
ProjectorElementException,
register_projector_slide,
)
# Important: All functions have to be prune. This means, that thay can only # Important: All functions have to be prune. This means, that thay can only
@ -12,8 +16,22 @@ from ..utils.projector import AllData, register_projector_slide
def topic_slide(all_data: AllData, element: Dict[str, Any]) -> Dict[str, Any]: def topic_slide(all_data: AllData, element: Dict[str, Any]) -> Dict[str, Any]:
""" """
Topic slide. Topic slide.
The returned dict can contain the following fields:
* title
* text
""" """
return {"error": "TODO"} topic_id = element.get("id")
if topic_id is None:
raise ProjectorElementException("id is required for topic slide")
try:
topic = all_data["topics/topic"][topic_id]
except KeyError:
raise ProjectorElementException(f"topic with id {topic_id} does not exist")
return {"title": topic["title"], "text": topic["text"]}
def register_projector_slides() -> None: def register_projector_slides() -> None: