2

Any way to get the ".indexOf()" string position of the start and end of a jQuery-selected element relative to the parent?

Example:

<ul><li>Coffee</li><li>Coffee</li><li>Coffee</li></ul>

After selecting the 2nd <li> item via jquery, the function would return 15 (or 29 with an argument switch).

I am thinking about a verbose javascript workaround but it gets nasty and unreliable very fast. Also it might not work if there are other tag types or text mixed in between. Bad. Not to take seriously.

//http://stackoverflow.com/a/14482123
function nthIndex(str, pat, n){
    var L= str.length, i= -1;
    while(n-- && i++<L){
        i= str.indexOf(pat, i);
    }
    return i;
}

function strpos(jelem, tag) {
    var nth = jelem.index();
    var contents = jelem.parent().text();
    var pos = nthIndex(contents, tag, nth+1);
    if (tag.indexOf('/') == 1) {
        return pos+4; //because ending of '</li>' is +4 (very bad)
    } else {
        return pos;
    }
}

strpos(jelem, '<li>'); //or '</li>' to return the ending position
user2464424
  • 1,536
  • 1
  • 14
  • 28
  • Just curious, what is this used for? –  Dec 20 '15 at 14:50
  • 1
    Why on earth would you need the string position of the HTML tags, including content etc? Me thinks this is a X/Y problem ! – adeneo Dec 20 '15 at 14:51
  • Once the original HTML markup has been parsed and the DOM created, the original text isn't really useful. – Pointy Dec 20 '15 at 14:54
  • @squint basically i have a html text editor with preview, i thought it would be a nice addition to display information such as the string position inside the raw html of, say, a hovered element in the preview and have nice things like highlighting the portion of the raw html refering to the element. – user2464424 Dec 20 '15 at 15:05
  • Yeah, the trouble is unless you wrote the renderer yourself, it throws away the original HTML, so the HTML you target for highlighting may not match up with whatever you get from the preview's DOM. –  Dec 20 '15 at 15:08

1 Answers1

2

Like adeneo said, this seems like an XY problem, but you really need a parser and I doubt you feel like writing your own.

One possibility would be to use the native .outerHTML and sum the .length of all the .previousSibling nodes, and then the .length of current one if you need the end position.

However, you should know that this has nothing to do with the original HTML. These will be HTML strings rendered by the browser after analysing the current state of the DOM.


Here's a quick example that receives an element and returns the start (or optionally the end) position:

function getPos(origElem, doEnding) {
  var sum = 0;
  var elem = origElem;

  while ((elem = elem.previousSibling)) {
    sum += elem.outerHTML.length;
  }

  if (doEnding) {
    sum += origElem.outerHTML.length-1;
  }
  return sum;
}

var li = document.querySelector("li:nth-child(2)");

var p = document.querySelector("pre");

p.textContent = "Position is: " + getPos(li);
p.textContent += "\nEnd position is: " + getPos(li, true);
<ul><li>Coffee</li><li>Coffee</li><li>Coffee</li></ul>

<pre></pre>