Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Toggle style properties with JavaScript by commenting-out CSS attributes

I want to send a list of properties to a function that will temporarily disable (via comments) those properties. The purpose is similar to what is accomplished by Chrome Dev Tools when inspecting the style of an element, except that the user will not check/uncheck boxes, instead, the action will be performed by JavaScript.

function disableProperties(el, properties) {
    var property; // property value pair
    var cssStr = el.style.cssText.replace(/; /g, ";");

    for (let i = 0; i < properties.length; i++) {
        property = properties[i] + ": " + eval("el.style." + properties[i]) + ";";
        cssStr = cssStr.replace(property, "/* " + property + " */");
    }

    el.setAttribute("style", cssStr);
}

function restoreProperties(el, properties) {
    var outHtml = el.outerHTML;
    var key = 'style="';
    var idx1 = outHtml.indexOf(key) + key.length;
    var idx2 = outHtml.indexOf('"', idx1);
    var style = outHtml.substring(idx1, idx2);

    for (let i = 0; i < properties.length; i++) {
        str = "/* " + properties[i];
        let a = style.indexOf(str);
        let b = style.indexOf(" */", a + a.length) + 3;
        let comment = style.substring(a, b);
        let property = (comment).replace("/*", "").replace("*/", "");

        style = style.replace(comment, property);
    }

    el.style.cssText = style;
}

When elements are created, their style is embedded in the HTML instead of external CSS files. It is important that the properties are only temporarily disabled; their earlier values must be preserved.

UPDATE: I thought my comment code was not working because I was trying to retrieve the comment by asking for el.style.cssText; however, the comment was only available through outerHTML.

The code below is functional, but I'm sure that could be cleaned up. If you have suggestions on how I can improve this code, please advise. Here is a fiddle to demonstrate one example of how I am using the code.

like image 824
Nathan Green Avatar asked Mar 08 '26 16:03

Nathan Green


1 Answers

Expanding on Volts deleted answer, use data attributes to store the initial state of your element. You can then that information to reset the values. One catch is that the style property is read only, so if we want to reset all style properties, we have to loop all the properties.

This is much cleaner than hacking comments in and out. This works with styles set inline and with classes.

const disableProperties = (el, properties) => {
  //store the style so we can restore it
  
  el.dataset.styles = JSON.stringify(el.style);
  console.log(JSON.parse(el.dataset.styles));
  properties.forEach(property => {
    el.style[property] = "unset";
  })
}

const enableProperties = (el, properties) => {
  //Get our saved initial state
  let styles = JSON.parse(el.dataset.styles);
  console.log(styles);
  properties.forEach(property => {
    el.style[property] = styles[property];
  })
}

const restoreAll = (el) => {   
  let styles = JSON.parse(el.dataset.styles);
  console.log(styles);
  /*You might think the following line should work, but the styles property is read only*/
  /*el.style = styles;*/
  /*So loop our properties instead*/
  for(prop in styles){
    if(styles.hasOwnProperty(prop)){
      el.style[prop] = styles[prop];
    }    
  }
}

document.querySelector('.child').addEventListener("click", function() {
  disableProperties(this.parentNode, ["top", "left"])
})

let enableButtons = document.querySelectorAll(".enable");

for (var i = 0; i < enableButtons.length; i++) {
  enableButtons[i].addEventListener("click", function(event) {
    let property = this.dataset.restore;
    let target = document.querySelector(this.dataset.target);
    enableProperties(target, property.split(","));
  });
}

document.getElementById("restoreAll").addEventListener("click", function() {
  restoreAll(document.querySelector(".parent"));
});
.parent {
  /*top: 50px;*/
  left: 50px;
  position: absolute;
}

.child {
  background: red;
  width: 50px;
  height: 50px;
}

.container {position:relative; height:200px;}
Click the square before restoring

<div class="container">
  <div class="parent" style="top:50px;">
    <div class="child">
    </div>
  </div>
</div>
<button id="restoreLeft" class="enable" data-restore="left" data-target=".parent">Restore Left</button>
<button id="restoreTop" class="enable" data-restore="top" data-target=".parent">Restore top</button>
<button id="restoreAll">RestoreAll</button>
like image 52
Jon P Avatar answered Mar 11 '26 04:03

Jon P