我想要得到包含的所有的用户选择的元素(如在DOM 2个范围/ MS TextRanges)。
/** @return {Array.<Element>} */
function getSelectedElements() {
var elements = [];
// get elements in the user selection somehow
return elements;
}
我试着按照蒂姆唐氏优良做到这一点的解决了类似的问题 ,以及一些万盎司和MS文档,有些PPK东西。
这种方法基本上是:
限定SelectionLikeObject作为DOM选择或IE选择。
限定RangeLikeObject作为DOM范围或IE的TextRange。
让
containerNode
是一个节点。让
containerElement
是Element。让
containedElements
是一个节点列表。让
elementRange
是RangeLikeObject。我们
selectedRange
是RangeLikeObject。让
selectedElements
是元素的数组。让
element
是一个元素。我们
selection
是一个SelectionLikeObject。设置
selection
从用户的选择。设置
selectedElements
到一个新的数组。对于每一个
selectedRange
的selection
:设置
containerNode
到的共同祖先容器selectedRange
。设置
containerElement
到最接近的元素祖先containerNode
。设置
containedElements
到后裔的名单containerElement
。对于每个
element
在containedElements
:设置
elementRange
的element
。如果边界
elementRange
下降的边界之内selectedRange
:- 按
element
在selectedElements
。
- 按
该DOM分支看起来是这样的:
/**
@param {Document} doc
@return {Array.<Element>}
*/
getSelectedElements.fromDOM = function (doc) {
/** @type {Range} */
var selectedRange;
/** @type {Array.<Element>} */
var selectedElements = [];
/** @type {Node} */
var containerNode;
/** @type {Element} */
var containerElement;
/** @type {NodeList} */
var containedElements;
/** @type {Range} */
var elementRange;
/** @type {Element} */
var element;
/** @type {Selection} */
var selection = doc.defaultView.getSelection();
/** @type {number} */
var rangeCount = selection.rangeCount;
/** @type {number} */
var elementCount;
/** @type {number} */
var i;
// hack for browsers without getRangeAt
// see http://www.quirksmode.org/dom/range_intro.html
if (!selection.getRangeAt) {
selection.getRangeAt = function (i) {
/** @type {Range} */
var range = doc.createRange();
if (i || !selection.anchorNode) {
return range;
}
range.setStart(selection.anchorNode, selection.anchorOffset);
range.setEnd(selection.focusNode, selection.focusOffset);
return range;
};
selection.rangeCount = 1;
}
elementRange = doc.createRange();
for (i = 0; i < rangeCount; ++i) {
selectedRange = selection.getRangeAt(i);
containerNode = selectedRange.commonAncestorContainer;
while (containerNode && containerNode.nodeType != 1) {
containerNode = containerNode.parentNode;
}
if (!containerNode) {
return selectedElements; // something went wrong...
}
containerElement = /** @type {Element} */ containerNode;
containedElements = containerElement.getElementsByTagName('*');
elementCount = containedElements.length;
for (var i = 0; i < elementCount; ++i) {
element = containedElements[i];
elementRange.selectNodeContents(element);
if (elementRange.compareBoundaryPoints(selectedRange.END_TO_START, selectedRange) < 1 &&
elementRange.compareBoundaryPoints(selectedRange.START_TO_END, selectedRange) > -1) {
selectedElements.push(element);
}
}
}
elementRange.detach();
return selectedElements;
};
IE的分支看起来是这样的:
/**
@param {Document} doc
@return {Array.<Element>}
*/
getSelectedElements.fromIE = function (doc) {
// Selection - http://msdn.microsoft.com/en-us/library/ie/dd347133(v=vs.85).aspx
// TextRange - http://msdn.microsoft.com/en-us/library/dd347140(v=vs.85).aspx
// ControlRange - http://msdn.microsoft.com/en-us/library/ie/ms537447(v=vs.85).aspx
/** @type {TextRange|ControlRange} */
var ieRange = doc.selection && doc.selection.createRange();
/** @type {Array.<Element>} */
var selectedElements = [];
/** @type {TextRange} */
var selectedRange;
/** @type {Element} */
var containerElement;
/** @type {NodeList} */
var containedElements;
/** @type {TextRange} */
var elementRange;
/** @type {Element} */
var element;
/** @type {Selection} */
var selection;
/** @type {number} */
var i = -1;
if (ieRange.text === void 0) {
return []; // FIXME: It's a ControlRange, give up.
}
selectedRange = /** @type {TextRange} */ ieRange;
containerElement = selectedRange.parentElement();
containedElements = containerElement.getElementsByTagName('*');
elementRange = doc.body.createTextRange();
while ((element = containedElements[++i])) {
elementRange.moveToElementText(element);
if (elementRange.compareEndPoints("StartToEnd", selectedRange) > -1 &&
elementRange.compareEndPoints("EndToStart", selectedRange) < 1) {
selectedElements.push(element);
}
}
return /** @type {Array.<Element>} */ selectedElements;
};
现在,我要解决的问题是这样的:如果选择只在元素中的文本的一部分,它出现在返回的数组中,即使只有部分选中 。
我想补充一点,改变行为只包括完全选择元件的参数。 我有一种感觉,答案在于compareBoundaryPoints,我只是不明白它不够好弄明白呢。
此外,IE的代码是未经测试,到目前为止,但请让我知道是否有任何不妥的地方(或DOM分支)。