mirror of
https://github.com/iconify/iconify.git
synced 2024-09-20 01:09:04 +00:00
Change behavior of scanDOM in SVG framework when used with custom root node
This commit is contained in:
parent
4207fd254a
commit
d1bd40bcb0
@ -6,7 +6,7 @@ import { addFinder } from '@iconify/iconify/lib/modules/finder';
|
|||||||
import { finder as iconifyFinder } from '@iconify/iconify/lib/finders/iconify';
|
import { finder as iconifyFinder } from '@iconify/iconify/lib/finders/iconify';
|
||||||
import { finder as iconifyIconFinder } from '@iconify/iconify/lib/finders/iconify-icon';
|
import { finder as iconifyIconFinder } from '@iconify/iconify/lib/finders/iconify-icon';
|
||||||
import { getStorage, addIconSet } from '@iconify/core/lib/storage';
|
import { getStorage, addIconSet } from '@iconify/core/lib/storage';
|
||||||
import { setRoot } from '@iconify/iconify/lib/modules/root';
|
import { setRoot, getRootNodes } from '@iconify/iconify/lib/modules/root';
|
||||||
import { scanDOM } from '@iconify/iconify/lib/modules/scanner';
|
import { scanDOM } from '@iconify/iconify/lib/modules/scanner';
|
||||||
|
|
||||||
const expect = chai.expect;
|
const expect = chai.expect;
|
||||||
@ -42,6 +42,9 @@ describe('Scanning DOM', () => {
|
|||||||
height: 24,
|
height: 24,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Sanity check before running tests
|
||||||
|
expect(getRootNodes()).to.be.eql([]);
|
||||||
|
|
||||||
it('Scan DOM with preloaded icons', () => {
|
it('Scan DOM with preloaded icons', () => {
|
||||||
const node = getNode('scan-dom');
|
const node = getNode('scan-dom');
|
||||||
node.innerHTML =
|
node.innerHTML =
|
||||||
@ -56,29 +59,46 @@ describe('Scanning DOM', () => {
|
|||||||
'</li>' +
|
'</li>' +
|
||||||
'</ul></div>';
|
'</ul></div>';
|
||||||
|
|
||||||
|
// Scan node
|
||||||
setRoot(node);
|
setRoot(node);
|
||||||
scanDOM();
|
scanDOM();
|
||||||
|
|
||||||
// Find elements
|
// Find elements
|
||||||
const elements = node.querySelectorAll('svg.iconify');
|
const elements = node.querySelectorAll('svg.iconify');
|
||||||
expect(elements.length).to.be.equal(4);
|
expect(elements.length).to.be.equal(4);
|
||||||
|
|
||||||
|
// Make sure tempoary node was not added as root, but new root node was
|
||||||
|
expect(getRootNodes()).to.be.eql([
|
||||||
|
{
|
||||||
|
node: node,
|
||||||
|
temporary: false,
|
||||||
|
},
|
||||||
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Scan DOM with unattached root', () => {
|
it('Scan DOM with unattached root', () => {
|
||||||
const node = document.createElement('div');
|
const node = document.createElement('div');
|
||||||
node.innerHTML = '<span class="iconify" data-icon="mdi:home"></span>';
|
node.innerHTML = '<span class="iconify" data-icon="mdi:home"></span>';
|
||||||
|
|
||||||
|
// Get old root nodes. It should not be empty because of previous test(s)
|
||||||
|
const oldRoot = getRootNodes();
|
||||||
|
|
||||||
|
// Scan node
|
||||||
scanDOM(node);
|
scanDOM(node);
|
||||||
|
|
||||||
// Find elements
|
// Find elements
|
||||||
const elements = node.querySelectorAll('svg.iconify');
|
const elements = node.querySelectorAll('svg.iconify');
|
||||||
expect(elements.length).to.be.equal(1);
|
expect(elements.length).to.be.equal(1);
|
||||||
|
|
||||||
|
// Make sure tempoary node was not added as root
|
||||||
|
expect(getRootNodes()).to.be.eql(oldRoot);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Scan DOM with icon as root', () => {
|
it('Scan DOM with icon as root', () => {
|
||||||
const node = document.createElement('span');
|
const node = document.createElement('span');
|
||||||
node.setAttribute('data-icon', 'mdi:home');
|
node.setAttribute('data-icon', 'mdi:home');
|
||||||
|
|
||||||
|
// Scan node
|
||||||
scanDOM(node);
|
scanDOM(node);
|
||||||
|
|
||||||
// Check node
|
// Check node
|
||||||
|
117
packages/browser-tests/tests/21-observe-dom-test.ts
Normal file
117
packages/browser-tests/tests/21-observe-dom-test.ts
Normal file
@ -0,0 +1,117 @@
|
|||||||
|
import mocha from 'mocha';
|
||||||
|
import chai from 'chai';
|
||||||
|
|
||||||
|
import { getNode } from './node';
|
||||||
|
import { addFinder } from '@iconify/iconify/lib/modules/finder';
|
||||||
|
import { finder as iconifyFinder } from '@iconify/iconify/lib/finders/iconify';
|
||||||
|
import { finder as iconifyIconFinder } from '@iconify/iconify/lib/finders/iconify-icon';
|
||||||
|
import { getStorage, addIconSet } from '@iconify/core/lib/storage';
|
||||||
|
import { setRoot, getRootNodes } from '@iconify/iconify/lib/modules/root';
|
||||||
|
import { scanDOM } from '@iconify/iconify/lib/modules/scanner';
|
||||||
|
import { initObserver } from '@iconify/iconify/lib/modules/observer';
|
||||||
|
|
||||||
|
const expect = chai.expect;
|
||||||
|
|
||||||
|
// Add finders
|
||||||
|
addFinder(iconifyFinder);
|
||||||
|
addFinder(iconifyIconFinder);
|
||||||
|
|
||||||
|
describe('Observe DOM', () => {
|
||||||
|
// Add mentioned icons to storage
|
||||||
|
const storage = getStorage('', 'mdi');
|
||||||
|
addIconSet(storage, {
|
||||||
|
prefix: 'mdi',
|
||||||
|
icons: {
|
||||||
|
'account-box': {
|
||||||
|
body:
|
||||||
|
'<path d="M6 17c0-2 4-3.1 6-3.1s6 1.1 6 3.1v1H6m9-9a3 3 0 0 1-3 3a3 3 0 0 1-3-3a3 3 0 0 1 3-3a3 3 0 0 1 3 3M3 5v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2V5a2 2 0 0 0-2-2H5a2 2 0 0 0-2 2z" fill="currentColor"/>',
|
||||||
|
},
|
||||||
|
'account-cash': {
|
||||||
|
body:
|
||||||
|
'<path d="M11 8c0 2.21-1.79 4-4 4s-4-1.79-4-4s1.79-4 4-4s4 1.79 4 4m0 6.72V20H0v-2c0-2.21 3.13-4 7-4c1.5 0 2.87.27 4 .72M24 20H13V3h11v17m-8-8.5a2.5 2.5 0 0 1 5 0a2.5 2.5 0 0 1-5 0M22 7a2 2 0 0 1-2-2h-3c0 1.11-.89 2-2 2v9a2 2 0 0 1 2 2h3c0-1.1.9-2 2-2V7z" fill="currentColor"/>',
|
||||||
|
},
|
||||||
|
'account': {
|
||||||
|
body:
|
||||||
|
'<path d="M12 4a4 4 0 0 1 4 4a4 4 0 0 1-4 4a4 4 0 0 1-4-4a4 4 0 0 1 4-4m0 10c4.42 0 8 1.79 8 4v2H4v-2c0-2.21 3.58-4 8-4z" fill="currentColor"/>',
|
||||||
|
},
|
||||||
|
'home': {
|
||||||
|
body:
|
||||||
|
'<path d="M10 20v-6h4v6h5v-8h3L12 3L2 12h3v8h5z" fill="currentColor"/>',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
width: 24,
|
||||||
|
height: 24,
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Basic test', (done) => {
|
||||||
|
const node = getNode('observe-dom');
|
||||||
|
|
||||||
|
// Set root and init observer
|
||||||
|
setRoot(node);
|
||||||
|
initObserver(scanDOM);
|
||||||
|
|
||||||
|
// Test getRootNodes
|
||||||
|
expect(getRootNodes()).to.be.eql([
|
||||||
|
{
|
||||||
|
node: node,
|
||||||
|
temporary: false,
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
|
||||||
|
// Set HTML
|
||||||
|
node.innerHTML =
|
||||||
|
'<p>Testing observing DOM</p>' +
|
||||||
|
'<span class="iconify" data-icon="mdi:home"></span>';
|
||||||
|
|
||||||
|
// Test nodes
|
||||||
|
setTimeout(() => {
|
||||||
|
// Find elements
|
||||||
|
const elements = node.querySelectorAll('svg.iconify');
|
||||||
|
expect(elements.length).to.be.equal(1);
|
||||||
|
|
||||||
|
// Test for "home" icon contents
|
||||||
|
expect(node.innerHTML.indexOf('20v-6h4v6h5v')).to.not.be.equal(-1);
|
||||||
|
|
||||||
|
done();
|
||||||
|
}, 100);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Change icon', (done) => {
|
||||||
|
const node = getNode('observe-dom');
|
||||||
|
|
||||||
|
// Set root and init observer
|
||||||
|
setRoot(node);
|
||||||
|
initObserver(scanDOM);
|
||||||
|
|
||||||
|
// Set HTML
|
||||||
|
node.innerHTML =
|
||||||
|
'<p>Testing observing DOM</p>' +
|
||||||
|
'<span class="iconify" data-icon="mdi:home"></span>';
|
||||||
|
|
||||||
|
// Test nodes
|
||||||
|
setTimeout(() => {
|
||||||
|
// Find elements
|
||||||
|
const elements = node.querySelectorAll('svg.iconify');
|
||||||
|
expect(elements.length).to.be.equal(1);
|
||||||
|
|
||||||
|
// Test for "home" icon contents
|
||||||
|
expect(node.innerHTML.indexOf('20v-6h4v6h5v')).to.not.be.equal(-1);
|
||||||
|
|
||||||
|
// Change icon
|
||||||
|
elements[0].setAttribute('data-icon', 'mdi:account');
|
||||||
|
|
||||||
|
// Test nodes after timer
|
||||||
|
setTimeout(() => {
|
||||||
|
// Find elements
|
||||||
|
const elements = node.querySelectorAll('svg.iconify');
|
||||||
|
expect(elements.length).to.be.equal(1);
|
||||||
|
|
||||||
|
// Test for "home" icon contents
|
||||||
|
expect(node.innerHTML.indexOf('20v-6h4v6h5v')).to.be.equal(-1);
|
||||||
|
expect(node.innerHTML.indexOf('M12 4a4')).to.not.be.equal(-1);
|
||||||
|
|
||||||
|
done();
|
||||||
|
}, 100);
|
||||||
|
}, 100);
|
||||||
|
});
|
||||||
|
});
|
@ -10,7 +10,7 @@ import { setAPIConfig } from '@iconify/core/lib/api/config';
|
|||||||
import { coreModules } from '@iconify/core/lib/modules';
|
import { coreModules } from '@iconify/core/lib/modules';
|
||||||
import { finder as iconifyFinder } from '@iconify/iconify/lib/finders/iconify';
|
import { finder as iconifyFinder } from '@iconify/iconify/lib/finders/iconify';
|
||||||
import { finder as iconifyIconFinder } from '@iconify/iconify/lib/finders/iconify-icon';
|
import { finder as iconifyIconFinder } from '@iconify/iconify/lib/finders/iconify-icon';
|
||||||
import { setRoot } from '@iconify/iconify/lib/modules/root';
|
import { setRoot, getRootNodes } from '@iconify/iconify/lib/modules/root';
|
||||||
import { scanDOM } from '@iconify/iconify/lib/modules/scanner';
|
import { scanDOM } from '@iconify/iconify/lib/modules/scanner';
|
||||||
|
|
||||||
const expect = chai.expect;
|
const expect = chai.expect;
|
||||||
@ -114,10 +114,18 @@ describe('Scanning DOM with API', () => {
|
|||||||
'</li>' +
|
'</li>' +
|
||||||
'</ul></div>';
|
'</ul></div>';
|
||||||
|
|
||||||
|
// Scan DOM
|
||||||
setRoot(node);
|
setRoot(node);
|
||||||
|
|
||||||
scanDOM();
|
scanDOM();
|
||||||
|
|
||||||
|
// Test getRootNodes
|
||||||
|
expect(getRootNodes()).to.be.eql([
|
||||||
|
{
|
||||||
|
node: node,
|
||||||
|
temporary: false,
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
|
||||||
// First API response should have loaded
|
// First API response should have loaded
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
const elements = node.querySelectorAll('svg.iconify');
|
const elements = node.querySelectorAll('svg.iconify');
|
||||||
@ -241,10 +249,18 @@ describe('Scanning DOM with API', () => {
|
|||||||
'</li>' +
|
'</li>' +
|
||||||
'</ul></div>';
|
'</ul></div>';
|
||||||
|
|
||||||
|
// Scan DOM
|
||||||
setRoot(node);
|
setRoot(node);
|
||||||
|
|
||||||
scanDOM();
|
scanDOM();
|
||||||
|
|
||||||
|
// Test getRootNodes
|
||||||
|
expect(getRootNodes()).to.be.eql([
|
||||||
|
{
|
||||||
|
node: node,
|
||||||
|
temporary: false,
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
|
||||||
// Make sure no icons were rendered yet
|
// Make sure no icons were rendered yet
|
||||||
const elements = node.querySelectorAll('svg.iconify');
|
const elements = node.querySelectorAll('svg.iconify');
|
||||||
expect(elements.length).to.be.equal(
|
expect(elements.length).to.be.equal(
|
||||||
@ -369,8 +385,8 @@ describe('Scanning DOM with API', () => {
|
|||||||
'</li>' +
|
'</li>' +
|
||||||
'</ul></div>';
|
'</ul></div>';
|
||||||
|
|
||||||
|
// Scan DOM
|
||||||
setRoot(node);
|
setRoot(node);
|
||||||
|
|
||||||
scanDOM();
|
scanDOM();
|
||||||
|
|
||||||
// Change icon name
|
// Change icon name
|
||||||
@ -429,18 +445,47 @@ describe('Scanning DOM with API', () => {
|
|||||||
prefix +
|
prefix +
|
||||||
':home"></span>';
|
':home"></span>';
|
||||||
|
|
||||||
console.log('\nUnattached node test start');
|
// Set root node, test nodes list
|
||||||
setRoot(fakeRoot);
|
setRoot(fakeRoot);
|
||||||
|
expect(getRootNodes()).to.be.eql([
|
||||||
|
{
|
||||||
|
node: fakeRoot,
|
||||||
|
temporary: false,
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
|
||||||
|
// Scan different node
|
||||||
scanDOM(node);
|
scanDOM(node);
|
||||||
|
|
||||||
|
// Test nodes list
|
||||||
|
expect(getRootNodes()).to.be.eql([
|
||||||
|
{
|
||||||
|
node: fakeRoot,
|
||||||
|
temporary: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
node: node,
|
||||||
|
temporary: true,
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
|
||||||
// API response should have loaded
|
// API response should have loaded
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
const elements = node.querySelectorAll('svg.iconify');
|
const elements = node.querySelectorAll('svg.iconify');
|
||||||
console.log('Unattached node test:', node.innerHTML);
|
|
||||||
expect(elements.length).to.be.equal(
|
expect(elements.length).to.be.equal(
|
||||||
1,
|
1,
|
||||||
'Expected to find 1 rendered SVG element'
|
'Expected to find 1 rendered SVG element'
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// Test nodes list: temporary node should have been removed
|
||||||
|
expect(getRootNodes()).to.be.eql([
|
||||||
|
{
|
||||||
|
node: fakeRoot,
|
||||||
|
temporary: false,
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
|
||||||
|
// Done
|
||||||
done();
|
done();
|
||||||
}, 200);
|
}, 200);
|
||||||
});
|
});
|
||||||
|
@ -66,7 +66,6 @@ describe('Testing Iconify object', () => {
|
|||||||
expect(node).to.not.be.equal(null);
|
expect(node).to.not.be.equal(null);
|
||||||
|
|
||||||
const html = node.outerHTML;
|
const html = node.outerHTML;
|
||||||
console.log('Rendered SVG:', html);
|
|
||||||
expect(html.indexOf('<svg')).to.be.equal(0);
|
expect(html.indexOf('<svg')).to.be.equal(0);
|
||||||
|
|
||||||
// Get HTML
|
// Get HTML
|
||||||
|
@ -66,7 +66,6 @@ describe('Testing Iconify object (without API)', () => {
|
|||||||
expect(node).to.not.be.equal(null);
|
expect(node).to.not.be.equal(null);
|
||||||
|
|
||||||
const html = node.outerHTML;
|
const html = node.outerHTML;
|
||||||
console.log('Rendered SVG:', html);
|
|
||||||
expect(html.indexOf('<svg')).to.be.equal(0);
|
expect(html.indexOf('<svg')).to.be.equal(0);
|
||||||
|
|
||||||
// Get HTML
|
// Get HTML
|
||||||
|
@ -1,6 +1,15 @@
|
|||||||
// Root element
|
// Default root element
|
||||||
let root: HTMLElement;
|
let root: HTMLElement;
|
||||||
|
|
||||||
|
// Interface for extra root nodes
|
||||||
|
export interface ExtraRootNode {
|
||||||
|
node: HTMLElement;
|
||||||
|
temporary: boolean; // True if node should be removed when all placeholders have been replaced
|
||||||
|
}
|
||||||
|
|
||||||
|
// Additional root elements
|
||||||
|
let customRoot: ExtraRootNode[] = [];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get root element
|
* Get root element
|
||||||
*/
|
*/
|
||||||
@ -14,3 +23,58 @@ export function getRoot(): HTMLElement {
|
|||||||
export function setRoot(node: HTMLElement): void {
|
export function setRoot(node: HTMLElement): void {
|
||||||
root = node;
|
root = node;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add extra root node
|
||||||
|
*/
|
||||||
|
export function addRoot(node: HTMLElement, autoRemove = false): ExtraRootNode {
|
||||||
|
if (root === node) {
|
||||||
|
return {
|
||||||
|
node: root,
|
||||||
|
temporary: false,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let i = 0; i < customRoot.length; i++) {
|
||||||
|
const item = customRoot[i];
|
||||||
|
if (item.node === node) {
|
||||||
|
// Found matching node
|
||||||
|
if (!autoRemove && item.temporary) {
|
||||||
|
// Change to permanent
|
||||||
|
item.temporary = false;
|
||||||
|
}
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add item
|
||||||
|
const item = {
|
||||||
|
node,
|
||||||
|
temporary: autoRemove,
|
||||||
|
};
|
||||||
|
customRoot.push(item);
|
||||||
|
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove root node
|
||||||
|
*/
|
||||||
|
export function removeRoot(node: HTMLElement): void {
|
||||||
|
customRoot = customRoot.filter((item) => item.node !== node);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get all root nodes
|
||||||
|
*/
|
||||||
|
export function getRootNodes(): ExtraRootNode[] {
|
||||||
|
return (root
|
||||||
|
? [
|
||||||
|
{
|
||||||
|
node: root,
|
||||||
|
temporary: false,
|
||||||
|
},
|
||||||
|
]
|
||||||
|
: []
|
||||||
|
).concat(customRoot);
|
||||||
|
}
|
||||||
|
@ -6,7 +6,13 @@ import { findPlaceholders } from './finder';
|
|||||||
import { IconifyElementData, elementDataProperty } from './element';
|
import { IconifyElementData, elementDataProperty } from './element';
|
||||||
import { renderIcon } from './render';
|
import { renderIcon } from './render';
|
||||||
import { pauseObserver, resumeObserver } from './observer';
|
import { pauseObserver, resumeObserver } from './observer';
|
||||||
import { getRoot } from './root';
|
import {
|
||||||
|
getRoot,
|
||||||
|
getRootNodes,
|
||||||
|
addRoot,
|
||||||
|
removeRoot,
|
||||||
|
ExtraRootNode,
|
||||||
|
} from './root';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Flag to avoid scanning DOM too often
|
* Flag to avoid scanning DOM too often
|
||||||
@ -48,108 +54,138 @@ const compareIcons = (
|
|||||||
/**
|
/**
|
||||||
* Scan DOM for placeholders
|
* Scan DOM for placeholders
|
||||||
*/
|
*/
|
||||||
export function scanDOM(root?: HTMLElement): void {
|
export function scanDOM(customRoot?: HTMLElement): void {
|
||||||
scanQueued = false;
|
scanQueued = false;
|
||||||
|
|
||||||
// Observer
|
|
||||||
let paused = false;
|
|
||||||
|
|
||||||
// List of icons to load: [provider][prefix][name] = boolean
|
// List of icons to load: [provider][prefix][name] = boolean
|
||||||
const loadIcons: Record<
|
const loadIcons: Record<
|
||||||
string,
|
string,
|
||||||
Record<string, Record<string, boolean>>
|
Record<string, Record<string, boolean>>
|
||||||
> = Object.create(null);
|
> = Object.create(null);
|
||||||
|
|
||||||
|
// Add temporary root node
|
||||||
|
let customRootItem: ExtraRootNode;
|
||||||
|
if (customRoot) {
|
||||||
|
customRootItem = addRoot(customRoot, true);
|
||||||
|
}
|
||||||
|
|
||||||
// Get root node and placeholders
|
// Get root node and placeholders
|
||||||
if (!root) {
|
const rootNodes: ExtraRootNode[] = customRoot
|
||||||
root = getRoot();
|
? [customRootItem]
|
||||||
}
|
: getRootNodes();
|
||||||
if (!root || !root.querySelectorAll) {
|
rootNodes.forEach((rootItem) => {
|
||||||
return;
|
const root = rootItem.node;
|
||||||
}
|
|
||||||
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];
|
|
||||||
|
|
||||||
// Icon has not been updated since last scan
|
|
||||||
if (data !== void 0 && compareIcons(data.name, iconName)) {
|
|
||||||
// Icon name was not changed and data is set - quickly return if icon is missing or still loading
|
|
||||||
switch (data.status) {
|
|
||||||
case 'missing':
|
|
||||||
return;
|
|
||||||
|
|
||||||
case 'loading':
|
|
||||||
if (
|
|
||||||
coreModules.api &&
|
|
||||||
coreModules.api.isPending({ provider, prefix, name })
|
|
||||||
) {
|
|
||||||
// Pending
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check icon
|
|
||||||
const storage = getStorage(provider, prefix);
|
|
||||||
if (storage.icons[name] !== void 0) {
|
|
||||||
// Icon exists - replace placeholder
|
|
||||||
if (!paused) {
|
|
||||||
pauseObserver(root);
|
|
||||||
paused = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get customisations
|
|
||||||
const customisations =
|
|
||||||
item.customisations !== void 0
|
|
||||||
? item.customisations
|
|
||||||
: item.finder.customisations(element);
|
|
||||||
|
|
||||||
// Render icon
|
|
||||||
renderIcon(
|
|
||||||
item,
|
|
||||||
customisations,
|
|
||||||
getIcon(storage, name) as FullIconifyIcon
|
|
||||||
);
|
|
||||||
|
|
||||||
|
if (!root || !root.querySelectorAll) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (storage.missing[name]) {
|
// Track placeholders
|
||||||
// Mark as missing
|
let hasPlaceholders = false;
|
||||||
|
|
||||||
|
// Observer
|
||||||
|
let paused = false;
|
||||||
|
|
||||||
|
// Find placeholders
|
||||||
|
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];
|
||||||
|
|
||||||
|
// Icon has not been updated since last scan
|
||||||
|
if (data !== void 0 && compareIcons(data.name, iconName)) {
|
||||||
|
// Icon name was not changed and data is set - quickly return if icon is missing or still loading
|
||||||
|
switch (data.status) {
|
||||||
|
case 'missing':
|
||||||
|
return;
|
||||||
|
|
||||||
|
case 'loading':
|
||||||
|
if (
|
||||||
|
coreModules.api &&
|
||||||
|
coreModules.api.isPending({
|
||||||
|
provider,
|
||||||
|
prefix,
|
||||||
|
name,
|
||||||
|
})
|
||||||
|
) {
|
||||||
|
// Pending
|
||||||
|
hasPlaceholders = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check icon
|
||||||
|
const storage = getStorage(provider, prefix);
|
||||||
|
if (storage.icons[name] !== void 0) {
|
||||||
|
// Icon exists - replace placeholder
|
||||||
|
if (!paused && !rootItem.temporary) {
|
||||||
|
pauseObserver(root);
|
||||||
|
paused = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get customisations
|
||||||
|
const customisations =
|
||||||
|
item.customisations !== void 0
|
||||||
|
? item.customisations
|
||||||
|
: item.finder.customisations(element);
|
||||||
|
|
||||||
|
// Render icon
|
||||||
|
renderIcon(
|
||||||
|
item,
|
||||||
|
customisations,
|
||||||
|
getIcon(storage, name) as FullIconifyIcon
|
||||||
|
);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (storage.missing[name]) {
|
||||||
|
// Mark as missing
|
||||||
|
data = {
|
||||||
|
name: iconName,
|
||||||
|
status: 'missing',
|
||||||
|
customisations: {},
|
||||||
|
};
|
||||||
|
element[elementDataProperty] = data;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (coreModules.api) {
|
||||||
|
if (!coreModules.api.isPending({ provider, prefix, name })) {
|
||||||
|
// Add icon to loading queue
|
||||||
|
if (loadIcons[provider] === void 0) {
|
||||||
|
loadIcons[provider] = Object.create(null);
|
||||||
|
}
|
||||||
|
const providerLoadIcons = loadIcons[provider];
|
||||||
|
if (providerLoadIcons[prefix] === void 0) {
|
||||||
|
providerLoadIcons[prefix] = Object.create(null);
|
||||||
|
}
|
||||||
|
providerLoadIcons[prefix][name] = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Mark as loading
|
||||||
data = {
|
data = {
|
||||||
name: iconName,
|
name: iconName,
|
||||||
status: 'missing',
|
status: 'loading',
|
||||||
customisations: {},
|
customisations: {},
|
||||||
};
|
};
|
||||||
element[elementDataProperty] = data;
|
element[elementDataProperty] = data;
|
||||||
return;
|
hasPlaceholders = true;
|
||||||
|
});
|
||||||
|
|
||||||
|
// Remove temporay node
|
||||||
|
if (rootItem.temporary && !hasPlaceholders) {
|
||||||
|
removeRoot(root);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (coreModules.api) {
|
if (paused && !rootItem.temporary) {
|
||||||
if (!coreModules.api.isPending({ provider, prefix, name })) {
|
resumeObserver(root);
|
||||||
// Add icon to loading queue
|
|
||||||
if (loadIcons[provider] === void 0) {
|
|
||||||
loadIcons[provider] = Object.create(null);
|
|
||||||
}
|
|
||||||
const providerLoadIcons = loadIcons[provider];
|
|
||||||
if (providerLoadIcons[prefix] === void 0) {
|
|
||||||
providerLoadIcons[prefix] = Object.create(null);
|
|
||||||
}
|
|
||||||
providerLoadIcons[prefix][name] = true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Mark as loading
|
|
||||||
data = {
|
|
||||||
name: iconName,
|
|
||||||
status: 'loading',
|
|
||||||
customisations: {},
|
|
||||||
};
|
|
||||||
element[elementDataProperty] = data;
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// Load icons
|
// Load icons
|
||||||
@ -172,8 +208,4 @@ export function scanDOM(root?: HTMLElement): void {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (paused) {
|
|
||||||
resumeObserver(root);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user