如何衡量Google文档中的单词/插入符号位置?

时间:2012-04-10 15:37:24

标签: javascript google-docs html caret cursor-position

对于那些没有使用过Google文档编辑器的人,这里有一个简短的解释:

  • Google文档没有可见的可编辑textarea或contentEditable元素。
  • Google Docs会在单独的iFrame中侦听keydown / press / up,他们会将操作系统光标放在事件监听位置。
  • 当iFrame捕获事件时,Google会通过对可见文档执行等效操作来处理它。
  • Google文档中的“插入符号”是一个DIV,其样式和脚本的外观和行为类似于操作系统光标。

有了这个,这是我的要求:

我正在开发一个与Google Doc交互的插件,我需要做两件事:

  • 突出显示带有不透明叠加的单词DIV。
  • 确定单词内的光标位置。

我一直在讨论如何处理这个问题的很多想法,但到目前为止,我只是设法为后一个问题找到一个错误的解决方案(我执行退格,确定文本更改的位置并撤消退格键)。

我正在寻找你能解决这些问题的所有最好的想法。它们不需要跨浏览器,但它们确实需要能够变成强大的东西,这些东西也可以处理诸如中线改变的字体大小之类的东西。

一些额外的信息,解释了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 个答案:

答案 0 :(得分:4)

经过更多的修改后,我得出的结论是,尝试以编程方式确定<span>内部字母的光标位置是非常麻烦的 - 如果不是不可能的话,只是因为<span>是可测量的最小元素(如果我错了,请纠正我)。

那么如何解决问题呢?这就是我最终做的事情:

  • 我创建了一个位于<div>
  • 的屏幕
  • 我得到当前段落的文本(<div class="kix-paragraphrenderer">) - 我可以获得整个文本,但是想限制计算负荷。
  • 我通过以下方式循环遍历其子句来提取段落的每个单个字符:
    • 循环显示段落(<div class="kix-lineview">
    • 的视图
    • 获取线视图内容(<div class="kix-lineview-content">
    • 循环浏览线视图内容(<span class="kix-lineview-text-block">
    • 的文本块
    • 循环显示文本块的<span>
    • 循环浏览innerText
    • <span>
    • 我在屏幕外<div> 中添加了每个字符,其中包含从当前style.cssText
    • <span>中提取的当前应用的样式
    • 对于每个附加的字符,我测量<div>的宽度并将其保存在数组中。我现在每个角色都有一个位置。
  • 我测量光标相对于我的宽度的位置和瞧 - 我知道光标在文本中的位置。

这显然有点简单(我省略了有关不同元素的边距和填充的细节),但它涵盖了如何获得光标位置背后的想法。

它运作良好,但存在许多陷阱和需要大量测量。最重要的是,如果您想将其用于任何内容,还需要对文本进行后期解析,因为标签,空格和换行符并不总是包含在innerText中(具体取决于文本中的位置,Google可能会也可能不会通过定位新元素来实现它们。)

答案 1 :(得分:0)

我两年前制作了类似Kix的文档Google Docs。对于任何HTML设计,是的,对于IE6也是如此:-)怎么样?我们所需要的只是计算字母绝对位置。怎么样?将textNode替换为没有布局的内联元素,这很重要,然后使用Element.getClientRects我记得我还需要包装正文并通过快速可靠的https://developer.mozilla.org/en-US/docs/Web/API/Element.getBoundingClientRect

计算其位置

如何检测主键和结束键的行和换行的技巧是基于一些垂直启发式字母位置更改。像基线不同的东西,比停止插入符号。它非常快,任何标记,没有任何缓存。圣杯:)

唯一无法解决的问题是合理的文本,因为字母是随机分布的,它们之间的空格是不可计算的。

现在这个项目已经死了http://webeena.com。糟糕的管理层杀了它(我几乎也是这样)。