我試圖編寫一個幫助函數,將選擇範圍擴大到最小可能的範圍,其中range.canSurroundContents() === true
。rangy:執行儘可能小的擴展,以便canSurroundContents()= true
在開始之前,Rangy庫中是否有任何方法可以做到這一點,我忽略了這一點?
我試圖編寫一個幫助函數,將選擇範圍擴大到最小可能的範圍,其中range.canSurroundContents() === true
。rangy:執行儘可能小的擴展,以便canSurroundContents()= true
在開始之前,Rangy庫中是否有任何方法可以做到這一點,我忽略了這一點?
這是問題的規定的問題:
我試圖寫一個可擴展的選擇到儘可能小的範圍,這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>
元素中)。舊版本會去選擇所有的段落。
我相信通過考慮setStartBefore
和setEndAfter
如何移動範圍的末端,我們可以避免在每次迭代中調用getDepth
,但我沒有爲這種優化而煩惱。
工作解決方案找到最不常見的祖先,並向後工作以嘗試使其更小。
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;
}
甜。
是的,這很好。爲了提供我已經實施的替代解決方案,請參閱我的更新答案。 –