contentEditable에서 커서 위치 설정
contentEditable = 'on'<div>가 포커스를 다시 얻었을 때 커서 / 캐럿 위치를 마지막으로 알려진 위치로 설정하는 결정적인 크로스 브라우저 솔루션을 사용하고 있습니다. 편집 가능한 콘텐츠 div의 기본 기능은 캐럿 / 커서를 클릭 할 때마다 div의 텍스트 시작 부분으로 이동하는 것이므로 바람직하지 않습니다.
나는 그들이 div의 초점을 떠날 때 현재 커서 위치를 변수에 저장하고 다시 내부에 초점이있을 때 이것을 다시 설정해야한다고 생각하지만, 함께 모을 수는 없었습니다. 아직 코드 샘플입니다.
누군가 생각, 작업 코드 스 니펫 또는 샘플이 있다면 기꺼이 볼 수 있습니다.
아직 코드가 없지만 여기에 내가 가진 것이 있습니다.
<script type="text/javascript">
// jQuery
$(document).ready(function() {
$('#area').focus(function() { .. } // focus I would imagine I need.
}
</script>
<div id="area" contentEditable="true"></div>
추신. 이 리소스를 시도했지만 <div>에서 작동하지 않는 것 같습니다. 아마도 텍스트 영역에만 해당 (콘텐츠 편집 가능 엔티티의 끝으로 커서를 이동하는 방법 )
이는 표준 기반 브라우저와 호환되지만 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);
};
이 솔루션은 모든 주요 브라우저에서 작동합니다.
saveSelection()
은 div 의 onmouseup
및 onkeyup
이벤트에 첨부되고 선택 사항을 변수에 저장합니다 savedRange
.
restoreSelection()
은 onfocus
div 의 이벤트에 첨부되고에 저장된 선택을 다시 선택합니다 savedRange
.
사용자가 div를 클릭 할 때 선택을 복원하지 않으려는 경우 완벽하게 작동합니다 (일반적으로 커서는 클릭하는 곳으로 이동하지만 코드는 완전성을 위해 포함됨)
이를 달성하기 위해 onclick
및 onmousedown
이벤트는 이벤트를 취소 cancelEvent()
하는 크로스 브라우저 기능인 기능에 의해 취소됩니다. cancelEvent()
기능도 실행 restoreSelection()
클릭 이벤트가 취소 될 때 사업부가 포커스를받지 않고이 기능을 실행하지 않는 때문에 아무것도 전혀 선택되지 않기 때문에 기능.
변수 isInFocus
는 포커스가 있는지 여부를 저장하고 "false" onblur
및 "true"로 변경됩니다 onfocus
. 이렇게하면 div의 초점이 맞지 않을 때만 클릭 이벤트를 취소 할 수 있습니다 (그렇지 않으면 선택을 전혀 변경할 수 없음).
클릭으로 div에 초점을 맞출 때 선택을 변경하고 선택을 복원하지 않으려면 onclick
(선택적으로 document.getElementById("area").focus();
또는 유사한 것을 사용하여 요소에 포커스가 부여 된 경우에만 onclick
and 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>
최신 정보
아래에 게시 한 코드의 향상된 버전을 통합하는 Rangy 라는 브라우저 간 범위 및 선택 라이브러리를 작성했습니다 . 당신이 사용할 수있는 저장 선택 및 모듈을 복원 내가 같이 사용 무언가에 유혹 될 거라고하지만,이 특정 질문에 대한 @Nico 화상의 대답은 당신이 당신의 프로젝트의 선택과 다른 아무것도하지 않는 경우와의 대부분을 필요가 없습니다 도서관.
이전 답변
IERange ( http://code.google.com/p/ierange/ )를 사용
하여 IE의 TextRange를 DOM 범위와 같은 것으로 변환하고 눈꺼풀이없는 시작점과 함께 사용할 수 있습니다. 개인적으로 나는 전체를 사용하는 대신 Range <-> TextRange 변환을 수행하는 IERange의 알고리즘 만 사용하려고합니다. 그리고 IE의 선택 객체에는 focusNode 및 anchorNode 속성이 없지만 선택에서 얻은 Range / TextRange를 대신 사용할 수 있습니다.
나는 이것을하기 위해 무언가를 모을 수도 있고, 내가 할 때 여기에 다시 게시 할 것입니다.
편집하다:
이 작업을 수행하는 스크립트 데모를 만들었습니다. 그것은 아직 조사 할 시간이 없었던 Opera 9의 버그를 제외하고는 지금까지 시도한 모든 작업에서 작동합니다. 작동하는 브라우저는 Windows의 IE 5.5, 6 및 7, Chrome 2, Firefox 2, 3 및 3.5 및 Safari 4입니다.
http://www.timdown.co.uk/code/selections/
브라우저에서 포커스 노드가 선택의 시작 부분에 있고 뒤로 오른쪽 또는 왼쪽 커서 키를 누르면 선택 영역의 시작 부분을 기준으로 캐럿이 이동합니다. 선택을 복원 할 때 이것을 복제 할 수 없다고 생각하므로 포커스 노드가 항상 선택의 끝에 있습니다.
나는 이것을 어느 시점에서 곧 완전히 쓸 것이다.
관련 상황이 있었는데 특히 커서 위치를 contenteditable div의 END로 설정해야했습니다. Rangy와 같은 완전한 라이브러리를 사용하고 싶지 않았으며 많은 솔루션이 너무 무거웠습니다.
결국 캐럿 위치를 contenteditable div의 끝으로 설정하는 간단한 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;
}
이론은 간단합니다. 편집 가능한 끝에 스팬을 추가하고 선택 한 다음 스팬을 제거하십시오 .div 끝에 커서가 남습니다. 이 솔루션을 조정하여 원하는 곳에 스팬을 삽입 할 수 있으므로 커서를 특정 지점에 놓을 수 있습니다.
사용법은 간단합니다.
$('#editable').focusEnd();
그게 다야!
Nico Burns의 답변을 jQuery를 사용하여 만들었습니다.
- 일반 : 모든
div contentEditable="true"
- 더 짧은
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 = 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();
}
});
div[contenteditable] {
padding: 1em;
font-family: Arial;
outline: 1px solid rgba(0,0,0,0.5);
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div contentEditable="true"></div>
<div contentEditable="true"></div>
<div contentEditable="true"></div>
놀았을 때 위의 눈꺼풀이없는 답변을 수정하고 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);
});
};
최신 브라우저에서 지원하는 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();
Firefox에서는 하위 노드에 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);
참고 URL : https://stackoverflow.com/questions/1181700/set-cursor-position-on-contenteditable-div
'Programming' 카테고리의 다른 글
자식 리포지토리에서 종속성을 어떻게 연결할 수 있습니까? (0) | 2020.06.22 |
---|---|
지점을 로컬로 제거하는 방법? (0) | 2020.06.22 |
XPath : 텍스트 노드 선택 (0) | 2020.06.22 |
리소스가 없습니다-Theme.AppCompat.Light.DarkActionBar (0) | 2020.06.22 |
IEqualityComparer의 차이점은 무엇입니까 (0) | 2020.06.22 |