import { InputBoolean , UpdateHostClassService } from 'ngx-tethys/core' ; import { take } from 'rxjs/operators' ; import { ChangeDetectionStrategy , Component , ElementRef , HostBinding , Input , OnChanges , OnInit , Renderer2 , SimpleChanges , ViewEncapsulation } from '@angular/core' ; import { getWhetherPrintErrorWhenIconNotFound } from './config' ; import { ThyIconRegistry } from './icon-registry' ; const iconSuffixMap = { fill : 'fill' , twotone : 'tt' } ; @ Component ( { selector : 'thy-icon' , template : '<ng-content></ng-content>' , changeDetection : ChangeDetectionStrategy . OnPush , encapsulation : ViewEncapsulation . None , providers : [ UpdateHostClassService ] } ) export class ThyIconComponent implements OnInit , OnChanges { @ HostBinding ( 'class.thy-icon' ) className = true ; private initialized = false ; @ Input ( 'thyIconType' ) iconType : 'outline' | 'fill' | 'twotone' = 'outline' ; @ Input ( 'thyTwotoneColor' ) iconTwotoneColor : string ; @ Input ( 'thyIconName' ) iconName : string ; @ Input ( 'thyIconRotate' ) iconRotate : number ; @ Input ( 'thyIconSet' ) iconSet : string ; @ HostBinding ( `class.thy-icon-legging` ) @ Input ( 'thyIconLegging' ) @ InputBoolean ( ) iconLegging : boolean ; @ Input ( 'thyIconLinearGradient' ) @ InputBoolean ( ) iconLinearGradient : boolean ; constructor ( private updateHostClassService , private render , private elementRef , private iconRegistry ) { updateHostClassService . initializeElement ( elementRef . nativeElement ) ; } ngOnInit ( ) { this . updateClasses ( ) ; this . initialized = true ; } ngOnChanges ( changes ) { if ( this . initialized ) { if ( changes [ 'iconName' ] || changes [ 'iconSet' ] || changes [ 'iconTwotoneColor' ] || changes [ 'iconType' ] || changes [ 'iconLinearGradient' ] ) { this . updateClasses ( ) ; } else if ( changes [ 'iconRotate' ] ) { this . setStyleRotate ( ) ; } } } private updateClasses ( ) { const [ namespace , iconName ] = this . iconRegistry . splitIconName ( this . iconName ) ; if ( iconName ) { if ( this . iconRegistry . iconMode === 'svg' ) { this . iconRegistry . getSvgIcon ( this . buildIconNameByType ( iconName ) , namespace ) . pipe ( take ( 1 ) ) . subscribe ( svg => { this . setSvgElement ( svg ) ; } , ( error ) => { if ( getWhetherPrintErrorWhenIconNotFound ( ) ) { console . error ( `Error retrieving icon: ${ error . message }` ) ; } } ) ; this . updateHostClassService . updateClass ( [ `thy-icon${ namespace ? `-${ namespace }` : `` }-${ this . buildIconNameByType ( iconName ) }` ] ) ; } else { const fontSetClass = this . iconSet ? this . iconRegistry . getFontSetClassByAlias ( this . iconSet ) : this . iconRegistry . getDefaultFontSetClass ( ) ; this . updateHostClassService . updateClass ( [ fontSetClass , `${ fontSetClass }-${ this . iconName }` ] ) ; } } } private setStyleRotate ( ) { if ( this . iconRotate !== undefined ) { this . render . setStyle ( this . elementRef . nativeElement . querySelector ( 'svg' ) , 'transform' , `rotate(${ this . iconRotate }deg)` ) ; } } private setSvgElement ( svg ) { this . clearSvgElement ( ) ; const styleTags = svg . querySelectorAll ( 'style' ) as NodeListOf < HTMLStyleElement > ; for ( let i = 0 ; i < styleTags . length ; i ++ ) { styleTags [ i ] . textContent += ' ' ; } if ( this . iconType === 'twotone' ) { const allPaths = svg . querySelectorAll ( 'path' ) ; if ( allPaths . length > 1 ) { allPaths . forEach ( ( child , index ) => { if ( child . getAttribute ( 'id' ) . includes ( 'secondary-color' ) ) { child . setAttribute ( 'fill' , this . iconTwotoneColor ) ; } } ) ; } } if ( this . iconLinearGradient ) { this . setBaseUrl ( svg ) ; this . clearTitleElement ( svg ) ; } this . elementRef . nativeElement . appendChild ( svg ) ; this . setStyleRotate ( ) ; } private clearSvgElement ( ) { const layoutElement = this . elementRef . nativeElement ; let childCount = layoutElement . childNodes . length ; while ( childCount -- ) { const child = layoutElement . childNodes [ childCount ] ; if ( child . nodeType !== 1 || child . nodeName . toLowerCase ( ) === 'svg' ) { layoutElement . removeChild ( child ) ; } } } private buildIconNameByType ( iconName ) { if ( this . iconType && [ 'fill' , 'twotone' ] . indexOf ( this . iconType ) >= 0 ) { const suffix = iconSuffixMap [ this . iconType ] ; return iconName . includes ( `-${ suffix }` ) ? iconName : `${ iconName }-${ suffix }` ; } else { return iconName ; } } param svg private setBaseUrl ( svg ) { const styleElements = svg . querySelectorAll ( 'style' ) ; styleElements . forEach ( ( n ) => { if ( n . style . cssText . includes ( 'url' ) ) { n . style . fill = n . style . fill . replace ( 'url("' , 'url("' + location . pathname ) ; } if ( n . style . cssText . includes ( 'clip-path' ) ) { n . style . clipPath = n . style . clipPath . replace ( 'url("' , 'url("' + location . pathname ) ; } } ) ; } private clearTitleElement ( svg ) { const titleElement = svg . querySelector ( 'title' ) ; titleElement && titleElement . remove ( ) ; } }