JavaScript Chrome Dev Tools - Remembering the selected element through page reload

I am building my own type of Chrome dev tools (inspect element) which will also be in the form of a Chrome extension using JavaScript. I would like it to have some similar functionality to Chromes dev tools, one of which I'm finding hard to debunk how they have done it.

Basically, when you right click on any element and click "inspect element" it will open up the dev tools if not already open and hover over the HTML element your right click was targeting.

The bit that I want to replicate is when you refresh the page the while you still have the element selected in dev tools, it will reload all the HTML and directly go to the element you had selected in the dev tools before reloading.

Here is what I mean if it's a little unclear:

HTML:

<div class="1">
    <div class="2">
        <div class="3"></div>
    </div>
</div>

If I was hovering over the div with class of "3" and refreshed the page, Chrome dev tools knows to reload with the dev tools highlighting that exact div. Even if there are multiple divs with that class or in a similar structure it will always hover the correct one.

Would anyone know if the best approach here is to have a big if statement which looks for certain traits of the element such as ideally an id but also a lot of fall-backs if the element does not have an id such as surrounding elements or unique classes/ attributes associated with that element?

I've tried searching for 'Chrome extension node selector' or similar variants but have not been able to find any information.

Answer:1

There already exists a pretty good "inspect element" extension that you can find here. However, it does not have support for saving the inspected element. But since it's a bounty question I could give you a few hints for improving it towards a working solution.

The main problem I see here is "serializing" the element. A good answer on this topic can be found here. (see fiddle also) It basically sums up to "find the nearest ancestor with an ID and track the path downwards to the inspected element". In your case this could be:

tracePath: function (element, result) {
  if (element.id !== '') {
    result.push({
      id: element.id
    });
    return;
  }
  if (element === document.body) {
    result.push({
      tag: element.tagName
    });
    return;
  }

  var siblings = element.parentNode.childNodes;
  for (var i = 0; i < siblings.length; ++i) {
    var sibling = siblings[i];
    if (sibling === element) {
      result.push({
        index: i,
        tag: element.tagName
      });
      return this.tracePath(element.parentNode, result);
    }
  }
},

The above just stores an array of nodes to follow during deserialization:

find: function (path) {
  var element;
  while (path.length) {
    var current = path.pop();

    if (!current) return element;
    if (current.id) element = document.getElementById(current.id);
    else if (element) {
      if (current.index < element.childNodes.length && current.tag === element.childNodes[current.index].tagName)
        element = element.childNodes[current.index];
      else
        return;
    } else {
      var matches = document.getElementsByTagName(current.tag);
      if (matches.length)
          element = matches[0];
    }
  }
  return element;
},

Once we these two, we only need ways to store/load the selection:

store: function (path) {
  var selection = Object.create({});
  selection[window.location.href] = path;
  chrome.storage.local.set(selection, function () {
    if (chrome.runtime.lastError) {
      console.error(chrome.runtime.lastError)
    }
  })
},

And load:

load: function () {
  var self = this, key = window.location.href;
  chrome.storage.local.get(key, function (found) {
    if (chrome.runtime.lastError) {
      console.error(chrome.runtime.lastError)
    } else if (found && found[key]) {
      var path = found[key],
        element = Util.find(path);

      if (element) {
        // zoom into inspected element
        element.scrollIntoView();
        // add selection to Inspector instance
        self.$selection = element;
        // function similar to layout() - highlights inspected element
        self.select();
      }
    }
  })
}

You could then write a highlighting function, say select for highlighting the inspected element, similar to already existing layout which highlights the ruler.

Saving the element could be done when clicking on it:

registerEvents: function() {
  ...
  document.addEventListener('click', function () {
      var path = [];
      Util.tracePath(this.$target, path);
      this.$selection = this.$target;
      this.select(true);
      this.storeSelection(path);
  }.bind(this));
  ...
},

There's a fork which contains the above modifications that you can find here. You can try it out by downloading it and loading the app folder as an unpacked extension in a new tab under chrome://extensions/. Enjoy!


Screenshots

enter image description here

Answer:2

You could always store the information for the element, such as id, class, font-family, etc. into chrome.storage.local/sync.

To handle a reload, you could do something such as fetching that chrome.storage object and window.location(myElement) inside your custom dev tools tab.

Answer:3

I have this line as a part from uml doc. <children xmi:type="corstr:heighj" uml:name="private" x="255" y="188" width="221" height="51"/> I need the values for x,y width and height * I tried ...

I have this line as a part from uml doc. <children xmi:type="corstr:heighj" uml:name="private" x="255" y="188" width="221" height="51"/> I need the values for x,y width and height * I tried ...

  1. file attributes from command line
  2. modify attributes from command line

const express = require('express'); const app = express(); app.use('/app', express.static(path.resolve(__dirname, './app'), { maxage: '600s' })) app.listen(9292, function(err){ if (err) ...

const express = require('express'); const app = express(); app.use('/app', express.static(path.resolve(__dirname, './app'), { maxage: '600s' })) app.listen(9292, function(err){ if (err) ...

  1. mvc ignore static files
  2. nginx ignore static files
  3. mvc route ignore static files

How could this conditional statement be simplified? Return statement is being used multiple times. Could for example ternary operators be used in this case? Is returning null a proper way to hide ...

How could this conditional statement be simplified? Return statement is being used multiple times. Could for example ternary operators be used in this case? Is returning null a proper way to hide ...

  1. using ternary operator
  2. using ternary operator javascript
  3. using ternary operator c#
  4. using ternary operator java
  5. using ternary operator python
  6. use ternary operator return
  7. use ternary operator swift
  8. use ternary operator typescript
  9. use ternary operator angularjs
  10. in ternary operators
  11. && in ternary operator javascript
  12. in ternary operator php
  13. && in ternary operator java
  14. in ternary operator c#
  15. using ternary operator in react

After searching a lot on internet when I could not get a solution I am here. I have a requirement in my project which supports multiple languages. When I am switching to a specific language it works ...

After searching a lot on internet when I could not get a solution I am here. I have a requirement in my project which supports multiple languages. When I am switching to a specific language it works ...