source: trip-planner-front/node_modules/css-has-pseudo/index.js@ eed0bf8

Last change on this file since eed0bf8 was 6a3a178, checked in by Ema <ema_spirova@…>, 3 years ago

initial commit

  • Property mode set to 100644
File size: 4.5 KB
RevLine 
[6a3a178]1'use strict';
2
3function cssHasPseudo(document) {
4 const observedItems = []; // document.createAttribute() doesn't support `:` in the name. innerHTML does
5
6 const attributeElement = document.createElement('x'); // walk all stylesheets to collect observed css rules
7
8 [].forEach.call(document.styleSheets, walkStyleSheet);
9 transformObservedItems(); // observe DOM modifications that affect selectors
10
11 const mutationObserver = new MutationObserver(mutationsList => {
12 mutationsList.forEach(mutation => {
13 [].forEach.call(mutation.addedNodes || [], node => {
14 // walk stylesheets to collect observed css rules
15 if (node.nodeType === 1 && node.sheet) {
16 walkStyleSheet(node.sheet);
17 }
18 }); // transform observed css rules
19
20 cleanupObservedCssRules();
21 transformObservedItems();
22 });
23 });
24 mutationObserver.observe(document, {
25 childList: true,
26 subtree: true
27 }); // observe DOM events that affect pseudo-selectors
28
29 document.addEventListener('focus', transformObservedItems, true);
30 document.addEventListener('blur', transformObservedItems, true);
31 document.addEventListener('input', transformObservedItems); // transform observed css rules
32
33 function transformObservedItems() {
34 requestAnimationFrame(() => {
35 observedItems.forEach(item => {
36 const nodes = [];
37 [].forEach.call(document.querySelectorAll(item.scopeSelector), element => {
38 const nthChild = [].indexOf.call(element.parentNode.children, element) + 1;
39 const relativeSelectors = item.relativeSelectors.map(relativeSelector => item.scopeSelector + ':nth-child(' + nthChild + ') ' + relativeSelector).join(); // find any relative :has element from the :scope element
40
41 const relativeElement = element.parentNode.querySelector(relativeSelectors);
42 const shouldElementMatch = item.isNot ? !relativeElement : relativeElement;
43
44 if (shouldElementMatch) {
45 // memorize the node
46 nodes.push(element); // set an attribute with an irregular attribute name
47 // document.createAttribute() doesn't support special characters
48
49 attributeElement.innerHTML = '<x ' + item.attributeName + '>';
50 element.setAttributeNode(attributeElement.children[0].attributes[0].cloneNode()); // trigger a style refresh in IE and Edge
51
52 document.documentElement.style.zoom = 1;
53 document.documentElement.style.zoom = null;
54 }
55 }); // remove the encoded attribute from all nodes that no longer match them
56
57 item.nodes.forEach(node => {
58 if (nodes.indexOf(node) === -1) {
59 node.removeAttribute(item.attributeName); // trigger a style refresh in IE and Edge
60
61 document.documentElement.style.zoom = 1;
62 document.documentElement.style.zoom = null;
63 }
64 }); // update the
65
66 item.nodes = nodes;
67 });
68 });
69 } // remove any observed cssrules that no longer apply
70
71
72 function cleanupObservedCssRules() {
73 [].push.apply(observedItems, observedItems.splice(0).filter(item => item.rule.parentStyleSheet && item.rule.parentStyleSheet.ownerNode && document.documentElement.contains(item.rule.parentStyleSheet.ownerNode)));
74 } // walk a stylesheet to collect observed css rules
75
76
77 function walkStyleSheet(styleSheet) {
78 try {
79 // walk a css rule to collect observed css rules
80 [].forEach.call(styleSheet.cssRules || [], rule => {
81 if (rule.selectorText) {
82 // decode the selector text in all browsers to:
83 // [1] = :scope, [2] = :not(:has), [3] = :has relative, [4] = :scope relative
84 const selectors = decodeURIComponent(rule.selectorText.replace(/\\(.)/g, '$1')).match(/^(.*?)\[:(not-)?has\((.+?)\)\](.*?)$/);
85
86 if (selectors) {
87 const attributeName = ':' + (selectors[2] ? 'not-' : '') + 'has(' + // encode a :has() pseudo selector as an attribute name
88 encodeURIComponent(selectors[3]).replace(/%3A/g, ':').replace(/%5B/g, '[').replace(/%5D/g, ']').replace(/%2C/g, ',') + ')';
89 observedItems.push({
90 rule,
91 scopeSelector: selectors[1],
92 isNot: selectors[2],
93 relativeSelectors: selectors[3].split(/\s*,\s*/),
94 attributeName,
95 nodes: []
96 });
97 }
98 } else {
99 walkStyleSheet(rule);
100 }
101 });
102 } catch (error) {
103 /* do nothing and continue */
104 }
105 }
106}
107
108module.exports = cssHasPseudo;
109//# sourceMappingURL=index.js.map
Note: See TracBrowser for help on using the repository browser.