import { AfterViewInit, ChangeDetectionStrategy, ChangeDetectorRef, Component, ElementRef, EmbeddedViewRef, Input, OnChanges, Renderer2, SecurityContext, SimpleChanges, TemplateRef, ViewChild, ViewContainerRef, ViewEncapsulation, } from '@angular/core'; import { DomSanitizer } from '@angular/platform-browser'; import { FuseHighlightService } from '@fuse/components/highlight/highlight.service'; @Component({ selector: 'textarea[fuse-highlight]', templateUrl: './highlight.component.html', styleUrls: ['./highlight.component.scss'], encapsulation: ViewEncapsulation.None, changeDetection: ChangeDetectionStrategy.OnPush, exportAs: 'fuseHighlight', }) export class FuseHighlightComponent implements OnChanges, AfterViewInit { @Input() code?: string; @Input() lang?: string; @ViewChild(TemplateRef) templateRef!: TemplateRef; highlightedCode: string | null = null; private _viewRef?: EmbeddedViewRef; /** * Constructor */ constructor( private _changeDetectorRef: ChangeDetectorRef, private _domSanitizer: DomSanitizer, private _elementRef: ElementRef, private _renderer2: Renderer2, private _fuseHighlightService: FuseHighlightService, private _viewContainerRef: ViewContainerRef ) {} // ----------------------------------------------------------------------------------------------------- // @ Lifecycle hooks // ----------------------------------------------------------------------------------------------------- /** * On changes * * @param changes */ ngOnChanges(changes: SimpleChanges): void { // Code & Lang if ('code' in changes || 'lang' in changes) { // Return if the viewContainerRef is not available if (!this._viewContainerRef.length) { return; } // Highlight and insert the code this._highlightAndInsert(); } } /** * After view init */ ngAfterViewInit(): void { // Return if there is no language set if (!this.lang) { return; } // If there is no code input, get the code from // the textarea if (!this.code) { // Get the code this.code = this._elementRef.nativeElement.value; } // Highlight and insert this._highlightAndInsert(); } // ----------------------------------------------------------------------------------------------------- // @ Private methods // ----------------------------------------------------------------------------------------------------- /** * Highlight and insert the highlighted code * * @private */ private _highlightAndInsert(): void { // Return if the template reference is not available if (!this.templateRef) { return; } // Return if the code or language is not defined if (!this.code || !this.lang) { return; } // Destroy the component if there is already one if (this._viewRef) { this._viewRef.destroy(); this._viewRef = undefined; } // Highlight and sanitize the code just in case this.highlightedCode = this._domSanitizer.sanitize( SecurityContext.HTML, this._fuseHighlightService.highlight(this.code, this.lang) ); // Return if the highlighted code is null if (this.highlightedCode === null) { return; } // Render and insert the template this._viewRef = this._viewContainerRef.createEmbeddedView( this.templateRef, { highlightedCode: this.highlightedCode, lang: this.lang, } ); // Detect the changes this._viewRef.detectChanges(); } }