2

I'm trying to hightlight some part of a text in a html page having only the xPath (or css path) of the selected area, an anchorOffset and a focusOffset.

I know how to manage this using the selection() method from user input, but i'm having serious difficulties trying to reproduce the same mechanism in an automathic way without the selection but only with these infos

Example: (imagine I have many others like this)

Xpath : heyThere[1]
anchorOffset  : 3
focusOffset : 45

My goal is something like this

(see pic) http://oi57.tinypic.com/68aebo.jpg

can anybody give me an hint for this task?

Thanks a lot!

Mirco Lcl
  • 373
  • 7
  • 19

1 Answers1

1

I don't see how a relative path like heyThere[1] would select anything in an HTML document as the root element name is html and not heyThere. As for styling a certain part, assuming you have a path leading to a text node and the offsets are inside that text node, you can create a range using the W3C DOM Level 2 Rang API, create a span with a certain CSS class as a wrapper and that way the text can be highlighted. Note that support for that DOM API is not available in older IE versions, I think only Edge on Windows 10 supports document.evaluate with XPath and I am not sure about the range support.

function highlight(textNode, start, end) {
  var range = document.createRange();
  range.setStart(textNode, start);
  range.setEnd(textNode, end);
  var span = textNode.ownerDocument.createElement('span');
  span.className = 'highlight';
  range.surroundContents(span);
}

window.onload = function() {
  var testData = [
    {
      path: 'html/body/section/h1/text()',
      start: 3,
      end: 5
    },
    {
      path: 'html/body/section/div/ul/li[2]/text()',
      start: 12,
      end: 19
    },
    {
      path: '//p',
      start: 1,
      end: 1
    }
  ];
  for (var i = 0; i < testData.length; i++) {
    var node = document.evaluate(testData[i].path, document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue;
    if (node !== null) {
      highlight(node, testData[i].start, testData[i].end);
    }
    else {
      console.log('No node found for path ' + testData[i].path);
    }
  }
};
.highlight {
  color: brown;
  font-weight: bold;
}
<section>
  <h1>Example</h1>
  <div>
    <ul>
      <li>This is list item 1.</li>
      <li>This is list item 2.</li>
    </ul>
  </div>
</section>
  

I looked up the IE support, the range API is supported since IE 9 so only the XPath based access does not work, an example for IE using CSS based node selection is

function highlight(textNode, start, end) {
  var range = document.createRange();
  range.setStart(textNode, start);
  range.setEnd(textNode, end);
  var span = textNode.ownerDocument.createElement('span');
  span.className = 'highlight';
  range.surroundContents(span);
}

window.onload = function() {
  var testData = [
    {
      css: 'section > h1',
      start: 3,
      end: 5
    },
    {
      css: 'section > div > ul li:nth-child(2)',
      start: 12,
      end: 19
    },
  ];
  for (var i = 0; i < testData.length; i++) {
    var node = document.body.querySelector(testData[i].css);
    if (node !== null) {
      highlight(node.firstChild, testData[i].start, testData[i].end);
    }
    else {
      console.log('No node found for CSS selector ' + testData[i].css);
    }
  }
};
.highlight {
  color: brown;
  font-weight: bold;
}
<section>
  <h1>Example</h1>
  <div>
    <ul>
      <li>This is list item 1.</li>
      <li>This is list item 2.</li>
    </ul>
  </div>
</section>
Martin Honnen
  • 160,499
  • 6
  • 90
  • 110
  • That xPath was just an example... just suppose it's full and correct! By the way thanks a lot for your help and your code, i'll study it and let you know if I managed to adapt it to my code. – Mirco Lcl Aug 14 '15 at 09:14
  • I managed to achieve this using both your answer's code and some parts of code from this page http://stackoverflow.com/questions/6240139/highlight-text-range-using-javascript/6242538#6242538 Thanks again – Mirco Lcl Aug 15 '15 at 18:43