Add trust pipe and remove duplicated functions

Adds a new shared pipe to set trusted HTML directly
from HTML components.
Removes all duplicates of "bypassSecurityTrustHtml"
This commit is contained in:
Sean Engelhardt 2019-09-16 16:24:40 +02:00
parent 4a83aa736e
commit 4e0f1409db
36 changed files with 173 additions and 299 deletions

View File

@ -1,5 +1,4 @@
import { Injectable } from '@angular/core'; import { Injectable } from '@angular/core';
import { DomSanitizer, SafeHtml } from '@angular/platform-browser';
import { TranslateService } from '@ngx-translate/core'; import { TranslateService } from '@ngx-translate/core';
import { Observable } from 'rxjs'; import { Observable } from 'rxjs';
@ -51,12 +50,7 @@ export interface ParagraphToChoose {
/** /**
* The raw HTML of this paragraph. * The raw HTML of this paragraph.
*/ */
rawHtml: string; html: string;
/**
* The HTML of this paragraph, wrapped in a `SafeHtml`-object.
*/
safeHtml: SafeHtml;
/** /**
* The first line number * The first line number
@ -186,7 +180,6 @@ export class MotionRepositoryService extends BaseIsAgendaItemAndListOfSpeakersCo
* @param mapperService Maps collection strings to classes * @param mapperService Maps collection strings to classes
* @param dataSend sending changed objects * @param dataSend sending changed objects
* @param httpService OpenSlides own Http service * @param httpService OpenSlides own Http service
* @param sanitizer DOM Sanitizer
* @param lineNumbering Line numbering for motion text * @param lineNumbering Line numbering for motion text
* @param diff Display changes in motion text as diff. * @param diff Display changes in motion text as diff.
* @param personalNoteService service fo personal notes * @param personalNoteService service fo personal notes
@ -201,7 +194,6 @@ export class MotionRepositoryService extends BaseIsAgendaItemAndListOfSpeakersCo
relationManager: RelationManagerService, relationManager: RelationManagerService,
config: ConfigService, config: ConfigService,
private httpService: HttpService, private httpService: HttpService,
private readonly sanitizer: DomSanitizer,
private readonly lineNumbering: LinenumberingService, private readonly lineNumbering: LinenumberingService,
private readonly diff: DiffService, private readonly diff: DiffService,
private operator: OperatorService private operator: OperatorService
@ -713,8 +705,7 @@ export class MotionRepositoryService extends BaseIsAgendaItemAndListOfSpeakersCo
const affected: LineNumberRange = this.lineNumbering.getLineNumberRange(paragraph); const affected: LineNumberRange = this.lineNumbering.getLineNumberRange(paragraph);
return { return {
paragraphNo: index, paragraphNo: index,
safeHtml: this.sanitizer.bypassSecurityTrustHtml(paragraph), html: this.lineNumbering.stripLineNumbers(paragraph),
rawHtml: this.lineNumbering.stripLineNumbers(paragraph),
lineFrom: affected.from, lineFrom: affected.from,
lineTo: affected.to lineTo: affected.to
}; };

View File

@ -1,6 +1,6 @@
<mat-card class="os-card"> <mat-card class="os-card">
<div> <div>
<div *ngIf="legalNotice" class="legal-notice-text" [innerHtml]="legalNotice"></div> <div *ngIf="legalNotice" class="legal-notice-text" [innerHtml]="legalNotice | trust: 'html'"></div>
<div *ngIf="!legalNotice" translate> <div *ngIf="!legalNotice" translate>
The event manager hasn't set up a legal notice yet. The event manager hasn't set up a legal notice yet.
</div> </div>

View File

@ -27,13 +27,13 @@
<mat-card class="os-card" *ngIf="entry.value !== '' && !entry.blockProperties"> <mat-card class="os-card" *ngIf="entry.value !== '' && !entry.blockProperties">
<div class="key-part">{{ entry.key | translate }}</div> <div class="key-part">{{ entry.key | translate }}</div>
<div *ngIf="!entry.trusted">{{ entry.value }}</div> <div *ngIf="!entry.trusted">{{ entry.value }}</div>
<div *ngIf="entry.trusted" [innerHTML]="sanitize(entry.value)"></div> <div *ngIf="entry.trusted" [innerHTML]="entry.value | trust: 'html'"></div>
</mat-card> </mat-card>
<mat-card class="os-card" *ngIf="entry.blockProperties"> <mat-card class="os-card" *ngIf="entry.blockProperties">
<div *ngFor="let property of entry.blockProperties"> <div *ngFor="let property of entry.blockProperties">
<div class="key-part">{{ property.key | translate }}</div> <div class="key-part">{{ property.key | translate }}</div>
<div *ngIf="!property.trusted">{{ property.value }}</div> <div *ngIf="!property.trusted">{{ property.value }}</div>
<div *ngIf="property.trusted" [innerHTML]="sanitize(property.value)"></div> <div *ngIf="property.trusted" [innerHTML]="property.value | trust: 'html'"></div>
</div> </div>
</mat-card> </mat-card>
</div> </div>

View File

@ -1,5 +1,4 @@
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, Input, OnDestroy } from '@angular/core'; import { ChangeDetectionStrategy, ChangeDetectorRef, Component, Input, OnDestroy } from '@angular/core';
import { DomSanitizer, SafeHtml } from '@angular/platform-browser';
import { SearchProperty } from 'app/core/ui-services/search.service'; import { SearchProperty } from 'app/core/ui-services/search.service';
import { BaseViewModel } from 'app/site/base/base-view-model'; import { BaseViewModel } from 'app/site/base/base-view-model';
@ -45,10 +44,8 @@ export class PreviewComponent implements OnDestroy {
/** /**
* Default constructor * Default constructor
*
* @param sanitizer DomSanitizer
*/ */
public constructor(private sanitizer: DomSanitizer, private cd: ChangeDetectorRef) {} public constructor(private cd: ChangeDetectorRef) {}
/** /**
* detach the change detection * detach the change detection
@ -56,15 +53,4 @@ export class PreviewComponent implements OnDestroy {
public ngOnDestroy(): void { public ngOnDestroy(): void {
this.cd.detach(); this.cd.detach();
} }
/**
* Function to sanitize any text to show html.
*
* @param text The text to sanitize.
*
* @returns {SafeHtml} The sanitized text as `HTML`.
*/
public sanitize(text: string): SafeHtml {
return this.sanitizer.bypassSecurityTrustHtml(text);
}
} }

View File

@ -1,5 +1,5 @@
<mat-card class="os-card"> <mat-card class="os-card">
<div *ngIf="privacyPolicy" [innerHtml]="privacyPolicy"></div> <div *ngIf="privacyPolicy" [innerHtml]="privacyPolicy | trust: 'html'"></div>
<div *ngIf="!privacyPolicy" translate> <div *ngIf="!privacyPolicy" translate>
The event manager hasn't set up a privacy policy yet. The event manager hasn't set up a privacy policy yet.
</div> </div>

