Skip to content

Commit

Permalink
fix(primeng/p-menu): render html via DomSanitizer
Browse files Browse the repository at this point in the history
  • Loading branch information
volvachev committed Jun 16, 2023
1 parent 4f69e5a commit 28ce8e4
Show file tree
Hide file tree
Showing 2 changed files with 49 additions and 14 deletions.
61 changes: 48 additions & 13 deletions src/app/components/menu/menu.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,23 @@
import { NgModule, Component, ElementRef, OnDestroy, Input, Output, EventEmitter, Renderer2, ViewChild, Inject, forwardRef, ChangeDetectorRef, ChangeDetectionStrategy, ViewEncapsulation, ViewRef, PLATFORM_ID, TemplateRef } from '@angular/core';
import {
NgModule,
Component,
ElementRef,
OnDestroy,
Input,
Output,
EventEmitter,
Renderer2,
Inject,
forwardRef,
ChangeDetectorRef,
ChangeDetectionStrategy,
ViewEncapsulation,
ViewRef,
PLATFORM_ID,
TemplateRef,
Pipe,
PipeTransform
} from '@angular/core';
import { trigger, style, transition, animate, AnimationEvent } from '@angular/animations';
import { CommonModule, DOCUMENT, isPlatformBrowser } from '@angular/common';
import { DomHandler, ConnectedOverlayScrollHandler } from 'primeng/dom';
Expand All @@ -8,6 +27,22 @@ import { RouterModule } from '@angular/router';
import { RippleModule } from 'primeng/ripple';
import { TooltipModule } from 'primeng/tooltip';
import { VoidListener } from 'primeng/ts-helpers';
import { DomSanitizer, SafeHtml } from '@angular/platform-browser';

@Pipe({
name: 'safeHtml'
})
class SafeHtmlPipe implements PipeTransform {
constructor(@Inject(PLATFORM_ID) private readonly platformId: any, private readonly sanitizer: DomSanitizer) {}

public transform(value: string): SafeHtml {
if (!value || !isPlatformBrowser(this.platformId)) {
return value;
}

return this.sanitizer.bypassSecurityTrustHtml(value);
}
}

@Component({
selector: '[pMenuItemContent]',
Expand All @@ -25,20 +60,16 @@ import { VoidListener } from 'primeng/ts-helpers';
[ngClass]="{ 'p-disabled': item.disabled }"
(click)="menu.itemClick($event, item)"
role="menuitem"
[target]="item.target"
>
<span class="p-menuitem-icon" *ngIf="item.icon" [ngClass]="item.icon" [class]="item.iconClass" [ngStyle]="item.iconStyle"></span>
<span class="p-menuitem-text" *ngIf="item.escape !== false; else htmlLabel">{{ item.label }}</span>
<ng-template #htmlLabel><span class="p-menuitem-text" [innerHTML]="item.label"></span></ng-template>
<span class="p-menuitem-badge" *ngIf="item.badge" [ngClass]="item.badgeStyleClass">{{ item.badge }}</span>
<ng-container *ngTemplateOutlet="itemContent"></ng-container>
</a>
<a
*ngIf="item?.routerLink"
(keydown)="onItemKeyDown($event)"
[routerLink]="item.routerLink"
[attr.data-automationid]="item.automationId"
[queryParams]="item.queryParams"
[routerLinkActive]="'p-menuitem-link-active'"
routerLinkActive="p-menuitem-link-active"
[routerLinkActiveOptions]="item.routerLinkActiveOptions || { exact: false }"
class="p-menuitem-link"
[target]="item.target"
Expand All @@ -56,11 +87,15 @@ import { VoidListener } from 'primeng/ts-helpers';
[replaceUrl]="item.replaceUrl"
[state]="item.state"
>
<span class="p-menuitem-icon" *ngIf="item.icon" [ngClass]="item.icon"></span>
<span class="p-menuitem-text" *ngIf="item.escape !== false; else htmlRouteLabel">{{ item.label }}</span>
<ng-template #htmlRouteLabel><span class="p-menuitem-text" [innerHTML]="item.label"></span></ng-template>
<span class="p-menuitem-badge" *ngIf="item.badge" [ngClass]="item.badgeStyleClass">{{ item.badge }}</span>
<ng-container *ngTemplateOutlet="itemContent"></ng-container>
</a>
<ng-template #itemContent>
<span class="p-menuitem-icon" *ngIf="item.icon" [ngClass]="item.icon" [class]="item.iconClass" [ngStyle]="item.iconStyle"></span>
<span class="p-menuitem-text" *ngIf="item.escape !== false; else htmlLabel">{{ item.label }}</span>
<ng-template #htmlLabel><span class="p-menuitem-text" [innerHTML]="item.label | safeHtml"></span></ng-template>
<span class="p-menuitem-badge" *ngIf="item.badge" [ngClass]="item.badgeStyleClass">{{ item.badge }}</span>
</ng-template>
`,
encapsulation: ViewEncapsulation.None,
host: {
Expand Down Expand Up @@ -158,7 +193,7 @@ export class MenuItemContent {
role="none"
>
<span *ngIf="submenu.escape !== false; else htmlSubmenuLabel">{{ submenu.label }}</span>
<ng-template #htmlSubmenuLabel><span [innerHTML]="submenu.label"></span></ng-template>
<ng-template #htmlSubmenuLabel><span [innerHTML]="submenu.label | safeHtml"></span></ng-template>
</li>
<ng-template ngFor let-item [ngForOf]="submenu.items">
<li class="p-menu-separator" *ngIf="item.separator" [ngClass]="{ 'p-hidden': item.visible === false || submenu.visible === false }" role="separator"></li>
Expand Down Expand Up @@ -505,6 +540,6 @@ export class Menu implements OnDestroy {
@NgModule({
imports: [CommonModule, RouterModule, RippleModule, TooltipModule],
exports: [Menu, RouterModule, TooltipModule],
declarations: [Menu, MenuItemContent]
declarations: [Menu, MenuItemContent, SafeHtmlPipe]
})
export class MenuModule {}
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ export class AppDocSectionNavComponent implements OnInit, OnDestroy {
label && label.parentElement.scrollIntoView({ block: 'start', behavior: 'smooth' });
}
}

isActiveChildId(isFirst: boolean, activeId: string, childId: string, parentId: string): boolean {
if (isFirst) {
return this.getActiveChildId(activeId, parentId);
Expand Down

0 comments on commit 28ce8e4

Please sign in to comment.