获取相对于某个父节点的选择偏移量

时间:2014-02-15 22:46:02

标签: javascript jquery text selection rangy

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

我一直在使用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

1 个答案:

答案 0 :(得分:4)

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

  

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

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

使用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表示法,仅用于说明目的。完整的解决方案可以做一些不同的事情。)

<ann-start>标记开头,<ann-end>标记文本中注释的结尾是必要的,因为注释可能跨越其他注释或标记结构,但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后,偏移量就会变得不正确。其他的例子是脚注,造型(对于一次性案例,使用sytlesheet没有意义),语言信息(这首诗用英语写,但诗人决定用法语单词作为标题)。