0

I'm on a website, I click on any element and manipulate it

document.addEventListener('click', function(e){
  e.target.innerHTML = `<span style="background: red">${e.target.innerText}</span>`
})

How can I store a reference to the element I clicked on?

I want to store a reference to the database so that when the page is reloaded, that exact same element is wrapped in a span tag.

relidon
  • 2,142
  • 4
  • 21
  • 37
  • Are you looking to store the actual element itself (JS can do this easily, elements can be stored as variables) or serialize it as a string? I feel like if you're storing an element as a string in a DB for a dynamic site, there are much more elegant / efficient ways of storing data; something more atomic that you can use to rebuild the elements with a server-side language or something. – matthew-e-brown Dec 08 '19 at 02:06
  • @matthew-e-brown I'm creating a highlighting chrome extension for myself. say I'm on a wiki article. The text I highlight turns red and it's stored in aa DB (I have that). Then when I refresh the same page I need to see the previous highlights. – relidon Dec 08 '19 at 02:12
  • 3
    You can't do this without adding unique identifiers to DOM nodes that stay stable across page reloads. Any other method of doing this would be really brittle. JavaScript references to DOM are not stable across page reloads. There is probably a better way to do what you want without using exactly this kind of solution. What problem are you trying to solve? – Dan Dec 08 '19 at 02:20
  • @DanPantry how this extension does it https://chrome.google.com/webstore/detail/weava-highlighter-pdf-web/cbnaodkpfinfiipjblikofhlhlcickei – relidon Dec 08 '19 at 02:22
  • 1
    You can use element selector to resolve on page reload, but there is no guarantee you will get the same element or any element at all. You have no control over 3rd party web pages. – dezull Dec 08 '19 at 02:27
  • Not sure, but PDF documents are different to web pages. Documents, in general, do not change. – Dan Dec 08 '19 at 02:27
  • Oh so the extension is for your own documents? then if you have control in rendering the document, you might as well put your own identifier on the element, data or id attributes for example. – dezull Dec 08 '19 at 02:30
  • @DanPantry The screenshot is misleading. I'm not bothered about PDF. I'm trying to clone the web part. If basically allows you to select text from any web page, it turns it gives the selection a background color (I did that sort of already). Then, when you refresh the page it remembers which section needs to be highlighted. – relidon Dec 08 '19 at 02:36
  • @dezull No, that's the problem, the chrome extension I provided as an example might be misleading. I'm creating an extension, where if you go to, saw, Wikipedia, it lets you highlight text (I know how to do that). but then when you refresh the page, how do I keep a reference to the nodes that need changing. – relidon Dec 08 '19 at 02:40
  • The example in my original example is exactly what I need, how to I remember which element I clicked on after reload. – relidon Dec 08 '19 at 02:41
  • 2
    You can't, but you can try saving the selector, but like I said, it might not get the same element. See https://stackoverflow.com/questions/29787964/build-the-queryselector-string-value-of-any-given-node-in-the-dom how to get selector (eg: from your `e.target`) – dezull Dec 08 '19 at 02:47
  • *how this extension does it* - download the extension and read the code :p – Jaromanda X Dec 08 '19 at 03:22
  • @JaromandaX I tried, I'm not good enough to make use of it :P – relidon Dec 08 '19 at 03:36
  • @dezull yep, that does bring me closer to what I need. – relidon Dec 08 '19 at 03:43

1 Answers1

0

Not thoroughly tested, but an alternative to the code in Build the querySelector string value of any given node in the DOM

Note: that code assumes well written HTML, i.e unique ID's - unfortunately, the web is full of rubbish pages that have non-unique ID's, therefore that code will fail

The result may well be a longer selector than the above code, but it seems to work - I've yet to break it :p

function getCSSPath(el) {
    const fullPath = [];
    const fn = el => {
        let tagName = el.tagName.toLowerCase();
        let elPath = '';
        if (el.id) {
            elPath += '#' + el.id;
        }
        if (el.classList.length) {
            elPath += '.' + [...el.classList].join('.');
        }
        if (el.parentElement) {
            if (el.previousElementSibling || el.nextElementSibling) {
                let nthChild = 1;
                for (let e = el.previousElementSibling; e; e = e.previousElementSibling, nthChild++);
                tagName += `:nth-child(${nthChild})`;
            }
            fn(el.parentElement);
        }
        fullPath.push(tagName + elPath);
    };
    fn(el);
    return fullPath.join('>');
}

I think this is better version of above though:

function getCSSPath(el) {
    let elPath = el.tagName.toLowerCase();
    if (el.parentElement && (el.previousElementSibling || el.nextElementSibling)) {
        let nthChild = 1;
        for (let e = el.previousElementSibling; e; e = e.previousElementSibling, nthChild++);
        elPath += `:nth-child(${nthChild})`;
    }
    if (el.id) {
        elPath += '#' + el.id;
    }
    if (el.classList.length) {
        elPath += '.' + [...el.classList].join('.');
    }
    return (el.parentElement ? getCSSPath(el.parentElement) + '>' : '') + elPath;
}
Jaromanda X
  • 53,868
  • 5
  • 73
  • 87
  • Now I'm at the testing stage and I'm getting into the problem of this function going too deep. For example in Reddit, the output doesn't result in anything. The solution would be for this function not to go all the way back to `html`. I'm trying to modify it but how would you do it so that it goes only a few levels deep, say `.gran>.parent>.element` - thanks – relidon Dec 19 '19 at 09:38
  • ... I sliced the result to get what I needed `getCSSPath(parentEl).split(">").slice(1).slice(-2).join(">")` and it works, I'm just asking for learning purposes, how you'd refactore the function – relidon Dec 19 '19 at 10:05