fix text formatting for multiline redactions

This commit is contained in:
Dan Percic 2023-09-15 13:42:09 +03:00
parent 8f9fff4d24
commit 6f94b1198a
4 changed files with 41 additions and 41 deletions

View File

@ -6,14 +6,16 @@
<div class="iqser-input-group w-450 selected-text-group"> <div class="iqser-input-group w-450 selected-text-group">
<label <label
[translate]=" [translate]="
initialText === form.get('selectedText').value initialText === form.controls.selectedText.value
? 'redact-text.dialog.content.selected-text' ? 'redact-text.dialog.content.selected-text'
: 'redact-text.dialog.content.text' : 'redact-text.dialog.content.text'
" "
class="selected-text" class="selected-text"
></label> ></label>
<div [ngClass]="isEditingSelectedText ? 'flex relative' : 'flex-align-items-center'" class="fixed-height"> <div [ngClass]="isEditingSelectedText ? 'flex relative' : 'flex-align-items-center'" class="fixed-height">
<span *ngIf="!isEditingSelectedText">{{ form.get('selectedText').value }}</span> <span *ngIf="!isEditingSelectedText" [innerHTML]="form.controls.selectedText.value" class="use-n-as-line-break"></span>
<textarea <textarea
*ngIf="isEditingSelectedText" *ngIf="isEditingSelectedText"
[rows]="selectedTextRows" [rows]="selectedTextRows"
@ -23,6 +25,7 @@
name="comment" name="comment"
type="text" type="text"
></textarea> ></textarea>
<iqser-circle-button <iqser-circle-button
(action)="toggleEditingSelectedText()" (action)="toggleEditingSelectedText()"
*ngIf="dictionaryRequest" *ngIf="dictionaryRequest"
@ -34,6 +37,7 @@
icon="iqser:edit" icon="iqser:edit"
tooltipPosition="below" tooltipPosition="below"
></iqser-circle-button> ></iqser-circle-button>
<iqser-circle-button <iqser-circle-button
(action)="undoTextChange()" (action)="undoTextChange()"
*ngIf="isEditingSelectedText" *ngIf="isEditingSelectedText"
@ -74,7 +78,7 @@
<div *ngIf="!dictionaryRequest" class="iqser-input-group w-450"> <div *ngIf="!dictionaryRequest" class="iqser-input-group w-450">
<label [translate]="'redact-text.dialog.content.legal-basis'"></label> <label [translate]="'redact-text.dialog.content.legal-basis'"></label>
<input [value]="form.get('reason').value?.legalBasis" disabled type="text" /> <input [value]="form.controls.reason.value?.legalBasis" disabled type="text" />
</div> </div>
<div *ngIf="dictionaryRequest" class="iqser-input-group required w-450"> <div *ngIf="dictionaryRequest" class="iqser-input-group required w-450">

View File

@ -43,3 +43,7 @@
textarea { textarea {
margin-top: 0; margin-top: 0;
} }
.use-n-as-line-break {
white-space: pre-line !important;
}

View File

