Проблемы с методом collapseToStart в Firefox

Рейтинг: 2Ответов: 1Опубликовано: 05.05.2015

Сразу к делу, метод collapseToStartEnd тоже) не работают в Firefox (версия 37 -- последняя на сегодняшний день)

function checkFor() {
  var el1 = document.getElementById("el1");

  var rng = document.createRange();
  rng.selectNodeContents(el1);

  var sel = window.getSelection();

  sel.removeAllRanges();
  sel.addRange(rng);

  sel.collapseToStart(); //Вот этот метод не работает в мозиле, версия 37
}
<div id="el1" contenteditable>Текст внутри div</div>
<br>
<br>
<div style="padding:10px;">[Устанавливаем каретку]</div>

Кликните по ссылке в квадратных скобках -- фокус должен появиться перед словом "Текст". В Chrome все работает, в IE (в последней версии) -- тоже.

ВНИМАНИЕ!!!

Проблему решил следующий образом: На блок установил фокус при помощи метода focus() и затем в Firefox все заработало. А именно: во вторую строчку функции checkFor добавил строчку el1.focus() и все.

P.S. Нужно было доки на mozilla.org читать, а я дурень)

Ответы

▲ 1

Хороший вопрос! Он побудил меня провести небольшое исследование.

Что происходит:

  1. При нажатии вне contenteditable элемента фокусированный элемент (document.activeElement) по умолчанию меняется: в приведенном примере фокус перемещается на <body>.
  2. При изменении selection (например, через метод collapseToStart), Chrome (и Safari) перемещают фокус на элемент, в котором оказалось выделение (selection). Firefox же этого не делает, отсюда и наблюдаемое поведение.

Исследование показывает, что в WebKit это поведение реализовано с древних времен и без явных на то причин. В спецификациях это поведение не описано (W3C 14383), и возможно, поведение еще изменится.

Соответственно, вариантов решения может быть два:

  • Ваш, где фокус принудительно возвращается в contenteditable и после этого устанавливается selection (отмечу, что сама по себе установка фокуса обратно "сбрасывает" selection в начало, как минимум в Firefox)
  • Отмена поведения по умолчанию: для этого надо ловить событие mousedown и выполнять в нем event.preventDefault().

P.S. Добавил эту информацию на MDN.