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

时间:2011-11-06 19:52:17

标签: javascript contenteditable assistant

我在html文档的可编辑区域中创建了一个内容助手的运行示例。因此,如果用户点击键盘上的ctrl和space,则会出现上下文菜单。目前(见下文演示)上下文菜单位于右侧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>

1 个答案:

答案 0 :(得分:0)

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

首先,您没有将约束矩形宽度计入建议对象的位置,因此无论文本有多长,您的建议框都会保留在左侧。

然而,这种方法最终会失败,因为如果文本有多条线(第二条线比第一条线短),边界矩形的宽度将等于第一条线的长度(或多或少) )。因此,建议对象将被错误定位。

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

事实证明它几乎可以工作。几乎,因为事实证明,不同的浏览器使用dealing with contentEditable line endings的不同方法。例如,Firefox会在行尾插入<br _moz_dirty=""/>,而Chrome则不会。因此,当我尝试在文本之后附加我的 beacon 元素后,<br/>再次导致错误的位置。

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

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

注意1:我已将if <p></p>元素添加到iframe的文档中,因为用户输入的Chrome文本未插入其中,导致定位建议对象的另一个问题

注意2:至于现在,我的解决方案仅适用于在文本末尾定位建议对象,在光标位置,因为它涉及拆分textNodes,插入信标,检查其位置并再次合并textNodes。根据用户的使用情况,可能导致性能不佳和/或可能需要更改如何处理定位建议对象的整个方法。