2

I'd like to keep track of changes that I make in chrome's dev tools on a website. I was wondering if chrome or javascript has any way of keeping track of this via a chrome plugin or something.

I was thinking one thing you might be able to do is store a page's HTML, and then when you're doing making changes, diff the current HTML with what was stored. This would allow you to keep track of the styling changes that were made on element.style because they get applied as inline styles right on the element like shown below where I add color:red;:

Imgur

But what about keeping track of style changes that are made to elements who's styles are being manipulated through a stylesheet like this? (where I added color:white;background:blue;

Imgur

Joshua Terrill
  • 1,995
  • 5
  • 21
  • 40
  • You can see the changes applied in dev tools. Go to the sources tab and find the css file in the top. Right click on it, select 'local modifications...'. – Gerard Jul 14 '17 at 08:06
  • The dev tools can be inspected like web pages when set to pop-out (ctrl+shift+i). Once there, you can do the same sorts of things you might to a web page, such as dig through it for data. Running `document.querySelector(".styles-pane").querySelectorAll(".styles-section").forEach((e)=>{console.log(e.querySelector(".style-properties").shadowRoot.textContent);});` for example, will output the `textContent` of each section in the styles pane. Sorry, too tired to develop proper answer. – Fred Gandt Jul 14 '17 at 08:16
  • @Gerard yes, I'm just wondering if I can programmatically get all the styles that have changed. I know that I can view them. I want to be able to store them in an array or something programatically. – Joshua Terrill Jul 14 '17 at 08:50
  • P.S. That rushed code in my comment above doesn't say anything useful. I didn't properly examine the results at the time, and actually most of the output is the styles of the styles, so derp. I was certainly heading in the right direction though ;-) – Fred Gandt Jul 16 '17 at 10:10

1 Answers1

2

window.getComputedStyle( element )

The window.getComputedStyle() method gives the values of all the CSS properties of an element after applying the active stylesheets and resolving any basic computation those values may contain.

The demonstration below omits keeping track of pseudo-elements, but that functionality could be shoehorned in using window.getComputedStyle(element[, pseudoElt]); where:

element
The Element for which to get the computed style.

pseudoElt Optional
A string specifying the pseudo-element to match. Must be omitted (or null) for regular elements.

Usage

  • Add the code to the HTML document you're working on, via <script> or the developer console.
  • Use setInitStyles() to set or reset the state of the styles of each of the elements, which is compared against when calling differenceEngine().
  • Use differenceEngine() to get the difference between the styles set when last calling setInitStyles() and now.

Example

This code would benefit from some optimization, and alteration to taste i.e. the output format may be undesirable.

The snippet will run as expected (tested in Chrome), but since large amounts of data are logged to the console, I disabled the snippet's console (for efficiency) so you'll need to see the output in your browser's.

const compressedStyles = ( e ) => {
  const ucs = window.getComputedStyle( e );
  var s, cs = {};
  for ( s in ucs ) {
    if ( ucs.hasOwnProperty( s ) && /[^0-9]+/.test( s ) ) {
      cs[ s.replace( /([A-Z])/g, "-$1" ).toLowerCase() ] = ucs[ s ];
    }
  }
  return cs;
},
setElementStyles = ( e ) => {
  e.stylesInit = compressedStyles( e );
  e.stylesDiff = {}; // while we're here
},
allTheThings = () => {
  var att = Array.from( document.body.querySelectorAll( "*:not( script )" ) );
  att.unshift( document.body );
  return att;
},
setInitStyles = () => {
  allTheThings().forEach( setElementStyles );
},
differenceEngine = () => {
  allTheThings().forEach( ( e ) => {
    if ( e.stylesInit ) {
      const cs = compressedStyles( e );
      var s, css, ess;
      for ( s in e.stylesInit ) {
        ess = e.stylesInit[ s ].toString();
        css = cs[ s ].toString();
        if ( ess != css ) {
          e.stylesDiff[ s ] = { "curr": css, "init": ess };
        }
      }
      console.log( e, e.stylesDiff );
    } else {
      setElementStyles( e ); // set current styles on new elements
    }
  } );
};

console.info( "Setting the initial styles" );
setInitStyles();

console.info( "Changing the style of one of the elements" );
document.querySelector( "div" ).style.border = "2px solid red";

console.info( "What's the difference?" );
differenceEngine();

console.info( "Resetting the style of the element" );
document.querySelector( "div" ).removeAttribute( "style" );

console.info( "What's the difference?" );
differenceEngine();

console.info( "Changing the class of one of the elements" );
document.querySelector( "p" ).classList.add( "foo" );

console.info( "What's the difference?" );
console.warn( "Properties that inherit from color have also changed" );
differenceEngine();

console.info( "Resetting the class of the element" );
document.querySelector( "p" ).classList.remove( "foo" );

console.info( "What's the difference?" );
differenceEngine();
p.foo {
  color: red;
}
<div>
  <p>Foo</p>
  <p>Bar</p>
  <p>Baz</p>
</div>

Made with love of the chase, as a suggestion, not a final solution.

Possible Chrome DevTools Extension

Since getComputedStyle() does exactly that, the results of the above can be a little less than helpful.

Turning our attention to the actual DevTools, we can inspect them (when popped out and focussed) and run scripts on the inspector.
This is a step toward extending the DevTools with a Chrome Extension.

