dynamicCSS.js 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163
  1. export function canUseDom() {
  2. return !!(typeof window !== 'undefined' && window.document && window.document.createElement);
  3. }
  4. function contains(root, n) {
  5. if (!root) {
  6. return false;
  7. } // Use native if support
  8. if (root.contains) {
  9. return root.contains(n);
  10. }
  11. return false;
  12. }
  13. var APPEND_ORDER = 'data-vc-order';
  14. var MARK_KEY = "vc-icon-key";
  15. var containerCache = new Map();
  16. function getMark() {
  17. var _ref = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {},
  18. mark = _ref.mark;
  19. if (mark) {
  20. return mark.startsWith('data-') ? mark : "data-".concat(mark);
  21. }
  22. return MARK_KEY;
  23. }
  24. function getContainer(option) {
  25. if (option.attachTo) {
  26. return option.attachTo;
  27. }
  28. var head = document.querySelector('head');
  29. return head || document.body;
  30. }
  31. function getOrder(prepend) {
  32. if (prepend === 'queue') {
  33. return 'prependQueue';
  34. }
  35. return prepend ? 'prepend' : 'append';
  36. }
  37. /**
  38. * Find style which inject by rc-util
  39. */
  40. function findStyles(container) {
  41. return Array.from((containerCache.get(container) || container).children).filter(function (node) {
  42. return node.tagName === 'STYLE';
  43. });
  44. }
  45. export function injectCSS(css) {
  46. var option = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
  47. if (!canUseDom()) {
  48. return null;
  49. }
  50. var csp = option.csp,
  51. prepend = option.prepend;
  52. var styleNode = document.createElement('style');
  53. styleNode.setAttribute(APPEND_ORDER, getOrder(prepend));
  54. if (csp && csp.nonce) {
  55. styleNode.nonce = csp.nonce;
  56. }
  57. styleNode.innerHTML = css;
  58. var container = getContainer(option);
  59. var firstChild = container.firstChild;
  60. if (prepend) {
  61. // If is queue `prepend`, it will prepend first style and then append rest style
  62. if (prepend === 'queue') {
  63. var existStyle = findStyles(container).filter(function (node) {
  64. return ['prepend', 'prependQueue'].includes(node.getAttribute(APPEND_ORDER));
  65. });
  66. if (existStyle.length) {
  67. container.insertBefore(styleNode, existStyle[existStyle.length - 1].nextSibling);
  68. return styleNode;
  69. }
  70. } // Use `insertBefore` as `prepend`
  71. container.insertBefore(styleNode, firstChild);
  72. } else {
  73. container.appendChild(styleNode);
  74. }
  75. return styleNode;
  76. }
  77. function findExistNode(key) {
  78. var option = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
  79. var container = getContainer(option);
  80. return findStyles(container).find(function (node) {
  81. return node.getAttribute(getMark(option)) === key;
  82. });
  83. }
  84. export function removeCSS(key) {
  85. var option = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
  86. var existNode = findExistNode(key, option);
  87. if (existNode) {
  88. var container = getContainer(option);
  89. container.removeChild(existNode);
  90. }
  91. }
  92. /**
  93. * qiankun will inject `appendChild` to insert into other
  94. */
  95. function syncRealContainer(container, option) {
  96. var cachedRealContainer = containerCache.get(container); // Find real container when not cached or cached container removed
  97. if (!cachedRealContainer || !contains(document, cachedRealContainer)) {
  98. var placeholderStyle = injectCSS('', option);
  99. var parentNode = placeholderStyle.parentNode;
  100. containerCache.set(container, parentNode);
  101. container.removeChild(placeholderStyle);
  102. }
  103. }
  104. /**
  105. * manually clear container cache to avoid global cache in unit testes
  106. */
  107. export function clearContainerCache() {
  108. containerCache.clear();
  109. }
  110. export function updateCSS(css, key) {
  111. var option = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
  112. var container = getContainer(option); // Sync real parent
  113. syncRealContainer(container, option);
  114. var existNode = findExistNode(key, option);
  115. if (existNode) {
  116. if (option.csp && option.csp.nonce && existNode.nonce !== option.csp.nonce) {
  117. existNode.nonce = option.csp.nonce;
  118. }
  119. if (existNode.innerHTML !== css) {
  120. existNode.innerHTML = css;
  121. }
  122. return existNode;
  123. }
  124. var newNode = injectCSS(css, option);
  125. newNode.setAttribute(getMark(option), key);
  126. return newNode;
  127. }