How to find cursor position in a contenteditable DIV? - javascript

I am writing a autocompleter for a content editable DIV (need to render html content in the text box. So preferred to use contenteditable DIV over TEXTAREA). Now I need to find the cursor position when there is a keyup/keydown/click event in the DIV. So that I can insert the html/text at that position. I am clueless how I can find it by some computation or is there a native browser functionality that would help me find the cursor position in a contententeditable DIV.

If all you want to do is insert some content at the cursor, there's no need to find its position explicitly. The following function will insert a DOM node (element or text node) at the cursor position in all the mainstream desktop browsers:
function insertNodeAtCursor(node) {
var range, html;
if (window.getSelection && window.getSelection().getRangeAt) {
range = window.getSelection().getRangeAt(0);
range.insertNode(node);
} else if (document.selection && document.selection.createRange) {
range = document.selection.createRange();
html = (node.nodeType == 3) ? node.data : node.outerHTML;
range.pasteHTML(html);
}
}
If you would rather insert an HTML string:
function insertHtmlAtCursor(html) {
var range, node;
if (window.getSelection && window.getSelection().getRangeAt) {
range = window.getSelection().getRangeAt(0);
node = range.createContextualFragment(html);
range.insertNode(node);
} else if (document.selection && document.selection.createRange) {
document.selection.createRange().pasteHTML(html);
}
}
UPDATE
Following the OP's comments, I suggest using my own Rangy library, which adds a wrapper to IE TextRange object that behaves like a DOM Range. A DOM Range consists of a start and end boundary, each of which is expressed in terms of a node and an offset within that node, and a bunch of methods for manipulating the Range. The MDC article should provide some introduction.

Related

Count cursor position with tags included in range

I am trying to find position of cursor in contentEditable div which has HTML tags inside it.
Example of div would be:
<div id='editor'>
<h2>some</h2> text <span>goes here</span>
</div>
So if cursor is on letter "T" in 'text' word i want to get position that includes:
"<h2>some</h2> t"
not just
"some "
I have found solution that doesn't count tags in position: Get a range's start and end offset's relative to its parent container
This works fine but i need to count tags as well in final range.
Range object gives a range indicating DOM elements currently selected, it gives you information regarding in which element, at which position selection started and in which element, at which position selection ended.
function replaceSelectionWith(value) {
const selection = window.getSelection();
const range = selection.getRangeAt(0);
const {
startContainer,
startOffset,
endContainer,
endOffset
} = range;
if(startContainer === endContainer) {
const container = startContainer;
// nodeType === 3 means text node, can also check same using nodeName === '#text'
if (container.nodeType === 3) {
container.nodeValue = container.nodeValue.slice(0, startOffset) + value + container.nodeValue.slice(endOffset);
}
}
}
// Once you change the DOM, you can just get your HTML value from #editor.innerHTML
This is a simplest usecase, which is your scenario right now. But it is possible that startContainer and endContainer are different nodes or they can be DOM elements instead of being simple text nodes. This example is just to set you in the right direction.
You can refer to following documentation to understand how they actually work.
https://developer.mozilla.org/en-US/docs/Web/API/Selection
https://developer.mozilla.org/en-US/docs/Web/API/Range
EDIT: Working solution for the case asked in question
function insertTextAndGetHTML(value) {
replaceSelectionWith(value);
return document.getElementById('editor').innerHTML;
}

How to set cursor position in contenteditable span

