gpt4 book ai didi

html - ContentEditable DIV 中不可编辑跨度的选择和删除问题

转载 作者:行者123 更新时间:2023-12-04 18:05:00 27 4
gpt4 key购买 nike

我有一个 ContentEditable 设置为 TRUE 的 DIV。在它里面有几个跨度,ContentEditable 设置为 FALSE。

我捕获 BackSpace 键,以便如果光标下的元素是 <span>我可以删除它。

问题是它只能与奇数跨度交替工作。

因此,例如,对于下面的 html 代码,将光标放在 DIV 中文本的末尾,然后一直按退格键直到 div 的开头。观察它会选择/删除第一个跨度,然后离开第二个,然后选择/删除第三个跨度,然后离开第四个,依此类推。

此行为仅适用于 Internet Explorer。它在 Firefox 上完全按预期工作。

我应该如何使行为在 Internet Explorer 中保持一致?

以下 html 代码可用于重现该行为:

var EditableDiv = document.getElementById('EditableDiv');

EditableDiv.onkeydown = function(event) {
var ignoreKey;
var key = event.keyCode || event.charCode;
if (!window.getSelection) return;
var selection = window.getSelection();
var focusNode = selection.focusNode,
anchorNode = selection.anchorNode;

if (key == 8) { //backspace
if (!selection.isCollapsed) {
if (focusNode.nodeName == 'SPAN' || anchorNode.nodeName == 'SPAN') {
anchorNode.parentNode.removeChild(anchorNode);
ignoreKey = true;
}
} else if (anchorNode.previousSibling && anchorNode.previousSibling.nodeName == 'SPAN' && selection.anchorOffset <= 1) {
SelectText(event, anchorNode.previousSibling);
ignoreKey = true;
}
}
if (ignoreKey) {
var evt = event || window.event;
if (evt.stopPropagation) evt.stopPropagation();
evt.preventDefault();
return false;
}
}

function SelectText(event, element) {
var range, selection;
EditableDiv.focus();
if (document.body.createTextRange && element.nodeName == 'SPAN') {
range = document.body.createTextRange();
range.moveToElementText(element);
range.select();
} else if (window.getSelection) {
selection = window.getSelection();
range = document.createRange();
range.selectNodeContents(element);
selection.removeAllRanges();
selection.addRange(range);
}
var evt = (event) ? event : window.event;
if (evt.stopPropagation) evt.stopPropagation();
if (evt.cancelBubble != null) evt.cancelBubble = true;
return false;
}
#EditableDiv {
height: 75px;
width: 500px;
font-family: Consolas;
font-size: 10pt;
font-weight: normal;
letter-spacing: 1px;
background-color: white;
overflow-y: scroll;
overflow-x: hidden;
border: 1px solid black;
padding: 5px;
}
#EditableDiv span {
color: brown;
font-family: Verdana;
font-size: 8.5pt;
min-width: 10px;
_width: 10px;
}
#EditableDiv p,
#EditableDiv br {
display: inline;
}
<div id="EditableDiv" contenteditable="true">
&nbsp;(<span contenteditable='false' onclick='SelectText(event, this);' unselectable='on'>Field1</span> < 500) <span contenteditable='false' onclick='SelectText(event, this);' unselectable='on'>OR</span> (<span contenteditable='false' onclick='SelectText(event, this);' unselectable='on'>Field2</span> > 100 <span contenteditable='false' onclick='SelectText(event, this);' unselectable='on'>AND</span> (<span contenteditable='false' onclick='SelectText(event, this);'
unselectable='on'>Field3</span> <=200) )
</div>


编辑

仅供引用。我在 MSDN Forum 中问过这个问题以及。

最佳答案

对此的挑战是让 IE11 从右侧直接对着 退格。然后下一个退格将选择并突出显示它。这似乎是一个如此简单的目标,但 IE11 就是不配合。应该有一个快速简单的补丁,对吧?错误就这样开始了。我想出的方法是将树向后移动到第一个前一个非空节点,清除它们之间的空节点以安抚 IE,然后评估一些条件。如果插入符号应该在 的右侧结束,那么通过在 的末尾创建一个新的范围 obj 来手动完成(因为 IE 不会)。 online demo在两个跨度相互拖动的情况下,我为 IE 添加了一个额外的 kludge。例如,Field2Field3。当您从右侧退格到 Field3,然后再次退格删除它时,IE 会将插入符号向左跳过 Field2。直接跳过 Field2。咕噜噜解决方法是拦截它并在这对跨度之间插入一个空格。我不相信你会对此感到满意。但是,您知道,这是一种解决方法。无论如何,这又出现了另一个错误,IE 将插入的空间更改为两个空的文本节点。更多因此,解决方法的解决方法。请参阅非 isCollapsed 代码。

代码片段

var EditableDiv = document.getElementById('EditableDiv');

