代码之家  ›  专栏  ›  技术社区  ›  Douglas Mayle

IE TEXTRANGE SELECT方法工作不正常

  •  7
  • Douglas Mayle  · 技术社区  · 16 年前

    我对ContentEditable设置为true的IE文档有一个异常问题。对位于块元素前面的文本节点末尾的区域调用select(),将导致所选内容右移一个字符,并出现在不应出现的位置。我已针对IE8向Microsoft提交了一个错误。如果可以的话,请投票决定这个问题,以便解决。

    https://connect.microsoft.com/IE/feedback/ViewFeedback.aspx?FeedbackID=390995

    我编写了一个测试用例来演示这种效果:

    <html>
      <body>
        <iframe id="editable">
          <html>
            <body>
              <div id="test">
                Click to the right of this line -&gt;
                <p id="par">Block Element</p>
              </div>
            </body>
          </html>
        </iframe>
        <input id="mytrigger" type="button" value="Then Click here to Save and Restore" />
        <script type="text/javascript">
            window.onload = function() {
                var iframe = document.getElementById('editable');
                var doc = iframe.contentDocument || iframe.contentWindow.document;
    
                // An IFRAME without a source points to a blank document.  Here we'll
                // copy the content we stored in between the IFRAME tags into that
                // document.  It's a hack to allow us to use only one HTML file for this
                // test.
                doc.body.innerHTML = iframe.textContent || iframe.innerHTML;
    
                // Marke the IFRAME as an editable document
                if (doc.body.contentEditable) {
                    doc.body.contentEditable = true;
                } else {
                    var mydoc = doc;
                    doc.designMode = 'On';
                }
    
                // A function to demonstrate the bug.
                var myhandler = function() {
                    // Step 1 Get the current selection
                    var selection = doc.selection || iframe.contentWindow.getSelection();
                    var range = selection.createRange ? selection.createRange() : selection.getRangeAt(0);
    
                    // Step 2 Restore the selection
                    if (range.select) {
                        range.select();
                    } else {
                        selection.removeAllRanges();
                        selection.addRange(range);
                        doc.body.focus();
                    }
                }
    
                // Set up the button to perform the test code.
                var button = document.getElementById('mytrigger');
                if (button.addEventListener) {
                    button.addEventListener('click', myhandler, false);
                } else {
                    button.attachEvent('onclick', myhandler);
                }
              }
        </script>
      </body>
    </html>
    

    问题在myhandler函数中暴露。这就是我要做的,在保存和恢复选择之间没有第3步,但是光标移动。除非选择为空(即,我有一个闪烁的光标,但没有文本),否则似乎不会发生这种情况,并且只有当光标位于紧接块节点之前的文本节点的末尾时,才会发生这种情况。

    范围似乎仍然在正确的位置上(如果我在它返回DIV的范围上调用parentelement),但是如果我从当前选择中得到一个新的范围,新的范围在paragraph标记内,这就是它的parentelement。

    如何解决此问题,并在Internet Explorer中始终保存和恢复所选内容?

    4 回复  |  直到 15 年前
        1
  •  12
  •   Dan Eisenberg    15 年前

    我已经想出了一些处理这类IE范围的方法。

    如果您只想保存光标所在位置,然后将其还原,则可以使用pastehtml方法在光标的当前位置插入一个空跨度,然后使用moveToelementText方法再次将其放回该位置:

    // 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);
    

    或者,您可以计算当前光标位置之前的字符数并保存该数字:

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

    要恢复光标,请将其设置为开始,然后移动该字符数:

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

    希望这有帮助。

        2
  •  1
  •   Alconja    15 年前

    我有点挖苦,不幸的是我看不到解决方法…尽管我在调试JavaScript时注意到一件事,但问题似乎在于范围对象本身,而不是后续对象。 range.select() . 如果您查看Range对象上的值, selection.createRange() 返回,是的,父dom对象可能是正确的,但定位信息已经引用了下一行的开头(即offsetleft/top、boundingleft/top等已经错误)。

    根据信息 here , here here ,我认为你在IE上不太走运,因为你只能访问微软的textrange对象,这个对象似乎被破坏了。从我的实验中,你可以移动范围并精确定位到它应该在的位置,但是一旦你这样做了,范围对象会自动向下移动到下一行,甚至在你试图移动之前。 .select() 它。例如,通过将此代码放在步骤1和步骤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);
    }
    

    因此,不幸的是,当您再次选择范围时,它看起来没有任何方法可以确保范围在正确的位置。

    显然,通过将步骤2改为以下步骤,上面的代码有一个小的修正:

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

    但是,假设您实际上想要在实际的步骤1和步骤2之间做一些事情,这涉及到移动选择,因此需要重新设置它。但以防万一。:)

    所以,我能做的最好的就是去投票给你创建的bug…希望他们能解决。

        3
  •  0
  •   Dave R    16 年前

    我最近在一个使用微软CMS的网站上工作,该网站使用了“msib+pack”控件,其中包括在Internet Explorer中运行的wysiwyg编辑器。

    我似乎还记得编辑器客户端javascript中的一些注释,它们与IE和range.select()方法中的这个bug特别相关。

    不幸的是,我不再在那里工作,所以我不能访问javascript文件,但也许你可以从其他地方获得它们?

    祝你好运

        4
  •  0
  •   mercator    15 年前

    也许我误解了,但是如果我点击第一行的右边,我的光标已经立即出现在第二行的开头,所以这不是文本范围问题,对吗?

    添加doctype使测试页以标准模式呈现,而不是以怪癖模式呈现,这为我解决了这个问题。

    我无法重现您的myhandler函数的功能,因为单击该按钮会将焦点移到按钮上,这样我就看不到光标,也无法将其返回。在中查找光标位置 可满足的 地区 seems to be a different problem altogether .