123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281 |
- import { DOCUMENT } from '@angular/common';
- import { HttpClient } from '@angular/common/http';
- import { Inject, Injectable, InjectionToken, Optional, SecurityContext } from '@angular/core';
- import { of, Observable, Subject } from 'rxjs';
- import { catchError, filter, finalize, map, share, take, tap } from 'rxjs/operators';
- import { cloneSVG, getIconDefinitionFromAbbr, getNameAndNamespace, getSecondaryColor, hasNamespace, isIconDefinition, replaceFillColor, warn, withSuffix, withSuffixAndColor } from '../utils';
- import { DynamicLoadingTimeoutError, HttpModuleNotImport, IconNotFoundError, NameSpaceIsNotSpecifyError, SVGTagNotFoundError, UrlNotSafeError } from './icon.error';
- import * as i0 from "@angular/core";
- import * as i1 from "@angular/common/http";
- import * as i2 from "@angular/platform-browser";
- const JSONP_HANDLER_NAME = '__ant_icon_load';
- export const ANT_ICONS = new InjectionToken('ant_icons');
- class IconService {
- set twoToneColor({ primaryColor, secondaryColor }) {
- this._twoToneColorPalette.primaryColor = primaryColor;
- this._twoToneColorPalette.secondaryColor =
- secondaryColor || getSecondaryColor(primaryColor);
- }
- get twoToneColor() {
-
- return { ...this._twoToneColorPalette };
- }
-
- get _disableDynamicLoading() {
- return false;
- }
- constructor(_rendererFactory, _handler, _document, sanitizer, _antIcons) {
- this._rendererFactory = _rendererFactory;
- this._handler = _handler;
- this._document = _document;
- this.sanitizer = sanitizer;
- this._antIcons = _antIcons;
- this.defaultTheme = 'outline';
-
- this._svgDefinitions = new Map();
-
- this._svgRenderedDefinitions = new Map();
- this._inProgressFetches = new Map();
-
- this._assetsUrlRoot = '';
- this._twoToneColorPalette = {
- primaryColor: '#333333',
- secondaryColor: '#E6E6E6'
- };
-
- this._enableJsonpLoading = false;
- this._jsonpIconLoad$ = new Subject();
- this._renderer = this._rendererFactory.createRenderer(null, null);
- if (this._handler) {
- this._http = new HttpClient(this._handler);
- }
- if (this._antIcons) {
- this.addIcon(...this._antIcons);
- }
- }
-
- useJsonpLoading() {
- if (!this._enableJsonpLoading) {
- this._enableJsonpLoading = true;
- window[JSONP_HANDLER_NAME] = (icon) => {
- this._jsonpIconLoad$.next(icon);
- };
- }
- else {
- warn('You are already using jsonp loading.');
- }
- }
-
- changeAssetsSource(prefix) {
- this._assetsUrlRoot = prefix.endsWith('/') ? prefix : prefix + '/';
- }
-
- addIcon(...icons) {
- icons.forEach(icon => {
- this._svgDefinitions.set(withSuffix(icon.name, icon.theme), icon);
- });
- }
-
- addIconLiteral(type, literal) {
- const [_, namespace] = getNameAndNamespace(type);
- if (!namespace) {
- throw NameSpaceIsNotSpecifyError();
- }
- this.addIcon({ name: type, icon: literal });
- }
-
- clear() {
- this._svgDefinitions.clear();
- this._svgRenderedDefinitions.clear();
- }
-
- getRenderedContent(icon, twoToneColor) {
-
- const definition = isIconDefinition(icon)
- ? icon
- : this._svgDefinitions.get(icon) || null;
- if (!definition && this._disableDynamicLoading) {
- throw IconNotFoundError(icon);
- }
-
-
- const $iconDefinition = definition
- ? of(definition)
- : this._loadIconDynamically(icon);
-
- return $iconDefinition.pipe(map(i => {
- if (!i) {
- throw IconNotFoundError(icon);
- }
- return this._loadSVGFromCacheOrCreateNew(i, twoToneColor);
- }));
- }
- getCachedIcons() {
- return this._svgDefinitions;
- }
-
- _loadIconDynamically(type) {
-
- if (!this._http && !this._enableJsonpLoading) {
- return of(HttpModuleNotImport());
- }
-
-
- let inProgress = this._inProgressFetches.get(type);
- if (!inProgress) {
- const [name, namespace] = getNameAndNamespace(type);
-
- const icon = namespace
- ? { name: type, icon: '' }
- : getIconDefinitionFromAbbr(name);
- const suffix = this._enableJsonpLoading ? '.js' : '.svg';
- const url = (namespace
- ? `${this._assetsUrlRoot}assets/${namespace}/${name}`
- : `${this._assetsUrlRoot}assets/${icon.theme}/${icon.name}`) + suffix;
- const safeUrl = this.sanitizer.sanitize(SecurityContext.URL, url);
- if (!safeUrl) {
- throw UrlNotSafeError(url);
- }
- const source = !this._enableJsonpLoading
- ? this._http
- .get(safeUrl, { responseType: 'text' })
- .pipe(map(literal => ({ ...icon, icon: literal })))
- : this._loadIconDynamicallyWithJsonp(icon, safeUrl);
- inProgress = source.pipe(tap(definition => this.addIcon(definition)), finalize(() => this._inProgressFetches.delete(type)), catchError(() => of(null)), share());
- this._inProgressFetches.set(type, inProgress);
- }
- return inProgress;
- }
- _loadIconDynamicallyWithJsonp(icon, url) {
- return new Observable(subscriber => {
- const loader = this._document.createElement('script');
- const timer = setTimeout(() => {
- clean();
- subscriber.error(DynamicLoadingTimeoutError());
- }, 6000);
- loader.src = url;
- function clean() {
- loader.parentNode.removeChild(loader);
- clearTimeout(timer);
- }
- this._document.body.appendChild(loader);
- this._jsonpIconLoad$
- .pipe(filter(i => i.name === icon.name && i.theme === icon.theme), take(1))
- .subscribe(i => {
- subscriber.next(i);
- clean();
- });
- });
- }
-
- _loadSVGFromCacheOrCreateNew(icon, twoToneColor) {
- let svg;
- const pri = twoToneColor || this._twoToneColorPalette.primaryColor;
- const sec = getSecondaryColor(pri) || this._twoToneColorPalette.secondaryColor;
- const key = icon.theme === 'twotone'
- ? withSuffixAndColor(icon.name, icon.theme, pri, sec)
- : icon.theme === undefined
- ? icon.name
- : withSuffix(icon.name, icon.theme);
-
- const cached = this._svgRenderedDefinitions.get(key);
- if (cached) {
- svg = cached.icon;
- }
- else {
- svg = this._setSVGAttribute(this._colorizeSVGIcon(
-
- this._createSVGElementFromString(hasNamespace(icon.name) ? icon.icon : replaceFillColor(icon.icon)), icon.theme === 'twotone', pri, sec));
-
- this._svgRenderedDefinitions.set(key, {
- ...icon,
- icon: svg
- });
- }
- return cloneSVG(svg);
- }
- _createSVGElementFromString(str) {
- const div = this._document.createElement('div');
- div.innerHTML = str;
- const svg = div.querySelector('svg');
- if (!svg) {
- throw SVGTagNotFoundError;
- }
- return svg;
- }
- _setSVGAttribute(svg) {
- this._renderer.setAttribute(svg, 'width', '1em');
- this._renderer.setAttribute(svg, 'height', '1em');
- return svg;
- }
- _colorizeSVGIcon(svg, twotone, pri, sec) {
- if (twotone) {
- const children = svg.childNodes;
- const length = children.length;
- for (let i = 0; i < length; i++) {
- const child = children[i];
- if (child.getAttribute('fill') === 'secondaryColor') {
- this._renderer.setAttribute(child, 'fill', sec);
- }
- else {
- this._renderer.setAttribute(child, 'fill', pri);
- }
- }
- }
- this._renderer.setAttribute(svg, 'fill', 'currentColor');
- return svg;
- }
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.0.2", ngImport: i0, type: IconService, deps: [{ token: i0.RendererFactory2 }, { token: i1.HttpBackend, optional: true }, { token: DOCUMENT, optional: true }, { token: i2.DomSanitizer }, { token: ANT_ICONS, optional: true }], target: i0.ɵɵFactoryTarget.Injectable }); }
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "16.0.2", ngImport: i0, type: IconService }); }
- }
- export { IconService };
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.0.2", ngImport: i0, type: IconService, decorators: [{
- type: Injectable
- }], ctorParameters: function () { return [{ type: i0.RendererFactory2 }, { type: i1.HttpBackend, decorators: [{
- type: Optional
- }] }, { type: undefined, decorators: [{
- type: Optional
- }, {
- type: Inject,
- args: [DOCUMENT]
- }] }, { type: i2.DomSanitizer }, { type: undefined, decorators: [{
- type: Optional
- }, {
- type: Inject,
- args: [ANT_ICONS]
- }] }]; } });
|