View File

@ -0,0 +1,11 @@
import { inject } from '@angular/core/testing';
import { DomSanitizer } from '@angular/platform-browser';
import { TrustPipe } from './trust.pipe';
describe('TrustHtmlPipe', () => {
it('create an instance', inject([DomSanitizer], (domSanitizer: DomSanitizer) => {
const pipe = new TrustPipe(domSanitizer);
expect(pipe).toBeTruthy();
}));
});

View File

@ -0,0 +1,29 @@
import { Pipe, PipeTransform } from '@angular/core';
import { DomSanitizer, SafeHtml, SafeResourceUrl, SafeScript, SafeStyle, SafeUrl } from '@angular/platform-browser';
/**
* Pipe to use bypassSecurityTrust
*/
@Pipe({
name: 'trust'
})
export class TrustPipe implements PipeTransform {
public constructor(protected sanitizer: DomSanitizer) {}
public transform(value: any, type: string): SafeHtml | SafeStyle | SafeScript | SafeUrl | SafeResourceUrl {
switch (type) {
case 'html':
return this.sanitizer.bypassSecurityTrustHtml(value);
case 'style':
return this.sanitizer.bypassSecurityTrustStyle(value);
case 'script':
return this.sanitizer.bypassSecurityTrustScript(value);
case 'url':
return this.sanitizer.bypassSecurityTrustUrl(value);
case 'resourceUrl':
return this.sanitizer.bypassSecurityTrustResourceUrl(value);
default:
throw new Error(`Invalid safe type specified: ${type}`);
}
}
}

View File

@ -107,6 +107,7 @@ import { PreviewComponent } from './components/preview/preview.component';
import { PdfViewerModule } from 'ng2-pdf-viewer'; import { PdfViewerModule } from 'ng2-pdf-viewer';
import { GlobalSpinnerComponent } from 'app/site/common/components/global-spinner/global-spinner.component'; import { GlobalSpinnerComponent } from 'app/site/common/components/global-spinner/global-spinner.component';
import { HeightResizingDirective } from './directives/height-resizing.directive'; import { HeightResizingDirective } from './directives/height-resizing.directive';
import { TrustPipe } from './pipes/trust.pipe';
/** /**
* Share Module for all "dumb" components and pipes. * Share Module for all "dumb" components and pipes.
@ -254,7 +255,8 @@ import { HeightResizingDirective } from './directives/height-resizing.directive'
GlobalSpinnerComponent, GlobalSpinnerComponent,
OverlayComponent, OverlayComponent,
PreviewComponent, PreviewComponent,
NgxMaterialTimepickerModule NgxMaterialTimepickerModule,
TrustPipe
], ],
declarations: [ declarations: [
PermsDirective, PermsDirective,
@ -299,7 +301,8 @@ import { HeightResizingDirective } from './directives/height-resizing.directive'
SuperSearchComponent, SuperSearchComponent,
OverlayComponent, OverlayComponent,
PreviewComponent, PreviewComponent,
HeightResizingDirective HeightResizingDirective,
TrustPipe
], ],
providers: [ providers: [
{ {
@ -313,7 +316,8 @@ import { HeightResizingDirective } from './directives/height-resizing.directive'
SortFilterBarComponent, SortFilterBarComponent,
SortBottomSheetComponent, SortBottomSheetComponent,
DecimalPipe, DecimalPipe,
ProgressSnackBarComponent ProgressSnackBarComponent,
TrustPipe
], ],
entryComponents: [ entryComponents: [
SortBottomSheetComponent, SortBottomSheetComponent,

View File

@ -76,7 +76,7 @@
<div *ngIf="assignment"> <div *ngIf="assignment">
<div <div
*ngIf="assignment.assignment.description" *ngIf="assignment.assignment.description"
[innerHTML]="getSanitizedText(assignment.assignment.description)" [innerHTML]="assignment.assignment.description | trust: 'html'"
></div> ></div>
</div> </div>
<div class="meta-info-grid"> <div class="meta-info-grid">

View File

@ -1,7 +1,7 @@
import { Component, OnInit } from '@angular/core'; import { Component, OnInit } from '@angular/core';
import { FormBuilder, FormGroup, Validators } from '@angular/forms'; import { FormBuilder, FormGroup, Validators } from '@angular/forms';
import { MatSnackBar } from '@angular/material'; import { MatSnackBar } from '@angular/material';
import { DomSanitizer, SafeHtml, Title } from '@angular/platform-browser'; import { Title } from '@angular/platform-browser';
import { ActivatedRoute, Router } from '@angular/router'; import { ActivatedRoute, Router } from '@angular/router';
import { TranslateService } from '@ngx-translate/core'; import { TranslateService } from '@ngx-translate/core';
@ -181,8 +181,7 @@ export class AssignmentDetailComponent extends BaseViewComponent implements OnIn
private tagRepo: TagRepositoryService, private tagRepo: TagRepositoryService,
private promptService: PromptService, private promptService: PromptService,
private pdfService: AssignmentPdfExportService, private pdfService: AssignmentPdfExportService,
private mediafileRepo: MediafileRepositoryService, private mediafileRepo: MediafileRepositoryService
private sanitizer: DomSanitizer
) { ) {
super(title, translate, matSnackBar); super(title, translate, matSnackBar);
this.subscriptions.push( this.subscriptions.push(
@ -503,17 +502,6 @@ export class AssignmentDetailComponent extends BaseViewComponent implements OnIn
.then(null, this.raiseError); .then(null, this.raiseError);
} }
/**
* Sanitize the text.
*
* @param text {string} The text to display.
*
* @returns {SafeHtml} the sanitized text.
*/
public getSanitizedText(text: string): SafeHtml {
return this.sanitizer.bypassSecurityTrustHtml(text);
}
public addToAgenda(): void { public addToAgenda(): void {
this.itemRepo.addItemToAgenda(this.assignment).then(null, this.raiseError); this.itemRepo.addItemToAgenda(this.assignment).then(null, this.raiseError);
} }

View File

@ -8,6 +8,6 @@
<div class="app-content"> <div class="app-content">
<h1>{{ welcomeTitle | translate }}</h1> <h1>{{ welcomeTitle | translate }}</h1>
<div [innerHTML]="welcomeText"></div> <div [innerHTML]="welcomeText | trust: 'html'"></div>
</div> </div>
</mat-card> </mat-card>

View File

