-1

I need to find out the position of selected text in WebBrowser control. I can acquire IHTMLTxtRange through

        IHTMLDocument2 htmlDocument = BookReaderWeb.Document as IHTMLDocument2;
        IMarkupServices ms = (IMarkupServices) htmlDocument;
        IHTMLSelectionObject selection = htmlDocument.selection;
        if (selection == null) return;
        IHTMLTxtRange range = selection.createRange() as IHTMLTxtRange;

but I have no idea how to obtain range position relative to full text (not html). thanks.

UPDATE


As Noseratio suggested, I implemented the following code:

        IHTMLDocument2 htmlDocument = BookReaderWeb.Document as IHTMLDocument2;
        var str = htmlDocument.body.outerText;
        IMarkupServices ms = (IMarkupServices) htmlDocument;
        IHTMLSelectionObject selection = htmlDocument.selection;
        if (selection == null) return;
        IHTMLTxtRange range = selection.createRange() as IHTMLTxtRange;
        dynamic body = htmlDocument.body;
        var bodyRange = body.createTextRange();
        bodyRange.moveToElementText(body);
        var bodyText = bodyRange.text;
        var counter = 0;
        while (bodyRange.compareEndPoints("StartToStart", range) != 0)
        {
            bodyRange.moveStart("character", 1);
            ++counter;
        }
        MessageBox.Show(str.Substring(counter, 20));

but it doesn't give correct result. The position is a few characters misplaced forward then it should be. It happens only on large html files, it works perfectly on smaller ones. Looks like dom api interprets some kind of tags as characters maybe..?

Davita
  • 8,928
  • 14
  • 67
  • 119

1 Answers1

3

A dumb method (using JavaScript notation for simplicity):

  1. Create a text range for document.body:
    var bodyRange = document.body.createTextRange(); bodyRange.moveToElementText(document.body);
    Now bodyRange.text corresponds to the full text.
  2. Use bodyRange.moveStart("character", 1) to move forward one char at a time, and compare its start to your selection's range start with bodyRange.compareEndPoints("StartToStart", range. When they match, you've found the position of the beginning in the full text.
  3. Do bodyRange.collapse(true), this would move the range's end to the the range's start.
  4. Use bodyRange.moveEnd("character", 1) to move forward one char at a time, and compare its start to your selection's range start with bodyRange.compareEndPoints("EndToEnd", range). When they match, you've found the position of the end in the full text.

You can improve this algorithm by moving one word or one sentence at a time for moveStart / moveEnd, then fine-matching by one char at a time.

Also, there's a better method, which uses the standard DOM Range and Selection API. I described it here.

Updated, try the following update to your code (untested):

var tempRange = bodyRange.duplicate();
while (bodyRange.compareEndPoints("StartToStart", range) != 0)
{
    bodyRange.moveStart("character", 1);
     tempRange.setEndPoint("EndToStart", bodyRange);
    //tempRange.EndToStart(bodyRange);
    if (String.Compare(tempRange.text, ((String)bodyText).Substring(counter)) != 0)
      ++counter;
}
MessageBox.Show(str.Substring(counter, 20));
Allanckw
  • 641
  • 1
  • 6
  • 17
noseratio
  • 59,932
  • 34
  • 208
  • 486
  • Thank you very much. Your answer was really helpful. Though, I'm much closer to the goal, the problem is still not solved. For small html files, the solution works perfectly, however, for large one, it doesn't give correct position. The acquired position is always misplaced by few to tens of characters. Have any idea why? Thanks again. P.S. I updated my question with the code you suggested – Davita Feb 21 '14 at 21:17
  • I have another problem with browser dom. Maybe you can take a look? :) Thanks http://stackoverflow.com/questions/21959096/ihtmltxtrange-pasthtml-limit – Davita Feb 22 '14 at 19:11