mirror of
https://github.com/iconify/iconify.git
synced 2025-01-06 07:20:40 +00:00
Implement icon providers (similar to namespaces)
This commit is contained in:
parent
0956dc7f9a
commit
2aad697264
@ -2,14 +2,14 @@ import mocha from 'mocha';
|
||||
import chai from 'chai';
|
||||
import { FakeData, setFakeData, prepareQuery, sendQuery } from './fake-api';
|
||||
import { API } from '@iconify/core/lib/api/';
|
||||
import { setAPIModule } from '@iconify/core/lib/api/modules';
|
||||
import { setDefaultAPIModule } from '@iconify/core/lib/api/modules';
|
||||
import { setAPIConfig } from '@iconify/core/lib/api/config';
|
||||
import { coreModules } from '@iconify/core/lib/modules';
|
||||
|
||||
const expect = chai.expect;
|
||||
|
||||
// Set API
|
||||
setAPIModule({
|
||||
setDefaultAPIModule({
|
||||
prepare: prepareQuery,
|
||||
send: sendQuery,
|
||||
});
|
||||
@ -21,7 +21,8 @@ function nextPrefix(): string {
|
||||
}
|
||||
|
||||
describe('Testing fake API', () => {
|
||||
it('Loading results', done => {
|
||||
it('Loading results', (done) => {
|
||||
const provider = nextPrefix();
|
||||
const prefix = nextPrefix();
|
||||
const data: FakeData = {
|
||||
icons: ['icon1', 'icon2'],
|
||||
@ -41,24 +42,26 @@ describe('Testing fake API', () => {
|
||||
height: 24,
|
||||
},
|
||||
};
|
||||
setAPIConfig(
|
||||
{
|
||||
resources: ['https://api1.local', 'https://api2.local'],
|
||||
},
|
||||
prefix
|
||||
);
|
||||
setFakeData(prefix, data);
|
||||
setAPIConfig(provider, {
|
||||
resources: ['https://api1.local', 'https://api2.local'],
|
||||
});
|
||||
setFakeData(provider, prefix, data);
|
||||
|
||||
// Attempt to load icons
|
||||
API.loadIcons(
|
||||
[prefix + ':icon1', prefix + ':icon2'],
|
||||
[
|
||||
provider + ':' + prefix + ':icon1',
|
||||
provider + ':' + prefix + ':icon2',
|
||||
],
|
||||
(loaded, missing, pending) => {
|
||||
expect(loaded).to.be.eql([
|
||||
{
|
||||
provider,
|
||||
prefix,
|
||||
name: 'icon1',
|
||||
},
|
||||
{
|
||||
provider,
|
||||
prefix,
|
||||
name: 'icon2',
|
||||
},
|
||||
@ -68,7 +71,8 @@ describe('Testing fake API', () => {
|
||||
);
|
||||
});
|
||||
|
||||
it('Loading results with delay', done => {
|
||||
it('Loading results with delay', (done) => {
|
||||
const provider = nextPrefix();
|
||||
const prefix = nextPrefix();
|
||||
const data: FakeData = {
|
||||
icons: ['icon1', 'icon2'],
|
||||
@ -89,23 +93,22 @@ describe('Testing fake API', () => {
|
||||
height: 24,
|
||||
},
|
||||
};
|
||||
setAPIConfig(
|
||||
{
|
||||
resources: ['https://api1.local', 'https://api2.local'],
|
||||
},
|
||||
prefix
|
||||
);
|
||||
setFakeData(prefix, data);
|
||||
setAPIConfig(provider, {
|
||||
resources: ['https://api1.local', 'https://api2.local'],
|
||||
});
|
||||
setFakeData(provider, prefix, data);
|
||||
|
||||
// Attempt to load icons
|
||||
const start = Date.now();
|
||||
API.loadIcons(
|
||||
[
|
||||
{
|
||||
provider,
|
||||
prefix,
|
||||
name: 'icon1',
|
||||
},
|
||||
{
|
||||
provider,
|
||||
prefix,
|
||||
name: 'icon2',
|
||||
},
|
||||
@ -113,10 +116,12 @@ describe('Testing fake API', () => {
|
||||
(loaded, missing, pending) => {
|
||||
expect(loaded).to.be.eql([
|
||||
{
|
||||
provider,
|
||||
prefix,
|
||||
name: 'icon1',
|
||||
},
|
||||
{
|
||||
provider,
|
||||
prefix,
|
||||
name: 'icon2',
|
||||
},
|
||||
@ -129,7 +134,8 @@ describe('Testing fake API', () => {
|
||||
);
|
||||
});
|
||||
|
||||
it('Loading partial results', done => {
|
||||
it('Loading partial results', (done) => {
|
||||
const provider = nextPrefix();
|
||||
const prefix = nextPrefix();
|
||||
const data: FakeData = {
|
||||
icons: ['icon1'],
|
||||
@ -146,21 +152,21 @@ describe('Testing fake API', () => {
|
||||
height: 24,
|
||||
},
|
||||
};
|
||||
setAPIConfig(
|
||||
{
|
||||
resources: ['https://api1.local', 'https://api2.local'],
|
||||
rotate: 20,
|
||||
timeout: 100,
|
||||
limit: 1,
|
||||
},
|
||||
prefix
|
||||
);
|
||||
setFakeData(prefix, data);
|
||||
setAPIConfig(provider, {
|
||||
resources: ['https://api1.local', 'https://api2.local'],
|
||||
rotate: 20,
|
||||
timeout: 100,
|
||||
limit: 1,
|
||||
});
|
||||
setFakeData(provider, prefix, data);
|
||||
|
||||
// Attempt to load icons
|
||||
let counter = 0;
|
||||
API.loadIcons(
|
||||
[prefix + ':icon1', prefix + ':icon2'],
|
||||
[
|
||||
provider + ':' + prefix + ':icon1',
|
||||
provider + ':' + prefix + ':icon2',
|
||||
],
|
||||
(loaded, missing, pending) => {
|
||||
try {
|
||||
counter++;
|
||||
@ -169,12 +175,14 @@ describe('Testing fake API', () => {
|
||||
// Loaded icon1
|
||||
expect(loaded).to.be.eql([
|
||||
{
|
||||
provider,
|
||||
prefix,
|
||||
name: 'icon1',
|
||||
},
|
||||
]);
|
||||
expect(pending).to.be.eql([
|
||||
{
|
||||
provider,
|
||||
prefix,
|
||||
name: 'icon2',
|
||||
},
|
||||
|
@ -46,6 +46,7 @@ describe('Testing legacy finder', () => {
|
||||
// Test all icons
|
||||
testIcon(
|
||||
{
|
||||
provider: '',
|
||||
prefix: 'mdi',
|
||||
name: 'home',
|
||||
},
|
||||
@ -54,6 +55,7 @@ describe('Testing legacy finder', () => {
|
||||
|
||||
testIcon(
|
||||
{
|
||||
provider: '',
|
||||
prefix: 'mdi',
|
||||
name: 'account',
|
||||
},
|
||||
@ -62,6 +64,7 @@ describe('Testing legacy finder', () => {
|
||||
|
||||
testIcon(
|
||||
{
|
||||
provider: '',
|
||||
prefix: 'ic',
|
||||
name: 'baseline-account',
|
||||
},
|
||||
|
@ -46,6 +46,7 @@ describe('Testing finder', () => {
|
||||
// Test all icons
|
||||
testIcon(
|
||||
{
|
||||
provider: '',
|
||||
prefix: 'mdi',
|
||||
name: 'home',
|
||||
},
|
||||
@ -54,6 +55,7 @@ describe('Testing finder', () => {
|
||||
|
||||
testIcon(
|
||||
{
|
||||
provider: '',
|
||||
prefix: 'mdi',
|
||||
name: 'account',
|
||||
},
|
||||
@ -62,6 +64,7 @@ describe('Testing finder', () => {
|
||||
|
||||
testIcon(
|
||||
{
|
||||
provider: '',
|
||||
prefix: 'ic',
|
||||
name: 'baseline-account',
|
||||
},
|
||||
|
@ -18,7 +18,7 @@ addFinder(iconifyFinder);
|
||||
|
||||
describe('Testing legacy renderer', () => {
|
||||
// Add mentioned icons to storage
|
||||
const storage = getStorage('mdi');
|
||||
const storage = getStorage('', 'mdi');
|
||||
addIconSet(storage, {
|
||||
prefix: 'mdi',
|
||||
icons: {
|
||||
@ -82,6 +82,7 @@ describe('Testing legacy renderer', () => {
|
||||
|
||||
// Test element
|
||||
expect(element.name).to.be.eql({
|
||||
provider: '',
|
||||
prefix: 'mdi',
|
||||
name: 'account-cash',
|
||||
});
|
||||
@ -124,6 +125,7 @@ describe('Testing legacy renderer', () => {
|
||||
|
||||
// Test element
|
||||
expect(element.name).to.be.eql({
|
||||
provider: '',
|
||||
prefix: 'mdi',
|
||||
name: 'account',
|
||||
});
|
||||
@ -167,6 +169,7 @@ describe('Testing legacy renderer', () => {
|
||||
|
||||
// Test element
|
||||
expect(element.name).to.be.eql({
|
||||
provider: '',
|
||||
prefix: 'mdi',
|
||||
name: 'account-box',
|
||||
});
|
||||
@ -214,6 +217,7 @@ describe('Testing legacy renderer', () => {
|
||||
|
||||
// Test element
|
||||
expect(element.name).to.be.eql({
|
||||
provider: '',
|
||||
prefix: 'mdi',
|
||||
name: 'home',
|
||||
});
|
||||
@ -255,6 +259,7 @@ describe('Testing legacy renderer', () => {
|
||||
|
||||
// Test element
|
||||
expect(element.name).to.be.eql({
|
||||
provider: '',
|
||||
prefix: 'mdi',
|
||||
name: 'home',
|
||||
});
|
||||
@ -299,6 +304,7 @@ describe('Testing legacy renderer', () => {
|
||||
|
||||
// Test element
|
||||
expect(element.name).to.be.eql({
|
||||
provider: '',
|
||||
prefix: 'mdi',
|
||||
name: 'account',
|
||||
});
|
||||
@ -372,6 +378,7 @@ describe('Testing legacy renderer', () => {
|
||||
|
||||
// Test element
|
||||
expect(element.name).to.be.eql({
|
||||
provider: '',
|
||||
prefix: 'mdi',
|
||||
name: 'home',
|
||||
});
|
||||
@ -537,6 +544,7 @@ describe('Testing legacy renderer', () => {
|
||||
expect(element).to.not.be.eql(lastElement); // different 'element' and 'name' properties
|
||||
expect(element.name).to.not.be.eql(lastElement.name);
|
||||
expect(element.name).to.be.eql({
|
||||
provider: '',
|
||||
prefix: 'mdi',
|
||||
name: 'account',
|
||||
});
|
||||
@ -582,6 +590,7 @@ describe('Testing legacy renderer', () => {
|
||||
|
||||
// Test element
|
||||
expect(element.name).to.be.eql({
|
||||
provider: '',
|
||||
prefix: 'mdi',
|
||||
name: 'home',
|
||||
});
|
||||
@ -630,6 +639,7 @@ describe('Testing legacy renderer', () => {
|
||||
|
||||
// Test element
|
||||
expect(element.name).to.be.eql({
|
||||
provider: '',
|
||||
prefix: 'mdi',
|
||||
name: 'home',
|
||||
});
|
||||
@ -676,6 +686,7 @@ describe('Testing legacy renderer', () => {
|
||||
|
||||
// Test element
|
||||
expect(element.name).to.be.eql({
|
||||
provider: '',
|
||||
prefix: 'mdi',
|
||||
name: 'home',
|
||||
});
|
||||
@ -764,6 +775,7 @@ describe('Testing legacy renderer', () => {
|
||||
|
||||
// Test element
|
||||
expect(element.name).to.be.eql({
|
||||
provider: '',
|
||||
prefix: 'mdi',
|
||||
name: 'home',
|
||||
});
|
||||
@ -861,6 +873,7 @@ describe('Testing legacy renderer', () => {
|
||||
|
||||
// Test element
|
||||
expect(element.name).to.be.eql({
|
||||
provider: '',
|
||||
prefix: 'mdi',
|
||||
name: 'home',
|
||||
});
|
||||
@ -946,6 +959,7 @@ describe('Testing legacy renderer', () => {
|
||||
|
||||
// Test element
|
||||
expect(element.name).to.be.eql({
|
||||
provider: '',
|
||||
prefix: 'mdi',
|
||||
name: 'home',
|
||||
});
|
||||
|
@ -18,7 +18,7 @@ addFinder(iconifyFinder);
|
||||
|
||||
describe('Testing renderer', () => {
|
||||
// Add mentioned icons to storage
|
||||
const storage = getStorage('mdi');
|
||||
const storage = getStorage('', 'mdi');
|
||||
addIconSet(storage, {
|
||||
prefix: 'mdi',
|
||||
icons: {
|
||||
@ -82,6 +82,7 @@ describe('Testing renderer', () => {
|
||||
|
||||
// Test element
|
||||
expect(element.name).to.be.eql({
|
||||
provider: '',
|
||||
prefix: 'mdi',
|
||||
name: 'account-cash',
|
||||
});
|
||||
@ -124,6 +125,7 @@ describe('Testing renderer', () => {
|
||||
|
||||
// Test element
|
||||
expect(element.name).to.be.eql({
|
||||
provider: '',
|
||||
prefix: 'mdi',
|
||||
name: 'account',
|
||||
});
|
||||
@ -167,6 +169,7 @@ describe('Testing renderer', () => {
|
||||
|
||||
// Test element
|
||||
expect(element.name).to.be.eql({
|
||||
provider: '',
|
||||
prefix: 'mdi',
|
||||
name: 'account-box',
|
||||
});
|
||||
@ -214,6 +217,7 @@ describe('Testing renderer', () => {
|
||||
|
||||
// Test element
|
||||
expect(element.name).to.be.eql({
|
||||
provider: '',
|
||||
prefix: 'mdi',
|
||||
name: 'home',
|
||||
});
|
||||
@ -255,6 +259,7 @@ describe('Testing renderer', () => {
|
||||
|
||||
// Test element
|
||||
expect(element.name).to.be.eql({
|
||||
provider: '',
|
||||
prefix: 'mdi',
|
||||
name: 'home',
|
||||
});
|
||||
@ -301,6 +306,7 @@ describe('Testing renderer', () => {
|
||||
|
||||
// Test element
|
||||
expect(element.name).to.be.eql({
|
||||
provider: '',
|
||||
prefix: 'mdi',
|
||||
name: 'account',
|
||||
});
|
||||
@ -374,6 +380,7 @@ describe('Testing renderer', () => {
|
||||
|
||||
// Test element
|
||||
expect(element.name).to.be.eql({
|
||||
provider: '',
|
||||
prefix: 'mdi',
|
||||
name: 'home',
|
||||
});
|
||||
@ -541,6 +548,7 @@ describe('Testing renderer', () => {
|
||||
expect(element).to.not.be.eql(lastElement); // different 'element' and 'name' properties
|
||||
expect(element.name).to.not.be.eql(lastElement.name);
|
||||
expect(element.name).to.be.eql({
|
||||
provider: '',
|
||||
prefix: 'mdi',
|
||||
name: 'account',
|
||||
});
|
||||
@ -586,6 +594,7 @@ describe('Testing renderer', () => {
|
||||
|
||||
// Test element
|
||||
expect(element.name).to.be.eql({
|
||||
provider: '',
|
||||
prefix: 'mdi',
|
||||
name: 'home',
|
||||
});
|
||||
@ -634,6 +643,7 @@ describe('Testing renderer', () => {
|
||||
|
||||
// Test element
|
||||
expect(element.name).to.be.eql({
|
||||
provider: '',
|
||||
prefix: 'mdi',
|
||||
name: 'home',
|
||||
});
|
||||
@ -680,6 +690,7 @@ describe('Testing renderer', () => {
|
||||
|
||||
// Test element
|
||||
expect(element.name).to.be.eql({
|
||||
provider: '',
|
||||
prefix: 'mdi',
|
||||
name: 'home',
|
||||
});
|
||||
@ -768,6 +779,7 @@ describe('Testing renderer', () => {
|
||||
|
||||
// Test element
|
||||
expect(element.name).to.be.eql({
|
||||
provider: '',
|
||||
prefix: 'mdi',
|
||||
name: 'home',
|
||||
});
|
||||
@ -865,6 +877,7 @@ describe('Testing renderer', () => {
|
||||
|
||||
// Test element
|
||||
expect(element.name).to.be.eql({
|
||||
provider: '',
|
||||
prefix: 'mdi',
|
||||
name: 'home',
|
||||
});
|
||||
@ -950,6 +963,7 @@ describe('Testing renderer', () => {
|
||||
|
||||
// Test element
|
||||
expect(element.name).to.be.eql({
|
||||
provider: '',
|
||||
prefix: 'mdi',
|
||||
name: 'home',
|
||||
});
|
||||
|
@ -17,7 +17,7 @@ addFinder(iconifyIconFinder);
|
||||
|
||||
describe('Scanning DOM', () => {
|
||||
// Add mentioned icons to storage
|
||||
const storage = getStorage('mdi');
|
||||
const storage = getStorage('', 'mdi');
|
||||
addIconSet(storage, {
|
||||
prefix: 'mdi',
|
||||
icons: {
|
||||
|
@ -5,7 +5,7 @@ import { getNode } from './node';
|
||||
import { addFinder } from '@iconify/iconify/lib/finder';
|
||||
import { FakeData, setFakeData, prepareQuery, sendQuery } from './fake-api';
|
||||
import { API } from '@iconify/core/lib/api/';
|
||||
import { setAPIModule } from '@iconify/core/lib/api/modules';
|
||||
import { setDefaultAPIModule } from '@iconify/core/lib/api/modules';
|
||||
import { setAPIConfig } from '@iconify/core/lib/api/config';
|
||||
import { coreModules } from '@iconify/core/lib/modules';
|
||||
import { finder as iconifyFinder } from '@iconify/iconify/lib/finders/iconify';
|
||||
@ -20,7 +20,7 @@ addFinder(iconifyFinder);
|
||||
addFinder(iconifyIconFinder);
|
||||
|
||||
// Set API
|
||||
setAPIModule({
|
||||
setDefaultAPIModule({
|
||||
prepare: prepareQuery,
|
||||
send: sendQuery,
|
||||
});
|
||||
@ -33,16 +33,14 @@ function nextPrefix(): string {
|
||||
|
||||
describe('Scanning DOM with API', () => {
|
||||
it('Scan DOM with API', (done) => {
|
||||
const provider = nextPrefix();
|
||||
const prefix1 = nextPrefix();
|
||||
const prefix2 = nextPrefix();
|
||||
|
||||
// Set fake API hosts to make test reliable
|
||||
setAPIConfig(
|
||||
{
|
||||
resources: ['https://api1.local', 'https://api2.local'],
|
||||
},
|
||||
[prefix1, prefix2]
|
||||
);
|
||||
setAPIConfig(provider, {
|
||||
resources: ['https://api1.local', 'https://api2.local'],
|
||||
});
|
||||
|
||||
// Set icons, load them with various delay
|
||||
const data1: FakeData = {
|
||||
@ -64,7 +62,7 @@ describe('Scanning DOM with API', () => {
|
||||
height: 24,
|
||||
},
|
||||
};
|
||||
setFakeData(prefix1, data1);
|
||||
setFakeData(provider, prefix1, data1);
|
||||
|
||||
const data2: FakeData = {
|
||||
icons: ['account', 'account-box'],
|
||||
@ -85,24 +83,32 @@ describe('Scanning DOM with API', () => {
|
||||
height: 24,
|
||||
},
|
||||
};
|
||||
setFakeData(prefix2, data2);
|
||||
setFakeData(provider, prefix2, data2);
|
||||
|
||||
const node = getNode('scan-dom');
|
||||
node.innerHTML =
|
||||
'<div><p>Testing scanning DOM with API</p><ul>' +
|
||||
'<li>Inline icons:' +
|
||||
' <span class="iconify iconify-inline" data-icon="' +
|
||||
' <span class="iconify iconify-inline" data-icon="@' +
|
||||
provider +
|
||||
':' +
|
||||
prefix1 +
|
||||
':home" style="color: red; box-shadow: 0 0 2px black;"></span>' +
|
||||
' <i class="iconify-inline test-icon iconify--mdi-account" data-icon="' +
|
||||
' <i class="iconify-inline test-icon iconify--mdi-account" data-icon="@' +
|
||||
provider +
|
||||
':' +
|
||||
prefix2 +
|
||||
':account" style="vertical-align: 0;" data-flip="horizontal" aria-hidden="false"></i>' +
|
||||
'</li>' +
|
||||
'<li>Block icons:' +
|
||||
' <iconify-icon data-icon="' +
|
||||
' <iconify-icon data-icon="@' +
|
||||
provider +
|
||||
':' +
|
||||
prefix1 +
|
||||
':account-cash" title="<Cash>!"></iconify-icon>' +
|
||||
' <i class="iconify-icon" data-icon="' +
|
||||
' <i class="iconify-icon" data-icon="@' +
|
||||
provider +
|
||||
':' +
|
||||
prefix2 +
|
||||
':account-box" data-inline="true" data-rotate="2" data-width="42"></i>' +
|
||||
'</li>' +
|
||||
@ -133,16 +139,14 @@ describe('Scanning DOM with API', () => {
|
||||
});
|
||||
|
||||
it('Changing icon name before it loaded', (done) => {
|
||||
const provider = nextPrefix();
|
||||
const prefix1 = nextPrefix();
|
||||
const prefix2 = nextPrefix();
|
||||
|
||||
// Set fake API hosts to make test reliable
|
||||
setAPIConfig(
|
||||
{
|
||||
resources: ['https://api1.local', 'https://api2.local'],
|
||||
},
|
||||
[prefix1, prefix2]
|
||||
);
|
||||
setAPIConfig(provider, {
|
||||
resources: ['https://api1.local', 'https://api2.local'],
|
||||
});
|
||||
|
||||
// Set icons, load them with various delay
|
||||
const data1: FakeData = {
|
||||
@ -164,7 +168,7 @@ describe('Scanning DOM with API', () => {
|
||||
height: 24,
|
||||
},
|
||||
};
|
||||
setFakeData(prefix1, data1);
|
||||
setFakeData(provider, prefix1, data1);
|
||||
|
||||
const data2: FakeData = {
|
||||
icons: ['account', 'account-box'],
|
||||
@ -185,7 +189,7 @@ describe('Scanning DOM with API', () => {
|
||||
height: 24,
|
||||
},
|
||||
};
|
||||
setFakeData(prefix2, data2);
|
||||
setFakeData(provider, prefix2, data2);
|
||||
|
||||
const data1b: FakeData = {
|
||||
icons: ['account', 'account-box'],
|
||||
@ -206,24 +210,32 @@ describe('Scanning DOM with API', () => {
|
||||
height: 24,
|
||||
},
|
||||
};
|
||||
setFakeData(prefix1, data1b);
|
||||
setFakeData(provider, prefix1, data1b);
|
||||
|
||||
const node = getNode('scan-dom');
|
||||
node.innerHTML =
|
||||
'<div><p>Testing scanning DOM with API: renamed icon</p><ul>' +
|
||||
'<li>Default finder:' +
|
||||
' <span class="iconify-inline first-icon" data-icon="' +
|
||||
' <span class="iconify-inline first-icon" data-icon="@' +
|
||||
provider +
|
||||
':' +
|
||||
prefix1 +
|
||||
':home" style="color: red; box-shadow: 0 0 2px black;"></span>' +
|
||||
' <i class="iconify-inline second-icon iconify--mdi-account" data-icon="' +
|
||||
' <i class="iconify-inline second-icon iconify--mdi-account" data-icon="@' +
|
||||
provider +
|
||||
':' +
|
||||
prefix2 +
|
||||
':account" style="vertical-align: 0;" data-flip="horizontal" aria-hidden="false"></i>' +
|
||||
'</li>' +
|
||||
'<li>IconifyIcon finder:' +
|
||||
' <iconify-icon class="third-icon" data-icon="' +
|
||||
' <iconify-icon class="third-icon" data-icon="@' +
|
||||
provider +
|
||||
':' +
|
||||
prefix1 +
|
||||
':account-cash" title="<Cash>!"></iconify-icon>' +
|
||||
' <iconify-icon class="fourth-icon" data-icon="' +
|
||||
' <iconify-icon class="fourth-icon" data-icon="@' +
|
||||
provider +
|
||||
':' +
|
||||
prefix2 +
|
||||
':account-box" data-inline="true" data-rotate="2" data-width="42"></iconify-icon>' +
|
||||
'</li>' +
|
||||
@ -244,7 +256,10 @@ describe('Scanning DOM with API', () => {
|
||||
const icon = node.querySelector('iconify-icon[title]');
|
||||
expect(icon).to.not.be.equal(null);
|
||||
expect(icon.getAttribute('class')).to.be.equal('third-icon');
|
||||
icon.setAttribute('data-icon', prefix1 + ':account');
|
||||
icon.setAttribute(
|
||||
'data-icon',
|
||||
'@' + provider + ':' + prefix1 + ':account'
|
||||
);
|
||||
|
||||
// First API response should have loaded, but only 1 icon should have been rendered
|
||||
setTimeout(() => {
|
||||
@ -273,16 +288,14 @@ describe('Scanning DOM with API', () => {
|
||||
});
|
||||
|
||||
it('Changing icon name before it loaded to invalid name', (done) => {
|
||||
const provider = nextPrefix();
|
||||
const prefix1 = nextPrefix();
|
||||
const prefix2 = nextPrefix();
|
||||
|
||||
// Set fake API hosts to make test reliable
|
||||
setAPIConfig(
|
||||
{
|
||||
resources: ['https://api1.local', 'https://api2.local'],
|
||||
},
|
||||
[prefix1, prefix2]
|
||||
);
|
||||
setAPIConfig(provider, {
|
||||
resources: ['https://api1.local', 'https://api2.local'],
|
||||
});
|
||||
|
||||
// Set icons, load them with various delay
|
||||
const data1: FakeData = {
|
||||
@ -304,7 +317,7 @@ describe('Scanning DOM with API', () => {
|
||||
height: 24,
|
||||
},
|
||||
};
|
||||
setFakeData(prefix1, data1);
|
||||
setFakeData(provider, prefix1, data1);
|
||||
|
||||
const data2: FakeData = {
|
||||
icons: ['account', 'account-box'],
|
||||
@ -325,24 +338,32 @@ describe('Scanning DOM with API', () => {
|
||||
height: 24,
|
||||
},
|
||||
};
|
||||
setFakeData(prefix2, data2);
|
||||
setFakeData(provider, prefix2, data2);
|
||||
|
||||
const node = getNode('scan-dom');
|
||||
node.innerHTML =
|
||||
'<div><p>Testing scanning DOM with API: invalid name</p><ul>' +
|
||||
'<li>Inline icons:' +
|
||||
' <span class="iconify" data-icon="' +
|
||||
' <span class="iconify" data-icon="@' +
|
||||
provider +
|
||||
':' +
|
||||
prefix1 +
|
||||
':home" style="color: red; box-shadow: 0 0 2px black;"></span>' +
|
||||
' <i class="iconify test-icon iconify--mdi-account" data-icon="' +
|
||||
' <i class="iconify test-icon iconify--mdi-account" data-icon="@' +
|
||||
provider +
|
||||
':' +
|
||||
prefix2 +
|
||||
':account" style="vertical-align: 0;" data-flip="horizontal" aria-hidden="false"></i>' +
|
||||
'</li>' +
|
||||
'<li>Block icons:' +
|
||||
' <iconify-icon data-icon="' +
|
||||
' <iconify-icon data-icon="@' +
|
||||
provider +
|
||||
':' +
|
||||
prefix1 +
|
||||
':account-cash" title="<Cash>!"></iconify-icon>' +
|
||||
' <iconify-icon data-icon="' +
|
||||
' <iconify-icon data-icon="@' +
|
||||
provider +
|
||||
':' +
|
||||
prefix2 +
|
||||
':account-box" data-inline="true" data-rotate="2" data-width="42"></iconify-icon>' +
|
||||
'</li>' +
|
||||
@ -355,7 +376,7 @@ describe('Scanning DOM with API', () => {
|
||||
// Change icon name
|
||||
const icon = node.querySelector('iconify-icon[title]');
|
||||
expect(icon).to.not.be.equal(null);
|
||||
icon.setAttribute('data-icon', 'foo');
|
||||
icon.setAttribute('data-icon', '@' + provider + ':foo');
|
||||
|
||||
// First API response should have loaded, but only 1 icon
|
||||
setTimeout(() => {
|
||||
|
@ -19,13 +19,23 @@ export interface FakeData {
|
||||
/**
|
||||
* Fake data storage
|
||||
*/
|
||||
const fakeData: Record<string, FakeData[]> = Object.create(null);
|
||||
const fakeData: Record<string, Record<string, FakeData[]>> = Object.create(
|
||||
null
|
||||
);
|
||||
|
||||
export function setFakeData(prefix: string, item: FakeData): void {
|
||||
if (fakeData[prefix] === void 0) {
|
||||
fakeData[prefix] = [];
|
||||
export function setFakeData(
|
||||
provider: string,
|
||||
prefix: string,
|
||||
item: FakeData
|
||||
): void {
|
||||
if (fakeData[provider] === void 0) {
|
||||
fakeData[provider] = Object.create(null);
|
||||
}
|
||||
fakeData[prefix].push(item);
|
||||
const providerFakeData = fakeData[provider];
|
||||
if (providerFakeData[prefix] === void 0) {
|
||||
providerFakeData[prefix] = [];
|
||||
}
|
||||
providerFakeData[prefix].push(item);
|
||||
}
|
||||
|
||||
interface FakeAPIQueryParams extends APIQueryParams {
|
||||
@ -36,6 +46,7 @@ interface FakeAPIQueryParams extends APIQueryParams {
|
||||
* Prepare params
|
||||
*/
|
||||
export const prepareQuery: IconifyAPIPrepareQuery = (
|
||||
provider: string,
|
||||
prefix: string,
|
||||
icons: string[]
|
||||
): APIQueryParams[] => {
|
||||
@ -43,10 +54,15 @@ export const prepareQuery: IconifyAPIPrepareQuery = (
|
||||
const items: APIQueryParams[] = [];
|
||||
let missing = icons.slice(0);
|
||||
|
||||
if (fakeData[prefix] !== void 0) {
|
||||
fakeData[prefix].forEach(item => {
|
||||
if (fakeData[provider] === void 0) {
|
||||
fakeData[provider] = Object.create(null);
|
||||
}
|
||||
const providerFakeData = fakeData[provider];
|
||||
|
||||
if (providerFakeData[prefix] !== void 0) {
|
||||
providerFakeData[prefix].forEach((item) => {
|
||||
const matches = item.icons.filter(
|
||||
icon => missing.indexOf(icon) !== -1
|
||||
(icon) => missing.indexOf(icon) !== -1
|
||||
);
|
||||
if (!matches.length) {
|
||||
// No match
|
||||
@ -54,8 +70,9 @@ export const prepareQuery: IconifyAPIPrepareQuery = (
|
||||
}
|
||||
|
||||
// Contains at least one matching icon
|
||||
missing = missing.filter(icon => matches.indexOf(icon) === -1);
|
||||
missing = missing.filter((icon) => matches.indexOf(icon) === -1);
|
||||
const query: FakeAPIQueryParams = {
|
||||
provider,
|
||||
prefix,
|
||||
icons: matches,
|
||||
data: item,
|
||||
@ -75,6 +92,7 @@ export const sendQuery: IconifyAPISendQuery = (
|
||||
params: APIQueryParams,
|
||||
status: RedundancyPendingItem
|
||||
): void => {
|
||||
const provider = params.provider;
|
||||
const prefix = params.prefix;
|
||||
const icons = params.icons;
|
||||
|
||||
@ -88,7 +106,13 @@ export const sendQuery: IconifyAPISendQuery = (
|
||||
}
|
||||
|
||||
const sendResponse = () => {
|
||||
console.log('Sending data for prefix "' + prefix + '", icons:', icons);
|
||||
console.log(
|
||||
'Sending data for prefix "' +
|
||||
(provider === '' ? '' : '@' + provider + ':') +
|
||||
prefix +
|
||||
'", icons:',
|
||||
icons
|
||||
);
|
||||
status.done(data.data);
|
||||
};
|
||||
|
||||
|
@ -4,6 +4,7 @@ import {
|
||||
} from '../interfaces/loader';
|
||||
import { getStorage } from '../storage';
|
||||
import { SortedIcons } from '../icon/sort';
|
||||
import { IconifyIconSource } from '../icon/name';
|
||||
|
||||
/**
|
||||
* Storage for callbacks
|
||||
@ -22,49 +23,70 @@ interface CallbackItem {
|
||||
abort: IconifyIconLoaderAbort;
|
||||
}
|
||||
|
||||
// Records sorted by provider and prefix
|
||||
// This export is only for unit testing, should not be used
|
||||
export const callbacks: Record<string, CallbackItem[]> = Object.create(null);
|
||||
const pendingUpdates: Record<string, boolean> = Object.create(null);
|
||||
export const callbacks: Record<
|
||||
string,
|
||||
Record<string, CallbackItem[]>
|
||||
> = Object.create(null);
|
||||
const pendingUpdates: Record<string, Record<string, boolean>> = Object.create(
|
||||
null
|
||||
);
|
||||
|
||||
/**
|
||||
* Remove callback
|
||||
*/
|
||||
function removeCallback(prefixes: string[], id: number): void {
|
||||
prefixes.forEach(prefix => {
|
||||
const items = callbacks[prefix];
|
||||
function removeCallback(sources: IconifyIconSource[], id: number): void {
|
||||
sources.forEach((source) => {
|
||||
const provider = source.provider;
|
||||
if (callbacks[provider] === void 0) {
|
||||
return;
|
||||
}
|
||||
const providerCallbacks = callbacks[provider];
|
||||
|
||||
const prefix = source.prefix;
|
||||
const items = providerCallbacks[prefix];
|
||||
if (items) {
|
||||
callbacks[prefix] = items.filter(row => row.id !== id);
|
||||
providerCallbacks[prefix] = items.filter((row) => row.id !== id);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Update all callbacks for prefix
|
||||
* Update all callbacks for provider and prefix
|
||||
*/
|
||||
export function updateCallbacks(prefix: string): void {
|
||||
if (!pendingUpdates[prefix]) {
|
||||
pendingUpdates[prefix] = true;
|
||||
setTimeout(() => {
|
||||
pendingUpdates[prefix] = false;
|
||||
export function updateCallbacks(provider: string, prefix: string): void {
|
||||
if (pendingUpdates[provider] === void 0) {
|
||||
pendingUpdates[provider] = Object.create(null);
|
||||
}
|
||||
const providerPendingUpdates = pendingUpdates[provider];
|
||||
|
||||
if (callbacks[prefix] === void 0) {
|
||||
if (!providerPendingUpdates[prefix]) {
|
||||
providerPendingUpdates[prefix] = true;
|
||||
setTimeout(() => {
|
||||
providerPendingUpdates[prefix] = false;
|
||||
|
||||
if (
|
||||
callbacks[provider] === void 0 ||
|
||||
callbacks[provider][prefix] === void 0
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Get all items
|
||||
const items = callbacks[prefix].slice(0);
|
||||
const items = callbacks[provider][prefix].slice(0);
|
||||
if (!items.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
const storage = getStorage(prefix);
|
||||
const storage = getStorage(provider, prefix);
|
||||
|
||||
// Check each item for changes
|
||||
let hasPending = false;
|
||||
items.forEach((item: CallbackItem) => {
|
||||
const icons = item.icons;
|
||||
const oldLength = icons.pending.length;
|
||||
icons.pending = icons.pending.filter(icon => {
|
||||
icons.pending = icons.pending.filter((icon) => {
|
||||
if (icon.prefix !== prefix) {
|
||||
// Checking only current prefix
|
||||
return true;
|
||||
@ -74,12 +96,14 @@ export function updateCallbacks(prefix: string): void {
|
||||
if (storage.icons[name] !== void 0) {
|
||||
// Loaded
|
||||
icons.loaded.push({
|
||||
provider,
|
||||
prefix,
|
||||
name,
|
||||
});
|
||||
} else if (storage.missing[name] !== void 0) {
|
||||
// Missing
|
||||
icons.missing.push({
|
||||
provider,
|
||||
prefix,
|
||||
name,
|
||||
});
|
||||
@ -96,7 +120,15 @@ export function updateCallbacks(prefix: string): void {
|
||||
if (icons.pending.length !== oldLength) {
|
||||
if (!hasPending) {
|
||||
// All icons have been loaded - remove callback from prefix
|
||||
removeCallback([prefix], item.id);
|
||||
removeCallback(
|
||||
[
|
||||
{
|
||||
provider,
|
||||
prefix,
|
||||
},
|
||||
],
|
||||
item.id
|
||||
);
|
||||
}
|
||||
item.callback(
|
||||
icons.loaded.slice(0),
|
||||
@ -121,11 +153,11 @@ let idCounter = 0;
|
||||
export function storeCallback(
|
||||
callback: IconifyIconLoaderCallback,
|
||||
icons: SortedIcons,
|
||||
pendingPrefixes: string[]
|
||||
pendingSources: IconifyIconSource[]
|
||||
): IconifyIconLoaderAbort {
|
||||
// Create unique id and abort function
|
||||
const id = idCounter++;
|
||||
const abort = removeCallback.bind(null, pendingPrefixes, id);
|
||||
const abort = removeCallback.bind(null, pendingSources, id);
|
||||
|
||||
if (!icons.pending.length) {
|
||||
// Do not store item without pending icons and return function that does nothing
|
||||
@ -140,11 +172,17 @@ export function storeCallback(
|
||||
abort: abort,
|
||||
};
|
||||
|
||||
pendingPrefixes.forEach(prefix => {
|
||||
if (callbacks[prefix] === void 0) {
|
||||
callbacks[prefix] = [];
|
||||
pendingSources.forEach((source) => {
|
||||
const provider = source.provider;
|
||||
const prefix = source.prefix;
|
||||
if (callbacks[provider] === void 0) {
|
||||
callbacks[provider] = Object.create(null);
|
||||
}
|
||||
callbacks[prefix].push(item);
|
||||
const providerCallbacks = callbacks[provider];
|
||||
if (providerCallbacks[prefix] === void 0) {
|
||||
providerCallbacks[prefix] = [];
|
||||
}
|
||||
providerCallbacks[prefix].push(item);
|
||||
});
|
||||
|
||||
return abort;
|
||||
|
@ -1,5 +1,4 @@
|
||||
import { RedundancyConfig } from '@cyberalien/redundancy';
|
||||
import { merge } from '../misc/merge';
|
||||
|
||||
/**
|
||||
* API config
|
||||
@ -12,17 +11,52 @@ export interface IconifyAPIConfig extends RedundancyConfig {
|
||||
maxURL: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* Local storage interfaces
|
||||
*/
|
||||
interface ConfigStorage {
|
||||
// API configuration for all prefixes
|
||||
default: IconifyAPIConfig;
|
||||
export type PartialIconifyAPIConfig = Partial<IconifyAPIConfig>;
|
||||
|
||||
// Prefix specific API configuration
|
||||
prefixes: Record<string, IconifyAPIConfig>;
|
||||
/**
|
||||
* Create full API configuration from partial data
|
||||
*/
|
||||
function createConfig(
|
||||
source: PartialIconifyAPIConfig
|
||||
): IconifyAPIConfig | null {
|
||||
if (!source.resources) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const result: IconifyAPIConfig = {
|
||||
// API hosts
|
||||
resources: source.resources,
|
||||
|
||||
// Root path
|
||||
path: source.path === void 0 ? '/' : source.path,
|
||||
|
||||
// URL length limit
|
||||
maxURL: source.maxURL ? source.maxURL : 500,
|
||||
|
||||
// Timeout before next host is used.
|
||||
rotate: source.rotate ? source.rotate : 750,
|
||||
|
||||
// Timeout to retry same host.
|
||||
timeout: source.timeout ? source.timeout : 5000,
|
||||
|
||||
// Number of attempts for each host.
|
||||
limit: source.limit ? source.limit : 2,
|
||||
|
||||
// Randomise default API end point.
|
||||
random: source.random === true,
|
||||
|
||||
// Start index
|
||||
index: source.index ? source.index : 0,
|
||||
};
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Local storage
|
||||
*/
|
||||
const configStorage: Record<string, IconifyAPIConfig> = Object.create(null);
|
||||
|
||||
/**
|
||||
* Redundancy for API servers.
|
||||
*
|
||||
@ -58,70 +92,28 @@ while (fallBackAPISources.length > 0) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Default configuration
|
||||
*/
|
||||
const defaultConfig: IconifyAPIConfig = {
|
||||
// API hosts
|
||||
// Add default API
|
||||
configStorage[''] = createConfig({
|
||||
resources: ['https://api.iconify.design'].concat(fallBackAPI),
|
||||
|
||||
// Root path
|
||||
path: '/',
|
||||
|
||||
// URL length limit
|
||||
maxURL: 500,
|
||||
|
||||
// Timeout before next host is used.
|
||||
rotate: 750,
|
||||
|
||||
// Timeout to retry same host.
|
||||
timeout: 5000,
|
||||
|
||||
// Number of attempts for each host.
|
||||
limit: 2,
|
||||
|
||||
// Randomise default API end point.
|
||||
random: false,
|
||||
|
||||
// Start index
|
||||
index: 0,
|
||||
};
|
||||
}) as IconifyAPIConfig;
|
||||
|
||||
/**
|
||||
* Local storage
|
||||
*/
|
||||
const configStorage: ConfigStorage = {
|
||||
default: defaultConfig,
|
||||
prefixes: Object.create(null),
|
||||
};
|
||||
|
||||
/**
|
||||
* Add custom config for prefix(es)
|
||||
*
|
||||
* This function should be used before any API queries.
|
||||
* On first API query computed configuration will be cached, so changes to config will not take effect.
|
||||
* Add custom config for provider
|
||||
*/
|
||||
export function setAPIConfig(
|
||||
customConfig: Partial<IconifyAPIConfig>,
|
||||
prefix?: string | string[]
|
||||
provider: string,
|
||||
customConfig: PartialIconifyAPIConfig
|
||||
): void {
|
||||
const mergedConfig = merge(
|
||||
configStorage.default,
|
||||
customConfig
|
||||
) as IconifyAPIConfig;
|
||||
if (prefix === void 0) {
|
||||
configStorage.default = mergedConfig;
|
||||
const config = createConfig(customConfig);
|
||||
if (config === null) {
|
||||
return;
|
||||
}
|
||||
(typeof prefix === 'string' ? [prefix] : prefix).forEach(prefix => {
|
||||
configStorage.prefixes[prefix] = mergedConfig;
|
||||
});
|
||||
configStorage[provider] = config;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get API configuration
|
||||
*/
|
||||
export function getAPIConfig(prefix: string): IconifyAPIConfig | null {
|
||||
const value = configStorage.prefixes[prefix];
|
||||
return value === void 0 ? configStorage.default : value;
|
||||
export function getAPIConfig(provider: string): IconifyAPIConfig | undefined {
|
||||
return configStorage[provider];
|
||||
}
|
||||
|
@ -15,8 +15,8 @@ import { getAPIModule } from './modules';
|
||||
import { getAPIConfig, IconifyAPIConfig } from './config';
|
||||
import { getStorage, addIconSet } from '../storage';
|
||||
import { coreModules } from '../modules';
|
||||
import { IconifyIconName } from '../icon/name';
|
||||
import { listToIcons, getPrefixes } from '../icon/list';
|
||||
import { IconifyIconName, IconifyIconSource } from '../icon/name';
|
||||
import { listToIcons } from '../icon/list';
|
||||
import { IconifyJSON } from '@iconify/types';
|
||||
|
||||
// Empty abort callback for loadIcons()
|
||||
@ -32,10 +32,13 @@ function emptyCallback(): void {
|
||||
* either an icon or a missing icon. This way same icon should
|
||||
* never be requested twice.
|
||||
*
|
||||
* [prefix][icon] = time when icon was added to queue
|
||||
* [provider][prefix][icon] = time when icon was added to queue
|
||||
*/
|
||||
type PendingIcons = Record<string, number>;
|
||||
const pendingIcons: Record<string, PendingIcons> = Object.create(null);
|
||||
const pendingIcons: Record<
|
||||
string,
|
||||
Record<string, PendingIcons>
|
||||
> = Object.create(null);
|
||||
|
||||
/**
|
||||
* List of icons that are waiting to be loaded.
|
||||
@ -45,31 +48,39 @@ const pendingIcons: Record<string, PendingIcons> = Object.create(null);
|
||||
* This list should not be used for any checks, use pendingIcons to check
|
||||
* if icons is being loaded.
|
||||
*
|
||||
* [prefix] = array of icon names
|
||||
* [provider][prefix] = array of icon names
|
||||
*/
|
||||
const iconsToLoad: Record<string, string[]> = Object.create(null);
|
||||
const iconsToLoad: Record<string, Record<string, string[]>> = Object.create(
|
||||
null
|
||||
);
|
||||
|
||||
// Flags to merge multiple synchronous icon requests in one asynchronous request
|
||||
const loaderFlags: Record<string, boolean> = Object.create(null);
|
||||
const queueFlags: Record<string, boolean> = Object.create(null);
|
||||
const loaderFlags: Record<string, Record<string, boolean>> = Object.create(
|
||||
null
|
||||
);
|
||||
const queueFlags: Record<string, Record<string, boolean>> = Object.create(null);
|
||||
|
||||
// Redundancy instances cache
|
||||
// Redundancy instances cache, sorted by provider
|
||||
interface LocalCache {
|
||||
config: IconifyAPIConfig | null;
|
||||
redundancy: Redundancy | null;
|
||||
config: IconifyAPIConfig;
|
||||
redundancy: Redundancy;
|
||||
}
|
||||
const redundancyCache: Record<string, LocalCache> = Object.create(null);
|
||||
|
||||
/**
|
||||
* Function called when new icons have been loaded
|
||||
*/
|
||||
function loadedNewIcons(prefix: string): void {
|
||||
function loadedNewIcons(provider: string, prefix: string): void {
|
||||
// Run only once per tick, possibly joining multiple API responses in one call
|
||||
if (!loaderFlags[prefix]) {
|
||||
loaderFlags[prefix] = true;
|
||||
if (loaderFlags[provider] === void 0) {
|
||||
loaderFlags[provider] = Object.create(null);
|
||||
}
|
||||
const providerLoaderFlags = loaderFlags[provider];
|
||||
if (!providerLoaderFlags[prefix]) {
|
||||
providerLoaderFlags[prefix] = true;
|
||||
setTimeout(() => {
|
||||
loaderFlags[prefix] = false;
|
||||
updateCallbacks(prefix);
|
||||
providerLoaderFlags[prefix] = false;
|
||||
updateCallbacks(provider, prefix);
|
||||
});
|
||||
}
|
||||
}
|
||||
@ -77,7 +88,7 @@ function loadedNewIcons(prefix: string): void {
|
||||
/**
|
||||
* Load icons
|
||||
*/
|
||||
function loadNewIcons(prefix: string, icons: string[]): void {
|
||||
function loadNewIcons(provider: string, prefix: string, icons: string[]): void {
|
||||
function err(): void {
|
||||
console.error(
|
||||
'Unable to retrieve icons for prefix "' +
|
||||
@ -86,68 +97,82 @@ function loadNewIcons(prefix: string, icons: string[]): void {
|
||||
);
|
||||
}
|
||||
|
||||
// Create nested objects if needed
|
||||
if (iconsToLoad[provider] === void 0) {
|
||||
iconsToLoad[provider] = Object.create(null);
|
||||
}
|
||||
const providerIconsToLoad = iconsToLoad[provider];
|
||||
|
||||
if (queueFlags[provider] === void 0) {
|
||||
queueFlags[provider] = Object.create(null);
|
||||
}
|
||||
const providerQueueFlags = queueFlags[provider];
|
||||
|
||||
if (pendingIcons[provider] === void 0) {
|
||||
pendingIcons[provider] = Object.create(null);
|
||||
}
|
||||
const providerPendingIcons = pendingIcons[provider];
|
||||
|
||||
// Add icons to queue
|
||||
if (iconsToLoad[prefix] === void 0) {
|
||||
iconsToLoad[prefix] = icons;
|
||||
if (providerIconsToLoad[prefix] === void 0) {
|
||||
providerIconsToLoad[prefix] = icons;
|
||||
} else {
|
||||
iconsToLoad[prefix] = iconsToLoad[prefix].concat(icons).sort();
|
||||
providerIconsToLoad[prefix] = providerIconsToLoad[prefix]
|
||||
.concat(icons)
|
||||
.sort();
|
||||
}
|
||||
|
||||
// Redundancy item
|
||||
let cachedReundancy: LocalCache;
|
||||
|
||||
// Trigger update on next tick, mering multiple synchronous requests into one asynchronous request
|
||||
if (!queueFlags[prefix]) {
|
||||
queueFlags[prefix] = true;
|
||||
if (!providerQueueFlags[prefix]) {
|
||||
providerQueueFlags[prefix] = true;
|
||||
setTimeout(() => {
|
||||
queueFlags[prefix] = false;
|
||||
providerQueueFlags[prefix] = false;
|
||||
|
||||
// Get icons and delete queue
|
||||
const icons = iconsToLoad[prefix];
|
||||
delete iconsToLoad[prefix];
|
||||
const icons = providerIconsToLoad[prefix];
|
||||
delete providerIconsToLoad[prefix];
|
||||
|
||||
// Get API module
|
||||
const api = getAPIModule(prefix);
|
||||
const api = getAPIModule(provider);
|
||||
if (!api) {
|
||||
// No way to load icons!
|
||||
err();
|
||||
return;
|
||||
}
|
||||
|
||||
// Get Redundancy instance
|
||||
if (redundancyCache[prefix] === void 0) {
|
||||
const config = getAPIConfig(prefix);
|
||||
|
||||
// Attempt to find matching instance from other prefixes
|
||||
// Using same Redundancy instance allows keeping track of failed hosts for multiple prefixes
|
||||
for (const prefix2 in redundancyCache) {
|
||||
const item = redundancyCache[prefix2];
|
||||
if (item.config === config) {
|
||||
redundancyCache[prefix] = item;
|
||||
break;
|
||||
// Get API config and Redundancy instance
|
||||
if (cachedReundancy === void 0) {
|
||||
if (redundancyCache[provider] === void 0) {
|
||||
const config = getAPIConfig(provider);
|
||||
if (!config) {
|
||||
// No way to load icons because configuration is not set!
|
||||
err();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (redundancyCache[prefix] === void 0) {
|
||||
redundancyCache[prefix] = {
|
||||
const redundancy = initRedundancy(config);
|
||||
cachedReundancy = {
|
||||
config,
|
||||
redundancy: config ? initRedundancy(config) : null,
|
||||
redundancy,
|
||||
};
|
||||
redundancyCache[provider] = cachedReundancy;
|
||||
} else {
|
||||
cachedReundancy = redundancyCache[provider];
|
||||
}
|
||||
}
|
||||
const redundancy = redundancyCache[prefix].redundancy;
|
||||
if (!redundancy) {
|
||||
// No way to load icons because configuration is not set!
|
||||
err();
|
||||
return;
|
||||
}
|
||||
|
||||
// Prepare parameters and run queries
|
||||
const params = api.prepare(prefix, icons);
|
||||
const params = api.prepare(provider, prefix, icons);
|
||||
params.forEach((item) => {
|
||||
redundancy.query(
|
||||
cachedReundancy.redundancy.query(
|
||||
item,
|
||||
api.send as RedundancyQueryCallback,
|
||||
(data) => {
|
||||
// Add icons to storage
|
||||
const storage = getStorage(prefix);
|
||||
const storage = getStorage(provider, prefix);
|
||||
try {
|
||||
const added = addIconSet(
|
||||
storage,
|
||||
@ -159,21 +184,24 @@ function loadNewIcons(prefix: string, icons: string[]): void {
|
||||
}
|
||||
|
||||
// Remove added icons from pending list
|
||||
const pending = pendingIcons[prefix];
|
||||
const pending = providerPendingIcons[prefix];
|
||||
added.forEach((name) => {
|
||||
delete pending[name];
|
||||
});
|
||||
|
||||
// Cache API response
|
||||
if (coreModules.cache) {
|
||||
coreModules.cache(data as IconifyJSON);
|
||||
coreModules.cache(
|
||||
provider,
|
||||
data as IconifyJSON
|
||||
);
|
||||
}
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
}
|
||||
|
||||
// Trigger update on next tick
|
||||
loadedNewIcons(prefix);
|
||||
loadedNewIcons(provider, prefix);
|
||||
}
|
||||
);
|
||||
});
|
||||
@ -184,9 +212,11 @@ function loadNewIcons(prefix: string, icons: string[]): void {
|
||||
/**
|
||||
* Check if icon is being loaded
|
||||
*/
|
||||
const isPending: IsPending = (prefix: string, icon: string): boolean => {
|
||||
const isPending: IsPending = (icon: IconifyIconName): boolean => {
|
||||
return (
|
||||
pendingIcons[prefix] !== void 0 && pendingIcons[prefix][icon] !== void 0
|
||||
pendingIcons[icon.provider] !== void 0 &&
|
||||
pendingIcons[icon.provider][icon.prefix] !== void 0 &&
|
||||
pendingIcons[icon.provider][icon.prefix][icon.name] !== void 0
|
||||
);
|
||||
};
|
||||
|
||||
@ -225,16 +255,42 @@ const loadIcons: IconifyLoadIcons = (
|
||||
};
|
||||
}
|
||||
|
||||
// Get all prefixes
|
||||
const prefixes = getPrefixes(sortedIcons.pending);
|
||||
// Get all sources for pending icons
|
||||
const newIcons: Record<string, Record<string, string[]>> = Object.create(
|
||||
null
|
||||
);
|
||||
const sources: IconifyIconSource[] = [];
|
||||
let lastProvider: string, lastPrefix: string;
|
||||
|
||||
// Get pending icons queue for prefix and create new icons list
|
||||
const newIcons: Record<string, string[]> = Object.create(null);
|
||||
prefixes.forEach((prefix) => {
|
||||
if (pendingIcons[prefix] === void 0) {
|
||||
pendingIcons[prefix] = Object.create(null);
|
||||
sortedIcons.pending.forEach((icon) => {
|
||||
const provider = icon.provider;
|
||||
const prefix = icon.prefix;
|
||||
if (prefix === lastPrefix && provider === lastProvider) {
|
||||
return;
|
||||
}
|
||||
|
||||
lastProvider = provider;
|
||||
lastPrefix = prefix;
|
||||
sources.push({
|
||||
provider,
|
||||
prefix,
|
||||
});
|
||||
|
||||
if (pendingIcons[provider] === void 0) {
|
||||
pendingIcons[provider] = Object.create(null);
|
||||
}
|
||||
const providerPendingIcons = pendingIcons[provider];
|
||||
if (providerPendingIcons[prefix] === void 0) {
|
||||
providerPendingIcons[prefix] = Object.create(null);
|
||||
}
|
||||
|
||||
if (newIcons[provider] === void 0) {
|
||||
newIcons[provider] = Object.create(null);
|
||||
}
|
||||
const providerNewIcons = newIcons[provider];
|
||||
if (providerNewIcons[prefix] === void 0) {
|
||||
providerNewIcons[prefix] = [];
|
||||
}
|
||||
newIcons[prefix] = [];
|
||||
});
|
||||
|
||||
// List of new icons
|
||||
@ -244,29 +300,32 @@ const loadIcons: IconifyLoadIcons = (
|
||||
// If icon was called before, it must exist in pendingIcons or storage, but because this
|
||||
// function is called right after sortIcons() that checks storage, icon is definitely not in storage.
|
||||
sortedIcons.pending.forEach((icon) => {
|
||||
const provider = icon.provider;
|
||||
const prefix = icon.prefix;
|
||||
const name = icon.name;
|
||||
|
||||
const pendingQueue = pendingIcons[prefix];
|
||||
const pendingQueue = pendingIcons[provider][prefix];
|
||||
if (pendingQueue[name] === void 0) {
|
||||
// New icon - add to pending queue to mark it as being loaded
|
||||
pendingQueue[name] = time;
|
||||
// Add it to new icons list to pass it to API module for loading
|
||||
newIcons[prefix].push(name);
|
||||
newIcons[provider][prefix].push(name);
|
||||
}
|
||||
});
|
||||
|
||||
// Load icons on next tick to make sure result is not returned before callback is stored and
|
||||
// to consolidate multiple synchronous loadIcons() calls into one asynchronous API call
|
||||
prefixes.forEach((prefix) => {
|
||||
if (newIcons[prefix].length) {
|
||||
loadNewIcons(prefix, newIcons[prefix]);
|
||||
sources.forEach((source) => {
|
||||
const provider = source.provider;
|
||||
const prefix = source.prefix;
|
||||
if (newIcons[provider][prefix].length) {
|
||||
loadNewIcons(provider, prefix, newIcons[provider][prefix]);
|
||||
}
|
||||
});
|
||||
|
||||
// Store callback and return abort function
|
||||
return callback
|
||||
? storeCallback(callback, sortedIcons, prefixes)
|
||||
? storeCallback(callback, sortedIcons, sources)
|
||||
: emptyCallback;
|
||||
};
|
||||
|
||||
|
@ -4,6 +4,7 @@ import { RedundancyPendingItem } from '@cyberalien/redundancy';
|
||||
* Params for sendQuery()
|
||||
*/
|
||||
export interface APIQueryParams {
|
||||
provider: string;
|
||||
prefix: string;
|
||||
icons: string[];
|
||||
}
|
||||
@ -12,6 +13,7 @@ export interface APIQueryParams {
|
||||
* Functions to implement in module
|
||||
*/
|
||||
export type IconifyAPIPrepareQuery = (
|
||||
provider: string,
|
||||
prefix: string,
|
||||
icons: string[]
|
||||
) => APIQueryParams[];
|
||||
@ -33,43 +35,36 @@ export interface IconifyAPIModule {
|
||||
/**
|
||||
* Local storate types and entries
|
||||
*/
|
||||
interface ModuleStorage {
|
||||
default: IconifyAPIModule | null;
|
||||
prefixes: Record<string, IconifyAPIModule>;
|
||||
interface ModulesStorage {
|
||||
default?: IconifyAPIModule;
|
||||
providers: Record<string, IconifyAPIModule>;
|
||||
}
|
||||
|
||||
const storage: ModuleStorage = {
|
||||
default: null,
|
||||
prefixes: Object.create(null),
|
||||
const storage: ModulesStorage = {
|
||||
providers: Object.create(null),
|
||||
};
|
||||
|
||||
/**
|
||||
* Set API module
|
||||
*
|
||||
* If prefix is not set, function sets default method.
|
||||
* If prefix is a string or array of strings, function sets method only for those prefixes.
|
||||
*
|
||||
* This should be used before sending any API requests. If used after sending API request, method
|
||||
* is already cached so changing callback will not have any effect.
|
||||
* Set default API module
|
||||
*/
|
||||
export function setAPIModule(
|
||||
item: IconifyAPIModule,
|
||||
prefix?: string | string[]
|
||||
): void {
|
||||
if (prefix === void 0) {
|
||||
storage.default = item;
|
||||
return;
|
||||
}
|
||||
export function setDefaultAPIModule(item: IconifyAPIModule): void {
|
||||
storage.default = item;
|
||||
}
|
||||
|
||||
(typeof prefix === 'string' ? [prefix] : prefix).forEach(prefix => {
|
||||
storage.prefixes[prefix] = item;
|
||||
});
|
||||
/**
|
||||
* Set API module
|
||||
*/
|
||||
export function setProviderAPIModule(
|
||||
provider: string,
|
||||
item: IconifyAPIModule
|
||||
): void {
|
||||
storage.providers[provider] = item;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get API module
|
||||
*/
|
||||
export function getAPIModule(prefix: string): IconifyAPIModule | null {
|
||||
const value = storage.prefixes[prefix];
|
||||
return value === void 0 ? storage.default : value;
|
||||
export function getAPIModule(provider: string): IconifyAPIModule | undefined {
|
||||
return storage.providers[provider] === void 0
|
||||
? storage.default
|
||||
: storage.providers[provider];
|
||||
}
|
||||
|
13
packages/core/src/cache/storage.ts
vendored
13
packages/core/src/cache/storage.ts
vendored
@ -13,13 +13,14 @@ type StorageEmptyList = StorageType<number[]>;
|
||||
|
||||
export interface StoredItem {
|
||||
cached: number;
|
||||
provider: string;
|
||||
data: IconifyJSON;
|
||||
}
|
||||
|
||||
// After changing configuration change it in tests/*/fake_cache.ts
|
||||
|
||||
// Cache version. Bump when structure changes
|
||||
const cacheVersion = 'iconify1';
|
||||
const cacheVersion = 'iconify2';
|
||||
|
||||
// Cache keys
|
||||
const cachePrefix = 'iconify';
|
||||
@ -200,14 +201,16 @@ export const loadCache: LoadIconsCache = (): void => {
|
||||
typeof data !== 'object' ||
|
||||
typeof data.cached !== 'number' ||
|
||||
data.cached < minTime ||
|
||||
typeof data.provider !== 'string' ||
|
||||
typeof data.data !== 'object' ||
|
||||
typeof data.data.prefix !== 'string'
|
||||
) {
|
||||
valid = false;
|
||||
} else {
|
||||
// Add icon set
|
||||
const provider = data.provider;
|
||||
const prefix = data.data.prefix;
|
||||
const storage = getStorage(prefix);
|
||||
const storage = getStorage(provider, prefix);
|
||||
valid = addIconSet(storage, data.data) as boolean;
|
||||
}
|
||||
} catch (err) {
|
||||
@ -263,7 +266,10 @@ export const loadCache: LoadIconsCache = (): void => {
|
||||
/**
|
||||
* Function to cache icons
|
||||
*/
|
||||
export const storeCache: CacheIcons = (data: IconifyJSON): void => {
|
||||
export const storeCache: CacheIcons = (
|
||||
provider: string,
|
||||
data: IconifyJSON
|
||||
): void => {
|
||||
if (!loaded) {
|
||||
loadCache();
|
||||
}
|
||||
@ -292,6 +298,7 @@ export const storeCache: CacheIcons = (data: IconifyJSON): void => {
|
||||
try {
|
||||
const item: StoredItem = {
|
||||
cached: Math.floor(Date.now() / hour),
|
||||
provider,
|
||||
data,
|
||||
};
|
||||
func.setItem(cachePrefix + index, JSON.stringify(item));
|
||||
|
@ -9,13 +9,14 @@ export function listToIcons(
|
||||
): IconifyIconName[] {
|
||||
const result: IconifyIconName[] = [];
|
||||
|
||||
list.forEach(item => {
|
||||
list.forEach((item) => {
|
||||
const icon: IconifyIconName =
|
||||
typeof item === 'string'
|
||||
? (stringToIcon(item) as IconifyIconName)
|
||||
: item;
|
||||
if (!validate || validateIcon(icon)) {
|
||||
result.push({
|
||||
provider: icon.provider,
|
||||
prefix: icon.prefix,
|
||||
name: icon.name,
|
||||
});
|
||||
@ -26,12 +27,12 @@ export function listToIcons(
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all prefixes
|
||||
* Get all providers
|
||||
*/
|
||||
export function getPrefixes(list: IconifyIconName[]): string[] {
|
||||
const prefixes: Record<string, boolean> = Object.create(null);
|
||||
list.forEach(icon => {
|
||||
prefixes[icon.prefix] = true;
|
||||
export function getProviders(list: IconifyIconName[]): string[] {
|
||||
const providers: Record<string, boolean> = Object.create(null);
|
||||
list.forEach((icon) => {
|
||||
providers[icon.provider] = true;
|
||||
});
|
||||
return Object.keys(prefixes);
|
||||
return Object.keys(providers);
|
||||
}
|
||||
|
@ -2,10 +2,16 @@
|
||||
* Icon name
|
||||
*/
|
||||
export interface IconifyIconName {
|
||||
readonly provider: string;
|
||||
readonly prefix: string;
|
||||
readonly name: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Icon source: icon object without name
|
||||
*/
|
||||
export type IconifyIconSource = Omit<IconifyIconName, 'name'>;
|
||||
|
||||
/**
|
||||
* Expression to test part of icon name.
|
||||
*/
|
||||
@ -15,22 +21,40 @@ const match = /^[a-z0-9]+(-[a-z0-9]+)*$/;
|
||||
* Convert string to Icon object.
|
||||
*/
|
||||
export const stringToIcon = (value: string): IconifyIconName | null => {
|
||||
// Attempt to split by colon: "prefix:name"
|
||||
let provider = '';
|
||||
const colonSeparated = value.split(':');
|
||||
if (colonSeparated.length > 2) {
|
||||
|
||||
// Check for provider with correct '@' at start
|
||||
if (value.slice(0, 1) === '@') {
|
||||
// First part is provider
|
||||
if (colonSeparated.length < 2 || colonSeparated.length > 3) {
|
||||
// "@provider:prefix:name" or "@provider:prefix-name"
|
||||
return null;
|
||||
}
|
||||
provider = (colonSeparated.shift() as string).slice(1);
|
||||
}
|
||||
|
||||
// Check split by colon: "prefix:name", "provider:prefix:name"
|
||||
if (colonSeparated.length > 3 || !colonSeparated.length) {
|
||||
return null;
|
||||
}
|
||||
if (colonSeparated.length === 2) {
|
||||
if (colonSeparated.length > 1) {
|
||||
// "prefix:name"
|
||||
const name = colonSeparated.pop() as string;
|
||||
const prefix = colonSeparated.pop() as string;
|
||||
return {
|
||||
prefix: colonSeparated[0],
|
||||
name: colonSeparated[1],
|
||||
// Allow provider without '@': "provider:prefix:name"
|
||||
provider: colonSeparated.length > 0 ? colonSeparated[0] : provider,
|
||||
prefix,
|
||||
name,
|
||||
};
|
||||
}
|
||||
|
||||
// Attempt to split by dash: "prefix-name"
|
||||
const dashSeparated = value.split('-');
|
||||
const dashSeparated = colonSeparated[0].split('-');
|
||||
if (dashSeparated.length > 1) {
|
||||
return {
|
||||
provider: provider,
|
||||
prefix: dashSeparated.shift() as string,
|
||||
name: dashSeparated.join('-'),
|
||||
};
|
||||
@ -49,5 +73,9 @@ export const validateIcon = (icon: IconifyIconName | null): boolean => {
|
||||
return false;
|
||||
}
|
||||
|
||||
return !!(icon.prefix.match(match) && icon.name.match(match));
|
||||
return !!(
|
||||
(icon.provider === '' || icon.provider.match(match)) &&
|
||||
icon.prefix.match(match) &&
|
||||
icon.name.match(match)
|
||||
);
|
||||
};
|
||||
|
@ -19,35 +19,50 @@ export function sortIcons(icons: IconifyIconName[]): SortedIcons {
|
||||
missing: [],
|
||||
pending: [],
|
||||
};
|
||||
const storage: Record<string, IconStorage> = Object.create(null);
|
||||
const storage: Record<string, Record<string, IconStorage>> = Object.create(
|
||||
null
|
||||
);
|
||||
|
||||
// Sort icons alphabetically to prevent duplicates and make sure they are sorted in API queries
|
||||
icons.sort((a, b) => {
|
||||
if (a.prefix === b.prefix) {
|
||||
return a.name.localeCompare(b.name);
|
||||
if (a.provider !== b.provider) {
|
||||
return a.provider.localeCompare(b.provider);
|
||||
}
|
||||
return a.prefix.localeCompare(b.prefix);
|
||||
if (a.prefix !== b.prefix) {
|
||||
return a.prefix.localeCompare(b.prefix);
|
||||
}
|
||||
return a.name.localeCompare(b.name);
|
||||
});
|
||||
|
||||
let lastIcon: IconifyIconName = {
|
||||
provider: '',
|
||||
prefix: '',
|
||||
name: '',
|
||||
};
|
||||
icons.forEach(icon => {
|
||||
if (lastIcon.prefix === icon.prefix && lastIcon.name === icon.name) {
|
||||
icons.forEach((icon) => {
|
||||
if (
|
||||
lastIcon.name === icon.name &&
|
||||
lastIcon.prefix === icon.prefix &&
|
||||
lastIcon.provider === icon.provider
|
||||
) {
|
||||
return;
|
||||
}
|
||||
lastIcon = icon;
|
||||
|
||||
// Check icon
|
||||
const provider = icon.provider;
|
||||
const prefix = icon.prefix;
|
||||
const name = icon.name;
|
||||
|
||||
if (storage[prefix] === void 0) {
|
||||
storage[prefix] = getStorage(prefix);
|
||||
if (storage[provider] === void 0) {
|
||||
storage[provider] = Object.create(null);
|
||||
}
|
||||
const providerStorage = storage[provider];
|
||||
|
||||
const localStorage = storage[prefix];
|
||||
if (providerStorage[prefix] === void 0) {
|
||||
providerStorage[prefix] = getStorage(provider, prefix);
|
||||
}
|
||||
const localStorage = providerStorage[prefix];
|
||||
|
||||
let list;
|
||||
if (localStorage.icons[name] !== void 0) {
|
||||
@ -59,6 +74,7 @@ export function sortIcons(icons: IconifyIconName[]): SortedIcons {
|
||||
}
|
||||
|
||||
const item: IconifyIconName = {
|
||||
provider,
|
||||
prefix,
|
||||
name,
|
||||
};
|
||||
|
@ -1,9 +1,10 @@
|
||||
import { IconifyLoadIcons } from './loader';
|
||||
import { IconifyIconName } from '../icon/name';
|
||||
|
||||
/**
|
||||
* Function to check if icon is pending
|
||||
*/
|
||||
export type IsPending = (prefix: string, name: string) => boolean;
|
||||
export type IsPending = (icon: IconifyIconName) => boolean;
|
||||
|
||||
/**
|
||||
* API interface
|
||||
|
@ -3,7 +3,7 @@ import { IconifyJSON } from '@iconify/types';
|
||||
/**
|
||||
* Function to cache loaded icons set
|
||||
*/
|
||||
export type CacheIcons = (data: IconifyJSON) => void;
|
||||
export type CacheIcons = (provider: string, data: IconifyJSON) => void;
|
||||
|
||||
/**
|
||||
* Function to load icons from cache
|
||||
|
@ -24,21 +24,25 @@ type IconRecords = Record<string, FullIconifyIcon | null>;
|
||||
* Storage type
|
||||
*/
|
||||
export interface IconStorage {
|
||||
provider: string;
|
||||
prefix: string;
|
||||
icons: IconRecords;
|
||||
missing: Record<string, number>;
|
||||
}
|
||||
|
||||
/**
|
||||
* Storage by prefix
|
||||
* Storage by provider and prefix
|
||||
*/
|
||||
const storage: Record<string, IconStorage> = Object.create(null);
|
||||
const storage: Record<string, Record<string, IconStorage>> = Object.create(
|
||||
null
|
||||
);
|
||||
|
||||
/**
|
||||
* Create new storage
|
||||
*/
|
||||
export function newStorage(prefix: string): IconStorage {
|
||||
export function newStorage(provider: string, prefix: string): IconStorage {
|
||||
return {
|
||||
provider,
|
||||
prefix,
|
||||
icons: Object.create(null),
|
||||
missing: Object.create(null),
|
||||
@ -46,20 +50,31 @@ export function newStorage(prefix: string): IconStorage {
|
||||
}
|
||||
|
||||
/**
|
||||
* Get storage for prefix
|
||||
* Get storage for provider and prefix
|
||||
*/
|
||||
export function getStorage(prefix: string): IconStorage {
|
||||
if (storage[prefix] === void 0) {
|
||||
storage[prefix] = newStorage(prefix);
|
||||
export function getStorage(provider: string, prefix: string): IconStorage {
|
||||
if (storage[provider] === void 0) {
|
||||
storage[provider] = Object.create(null);
|
||||
}
|
||||
return storage[prefix];
|
||||
const providerStorage = storage[provider];
|
||||
if (providerStorage[prefix] === void 0) {
|
||||
providerStorage[prefix] = newStorage(provider, prefix);
|
||||
}
|
||||
return providerStorage[prefix];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all providers
|
||||
*/
|
||||
export function listStoredProviders(): string[] {
|
||||
return Object.keys(storage);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all prefixes
|
||||
*/
|
||||
export function listStoredPrefixes(): string[] {
|
||||
return Object.keys(storage);
|
||||
export function listStoredPrefixes(provider: string): string[] {
|
||||
return storage[provider] === void 0 ? [] : Object.keys(storage[provider]);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -119,7 +134,7 @@ export function addIconSet(
|
||||
// Check for missing icons list returned by API
|
||||
if (data.not_found instanceof Array) {
|
||||
const t = Date.now();
|
||||
data.not_found.forEach(name => {
|
||||
data.not_found.forEach((name) => {
|
||||
storage.missing[name] = t;
|
||||
if (list === 'all') {
|
||||
added.push(name);
|
||||
@ -134,7 +149,7 @@ export function addIconSet(
|
||||
|
||||
// Get default values
|
||||
const defaults = Object.create(null);
|
||||
defaultsKeys.forEach(key => {
|
||||
defaultsKeys.forEach((key) => {
|
||||
if (data[key] !== void 0 && typeof data[key] !== 'object') {
|
||||
defaults[key] = data[key];
|
||||
}
|
||||
@ -142,7 +157,7 @@ export function addIconSet(
|
||||
|
||||
// Get icons
|
||||
const icons = data.icons;
|
||||
Object.keys(icons).forEach(name => {
|
||||
Object.keys(icons).forEach((name) => {
|
||||
const icon = icons[name];
|
||||
if (typeof icon.body !== 'string') {
|
||||
throw new Error('Invalid icon');
|
||||
@ -160,7 +175,7 @@ export function addIconSet(
|
||||
// Get aliases
|
||||
if (typeof data.aliases === 'object') {
|
||||
const aliases = data.aliases;
|
||||
Object.keys(aliases).forEach(name => {
|
||||
Object.keys(aliases).forEach((name) => {
|
||||
const icon = resolveAlias(aliases[name], icons, aliases, 1);
|
||||
if (icon) {
|
||||
// Freeze icon to make sure it will not be modified
|
||||
|
@ -7,12 +7,13 @@ import {
|
||||
} from '../../lib/icon/name';
|
||||
|
||||
describe('Testing icon name', () => {
|
||||
it('Converting and validating', () => {
|
||||
it('Simple icon names', () => {
|
||||
let icon;
|
||||
|
||||
// Simple prefix-name
|
||||
icon = stringToIcon('fa-home') as IconifyIconName;
|
||||
expect(icon).to.be.eql({
|
||||
provider: '',
|
||||
prefix: 'fa',
|
||||
name: 'home',
|
||||
});
|
||||
@ -21,6 +22,7 @@ describe('Testing icon name', () => {
|
||||
// Simple prefix:name
|
||||
icon = stringToIcon('fa:arrow-left') as IconifyIconName;
|
||||
expect(icon).to.be.eql({
|
||||
provider: '',
|
||||
prefix: 'fa',
|
||||
name: 'arrow-left',
|
||||
});
|
||||
@ -29,11 +31,17 @@ describe('Testing icon name', () => {
|
||||
// Longer prefix:name
|
||||
icon = stringToIcon('mdi-light:home-outline') as IconifyIconName;
|
||||
expect(icon).to.be.eql({
|
||||
provider: '',
|
||||
prefix: 'mdi-light',
|
||||
name: 'home-outline',
|
||||
});
|
||||
expect(validateIcon(icon)).to.be.equal(true);
|
||||
|
||||
// Missing icon name
|
||||
icon = stringToIcon('@iconify-home-icon');
|
||||
expect(icon).to.be.eql(null);
|
||||
expect(validateIcon(icon)).to.be.equal(false);
|
||||
|
||||
// Underscore is not an acceptable separator
|
||||
icon = stringToIcon('fa_home');
|
||||
expect(icon).to.be.eql(null);
|
||||
@ -42,19 +50,21 @@ describe('Testing icon name', () => {
|
||||
// Invalid character '_': fail validateIcon
|
||||
icon = stringToIcon('fa:home_outline') as IconifyIconName;
|
||||
expect(icon).to.be.eql({
|
||||
provider: '',
|
||||
prefix: 'fa',
|
||||
name: 'home_outline',
|
||||
});
|
||||
expect(validateIcon(icon)).to.be.equal(false);
|
||||
|
||||
// Too many colons: fail stringToIcon
|
||||
icon = stringToIcon('mdi-light:home:outline');
|
||||
icon = stringToIcon('mdi:light:home:outline');
|
||||
expect(icon).to.be.eql(null);
|
||||
expect(validateIcon(icon)).to.be.equal(false);
|
||||
|
||||
// Upper case: fail validateIcon
|
||||
icon = stringToIcon('MD:Home') as IconifyIconName;
|
||||
expect(icon).to.be.eql({
|
||||
provider: '',
|
||||
prefix: 'MD',
|
||||
name: 'Home',
|
||||
});
|
||||
@ -63,6 +73,7 @@ describe('Testing icon name', () => {
|
||||
// Numbers: pass
|
||||
icon = stringToIcon('1:foo') as IconifyIconName;
|
||||
expect(icon).to.be.eql({
|
||||
provider: '',
|
||||
prefix: '1',
|
||||
name: 'foo',
|
||||
});
|
||||
@ -71,9 +82,68 @@ describe('Testing icon name', () => {
|
||||
// Accented letters: fail validateIcon
|
||||
icon = stringToIcon('md-fõö') as IconifyIconName;
|
||||
expect(icon).to.be.eql({
|
||||
provider: '',
|
||||
prefix: 'md',
|
||||
name: 'fõö',
|
||||
});
|
||||
expect(validateIcon(icon)).to.be.equal(false);
|
||||
});
|
||||
|
||||
it('Providers', () => {
|
||||
let icon;
|
||||
|
||||
// Simple @provider:prefix-name
|
||||
icon = stringToIcon('@iconify:fa-home') as IconifyIconName;
|
||||
expect(icon).to.be.eql({
|
||||
provider: 'iconify',
|
||||
prefix: 'fa',
|
||||
name: 'home',
|
||||
});
|
||||
expect(validateIcon(icon)).to.be.equal(true);
|
||||
|
||||
// Simple @provider:prefix:name
|
||||
icon = stringToIcon('@iconify:fa:arrow-left') as IconifyIconName;
|
||||
expect(icon).to.be.eql({
|
||||
provider: 'iconify',
|
||||
prefix: 'fa',
|
||||
name: 'arrow-left',
|
||||
});
|
||||
expect(validateIcon(icon)).to.be.equal(true);
|
||||
|
||||
// Longer @provider:prefix:name
|
||||
icon = stringToIcon(
|
||||
'@iconify-backup:mdi-light:home-outline'
|
||||
) as IconifyIconName;
|
||||
expect(icon).to.be.eql({
|
||||
provider: 'iconify-backup',
|
||||
prefix: 'mdi-light',
|
||||
name: 'home-outline',
|
||||
});
|
||||
expect(validateIcon(icon)).to.be.equal(true);
|
||||
|
||||
// Missing @ for provider
|
||||
icon = stringToIcon(
|
||||
'iconify-backup:mdi-light:home-outline'
|
||||
) as IconifyIconName;
|
||||
expect(icon).to.be.eql({
|
||||
provider: 'iconify-backup',
|
||||
prefix: 'mdi-light',
|
||||
name: 'home-outline',
|
||||
});
|
||||
expect(validateIcon(icon)).to.be.equal(true);
|
||||
|
||||
// Too many colons: fail stringToIcon
|
||||
icon = stringToIcon('@mdi:light:home:outline');
|
||||
expect(icon).to.be.eql(null);
|
||||
expect(validateIcon(icon)).to.be.equal(false);
|
||||
|
||||
// Upper case: fail validateIcon
|
||||
icon = stringToIcon('@MD:home-outline') as IconifyIconName;
|
||||
expect(icon).to.be.eql({
|
||||
provider: 'MD',
|
||||
prefix: 'home',
|
||||
name: 'outline',
|
||||
});
|
||||
expect(validateIcon(icon)).to.be.equal(false);
|
||||
});
|
||||
});
|
||||
|
@ -13,7 +13,7 @@ import { IconifyJSON } from '@iconify/types';
|
||||
|
||||
describe('Testing storage', () => {
|
||||
it('Adding icon', () => {
|
||||
const storage = newStorage('foo');
|
||||
const storage = newStorage('', 'foo');
|
||||
|
||||
// Add one icon
|
||||
addIcon(storage, 'test', {
|
||||
@ -82,7 +82,7 @@ describe('Testing storage', () => {
|
||||
});
|
||||
|
||||
it('Adding simple icon set', () => {
|
||||
const storage = newStorage('foo');
|
||||
const storage = newStorage('', 'foo');
|
||||
|
||||
// Add two icons
|
||||
expect(
|
||||
@ -138,7 +138,7 @@ describe('Testing storage', () => {
|
||||
});
|
||||
|
||||
it('Icon set with invalid default values', () => {
|
||||
const storage = newStorage('foo');
|
||||
const storage = newStorage('', 'foo');
|
||||
|
||||
// Missing prefix, invalid default values
|
||||
expect(
|
||||
@ -205,7 +205,7 @@ describe('Testing storage', () => {
|
||||
});
|
||||
|
||||
it('Icon set with simple aliases', () => {
|
||||
const storage = newStorage('foo');
|
||||
const storage = newStorage('', 'foo');
|
||||
|
||||
expect(
|
||||
addIconSet(storage, {
|
||||
@ -275,7 +275,7 @@ describe('Testing storage', () => {
|
||||
});
|
||||
|
||||
it('Icon set with nested aliases', () => {
|
||||
const storage = newStorage('foo');
|
||||
const storage = newStorage('', 'foo');
|
||||
|
||||
expect(
|
||||
addIconSet(storage, {
|
||||
@ -402,7 +402,7 @@ describe('Testing storage', () => {
|
||||
});
|
||||
|
||||
it('Icon set with aliases that use transformations', () => {
|
||||
const storage = newStorage('arty-animated');
|
||||
const storage = newStorage('iconify', 'arty-animated');
|
||||
const iconBody =
|
||||
'<g stroke="currentColor" stroke-width="16" stroke-linecap="round" stroke-linejoin="round" fill="none" fill-rule="evenodd"><path d="M40 64l48-48" class="animation-delay-0 animation-duration-10 animate-stroke stroke-length-102"/><path d="M40 64l48 48" class="animation-delay-0 animation-duration-10 animate-stroke stroke-length-102"/></g>';
|
||||
|
||||
|
@ -18,11 +18,12 @@ describe('Testing API callbacks', () => {
|
||||
return 'api-cb-test-' + (prefixCounter < 10 ? '0' : '') + prefixCounter;
|
||||
}
|
||||
|
||||
it('Simple callback', done => {
|
||||
it('Simple callback', (done) => {
|
||||
const provider = 'iconify';
|
||||
const prefix = nextPrefix();
|
||||
let counter = 0;
|
||||
|
||||
const storage = getStorage(prefix);
|
||||
const storage = getStorage(provider, prefix);
|
||||
const abort = storeCallback(
|
||||
(loaded, missing, pending, unsubscribe) => {
|
||||
expect(unsubscribe).to.be.equal(abort);
|
||||
@ -33,23 +34,28 @@ describe('Testing API callbacks', () => {
|
||||
// First run - icon1 should be loaded, icon3 should be missing
|
||||
expect(loaded).to.be.eql([
|
||||
{
|
||||
provider,
|
||||
prefix,
|
||||
name: 'icon1',
|
||||
},
|
||||
]);
|
||||
expect(missing).to.be.eql([
|
||||
{
|
||||
provider,
|
||||
prefix,
|
||||
name: 'icon3',
|
||||
},
|
||||
]);
|
||||
expect(pending).to.be.eql([
|
||||
{
|
||||
provider,
|
||||
prefix,
|
||||
name: 'icon2',
|
||||
},
|
||||
]);
|
||||
expect(callbacks[prefix].length).to.be.equal(1);
|
||||
expect(callbacks[provider][prefix].length).to.be.equal(
|
||||
1
|
||||
);
|
||||
|
||||
// Add icon2 and trigger update
|
||||
addIconSet(storage, {
|
||||
@ -61,54 +67,67 @@ describe('Testing API callbacks', () => {
|
||||
},
|
||||
});
|
||||
|
||||
updateCallbacks(prefix);
|
||||
updateCallbacks(provider, prefix);
|
||||
return;
|
||||
|
||||
case 2:
|
||||
// Second run - icon2 should be added, completing callback
|
||||
expect(loaded).to.be.eql([
|
||||
{
|
||||
provider,
|
||||
prefix,
|
||||
name: 'icon1',
|
||||
},
|
||||
{
|
||||
provider,
|
||||
prefix,
|
||||
name: 'icon2',
|
||||
},
|
||||
]);
|
||||
expect(missing).to.be.eql([
|
||||
{
|
||||
provider,
|
||||
prefix,
|
||||
name: 'icon3',
|
||||
},
|
||||
]);
|
||||
expect(pending).to.be.eql([]);
|
||||
expect(callbacks[prefix].length).to.be.equal(0);
|
||||
expect(callbacks[provider][prefix].length).to.be.equal(
|
||||
0
|
||||
);
|
||||
done();
|
||||
}
|
||||
},
|
||||
sortIcons([
|
||||
{
|
||||
provider,
|
||||
prefix,
|
||||
name: 'icon1',
|
||||
},
|
||||
{
|
||||
provider,
|
||||
prefix,
|
||||
name: 'icon2',
|
||||
},
|
||||
{
|
||||
provider,
|
||||
prefix,
|
||||
name: 'icon3',
|
||||
},
|
||||
]),
|
||||
[prefix]
|
||||
[
|
||||
{
|
||||
provider,
|
||||
prefix,
|
||||
},
|
||||
]
|
||||
);
|
||||
|
||||
// Test callbacks
|
||||
expect(callbacks[prefix].length).to.be.equal(1);
|
||||
expect(callbacks[provider][prefix].length).to.be.equal(1);
|
||||
|
||||
// Test update - should do nothing
|
||||
updateCallbacks(prefix);
|
||||
updateCallbacks(provider, prefix);
|
||||
|
||||
// Wait for tick because updateCallbacks will use one
|
||||
setTimeout(() => {
|
||||
@ -125,14 +144,15 @@ describe('Testing API callbacks', () => {
|
||||
},
|
||||
not_found: ['icon3'],
|
||||
});
|
||||
updateCallbacks(prefix);
|
||||
updateCallbacks(provider, prefix);
|
||||
});
|
||||
});
|
||||
|
||||
it('Callback that should not be stored', () => {
|
||||
const provider = '';
|
||||
const prefix = nextPrefix();
|
||||
|
||||
const storage = getStorage(prefix);
|
||||
const storage = getStorage(provider, prefix);
|
||||
addIconSet(storage, {
|
||||
prefix,
|
||||
icons: {
|
||||
@ -152,30 +172,39 @@ describe('Testing API callbacks', () => {
|
||||
},
|
||||
sortIcons([
|
||||
{
|
||||
provider,
|
||||
prefix,
|
||||
name: 'icon1',
|
||||
},
|
||||
{
|
||||
provider,
|
||||
prefix,
|
||||
name: 'icon2',
|
||||
},
|
||||
{
|
||||
provider,
|
||||
prefix,
|
||||
name: 'icon3',
|
||||
},
|
||||
]),
|
||||
[prefix]
|
||||
[
|
||||
{
|
||||
provider,
|
||||
prefix,
|
||||
},
|
||||
]
|
||||
);
|
||||
|
||||
// callbacks should not have been initialised
|
||||
expect(callbacks[prefix]).to.be.equal(void 0);
|
||||
});
|
||||
|
||||
it('Cancel callback', done => {
|
||||
it('Cancel callback', (done) => {
|
||||
const provider = 'foo';
|
||||
const prefix = nextPrefix();
|
||||
let counter = 0;
|
||||
|
||||
const storage = getStorage(prefix);
|
||||
const storage = getStorage(provider, prefix);
|
||||
const abort = storeCallback(
|
||||
(loaded, missing, pending, unsubscribe) => {
|
||||
expect(unsubscribe).to.be.equal(abort);
|
||||
@ -186,23 +215,26 @@ describe('Testing API callbacks', () => {
|
||||
// First run - icon1 should be loaded, icon3 should be missing
|
||||
expect(loaded).to.be.eql([
|
||||
{
|
||||
provider,
|
||||
prefix,
|
||||
name: 'icon1',
|
||||
},
|
||||
]);
|
||||
expect(missing).to.be.eql([
|
||||
{
|
||||
provider,
|
||||
prefix,
|
||||
name: 'icon3',
|
||||
},
|
||||
]);
|
||||
expect(pending).to.be.eql([
|
||||
{
|
||||
provider,
|
||||
prefix,
|
||||
name: 'icon2',
|
||||
},
|
||||
]);
|
||||
expect(callbacks[prefix].length).to.be.equal(1);
|
||||
expect(callbacks[provider][prefix].length).to.be.equal(1);
|
||||
|
||||
// Add icon2 and trigger update
|
||||
addIconSet(storage, {
|
||||
@ -214,35 +246,43 @@ describe('Testing API callbacks', () => {
|
||||
},
|
||||
});
|
||||
|
||||
updateCallbacks(prefix);
|
||||
updateCallbacks(provider, prefix);
|
||||
|
||||
// Unsubscribe and set timer to call done()
|
||||
unsubscribe();
|
||||
expect(callbacks[prefix].length).to.be.equal(0);
|
||||
expect(callbacks[provider][prefix].length).to.be.equal(0);
|
||||
setTimeout(done);
|
||||
},
|
||||
sortIcons([
|
||||
{
|
||||
provider,
|
||||
prefix,
|
||||
name: 'icon1',
|
||||
},
|
||||
{
|
||||
provider,
|
||||
prefix,
|
||||
name: 'icon2',
|
||||
},
|
||||
{
|
||||
provider,
|
||||
prefix,
|
||||
name: 'icon3',
|
||||
},
|
||||
]),
|
||||
[prefix]
|
||||
[
|
||||
{
|
||||
provider,
|
||||
prefix,
|
||||
},
|
||||
]
|
||||
);
|
||||
|
||||
// Test callbacks
|
||||
expect(callbacks[prefix].length).to.be.equal(1);
|
||||
expect(callbacks[provider][prefix].length).to.be.equal(1);
|
||||
|
||||
// Test update - should do nothing
|
||||
updateCallbacks(prefix);
|
||||
updateCallbacks(provider, prefix);
|
||||
|
||||
// Wait for tick because updateCallbacks will use one
|
||||
setTimeout(() => {
|
||||
@ -259,17 +299,18 @@ describe('Testing API callbacks', () => {
|
||||
},
|
||||
not_found: ['icon3'],
|
||||
});
|
||||
updateCallbacks(prefix);
|
||||
updateCallbacks(provider, prefix);
|
||||
});
|
||||
});
|
||||
|
||||
it('Multiple prefixes', done => {
|
||||
it('Multiple prefixes', (done) => {
|
||||
const provider = '';
|
||||
const prefix1 = nextPrefix();
|
||||
const prefix2 = nextPrefix();
|
||||
let counter = 0;
|
||||
|
||||
const storage1 = getStorage(prefix1);
|
||||
const storage2 = getStorage(prefix2);
|
||||
const storage1 = getStorage(provider, prefix1);
|
||||
const storage2 = getStorage(provider, prefix2);
|
||||
|
||||
const abort = storeCallback(
|
||||
(loaded, missing, pending, unsubscribe) => {
|
||||
@ -281,24 +322,31 @@ describe('Testing API callbacks', () => {
|
||||
// First run - icon1 should be loaded, icon3 should be missing
|
||||
expect(loaded).to.be.eql([
|
||||
{
|
||||
provider,
|
||||
prefix: prefix1,
|
||||
name: 'icon1',
|
||||
},
|
||||
]);
|
||||
expect(missing).to.be.eql([
|
||||
{
|
||||
provider,
|
||||
prefix: prefix1,
|
||||
name: 'icon3',
|
||||
},
|
||||
]);
|
||||
expect(pending).to.be.eql([
|
||||
{
|
||||
provider,
|
||||
prefix: prefix2,
|
||||
name: 'icon2',
|
||||
},
|
||||
]);
|
||||
expect(callbacks[prefix1].length).to.be.equal(0);
|
||||
expect(callbacks[prefix2].length).to.be.equal(1);
|
||||
expect(callbacks[provider][prefix1].length).to.be.equal(
|
||||
0
|
||||
);
|
||||
expect(callbacks[provider][prefix2].length).to.be.equal(
|
||||
1
|
||||
);
|
||||
|
||||
// Add icon2 and trigger update
|
||||
addIconSet(storage2, {
|
||||
@ -310,13 +358,17 @@ describe('Testing API callbacks', () => {
|
||||
},
|
||||
});
|
||||
|
||||
updateCallbacks(prefix2);
|
||||
updateCallbacks(provider, prefix2);
|
||||
break;
|
||||
|
||||
case 2:
|
||||
// Second run - icon2 should be loaded
|
||||
expect(callbacks[prefix1].length).to.be.equal(0);
|
||||
expect(callbacks[prefix2].length).to.be.equal(0);
|
||||
expect(callbacks[provider][prefix1].length).to.be.equal(
|
||||
0
|
||||
);
|
||||
expect(callbacks[provider][prefix2].length).to.be.equal(
|
||||
0
|
||||
);
|
||||
done();
|
||||
break;
|
||||
|
||||
@ -326,27 +378,33 @@ describe('Testing API callbacks', () => {
|
||||
},
|
||||
sortIcons([
|
||||
{
|
||||
provider,
|
||||
prefix: prefix1,
|
||||
name: 'icon1',
|
||||
},
|
||||
{
|
||||
provider,
|
||||
prefix: prefix2,
|
||||
name: 'icon2',
|
||||
},
|
||||
{
|
||||
provider,
|
||||
prefix: prefix1,
|
||||
name: 'icon3',
|
||||
},
|
||||
]),
|
||||
[prefix1, prefix2]
|
||||
[
|
||||
{ provider, prefix: prefix1 },
|
||||
{ provider, prefix: prefix2 },
|
||||
]
|
||||
);
|
||||
|
||||
// Test callbacks
|
||||
expect(callbacks[prefix1].length).to.be.equal(1);
|
||||
expect(callbacks[prefix2].length).to.be.equal(1);
|
||||
expect(callbacks[provider][prefix1].length).to.be.equal(1);
|
||||
expect(callbacks[provider][prefix2].length).to.be.equal(1);
|
||||
|
||||
// Test update - should do nothing
|
||||
updateCallbacks(prefix1);
|
||||
updateCallbacks(provider, prefix1);
|
||||
|
||||
// Wait for tick because updateCallbacks will use one
|
||||
setTimeout(() => {
|
||||
@ -363,7 +421,150 @@ describe('Testing API callbacks', () => {
|
||||
},
|
||||
not_found: ['icon3'],
|
||||
});
|
||||
updateCallbacks(prefix1);
|
||||
updateCallbacks(provider, prefix1);
|
||||
});
|
||||
});
|
||||
|
||||
it('Multiple providers', (done) => {
|
||||
const provider1 = nextPrefix();
|
||||
const provider2 = nextPrefix();
|
||||
const prefix1 = nextPrefix();
|
||||
const prefix2 = nextPrefix();
|
||||
let counter = 0;
|
||||
|
||||
const storage1 = getStorage(provider1, prefix1);
|
||||
const storage2 = getStorage(provider2, prefix2);
|
||||
|
||||
const abort = storeCallback(
|
||||
(loaded, missing, pending, unsubscribe) => {
|
||||
expect(unsubscribe).to.be.equal(abort);
|
||||
|
||||
counter++;
|
||||
switch (counter) {
|
||||
case 1:
|
||||
// First run - icon1 should be loaded, icon3 should be missing
|
||||
expect(loaded).to.be.eql([
|
||||
{
|
||||
provider: provider1,
|
||||
prefix: prefix1,
|
||||
name: 'icon1',
|
||||
},
|
||||
]);
|
||||
expect(missing).to.be.eql([
|
||||
{
|
||||
provider: provider1,
|
||||
prefix: prefix1,
|
||||
name: 'icon3',
|
||||
},
|
||||
]);
|
||||
expect(pending).to.be.eql([
|
||||
{
|
||||
provider: provider2,
|
||||
prefix: prefix2,
|
||||
name: 'icon2',
|
||||
},
|
||||
]);
|
||||
expect(
|
||||
callbacks[provider1][prefix1].length
|
||||
).to.be.equal(0);
|
||||
expect(
|
||||
callbacks[provider2][prefix2].length
|
||||
).to.be.equal(1);
|
||||
|
||||
// Make sure providers/prefixes aren't mixed
|
||||
expect(callbacks[provider1][prefix2]).to.be.equal(
|
||||
void 0
|
||||
);
|
||||
expect(callbacks[provider2][prefix1]).to.be.equal(
|
||||
void 0
|
||||
);
|
||||
|
||||
// Add icon2 and trigger update
|
||||
addIconSet(storage2, {
|
||||
prefix: prefix2,
|
||||
icons: {
|
||||
icon2: {
|
||||
body: '<g></g>',
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
updateCallbacks(provider2, prefix2);
|
||||
break;
|
||||
|
||||
case 2:
|
||||
// Second run - icon2 should be loaded
|
||||
expect(
|
||||
callbacks[provider1][prefix1].length
|
||||
).to.be.equal(0);
|
||||
expect(
|
||||
callbacks[provider2][prefix2].length
|
||||
).to.be.equal(0);
|
||||
|
||||
// Make sure providers/prefixes aren't mixed
|
||||
expect(callbacks[provider1][prefix2]).to.be.equal(
|
||||
void 0
|
||||
);
|
||||
expect(callbacks[provider2][prefix1]).to.be.equal(
|
||||
void 0
|
||||
);
|
||||
|
||||
done();
|
||||
break;
|
||||
|
||||
default:
|
||||
done('Callback was called ' + counter + ' times.');
|
||||
}
|
||||
},
|
||||
sortIcons([
|
||||
{
|
||||
provider: provider1,
|
||||
prefix: prefix1,
|
||||
name: 'icon1',
|
||||
},
|
||||
{
|
||||
provider: provider2,
|
||||
prefix: prefix2,
|
||||
name: 'icon2',
|
||||
},
|
||||
{
|
||||
provider: provider1,
|
||||
prefix: prefix1,
|
||||
name: 'icon3',
|
||||
},
|
||||
]),
|
||||
[
|
||||
{ provider: provider1, prefix: prefix1 },
|
||||
{ provider: provider2, prefix: prefix2 },
|
||||
]
|
||||
);
|
||||
|
||||
// Test callbacks
|
||||
expect(callbacks[provider1][prefix1].length).to.be.equal(1);
|
||||
expect(callbacks[provider2][prefix2].length).to.be.equal(1);
|
||||
|
||||
expect(callbacks[provider1][prefix2]).to.be.equal(void 0);
|
||||
expect(callbacks[provider2][prefix1]).to.be.equal(void 0);
|
||||
|
||||
// Test update - should do nothing
|
||||
updateCallbacks(provider1, prefix1);
|
||||
|
||||
// Wait for tick because updateCallbacks will use one
|
||||
setTimeout(() => {
|
||||
// Callback should not have been called yet
|
||||
expect(counter).to.be.equal(0);
|
||||
|
||||
// Add few icons and run updateCallbacks
|
||||
addIconSet(storage1, {
|
||||
prefix: prefix1,
|
||||
icons: {
|
||||
icon1: {
|
||||
body: '<g></g>',
|
||||
},
|
||||
},
|
||||
not_found: ['icon3'],
|
||||
});
|
||||
updateCallbacks(provider1, prefix1);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -9,7 +9,7 @@ import {
|
||||
IconifyAPIConfig,
|
||||
} from '../../lib/api/config';
|
||||
import {
|
||||
setAPIModule,
|
||||
setProviderAPIModule,
|
||||
APIQueryParams,
|
||||
getAPIModule,
|
||||
IconifyAPIModule,
|
||||
@ -25,10 +25,12 @@ describe('Testing API modules', () => {
|
||||
}
|
||||
|
||||
const prepareQuery = (
|
||||
provider: string,
|
||||
prefix: string,
|
||||
icons: string[]
|
||||
): APIQueryParams[] => {
|
||||
const item: APIQueryParams = {
|
||||
provider,
|
||||
prefix,
|
||||
icons,
|
||||
};
|
||||
@ -44,42 +46,36 @@ describe('Testing API modules', () => {
|
||||
};
|
||||
|
||||
it('Empty module', () => {
|
||||
const prefix = nextPrefix();
|
||||
const provider = nextPrefix();
|
||||
|
||||
// Set config
|
||||
setAPIConfig(
|
||||
{
|
||||
resources: ['https://localhost:3000'],
|
||||
maxURL: 500,
|
||||
},
|
||||
prefix
|
||||
);
|
||||
setAPIConfig(provider, {
|
||||
resources: ['https://localhost:3000'],
|
||||
maxURL: 500,
|
||||
});
|
||||
|
||||
// Set fake module
|
||||
setAPIModule(
|
||||
{
|
||||
prepare: prepareQuery,
|
||||
send: sendQuery,
|
||||
},
|
||||
prefix
|
||||
);
|
||||
setProviderAPIModule(provider, {
|
||||
prepare: prepareQuery,
|
||||
send: sendQuery,
|
||||
});
|
||||
|
||||
// Get config
|
||||
const config = getAPIConfig(prefix) as IconifyAPIConfig;
|
||||
expect(config).to.not.be.equal(null);
|
||||
const config = getAPIConfig(provider) as IconifyAPIConfig;
|
||||
expect(config).to.not.be.equal(void 0);
|
||||
|
||||
// Check setAPIConfig
|
||||
expect(config.resources).to.be.eql(['https://localhost:3000']);
|
||||
|
||||
// Check getAPIModule()
|
||||
const item = getAPIModule(prefix) as IconifyAPIModule;
|
||||
expect(item).to.not.be.equal(null);
|
||||
const item = getAPIModule(provider) as IconifyAPIModule;
|
||||
expect(item).to.not.be.equal(void 0);
|
||||
expect(item.prepare).to.be.equal(prepareQuery);
|
||||
expect(item.send).to.be.equal(sendQuery);
|
||||
|
||||
// Get module for different prefix to make sure it is empty
|
||||
const prefix2 = nextPrefix();
|
||||
const item2 = getAPIModule(prefix2);
|
||||
expect(item2).to.be.equal(null);
|
||||
// Get module for different provider to make sure it is empty
|
||||
const provider2 = nextPrefix();
|
||||
const item2 = getAPIModule(provider2);
|
||||
expect(item2).to.be.equal(void 0);
|
||||
});
|
||||
});
|
||||
|
@ -3,8 +3,8 @@
|
||||
import 'mocha';
|
||||
import { expect } from 'chai';
|
||||
import { RedundancyPendingItem } from '@cyberalien/redundancy';
|
||||
import { setAPIConfig } from '../../lib/api/config';
|
||||
import { setAPIModule, APIQueryParams } from '../../lib/api/modules';
|
||||
import { setAPIConfig, IconifyAPIConfig } from '../../lib/api/config';
|
||||
import { setProviderAPIModule, APIQueryParams } from '../../lib/api/modules';
|
||||
import { API } from '../../lib/api/';
|
||||
|
||||
describe('Testing API loadIcons', () => {
|
||||
@ -16,24 +16,24 @@ describe('Testing API loadIcons', () => {
|
||||
);
|
||||
}
|
||||
|
||||
it('Loading few icons', done => {
|
||||
it('Loading few icons', (done) => {
|
||||
const provider = nextPrefix();
|
||||
const prefix = nextPrefix();
|
||||
let asyncCounter = 0;
|
||||
|
||||
// Set config
|
||||
setAPIConfig(
|
||||
{
|
||||
resources: ['https://api1.local', 'https://api2.local'],
|
||||
},
|
||||
prefix
|
||||
);
|
||||
setAPIConfig(provider, {
|
||||
resources: ['https://api1.local', 'https://api2.local'],
|
||||
});
|
||||
|
||||
// Icon loader
|
||||
const prepareQuery = (
|
||||
provider: string,
|
||||
prefix: string,
|
||||
icons: string[]
|
||||
): APIQueryParams[] => {
|
||||
const item: APIQueryParams = {
|
||||
provider,
|
||||
prefix,
|
||||
icons,
|
||||
};
|
||||
@ -44,6 +44,7 @@ describe('Testing API loadIcons', () => {
|
||||
|
||||
// Test input and return as one item
|
||||
const expected: APIQueryParams = {
|
||||
provider,
|
||||
prefix,
|
||||
icons: ['icon1', 'icon2'],
|
||||
};
|
||||
@ -64,6 +65,7 @@ describe('Testing API loadIcons', () => {
|
||||
// Test input
|
||||
expect(host).to.be.equal('https://api1.local');
|
||||
const expected: APIQueryParams = {
|
||||
provider,
|
||||
prefix,
|
||||
icons: ['icon1', 'icon2'],
|
||||
};
|
||||
@ -86,24 +88,22 @@ describe('Testing API loadIcons', () => {
|
||||
expect(asyncCounter).to.be.equal(3);
|
||||
};
|
||||
|
||||
setAPIModule(
|
||||
{
|
||||
prepare: prepareQuery,
|
||||
send: sendQuery,
|
||||
},
|
||||
prefix
|
||||
);
|
||||
setProviderAPIModule(provider, {
|
||||
prepare: prepareQuery,
|
||||
send: sendQuery,
|
||||
});
|
||||
|
||||
// Load icons
|
||||
API.loadIcons(
|
||||
[
|
||||
// as icon
|
||||
{
|
||||
provider,
|
||||
prefix,
|
||||
name: 'icon1',
|
||||
},
|
||||
// as string
|
||||
prefix + ':icon2',
|
||||
provider + ':' + prefix + ':icon2',
|
||||
],
|
||||
(loaded, missing, pending, unsubscribe) => {
|
||||
// This callback should be called last
|
||||
@ -112,10 +112,12 @@ describe('Testing API loadIcons', () => {
|
||||
|
||||
expect(loaded).to.be.eql([
|
||||
{
|
||||
provider,
|
||||
prefix,
|
||||
name: 'icon1',
|
||||
},
|
||||
{
|
||||
provider,
|
||||
prefix,
|
||||
name: 'icon2',
|
||||
},
|
||||
@ -123,42 +125,54 @@ describe('Testing API loadIcons', () => {
|
||||
expect(missing).to.be.eql([]);
|
||||
expect(pending).to.be.eql([]);
|
||||
|
||||
expect(API.isPending(prefix, 'icon1')).to.be.equal(false);
|
||||
expect(API.isPending(prefix, 'icon3')).to.be.equal(false);
|
||||
expect(
|
||||
API.isPending({
|
||||
provider,
|
||||
prefix,
|
||||
name: 'icon1',
|
||||
})
|
||||
).to.be.equal(false);
|
||||
expect(
|
||||
API.isPending({ provider, prefix, name: 'icon3' })
|
||||
).to.be.equal(false);
|
||||
|
||||
done();
|
||||
}
|
||||
);
|
||||
|
||||
// Test isPending
|
||||
expect(API.isPending(prefix, 'icon1')).to.be.equal(true);
|
||||
expect(API.isPending(prefix, 'icon3')).to.be.equal(false);
|
||||
expect(API.isPending({ provider, prefix, name: 'icon1' })).to.be.equal(
|
||||
true
|
||||
);
|
||||
expect(API.isPending({ provider, prefix, name: 'icon3' })).to.be.equal(
|
||||
false
|
||||
);
|
||||
|
||||
// Make sure asyncCounter wasn't increased because loading shoud happen on next tick
|
||||
expect(asyncCounter).to.be.equal(0);
|
||||
asyncCounter++;
|
||||
});
|
||||
|
||||
it('Split results', done => {
|
||||
it('Split results', (done) => {
|
||||
const provider = nextPrefix();
|
||||
const prefix = nextPrefix();
|
||||
|
||||
// Set config
|
||||
setAPIConfig(
|
||||
{
|
||||
resources: ['https://api1.local', 'https://api2.local'],
|
||||
},
|
||||
prefix
|
||||
);
|
||||
setAPIConfig(provider, {
|
||||
resources: ['https://api1.local', 'https://api2.local'],
|
||||
});
|
||||
|
||||
// Icon loader
|
||||
const prepareQuery = (
|
||||
provider: string,
|
||||
prefix: string,
|
||||
icons: string[]
|
||||
): APIQueryParams[] => {
|
||||
// Split all icons in multiple queries, one icon per query
|
||||
const results: APIQueryParams[] = [];
|
||||
icons.forEach(icon => {
|
||||
icons.forEach((icon) => {
|
||||
const item: APIQueryParams = {
|
||||
provider,
|
||||
prefix,
|
||||
icons: [icon],
|
||||
};
|
||||
@ -182,6 +196,7 @@ describe('Testing API loadIcons', () => {
|
||||
// Icon names should match queryCounter: 'icon1' on first run, 'icon2' on second run
|
||||
queryCounter++;
|
||||
const expected: APIQueryParams = {
|
||||
provider,
|
||||
prefix,
|
||||
icons: ['icon' + queryCounter],
|
||||
};
|
||||
@ -189,7 +204,7 @@ describe('Testing API loadIcons', () => {
|
||||
|
||||
// Send only requested icons
|
||||
const icons = Object.create(null);
|
||||
params.icons.forEach(icon => {
|
||||
params.icons.forEach((icon) => {
|
||||
icons[icon] = {
|
||||
body: '<path d="" />',
|
||||
};
|
||||
@ -200,18 +215,18 @@ describe('Testing API loadIcons', () => {
|
||||
});
|
||||
};
|
||||
|
||||
setAPIModule(
|
||||
{
|
||||
prepare: prepareQuery,
|
||||
send: sendQuery,
|
||||
},
|
||||
prefix
|
||||
);
|
||||
setProviderAPIModule(provider, {
|
||||
prepare: prepareQuery,
|
||||
send: sendQuery,
|
||||
});
|
||||
|
||||
// Load icons
|
||||
let callbackCalled = false;
|
||||
API.loadIcons(
|
||||
[prefix + ':icon1', prefix + ':icon2'],
|
||||
[
|
||||
provider + ':' + prefix + ':icon1',
|
||||
provider + ':' + prefix + ':icon2',
|
||||
],
|
||||
(loaded, missing, pending, unsubscribe) => {
|
||||
// Callback should be called only once because results should be sent in same tick
|
||||
expect(callbackCalled).to.be.equal(false);
|
||||
@ -220,10 +235,12 @@ describe('Testing API loadIcons', () => {
|
||||
// Test data
|
||||
expect(loaded).to.be.eql([
|
||||
{
|
||||
provider,
|
||||
prefix,
|
||||
name: 'icon1',
|
||||
},
|
||||
{
|
||||
provider,
|
||||
prefix,
|
||||
name: 'icon2',
|
||||
},
|
||||
@ -235,24 +252,24 @@ describe('Testing API loadIcons', () => {
|
||||
);
|
||||
});
|
||||
|
||||
it('Fail on default host', done => {
|
||||
it('Fail on default host', (done) => {
|
||||
const provider = nextPrefix();
|
||||
const prefix = nextPrefix();
|
||||
|
||||
// Set config
|
||||
setAPIConfig(
|
||||
{
|
||||
resources: ['https://api1.local', 'https://api2.local'],
|
||||
rotate: 100, // 100ms to speed up test
|
||||
},
|
||||
prefix
|
||||
);
|
||||
setAPIConfig(provider, {
|
||||
resources: ['https://api1.local', 'https://api2.local'],
|
||||
rotate: 100, // 100ms to speed up test
|
||||
});
|
||||
|
||||
// Icon loader
|
||||
const prepareQuery = (
|
||||
provider: string,
|
||||
prefix: string,
|
||||
icons: string[]
|
||||
): APIQueryParams[] => {
|
||||
const item: APIQueryParams = {
|
||||
provider,
|
||||
prefix,
|
||||
icons,
|
||||
};
|
||||
@ -299,18 +316,18 @@ describe('Testing API loadIcons', () => {
|
||||
}
|
||||
};
|
||||
|
||||
setAPIModule(
|
||||
{
|
||||
prepare: prepareQuery,
|
||||
send: sendQuery,
|
||||
},
|
||||
prefix
|
||||
);
|
||||
setProviderAPIModule(provider, {
|
||||
prepare: prepareQuery,
|
||||
send: sendQuery,
|
||||
});
|
||||
|
||||
// Load icons
|
||||
let callbackCalled = false;
|
||||
API.loadIcons(
|
||||
[prefix + ':icon1', prefix + ':icon2'],
|
||||
[
|
||||
provider + ':' + prefix + ':icon1',
|
||||
provider + ':' + prefix + ':icon2',
|
||||
],
|
||||
(loaded, missing, pending, unsubscribe) => {
|
||||
// Callback should be called only once
|
||||
expect(callbackCalled).to.be.equal(false);
|
||||
@ -319,10 +336,12 @@ describe('Testing API loadIcons', () => {
|
||||
// Test data
|
||||
expect(loaded).to.be.eql([
|
||||
{
|
||||
provider,
|
||||
prefix,
|
||||
name: 'icon1',
|
||||
},
|
||||
{
|
||||
provider,
|
||||
prefix,
|
||||
name: 'icon2',
|
||||
},
|
||||
@ -335,24 +354,24 @@ describe('Testing API loadIcons', () => {
|
||||
);
|
||||
});
|
||||
|
||||
it('Fail on default host, multiple queries', done => {
|
||||
it('Fail on default host, multiple queries', (done) => {
|
||||
const provider = nextPrefix();
|
||||
const prefix = nextPrefix();
|
||||
|
||||
// Set config
|
||||
setAPIConfig(
|
||||
{
|
||||
resources: ['https://api1.local', 'https://api2.local'],
|
||||
rotate: 100, // 100ms to speed up test
|
||||
},
|
||||
prefix
|
||||
);
|
||||
setAPIConfig(provider, {
|
||||
resources: ['https://api1.local', 'https://api2.local'],
|
||||
rotate: 100, // 100ms to speed up test
|
||||
});
|
||||
|
||||
// Icon loader
|
||||
const prepareQuery = (
|
||||
provider: string,
|
||||
prefix: string,
|
||||
icons: string[]
|
||||
): APIQueryParams[] => {
|
||||
const item: APIQueryParams = {
|
||||
provider,
|
||||
prefix,
|
||||
icons,
|
||||
};
|
||||
@ -420,18 +439,18 @@ describe('Testing API loadIcons', () => {
|
||||
}
|
||||
};
|
||||
|
||||
setAPIModule(
|
||||
{
|
||||
prepare: prepareQuery,
|
||||
send: sendQuery,
|
||||
},
|
||||
prefix
|
||||
);
|
||||
setProviderAPIModule(provider, {
|
||||
prepare: prepareQuery,
|
||||
send: sendQuery,
|
||||
});
|
||||
|
||||
// Load icons
|
||||
let callbackCalled = false;
|
||||
API.loadIcons(
|
||||
[prefix + ':icon1', prefix + ':icon2'],
|
||||
[
|
||||
provider + ':' + prefix + ':icon1',
|
||||
provider + ':' + prefix + ':icon2',
|
||||
],
|
||||
(loaded, missing, pending, unsubscribe) => {
|
||||
// Callback should be called only once
|
||||
expect(callbackCalled).to.be.equal(false);
|
||||
@ -440,10 +459,12 @@ describe('Testing API loadIcons', () => {
|
||||
// Test data
|
||||
expect(loaded).to.be.eql([
|
||||
{
|
||||
provider,
|
||||
prefix,
|
||||
name: 'icon1',
|
||||
},
|
||||
{
|
||||
provider,
|
||||
prefix,
|
||||
name: 'icon2',
|
||||
},
|
||||
@ -455,7 +476,10 @@ describe('Testing API loadIcons', () => {
|
||||
setTimeout(() => {
|
||||
let callbackCalled = false;
|
||||
API.loadIcons(
|
||||
[prefix + ':icon3', prefix + ':icon4'],
|
||||
[
|
||||
provider + ':' + prefix + ':icon3',
|
||||
provider + ':' + prefix + ':icon4',
|
||||
],
|
||||
(loaded, missing, pending, unsubscribe) => {
|
||||
// Callback should be called only once
|
||||
expect(callbackCalled).to.be.equal(false);
|
||||
@ -464,10 +488,12 @@ describe('Testing API loadIcons', () => {
|
||||
// Test data
|
||||
expect(loaded).to.be.eql([
|
||||
{
|
||||
provider,
|
||||
prefix,
|
||||
name: 'icon3',
|
||||
},
|
||||
{
|
||||
provider,
|
||||
prefix,
|
||||
name: 'icon4',
|
||||
},
|
||||
@ -483,25 +509,25 @@ describe('Testing API loadIcons', () => {
|
||||
);
|
||||
});
|
||||
|
||||
it('Fail on default host, multiple queries with different prefixes', done => {
|
||||
it('Fail on default host, multiple queries with different prefixes', (done) => {
|
||||
const provider = nextPrefix();
|
||||
const prefix = nextPrefix();
|
||||
const prefix2 = nextPrefix();
|
||||
|
||||
// Set config
|
||||
setAPIConfig(
|
||||
{
|
||||
resources: ['https://api1.local', 'https://api2.local'],
|
||||
rotate: 100, // 100ms to speed up test
|
||||
},
|
||||
[prefix, prefix2]
|
||||
);
|
||||
setAPIConfig(provider, {
|
||||
resources: ['https://api1.local', 'https://api2.local'],
|
||||
rotate: 100, // 100ms to speed up test
|
||||
});
|
||||
|
||||
// Icon loader
|
||||
const prepareQuery = (
|
||||
provider: string,
|
||||
prefix: string,
|
||||
icons: string[]
|
||||
): APIQueryParams[] => {
|
||||
const item: APIQueryParams = {
|
||||
provider,
|
||||
prefix,
|
||||
icons,
|
||||
};
|
||||
@ -572,18 +598,18 @@ describe('Testing API loadIcons', () => {
|
||||
}
|
||||
};
|
||||
|
||||
setAPIModule(
|
||||
{
|
||||
prepare: prepareQuery,
|
||||
send: sendQuery,
|
||||
},
|
||||
[prefix, prefix2]
|
||||
);
|
||||
setProviderAPIModule(provider, {
|
||||
prepare: prepareQuery,
|
||||
send: sendQuery,
|
||||
});
|
||||
|
||||
// Load icons
|
||||
let callbackCalled = false;
|
||||
API.loadIcons(
|
||||
[prefix + ':icon1', prefix + ':icon2'],
|
||||
[
|
||||
provider + ':' + prefix + ':icon1',
|
||||
provider + ':' + prefix + ':icon2',
|
||||
],
|
||||
(loaded, missing, pending, unsubscribe) => {
|
||||
// Callback should be called only once
|
||||
expect(callbackCalled).to.be.equal(false);
|
||||
@ -592,10 +618,12 @@ describe('Testing API loadIcons', () => {
|
||||
// Test data
|
||||
expect(loaded).to.be.eql([
|
||||
{
|
||||
provider,
|
||||
prefix,
|
||||
name: 'icon1',
|
||||
},
|
||||
{
|
||||
provider,
|
||||
prefix,
|
||||
name: 'icon2',
|
||||
},
|
||||
@ -607,7 +635,10 @@ describe('Testing API loadIcons', () => {
|
||||
setTimeout(() => {
|
||||
let callbackCalled = false;
|
||||
API.loadIcons(
|
||||
[prefix2 + ':icon2', prefix2 + ':icon4'],
|
||||
[
|
||||
provider + ':' + prefix2 + ':icon2',
|
||||
provider + ':' + prefix2 + ':icon4',
|
||||
],
|
||||
(loaded, missing, pending, unsubscribe) => {
|
||||
// Callback should be called only once
|
||||
expect(callbackCalled).to.be.equal(false);
|
||||
@ -616,10 +647,12 @@ describe('Testing API loadIcons', () => {
|
||||
// Test data
|
||||
expect(loaded).to.be.eql([
|
||||
{
|
||||
provider,
|
||||
prefix: prefix2,
|
||||
name: 'icon2',
|
||||
},
|
||||
{
|
||||
provider,
|
||||
prefix: prefix2,
|
||||
name: 'icon4',
|
||||
},
|
||||
|
@ -14,6 +14,8 @@ import {
|
||||
} from './fake_cache';
|
||||
|
||||
describe('Testing mocked localStorage', () => {
|
||||
const provider = '';
|
||||
|
||||
it('No usable cache', () => {
|
||||
reset({});
|
||||
|
||||
@ -85,6 +87,7 @@ describe('Testing mocked localStorage', () => {
|
||||
cachePrefix + '0',
|
||||
JSON.stringify({
|
||||
cached: Date.now(),
|
||||
provider,
|
||||
data: {
|
||||
prefix: prefix,
|
||||
icons: {
|
||||
@ -143,6 +146,7 @@ describe('Testing mocked localStorage', () => {
|
||||
cachePrefix + '0',
|
||||
JSON.stringify({
|
||||
cached: Date.now(),
|
||||
provider,
|
||||
data: {
|
||||
prefix: prefix,
|
||||
icons: {
|
||||
|
@ -24,6 +24,8 @@ import {
|
||||
import { IconifyIcon, IconifyJSON } from '@iconify/types';
|
||||
|
||||
describe('Testing loading from localStorage', () => {
|
||||
const provider = '';
|
||||
|
||||
it('Valid icon set', () => {
|
||||
const prefix = nextPrefix();
|
||||
const cache = createCache();
|
||||
@ -34,6 +36,7 @@ describe('Testing loading from localStorage', () => {
|
||||
|
||||
const item: StoredItem = {
|
||||
cached: Math.floor(Date.now() / hour),
|
||||
provider,
|
||||
data: {
|
||||
prefix: prefix,
|
||||
icons: {
|
||||
@ -51,7 +54,7 @@ describe('Testing loading from localStorage', () => {
|
||||
});
|
||||
|
||||
// Check icon storage
|
||||
const icons = getStorage(prefix);
|
||||
const icons = getStorage(provider, prefix);
|
||||
expect(iconExists(icons, 'foo')).to.be.equal(false);
|
||||
|
||||
// Load localStorage
|
||||
@ -75,6 +78,64 @@ describe('Testing loading from localStorage', () => {
|
||||
});
|
||||
});
|
||||
|
||||
it('Different provider', () => {
|
||||
const provider = nextPrefix();
|
||||
const prefix = nextPrefix();
|
||||
const cache = createCache();
|
||||
|
||||
// Add one icon set
|
||||
cache.setItem(versionKey, cacheVersion);
|
||||
cache.setItem(countKey, '1');
|
||||
|
||||
const item: StoredItem = {
|
||||
cached: Math.floor(Date.now() / hour),
|
||||
provider,
|
||||
data: {
|
||||
prefix: prefix,
|
||||
icons: {
|
||||
foo: {
|
||||
body: '<g></g>',
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
cache.setItem(cachePrefix + '0', JSON.stringify(item));
|
||||
|
||||
// Set cache
|
||||
reset({
|
||||
localStorage: cache,
|
||||
});
|
||||
|
||||
// Check icon storage
|
||||
const icons = getStorage(provider, prefix);
|
||||
expect(iconExists(icons, 'foo')).to.be.equal(false);
|
||||
|
||||
// Check default provider
|
||||
const icons2 = getStorage('', prefix);
|
||||
expect(iconExists(icons2, 'foo')).to.be.equal(false);
|
||||
|
||||
// Load localStorage
|
||||
loadCache();
|
||||
|
||||
// Icon should exist now
|
||||
expect(iconExists(icons, 'foo')).to.be.equal(true);
|
||||
expect(iconExists(icons2, 'foo')).to.be.equal(false);
|
||||
|
||||
// Check data
|
||||
expect(config).to.be.eql({
|
||||
local: true,
|
||||
session: false,
|
||||
});
|
||||
expect(count).to.be.eql({
|
||||
local: 1,
|
||||
session: 0,
|
||||
});
|
||||
expect(emptyList).to.be.eql({
|
||||
local: [],
|
||||
session: [],
|
||||
});
|
||||
});
|
||||
|
||||
it('Expired icon set', () => {
|
||||
const prefix = nextPrefix();
|
||||
const cache = createCache();
|
||||
@ -86,6 +147,7 @@ describe('Testing loading from localStorage', () => {
|
||||
const item: StoredItem = {
|
||||
// Expiration date
|
||||
cached: Math.floor(Date.now() / hour) - cacheExpiration - 1,
|
||||
provider,
|
||||
data: {
|
||||
prefix: prefix,
|
||||
icons: {
|
||||
@ -103,7 +165,7 @@ describe('Testing loading from localStorage', () => {
|
||||
});
|
||||
|
||||
// Check icon storage
|
||||
const icons = getStorage(prefix);
|
||||
const icons = getStorage(provider, prefix);
|
||||
expect(iconExists(icons, 'foo')).to.be.equal(false);
|
||||
|
||||
// Load localStorage
|
||||
@ -138,6 +200,7 @@ describe('Testing loading from localStorage', () => {
|
||||
cachePrefix + '0',
|
||||
JSON.stringify({
|
||||
cached: Math.floor(Date.now() / hour),
|
||||
provider,
|
||||
data: {
|
||||
prefix: prefix,
|
||||
icons: {
|
||||
@ -156,7 +219,7 @@ describe('Testing loading from localStorage', () => {
|
||||
});
|
||||
|
||||
// Check icon storage
|
||||
const icons = getStorage(prefix);
|
||||
const icons = getStorage(provider, prefix);
|
||||
expect(iconExists(icons, 'foo')).to.be.equal(false);
|
||||
|
||||
// Load localStorage
|
||||
@ -190,6 +253,7 @@ describe('Testing loading from localStorage', () => {
|
||||
|
||||
const item: StoredItem = {
|
||||
cached: Math.floor(Date.now() / hour),
|
||||
provider,
|
||||
data: {
|
||||
prefix: prefix,
|
||||
icons: {
|
||||
@ -207,7 +271,7 @@ describe('Testing loading from localStorage', () => {
|
||||
});
|
||||
|
||||
// Check icon storage
|
||||
const icons = getStorage(prefix);
|
||||
const icons = getStorage(provider, prefix);
|
||||
expect(iconExists(icons, 'foo')).to.be.equal(false);
|
||||
|
||||
// Load localStorage
|
||||
@ -241,6 +305,7 @@ describe('Testing loading from localStorage', () => {
|
||||
|
||||
const item: StoredItem = {
|
||||
cached: Math.floor(Date.now() / hour),
|
||||
provider,
|
||||
data: {
|
||||
prefix: prefix,
|
||||
icons: {
|
||||
@ -258,7 +323,7 @@ describe('Testing loading from localStorage', () => {
|
||||
});
|
||||
|
||||
// Check icon storage
|
||||
const icons = getStorage(prefix);
|
||||
const icons = getStorage(provider, prefix);
|
||||
expect(iconExists(icons, 'foo')).to.be.equal(false);
|
||||
|
||||
// Load localStorage
|
||||
@ -293,6 +358,7 @@ describe('Testing loading from localStorage', () => {
|
||||
// Missing: 0, 2, 3
|
||||
const item1: StoredItem = {
|
||||
cached: Math.floor(Date.now() / hour),
|
||||
provider,
|
||||
data: {
|
||||
prefix: prefix,
|
||||
icons: {
|
||||
@ -304,6 +370,7 @@ describe('Testing loading from localStorage', () => {
|
||||
};
|
||||
const item4: StoredItem = {
|
||||
cached: Math.floor(Date.now() / hour),
|
||||
provider,
|
||||
data: {
|
||||
prefix: prefix,
|
||||
icons: {
|
||||
@ -323,7 +390,7 @@ describe('Testing loading from localStorage', () => {
|
||||
});
|
||||
|
||||
// Check icon storage
|
||||
const icons = getStorage(prefix);
|
||||
const icons = getStorage(provider, prefix);
|
||||
expect(iconExists(icons, 'foo1')).to.be.equal(false);
|
||||
expect(iconExists(icons, 'foo4')).to.be.equal(false);
|
||||
|
||||
@ -376,6 +443,7 @@ describe('Testing loading from localStorage', () => {
|
||||
};
|
||||
const item: StoredItem = {
|
||||
cached: Math.floor(Date.now() / hour),
|
||||
provider,
|
||||
data: icon,
|
||||
};
|
||||
icons.push(icon);
|
||||
@ -399,7 +467,7 @@ describe('Testing loading from localStorage', () => {
|
||||
});
|
||||
|
||||
// Check icon storage
|
||||
const iconsStorage = getStorage(prefix);
|
||||
const iconsStorage = getStorage(provider, prefix);
|
||||
for (let i = 0; i < 6; i++) {
|
||||
expect(iconExists(iconsStorage, 'foo' + i)).to.be.equal(
|
||||
false,
|
||||
|
@ -25,6 +25,8 @@ import {
|
||||
import { IconifyJSON } from '@iconify/types';
|
||||
|
||||
describe('Testing saving to localStorage', () => {
|
||||
const provider = '';
|
||||
|
||||
it('One icon set', () => {
|
||||
const prefix = nextPrefix();
|
||||
const cache = createCache();
|
||||
@ -40,6 +42,7 @@ describe('Testing saving to localStorage', () => {
|
||||
};
|
||||
const item: StoredItem = {
|
||||
cached: Math.floor(Date.now() / hour),
|
||||
provider,
|
||||
data: icon,
|
||||
};
|
||||
|
||||
@ -49,11 +52,11 @@ describe('Testing saving to localStorage', () => {
|
||||
});
|
||||
|
||||
// Check icon storage
|
||||
const icons = getStorage(prefix);
|
||||
const icons = getStorage(provider, prefix);
|
||||
expect(iconExists(icons, 'foo')).to.be.equal(false);
|
||||
|
||||
// Save item
|
||||
storeCache(icon);
|
||||
storeCache(provider, icon);
|
||||
|
||||
// Storing in cache should not add item to storage
|
||||
expect(iconExists(icons, 'foo')).to.be.equal(false);
|
||||
@ -96,6 +99,7 @@ describe('Testing saving to localStorage', () => {
|
||||
};
|
||||
const item0: StoredItem = {
|
||||
cached: Math.floor(Date.now() / hour),
|
||||
provider,
|
||||
data: icon0,
|
||||
};
|
||||
const icon1: IconifyJSON = {
|
||||
@ -108,6 +112,7 @@ describe('Testing saving to localStorage', () => {
|
||||
};
|
||||
const item1: StoredItem = {
|
||||
cached: Math.floor(Date.now() / hour),
|
||||
provider,
|
||||
data: icon1,
|
||||
};
|
||||
|
||||
@ -117,8 +122,8 @@ describe('Testing saving to localStorage', () => {
|
||||
});
|
||||
|
||||
// Save items
|
||||
storeCache(icon0);
|
||||
storeCache(icon1);
|
||||
storeCache(provider, icon0);
|
||||
storeCache(provider, icon1);
|
||||
|
||||
// Check data that should have been updated because storeCache()
|
||||
// should call load function before first execution
|
||||
@ -161,6 +166,7 @@ describe('Testing saving to localStorage', () => {
|
||||
};
|
||||
const item0: StoredItem = {
|
||||
cached: Math.floor(Date.now() / hour),
|
||||
provider,
|
||||
data: icon0,
|
||||
};
|
||||
const icon1: IconifyJSON = {
|
||||
@ -173,6 +179,7 @@ describe('Testing saving to localStorage', () => {
|
||||
};
|
||||
const item1: StoredItem = {
|
||||
cached: Math.floor(Date.now() / hour),
|
||||
provider,
|
||||
data: icon1,
|
||||
};
|
||||
|
||||
@ -204,7 +211,7 @@ describe('Testing saving to localStorage', () => {
|
||||
});
|
||||
|
||||
// Save items
|
||||
storeCache(icon0);
|
||||
storeCache(provider, icon0);
|
||||
|
||||
// Check data
|
||||
expect(count).to.be.eql({
|
||||
@ -245,6 +252,7 @@ describe('Testing saving to localStorage', () => {
|
||||
};
|
||||
const item: StoredItem = {
|
||||
cached: Math.floor(Date.now() / hour),
|
||||
provider,
|
||||
data: icon,
|
||||
};
|
||||
|
||||
@ -313,7 +321,7 @@ describe('Testing saving to localStorage', () => {
|
||||
});
|
||||
|
||||
// Add item 5
|
||||
storeCache(icons[5]);
|
||||
storeCache(provider, icons[5]);
|
||||
expect(count).to.be.eql({
|
||||
local: 0,
|
||||
session: 9,
|
||||
@ -328,7 +336,7 @@ describe('Testing saving to localStorage', () => {
|
||||
const list = [4, 2, 1];
|
||||
list.slice(0).forEach((index) => {
|
||||
expect(list.shift()).to.be.equal(index);
|
||||
storeCache(icons[index]);
|
||||
storeCache(provider, icons[index]);
|
||||
expect(count).to.be.eql({
|
||||
local: 0,
|
||||
session: 9,
|
||||
@ -341,7 +349,7 @@ describe('Testing saving to localStorage', () => {
|
||||
});
|
||||
|
||||
// Add item 10
|
||||
storeCache(icons[10]);
|
||||
storeCache(provider, icons[10]);
|
||||
expect(count).to.be.eql({
|
||||
local: 0,
|
||||
session: 10,
|
||||
@ -353,7 +361,7 @@ describe('Testing saving to localStorage', () => {
|
||||
expect(cache.getItem(countKey)).to.be.equal('10');
|
||||
|
||||
// Add item 11
|
||||
storeCache(icons[11]);
|
||||
storeCache(provider, icons[11]);
|
||||
expect(count).to.be.eql({
|
||||
local: 0,
|
||||
session: 11,
|
||||
@ -392,7 +400,7 @@ describe('Testing saving to localStorage', () => {
|
||||
});
|
||||
|
||||
// Check icon storage
|
||||
const icons = getStorage(prefix);
|
||||
const icons = getStorage(provider, prefix);
|
||||
expect(iconExists(icons, 'foo1')).to.be.equal(false);
|
||||
|
||||
// Load cache
|
||||
@ -422,11 +430,12 @@ describe('Testing saving to localStorage', () => {
|
||||
};
|
||||
const item: StoredItem = {
|
||||
cached: Math.floor(Date.now() / hour),
|
||||
provider,
|
||||
data: icon,
|
||||
};
|
||||
|
||||
// Save item
|
||||
storeCache(icon);
|
||||
storeCache(provider, icon);
|
||||
|
||||
// Storing in cache should not add item to storage
|
||||
expect(iconExists(icons, 'foo')).to.be.equal(false);
|
||||
@ -473,6 +482,7 @@ describe('Testing saving to localStorage', () => {
|
||||
};
|
||||
const item: StoredItem = {
|
||||
cached: Math.floor(Date.now() / hour),
|
||||
provider,
|
||||
data: icon,
|
||||
};
|
||||
cache1.setItem(cachePrefix + index, JSON.stringify(item));
|
||||
@ -492,6 +502,7 @@ describe('Testing saving to localStorage', () => {
|
||||
};
|
||||
const item: StoredItem = {
|
||||
cached: Math.floor(Date.now() / hour),
|
||||
provider,
|
||||
data: icon,
|
||||
};
|
||||
cache2.setItem(cachePrefix + index, JSON.stringify(item));
|
||||
@ -521,7 +532,7 @@ describe('Testing saving to localStorage', () => {
|
||||
});
|
||||
|
||||
// Check icon storage
|
||||
const iconsStorage = getStorage(prefix);
|
||||
const iconsStorage = getStorage(provider, prefix);
|
||||
for (let i = 0; i < count.local; i++) {
|
||||
expect(iconExists(iconsStorage, 'foo' + i)).to.be.equal(
|
||||
true,
|
||||
@ -546,9 +557,10 @@ describe('Testing saving to localStorage', () => {
|
||||
};
|
||||
const item: StoredItem = {
|
||||
cached: Math.floor(Date.now() / hour),
|
||||
provider,
|
||||
data: icon,
|
||||
};
|
||||
storeCache(icon);
|
||||
storeCache(provider, icon);
|
||||
|
||||
// Check data
|
||||
expect(count).to.be.eql({
|
||||
@ -585,6 +597,7 @@ describe('Testing saving to localStorage', () => {
|
||||
};
|
||||
const item: StoredItem = {
|
||||
cached: Math.floor(Date.now() / hour),
|
||||
provider,
|
||||
data: icon,
|
||||
};
|
||||
cache1.setItem(cachePrefix + index, JSON.stringify(item));
|
||||
@ -604,6 +617,7 @@ describe('Testing saving to localStorage', () => {
|
||||
};
|
||||
const item: StoredItem = {
|
||||
cached: Math.floor(Date.now() / hour),
|
||||
provider,
|
||||
data: icon,
|
||||
};
|
||||
cache2.setItem(cachePrefix + index, JSON.stringify(item));
|
||||
@ -633,7 +647,7 @@ describe('Testing saving to localStorage', () => {
|
||||
});
|
||||
|
||||
// Check icon storage
|
||||
const iconsStorage = getStorage(prefix);
|
||||
const iconsStorage = getStorage(provider, prefix);
|
||||
for (let i = 0; i < count.local; i++) {
|
||||
expect(iconExists(iconsStorage, 'foo' + i)).to.be.equal(
|
||||
true,
|
||||
@ -661,9 +675,10 @@ describe('Testing saving to localStorage', () => {
|
||||
};
|
||||
const item: StoredItem = {
|
||||
cached: Math.floor(Date.now() / hour),
|
||||
provider,
|
||||
data: icon,
|
||||
};
|
||||
storeCache(icon);
|
||||
storeCache(provider, icon);
|
||||
|
||||
// Check data
|
||||
expect(count).to.be.eql({
|
||||
|
@ -9,7 +9,7 @@ export function nextPrefix(): string {
|
||||
}
|
||||
|
||||
// Cache version. Bump when structure changes
|
||||
export const cacheVersion = 'iconify1';
|
||||
export const cacheVersion = 'iconify2';
|
||||
|
||||
// Cache keys
|
||||
export const cachePrefix = 'iconify';
|
||||
|
@ -19,6 +19,7 @@ import {
|
||||
getIcon,
|
||||
addIcon,
|
||||
addIconSet,
|
||||
listStoredProviders,
|
||||
listStoredPrefixes,
|
||||
} from '@iconify/core/lib/storage';
|
||||
import { iconToSVG, IconifyIconBuildResult } from '@iconify/core/lib/builder';
|
||||
@ -39,7 +40,7 @@ import { storeCache, loadCache, config } from '@iconify/core/lib/cache/storage';
|
||||
|
||||
// API
|
||||
import { API } from '@iconify/core/lib/api/';
|
||||
import { setAPIModule } from '@iconify/core/lib/api/modules';
|
||||
import { setDefaultAPIModule } from '@iconify/core/lib/api/modules';
|
||||
import { setAPIConfig, IconifyAPIConfig } from '@iconify/core/lib/api/config';
|
||||
import { prepareQuery, sendQuery } from './modules/api-jsonp';
|
||||
import {
|
||||
@ -105,7 +106,7 @@ export interface IconifyGlobal {
|
||||
/**
|
||||
* List all available icons
|
||||
*/
|
||||
listIcons: (prefix?: string) => string[];
|
||||
listIcons: (provider?: string, prefix?: string) => string[];
|
||||
|
||||
/**
|
||||
* Load icons
|
||||
@ -157,7 +158,7 @@ export interface IconifyGlobal {
|
||||
/**
|
||||
* Add icon set to storage
|
||||
*/
|
||||
addCollection: (data: IconifyJSON) => boolean;
|
||||
addCollection: (data: IconifyJSON, provider?: string) => boolean;
|
||||
|
||||
/* API stuff */
|
||||
/**
|
||||
@ -174,8 +175,8 @@ export interface IconifyGlobal {
|
||||
* Set API configuration
|
||||
*/
|
||||
setAPIConfig: (
|
||||
customConfig: Partial<IconifyAPIConfig>,
|
||||
prefix?: string | string[]
|
||||
provider: string,
|
||||
customConfig: Partial<IconifyAPIConfig>
|
||||
) => void;
|
||||
|
||||
/* Scan DOM */
|
||||
@ -211,7 +212,9 @@ function getIconName(name: string): IconifyIconName | null {
|
||||
*/
|
||||
function getIconData(name: string): FullIconifyIcon | null {
|
||||
const icon = getIconName(name);
|
||||
return icon ? getIcon(getStorage(icon.prefix), icon.name) : null;
|
||||
return icon
|
||||
? getIcon(getStorage(icon.provider, icon.prefix), icon.name)
|
||||
: null;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -282,23 +285,38 @@ const Iconify: IconifyGlobal = {
|
||||
},
|
||||
|
||||
// List icons
|
||||
listIcons: (prefix?: string) => {
|
||||
listIcons: (provider?: string, prefix?: string) => {
|
||||
let icons = [];
|
||||
|
||||
let prefixes = listStoredPrefixes();
|
||||
let addPrefix = true;
|
||||
if (typeof prefix === 'string') {
|
||||
prefixes = prefixes.indexOf(prefix) !== -1 ? [] : [prefix];
|
||||
addPrefix = false;
|
||||
// Get providers
|
||||
let providers: string[];
|
||||
if (typeof provider === 'string') {
|
||||
providers = [provider];
|
||||
} else {
|
||||
providers = listStoredProviders();
|
||||
}
|
||||
|
||||
prefixes.forEach((prefix) => {
|
||||
const storage = getStorage(prefix);
|
||||
let icons = Object.keys(storage.icons);
|
||||
if (addPrefix) {
|
||||
icons = icons.map((name) => prefix + ':' + name);
|
||||
// Get all icons
|
||||
providers.forEach((provider) => {
|
||||
let prefixes: string[];
|
||||
|
||||
if (typeof prefix === 'string') {
|
||||
prefixes = [prefix];
|
||||
} else {
|
||||
prefixes = listStoredPrefixes(provider);
|
||||
}
|
||||
icons = icons.concat(icons);
|
||||
|
||||
prefixes.forEach((prefix) => {
|
||||
const storage = getStorage(provider, prefix);
|
||||
let icons = Object.keys(storage.icons).map(
|
||||
(name) =>
|
||||
(provider !== '' ? '@' + provider + ':' : '') +
|
||||
prefix +
|
||||
':' +
|
||||
name
|
||||
);
|
||||
icons = icons.concat(icons);
|
||||
});
|
||||
});
|
||||
|
||||
return icons;
|
||||
@ -331,16 +349,21 @@ const Iconify: IconifyGlobal = {
|
||||
if (!icon) {
|
||||
return false;
|
||||
}
|
||||
const storage = getStorage(icon.prefix);
|
||||
const storage = getStorage(icon.provider, icon.prefix);
|
||||
return addIcon(storage, icon.name, data);
|
||||
},
|
||||
|
||||
// Add icon set
|
||||
addCollection: (data) => {
|
||||
addCollection: (data, provider?: string) => {
|
||||
if (typeof provider !== 'string') {
|
||||
provider = '';
|
||||
}
|
||||
|
||||
if (
|
||||
typeof data !== 'object' ||
|
||||
typeof data.prefix !== 'string' ||
|
||||
!validateIcon({
|
||||
provider,
|
||||
prefix: data.prefix,
|
||||
name: 'a',
|
||||
})
|
||||
@ -348,7 +371,7 @@ const Iconify: IconifyGlobal = {
|
||||
return false;
|
||||
}
|
||||
|
||||
const storage = getStorage(data.prefix);
|
||||
const storage = getStorage(provider, data.prefix);
|
||||
return !!addIconSet(storage, data);
|
||||
},
|
||||
|
||||
@ -404,11 +427,11 @@ coreModules.cache = storeCache;
|
||||
loadCache();
|
||||
|
||||
// Set API
|
||||
setAPIModule({
|
||||
coreModules.api = API;
|
||||
setDefaultAPIModule({
|
||||
send: sendQuery,
|
||||
prepare: prepareQuery,
|
||||
});
|
||||
coreModules.api = API;
|
||||
|
||||
// Load observer
|
||||
browserModules.observer = observer;
|
||||
|
@ -84,9 +84,9 @@ function getGlobal(): JSONPRoot {
|
||||
/**
|
||||
* Calculate maximum icons list length for prefix
|
||||
*/
|
||||
function calculateMaxLength(prefix: string): number {
|
||||
function calculateMaxLength(provider: string, prefix: string): number {
|
||||
// Get config and store path
|
||||
const config = getAPIConfig(prefix);
|
||||
const config = getAPIConfig(provider);
|
||||
if (!config) {
|
||||
return 0;
|
||||
}
|
||||
@ -112,7 +112,10 @@ function calculateMaxLength(prefix: string): number {
|
||||
config.maxURL -
|
||||
maxHostLength -
|
||||
config.path.length -
|
||||
endPoint.replace('{prefix}', prefix).replace('{icons}', '').length -
|
||||
endPoint
|
||||
.replace('{provider}', provider)
|
||||
.replace('{prefix}', prefix)
|
||||
.replace('{icons}', '').length -
|
||||
extraLength;
|
||||
}
|
||||
|
||||
@ -126,6 +129,7 @@ function calculateMaxLength(prefix: string): number {
|
||||
* Prepare params
|
||||
*/
|
||||
export const prepareQuery: IconifyAPIPrepareQuery = (
|
||||
provider: string,
|
||||
prefix: string,
|
||||
icons: string[]
|
||||
): APIQueryParams[] => {
|
||||
@ -134,11 +138,12 @@ export const prepareQuery: IconifyAPIPrepareQuery = (
|
||||
// Get maximum icons list length
|
||||
let maxLength = maxLengthCache[prefix];
|
||||
if (maxLength === void 0) {
|
||||
maxLength = calculateMaxLength(prefix);
|
||||
maxLength = calculateMaxLength(provider, prefix);
|
||||
}
|
||||
|
||||
// Split icons
|
||||
let item: APIQueryParams = {
|
||||
provider,
|
||||
prefix,
|
||||
icons: [],
|
||||
};
|
||||
@ -149,6 +154,7 @@ export const prepareQuery: IconifyAPIPrepareQuery = (
|
||||
// Next set
|
||||
results.push(item);
|
||||
item = {
|
||||
provider,
|
||||
prefix,
|
||||
icons: [],
|
||||
};
|
||||
@ -170,6 +176,7 @@ export const sendQuery: IconifyAPISendQuery = (
|
||||
params: APIQueryParams,
|
||||
status: RedundancyPendingItem
|
||||
): void => {
|
||||
const provider = params.provider;
|
||||
const prefix = params.prefix;
|
||||
const icons = params.icons;
|
||||
const iconsList = icons.join(',');
|
||||
@ -180,7 +187,9 @@ export const sendQuery: IconifyAPISendQuery = (
|
||||
const global = getGlobal();
|
||||
|
||||
// Callback hash
|
||||
let cbCounter = hash(host + ':' + prefix + ':' + iconsList);
|
||||
let cbCounter = hash(
|
||||
provider + ':' + host + ':' + prefix + ':' + iconsList
|
||||
);
|
||||
while (global[cbPrefix + cbCounter] !== void 0) {
|
||||
cbCounter++;
|
||||
}
|
||||
@ -189,6 +198,7 @@ export const sendQuery: IconifyAPISendQuery = (
|
||||
let path =
|
||||
pathCache[prefix] +
|
||||
endPoint
|
||||
.replace('{provider}', provider)
|
||||
.replace('{prefix}', prefix)
|
||||
.replace('{icons}', iconsList)
|
||||
.replace('{cb}', callbackName);
|
||||
|
@ -53,18 +53,20 @@ export function scanDOM(root?: HTMLElement): void {
|
||||
// Observer
|
||||
let paused = false;
|
||||
|
||||
// List of icons to load
|
||||
const loadIcons: Record<string, Record<string, boolean>> = Object.create(
|
||||
null
|
||||
);
|
||||
// List of icons to load: [provider][prefix][name] = boolean
|
||||
const loadIcons: Record<
|
||||
string,
|
||||
Record<string, Record<string, boolean>>
|
||||
> = Object.create(null);
|
||||
|
||||
// Get root node and placeholders
|
||||
if (!root) {
|
||||
root = getRoot();
|
||||
}
|
||||
findPlaceholders(root).forEach(item => {
|
||||
findPlaceholders(root).forEach((item) => {
|
||||
const element = item.element;
|
||||
const iconName = item.name;
|
||||
const provider = iconName.provider;
|
||||
const prefix = iconName.prefix;
|
||||
const name = iconName.name;
|
||||
let data: IconifyElementData = element[elementDataProperty];
|
||||
@ -79,7 +81,7 @@ export function scanDOM(root?: HTMLElement): void {
|
||||
case 'loading':
|
||||
if (
|
||||
coreModules.api &&
|
||||
coreModules.api.isPending(prefix, name)
|
||||
coreModules.api.isPending({ provider, prefix, name })
|
||||
) {
|
||||
// Pending
|
||||
return;
|
||||
@ -88,7 +90,7 @@ export function scanDOM(root?: HTMLElement): void {
|
||||
}
|
||||
|
||||
// Check icon
|
||||
const storage = getStorage(prefix);
|
||||
const storage = getStorage(provider, prefix);
|
||||
if (storage.icons[name] !== void 0) {
|
||||
// Icon exists - replace placeholder
|
||||
if (browserModules.observer && !paused) {
|
||||
@ -124,12 +126,16 @@ export function scanDOM(root?: HTMLElement): void {
|
||||
}
|
||||
|
||||
if (coreModules.api) {
|
||||
if (!coreModules.api.isPending(prefix, name)) {
|
||||
if (!coreModules.api.isPending({ provider, prefix, name })) {
|
||||
// Add icon to loading queue
|
||||
if (loadIcons[prefix] === void 0) {
|
||||
loadIcons[prefix] = Object.create(null);
|
||||
if (loadIcons[provider] === void 0) {
|
||||
loadIcons[provider] = Object.create(null);
|
||||
}
|
||||
loadIcons[prefix][name] = true;
|
||||
const providerLoadIcons = loadIcons[provider];
|
||||
if (providerLoadIcons[prefix] === void 0) {
|
||||
providerLoadIcons[prefix] = Object.create(null);
|
||||
}
|
||||
providerLoadIcons[prefix][name] = true;
|
||||
}
|
||||
}
|
||||
|
||||
@ -145,17 +151,21 @@ export function scanDOM(root?: HTMLElement): void {
|
||||
// Load icons
|
||||
if (coreModules.api) {
|
||||
const api = coreModules.api;
|
||||
Object.keys(loadIcons).forEach(prefix => {
|
||||
api.loadIcons(
|
||||
Object.keys(loadIcons[prefix]).map(name => {
|
||||
const icon: IconifyIconName = {
|
||||
prefix,
|
||||
name,
|
||||
};
|
||||
return icon;
|
||||
}),
|
||||
checkPendingIcons
|
||||
);
|
||||
Object.keys(loadIcons).forEach((provider) => {
|
||||
const providerLoadIcons = loadIcons[provider];
|
||||
Object.keys(providerLoadIcons).forEach((prefix) => {
|
||||
api.loadIcons(
|
||||
Object.keys(providerLoadIcons[prefix]).map((name) => {
|
||||
const icon: IconifyIconName = {
|
||||
provider,
|
||||
prefix,
|
||||
name,
|
||||
};
|
||||
return icon;
|
||||
}),
|
||||
checkPendingIcons
|
||||
);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user