@ -1,5 +1,5 @@
import { Component, OnInit } from '@angular/core'; import { Component, OnInit } from '@angular/core';
import { DomSanitizer, SafeHtml, Title } from '@angular/platform-browser'; import { Title } from '@angular/platform-browser';
import { TranslateService } from '@ngx-translate/core'; // showcase import { TranslateService } from '@ngx-translate/core'; // showcase
@ -16,7 +16,7 @@ import { ConfigService } from 'app/core/ui-services/config.service';
}) })
export class StartComponent extends BaseComponent implements OnInit { export class StartComponent extends BaseComponent implements OnInit {
public welcomeTitle: string; public welcomeTitle: string;
public welcomeText: SafeHtml; public welcomeText: string;
/** /**
* Constructor of the StartComponent * Constructor of the StartComponent
@ -24,14 +24,8 @@ export class StartComponent extends BaseComponent implements OnInit {
* @param titleService the title serve * @param titleService the title serve
* @param translate to translation module * @param translate to translation module
* @param configService read out config values * @param configService read out config values
* @param sanitizer
*/ */
public constructor( public constructor(titleService: Title, translate: TranslateService, private configService: ConfigService) {
titleService: Title,
translate: TranslateService,
private configService: ConfigService,
private sanitizer: DomSanitizer
) {
super(titleService, translate); super(titleService, translate);
} }
@ -50,18 +44,7 @@ export class StartComponent extends BaseComponent implements OnInit {
// set the welcome text // set the welcome text
this.configService.get<string>('general_event_welcome_text').subscribe(welcomeText => { this.configService.get<string>('general_event_welcome_text').subscribe(welcomeText => {
this.welcomeText = this.sanitizeText(this.translate.instant(welcomeText)); this.welcomeText = this.translate.instant(welcomeText);
}); });
} }
/**
* Sanitizes the value from database.
*
* @param text The plain text to sanitize.
*
* @returns {SafeHtml} Html, that will be rendered with styles and so on...
*/
public sanitizeText(text: string): SafeHtml {
return this.sanitizer.bypassSecurityTrustHtml(text);
}
} }

View File

@ -84,7 +84,7 @@
<div *pblNgridCellDef="'summary'; row as motion" class="cell-slot fill"> <div *pblNgridCellDef="'summary'; row as motion" class="cell-slot fill">
<a class="detail-link" [routerLink]="motion.getDetailStateURL()"></a> <a class="detail-link" [routerLink]="motion.getDetailStateURL()"></a>
<div class="innerTable"> <div class="innerTable">
<div class="motion-text" [innerHtml]="sanitizeText(getAmendmentSummary(motion))"></div> <div class="motion-text" [innerHtml]="getAmendmentSummary(motion) | trust: 'html'"></div>
</div> </div>
</div> </div>

View File

@ -1,6 +1,6 @@
import { ChangeDetectionStrategy, Component, OnInit, ViewEncapsulation } from '@angular/core'; import { ChangeDetectionStrategy, Component, OnInit, ViewEncapsulation } from '@angular/core';
import { MatDialog, MatSnackBar } from '@angular/material'; import { MatDialog, MatSnackBar } from '@angular/material';
import { DomSanitizer, SafeHtml, Title } from '@angular/platform-browser'; import { Title } from '@angular/platform-browser';
import { ActivatedRoute, ParamMap } from '@angular/router'; import { ActivatedRoute, ParamMap } from '@angular/router';
import { TranslateService } from '@ngx-translate/core'; import { TranslateService } from '@ngx-translate/core';
@ -94,7 +94,6 @@ export class AmendmentListComponent extends BaseListViewComponent<ViewMotion> im
public motionSortService: MotionSortListService, public motionSortService: MotionSortListService,
public amendmentSortService: AmendmentSortListService, public amendmentSortService: AmendmentSortListService,
public amendmentFilterService: AmendmentFilterListService, public amendmentFilterService: AmendmentFilterListService,
private sanitizer: DomSanitizer,
private dialog: MatDialog, private dialog: MatDialog,
private motionExport: MotionExportService, private motionExport: MotionExportService,
private linenumberingService: LinenumberingService, private linenumberingService: LinenumberingService,
@ -163,8 +162,4 @@ export class AmendmentListComponent extends BaseListViewComponent<ViewMotion> im
const parentMotion = this.parentMotionId ? this.motionRepo.getViewModel(this.parentMotionId) : undefined; const parentMotion = this.parentMotionId ? this.motionRepo.getViewModel(this.parentMotionId) : undefined;
this.pdfExport.exportAmendmentList(this.dataSource.filteredData, parentMotion); this.pdfExport.exportAmendmentList(this.dataSource.filteredData, parentMotion);
} }
public sanitizeText(text: string): SafeHtml {
return this.sanitizer.bypassSecurityTrustHtml(text);
}
} }

View File

@ -12,7 +12,11 @@
<!-- Next-button --> <!-- Next-button -->
<div class="extra-controls-slot"> <div class="extra-controls-slot">
<div *ngIf="matStepper.selectedIndex === 0"> <div *ngIf="matStepper.selectedIndex === 0">
<button mat-button [disabled]="contentForm.value.selectedParagraphs.length === 0" (click)="matStepper.next()"> <button
mat-button
[disabled]="contentForm.value.selectedParagraphs.length === 0"
(click)="matStepper.next()"
>
<span class="upper" translate>Next</span> <span class="upper" translate>Next</span>
</button> </button>
</div> </div>
@ -48,7 +52,7 @@
[checked]="isParagraphSelected(paragraph)" [checked]="isParagraphSelected(paragraph)"
> >
</mat-radio-button> </mat-radio-button>
<div class="paragraph-text motion-text" [innerHTML]="paragraph.safeHtml"></div> <div class="paragraph-text motion-text" [innerHTML]="paragraph.html | trust: 'html'"></div>
</section> </section>
</div> </div>
</mat-step> </mat-step>

View File

