IE TextRange select method not working properly

前端 未结 4 825
面向向阳花
面向向阳花 2020-12-28 11:50

I\'m having an unusual problem with an IE document with contentEditable set to true. Calling select() on a range that is positioned at the end of a text node that immediate

相关标签:
4条回答
  • 2020-12-28 12:24

    I recently worked at a site which used Microsoft CMS with the "MSIB+ pack" of controls which included a WYSIWYG editor which ran in Internet Explorer.

    I seem to remember some comments in the editor client-side Javascript which were specifically related to this bug in IE and the Range.Select() method.

    Unfortunately, I'm not working there anymore so I can't access the Javascript files, but perhaps you may be able to get them from elsewhere?

    Good luck

    0 讨论(0)
  • 2020-12-28 12:27

    I've figured out a few methods for dealing with IE ranges like this.

    If all you want to do is save where the cursor is, and then restore it, you can use the pasteHTML method to insert an empty span at the current position of the cursor, and then use the moveToElementText method to put it back at that position again:

    // Save position of cursor
    range.pasteHTML('<span id="caret"></span>')
    
    ...
    
    // Create new cursor and put it in the old position
    var caretSpan = iframe.contentWindow.document.getElementById("caret");
    var selection = iframe.contentWindow.document.selection;
    newRange = selection.createRange();
    newRange.moveToElementText(caretSpan);
    

    Alternatively, you can count how many characters precede the current cursor position and save that number:

    var selection = iframe.contentWindow.document.selection;
    var range = selection.createRange().duplicate();
    range.moveStart('sentence', -1000000);
    var cursorPosition = range.text.length;
    

    To restore the cursor, you set it to the beginning and then move it that number of characters:

    var newRange = selection.createRange();
    newRange.move('sentence', -1000000);
    newRange.move('character', cursorPosition);
    

    Hope this helps.

    0 讨论(0)
  • 2020-12-28 12:28

    I've had a bit of a dig & unfortunately can't see a workaround... Although one thing I noticed while debugging the javascript, it seems like the problem is actually with the range object itself rather than with the subsequent range.select(). If you look at the values on the range object that selection.createRange() returns, yes the parent dom object may be correct, but the positioning info is already referring to the start of the next line (i.e. offsetLeft/Top, boundingLeft/Top, etc are already wrong).

    Based on the info here, here and here, I think you're out of luck with IE, since you only have access to Microsoft's TextRange object, which appears to be broken. From my experimentation, you can move the range around and position it exactly where it should be, but once you do so, the range object automatically shifts down to the next line even before you've tried to .select() it. For example, you can see the problem by putting this code in between your Step 1 & Step 2:

    if (range.boundingWidth == 0)
    {
        //looks like its already at the start of the next line down...
        alert('default position: ' + range.offsetLeft + ', ' + range.offsetTop);
        //lets move the start of the range one character back
        //(i.e. select the last char on the line)
        range.moveStart("character", -1);
        //now the range looks good (except that its width will be one char);
        alert('one char back: ' + range.offsetLeft + ', ' + range.offsetTop);
        //calculate the true end of the line...
        var left = range.offsetLeft + range.boundingWidth;
        var top = range.offsetTop;
        //now we can collapse back down to 0 width range
        range.collapse();
        //the position looks right
        alert('moving to: ' + left + ', ' + top);
        //move there.
        range.moveToPoint(left, top);
        //oops... on the next line again... stupid IE.
        alert('moved to: ' + range.offsetLeft + ', ' + range.offsetTop);
    }
    

    So, unfortunately it doesn't look like there's any way to ensure that the range is in the right spot when you select it again.

    Obviously there's the trivial fix to your code above, by changing Step 2 it to this:

    // Step 2 Restore the selection
    if (range.select) {
        if (range.boundingWidth > 0) {
            range.select();
        }
    } else {
        selection.removeAllRanges();
        selection.addRange(range);
        doc.body.focus();
    }
    

    But presumably, you actually want to do something between Step 1 & Step 2 in your actual which involves moving the selection, hence the need to re-set it. But just in case. :)

    So, the best I can do is go & vote for the bug you created... Hopefully they'll fix it.

    0 讨论(0)
  • 2020-12-28 12:39

    Maybe I misunderstand, but if I click to the right of that first line, my cursor already immediately appears at the start of the second line, so that's not a TextRange issue, right?

    Adding a doctype so the test page is rendered in standards mode instead of quirks mode fixes that for me.

    And I can't reproduce what your myhandler function does, because clicking that button moves the focus away to the button so I can no longer see the cursor and can't get it back either. Finding the cursor position in a contentEditable area seems to be a different problem altogether.

    0 讨论(0)
提交回复
热议问题