rangy:执行尽可能小的扩展,以便canSurroundContents()= true

时间:2014-01-23 13:35:00

标签: rangy

我正在尝试编写一个辅助函数,将选择范围扩展到range.canSurroundContents() === true的最小可能范围。

在开始这个之前,Rangy库中是否有任何方法可以解决这个问题?

2 个答案:

答案 0 :(得分:2)

这是问题中指定的问题:

  

我正在尝试编写一个辅助函数,将选择范围扩展到range.canSurroundContents()=== true的最小可能范围。

这是一个解决方案:

// Provides the depth of ``descendant`` relative to ``ancestor``
function getDepth(ancestor, descendant) {
    var ret = 0;
    while (descendant !== ancestor) {
        ret++;
        descendant = descendant.parentNode;
        if (!descendant)
            throw new Error("not a descendant of ancestor!");
    }
    return ret;
}


function smallestExpansion() {
    var range = rangy.getSelection().getRangeAt(0);
    if (range.canSurroundContents()) return;

    var common = range.commonAncestorContainer;
    var start_depth = getDepth(common, range.startContainer);
    var end_depth = getDepth(common, range.endContainer);

    while(!range.canSurroundContents()) {
        // In the following branches, we cannot just decrement the depth variables because the setStartBefore/setEndAfter may move the start or end of the range more than one level relative to ``common``. So we need to recompute the depth.
        if (start_depth > end_depth) {
            range.setStartBefore(range.startContainer.parentNode);
            start_depth = getDepth(common, range.startContainer);
        }
        else {
            range.setEndAfter(range.endContainer.parentNode);
            end_depth = getDepth(common, range.endContainer);
        }
    }
}

这是一个fiddle来说明。我忽略了选择可能有多个范围的情况。

更新:我发布的第一个代码在方法上是悲观的,因为它过快地用于共同的祖先。更新的代码逐渐将范围的末尾移动到父元素,直到选择使得节点可以包围范围的内容(即range.canSurroundContents()true)。所以在这样的情况下:

<p>This i|s a <strong>te|st</strong> for selecting text.</p>

其中|符号标记初始区域的开头和结尾。更新的代码将以覆盖s a <strong>test</strong>的区域结束,这足以满足要求(如果您愿意,可以将区域包装在<span>元素中)。旧版本将用于选择所有段落。

我相信通过考虑getDepthsetStartBefore如何移动范围的结尾,我可以避免在每次迭代时调用setEndAfter,但我并没有对此优化感到困扰。

答案 1 :(得分:0)

工作解决方案找到最小共同祖先,并向后工作以尝试使其变小。

var sel = rangy.getSelection(),
    range = sel.getRangeAt(0),
    startNode = range.startContainer,
    endNode = range.endContainer,
    commonAncestor = getCommonAncestor(range);
    range = getSmallestPossibleExpansion(range, commonAncestor, startNode, endNode);

function getRangeContainerElement(range) {
  var container = range.commonAncestorContainer;
  if (container.nodeType == 3) {
    container = container.parentNode;
  }
  return container;
}

function getChildOfAncestor(node, ancestor) {
  if (node.parentNode === ancestor) return node;
  return getChildOfAncestor(node.parentNode, ancestor);
}


function getSmallestPossibleExpansion(range, commonAncestor, startNode, endNode) {
  if (startNode === endNode) {
    if (!range.canSurroundContents()) {
      throw new Error("Sanity Check: startNode = endNOde. This should mean canSurroundContents() == true!");
    }
  } else {
    if (commonAncestor !== endNode) {
      //expand range of endpoint (to right) by including the 'anscestorOrSelf' from endNode that is the child of commonAncestor
      range.setEndAfter(getChildOfAncestor(endNode, commonAncestor));
    }
    if (commonAncestor !== startNode) { //NOTE: NOT ELSE IF!
      //expand range of startNode (to left) by including the 'anscestorOrSelf' from startNode that is the child of commonAncestor
      range.setStartBefore(getChildOfAncestor(startNode, commonAncestor));
    }
  }
  return range;
}

甜。