1
This commit is contained in:
+156
@@ -0,0 +1,156 @@
|
||||
"use strict";
|
||||
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
exports.clearContainerCache = clearContainerCache;
|
||||
exports.injectCSS = injectCSS;
|
||||
exports.removeCSS = removeCSS;
|
||||
exports.updateCSS = updateCSS;
|
||||
var _canUseDom = _interopRequireDefault(require("./canUseDom"));
|
||||
var _contains = _interopRequireDefault(require("./contains"));
|
||||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
||||
const APPEND_ORDER = 'data-rc-order';
|
||||
const APPEND_PRIORITY = 'data-rc-priority';
|
||||
const MARK_KEY = `rc-util-key`;
|
||||
const containerCache = new Map();
|
||||
function getMark({
|
||||
mark
|
||||
} = {}) {
|
||||
if (mark) {
|
||||
return mark.startsWith('data-') ? mark : `data-${mark}`;
|
||||
}
|
||||
return MARK_KEY;
|
||||
}
|
||||
function getContainer(option) {
|
||||
if (option.attachTo) {
|
||||
return option.attachTo;
|
||||
}
|
||||
const head = document.querySelector('head');
|
||||
return head || document.body;
|
||||
}
|
||||
function getOrder(prepend) {
|
||||
if (prepend === 'queue') {
|
||||
return 'prependQueue';
|
||||
}
|
||||
return prepend ? 'prepend' : 'append';
|
||||
}
|
||||
|
||||
/**
|
||||
* Find style which inject by rc-util
|
||||
*/
|
||||
function findStyles(container) {
|
||||
return Array.from((containerCache.get(container) || container).children).filter(node => node.tagName === 'STYLE');
|
||||
}
|
||||
function injectCSS(css, option = {}) {
|
||||
if (!(0, _canUseDom.default)()) {
|
||||
return null;
|
||||
}
|
||||
const {
|
||||
csp,
|
||||
prepend,
|
||||
priority = 0
|
||||
} = option;
|
||||
const mergedOrder = getOrder(prepend);
|
||||
const isPrependQueue = mergedOrder === 'prependQueue';
|
||||
const styleNode = document.createElement('style');
|
||||
styleNode.setAttribute(APPEND_ORDER, mergedOrder);
|
||||
if (isPrependQueue && priority) {
|
||||
styleNode.setAttribute(APPEND_PRIORITY, `${priority}`);
|
||||
}
|
||||
if (csp?.nonce) {
|
||||
styleNode.nonce = csp?.nonce;
|
||||
}
|
||||
styleNode.innerHTML = css;
|
||||
const container = getContainer(option);
|
||||
const {
|
||||
firstChild
|
||||
} = container;
|
||||
if (prepend) {
|
||||
// If is queue `prepend`, it will prepend first style and then append rest style
|
||||
if (isPrependQueue) {
|
||||
const existStyle = (option.styles || findStyles(container)).filter(node => {
|
||||
// Ignore style which not injected by rc-util with prepend
|
||||
if (!['prepend', 'prependQueue'].includes(node.getAttribute(APPEND_ORDER))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Ignore style which priority less then new style
|
||||
const nodePriority = Number(node.getAttribute(APPEND_PRIORITY) || 0);
|
||||
return priority >= nodePriority;
|
||||
});
|
||||
if (existStyle.length) {
|
||||
container.insertBefore(styleNode, existStyle[existStyle.length - 1].nextSibling);
|
||||
return styleNode;
|
||||
}
|
||||
}
|
||||
|
||||
// Use `insertBefore` as `prepend`
|
||||
container.insertBefore(styleNode, firstChild);
|
||||
} else {
|
||||
container.appendChild(styleNode);
|
||||
}
|
||||
return styleNode;
|
||||
}
|
||||
function findExistNode(key, option = {}) {
|
||||
let {
|
||||
styles
|
||||
} = option;
|
||||
styles ||= findStyles(getContainer(option));
|
||||
return styles.find(node => node.getAttribute(getMark(option)) === key);
|
||||
}
|
||||
function removeCSS(key, option = {}) {
|
||||
const existNode = findExistNode(key, option);
|
||||
if (existNode) {
|
||||
const container = getContainer(option);
|
||||
container.removeChild(existNode);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* qiankun will inject `appendChild` to insert into other
|
||||
*/
|
||||
function syncRealContainer(container, option) {
|
||||
const cachedRealContainer = containerCache.get(container);
|
||||
|
||||
// Find real container when not cached or cached container removed
|
||||
if (!cachedRealContainer || !(0, _contains.default)(document, cachedRealContainer)) {
|
||||
const placeholderStyle = injectCSS('', option);
|
||||
const {
|
||||
parentNode
|
||||
} = placeholderStyle;
|
||||
containerCache.set(container, parentNode);
|
||||
container.removeChild(placeholderStyle);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* manually clear container cache to avoid global cache in unit testes
|
||||
*/
|
||||
function clearContainerCache() {
|
||||
containerCache.clear();
|
||||
}
|
||||
function updateCSS(css, key, originOption = {}) {
|
||||
const container = getContainer(originOption);
|
||||
const styles = findStyles(container);
|
||||
const option = {
|
||||
...originOption,
|
||||
styles
|
||||
};
|
||||
|
||||
// Sync real parent
|
||||
syncRealContainer(container, option);
|
||||
const existNode = findExistNode(key, option);
|
||||
if (existNode) {
|
||||
if (option.csp?.nonce && existNode.nonce !== option.csp?.nonce) {
|
||||
existNode.nonce = option.csp?.nonce;
|
||||
}
|
||||
if (existNode.innerHTML !== css) {
|
||||
existNode.innerHTML = css;
|
||||
}
|
||||
return existNode;
|
||||
}
|
||||
const newNode = injectCSS(css, option);
|
||||
newNode.setAttribute(getMark(option), key);
|
||||
return newNode;
|
||||
}
|
||||
Reference in New Issue
Block a user