如何在替换 contenteditable div 的 html 后将插入符号放在原来的位置?
How to place the caret where it previously was after replacing the html of a contenteditable div?
我有一个 contenteditable div,当用户点击 space 或输入时,我用可点击的 link 替换主题标签。用户记下:
I love but there is no fish at home|
然后他意识到自己犯了一个错误,然后决定回去写
I love #sushi | but there is no fish at home
#sushi
被替换为:
<a href="https://google.com/sushi>#sushi</a>
注意 |显示当用户按下 spacebar 时我希望插入符号所在的位置。我当前的 "placeCaretAtEnd" 函数将插入符号放在 div 的末尾,而不是我刚刚用 sushi 替换的 link 后面。有没有办法改变我当前的功能,将插入符放在 link 后面,我刚刚在上面显示的位置替换了文本,以便用户可以继续不小心输入?所以在原始 html:
I love < a> #sushi< /a> | but there is no fish at home
/**
* Trigger when someone releases a key on the field where you can post remarks, posts or reactions
*/
$(document).on("keyup", ".post-input-field", function (event) {
// if the user has pressed the spacebar (32) or the enter key (13)
if (event.keyCode === 32 || event.keyCode === 13) {
let html = $(this).html();
html = html.replace(/(^|\s)(#\w+)/g, " <a href=#></a>").replace("<br>", "");
$(this).html(html);
placeCaretAtEnd($(this)[0]);
}
});
/**
* Place the caret at the end of the textfield
* @param {object} el - the DOM element where the caret should be placed
*/
function placeCaretAtEnd(el) {
el.focus();
if (typeof window.getSelection != "undefined"
&& typeof document.createRange != "undefined") {
var range = document.createRange();
range.selectNodeContents(el);
range.collapse(false);
var sel = window.getSelection();
sel.removeAllRanges();
sel.addRange(range);
} else if (typeof document.body.createTextRange != "undefined"){
var textRange = document.body.createTextRange();
textRange.moveToElementText(el);
textRange.collapse(false);
textRange.select();
}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div contenteditable="true" class="post-input-field">
I love (replace this with #sushi and type space) but there is no fish at home
</div>
rangy.js 有一个 text range module 可以让您将选择保存为所选字符的索引,然后恢复它。由于您的修改不会改变 innerText
,这看起来非常适合:
var sel = rangy.getSelection();
var savedSel = sel.saveCharacterRanges(this);
$(this).html(html);
sel.restoreCharacterRanges(this, savedSel);
手动执行此操作需要仔细遍历 contenteditable
中的 DOM 并仔细计算索引;这不是几行代码就能完成的。
您的 placeCaretAtEnd
不可能将插入符号放在您插入的 link 之后,因为它 "know" 不是哪个(可能是多个)link 是的。您必须事先保存此信息。
/**
* Trigger when someone releases a key on the field where you can post remarks, posts or reactions
*/
$(document).on("keyup", ".post-input-field", function (event) {
// if the user has pressed the spacebar (32) or the enter key (13)
if (event.keyCode === 32 || event.keyCode === 13) {
let html = $(this).html();
html = html.replace(/(^|\s)(#\w+)/g, " <a href=#></a>").replace("<br>", "");
var sel = rangy.getSelection();
var savedSel = sel.saveCharacterRanges(this);
$(this).html(html);
sel.restoreCharacterRanges(this, savedSel);
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/rangy/1.3.0/rangy-core.js"></script>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/rangy/1.3.0/rangy-textrange.js"></script>
<div contenteditable="true" class="post-input-field">
I love (replace this with #sushi and type space) but there is no fish at home
</div>
我有一个 contenteditable div,当用户点击 space 或输入时,我用可点击的 link 替换主题标签。用户记下:
I love but there is no fish at home|
然后他意识到自己犯了一个错误,然后决定回去写
I love #sushi | but there is no fish at home
#sushi
被替换为:
<a href="https://google.com/sushi>#sushi</a>
注意 |显示当用户按下 spacebar 时我希望插入符号所在的位置。我当前的 "placeCaretAtEnd" 函数将插入符号放在 div 的末尾,而不是我刚刚用 sushi 替换的 link 后面。有没有办法改变我当前的功能,将插入符放在 link 后面,我刚刚在上面显示的位置替换了文本,以便用户可以继续不小心输入?所以在原始 html:
I love < a> #sushi< /a> | but there is no fish at home
/**
* Trigger when someone releases a key on the field where you can post remarks, posts or reactions
*/
$(document).on("keyup", ".post-input-field", function (event) {
// if the user has pressed the spacebar (32) or the enter key (13)
if (event.keyCode === 32 || event.keyCode === 13) {
let html = $(this).html();
html = html.replace(/(^|\s)(#\w+)/g, " <a href=#></a>").replace("<br>", "");
$(this).html(html);
placeCaretAtEnd($(this)[0]);
}
});
/**
* Place the caret at the end of the textfield
* @param {object} el - the DOM element where the caret should be placed
*/
function placeCaretAtEnd(el) {
el.focus();
if (typeof window.getSelection != "undefined"
&& typeof document.createRange != "undefined") {
var range = document.createRange();
range.selectNodeContents(el);
range.collapse(false);
var sel = window.getSelection();
sel.removeAllRanges();
sel.addRange(range);
} else if (typeof document.body.createTextRange != "undefined"){
var textRange = document.body.createTextRange();
textRange.moveToElementText(el);
textRange.collapse(false);
textRange.select();
}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div contenteditable="true" class="post-input-field">
I love (replace this with #sushi and type space) but there is no fish at home
</div>
rangy.js 有一个 text range module 可以让您将选择保存为所选字符的索引,然后恢复它。由于您的修改不会改变 innerText
,这看起来非常适合:
var sel = rangy.getSelection();
var savedSel = sel.saveCharacterRanges(this);
$(this).html(html);
sel.restoreCharacterRanges(this, savedSel);
手动执行此操作需要仔细遍历 contenteditable
中的 DOM 并仔细计算索引;这不是几行代码就能完成的。
您的 placeCaretAtEnd
不可能将插入符号放在您插入的 link 之后,因为它 "know" 不是哪个(可能是多个)link 是的。您必须事先保存此信息。
/**
* Trigger when someone releases a key on the field where you can post remarks, posts or reactions
*/
$(document).on("keyup", ".post-input-field", function (event) {
// if the user has pressed the spacebar (32) or the enter key (13)
if (event.keyCode === 32 || event.keyCode === 13) {
let html = $(this).html();
html = html.replace(/(^|\s)(#\w+)/g, " <a href=#></a>").replace("<br>", "");
var sel = rangy.getSelection();
var savedSel = sel.saveCharacterRanges(this);
$(this).html(html);
sel.restoreCharacterRanges(this, savedSel);
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/rangy/1.3.0/rangy-core.js"></script>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/rangy/1.3.0/rangy-textrange.js"></script>
<div contenteditable="true" class="post-input-field">
I love (replace this with #sushi and type space) but there is no fish at home
</div>