У меня необычная проблема с документом IE, для которого для contentEditable установлено значение true. Вызов select () в диапазоне, который расположен в конце текстового узла, который непосредственно предшествует элементу блока, приводит к смещению выделения на один символ вправо и появлению там, где этого не должно быть. Я отправил в Microsoft ошибку против IE8. Если можете, проголосуйте за эту проблему, чтобы ее можно было исправить.
https://connect.microsoft.com/IE/feedback/ViewFeedback.aspx?FeedbackID=390995
Я написал тестовый пример, чтобы продемонстрировать эффект:
<html>
<body>
<iframe id = "editable">
<html>
<body>
<div id = "test">
Click to the right of this line ->
<p id = "par">Block Element</p>
</div>
</body>
</html>
</iframe>
<input id = "mytrigger" type = "button" value = "Then Click here to Save and Restore" />
<script type = "text/javascript">
window.onload = function() {
var iframe = document.getElementById('editable');
var doc = iframe.contentDocument || iframe.contentWindow.document;
// An IFRAME without a source points to a blank document. Here we'll
// copy the content we stored in between the IFRAME tags into that
// document. It's a hack to allow us to use only one HTML file for this
// test.
doc.body.innerHTML = iframe.textContent || iframe.innerHTML;
// Marke the IFRAME as an editable document
if (doc.body.contentEditable) {
doc.body.contentEditable = true;
} else {
var mydoc = doc;
doc.designMode = 'On';
}
// A function to demonstrate the bug.
var myhandler = function() {
// Step 1 Get the current selection
var selection = doc.selection || iframe.contentWindow.getSelection();
var range = selection.createRange ? selection.createRange() : selection.getRangeAt(0);
// Step 2 Restore the selection
if (range.select) {
range.select();
} else {
selection.removeAllRanges();
selection.addRange(range);
doc.body.focus();
}
}
// Set up the button to perform the test code.
var button = document.getElementById('mytrigger');
if (button.addEventListener) {
button.addEventListener('click', myhandler, false);
} else {
button.attachEvent('onclick', myhandler);
}
}
</script>
</body>
</html>
Проблема обнаружена в функции myhandler. Это все, что я делаю, между сохранением и восстановлением выделения нет Шага 3, и все же курсор перемещается. Кажется, что этого не происходит, если выделение не пусто (т. Е. У меня есть мигающий курсор, но нет текста), и это происходит только тогда, когда курсор находится в конце текстового узла, который непосредственно предшествует узлу блока.
Кажется, что диапазон все еще находится в правильном положении (если я вызываю parentElement в диапазоне, который возвращает div), но если я получаю новый диапазон из текущего выделения, новый диапазон находится внутри тега абзаца, и это его parentElement.
Как мне обойти это и последовательно сохранять и восстанавливать выбор в Internet Explorer?



