Merge pull request #4648 from FinnStutzenstein/motionBlockSlideTwoColumns
Dynamic a two column layout in motion block slides
This commit is contained in:
commit
9f5226c1d9
@ -4,14 +4,18 @@
|
||||
<h2><span translate>Motion block</span> – {{ data.data.motions.length }} <span translate>motions</span></h2>
|
||||
</div>
|
||||
|
||||
<div *ngFor="let motion of data.data.motions" class="blockitem">
|
||||
<div class="ellipsis-overflow">
|
||||
{{ getMotionTitle(motion) }}
|
||||
</div>
|
||||
<div class="white ellipsis-overflow">
|
||||
<mat-basic-chip *ngIf="motion.recommendation" disableRipple [ngClass]="getStateCssColor(motion)" class="block-recommendation">
|
||||
{{ getRecommendationLabel(motion) }}
|
||||
</mat-basic-chip>
|
||||
</div>
|
||||
</div>
|
||||
<table>
|
||||
<tr *ngFor="let i of rowsArray">
|
||||
<td *ngFor="let j of columnsArray">
|
||||
<div class="ellipsis-overflow">
|
||||
{{ getMotionTitle(i, j) }}
|
||||
</div>
|
||||
<div class="white"><!-- ellipsis-overflow?? -->
|
||||
<mat-basic-chip *ngIf="hasRecommendation(i, j)" disableRipple [ngClass]="getStateCssColor(i, j)" class="block-recommendation">
|
||||
{{ getRecommendationLabel(i, j) }}
|
||||
</mat-basic-chip>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
|
@ -1,4 +1,9 @@
|
||||
.blockitem {
|
||||
table {
|
||||
line-height: 1;
|
||||
margin-bottom: 10px;
|
||||
width: 100%;
|
||||
table-layout: fixed;
|
||||
}
|
||||
|
||||
td {
|
||||
min-width: 50%;
|
||||
}
|
||||
|
@ -5,9 +5,14 @@ import { TranslateService } from '@ngx-translate/core';
|
||||
import { MotionBlockSlideData, MotionBlockSlideMotionRepresentation } from './motion-block-slide-data';
|
||||
import { MotionRepositoryService } from 'app/core/repositories/motions/motion-repository.service';
|
||||
import { StateCssClassMapping } from 'app/site/motions/models/view-workflow';
|
||||
import { BaseMotionSlideComponent, MotionTitleInformation } from '../base/base-motion-slide';
|
||||
import { BaseMotionSlideComponent } from '../base/base-motion-slide';
|
||||
import { SlideData } from 'app/core/core-services/projector-data.service';
|
||||
|
||||
/**
|
||||
* The row threshold to switch from one to a two column layout
|
||||
*/
|
||||
const TWO_COLUMNS_THRESHOLD = 8;
|
||||
|
||||
@Component({
|
||||
selector: 'os-motion-block-slide',
|
||||
templateUrl: './motion-block-slide.component.html',
|
||||
@ -28,7 +33,10 @@ export class MotionBlockSlideComponent extends BaseMotionSlideComponent<MotionBl
|
||||
public set data(data: SlideData<MotionBlockSlideData>) {
|
||||
if (data && data.data.motions) {
|
||||
data.data.motions = data.data.motions.sort((a, b) =>
|
||||
this.languageCollator.compare(this.getMotionIdentifier(a), this.getMotionIdentifier(b))
|
||||
this.languageCollator.compare(
|
||||
this.motionRepo.getIdentifierOrTitle(a),
|
||||
this.motionRepo.getIdentifierOrTitle(b)
|
||||
)
|
||||
);
|
||||
}
|
||||
this._data = data;
|
||||
@ -38,30 +46,100 @@ export class MotionBlockSlideComponent extends BaseMotionSlideComponent<MotionBl
|
||||
return this._data;
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns the amount of motions in this block
|
||||
*/
|
||||
public get motionsAmount(): number {
|
||||
if (this.data && this.data.data.motions) {
|
||||
return this.data.data.motions.length;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns the amount of rows to display.
|
||||
*/
|
||||
public get rows(): number {
|
||||
let rows = this.motionsAmount;
|
||||
if (this.motionsAmount > TWO_COLUMNS_THRESHOLD) {
|
||||
rows = Math.ceil(rows / 2);
|
||||
}
|
||||
return rows;
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns an aray with [1, ..., this.rows]
|
||||
*/
|
||||
public get rowsArray(): number[] {
|
||||
const indices = [];
|
||||
const rows = this.rows;
|
||||
for (let i = 0; i < rows; i++) {
|
||||
indices.push(i);
|
||||
}
|
||||
return indices;
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns [0] or [0, 1] if one or two columns are used
|
||||
*/
|
||||
public get columnsArray(): number[] {
|
||||
if (this.motionsAmount > TWO_COLUMNS_THRESHOLD) {
|
||||
return [0, 1];
|
||||
} else {
|
||||
return [0];
|
||||
}
|
||||
}
|
||||
|
||||
public constructor(translate: TranslateService, motionRepo: MotionRepositoryService) {
|
||||
super(translate, motionRepo);
|
||||
this.languageCollator = new Intl.Collator(this.translate.currentLang);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the motion for the cell given by i and j
|
||||
*
|
||||
* @param i the row
|
||||
* @param j the column
|
||||
*/
|
||||
private getMotion(i: number, j: number): MotionBlockSlideMotionRepresentation {
|
||||
const index = i + this.rows * j;
|
||||
return this.data.data.motions[index];
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns the title of the given motion.
|
||||
*/
|
||||
public getMotionTitle(motion: MotionTitleInformation): string {
|
||||
return this.motionRepo.getTitle(motion);
|
||||
public getMotionTitle(i: number, j: number): string {
|
||||
return this.motionRepo.getTitle(this.getMotion(i, j));
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns the identifier (of title if identifier not availabe) of the given motion.
|
||||
*/
|
||||
public getMotionIdentifier(motion: MotionTitleInformation): string {
|
||||
return this.motionRepo.getIdentifierOrTitle(motion);
|
||||
public getMotionIdentifier(i: number, j: number): string {
|
||||
return this.motionRepo.getIdentifierOrTitle(this.getMotion(i, j));
|
||||
}
|
||||
|
||||
public getStateCssColor(motion: MotionBlockSlideMotionRepresentation): string {
|
||||
return StateCssClassMapping[motion.recommendation.css_class] || '';
|
||||
/**
|
||||
* @returns true if the motion in cell i and j has a recommendation
|
||||
*/
|
||||
public hasRecommendation(i: number, j: number): boolean {
|
||||
return !!this.getMotion(i, j).recommendation;
|
||||
}
|
||||
|
||||
public getRecommendationLabel(motion: MotionBlockSlideMotionRepresentation): string {
|
||||
/**
|
||||
* @returns the css color for the state of the motion in cell i and j
|
||||
*/
|
||||
public getStateCssColor(i: number, j: number): string {
|
||||
return StateCssClassMapping[this.getMotion(i, j).recommendation.css_class] || '';
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns the recommendation label for motion in cell i and j
|
||||
*/
|
||||
public getRecommendationLabel(i: number, j: number): string {
|
||||
const motion = this.getMotion(i, j);
|
||||
let recommendation = this.translate.instant(motion.recommendation.name);
|
||||
if (motion.recommendation_extension) {
|
||||
recommendation +=
|
||||
|
@ -1,5 +1,5 @@
|
||||
import re
|
||||
from typing import Any, Dict
|
||||
from typing import Any, Dict, Optional
|
||||
|
||||
from ..users.projector import get_user_name
|
||||
from ..utils.projector import (
|
||||
@ -121,13 +121,16 @@ async def get_amendment_base_statute(amendment, all_data):
|
||||
|
||||
async def extend_reference_motion_dict(
|
||||
all_data: AllData,
|
||||
recommendation: str,
|
||||
recommendation: Optional[str],
|
||||
referenced_motions: Dict[int, Dict[str, str]],
|
||||
) -> None:
|
||||
"""
|
||||
Extends a dict of motion ids mapped to their title information.
|
||||
The client can replace the placeholders in the recommendation correctly.
|
||||
"""
|
||||
if recommendation is None:
|
||||
return
|
||||
|
||||
# Collect all meantioned motions via [motion:<id>]
|
||||
referenced_ids = [
|
||||
int(id) for id in motion_placeholder_regex.findall(recommendation)
|
||||
|
Loading…
Reference in New Issue
Block a user