+ From inline template with MatIconProvider:
+
+
+
+
Mirrored in RTL:
+
+
@@ -22,6 +30,13 @@
+
+ From inline icon set:
+
+
+
+
+
Ligature from Material Icons font:
home
diff --git a/src/demo-app/icon/icon-demo.ts b/src/demo-app/icon/icon-demo.ts
index bc032395c3eb..f1db8062052e 100644
--- a/src/demo-app/icon/icon-demo.ts
+++ b/src/demo-app/icon/icon-demo.ts
@@ -22,8 +22,47 @@ export class IconDemo {
iconRegistry
.addSvgIcon('thumb-up',
sanitizer.bypassSecurityTrustResourceUrl('/icon/assets/thumbup-icon.svg'))
+ .addSvgIconLiteral('bike',
+ sanitizer.bypassSecurityTrustHtml(BIKE_ICON))
.addSvgIconSetInNamespace('core',
sanitizer.bypassSecurityTrustResourceUrl('/icon/assets/core-icon-set.svg'))
+ .addSvgIconSetLiteralInNamespace('core-inline',
+ sanitizer.bypassSecurityTrustHtml(INLINE_ICON_SET))
.registerFontClassAlias('fontawesome', 'fa');
}
}
+
+const BIKE_ICON = `
+
+
+
+
+`;
+
+const INLINE_ICON_SET = `
+
+
+
+
+
+
+
+
+
+
+
+
+
+`;
diff --git a/src/lib/icon/icon-registry.ts b/src/lib/icon/icon-registry.ts
index 30003f42903b..22f66e61c728 100644
--- a/src/lib/icon/icon-registry.ts
+++ b/src/lib/icon/icon-registry.ts
@@ -16,7 +16,7 @@ import {
SecurityContext,
SkipSelf,
} from '@angular/core';
-import {DomSanitizer, SafeResourceUrl} from '@angular/platform-browser';
+import {DomSanitizer, SafeResourceUrl, SafeHtml} from '@angular/platform-browser';
import {forkJoin, Observable, of as observableOf, throwError as observableThrow} from 'rxjs';
import {catchError, finalize, map, share, tap} from 'rxjs/operators';
@@ -48,18 +48,41 @@ export function getMatIconNoHttpProviderError(): Error {
* @param url URL that was attempted to be sanitized.
* @docs-private
*/
-export function getMatIconFailedToSanitizeError(url: SafeResourceUrl): Error {
+export function getMatIconFailedToSanitizeUrlError(url: SafeResourceUrl): Error {
return Error(`The URL provided to MatIconRegistry was not trusted as a resource URL ` +
`via Angular's DomSanitizer. Attempted URL was "${url}".`);
}
+/**
+ * Returns an exception to be thrown when a HTML string couldn't be sanitized.
+ * @param literal HTML that was attempted to be sanitized.
+ * @docs-private
+ */
+export function getMatIconFailedToSanitizeLiteralError(literal: SafeHtml): Error {
+ return Error(`The literal provided to MatIconRegistry was not trusted as safe HTML by ` +
+ `Angular's DomSanitizer. Attempted literal was "${literal}".`);
+}
+
+
/**
* Configuration for an icon, including the URL and possibly the cached SVG element.
* @docs-private
*/
class SvgIconConfig {
- svgElement: SVGElement | null = null;
- constructor(public url: SafeResourceUrl) { }
+ url: SafeResourceUrl | null;
+ svgElement: SVGElement | null;
+
+ constructor(url: SafeResourceUrl);
+ constructor(svgElement: SVGElement);
+ constructor(data: SafeResourceUrl | SVGElement) {
+ // Note that we can't use `instanceof SVGElement` here,
+ // because it'll break during server-side rendering.
+ if (!!(data as any).nodeName) {
+ this.svgElement = data as SVGElement;
+ } else {
+ this.url = data as SafeResourceUrl;
+ }
+ }
}
/**
@@ -116,6 +139,15 @@ export class MatIconRegistry {
return this.addSvgIconInNamespace('', iconName, url);
}
+ /**
+ * Registers an icon using an HTML string in the default namespace.
+ * @param iconName Name under which the icon should be registered.
+ * @param literal SVG source of the icon.
+ */
+ addSvgIconLiteral(iconName: string, literal: SafeHtml): this {
+ return this.addSvgIconLiteralInNamespace('', iconName, literal);
+ }
+
/**
* Registers an icon by URL in the specified namespace.
* @param namespace Namespace in which the icon should be registered.
@@ -123,9 +155,24 @@ export class MatIconRegistry {
* @param url
*/
addSvgIconInNamespace(namespace: string, iconName: string, url: SafeResourceUrl): this {
- const key = iconKey(namespace, iconName);
- this._svgIconConfigs.set(key, new SvgIconConfig(url));
- return this;
+ return this._addSvgIconConfig(namespace, iconName, new SvgIconConfig(url));
+ }
+
+ /**
+ * Registers an icon using an HTML string in the specified namespace.
+ * @param namespace Namespace in which the icon should be registered.
+ * @param iconName Name under which the icon should be registered.
+ * @param literal SVG source of the icon.
+ */
+ addSvgIconLiteralInNamespace(namespace: string, iconName: string, literal: SafeHtml): this {
+ const sanitizedLiteral = this._sanitizer.sanitize(SecurityContext.HTML, literal);
+
+ if (!sanitizedLiteral) {
+ throw getMatIconFailedToSanitizeLiteralError(literal);
+ }
+
+ const svgElement = this._createSvgElementForSingleIcon(sanitizedLiteral);
+ return this._addSvgIconConfig(namespace, iconName, new SvgIconConfig(svgElement));
}
/**
@@ -136,21 +183,37 @@ export class MatIconRegistry {
return this.addSvgIconSetInNamespace('', url);
}
+ /**
+ * Registers an icon set using an HTML string in the default namespace.
+ * @param literal SVG source of the icon set.
+ */
+ addSvgIconSetLiteral(literal: SafeHtml): this {
+ return this.addSvgIconSetLiteralInNamespace('', literal);
+ }
+
/**
* Registers an icon set by URL in the specified namespace.
* @param namespace Namespace in which to register the icon set.
* @param url
*/
addSvgIconSetInNamespace(namespace: string, url: SafeResourceUrl): this {
- const config = new SvgIconConfig(url);
- const configNamespace = this._iconSetConfigs.get(namespace);
+ return this._addSvgIconSetConfig(namespace, new SvgIconConfig(url));
+ }
- if (configNamespace) {
- configNamespace.push(config);
- } else {
- this._iconSetConfigs.set(namespace, [config]);
+ /**
+ * Registers an icon set using an HTML string in the specified namespace.
+ * @param namespace Namespace in which to register the icon set.
+ * @param literal SVG source of the icon set.
+ */
+ addSvgIconSetLiteralInNamespace(namespace: string, literal: SafeHtml): this {
+ const sanitizedLiteral = this._sanitizer.sanitize(SecurityContext.HTML, literal);
+
+ if (!sanitizedLiteral) {
+ throw getMatIconFailedToSanitizeLiteralError(literal);
}
- return this;
+
+ const svgElement = this._svgElementFromString(sanitizedLiteral);
+ return this._addSvgIconSetConfig(namespace, new SvgIconConfig(svgElement));
}
/**
@@ -202,13 +265,13 @@ export class MatIconRegistry {
* @param safeUrl URL from which to fetch the SVG icon.
*/
getSvgIconFromUrl(safeUrl: SafeResourceUrl): Observable {
- let url = this._sanitizer.sanitize(SecurityContext.RESOURCE_URL, safeUrl);
+ const url = this._sanitizer.sanitize(SecurityContext.RESOURCE_URL, safeUrl);
if (!url) {
- throw getMatIconFailedToSanitizeError(safeUrl);
+ throw getMatIconFailedToSanitizeUrlError(safeUrl);
}
- let cachedIcon = this._cachedIconsByUrl.get(url);
+ const cachedIcon = this._cachedIconsByUrl.get(url);
if (cachedIcon) {
return observableOf(cloneSvg(cachedIcon));
@@ -461,15 +524,19 @@ export class MatIconRegistry {
* Returns an Observable which produces the string contents of the given URL. Results may be
* cached, so future calls with the same URL may not cause another HTTP request.
*/
- private _fetchUrl(safeUrl: SafeResourceUrl): Observable {
+ private _fetchUrl(safeUrl: SafeResourceUrl | null): Observable {
if (!this._httpClient) {
throw getMatIconNoHttpProviderError();
}
+ if (safeUrl == null) {
+ throw Error(`Cannot fetch icon from URL "${safeUrl}".`);
+ }
+
const url = this._sanitizer.sanitize(SecurityContext.RESOURCE_URL, safeUrl);
if (!url) {
- throw getMatIconFailedToSanitizeError(safeUrl);
+ throw getMatIconFailedToSanitizeUrlError(safeUrl);
}
// Store in-progress fetches to avoid sending a duplicate request for a URL when there is
@@ -491,6 +558,34 @@ export class MatIconRegistry {
this._inProgressUrlFetches.set(url, req);
return req;
}
+
+ /**
+ * Registers an icon config by name in the specified namespace.
+ * @param namespace Namespace in which to register the icon config.
+ * @param iconName Name under which to register the config.
+ * @param config Config to be registered.
+ */
+ private _addSvgIconConfig(namespace: string, iconName: string, config: SvgIconConfig): this {
+ this._svgIconConfigs.set(iconKey(namespace, iconName), config);
+ return this;
+ }
+
+ /**
+ * Registers an icon set config in the specified namespace.
+ * @param namespace Namespace in which to register the icon config.
+ * @param config Config to be registered.
+ */
+ private _addSvgIconSetConfig(namespace: string, config: SvgIconConfig): this {
+ const configNamespace = this._iconSetConfigs.get(namespace);
+
+ if (configNamespace) {
+ configNamespace.push(config);
+ } else {
+ this._iconSetConfigs.set(namespace, [config]);
+ }
+
+ return this;
+ }
}
/** @docs-private */
diff --git a/src/lib/icon/icon.md b/src/lib/icon/icon.md
index 21ad287c243f..3936cdeaa6aa 100644
--- a/src/lib/icon/icon.md
+++ b/src/lib/icon/icon.md
@@ -5,8 +5,9 @@ icon fonts and SVG icons, but not bitmap-based formats (png, jpg, etc.).
### Registering icons
-`MatIconRegistry` is an injectable service that allows you to associate icon names with SVG URLs and
-define aliases for CSS font classes. Its methods are discussed below and listed in the API summary.
+`MatIconRegistry` is an injectable service that allows you to associate icon names with SVG URLs,
+HTML strings and to define aliases for CSS font classes. Its methods are discussed below and listed
+in the API summary.
### Font icons with ligatures
@@ -44,19 +45,20 @@ SVG content is the CSS
value. This makes SVG icons by default have the same color as surrounding text, and allows you to
change the color by setting the "color" style on the `mat-icon` element.
-In order to prevent XSS vulnerabilities, any SVG URLs passed to the `MatIconRegistry` must be
-marked as trusted resource URLs by using Angular's `DomSanitizer` service.
+In order to prevent XSS vulnerabilities, any SVG URLs and HTML strings passed to the
+`MatIconRegistry` must be marked as trusted by using Angular's `DomSanitizer` service.
-Also note that all SVG icons are fetched via XmlHttpRequest, and due to the same-origin policy,
-their URLs must be on the same domain as the containing page, or their servers must be configured
-to allow cross-domain access.
+Also note that all SVG icons, registered by URL, are fetched via XmlHttpRequest, and due to the
+same-origin policy, their URLs must be on the same domain as the containing page, or their servers
+must be configured to allow cross-domain access.
#### Named icons
-To associate a name with an icon URL, use the `addSvgIcon` or `addSvgIconInNamespace` methods of
-`MatIconRegistry`. After registering an icon, it can be displayed by setting the `svgIcon` input.
-For an icon in the default namespace, use the name directly. For a non-default namespace, use the
-format `[namespace]:[name]`.
+To associate a name with an icon URL, use the `addSvgIcon`, `addSvgIconInNamespace`,
+`addSvgIconLiteral` or `addSvgIconLiteralInNamespace` methods of `MatIconRegistry`. After
+registering an icon, it can be displayed by setting the `svgIcon` input. For an icon in the
+default namespace, use the name directly. For a non-default namespace, use the format
+`[namespace]:[name]`.
#### Icon sets
@@ -64,9 +66,10 @@ Icon sets allow grouping multiple icons into a single SVG file. This is done by
root `` tag that contains multiple nested `` tags in its `` section. Each of these
nested tags is identified with an `id` attribute. This `id` is used as the name of the icon.
-Icon sets are registered using the `addSvgIconSet` or `addSvgIconSetInNamespace` methods of
-`MatIconRegistry`. After an icon set is registered, each of its embedded icons can be accessed by
-their `id` attributes. To display an icon from an icon set, use the `svgIcon` input in the same way
+Icon sets are registered using the `addSvgIconSet`, `addSvgIconSetInNamespace`,
+`addSvgIconSetLiteral` or `addSvgIconSetLiteralInNamespace` methods of `MatIconRegistry`.
+After an icon set is registered, each of its embedded icons can be accessed by their `id`
+attributes. To display an icon from an icon set, use the `svgIcon` input in the same way
as for individually registered icons.
Multiple icon sets can be registered in the same namespace. Requesting an icon whose id appears in
diff --git a/src/lib/icon/icon.spec.ts b/src/lib/icon/icon.spec.ts
index 842524abfa16..5b39d4cc7aa1 100644
--- a/src/lib/icon/icon.spec.ts
+++ b/src/lib/icon/icon.spec.ts
@@ -1,5 +1,5 @@
import {inject, async, fakeAsync, tick, TestBed} from '@angular/core/testing';
-import {SafeResourceUrl, DomSanitizer} from '@angular/platform-browser';
+import {SafeResourceUrl, DomSanitizer, SafeHtml} from '@angular/platform-browser';
import {HttpClientTestingModule, HttpTestingController} from '@angular/common/http/testing';
import {Component} from '@angular/core';
import {MatIconModule} from './index';
@@ -131,8 +131,8 @@ describe('MatIcon', () => {
describe('Icons from URLs', () => {
it('should register icon URLs by name', fakeAsync(() => {
- iconRegistry.addSvgIcon('fluffy', trust('cat.svg'));
- iconRegistry.addSvgIcon('fido', trust('dog.svg'));
+ iconRegistry.addSvgIcon('fluffy', trustUrl('cat.svg'));
+ iconRegistry.addSvgIcon('fido', trustUrl('dog.svg'));
let fixture = TestBed.createComponent(IconFromSvgName);
let svgElement: SVGElement;
@@ -160,7 +160,7 @@ describe('MatIcon', () => {
verifyPathChildElement(svgElement, 'woof');
// Assert that a registered icon can be looked-up by url.
- iconRegistry.getSvgIconFromUrl(trust('cat.svg')).subscribe(element => {
+ iconRegistry.getSvgIconFromUrl(trustUrl('cat.svg')).subscribe(element => {
verifyPathChildElement(element, 'meow');
});
@@ -188,7 +188,7 @@ describe('MatIcon', () => {
});
it('should extract icon from SVG icon set', () => {
- iconRegistry.addSvgIconSetInNamespace('farm', trust('farm-set-1.svg'));
+ iconRegistry.addSvgIconSetInNamespace('farm', trustUrl('farm-set-1.svg'));
const fixture = TestBed.createComponent(IconFromSvgName);
const testComponent = fixture.componentInstance;
@@ -226,7 +226,7 @@ describe('MatIcon', () => {
// is important enough to warrant the brittle-ness that results.
spyOn(iconRegistry, '_svgElementFromString' as any).and.callThrough();
- iconRegistry.addSvgIconSetInNamespace('farm', trust('farm-set-1.svg'));
+ iconRegistry.addSvgIconSetInNamespace('farm', trustUrl('farm-set-1.svg'));
// Requests for icons must be subscribed to in order for requests to be made.
iconRegistry.getNamedSvgIcon('pig', 'farm').subscribe(() => {});
@@ -240,8 +240,8 @@ describe('MatIcon', () => {
});
it('should allow multiple icon sets in a namespace', () => {
- iconRegistry.addSvgIconSetInNamespace('farm', trust('farm-set-1.svg'));
- iconRegistry.addSvgIconSetInNamespace('farm', trust('farm-set-2.svg'));
+ iconRegistry.addSvgIconSetInNamespace('farm', trustUrl('farm-set-1.svg'));
+ iconRegistry.addSvgIconSetInNamespace('farm', trustUrl('farm-set-2.svg'));
const fixture = TestBed.createComponent(IconFromSvgName);
const testComponent = fixture.componentInstance;
@@ -279,7 +279,7 @@ describe('MatIcon', () => {
});
it('should unwrap nodes', () => {
- iconRegistry.addSvgIconSetInNamespace('farm', trust('farm-set-3.svg'));
+ iconRegistry.addSvgIconSetInNamespace('farm', trustUrl('farm-set-3.svg'));
const fixture = TestBed.createComponent(IconFromSvgName);
const testComponent = fixture.componentInstance;
@@ -299,7 +299,7 @@ describe('MatIcon', () => {
});
it('should not wrap elements in icon sets in another svg tag', () => {
- iconRegistry.addSvgIconSet(trust('arrow-set.svg'));
+ iconRegistry.addSvgIconSet(trustUrl('arrow-set.svg'));
const fixture = TestBed.createComponent(IconFromSvgName);
const testComponent = fixture.componentInstance;
@@ -317,7 +317,7 @@ describe('MatIcon', () => {
});
it('should return unmodified copies of icons from icon sets', () => {
- iconRegistry.addSvgIconSet(trust('arrow-set.svg'));
+ iconRegistry.addSvgIconSet(trustUrl('arrow-set.svg'));
const fixture = TestBed.createComponent(IconFromSvgName);
const testComponent = fixture.componentInstance;
@@ -347,7 +347,7 @@ describe('MatIcon', () => {
});
it('should not throw when toggling an icon that has a binding in IE11', () => {
- iconRegistry.addSvgIcon('fluffy', trust('cat.svg'));
+ iconRegistry.addSvgIcon('fluffy', trustUrl('cat.svg'));
const fixture = TestBed.createComponent(IconWithBindingAndNgIf);
@@ -364,7 +364,7 @@ describe('MatIcon', () => {
});
it('should remove the SVG element from the DOM when the binding is cleared', () => {
- iconRegistry.addSvgIconSet(trust('arrow-set.svg'));
+ iconRegistry.addSvgIconSet(trustUrl('arrow-set.svg'));
let fixture = TestBed.createComponent(IconFromSvgName);
@@ -382,7 +382,148 @@ describe('MatIcon', () => {
expect(icon.querySelector('svg')).toBeFalsy();
});
+ });
+
+ describe('Icons from HTML string', () => {
+ it('should register icon HTML strings by name', fakeAsync(() => {
+ iconRegistry.addSvgIconLiteral('fluffy', trustHtml(FAKE_SVGS.cat));
+ iconRegistry.addSvgIconLiteral('fido', trustHtml(FAKE_SVGS.dog));
+
+ let fixture = TestBed.createComponent(IconFromSvgName);
+ let svgElement: SVGElement;
+ const testComponent = fixture.componentInstance;
+ const iconElement = fixture.debugElement.nativeElement.querySelector('mat-icon');
+
+ testComponent.iconName = 'fido';
+ fixture.detectChanges();
+ svgElement = verifyAndGetSingleSvgChild(iconElement);
+ verifyPathChildElement(svgElement, 'woof');
+
+ testComponent.iconName = 'fluffy';
+ fixture.detectChanges();
+ svgElement = verifyAndGetSingleSvgChild(iconElement);
+ verifyPathChildElement(svgElement, 'meow');
+
+ // Assert that a registered icon can be looked-up by name.
+ iconRegistry.getNamedSvgIcon('fluffy').subscribe(element => {
+ verifyPathChildElement(element, 'meow');
+ });
+
+ tick();
+ }));
+
+ it('should throw an error when using untrusted HTML', () => {
+ // Stub out console.warn so we don't pollute our logs with Angular's warnings.
+ // Jasmine will tear the spy down at the end of the test.
+ spyOn(console, 'warn');
+
+ expect(() => {
+ iconRegistry.addSvgIconLiteral('circle', '');
+ }).toThrowError(/was not trusted as safe HTML/);
+ });
+
+ it('should extract an icon from SVG icon set', () => {
+ iconRegistry.addSvgIconSetLiteralInNamespace('farm', trustHtml(FAKE_SVGS.farmSet1));
+
+ const fixture = TestBed.createComponent(IconFromSvgName);
+ const testComponent = fixture.componentInstance;
+ const matIconElement = fixture.debugElement.nativeElement.querySelector('mat-icon');
+ let svgElement: any;
+ let svgChild: any;
+
+ testComponent.iconName = 'farm:pig';
+ fixture.detectChanges();
+
+ expect(matIconElement.childNodes.length).toBe(1);
+ svgElement = verifyAndGetSingleSvgChild(matIconElement);
+ expect(svgElement.childNodes.length).toBe(1);
+ svgChild = svgElement.childNodes[0];
+
+ // The first child should be the element.
+ expect(svgChild.tagName.toLowerCase()).toBe('g');
+ expect(svgChild.getAttribute('name')).toBe('pig');
+ verifyPathChildElement(svgChild, 'oink');
+
+ // Change the icon, and the SVG element should be replaced.
+ testComponent.iconName = 'farm:cow';
+ fixture.detectChanges();
+ svgElement = verifyAndGetSingleSvgChild(matIconElement);
+ svgChild = svgElement.childNodes[0];
+
+ // The first child should be the element.
+ expect(svgChild.tagName.toLowerCase()).toBe('g');
+ expect(svgChild.getAttribute('name')).toBe('cow');
+ verifyPathChildElement(svgChild, 'moo');
+ });
+
+ it('should allow multiple icon sets in a namespace', () => {
+ iconRegistry.addSvgIconSetLiteralInNamespace('farm', trustHtml(FAKE_SVGS.farmSet1));
+ iconRegistry.addSvgIconSetLiteralInNamespace('farm', trustHtml(FAKE_SVGS.farmSet2));
+
+ const fixture = TestBed.createComponent(IconFromSvgName);
+ const testComponent = fixture.componentInstance;
+ const matIconElement = fixture.debugElement.nativeElement.querySelector('mat-icon');
+ let svgElement: any;
+ let svgChild: any;
+
+ testComponent.iconName = 'farm:pig';
+ fixture.detectChanges();
+
+ svgElement = verifyAndGetSingleSvgChild(matIconElement);
+ expect(svgElement.childNodes.length).toBe(1);
+ svgChild = svgElement.childNodes[0];
+
+ // The child should be the element.
+ expect(svgChild.tagName.toLowerCase()).toBe('g');
+ expect(svgChild.getAttribute('name')).toBe('pig');
+ expect(svgChild.getAttribute('id')).toBe('');
+ expect(svgChild.childNodes.length).toBe(1);
+ verifyPathChildElement(svgChild, 'oink');
+
+ // Change the icon name to one that appears in both icon sets. The icon from the set that
+ // was registered last should be used (with id attribute of 'moo moo' instead of 'moo'),
+ // and no additional HTTP request should be made.
+ testComponent.iconName = 'farm:cow';
+ fixture.detectChanges();
+ svgElement = verifyAndGetSingleSvgChild(matIconElement);
+ svgChild = svgElement.childNodes[0];
+ // The first child should be the element.
+ expect(svgChild.tagName.toLowerCase()).toBe('g');
+ expect(svgChild.getAttribute('name')).toBe('cow');
+ expect(svgChild.childNodes.length).toBe(1);
+ verifyPathChildElement(svgChild, 'moo moo');
+ });
+
+ it('should return unmodified copies of icons from icon sets', () => {
+ iconRegistry.addSvgIconSetLiteral(trustHtml(FAKE_SVGS.arrows));
+
+ const fixture = TestBed.createComponent(IconFromSvgName);
+ const testComponent = fixture.componentInstance;
+ const matIconElement = fixture.debugElement.nativeElement.querySelector('mat-icon');
+ let svgElement: any;
+
+ testComponent.iconName = 'left-arrow';
+ fixture.detectChanges();
+ svgElement = verifyAndGetSingleSvgChild(matIconElement);
+ verifyPathChildElement(svgElement, 'left');
+
+ // Modify the SVG element by setting a viewBox attribute.
+ svgElement.setAttribute('viewBox', '0 0 100 100');
+
+ // Switch to a different icon.
+ testComponent.iconName = 'right-arrow';
+ fixture.detectChanges();
+ svgElement = verifyAndGetSingleSvgChild(matIconElement);
+ verifyPathChildElement(svgElement, 'right');
+
+ // Switch back to the first icon. The viewBox attribute should not be present.
+ testComponent.iconName = 'left-arrow';
+ fixture.detectChanges();
+ svgElement = verifyAndGetSingleSvgChild(matIconElement);
+ verifyPathChildElement(svgElement, 'left');
+ expect(svgElement.getAttribute('viewBox')).toBeFalsy();
+ });
});
describe('custom fonts', () => {
@@ -450,10 +591,15 @@ describe('MatIcon', () => {
});
- /** Marks an svg icon url as explicitly trusted. */
- function trust(iconUrl: string): SafeResourceUrl {
+ /** Marks an SVG icon url as explicitly trusted. */
+ function trustUrl(iconUrl: string): SafeResourceUrl {
return sanitizer.bypassSecurityTrustResourceUrl(iconUrl);
}
+
+ /** Marks an SVG icon string as explicitly trusted. */
+ function trustHtml(iconHtml: string): SafeHtml {
+ return sanitizer.bypassSecurityTrustHtml(iconHtml);
+ }
});
diff --git a/src/lib/table/table.spec.ts b/src/lib/table/table.spec.ts
index 98bd3ff0a32b..67ba1fc4f431 100644
--- a/src/lib/table/table.spec.ts
+++ b/src/lib/table/table.spec.ts
@@ -277,7 +277,7 @@ describe('MatTable', () => {
component.sort.sort(component.sortHeader);
fixture.detectChanges();
expectTableToMatchContent(tableElement, [
- ['Column A\xa0Sorted by a ascending', 'Column B', 'Column C'],
+ ['Column A', 'Column B', 'Column C'],
['-1', 'b_3', 'c_3'],
['0', 'b_2', 'c_2'],
['1', 'b_1', 'c_1'],
@@ -289,7 +289,7 @@ describe('MatTable', () => {
component.sort.sort(component.sortHeader);
fixture.detectChanges();
expectTableToMatchContent(tableElement, [
- ['Column A\xa0Sorted by a descending', 'Column B', 'Column C'],
+ ['Column A', 'Column B', 'Column C'],
['1', 'b_1', 'c_1'],
['0', 'b_2', 'c_2'],
['-1', 'b_3', 'c_3'],