I have a span, it becomes editable after double clicking on it. However, some text is selected due to double click and I remove that selection using this code:
function removeSelectedText(element) {
if (window.getSelection || document.getSelection) {
oSelection = (window.getSelection ? window:document).getSelection();
oSelection.removeAllRanges();
} else {
document.selection.empty();
}
}
After this operation, now-editable non-selected span loses focus. All I want to move the caret to the last clicked place in the span. I try the code below but didn't work ('element' is span itself):
...
var selection = (window.getSelection ? window:document).getSelection();
var position = selection.getRangeAt(0).focusOffset;
element.focus();
var range = document.createRange();
range.setStart(element, position);
range.setEnd(element, position);
range.collapse(true);
selection.removeAllRanges();
selection.addRange(range);
I try whatever I found but couldn't get it working. I can't focus it anymore due to frustration. That would be awesome if you help me...
UPDATE: In range.setStart() and range.setEnd(), element.firstChild should be used instead of element.
A similar problem and its solution is here, I am surprised for finding it in the second day of search considering my offensive search yesterday. Any better solution is welcomed, since even this one cannot bypass text selection at first double click.

Check if any formatting have been given in a Page

While searching text in a document
window.find(t)
Will highlight the text in document. But how can I highlight all the text in a web page. That means how can I highlight all the text in web page as giving complete design mode text as input to the window.find()
The original intention behind this is using the trick provided by Tim Down in this page I want to check whether any formatting have been given in the document.
Please let me know if you need any other input to be more helpful.
Try this
window.find(document.body.innerText)
or
function selectElementContents(el) {
var range;
if (window.getSelection && document.createRange) {
range = document.createRange();
var sel = window.getSelection();
range.selectNodeContents(el);
sel.removeAllRanges();
sel.addRange(range);
} else if (document.body && document.body.createTextRange) {
range = document.body.createTextRange();
range.moveToElementText(el);
range.select();
}
}
selectElementContents(document.body)
If you want all the text in the document's body, you would use document.body.innerText. If you want all the HTML in the document's body, you would use document.body.innerHTML.

get range and coordinate of selected text

How to select the text of the page in FireFox?
For example, there's a paragraph of text, user select the text in those paragraph in a regular way.then, I want to know in which paragraph the text selected by user (in which position-xy coordinates, range position).
You've asked about selection coordinates twice before. I know I've given you a working answer, so why are you asking again?
Here's some code that will return you the innermost element containing the selection in Firefox (assuming a single selection; Firefox allows multiple selections). Hope it's helpful.
function getSelectionContainerElement() {
var sel = window.getSelection(), el = null;
if (sel.rangeCount) {
var range = sel.getRangeAt(0);
el = range.commonAncestorContainer;
if (el.nodeType != 1) {
el = el.parentNode;
}
}
return el;
}
refer the getSelection(), to get an object which contains information about the selected text and its position in the parent Element
Selection - MDC might help you to find answer of all your questions.
You can find the exact answer here
but this module is under construction, You can browse project and find this module.

Editable Div Caret Position

I have an editable div and I am using a button to insert an image into the div. Right now, I am just doing document.getElementById('elementid').innerHTML. += ; in order to get the image added to the end of the div. I would like to enter the image where the caret is. How would I go about doing this?
Thanks
To insert an element at the caret is not too hard. The following function inserts a node at the caret (or at the end of the selection, if content is selected) in all major browsers:
function insertNodeAfterSelection(node) {
var sel, range, html;
if (window.getSelection) {
sel = window.getSelection();
if (sel.getRangeAt && sel.rangeCount) {
range = sel.getRangeAt(0);
range.collapse(false);
range.insertNode(node);
}
} else if (document.selection && document.selection.createRange) {
range = document.selection.createRange();
range.collapse(false);
html = (node.nodeType == 3) ? node.data : node.outerHTML;
range.pasteHTML(html);
}
}
I hate to sound negative, but this is so hard it's ridiculous. You have to deal with IE and others, and the implementations are vastly different. But where it gets uber-hard is that if you click a button to insert the image, you lose focus and the caret position, so you need to remember the position with some onblur bookmarking ability (again, IE different). The focus thing is not so much an issue if your editablecontent is in an iframe and maintains its own focus. (Note: not dissing IE here, I actually prefer their implementation to the W3C standard drek.)
You can look at some open source text editors for clues and hints. But you'll find an enormous amount of code to handle these simple tasks.
Does this help: http://jsfiddle.net/8akDr/

Categories