refactor: Refactor SharedService, extract logic into smaller services (ResizeService and ColorService)
This commit is contained in:
parent
a00690ffae
commit
8659c16517
11 changed files with 92 additions and 139 deletions
|
|
@ -227,7 +227,7 @@ export class AddTaskComponent implements OnInit {
|
||||||
* @returns The updated search input flag.
|
* @returns The updated search input flag.
|
||||||
*/
|
*/
|
||||||
updateSearchInput() {
|
updateSearchInput() {
|
||||||
this.searchValue = this.sharedService.replaceXSSChars(this.searchValue);
|
this.searchValue = this.replaceXSSChars(this.searchValue);
|
||||||
if (this.searchValue) {
|
if (this.searchValue) {
|
||||||
this.searchInput = this.searchValue.toLowerCase().length > 0;
|
this.searchInput = this.searchValue.toLowerCase().length > 0;
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -241,7 +241,7 @@ export class AddTaskComponent implements OnInit {
|
||||||
* This ensures that the subtask value is sanitized before further processing or storage.
|
* This ensures that the subtask value is sanitized before further processing or storage.
|
||||||
*/
|
*/
|
||||||
updateSubtaskValue() {
|
updateSubtaskValue() {
|
||||||
this.subtaskValue = this.sharedService.replaceXSSChars(this.subtaskValue);
|
this.subtaskValue = this.replaceXSSChars(this.subtaskValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -400,14 +400,10 @@ export class AddTaskComponent implements OnInit {
|
||||||
* @returns {void}
|
* @returns {void}
|
||||||
*/
|
*/
|
||||||
checkCrossSiteScripting() {
|
checkCrossSiteScripting() {
|
||||||
this.taskData.title = this.sharedService.replaceXSSChars(
|
this.taskData.title = this.replaceXSSChars(this.taskData.title);
|
||||||
this.taskData.title
|
this.taskData.description = this.replaceXSSChars(this.taskData.description);
|
||||||
);
|
|
||||||
this.taskData.description = this.sharedService.replaceXSSChars(
|
|
||||||
this.taskData.description
|
|
||||||
);
|
|
||||||
this.taskData.subtasksTitle = this.taskData.subtasksTitle.map((title) =>
|
this.taskData.subtasksTitle = this.taskData.subtasksTitle.map((title) =>
|
||||||
this.sharedService.replaceXSSChars(title)
|
this.replaceXSSChars(title)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -421,6 +417,10 @@ export class AddTaskComponent implements OnInit {
|
||||||
this.closeDialog();
|
this.closeDialog();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
replaceXSSChars(input: string) {
|
||||||
|
return input.replace(/</g, '<').replace(/>/g, '>');
|
||||||
|
}
|
||||||
|
|
||||||
@HostListener('document:click', ['$event'])
|
@HostListener('document:click', ['$event'])
|
||||||
/**
|
/**
|
||||||
* Closes the assigned dropdown menu if the user clicks anywhere outside of
|
* Closes the assigned dropdown menu if the user clicks anywhere outside of
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,6 @@ import { TaskEmptyComponent } from './task/task-empty/task-empty.component';
|
||||||
import { FormsModule } from '@angular/forms';
|
import { FormsModule } from '@angular/forms';
|
||||||
import { OverlayService } from '../../services/overlay.service';
|
import { OverlayService } from '../../services/overlay.service';
|
||||||
import { Router } from '@angular/router';
|
import { Router } from '@angular/router';
|
||||||
import { SharedService } from '../../services/shared.service';
|
|
||||||
import { TranslateModule } from '@ngx-translate/core';
|
import { TranslateModule } from '@ngx-translate/core';
|
||||||
import { TaskHighlightedComponent } from './task/task-highlighted/task-highlighted.component';
|
import { TaskHighlightedComponent } from './task/task-highlighted/task-highlighted.component';
|
||||||
import { ApiService } from '../../services/api.service';
|
import { ApiService } from '../../services/api.service';
|
||||||
|
|
@ -16,6 +15,7 @@ import { LoadingSpinnerComponent } from '../../shared/components/loading-spinner
|
||||||
import { finalize, Subject, takeUntil } from 'rxjs';
|
import { finalize, Subject, takeUntil } from 'rxjs';
|
||||||
import { TaskUpdateService } from '../../services/task-update.service';
|
import { TaskUpdateService } from '../../services/task-update.service';
|
||||||
import { ToastNotificationService } from '../../services/toast-notification.servic';
|
import { ToastNotificationService } from '../../services/toast-notification.servic';
|
||||||
|
import { ResizeService } from '../../services/resize.service';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-board',
|
selector: 'app-board',
|
||||||
|
|
@ -43,7 +43,7 @@ export class BoardComponent {
|
||||||
constructor(
|
constructor(
|
||||||
public dragDropService: DragDropService,
|
public dragDropService: DragDropService,
|
||||||
public overlayService: OverlayService,
|
public overlayService: OverlayService,
|
||||||
private sharedService: SharedService,
|
private resizeService: ResizeService,
|
||||||
private taskService: TaskService,
|
private taskService: TaskService,
|
||||||
private apiService: ApiService,
|
private apiService: ApiService,
|
||||||
private taskUpdateService: TaskUpdateService,
|
private taskUpdateService: TaskUpdateService,
|
||||||
|
|
@ -129,7 +129,7 @@ export class BoardComponent {
|
||||||
* @param status The status to be used for the new task.
|
* @param status The status to be used for the new task.
|
||||||
*/
|
*/
|
||||||
addNewTaskOverlay(status: string) {
|
addNewTaskOverlay(status: string) {
|
||||||
this.sharedService.isPageViewMedia
|
this.resizeService.isPageViewMedia
|
||||||
? this.router.navigate(['/add-task', status])
|
? this.router.navigate(['/add-task', status])
|
||||||
: this.overlayService.setOverlayData('newTaskOverlay', status);
|
: this.overlayService.setOverlayData('newTaskOverlay', status);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,7 @@
|
||||||
>
|
>
|
||||||
{{ task.category }}
|
{{ task.category }}
|
||||||
</div>
|
</div>
|
||||||
@if (sharedService.isPageViewMedia) {
|
@if (resizeService.isPageViewMedia) {
|
||||||
<div class="menu-btn" (click)="handleMenuButtonClick($event, task.id)">
|
<div class="menu-btn" (click)="handleMenuButtonClick($event, task.id)">
|
||||||
<img
|
<img
|
||||||
class="menu-img"
|
class="menu-img"
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@ import { FirebaseService } from '../../../services/firebase.service';
|
||||||
import { OverlayService } from '../../../services/overlay.service';
|
import { OverlayService } from '../../../services/overlay.service';
|
||||||
import { Router } from '@angular/router';
|
import { Router } from '@angular/router';
|
||||||
import { TaskMenuComponent } from './task-menu/task-menu.component';
|
import { TaskMenuComponent } from './task-menu/task-menu.component';
|
||||||
import { SharedService } from '../../../services/shared.service';
|
import { ResizeService } from '../../../services/resize.service';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-task',
|
selector: 'app-task',
|
||||||
|
|
@ -34,7 +34,7 @@ export class TaskComponent {
|
||||||
public dragDropService: DragDropService,
|
public dragDropService: DragDropService,
|
||||||
public firebaseService: FirebaseService,
|
public firebaseService: FirebaseService,
|
||||||
public overlayService: OverlayService,
|
public overlayService: OverlayService,
|
||||||
public sharedService: SharedService,
|
public resizeService: ResizeService,
|
||||||
private router: Router
|
private router: Router
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
|
|
@ -74,7 +74,7 @@ export class TaskComponent {
|
||||||
if (this.isMenuOpen) {
|
if (this.isMenuOpen) {
|
||||||
this.toggleTaskMenu();
|
this.toggleTaskMenu();
|
||||||
}
|
}
|
||||||
this.sharedService.isPageViewMedia
|
this.resizeService.isPageViewMedia
|
||||||
? this.router.navigate(['/task', taskId])
|
? this.router.navigate(['/task', taskId])
|
||||||
: this.overlayService.setOverlayData('taskOverlay', taskId);
|
: this.overlayService.setOverlayData('taskOverlay', taskId);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@ import { TranslateModule } from '@ngx-translate/core';
|
||||||
import { ContactFormComponent } from './contact-form/contact-form.component';
|
import { ContactFormComponent } from './contact-form/contact-form.component';
|
||||||
import { SharedService } from '../../../services/shared.service';
|
import { SharedService } from '../../../services/shared.service';
|
||||||
import { ColorPickerModule } from 'ngx-color-picker';
|
import { ColorPickerModule } from 'ngx-color-picker';
|
||||||
|
import { ColorService } from '../../../services/color.service';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-contact-edit',
|
selector: 'app-contact-edit',
|
||||||
|
|
@ -30,7 +31,8 @@ export class ContactEditNewComponent implements OnInit {
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
public firebaseService: FirebaseService,
|
public firebaseService: FirebaseService,
|
||||||
public sharedService: SharedService
|
public sharedService: SharedService,
|
||||||
|
private colorService: ColorService
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -39,7 +41,7 @@ export class ContactEditNewComponent implements OnInit {
|
||||||
* This method sets a random color for the user to be edited.
|
* This method sets a random color for the user to be edited.
|
||||||
*/
|
*/
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
this.randomColor = this.sharedService.generateRandomColor();
|
this.randomColor = this.colorService.generateRandomColor();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,7 @@
|
||||||
autocomplete="off"
|
autocomplete="off"
|
||||||
required
|
required
|
||||||
/>
|
/>
|
||||||
@if (sharedService.isContactViewMedia) {
|
@if (resizeService.isContactViewMedia) {
|
||||||
<div class="error-msg">
|
<div class="error-msg">
|
||||||
@if (firstName.hasError('pattern') && firstName.touched) {
|
@if (firstName.hasError('pattern') && firstName.touched) {
|
||||||
<p>{{ "contactDialogForm.invalidPattern" | translate }}</p>
|
<p>{{ "contactDialogForm.invalidPattern" | translate }}</p>
|
||||||
|
|
@ -49,7 +49,7 @@
|
||||||
required
|
required
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
@if (sharedService.isContactViewMedia) {
|
@if (resizeService.isContactViewMedia) {
|
||||||
<div class="error-msg">
|
<div class="error-msg">
|
||||||
@if (lastName.hasError('pattern') && lastName.touched) {
|
@if (lastName.hasError('pattern') && lastName.touched) {
|
||||||
<p>{{ "contactDialogForm.invalidPattern" | translate }}</p>
|
<p>{{ "contactDialogForm.invalidPattern" | translate }}</p>
|
||||||
|
|
@ -57,7 +57,7 @@
|
||||||
<p>{{ "contactDialogForm.invalidLastName" | translate }}</p>
|
<p>{{ "contactDialogForm.invalidLastName" | translate }}</p>
|
||||||
}}
|
}}
|
||||||
</div>
|
</div>
|
||||||
} @if (!sharedService.isContactViewMedia) {
|
} @if (!resizeService.isContactViewMedia) {
|
||||||
<div class="error-msg">
|
<div class="error-msg">
|
||||||
@if (firstName.hasError('pattern') || lastName.hasError('pattern') &&
|
@if (firstName.hasError('pattern') || lastName.hasError('pattern') &&
|
||||||
firstName.touched) {
|
firstName.touched) {
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,7 @@ import { FirebaseService } from '../../../../services/firebase.service';
|
||||||
import { FormBtnComponent } from '../../../../shared/components/buttons/form-btn/form-btn.component';
|
import { FormBtnComponent } from '../../../../shared/components/buttons/form-btn/form-btn.component';
|
||||||
import { User } from '../../../../interfaces/user.interface';
|
import { User } from '../../../../interfaces/user.interface';
|
||||||
import { Router } from '@angular/router';
|
import { Router } from '@angular/router';
|
||||||
|
import { ResizeService } from '../../../../services/resize.service';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-contact-form',
|
selector: 'app-contact-form',
|
||||||
|
|
@ -32,6 +33,7 @@ export class ContactFormComponent implements OnInit, OnChanges {
|
||||||
constructor(
|
constructor(
|
||||||
private router: Router,
|
private router: Router,
|
||||||
public firebaseService: FirebaseService,
|
public firebaseService: FirebaseService,
|
||||||
|
public resizeService: ResizeService,
|
||||||
public sharedService: SharedService
|
public sharedService: SharedService
|
||||||
) {
|
) {
|
||||||
this.updateContactData();
|
this.updateContactData();
|
||||||
|
|
|
||||||
34
src/app/services/color.service.ts
Normal file
34
src/app/services/color.service.ts
Normal file
|
|
@ -0,0 +1,34 @@
|
||||||
|
import { Injectable } from '@angular/core';
|
||||||
|
|
||||||
|
@Injectable({
|
||||||
|
providedIn: 'root',
|
||||||
|
})
|
||||||
|
export class ColorService {
|
||||||
|
generateRandomColor(): string {
|
||||||
|
const letters = '0123456789ABCDEF';
|
||||||
|
let color = '#';
|
||||||
|
let isGrayScale = true;
|
||||||
|
|
||||||
|
while (isGrayScale) {
|
||||||
|
for (let i = 0; i < 6; i++) {
|
||||||
|
color += letters[Math.floor(Math.random() * 16)];
|
||||||
|
}
|
||||||
|
const rgb = this.hexToRgb(color);
|
||||||
|
if (rgb.r !== rgb.g || rgb.g !== rgb.b) {
|
||||||
|
isGrayScale = false;
|
||||||
|
} else {
|
||||||
|
color = '#';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return color;
|
||||||
|
}
|
||||||
|
|
||||||
|
hexToRgb(hex: string): { r: number; g: number; b: number } {
|
||||||
|
const bigint = parseInt(hex.substring(1), 16);
|
||||||
|
const r = (bigint >> 16) & 255;
|
||||||
|
const g = (bigint >> 8) & 255;
|
||||||
|
const b = bigint & 255;
|
||||||
|
return { r, g, b };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -25,6 +25,7 @@ import { Router } from '@angular/router';
|
||||||
import CryptoES from 'crypto-es';
|
import CryptoES from 'crypto-es';
|
||||||
import { CryptoESSecretKey } from '../environments/config';
|
import { CryptoESSecretKey } from '../environments/config';
|
||||||
import { catchError, map, Observable, of } from 'rxjs';
|
import { catchError, map, Observable, of } from 'rxjs';
|
||||||
|
import { ColorService } from './color.service';
|
||||||
|
|
||||||
@Injectable({
|
@Injectable({
|
||||||
providedIn: 'root',
|
providedIn: 'root',
|
||||||
|
|
@ -39,6 +40,7 @@ export class LoginService {
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private firebaseService: FirebaseService,
|
private firebaseService: FirebaseService,
|
||||||
|
private colorService: ColorService,
|
||||||
public sharedService: SharedService,
|
public sharedService: SharedService,
|
||||||
private router: Router
|
private router: Router
|
||||||
) {}
|
) {}
|
||||||
|
|
@ -124,7 +126,7 @@ export class LoginService {
|
||||||
? registerData.firstName.slice(0, 1).toUpperCase() +
|
? registerData.firstName.slice(0, 1).toUpperCase() +
|
||||||
registerData.lastName.slice(0, 1).toUpperCase()
|
registerData.lastName.slice(0, 1).toUpperCase()
|
||||||
: '',
|
: '',
|
||||||
color: this.sharedService.generateRandomColor(),
|
color: this.colorService.generateRandomColor(),
|
||||||
lastLogin: new Date().getTime(),
|
lastLogin: new Date().getTime(),
|
||||||
};
|
};
|
||||||
this.createUserInFirestore(userDataToSave);
|
this.createUserInFirestore(userDataToSave);
|
||||||
|
|
@ -169,7 +171,7 @@ export class LoginService {
|
||||||
isOnline: true,
|
isOnline: true,
|
||||||
phone: '',
|
phone: '',
|
||||||
initials: firstName.slice(0, 1) + lastName.slice(0, 1),
|
initials: firstName.slice(0, 1) + lastName.slice(0, 1),
|
||||||
color: this.sharedService.generateRandomColor(),
|
color: this.colorService.generateRandomColor(),
|
||||||
lastLogin: 0,
|
lastLogin: 0,
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
|
|
|
||||||
29
src/app/services/resize.service.ts
Normal file
29
src/app/services/resize.service.ts
Normal file
|
|
@ -0,0 +1,29 @@
|
||||||
|
import { Injectable } from '@angular/core';
|
||||||
|
|
||||||
|
@Injectable({
|
||||||
|
providedIn: 'root',
|
||||||
|
})
|
||||||
|
export class ResizeService {
|
||||||
|
isPageViewMedia: boolean = window.innerWidth <= 650;
|
||||||
|
isContactViewMedia: boolean = window.innerWidth <= 800;
|
||||||
|
|
||||||
|
private resizeListener!: () => void;
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
this.initResizeListener();
|
||||||
|
}
|
||||||
|
|
||||||
|
private initResizeListener() {
|
||||||
|
this.resizeListener = this.onResize.bind(this);
|
||||||
|
window.addEventListener('resize', this.resizeListener);
|
||||||
|
}
|
||||||
|
|
||||||
|
private onResize() {
|
||||||
|
this.isPageViewMedia = window.innerWidth <= 650;
|
||||||
|
this.isContactViewMedia = window.innerWidth <= 800;
|
||||||
|
}
|
||||||
|
|
||||||
|
cleanup() {
|
||||||
|
window.removeEventListener('resize', this.resizeListener);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -10,121 +10,5 @@ export class SharedService {
|
||||||
isNewContactDialogOpen: boolean = false;
|
isNewContactDialogOpen: boolean = false;
|
||||||
isEditContactDialogOpen: boolean = false;
|
isEditContactDialogOpen: boolean = false;
|
||||||
isDeleteContactDialogOpen: boolean = false;
|
isDeleteContactDialogOpen: boolean = false;
|
||||||
isPageViewMedia: boolean = window.innerWidth <= 650;
|
|
||||||
isContactViewMedia: boolean = window.innerWidth <= 800;
|
|
||||||
currentUserId: string = '';
|
currentUserId: string = '';
|
||||||
|
|
||||||
private resizeListener!: () => void;
|
|
||||||
|
|
||||||
constructor() {
|
|
||||||
this.initResizeListener();
|
|
||||||
}
|
|
||||||
|
|
||||||
// CHECK VIEW WIDTH
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Initializes the window resize listener.
|
|
||||||
*
|
|
||||||
* @remarks
|
|
||||||
* This function will set up the window resize listener and bind the
|
|
||||||
* onResize() method to it.
|
|
||||||
*/
|
|
||||||
private initResizeListener() {
|
|
||||||
this.resizeListener = this.onResize.bind(this);
|
|
||||||
window.addEventListener('resize', this.resizeListener);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Removes the window resize listener.
|
|
||||||
*
|
|
||||||
* @remarks
|
|
||||||
* This function will remove the window resize listener that was set up in
|
|
||||||
* the constructor. This is useful when the service is being destroyed.
|
|
||||||
*/
|
|
||||||
private removeResizeListener() {
|
|
||||||
window.removeEventListener('resize', this.resizeListener);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Window resize event listener method.
|
|
||||||
*
|
|
||||||
* @remarks
|
|
||||||
* This method will update the isPageViewMedia and isContactViewMedia
|
|
||||||
* properties based on the current window width whenever the window is
|
|
||||||
* resized.
|
|
||||||
*/
|
|
||||||
private onResize() {
|
|
||||||
this.isPageViewMedia = window.innerWidth <= 650;
|
|
||||||
this.isContactViewMedia = window.innerWidth <= 800;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Cleans up the service by removing the window resize listener.
|
|
||||||
*
|
|
||||||
* @remarks
|
|
||||||
* This function is useful when the service is being destroyed.
|
|
||||||
*/
|
|
||||||
cleanup() {
|
|
||||||
this.removeResizeListener();
|
|
||||||
}
|
|
||||||
|
|
||||||
// RANDOM COLOR
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Generates a random color string.
|
|
||||||
*
|
|
||||||
* @remarks
|
|
||||||
* The generated color is a hex string that is not a shade of gray.
|
|
||||||
* The color is generated by randomly selecting a hex digit from the
|
|
||||||
* string '0123456789ABCDEF' and appending it to the color string. The
|
|
||||||
* loop continues until a non-gray color is generated.
|
|
||||||
*
|
|
||||||
* @returns A random color string.
|
|
||||||
*/
|
|
||||||
generateRandomColor(): string {
|
|
||||||
const letters = '0123456789ABCDEF';
|
|
||||||
let color = '#';
|
|
||||||
let isGrayScale = true;
|
|
||||||
|
|
||||||
while (isGrayScale) {
|
|
||||||
for (let i = 0; i < 6; i++) {
|
|
||||||
color += letters[Math.floor(Math.random() * 16)];
|
|
||||||
}
|
|
||||||
const rgb = this.hexToRgb(color);
|
|
||||||
if (rgb.r !== rgb.g || rgb.g !== rgb.b) {
|
|
||||||
isGrayScale = false;
|
|
||||||
} else {
|
|
||||||
color = '#';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return color;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Converts a hex color string to an RGB object.
|
|
||||||
*
|
|
||||||
* @param hex A color string in hex format, e.g. '#FF0000'.
|
|
||||||
* @returns An object with r, g, and b properties, each an integer between
|
|
||||||
* 0 and 255, representing the red, green, and blue components of the color.
|
|
||||||
*/
|
|
||||||
hexToRgb(hex: string): { r: number; g: number; b: number } {
|
|
||||||
const bigint = parseInt(hex.substring(1), 16);
|
|
||||||
const r = (bigint >> 16) & 255;
|
|
||||||
const g = (bigint >> 8) & 255;
|
|
||||||
const b = bigint & 255;
|
|
||||||
return { r, g, b };
|
|
||||||
}
|
|
||||||
|
|
||||||
// SECURITY
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sanitizes the input string by replacing any potential cross-site scripting characters.
|
|
||||||
* This ensures that the input string is safe to be stored in the Firebase Realtime Database.
|
|
||||||
* @param input The input string to be sanitized.
|
|
||||||
* @returns The sanitized string.
|
|
||||||
*/
|
|
||||||
replaceXSSChars(input: string) {
|
|
||||||
return input.replace(/</g, '<').replace(/>/g, '>');
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue