UNPKG

@angular/material

Version:
369 lines (366 loc) 12.5 kB
import { trustedHTMLFromString } from '@angular/cdk/private'; import * as i1 from '@angular/common/http'; import * as i0 from '@angular/core'; import { SecurityContext, DOCUMENT, Injectable, Optional, Inject } from '@angular/core'; import * as i2 from '@angular/platform-browser'; import { of, throwError, forkJoin } from 'rxjs'; import { tap, map, catchError, finalize, share } from 'rxjs/operators'; function getMatIconNameNotFoundError(iconName) { return Error(`Unable to find icon with the name "${iconName}"`); } function getMatIconNoHttpProviderError() { return Error('Could not find HttpClient for use with Angular Material icons. ' + 'Please add provideHttpClient() to your providers.'); } function getMatIconFailedToSanitizeUrlError(url) { return Error(`The URL provided to MatIconRegistry was not trusted as a resource URL ` + `via Angular's DomSanitizer. Attempted URL was "${url}".`); } function getMatIconFailedToSanitizeLiteralError(literal) { return Error(`The literal provided to MatIconRegistry was not trusted as safe HTML by ` + `Angular's DomSanitizer. Attempted literal was "${literal}".`); } class SvgIconConfig { url; svgText; options; svgElement; constructor(url, svgText, options) { this.url = url; this.svgText = svgText; this.options = options; } } class MatIconRegistry { _httpClient; _sanitizer; _errorHandler; _document; _svgIconConfigs = new Map(); _iconSetConfigs = new Map(); _cachedIconsByUrl = new Map(); _inProgressUrlFetches = new Map(); _fontCssClassesByAlias = new Map(); _resolvers = []; _defaultFontSetClass = ['material-icons', 'mat-ligature-font']; constructor(_httpClient, _sanitizer, document, _errorHandler) { this._httpClient = _httpClient; this._sanitizer = _sanitizer; this._errorHandler = _errorHandler; this._document = document; } addSvgIcon(iconName, url, options) { return this.addSvgIconInNamespace('', iconName, url, options); } addSvgIconLiteral(iconName, literal, options) { return this.addSvgIconLiteralInNamespace('', iconName, literal, options); } addSvgIconInNamespace(namespace, iconName, url, options) { return this._addSvgIconConfig(namespace, iconName, new SvgIconConfig(url, null, options)); } addSvgIconResolver(resolver) { this._resolvers.push(resolver); return this; } addSvgIconLiteralInNamespace(namespace, iconName, literal, options) { const cleanLiteral = this._sanitizer.sanitize(SecurityContext.HTML, literal); if (!cleanLiteral) { throw getMatIconFailedToSanitizeLiteralError(literal); } const trustedLiteral = trustedHTMLFromString(cleanLiteral); return this._addSvgIconConfig(namespace, iconName, new SvgIconConfig('', trustedLiteral, options)); } addSvgIconSet(url, options) { return this.addSvgIconSetInNamespace('', url, options); } addSvgIconSetLiteral(literal, options) { return this.addSvgIconSetLiteralInNamespace('', literal, options); } addSvgIconSetInNamespace(namespace, url, options) { return this._addSvgIconSetConfig(namespace, new SvgIconConfig(url, null, options)); } addSvgIconSetLiteralInNamespace(namespace, literal, options) { const cleanLiteral = this._sanitizer.sanitize(SecurityContext.HTML, literal); if (!cleanLiteral) { throw getMatIconFailedToSanitizeLiteralError(literal); } const trustedLiteral = trustedHTMLFromString(cleanLiteral); return this._addSvgIconSetConfig(namespace, new SvgIconConfig('', trustedLiteral, options)); } registerFontClassAlias(alias, classNames = alias) { this._fontCssClassesByAlias.set(alias, classNames); return this; } classNameForFontAlias(alias) { return this._fontCssClassesByAlias.get(alias) || alias; } setDefaultFontSetClass(...classNames) { this._defaultFontSetClass = classNames; return this; } getDefaultFontSetClass() { return this._defaultFontSetClass; } getSvgIconFromUrl(safeUrl) { const url = this._sanitizer.sanitize(SecurityContext.RESOURCE_URL, safeUrl); if (!url) { throw getMatIconFailedToSanitizeUrlError(safeUrl); } const cachedIcon = this._cachedIconsByUrl.get(url); if (cachedIcon) { return of(cloneSvg(cachedIcon)); } return this._loadSvgIconFromConfig(new SvgIconConfig(safeUrl, null)).pipe(tap(svg => this._cachedIconsByUrl.set(url, svg)), map(svg => cloneSvg(svg))); } getNamedSvgIcon(name, namespace = '') { const key = iconKey(namespace, name); let config = this._svgIconConfigs.get(key); if (config) { return this._getSvgFromConfig(config); } config = this._getIconConfigFromResolvers(namespace, name); if (config) { this._svgIconConfigs.set(key, config); return this._getSvgFromConfig(config); } const iconSetConfigs = this._iconSetConfigs.get(namespace); if (iconSetConfigs) { return this._getSvgFromIconSetConfigs(name, iconSetConfigs); } return throwError(getMatIconNameNotFoundError(key)); } ngOnDestroy() { this._resolvers = []; this._svgIconConfigs.clear(); this._iconSetConfigs.clear(); this._cachedIconsByUrl.clear(); } _getSvgFromConfig(config) { if (config.svgText) { return of(cloneSvg(this._svgElementFromConfig(config))); } else { return this._loadSvgIconFromConfig(config).pipe(map(svg => cloneSvg(svg))); } } _getSvgFromIconSetConfigs(name, iconSetConfigs) { const namedIcon = this._extractIconWithNameFromAnySet(name, iconSetConfigs); if (namedIcon) { return of(namedIcon); } const iconSetFetchRequests = iconSetConfigs.filter(iconSetConfig => !iconSetConfig.svgText).map(iconSetConfig => { return this._loadSvgIconSetFromConfig(iconSetConfig).pipe(catchError(err => { const url = this._sanitizer.sanitize(SecurityContext.RESOURCE_URL, iconSetConfig.url); const errorMessage = `Loading icon set URL: ${url} failed: ${err.message}`; this._errorHandler.handleError(new Error(errorMessage)); return of(null); })); }); return forkJoin(iconSetFetchRequests).pipe(map(() => { const foundIcon = this._extractIconWithNameFromAnySet(name, iconSetConfigs); if (!foundIcon) { throw getMatIconNameNotFoundError(name); } return foundIcon; })); } _extractIconWithNameFromAnySet(iconName, iconSetConfigs) { for (let i = iconSetConfigs.length - 1; i >= 0; i--) { const config = iconSetConfigs[i]; if (config.svgText && config.svgText.toString().indexOf(iconName) > -1) { const svg = this._svgElementFromConfig(config); const foundIcon = this._extractSvgIconFromSet(svg, iconName, config.options); if (foundIcon) { return foundIcon; } } } return null; } _loadSvgIconFromConfig(config) { return this._fetchIcon(config).pipe(tap(svgText => config.svgText = svgText), map(() => this._svgElementFromConfig(config))); } _loadSvgIconSetFromConfig(config) { if (config.svgText) { return of(null); } return this._fetchIcon(config).pipe(tap(svgText => config.svgText = svgText)); } _extractSvgIconFromSet(iconSet, iconName, options) { const iconSource = iconSet.querySelector(`[id="${iconName}"]`); if (!iconSource) { return null; } const iconElement = iconSource.cloneNode(true); iconElement.removeAttribute('id'); if (iconElement.nodeName.toLowerCase() === 'svg') { return this._setSvgAttributes(iconElement, options); } if (iconElement.nodeName.toLowerCase() === 'symbol') { return this._setSvgAttributes(this._toSvgElement(iconElement), options); } const svg = this._svgElementFromString(trustedHTMLFromString('<svg></svg>')); svg.appendChild(iconElement); return this._setSvgAttributes(svg, options); } _svgElementFromString(str) { const div = this._document.createElement('DIV'); div.innerHTML = str; const svg = div.querySelector('svg'); if (!svg) { throw Error('<svg> tag not found'); } return svg; } _toSvgElement(element) { const svg = this._svgElementFromString(trustedHTMLFromString('<svg></svg>')); const attributes = element.attributes; for (let i = 0; i < attributes.length; i++) { const { name, value } = attributes[i]; if (name !== 'id') { svg.setAttribute(name, value); } } for (let i = 0; i < element.childNodes.length; i++) { if (element.childNodes[i].nodeType === this._document.ELEMENT_NODE) { svg.appendChild(element.childNodes[i].cloneNode(true)); } } return svg; } _setSvgAttributes(svg, options) { svg.setAttribute('fit', ''); svg.setAttribute('height', '100%'); svg.setAttribute('width', '100%'); svg.setAttribute('preserveAspectRatio', 'xMidYMid meet'); svg.setAttribute('focusable', 'false'); if (options && options.viewBox) { svg.setAttribute('viewBox', options.viewBox); } return svg; } _fetchIcon(iconConfig) { const { url: safeUrl, options } = iconConfig; const withCredentials = options?.withCredentials ?? false; 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 getMatIconFailedToSanitizeUrlError(safeUrl); } const inProgressFetch = this._inProgressUrlFetches.get(url); if (inProgressFetch) { return inProgressFetch; } const req = this._httpClient.get(url, { responseType: 'text', withCredentials }).pipe(map(svg => { return trustedHTMLFromString(svg); }), finalize(() => this._inProgressUrlFetches.delete(url)), share()); this._inProgressUrlFetches.set(url, req); return req; } _addSvgIconConfig(namespace, iconName, config) { this._svgIconConfigs.set(iconKey(namespace, iconName), config); return this; } _addSvgIconSetConfig(namespace, config) { const configNamespace = this._iconSetConfigs.get(namespace); if (configNamespace) { configNamespace.push(config); } else { this._iconSetConfigs.set(namespace, [config]); } return this; } _svgElementFromConfig(config) { if (!config.svgElement) { const svg = this._svgElementFromString(config.svgText); this._setSvgAttributes(svg, config.options); config.svgElement = svg; } return config.svgElement; } _getIconConfigFromResolvers(namespace, name) { for (let i = 0; i < this._resolvers.length; i++) { const result = this._resolvers[i](name, namespace); if (result) { return isSafeUrlWithOptions(result) ? new SvgIconConfig(result.url, null, result.options) : new SvgIconConfig(result, null); } } return undefined; } static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.0", ngImport: i0, type: MatIconRegistry, deps: [{ token: i1.HttpClient, optional: true }, { token: i2.DomSanitizer }, { token: DOCUMENT, optional: true }, { token: i0.ErrorHandler }], target: i0.ɵɵFactoryTarget.Injectable }); static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.0.0", ngImport: i0, type: MatIconRegistry, providedIn: 'root' }); } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.0", ngImport: i0, type: MatIconRegistry, decorators: [{ type: Injectable, args: [{ providedIn: 'root' }] }], ctorParameters: () => [{ type: i1.HttpClient, decorators: [{ type: Optional }] }, { type: i2.DomSanitizer }, { type: undefined, decorators: [{ type: Optional }, { type: Inject, args: [DOCUMENT] }] }, { type: i0.ErrorHandler }] }); function cloneSvg(svg) { return svg.cloneNode(true); } function iconKey(namespace, name) { return namespace + ':' + name; } function isSafeUrlWithOptions(value) { return !!(value.url && value.options); } export { MatIconRegistry, getMatIconFailedToSanitizeLiteralError, getMatIconFailedToSanitizeUrlError, getMatIconNameNotFoundError, getMatIconNoHttpProviderError }; //# sourceMappingURL=_icon-registry-chunk.mjs.map