@ -1,18 +1,18 @@
import { Component, inject, OnInit } from '@angular/core'; import { Component, inject, OnInit } from '@angular/core';
import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
import { FormBuilder, UntypedFormGroup } from '@angular/forms'; import { FormBuilder } from '@angular/forms';
import { DetailsRadioOption, IconButtonTypes, IqserDialogComponent } from '@iqser/common-ui'; import { DetailsRadioOption, IconButtonTypes, IqserDialogComponent } from '@iqser/common-ui';
import { Dictionary, IAddRedactionRequest, SuperTypes } from '@red/domain'; import { Dictionary, IAddRedactionRequest, SuperTypes } from '@red/domain';
import { ActiveDossiersService } from '@services/dossiers/active-dossiers.service'; import { ActiveDossiersService } from '@services/dossiers/active-dossiers.service';
import { DictionaryService } from '@services/entity-services/dictionary.service'; import { DictionaryService } from '@services/entity-services/dictionary.service';
import { JustificationsService } from '@services/entity-services/justifications.service'; import { JustificationsService } from '@services/entity-services/justifications.service';
import { Roles } from '@users/roles'; import { Roles } from '@users/roles';
import { calcTextWidthInPixels } from '@utils/functions';
import { firstValueFrom } from 'rxjs'; import { firstValueFrom } from 'rxjs';
import { tap } from 'rxjs/operators'; import { tap } from 'rxjs/operators';
import { getRedactOrHintOptions, RedactOrHintOption, RedactOrHintOptions } from '../../utils/dialog-options'; import { getRedactOrHintOptions, RedactOrHintOption, RedactOrHintOptions } from '../../utils/dialog-options';
import { RedactTextData, RedactTextResult } from '../../utils/dialog-types'; import { RedactTextData, RedactTextResult } from '../../utils/dialog-types';
import { LegalBasisOption } from '../manual-redaction-dialog/manual-annotation-dialog.component'; import { LegalBasisOption } from '../manual-redaction-dialog/manual-annotation-dialog.component';
import { calcTextWidthInPixels } from '@utils/functions';
const MAXIMUM_SELECTED_TEXT_WIDTH = 421; const MAXIMUM_SELECTED_TEXT_WIDTH = 421;
@ -24,19 +24,19 @@ export class RedactTextDialogComponent
extends IqserDialogComponent<RedactTextDialogComponent, RedactTextData, RedactTextResult> extends IqserDialogComponent<RedactTextDialogComponent, RedactTextData, RedactTextResult>
implements OnInit implements OnInit
{ {
readonly #manualRedactionTypeExists: boolean;
readonly #dossier = inject(ActiveDossiersService).find(this.data.dossierId); readonly #dossier = inject(ActiveDossiersService).find(this.data.dossierId);
readonly #manualRedactionTypeExists = inject(DictionaryService).hasManualType(this.#dossier.dossierTemplateId);
#applyToAllDossiers = this.data.applyToAllDossiers ?? true; #applyToAllDossiers = this.data.applyToAllDossiers ?? true;
readonly roles = Roles; readonly roles = Roles;
readonly iconButtonTypes = IconButtonTypes; readonly iconButtonTypes = IconButtonTypes;
readonly options: DetailsRadioOption<RedactOrHintOption>[]; readonly options = getRedactOrHintOptions(this.#dossier, this.#applyToAllDossiers, this.data.isApprover);
readonly form: UntypedFormGroup; readonly initialText = this.data?.manualRedactionEntryWrapper?.manualRedactionEntry?.value;
readonly initialText: string; readonly form = this.#getForm();
dictionaryRequest = false; dictionaryRequest = false;
legalOptions: LegalBasisOption[] = []; legalOptions: LegalBasisOption[] = [];
dictionaries: Dictionary[] = []; dictionaries: Dictionary[] = [];
isEditingSelectedText = false; isEditingSelectedText = false;
modifiedText: string; modifiedText = this.initialText;
selectedTextRows = 1; selectedTextRows = 1;
constructor( constructor(
@ -45,16 +45,8 @@ export class RedactTextDialogComponent
private readonly _formBuilder: FormBuilder, private readonly _formBuilder: FormBuilder,
) { ) {
super(); super();
this.#manualRedactionTypeExists = this._dictionaryService.hasManualType(this.#dossier.dossierTemplateId); this.form.controls.option.valueChanges
this.options = getRedactOrHintOptions(this.#dossier, this.#applyToAllDossiers, this.data.isApprover); .pipe(
this.form = this.#getForm();
this.initialText = this.data?.manualRedactionEntryWrapper?.manualRedactionEntry?.value;
this.modifiedText = this.initialText;
this.form
.get('option')
.valueChanges.pipe(
tap((option: DetailsRadioOption<RedactOrHintOption>) => { tap((option: DetailsRadioOption<RedactOrHintOption>) => {
this.dictionaryRequest = option.value === RedactOrHintOptions.IN_DOSSIER; this.dictionaryRequest = option.value === RedactOrHintOptions.IN_DOSSIER;
if (this.dictionaryRequest) { if (this.dictionaryRequest) {
@ -62,7 +54,7 @@ export class RedactTextDialogComponent
this.form.patchValue({ selectedText: this.modifiedText }); this.form.patchValue({ selectedText: this.modifiedText });
} else { } else {
this.isEditingSelectedText = false; this.isEditingSelectedText = false;
this.modifiedText = this.form.get('selectedText').value; this.modifiedText = this.form.controls.selectedText.value;
this.form.patchValue({ selectedText: this.initialText }); this.form.patchValue({ selectedText: this.initialText });
} }
this.#resetValues(); this.#resetValues();
@ -73,7 +65,7 @@ export class RedactTextDialogComponent
} }
get displayedDictionaryLabel() { get displayedDictionaryLabel() {
const dictType = this.form.get('dictionary').value; const dictType = this.form.controls.dictionary.value;
if (dictType) { if (dictType) {
return this.dictionaries.find(d => d.type === dictType)?.label ?? null; return this.dictionaries.find(d => d.type === dictType)?.label ?? null;
} }
@ -82,9 +74,9 @@ export class RedactTextDialogComponent
get disabled() { get disabled() {
if (this.dictionaryRequest) { if (this.dictionaryRequest) {
return !this.form.get('dictionary').value; return !this.form.controls.dictionary.value;
} }
return !this.form.get('reason').value; return !this.form.controls.dictionary.value;
} }
async ngOnInit(): Promise<void> { async ngOnInit(): Promise<void> {
@ -108,18 +100,18 @@ export class RedactTextDialogComponent
this.#applyToAllDossiers = option.extraOption.checked; this.#applyToAllDossiers = option.extraOption.checked;
this.#setDictionaries(); this.#setDictionaries();
if (this.#applyToAllDossiers && this.form.get('dictionary').value) { if (this.#applyToAllDossiers && this.form.controls.dictionary.value) {
const selectedDictionaryLabel = this.form.get('dictionary').value; const selectedDictionaryLabel = this.form.controls.dictionary.value;
const selectedDictionary = this.dictionaries.find(d => d.type === selectedDictionaryLabel); const selectedDictionary = this.dictionaries.find(d => d.type === selectedDictionaryLabel);
if (!selectedDictionary) { if (!selectedDictionary) {
this.form.get('dictionary').setValue(null); this.form.controls.dictionary.setValue(null);
} }
} }
} }
typeChanged() { typeChanged() {
if (!this.#applyToAllDossiers) { if (!this.#applyToAllDossiers) {
const selectedDictionaryType = this.form.get('dictionary').value; const selectedDictionaryType = this.form.controls.dictionary.value;
const selectedDictionary = this.dictionaries.find(d => d.type === selectedDictionaryType); const selectedDictionary = this.dictionaries.find(d => d.type === selectedDictionaryType);
this.options[1].extraOption.disabled = selectedDictionary.dossierDictionaryOnly; this.options[1].extraOption.disabled = selectedDictionary.dossierDictionaryOnly;
} }
@ -130,14 +122,14 @@ export class RedactTextDialogComponent
const redaction = this.data.manualRedactionEntryWrapper.manualRedactionEntry; const redaction = this.data.manualRedactionEntryWrapper.manualRedactionEntry;
this.close({ this.close({
redaction, redaction,
dictionary: this.dictionaries.find(d => d.type === this.form.get('dictionary').value), dictionary: this.dictionaries.find(d => d.type === this.form.controls.dictionary.value),
}); });
} }
toggleEditingSelectedText() { toggleEditingSelectedText() {
this.isEditingSelectedText = !this.isEditingSelectedText; this.isEditingSelectedText = !this.isEditingSelectedText;
if (this.isEditingSelectedText) { if (this.isEditingSelectedText) {
const width = calcTextWidthInPixels(this.form.get('selectedText').value); const width = calcTextWidthInPixels(this.form.controls.selectedText.value);
this.selectedTextRows = Math.ceil(width / MAXIMUM_SELECTED_TEXT_WIDTH); this.selectedTextRows = Math.ceil(width / MAXIMUM_SELECTED_TEXT_WIDTH);
} }
} }
@ -149,25 +141,25 @@ export class RedactTextDialogComponent
#getForm() { #getForm() {
return this._formBuilder.group({ return this._formBuilder.group({
selectedText: this.data?.manualRedactionEntryWrapper?.manualRedactionEntry?.value, selectedText: this.data?.manualRedactionEntryWrapper?.manualRedactionEntry?.value,
reason: [null], reason: null as LegalBasisOption,
comment: [null], comment: [null],
dictionary: [this.#manualRedactionTypeExists ? SuperTypes.ManualRedaction : null], dictionary: [this.#manualRedactionTypeExists ? SuperTypes.ManualRedaction : null],
option: [this.options[0]], option: this.options[0],
}); });
} }
#selectReason() { #selectReason() {
if (this.legalOptions.length === 1) { if (this.legalOptions.length === 1) {
this.form.get('reason').setValue(this.legalOptions[0]); this.form.controls.reason.setValue(this.legalOptions[0]);
} }
} }
#enhanceManualRedaction(addRedactionRequest: IAddRedactionRequest) { #enhanceManualRedaction(addRedactionRequest: IAddRedactionRequest) {
addRedactionRequest.type = this.form.get('dictionary').value; addRedactionRequest.type = this.form.controls.dictionary.value;
addRedactionRequest.section = null; addRedactionRequest.section = null;
addRedactionRequest.value = this.form.get('selectedText').value; addRedactionRequest.value = this.form.controls.selectedText.value;
const legalOption: LegalBasisOption = this.form.get('reason').value; const legalOption: LegalBasisOption = this.form.controls.reason.value;
if (legalOption) { if (legalOption) {
addRedactionRequest.reason = legalOption.description; addRedactionRequest.reason = legalOption.description;
addRedactionRequest.legalBasis = legalOption.legalBasis; addRedactionRequest.legalBasis = legalOption.legalBasis;
@ -184,7 +176,7 @@ export class RedactTextDialogComponent
if (!addRedactionRequest.reason) { if (!addRedactionRequest.reason) {
addRedactionRequest.reason = 'Dictionary Request'; addRedactionRequest.reason = 'Dictionary Request';
} }
const commentValue = this.form.get('comment').value; const commentValue = this.form.controls.comment.value;
addRedactionRequest.comment = commentValue ? { text: commentValue } : null; addRedactionRequest.comment = commentValue ? { text: commentValue } : null;
addRedactionRequest.addToAllDossiers = this.data.isApprover && this.dictionaryRequest && this.#applyToAllDossiers; addRedactionRequest.addToAllDossiers = this.data.isApprover && this.dictionaryRequest && this.#applyToAllDossiers;
} }
@ -193,10 +185,10 @@ export class RedactTextDialogComponent
this.#applyToAllDossiers = this.data.applyToAllDossiers ?? true; this.#applyToAllDossiers = this.data.applyToAllDossiers ?? true;
this.options[1].extraOption.checked = this.#applyToAllDossiers; this.options[1].extraOption.checked = this.#applyToAllDossiers;
if (this.dictionaryRequest) { if (this.dictionaryRequest) {
this.form.get('reason').setValue(null); this.form.controls.reason.setValue(null);
this.form.get('dictionary').setValue(null); this.form.controls.dictionary.setValue(null);
return; return;
} }
this.form.get('dictionary').setValue(this.#manualRedactionTypeExists ? SuperTypes.ManualRedaction : null); this.form.controls.dictionary.setValue(this.#manualRedactionTypeExists ? SuperTypes.ManualRedaction : null);
} }
} }

View File

@ -274,7 +274,7 @@ export class PdfProxyService {
#formatSelectedText(text: string): string { #formatSelectedText(text: string): string {
return text?.replace( return text?.replace(
// eslint-disable-next-line no-control-regex,max-len // eslint-disable-next-line no-control-regex,max-len
/([^\s\d-]{2,})[-\u00AD]\u000D\u000A|[\u000A\u000B\u000C\u000D\u0085\u2028\u2029]/gi, /([^\s\d-]{2,})[-\u00AD]\u000D|[\u000B\u000C\u000D\u0085\u2028\u2029]/gi,
'$1', '$1',
); );
} }