简体   繁体   English

如何测量谷歌文档中的单词/插入符号 position?

[英]How to measure word/caret position in Google Docs?

For those who haven't worked with the Google Docs editor here's a short explanation of how it works:对于那些没有使用过 Google 文档编辑器的人,这里有一个关于它如何工作的简短说明:

  • Google Docs has no visible editable textarea or contentEditable elements. Google 文档没有可见的可编辑文本区域或内容可编辑元素。
  • Google Docs listens for keydown/press/up in a separate iFrame where they place the OS cursor for event listening. Google Docs 在单独的 iFrame 中侦听按键/按下/向上,他们将操作系统 cursor 放置在其中以进行事件侦听。
  • When the iFrame catches an event Google handles it by performing the equivalent operations on the visible document.当 iFrame 捕捉到事件时,Google 通过对可见文档执行等效操作来处理它。
  • The "caret" in Google Docs is a DIV that is styled and scripted to look and act like an OS cursor. Google Docs 中的“插入符号”是一个 DIV,其样式和脚本的外观和行为类似于操作系统 cursor。

With that out of the way, here's my request:顺便说一句,这是我的要求:

I'm working on a plugin that interacts with the Google Doc and I need to be able to do two things:我正在开发一个与 Google 文档交互的插件,我需要能够做两件事:

  • Highlight words with an opaque overlay DIV.使用不透明的叠加 DIV 突出显示单词。
  • Determine cursor position inside a word.判断一个词里面的cursor position。

I've been exhausting a lot of ideas about just how to handle this, but so far I've only manage to get a buggy solution for the latter problem (I perform a backspace, determine where the text changed and undo the backspace).关于如何处理这个问题,我已经用尽了很多想法,但到目前为止,我只设法为后一个问题找到了一个有缺陷的解决方案(我执行退格,确定文本更改的位置并撤消退格)。

I'm looking for all the best ideas you can come up with to solve these problems.我正在寻找您可以提出的所有最佳想法来解决这些问题。 They don't need to be cross browser, but they do need to be able to be turned into something robust that will also handle things such as font size changed mid line.它们不需要跨浏览器,但它们确实需要能够变成健壮的东西,也能处理诸如字体大小更改中线之类的事情。

A little bit of extra info explaining what a Google Doc looks like in HTML:一些额外的信息来解释 HTML 中的 Google 文档是什么样子的:

<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>

After more tinkering I came to the conclusion that it is extremely troublesome - if not impossible - to try and programmatically determine cursor position with regard to a letter inside a <span> , simply because the <span> is the smallest element that is measurable (correct me if I am wrong).经过更多的修改后,我得出的结论是,尝试以编程方式确定 cursor position 关于<span>内的字母是非常麻烦的 - 如果不是不可能的话,仅仅是因为<span>是可测量的最小元素(如果我错了,请纠正我)。

So how to solve the problem?那么如何解决问题呢? Here's what I ended up doing:这是我最终做的:

  • I create an offscreen positioned <div>我创建了一个位于屏幕外的<div>
  • I get the text of the current paragraph ( <div class="kix-paragraphrenderer"> ) - I could get the entire text, but wanted to limit the computational load.我得到了当前段落的文本 ( <div class="kix-paragraphrenderer"> ) - 我可以得到整个文本,但想限制计算负载。
  • I extract each single character of the paragraph by looping through its children in the following way:我通过以下方式遍历其子项来提取段落的每个字符:
    • Loop through linveviews of the paragraph ( <div class="kix-lineview"> )循环段落的 linveviews ( <div class="kix-lineview"> )
    • Get the lineview content ( <div class="kix-lineview-content"> )获取线景内容 ( <div class="kix-lineview-content"> )
    • Loop through text blocks of the lineview content ( <span class="kix-lineview-text-block"> )循环浏览 lineview 内容的文本块 ( <span class="kix-lineview-text-block"> )
    • Loop through <span> 's of the text block遍历文本块的<span>
    • Loop through innerText of the <span>循环遍历<span>innerText
    • I append each character in my offscreen <div> with the currently applied style extracted from style.cssText of the current <span>我 append 我的屏幕外<div>中的每个字符都使用从当前<span>style.cssText中提取的当前应用样式
    • For each character appended I measure the width of the <div> and save this in an array.对于附加的每个字符,我测量<div>的宽度并将其保存在一个数组中。 I now have a position of each single character.我现在每个字符都有一个 position。
  • I measure the position of the cursor relative to my widths and voila - I know where the cursor is positioned in the text.我测量了 cursor 的 position 相对于我的宽度,瞧——我知道 cursor 在文本中的位置。

This is obviously a bit simplied (I left out details about margins and paddings of the different elements), but it covers the idea behind how it's possible to get the cursor position.这显然有点简化(我省略了有关不同元素的边距和填充的详细信息),但它涵盖了如何获得 cursor position 背后的想法。

It works quite well, but there are many pitfalls and a lot of measuring required.它工作得很好,但是有很多陷阱并且需要进行大量测量。 On top of that it's also required to post-parse the text if you want to use it for anything, since tabs, spaces and linebreaks aren't always included in innerText (depending on where these are in the text, Google may or may not make them through positioning of new elements).最重要的是,如果您想将它用于任何事情,还需要对文本进行后解析,因为制表符、空格和换行符并不总是包含在innerText中(取决于它们在文本中的位置,谷歌可能会也可能不会通过定位新元素来制作它们)。

I made something like Kix two years ago Google Docs.两年前我制作了类似 Kix 的 Google Docs。 And for any HTML design and yes, for IE6 too:-) How?对于任何 HTML 设计,是的,对于 IE6 也是如此:-) 如何? All we need is to compute letter absolute position. How?我们只需要计算字母绝对值 position。怎么做? Replace textNode with inline element without layout, that's important, and then use Element.getClientRects I remember I also needed wrap just letter and compute its position via fast and reliable https://developer.mozilla.org/en-US/docs/Web/API/Element.getBoundingClientRect用没有布局的内联元素替换 textNode,这很重要,然后使用 Element.getClientRects 我记得我还需要换行字母并通过快速可靠的 https 计算其position://developer.mozilla.org/en-US/docs/Web /API/Element.getBoundingClientRect

The trick how to detect lines and wraps for home and end keys was based on some vertical heuristic letter position change.如何检测 home 和 end 键的行和换行的技巧是基于一些垂直启发式字母 position 的变化。 Something like if base line is different, than stop caret walking.如果基线不同,则停止插入符号。 It was pretty fast and with any markup and without any caching.它非常快,带有任何标记且没有任何缓存。 Holy grail:)圣杯:)

The only not resolvable problem was justified text, because letters were distributed randomly and spaces between them was not computable.唯一无法解决的问题是对齐文本,因为字母是随机分布的,它们之间的空格是不可计算的。

That project is dead http://webeena.com now.那个项目现在已经死了http://webeena.com Bad management killed it (and me almost too).糟糕的管理扼杀了它(我也差不多)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM