Программно выбирать текст в контентном HTML-элементе?
В JavaScript можно программно выбирать текст в элементе input
или textarea
. Вы можете сфокусировать вход с помощью ipt.focus()
, а затем выбрать его содержимое с помощью ipt.select()
. Вы даже можете выбрать определенный диапазон ipt.setSelectionRange(from,to)
.
Мой вопрос: есть ли способ сделать это в элементе contenteditable
тоже?
Я обнаружил, что могу сделать elem.focus()
, чтобы поместить каретку в элемент contenteditable
, но в дальнейшем запуск elem.select()
не работает (и не работает setSelectionRange
). Я не могу найти что-либо в Интернете об этом, но, возможно, я искал неправильную вещь...
Кстати, если это имеет значение, мне нужно только его работать в Google Chrome, так как это для расширения Chrome.
Ответы
Ответ 1
Если вы хотите выбрать все содержимое элемента (contenteditable или нет) в Chrome, вот как. Это также будет работать в Firefox, Safari 3+, Opera 9+ (возможно, более ранних версиях) и IE 9. Вы также можете создавать подборки до уровня персонажа. Необходимые API-интерфейсы: DOM Range (текущая спецификация DOM Level 2, см. Также MDN) и Selection, который определяется как часть новой спецификации диапазона (MDN docs).
function selectElementContents(el) {
var range = document.createRange();
range.selectNodeContents(el);
var sel = window.getSelection();
sel.removeAllRanges();
sel.addRange(range);
}
var el = document.getElementById("foo");
selectElementContents(el);
Ответ 2
В дополнение к ответ Tim Downs, я сделал решение, которое работает даже в oldIE:
var selectText = function() {
var range, selection;
if (document.body.createTextRange) {
range = document.body.createTextRange();
range.moveToElementText(this);
range.select();
} else if (window.getSelection) {
selection = window.getSelection();
range = document.createRange();
range.selectNodeContents(this);
selection.removeAllRanges();
selection.addRange(range);
}
};
document.getElementById('foo').ondblclick = selectText;
Протестировано в IE 8+, Firefox 3+, Opera 9+ и Chrome 2+. Даже я установил его в плагин jQuery:
jQuery.fn.selectText = function() {
var range, selection;
return this.each(function() {
if (document.body.createTextRange) {
range = document.body.createTextRange();
range.moveToElementText(this);
range.select();
} else if (window.getSelection) {
selection = window.getSelection();
range = document.createRange();
range.selectNodeContents(this);
selection.removeAllRanges();
selection.addRange(range);
}
});
};
$('#foo').on('dblclick', function() {
$(this).selectText();
});
... и кто посмеялся, здесь одинаково для всех наркоманов:
jQuery.fn.selectText = ->
@each ->
if document.body.createTextRange
range = document.body.createTextRange()
range.moveToElementText @
range.select()
else if window.getSelection
selection = window.getSelection()
range = document.createRange()
range.selectNodeContents @
selection.removeAllRanges()
selection.addRange range
return
Update:
Если вы хотите выбрать всю страницу или содержимое редактируемого региона (помечено знаком contentEditable
), вы можете сделать это намного проще, переключившись на designMode
и используя document.execCommand
:
Там хорошая начальная точка в MDN и littledocumentation.
var selectText = function () {
document.execCommand('selectAll', false, null);
};
(хорошо работает в IE6 +, Opera 9+, Firefoy 3+, Chrome 2+) http://caniuse.com/#search=execCommand
Ответ 3
Rangy позволяет вам делать этот кросс-браузер с тем же кодом. Rangy - это кросс-браузерная реализация методов DOM для выбора. Он хорошо протестирован и делает это намного менее болезненным. Я отказываюсь дотронуться до контента без него.
Здесь вы можете найти rangy:
http://code.google.com/p/rangy/
С rangy в вашем проекте вы всегда можете написать это, даже если браузер IE 8 или ранее и имеет совершенно другой собственный API для выбора:
var range = rangy.createRange();
range.selectNodeContents(contentEditableNode);
var sel = rangy.getSelection();
sel.removeAllRanges();
sel.addRange(range);
Где "contentEditableNode" - это DOM node, который имеет атрибут contenteditable. Вы можете получить его следующим образом:
var contentEditable = document.getElementById('my-editable-thing');
Или, если jQuery уже является частью вашего проекта, и вы считаете его удобным:
var contentEditable = $('.some-selector')[0];
Ответ 4
Поскольку все существующие ответы касаются элементов div
, я объясню, как это сделать с помощью span
s.
При выборе диапазона текста в span
существует тонкая разница. Чтобы иметь возможность передавать индекс начала и конца текста, вы должны использовать Text
node, как описано здесь:
Если startNode является Node типа Text, Comment или CDATASection, то startOffset - это количество символов с начала startNode. Для других типов Node startOffset - это число дочерних узлов между началом startNode.
var e = document.getElementById("id of the span element you want to select text in");
var textNode = e.childNodes[0]; //text node is the first child node of a span
var r = document.createRange();
var startIndex = 0;
var endIndex = textNode.textContent.length;
r.setStart(textNode, startIndex);
r.setEnd(textNode, endIndex);
var s = window.getSelection();
s.removeAllRanges();
s.addRange(r);
Ответ 5
[Обновлено, чтобы исправить ошибку]
Вот пример, который адаптирован из этого ответа, который, как представляется, хорошо работает в Chrome - Выберите диапазон в contenteditable div
var elm = document.getElementById("myText"),
fc = elm.firstChild,
ec = elm.lastChild,
range = document.createRange(),
sel;
elm.focus();
range.setStart(fc,1);
range.setEnd(ec,3);
sel = window.getSelection();
sel.removeAllRanges();
sel.addRange(range);
HTML:
<div id="myText" contenteditable>test</div>
Ответ 6
contenteditable
- это просто атрибут, который интерпретируется браузером. Вы можете изменять такие элементы с помощью обычных функций DOM.
Смотрите javascript TextRanges.
Btw, быстрый поиск в SO, дал мне результаты пары.