@ -158,7 +158,7 @@ export class AmendmentCreateWizardComponent extends BaseViewComponent {
}); });
this.contentForm.addControl( this.contentForm.addControl(
'text_' + paragraph.paragraphNo, 'text_' + paragraph.paragraphNo,
new FormControl(paragraph.rawHtml, Validators.required) new FormControl(paragraph.html, Validators.required)
); );
this.contentForm.patchValue({ this.contentForm.patchValue({
selectedParagraphs: [paragraph] selectedParagraphs: [paragraph]
@ -195,7 +195,7 @@ export class AmendmentCreateWizardComponent extends BaseViewComponent {
this.contentForm.addControl( this.contentForm.addControl(
'text_' + paragraph.paragraphNo, 'text_' + paragraph.paragraphNo,
new FormControl(paragraph.rawHtml, Validators.required) new FormControl(paragraph.html, Validators.required)
); );
this.contentForm.patchValue({ this.contentForm.patchValue({
selectedParagraphs: newParagraphs selectedParagraphs: newParagraphs

View File

@ -11,7 +11,7 @@
<ng-container class="meta-text-block-content"> <ng-container class="meta-text-block-content">
<ng-container *ngIf="!isCommentEdited(section)"> <ng-container *ngIf="!isCommentEdited(section)">
<div *ngIf="comments[section.id]" [innerHTML]="sanitizeText(comments[section.id].comment)"></div> <div *ngIf="comments[section.id]" [innerHTML]="comments[section.id].comment | trust: 'html'"></div>
<div class="no-content" *ngIf="!comments[section.id] || !comments[section.id].comment" translate> <div class="no-content" *ngIf="!comments[section.id] || !comments[section.id].comment" translate>
No comment No comment
</div> </div>

View File

@ -1,7 +1,7 @@
import { Component, Input } from '@angular/core'; import { Component, Input } from '@angular/core';
import { FormBuilder, FormGroup } from '@angular/forms'; import { FormBuilder, FormGroup } from '@angular/forms';
import { MatSnackBar } from '@angular/material/snack-bar'; import { MatSnackBar } from '@angular/material/snack-bar';
import { DomSanitizer, SafeHtml, Title } from '@angular/platform-browser'; import { Title } from '@angular/platform-browser';
import { TranslateService } from '@ngx-translate/core'; import { TranslateService } from '@ngx-translate/core';
@ -65,7 +65,6 @@ export class MotionCommentsComponent extends BaseViewComponent {
* @param formBuilder Form builder to handle text editing * @param formBuilder Form builder to handle text editing
* @param operator service to get the sections * @param operator service to get the sections
* @param pdfService service to export a comment section to pdf * @param pdfService service to export a comment section to pdf
* @param sanitizer to sanitize the inner html text
* @param titleService set the browser title * @param titleService set the browser title
* @param translate the translation service * @param translate the translation service
* @param matSnackBar showing errors and information * @param matSnackBar showing errors and information
@ -75,7 +74,6 @@ export class MotionCommentsComponent extends BaseViewComponent {
private formBuilder: FormBuilder, private formBuilder: FormBuilder,
private operator: OperatorService, private operator: OperatorService,
private pdfService: MotionPdfExportService, private pdfService: MotionPdfExportService,
private sanitizer: DomSanitizer,
titleService: Title, titleService: Title,
translate: TranslateService, translate: TranslateService,
matSnackBar: MatSnackBar matSnackBar: MatSnackBar
@ -189,15 +187,4 @@ export class MotionCommentsComponent extends BaseViewComponent {
public pdfExportSection(section: ViewMotionCommentSection): void { public pdfExportSection(section: ViewMotionCommentSection): void {
this.pdfService.exportComment(section, this.motion); this.pdfService.exportComment(section, this.motion);
} }
/**
* Sanitize the text to be safe.
*
* @param text to be sanitized.
*
* @returns SafeHtml
*/
public sanitizeText(text: string): SafeHtml {
return this.sanitizer.bypassSecurityTrustHtml(text);
}
} }

View File

@ -67,7 +67,7 @@
[attr.data-change-id]="changedTitle.getChangeId()" [attr.data-change-id]="changedTitle.getChangeId()"
> >
<div class="bold">{{ 'Changed title' | translate }}:</div> <div class="bold">{{ 'Changed title' | translate }}:</div>
<div [innerHTML]="getFormattedTitleDiff()"></div> <div [innerHTML]="getFormattedTitleDiff() | trust: 'html'"></div>
</div> </div>
</div> </div>
</div> </div>
@ -122,7 +122,7 @@
[class.line-numbers-inline]="isLineNumberingInline()" [class.line-numbers-inline]="isLineNumberingInline()"
[class.line-numbers-outside]="isLineNumberingOutside()" [class.line-numbers-outside]="isLineNumberingOutside()"
[attr.data-change-id]="change.getChangeId()" [attr.data-change-id]="change.getChangeId()"
[innerHTML]="getDiff(change)" [innerHTML]="getDiff(change) | trust: 'html'"
></div> ></div>
</div> </div>
</div> </div>

View File

@ -1,7 +1,7 @@
import { AfterViewInit, Component, ElementRef, EventEmitter, Input, Output } from '@angular/core'; import { AfterViewInit, Component, ElementRef, EventEmitter, Input, Output } from '@angular/core';
import { MatDialog } from '@angular/material/dialog'; import { MatDialog } from '@angular/material/dialog';
import { MatSnackBar } from '@angular/material/snack-bar'; import { MatSnackBar } from '@angular/material/snack-bar';
import { DomSanitizer, SafeHtml, Title } from '@angular/platform-browser'; import { Title } from '@angular/platform-browser';
import { TranslateService } from '@ngx-translate/core'; import { TranslateService } from '@ngx-translate/core';
@ -81,7 +81,6 @@ export class MotionDetailDiffComponent extends BaseViewComponent implements Afte
* @param title * @param title
* @param translate * @param translate
* @param matSnackBar * @param matSnackBar
* @param sanitizer
* @param diff * @param diff
* @param recoRepo * @param recoRepo
* @param dialogService * @param dialogService
@ -93,7 +92,6 @@ export class MotionDetailDiffComponent extends BaseViewComponent implements Afte
title: Title, title: Title,
protected translate: TranslateService, // protected required for ng-translate-extract protected translate: TranslateService, // protected required for ng-translate-extract
matSnackBar: MatSnackBar, matSnackBar: MatSnackBar,
private sanitizer: DomSanitizer,
private diff: DiffService, private diff: DiffService,
private recoRepo: ChangeRecommendationRepositoryService, private recoRepo: ChangeRecommendationRepositoryService,
private dialogService: MatDialog, private dialogService: MatDialog,
@ -157,9 +155,8 @@ export class MotionDetailDiffComponent extends BaseViewComponent implements Afte
* Returns the diff string from the motion to the change * Returns the diff string from the motion to the change
* @param {ViewUnifiedChange} change * @param {ViewUnifiedChange} change
*/ */
public getDiff(change: ViewUnifiedChange): SafeHtml { public getDiff(change: ViewUnifiedChange): string {
const html = this.diff.getChangeDiff(this.motion.text, change, this.lineLength, this.highlightedLine); return this.diff.getChangeDiff(this.motion.text, change, this.lineLength, this.highlightedLine);
return this.sanitizer.bypassSecurityTrustHtml(html);
} }
/** /**
@ -253,9 +250,9 @@ export class MotionDetailDiffComponent extends BaseViewComponent implements Afte
return this.changes.find((obj: ViewUnifiedChange) => obj.isTitleChange()); return this.changes.find((obj: ViewUnifiedChange) => obj.isTitleChange());
} }
public getFormattedTitleDiff(): SafeHtml { public getFormattedTitleDiff(): string {
const change = this.getTitleChangingObject(); const change = this.getTitleChangingObject();
return this.sanitizer.bypassSecurityTrustHtml(this.recoRepo.getTitleChangesAsDiff(this.motion.title, change)); return this.recoRepo.getTitleChangesAsDiff(this.motion.title, change);
} }
/** /**

View File

@ -655,7 +655,7 @@
></os-motion-detail-original-change-recommendations> ></os-motion-detail-original-change-recommendations>
<div <div
*ngIf="!isLineNumberingOutside() || !isRecoMode(ChangeRecoMode.Original)" *ngIf="!isLineNumberingOutside() || !isRecoMode(ChangeRecoMode.Original)"
[innerHTML]="sanitizedText(getFormattedTextPlain())" [innerHTML]="getFormattedTextPlain() | trust: 'html'"
></div> ></div>
</div> </div>
<os-motion-detail-diff <os-motion-detail-diff
@ -693,7 +693,7 @@
<div <div
class="motion-text line-numbers-none" class="motion-text line-numbers-none"
*ngIf="!editMotion && motion.isStatuteAmendment()" *ngIf="!editMotion && motion.isStatuteAmendment()"
[innerHTML]="getFormattedStatuteAmendment()" [innerHTML]="getFormattedStatuteAmendment() | trust: 'html'"
></div> ></div>
<!-- The HTML Editor for motions and traditional amendments --> <!-- The HTML Editor for motions and traditional amendments -->
@ -755,7 +755,7 @@
> >
<span translate>Reason</span>&nbsp;<span *ngIf="reasonRequired && editMotion">*</span> <span translate>Reason</span>&nbsp;<span *ngIf="reasonRequired && editMotion">*</span>
</h3> </h3>
<div class="motion-text" *ngIf="!editMotion"><div [innerHtml]="sanitizedText(motion.reason)"></div></div> <div class="motion-text" *ngIf="!editMotion" [innerHtml]="motion.reason | trust: 'html'"></div>
<!-- The HTML Editor --> <!-- The HTML Editor -->
<editor <editor
@ -883,9 +883,10 @@
{{ 'Line' | translate }} {{ paragraph.diffLineFrom }} - {{ paragraph.diffLineTo - 1 }}: {{ 'Line' | translate }} {{ paragraph.diffLineFrom }} - {{ paragraph.diffLineTo - 1 }}:
</h3> </h3>
<div class="paragraphcontext" [innerHtml]="sanitizedText(paragraph.textPre)"></div> <!-- TODO: Seems to be directly duplicated in the slide -->
<div [innerHtml]="sanitizedText(paragraph.text)"></div> <div class="paragraphcontext" [innerHtml]="paragraph.textPre | trust: 'html'"></div>
<div class="paragraphcontext" [innerHtml]="sanitizedText(paragraph.textPost)"></div> <div [innerHtml]="paragraph.text | trust: 'html'"></div>
<div class="paragraphcontext" [innerHtml]="paragraph.textPost | trust: 'html'"></div>
</div> </div>
</div> </div>
<div *ngIf="!motion.diffLines"> <div *ngIf="!motion.diffLines">

View File

@ -4,7 +4,7 @@ import { MatCheckboxChange } from '@angular/material/checkbox';
import { ErrorStateMatcher } from '@angular/material/core'; import { ErrorStateMatcher } from '@angular/material/core';
import { MatDialog } from '@angular/material/dialog'; import { MatDialog } from '@angular/material/dialog';
import { MatSnackBar } from '@angular/material/snack-bar'; import { MatSnackBar } from '@angular/material/snack-bar';
import { DomSanitizer, SafeHtml, Title } from '@angular/platform-browser'; import { Title } from '@angular/platform-browser';
import { ActivatedRoute, NavigationEnd, Router } from '@angular/router'; import { ActivatedRoute, NavigationEnd, Router } from '@angular/router';
import { TranslateService } from '@ngx-translate/core'; import { TranslateService } from '@ngx-translate/core';
@ -22,7 +22,7 @@ import { WorkflowRepositoryService } from 'app/core/repositories/motions/workflo
import { TagRepositoryService } from 'app/core/repositories/tags/tag-repository.service'; import { TagRepositoryService } from 'app/core/repositories/tags/tag-repository.service';
import { UserRepositoryService } from 'app/core/repositories/users/user-repository.service'; import { UserRepositoryService } from 'app/core/repositories/users/user-repository.service';
import { ConfigService } from 'app/core/ui-services/config.service'; import { ConfigService } from 'app/core/ui-services/config.service';
import { DiffLinesInParagraph, DiffService, LineRange } from 'app/core/ui-services/diff.service'; import { DiffLinesInParagraph, LineRange } from 'app/core/ui-services/diff.service';
import { LinenumberingService } from 'app/core/ui-services/linenumbering.service'; import { LinenumberingService } from 'app/core/ui-services/linenumbering.service';
import { PersonalNoteService } from 'app/core/ui-services/personal-note.service'; import { PersonalNoteService } from 'app/core/ui-services/personal-note.service';
import { PromptService } from 'app/core/ui-services/prompt.service'; import { PromptService } from 'app/core/ui-services/prompt.service';
@ -398,12 +398,10 @@ export class MotionDetailComponent extends BaseViewComponent implements OnInit,
* @param mediafileRepo Mediafile Repository * @param mediafileRepo Mediafile Repository
* @param DS The DataStoreService * @param DS The DataStoreService
* @param configService The configuration provider * @param configService The configuration provider
* @param sanitizer For making HTML SafeHTML
* @param promptService ensure safe deletion * @param promptService ensure safe deletion
* @param pdfExport export the motion to pdf * @param pdfExport export the motion to pdf
* @param personalNoteService: personal comments and favorite marker * @param personalNoteService: personal comments and favorite marker
* @param linenumberingService The line numbering service * @param linenumberingService The line numbering service
* @param diffService The diff service
* @param categoryRepo Repository for categories * @param categoryRepo Repository for categories
* @param viewModelStore accessing view models * @param viewModelStore accessing view models
* @param categoryRepo access the category repository * @param categoryRepo access the category repository
@ -433,12 +431,10 @@ export class MotionDetailComponent extends BaseViewComponent implements OnInit,
private changeRecoRepo: ChangeRecommendationRepositoryService, private changeRecoRepo: ChangeRecommendationRepositoryService,
private statuteRepo: StatuteParagraphRepositoryService, private statuteRepo: StatuteParagraphRepositoryService,
private configService: ConfigService, private configService: ConfigService,
private sanitizer: DomSanitizer,
private promptService: PromptService, private promptService: PromptService,
private pdfExport: MotionPdfExportService, private pdfExport: MotionPdfExportService,
private personalNoteService: PersonalNoteService, private personalNoteService: PersonalNoteService,
private linenumberingService: LinenumberingService, private linenumberingService: LinenumberingService,
private diffService: DiffService,
private categoryRepo: CategoryRepositoryService, private categoryRepo: CategoryRepositoryService,
private userRepo: UserRepositoryService, private userRepo: UserRepositoryService,
private notifyService: NotifyService, private notifyService: NotifyService,
@ -861,17 +857,6 @@ export class MotionDetailComponent extends BaseViewComponent implements OnInit,
return this.repo.formatMotion(this.motion.id, this.crMode, changes, this.lineLength, this.highlightedLine); return this.repo.formatMotion(this.motion.id, this.crMode, changes, this.lineLength, this.highlightedLine);
} }
/**
* Called from the template to make a HTML string compatible with [innerHTML]
* (otherwise line-number-data-attributes would be stripped out)
*
* @param {string} text
* @returns {SafeHtml}
*/
public sanitizedText(text: string): SafeHtml {
return this.sanitizer.bypassSecurityTrustHtml(text);
}
/** /**
* If `this.motion` is an amendment, this returns the list of all changed paragraphs. * If `this.motion` is an amendment, this returns the list of all changed paragraphs.
* *
@ -882,34 +867,13 @@ export class MotionDetailComponent extends BaseViewComponent implements OnInit,
return this.repo.getAmendmentParagraphs(this.motion, this.lineLength, includeUnchanged); return this.repo.getAmendmentParagraphs(this.motion, this.lineLength, includeUnchanged);
} }
/**
* If `this.motion` is an amendment, this returns a specified line range from the parent motion
* (e.g. to show the contect in which this amendment is happening)
*
* @param from the line number to start
* @param to the line number to stop
* @returns safe html strings
*/
public getParentMotionRange(from: number, to: number): SafeHtml {
const parentMotion = this.repo.getViewModel(this.motion.parent_id);
const str = this.diffService.extractMotionLineRange(
parentMotion.text,
{ from, to },
true,
this.lineLength,
this.highlightedLine
);
return this.sanitizer.bypassSecurityTrustHtml(str);
}
/** /**
* get the diff html from the statute amendment, as SafeHTML for [innerHTML] * get the diff html from the statute amendment, as SafeHTML for [innerHTML]
* *
* @returns safe html strings * @returns safe html strings
*/ */
public getFormattedStatuteAmendment(): SafeHtml { public getFormattedStatuteAmendment(): string {
const diffHtml = this.repo.formatStatuteAmendment(this.statuteParagraphs, this.motion, this.lineLength); return this.repo.formatStatuteAmendment(this.statuteParagraphs, this.motion, this.lineLength);
return this.sanitizer.bypassSecurityTrustHtml(diffHtml);
} }
public getChangesForDiffMode(): ViewUnifiedChange[] { public getChangesForDiffMode(): ViewUnifiedChange[] {

View File

@ -39,7 +39,7 @@
<!-- Content --> <!-- Content -->
<ng-container class="meta-text-block-content"> <ng-container class="meta-text-block-content">
<ng-container *ngIf="!isEditMode"> <ng-container *ngIf="!isEditMode">
<div *ngIf="motion && motion.personalNote" [innerHTML]="sanitizeText(personalNoteText)"></div> <div *ngIf="motion && motion.personalNote" [innerHTML]="personalNoteText | trust: 'html'"></div>
<div class="no-content" *ngIf="!motion || !motion.hasNotes" translate> <div class="no-content" *ngIf="!motion || !motion.hasNotes" translate>
No personal note No personal note
</div> </div>

View File

@ -1,7 +1,7 @@
import { Component, Input } from '@angular/core'; import { Component, Input } from '@angular/core';
import { FormBuilder, FormGroup } from '@angular/forms'; import { FormBuilder, FormGroup } from '@angular/forms';
import { MatSnackBar } from '@angular/material'; import { MatSnackBar } from '@angular/material';
import { DomSanitizer, SafeHtml, Title } from '@angular/platform-browser'; import { Title } from '@angular/platform-browser';
import { TranslateService } from '@ngx-translate/core'; import { TranslateService } from '@ngx-translate/core';
@ -46,7 +46,6 @@ export class PersonalNoteComponent extends BaseViewComponent {
* @param personalNoteService * @param personalNoteService
* @param formBuilder * @param formBuilder
* @param pdfService * @param pdfService
* @param sanitizer
*/ */
public constructor( public constructor(
title: Title, title: Title,
@ -54,8 +53,7 @@ export class PersonalNoteComponent extends BaseViewComponent {
matSnackBar: MatSnackBar, matSnackBar: MatSnackBar,
private personalNoteService: PersonalNoteService, private personalNoteService: PersonalNoteService,
formBuilder: FormBuilder, formBuilder: FormBuilder,
private pdfService: MotionPdfExportService, private pdfService: MotionPdfExportService
private sanitizer: DomSanitizer
) { ) {
super(title, translate, matSnackBar); super(title, translate, matSnackBar);
this.personalNoteForm = formBuilder.group({ this.personalNoteForm = formBuilder.group({
@ -102,15 +100,4 @@ export class PersonalNoteComponent extends BaseViewComponent {
public printPersonalNote(): void { public printPersonalNote(): void {
this.pdfService.exportPersonalNote(this.motion.personalNote, this.motion); this.pdfService.exportPersonalNote(this.motion.personalNote, this.motion);
} }
/**
* Sanitize the text to be safe.
*
* @param text to be sanitized.
*
* @returns SafeHtml
*/
public sanitizeText(text: string): SafeHtml {
return this.sanitizer.bypassSecurityTrustHtml(text);
}
} }

View File

@ -26,7 +26,7 @@
<mat-card> <mat-card>
<mat-card-title>{{ statuteParagraph.title }}</mat-card-title> <mat-card-title>{{ statuteParagraph.title }}</mat-card-title>
<mat-card-content> <mat-card-content>
<div [innerHTML]="statuteParagraph.text"></div> <div [innerHTML]="statuteParagraph.text | trust: 'html'"></div>
</mat-card-content> </mat-card-content>
</mat-card> </mat-card>
<mat-action-row> <mat-action-row>

View File

@ -32,7 +32,7 @@
<div> <div>
<span *ngIf="!editTopic"> <span *ngIf="!editTopic">
<!-- Render topic text as HTML --> <!-- Render topic text as HTML -->
<div [innerHTML]="sanitizedText(topic.text)"></div> <div [innerHTML]="topic.text | trust: 'html'"></div>
</span> </span>
</div> </div>

View File

@ -1,7 +1,7 @@
import { Component } from '@angular/core'; import { Component } from '@angular/core';
import { FormBuilder, FormGroup, Validators } from '@angular/forms'; import { FormBuilder, FormGroup, Validators } from '@angular/forms';
import { MatSnackBar } from '@angular/material/snack-bar'; import { MatSnackBar } from '@angular/material/snack-bar';
import { DomSanitizer, SafeHtml, Title } from '@angular/platform-browser'; import { Title } from '@angular/platform-browser';
import { ActivatedRoute, Router } from '@angular/router'; import { ActivatedRoute, Router } from '@angular/router';
import { TranslateService } from '@ngx-translate/core'; import { TranslateService } from '@ngx-translate/core';
@ -81,8 +81,7 @@ export class TopicDetailComponent extends BaseViewComponent {
private repo: TopicRepositoryService, private repo: TopicRepositoryService,
private promptService: PromptService, private promptService: PromptService,
private operator: OperatorService, private operator: OperatorService,
private itemRepo: ItemRepositoryService, private itemRepo: ItemRepositoryService
private sanitizer: DomSanitizer
) { ) {
super(title, translate, matSnackBar); super(title, translate, matSnackBar);
this.getTopicByUrl(); this.getTopicByUrl();
@ -241,16 +240,4 @@ export class TopicDetailComponent extends BaseViewComponent {
this.setEditMode(false); this.setEditMode(false);
} }
} }
/**
* Function to sanitize text.
* Necessary to render styles etc. correctly.
*
* @param text which will be sanitized.
*
* @returns safeHtml which can be displayed whithout loss.
*/
public sanitizedText(text: string): SafeHtml {
return this.sanitizer.bypassSecurityTrustHtml(text);
}
} }

View File

@ -315,7 +315,7 @@
<!-- About me --> <!-- About me -->
<div *ngIf="user.about_me"> <div *ngIf="user.about_me">
<h4 translate>About me</h4> <h4 translate>About me</h4>
<div [innerHTML]="sanitizedText(user.about_me)"></div> <div [innerHTML]="user.about_me | trust: 'html'"></div>
</div> </div>
<!-- Username --> <!-- Username -->

View File

@ -1,7 +1,7 @@
import { Component, OnInit } from '@angular/core'; import { Component, OnInit } from '@angular/core';
import { FormBuilder, FormGroup, Validators } from '@angular/forms'; import { FormBuilder, FormGroup, Validators } from '@angular/forms';
import { MatSnackBar } from '@angular/material/snack-bar'; import { MatSnackBar } from '@angular/material/snack-bar';
import { DomSanitizer, SafeHtml, Title } from '@angular/platform-browser'; import { Title } from '@angular/platform-browser';
import { ActivatedRoute, Router } from '@angular/router'; import { ActivatedRoute, Router } from '@angular/router';
import { TranslateService } from '@ngx-translate/core'; import { TranslateService } from '@ngx-translate/core';
@ -97,8 +97,7 @@ export class UserDetailComponent extends BaseViewComponent implements OnInit {
private operator: OperatorService, private operator: OperatorService,
private promptService: PromptService, private promptService: PromptService,
private pdfService: UserPdfExportService, private pdfService: UserPdfExportService,
private groupRepo: GroupRepositoryService, private groupRepo: GroupRepositoryService
private sanitizer: DomSanitizer
) { ) {
super(title, translate, matSnackBar); super(title, translate, matSnackBar);
// prevent 'undefined' to appear in the ui // prevent 'undefined' to appear in the ui
@ -422,18 +421,6 @@ export class UserDetailComponent extends BaseViewComponent implements OnInit {
this.pdfService.exportSingleUserAccessPDF(this.user); this.pdfService.exportSingleUserAccessPDF(this.user);
} }
/**
* Function to sanitize the text.
* Necessary to render text etc. correctly.
*
* @param text which should be sanitized.
*
* @returns safeHtml which can be displayed.
*/
public sanitizedText(text: string): SafeHtml {
return this.sanitizer.bypassSecurityTrustHtml(text);
}
/** /**
* (Re)- send an invitation email for this user after confirmation * (Re)- send an invitation email for this user after confirmation
*/ */

View File

@ -4,7 +4,7 @@
<h2 translate>Election</h2> <h2 translate>Election</h2>
</div> </div>
<div *ngIf="data.data && data.data.description" [innerHTML]="data.data.description"></div> <div *ngIf="data.data && data.data.description" [innerHTML]="data.data.description | trust: 'html'"></div>
<h3 translate>Candidates</h3> <h3 translate>Candidates</h3>
<ul *ngIf="data.data.assignment_related_users && data.data.assignment_related_users.length"> <ul *ngIf="data.data.assignment_related_users && data.data.assignment_related_users.length">

View File

@ -1,5 +1,5 @@
<div id="background" *ngIf="data"> <div id="background" *ngIf="data">
<div id="message"> <div id="message">
<div [innerHTML]="trustHTML(data.data.message)"></div> <div [innerHTML]="data.data.message | trust: 'html'"></div>
</div> </div>
</div> </div>

View File

@ -1,5 +1,4 @@
import { Component, ViewEncapsulation } from '@angular/core'; import { Component, ViewEncapsulation } from '@angular/core';
import { DomSanitizer, SafeHtml } from '@angular/platform-browser';
import { BaseSlideComponent } from 'app/slides/base-slide-component'; import { BaseSlideComponent } from 'app/slides/base-slide-component';
import { ProjectorMessageSlideData } from './projector-message-slide-data'; import { ProjectorMessageSlideData } from './projector-message-slide-data';
@ -11,11 +10,7 @@ import { ProjectorMessageSlideData } from './projector-message-slide-data';
encapsulation: ViewEncapsulation.None encapsulation: ViewEncapsulation.None
}) })
export class ProjectorMessageSlideComponent extends BaseSlideComponent<ProjectorMessageSlideData> { export class ProjectorMessageSlideComponent extends BaseSlideComponent<ProjectorMessageSlideData> {
public constructor(private sanitizer: DomSanitizer) { public constructor() {
super(); super();
} }
public trustHTML(html: string): SafeHtml {
return this.sanitizer.bypassSecurityTrustHtml(html);
}
} }

View File

@ -1,5 +1,9 @@
<div *ngIf="data"> <div *ngIf="data">
<div id="sidebox" *ngIf="data.data.show_meta_box" [ngStyle]="{'margin-top': projector.show_header_footer ? '144px' : '94px'}"> <div
id="sidebox"
*ngIf="data.data.show_meta_box"
[ngStyle]="{ 'margin-top': projector.show_header_footer ? '144px' : '94px' }"
>
<!-- Submitters --> <!-- Submitters -->
<h3 translate>Submitters</h3> <h3 translate>Submitters</h3>
<span *ngFor="let submitter of data.data.submitter; let last = last"> <span *ngFor="let submitter of data.data.submitter; let last = last">
@ -35,7 +39,11 @@
<div id="text-wrapper"> <div id="text-wrapper">
<div id="text" [ngStyle]="textDivStyles"> <div id="text" [ngStyle]="textDivStyles">
<!-- Text --> <!-- Text -->
<span *ngIf="isStatuteAmendment() || isParagraphBasedAmendment() || !!getFormattedText()" class="text-prefix-label">{{ preamble | translate }}</span> <span
*ngIf="isStatuteAmendment() || isParagraphBasedAmendment() || !!getFormattedText()"
class="text-prefix-label"
>{{ preamble | translate }}</span
>
<!-- Regular motions or traditional amendments --> <!-- Regular motions or traditional amendments -->
<ng-container *ngIf="!isStatuteAmendment() && !isParagraphBasedAmendment()"> <ng-container *ngIf="!isStatuteAmendment() && !isParagraphBasedAmendment()">
@ -46,12 +54,10 @@
[class.line-numbers-outside]="isLineNumberingOutside()" [class.line-numbers-outside]="isLineNumberingOutside()"
> >
<div *ngIf="getTitleChangingObject() && crMode === 'diff'"> <div *ngIf="getTitleChangingObject() && crMode === 'diff'">
<div class="bold"> <div class="bold">{{ 'Changed title' | translate }}:</div>
{{ 'Changed title' | translate }}: <div [innerHTML]="getFormattedTitleDiff() | trust: 'html'"></div>
</div> </div>
<div [innerHTML]="getFormattedTitleDiff()"></div> <div *ngIf="getFormattedText()" [innerHTML]="getFormattedText() | trust: 'html'"></div>
</div>
<div *ngIf="getFormattedText()" [innerHTML]="sanitizedText(getFormattedText())"></div>
</div> </div>
</ng-container> </ng-container>
@ -59,7 +65,7 @@
<div <div
class="motion-text line-numbers-none" class="motion-text line-numbers-none"
*ngIf="isStatuteAmendment()" *ngIf="isStatuteAmendment()"
[innerHTML]="getFormattedStatuteAmendment()" [innerHTML]="getFormattedStatuteAmendment() | trust: 'html'"
></div> ></div>
<!-- Amendment text --> <!-- Amendment text -->
@ -81,16 +87,16 @@
<span translate>Line</span> {{ paragraph.diffLineFrom }} - {{ paragraph.diffLineTo - 1 }}: <span translate>Line</span> {{ paragraph.diffLineFrom }} - {{ paragraph.diffLineTo - 1 }}:
</h3> </h3>
<div class="paragraph-context" [innerHtml]="sanitizedText(paragraph.textPre)"></div> <div class="paragraph-context" [innerHtml]="paragraph.textPre | trust: 'html'"></div>
<div [innerHtml]="sanitizedText(paragraph.text)"></div> <div [innerHtml]="paragraph.text | trust: 'html'"></div>
<div class="paragraph-context" [innerHtml]="sanitizedText(paragraph.textPost)"></div> <div class="paragraph-context" [innerHtml]="paragraph.textPost | trust: 'html'"></div>
</div> </div>
</section> </section>
<!-- Reason --> <!-- Reason -->
<div *ngIf="data.data.reason"> <div *ngIf="data.data.reason">
<h3 translate>Reason</h3> <h3 translate>Reason</h3>
<div [innerHTML]="data.data.reason"></div> <div [innerHTML]="data.data.reason | trust: 'html'"></div>
</div> </div>
</div> </div>
</div> </div>

View File

@ -1,5 +1,4 @@
import { Component, Input, ViewEncapsulation } from '@angular/core'; import { Component, Input, ViewEncapsulation } from '@angular/core';
import { DomSanitizer, SafeHtml } from '@angular/platform-browser';
import { TranslateService } from '@ngx-translate/core'; import { TranslateService } from '@ngx-translate/core';
@ -114,7 +113,6 @@ export class MotionSlideComponent extends BaseMotionSlideComponent<MotionSlideDa
translate: TranslateService, translate: TranslateService,
motionRepo: MotionRepositoryService, motionRepo: MotionRepositoryService,
private changeRepo: ChangeRecommendationRepositoryService, private changeRepo: ChangeRecommendationRepositoryService,
private sanitizer: DomSanitizer,
private lineNumbering: LinenumberingService, private lineNumbering: LinenumberingService,
private diff: DiffService private diff: DiffService
) { ) {
@ -257,17 +255,6 @@ export class MotionSlideComponent extends BaseMotionSlideComponent<MotionSlideDa
return this.lnMode === LineNumberingMode.Outside; return this.lnMode === LineNumberingMode.Outside;
} }
/**
* Called from the template to make a HTML string compatible with [innerHTML]
* (otherwise line-number-data-attributes would be stripped out)
*
* @param {string} text
* @returns {SafeHtml}
*/
public sanitizedText(text: string): SafeHtml {
return this.sanitizer.bypassSecurityTrustHtml(text);
}
/** /**
* Extracts a renderable HTML string representing the given line number range of this motion * Extracts a renderable HTML string representing the given line number range of this motion
* *
@ -308,10 +295,9 @@ export class MotionSlideComponent extends BaseMotionSlideComponent<MotionSlideDa
return this.changeRepo.getTitleWithChanges(this.data.data.title, this.getTitleChangingObject(), this.crMode); return this.changeRepo.getTitleWithChanges(this.data.data.title, this.getTitleChangingObject(), this.crMode);
} }
public getFormattedTitleDiff(): SafeHtml { public getFormattedTitleDiff(): string {
const change = this.getTitleChangingObject(); const change = this.getTitleChangingObject();
const diff = this.changeRepo.getTitleChangesAsDiff(this.data.data.title, change); return this.changeRepo.getTitleChangesAsDiff(this.data.data.title, change);
return this.sanitizer.bypassSecurityTrustHtml(diff);
} }
/** /**
@ -430,9 +416,8 @@ export class MotionSlideComponent extends BaseMotionSlideComponent<MotionSlideDa
* *
* @returns safe html strings * @returns safe html strings
*/ */
public getFormattedStatuteAmendment(): SafeHtml { public getFormattedStatuteAmendment(): string {
let diffHtml = this.diff.diff(this.data.data.base_statute.text, this.data.data.text); const diffHtml = this.diff.diff(this.data.data.base_statute.text, this.data.data.text);
diffHtml = this.lineNumbering.insertLineBreaksWithoutNumbers(diffHtml, this.lineLength, true); return this.lineNumbering.insertLineBreaksWithoutNumbers(diffHtml, this.lineLength, true);
return this.sanitizer.bypassSecurityTrustHtml(diffHtml);
} }
} }

View File

@ -6,5 +6,5 @@
{{ data.data.title }} {{ data.data.title }}
</h1> </h1>
<div [innerHTML]="sanitizedText(data.data.text)"></div> <div [innerHTML]="data.data.text | trust: 'html'"></div>
</div> </div>

View File

@ -1,5 +1,4 @@
import { Component } from '@angular/core'; import { Component } from '@angular/core';
import { DomSanitizer, SafeHtml } from '@angular/platform-browser';
import { BaseSlideComponent } from 'app/slides/base-slide-component'; import { BaseSlideComponent } from 'app/slides/base-slide-component';
import { TopicSlideData } from './topic-slide-data'; import { TopicSlideData } from './topic-slide-data';
@ -10,19 +9,7 @@ import { TopicSlideData } from './topic-slide-data';
styleUrls: ['./topic-slide.component.scss'] styleUrls: ['./topic-slide.component.scss']
}) })
export class TopicSlideComponent extends BaseSlideComponent<TopicSlideData> { export class TopicSlideComponent extends BaseSlideComponent<TopicSlideData> {
public constructor(private sanitizer: DomSanitizer) { public constructor() {
super(); super();
} }
/**
* Function to sanitize text.
* Necessary to render the text correctly.
*
* @param text which should be displayed.
*
* @returns safeHtml which can be displayed.
*/
public sanitizedText(text: string): SafeHtml {
return this.sanitizer.bypassSecurityTrustHtml(text);
}
} }