Как измерить позицию слова / курсора в Google Docs?


Для тех, кто не работал с редактором Google Docs, вот краткое объяснение того, как он работает:

    В Google Docs нет видимых редактируемых текстовых областей или элементов contentEditable.
  • Google Docs прослушивает keydown / press/up в отдельном iFrame, где они помещают курсор ОС для прослушивания событий.
  • Когда iFrame ловит событие, Google обрабатывает его, выполняя эквивалентные операции с видимым документом.
  • "каретка" в Google Docs-это DIV это стиль и сценарий, чтобы выглядеть и действовать как курсор операционной системы.

С этим покончено, вот моя просьба:

Я работаю над плагином, который взаимодействует с Google Doc, и мне нужно уметь делать две вещи:

  • выделите слова с непрозрачным наложением DIV.
  • определите положение курсора внутри слова.

Я исчерпал множество идей о том, как справиться с этим, но пока мне удалось получить только ошибочное решение для последнего проблема (я выполняю backspace, определяю, где текст изменился, и отменяю backspace).

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

Немного дополнительной информации, объясняющей, как выглядит Google Doc в HTML:

<wrapper> // Simplified wrapper containing margins, pagination and similar
  <div class="kix-paragraphrenderer"> // single DIV per page wrapping all content
    // Multiple paragraphs separated by linebreak created by Enter key:
    <div class="kix-paragraphrendeder">...</div>
    <div class="kix-paragraphrendeder">...</div>
    <div class="kix-paragraphrendeder">
      // Multiple wrapper divs created by Google's word wrapping:
      <div class="kix-lineview">...</div>
      <div class="kix-lineview">...</div>
      <div class="kix-lineview">
        // Single inner wrapper, still full width of first wrapper paragraph:
        <div class="kix-lineview-content">
          // Single wrapper SPAN containing full text of the line, but not display:block
          <span class="kix-lineview-text-block">
            // Multiple spans, one per new font change such as normal/bold text,
              // change in font size, indentation and similar:
            <span>This is normal text</span>
            <span style="font-size:40px; padding-left:4px;">This larger text.</span>
            <span style="font-weight:bold; padding-left:10px;">This is bold text</span>
            <span style="padding-left:4px;">More normal text</span>
          </span>
        </div>
      </div>
    </div>
  </div>
</wrapper>
2 2

2 ответа:

После долгих размышлений я пришел к выводу, что очень трудно - если вообще возможно - попытаться программно определить положение курсора относительно буквы внутри <span>, просто потому, что <span> является наименьшим измеряемым элементом (поправьте меня, если я ошибаюсь).

Так как же решить эту проблему? Вот что я в итоге сделал:

  • я создаю закадровое Изображение <div>
  • я получаю текст текущего абзаца (<div class="kix-paragraphrenderer">) - I можно было получить весь текст целиком, но хотелось ограничить вычислительную нагрузку.
  • я извлекаю каждый отдельный символ абзаца, прокручивая его дочерние элементы следующим образом:
    • цикл через linveviews абзаца (<div class="kix-lineview">)
    • получить содержимое lineview(<div class="kix-lineview-content">)
    • цикл через текстовые блоки содержимого lineview (<span class="kix-lineview-text-block">)
    • цикл через <span> ' s текстового блока
    • цикл через innerText из <span>
    • я добавляю каждый символ в мой закадровый экран <div> с текущим применяемым стилем, извлеченным из style.cssText текущего <span>
    • для каждого добавляемого символа я измеряю ширину <div> и сохраняю ее в массиве. Теперь у меня есть позиция каждого отдельного персонажа.
  • Я измеряю положение курсора относительно моей ширины и вуаля-я знаю, где курсор расположен в тексте.

Это, очевидно, немного упрощено (я опустил детали о полях и paddings of the different elements), но он охватывает идею о том, как можно получить положение курсора.

Это работает довольно хорошо, но есть много подводных камней и требуется много измерений. Кроме того, если вы хотите использовать его для чего-либо, вам также необходимо выполнить пост-синтаксический анализ текста, поскольку вкладки, пробелы и прерывания линий не всегда включены в innerText (в зависимости от того, где они находятся в тексте, Google может сделать или не сделать их путем размещения новых элементов).

Я сделал что-то вроде Kix два года назад Google Docs. И для любого HTML дизайна и да, для IE6 тоже : -) как? Все, что нам нужно, это вычислить абсолютное положение буквы. Но как? Замените textNode встроенным элементом без макета, это важно,а затем используйте элемент.getClientRects я помню, что мне также нужно было обернуть только букву и вычислить ее положение с помощью быстрого и надежного https://developer.mozilla.org/en-US/docs/Web/API/Element.getBoundingClientRect

Трюк, как обнаружить линии а обертывание для ключей home и end основывалось на некотором вертикальном эвристическом изменении положения букв. Что-то вроде, если базовая линия отличается, чем остановить каре ходить. Это было довольно быстро и с любой разметкой и без какого-либо кэширования. Святой Грааль:)

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

Этот проект мертв http://webeena.com теперь. Плохой менеджмент убил его (и меня почти тоже).