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:
parent
534f2d1835
commit
71fdc28413
@ -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",
|
||||
|
@ -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
|
||||
*/
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
*/
|
||||
|
@ -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"
|
||||
|
@ -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 {
|
||||
|
@ -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,
|
||||
|
@ -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">
|
||||
{{ item.getListTitle() }}
|
||||
<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>
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -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}
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
|
||||
/**
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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(
|
||||
|
Loading…
Reference in New Issue
Block a user