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
*/
public getParagraphsToChoose(motion: ViewMotion, lineLength: number): ParagraphToChoose[] {
return this.getTextParagraphs(motion, true, lineLength).map((paragraph: string, index: number) => {
const affected: LineNumberRange = this.lineNumbering.getLineNumberRange(paragraph);
return {
paragraphNo: index,
html: this.lineNumbering.stripLineNumbers(paragraph),
lineFrom: affected.from,
lineTo: affected.to
};
const parent = motion.hasParent ? motion.parent : motion;
return this.getTextParagraphs(parent, true, lineLength).map((paragraph: string, index: number) => {
let localParagraph;
if (motion.hasParent) {
localParagraph = motion.amendment_paragraphs[index] ? motion.amendment_paragraphs[index] : paragraph;
} else {
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
*

View File

@ -34,7 +34,7 @@
<ng-template matStepLabel>{{ 'Select paragraphs' | translate }}</ng-template>
<div class="amendment-create-wizard-wrapper">
<section
*ngFor="let paragraph of paragraphs"
*ngFor="let paragraph of paragraphs; let i = index"
class="paragraph-row"
[class.active]="isParagraphSelected(paragraph)"
(click)="onParagraphClicked(paragraph)"
@ -52,7 +52,7 @@
[checked]="isParagraphSelected(paragraph)"
>
</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>
</div>
</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 { MatSnackBar } from '@angular/material/snack-bar';
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'],
encapsulation: ViewEncapsulation.None
})
export class AmendmentCreateWizardComponent extends BaseViewComponent {
export class AmendmentCreateWizardComponent extends BaseViewComponent implements OnInit {
/**
* The motion to be amended
*/
@ -33,6 +33,17 @@ export class AmendmentCreateWizardComponent extends BaseViewComponent {
*/
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.
*/
@ -79,7 +90,9 @@ export class AmendmentCreateWizardComponent extends BaseViewComponent {
) {
super(titleService, translate, matSnackBar);
this.createForm();
}
public ngOnInit(): void {
this.configService.get<number>('motions_line_length').subscribe(lineLength => {
this.lineLength = lineLength;
this.getMotionByUrl();
@ -101,12 +114,30 @@ export class AmendmentCreateWizardComponent extends BaseViewComponent {
// load existing motion
this.route.params.subscribe(params => {
this.repo.getViewModelObservable(params.id).subscribe(newViewMotion => {
this.motion = newViewMotion;
this.paragraphs = this.repo.getParagraphsToChoose(newViewMotion, this.lineLength);
if (newViewMotion) {
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.
* Only fires when the form was dirty

View File

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