![Безумие обратных вызовов в javascript [JS]](https://i.imgur.com/WsjO6zJb.png)


Недавно я работал на сайте, который использовал Microsoft CMS с «MSIB + pack» элементов управления, который включал редактор WYSIWYG, работающий в Internet Explorer.
Кажется, я помню некоторые комментарии в клиентском Javascript редактора, которые были конкретно связаны с этой ошибкой в IE и методом Range.Select ().
К сожалению, я там больше не работаю, поэтому не могу получить доступ к файлам Javascript, но, возможно, вы сможете получить их откуда-нибудь?
Удачи
Вы знаете, было ли у редактора WYSIWYG имя? Может облегчить поиск ...
Мне удалось получить копию пакета MSIB +, но я не могу найти внутри редактор WYSIWYG. Я не уверен, что моя копия устарела или редактор является частью редактора CMS ...
Я немного покопался и, к сожалению, не вижу обходного пути ... Хотя одна вещь, которую я заметил при отладке javascript, похоже, что проблема на самом деле связана с самим объектом диапазона, а не с последующим range.select(). Если вы посмотрите на значения в объекте диапазона, который возвращает selection.createRange(), да, родительский объект dom может быть правильным, но информация о позиционировании уже относится к началу следующей строки (т.е. offsetLeft / Top, boundingLeft / Top и т. д. Уже неправильный).
Основываясь на информации здесь, здесь и здесь, я думаю, вам не повезло с IE, поскольку у вас есть доступ только к объекту Microsoft TextRange, который, похоже, не работает. Исходя из моих экспериментов, вы можете перемещать диапазон и позиционировать его точно там, где он должен быть, но как только вы это сделаете, объект диапазона автоматически перейдет к следующей строке, даже до того, как вы попытались установить его в .select(). Например, вы можете увидеть проблему, поместив этот код между шагами 1 и 2:
if (range.boundingWidth == 0)
{
//looks like its already at the start of the next line down...
alert('default position: ' + range.offsetLeft + ', ' + range.offsetTop);
//lets move the start of the range one character back
//(i.e. select the last char on the line)
range.moveStart("character", -1);
//now the range looks good (except that its width will be one char);
alert('one char back: ' + range.offsetLeft + ', ' + range.offsetTop);
//calculate the true end of the line...
var left = range.offsetLeft + range.boundingWidth;
var top = range.offsetTop;
//now we can collapse back down to 0 width range
range.collapse();
//the position looks right
alert('moving to: ' + left + ', ' + top);
//move there.
range.moveToPoint(left, top);
//oops... on the next line again... stupid IE.
alert('moved to: ' + range.offsetLeft + ', ' + range.offsetTop);
}
Так что, к сожалению, не похоже, что есть какой-либо способ убедиться, что диапазон находится в нужном месте, когда вы выбираете его снова.
Очевидно, есть тривиальное исправление вашего кода выше, изменив его на шаге 2 следующим образом:
// Step 2 Restore the selection
if (range.select) {
if (range.boundingWidth > 0) {
range.select();
}
} else {
selection.removeAllRanges();
selection.addRange(range);
doc.body.focus();
}
Но, по-видимому, вы действительно хотите сделать что-то между Шагом 1 и Шагом 2 в вашем реальном, что включает в себя перемещение выделения, следовательно, необходимо его переустановить. Но на всякий случай. :)
Итак, лучшее, что я могу сделать, это пойти и проголосовать за созданную вами ошибку ... Надеюсь, они ее исправят.
Спасибо, что заглянули. Я знаю, что это ошибка в IE, я просто ищу безопасный обходной путь, потому что мне нужно переместить выделение, прежде чем восстанавливать его.
Я придумал несколько методов работы с такими диапазонами IE.
Если все, что вы хотите сделать, это сохранить место, где находится курсор, а затем восстановить его, вы можете использовать метод pasteHTML, чтобы вставить пустой диапазон в текущую позицию курсора, а затем использовать метод moveToElementText, чтобы вернуть его в это положение. очередной раз:
// Save position of cursor
range.pasteHTML('<span id = "caret"></span>')
...
// Create new cursor and put it in the old position
var caretSpan = iframe.contentWindow.document.getElementById("caret");
var selection = iframe.contentWindow.document.selection;
newRange = selection.createRange();
newRange.moveToElementText(caretSpan);
Кроме того, вы можете подсчитать, сколько символов предшествует текущей позиции курсора, и сохранить это число:
var selection = iframe.contentWindow.document.selection;
var range = selection.createRange().duplicate();
range.moveStart('sentence', -1000000);
var cursorPosition = range.text.length;
Чтобы восстановить курсор, вы устанавливаете его в начало, а затем перемещаете на это количество символов:
var newRange = selection.createRange();
newRange.move('sentence', -1000000);
newRange.move('character', cursorPosition);
Надеюсь это поможет.
Возможно, я неправильно понял, но если я щелкну справа от этой первой строки, мой курсор сразу же появится в начале второй строки, так что это не проблема TextRange, верно?
Добавление doctype, чтобы тестовая страница отображалась в стандартном режиме, а не в режиме quirks, исправляет это для меня.
И я не могу воспроизвести то, что делает ваша функция myhandler, потому что нажатие этой кнопки перемещает фокус на кнопку, поэтому я больше не могу видеть курсор и не могу вернуть его. Нахождение позиции курсора в области contentEditableкажется, это совсем другая проблема.
Потратив некоторое время на это, я обоснованно убежден, что не существует способа программно разместить курсор в конце текстового узла, который непосредственно предшествует блочному элементу.