Merge pull request #4730 from FinnStutzenstein/motionBlockSlideLayout
Improved motion block slide layout
This commit is contained in:
commit
6f36094cde
@ -7,6 +7,9 @@ export interface MotionBlockSlideMotionRepresentation extends MotionTitleInforma
|
||||
css_class: string;
|
||||
};
|
||||
recommendation_extension?: string;
|
||||
|
||||
// This property will be calculated and saved here.
|
||||
recommendationLabel?: string;
|
||||
}
|
||||
|
||||
export interface MotionBlockSlideData {
|
||||
|
@ -4,17 +4,24 @@
|
||||
<h2><span translate>Motion block</span> – {{ data.data.motions.length }} <span translate>motions</span></h2>
|
||||
</div>
|
||||
|
||||
<div *ngIf="commonRecommendation" class="spacer-bottom-20">
|
||||
<mat-basic-chip class="large" [ngClass]="getStateCssColor(0, 0)">
|
||||
{{ commonRecommendation }}
|
||||
</mat-basic-chip>
|
||||
</div>
|
||||
|
||||
<table>
|
||||
<tr *ngFor="let i of rowsArray">
|
||||
<td *ngFor="let j of columnsArray">
|
||||
<ng-container *ngIf="getMotion(i, j)">
|
||||
<div class="ellipsis-overflow">
|
||||
<div class="ellipsis-overflow spacer-top-5">
|
||||
{{ getMotionTitle(i, j) }}
|
||||
</div>
|
||||
<div class="white">
|
||||
<mat-basic-chip *ngIf="hasRecommendation(i, j)" disableRipple [ngClass]="getStateCssColor(i, j)" class="block-recommendation">
|
||||
{{ getRecommendationLabel(i, j) }}
|
||||
<br *ngIf="!shortDisplayStyle"/>
|
||||
<span class="white" *ngIf="!commonRecommendation && getMotion(i, j).recommendationLabel">
|
||||
<mat-basic-chip disableRipple [ngClass]="getStateCssColor(i, j)" class="block-recommendation">
|
||||
{{ getMotion(i, j).recommendationLabel }}
|
||||
</mat-basic-chip>
|
||||
</span>
|
||||
</div>
|
||||
</ng-container>
|
||||
</td>
|
||||
|
@ -6,4 +6,9 @@ table {
|
||||
|
||||
td {
|
||||
min-width: 50%;
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
.mat-basic-chip.large {
|
||||
font-size: 100%;
|
||||
}
|
||||
|
@ -8,10 +8,20 @@ import { StateCssClassMapping } from 'app/site/motions/models/view-workflow';
|
||||
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;
|
||||
// Layout:
|
||||
// 1) Long layout: Motion title is shown and the motions are
|
||||
// displayed in two lines: title and recommendation. This
|
||||
// mode is used until #motions<=SHORT_LAYOUT_THRESHOLD. There
|
||||
// are ROWS_PER_COLUMN_SHORT rows per column, is MAX_COLUMNS
|
||||
// is reached. If so, thhe rows per columns will be ignored.
|
||||
// 2) Short Layout: Just motion identifier and the recommendation
|
||||
// in one line. This mode is used if #motions>SHORT_LAYOUT_THRESHOLD.
|
||||
// The same as in the log layout holds, just with ROWS_PER_COLUMN_SHORT.
|
||||
|
||||
const ROWS_PER_COLUMN_SHORT = 8;
|
||||
const ROWS_PER_COLUMN_LONG = 16;
|
||||
const SHORT_LAYOUT_THRESHOLD = 8;
|
||||
const MAX_COLUMNS = 3;
|
||||
|
||||
@Component({
|
||||
selector: 'os-motion-block-slide',
|
||||
@ -38,6 +48,36 @@ export class MotionBlockSlideComponent extends BaseMotionSlideComponent<MotionBl
|
||||
this.motionRepo.getIdentifierOrTitle(b)
|
||||
)
|
||||
);
|
||||
|
||||
// Populate the motion with the recommendation_label
|
||||
data.data.motions.forEach(motion => {
|
||||
if (motion.recommendation) {
|
||||
let recommendation = this.translate.instant(motion.recommendation.name);
|
||||
if (motion.recommendation_extension) {
|
||||
recommendation +=
|
||||
' ' +
|
||||
this.replaceReferencedMotions(
|
||||
motion.recommendation_extension,
|
||||
data.data.referenced_motions
|
||||
);
|
||||
}
|
||||
motion.recommendationLabel = recommendation;
|
||||
} else {
|
||||
motion.recommendationLabel = null;
|
||||
}
|
||||
});
|
||||
|
||||
// Check, if all motions have the same recommendation label
|
||||
if (data.data.motions.length > 0) {
|
||||
const recommendationLabel = data.data.motions[0].recommendationLabel;
|
||||
if (data.data.motions.every(motion => motion.recommendationLabel === recommendationLabel)) {
|
||||
this.commonRecommendation = recommendationLabel;
|
||||
}
|
||||
} else {
|
||||
this.commonRecommendation = null;
|
||||
}
|
||||
} else {
|
||||
this.commonRecommendation = null;
|
||||
}
|
||||
this._data = data;
|
||||
}
|
||||
@ -46,6 +86,11 @@ export class MotionBlockSlideComponent extends BaseMotionSlideComponent<MotionBl
|
||||
return this._data;
|
||||
}
|
||||
|
||||
/**
|
||||
* If this is set, all motions have the same recommendation, saved in this variable.
|
||||
*/
|
||||
public commonRecommendation: string | null = null;
|
||||
|
||||
/**
|
||||
* @returns the amount of motions in this block
|
||||
*/
|
||||
@ -57,38 +102,39 @@ export class MotionBlockSlideComponent extends BaseMotionSlideComponent<MotionBl
|
||||
}
|
||||
}
|
||||
|
||||
public get shortDisplayStyle(): boolean {
|
||||
return this.motionsAmount > SHORT_LAYOUT_THRESHOLD;
|
||||
}
|
||||
|
||||
/**
|
||||
* @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;
|
||||
return Math.ceil(this.motionsAmount / this.columns);
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns an aray with [1, ..., this.rows]
|
||||
* @returns an aray with [0, ..., this.rows-1]
|
||||
*/
|
||||
public get rowsArray(): number[] {
|
||||
const indices = [];
|
||||
const rows = this.rows;
|
||||
for (let i = 0; i < rows; i++) {
|
||||
indices.push(i);
|
||||
return this.makeIndicesArray(this.rows);
|
||||
}
|
||||
|
||||
public get columns(): number {
|
||||
const rowsPerColumn = this.shortDisplayStyle ? ROWS_PER_COLUMN_SHORT : ROWS_PER_COLUMN_LONG;
|
||||
const columns = Math.ceil(this.motionsAmount / rowsPerColumn);
|
||||
if (columns > MAX_COLUMNS) {
|
||||
return MAX_COLUMNS;
|
||||
} else {
|
||||
return columns;
|
||||
}
|
||||
return indices;
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns [0] or [0, 1] if one or two columns are used
|
||||
* @returns an aray with [0, ..., this.columns-1]
|
||||
*/
|
||||
public get columnsArray(): number[] {
|
||||
if (this.motionsAmount > TWO_COLUMNS_THRESHOLD) {
|
||||
return [0, 1];
|
||||
} else {
|
||||
return [0];
|
||||
}
|
||||
return this.makeIndicesArray(this.columns);
|
||||
}
|
||||
|
||||
public constructor(translate: TranslateService, motionRepo: MotionRepositoryService) {
|
||||
@ -96,6 +142,17 @@ export class MotionBlockSlideComponent extends BaseMotionSlideComponent<MotionBl
|
||||
this.languageCollator = new Intl.Collator(this.translate.currentLang);
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns an array [0, ..., n-1]
|
||||
*/
|
||||
public makeIndicesArray(n: number): number[] {
|
||||
const indices = [];
|
||||
for (let i = 0; i < n; i++) {
|
||||
indices.push(i);
|
||||
}
|
||||
return indices;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the motion for the cell given by i and j
|
||||
*
|
||||
@ -108,11 +165,16 @@ export class MotionBlockSlideComponent extends BaseMotionSlideComponent<MotionBl
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns the title of the given motion.
|
||||
* @returns the title of the given motion. If no title should be shown, just the
|
||||
* identifier is returned.
|
||||
*/
|
||||
public getMotionTitle(i: number, j: number): string {
|
||||
if (this.shortDisplayStyle) {
|
||||
return this.motionRepo.getIdentifierOrTitle(this.getMotion(i, j));
|
||||
} else {
|
||||
return this.motionRepo.getTitle(this.getMotion(i, j));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns the identifier (of title if identifier not availabe) of the given motion.
|
||||
@ -121,30 +183,10 @@ export class MotionBlockSlideComponent extends BaseMotionSlideComponent<MotionBl
|
||||
return this.motionRepo.getIdentifierOrTitle(this.getMotion(i, j));
|
||||
}
|
||||
|
||||
/**
|
||||
* @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;
|
||||
}
|
||||
|
||||
/**
|
||||
* @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 +=
|
||||
' ' + this.replaceReferencedMotions(motion.recommendation_extension, this.data.data.referenced_motions);
|
||||
}
|
||||
return recommendation;
|
||||
}
|
||||
}
|
||||
|
@ -505,6 +505,9 @@ button.mat-menu-item.selected {
|
||||
.spacer-top-3 {
|
||||
margin-top: 3px !important;
|
||||
}
|
||||
.spacer-top-5 {
|
||||
margin-top: 5px !important;
|
||||
}
|
||||
.spacer-top-10 {
|
||||
margin-top: 10px !important;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user