I wrote my function to assign properties to pseudo-elements and noticed an unknown error. The assignment of properties goes through the addition of lines to the styleSheet.

When in the third case I call the function, for some reason the first element is painted in blue, although I did not set color for it.

 (function() { var setPseudoElement = function(parameters) { for (var element of parameters.elements.get()) { if (!element.pseudoElements) element.pseudoElements = { styleSheet: null, before: { index: null, properties: null }, after: { index: null, properties: null } }; var selector = (function() { if (element.id) { return '#' + element.id + '::' + parameters.pseudoElement; } else { var parentsList = $(element).parents().map(function() { return this.tagName.toLowerCase(); }).get().reverse().join(' > ') + ' > ' + element.tagName.toLowerCase(); var elementClass = element.classList.length ? '.' + $(element.classList).get().join('.') : ''; var elementAttributes = element.hasAttributes() ? $(element.attributes).get().map(function(className) { return className.nodeName !== 'class' ? className.nodeValue ? '[' + className.nodeName + '="' + className.nodeValue + '"]' : '[' + className.nodeName + '"]' : ''; }).join('') : ''; var elementNthChild = ':nth-child(' + ($(element).index() + 1) + ')'; return parentsList + elementClass + elementAttributes + elementNthChild + '::' + parameters.pseudoElement; }; })(); if (!element.pseudoElements.styleSheet) { if (document.styleSheets[0]) { element.pseudoElements.styleSheet = document.styleSheets[0]; } else { var styleSheet = document.createElement('style'); document.head.appendChild(styleSheet); element.pseudoElements.styleSheet = styleSheet.sheet; }; }; if (element.pseudoElements[parameters.pseudoElement].properties !== null && element.pseudoElements[parameters.pseudoElement].index !== null) { element.pseudoElements.styleSheet.deleteRule(element.pseudoElements[parameters.pseudoElement].index); }; if (typeof parameters.argument === 'object') { if (!element.pseudoElements[parameters.pseudoElement].properties && !element.pseudoElements[parameters.pseudoElement].index) { var newIndex = element.pseudoElements.styleSheet.rules.length || element.pseudoElements.styleSheet.cssRules.length || element.pseudoElements.styleSheet.length; element.pseudoElements[parameters.pseudoElement].index = newIndex; element.pseudoElements[parameters.pseudoElement].properties = parameters.argument; }; var properties = ''; for (var property in parameters.argument) { element.pseudoElements[parameters.pseudoElement].properties[property] = parameters.argument[property]; }; for (var property in element.pseudoElements[parameters.pseudoElement].properties) { properties += property + ': ' + element.pseudoElements[parameters.pseudoElement].properties[property] + ' !important; '; }; element.pseudoElements.styleSheet.addRule(selector, properties, element.pseudoElements[parameters.pseudoElement].index); } else if (parameters.argument !== undefined && parameters.property !== undefined) { } else if (parameters.argument !== undefined && parameters.property === undefined) { } else { console.error('Invalid values!'); return false; }; }; }; $.fn.cssBefore = function(argument, property) { setPseudoElement({ elements: this, pseudoElement: 'before', argument: argument, property: property }); }; })(); $(function() { // Случай 1 $('.el0').cssBefore({ 'content': '"Новый \'before\'"', 'color': 'green' }); // Случай 2 $('.el1').cssBefore({ 'content': '"Новый \'before\' №2"', 'color': 'blue' }); // Случай 3 $('.el0').cssBefore({ 'content': '"Новый \'before\' №3"' }); }); 
 .element { width: 480px; margin: 0 auto; border: 2px solid red; } .element:before { content: "Старый 'before'"; color: orange; } 
 <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script> <div class="element el0" name="MyName"></div> <div class="element el0 el1" id="elem"></div> <div> <div class="element el1"></div> </div> 

Why in the third case is the first element painted blue? How to fix it?


UPDATA:

If you output the values ​​of the elements to the console after each assignment, then very strange values ​​come out:

 (function () { var i = 1; var setPseudoElement = function (parameters) { for (var element of parameters.elements.get()) { if (!element.pseudoElements) element.pseudoElements = {styleSheet: null, before: {index: null, properties: null}, after: {index: null, properties: null}}; var selector = (function () { if (element.id) { return '#' + element.id + '::' + parameters.pseudoElement; } else { var parentsList = $(element).parents().map(function () { return this.tagName.toLowerCase(); }).get().reverse().join(' > ') + ' > ' + element.tagName.toLowerCase(); var elementClass = element.classList.length ? '.' + $(element.classList).get().join('.') : ''; var elementAttributes = element.hasAttributes() ? $(element.attributes).get().map(function (className) { return className.nodeName !== 'class' ? className.nodeValue ? '[' + className.nodeName + '="' + className.nodeValue + '"]' : '[' + className.nodeName + '"]' : ''; }).join('') : ''; var elementNthChild = ':nth-child(' + ($(element).index() + 1) + ')'; return parentsList + elementClass + elementAttributes + elementNthChild + '::' + parameters.pseudoElement; }; })(); if (!element.pseudoElements.styleSheet) { if (document.styleSheets[0]) { element.pseudoElements.styleSheet = document.styleSheets[0]; } else { var styleSheet = document.createElement('style'); document.head.appendChild(styleSheet); element.pseudoElements.styleSheet = styleSheet.sheet; }; }; if (element.pseudoElements[parameters.pseudoElement].properties !== null && element.pseudoElements[parameters.pseudoElement].index !== null) { element.pseudoElements.styleSheet.deleteRule(element.pseudoElements[parameters.pseudoElement].index); }; if (typeof parameters.argument === 'object') { if (!element.pseudoElements[parameters.pseudoElement].properties && !element.pseudoElements[parameters.pseudoElement].index) { var newIndex = element.pseudoElements.styleSheet.rules.length || element.pseudoElements.styleSheet.cssRules.length || element.pseudoElements.styleSheet.length; element.pseudoElements[parameters.pseudoElement].index = newIndex; element.pseudoElements[parameters.pseudoElement].properties = parameters.argument; }; var properties = ''; for (var property in parameters.argument) { element.pseudoElements[parameters.pseudoElement].properties[property] = parameters.argument[property]; }; for (var property in element.pseudoElements[parameters.pseudoElement].properties) { properties += property + ': ' + element.pseudoElements[parameters.pseudoElement].properties[property] + ' !important; '; }; element.pseudoElements.styleSheet.addRule(selector, properties, element.pseudoElements[parameters.pseudoElement].index); console.log('Номер запуска: ' + Math.round(i / 2) + '; Номер присваивания элементу: ' + i); console.log({ 'Элемент 1': $('.el0:not(.el1)').get(0).pseudoElements, 'Элемент 2': $('.el0.el1').get(0).pseudoElements, 'Элемент 3': $('.el1:not(.el0)').get(0).pseudoElements }); i++; } else if (parameters.argument !== undefined && parameters.property !== undefined) { } else if (parameters.argument !== undefined && parameters.property === undefined) { } else { console.error('Invalid values!'); return false; }; }; }; $.fn.cssBefore = function (argument, property) { setPseudoElement ({ elements: this, pseudoElement: 'before', argument: argument, property: property }); }; })(); $(function() { // Случай 1 $('.el0').cssBefore({ 'content': '"Новый \'before\'"', 'color': 'green' }); // Случай 2 $('.el1').cssBefore({ 'content': '"Новый \'before\' №2"', 'color': 'blue' }); // Случай 3 $('.el0').cssBefore({ 'content': '"Новый \'before\' №3"' }); }); 
 .element { width: 480px; margin: 0 auto; border: 2px solid red; } .element:before { content: "Старый 'before'"; color: orange; } 
 <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script> <div class="element el0" name="MyName"></div> <div class="element el0 el1" id="elem"></div> <div> <div class="element el1"></div> </div> 

If you look at the console, then the first time you call the function, element number 1 is blue and the content is number 3.

  • Because you added a style to it: html> body> div: nth-child (4) :: before color: blue; - Drag13
  • @Vitalii, that's right. After all :nth-child(1) is a script element - Yuri
  • one
    Prodebte code in the console, find what the error is. - Dantessss
  • @Yuri well, and debugging (debugging) to correct this error, and not just look at the console)) - Alex Shimansky
  • add at least a description of what your code does - Grundy

2 answers 2

I think I found a problem:

 element.pseudoElements[parameters.pseudoElement].properties = parameters.argument; 

where parameters.argument is an object. When we make the first pass, we set it for the first and second element. When on the second pass we change it for the second case, it changes for the first one too.

And proof and decision

 element.pseudoElements[parameters.pseudoElement].properties = Object.assign({}, parameters.argument); 
  • But I did not add blue color to the parameters of the first element ... There should be green - Yuri
  • He lies in before ... Now we dig out where he came from. - Drag13
  • Here it is not clear :) - Yuri
  • So, he said that he was obviously somehow tied to the parameters . Bravo - Vyacheslav Potseluyko
  • Actually, it is enough .properties = {} , because next is a cycle in which the properties from arguments are copied - Grundy

This is how the behavior will be expected by you. What was originally a trick - while I figure it out, I will add in half an hour. setTimeouts are for debug convenience, if that. Comrades, at least kill me, I do not understand why it works and what is not initially so. Slippage in the body of the parameters element is embarrassing, since, logically, it should not be inside the loop, work is done with a specific element , but most likely I just don’t know jquery .

 (function() { var i = 1; var setPseudoElement = function(parameters) { for (var element of parameters.elements.get()) { if (!element.pseudoElements){ element.pseudoElements = { styleSheet: null, before: { index: null, properties: null }, after: { index: null, properties: null } };} if (element.pseudoElements) { element.pseudoElements.before.properties = null; element.pseudoElements.before.index = null; } var selector = (function() { if (element.id) { return '#' + element.id + '::' + parameters.pseudoElement; } else { var parentsList = $(element).parents().map(function() { return this.tagName.toLowerCase(); }).get().reverse().join(' > ') + ' > ' + element.tagName.toLowerCase(); var elementClass = element.classList.length ? '.' + $(element.classList).get().join('.') : ''; var elementAttributes = element.hasAttributes() ? $(element.attributes).get().map(function(className) { return className.nodeName !== 'class' ? className.nodeValue ? '[' + className.nodeName + '="' + className.nodeValue + '"]' : '[' + className.nodeName + '"]' : ''; }).join('') : ''; var elementNthChild = ':nth-child(' + ($(element).index() + 1) + ')'; return parentsList + elementClass + elementAttributes + elementNthChild + '::' + parameters.pseudoElement; }; })(); if (!element.pseudoElements.styleSheet) { if (document.styleSheets[0]) { element.pseudoElements.styleSheet = document.styleSheets[0]; } else { var styleSheet = document.createElement('style'); document.head.appendChild(styleSheet); element.pseudoElements.styleSheet = styleSheet.sheet; }; }; if (element.pseudoElements[parameters.pseudoElement].properties !== null && element.pseudoElements[parameters.pseudoElement].index !== null) { element.pseudoElements.styleSheet.deleteRule(element.pseudoElements[parameters.pseudoElement].index); }; if (typeof parameters.argument === 'object') { if (!element.pseudoElements[parameters.pseudoElement].properties && !element.pseudoElements[parameters.pseudoElement].index) { var newIndex = element.pseudoElements.styleSheet.rules.length || element.pseudoElements.styleSheet.cssRules.length || element.pseudoElements.styleSheet.length; element.pseudoElements[parameters.pseudoElement].index = newIndex; element.pseudoElements[parameters.pseudoElement].properties = parameters.argument; }; var properties = ''; for (var property in parameters.argument) { element.pseudoElements[parameters.pseudoElement].properties[property] = parameters.argument[property]; }; for (var property in element.pseudoElements[parameters.pseudoElement].properties) { properties += property + ': ' + element.pseudoElements[parameters.pseudoElement].properties[property] + ' !important; '; }; element.pseudoElements.styleSheet.addRule(selector, properties, element.pseudoElements[parameters.pseudoElement].index); console.log('Номер запуска: ' + Math.round(i / 2) + '; Номер присваивания элементу: ' + i); console.log({ 'Элемент 1': $('.el0:not(.el1)').get(0).pseudoElements, 'Элемент 2': $('.el0.el1').get(0).pseudoElements, 'Элемент 3': $('.el1:not(.el0)').get(0).pseudoElements }); i++; } else if (parameters.argument !== undefined && parameters.property !== undefined) { } else if (parameters.argument !== undefined && parameters.property === undefined) { } else { console.error('Invalid values!'); return false; }; }; }; $.fn.cssBefore = function(argument, property) { setPseudoElement({ elements: this, pseudoElement: 'before', argument: argument, property: property }); }; })(); $(function() { // Случай 1 $('.el0').cssBefore({ 'content': '"Новый \'before\'"', 'color': 'green' }); setTimeout(() => { // Случай 2 $('.el1').cssBefore({ 'content': '"Новый \'before\' №2"', 'color': 'blue' }); }, 3000); // Случай 3 setTimeout(() => { $('.el0').cssBefore({ 'content': '"Новый \'before\' №3"' });}, 6000); }); 
 .element { width: 480px; margin: 0 auto; border: 2px solid red; } .element:before { content: "Старый 'before'"; color: orange; } 
 <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script> <div class="element el0" name="MyName"></div> <div class="element el0 el1" id="elem"></div> <div> <div class="element el1"></div> </div> 

  • Completed the answer. Honestly, I thought this does not happen. I sit, I'm stupid .. - Vyacheslav Potseluyko
  • To be honest, I also do not understand why your answer works. I myself can not sit understand - Yuri
  • If nobody writes why, then your reputation is Yuri
  • @Yuri, but it works, I did not think? Have you tested on other examples? - Vyacheslav Potseluyko
  • I tested it in several cases and it works in all variants. Interesting, of course - Yuri