Build agenda with optional subtitle

- Updates the `virtual-scroll`-package.
- Updates the `list-view-table.component` for variable row-height.
- Adds config to have optional a subtitle in the `agenda-list`.
This commit is contained in:
GabrielMeyer 2019-09-09 18:20:58 +02:00
parent 534f2d1835
commit 71fdc28413
16 changed files with 169 additions and 15 deletions

View File

@ -47,8 +47,8 @@
"@ngx-pwa/local-storage": "~8.2.1",
"@ngx-translate/core": "~11.0.1",
"@ngx-translate/http-loader": "^4.0.0",
"@pebula/ngrid": "1.0.0-rc.5",
"@pebula/ngrid-material": "1.0.0-rc.5",
"@pebula/ngrid": "1.0.0-rc.9",
"@pebula/ngrid-material": "1.0.0-rc.9",
"@pebula/utils": "1.0.0",
"@tinymce/tinymce-angular": "^3.2.0",
"acorn": "^7.0.0",

View File

@ -91,6 +91,22 @@ export class ItemRepositoryService extends BaseHasContentObjectRepository<
}
};
/**
* Overrides the base function, if implemented.
*
* @returns An optional subtitle as `string`. Defaults to `null`.
*/
public getSubtitle = (titleInformation: ItemTitleInformation) => {
if (titleInformation.contentObject) {
return titleInformation.contentObject.getAgendaSubtitle();
} else {
const repo = this.collectionStringMapperService.getRepository(
titleInformation.contentObjectData.collection
) as BaseIsAgendaItemContentObjectRepository<any, any, any>;
return repo.getAgendaSubtitle(titleInformation.title_information);
}
};
/**
* Overrides the base function.
*
@ -107,6 +123,20 @@ export class ItemRepositoryService extends BaseHasContentObjectRepository<
}
};
/**
* @override The base-function to extends the items with an optional subtitle.
*
* @param model The underlying item.
* @param initialLoading boolean passed to the base-function.
*
* @returns {ViewItem} The modified item extended with the `getSubtitle()`-function.
*/
protected createViewModelWithTitles(model: Item, initialLoading: boolean): ViewItem {
const viewModel = super.createViewModelWithTitles(model, initialLoading);
viewModel.getSubtitle = () => this.getSubtitle(viewModel);
return viewModel;
}
/**
* Trigger the automatic numbering sequence on the server
*/

View File

@ -59,6 +59,17 @@ export abstract class BaseIsAgendaItemAndListOfSpeakersContentObjectRepository<
return numberPrefix + this.getTitle(titleInformation) + ' (' + this.getVerboseName() + ')';
}
/**
* Overwrites the base function.
*
* @param titleInformation The information about the model.
*
* @returns {string | null} An optional subtitle. `Null`, if it returns no subtitle, otherwise `string`.
*/
public getAgendaSubtitle(titleInformation: T): string | null {
return null;
}
public getAgendaSlideTitle(titleInformation: T): string {
const numberPrefix = titleInformation.agenda_item_number ? `${titleInformation.agenda_item_number} · ` : '';
return numberPrefix + this.getTitle(titleInformation);
@ -88,6 +99,7 @@ export abstract class BaseIsAgendaItemAndListOfSpeakersContentObjectRepository<
viewModel.getAgendaListTitle = () => this.getAgendaListTitle(viewModel);
viewModel.getAgendaListTitleWithoutItemNumber = () => this.getAgendaListTitleWithoutItemNumber(viewModel);
viewModel.getAgendaSlideTitle = () => this.getAgendaSlideTitle(viewModel);
viewModel.getAgendaSubtitle = () => this.getAgendaSubtitle(viewModel);
viewModel.getListOfSpeakersTitle = () => this.getListOfSpeakersTitle(viewModel);
viewModel.getListOfSpeakersSlideTitle = () => this.getListOfSpeakersSlideTitle(viewModel);
return viewModel;

View File

@ -84,6 +84,17 @@ export abstract class BaseIsAgendaItemContentObjectRepository<
return numberPrefix + this.getTitle(titleInformation) + ' (' + this.getVerboseName() + ')';
}
/**
* Overrides the base function. Returns an optional subtitle.
*
* @param titleInformation The information about the underlying model.
*
* @returns A string as subtitle. Defaults to `null`.
*/
public getAgendaSubtitle(titleInformation: T): string | null {
return null;
}
/**
* Function to return the title without item-number, in example used for pdf-creation.
*
@ -110,6 +121,7 @@ export abstract class BaseIsAgendaItemContentObjectRepository<
viewModel.getAgendaListTitle = () => this.getAgendaListTitle(viewModel);
viewModel.getAgendaListTitleWithoutItemNumber = () => this.getAgendaListTitleWithoutItemNumber(viewModel);
viewModel.getAgendaSlideTitle = () => this.getAgendaSlideTitle(viewModel);
viewModel.getAgendaSubtitle = () => this.getAgendaSubtitle(viewModel);
return viewModel;
}
}

View File

@ -293,6 +293,13 @@ export class MotionRepositoryService extends BaseIsAgendaItemAndListOfSpeakersCo
}
};
/**
* @override The base function and returns the submitters as optional subtitle.
*/
public getAgendaSubtitle = (model: ViewMotion) => {
return model.submittersAsUsers.join(', ');
};
/**
* @override The base function
*/

