Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

css-has-pseudo

Package Overview
Dependencies
Maintainers
1
Versions
31
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

css-has-pseudo - npm Package Compare versions

Comparing version 0.1.0 to 0.2.0

2

browser.js

@@ -1,1 +0,1 @@

function cssHas(e){var t=/^(.*?)\[:(not-)?has\((.+?)\)\]/,o=[];function n(){o.forEach(function(t){var o=[];Array.prototype.forEach.call(e.querySelectorAll(t.elementSelector),function(n){var r=Array.prototype.indexOf.call(n.parentNode.children,n)+1,c=t.scopedSelectors.map(function(e){return t.elementSelector+":nth-child("+r+") "+e}).join(),l=n.parentNode.querySelector(c);(t.hasSelectorNot?!l:l)&&(o.push(n),function(t,o){var n="<x "+o+">",r=e.createElement("x");r.innerHTML=n;var c=r.firstChild.attributes[0].cloneNode();t.attributes.setNamedItem(c)}(n,t.encodedAttributeName),e.documentElement.style.zoom=1,e.documentElement.style.zoom=null)}),t.nodes.splice(0).forEach(function(n){-1===o.indexOf(n)&&(n.removeAttribute(t.encodedAttributeName),e.documentElement.style.zoom=1,e.documentElement.style.zoom=null)}),t.nodes=o})}function r(e){Array.prototype.forEach.call(e.cssRules,c)}function c(e){t.lastIndex=0;var n,r,c=(n=e.selectorText,decodeURIComponent(n.replace(/\\([^\\])/g,"$1"))).match(t);if(c){var l=c[2],a=c[1],s=c[3].split(/\s*,\s*/),u=":"+(l?"not-":"")+"has("+(r=c[3],encodeURIComponent(r).replace(/%3A/g,":").replace(/%5B/g,"[").replace(/%5D/g,"]").replace(/%2C/g,","))+")";o.push({cssRule:e,hasSelectorNot:l,elementSelector:a,scopedSelectors:s,encodedAttributeName:u,nodes:[]})}}Array.prototype.forEach.call(e.styleSheets,r),n(),new MutationObserver(function(t){t.forEach(function(t){Array.prototype.forEach.call(t.addedNodes||[],function(t){1===t.nodeType&&t.sheet&&(Array.prototype.push.apply(o,o.splice(0).filter(function(t){return t.cssRule.parentStyleSheet&&t.cssRule.parentStyleSheet.ownerNode&&e.contains(t.cssRule.parentStyleSheet.ownerNode)})),Array.prototype.forEach.call(e.styleSheets,r))}),n()})}).observe(e,{childList:!0,subtree:!0}),e.addEventListener("focus",function(){return setImmediate(n)},!0),e.addEventListener("blur",function(){return setImmediate(n)},!0),e.addEventListener("input",function(){return setImmediate(n)})}
function cssHasPseudo(n){var t=[],e=n.createElement("x");function r(){t.forEach(function(t){var r=[];Array.prototype.forEach.call(n.querySelectorAll(t.n),function(u){var o=Array.prototype.indexOf.call(u.parentNode.children,u)+1,i=t.t.map(function(n){return t.n+":nth-child("+o+") "+n}).join(),c=u.parentNode.querySelector(i);(t.e?!c:c)&&(r.push(u),e.innerHTML="<x "+t.r+">",u.attributes.setNamedItem(e.firstChild.attributes[0].cloneNode()),n.documentElement.style.zoom=1,n.documentElement.style.zoom=null)}),t.u.forEach(function(e){-1===r.indexOf(e)&&(e.removeAttribute(t.r),n.documentElement.style.zoom=1,n.documentElement.style.zoom=null)}),t.u=r})}function u(n){Array.prototype.forEach.call(n.cssRules,function(n){var e=decodeURIComponent(n.selectorText.replace(/\\(.)/g,"$1")).match(/^(.*?)\[:(not-)?has\((.+?)\)\](.*?)$/);if(e){var r=":"+(e[2]?"not-":"")+"has("+e[3].replace(/%3A/g,":").replace(/%5B/g,"[").replace(/%5D/g,"]").replace(/%2C/g,",")+")";t.push({o:n,n:e[1],e:e[2],t:e[3].split(/\s*,\s*/),r:r,u:[]})}})}Array.prototype.forEach.call(n.styleSheets,u),r(),new MutationObserver(function(e){e.forEach(function(e){Array.prototype.forEach.call(e.i||[],function(n){1===n.nodeType&&n.sheet&&u(n.sheet)}),Array.prototype.push.apply(t,t.splice(0).filter(function(t){return t.o.parentStyleSheet&&t.o.parentStyleSheet.ownerNode&&n.documentElement.contains(t.o.parentStyleSheet.ownerNode)})),r()})}).observe(n,{childList:!0,subtree:!0}),n.addEventListener("focus",function(){return setImmediate(r)},!0),n.addEventListener("blur",function(){return setImmediate(r)},!0),n.addEventListener("input",function(){return setImmediate(r)})}module.c=cssHasPseudo;
# Changes to CSS Has Pseudo
### 0.2.0 (November 21, 2018)
- Improved browser compatibility with updated parsers, encoders, and decoders
- Improved performance by walking the DOM less
- Fixed the misnamed function name for the browser-ready script
- Reduced script size by 9%; from 855 bytes to 775 bytes
### 0.1.0 (November 20, 2018)
- Initial version
'use strict';
function cssHas(document) {
const hasPseudoRegExp = /^(.*?)\[:(not-)?has\((.+?)\)\]/;
const observedCssRules = []; // walk all stylesheets to collect observed css rules
function cssHasPseudo(document) {
const observedItems = [];
const attributeElement = document.createElement('x'); // walk all stylesheets to collect observed css rules
Array.prototype.forEach.call(document.styleSheets, walkStyleSheet);
transformObservedCssRules(); // observe DOM modifications that affect selectors
transformObservedItems(); // observe DOM modifications that affect selectors
new MutationObserver(mutationsList => {
const mutationObserver = new MutationObserver(mutationsList => {
mutationsList.forEach(mutation => {

@@ -15,10 +15,11 @@ Array.prototype.forEach.call(mutation.addedNodes || [], node => {

if (node.nodeType === 1 && node.sheet) {
cleanupObservedCssRules();
Array.prototype.forEach.call(document.styleSheets, walkStyleSheet);
walkStyleSheet(node.sheet);
}
}); // transform observed css rules
transformObservedCssRules();
cleanupObservedCssRules();
transformObservedItems();
});
}).observe(document, {
});
mutationObserver.observe(document, {
childList: true,

@@ -28,21 +29,22 @@ subtree: true

document.addEventListener('focus', () => setImmediate(transformObservedCssRules), true);
document.addEventListener('blur', () => setImmediate(transformObservedCssRules), true);
document.addEventListener('input', () => setImmediate(transformObservedCssRules)); // transform observed css rules
document.addEventListener('focus', () => setImmediate(transformObservedItems), true);
document.addEventListener('blur', () => setImmediate(transformObservedItems), true);
document.addEventListener('input', () => setImmediate(transformObservedItems)); // transform observed css rules
function transformObservedCssRules() {
observedCssRules.forEach(item => {
function transformObservedItems() {
observedItems.forEach(item => {
const nodes = [];
Array.prototype.forEach.call(document.querySelectorAll(item.elementSelector), element => {
const index = Array.prototype.indexOf.call(element.parentNode.children, element) + 1;
const nextSelector = item.scopedSelectors.map(scopedSelector => item.elementSelector + ':nth-child(' + index + ') ' + scopedSelector).join(); // find the :has element from the scope of the element
Array.prototype.forEach.call(document.querySelectorAll(item.scopeSelector), element => {
const nthChild = Array.prototype.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 scopedElement = element.parentNode.querySelector(nextSelector);
const shouldContinue = item.hasSelectorNot ? !scopedElement : scopedElement;
const relativeElement = element.parentNode.querySelector(relativeSelectors);
const shouldElementMatch = item.isNot ? !relativeElement : relativeElement;
if (shouldContinue) {
if (shouldElementMatch) {
// memorize the node
nodes.push(element); // set the encoded attribute on the node
nodes.push(element); // set an attribute with an irregular attribute name
setAttribute(element, item.encodedAttributeName); // trigger a style refresh in IE and Edge
attributeElement.innerHTML = '<x ' + item.attributeName + '>';
element.attributes.setNamedItem(attributeElement.firstChild.attributes[0].cloneNode()); // trigger a style refresh in IE and Edge

@@ -54,5 +56,5 @@ document.documentElement.style.zoom = 1;

item.nodes.splice(0).forEach(node => {
item.nodes.forEach(node => {
if (nodes.indexOf(node) === -1) {
node.removeAttribute(item.encodedAttributeName); // trigger a style refresh in IE and Edge
node.removeAttribute(item.attributeName); // trigger a style refresh in IE and Edge

@@ -62,3 +64,4 @@ document.documentElement.style.zoom = 1;

}
});
}); // update the
item.nodes = nodes;

@@ -70,3 +73,3 @@ });

function cleanupObservedCssRules() {
Array.prototype.push.apply(observedCssRules, observedCssRules.splice(0).filter(item => item.cssRule.parentStyleSheet && item.cssRule.parentStyleSheet.ownerNode && document.contains(item.cssRule.parentStyleSheet.ownerNode)));
Array.prototype.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

@@ -76,49 +79,25 @@

function walkStyleSheet(styleSheet) {
Array.prototype.forEach.call(styleSheet.cssRules, walkCssRule);
} // walk a css rule to collect observed css rules
// walk a css rule to collect observed css rules
Array.prototype.forEach.call(styleSheet.cssRules, rule => {
// 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\((.+?)\)\](.*?)$/);
function walkCssRule(cssRule) {
hasPseudoRegExp.lastIndex = 0; // decode the selector text, unifying their design between most browsers and IE/Edge
const selectorText = decodeHasPseudoSelector(cssRule.selectorText);
const selectorTextMatches = selectorText.match(hasPseudoRegExp);
if (selectorTextMatches) {
const hasSelectorNot = selectorTextMatches[2];
const elementSelector = selectorTextMatches[1];
const scopedSelectors = selectorTextMatches[3].split(/\s*,\s*/);
const encodedAttributeName = ':' + (hasSelectorNot ? 'not-' : '') + 'has(' + encodeAttributeName(selectorTextMatches[3]) + ')';
observedCssRules.push({
cssRule,
hasSelectorNot,
elementSelector,
scopedSelectors,
encodedAttributeName,
nodes: []
});
}
} // set an attribute with an irregular attribute name
function setAttribute(target, attributeName) {
const innerHTML = '<x ' + attributeName + '>';
const x = document.createElement('x');
x.innerHTML = innerHTML;
const attribute = x.firstChild.attributes[0].cloneNode();
target.attributes.setNamedItem(attribute);
} // encode a :has() pseudo selector as an attribute name
function encodeAttributeName(attributeName) {
return encodeURIComponent(attributeName).replace(/%3A/g, ':').replace(/%5B/g, '[').replace(/%5D/g, ']').replace(/%2C/g, ',');
} // decode the :has() pseudo selector
function decodeHasPseudoSelector(hasPseudoText) {
return decodeURIComponent(hasPseudoText.replace(/\\([^\\])/g, '$1'));
if (selectors) {
const attributeName = ':' + (selectors[2] ? 'not-' : '') + 'has(' + // encode a :has() pseudo selector as an attribute name
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: []
});
}
});
}
}
module.exports = cssHas;
module.exports = cssHasPseudo;
//# sourceMappingURL=index.js.map
{
"name": "css-has-pseudo",
"version": "0.1.0",
"version": "0.2.0",
"description": "Style elements relative to other elements in CSS",

@@ -5,0 +5,0 @@ "author": "Jonathan Neal <jonathantneal@hotmail.com>",

@@ -41,6 +41,6 @@ # CSS Has Pseudo [<img src="http://jonathantneal.github.io/js-logo.svg" alt="" width="90" height="90" align="right">][CSS Has Pseudo]

<script src="https://unpkg.com/css-has-pseudo/browser"></script>
<script>cssHasPseudo(document)</script>
<script>cssHas(document)</script>
```
That’s it. The script is 855 bytes and works in all browsers, including
That’s it. The script is 775 bytes and works in all browsers, including
Internet Explorer 11. With a [Mutation Observer polyfill], the script will work

@@ -47,0 +47,0 @@ down to Internet Explorer 9.

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc