@limetech/lime-elements
Version:
74 lines (73 loc) • 2.38 kB
JavaScript
export class InMemoryIconCache {
constructor() {
/*
* Cache of all loaded SVGs
*/
this.cache = {};
/*
* Contains resolve functions for all unresolved promises that are waiting for SVG data.
*/
this.resolveFunctions = {};
}
/**
* Get icon data from the cache
*
* @param name - Name of the icon
* @param path - Path on the server where the assets are located
* @returns SVG markup
*/
async get(name, path = '') {
if (!this.cache[name]) {
this.cache[name] = await this.getIcon(name, path);
}
return this.cache[name];
}
/*
* Creates and returns a promise that will be resolved when SVG data is available
*/
getIcon(name, path) {
return new Promise((resolve) => {
if (!this.resolveFunctions[name]) {
this.resolveFunctions[name] = [];
this.fetchData(name, path);
}
this.resolveFunctions[name].push(resolve);
});
}
/*
* Fetch SVG data from the server
*/
async fetchData(name, path) {
let iconPath = path || '';
if (path && !path.endsWith('/')) {
iconPath = `${path}/`;
}
const response = await fetch(`${iconPath}assets/icons/${name}.svg`);
let svgData = await response.text();
// Some of the icons in the Icons8 library have hard coded black color on some of the paths.
// In order to apply coloring with CSS, these have to be set to 'currentColor'
svgData = svgData.replaceAll('#000000', 'currentColor');
if (!this.validSvg(svgData)) {
throw new Error('Invalid SVG');
}
this.resolvePromises(name, svgData);
}
/*
* Check if the given data is a valid SVG document
*/
validSvg(data) {
const parser = new DOMParser();
const svgDoc = parser.parseFromString(data, 'image/svg+xml');
return svgDoc.documentElement.tagName.toLowerCase() === 'svg';
}
/*
* Resolve all promises waiting for data for a specific icon
*/
resolvePromises(name, svgData) {
const resolves = this.resolveFunctions[name];
for (const resolve of resolves) {
resolve(svgData);
}
this.resolveFunctions[name] = null;
}
}