Skip to content

Commit cf03621

Browse files
crisbetojelbourn
authored andcommitted
fix(icon): handle unescaped characters in names (#15678)
Handles the icon registry not being able to find icons whose ids contain unescaped characters (e.g. spaces). Note that for this example in particular having a space in the id is invalid, however I did it since supporting it is trivial. Fixes #15673.
1 parent 7794304 commit cf03621

File tree

3 files changed

+34
-1
lines changed

3 files changed

+34
-1
lines changed

src/material/icon/fake-svgs.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
export const FAKE_SVGS = {
1515
cat: '<svg><path id="meow" name="meow"></path></svg>',
1616
dog: '<svg><path id="woof" name="woof"></path></svg>',
17+
dogWithSpaces: '<svg><path id="woof says the dog" name="woof"></path></svg>',
1718
farmSet1: `
1819
<svg>
1920
<defs>
@@ -37,6 +38,13 @@ export const FAKE_SVGS = {
3738
</symbol>
3839
</svg>
3940
`,
41+
farmSet4: `
42+
<svg>
43+
<defs>
44+
<g id="pig with spaces" name="pig"><path name="oink"></path></g>
45+
</defs>
46+
</svg>
47+
`,
4048
arrows: `
4149
<svg>
4250
<defs>

src/material/icon/icon-registry.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -449,7 +449,9 @@ export class MatIconRegistry implements OnDestroy {
449449
* returns it. Returns null if no matching element is found.
450450
*/
451451
private _extractSvgIconFromSet(iconSet: SVGElement, iconName: string): SVGElement | null {
452-
const iconSource = iconSet.querySelector('#' + iconName);
452+
// Use the `id="iconName"` syntax in order to escape special
453+
// characters in the ID (versus using the #iconName syntax).
454+
const iconSource = iconSet.querySelector(`[id="${iconName}"]`);
453455

454456
if (!iconSource) {
455457
return null;

src/material/icon/icon.spec.ts

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -268,6 +268,29 @@ describe('MatIcon', () => {
268268
verifyPathChildElement(svgChild, 'moo');
269269
});
270270

271+
it('should handle unescape characters in icon names', () => {
272+
iconRegistry.addSvgIconSetInNamespace('farm', trustUrl('farm-set-4.svg'));
273+
274+
const fixture = TestBed.createComponent(IconFromSvgName);
275+
const testComponent = fixture.componentInstance;
276+
const matIconElement = fixture.debugElement.nativeElement.querySelector('mat-icon');
277+
let svgElement: any;
278+
let svgChild: any;
279+
280+
testComponent.iconName = 'farm:pig with spaces';
281+
fixture.detectChanges();
282+
http.expectOne('farm-set-4.svg').flush(FAKE_SVGS.farmSet4);
283+
284+
expect(matIconElement.childNodes.length).toBe(1);
285+
svgElement = verifyAndGetSingleSvgChild(matIconElement);
286+
expect(svgElement.childNodes.length).toBe(1);
287+
svgChild = svgElement.childNodes[0];
288+
// The first <svg> child should be the <g id="pig"> element.
289+
expect(svgChild.tagName.toLowerCase()).toBe('g');
290+
expect(svgChild.getAttribute('name')).toBe('pig');
291+
verifyPathChildElement(svgChild, 'oink');
292+
});
293+
271294
it('should never parse the same icon set multiple times', () => {
272295
// Normally we avoid spying on private methods like this, but the parsing is a private
273296
// implementation detail that should not be exposed to the public API. This test, though,

0 commit comments

Comments
 (0)