diff --git a/client/src/app/core/repositories/motions/motion-repository.service.ts b/client/src/app/core/repositories/motions/motion-repository.service.ts index 32842a1b8..2cad3fbf4 100644 --- a/client/src/app/core/repositories/motions/motion-repository.service.ts +++ b/client/src/app/core/repositories/motions/motion-repository.service.ts @@ -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 * diff --git a/client/src/app/site/motions/modules/motion-detail/components/amendment-create-wizard/amendment-create-wizard.component.html b/client/src/app/site/motions/modules/motion-detail/components/amendment-create-wizard/amendment-create-wizard.component.html index 976577164..45b136867 100644 --- a/client/src/app/site/motions/modules/motion-detail/components/amendment-create-wizard/amendment-create-wizard.component.html +++ b/client/src/app/site/motions/modules/motion-detail/components/amendment-create-wizard/amendment-create-wizard.component.html @@ -34,7 +34,7 @@ {{ 'Select paragraphs' | translate }}
-
+
diff --git a/client/src/app/site/motions/modules/motion-detail/components/amendment-create-wizard/amendment-create-wizard.component.ts b/client/src/app/site/motions/modules/motion-detail/components/amendment-create-wizard/amendment-create-wizard.component.ts index ea418745c..c4e0f26b7 100644 --- a/client/src/app/site/motions/modules/motion-detail/components/amendment-create-wizard/amendment-create-wizard.component.ts +++ b/client/src/app/site/motions/modules/motion-detail/components/amendment-create-wizard/amendment-create-wizard.component.ts @@ -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('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 diff --git a/client/src/app/site/motions/modules/motion-detail/components/motion-detail/motion-detail.component.ts b/client/src/app/site/motions/modules/motion-detail/components/motion-detail/motion-detail.component.ts index 311807d31..3705d09c4 100644 --- a/client/src/app/site/motions/modules/motion-detail/components/motion-detail/motion-detail.component.ts +++ b/client/src/app/site/motions/modules/motion-detail/components/motion-detail/motion-detail.component.ts @@ -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('motions_show_sequential_numbers') .subscribe(shown => (this.showSequential = shown)); + this.configService + .get('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('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('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'], {