Как измерить позицию слова / курсора в 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 ответа:
После долгих размышлений я пришел к выводу, что очень трудно - если вообще возможно - попытаться программно определить положение курсора относительно буквы внутри
<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 теперь. Плохой менеджмент убил его (и меня почти тоже).