使用Javascript和可编辑文档创建内容助手(ctrl+space)

Creating a content assistant (ctrl+space) using Javascript and editable document

本文关键字:ctrl+space 创建 Javascript 编辑 文档 使用      更新时间:2023-09-26

我在html文档的可编辑区域创建了一个内容助手的运行示例。因此,如果用户按下键盘上的ctrl和空格键,就会出现一个上下文菜单。当前(参见下面的演示),上下文菜单位于y的右侧位置(文本的下方)。但是它并不是沿着x轴移动的(如果文本变长,那么这个方框将被放置在行首)。

你能帮我解决这个问题吗?

问候,mythbu

示例代码:

<!doctype html>
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<title>Test</title>
<script type="text/javascript">
var iframe = null, iwindow = null, iDocument = null;
function setUpInput() {
        iframe = document.createElement( 'iframe' );
        iframe.setAttribute( 'id', 'iframe-test' );
        iframe.setAttribute( 'frameborder', 0 );
        iframe.setAttribute( 'style', 'width:100%; height:100%;border: solid 1px red;' );
        document.getElementById( "input" ).appendChild( iframe );
        iwindow   = iframe.contentWindow;
        idocument = iwindow.document;
        idocument.open();
        idocument.write("<p></p>");
        idocument.close();
        idocument.body.setAttribute( 'spellcheck', false );
        idocument.body.setAttribute( 'style', 'font-family: Consolas,serif;font-size: 0.8em;' );
        idocument.body.contentEditable = true;
        iwindow.onkeydown = function(e) {
            if (e.ctrlKey && e.keyCode == 32) {
                createSuggestObject();
                return false;
            }
            if (e.ctrlKey) return false;
        };
        iwindow.onkeypress = function(e) {if (e.ctrlKey) return false;};
}
function createSuggestObject() {
suggest = new Object();
suggest.box = document.createElement( 'div' );
suggest.box.style.position = 'absolute';
suggest.box.style.width = '120px';
suggest.box.style.overflow = 'auto';
suggest.box.style.border = '1px solid #BEC7E4';
suggest.box.style.display = 'block';
suggest.box.style.marginTop = '16px';
suggest.box.innerHTML = "Example 1";
document.body.appendChild( suggest.box )
var position = iframe.getBoundingClientRect();
var selObj = iwindow.getSelection();
var selRange = selObj.getRangeAt(0);
var p2 = selObj.anchorNode.parentNode.getBoundingClientRect();  
suggest.box.style.top = Math.round( window.scrollY + position.top + p2.top) + 'px';
suggest.box.style.left = Math.round( window.scrollX + position.left + p2.left) + 'px';
}
window.onload = function() {
    setUpInput();
};
</script>
</head>
<body>
<div id="input"></div>
</body>
</html>

您的解决方案的主要问题是,您正在使用p元素的边界矩形(您假设包含用户输入的文本)作为放置建议对象的位置的参考。

首先,你没有考虑到建议对象位置的边框宽度,所以无论文本有多长,你的建议框都留在左边。

然而,这种方法最终会失败,因为如果文本有多行(其中第二行将比第一行短),边界矩形的宽度将等于第一行的长度(或多或少)。因此,建议对象的位置将不正确。

我关于如何修复代码的第一个想法是将一些内联元素附加到文本(beacon,如果你愿意的话),测量它的位置,将其从DOM中删除并使用计算位置来正确设置建议对象。

结果几乎成功了。差不多,因为事实证明,不同的浏览器使用不同的方法来处理可内容的行结尾。例如,Firefox会在行尾插入<br _moz_dirty=""/>,而Chrome则不会。因此,当我试图将beacon元素附加在文本之后时,它被附加在<br/>之后,再次导致不正确的位置。

解决方案是改变获取我们正在处理的文本节点的方式,并在其nextSibling之前插入beacon

下面是工作示例http://jsfiddle.net/MmKXS/10/

注1:我已经删除了添加的空<p></p>元素的iframe的文档,因为在Chrome文本输入的用户没有插入到它,导致另一个问题与定位建议对象。

注2:目前我的解决方案只适用于在文本末尾定位建议对象,而不是光标位置的,因为它将涉及分割textNodes,插入信标,检查其位置并再次合并textNodes。根据用例,你的代码可能会导致较差的性能和/或可能需要改变如何处理定位您的建议对象的整个方法。