2014-01-23 64 views

回答

2

這是問題的規定的問題:

我試圖寫一個可擴展的選擇到儘可能小的範圍,這range.canSurroundContents()===真helperfunction。

這裏有一個解決方案:

// 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>元素中)。舊版本會去選擇所有的段落。

我相信通過考慮setStartBeforesetEndAfter如何移動範圍的末端,我們可以避免在每次迭代中調用getDepth,但我沒有爲這種優化而煩惱。

+0

是的,這很好。爲了提供我已經實施的替代解決方案,請參閱我的更新答案。 –

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

甜。