Pet*_*rov 10 html javascript range contenteditable rangy
我需要在contenteditable div中实现数字的突出显示(将来我添加更复杂的规则).问题是当我使用javascript替换插入新内容时,DOM更改和contenteditable div失去焦点.我需要的是保持对当前位置的重点关注div,因此用户只需键入没有任何问题,我的功能简单突出显示数字.谷歌搜索我认为Rangy库是最好的解决方案.我有以下代码:
function formatText() {
var savedSel = rangy.saveSelection();
el = document.getElementById('pad');
el.innerHTML = el.innerHTML.replace(/(<([^>]+)>)/ig,"");
el.innerHTML = el.innerHTML.replace(/([0-9])/ig,"<font color='red'>$1</font>");
rangy.restoreSelection(savedSel);
}
<div contenteditable="true" id="pad" onkeyup="formatText();"></div>
Run Code Online (Sandbox Code Playgroud)
问题是在函数结束工作焦点回到div之后,但是插入总是指向div开始,我可以在任何地方输入,除了div开始.还有console.log类型以下Rangy warning: Module SaveRestore: Marker element has been removed. Cannot restore selection.
请帮我实现这个功能.我打开另一个解决方案,不仅是rangy库.谢谢!
http://jsfiddle.net/2rTA5/这是jsfiddle,但是它不能正常工作(当我在我的div中输入数字时没有任何反应),不管我(第一次通过jsfiddle发布代码)或者资源不支持contenteditable.UPD*我在stackoverflow上读到类似的问题,但解决方案不适合我的情况:(
Tim*_*own 24
问题是Rangy的保存/恢复选择模块的工作原理是将不可见的标记元素插入到选择边界所在的DOM中,然后您的代码将删除所有HTML标记,包括Rangy的标记元素(如错误消息所示).您有两种选择:
innerHTML
.这将更可靠,但更具参与性.UPDATE
我为Rangy敲了一个基于字符索引的选择保存/恢复(上面的选项2).这有点粗糙,但它确实适用于这种情况.它通过遍历文本节点来工作.我可以用某种形式将它添加到Rangy中.(2012年6月5日更新: 我现在以更可靠的方式为Rangy实现了这一点.)
jsFiddle:http://jsfiddle.net/2rTA5/2/
码:
function saveSelection(containerEl) {
var charIndex = 0, start = 0, end = 0, foundStart = false, stop = {};
var sel = rangy.getSelection(), range;
function traverseTextNodes(node, range) {
if (node.nodeType == 3) {
if (!foundStart && node == range.startContainer) {
start = charIndex + range.startOffset;
foundStart = true;
}
if (foundStart && node == range.endContainer) {
end = charIndex + range.endOffset;
throw stop;
}
charIndex += node.length;
} else {
for (var i = 0, len = node.childNodes.length; i < len; ++i) {
traverseTextNodes(node.childNodes[i], range);
}
}
}
if (sel.rangeCount) {
try {
traverseTextNodes(containerEl, sel.getRangeAt(0));
} catch (ex) {
if (ex != stop) {
throw ex;
}
}
}
return {
start: start,
end: end
};
}
function restoreSelection(containerEl, savedSel) {
var charIndex = 0, range = rangy.createRange(), foundStart = false, stop = {};
range.collapseToPoint(containerEl, 0);
function traverseTextNodes(node) {
if (node.nodeType == 3) {
var nextCharIndex = charIndex + node.length;
if (!foundStart && savedSel.start >= charIndex && savedSel.start <= nextCharIndex) {
range.setStart(node, savedSel.start - charIndex);
foundStart = true;
}
if (foundStart && savedSel.end >= charIndex && savedSel.end <= nextCharIndex) {
range.setEnd(node, savedSel.end - charIndex);
throw stop;
}
charIndex = nextCharIndex;
} else {
for (var i = 0, len = node.childNodes.length; i < len; ++i) {
traverseTextNodes(node.childNodes[i]);
}
}
}
try {
traverseTextNodes(containerEl);
} catch (ex) {
if (ex == stop) {
rangy.getSelection().setSingleRange(range);
} else {
throw ex;
}
}
}
function formatText() {
var el = document.getElementById('pad');
var savedSel = saveSelection(el);
el.innerHTML = el.innerHTML.replace(/(<([^>]+)>)/ig,"");
el.innerHTML = el.innerHTML.replace(/([0-9])/ig,"<font color='red'>$1</font>");
// Restore the original selection
restoreSelection(el, savedSel);
}
Run Code Online (Sandbox Code Playgroud)