From 699ca5fe6cf8b85203e39176e218242223f6dd75 Mon Sep 17 00:00:00 2001 From: Simeon Simeonoff Date: Mon, 27 Sep 2021 18:08:29 +0300 Subject: [PATCH 01/18] refactor(icon-service): cache svg icons as text --- .../src/lib/icon/icon.component.html | 4 +- .../src/lib/icon/icon.component.ts | 4 +- .../src/lib/icon/icon.service.ts | 82 +++++++------------ 3 files changed, 32 insertions(+), 58 deletions(-) diff --git a/projects/igniteui-angular/src/lib/icon/icon.component.html b/projects/igniteui-angular/src/lib/icon/icon.component.html index 665287d1806..f9863a0166b 100644 --- a/projects/igniteui-angular/src/lib/icon/icon.component.html +++ b/projects/igniteui-angular/src/lib/icon/icon.component.html @@ -5,9 +5,7 @@ - - - + diff --git a/projects/igniteui-angular/src/lib/icon/icon.component.ts b/projects/igniteui-angular/src/lib/icon/icon.component.ts index d3354ebb414..f3a1b03fe1b 100644 --- a/projects/igniteui-angular/src/lib/icon/icon.component.ts +++ b/projects/igniteui-angular/src/lib/icon/icon.component.ts @@ -238,9 +238,9 @@ export class IgxIconComponent implements OnInit, OnDestroy { * } * ``` */ - public get getSvgKey(): string { + public get getSvg(): string { if (this.iconService.isSvgIconCached(this.name, this.family)) { - return '#' + this.iconService.getSvgIconKey(this.name, this.family); + return this.iconService.getSvgIcon(this.name, this.family); } return null; diff --git a/projects/igniteui-angular/src/lib/icon/icon.service.ts b/projects/igniteui-angular/src/lib/icon/icon.service.ts index 12f5e426d6e..fb163bc3bf9 100644 --- a/projects/igniteui-angular/src/lib/icon/icon.service.ts +++ b/projects/igniteui-angular/src/lib/icon/icon.service.ts @@ -1,4 +1,4 @@ -import { Injectable, SecurityContext, Inject, OnDestroy, Optional } from '@angular/core'; +import { Injectable, SecurityContext, Inject, Optional } from '@angular/core'; import { DomSanitizer } from '@angular/platform-browser'; import { DOCUMENT } from '@angular/common'; import { HttpClient } from '@angular/common/http'; @@ -32,7 +32,7 @@ export interface IgxIconLoadedEvent { @Injectable({ providedIn: 'root' }) -export class IgxIconService implements OnDestroy { +export class IgxIconService { /** * Observable that emits when an icon is successfully loaded * through a HTTP request. @@ -46,8 +46,7 @@ export class IgxIconService implements OnDestroy { private _family = 'material-icons'; private _familyAliases = new Map(); - private _svgContainer: HTMLElement; - private _cachedSvgIcons: Set = new Set(); + private _cachedSvgIcons = new Map>(); private _iconLoaded = new Subject(); constructor( @@ -58,14 +57,6 @@ export class IgxIconService implements OnDestroy { this.iconLoaded = this._iconLoaded.asObservable(); } - /** - * @hidden - * @internal - */ - public ngOnDestroy(): void { - this.cleanSvgContainer(); - } - /** * Returns the default font-family. * ```typescript @@ -162,18 +153,25 @@ export class IgxIconService implements OnDestroy { * ``` */ public isSvgIconCached(name: string, family: string = ''): boolean { - const iconKey = this.getSvgIconKey(name, family); - return this._cachedSvgIcons.has(iconKey); + if(this._cachedSvgIcons.has(family)) { + const familyRegistry = this._cachedSvgIcons.get(family) as Map; + return familyRegistry.has(name); + } + + return false; } /** * Returns the key of a cached SVG image. * ```typescript - * const svgIconKey = this.iconService.getSvgIconKey('aruba', 'svg-flags'); + * const svgIcon = this.iconService.getSvgIcon('aruba', 'svg-flags'); * ``` */ - public getSvgIconKey(name: string, family: string = '') { - return family + '_' + name; + public getSvgIcon(name: string, family: string = '') { + if(this._cachedSvgIcons.has(family)) { + const familyRegistry = this._cachedSvgIcons.get(family) as Map; + return familyRegistry.get(name); + } } /** @@ -184,15 +182,17 @@ export class IgxIconService implements OnDestroy { return req; } - /** - * @hidden - */ - private cleanSvgContainer() { - const container = this._document.documentElement.querySelector('.igx-svg-container'); + private getOrCreateIconFamily(name: string) { + let family: Map; - while (container.firstChild) { - container.removeChild(container.firstChild); + if(this._cachedSvgIcons.has(name)) { + family = this._cachedSvgIcons.get(name) as Map; + } else { + family = new Map(); + this._cachedSvgIcons.set(name, family); } + + return family; } /** @@ -200,41 +200,17 @@ export class IgxIconService implements OnDestroy { */ private cacheSvgIcon(name: string, value: string, family: string = '') { if (name && value) { - this.ensureSvgContainerCreated(); - - const div = this._document.createElement('DIV'); + const div = this._document.createElement('div'); div.innerHTML = value; const svg = div.querySelector('svg') as SVGElement; - if (svg) { - const iconKey = this.getSvgIconKey(name, family); - - svg.setAttribute('id', iconKey); + if(svg) { svg.setAttribute('fit', ''); svg.setAttribute('preserveAspectRatio', 'xMidYMid meet'); - svg.setAttribute('focusable', 'false'); // Disable IE11 default behavior to make SVGs focusable. + const svgText = svg.outerHTML; - if (this.isSvgIconCached(name, family)) { - const oldChild = this._svgContainer.querySelector(`svg[id='${iconKey}']`); - this._svgContainer.removeChild(oldChild); - } - - this._svgContainer.appendChild(svg); - this._cachedSvgIcons.add(iconKey); - } - } - } - - /** - * @hidden - */ - private ensureSvgContainerCreated() { - if (!this._svgContainer) { - this._svgContainer = this._document.documentElement.querySelector('.igx-svg-container'); - if (!this._svgContainer) { - this._svgContainer = this._document.createElement('DIV'); - this._svgContainer.classList.add('igx-svg-container'); - this._document.body.appendChild(this._svgContainer); + const familyRegistry = this.getOrCreateIconFamily(family); + familyRegistry.set(name, svgText); } } } From 421a55f6d62751b4778a238c519fb737db6b770b Mon Sep 17 00:00:00 2001 From: Simeon Simeonoff Date: Mon, 27 Sep 2021 20:21:06 +0300 Subject: [PATCH 02/18] refactor(icon): return SafeHtml from IconService --- .../src/lib/icon/icon.component.ts | 50 ++++++++++++++----- 1 file changed, 38 insertions(+), 12 deletions(-) diff --git a/projects/igniteui-angular/src/lib/icon/icon.component.ts b/projects/igniteui-angular/src/lib/icon/icon.component.ts index f3a1b03fe1b..27a84e7f59c 100644 --- a/projects/igniteui-angular/src/lib/icon/icon.component.ts +++ b/projects/igniteui-angular/src/lib/icon/icon.component.ts @@ -1,8 +1,20 @@ -import { Component, ElementRef, HostBinding, Input, OnInit, TemplateRef, ViewChild, ChangeDetectorRef, OnDestroy } from '@angular/core'; +import { + Component, + ElementRef, + HostBinding, + Input, + OnInit, + TemplateRef, + ViewChild, + ChangeDetectorRef, + OnDestroy, + AfterViewInit +} from '@angular/core'; import { IgxIconService } from './icon.service'; import { first, takeUntil } from 'rxjs/operators'; import { Subject } from 'rxjs'; import { DeprecateProperty } from '../core/deprecateDecorators'; +import { DomSanitizer, SafeHtml } from '@angular/platform-browser'; /** * Icon provides a way to include material icons to markup @@ -30,7 +42,7 @@ import { DeprecateProperty } from '../core/deprecateDecorators'; selector: 'igx-icon', templateUrl: 'icon.component.html' }) -export class IgxIconComponent implements OnInit, OnDestroy { +export class IgxIconComponent implements OnInit, AfterViewInit, OnDestroy { /** * This allows you to change the value of `class.igx-icon`. By default it's `igx-icon`. * @@ -114,16 +126,20 @@ export class IgxIconComponent implements OnInit, OnDestroy { private destroy$ = new Subject(); - constructor(public el: ElementRef, - private iconService: IgxIconService, - private ref: ChangeDetectorRef) { + constructor( + public el: ElementRef, + private iconService: IgxIconService, + private ref: ChangeDetectorRef, + private sanitizer: DomSanitizer + ) { this.family = this.iconService.defaultFamily; this.iconService.registerFamilyAlias('material', 'material-icons'); - this.iconService.iconLoaded.pipe( - first(e => e.name === this.name && e.family === this.family), - takeUntil(this.destroy$) - ) - .subscribe(() => this.ref.detectChanges()); + this.iconService.iconLoaded + .pipe( + first((e) => e.name === this.name && e.family === this.family), + takeUntil(this.destroy$) + ) + .subscribe(() => this.ref.detectChanges()); } /** @@ -134,6 +150,14 @@ export class IgxIconComponent implements OnInit, OnDestroy { this.updateIconClass(); } + /** + * @hidden + * @internal + */ + public ngAfterViewInit() { + console.log(this.getSvg); + } + /** * @hidden * @internal @@ -238,9 +262,11 @@ export class IgxIconComponent implements OnInit, OnDestroy { * } * ``` */ - public get getSvg(): string { + public get getSvg(): SafeHtml { if (this.iconService.isSvgIconCached(this.name, this.family)) { - return this.iconService.getSvgIcon(this.name, this.family); + const svgText = this.iconService.getSvgIcon(this.name, this.family); + const svg = this.sanitizer.bypassSecurityTrustHtml(svgText); + return svg; } return null; From 954a3261160b2e03cde922a5488c77009c5b7d06 Mon Sep 17 00:00:00 2001 From: Simeon Simeonoff Date: Mon, 27 Sep 2021 20:21:31 +0300 Subject: [PATCH 03/18] spec(icon-service): update --- .../src/lib/icon/icon.service.spec.ts | 27 +------------------ 1 file changed, 1 insertion(+), 26 deletions(-) diff --git a/projects/igniteui-angular/src/lib/icon/icon.service.spec.ts b/projects/igniteui-angular/src/lib/icon/icon.service.spec.ts index 58e667387e7..1281c9855d5 100644 --- a/projects/igniteui-angular/src/lib/icon/icon.service.spec.ts +++ b/projects/igniteui-angular/src/lib/icon/icon.service.spec.ts @@ -1,6 +1,5 @@ import { TestBed } from '@angular/core/testing'; import { IgxIconService } from './icon.service'; -import { DOCUMENT } from '@angular/common'; import { configureTestSuite } from '../test-utils/configure-suite'; import { first } from 'rxjs/operators'; @@ -55,11 +54,9 @@ describe('Icon Service', () => { it('should add custom svg icon from url', () => { const iconService = TestBed.inject(IgxIconService) as IgxIconService; - const document = TestBed.inject(DOCUMENT); const name = 'test'; const family = 'svg-icons'; - const iconKey = family + '_' + name; spyOn(XMLHttpRequest.prototype, 'open').and.callThrough(); spyOn(XMLHttpRequest.prototype, 'send'); @@ -68,26 +65,17 @@ describe('Icon Service', () => { expect(XMLHttpRequest.prototype.open).toHaveBeenCalledTimes(1); expect(XMLHttpRequest.prototype.send).toHaveBeenCalledTimes(1); - - const svgElement = document.querySelector(`svg[id='${iconKey}']`); - expect(svgElement).toBeDefined(); + expect(iconService.isSvgIconCached(name, family)).toBeTruthy(); }); it('should add custom svg icon from text', () => { const iconService = TestBed.inject(IgxIconService) as IgxIconService; - const document = TestBed.inject(DOCUMENT); const name = 'test'; const family = 'svg-icons'; - const iconKey = family + '_' + name; iconService.addSvgIconFromText(name, svgText, family); - expect(iconService.isSvgIconCached(name, family)).toBeTruthy(); - expect(iconService.getSvgIconKey(name, family)).toEqual(iconKey); - - const svgElement = document.querySelector(`svg[id='${iconKey}']`); - expect(svgElement).toBeDefined(); }); it('should emit loading event for a custom svg icon from url', done => { @@ -113,17 +101,4 @@ describe('Icon Service', () => { iconService.addSvgIcon(name, 'test.svg', family); }); - - it('should create svg container inside the body', () => { - const iconService = TestBed.inject(IgxIconService) as IgxIconService; - const document = TestBed.inject(DOCUMENT); - - const name = 'test'; - const family = 'svg-icons'; - - iconService.addSvgIconFromText(name, svgText, family); - - const svgContainer = document.body.querySelector('.igx-svg-container'); - expect(svgContainer).not.toBeNull(); - }); }); From 1d355d301f5fa3290cc2a308c683aef12f1d378b Mon Sep 17 00:00:00 2001 From: Simeon Simeonoff Date: Mon, 27 Sep 2021 20:25:08 +0300 Subject: [PATCH 04/18] refactor(icon): remove lifecycle hook changes --- .../src/lib/icon/icon.component.ts | 23 ++----------------- 1 file changed, 2 insertions(+), 21 deletions(-) diff --git a/projects/igniteui-angular/src/lib/icon/icon.component.ts b/projects/igniteui-angular/src/lib/icon/icon.component.ts index 27a84e7f59c..52f388d7290 100644 --- a/projects/igniteui-angular/src/lib/icon/icon.component.ts +++ b/projects/igniteui-angular/src/lib/icon/icon.component.ts @@ -1,15 +1,4 @@ -import { - Component, - ElementRef, - HostBinding, - Input, - OnInit, - TemplateRef, - ViewChild, - ChangeDetectorRef, - OnDestroy, - AfterViewInit -} from '@angular/core'; +import { Component, ElementRef, HostBinding, Input, OnInit, TemplateRef, ViewChild, ChangeDetectorRef, OnDestroy } from '@angular/core'; import { IgxIconService } from './icon.service'; import { first, takeUntil } from 'rxjs/operators'; import { Subject } from 'rxjs'; @@ -42,7 +31,7 @@ import { DomSanitizer, SafeHtml } from '@angular/platform-browser'; selector: 'igx-icon', templateUrl: 'icon.component.html' }) -export class IgxIconComponent implements OnInit, AfterViewInit, OnDestroy { +export class IgxIconComponent implements OnInit, OnDestroy { /** * This allows you to change the value of `class.igx-icon`. By default it's `igx-icon`. * @@ -150,14 +139,6 @@ export class IgxIconComponent implements OnInit, AfterViewInit, OnDestroy { this.updateIconClass(); } - /** - * @hidden - * @internal - */ - public ngAfterViewInit() { - console.log(this.getSvg); - } - /** * @hidden * @internal From 1914241c025a1f3537bbcf1d3bf49bae1feffc71 Mon Sep 17 00:00:00 2001 From: Simeon Simeonoff Date: Mon, 27 Sep 2021 20:29:13 +0300 Subject: [PATCH 05/18] docs(icon, icon-service): update after changes --- projects/igniteui-angular/src/lib/icon/icon.component.ts | 5 ++--- projects/igniteui-angular/src/lib/icon/icon.service.ts | 2 +- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/projects/igniteui-angular/src/lib/icon/icon.component.ts b/projects/igniteui-angular/src/lib/icon/icon.component.ts index 52f388d7290..65143033d27 100644 --- a/projects/igniteui-angular/src/lib/icon/icon.component.ts +++ b/projects/igniteui-angular/src/lib/icon/icon.component.ts @@ -231,15 +231,14 @@ export class IgxIconComponent implements OnInit, OnDestroy { } /** - * An accessor that returns the key of the SVG image. - * The key consists of the font-family and the name separated by underscore. + * An accessor that returns the underlying SVG image as SafeHtml. * * @example * ```typescript * @ViewChild("MyIcon") * public icon: IgxIconComponent; * ngAfterViewInit() { - * let svgKey = this.icon.getSvgKey; + * let svg: SafeHtml = this.icon.getSvg; * } * ``` */ diff --git a/projects/igniteui-angular/src/lib/icon/icon.service.ts b/projects/igniteui-angular/src/lib/icon/icon.service.ts index fb163bc3bf9..056bcc05bd5 100644 --- a/projects/igniteui-angular/src/lib/icon/icon.service.ts +++ b/projects/igniteui-angular/src/lib/icon/icon.service.ts @@ -162,7 +162,7 @@ export class IgxIconService { } /** - * Returns the key of a cached SVG image. + * Returns the cached SVG image as string. * ```typescript * const svgIcon = this.iconService.getSvgIcon('aruba', 'svg-flags'); * ``` From 9a66b4445db47d4651b802f11c1774313cd238fd Mon Sep 17 00:00:00 2001 From: Simeon Simeonoff Date: Tue, 28 Sep 2021 14:51:37 +0300 Subject: [PATCH 06/18] docs(icon-service): update --- projects/igniteui-angular/src/lib/icon/icon.service.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/projects/igniteui-angular/src/lib/icon/icon.service.ts b/projects/igniteui-angular/src/lib/icon/icon.service.ts index 056bcc05bd5..c2b5f83d804 100644 --- a/projects/igniteui-angular/src/lib/icon/icon.service.ts +++ b/projects/igniteui-angular/src/lib/icon/icon.service.ts @@ -182,6 +182,9 @@ export class IgxIconService { return req; } + /** + * @hidden + */ private getOrCreateIconFamily(name: string) { let family: Map; From 52ee5061faa90213d6dad205b044f0c0684447a5 Mon Sep 17 00:00:00 2001 From: Simeon Simeonoff Date: Tue, 28 Sep 2021 14:52:23 +0300 Subject: [PATCH 07/18] refactor(icon): update template and theme --- .../src/lib/core/styles/components/icon/_icon-theme.scss | 4 ---- .../igniteui-angular/src/lib/icon/icon.component.html | 8 +++++++- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/projects/igniteui-angular/src/lib/core/styles/components/icon/_icon-theme.scss b/projects/igniteui-angular/src/lib/core/styles/components/icon/_icon-theme.scss index 5984304189d..04957eaa8ea 100644 --- a/projects/igniteui-angular/src/lib/core/styles/components/icon/_icon-theme.scss +++ b/projects/igniteui-angular/src/lib/core/styles/components/icon/_icon-theme.scss @@ -68,10 +68,6 @@ width: inherit; height: inherit; fill: currentColor; - - use { - pointer-events: none; - } } } diff --git a/projects/igniteui-angular/src/lib/icon/icon.component.html b/projects/igniteui-angular/src/lib/icon/icon.component.html index f9863a0166b..30ada748d25 100644 --- a/projects/igniteui-angular/src/lib/icon/icon.component.html +++ b/projects/igniteui-angular/src/lib/icon/icon.component.html @@ -5,7 +5,13 @@ - + From e95d2570044384e81b59b28aab2f57072dd84453 Mon Sep 17 00:00:00 2001 From: Simeon Simeonoff Date: Tue, 28 Sep 2021 14:52:41 +0300 Subject: [PATCH 08/18] chore(*): update svg assets --- src/assets/svg/filtering/contains.svg | 19 +---------------- src/assets/svg/filtering/does_not_contain.svg | 21 ++----------------- src/assets/svg/filtering/does_not_equal.svg | 19 +---------------- src/assets/svg/filtering/ends_with.svg | 19 +---------------- src/assets/svg/filtering/equals.svg | 19 +---------------- src/assets/svg/filtering/is_empty.svg | 19 +---------------- src/assets/svg/filtering/starts_with.svg | 19 +---------------- 7 files changed, 8 insertions(+), 127 deletions(-) diff --git a/src/assets/svg/filtering/contains.svg b/src/assets/svg/filtering/contains.svg index a69a25741ca..67ca24a7550 100644 --- a/src/assets/svg/filtering/contains.svg +++ b/src/assets/svg/filtering/contains.svg @@ -1,21 +1,4 @@ - - Icons/filter/contains - Created with Sketch. - - - - - - - - - - - - - - - \ No newline at end of file + diff --git a/src/assets/svg/filtering/does_not_contain.svg b/src/assets/svg/filtering/does_not_contain.svg index 75e0c0a9a2c..ea539ea543e 100644 --- a/src/assets/svg/filtering/does_not_contain.svg +++ b/src/assets/svg/filtering/does_not_contain.svg @@ -1,21 +1,4 @@ - - - Icons/filter/does not contain - Created with Sketch. + - - - - - - - - - - - - - - - \ No newline at end of file + diff --git a/src/assets/svg/filtering/does_not_equal.svg b/src/assets/svg/filtering/does_not_equal.svg index 585f8475ac7..3f45e895704 100644 --- a/src/assets/svg/filtering/does_not_equal.svg +++ b/src/assets/svg/filtering/does_not_equal.svg @@ -1,21 +1,4 @@ - - Icons/filter/does not equal - Created with Sketch. - - - - - - - - - - - - - - - \ No newline at end of file + diff --git a/src/assets/svg/filtering/ends_with.svg b/src/assets/svg/filtering/ends_with.svg index 6e0ce79bf28..eac2e5e66ba 100644 --- a/src/assets/svg/filtering/ends_with.svg +++ b/src/assets/svg/filtering/ends_with.svg @@ -1,21 +1,4 @@ - - Icons/filter/ends with - Created with Sketch. - - - - - - - - - - - - - - - \ No newline at end of file + diff --git a/src/assets/svg/filtering/equals.svg b/src/assets/svg/filtering/equals.svg index 47cf89046e6..6123793ff4b 100644 --- a/src/assets/svg/filtering/equals.svg +++ b/src/assets/svg/filtering/equals.svg @@ -1,21 +1,4 @@ - - Icons/filter/equals - Created with Sketch. - - - - - - - - - - - - - - - \ No newline at end of file + diff --git a/src/assets/svg/filtering/is_empty.svg b/src/assets/svg/filtering/is_empty.svg index dd271bcbbd9..5a8e83cb64b 100644 --- a/src/assets/svg/filtering/is_empty.svg +++ b/src/assets/svg/filtering/is_empty.svg @@ -1,21 +1,4 @@ - - Icons/filter/is empty - Created with Sketch. - - - - - - - - - - - - - - - \ No newline at end of file + diff --git a/src/assets/svg/filtering/starts_with.svg b/src/assets/svg/filtering/starts_with.svg index c5e44e0b699..317824785a2 100644 --- a/src/assets/svg/filtering/starts_with.svg +++ b/src/assets/svg/filtering/starts_with.svg @@ -1,21 +1,4 @@ - - Icons/filter/starts with - Created with Sketch. - - - - - - - - - - - - - - - \ No newline at end of file + From 02de7a831088d54f8b16fe4c986140ba29c36632 Mon Sep 17 00:00:00 2001 From: simeonoff Date: Tue, 28 Sep 2021 20:45:46 +0300 Subject: [PATCH 09/18] refactor(icon-service): simplify family initialization --- .../src/lib/icon/icon.service.ts | 27 +++++-------------- 1 file changed, 6 insertions(+), 21 deletions(-) diff --git a/projects/igniteui-angular/src/lib/icon/icon.service.ts b/projects/igniteui-angular/src/lib/icon/icon.service.ts index c2b5f83d804..47a838fa6e5 100644 --- a/projects/igniteui-angular/src/lib/icon/icon.service.ts +++ b/projects/igniteui-angular/src/lib/icon/icon.service.ts @@ -182,22 +182,6 @@ export class IgxIconService { return req; } - /** - * @hidden - */ - private getOrCreateIconFamily(name: string) { - let family: Map; - - if(this._cachedSvgIcons.has(name)) { - family = this._cachedSvgIcons.get(name) as Map; - } else { - family = new Map(); - this._cachedSvgIcons.set(name, family); - } - - return family; - } - /** * @hidden */ @@ -207,13 +191,14 @@ export class IgxIconService { div.innerHTML = value; const svg = div.querySelector('svg') as SVGElement; - if(svg) { + if (!this._cachedSvgIcons.has(family)) { + this._cachedSvgIcons.set(family, new Map()); + } + + if (svg) { svg.setAttribute('fit', ''); svg.setAttribute('preserveAspectRatio', 'xMidYMid meet'); - const svgText = svg.outerHTML; - - const familyRegistry = this.getOrCreateIconFamily(family); - familyRegistry.set(name, svgText); + this._cachedSvgIcons.get(family).set(name, svg.outerHTML); } } } From 9053bd475c48a95c9c1dd0f8b2a47034edd7733c Mon Sep 17 00:00:00 2001 From: simeonoff Date: Tue, 28 Sep 2021 20:46:10 +0300 Subject: [PATCH 10/18] spec(icon-service): fix failing test --- .../src/lib/icon/icon.service.spec.ts | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/projects/igniteui-angular/src/lib/icon/icon.service.spec.ts b/projects/igniteui-angular/src/lib/icon/icon.service.spec.ts index 1281c9855d5..89e9cdff673 100644 --- a/projects/igniteui-angular/src/lib/icon/icon.service.spec.ts +++ b/projects/igniteui-angular/src/lib/icon/icon.service.spec.ts @@ -1,4 +1,4 @@ -import { TestBed } from '@angular/core/testing'; +import { TestBed, fakeAsync } from '@angular/core/testing'; import { IgxIconService } from './icon.service'; import { configureTestSuite } from '../test-utils/configure-suite'; @@ -52,7 +52,7 @@ describe('Icon Service', () => { expect(iconService.familyClassName(ALIAS)).toBe(MY_FONT); }); - it('should add custom svg icon from url', () => { + it('should add custom svg icon from url', fakeAsync((done) => { const iconService = TestBed.inject(IgxIconService) as IgxIconService; const name = 'test'; @@ -65,8 +65,12 @@ describe('Icon Service', () => { expect(XMLHttpRequest.prototype.open).toHaveBeenCalledTimes(1); expect(XMLHttpRequest.prototype.send).toHaveBeenCalledTimes(1); - expect(iconService.isSvgIconCached(name, family)).toBeTruthy(); - }); + + iconService.iconLoaded.pipe().subscribe(() => { + expect(iconService.isSvgIconCached(name, family)).toBeTruthy(); + done(); + }); + })); it('should add custom svg icon from text', () => { const iconService = TestBed.inject(IgxIconService) as IgxIconService; From f60159c2b16e391520fc8464901e422a7950e266 Mon Sep 17 00:00:00 2001 From: Simeon Simeonoff Date: Fri, 1 Oct 2021 16:31:14 +0200 Subject: [PATCH 11/18] refactor(advanced-filtering): show friendly name for igx-select text --- .../advanced-filtering/advanced-filtering-dialog.component.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/projects/igniteui-angular/src/lib/grids/filtering/advanced-filtering/advanced-filtering-dialog.component.html b/projects/igniteui-angular/src/lib/grids/filtering/advanced-filtering/advanced-filtering-dialog.component.html index 918d4a09464..56b2d61ad00 100644 --- a/projects/igniteui-angular/src/lib/grids/filtering/advanced-filtering/advanced-filtering-dialog.component.html +++ b/projects/igniteui-angular/src/lib/grids/filtering/advanced-filtering/advanced-filtering-dialog.component.html @@ -162,7 +162,7 @@
- +
From b56d8beb2f3687488a89246995ed670ab801f8a6 Mon Sep 17 00:00:00 2001 From: Simeon Simeonoff Date: Fri, 1 Oct 2021 18:28:34 +0200 Subject: [PATCH 12/18] refactor(excel-filter): use condition friendly name --- .../excel-style/excel-style-default-expression.component.html | 2 +- .../excel-style/excel-style-default-expression.component.ts | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/projects/igniteui-angular/src/lib/grids/filtering/excel-style/excel-style-default-expression.component.html b/projects/igniteui-angular/src/lib/grids/filtering/excel-style/excel-style-default-expression.component.html index 53f40145c0f..ba9f88ac028 100644 --- a/projects/igniteui-angular/src/lib/grids/filtering/excel-style/excel-style-default-expression.component.html +++ b/projects/igniteui-angular/src/lib/grids/filtering/excel-style/excel-style-default-expression.component.html @@ -8,7 +8,7 @@ filter_list - +
{{translateCondition(condition)}} diff --git a/projects/igniteui-angular/src/lib/grids/filtering/excel-style/excel-style-default-expression.component.ts b/projects/igniteui-angular/src/lib/grids/filtering/excel-style/excel-style-default-expression.component.ts index 878b7e8df9a..2a48c59e02a 100644 --- a/projects/igniteui-angular/src/lib/grids/filtering/excel-style/excel-style-default-expression.component.ts +++ b/projects/igniteui-angular/src/lib/grids/filtering/excel-style/excel-style-default-expression.component.ts @@ -155,6 +155,10 @@ export class IgxExcelStyleDefaultExpressionComponent implements AfterViewInit { return this.column.filters.condition(value); } + public getConditionFriendlyName(name: string): string { + return this.grid.resourceStrings[`igx_grid_filter_${name}`] || name; + } + public onValuesInput(eventArgs) { this.expressionUI.expression.searchVal = DataUtil.parseValue(this.column.dataType, eventArgs.target.value); } From 54ca87f1f2c72049d4edf97c1658b5768ad71259 Mon Sep 17 00:00:00 2001 From: Simeon Simeonoff Date: Mon, 4 Oct 2021 12:29:05 +0200 Subject: [PATCH 13/18] refactor(icon, icon-service): simplify code --- projects/igniteui-angular/src/lib/icon/icon.component.ts | 3 +-- projects/igniteui-angular/src/lib/icon/icon.service.ts | 5 +---- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/projects/igniteui-angular/src/lib/icon/icon.component.ts b/projects/igniteui-angular/src/lib/icon/icon.component.ts index 65143033d27..443b005d587 100644 --- a/projects/igniteui-angular/src/lib/icon/icon.component.ts +++ b/projects/igniteui-angular/src/lib/icon/icon.component.ts @@ -245,8 +245,7 @@ export class IgxIconComponent implements OnInit, OnDestroy { public get getSvg(): SafeHtml { if (this.iconService.isSvgIconCached(this.name, this.family)) { const svgText = this.iconService.getSvgIcon(this.name, this.family); - const svg = this.sanitizer.bypassSecurityTrustHtml(svgText); - return svg; + return this.sanitizer.bypassSecurityTrustHtml(svgText); } return null; diff --git a/projects/igniteui-angular/src/lib/icon/icon.service.ts b/projects/igniteui-angular/src/lib/icon/icon.service.ts index 47a838fa6e5..26d2b36a288 100644 --- a/projects/igniteui-angular/src/lib/icon/icon.service.ts +++ b/projects/igniteui-angular/src/lib/icon/icon.service.ts @@ -168,10 +168,7 @@ export class IgxIconService { * ``` */ public getSvgIcon(name: string, family: string = '') { - if(this._cachedSvgIcons.has(family)) { - const familyRegistry = this._cachedSvgIcons.get(family) as Map; - return familyRegistry.get(name); - } + return this._cachedSvgIcons.get(family)?.get(name); } /** From 0252f7cf8e2b0a6f796c214abeb3d7dabe54cb0e Mon Sep 17 00:00:00 2001 From: Hristo Anastasov Date: Mon, 4 Oct 2021 14:47:16 +0300 Subject: [PATCH 14/18] test(grid): dont include the svg icon in the query for dropdown item --- .../src/lib/test-utils/grid-functions.spec.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/projects/igniteui-angular/src/lib/test-utils/grid-functions.spec.ts b/projects/igniteui-angular/src/lib/test-utils/grid-functions.spec.ts index c822dd4d2d9..35de81a1d9d 100644 --- a/projects/igniteui-angular/src/lib/test-utils/grid-functions.spec.ts +++ b/projects/igniteui-angular/src/lib/test-utils/grid-functions.spec.ts @@ -596,8 +596,9 @@ export class GridFunctions { const ddItems = ddList.nativeElement.children; let i; for (i = 0; i < ddItems.length; i++) { - if (ddItems[i].textContent === cond) { - ddItems[i].click(); + const ddItem = ddItems[i].querySelector('.igx-grid__filtering-dropdown-items span'); + if (ddItem.textContent === cond) { + ddItem.click(); tick(100); return; } From b14c0ee1a8431eb4458b91affea1201539a24c1b Mon Sep 17 00:00:00 2001 From: Simeon Simeonoff Date: Thu, 7 Oct 2021 14:59:54 +0300 Subject: [PATCH 15/18] refactor(icon, icon service): cache svg icons as SafeHtml --- .../src/lib/icon/icon.component.html | 8 +------- .../src/lib/icon/icon.component.ts | 6 ++---- .../src/lib/icon/icon.service.ts | 17 +++++++++-------- 3 files changed, 12 insertions(+), 19 deletions(-) diff --git a/projects/igniteui-angular/src/lib/icon/icon.component.html b/projects/igniteui-angular/src/lib/icon/icon.component.html index 30ada748d25..023d7706538 100644 --- a/projects/igniteui-angular/src/lib/icon/icon.component.html +++ b/projects/igniteui-angular/src/lib/icon/icon.component.html @@ -5,13 +5,7 @@ - + diff --git a/projects/igniteui-angular/src/lib/icon/icon.component.ts b/projects/igniteui-angular/src/lib/icon/icon.component.ts index 443b005d587..b1f83eb65da 100644 --- a/projects/igniteui-angular/src/lib/icon/icon.component.ts +++ b/projects/igniteui-angular/src/lib/icon/icon.component.ts @@ -3,7 +3,7 @@ import { IgxIconService } from './icon.service'; import { first, takeUntil } from 'rxjs/operators'; import { Subject } from 'rxjs'; import { DeprecateProperty } from '../core/deprecateDecorators'; -import { DomSanitizer, SafeHtml } from '@angular/platform-browser'; +import { SafeHtml } from '@angular/platform-browser'; /** * Icon provides a way to include material icons to markup @@ -119,7 +119,6 @@ export class IgxIconComponent implements OnInit, OnDestroy { public el: ElementRef, private iconService: IgxIconService, private ref: ChangeDetectorRef, - private sanitizer: DomSanitizer ) { this.family = this.iconService.defaultFamily; this.iconService.registerFamilyAlias('material', 'material-icons'); @@ -244,8 +243,7 @@ export class IgxIconComponent implements OnInit, OnDestroy { */ public get getSvg(): SafeHtml { if (this.iconService.isSvgIconCached(this.name, this.family)) { - const svgText = this.iconService.getSvgIcon(this.name, this.family); - return this.sanitizer.bypassSecurityTrustHtml(svgText); + return this.iconService.getSvgIcon(this.name, this.family); } return null; diff --git a/projects/igniteui-angular/src/lib/icon/icon.service.ts b/projects/igniteui-angular/src/lib/icon/icon.service.ts index 26d2b36a288..ca22d4b463a 100644 --- a/projects/igniteui-angular/src/lib/icon/icon.service.ts +++ b/projects/igniteui-angular/src/lib/icon/icon.service.ts @@ -1,5 +1,5 @@ import { Injectable, SecurityContext, Inject, Optional } from '@angular/core'; -import { DomSanitizer } from '@angular/platform-browser'; +import { DomSanitizer, SafeHtml } from '@angular/platform-browser'; import { DOCUMENT } from '@angular/common'; import { HttpClient } from '@angular/common/http'; import { Observable, Subject } from 'rxjs'; @@ -46,8 +46,9 @@ export class IgxIconService { private _family = 'material-icons'; private _familyAliases = new Map(); - private _cachedSvgIcons = new Map>(); + private _cachedSvgIcons = new Map>(); private _iconLoaded = new Subject(); + private _domParser = new DOMParser(); constructor( @Optional() private _sanitizer: DomSanitizer, @@ -154,7 +155,7 @@ export class IgxIconService { */ public isSvgIconCached(name: string, family: string = ''): boolean { if(this._cachedSvgIcons.has(family)) { - const familyRegistry = this._cachedSvgIcons.get(family) as Map; + const familyRegistry = this._cachedSvgIcons.get(family) as Map; return familyRegistry.has(name); } @@ -184,18 +185,18 @@ export class IgxIconService { */ private cacheSvgIcon(name: string, value: string, family: string = '') { if (name && value) { - const div = this._document.createElement('div'); - div.innerHTML = value; - const svg = div.querySelector('svg') as SVGElement; + const doc = this._domParser.parseFromString(value, 'image/svg+xml'); + const svg = doc.querySelector('svg') as SVGElement; if (!this._cachedSvgIcons.has(family)) { - this._cachedSvgIcons.set(family, new Map()); + this._cachedSvgIcons.set(family, new Map()); } if (svg) { svg.setAttribute('fit', ''); svg.setAttribute('preserveAspectRatio', 'xMidYMid meet'); - this._cachedSvgIcons.get(family).set(name, svg.outerHTML); + const safeSvg = this._sanitizer.bypassSecurityTrustHtml(svg.outerHTML); + this._cachedSvgIcons.get(family).set(name, safeSvg); } } } From 283951554871b7b944bbb2dbbba73be73748c1cb Mon Sep 17 00:00:00 2001 From: Simeon Simeonoff Date: Thu, 7 Oct 2021 16:05:56 +0300 Subject: [PATCH 16/18] refactor(icon): replace svg wrapper with a div --- .../src/lib/core/styles/components/icon/_icon-theme.scss | 1 + projects/igniteui-angular/src/lib/icon/icon.component.html | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/projects/igniteui-angular/src/lib/core/styles/components/icon/_icon-theme.scss b/projects/igniteui-angular/src/lib/core/styles/components/icon/_icon-theme.scss index 04957eaa8ea..31af23f91e3 100644 --- a/projects/igniteui-angular/src/lib/core/styles/components/icon/_icon-theme.scss +++ b/projects/igniteui-angular/src/lib/core/styles/components/icon/_icon-theme.scss @@ -64,6 +64,7 @@ font-size: $igx-icon-font-size; color: --var($theme, 'color'); + div, svg { width: inherit; height: inherit; diff --git a/projects/igniteui-angular/src/lib/icon/icon.component.html b/projects/igniteui-angular/src/lib/icon/icon.component.html index 023d7706538..09a4d7d7cf1 100644 --- a/projects/igniteui-angular/src/lib/icon/icon.component.html +++ b/projects/igniteui-angular/src/lib/icon/icon.component.html @@ -5,7 +5,7 @@ - +
From 52ab7d5f016ee1cacbbe816fef45ca2265fcf0c7 Mon Sep 17 00:00:00 2001 From: Simeon Simeonoff Date: Thu, 7 Oct 2021 16:06:14 +0300 Subject: [PATCH 17/18] refactor(demos): add a new test icon --- src/app/icon/icon.sample.html | 1 + src/app/icon/icon.sample.ts | 1 + src/assets/svg/filtering/copy.svg | 3 +++ 3 files changed, 5 insertions(+) create mode 100644 src/assets/svg/filtering/copy.svg diff --git a/src/app/icon/icon.sample.html b/src/app/icon/icon.sample.html index 3babb750cff..625b60acf75 100644 --- a/src/app/icon/icon.sample.html +++ b/src/app/icon/icon.sample.html @@ -86,6 +86,7 @@

Using SVG Icons

+
diff --git a/src/app/icon/icon.sample.ts b/src/app/icon/icon.sample.ts index 0b2174a9d52..341e3427249 100644 --- a/src/app/icon/icon.sample.ts +++ b/src/app/icon/icon.sample.ts @@ -19,5 +19,6 @@ export class IconSampleComponent implements OnInit { this._iconService.addSvgIcon('equals', '/assets/svg/filtering/equals.svg', 'svg-flags'); this._iconService.addSvgIcon('is_empty', '/assets/svg/filtering/is_empty.svg', 'svg-flags'); this._iconService.addSvgIcon('starts_with', '/assets/svg/filtering/starts_with.svg', 'svg-flags'); + this._iconService.addSvgIcon('copy', '/assets/svg/filtering/copy.svg', 'svg-flags'); } } diff --git a/src/assets/svg/filtering/copy.svg b/src/assets/svg/filtering/copy.svg new file mode 100644 index 00000000000..9837dbd779f --- /dev/null +++ b/src/assets/svg/filtering/copy.svg @@ -0,0 +1,3 @@ + + + From 5f652acfa212e131bf3777faf713aa3dc53d1e33 Mon Sep 17 00:00:00 2001 From: Simeon Simeonoff Date: Fri, 8 Oct 2021 12:33:59 +0300 Subject: [PATCH 18/18] refactor(icon): set svg and div to display block --- .../src/lib/core/styles/components/icon/_icon-theme.scss | 1 + 1 file changed, 1 insertion(+) diff --git a/projects/igniteui-angular/src/lib/core/styles/components/icon/_icon-theme.scss b/projects/igniteui-angular/src/lib/core/styles/components/icon/_icon-theme.scss index 31af23f91e3..00167f8686f 100644 --- a/projects/igniteui-angular/src/lib/core/styles/components/icon/_icon-theme.scss +++ b/projects/igniteui-angular/src/lib/core/styles/components/icon/_icon-theme.scss @@ -66,6 +66,7 @@ div, svg { + display: block; width: inherit; height: inherit; fill: currentColor;