2022-06-28 16:40:33 +09:00

141 lines
3.5 KiB
TypeScript

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<any>;
highlightedCode: string | null = null;
private _viewRef?: EmbeddedViewRef<any>;
/**
* 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();
}
}