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>
|
<h2><span translate>Motion block</span> – {{ data.data.motions.length }} <span translate>motions</span></h2>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div *ngFor="let motion of data.data.motions" class="blockitem">
|
<table>
|
||||||
<div class="ellipsis-overflow">
|
<tr *ngFor="let i of rowsArray">
|
||||||
{{ getMotionTitle(motion) }}
|
<td *ngFor="let j of columnsArray">
|
||||||
</div>
|
<div class="ellipsis-overflow">
|
||||||
<div class="white ellipsis-overflow">
|
{{ getMotionTitle(i, j) }}
|
||||||
<mat-basic-chip *ngIf="motion.recommendation" disableRipple [ngClass]="getStateCssColor(motion)" class="block-recommendation">
|
</div>
|
||||||
{{ getRecommendationLabel(motion) }}
|
<div class="white"><!-- ellipsis-overflow?? -->
|
||||||
</mat-basic-chip>
|
<mat-basic-chip *ngIf="hasRecommendation(i, j)" disableRipple [ngClass]="getStateCssColor(i, j)" class="block-recommendation">
|
||||||
</div>
|
{{ getRecommendationLabel(i, j) }}
|
||||||
</div>
|
</mat-basic-chip>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,4 +1,9 @@
|
|||||||
.blockitem {
|
table {
|
||||||
line-height: 1;
|
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 { MotionBlockSlideData, MotionBlockSlideMotionRepresentation } from './motion-block-slide-data';
|
||||||
import { MotionRepositoryService } from 'app/core/repositories/motions/motion-repository.service';
|
import { MotionRepositoryService } from 'app/core/repositories/motions/motion-repository.service';
|
||||||
import { StateCssClassMapping } from 'app/site/motions/models/view-workflow';
|
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';
|
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({
|
@Component({
|
||||||
selector: 'os-motion-block-slide',
|
selector: 'os-motion-block-slide',
|
||||||
templateUrl: './motion-block-slide.component.html',
|
templateUrl: './motion-block-slide.component.html',
|
||||||
@ -28,7 +33,10 @@ export class MotionBlockSlideComponent extends BaseMotionSlideComponent<MotionBl
|
|||||||
public set data(data: SlideData<MotionBlockSlideData>) {
|
public set data(data: SlideData<MotionBlockSlideData>) {
|
||||||
if (data && data.data.motions) {
|
if (data && data.data.motions) {
|
||||||
data.data.motions = data.data.motions.sort((a, b) =>
|
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;
|
this._data = data;
|
||||||
@ -38,30 +46,100 @@ export class MotionBlockSlideComponent extends BaseMotionSlideComponent<MotionBl
|
|||||||
return this._data;
|
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) {
|
public constructor(translate: TranslateService, motionRepo: MotionRepositoryService) {
|
||||||
super(translate, motionRepo);
|
super(translate, motionRepo);
|
||||||
this.languageCollator = new Intl.Collator(this.translate.currentLang);
|
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.
|
* @returns the title of the given motion.
|
||||||
*/
|
*/
|
||||||
public getMotionTitle(motion: MotionTitleInformation): string {
|
public getMotionTitle(i: number, j: number): string {
|
||||||
return this.motionRepo.getTitle(motion);
|
return this.motionRepo.getTitle(this.getMotion(i, j));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @returns the identifier (of title if identifier not availabe) of the given motion.
|
* @returns the identifier (of title if identifier not availabe) of the given motion.
|
||||||
*/
|
*/
|
||||||
public getMotionIdentifier(motion: MotionTitleInformation): string {
|
public getMotionIdentifier(i: number, j: number): string {
|
||||||
return this.motionRepo.getIdentifierOrTitle(motion);
|
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);
|
let recommendation = this.translate.instant(motion.recommendation.name);
|
||||||
if (motion.recommendation_extension) {
|
if (motion.recommendation_extension) {
|
||||||
recommendation +=
|
recommendation +=
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import re
|
import re
|
||||||
from typing import Any, Dict
|
from typing import Any, Dict, Optional
|
||||||
|
|
||||||
from ..users.projector import get_user_name
|
from ..users.projector import get_user_name
|
||||||
from ..utils.projector import (
|
from ..utils.projector import (
|
||||||
@ -121,13 +121,16 @@ async def get_amendment_base_statute(amendment, all_data):
|
|||||||
|
|
||||||
async def extend_reference_motion_dict(
|
async def extend_reference_motion_dict(
|
||||||
all_data: AllData,
|
all_data: AllData,
|
||||||
recommendation: str,
|
recommendation: Optional[str],
|
||||||
referenced_motions: Dict[int, Dict[str, str]],
|
referenced_motions: Dict[int, Dict[str, str]],
|
||||||
) -> None:
|
) -> None:
|
||||||
"""
|
"""
|
||||||
Extends a dict of motion ids mapped to their title information.
|
Extends a dict of motion ids mapped to their title information.
|
||||||
The client can replace the placeholders in the recommendation correctly.
|
The client can replace the placeholders in the recommendation correctly.
|
||||||
"""
|
"""
|
||||||
|
if recommendation is None:
|
||||||
|
return
|
||||||
|
|
||||||
# Collect all meantioned motions via [motion:<id>]
|
# Collect all meantioned motions via [motion:<id>]
|
||||||
referenced_ids = [
|
referenced_ids = [
|
||||||
int(id) for id in motion_placeholder_regex.findall(recommendation)
|
int(id) for id in motion_placeholder_regex.findall(recommendation)
|
||||||
|
Loading…
Reference in New Issue
Block a user