@@ -17,7 +17,9 @@ import {
17
17
OnInit ,
18
18
SimpleChanges ,
19
19
ViewEncapsulation ,
20
+ Optional ,
20
21
} from '@angular/core' ;
22
+ import { Location } from '@angular/common' ;
21
23
import { CanColor , mixinColor } from '@angular/material/core' ;
22
24
import { coerceBooleanProperty } from '@angular/cdk/coercion' ;
23
25
import { MatIconRegistry } from './icon-registry' ;
@@ -30,6 +32,27 @@ export class MatIconBase {
30
32
}
31
33
export const _MatIconMixinBase = mixinColor ( MatIconBase ) ;
32
34
35
+ /** SVG attributes that accept a FuncIRI (e.g. `url(<something>)`). */
36
+ const funcIriAttributes = [
37
+ 'clip-path' ,
38
+ 'color-profile' ,
39
+ 'src' ,
40
+ 'cursor' ,
41
+ 'fill' ,
42
+ 'filter' ,
43
+ 'marker' ,
44
+ 'marker-start' ,
45
+ 'marker-mid' ,
46
+ 'marker-end' ,
47
+ 'mask' ,
48
+ 'stroke'
49
+ ] ;
50
+
51
+ /** Selector that can be used to find all elements that are using a `FuncIRI`. */
52
+ const funcIriAttributeSelector = funcIriAttributes . map ( attr => `[${ attr } ]` ) . join ( ', ' ) ;
53
+
54
+ /** Regex that can be used to extract the id out of a FuncIRI. */
55
+ const funcIriPattern = / ^ u r l \( [ ' " ] ? # ( .* ?) [ ' " ] ? \) $ / ;
33
56
34
57
/**
35
58
* Component to display an icon. It can be used in the following ways:
@@ -112,7 +135,12 @@ export class MatIcon extends _MatIconMixinBase implements OnChanges, OnInit, Can
112
135
constructor (
113
136
elementRef : ElementRef ,
114
137
private _iconRegistry : MatIconRegistry ,
115
- @Attribute ( 'aria-hidden' ) ariaHidden : string ) {
138
+ @Attribute ( 'aria-hidden' ) ariaHidden : string ,
139
+ /**
140
+ * @deprecated `location` parameter to be made required.
141
+ * @breaking -change 8.0.0
142
+ */
143
+ @Optional ( ) private _location ?: Location ) {
116
144
super ( elementRef ) ;
117
145
118
146
// If the user has not explicitly set aria-hidden, mark the icon as hidden, as this is
@@ -191,6 +219,9 @@ export class MatIcon extends _MatIconMixinBase implements OnChanges, OnInit, Can
191
219
styleTags [ i ] . textContent += ' ' ;
192
220
}
193
221
222
+ // Note: we do this fix here, rather than the icon registry, because the
223
+ // references have to point to the URL at the time that the icon was created.
224
+ this . _prependCurrentPathToReferences ( svg ) ;
194
225
this . _elementRef . nativeElement . appendChild ( svg ) ;
195
226
}
196
227
@@ -250,4 +281,32 @@ export class MatIcon extends _MatIconMixinBase implements OnChanges, OnInit, Can
250
281
private _cleanupFontValue ( value : string ) {
251
282
return typeof value === 'string' ? value . trim ( ) . split ( ' ' ) [ 0 ] : value ;
252
283
}
284
+
285
+ /**
286
+ * Prepends the current path to all elements that have an attribute pointing to a `FuncIRI`
287
+ * reference. This is required because WebKit browsers require references to be prefixed with
288
+ * the current path, if the page has a `base` tag.
289
+ */
290
+ private _prependCurrentPathToReferences ( element : SVGElement ) {
291
+ // @breaking -change 8.0.0 Remove this null check once `_location` parameter is required.
292
+ if ( ! this . _location ) {
293
+ return ;
294
+ }
295
+
296
+ const elementsWithFuncIri = element . querySelectorAll ( funcIriAttributeSelector ) ;
297
+ const path = this . _location . path ( ) ;
298
+
299
+ for ( let i = 0 ; i < elementsWithFuncIri . length ; i ++ ) {
300
+ funcIriAttributes . forEach ( attr => {
301
+ const value = elementsWithFuncIri [ i ] . getAttribute ( attr ) ;
302
+ const match = value ? value . match ( funcIriPattern ) : null ;
303
+
304
+ if ( match ) {
305
+ // Note the quotes inside the `url()`. They're important, because URLs pointing to named
306
+ // router outlets can contain parentheses which will break if they aren't quoted.
307
+ elementsWithFuncIri [ i ] . setAttribute ( attr , `url('${ path } #${ match [ 1 ] } ')` ) ;
308
+ }
309
+ } ) ;
310
+ }
311
+ }
253
312
}
0 commit comments