View File

@ -13,15 +13,11 @@
<!-- vScrollFixed="110" -->
<!-- vScrollAuto () -->
<pbl-ngrid
[ngClass]="{
'virtual-scroll-with-head-bar ngrid-hide-head': showFilterBar,
'virtual-scroll-full-page': !showFilterBar,
multiselect: multiSelect
}"
[ngClass]="cssClasses"
[vScrollFixed]="vScrollFixed"
cellTooltip
[showHeader]="!showFilterBar"
matCheckboxSelection="selection"
vScrollFixed="110"
[dataSource]="dataSource"
[columns]="columnSet"
[hideColumns]="hiddenColumns"

View File

@ -1,11 +1,13 @@
@import '~assets/styles/tables.scss';
$pbl-height: var(--pbl-height);
.projector-button {
margin: auto;
}
.pbl-ngrid-row {
height: 110px;
height: $pbl-height;
}
.pbl-ngrid-cell {

View File

@ -27,6 +27,10 @@ import { BaseProjectableViewModel } from 'app/site/base/base-projectable-view-mo
import { BaseViewModel } from 'app/site/base/base-view-model';
import { BaseViewModelWithContentObject } from 'app/site/base/base-view-model-with-content-object';
export interface CssClassDefinition {
[key: string]: boolean;
}
/**
* To hide columns via restriction
*/
@ -181,6 +185,37 @@ export class ListViewTableComponent<V extends BaseViewModel, M extends BaseModel
@Input()
public showListOfSpeakers = true;
/**
* Fix value for the height of the rows in the virtual-scroll-list.
*/
@Input()
public vScrollFixed = 110;
/**
* Option to apply additional classes to the virtual-scrolling-list.
*/
@Input()
public set cssClasses(values: CssClassDefinition) {
this._cssClasses = values;
}
/**
* Returns the list of classes, that are applied to the virtual-scrolling-list.
* Already prepared for the `[ngClass]`-property.
*
* `Warning: The defaultClasses will overwrite custom classes with the same key.`
*
* @returns An object looking like `{ [key: string]: boolean }`.
*/
public get cssClasses(): CssClassDefinition {
const defaultClasses = {
'virtual-scroll-with-head-bar ngrid-hide-head': this.showFilterBar,
'virtual-scroll-full-page': !this.showFilterBar,
multiselect: this.multiSelect
};
return Object.assign(this._cssClasses, defaultClasses);
}
/**
* Inform about changes in the dataSource
*/
@ -223,6 +258,11 @@ export class ListViewTableComponent<V extends BaseViewModel, M extends BaseModel
*/
private initialLoading = true;
/**
* Private variable to hold all classes for the virtual-scrolling-list.
*/
private _cssClasses: CssClassDefinition = {};
/**
* Most, of not all list views require these
*/
@ -450,6 +490,9 @@ export class ListViewTableComponent<V extends BaseViewModel, M extends BaseModel
.table(...this.defaultStartColumns, ...this.columns, ...this.defaultEndColumns)
.build();
// Sets the row height.
this.changeRowHeight();
// restore scroll position
if (this.listStorageKey) {
this.scrollToPreviousPosition(this.listStorageKey);
@ -567,6 +610,13 @@ export class ListViewTableComponent<V extends BaseViewModel, M extends BaseModel
});
}
/**
* This function changes the height of the row for virtual-scrolling in the relating `.scss`-file.
*/
private changeRowHeight(): void {
document.documentElement.style.setProperty('--pbl-height', this.vScrollFixed + 'px');
}
/**
* Checks the array of selected items against the datastore data. This is
* meant to reselect items by their id even if some of their data changed,

View File

@ -15,6 +15,7 @@
<os-list-view-table
[repo]="repo"
[vScrollFixed]="64"
[filterService]="filterService"
[columns]="tableColumnDefinition"
[multiSelect]="isMultiSelect"
@ -36,7 +37,14 @@
></a>
<div [ngStyle]="{ 'margin-left': item.level * 25 + 'px' }">
<os-icon-container [icon]="item.closed ? 'check' : null" size="large">
<div>
<div>
{{ item.getListTitle() }}
</div>
<div *ngIf="showSubtitle" class="subtitle">
{{ item.getSubtitle() }}
</div>
</div>
</os-icon-container>
</div>
</div>
@ -52,10 +60,6 @@
{{ durationService.durationToString(item.duration, 'h') }}
</os-icon-container>
</div>
<div *ngIf="item.comment" class="spacer-top-5">
<os-icon-container icon="comment">{{ item.comment }}</os-icon-container>
</div>
</div>
</div>

View File

@ -1,5 +1,4 @@
@import '~assets/styles/tables.scss';
.info-col-items {
display: inline-block;
white-space: nowrap;
@ -15,6 +14,9 @@
}
}
/*
* Where is this used?
*/
.done-check {
margin-right: 10px;
}

