var SelectionUtils = {};
/**
* Returns an object with 2 properties: a boolean value indicating if #child was found in the currently iterating
* set of child nodes, and an integer value representing how many characters of textContent were examined in that same
* iteration.
* @private
* @param {Node} child
* @param {Node} container
* @returns {{offset: number, found: boolean}}
*/
SelectionUtils.getCharacterCountToNodeRecursive = function(child, container){
var response = {
offset : 0,
found : false
};
var current = container.firstChild;
loop: while(current){
if(current == child){
response.found = true;
break;
}
switch(current.nodeType){
case 3 :
response.offset += current.textContent.length;
break;
case 1 :
var childResponse = arguments.callee(child, current);
response.offset += childResponse.offset;
if(childResponse.found){
response.found = true;
break loop;
}
break;
}
current = current.nextSibling;
}
return response;
};
/**
* Returns the number of characters of text content preceding #child, in #container.
* @param {Node} child
* @param {Node} container
* @returns {number}
*/
SelectionUtils.getCharacterCountToNode = function(child, container){
container = container || document.body;
if(!container.contains(child)){
throw new Error('child must be descendant of container');
}
return SelectionUtils.getCharacterCountToNodeRecursive(child, container).offset;
};
/**
* Convenience method to count the number of characters of text content to the start of the current selection.
* @param range
* @param container
* @returns {number}
*/
SelectionUtils.getSelectionStartOffset = function(range, container){
return range.startOffset + SelectionUtils.getCharacterCountToNode(range.startContainer, container);
};
/**
* Convenience method to count the number of characters of text content to the end of the current selection.
* @param range
* @param container
* @returns {number}
*/
SelectionUtils.getSelectionEndOffset = function(range, container){
return range.endOffset + SelectionUtils.getCharacterCountToNode(range.endContainer, container);
};
----
{{:javascript:position:css_-_content_editable.png?800|}}