最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Character offset in an Internet Explorer TextRange - Stack Overflow

programmeradmin0浏览0评论

As far as I can tell there's no simple way of retrieving a character offset from a TextRange object in Internet Explorer. The W3C Range object has a node, and the offset into the text within that node. IE seems to just have pixel offsets. There are methods to create, extend and compare ranges, so it would be possible to write an algorithm to calculate the character offset, but I feel I must be missing something.

So, what's the easiest way to calculate the character offset of the start of an Internet Explorer TextRange?

As far as I can tell there's no simple way of retrieving a character offset from a TextRange object in Internet Explorer. The W3C Range object has a node, and the offset into the text within that node. IE seems to just have pixel offsets. There are methods to create, extend and compare ranges, so it would be possible to write an algorithm to calculate the character offset, but I feel I must be missing something.

So, what's the easiest way to calculate the character offset of the start of an Internet Explorer TextRange?

Share Improve this question edited Jan 24, 2024 at 15:45 community wiki
3 revs, 3 users 100%
Thom 1
  • Do you want to count the number of characters to the left of the screen before the start of the range? – Diodeus - James MacFarlane Commented Oct 2, 2008 at 20:06
Add a comment  | 

4 Answers 4

Reset to default 8

I use a method based on this caret position trick:

// Assume r is a range:
var offsetFromBody = Math.abs( r.moveEnd('character', -1000000) );

Since moveEnd returns the number of characters actually moved, offset should now be the offset from the start of the document. This works fine for testing primitive caret movement, but for expanded selections and for getting the exact node that holds the range anchor you'll need something more complex:

// where paramter r is a range:
function getRangeOffsetIE( r ) {
  var end = Math.abs( r.duplicate().moveEnd('character', -1000000) );
  // find the anchor element's offset
  var range = r.duplicate();
  r.collapse( false );
  var parentElm = range.parentElement();
  var children = parentElm.getElementsByTagName('*');
  for (var i = children.length - 1; i >= 0; i--) {
    range.moveToElementText( children[i] );
    if ( range.inRange(r) ) {
      parentElm = children[i];
      break;
    }
  }
  range.moveToElementText( parentElm );
  return end - Math.abs( range.moveStart('character', -1000000) );
}

This should return the correct caret text offset. Of course, if you know the target node already, or are able to provide a context, then you can skip the whole looping search mess.

I'd suggest IERange, or just the TextRange-to-DOM Range algorithm from it.

Update, 9 August 2011

I'd now suggest using my own Rangy library, which is similar in idea to IERange but much more fully realized and supported.

I used a slightly simpler solution using the offset values of a textRange:

function getIECharOffset() {
  var offset = 0;

  // get the users selection - this handles empty selections
  var userSelection = document.selection.createRange();

  // get a selection from the contents of the parent element
  var parentSelection = userSelection.parentElement().createTextRange();

  // loop - moving the parent selection on a character at a time until the offsets match
  while (!offsetEqual(parentSelection, userSelection)) {
    parentSelection.move('character');
    offset++;
  }

  // return the number of char you have moved through
  return offset;
}

function offsetEqual(arg1, arg2) {
  if (arg1.offsetLeft == arg2.offsetLeft && arg1.offsetTop == arg2.offsetTop) {
    return true;
  }
  return false;
}

You can iterate through the body element's TextRange.text property using String.substring() to compare against the TextRange for which you want the character offset.

function charOffset(textRange, parentTextRange)
 { var parentTxt = parentTextRange.text;
   var txt       = textRange.text;
   var parentLen = parentTxt.length;

   for(int i=0; i < parentLen ; ++i) 
    { if (parentTxt.substring(i, txt.length+i) == txt) 
       { var originalPosition = textRange.getBookmark();

         //moves back one and searches backwards for same text
         textRange.moveStart("character",-1);
         var foundOther = textRange.findText(textRange.text,-parentLen,1);

         //if no others were found return offset
         if (!foundOther) return i;

         //returns to original position to try next offset
         else textRange.moveToBookmark(originalPosition);
       }
    }

   return -1;
 }

[Reference for findText()]

发布评论

评论列表(0)

  1. 暂无评论