JavaScript «contenteditable» - получение / установка позиции каретки - PullRequest
14 голосов
/ 16 мая 2010

Я прочитал несколько постов о позиционировании каретки, но ни один из них не отвечает на мой конкретный вопрос.

  1. У меня есть 2 div ( div1 и div2 )
  2. div1 = не редактируемый div
  3. div2 = contenteditable div
  4. оба элемента содержат одно и то же содержимое
  5. когда пользователь нажимает div1 , он скрывается, и div2 появляется в точном месте, и пользователь может редактировать

Проблема : я хочу, чтобы каретка отображалась в точном месте на div2 как div1

Итак, мне нужен какой-то способ ЧИТАТЬ место, где пользователь нажимает на div1, а затем, когда появляется div2, поместить курсор / каретку в то же место, поэтому getCaretLocation (in_div_id) и setCaretLocation (in_div_id) набор функций.

Есть ли способ сделать это?

Спасибо -

Ответы [ 6 ]

7 голосов
/ 16 мая 2010

Краткий ответ : Вы не можете

Длинный ответ : Проблема, с которой вы столкнетесь, заключается в том, что вы сможете получить (x, y) координаты для события click на div1, но любая реализация положения каретки требует от вас зная положение каретки в контенте (количество символов, предшествующих каретке).

Чтобы преобразовать координаты (x, y) в позицию символа, вам на самом деле нужно знать, сколько символов было раньше (т. Е. Осталось в текущей строке и выше, если текст ltr).

Если вы используете шрифт фиксированной ширины, вы можете упростить задачу: сопоставить координату (x, y) с координатой (строка, столбец) в символьной сетке.

Однако вы все еще сталкиваетесь с проблемой незнания того, как переносится текст. Например:

------------------
|Lorem ipsum     |
|dolor sit amet  |
|consectetur     |
|adipiscing elit |
------------------

Если пользователь нажимает на d в dolor , вы знаете, что символ находится на 1-й строке во 2-й строке, но без знания алгоритма переноса вы не сможете Вы узнаете, что это 13-й персонаж в «Lorem ipsum dolor sit…». И нет никакой гарантии, что такой алгоритм упаковки одинаков для всех браузеров и платформ.

Теперь, что мне интересно, зачем вам использовать 2 разных синхронизированных div в первую очередь? Разве не было бы проще использовать только один div и установить его содержимое для редактирования, когда пользователь нажимает (или наводит курсор)?

1 голос
/ 17 декабря 2012

вы можете, в основном вам нужно установить временный контент, редактируемый на вашем первом div, чтобы поймать знак вставки

$('div1').hover(function()
{ $(this).attr('contenteditable','true');
},function()
{ $(this).removeAttr('contenteditable');
}).mouseup(function()
{   var t = $(this);
    // get caret position and remove content editable
    var caret = t.getCaret();
    t.removeAttr('contenteditable');
    // do your div switch stuff
    ...
    // and apply saved caret position
    $('div2').setCaret(caret);
});

теперь просто нужно получить / установить метод вставки:)

edit> вот мое собственное, ( live демо )

        getSelection:function($e)
        {   if(undefined === window.getSelection) return false;
            var range = window.getSelection().getRangeAt(0);

            function getTreeOffset($root,$node)
            {   if($node.parents($root).length === 0) return false; // is node child of root ?
                var tree = [], treesize = 0;
                while(1)
                {   if($node.is($root)) break;
                    var index, $parent = $node.parent();
                    index = $parent.contents().index($node);
                    if(index !== -1) { tree[treesize++] = index; } $node = $parent;
                };  return tree.reverse();
            }

            var start = getTreeOffset($e,$(range.startContainer));
            var end   = getTreeOffset($e,$(range.endContainer));

            if(start & end === false) return false;

            return {start:start,end:end,startOffset:range.startOffset,endOffset:range.endOffset};
        }, setSelection:function($e,s,win)
        {   $e.focus(); if(s === false) return; var sel = win.getSelection(); sel.removeAllRanges();

            function getNode($e,s)
            {   var node = $e;
                for( var n=0;n<s.length;n++ )
                {   var index = s[n]; if(index < 0) break;
                    node = node.contents(':eq('+index+')');
                }   return node.get(0);
            }

            var start = getNode($e,s.start), end = getNode($e,s.end), range = win.document.createRange();
            range.setStart(start,s.startOffset); range.setEnd(end,s.endOffset); sel.addRange(range);
        }
1 голос
/ 01 февраля 2011

Вы можете вставить крошечный элемент span в каретку, получить его положение и удалить его. Для кросс-браузерного диапазона и библиотеки выбора см. rangy .

0 голосов
/ 19 декабря 2013

Считайте позицию каретки в тексте и затем установите позицию каретки в окне редактирования.

0 голосов
/ 15 июня 2012

Когда вы щелкаете по элементу, создается объект Selection с нулевой длиной (получите его из element.getSelection (), где element - это рассматриваемый div). FocusOffset этого объекта сообщит вам, например, что вы щелкнули, например, по 74-му символу в этом div (это то, что, по словам Адриена, было невозможно в другом ответе).

0 голосов
/ 17 мая 2010

Звучит так, будто вы пытаетесь выполнить встроенное редактирование ... Вы смотрели на плагин jeditable ?

...