Метод выбора IE TextRange не работает должным образом

У меня необычная проблема с документом 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 -&gt;
            <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?

Потратив некоторое время на это, я обоснованно убежден, что не существует способа программно разместить курсор в конце текстового узла, который непосредственно предшествует блочному элементу.

Tim Down 10.08.2011 02:08
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
7
1
12 270
4
Перейти к ответу Данный вопрос помечен как решенный

Ответы 4

Недавно я работал на сайте, который использовал Microsoft CMS с «MSIB + pack» элементов управления, который включал редактор WYSIWYG, работающий в Internet Explorer.

Кажется, я помню некоторые комментарии в клиентском Javascript редактора, которые были конкретно связаны с этой ошибкой в ​​IE и методом Range.Select ().

К сожалению, я там больше не работаю, поэтому не могу получить доступ к файлам Javascript, но, возможно, вы сможете получить их откуда-нибудь?

Удачи

Вы знаете, было ли у редактора WYSIWYG имя? Может облегчить поиск ...

Douglas Mayle 29.09.2008 19:59

Мне удалось получить копию пакета MSIB +, но я не могу найти внутри редактор WYSIWYG. Я не уверен, что моя копия устарела или редактор является частью редактора CMS ...

Douglas Mayle 29.09.2008 22:04

Я немного покопался и, к сожалению, не вижу обходного пути ... Хотя одна вещь, которую я заметил при отладке 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, я просто ищу безопасный обходной путь, потому что мне нужно переместить выделение, прежде чем восстанавливать его.

Douglas Mayle 06.05.2009 01:12
Ответ принят как подходящий

Я придумал несколько методов работы с такими диапазонами 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кажется, это совсем другая проблема.

Другие вопросы по теме