141 lines
3.5 KiB
TypeScript
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();
|
|
}
|
|
}
|