Whilst pondering the build process, I stumbled upon SnappySnippet; a Chrome Extension inspired by a Stack Overflow question that supposedly (I have not used it) makes the creation of Snippets from web pages easy.

That extension may provide functionality that would effectively answer your question, but in case it doesn't (and for fun), I have started to work on what may become another Chrome Extension.
Be aware, this process may be long, slow and fruitless; if at any point I create anything more useful than the code below, I will return to update this answer.

I hereby present my latest kludge! \o/

document.querySelectorAll( ".styles-section" ).forEach( ( e ) => {
  var output;
  const selector = e.querySelector( ".selector" ).textContent,
        properties = e.querySelector( ".style-properties" )
                       .shadowRoot.querySelectorAll( ".tree-outline > li" );
  if ( properties ) {
    output = selector + " {\n";
    properties.forEach( ( p ) => {
      const property = p.querySelector( ".webkit-css-property" ).textContent,
            value = p.querySelector( ".value" ).textContent;
      if ( p.classList.contains( "inactive" ) ) {
        output += "\t/* " + property + ": " + value + "; */\n";
      } else {
        output += "\t" + property + ": " + value + ";\n";
      }
    } );
  }
  console.log( output + "}" );
} );

This code, when run on an inspector on an inspector (not a typo), will spit out a pretty copy of the content of the styles pane for the currently selected element in the inspector of the original HTML.

Mhmm - kludge.

Instead of spitting out a bunch of text, it could be relatively simply tweaked to spit out an object of data, which like in the code of my first response, could be compared with other snapshots to get the difference.

And, since this code is being run on the inspector, and not on the document being manipulated, it is a solid step toward exactly what we could achieve with a DevTools Extension.

I will continue fiddling with this, and update this answer as I go, but don't hold your breath.

Manual Solution (in lieu of wizardry)

Although not even remotely high-tech, there is a very simple and reliable method to keep track of changes one makes to element.style and CSS from resources or <style>sheets:

Screenshot of manual solution in use

As you can see in the screenshot above, we can add comments to any value of any property we change or add, showing what the value used to be, or that the value is entirely new.
And of course, if we want to remove anything, we can just uncheck the checkbox to the left of the property, so the value is maintained.

Fred Gandt
  • 4,217
  • 2
  • 33
  • 41
  • Thank you. This is super cool. I wonder if there's a way to get it to not show the styles that weren't directly affected. I understand why it's doing that, I just wonder if there's a way so that if you edit `color:red;`, it only will output `color:red;` and not `border:"0px none rgb(255, 0, 0)";border-bottom:"0px none rgb(255, 0, 0)";border-color:"rgb(255, 0, 0)";` etc etc. Thanks for the answer! – Joshua Terrill Jul 16 '17 at 01:42
  • @JoshuaTerrill - I just woke up and logged in, so although I have read and understood your message, my brain is only responding with _"I can haz tea now?"_ I'll see what I can figure out in a while. _e.g._ If you change the value of a CSS class's `color` and that class relies on the `color` to apply a `border` in the same color; to get only that the `color` has changed may be a nightmare without running the script on the inspector (per my comment under your question). If you create a new class in the inspector a whole bunch of other concerns step in. Tea first then walk dog. See ya later! – Fred Gandt Jul 16 '17 at 02:08
  • Totally understandable. I look forward to your response! – Joshua Terrill Jul 16 '17 at 03:04
  • @JoshuaTerrill - I have started the process, but it may take some time (I've only published one Chrome Extension before and it's dirt simple). I updated the answer to show my working, provide some code that does something useful, and provided a link to what may be a ready to use solution. – Fred Gandt Jul 16 '17 at 10:05
  • Added manual solution that's actually not half bad, but I have built a devtools extension with truly horrific UX that I may not be able to make nice. I will continue to work on it and post whatever I have when I either give up or succeed. – Fred Gandt Jul 18 '17 at 18:41
  • @JoshuaTerrill - I just wanted to let you know that after much wrangling and head scratching, I have concluded that a devtools extension will not work (nicely (many reasons for later)). However, using [the devtools protocol](https://chromedevtools.github.io/devtools-protocol/) an extension can be built to emulate the Chrome tools style pane, which can include the desired functionality. This is however a substantial task, and may take me a long (long) time. I am keen on making it work myself though, so don't give up yet :-) – Fred Gandt Jul 22 '17 at 16:36
  • @JoshuaTerrill - I worked something out that appears to be working - so far. It's pulling copies of all the CSS resources, content of all ` – Fred Gandt Jul 23 '17 at 20:16
  • Thank you for all the help, I cannot wait to see it! Is there a way you could send me your email address/some place that I could find your email? – Joshua Terrill Jul 24 '17 at 09:40
  • @JoshuaTerrill - Just letting you know this is still in development; parsing CSS is taxing; recursivity required. RE email: I do code purely for fun - not work, and as such am quite purposefully _hard_ to find; what little sanity I have collapses under even light pressure, so I make great effort to pick projects as and when it suits me, rather than have them _offered_. I hope you understand. That said: this looks like it will actually work (reasonably well), and should be ready to roll soon-ish. I'll be quiet 'till then :-) – Fred Gandt Jul 29 '17 at 04:43