0

I built a chrome extension that manipulates the DOM - i.e. highlight, underline, etc via the following functions.

function getSelectedText() {
    let selected = window.getSelection();
    if (selected.rangeCount && selected.getRangeAt) {
        range = selected.getRangeAt(0);
    }
    if (range) {
        selected.removeAllRanges();
        selected.addRange(range);
    }
}
function createSpan(addClass) {
    try {
        let newElement = document.createElement('span');
        newElement.classList.add(addClass);
        range.surroundContents(newElement);
    } catch (error) {
        if (error instanceof DOMException) {
            alert('XYZ');
        }
    }
}

The paramter "addClass" attaches to its respective CSS script, which is appended to the html at the beginning of my content script. This works fine, but now I am not sure how to re-build the range object in order to load all of the changes made on tab refresh or reopen.

Some of my attempts include the following;

  • saving the innerHTML of the parentElement, so it includes the newly created span tags and overwriting the html innerHTML with it on page load. I received a warning that stated "reverting mutation of childList in component" and this did not work
  • trying to save the range object as a whole, returned an {} empty object

Unable to store/retrieve an object using chrome.storage.sync in chrome extension

Then, I came across another post in which the user was also having trouble because node objects, required for range.setStart and .setEnd, are not JSONifiable and hence cannot be saved to chrome.storage.

Is there a workaround for this please? Or if you think my entire approach of using .surroundContents to manipulate the DOM should be changed, I would kindly appreciate any insights as this is my very first extension and I am about 2 months into javascript.

A sample of a DOM manipulated node would look something like this;

<div>ABC <span class="highlighted">DEF</span> GHI</div>
kenta_desu
  • 303
  • 1
  • 9
  • 1
    You can store the relative index of the range boundary elements inside the all elements array [...document.getElementsByTagName('*')]. This will fail on sites that conditionally add elements in the middle so a more reliable method is to [generate a unique selector](/questions/8588301). – wOxxOm Jul 30 '22 at 12:25
  • @wOxxOm thank you. Do you mind breaking down your first solution a bit please? I am not sure if I understand. – kenta_desu Jul 31 '22 at 02:55
  • 1
    Storing: `[].indexOf.call(document.getElementsByTagName('*'), elem1)`, reading: `document.getElementsByTagName('*')[elem1index]` – wOxxOm Jul 31 '22 at 04:09
  • @wOxxOm thank you. So, am I right to say that your former code will identify the index of elem1 within the entire array to be stored and then extracted on page load to be used to find the node which had its innerText edited? If so, would the idea then be to use the range offsets to define the segment of innerText subject to surroundContent()? – kenta_desu Jul 31 '22 at 09:48

0 Answers0