Rangy + ContentEditable + Set Caret and Replace Selection

I have the following code snippet for setting a caret on a given index index

 var el = $("#subjectMessage"), index = 9 ; var range = rangy.createRange(); range.setStart(el[0].childNodes[0], index); range.collapse(true); var sel = rangy.getSelection(); sel.setSingleRange(range); 

Problems arise when I add input elements to the contentEditable div , I cannot sequentially set the caret to the desired position anymore.

I want to treat these inputs as one position in a div (as if they were just one character).

In addition, I will also need similar code to replace the selection in this contentEditable div with some own text, and I'm not very familiar (at all) with rangy to figure out how to make this work ...

All help is desperately appreciated!

Here you can play with the violin:

http://jsfiddle.net/ee93P/

+4
source share
1 answer

The Rangy Selection and Range APIs are supersets of the standard DOM Selection and Range APIs, so the documentation is from places like MDN ( Range , Selection ).

The problem you are facing is that the range bounds are expressed as an offset inside the containing DOM node. For example, in the HTML below, where the carriage is indicated as a channel symbol:

 <p>Foo<br>b|ar</p> 

... the boundaries of the beginning and end of the carriage range are identical and are set to offset 1 in the node text string.

If you want to set the position as an offset in the text content of the <p> element, you need to do a DOM traversal. I wrote an implementation of this based on another answer . This is a naive implementation: it does not take into account any text that may be invisible (for example, using CSS or, for example, inside or an element) and may have browser deviations (IE compared to the others) with line breaks and accepts without regard to collapsed spaces ( for example, two or more consecutive run characters that match the same visible space on the page). It is a difficult thing to get right, so I would not recommend it at all. I plan to write a text module for Rangy that will handle all this, but I haven't started it yet.

http://jsfiddle.net/ee93P/2/

code:

 function setCaretCharIndex(containerEl, index) { var charIndex = 0, stop = {}; function traverseNodes(node) { if (node.nodeType == 3) { var nextCharIndex = charIndex + node.length; if (index >= charIndex && index <= nextCharIndex) { rangy.getSelection().collapse(node, index - charIndex); throw stop; } charIndex = nextCharIndex; } // Count an empty element as a single character. The list below may not be exhaustive. else if (node.nodeType == 1 && /^(input|br|img|col|area|link|meta|link|param|base)$/i.test(node.nodeName)) { charIndex += 1; } else { var child = node.firstChild; while (child) { traverseNodes(child); child = child.nextSibling; } } } try { traverseNodes(containerEl); } catch (ex) { if (ex != stop) { throw ex; } } } 
+7
source

Source: https://habr.com/ru/post/1386100/


All Articles