Skip to content

Commit 95975f4

Browse files
committed
dom sanitizer pipe, youtube video directive
1 parent ddd65db commit 95975f4

File tree

7 files changed

+86
-8
lines changed

7 files changed

+86
-8
lines changed

angular-primeng-app/src/app/components/post-details/post-details.component.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ <h1 class="title">{{ post.title }}</h1>
3030
</div>
3131
</div>
3232
</div>
33-
<div class="content" [innerHTML]="sanitizeHtml(post.content.html)"></div>
33+
<div class="content" [innerHTML]="post.content.html | sanitizerHtml" youtubeVideoEmbed></div>
3434
</article>
3535
}
3636
<app-footer></app-footer>

angular-primeng-app/src/app/components/post-details/post-details.component.scss

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,11 @@
7575
.content {
7676
font-size: 1rem;
7777
line-height: 1.5rem;
78+
79+
iframe {
80+
width: 100%;
81+
height: calc(50vw * 0.5625);
82+
}
7883
}
7984
}
8085

angular-primeng-app/src/app/components/post-details/post-details.component.ts

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { BlogService } from "../../services/blog.service";
33
import { AsyncPipe, DatePipe } from "@angular/common";
44
import { Post, SeriesList } from "../../models/post";
55
import { Observable, Subscription } from "rxjs";
6-
import { ActivatedRoute, RouterLink } from "@angular/router";
6+
import { RouterLink } from "@angular/router";
77
import { BlogInfo, BlogLinks } from "../../models/blog-info";
88
import { FormsModule } from "@angular/forms";
99
import { SidenavComponent } from "../sidenav/sidenav.component";
@@ -15,17 +15,20 @@ import { TagModule } from "primeng/tag";
1515
import { ToolbarModule } from "primeng/toolbar";
1616
import { ButtonModule } from "primeng/button";
1717
import { InputSwitchModule } from "primeng/inputswitch";
18-
import { DomSanitizer, SafeHtml } from "@angular/platform-browser";
18+
import { SanitizerHtmlPipe } from "../../pipes/sanitizer-html.pipe";
19+
import { YoutubeVideoEmbedDirective } from "../../directives/youtube-video-embed.directive";
1920

2021
@Component({
2122
selector: "app-post-details",
2223
standalone: true,
2324
imports: [
2425
DatePipe,
2526
AsyncPipe,
27+
SanitizerHtmlPipe,
2628
RouterLink,
2729
SidenavComponent,
2830
FooterComponent,
31+
YoutubeVideoEmbedDirective,
2932
FormsModule,
3033
TagModule,
3134
ToolbarModule,
@@ -47,7 +50,6 @@ export class PostDetailsComponent implements OnInit, OnDestroy {
4750
seriesList!: SeriesList[];
4851
post$!: Observable<Post>;
4952
themeService: ThemeService = inject(ThemeService);
50-
private sanitizer: DomSanitizer = inject(DomSanitizer);
5153
private blogService: BlogService = inject(BlogService);
5254
private querySubscription?: Subscription;
5355

@@ -72,10 +74,6 @@ export class PostDetailsComponent implements OnInit, OnDestroy {
7274
});
7375
}
7476

75-
sanitizeHtml(html: string): SafeHtml {
76-
return this.sanitizer.bypassSecurityTrustHtml(html);
77-
}
78-
7977
onThemeChange(theme: string): void {
8078
this.selectedTheme = theme;
8179
this.themeService.setTheme(theme);
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import { YoutubeVideoDirective } from './youtube-video-embed.directive';
2+
3+
describe('YoutubeVideoDirective', () => {
4+
it('should create an instance', () => {
5+
const directive = new YoutubeVideoDirective();
6+
expect(directive).toBeTruthy();
7+
});
8+
});
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
import { AfterViewInit, Directive, Renderer2, ElementRef } from "@angular/core";
2+
3+
@Directive({
4+
selector: "[youtubeVideoEmbed]",
5+
standalone: true,
6+
})
7+
export class YoutubeVideoEmbedDirective implements AfterViewInit {
8+
constructor(private el: ElementRef, private render2: Renderer2) {}
9+
10+
ngAfterViewInit(): void {
11+
const embedWrappers: HTMLDivElement[] = Array.from(
12+
this.el.nativeElement.querySelectorAll(".embed-wrapper")
13+
);
14+
embedWrappers.forEach((embedWrapper) => {
15+
let anchorElement: HTMLAnchorElement | null =
16+
embedWrapper.querySelector(".embed-card");
17+
if (anchorElement) {
18+
let youtubeURL: string = anchorElement.href;
19+
let videoID: string = "";
20+
if (youtubeURL) {
21+
if (youtubeURL.includes("youtube.com/watch?v=")) {
22+
videoID = youtubeURL.split("v=")[1];
23+
} else if (youtubeURL.includes("youtu.be/")) {
24+
videoID = youtubeURL.split("youtu.be/")[1];
25+
}
26+
}
27+
embedWrapper.innerHTML = '';
28+
this._buildIframe(embedWrapper, videoID);
29+
}
30+
});
31+
}
32+
33+
private _buildIframe(block: HTMLDivElement, videoID: string): HTMLIFrameElement {
34+
const iframe: HTMLIFrameElement = this.render2.createElement("iframe");
35+
this.render2.setAttribute(
36+
iframe,
37+
"src",
38+
`https://www.youtube.com/embed/${videoID}`
39+
);
40+
this.render2.setAttribute(iframe, "frameborder", "0");
41+
this.render2.setAttribute(iframe, "allowfullscreen", "true");
42+
this.render2.appendChild(block, iframe);
43+
return iframe;
44+
}
45+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import { SanitizerHtmlPipe } from './sanitizer-html.pipe';
2+
3+
describe('SanitizerHtmlPipe', () => {
4+
it('create an instance', () => {
5+
const pipe = new SanitizerHtmlPipe();
6+
expect(pipe).toBeTruthy();
7+
});
8+
});
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import { Pipe, PipeTransform } from '@angular/core';
2+
import { DomSanitizer, SafeHtml } from '@angular/platform-browser';
3+
4+
@Pipe({
5+
name: 'sanitizerHtml',
6+
standalone: true
7+
})
8+
export class SanitizerHtmlPipe implements PipeTransform {
9+
constructor(private domSanitizer: DomSanitizer) {}
10+
11+
transform(value: string): SafeHtml {
12+
return this.domSanitizer.bypassSecurityTrustHtml(value);
13+
}
14+
}

0 commit comments

Comments
 (0)