Use amendmend wizzard for amendments

Allows paragraph based amendments for other paragraph based
amendments.
Amendments to amendments will be amended to the main motion,
but will contain all the changes to the amendments they were
refering to

solves #5171
This commit is contained in:
Sean Engelhardt 2020-01-23 12:46:18 +01:00
parent 7a23139f5e
commit faf8004280
4 changed files with 102 additions and 33 deletions

View File

@ -715,17 +715,50 @@ export class MotionRepositoryService extends BaseIsAgendaItemAndListOfSpeakersCo
* @param {number} lineLength * @param {number} lineLength
*/ */
public getParagraphsToChoose(motion: ViewMotion, lineLength: number): ParagraphToChoose[] { public getParagraphsToChoose(motion: ViewMotion, lineLength: number): ParagraphToChoose[] {
return this.getTextParagraphs(motion, true, lineLength).map((paragraph: string, index: number) => { const parent = motion.hasParent ? motion.parent : motion;
const affected: LineNumberRange = this.lineNumbering.getLineNumberRange(paragraph); return this.getTextParagraphs(parent, true, lineLength).map((paragraph: string, index: number) => {
return { let localParagraph;
paragraphNo: index, if (motion.hasParent) {
html: this.lineNumbering.stripLineNumbers(paragraph), localParagraph = motion.amendment_paragraphs[index] ? motion.amendment_paragraphs[index] : paragraph;
lineFrom: affected.from, } else {
lineTo: affected.to localParagraph = paragraph;
}; }
return this.extractAffectedParagraphs(localParagraph, index);
}); });
} }
/**
* To create paragraph based amendments for amendments, creates diffed paragraphs
* for selection
*/
public getDiffedParagraphToChoose(amendment: ViewMotion, lineLength: number): ParagraphToChoose[] {
if (amendment.hasParent) {
const parent = amendment.parent;
return this.getTextParagraphs(parent, true, lineLength).map((paragraph: string, index: number) => {
const diffedParagraph = amendment.amendment_paragraphs[index]
? this.diff.diff(paragraph, amendment.amendment_paragraphs[index], lineLength)
: paragraph;
return this.extractAffectedParagraphs(diffedParagraph, index);
});
} else {
throw new Error('getDiffedParagraphToChoose: given amendment has no parent');
}
}
/**
* Creates a selectable and editable paragraph
*/
private extractAffectedParagraphs(paragraph: string, index: number): ParagraphToChoose {
const affected: LineNumberRange = this.lineNumbering.getLineNumberRange(paragraph);
return {
paragraphNo: index,
html: this.lineNumbering.stripLineNumbers(paragraph),
lineFrom: affected.from,
lineTo: affected.to
} as ParagraphToChoose;
}
/** /**
* Returns all paragraphs that are affected by the given amendment in diff-format * Returns all paragraphs that are affected by the given amendment in diff-format
* *

View File

@ -34,7 +34,7 @@
<ng-template matStepLabel>{{ 'Select paragraphs' | translate }}</ng-template> <ng-template matStepLabel>{{ 'Select paragraphs' | translate }}</ng-template>
<div class="amendment-create-wizard-wrapper"> <div class="amendment-create-wizard-wrapper">
<section <section
*ngFor="let paragraph of paragraphs" *ngFor="let paragraph of paragraphs; let i = index"
class="paragraph-row" class="paragraph-row"
[class.active]="isParagraphSelected(paragraph)" [class.active]="isParagraphSelected(paragraph)"
(click)="onParagraphClicked(paragraph)" (click)="onParagraphClicked(paragraph)"
@ -52,7 +52,7 @@
[checked]="isParagraphSelected(paragraph)" [checked]="isParagraphSelected(paragraph)"
> >
</mat-radio-button> </mat-radio-button>
<div class="paragraph-text motion-text" [innerHTML]="paragraph.html | trust: 'html'"></div> <div class="paragraph-text motion-text" [innerHTML]="getParagraphPreview(i) | trust: 'html'"></div>
</section> </section>
</div> </div>
</mat-step> </mat-step>

View File

@ -1,4 +1,4 @@
import { Component, ViewEncapsulation } from '@angular/core'; import { Component, OnInit, ViewEncapsulation } from '@angular/core';
import { FormBuilder, FormControl, FormGroup, Validators } from '@angular/forms'; import { FormBuilder, FormControl, FormGroup, Validators } from '@angular/forms';
import { MatSnackBar } from '@angular/material/snack-bar'; import { MatSnackBar } from '@angular/material/snack-bar';
import { Title } from '@angular/platform-browser'; import { Title } from '@angular/platform-browser';
@ -22,7 +22,7 @@ import { ViewMotion } from 'app/site/motions/models/view-motion';
styleUrls: ['./amendment-create-wizard.component.scss'], styleUrls: ['./amendment-create-wizard.component.scss'],
encapsulation: ViewEncapsulation.None encapsulation: ViewEncapsulation.None
}) })
export class AmendmentCreateWizardComponent extends BaseViewComponent { export class AmendmentCreateWizardComponent extends BaseViewComponent implements OnInit {
/** /**
* The motion to be amended * The motion to be amended
*/ */
@ -33,6 +33,17 @@ export class AmendmentCreateWizardComponent extends BaseViewComponent {
*/ */
public paragraphs: ParagraphToChoose[]; public paragraphs: ParagraphToChoose[];
/**
* Diffed version of the paragraphs, mainly for the preview
* in case of amendments of amendments
*/
public diffedParagraphs: ParagraphToChoose[];
/**
* determine if we are in the amendment of amendment mode
*/
private isAmendmentOfAmendment: boolean;
/** /**
* Change recommendation content. * Change recommendation content.
*/ */
@ -79,7 +90,9 @@ export class AmendmentCreateWizardComponent extends BaseViewComponent {
) { ) {
super(titleService, translate, matSnackBar); super(titleService, translate, matSnackBar);
this.createForm(); this.createForm();
}
public ngOnInit(): void {
this.configService.get<number>('motions_line_length').subscribe(lineLength => { this.configService.get<number>('motions_line_length').subscribe(lineLength => {
this.lineLength = lineLength; this.lineLength = lineLength;
this.getMotionByUrl(); this.getMotionByUrl();
@ -101,12 +114,30 @@ export class AmendmentCreateWizardComponent extends BaseViewComponent {
// load existing motion // load existing motion
this.route.params.subscribe(params => { this.route.params.subscribe(params => {
this.repo.getViewModelObservable(params.id).subscribe(newViewMotion => { this.repo.getViewModelObservable(params.id).subscribe(newViewMotion => {
this.motion = newViewMotion; if (newViewMotion) {
this.paragraphs = this.repo.getParagraphsToChoose(newViewMotion, this.lineLength); this.paragraphs = this.repo.getParagraphsToChoose(newViewMotion, this.lineLength);
if (newViewMotion.hasParent) {
this.isAmendmentOfAmendment = true;
this.motion = newViewMotion.parent;
this.diffedParagraphs = this.repo.getDiffedParagraphToChoose(newViewMotion, this.lineLength);
} else {
this.isAmendmentOfAmendment = false;
this.motion = newViewMotion;
}
}
}); });
}); });
} }
/**
* Creates the selectable preview of the motion paragraphs, depending
* on the amendment state
*/
public getParagraphPreview(index: number): string {
return this.isAmendmentOfAmendment ? this.diffedParagraphs[index].html : this.paragraphs[index].html;
}
/** /**
* Cancel the editing. * Cancel the editing.
* Only fires when the form was dirty * Only fires when the form was dirty

View File

@ -301,6 +301,11 @@ export class MotionDetailComponent extends BaseViewComponent implements OnInit,
*/ */
public showAmendmentContext = false; public showAmendmentContext = false;
/**
* Sets the current amendment text mode from the settings
*/
private amendmentTextMode: string;
/** /**
* For using the enum constants from the template * For using the enum constants from the template
*/ */
@ -503,6 +508,9 @@ export class MotionDetailComponent extends BaseViewComponent implements OnInit,
this.configService this.configService
.get<boolean>('motions_show_sequential_numbers') .get<boolean>('motions_show_sequential_numbers')
.subscribe(shown => (this.showSequential = shown)); .subscribe(shown => (this.showSequential = shown));
this.configService
.get<string>('motions_amendments_text_mode')
.subscribe(amendmentTextMode => (this.amendmentTextMode = amendmentTextMode));
// Update statute paragraphs // Update statute paragraphs
this.statuteRepo.getViewModelListObservable().subscribe(newViewStatuteParagraphs => { this.statuteRepo.getViewModelListObservable().subscribe(newViewStatuteParagraphs => {
@ -652,24 +660,22 @@ export class MotionDetailComponent extends BaseViewComponent implements OnInit,
this.amendmentEdit = true; this.amendmentEdit = true;
const parentMotion = this.repo.getViewModel(this.route.snapshot.queryParams.parent); const parentMotion = this.repo.getViewModel(this.route.snapshot.queryParams.parent);
const defaultTitle = `${this.translate.instant('Amendment to')} ${parentMotion.identifierOrTitle}`; const defaultTitle = `${this.translate.instant('Amendment to')} ${parentMotion.identifierOrTitle}`;
const mode = this.configService.instant<string>('motions_amendments_text_mode'); defaultMotion.title = defaultTitle;
if (mode === 'freestyle' || mode === 'fulltext') { defaultMotion.parent_id = parentMotion.id;
defaultMotion.title = defaultTitle; defaultMotion.category_id = parentMotion.category_id;
defaultMotion.parent_id = parentMotion.id; defaultMotion.tags_id = parentMotion.tags_id;
defaultMotion.category_id = parentMotion.category_id; defaultMotion.motion_block_id = parentMotion.motion_block_id;
defaultMotion.tags_id = parentMotion.tags_id; this.contentForm.patchValue({
defaultMotion.motion_block_id = parentMotion.motion_block_id; title: defaultTitle,
this.contentForm.patchValue({ category_id: parentMotion.category_id,
title: defaultTitle, motion_block_id: parentMotion.motion_block_id,
category_id: parentMotion.category_id, parent_id: parentMotion.id,
motion_block_id: parentMotion.motion_block_id, tags_id: parentMotion.tags_id
parent_id: parentMotion.id, });
tags_id: parentMotion.tags_id
}); if (this.amendmentTextMode === 'fulltext') {
}
if (mode === 'fulltext') {
defaultMotion.text = parentMotion.text; defaultMotion.text = parentMotion.text;
this.contentForm.patchValue({ text: parentMotion.text }); this.contentForm.patchValue({ text: defaultMotion.text });
} }
} }
this.motion = new ViewCreateMotion(new CreateMotion(defaultMotion)); this.motion = new ViewCreateMotion(new CreateMotion(defaultMotion));
@ -1082,8 +1088,7 @@ export class MotionDetailComponent extends BaseViewComponent implements OnInit,
* Goes to the amendment creation wizard. Executed via click. * Goes to the amendment creation wizard. Executed via click.
*/ */
public createAmendment(): void { public createAmendment(): void {
const mode = this.configService.instant<string>('motions_amendments_text_mode'); if (this.amendmentTextMode === 'paragraph') {
if (mode === 'paragraph') {
this.router.navigate(['./create-amendment'], { relativeTo: this.route }); this.router.navigate(['./create-amendment'], { relativeTo: this.route });
} else { } else {
this.router.navigate(['./motions/new-amendment'], { this.router.navigate(['./motions/new-amendment'], {