Подтвердить что ты не робот

JavaScript "contenteditable" - Получение/настройка позиции Caret

Я прочитал несколько сообщений о размещении каретки, но никто, кажется, не ответил на мою конкретную проблему.

  • У меня есть 2 divs (div1 и div2)
  • div1= uneditable div
  • div2= contenteditable div
  • оба divs содержат точное содержимое
  • когда пользователь нажимает div1, он скрывается, а div2 отображается в точном месте, и пользователь может редактировать

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

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

Как это сделать?

Спасибо -

4b9b3361

Ответ 1

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

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

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

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

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

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

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

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

Ответ 2

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

Ответ 3

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

$('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);
});

теперь просто нужен метод get/set caret:)

edit > вот моя собственная, (живая демонстрация)

        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);
        }

Ответ 4

Похоже, вы пытаетесь сделать встроенное редактирование... посмотрели ли вы на jeditable плагин?

Ответ 5

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

Ответ 6

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