View File

@ -44,6 +44,11 @@ export class AgendaListComponent extends BaseListViewComponent<ViewItem> impleme
*/
public isNumberingAllowed: boolean;
/**
* A boolean, that decides, if the optional subtitles should be shown.
*/
public showSubtitle: boolean;
/**
* Helper to check main button permissions
*
@ -146,6 +151,7 @@ export class AgendaListComponent extends BaseListViewComponent<ViewItem> impleme
this.config
.get<boolean>('agenda_enable_numbering')
.subscribe(autoNumbering => (this.isNumberingAllowed = autoNumbering));
this.config.get<boolean>('agenda_show_subtitle').subscribe(showSubtitle => (this.showSubtitle = showSubtitle));
}
/**

View File

@ -46,6 +46,8 @@ export class ViewItem extends BaseViewModelWithContentObject<Item, BaseViewModel
return this.item.level;
}
public getSubtitle: () => string | null;
/**
* Gets the string representation of the item type
* @returns The visibility for this item, as defined in {@link itemVisibilityChoices}

View File

@ -47,6 +47,7 @@ export abstract class BaseViewModelWithAgendaItemAndListOfSpeakers<
public getAgendaSlideTitle: () => string;
public getAgendaListTitle: () => string;
public getAgendaListTitleWithoutItemNumber: () => string;
public getAgendaSubtitle: () => string;
public getListOfSpeakersTitle: () => string;
public getListOfSpeakersSlideTitle: () => string;

View File

@ -46,6 +46,11 @@ export interface IBaseViewModelWithAgendaItem<M extends BaseModelWithAgendaItem
*/
getAgendaListTitle: () => string;
/**
* @return an optional subtitle for the agenda.
*/
getAgendaSubtitle: () => string | null;
/**
* @return the agenda title with the verbose name of the content object
*/
@ -108,6 +113,15 @@ export abstract class BaseViewModelWithAgendaItem<M extends BaseModelWithAgendaI
return '';
}
/**
* @override The base-method from `IBaseViewModelWithAgendaItem`.
*
* @returns Defaults to `null`.
*/
public getAgendaSubtitle(): string | null {
return null;
}
public abstract getDetailStateURL(): string;
/**

View File

@ -82,6 +82,12 @@
color: mat-color($foreground, secondary-text);
}
.subtitle {
color: mat-color($foreground, secondary-text);
font-size: 12px;
font-weight: 400;
}
mat-card-header {
background-color: mat-color($background, app-bar);
}

View File

@ -23,6 +23,16 @@ def get_config_variables():
subgroup="General",
)
yield ConfigVariable(
name="agenda_show_subtitle",
default_value=False,
input_type="boolean",
label="Show subtitles in the agenda",
weight=201,
group="Agenda",
subgroup="General",
)
# Numbering
yield ConfigVariable(