【问题标题】:Get selection's offset relative to certain parent node获取选择相对于某个父节点的偏移量
【发布时间】:2014-02-15 22:46:01
【问题描述】:

我希望能够找出用户在网页中选择的文本(突出显示)相对于特定父节点的位置(也称为:偏移量、索引)。

我一直在使用Rangy 来帮助我,但它似乎没有内置到 API 中的偏移属性。这是我目前所拥有的:

function GetSelectionIndexRelativeTo(parentNodeId) 
{
    var parentNode = document.getElementById(parentNodeId);

    var txt = rangy.getSelection().toString();
    var code = rangy.getSelection().toHtml();
    var len = code.length;

    var x1 =         ;       // THIS IS WHAT I REALLY WANT. WHAT DO I DO?
    var x2 = x1 + len;

    return {
        text: txt,
        html: code,
        start: x1,
        end: x2,
        length: len
    }
}

举几个例子:

PAGETEXT:      <poem><title>Galaxy</title>Twinkle Twinkle Little Star</poem>

1. SELECTION:  Galaxy
   RELATIVETO: title
   RESULT:     start = 0

2. SELECTION:  Star
   RELATIVETO: poem
   RESULT:     start = 43

3. SELECTION:  Twinkle (the second one)
   RELATIVETO: poem
   RESULT:     start = 28

【问题讨论】:

  • 您为什么要尝试捕获这些偏移量?你想用它们做什么?
  • 我想让用户选择一首诗中的某些单词并添加注释。我想将每个注释保存为元组 .

标签: javascript jquery text selection rangy


【解决方案1】:

在您对我的评论的回答中,您表示这是目标:

我想允许用户选择一首诗中的某些单词并添加注释。我想将每个注释保存为一个元组。

鉴于此目标,我不会使用您在问题中提出的方法。我用过几种方法来保存范围。哪一个适合您取决于您​​的项目的具体情况。

使用 Rangy 的选择保存和恢复模块

记录在案的here。如果需要任何类型的持久性,这将不起作用。如果以任何方式修改 DOM 以删除 Rangy 放入的标记,这也会失败。例如,通过删除它们并重新显示它们来刷新页面上的诗歌的操作将删除标记。例如,如果可以通过关键字动态过滤诗歌,就会发生这种情况。

在手头的情况下不太可能有用。 (在其他情况下很有用。)

使用 Rangy 的序列化模块

记录在案的here。这允许以持久的方式保存选择,并且以这种方式保存的选择将在 DOM 刷新后继续存在。

请注意,在序列化之前存在选择的 DOM 树不能改变结构。如果 DOM 树改变了结构,那么范围可能无法反序列化。 (这要视具体情况而定。)

如果你有这样一首诗:

<poem><title>Galaxy</title>Twinkle Twinkle Little Star</poem>

而且这个结构永远不会改变,那你就没事了。即使某些动态操作通过将诗歌从页面中删除并重新显示来刷新诗歌,只要其结构相同,序列化程序将能够反序列化所选内容。但是,如果您保存选择,然后决定添加这样的作者:

<poem><title>Galaxy</title><author>John Doe</author>Twinkle Twinkle Little Star</poem>

那么结构已经改变,序列化器将无法反序列化。

请注意,序列化程序能够记录与特定元素相关的序列化范围,就像您想要的那样。调用格式如下:

rangy.serializeSelection(sel, false, root)

您会将选择传递为sel。第二个参数设置为false,让序列化程序计算一个校验和,以检测 DOM 是否在序列化和反序列化之间发生了变化。 root 参数将是您想要序列化的元素。

我建议始终使用相同类型的元素来进行序列化和反序列化。选择您关心的最顶层元素。如果您只关心诗歌中的选择,大概是poem。因此,给定诗歌中的所有注释都将针对这首诗歌的 poem 元素进行序列化。

使注释成为您的标记的一部分

如果您将来需要能够更改数据结构,那么您必须将注释作为标记的一部分,因此如果 Bob 添加注释,您可以这样编码:

<poem><title>Galaxy</title>Twinkle Twinkle <ann-start ann="#ANN.1"/>Little Star<ann-end ann="#ANN.1"/></poem>
<ann id="ANN.1" creator="Bob">In private correspondence, the author referred to his daughter as his "Little Star"</ann>

(以上假设是 XML 符号,仅用于说明目的。完整的解决方案会做一些不同的事情。)

在文本中使用&lt;ann-start&gt; 标记开始和&lt;ann-end&gt; 标记结束是必要的,因为注释可以跨越其他注释或标记结构,但XML(和HTML)不允许标签跨越。 ann 属性是一个 ID 引用,指示 ann-startann-end 元素属于哪个注释。

通过让注释成为它们所引用的数据的一部分,您可以随意更改结构。所以添加这样的作者:

<poem><title>Galaxy</title><author>John Doe</author>Twinkle Twinkle <ann-start ann="#ANN.1"/>Little Star<ann-end ann="#ANN.1"/></poem>
<ann id="ANN.1" creator="Bob">In private correspondence, the author referred to his daughter as his "Little Star"</ann>

这不是问题,因为您的应用程序仍然可以找到注释的开始和结束。

为什么不是问题中提出的方法?

因为它极其脆弱。让我们以给出的第三个例子为例:

PAGETEXT:      <poem><title>Galaxy</title>Twinkle Twinkle Little Star</poem>

3. SELECTION:  Twinkle (the second one)
   RELATIVETO: poem
   RESULT:     start = 28

如果发生以下任何一种情况,偏移量28 将不正确:

  • 在注释开始之前发现了一个错字,并修正了诗歌的文本。

  • 应用程序的开发人员决定显示更多信息并更改诗歌的结构。例如,如上图,在标题后添加作者姓名。

  • 标记已更改以支持更多功能。例如,如果需要使用超链接引用标题:

    <poem><title id="...">Galaxy</title>Twinkle Twinkle Little Star</poem>
    

一旦添加id,偏移量就会变得不正确。其他示例包括脚注、样式(对于一次性的情况,使用样式表没有意义)、语言信息(这首诗是英文的,但诗人决定使用法语单词作为标题)。

【讨论】:

  • 如果我将注释作为标记的一部分——使用您描述的 ann-start/ann-end 方案——我如何向用户显示这样的范围有注释?如果它是一个常规的 xml/html 样式标签,我可以以某种方式对其进行样式设置或转换。但是像这样,我怎样才能让带注释的范围对用户可见?
  • 我建议将此问题作为一个新问题提出,主要是因为评论太小而无法提供答案。
猜你喜欢
  • 2012-07-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-11-22
  • 1970-01-01
  • 2014-08-03
  • 1970-01-01
相关资源
最近更新 更多