@@ -16,7 +16,7 @@ import {
16
16
SecurityContext ,
17
17
SkipSelf ,
18
18
} from '@angular/core' ;
19
- import { DomSanitizer , SafeResourceUrl } from '@angular/platform-browser' ;
19
+ import { DomSanitizer , SafeResourceUrl , SafeHtml } from '@angular/platform-browser' ;
20
20
import { forkJoin , Observable , of as observableOf , throwError as observableThrow } from 'rxjs' ;
21
21
import { catchError , finalize , map , share , tap } from 'rxjs/operators' ;
22
22
@@ -48,18 +48,39 @@ export function getMatIconNoHttpProviderError(): Error {
48
48
* @param url URL that was attempted to be sanitized.
49
49
* @docs -private
50
50
*/
51
- export function getMatIconFailedToSanitizeError ( url : SafeResourceUrl ) : Error {
51
+ export function getMatIconFailedToSanitizeUrlError ( url : SafeResourceUrl ) : Error {
52
52
return Error ( `The URL provided to MatIconRegistry was not trusted as a resource URL ` +
53
53
`via Angular's DomSanitizer. Attempted URL was "${ url } ".` ) ;
54
54
}
55
55
56
+ /**
57
+ * Returns an exception to be thrown when a HTML string couldn't be sanitized.
58
+ * @param template HTML that was attempted to be sanitized.
59
+ * @docs -private
60
+ */
61
+ export function getMatIconFailedToSanitizeTemplateError ( template : SafeHtml ) : Error {
62
+ return Error ( `The template provided to MatIconRegistry was not trusted as safe HTML by ` +
63
+ `Angular's DomSanitizer. Attempted template was "${ template } ".` ) ;
64
+ }
65
+
66
+
56
67
/**
57
68
* Configuration for an icon, including the URL and possibly the cached SVG element.
58
69
* @docs -private
59
70
*/
60
71
class SvgIconConfig {
61
- svgElement : SVGElement | null = null ;
62
- constructor ( public url : SafeResourceUrl ) { }
72
+ url : SafeResourceUrl | null ;
73
+ svgElement : SVGElement | null ;
74
+
75
+ constructor ( url : SafeResourceUrl ) ;
76
+ constructor ( svgElement : SVGElement ) ;
77
+ constructor ( data : SafeResourceUrl | SVGElement ) {
78
+ if ( data instanceof SVGElement ) {
79
+ this . svgElement = data ;
80
+ } else {
81
+ this . url = data ;
82
+ }
83
+ }
63
84
}
64
85
65
86
/**
@@ -116,16 +137,40 @@ export class MatIconRegistry {
116
137
return this . addSvgIconInNamespace ( '' , iconName , url ) ;
117
138
}
118
139
140
+ /**
141
+ * Registers an icon using an HTML string in the default namespace.
142
+ * @param iconName Name under which the icon should be registered.
143
+ * @param template SVG source of the icon.
144
+ */
145
+ addSvgIconTemplate ( iconName : string , template : SafeHtml ) : this {
146
+ return this . addSvgIconTemplateInNamespace ( '' , iconName , template ) ;
147
+ }
148
+
119
149
/**
120
150
* Registers an icon by URL in the specified namespace.
121
151
* @param namespace Namespace in which the icon should be registered.
122
152
* @param iconName Name under which the icon should be registered.
123
153
* @param url
124
154
*/
125
155
addSvgIconInNamespace ( namespace : string , iconName : string , url : SafeResourceUrl ) : this {
126
- const key = iconKey ( namespace , iconName ) ;
127
- this . _svgIconConfigs . set ( key , new SvgIconConfig ( url ) ) ;
128
- return this ;
156
+ return this . _addSvgIconConfig ( namespace , iconName , new SvgIconConfig ( url ) ) ;
157
+ }
158
+
159
+ /**
160
+ * Registers an icon using an HTML string in the specified namespace.
161
+ * @param namespace Namespace in which the icon should be registered.
162
+ * @param iconName Name under which the icon should be registered.
163
+ * @param template SVG source of the icon.
164
+ */
165
+ addSvgIconTemplateInNamespace ( namespace : string , iconName : string , template : SafeHtml ) : this {
166
+ const sanitizedTemplate = this . _sanitizer . sanitize ( SecurityContext . HTML , template ) ;
167
+
168
+ if ( ! sanitizedTemplate ) {
169
+ throw getMatIconFailedToSanitizeTemplateError ( template ) ;
170
+ }
171
+
172
+ const svgElement = this . _createSvgElementForSingleIcon ( sanitizedTemplate ) ;
173
+ return this . _addSvgIconConfig ( namespace , iconName , new SvgIconConfig ( svgElement ) ) ;
129
174
}
130
175
131
176
/**
@@ -136,21 +181,37 @@ export class MatIconRegistry {
136
181
return this . addSvgIconSetInNamespace ( '' , url ) ;
137
182
}
138
183
184
+ /**
185
+ * Registers an icon set using an HTML string in the default namespace.
186
+ * @param template SVG source of the icon set.
187
+ */
188
+ addSvgIconSetTemplate ( template : SafeHtml ) : this {
189
+ return this . addSvgIconSetTemplateInNamespace ( '' , template ) ;
190
+ }
191
+
139
192
/**
140
193
* Registers an icon set by URL in the specified namespace.
141
194
* @param namespace Namespace in which to register the icon set.
142
195
* @param url
143
196
*/
144
197
addSvgIconSetInNamespace ( namespace : string , url : SafeResourceUrl ) : this {
145
- const config = new SvgIconConfig ( url ) ;
146
- const configNamespace = this . _iconSetConfigs . get ( namespace ) ;
198
+ return this . _addSvgIconSetConfig ( namespace , new SvgIconConfig ( url ) ) ;
199
+ }
147
200
148
- if ( configNamespace ) {
149
- configNamespace . push ( config ) ;
150
- } else {
151
- this . _iconSetConfigs . set ( namespace , [ config ] ) ;
201
+ /**
202
+ * Registers an icon set using an HTML string in the specified namespace.
203
+ * @param namespace Namespace in which to register the icon set.
204
+ * @param template SVG source of the icon set.
205
+ */
206
+ addSvgIconSetTemplateInNamespace ( namespace : string , template : SafeHtml ) : this {
207
+ const sanitizedTemplate = this . _sanitizer . sanitize ( SecurityContext . HTML , template ) ;
208
+
209
+ if ( ! sanitizedTemplate ) {
210
+ throw getMatIconFailedToSanitizeTemplateError ( template ) ;
152
211
}
153
- return this ;
212
+
213
+ const svgElement = this . _svgElementFromString ( sanitizedTemplate ) ;
214
+ return this . _addSvgIconSetConfig ( namespace , new SvgIconConfig ( svgElement ) ) ;
154
215
}
155
216
156
217
/**
@@ -202,13 +263,13 @@ export class MatIconRegistry {
202
263
* @param safeUrl URL from which to fetch the SVG icon.
203
264
*/
204
265
getSvgIconFromUrl ( safeUrl : SafeResourceUrl ) : Observable < SVGElement > {
205
- let url = this . _sanitizer . sanitize ( SecurityContext . RESOURCE_URL , safeUrl ) ;
266
+ const url = this . _sanitizer . sanitize ( SecurityContext . RESOURCE_URL , safeUrl ) ;
206
267
207
268
if ( ! url ) {
208
- throw getMatIconFailedToSanitizeError ( safeUrl ) ;
269
+ throw getMatIconFailedToSanitizeUrlError ( safeUrl ) ;
209
270
}
210
271
211
- let cachedIcon = this . _cachedIconsByUrl . get ( url ) ;
272
+ const cachedIcon = this . _cachedIconsByUrl . get ( url ) ;
212
273
213
274
if ( cachedIcon ) {
214
275
return observableOf ( cloneSvg ( cachedIcon ) ) ;
@@ -461,15 +522,19 @@ export class MatIconRegistry {
461
522
* Returns an Observable which produces the string contents of the given URL. Results may be
462
523
* cached, so future calls with the same URL may not cause another HTTP request.
463
524
*/
464
- private _fetchUrl ( safeUrl : SafeResourceUrl ) : Observable < string > {
525
+ private _fetchUrl ( safeUrl : SafeResourceUrl | null ) : Observable < string > {
465
526
if ( ! this . _httpClient ) {
466
527
throw getMatIconNoHttpProviderError ( ) ;
467
528
}
468
529
530
+ if ( safeUrl == null ) {
531
+ throw Error ( `Cannot fetch icon from URL "${ safeUrl } ".` ) ;
532
+ }
533
+
469
534
const url = this . _sanitizer . sanitize ( SecurityContext . RESOURCE_URL , safeUrl ) ;
470
535
471
536
if ( ! url ) {
472
- throw getMatIconFailedToSanitizeError ( safeUrl ) ;
537
+ throw getMatIconFailedToSanitizeUrlError ( safeUrl ) ;
473
538
}
474
539
475
540
// Store in-progress fetches to avoid sending a duplicate request for a URL when there is
@@ -491,6 +556,34 @@ export class MatIconRegistry {
491
556
this . _inProgressUrlFetches . set ( url , req ) ;
492
557
return req ;
493
558
}
559
+
560
+ /**
561
+ * Registers an icon config by name in the specified namespace.
562
+ * @param namespace Namespace in which to register the icon config.
563
+ * @param iconName Name under which to register the config.
564
+ * @param config Config to be registered.
565
+ */
566
+ private _addSvgIconConfig ( namespace : string , iconName : string , config : SvgIconConfig ) : this {
567
+ this . _svgIconConfigs . set ( iconKey ( namespace , iconName ) , config ) ;
568
+ return this ;
569
+ }
570
+
571
+ /**
572
+ * Registers an icon set config in the specified namespace.
573
+ * @param namespace Namespace in which to register the icon config.
574
+ * @param config Config to be registered.
575
+ */
576
+ private _addSvgIconSetConfig ( namespace : string , config : SvgIconConfig ) : this {
577
+ const configNamespace = this . _iconSetConfigs . get ( namespace ) ;
578
+
579
+ if ( configNamespace ) {
580
+ configNamespace . push ( config ) ;
581
+ } else {
582
+ this . _iconSetConfigs . set ( namespace , [ config ] ) ;
583
+ }
584
+
585
+ return this ;
586
+ }
494
587
}
495
588
496
589
/** @docs -private */
0 commit comments