SitePoint Sponsor

User Tag List

Results 1 to 9 of 9

Hybrid View

  1. #1
    SitePoint Guru
    Join Date
    Sep 2008
    Location
    Dubai
    Posts
    971
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)

    set caret position in contenteditable div

    I have a contenteditable div, it has some paragraphs in it.

    Assuming a situation, when I click the button "set caret position", the main div will focus, the caret will start at position number 8 of second paragraph, which means the caret will appear after the word "draw".

    How would you do it?


    Code JavaScript:
    <script src="http://code.jquery.com/jquery-latest.js"></script>
    <script type="text/javascript">
    $(function(){
    //code
    });
    </script>
    <div id="main" contenteditable="true" style="border:solid 1px black">
        <div>Said Hamlet to Ophelia,</div>
        <div>I'll draw a sketch of thee,</div>
        <div>What kind of pencil shall I use?</div>
        <div>2B or not 2B?</div>
    </div>
    <button>Set caret position</button>

  2. #2
    SitePoint Enthusiast nimpkish-media's Avatar
    Join Date
    Jun 2010
    Location
    Victoria BC, Canada
    Posts
    43
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    I am a bit confused. Do you mean, the user clicks the button, and the caret is inserted after the word 'draw'. And that's it?

  3. #3
    I meant that to happen silver trophybronze trophy Raffles's Avatar
    Join Date
    Sep 2005
    Location
    Tanzania
    Posts
    4,662
    Mentioned
    2 Post(s)
    Tagged
    0 Thread(s)
    In firefox (and probably webkit and opera too), where "content" is the contentEditable node:

    Code javascript:
    var char = 3; // character at which to place caret  content.focus();
      var sel = window.getSelection();
      sel.collapse(content.firstChild, char);

  4. #4
    I meant that to happen silver trophybronze trophy Raffles's Avatar
    Join Date
    Sep 2005
    Location
    Tanzania
    Posts
    4,662
    Mentioned
    2 Post(s)
    Tagged
    0 Thread(s)
    Here's a solution that works in IE too:

    Code javascript:
      var char = 3, sel; // character at which to place caret
    content.focus();
    if (document.selection) {
      sel = document.selection.createRange();
      sel.moveStart('character', char);
      sel.select();
    }
    else {
       sel = window.getSelection();
      sel.collapse(content.firstChild, char);
    }
    Took me ages to figure out because I was testing on an anchor - turns out IE doesn't like doing focus() on an anchor that is contentEditable. Other elements (p, div) seem to be OK!

  5. #5
    SitePoint Guru
    Join Date
    Sep 2008
    Location
    Dubai
    Posts
    971
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Great, it works like charm. I've been battling with this for five 4 days now.

    Raffles do you know how to get the node's index where the caret is? I only need solution for compliant browsers.

  6. #6
    I meant that to happen silver trophybronze trophy Raffles's Avatar
    Join Date
    Sep 2005
    Location
    Tanzania
    Posts
    4,662
    Mentioned
    2 Post(s)
    Tagged
    0 Thread(s)
    What do you mean the index? You should know where the caret is, as that's where you're placing it!

  7. #7
    SitePoint Guru
    Join Date
    Sep 2008
    Location
    Dubai
    Posts
    971
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Index, by my definition is, the numbers indicate the position order of elements within a container.

    Code:
    <!DOCTYPE html>
    <html>
    <head>
    <style>
    </style>
    <script src="http://code.jquery.com/jquery-latest.min.js"></script>
    </head>
    <body>
      <div></div>
      <div></div>
      <div id="blinking"></div>
      <div></div>
      <div></div>
      <div></div>
    <script>
    alert($("#blinking").index());
    </script>
    </body>
    </html>
    In this code, the id blinking represents the node where the caret is. the id blinking has index of 2 inside body container.

    What I am trying to archive is, when I open a working document, I want the caret to be exact position when I left off.

    To do so I need to store the words offset and the node which contain the caret, but the node returned by selection.anchorNode is an object, we can't store object in database. Therefore, we need to get the index value of the node. so that we can do something like this

    Code:
    sel.collapse(content.childsNode[4], 23);// put the caret at fifth node, offset 23 characters
    Back to my question, how do we capture index of the node where the caret is ?

  8. #8
    I meant that to happen silver trophybronze trophy Raffles's Avatar
    Join Date
    Sep 2005
    Location
    Tanzania
    Posts
    4,662
    Mentioned
    2 Post(s)
    Tagged
    0 Thread(s)
    You really should have mentioned that you wanted to save the caret position from the outset.

    There is a stack overflow question (which was very easy to find via google) addressing your issue. See the solution by Nico Burns.

  9. #9
    SitePoint Guru
    Join Date
    Sep 2008
    Location
    Dubai
    Posts
    971
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Those codes on Stackoverflow basically get selection, and restore it as long as page is live. They can't store values for later use.

    After five days of struggling, with the help of yours and Tim Down at Stack overflow I've got it to work.

    Code JavaScript:
    var range, selection, star, end, selectedText, startNode, endNode, containerId ="editableDiv";
    function getCaretPos(){
    	range= window.getSelection().getRangeAt(0);
    	start = range.startOffset;
    	end = range.endOffset;
    	startNode = range.startContainer;
    	endNode = range.endContainer;
    	selectedText = range.toString();
    //	alert('start: '+start+'\n\n end: '+ end+'\n\n text: '+selectedText +'\n\n startnode: '+$(startNode.parentNode).index()+'\n\n endnode: '+$(endNode.parentNode).index() );
    }
    function restoreCaretPos(){
    	selection = window.getSelection();
    	if (selection.rangeCount > 0) {
    		selection.removeAllRanges();
    		selection.addRange(range);
    	}
    }
    function setCaretPos(startNodeIndex, endNodeIndex, start, end){
    	range = document.createRange();
    	var editableContainer = document.getElementById(containerId);
    	range.setStart(editableContainer.childNodes[startNodeIndex].firstChild,start);
    	range.setEnd(editableContainer.childNodes[endNodeIndex].firstChild,end);
    	var selection = window.getSelection();
    	selection.addRange(range);
    }

    The tricky part is to get the node index, as you can see in function setCaretPos, there is node index utilizing. And I attained it by using jquery index() function, as seen in alert() function above.

    For this snippet work correctly, The html inside contenteditable needs to be controlled strictly. Hopefully, I can improve it to work with arbitrary html.


Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •