Каков наилучший способ установить курсор / позицию каретки? - PullRequest
31 голосов
/ 10 августа 2009

Если я вставляю контент в текстовую область, кооптированную TinyMCE, каков наилучший способ установить положение курсора / каретки?

Я использую tinyMCE.execCommand("mceInsertRawHTML", false, content); для вставки содержимого, и я хотел бы установить курсор в конец содержимого.

И document.selection, и myField.selectionStart не будут работать для этого, и я чувствую, что это будет поддерживаться TinyMCE (через что-то, чего я не могу найти на их форуме), или это будет действительно безобразный хак.

Позже: Становится лучше; Я только что понял, что когда вы загружаете TinyMCE в WordPress, он загружает весь редактор во встроенном фрейме.

Позже (2): Я могу использовать document.getElementById('content_ifr').contentDocument.getSelection();, чтобы получить выделение в виде строки, но не объект выделения, для которого я могу использовать getRangeAt(0). Делая успехи понемногу.

Ответы [ 12 ]

27 голосов
/ 25 апреля 2010

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

var ed = tinyMCE.activeEditor;

//add an empty span with a unique id
var endId = tinymce.DOM.uniqueId();
ed.dom.add(ed.getBody(), 'span', {'id': endId}, '');

//select that span
var newNode = ed.dom.select('span#' + endId);
ed.selection.select(newNode[0]);

Это стратегия, используемая самими разработчиками TinyMCE при написании Selection.js. Чтение основного источника может быть чрезвычайно полезным для решения этой проблемы.

24 голосов
/ 18 августа 2009

Потратив более 15 часов на эту проблему (самоотверженность, я знаю), я нашел частичное решение, которое работает в FF и Safari, но не в IE. На данный момент это достаточно хорошо для меня, хотя я мог бы продолжить работу над этим в будущем.

Решение: при вставке HTML в текущую позицию каретки лучше всего использовать следующую функцию:

tinyMCE.activeEditor.selection.setContent(htmlcontent);

В Firefox и Safari эта функция будет вставлять содержимое в текущую позицию каретки внутри фрейма, который WordPress использует в качестве редактора TinyMCE. Проблема с IE 7 и 8 заключается в том, что функция добавляет содержимое в верхнюю часть страницы, а не в iframe (то есть полностью пропускает текстовый редактор). Чтобы решить эту проблему, я добавил условный оператор на основе этого кода , который будет использовать эту функцию вместо IE:

tinyMCE.activeEditor.execCommand("mceInsertRawHTML", false, htmlcontent);

Однако проблема для этой второй функции заключается в том, что позиция каретки устанавливается в начало области публикации после того, как она была вызвана (без надежды вызвать ее в зависимости от диапазона браузера и т. Д.). Где-то ближе к концу я обнаружил, что эта функция работает для восстановления позиции каретки в конце вставленного содержимого с помощью первой функции:

tinyMCE.activeEditor.focus();

Кроме того, он восстанавливает позицию каретки до конца вставленного содержимого без необходимости расчета длины вставленного текста. Недостатком является то, что он работает только с первой функцией вставки, которая, похоже, вызывает проблемы в IE 7 и IE 8 (что может быть скорее ошибкой WordPress, чем TinyMCE).

Словесный ответ, я знаю. Не стесняйтесь задавать вопросы для уточнения.

15 голосов
/ 30 ноября 2011

Переместить курсор до конца так просто, что я не могу поверить, что ужасные клуджи, которые были размещены где-то в Интернете, сделали это. Ответ мистера Спока изначально не был полезен, но в конце концов документы по API предоставили мне ответ. «Выделите все содержимое, а затем сверните выделение»:

ed.selection.select(ed.getBody(), true); // ed is the editor instance

ed.selection.collapse(false);

Надеюсь, это поможет кому-то еще, так как эта тема одна из первых, появившихся в Google.

7 голосов
/ 24 марта 2011

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

Надеюсь, это поможет.

            var ed = tinyMCE.activeEditor;

            ed.execCommand('mceInsertContent', false, '<a id="_mce_temp_rob" href="http://robubu.com">robubu.com</a>');

            //horrible hack to put the cursor in the right spot
            ed.focus(); //give the editor focus
            ed.selection.select(ed.dom.select('#_mce_temp_rob')[0]); //select the inserted element
            ed.selection.collapse(0); //collapses the selection to the end of the range, so the cursor is after the inserted element
            ed.dom.setAttrib('_mce_temp_rob', 'id', ''); //remove the temp id

Если вы делаете это из всплывающего окна, я думаю, вам также нужно добавить

        tinyMCEPopup.storeSelection();

перед закрытием всплывающего окна.

Для тех, кто пытается вставить содержимое из пользовательского метаблока Wordpress в редактор TinyMCE, это решение работает. Я попробовал множество других сценариев, в том числе другой на этой странице, ответ Гэри Тана, приведенный выше, который помог мне при установке пользовательских кнопок TinyMCE, но не сработал в этом сценарии.

6 голосов
/ 17 февраля 2012

Правильное решение заключается в использовании tinyMCE api tinymce.dom.Selection

http://www.tinymce.com/wiki.php/API3:class.tinymce.dom.Selection

синтаксис выглядит примерно так:

var rng = tinymce.DOM.createRng();  // the range obj
var newNode = editor.dom.select(...    // find the correct selector so that newNode is the element of your editor text
rng.setStart(newNode.firstChild, 0); // 0 is the offset : here it will be at the beginning of the line.
rng.setEnd(newNode.firstChild, 0);
editor.selection.setRng(rng);

он работает Iиспользуй это сам.

2 голосов
/ 17 августа 2018

Итак, вот решение нашего проекта. Нашей целью было изменить (+)/(-)/(?) строки на соответствующие изображения "на лету", пока пользователь печатает.

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

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

Ключевая часть: вместо использования editor.getBody, существует более элегантный способ создания временного промежутка и, более того, удаляйте его сразу после необходимых действий.

if (value.match(/\([+?-]\)/)) {
        // set current cursor via span
        editor.selection.setContent('<span id="temp-span"/>');

        // refresh Content with new span
        value = editor.getContent();

        // changing (+)/(-)/(?) to the appropriate image "on the fly"
        value = value.replace('(+)', ' <img src="https://url_here/static/task_manager/img/add.png">&nbsp;');
        value = value.replace('(-)', ' <img src="https://url_here/static/task_manager/img/forbidden.png">&nbsp;');
        value = value.replace('(?)', ' <img src="https://url_here/static/task_manager/img/help_16.png">&nbsp;');
        if (this.state.editor) {
            editor.setContent(value);

            // move cursor to the latter span
            var newNode = editor.dom.select('span#temp-span');
            editor.selection.select(newNode[0]);
            editor.selection.setContent('');
        }
        // and refreshing content again w/o span
        value = editor.getContent();
    }
1 голос
/ 17 ноября 2015

Просто добавляю свои 2 цента сюда. Никто из них не ответил на мой вопрос. Я вставлял не элемент HTML, а блок текста (например, [code][/code]), и мне нужен курсор для перехода между ними.

Используя часть ответа @robyates, я поместил временный элемент HTML между тегами 2 [code], сфокусировался на нем, затем полностью удалил элемент HTML. Вот мой код:

setup : function(ed) {
    // Add a custom button
    ed.addButton('codeblock', {
        title : 'Code Block',
        text : '[code/]',
        icon: false,
        onclick : function() {
            // Add you own code to execute something on click
            ed.focus();
            //ed.selection.setContent('[code][/code]');
            ed.execCommand('mceInsertContent', false, '[code]<span id="_cursor" />[/code]');

            ed.selection.select(ed.dom.select('#_cursor')[0]); //select the inserted element
            ed.selection.collapse(0); //collapses the selection to the end of the range, so the cursor is after the inserted element
            ed.dom.remove('_cursor'); //remove the element
        }
    });
}
1 голос
/ 23 октября 2012

Вставить узел DOM в текущем месте выбора / каретки.

tinyMCE.activeEditor.selection.setNode(tinyMCE.activeEditor.dom.create('img', {src : 'some.gif', title : 'some title'}));
1 голос
/ 12 августа 2009

Я плагиат это от здесь .

function setCaretTo(obj, pos) { 
    if(obj.createTextRange) { 
        /* Create a TextRange, set the internal pointer to
           a specified position and show the cursor at this
           position
        */ 
        var range = obj.createTextRange(); 
        range.move("character", pos); 
        range.select(); 
    } else if(obj.selectionStart) { 
        /* Gecko is a little bit shorter on that. Simply
           focus the element and set the selection to a
           specified position
        */ 
        obj.focus(); 
        obj.setSelectionRange(pos, pos); 
    } 
} 
0 голосов
/ 22 июня 2019

В крошечной версии 5

editor.selection.setCursorLocation(editor.getBody(), editor.getBody().childElementCount);
...