123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109 |
- 'use strict';
- function cssHasPseudo(document) {
- const observedItems = []; // document.createAttribute() doesn't support `:` in the name. innerHTML does
- const attributeElement = document.createElement('x'); // walk all stylesheets to collect observed css rules
- [].forEach.call(document.styleSheets, walkStyleSheet);
- transformObservedItems(); // observe DOM modifications that affect selectors
- const mutationObserver = new MutationObserver(mutationsList => {
- mutationsList.forEach(mutation => {
- [].forEach.call(mutation.addedNodes || [], node => {
- // walk stylesheets to collect observed css rules
- if (node.nodeType === 1 && node.sheet) {
- walkStyleSheet(node.sheet);
- }
- }); // transform observed css rules
- cleanupObservedCssRules();
- transformObservedItems();
- });
- });
- mutationObserver.observe(document, {
- childList: true,
- subtree: true
- }); // observe DOM events that affect pseudo-selectors
- document.addEventListener('focus', transformObservedItems, true);
- document.addEventListener('blur', transformObservedItems, true);
- document.addEventListener('input', transformObservedItems); // transform observed css rules
- function transformObservedItems() {
- requestAnimationFrame(() => {
- observedItems.forEach(item => {
- const nodes = [];
- [].forEach.call(document.querySelectorAll(item.scopeSelector), element => {
- const nthChild = [].indexOf.call(element.parentNode.children, element) + 1;
- const relativeSelectors = item.relativeSelectors.map(relativeSelector => item.scopeSelector + ':nth-child(' + nthChild + ') ' + relativeSelector).join(); // find any relative :has element from the :scope element
- const relativeElement = element.parentNode.querySelector(relativeSelectors);
- const shouldElementMatch = item.isNot ? !relativeElement : relativeElement;
- if (shouldElementMatch) {
- // memorize the node
- nodes.push(element); // set an attribute with an irregular attribute name
- // document.createAttribute() doesn't support special characters
- attributeElement.innerHTML = '<x ' + item.attributeName + '>';
- element.setAttributeNode(attributeElement.children[0].attributes[0].cloneNode()); // trigger a style refresh in IE and Edge
- document.documentElement.style.zoom = 1;
- document.documentElement.style.zoom = null;
- }
- }); // remove the encoded attribute from all nodes that no longer match them
- item.nodes.forEach(node => {
- if (nodes.indexOf(node) === -1) {
- node.removeAttribute(item.attributeName); // trigger a style refresh in IE and Edge
- document.documentElement.style.zoom = 1;
- document.documentElement.style.zoom = null;
- }
- }); // update the
- item.nodes = nodes;
- });
- });
- } // remove any observed cssrules that no longer apply
- function cleanupObservedCssRules() {
- [].push.apply(observedItems, observedItems.splice(0).filter(item => item.rule.parentStyleSheet && item.rule.parentStyleSheet.ownerNode && document.documentElement.contains(item.rule.parentStyleSheet.ownerNode)));
- } // walk a stylesheet to collect observed css rules
- function walkStyleSheet(styleSheet) {
- try {
- // walk a css rule to collect observed css rules
- [].forEach.call(styleSheet.cssRules || [], rule => {
- if (rule.selectorText) {
- // decode the selector text in all browsers to:
- // [1] = :scope, [2] = :not(:has), [3] = :has relative, [4] = :scope relative
- const selectors = decodeURIComponent(rule.selectorText.replace(/\\(.)/g, '$1')).match(/^(.*?)\[:(not-)?has\((.+?)\)\](.*?)$/);
- if (selectors) {
- const attributeName = ':' + (selectors[2] ? 'not-' : '') + 'has(' + // encode a :has() pseudo selector as an attribute name
- encodeURIComponent(selectors[3]).replace(/%3A/g, ':').replace(/%5B/g, '[').replace(/%5D/g, ']').replace(/%2C/g, ',') + ')';
- observedItems.push({
- rule,
- scopeSelector: selectors[1],
- isNot: selectors[2],
- relativeSelectors: selectors[3].split(/\s*,\s*/),
- attributeName,
- nodes: []
- });
- }
- } else {
- walkStyleSheet(rule);
- }
- });
- } catch (error) {
- /* do nothing and continue */
- }
- }
- }
- module.exports = cssHasPseudo;
- //# sourceMappingURL=index.js.map
|