JavaScript 'contenteditable' — Getting/Setting Caret Position

后端 未结 6 494
别跟我提以往
别跟我提以往 2021-01-04 04:50

I have read a few posts on positioning the caret, but none seem to answer my particular issue.

  1. I have 2 divs (div1 and div2)<
相关标签:
6条回答
  • 2021-01-04 05:03

    When you click on an element, a Selection object with zero length is created (get it from element.getSelection() , where element is the div in question). The focusOffset of that object will let you know that you clicked on, for example, the 74th character in that div (this is the thing that Adrien said was impossible in a different answer).

    0 讨论(0)
  • 2021-01-04 05:05

    you can, basically you need set temporary content editable on your first div to catch caret pos

    $('div1').hover(function()
    { $(this).attr('contenteditable','true');
    },function()
    { $(this).removeAttr('contenteditable');
    }).mouseup(function()
    {   var t = $(this);
        // get caret position and remove content editable
        var caret = t.getCaret();
        t.removeAttr('contenteditable');
        // do your div switch stuff
        ...
        // and apply saved caret position
        $('div2').setCaret(caret);
    });
    

    now just need get/set caret method :)

    edit > here is my own, (live demo)

            getSelection:function($e)
            {   if(undefined === window.getSelection) return false;
                var range = window.getSelection().getRangeAt(0);
    
                function getTreeOffset($root,$node)
                {   if($node.parents($root).length === 0) return false; // is node child of root ?
                    var tree = [], treesize = 0;
                    while(1)
                    {   if($node.is($root)) break;
                        var index, $parent = $node.parent();
                        index = $parent.contents().index($node);
                        if(index !== -1) { tree[treesize++] = index; } $node = $parent;
                    };  return tree.reverse();
                }
    
                var start = getTreeOffset($e,$(range.startContainer));
                var end   = getTreeOffset($e,$(range.endContainer));
    
                if(start & end === false) return false;
    
                return {start:start,end:end,startOffset:range.startOffset,endOffset:range.endOffset};
            }, setSelection:function($e,s,win)
            {   $e.focus(); if(s === false) return; var sel = win.getSelection(); sel.removeAllRanges();
    
                function getNode($e,s)
                {   var node = $e;
                    for( var n=0;n<s.length;n++ )
                    {   var index = s[n]; if(index < 0) break;
                        node = node.contents(':eq('+index+')');
                    }   return node.get(0);
                }
    
                var start = getNode($e,s.start), end = getNode($e,s.end), range = win.document.createRange();
                range.setStart(start,s.startOffset); range.setEnd(end,s.endOffset); sel.addRange(range);
            }
    
    0 讨论(0)
  • 2021-01-04 05:08

    Read the caret position in text and then set caret position in your edit window.

    0 讨论(0)
  • 2021-01-04 05:12

    You could insert a tiny span-element at the caret, get its position, and remove it. For a cross-browser range and selection library, see rangy.

    0 讨论(0)
  • 2021-01-04 05:15

    It sounds like you are trying to do an inline edit... have you looked at the jeditable plugin?

    0 讨论(0)
  • 2021-01-04 05:21

    Short answer : You can't

    Long answer : The problem you'll face is that you'll be able to get (x,y) coordinates for the click event on div1, but any implementation of the caret position while require you knowing the position of the caret in the content (which is the number of characters preceding the caret).

    To convert the (x,y) coordinates to a character position you actually need to know how many characters were before (ie. left on the current line and above, if the text is ltr).

    If you use a fixed width font, you can simplify the problem : mapping an (x,y) coordinate to a (line, column) coordinate on a character grid.

    However, you still face the problem of not knowing how the text is wrapped. For example :

    ------------------
    |Lorem ipsum     |
    |dolor sit amet  |
    |consectetur     |
    |adipiscing elit |
    ------------------
    

    If the user clicks on the d in dolor, you know that the character is the 1st on the 2nd line, but without knowing the wrapping algorithm there is no way you'll know that it is the 13th character in "Lorem ipsum dolor sit…". And there is no guarantee that such a wrapping algorithm is identical across browsers and platform.

    Now, what I'm wondering is why would you use 2 different synced div in the first place ? Wouldn't it be easier to use only one div and set its content to editable when the user clicks (or hovers) ?

    0 讨论(0)
提交回复
热议问题