Skip to content

Commit d9e12e2

Browse files
authored
Merge branch '12.2.x' into dmdimitrov/fix-10005-12.2.x
2 parents f38756f + d6bc47e commit d9e12e2

20 files changed

+74
-245
lines changed

README.md

+4-6
Original file line numberDiff line numberDiff line change
@@ -25,12 +25,10 @@ Ignite UI for Angular arrives with an extensive library of data visualizations t
2525

2626
Some of the Angular chart types included are: [Polar chart](https://www.infragistics.com/products/ignite-ui-angular/angular/components/charts/types/polar-chart), [Pie chart](https://www.infragistics.com/products/ignite-ui-angular/angular/components/charts/types/pie-chart), [Donut chart](https://www.infragistics.com/products/ignite-ui-angular/angular/components/charts/types/donut-chart), [Bubble chart](https://www.infragistics.com/products/ignite-ui-angular/angular/components/charts/types/bubble-chart), [Area chart](https://www.infragistics.com/products/ignite-ui-angular/angular/components/charts/types/area-chart), [Treemap chart](https://www.infragistics.com/products/ignite-ui-angular/angular/components/charts/types/treemap-chart), and many others. And if you look for [Angular financial charts](https://www.infragistics.com/products/ignite-ui-angular/angular/components/charts/types/stock-chart), with Ignite UI you can get the same features as the ones you come across with Google Finance and Yahoo Finance Charts.
2727

28-
### [**Install our VSCode Toolbox extension**](https://marketplace.visualstudio.com/items?itemName=Infragistics.igniteui-angular-toolbox)
29-
![](https://dl.infragistics.com/tools/extensions/angular-toolbox/toolbox.gif)
30-
### [**Install our VSCode tooltip extension**](https://marketplace.visualstudio.com/items?itemName=Infragistics.igniteui-angular-tooltips)
31-
![](https://dl.infragistics.com/tools/extensions/angular-tooltips/tooltip_preview.gif)
32-
33-
**IMPORTANT** The repository has been renamed from `igniteui-js-blocks` to `igniteui-angular`. Read more on our new [naming convention](https://www.infragistics.com/community/blogs/b/infragistics/posts/ignite-ui-github-repo-name-changes).
28+
### Build Apps with Ignite UI for Angular faster using our [App Builder](https://www.infragistics.com/products/indigo-design/app-builder)
29+
![5661 drag drop](https://user-images.githubusercontent.com/1472513/132676597-09eec222-42f7-40ff-bd0d-fe8b91fd0c1c.gif)
30+
### Generate your Angular code projects using the [App Builder](https://www.infragistics.com/products/indigo-design/app-builder)
31+
![0871 change-preview-code](https://user-images.githubusercontent.com/1472513/132676607-3851f308-416b-45d6-99bc-c34266b55c44.gif)
3432

3533
### Current List of Components Include:
3634

projects/igniteui-angular/src/lib/core/styles/components/icon/_icon-theme.scss

+2-4
Original file line numberDiff line numberDiff line change
@@ -64,14 +64,12 @@
6464
font-size: $igx-icon-font-size;
6565
color: --var($theme, 'color');
6666

67+
div,
6768
svg {
69+
display: block;
6870
width: inherit;
6971
height: inherit;
7072
fill: currentColor;
71-
72-
use {
73-
pointer-events: none;
74-
}
7573
}
7674
}
7775

projects/igniteui-angular/src/lib/grids/filtering/advanced-filtering/advanced-filtering-dialog.component.html

+1-1
Original file line numberDiff line numberDiff line change
@@ -162,7 +162,7 @@ <h6 class="igx-filter-empty__title">
162162
<igx-icon family="imx-icons" [name]="selectedColumn.filters.condition(conditionSelect.value).iconName">
163163
</igx-icon>
164164
</igx-prefix>
165-
<igx-select-item *ngFor="let condition of getConditionList()" [value]="condition">
165+
<igx-select-item *ngFor="let condition of getConditionList()" [value]="condition" [text]="getConditionFriendlyName(condition)">
166166
<div class="igx-grid__filtering-dropdown-items">
167167
<igx-icon family="imx-icons"
168168
[name]="selectedColumn.filters.condition(condition).iconName">

projects/igniteui-angular/src/lib/grids/filtering/excel-style/excel-style-default-expression.component.html

+1-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
<igx-icon *ngIf="expressionUI.expression.condition" family="imx-icons" [name]="getIconName()"></igx-icon>
99
<igx-icon *ngIf="!expressionUI.expression.condition">filter_list</igx-icon>
1010
</igx-prefix>
11-
<igx-select-item *ngFor="let condition of conditions" [value]="condition" [selected]="isConditionSelected(condition)">
11+
<igx-select-item *ngFor="let condition of conditions" [value]="condition" [text]="getConditionFriendlyName(condition)" [selected]="isConditionSelected(condition)">
1212
<div class="igx-grid__filtering-dropdown-items">
1313
<igx-icon family="imx-icons" [name]="getCondition(condition).iconName"></igx-icon>
1414
<span class="igx-grid__filtering-dropdown-text">{{translateCondition(condition)}}</span>

projects/igniteui-angular/src/lib/grids/filtering/excel-style/excel-style-default-expression.component.ts

+4
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,10 @@ export class IgxExcelStyleDefaultExpressionComponent implements AfterViewInit {
155155
return this.column.filters.condition(value);
156156
}
157157

158+
public getConditionFriendlyName(name: string): string {
159+
return this.grid.resourceStrings[`igx_grid_filter_${name}`] || name;
160+
}
161+
158162
public onValuesInput(eventArgs) {
159163
this.expressionUI.expression.searchVal = DataUtil.parseValue(this.column.dataType, eventArgs.target.value);
160164
}

projects/igniteui-angular/src/lib/icon/icon.component.html

+1-3
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,7 @@
55
</ng-template>
66

77
<ng-template #svgImage>
8-
<svg>
9-
<use [attr.href]="getSvgKey"></use>
10-
</svg>
8+
<div [innerHTML]="getSvg"></div>
119
</ng-template>
1210

1311
<ng-container *ngTemplateOutlet="template"></ng-container>

projects/igniteui-angular/src/lib/icon/icon.component.ts

+16-13
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { IgxIconService } from './icon.service';
33
import { first, takeUntil } from 'rxjs/operators';
44
import { Subject } from 'rxjs';
55
import { DeprecateProperty } from '../core/deprecateDecorators';
6+
import { SafeHtml } from '@angular/platform-browser';
67

78
/**
89
* Icon provides a way to include material icons to markup
@@ -114,16 +115,19 @@ export class IgxIconComponent implements OnInit, OnDestroy {
114115

115116
private destroy$ = new Subject<void>();
116117

117-
constructor(public el: ElementRef,
118-
private iconService: IgxIconService,
119-
private ref: ChangeDetectorRef) {
118+
constructor(
119+
public el: ElementRef,
120+
private iconService: IgxIconService,
121+
private ref: ChangeDetectorRef,
122+
) {
120123
this.family = this.iconService.defaultFamily;
121124
this.iconService.registerFamilyAlias('material', 'material-icons');
122-
this.iconService.iconLoaded.pipe(
123-
first(e => e.name === this.name && e.family === this.family),
124-
takeUntil(this.destroy$)
125-
)
126-
.subscribe(() => this.ref.detectChanges());
125+
this.iconService.iconLoaded
126+
.pipe(
127+
first((e) => e.name === this.name && e.family === this.family),
128+
takeUntil(this.destroy$)
129+
)
130+
.subscribe(() => this.ref.detectChanges());
127131
}
128132

129133
/**
@@ -226,21 +230,20 @@ export class IgxIconComponent implements OnInit, OnDestroy {
226230
}
227231

228232
/**
229-
* An accessor that returns the key of the SVG image.
230-
* The key consists of the font-family and the name separated by underscore.
233+
* An accessor that returns the underlying SVG image as SafeHtml.
231234
*
232235
* @example
233236
* ```typescript
234237
* @ViewChild("MyIcon")
235238
* public icon: IgxIconComponent;
236239
* ngAfterViewInit() {
237-
* let svgKey = this.icon.getSvgKey;
240+
* let svg: SafeHtml = this.icon.getSvg;
238241
* }
239242
* ```
240243
*/
241-
public get getSvgKey(): string {
244+
public get getSvg(): SafeHtml {
242245
if (this.iconService.isSvgIconCached(this.name, this.family)) {
243-
return '#' + this.iconService.getSvgIconKey(this.name, this.family);
246+
return this.iconService.getSvgIcon(this.name, this.family);
244247
}
245248

246249
return null;

projects/igniteui-angular/src/lib/icon/icon.service.spec.ts

+7-28
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
1-
import { TestBed } from '@angular/core/testing';
1+
import { TestBed, fakeAsync } from '@angular/core/testing';
22
import { IgxIconService } from './icon.service';
3-
import { DOCUMENT } from '@angular/common';
43

54
import { configureTestSuite } from '../test-utils/configure-suite';
65
import { first } from 'rxjs/operators';
@@ -53,13 +52,11 @@ describe('Icon Service', () => {
5352
expect(iconService.familyClassName(ALIAS)).toBe(MY_FONT);
5453
});
5554

56-
it('should add custom svg icon from url', () => {
55+
it('should add custom svg icon from url', fakeAsync((done) => {
5756
const iconService = TestBed.inject(IgxIconService) as IgxIconService;
58-
const document = TestBed.inject(DOCUMENT);
5957

6058
const name = 'test';
6159
const family = 'svg-icons';
62-
const iconKey = family + '_' + name;
6360

6461
spyOn(XMLHttpRequest.prototype, 'open').and.callThrough();
6562
spyOn(XMLHttpRequest.prototype, 'send');
@@ -69,25 +66,20 @@ describe('Icon Service', () => {
6966
expect(XMLHttpRequest.prototype.open).toHaveBeenCalledTimes(1);
7067
expect(XMLHttpRequest.prototype.send).toHaveBeenCalledTimes(1);
7168

72-
const svgElement = document.querySelector(`svg[id='${iconKey}']`);
73-
expect(svgElement).toBeDefined();
74-
});
69+
iconService.iconLoaded.pipe().subscribe(() => {
70+
expect(iconService.isSvgIconCached(name, family)).toBeTruthy();
71+
done();
72+
});
73+
}));
7574

7675
it('should add custom svg icon from text', () => {
7776
const iconService = TestBed.inject(IgxIconService) as IgxIconService;
78-
const document = TestBed.inject(DOCUMENT);
7977

8078
const name = 'test';
8179
const family = 'svg-icons';
82-
const iconKey = family + '_' + name;
8380

8481
iconService.addSvgIconFromText(name, svgText, family);
85-
8682
expect(iconService.isSvgIconCached(name, family)).toBeTruthy();
87-
expect(iconService.getSvgIconKey(name, family)).toEqual(iconKey);
88-
89-
const svgElement = document.querySelector(`svg[id='${iconKey}']`);
90-
expect(svgElement).toBeDefined();
9183
});
9284

9385
it('should emit loading event for a custom svg icon from url', done => {
@@ -113,17 +105,4 @@ describe('Icon Service', () => {
113105

114106
iconService.addSvgIcon(name, 'test.svg', family);
115107
});
116-
117-
it('should create svg container inside the body', () => {
118-
const iconService = TestBed.inject(IgxIconService) as IgxIconService;
119-
const document = TestBed.inject(DOCUMENT);
120-
121-
const name = 'test';
122-
const family = 'svg-icons';
123-
124-
iconService.addSvgIconFromText(name, svgText, family);
125-
126-
const svgContainer = document.body.querySelector('.igx-svg-container');
127-
expect(svgContainer).not.toBeNull();
128-
});
129108
});

projects/igniteui-angular/src/lib/icon/icon.service.ts

+22-60
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
import { Injectable, SecurityContext, Inject, OnDestroy, Optional } from '@angular/core';
2-
import { DomSanitizer } from '@angular/platform-browser';
1+
import { Injectable, SecurityContext, Inject, Optional } from '@angular/core';
2+
import { DomSanitizer, SafeHtml } from '@angular/platform-browser';
33
import { DOCUMENT } from '@angular/common';
44
import { HttpClient } from '@angular/common/http';
55
import { Observable, Subject } from 'rxjs';
@@ -32,7 +32,7 @@ export interface IgxIconLoadedEvent {
3232
@Injectable({
3333
providedIn: 'root'
3434
})
35-
export class IgxIconService implements OnDestroy {
35+
export class IgxIconService {
3636
/**
3737
* Observable that emits when an icon is successfully loaded
3838
* through a HTTP request.
@@ -46,9 +46,9 @@ export class IgxIconService implements OnDestroy {
4646

4747
private _family = 'material-icons';
4848
private _familyAliases = new Map<string, string>();
49-
private _svgContainer: HTMLElement;
50-
private _cachedSvgIcons: Set<string> = new Set<string>();
49+
private _cachedSvgIcons = new Map<string, Map<string, SafeHtml>>();
5150
private _iconLoaded = new Subject<IgxIconLoadedEvent>();
51+
private _domParser = new DOMParser();
5252

5353
constructor(
5454
@Optional() private _sanitizer: DomSanitizer,
@@ -58,14 +58,6 @@ export class IgxIconService implements OnDestroy {
5858
this.iconLoaded = this._iconLoaded.asObservable();
5959
}
6060

61-
/**
62-
* @hidden
63-
* @internal
64-
*/
65-
public ngOnDestroy(): void {
66-
this.cleanSvgContainer();
67-
}
68-
6961
/**
7062
* Returns the default font-family.
7163
* ```typescript
@@ -162,18 +154,22 @@ export class IgxIconService implements OnDestroy {
162154
* ```
163155
*/
164156
public isSvgIconCached(name: string, family: string = ''): boolean {
165-
const iconKey = this.getSvgIconKey(name, family);
166-
return this._cachedSvgIcons.has(iconKey);
157+
if(this._cachedSvgIcons.has(family)) {
158+
const familyRegistry = this._cachedSvgIcons.get(family) as Map<string, SafeHtml>;
159+
return familyRegistry.has(name);
160+
}
161+
162+
return false;
167163
}
168164

169165
/**
170-
* Returns the key of a cached SVG image.
166+
* Returns the cached SVG image as string.
171167
* ```typescript
172-
* const svgIconKey = this.iconService.getSvgIconKey('aruba', 'svg-flags');
168+
* const svgIcon = this.iconService.getSvgIcon('aruba', 'svg-flags');
173169
* ```
174170
*/
175-
public getSvgIconKey(name: string, family: string = '') {
176-
return family + '_' + name;
171+
public getSvgIcon(name: string, family: string = '') {
172+
return this._cachedSvgIcons.get(family)?.get(name);
177173
}
178174

179175
/**
@@ -184,57 +180,23 @@ export class IgxIconService implements OnDestroy {
184180
return req;
185181
}
186182

187-
/**
188-
* @hidden
189-
*/
190-
private cleanSvgContainer() {
191-
const container = this._document.documentElement.querySelector('.igx-svg-container');
192-
193-
while (container.firstChild) {
194-
container.removeChild(container.firstChild);
195-
}
196-
}
197-
198183
/**
199184
* @hidden
200185
*/
201186
private cacheSvgIcon(name: string, value: string, family: string = '') {
202187
if (name && value) {
203-
this.ensureSvgContainerCreated();
188+
const doc = this._domParser.parseFromString(value, 'image/svg+xml');
189+
const svg = doc.querySelector('svg') as SVGElement;
204190

205-
const div = this._document.createElement('DIV');
206-
div.innerHTML = value;
207-
const svg = div.querySelector('svg') as SVGElement;
191+
if (!this._cachedSvgIcons.has(family)) {
192+
this._cachedSvgIcons.set(family, new Map<string, SafeHtml>());
193+
}
208194

209195
if (svg) {
210-
const iconKey = this.getSvgIconKey(name, family);
211-
212-
svg.setAttribute('id', iconKey);
213196
svg.setAttribute('fit', '');
214197
svg.setAttribute('preserveAspectRatio', 'xMidYMid meet');
215-
svg.setAttribute('focusable', 'false'); // Disable IE11 default behavior to make SVGs focusable.
216-
217-
if (this.isSvgIconCached(name, family)) {
218-
const oldChild = this._svgContainer.querySelector(`svg[id='${iconKey}']`);
219-
this._svgContainer.removeChild(oldChild);
220-
}
221-
222-
this._svgContainer.appendChild(svg);
223-
this._cachedSvgIcons.add(iconKey);
224-
}
225-
}
226-
}
227-
228-
/**
229-
* @hidden
230-
*/
231-
private ensureSvgContainerCreated() {
232-
if (!this._svgContainer) {
233-
this._svgContainer = this._document.documentElement.querySelector('.igx-svg-container');
234-
if (!this._svgContainer) {
235-
this._svgContainer = this._document.createElement('DIV');
236-
this._svgContainer.classList.add('igx-svg-container');
237-
this._document.body.appendChild(this._svgContainer);
198+
const safeSvg = this._sanitizer.bypassSecurityTrustHtml(svg.outerHTML);
199+
this._cachedSvgIcons.get(family).set(name, safeSvg);
238200
}
239201
}
240202
}

projects/igniteui-angular/src/lib/test-utils/grid-functions.spec.ts

+3-2
Original file line numberDiff line numberDiff line change
@@ -596,8 +596,9 @@ export class GridFunctions {
596596
const ddItems = ddList.nativeElement.children;
597597
let i;
598598
for (i = 0; i < ddItems.length; i++) {
599-
if (ddItems[i].textContent === cond) {
600-
ddItems[i].click();
599+
const ddItem = ddItems[i].querySelector('.igx-grid__filtering-dropdown-items span');
600+
if (ddItem.textContent === cond) {
601+
ddItem.click();
601602
tick(100);
602603
return;
603604
}

src/app/icon/icon.sample.html

+1
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@ <h4 class="sample-title">Using SVG Icons</h4>
8686
<igx-icon family="svg-flags" name="equals"></igx-icon>
8787
<igx-icon family="svg-flags" name="is_empty"></igx-icon>
8888
<igx-icon family="svg-flags" name="starts_with"></igx-icon>
89+
<igx-icon family="svg-flags" name="copy"></igx-icon>
8990
</div>
9091
</article>
9192

src/app/icon/icon.sample.ts

+1
Original file line numberDiff line numberDiff line change
@@ -19,5 +19,6 @@ export class IconSampleComponent implements OnInit {
1919
this._iconService.addSvgIcon('equals', '/assets/svg/filtering/equals.svg', 'svg-flags');
2020
this._iconService.addSvgIcon('is_empty', '/assets/svg/filtering/is_empty.svg', 'svg-flags');
2121
this._iconService.addSvgIcon('starts_with', '/assets/svg/filtering/starts_with.svg', 'svg-flags');
22+
this._iconService.addSvgIcon('copy', '/assets/svg/filtering/copy.svg', 'svg-flags');
2223
}
2324
}

src/assets/svg/filtering/contains.svg

+1-18
Loading

0 commit comments

Comments
 (0)