복붙노트

[JQUERY] 의 contentEditable <DIV>에 설정 커서 위치

JQUERY

의 contentEditable
에 설정 커서 위치

해결법


  1. 1.이 표준 기반 브라우저와 호환이지만, 아마 IE에 실패합니다. 나는 시작 지점으로 제공하고 있습니다. IE는 DOM 범위를 지원하지 않습니다.

    이 표준 기반 브라우저와 호환이지만, 아마 IE에 실패합니다. 나는 시작 지점으로 제공하고 있습니다. IE는 DOM 범위를 지원하지 않습니다.

    var editable = document.getElementById('editable'),
        selection, range;
    
    // Populates selection and range variables
    var captureSelection = function(e) {
        // Don't capture selection outside editable region
        var isOrContainsAnchor = false,
            isOrContainsFocus = false,
            sel = window.getSelection(),
            parentAnchor = sel.anchorNode,
            parentFocus = sel.focusNode;
    
        while(parentAnchor && parentAnchor != document.documentElement) {
            if(parentAnchor == editable) {
                isOrContainsAnchor = true;
            }
            parentAnchor = parentAnchor.parentNode;
        }
    
        while(parentFocus && parentFocus != document.documentElement) {
            if(parentFocus == editable) {
                isOrContainsFocus = true;
            }
            parentFocus = parentFocus.parentNode;
        }
    
        if(!isOrContainsAnchor || !isOrContainsFocus) {
            return;
        }
    
        selection = window.getSelection();
    
        // Get range (standards)
        if(selection.getRangeAt !== undefined) {
            range = selection.getRangeAt(0);
    
        // Get range (Safari 2)
        } else if(
            document.createRange &&
            selection.anchorNode &&
            selection.anchorOffset &&
            selection.focusNode &&
            selection.focusOffset
        ) {
            range = document.createRange();
            range.setStart(selection.anchorNode, selection.anchorOffset);
            range.setEnd(selection.focusNode, selection.focusOffset);
        } else {
            // Failure here, not handled by the rest of the script.
            // Probably IE or some older browser
        }
    };
    
    // Recalculate selection while typing
    editable.onkeyup = captureSelection;
    
    // Recalculate selection after clicking/drag-selecting
    editable.onmousedown = function(e) {
        editable.className = editable.className + ' selecting';
    };
    document.onmouseup = function(e) {
        if(editable.className.match(/\sselecting(\s|$)/)) {
            editable.className = editable.className.replace(/ selecting(\s|$)/, '');
            captureSelection();
        }
    };
    
    editable.onblur = function(e) {
        var cursorStart = document.createElement('span'),
            collapsed = !!range.collapsed;
    
        cursorStart.id = 'cursorStart';
        cursorStart.appendChild(document.createTextNode('—'));
    
        // Insert beginning cursor marker
        range.insertNode(cursorStart);
    
        // Insert end cursor marker if any text is selected
        if(!collapsed) {
            var cursorEnd = document.createElement('span');
            cursorEnd.id = 'cursorEnd';
            range.collapse();
            range.insertNode(cursorEnd);
        }
    };
    
    // Add callbacks to afterFocus to be called after cursor is replaced
    // if you like, this would be useful for styling buttons and so on
    var afterFocus = [];
    editable.onfocus = function(e) {
        // Slight delay will avoid the initial selection
        // (at start or of contents depending on browser) being mistaken
        setTimeout(function() {
            var cursorStart = document.getElementById('cursorStart'),
                cursorEnd = document.getElementById('cursorEnd');
    
            // Don't do anything if user is creating a new selection
            if(editable.className.match(/\sselecting(\s|$)/)) {
                if(cursorStart) {
                    cursorStart.parentNode.removeChild(cursorStart);
                }
                if(cursorEnd) {
                    cursorEnd.parentNode.removeChild(cursorEnd);
                }
            } else if(cursorStart) {
                captureSelection();
                var range = document.createRange();
    
                if(cursorEnd) {
                    range.setStartAfter(cursorStart);
                    range.setEndBefore(cursorEnd);
    
                    // Delete cursor markers
                    cursorStart.parentNode.removeChild(cursorStart);
                    cursorEnd.parentNode.removeChild(cursorEnd);
    
                    // Select range
                    selection.removeAllRanges();
                    selection.addRange(range);
                } else {
                    range.selectNode(cursorStart);
    
                    // Select range
                    selection.removeAllRanges();
                    selection.addRange(range);
    
                    // Delete cursor marker
                    document.execCommand('delete', false, null);
                }
            }
    
            // Call callbacks here
            for(var i = 0; i < afterFocus.length; i++) {
                afterFocus[i]();
            }
            afterFocus = [];
    
            // Register selection again
            captureSelection();
        }, 10);
    };
    

  2. 2.이 솔루션은 모든 주요 브라우저에서 작동 :

    이 솔루션은 모든 주요 브라우저에서 작동 :

    saveSelection는 () 사업부의 축제 및 행사 onMouseUp에와 onKeyUp에 부착 변수 savedRange에 선택을 저장합니다.

    restoreSelection는 () 사업부의 onfocus 및 이벤트에 부착 savedRange에 저장된 선택을 다시 선택합니다.

    당신은 사용자가 (당신이 클릭하지만 코드 완전성을 위해서 곳에 커서가 이동 할 것으로 예상 일반적으로 비트 unintuitative가) 사업부의 aswell을 클릭하면 선택이 복원하려는 경우가 아니면이 완벽하게 작동

    이것을 온 클릭하고 이벤트가 이벤트를 취소 할 수있는 크로스 브라우저 기능입니다 함수 cancelEvent ()에 의해 취소하면 onMouseDown 달성하기 위해. 클릭 이벤트가 취소 될 때 사업부가 포커스를받지 않고이 기능을 실행하지 않는 때문에 아무것도 전혀 선택되지 않기 때문에 cancelEvent () 함수는 또한 restoreSelection () 함수를 실행합니다.

    그것은 초점이와 "거짓"으로 변경에 onblur 및 onfocus 및 "true"로되어 있는지 여부 변수는 isInFocus 저장합니다. 이 클릭 이벤트가 사업부는 (그렇지 않으면 당신은 전혀 선택을 변경 할 수 없을 것입니다)에 포커스가없는 경우에만 취소 할 수 있습니다.

    . 당신은 document.getElementById를 ( "영역")의 onclick 선택을 복원 (초점이 요소에 부여 된 경우에만 programtically 사용하여 초점을 () 사업부는 클릭에 의해 초점이 맞춰지면 변화를, 그리고하지 않는 선택을하고자하는 경우, 또는 유사한 다음 단순히 온 클릭하고 이벤트하면 onMouseDown 제거합니다.에 onblur 이벤트와 onDivBlur ()와 cancelEvent를 () 함수도 안전하게 이러한 상황에서 제거 할 수 있습니다.

    당신이 신속하게 테스트하려는 경우이 코드는 HTML 페이지의 본문에 직접 떨어 뜨리면 작동합니다 :

    <div id="area" style="width:300px;height:300px;" onblur="onDivBlur();" onmousedown="return cancelEvent(event);" onclick="return cancelEvent(event);" contentEditable="true" onmouseup="saveSelection();" onkeyup="saveSelection();" onfocus="restoreSelection();"></div>
    <script type="text/javascript">
    var savedRange,isInFocus;
    function saveSelection()
    {
        if(window.getSelection)//non IE Browsers
        {
            savedRange = window.getSelection().getRangeAt(0);
        }
        else if(document.selection)//IE
        { 
            savedRange = document.selection.createRange();  
        } 
    }
    
    function restoreSelection()
    {
        isInFocus = true;
        document.getElementById("area").focus();
        if (savedRange != null) {
            if (window.getSelection)//non IE and there is already a selection
            {
                var s = window.getSelection();
                if (s.rangeCount > 0) 
                    s.removeAllRanges();
                s.addRange(savedRange);
            }
            else if (document.createRange)//non IE and no selection
            {
                window.getSelection().addRange(savedRange);
            }
            else if (document.selection)//IE
            {
                savedRange.select();
            }
        }
    }
    //this part onwards is only needed if you want to restore selection onclick
    var isInFocus = false;
    function onDivBlur()
    {
        isInFocus = false;
    }
    
    function cancelEvent(e)
    {
        if (isInFocus == false && savedRange != null) {
            if (e && e.preventDefault) {
                //alert("FF");
                e.stopPropagation(); // DOM style (return false doesn't always work in FF)
                e.preventDefault();
            }
            else {
                window.event.cancelBubble = true;//IE stopPropagation
            }
            restoreSelection();
            return false; // false = IE style
        }
    }
    </script>
    

  3. 3.최신 정보

    최신 정보

    나는 아래 게시 된 코드의 개선 된 버전을 포함하고 돌아 다니기에 알맞은라는 크로스 브라우저 범위와 선택 라이브러리를 작성했습니다. 당신은 저장 선택을 사용하고 프로젝트의 선택과 다른 아무것도하지 않는 경우 내가 @Nico 화상의 대답처럼 사용 무언가에 유혹 될 거라고하지만,이 특정 질문에 대한 모듈을 복원하고의 대부분을 필요가 없습니다 수 있습니다 도서관.

    이전 대답

    당신은 DOM 범위 같은으로 IE의 TextRange를 변환 eyelidlessness의 시작 지점과 같이와 관련하여 사용하는 IERange을 (http://code.google.com/p/ierange/)를 사용할 수 있습니다. <-> TextRange 변환 오히려 사용하는 것보다 모든 것이 개인적으로 나는 단지 범위을 IERange의 알고리즘을 사용합니다. 그리고 IE의 선택 객체는 focusNode 및 anchorNode 속성을 가지고 있지 않지만 그냥 범위 / TextRange 대신 선택에서 얻은 사용할 수 있어야합니다.

    내가 다시 여기에 내가 할 경우 언제 게시 할 예정입니다,이 작업을 수행하기 위해 함께 뭔가를 넣어 수 있습니다.

    편집하다:

    나는이 작업을 수행하는 스크립트의 데모를 만들었습니다. 그것은 내가 아직 조사 할 시간이 없었어요 오페라 9의 버그를 제외하고 지금까지 그것을 시도했습니다 모든 작동합니다. 그것이 작동 브라우저는 IE 5.5, 6, 7, 크롬이 파이어 폭스 2, 3, 3.5, 사파리 4, 윈도우에 있습니다.

    http://www.timdown.co.uk/code/selections/

    선택이 브라우저에서 뒤로 할 수 있음을 참고 그래서 초점 노드는 선택의 시작과 선택의 시작에 대한 상대적인 위치로 캐럿을 이동 오른쪽이나 왼쪽 커서 키를 타격이다. 나는 선택을 복원 할 때 초점 노드가 선택의 끝에 항상 그래서,이를 복제 할 수 있다고 생각하지 않습니다.

    나는 곧 어떤 시점에서 완전히 이것을 기록합니다.


  4. 4.나는 특별히의 contentEditable 사업부의 끝으로 커서의 위치를 ​​설정하는 데 필요한 관련 상황을 가지고 있었다. 나는 배회 같은 전체 깃털 라이브러리를 사용하지 않았고, 많은 솔루션은 너무 헤비급했다.

    나는 특별히의 contentEditable 사업부의 끝으로 커서의 위치를 ​​설정하는 데 필요한 관련 상황을 가지고 있었다. 나는 배회 같은 전체 깃털 라이브러리를 사용하지 않았고, 많은 솔루션은 너무 헤비급했다.

    결국, 나는의 contentEditable 사업부의 마지막에 캐럿 위치를 설정하려면이 간단한 jQuery를 기능을 함께했다 :

    $.fn.focusEnd = function() {
        $(this).focus();
        var tmp = $('<span />').appendTo($(this)),
            node = tmp.get(0),
            range = null,
            sel = null;
    
        if (document.selection) {
            range = document.body.createTextRange();
            range.moveToElementText(node);
            range.select();
        } else if (window.getSelection) {
            range = document.createRange();
            range.selectNode(node);
            sel = window.getSelection();
            sel.removeAllRanges();
            sel.addRange(range);
        }
        tmp.remove();
        return this;
    }
    

    이론은 간단하다 : 스팬을 제거 한 후, 편집 가능한 끝에 범위를 추가를 선택하고 - 사업부의 끝에 커서 우리를 떠나. 당신이 원하는 어디든지 당신은 따라서 특정 지점에 커서를두고, 스팬을 삽입하기 위해이 솔루션을 적용 할 수있다.

    사용법은 간단하다 :

    $('#editable').focusEnd();
    

    즉입니다!


  5. 5.나는 니코 화상의 답변을했다 및 jQuery를 사용하여 만든 :

    나는 니코 화상의 답변을했다 및 jQuery를 사용하여 만든 :

    당신은 jQuery를 1.6 이상이 필요합니다 :

    savedRanges = new Object();
    $('div[contenteditable="true"]').focus(function(){
        var s = window.getSelection();
        var t = $('div[contenteditable="true"]').index(this);
        if (typeof(savedRanges[t]) === "undefined"){
            savedRanges[t]= new Range();
        } else if(s.rangeCount > 0) {
            s.removeAllRanges();
            s.addRange(savedRanges[t]);
        }
    }).bind("mouseup keyup",function(){
        var t = $('div[contenteditable="true"]').index(this);
        savedRanges[t] = window.getSelection().getRangeAt(0);
    }).on("mousedown click",function(e){
        if(!$(this).is(":focus")){
            e.stopPropagation();
            e.preventDefault();
            $(this).focus();
        }
    });
    

    savedRanges = 새 개체 (); $ ( 'DIV [의 contentEditable = "참"]). 포커스 (함수 () { VAR window.getSelection S = (); . VAR t = $ ( 'DIV [의 contentEditable = "true"로]) 인덱스 (이); 경우 (대해서 typeof (savedRanges [t]) === "미등록") { savedRanges [t]는 새로운 범위 () =; } 다른 경우 (s.rangeCount> 0) { s.removeAllRanges (); s.addRange (savedRanges [t]); } }). 결합 ( "와 mouseUp의 keyup"함수 () { . VAR t = $ ( 'DIV [의 contentEditable = "true"로]) 인덱스 (이); savedRanges [t] = window.getSelection () getRangeAt (0).; }). {(함수 (예 "를 클릭 mousedown")에 ($ (이) .is는 (! "초점")) {경우 e.stopPropagation (); e.preventDefault (); $ (이) .focus (); } }); DIV [의 contentEditable { 패딩 : 1em; 글꼴 - 가족 : 굴림; 개요 : 1 픽셀의 고체 RGBA (0,0,0,0.5); } <스크립트 SRC = "https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js">


  6. 6.내가 위에서 eyelidlessness '답을 수정하고 방금 다음 중 하나를 수행 할 수 있도록 그것을 jQuery 플러그인을 만들었다 주위에 재생 후 :

    내가 위에서 eyelidlessness '답을 수정하고 방금 다음 중 하나를 수행 할 수 있도록 그것을 jQuery 플러그인을 만들었다 주위에 재생 후 :

    var html = "The quick brown fox";
    $div.html(html);
    
    // Select at the text "quick":
    $div.setContentEditableSelection(4, 5);
    
    // Select at the beginning of the contenteditable div:
    $div.setContentEditableSelection(0);
    
    // Select at the end of the contenteditable div:
    $div.setContentEditableSelection(html.length);
    

    긴 코드 게시물을 실례지만 사람을 도움이 될 수 있습니다 :

    $.fn.setContentEditableSelection = function(position, length) {
        if (typeof(length) == "undefined") {
            length = 0;
        }
    
        return this.each(function() {
            var $this = $(this);
            var editable = this;
            var selection;
            var range;
    
            var html = $this.html();
            html = html.substring(0, position) +
                '<a id="cursorStart"></a>' +
                html.substring(position, position + length) +
                '<a id="cursorEnd"></a>' +
                html.substring(position + length, html.length);
            console.log(html);
            $this.html(html);
    
            // Populates selection and range variables
            var captureSelection = function(e) {
                // Don't capture selection outside editable region
                var isOrContainsAnchor = false,
                    isOrContainsFocus = false,
                    sel = window.getSelection(),
                    parentAnchor = sel.anchorNode,
                    parentFocus = sel.focusNode;
    
                while (parentAnchor && parentAnchor != document.documentElement) {
                    if (parentAnchor == editable) {
                        isOrContainsAnchor = true;
                    }
                    parentAnchor = parentAnchor.parentNode;
                }
    
                while (parentFocus && parentFocus != document.documentElement) {
                    if (parentFocus == editable) {
                        isOrContainsFocus = true;
                    }
                    parentFocus = parentFocus.parentNode;
                }
    
                if (!isOrContainsAnchor || !isOrContainsFocus) {
                    return;
                }
    
                selection = window.getSelection();
    
                // Get range (standards)
                if (selection.getRangeAt !== undefined) {
                    range = selection.getRangeAt(0);
    
                    // Get range (Safari 2)
                } else if (
                    document.createRange &&
                    selection.anchorNode &&
                    selection.anchorOffset &&
                    selection.focusNode &&
                    selection.focusOffset
                ) {
                    range = document.createRange();
                    range.setStart(selection.anchorNode, selection.anchorOffset);
                    range.setEnd(selection.focusNode, selection.focusOffset);
                } else {
                    // Failure here, not handled by the rest of the script.
                    // Probably IE or some older browser
                }
            };
    
            // Slight delay will avoid the initial selection
            // (at start or of contents depending on browser) being mistaken
            setTimeout(function() {
                var cursorStart = document.getElementById('cursorStart');
                var cursorEnd = document.getElementById('cursorEnd');
    
                // Don't do anything if user is creating a new selection
                if (editable.className.match(/\sselecting(\s|$)/)) {
                    if (cursorStart) {
                        cursorStart.parentNode.removeChild(cursorStart);
                    }
                    if (cursorEnd) {
                        cursorEnd.parentNode.removeChild(cursorEnd);
                    }
                } else if (cursorStart) {
                    captureSelection();
                    range = document.createRange();
    
                    if (cursorEnd) {
                        range.setStartAfter(cursorStart);
                        range.setEndBefore(cursorEnd);
    
                        // Delete cursor markers
                        cursorStart.parentNode.removeChild(cursorStart);
                        cursorEnd.parentNode.removeChild(cursorEnd);
    
                        // Select range
                        selection.removeAllRanges();
                        selection.addRange(range);
                    } else {
                        range.selectNode(cursorStart);
    
                        // Select range
                        selection.removeAllRanges();
                        selection.addRange(range);
    
                        // Delete cursor marker
                        document.execCommand('delete', false, null);
                    }
                }
    
                // Register selection again
                captureSelection();
            }, 10);
        });
    };
    

  7. 7.당신은 최신 브라우저에서 지원 selectNodeContents을 활용할 수 있습니다.

    당신은 최신 브라우저에서 지원 selectNodeContents을 활용할 수 있습니다.

    var el = document.getElementById('idOfYoursContentEditable');
    var selection = window.getSelection();
    var range = document.createRange();
    selection.removeAllRanges();
    range.selectNodeContents(el);
    range.collapse(false);
    selection.addRange(range);
    el.focus();
    

  8. 8.파이어 폭스에서 당신은 자식 노드의 DIV의 텍스트가있을 수 있습니다 (o_div.childNodes [0])

    파이어 폭스에서 당신은 자식 노드의 DIV의 텍스트가있을 수 있습니다 (o_div.childNodes [0])

    var range = document.createRange();
    
    range.setStart(o_div.childNodes[0],last_caret_pos);
    range.setEnd(o_div.childNodes[0],last_caret_pos);
    range.collapse(false);
    
    var sel = window.getSelection(); 
    sel.removeAllRanges();
    sel.addRange(range);
    
  9. from https://stackoverflow.com/questions/1181700/set-cursor-position-on-contenteditable-div by cc-by-sa and MIT license