EditableDiv.onkeydown = function(event) {
var ignoreKey;
var key = event.keyCode || event.charCode;
if (!window.getSelection) return;
var selection = window.getSelection();
var focusNode = selection.focusNode,
anchorNode = selection.anchorNode;

var anchorOffset = selection.anchorOffset;

if (!anchorNode) return

if (anchorNode.nodeName.toLowerCase() != '#text') {
if (anchorOffset < anchorNode.childNodes.length)
anchorNode = anchorNode.childNodes[anchorOffset]
else {
while (!anchorNode.nextSibling) anchorNode = anchorNode.parentNode // this might step out of EditableDiv to "justincase" comment node
anchorNode = anchorNode.nextSibling
}
anchorOffset = 0
}

function backseek() {

while ((anchorOffset == 0) && (anchorNode != EditableDiv)) {

if (anchorNode.previousSibling) {
if (anchorNode.previousSibling.nodeName.toLowerCase() == '#text') {
if (anchorNode.previousSibling.nodeValue.length == 0)
anchorNode.parentNode.removeChild(anchorNode.previousSibling)
else {
anchorNode = anchorNode.previousSibling
anchorOffset = anchorNode.nodeValue.length
}
} else if ((anchorNode.previousSibling.offsetWidth == 0) && (anchorNode.previousSibling.offsetHeight == 0))
anchorNode.parentNode.removeChild(anchorNode.previousSibling)

else {
anchorNode = anchorNode.previousSibling

while ((anchorNode.lastChild) && (anchorNode.nodeName.toUpperCase() != 'SPAN')) {

if ((anchorNode.lastChild.offsetWidth == 0) && (anchorNode.lastChild.offsetHeight == 0))
anchorNode.removeChild(anchorNode.lastChild)

else if (anchorNode.lastChild.nodeName.toLowerCase() != '#text')
anchorNode = anchorNode.lastChild

else if (anchorNode.lastChild.nodeValue.length == 0)
anchorNode.removeChild(anchorNode.lastChild)

else {
anchorNode = anchorNode.lastChild
anchorOffset = anchorNode.nodeValue.length
//break //don't need to break, textnode has no children
}
}
break
}
} else
while (((anchorNode = anchorNode.parentNode) != EditableDiv) && !anchorNode.previousSibling) {}
}
}

if (key == 8) { //backspace
if (!selection.isCollapsed) {

try {
document.createElement("select").size = -1
} catch (e) { //kludge for IE when 2+ SPANs are back-to-back adjacent

if (anchorNode.nodeName.toUpperCase() == 'SPAN') {
backseek()
if (anchorNode.nodeName.toUpperCase() == 'SPAN') {
var k = document.createTextNode(" ") // doesn't work here between two spans. IE makes TWO EMPTY textnodes instead !
anchorNode.parentNode.insertBefore(k, anchorNode) // this works
anchorNode.parentNode.insertBefore(anchorNode, k) // simulate "insertAfter"
}
}
}


} else {
backseek()

if (anchorNode == EditableDiv)
ignoreKey = true

else if (anchorNode.nodeName.toUpperCase() == 'SPAN') {
SelectText(event, anchorNode)
ignoreKey = true
} else if ((anchorNode.nodeName.toLowerCase() == '#text') && (anchorOffset <= 1)) {

var prev, anchorNodeSave = anchorNode,
anchorOffsetSave = anchorOffset
anchorOffset = 0
backseek()
if (anchorNode.nodeName.toUpperCase() == 'SPAN') prev = anchorNode
anchorNode = anchorNodeSave
anchorOffset = anchorOffsetSave

if (prev) {
if (anchorOffset == 0)
SelectEvent(prev)

else {
var r = document.createRange()
selection.removeAllRanges()

if (anchorNode.nodeValue.length > 1) {
r.setStart(anchorNode, 0)
selection.addRange(r)
anchorNode.deleteData(0, 1)
}
else {
for (var i = 0, p = prev.parentNode; true; i++)
if (p.childNodes[i] == prev) break
r.setStart(p, ++i)
selection.addRange(r)
anchorNode.parentNode.removeChild(anchorNode)
}
}
ignoreKey = true
}
}
}
}
if (ignoreKey) {
var evt = event || window.event;
if (evt.stopPropagation) evt.stopPropagation();
evt.preventDefault();
return false;
}
}

function SelectText(event, element) {
var range, selection;
EditableDiv.focus();
if (window.getSelection) {
selection = window.getSelection();
range = document.createRange();
range.selectNode(element)
selection.removeAllRanges();
selection.addRange(range);
} else {
range = document.body.createTextRange();
range.moveToElementText(element);
range.select();
}
var evt = (event) ? event : window.event;
if (evt.stopPropagation) evt.stopPropagation();
if (evt.cancelBubble != null) evt.cancelBubble = true;
return false;
}
#EditableDiv {
height: 75px;
width: 500px;
font-family: Consolas;
font-size: 10pt;
font-weight: normal;
letter-spacing: 1px;
background-color: white;
overflow-y: scroll;
overflow-x: hidden;
border: 1px solid black;
padding: 5px;
}
#EditableDiv span {
color: brown;
font-family: Verdana;
font-size: 8.5pt;
min-width: 10px;
/*_width: 10px;*/
/* what is this? */
}
#EditableDiv p,
#EditableDiv br {
display: inline;
}
<div id="EditableDiv" contenteditable="true">
&nbsp;(<span contenteditable='false' onclick='SelectText(event, this);' unselectable='on'>Field1</span> < 500) <span contenteditable='false' onclick='SelectText(event, this);' unselectable='on'>OR</span> (<span contenteditable='false' onclick='SelectText(event, this);' unselectable='on'>Field2</span> > 100 <span contenteditable='false' onclick='SelectText(event, this);' unselectable='on'>AND</span> (<span contenteditable='false' onclick='SelectText(event, this);' unselectable='on'>Field3</span> <= 200) )
</div>

关于html - ContentEditable DIV 中不可编辑跨度的选择和删除问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31391571/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com