I have a contenteditable div where I need to insert text at the caret position,
This can be easily done in IE by document.selection.createRange().text = "banana"
Is there a similar way of implementing this in Firefox/Chrome?
(I know a solution exists here , but it can't be used in contenteditable div, and looks clumsy)
Thank you!
The following function will insert text at the caret position and delete the existing selection. It works in all the mainstream desktop browsers:
function insertTextAtCaret(text) {
var sel, range;
if (window.getSelection) {
sel = window.getSelection();
if (sel.getRangeAt && sel.rangeCount) {
range = sel.getRangeAt(0);
range.deleteContents();
range.insertNode( document.createTextNode(text) );
}
} else if (document.selection && document.selection.createRange) {
document.selection.createRange().text = text;
}
}
UPDATE
Based on comment, here's some code for saving and restoring the selection. Before displaying your context menu, you should store the return value of saveSelection
in a variable and then pass that variable into restoreSelection
to restore the selection after hiding the context menu and before inserting text.
function saveSelection() {
if (window.getSelection) {
sel = window.getSelection();
if (sel.getRangeAt && sel.rangeCount) {
return sel.getRangeAt(0);
}
} else if (document.selection && document.selection.createRange) {
return document.selection.createRange();
}
return null;
}
function restoreSelection(range) {
if (range) {
if (window.getSelection) {
sel = window.getSelection();
sel.removeAllRanges();
sel.addRange(range);
} else if (document.selection && range.select) {
range.select();
}
}
}
window.getSelection()
.Selection.getRangeAt(0).insertNode()
to add a textnode. If necessary, move the cursor position behind the added text with Selection.modify()
. (Not standardized, but this feature is supported in Firefox, Chrome and Safari)
function insertTextAtCursor(text) { let selection = window.getSelection(); let range = selection.getRangeAt(0); range.deleteContents(); let node = document.createTextNode(text); range.insertNode(node); for(let position = 0; position != text.length; position++) { selection.modify("move", "right", "character"); }; }
I have used next code to insert icons in chat msg
<div class="chat-msg-text" id="chat_message_text" contenteditable="true"></div>
<script>
var lastCaretPos = 0;
var parentNode;
var range;
var selection;
$(function(){
$('#chat_message_text').focus();
$('#chat_message_text').on('keyup mouseup',function (e){
selection = window.getSelection();
range = selection.getRangeAt(0);
parentNode = range.commonAncestorContainer.parentNode;
});
})
function insertTextAtCursor(text) {
if($(parentNode).parents().is('#chat_message_text') || $(parentNode).is('#chat_message_text') )
{
var span = document.createElement('span');
span.innerHTML=text;
range.deleteContents();
range.insertNode(span);
//cursor at the last with this
range.collapse(false);
selection.removeAllRanges();
selection.addRange(range);
}
else
{
msg_text = $("#chat_message_text").html()
$("#chat_message_text").html(text+msg_text).focus()
}
}
</script>
Pasting plain text can be handled with the following code.
const editorEle = document.getElementById('editor');
// Handle the `paste` event
editorEle.addEventListener('paste', function (e) {
// Prevent the default action
e.preventDefault();
// Get the copied text from the clipboard
const text = e.clipboardData
? (e.originalEvent || e).clipboardData.getData('text/plain')
: // For IE
window.clipboardData
? window.clipboardData.getData('Text')
: '';
if (document.queryCommandSupported('insertText')) {
document.execCommand('insertText', false, text);
} else {
// Insert text at the current position of caret
const range = document.getSelection().getRangeAt(0);
range.deleteContents();
const textNode = document.createTextNode(text);
range.insertNode(textNode);
range.selectNodeContents(textNode);
range.collapse(false);
const selection = window.getSelection();
selection.removeAllRanges();
selection.addRange(range);
}
});
If you are working with rich editors (like DraftJs) but have no access to their APIs (eg modifying from an extension), these are the solutions I've found:
beforeinput
event, this is the recommended way, and most editors supporttarget.dispatchEvent(new InputEvent("beforeinput", {
inputType: "insertText",
data: text,
bubbles: true,
cancelable: true
}))
paste
eventconst data = new DataTransfer();
data.setData(
'text/plain',
text
);
target.dispatchEvent(new ClipboardEvent("paste", {
dataType: "text/plain",
data: text,
bubbles: true,
clipboardData: data,
cancelable: true
}));
This last one uses 2 different methods:
data
and dataType
properties. This one works in FirefoxclipboardData
property. Which works in Chrome but not in Firefox? https://github.com/facebook/draft-js/issues/616#issuecomment-426047799 . Though It's supposed to work in Firefox , maybe I don't know how to use it or there's a bug.If you want to replace all existing text, you have to select it first
function selectTargetText(target) {
const selection = window.getSelection();
const range = document.createRange();
range.selectNodeContents(target);
selection.removeAllRanges();
selection.addRange(range);
}
selectTargetText(target)
// wait for selection before dispatching the `beforeinput` event
document.addEventListener("selectionchange",()=>{
target.dispatchEvent(new InputEvent("beforeinput", {
inputType: "insertText",
data: text,
bubbles: true,
cancelable: true
}))
},{once: true})
just an easier method with jquery:
copy the entire content of the div
var oldhtml=$('#elementID').html();
var tobejoined='<span>hii</span>';
//element with new html would be
$('#elementID').html(oldhtml+tobejoined);
simple!
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.