Merge pull request #5002 from GabrielInTheWorld/coolestAgenda
Build agenda with optional subtitle
This commit is contained in:
commit
1dc96b0f2f
@ -47,8 +47,8 @@
|
|||||||
"@ngx-pwa/local-storage": "~8.2.1",
|
"@ngx-pwa/local-storage": "~8.2.1",
|
||||||
"@ngx-translate/core": "~11.0.1",
|
"@ngx-translate/core": "~11.0.1",
|
||||||
"@ngx-translate/http-loader": "^4.0.0",
|
"@ngx-translate/http-loader": "^4.0.0",
|
||||||
"@pebula/ngrid": "1.0.0-rc.5",
|
"@pebula/ngrid": "1.0.0-rc.9",
|
||||||
"@pebula/ngrid-material": "1.0.0-rc.5",
|
"@pebula/ngrid-material": "1.0.0-rc.9",
|
||||||
"@pebula/utils": "1.0.0",
|
"@pebula/utils": "1.0.0",
|
||||||
"@tinymce/tinymce-angular": "^3.2.0",
|
"@tinymce/tinymce-angular": "^3.2.0",
|
||||||
"acorn": "^7.0.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.
|
* 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
|
* Trigger the automatic numbering sequence on the server
|
||||||
*/
|
*/
|
||||||
|
@ -59,6 +59,17 @@ export abstract class BaseIsAgendaItemAndListOfSpeakersContentObjectRepository<
|
|||||||
return numberPrefix + this.getTitle(titleInformation) + ' (' + this.getVerboseName() + ')';
|
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 {
|
public getAgendaSlideTitle(titleInformation: T): string {
|
||||||
const numberPrefix = titleInformation.agenda_item_number ? `${titleInformation.agenda_item_number} · ` : '';
|
const numberPrefix = titleInformation.agenda_item_number ? `${titleInformation.agenda_item_number} · ` : '';
|
||||||
return numberPrefix + this.getTitle(titleInformation);
|
return numberPrefix + this.getTitle(titleInformation);
|
||||||
@ -88,6 +99,7 @@ export abstract class BaseIsAgendaItemAndListOfSpeakersContentObjectRepository<
|
|||||||
viewModel.getAgendaListTitle = () => this.getAgendaListTitle(viewModel);
|
viewModel.getAgendaListTitle = () => this.getAgendaListTitle(viewModel);
|
||||||
viewModel.getAgendaListTitleWithoutItemNumber = () => this.getAgendaListTitleWithoutItemNumber(viewModel);
|
viewModel.getAgendaListTitleWithoutItemNumber = () => this.getAgendaListTitleWithoutItemNumber(viewModel);
|
||||||
viewModel.getAgendaSlideTitle = () => this.getAgendaSlideTitle(viewModel);
|
viewModel.getAgendaSlideTitle = () => this.getAgendaSlideTitle(viewModel);
|
||||||
|
viewModel.getAgendaSubtitle = () => this.getAgendaSubtitle(viewModel);
|
||||||
viewModel.getListOfSpeakersTitle = () => this.getListOfSpeakersTitle(viewModel);
|
viewModel.getListOfSpeakersTitle = () => this.getListOfSpeakersTitle(viewModel);
|
||||||
viewModel.getListOfSpeakersSlideTitle = () => this.getListOfSpeakersSlideTitle(viewModel);
|
viewModel.getListOfSpeakersSlideTitle = () => this.getListOfSpeakersSlideTitle(viewModel);
|
||||||
return viewModel;
|
return viewModel;
|
||||||
|
@ -84,6 +84,17 @@ export abstract class BaseIsAgendaItemContentObjectRepository<
|
|||||||
return numberPrefix + this.getTitle(titleInformation) + ' (' + this.getVerboseName() + ')';
|
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.
|
* 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.getAgendaListTitle = () => this.getAgendaListTitle(viewModel);
|
||||||
viewModel.getAgendaListTitleWithoutItemNumber = () => this.getAgendaListTitleWithoutItemNumber(viewModel);
|
viewModel.getAgendaListTitleWithoutItemNumber = () => this.getAgendaListTitleWithoutItemNumber(viewModel);
|
||||||
viewModel.getAgendaSlideTitle = () => this.getAgendaSlideTitle(viewModel);
|
viewModel.getAgendaSlideTitle = () => this.getAgendaSlideTitle(viewModel);
|
||||||
|
viewModel.getAgendaSubtitle = () => this.getAgendaSubtitle(viewModel);
|
||||||
return 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
|
* @override The base function
|
||||||
*/
|
*/
|
||||||
|
@ -13,15 +13,11 @@
|
|||||||
<!-- vScrollFixed="110" -->
|
<!-- vScrollFixed="110" -->
|
||||||
<!-- vScrollAuto () -->
|
<!-- vScrollAuto () -->
|
||||||
<pbl-ngrid
|
<pbl-ngrid
|
||||||
[ngClass]="{
|
[ngClass]="cssClasses"
|
||||||
'virtual-scroll-with-head-bar ngrid-hide-head': showFilterBar,
|
[vScrollFixed]="vScrollFixed"
|
||||||
'virtual-scroll-full-page': !showFilterBar,
|
|
||||||
multiselect: multiSelect
|
|
||||||
}"
|
|
||||||
cellTooltip
|
cellTooltip
|
||||||
[showHeader]="!showFilterBar"
|
[showHeader]="!showFilterBar"
|
||||||
matCheckboxSelection="selection"
|
matCheckboxSelection="selection"
|
||||||
vScrollFixed="110"
|
|
||||||
[dataSource]="dataSource"
|
[dataSource]="dataSource"
|
||||||
[columns]="columnSet"
|
[columns]="columnSet"
|
||||||
[hideColumns]="hiddenColumns"
|
[hideColumns]="hiddenColumns"
|
||||||
|
@ -1,11 +1,13 @@
|
|||||||
@import '~assets/styles/tables.scss';
|
@import '~assets/styles/tables.scss';
|
||||||
|
|
||||||
|
$pbl-height: var(--pbl-height);
|
||||||
|
|
||||||
.projector-button {
|
.projector-button {
|
||||||
margin: auto;
|
margin: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
.pbl-ngrid-row {
|
.pbl-ngrid-row {
|
||||||
height: 110px;
|
height: $pbl-height;
|
||||||
}
|
}
|
||||||
|
|
||||||
.pbl-ngrid-cell {
|
.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 { BaseViewModel } from 'app/site/base/base-view-model';
|
||||||
import { BaseViewModelWithContentObject } from 'app/site/base/base-view-model-with-content-object';
|
import { BaseViewModelWithContentObject } from 'app/site/base/base-view-model-with-content-object';
|
||||||
|
|
||||||
|
export interface CssClassDefinition {
|
||||||
|
[key: string]: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* To hide columns via restriction
|
* To hide columns via restriction
|
||||||
*/
|
*/
|
||||||
@ -181,6 +185,37 @@ export class ListViewTableComponent<V extends BaseViewModel, M extends BaseModel
|
|||||||
@Input()
|
@Input()
|
||||||
public showListOfSpeakers = true;
|
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
|
* Inform about changes in the dataSource
|
||||||
*/
|
*/
|
||||||
@ -223,6 +258,11 @@ export class ListViewTableComponent<V extends BaseViewModel, M extends BaseModel
|
|||||||
*/
|
*/
|
||||||
private initialLoading = true;
|
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
|
* 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)
|
.table(...this.defaultStartColumns, ...this.columns, ...this.defaultEndColumns)
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
|
// Sets the row height.
|
||||||
|
this.changeRowHeight();
|
||||||
|
|
||||||
// restore scroll position
|
// restore scroll position
|
||||||
if (this.listStorageKey) {
|
if (this.listStorageKey) {
|
||||||
this.scrollToPreviousPosition(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
|
* 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,
|
* meant to reselect items by their id even if some of their data changed,
|
||||||
|
@ -15,6 +15,7 @@
|
|||||||
|
|
||||||
<os-list-view-table
|
<os-list-view-table
|
||||||
[repo]="repo"
|
[repo]="repo"
|
||||||
|
[vScrollFixed]="64"
|
||||||
[filterService]="filterService"
|
[filterService]="filterService"
|
||||||
[columns]="tableColumnDefinition"
|
[columns]="tableColumnDefinition"
|
||||||
[multiSelect]="isMultiSelect"
|
[multiSelect]="isMultiSelect"
|
||||||
@ -36,7 +37,14 @@
|
|||||||
></a>
|
></a>
|
||||||
<div [ngStyle]="{ 'margin-left': item.level * 25 + 'px' }">
|
<div [ngStyle]="{ 'margin-left': item.level * 25 + 'px' }">
|
||||||
<os-icon-container [icon]="item.closed ? 'check' : null" size="large">
|
<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>
|
</os-icon-container>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -52,10 +60,6 @@
|
|||||||
{{ durationService.durationToString(item.duration, 'h') }}
|
{{ durationService.durationToString(item.duration, 'h') }}
|
||||||
</os-icon-container>
|
</os-icon-container>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div *ngIf="item.comment" class="spacer-top-5">
|
|
||||||
<os-icon-container icon="comment">{{ item.comment }}</os-icon-container>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
@import '~assets/styles/tables.scss';
|
@import '~assets/styles/tables.scss';
|
||||||
|
|
||||||
.info-col-items {
|
.info-col-items {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
@ -15,6 +14,9 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Where is this used?
|
||||||
|
*/
|
||||||
.done-check {
|
.done-check {
|
||||||
margin-right: 10px;
|
margin-right: 10px;
|
||||||
}
|
}
|
||||||
|
@ -44,6 +44,11 @@ export class AgendaListComponent extends BaseListViewComponent<ViewItem> impleme
|
|||||||
*/
|
*/
|
||||||
public isNumberingAllowed: boolean;
|
public isNumberingAllowed: boolean;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A boolean, that decides, if the optional subtitles should be shown.
|
||||||
|
*/
|
||||||
|
public showSubtitle: boolean;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Helper to check main button permissions
|
* Helper to check main button permissions
|
||||||
*
|
*
|
||||||
@ -146,6 +151,7 @@ export class AgendaListComponent extends BaseListViewComponent<ViewItem> impleme
|
|||||||
this.config
|
this.config
|
||||||
.get<boolean>('agenda_enable_numbering')
|
.get<boolean>('agenda_enable_numbering')
|
||||||
.subscribe(autoNumbering => (this.isNumberingAllowed = autoNumbering));
|
.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;
|
return this.item.level;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public getSubtitle: () => string | null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the string representation of the item type
|
* Gets the string representation of the item type
|
||||||
* @returns The visibility for this item, as defined in {@link itemVisibilityChoices}
|
* @returns The visibility for this item, as defined in {@link itemVisibilityChoices}
|
||||||
|
@ -47,6 +47,7 @@ export abstract class BaseViewModelWithAgendaItemAndListOfSpeakers<
|
|||||||
public getAgendaSlideTitle: () => string;
|
public getAgendaSlideTitle: () => string;
|
||||||
public getAgendaListTitle: () => string;
|
public getAgendaListTitle: () => string;
|
||||||
public getAgendaListTitleWithoutItemNumber: () => string;
|
public getAgendaListTitleWithoutItemNumber: () => string;
|
||||||
|
public getAgendaSubtitle: () => string;
|
||||||
public getListOfSpeakersTitle: () => string;
|
public getListOfSpeakersTitle: () => string;
|
||||||
public getListOfSpeakersSlideTitle: () => string;
|
public getListOfSpeakersSlideTitle: () => string;
|
||||||
|
|
||||||
|
@ -46,6 +46,11 @@ export interface IBaseViewModelWithAgendaItem<M extends BaseModelWithAgendaItem
|
|||||||
*/
|
*/
|
||||||
getAgendaListTitle: () => string;
|
getAgendaListTitle: () => string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return an optional subtitle for the agenda.
|
||||||
|
*/
|
||||||
|
getAgendaSubtitle: () => string | null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the agenda title with the verbose name of the content object
|
* @return the agenda title with the verbose name of the content object
|
||||||
*/
|
*/
|
||||||
@ -108,6 +113,15 @@ export abstract class BaseViewModelWithAgendaItem<M extends BaseModelWithAgendaI
|
|||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @override The base-method from `IBaseViewModelWithAgendaItem`.
|
||||||
|
*
|
||||||
|
* @returns Defaults to `null`.
|
||||||
|
*/
|
||||||
|
public getAgendaSubtitle(): string | null {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
public abstract getDetailStateURL(): string;
|
public abstract getDetailStateURL(): string;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -82,6 +82,12 @@
|
|||||||
color: mat-color($foreground, secondary-text);
|
color: mat-color($foreground, secondary-text);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.subtitle {
|
||||||
|
color: mat-color($foreground, secondary-text);
|
||||||
|
font-size: 12px;
|
||||||
|
font-weight: 400;
|
||||||
|
}
|
||||||
|
|
||||||
mat-card-header {
|
mat-card-header {
|
||||||
background-color: mat-color($background, app-bar);
|
background-color: mat-color($background, app-bar);
|
||||||
}
|
}
|
||||||
|
@ -23,6 +23,16 @@ def get_config_variables():
|
|||||||
subgroup="General",
|
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
|
# Numbering
|
||||||
|
|
||||||
yield ConfigVariable(
|
yield ConfigVariable(
|
||||||
|
Loading…
Reference in New Issue
Block a user