1 | import * as i0 from '@angular/core';
|
---|
2 | import { SecurityContext, Injectable, Optional, Inject, ErrorHandler, SkipSelf, InjectionToken, inject, Component, ViewEncapsulation, ChangeDetectionStrategy, ElementRef, Attribute, Input, NgModule } from '@angular/core';
|
---|
3 | import { mixinColor, MatCommonModule } from '@angular/material/core';
|
---|
4 | import { coerceBooleanProperty } from '@angular/cdk/coercion';
|
---|
5 | import * as i3 from '@angular/common';
|
---|
6 | import { DOCUMENT } from '@angular/common';
|
---|
7 | import { of, throwError, forkJoin, Subscription } from 'rxjs';
|
---|
8 | import { tap, map, catchError, finalize, share, take } from 'rxjs/operators';
|
---|
9 | import * as i1 from '@angular/common/http';
|
---|
10 | import { HttpClient } from '@angular/common/http';
|
---|
11 | import * as i2 from '@angular/platform-browser';
|
---|
12 | import { DomSanitizer } from '@angular/platform-browser';
|
---|
13 |
|
---|
14 | /**
|
---|
15 | * @license
|
---|
16 | * Copyright Google LLC All Rights Reserved.
|
---|
17 | *
|
---|
18 | * Use of this source code is governed by an MIT-style license that can be
|
---|
19 | * found in the LICENSE file at https://angular.io/license
|
---|
20 | */
|
---|
21 | /**
|
---|
22 | * Returns an exception to be thrown in the case when attempting to
|
---|
23 | * load an icon with a name that cannot be found.
|
---|
24 | * @docs-private
|
---|
25 | */
|
---|
26 | function getMatIconNameNotFoundError(iconName) {
|
---|
27 | return Error(`Unable to find icon with the name "${iconName}"`);
|
---|
28 | }
|
---|
29 | /**
|
---|
30 | * Returns an exception to be thrown when the consumer attempts to use
|
---|
31 | * `<mat-icon>` without including @angular/common/http.
|
---|
32 | * @docs-private
|
---|
33 | */
|
---|
34 | function getMatIconNoHttpProviderError() {
|
---|
35 | return Error('Could not find HttpClient provider for use with Angular Material icons. ' +
|
---|
36 | 'Please include the HttpClientModule from @angular/common/http in your ' +
|
---|
37 | 'app imports.');
|
---|
38 | }
|
---|
39 | /**
|
---|
40 | * Returns an exception to be thrown when a URL couldn't be sanitized.
|
---|
41 | * @param url URL that was attempted to be sanitized.
|
---|
42 | * @docs-private
|
---|
43 | */
|
---|
44 | function getMatIconFailedToSanitizeUrlError(url) {
|
---|
45 | return Error(`The URL provided to MatIconRegistry was not trusted as a resource URL ` +
|
---|
46 | `via Angular's DomSanitizer. Attempted URL was "${url}".`);
|
---|
47 | }
|
---|
48 | /**
|
---|
49 | * Returns an exception to be thrown when a HTML string couldn't be sanitized.
|
---|
50 | * @param literal HTML that was attempted to be sanitized.
|
---|
51 | * @docs-private
|
---|
52 | */
|
---|
53 | function getMatIconFailedToSanitizeLiteralError(literal) {
|
---|
54 | return Error(`The literal provided to MatIconRegistry was not trusted as safe HTML by ` +
|
---|
55 | `Angular's DomSanitizer. Attempted literal was "${literal}".`);
|
---|
56 | }
|
---|
57 | /**
|
---|
58 | * Configuration for an icon, including the URL and possibly the cached SVG element.
|
---|
59 | * @docs-private
|
---|
60 | */
|
---|
61 | class SvgIconConfig {
|
---|
62 | constructor(url, svgText, options) {
|
---|
63 | this.url = url;
|
---|
64 | this.svgText = svgText;
|
---|
65 | this.options = options;
|
---|
66 | }
|
---|
67 | }
|
---|
68 | /**
|
---|
69 | * Service to register and display icons used by the `<mat-icon>` component.
|
---|
70 | * - Registers icon URLs by namespace and name.
|
---|
71 | * - Registers icon set URLs by namespace.
|
---|
72 | * - Registers aliases for CSS classes, for use with icon fonts.
|
---|
73 | * - Loads icons from URLs and extracts individual icons from icon sets.
|
---|
74 | */
|
---|
75 | class MatIconRegistry {
|
---|
76 | constructor(_httpClient, _sanitizer, document, _errorHandler) {
|
---|
77 | this._httpClient = _httpClient;
|
---|
78 | this._sanitizer = _sanitizer;
|
---|
79 | this._errorHandler = _errorHandler;
|
---|
80 | /**
|
---|
81 | * URLs and cached SVG elements for individual icons. Keys are of the format "[namespace]:[icon]".
|
---|
82 | */
|
---|
83 | this._svgIconConfigs = new Map();
|
---|
84 | /**
|
---|
85 | * SvgIconConfig objects and cached SVG elements for icon sets, keyed by namespace.
|
---|
86 | * Multiple icon sets can be registered under the same namespace.
|
---|
87 | */
|
---|
88 | this._iconSetConfigs = new Map();
|
---|
89 | /** Cache for icons loaded by direct URLs. */
|
---|
90 | this._cachedIconsByUrl = new Map();
|
---|
91 | /** In-progress icon fetches. Used to coalesce multiple requests to the same URL. */
|
---|
92 | this._inProgressUrlFetches = new Map();
|
---|
93 | /** Map from font identifiers to their CSS class names. Used for icon fonts. */
|
---|
94 | this._fontCssClassesByAlias = new Map();
|
---|
95 | /** Registered icon resolver functions. */
|
---|
96 | this._resolvers = [];
|
---|
97 | /**
|
---|
98 | * The CSS class to apply when an `<mat-icon>` component has no icon name, url, or font specified.
|
---|
99 | * The default 'material-icons' value assumes that the material icon font has been loaded as
|
---|
100 | * described at http://google.github.io/material-design-icons/#icon-font-for-the-web
|
---|
101 | */
|
---|
102 | this._defaultFontSetClass = 'material-icons';
|
---|
103 | this._document = document;
|
---|
104 | }
|
---|
105 | /**
|
---|
106 | * Registers an icon by URL in the default namespace.
|
---|
107 | * @param iconName Name under which the icon should be registered.
|
---|
108 | * @param url
|
---|
109 | */
|
---|
110 | addSvgIcon(iconName, url, options) {
|
---|
111 | return this.addSvgIconInNamespace('', iconName, url, options);
|
---|
112 | }
|
---|
113 | /**
|
---|
114 | * Registers an icon using an HTML string in the default namespace.
|
---|
115 | * @param iconName Name under which the icon should be registered.
|
---|
116 | * @param literal SVG source of the icon.
|
---|
117 | */
|
---|
118 | addSvgIconLiteral(iconName, literal, options) {
|
---|
119 | return this.addSvgIconLiteralInNamespace('', iconName, literal, options);
|
---|
120 | }
|
---|
121 | /**
|
---|
122 | * Registers an icon by URL in the specified namespace.
|
---|
123 | * @param namespace Namespace in which the icon should be registered.
|
---|
124 | * @param iconName Name under which the icon should be registered.
|
---|
125 | * @param url
|
---|
126 | */
|
---|
127 | addSvgIconInNamespace(namespace, iconName, url, options) {
|
---|
128 | return this._addSvgIconConfig(namespace, iconName, new SvgIconConfig(url, null, options));
|
---|
129 | }
|
---|
130 | /**
|
---|
131 | * Registers an icon resolver function with the registry. The function will be invoked with the
|
---|
132 | * name and namespace of an icon when the registry tries to resolve the URL from which to fetch
|
---|
133 | * the icon. The resolver is expected to return a `SafeResourceUrl` that points to the icon,
|
---|
134 | * an object with the icon URL and icon options, or `null` if the icon is not supported. Resolvers
|
---|
135 | * will be invoked in the order in which they have been registered.
|
---|
136 | * @param resolver Resolver function to be registered.
|
---|
137 | */
|
---|
138 | addSvgIconResolver(resolver) {
|
---|
139 | this._resolvers.push(resolver);
|
---|
140 | return this;
|
---|
141 | }
|
---|
142 | /**
|
---|
143 | * Registers an icon using an HTML string in the specified namespace.
|
---|
144 | * @param namespace Namespace in which the icon should be registered.
|
---|
145 | * @param iconName Name under which the icon should be registered.
|
---|
146 | * @param literal SVG source of the icon.
|
---|
147 | */
|
---|
148 | addSvgIconLiteralInNamespace(namespace, iconName, literal, options) {
|
---|
149 | const cleanLiteral = this._sanitizer.sanitize(SecurityContext.HTML, literal);
|
---|
150 | // TODO: add an ngDevMode check
|
---|
151 | if (!cleanLiteral) {
|
---|
152 | throw getMatIconFailedToSanitizeLiteralError(literal);
|
---|
153 | }
|
---|
154 | return this._addSvgIconConfig(namespace, iconName, new SvgIconConfig('', cleanLiteral, options));
|
---|
155 | }
|
---|
156 | /**
|
---|
157 | * Registers an icon set by URL in the default namespace.
|
---|
158 | * @param url
|
---|
159 | */
|
---|
160 | addSvgIconSet(url, options) {
|
---|
161 | return this.addSvgIconSetInNamespace('', url, options);
|
---|
162 | }
|
---|
163 | /**
|
---|
164 | * Registers an icon set using an HTML string in the default namespace.
|
---|
165 | * @param literal SVG source of the icon set.
|
---|
166 | */
|
---|
167 | addSvgIconSetLiteral(literal, options) {
|
---|
168 | return this.addSvgIconSetLiteralInNamespace('', literal, options);
|
---|
169 | }
|
---|
170 | /**
|
---|
171 | * Registers an icon set by URL in the specified namespace.
|
---|
172 | * @param namespace Namespace in which to register the icon set.
|
---|
173 | * @param url
|
---|
174 | */
|
---|
175 | addSvgIconSetInNamespace(namespace, url, options) {
|
---|
176 | return this._addSvgIconSetConfig(namespace, new SvgIconConfig(url, null, options));
|
---|
177 | }
|
---|
178 | /**
|
---|
179 | * Registers an icon set using an HTML string in the specified namespace.
|
---|
180 | * @param namespace Namespace in which to register the icon set.
|
---|
181 | * @param literal SVG source of the icon set.
|
---|
182 | */
|
---|
183 | addSvgIconSetLiteralInNamespace(namespace, literal, options) {
|
---|
184 | const cleanLiteral = this._sanitizer.sanitize(SecurityContext.HTML, literal);
|
---|
185 | if (!cleanLiteral) {
|
---|
186 | throw getMatIconFailedToSanitizeLiteralError(literal);
|
---|
187 | }
|
---|
188 | return this._addSvgIconSetConfig(namespace, new SvgIconConfig('', cleanLiteral, options));
|
---|
189 | }
|
---|
190 | /**
|
---|
191 | * Defines an alias for a CSS class name to be used for icon fonts. Creating an matIcon
|
---|
192 | * component with the alias as the fontSet input will cause the class name to be applied
|
---|
193 | * to the `<mat-icon>` element.
|
---|
194 | *
|
---|
195 | * @param alias Alias for the font.
|
---|
196 | * @param className Class name override to be used instead of the alias.
|
---|
197 | */
|
---|
198 | registerFontClassAlias(alias, className = alias) {
|
---|
199 | this._fontCssClassesByAlias.set(alias, className);
|
---|
200 | return this;
|
---|
201 | }
|
---|
202 | /**
|
---|
203 | * Returns the CSS class name associated with the alias by a previous call to
|
---|
204 | * registerFontClassAlias. If no CSS class has been associated, returns the alias unmodified.
|
---|
205 | */
|
---|
206 | classNameForFontAlias(alias) {
|
---|
207 | return this._fontCssClassesByAlias.get(alias) || alias;
|
---|
208 | }
|
---|
209 | /**
|
---|
210 | * Sets the CSS class name to be used for icon fonts when an `<mat-icon>` component does not
|
---|
211 | * have a fontSet input value, and is not loading an icon by name or URL.
|
---|
212 | *
|
---|
213 | * @param className
|
---|
214 | */
|
---|
215 | setDefaultFontSetClass(className) {
|
---|
216 | this._defaultFontSetClass = className;
|
---|
217 | return this;
|
---|
218 | }
|
---|
219 | /**
|
---|
220 | * Returns the CSS class name to be used for icon fonts when an `<mat-icon>` component does not
|
---|
221 | * have a fontSet input value, and is not loading an icon by name or URL.
|
---|
222 | */
|
---|
223 | getDefaultFontSetClass() {
|
---|
224 | return this._defaultFontSetClass;
|
---|
225 | }
|
---|
226 | /**
|
---|
227 | * Returns an Observable that produces the icon (as an `<svg>` DOM element) from the given URL.
|
---|
228 | * The response from the URL may be cached so this will not always cause an HTTP request, but
|
---|
229 | * the produced element will always be a new copy of the originally fetched icon. (That is,
|
---|
230 | * it will not contain any modifications made to elements previously returned).
|
---|
231 | *
|
---|
232 | * @param safeUrl URL from which to fetch the SVG icon.
|
---|
233 | */
|
---|
234 | getSvgIconFromUrl(safeUrl) {
|
---|
235 | const url = this._sanitizer.sanitize(SecurityContext.RESOURCE_URL, safeUrl);
|
---|
236 | if (!url) {
|
---|
237 | throw getMatIconFailedToSanitizeUrlError(safeUrl);
|
---|
238 | }
|
---|
239 | const cachedIcon = this._cachedIconsByUrl.get(url);
|
---|
240 | if (cachedIcon) {
|
---|
241 | return of(cloneSvg(cachedIcon));
|
---|
242 | }
|
---|
243 | return this._loadSvgIconFromConfig(new SvgIconConfig(safeUrl, null)).pipe(tap(svg => this._cachedIconsByUrl.set(url, svg)), map(svg => cloneSvg(svg)));
|
---|
244 | }
|
---|
245 | /**
|
---|
246 | * Returns an Observable that produces the icon (as an `<svg>` DOM element) with the given name
|
---|
247 | * and namespace. The icon must have been previously registered with addIcon or addIconSet;
|
---|
248 | * if not, the Observable will throw an error.
|
---|
249 | *
|
---|
250 | * @param name Name of the icon to be retrieved.
|
---|
251 | * @param namespace Namespace in which to look for the icon.
|
---|
252 | */
|
---|
253 | getNamedSvgIcon(name, namespace = '') {
|
---|
254 | const key = iconKey(namespace, name);
|
---|
255 | let config = this._svgIconConfigs.get(key);
|
---|
256 | // Return (copy of) cached icon if possible.
|
---|
257 | if (config) {
|
---|
258 | return this._getSvgFromConfig(config);
|
---|
259 | }
|
---|
260 | // Otherwise try to resolve the config from one of the resolver functions.
|
---|
261 | config = this._getIconConfigFromResolvers(namespace, name);
|
---|
262 | if (config) {
|
---|
263 | this._svgIconConfigs.set(key, config);
|
---|
264 | return this._getSvgFromConfig(config);
|
---|
265 | }
|
---|
266 | // See if we have any icon sets registered for the namespace.
|
---|
267 | const iconSetConfigs = this._iconSetConfigs.get(namespace);
|
---|
268 | if (iconSetConfigs) {
|
---|
269 | return this._getSvgFromIconSetConfigs(name, iconSetConfigs);
|
---|
270 | }
|
---|
271 | return throwError(getMatIconNameNotFoundError(key));
|
---|
272 | }
|
---|
273 | ngOnDestroy() {
|
---|
274 | this._resolvers = [];
|
---|
275 | this._svgIconConfigs.clear();
|
---|
276 | this._iconSetConfigs.clear();
|
---|
277 | this._cachedIconsByUrl.clear();
|
---|
278 | }
|
---|
279 | /**
|
---|
280 | * Returns the cached icon for a SvgIconConfig if available, or fetches it from its URL if not.
|
---|
281 | */
|
---|
282 | _getSvgFromConfig(config) {
|
---|
283 | if (config.svgText) {
|
---|
284 | // We already have the SVG element for this icon, return a copy.
|
---|
285 | return of(cloneSvg(this._svgElementFromConfig(config)));
|
---|
286 | }
|
---|
287 | else {
|
---|
288 | // Fetch the icon from the config's URL, cache it, and return a copy.
|
---|
289 | return this._loadSvgIconFromConfig(config).pipe(map(svg => cloneSvg(svg)));
|
---|
290 | }
|
---|
291 | }
|
---|
292 | /**
|
---|
293 | * Attempts to find an icon with the specified name in any of the SVG icon sets.
|
---|
294 | * First searches the available cached icons for a nested element with a matching name, and
|
---|
295 | * if found copies the element to a new `<svg>` element. If not found, fetches all icon sets
|
---|
296 | * that have not been cached, and searches again after all fetches are completed.
|
---|
297 | * The returned Observable produces the SVG element if possible, and throws
|
---|
298 | * an error if no icon with the specified name can be found.
|
---|
299 | */
|
---|
300 | _getSvgFromIconSetConfigs(name, iconSetConfigs) {
|
---|
301 | // For all the icon set SVG elements we've fetched, see if any contain an icon with the
|
---|
302 | // requested name.
|
---|
303 | const namedIcon = this._extractIconWithNameFromAnySet(name, iconSetConfigs);
|
---|
304 | if (namedIcon) {
|
---|
305 | // We could cache namedIcon in _svgIconConfigs, but since we have to make a copy every
|
---|
306 | // time anyway, there's probably not much advantage compared to just always extracting
|
---|
307 | // it from the icon set.
|
---|
308 | return of(namedIcon);
|
---|
309 | }
|
---|
310 | // Not found in any cached icon sets. If there are icon sets with URLs that we haven't
|
---|
311 | // fetched, fetch them now and look for iconName in the results.
|
---|
312 | const iconSetFetchRequests = iconSetConfigs
|
---|
313 | .filter(iconSetConfig => !iconSetConfig.svgText)
|
---|
314 | .map(iconSetConfig => {
|
---|
315 | return this._loadSvgIconSetFromConfig(iconSetConfig).pipe(catchError((err) => {
|
---|
316 | const url = this._sanitizer.sanitize(SecurityContext.RESOURCE_URL, iconSetConfig.url);
|
---|
317 | // Swallow errors fetching individual URLs so the
|
---|
318 | // combined Observable won't necessarily fail.
|
---|
319 | const errorMessage = `Loading icon set URL: ${url} failed: ${err.message}`;
|
---|
320 | this._errorHandler.handleError(new Error(errorMessage));
|
---|
321 | return of(null);
|
---|
322 | }));
|
---|
323 | });
|
---|
324 | // Fetch all the icon set URLs. When the requests complete, every IconSet should have a
|
---|
325 | // cached SVG element (unless the request failed), and we can check again for the icon.
|
---|
326 | return forkJoin(iconSetFetchRequests).pipe(map(() => {
|
---|
327 | const foundIcon = this._extractIconWithNameFromAnySet(name, iconSetConfigs);
|
---|
328 | // TODO: add an ngDevMode check
|
---|
329 | if (!foundIcon) {
|
---|
330 | throw getMatIconNameNotFoundError(name);
|
---|
331 | }
|
---|
332 | return foundIcon;
|
---|
333 | }));
|
---|
334 | }
|
---|
335 | /**
|
---|
336 | * Searches the cached SVG elements for the given icon sets for a nested icon element whose "id"
|
---|
337 | * tag matches the specified name. If found, copies the nested element to a new SVG element and
|
---|
338 | * returns it. Returns null if no matching element is found.
|
---|
339 | */
|
---|
340 | _extractIconWithNameFromAnySet(iconName, iconSetConfigs) {
|
---|
341 | // Iterate backwards, so icon sets added later have precedence.
|
---|
342 | for (let i = iconSetConfigs.length - 1; i >= 0; i--) {
|
---|
343 | const config = iconSetConfigs[i];
|
---|
344 | // Parsing the icon set's text into an SVG element can be expensive. We can avoid some of
|
---|
345 | // the parsing by doing a quick check using `indexOf` to see if there's any chance for the
|
---|
346 | // icon to be in the set. This won't be 100% accurate, but it should help us avoid at least
|
---|
347 | // some of the parsing.
|
---|
348 | if (config.svgText && config.svgText.indexOf(iconName) > -1) {
|
---|
349 | const svg = this._svgElementFromConfig(config);
|
---|
350 | const foundIcon = this._extractSvgIconFromSet(svg, iconName, config.options);
|
---|
351 | if (foundIcon) {
|
---|
352 | return foundIcon;
|
---|
353 | }
|
---|
354 | }
|
---|
355 | }
|
---|
356 | return null;
|
---|
357 | }
|
---|
358 | /**
|
---|
359 | * Loads the content of the icon URL specified in the SvgIconConfig and creates an SVG element
|
---|
360 | * from it.
|
---|
361 | */
|
---|
362 | _loadSvgIconFromConfig(config) {
|
---|
363 | return this._fetchIcon(config).pipe(tap(svgText => config.svgText = svgText), map(() => this._svgElementFromConfig(config)));
|
---|
364 | }
|
---|
365 | /**
|
---|
366 | * Loads the content of the icon set URL specified in the
|
---|
367 | * SvgIconConfig and attaches it to the config.
|
---|
368 | */
|
---|
369 | _loadSvgIconSetFromConfig(config) {
|
---|
370 | if (config.svgText) {
|
---|
371 | return of(null);
|
---|
372 | }
|
---|
373 | return this._fetchIcon(config).pipe(tap(svgText => config.svgText = svgText));
|
---|
374 | }
|
---|
375 | /**
|
---|
376 | * Searches the cached element of the given SvgIconConfig for a nested icon element whose "id"
|
---|
377 | * tag matches the specified name. If found, copies the nested element to a new SVG element and
|
---|
378 | * returns it. Returns null if no matching element is found.
|
---|
379 | */
|
---|
380 | _extractSvgIconFromSet(iconSet, iconName, options) {
|
---|
381 | // Use the `id="iconName"` syntax in order to escape special
|
---|
382 | // characters in the ID (versus using the #iconName syntax).
|
---|
383 | const iconSource = iconSet.querySelector(`[id="${iconName}"]`);
|
---|
384 | if (!iconSource) {
|
---|
385 | return null;
|
---|
386 | }
|
---|
387 | // Clone the element and remove the ID to prevent multiple elements from being added
|
---|
388 | // to the page with the same ID.
|
---|
389 | const iconElement = iconSource.cloneNode(true);
|
---|
390 | iconElement.removeAttribute('id');
|
---|
391 | // If the icon node is itself an <svg> node, clone and return it directly. If not, set it as
|
---|
392 | // the content of a new <svg> node.
|
---|
393 | if (iconElement.nodeName.toLowerCase() === 'svg') {
|
---|
394 | return this._setSvgAttributes(iconElement, options);
|
---|
395 | }
|
---|
396 | // If the node is a <symbol>, it won't be rendered so we have to convert it into <svg>. Note
|
---|
397 | // that the same could be achieved by referring to it via <use href="#id">, however the <use>
|
---|
398 | // tag is problematic on Firefox, because it needs to include the current page path.
|
---|
399 | if (iconElement.nodeName.toLowerCase() === 'symbol') {
|
---|
400 | return this._setSvgAttributes(this._toSvgElement(iconElement), options);
|
---|
401 | }
|
---|
402 | // createElement('SVG') doesn't work as expected; the DOM ends up with
|
---|
403 | // the correct nodes, but the SVG content doesn't render. Instead we
|
---|
404 | // have to create an empty SVG node using innerHTML and append its content.
|
---|
405 | // Elements created using DOMParser.parseFromString have the same problem.
|
---|
406 | // http://stackoverflow.com/questions/23003278/svg-innerhtml-in-firefox-can-not-display
|
---|
407 | const svg = this._svgElementFromString('<svg></svg>');
|
---|
408 | // Clone the node so we don't remove it from the parent icon set element.
|
---|
409 | svg.appendChild(iconElement);
|
---|
410 | return this._setSvgAttributes(svg, options);
|
---|
411 | }
|
---|
412 | /**
|
---|
413 | * Creates a DOM element from the given SVG string.
|
---|
414 | */
|
---|
415 | _svgElementFromString(str) {
|
---|
416 | const div = this._document.createElement('DIV');
|
---|
417 | div.innerHTML = str;
|
---|
418 | const svg = div.querySelector('svg');
|
---|
419 | // TODO: add an ngDevMode check
|
---|
420 | if (!svg) {
|
---|
421 | throw Error('<svg> tag not found');
|
---|
422 | }
|
---|
423 | return svg;
|
---|
424 | }
|
---|
425 | /**
|
---|
426 | * Converts an element into an SVG node by cloning all of its children.
|
---|
427 | */
|
---|
428 | _toSvgElement(element) {
|
---|
429 | const svg = this._svgElementFromString('<svg></svg>');
|
---|
430 | const attributes = element.attributes;
|
---|
431 | // Copy over all the attributes from the `symbol` to the new SVG, except the id.
|
---|
432 | for (let i = 0; i < attributes.length; i++) {
|
---|
433 | const { name, value } = attributes[i];
|
---|
434 | if (name !== 'id') {
|
---|
435 | svg.setAttribute(name, value);
|
---|
436 | }
|
---|
437 | }
|
---|
438 | for (let i = 0; i < element.childNodes.length; i++) {
|
---|
439 | if (element.childNodes[i].nodeType === this._document.ELEMENT_NODE) {
|
---|
440 | svg.appendChild(element.childNodes[i].cloneNode(true));
|
---|
441 | }
|
---|
442 | }
|
---|
443 | return svg;
|
---|
444 | }
|
---|
445 | /**
|
---|
446 | * Sets the default attributes for an SVG element to be used as an icon.
|
---|
447 | */
|
---|
448 | _setSvgAttributes(svg, options) {
|
---|
449 | svg.setAttribute('fit', '');
|
---|
450 | svg.setAttribute('height', '100%');
|
---|
451 | svg.setAttribute('width', '100%');
|
---|
452 | svg.setAttribute('preserveAspectRatio', 'xMidYMid meet');
|
---|
453 | svg.setAttribute('focusable', 'false'); // Disable IE11 default behavior to make SVGs focusable.
|
---|
454 | if (options && options.viewBox) {
|
---|
455 | svg.setAttribute('viewBox', options.viewBox);
|
---|
456 | }
|
---|
457 | return svg;
|
---|
458 | }
|
---|
459 | /**
|
---|
460 | * Returns an Observable which produces the string contents of the given icon. Results may be
|
---|
461 | * cached, so future calls with the same URL may not cause another HTTP request.
|
---|
462 | */
|
---|
463 | _fetchIcon(iconConfig) {
|
---|
464 | var _a;
|
---|
465 | const { url: safeUrl, options } = iconConfig;
|
---|
466 | const withCredentials = (_a = options === null || options === void 0 ? void 0 : options.withCredentials) !== null && _a !== void 0 ? _a : false;
|
---|
467 | if (!this._httpClient) {
|
---|
468 | throw getMatIconNoHttpProviderError();
|
---|
469 | }
|
---|
470 | // TODO: add an ngDevMode check
|
---|
471 | if (safeUrl == null) {
|
---|
472 | throw Error(`Cannot fetch icon from URL "${safeUrl}".`);
|
---|
473 | }
|
---|
474 | const url = this._sanitizer.sanitize(SecurityContext.RESOURCE_URL, safeUrl);
|
---|
475 | // TODO: add an ngDevMode check
|
---|
476 | if (!url) {
|
---|
477 | throw getMatIconFailedToSanitizeUrlError(safeUrl);
|
---|
478 | }
|
---|
479 | // Store in-progress fetches to avoid sending a duplicate request for a URL when there is
|
---|
480 | // already a request in progress for that URL. It's necessary to call share() on the
|
---|
481 | // Observable returned by http.get() so that multiple subscribers don't cause multiple XHRs.
|
---|
482 | const inProgressFetch = this._inProgressUrlFetches.get(url);
|
---|
483 | if (inProgressFetch) {
|
---|
484 | return inProgressFetch;
|
---|
485 | }
|
---|
486 | const req = this._httpClient.get(url, { responseType: 'text', withCredentials }).pipe(finalize(() => this._inProgressUrlFetches.delete(url)), share());
|
---|
487 | this._inProgressUrlFetches.set(url, req);
|
---|
488 | return req;
|
---|
489 | }
|
---|
490 | /**
|
---|
491 | * Registers an icon config by name in the specified namespace.
|
---|
492 | * @param namespace Namespace in which to register the icon config.
|
---|
493 | * @param iconName Name under which to register the config.
|
---|
494 | * @param config Config to be registered.
|
---|
495 | */
|
---|
496 | _addSvgIconConfig(namespace, iconName, config) {
|
---|
497 | this._svgIconConfigs.set(iconKey(namespace, iconName), config);
|
---|
498 | return this;
|
---|
499 | }
|
---|
500 | /**
|
---|
501 | * Registers an icon set config in the specified namespace.
|
---|
502 | * @param namespace Namespace in which to register the icon config.
|
---|
503 | * @param config Config to be registered.
|
---|
504 | */
|
---|
505 | _addSvgIconSetConfig(namespace, config) {
|
---|
506 | const configNamespace = this._iconSetConfigs.get(namespace);
|
---|
507 | if (configNamespace) {
|
---|
508 | configNamespace.push(config);
|
---|
509 | }
|
---|
510 | else {
|
---|
511 | this._iconSetConfigs.set(namespace, [config]);
|
---|
512 | }
|
---|
513 | return this;
|
---|
514 | }
|
---|
515 | /** Parses a config's text into an SVG element. */
|
---|
516 | _svgElementFromConfig(config) {
|
---|
517 | if (!config.svgElement) {
|
---|
518 | const svg = this._svgElementFromString(config.svgText);
|
---|
519 | this._setSvgAttributes(svg, config.options);
|
---|
520 | config.svgElement = svg;
|
---|
521 | }
|
---|
522 | return config.svgElement;
|
---|
523 | }
|
---|
524 | /** Tries to create an icon config through the registered resolver functions. */
|
---|
525 | _getIconConfigFromResolvers(namespace, name) {
|
---|
526 | for (let i = 0; i < this._resolvers.length; i++) {
|
---|
527 | const result = this._resolvers[i](name, namespace);
|
---|
528 | if (result) {
|
---|
529 | return isSafeUrlWithOptions(result) ?
|
---|
530 | new SvgIconConfig(result.url, null, result.options) :
|
---|
531 | new SvgIconConfig(result, null);
|
---|
532 | }
|
---|
533 | }
|
---|
534 | return undefined;
|
---|
535 | }
|
---|
536 | }
|
---|
537 | MatIconRegistry.ɵprov = i0.ɵɵdefineInjectable({ factory: function MatIconRegistry_Factory() { return new MatIconRegistry(i0.ɵɵinject(i1.HttpClient, 8), i0.ɵɵinject(i2.DomSanitizer), i0.ɵɵinject(i3.DOCUMENT, 8), i0.ɵɵinject(i0.ErrorHandler)); }, token: MatIconRegistry, providedIn: "root" });
|
---|
538 | MatIconRegistry.decorators = [
|
---|
539 | { type: Injectable, args: [{ providedIn: 'root' },] }
|
---|
540 | ];
|
---|
541 | MatIconRegistry.ctorParameters = () => [
|
---|
542 | { type: HttpClient, decorators: [{ type: Optional }] },
|
---|
543 | { type: DomSanitizer },
|
---|
544 | { type: undefined, decorators: [{ type: Optional }, { type: Inject, args: [DOCUMENT,] }] },
|
---|
545 | { type: ErrorHandler }
|
---|
546 | ];
|
---|
547 | /** @docs-private */
|
---|
548 | function ICON_REGISTRY_PROVIDER_FACTORY(parentRegistry, httpClient, sanitizer, errorHandler, document) {
|
---|
549 | return parentRegistry || new MatIconRegistry(httpClient, sanitizer, document, errorHandler);
|
---|
550 | }
|
---|
551 | /** @docs-private */
|
---|
552 | const ICON_REGISTRY_PROVIDER = {
|
---|
553 | // If there is already an MatIconRegistry available, use that. Otherwise, provide a new one.
|
---|
554 | provide: MatIconRegistry,
|
---|
555 | deps: [
|
---|
556 | [new Optional(), new SkipSelf(), MatIconRegistry],
|
---|
557 | [new Optional(), HttpClient],
|
---|
558 | DomSanitizer,
|
---|
559 | ErrorHandler,
|
---|
560 | [new Optional(), DOCUMENT],
|
---|
561 | ],
|
---|
562 | useFactory: ICON_REGISTRY_PROVIDER_FACTORY,
|
---|
563 | };
|
---|
564 | /** Clones an SVGElement while preserving type information. */
|
---|
565 | function cloneSvg(svg) {
|
---|
566 | return svg.cloneNode(true);
|
---|
567 | }
|
---|
568 | /** Returns the cache key to use for an icon namespace and name. */
|
---|
569 | function iconKey(namespace, name) {
|
---|
570 | return namespace + ':' + name;
|
---|
571 | }
|
---|
572 | function isSafeUrlWithOptions(value) {
|
---|
573 | return !!(value.url && value.options);
|
---|
574 | }
|
---|
575 |
|
---|
576 | /**
|
---|
577 | * @license
|
---|
578 | * Copyright Google LLC All Rights Reserved.
|
---|
579 | *
|
---|
580 | * Use of this source code is governed by an MIT-style license that can be
|
---|
581 | * found in the LICENSE file at https://angular.io/license
|
---|
582 | */
|
---|
583 | // Boilerplate for applying mixins to MatIcon.
|
---|
584 | /** @docs-private */
|
---|
585 | const _MatIconBase = mixinColor(class {
|
---|
586 | constructor(_elementRef) {
|
---|
587 | this._elementRef = _elementRef;
|
---|
588 | }
|
---|
589 | });
|
---|
590 | /**
|
---|
591 | * Injection token used to provide the current location to `MatIcon`.
|
---|
592 | * Used to handle server-side rendering and to stub out during unit tests.
|
---|
593 | * @docs-private
|
---|
594 | */
|
---|
595 | const MAT_ICON_LOCATION = new InjectionToken('mat-icon-location', {
|
---|
596 | providedIn: 'root',
|
---|
597 | factory: MAT_ICON_LOCATION_FACTORY
|
---|
598 | });
|
---|
599 | /** @docs-private */
|
---|
600 | function MAT_ICON_LOCATION_FACTORY() {
|
---|
601 | const _document = inject(DOCUMENT);
|
---|
602 | const _location = _document ? _document.location : null;
|
---|
603 | return {
|
---|
604 | // Note that this needs to be a function, rather than a property, because Angular
|
---|
605 | // will only resolve it once, but we want the current path on each call.
|
---|
606 | getPathname: () => _location ? (_location.pathname + _location.search) : ''
|
---|
607 | };
|
---|
608 | }
|
---|
609 | /** SVG attributes that accept a FuncIRI (e.g. `url(<something>)`). */
|
---|
610 | const funcIriAttributes = [
|
---|
611 | 'clip-path',
|
---|
612 | 'color-profile',
|
---|
613 | 'src',
|
---|
614 | 'cursor',
|
---|
615 | 'fill',
|
---|
616 | 'filter',
|
---|
617 | 'marker',
|
---|
618 | 'marker-start',
|
---|
619 | 'marker-mid',
|
---|
620 | 'marker-end',
|
---|
621 | 'mask',
|
---|
622 | 'stroke'
|
---|
623 | ];
|
---|
624 | const ɵ0 = attr => `[${attr}]`;
|
---|
625 | /** Selector that can be used to find all elements that are using a `FuncIRI`. */
|
---|
626 | const funcIriAttributeSelector = funcIriAttributes.map(ɵ0).join(', ');
|
---|
627 | /** Regex that can be used to extract the id out of a FuncIRI. */
|
---|
628 | const funcIriPattern = /^url\(['"]?#(.*?)['"]?\)$/;
|
---|
629 | /**
|
---|
630 | * Component to display an icon. It can be used in the following ways:
|
---|
631 | *
|
---|
632 | * - Specify the svgIcon input to load an SVG icon from a URL previously registered with the
|
---|
633 | * addSvgIcon, addSvgIconInNamespace, addSvgIconSet, or addSvgIconSetInNamespace methods of
|
---|
634 | * MatIconRegistry. If the svgIcon value contains a colon it is assumed to be in the format
|
---|
635 | * "[namespace]:[name]", if not the value will be the name of an icon in the default namespace.
|
---|
636 | * Examples:
|
---|
637 | * `<mat-icon svgIcon="left-arrow"></mat-icon>
|
---|
638 | * <mat-icon svgIcon="animals:cat"></mat-icon>`
|
---|
639 | *
|
---|
640 | * - Use a font ligature as an icon by putting the ligature text in the content of the `<mat-icon>`
|
---|
641 | * component. By default the Material icons font is used as described at
|
---|
642 | * http://google.github.io/material-design-icons/#icon-font-for-the-web. You can specify an
|
---|
643 | * alternate font by setting the fontSet input to either the CSS class to apply to use the
|
---|
644 | * desired font, or to an alias previously registered with MatIconRegistry.registerFontClassAlias.
|
---|
645 | * Examples:
|
---|
646 | * `<mat-icon>home</mat-icon>
|
---|
647 | * <mat-icon fontSet="myfont">sun</mat-icon>`
|
---|
648 | *
|
---|
649 | * - Specify a font glyph to be included via CSS rules by setting the fontSet input to specify the
|
---|
650 | * font, and the fontIcon input to specify the icon. Typically the fontIcon will specify a
|
---|
651 | * CSS class which causes the glyph to be displayed via a :before selector, as in
|
---|
652 | * https://fortawesome.github.io/Font-Awesome/examples/
|
---|
653 | * Example:
|
---|
654 | * `<mat-icon fontSet="fa" fontIcon="alarm"></mat-icon>`
|
---|
655 | */
|
---|
656 | class MatIcon extends _MatIconBase {
|
---|
657 | constructor(elementRef, _iconRegistry, ariaHidden, _location, _errorHandler) {
|
---|
658 | super(elementRef);
|
---|
659 | this._iconRegistry = _iconRegistry;
|
---|
660 | this._location = _location;
|
---|
661 | this._errorHandler = _errorHandler;
|
---|
662 | this._inline = false;
|
---|
663 | /** Subscription to the current in-progress SVG icon request. */
|
---|
664 | this._currentIconFetch = Subscription.EMPTY;
|
---|
665 | // If the user has not explicitly set aria-hidden, mark the icon as hidden, as this is
|
---|
666 | // the right thing to do for the majority of icon use-cases.
|
---|
667 | if (!ariaHidden) {
|
---|
668 | elementRef.nativeElement.setAttribute('aria-hidden', 'true');
|
---|
669 | }
|
---|
670 | }
|
---|
671 | /**
|
---|
672 | * Whether the icon should be inlined, automatically sizing the icon to match the font size of
|
---|
673 | * the element the icon is contained in.
|
---|
674 | */
|
---|
675 | get inline() {
|
---|
676 | return this._inline;
|
---|
677 | }
|
---|
678 | set inline(inline) {
|
---|
679 | this._inline = coerceBooleanProperty(inline);
|
---|
680 | }
|
---|
681 | /** Name of the icon in the SVG icon set. */
|
---|
682 | get svgIcon() { return this._svgIcon; }
|
---|
683 | set svgIcon(value) {
|
---|
684 | if (value !== this._svgIcon) {
|
---|
685 | if (value) {
|
---|
686 | this._updateSvgIcon(value);
|
---|
687 | }
|
---|
688 | else if (this._svgIcon) {
|
---|
689 | this._clearSvgElement();
|
---|
690 | }
|
---|
691 | this._svgIcon = value;
|
---|
692 | }
|
---|
693 | }
|
---|
694 | /** Font set that the icon is a part of. */
|
---|
695 | get fontSet() { return this._fontSet; }
|
---|
696 | set fontSet(value) {
|
---|
697 | const newValue = this._cleanupFontValue(value);
|
---|
698 | if (newValue !== this._fontSet) {
|
---|
699 | this._fontSet = newValue;
|
---|
700 | this._updateFontIconClasses();
|
---|
701 | }
|
---|
702 | }
|
---|
703 | /** Name of an icon within a font set. */
|
---|
704 | get fontIcon() { return this._fontIcon; }
|
---|
705 | set fontIcon(value) {
|
---|
706 | const newValue = this._cleanupFontValue(value);
|
---|
707 | if (newValue !== this._fontIcon) {
|
---|
708 | this._fontIcon = newValue;
|
---|
709 | this._updateFontIconClasses();
|
---|
710 | }
|
---|
711 | }
|
---|
712 | /**
|
---|
713 | * Splits an svgIcon binding value into its icon set and icon name components.
|
---|
714 | * Returns a 2-element array of [(icon set), (icon name)].
|
---|
715 | * The separator for the two fields is ':'. If there is no separator, an empty
|
---|
716 | * string is returned for the icon set and the entire value is returned for
|
---|
717 | * the icon name. If the argument is falsy, returns an array of two empty strings.
|
---|
718 | * Throws an error if the name contains two or more ':' separators.
|
---|
719 | * Examples:
|
---|
720 | * `'social:cake' -> ['social', 'cake']
|
---|
721 | * 'penguin' -> ['', 'penguin']
|
---|
722 | * null -> ['', '']
|
---|
723 | * 'a:b:c' -> (throws Error)`
|
---|
724 | */
|
---|
725 | _splitIconName(iconName) {
|
---|
726 | if (!iconName) {
|
---|
727 | return ['', ''];
|
---|
728 | }
|
---|
729 | const parts = iconName.split(':');
|
---|
730 | switch (parts.length) {
|
---|
731 | case 1: return ['', parts[0]]; // Use default namespace.
|
---|
732 | case 2: return parts;
|
---|
733 | default: throw Error(`Invalid icon name: "${iconName}"`); // TODO: add an ngDevMode check
|
---|
734 | }
|
---|
735 | }
|
---|
736 | ngOnInit() {
|
---|
737 | // Update font classes because ngOnChanges won't be called if none of the inputs are present,
|
---|
738 | // e.g. <mat-icon>arrow</mat-icon> In this case we need to add a CSS class for the default font.
|
---|
739 | this._updateFontIconClasses();
|
---|
740 | }
|
---|
741 | ngAfterViewChecked() {
|
---|
742 | const cachedElements = this._elementsWithExternalReferences;
|
---|
743 | if (cachedElements && cachedElements.size) {
|
---|
744 | const newPath = this._location.getPathname();
|
---|
745 | // We need to check whether the URL has changed on each change detection since
|
---|
746 | // the browser doesn't have an API that will let us react on link clicks and
|
---|
747 | // we can't depend on the Angular router. The references need to be updated,
|
---|
748 | // because while most browsers don't care whether the URL is correct after
|
---|
749 | // the first render, Safari will break if the user navigates to a different
|
---|
750 | // page and the SVG isn't re-rendered.
|
---|
751 | if (newPath !== this._previousPath) {
|
---|
752 | this._previousPath = newPath;
|
---|
753 | this._prependPathToReferences(newPath);
|
---|
754 | }
|
---|
755 | }
|
---|
756 | }
|
---|
757 | ngOnDestroy() {
|
---|
758 | this._currentIconFetch.unsubscribe();
|
---|
759 | if (this._elementsWithExternalReferences) {
|
---|
760 | this._elementsWithExternalReferences.clear();
|
---|
761 | }
|
---|
762 | }
|
---|
763 | _usingFontIcon() {
|
---|
764 | return !this.svgIcon;
|
---|
765 | }
|
---|
766 | _setSvgElement(svg) {
|
---|
767 | this._clearSvgElement();
|
---|
768 | // Workaround for IE11 and Edge ignoring `style` tags inside dynamically-created SVGs.
|
---|
769 | // See: https://developer.microsoft.com/en-us/microsoft-edge/platform/issues/10898469/
|
---|
770 | // Do this before inserting the element into the DOM, in order to avoid a style recalculation.
|
---|
771 | const styleTags = svg.querySelectorAll('style');
|
---|
772 | for (let i = 0; i < styleTags.length; i++) {
|
---|
773 | styleTags[i].textContent += ' ';
|
---|
774 | }
|
---|
775 | // Note: we do this fix here, rather than the icon registry, because the
|
---|
776 | // references have to point to the URL at the time that the icon was created.
|
---|
777 | const path = this._location.getPathname();
|
---|
778 | this._previousPath = path;
|
---|
779 | this._cacheChildrenWithExternalReferences(svg);
|
---|
780 | this._prependPathToReferences(path);
|
---|
781 | this._elementRef.nativeElement.appendChild(svg);
|
---|
782 | }
|
---|
783 | _clearSvgElement() {
|
---|
784 | const layoutElement = this._elementRef.nativeElement;
|
---|
785 | let childCount = layoutElement.childNodes.length;
|
---|
786 | if (this._elementsWithExternalReferences) {
|
---|
787 | this._elementsWithExternalReferences.clear();
|
---|
788 | }
|
---|
789 | // Remove existing non-element child nodes and SVGs, and add the new SVG element. Note that
|
---|
790 | // we can't use innerHTML, because IE will throw if the element has a data binding.
|
---|
791 | while (childCount--) {
|
---|
792 | const child = layoutElement.childNodes[childCount];
|
---|
793 | // 1 corresponds to Node.ELEMENT_NODE. We remove all non-element nodes in order to get rid
|
---|
794 | // of any loose text nodes, as well as any SVG elements in order to remove any old icons.
|
---|
795 | if (child.nodeType !== 1 || child.nodeName.toLowerCase() === 'svg') {
|
---|
796 | layoutElement.removeChild(child);
|
---|
797 | }
|
---|
798 | }
|
---|
799 | }
|
---|
800 | _updateFontIconClasses() {
|
---|
801 | if (!this._usingFontIcon()) {
|
---|
802 | return;
|
---|
803 | }
|
---|
804 | const elem = this._elementRef.nativeElement;
|
---|
805 | const fontSetClass = this.fontSet ?
|
---|
806 | this._iconRegistry.classNameForFontAlias(this.fontSet) :
|
---|
807 | this._iconRegistry.getDefaultFontSetClass();
|
---|
808 | if (fontSetClass != this._previousFontSetClass) {
|
---|
809 | if (this._previousFontSetClass) {
|
---|
810 | elem.classList.remove(this._previousFontSetClass);
|
---|
811 | }
|
---|
812 | if (fontSetClass) {
|
---|
813 | elem.classList.add(fontSetClass);
|
---|
814 | }
|
---|
815 | this._previousFontSetClass = fontSetClass;
|
---|
816 | }
|
---|
817 | if (this.fontIcon != this._previousFontIconClass) {
|
---|
818 | if (this._previousFontIconClass) {
|
---|
819 | elem.classList.remove(this._previousFontIconClass);
|
---|
820 | }
|
---|
821 | if (this.fontIcon) {
|
---|
822 | elem.classList.add(this.fontIcon);
|
---|
823 | }
|
---|
824 | this._previousFontIconClass = this.fontIcon;
|
---|
825 | }
|
---|
826 | }
|
---|
827 | /**
|
---|
828 | * Cleans up a value to be used as a fontIcon or fontSet.
|
---|
829 | * Since the value ends up being assigned as a CSS class, we
|
---|
830 | * have to trim the value and omit space-separated values.
|
---|
831 | */
|
---|
832 | _cleanupFontValue(value) {
|
---|
833 | return typeof value === 'string' ? value.trim().split(' ')[0] : value;
|
---|
834 | }
|
---|
835 | /**
|
---|
836 | * Prepends the current path to all elements that have an attribute pointing to a `FuncIRI`
|
---|
837 | * reference. This is required because WebKit browsers require references to be prefixed with
|
---|
838 | * the current path, if the page has a `base` tag.
|
---|
839 | */
|
---|
840 | _prependPathToReferences(path) {
|
---|
841 | const elements = this._elementsWithExternalReferences;
|
---|
842 | if (elements) {
|
---|
843 | elements.forEach((attrs, element) => {
|
---|
844 | attrs.forEach(attr => {
|
---|
845 | element.setAttribute(attr.name, `url('${path}#${attr.value}')`);
|
---|
846 | });
|
---|
847 | });
|
---|
848 | }
|
---|
849 | }
|
---|
850 | /**
|
---|
851 | * Caches the children of an SVG element that have `url()`
|
---|
852 | * references that we need to prefix with the current path.
|
---|
853 | */
|
---|
854 | _cacheChildrenWithExternalReferences(element) {
|
---|
855 | const elementsWithFuncIri = element.querySelectorAll(funcIriAttributeSelector);
|
---|
856 | const elements = this._elementsWithExternalReferences =
|
---|
857 | this._elementsWithExternalReferences || new Map();
|
---|
858 | for (let i = 0; i < elementsWithFuncIri.length; i++) {
|
---|
859 | funcIriAttributes.forEach(attr => {
|
---|
860 | const elementWithReference = elementsWithFuncIri[i];
|
---|
861 | const value = elementWithReference.getAttribute(attr);
|
---|
862 | const match = value ? value.match(funcIriPattern) : null;
|
---|
863 | if (match) {
|
---|
864 | let attributes = elements.get(elementWithReference);
|
---|
865 | if (!attributes) {
|
---|
866 | attributes = [];
|
---|
867 | elements.set(elementWithReference, attributes);
|
---|
868 | }
|
---|
869 | attributes.push({ name: attr, value: match[1] });
|
---|
870 | }
|
---|
871 | });
|
---|
872 | }
|
---|
873 | }
|
---|
874 | /** Sets a new SVG icon with a particular name. */
|
---|
875 | _updateSvgIcon(rawName) {
|
---|
876 | this._svgNamespace = null;
|
---|
877 | this._svgName = null;
|
---|
878 | this._currentIconFetch.unsubscribe();
|
---|
879 | if (rawName) {
|
---|
880 | const [namespace, iconName] = this._splitIconName(rawName);
|
---|
881 | if (namespace) {
|
---|
882 | this._svgNamespace = namespace;
|
---|
883 | }
|
---|
884 | if (iconName) {
|
---|
885 | this._svgName = iconName;
|
---|
886 | }
|
---|
887 | this._currentIconFetch = this._iconRegistry.getNamedSvgIcon(iconName, namespace)
|
---|
888 | .pipe(take(1))
|
---|
889 | .subscribe(svg => this._setSvgElement(svg), (err) => {
|
---|
890 | const errorMessage = `Error retrieving icon ${namespace}:${iconName}! ${err.message}`;
|
---|
891 | this._errorHandler.handleError(new Error(errorMessage));
|
---|
892 | });
|
---|
893 | }
|
---|
894 | }
|
---|
895 | }
|
---|
896 | MatIcon.decorators = [
|
---|
897 | { type: Component, args: [{
|
---|
898 | template: '<ng-content></ng-content>',
|
---|
899 | selector: 'mat-icon',
|
---|
900 | exportAs: 'matIcon',
|
---|
901 | inputs: ['color'],
|
---|
902 | host: {
|
---|
903 | 'role': 'img',
|
---|
904 | 'class': 'mat-icon notranslate',
|
---|
905 | '[attr.data-mat-icon-type]': '_usingFontIcon() ? "font" : "svg"',
|
---|
906 | '[attr.data-mat-icon-name]': '_svgName || fontIcon',
|
---|
907 | '[attr.data-mat-icon-namespace]': '_svgNamespace || fontSet',
|
---|
908 | '[class.mat-icon-inline]': 'inline',
|
---|
909 | '[class.mat-icon-no-color]': 'color !== "primary" && color !== "accent" && color !== "warn"',
|
---|
910 | },
|
---|
911 | encapsulation: ViewEncapsulation.None,
|
---|
912 | changeDetection: ChangeDetectionStrategy.OnPush,
|
---|
913 | styles: [".mat-icon{-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;background-repeat:no-repeat;display:inline-block;fill:currentColor;height:24px;width:24px}.mat-icon.mat-icon-inline{font-size:inherit;height:inherit;line-height:inherit;width:inherit}[dir=rtl] .mat-icon-rtl-mirror{transform:scale(-1, 1)}.mat-form-field:not(.mat-form-field-appearance-legacy) .mat-form-field-prefix .mat-icon,.mat-form-field:not(.mat-form-field-appearance-legacy) .mat-form-field-suffix .mat-icon{display:block}.mat-form-field:not(.mat-form-field-appearance-legacy) .mat-form-field-prefix .mat-icon-button .mat-icon,.mat-form-field:not(.mat-form-field-appearance-legacy) .mat-form-field-suffix .mat-icon-button .mat-icon{margin:auto}\n"]
|
---|
914 | },] }
|
---|
915 | ];
|
---|
916 | MatIcon.ctorParameters = () => [
|
---|
917 | { type: ElementRef },
|
---|
918 | { type: MatIconRegistry },
|
---|
919 | { type: String, decorators: [{ type: Attribute, args: ['aria-hidden',] }] },
|
---|
920 | { type: undefined, decorators: [{ type: Inject, args: [MAT_ICON_LOCATION,] }] },
|
---|
921 | { type: ErrorHandler }
|
---|
922 | ];
|
---|
923 | MatIcon.propDecorators = {
|
---|
924 | inline: [{ type: Input }],
|
---|
925 | svgIcon: [{ type: Input }],
|
---|
926 | fontSet: [{ type: Input }],
|
---|
927 | fontIcon: [{ type: Input }]
|
---|
928 | };
|
---|
929 |
|
---|
930 | /**
|
---|
931 | * @license
|
---|
932 | * Copyright Google LLC All Rights Reserved.
|
---|
933 | *
|
---|
934 | * Use of this source code is governed by an MIT-style license that can be
|
---|
935 | * found in the LICENSE file at https://angular.io/license
|
---|
936 | */
|
---|
937 | class MatIconModule {
|
---|
938 | }
|
---|
939 | MatIconModule.decorators = [
|
---|
940 | { type: NgModule, args: [{
|
---|
941 | imports: [MatCommonModule],
|
---|
942 | exports: [MatIcon, MatCommonModule],
|
---|
943 | declarations: [MatIcon],
|
---|
944 | },] }
|
---|
945 | ];
|
---|
946 |
|
---|
947 | /**
|
---|
948 | * @license
|
---|
949 | * Copyright Google LLC All Rights Reserved.
|
---|
950 | *
|
---|
951 | * Use of this source code is governed by an MIT-style license that can be
|
---|
952 | * found in the LICENSE file at https://angular.io/license
|
---|
953 | */
|
---|
954 |
|
---|
955 | /**
|
---|
956 | * Generated bundle index. Do not edit.
|
---|
957 | */
|
---|
958 |
|
---|
959 | export { ICON_REGISTRY_PROVIDER, ICON_REGISTRY_PROVIDER_FACTORY, MAT_ICON_LOCATION, MAT_ICON_LOCATION_FACTORY, MatIcon, MatIconModule, MatIconRegistry, getMatIconFailedToSanitizeLiteralError, getMatIconFailedToSanitizeUrlError, getMatIconNameNotFoundError, getMatIconNoHttpProviderError, ɵ0 };
|
---|
960 | //# sourceMappingURL=icon.js.map
|
---|