dynamicCSS.js 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132
  1. "use strict";
  2. var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
  3. Object.defineProperty(exports, "__esModule", {
  4. value: true
  5. });
  6. exports.clearContainerCache = clearContainerCache;
  7. exports.injectCSS = injectCSS;
  8. exports.removeCSS = removeCSS;
  9. exports.updateCSS = updateCSS;
  10. var _canUseDom = _interopRequireDefault(require("../../_util/canUseDom"));
  11. var _contains = _interopRequireDefault(require("./contains"));
  12. const APPEND_ORDER = 'data-vc-order';
  13. const MARK_KEY = `vc-util-key`;
  14. const containerCache = new Map();
  15. function getMark() {
  16. let {
  17. mark
  18. } = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
  19. if (mark) {
  20. return mark.startsWith('data-') ? mark : `data-${mark}`;
  21. }
  22. return MARK_KEY;
  23. }
  24. function getContainer(option) {
  25. if (option.attachTo) {
  26. return option.attachTo;
  27. }
  28. const 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(node => node.tagName === 'STYLE');
  42. }
  43. function injectCSS(css) {
  44. let option = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
  45. if (!(0, _canUseDom.default)()) {
  46. return null;
  47. }
  48. const {
  49. csp,
  50. prepend
  51. } = option;
  52. const styleNode = document.createElement('style');
  53. styleNode.setAttribute(APPEND_ORDER, getOrder(prepend));
  54. if (csp === null || csp === void 0 ? void 0 : csp.nonce) {
  55. styleNode.nonce = csp === null || csp === void 0 ? void 0 : csp.nonce;
  56. }
  57. styleNode.innerHTML = css;
  58. const container = getContainer(option);
  59. const {
  60. firstChild
  61. } = container;
  62. if (prepend) {
  63. // If is queue `prepend`, it will prepend first style and then append rest style
  64. if (prepend === 'queue') {
  65. const existStyle = findStyles(container).filter(node => ['prepend', 'prependQueue'].includes(node.getAttribute(APPEND_ORDER)));
  66. if (existStyle.length) {
  67. container.insertBefore(styleNode, existStyle[existStyle.length - 1].nextSibling);
  68. return styleNode;
  69. }
  70. }
  71. // Use `insertBefore` as `prepend`
  72. container.insertBefore(styleNode, firstChild);
  73. } else {
  74. container.appendChild(styleNode);
  75. }
  76. return styleNode;
  77. }
  78. function findExistNode(key) {
  79. let option = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
  80. const container = getContainer(option);
  81. return findStyles(container).find(node => node.getAttribute(getMark(option)) === key);
  82. }
  83. function removeCSS(key) {
  84. let option = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
  85. const existNode = findExistNode(key, option);
  86. if (existNode) {
  87. const container = getContainer(option);
  88. container.removeChild(existNode);
  89. }
  90. }
  91. /**
  92. * qiankun will inject `appendChild` to insert into other
  93. */
  94. function syncRealContainer(container, option) {
  95. const cachedRealContainer = containerCache.get(container);
  96. // Find real container when not cached or cached container removed
  97. if (!cachedRealContainer || !(0, _contains.default)(document, cachedRealContainer)) {
  98. const placeholderStyle = injectCSS('', option);
  99. const {
  100. parentNode
  101. } = placeholderStyle;
  102. containerCache.set(container, parentNode);
  103. container.removeChild(placeholderStyle);
  104. }
  105. }
  106. /**
  107. * manually clear container cache to avoid global cache in unit testes
  108. */
  109. function clearContainerCache() {
  110. containerCache.clear();
  111. }
  112. function updateCSS(css, key) {
  113. let option = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
  114. var _a, _b, _c;
  115. const container = getContainer(option);
  116. // Sync real parent
  117. syncRealContainer(container, option);
  118. const existNode = findExistNode(key, option);
  119. if (existNode) {
  120. if (((_a = option.csp) === null || _a === void 0 ? void 0 : _a.nonce) && existNode.nonce !== ((_b = option.csp) === null || _b === void 0 ? void 0 : _b.nonce)) {
  121. existNode.nonce = (_c = option.csp) === null || _c === void 0 ? void 0 : _c.nonce;
  122. }
  123. if (existNode.innerHTML !== css) {
  124. existNode.innerHTML = css;
  125. }
  126. return existNode;
  127. }
  128. const newNode = injectCSS(css, option);
  129. newNode.setAttribute(getMark(option), key);
  130. return newNode;
  131. }