Blame | Last modification | View Log | RSS feed
if(!dojo._hasResource["dijit._editor.range"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.dojo._hasResource["dijit._editor.range"] = true;dojo.provide("dijit._editor.range");dijit.range={};dijit.range.getIndex=function(/*DomNode*/node, /*DomNode*/parent){// dojo.profile.start("dijit.range.getIndex");var ret=[], retR=[];var stop = parent;var onode = node;while(node != stop){var i = 0;var pnode = node.parentNode, n;while(n=pnode.childNodes[i++]){if(n===node){--i;break;}}if(i>=pnode.childNodes.length){dojo.debug("Error finding index of a node in dijit.range.getIndex");}ret.unshift(i);retR.unshift(i-pnode.childNodes.length);node = pnode;}//normalized() can not be called so often to prevent//invalidating selection/range, so we have to detect//here that any text nodes in a rowif(ret.length>0 && onode.nodeType==3){var n = onode.previousSibling;while(n && n.nodeType==3){ret[ret.length-1]--;n = n.previousSibling;}n = onode.nextSibling;while(n && n.nodeType==3){retR[retR.length-1]++;n = n.nextSibling;}}// dojo.profile.end("dijit.range.getIndex");return {o: ret, r:retR};}dijit.range.getNode = function(/*Array*/index, /*DomNode*/parent){if(!dojo.isArray(index) || index.length==0){return parent;}var node = parent;// if(!node)debuggerdojo.every(index, function(i){if(i>=0&&i< node.childNodes.length){node = node.childNodes[i];}else{node = null;console.debug('Error: can not find node with index',index,'under parent node',parent );return false; //terminate dojo.every}return true; //carry on the every loop});return node;}dijit.range.getCommonAncestor = function(n1,n2,root){var getAncestors = function(n,root){var as=[];while(n){as.unshift(n);if(n!=root && n.tagName!='BODY'){n = n.parentNode;}else{break;}}return as;};var n1as = getAncestors(n1,root);var n2as = getAncestors(n2,root);var m = Math.min(n1as.length,n2as.length);var com = n1as[0]; //at least, one element should be in the array: the root (BODY by default)for(var i=1;i<m;i++){if(n1as[i]===n2as[i]){com = n1as[i]}else{break;}}return com;}dijit.range.getAncestor = function(/*DomNode*/node, /*RegEx?*/regex, /*DomNode?*/root){root = root || node.ownerDocument.body;while(node && node !== root){var name = node.nodeName.toUpperCase() ;if(regex.test(name)){return node;}node = node.parentNode;}return null;}dijit.range.BlockTagNames = /^(?:P|DIV|H1|H2|H3|H4|H5|H6|ADDRESS|PRE|OL|UL|LI|DT|DE)$/;dijit.range.getBlockAncestor = function(/*DomNode*/node, /*RegEx?*/regex, /*DomNode?*/root){root = root || node.ownerDocument.body;regex = regex || dijit.range.BlockTagNames;var block=null, blockContainer;while(node && node !== root){var name = node.nodeName.toUpperCase() ;if(!block && regex.test(name)){block = node;}if(!blockContainer && (/^(?:BODY|TD|TH|CAPTION)$/).test(name)){blockContainer = node;}node = node.parentNode;}return {blockNode:block, blockContainer:blockContainer || node.ownerDocument.body};}dijit.range.atBeginningOfContainer = function(/*DomNode*/container, /*DomNode*/node, /*Int*/offset){var atBeginning = false;var offsetAtBeginning = (offset == 0);if(!offsetAtBeginning && node.nodeType==3){ //if this is a text node, check whether the left part is all spaceif(dojo.trim(node.nodeValue.substr(0,offset))==0){offsetAtBeginning = true;}}if(offsetAtBeginning){var cnode = node;atBeginning = true;while(cnode && cnode !== container){if(cnode.previousSibling){atBeginning = false;break;}cnode = cnode.parentNode;}}return atBeginning;}dijit.range.atEndOfContainer = function(/*DomNode*/container, /*DomNode*/node, /*Int*/offset){var atEnd = false;var offsetAtEnd = (offset == (node.length || node.childNodes.length));if(!offsetAtEnd && node.nodeType==3){ //if this is a text node, check whether the right part is all spaceif(dojo.trim(node.nodeValue.substr(offset))==0){offsetAtEnd = true;}}if(offsetAtEnd){var cnode = node;atEnd = true;while(cnode && cnode !== container){if(cnode.nextSibling){atEnd = false;break;}cnode = cnode.parentNode;}}return atEnd;}dijit.range.adjacentNoneTextNode=function(startnode, next){var node = startnode;var len = (0-startnode.length) || 0;var prop = next?'nextSibling':'previousSibling';while(node){if(node.nodeType!=3){break;}len += node.lengthnode = node[prop];}return [node,len];}dijit.range._w3c = Boolean(window['getSelection']);dijit.range.create = function(){if(dijit.range._w3c){return document.createRange();}else{//IEreturn new dijit.range.W3CRange;}}dijit.range.getSelection = function(win, /*Boolean?*/ignoreUpdate){if(dijit.range._w3c){return win.getSelection();}else{//IEvar id=win.__W3CRange;if(!id || !dijit.range.ie.cachedSelection[id]){var s = new dijit.range.ie.selection(win);//use win as the key in an object is not reliable, which//can leads to quite odd behaviors. thus we generate a//string and use it as a key in the cacheid=(new Date).getTime();while(id in dijit.range.ie.cachedSelection){id=id+1;}id=String(id);dijit.range.ie.cachedSelection[id] = s;}else{var s = dijit.range.ie.cachedSelection[id];}if(!ignoreUpdate){s._getCurrentSelection();}return s;}}if(!dijit.range._w3c){dijit.range.ie={cachedSelection: {},selection: function(win){this._ranges = [];this.addRange = function(r, /*boolean*/internal){this._ranges.push(r);if(!internal){r._select();}this.rangeCount = this._ranges.length;};this.removeAllRanges = function(){//don't detach, the range may be used later// for(var i=0;i<this._ranges.length;i++){// this._ranges[i].detach();// }this._ranges = [];this.rangeCount = 0;};var _initCurrentRange = function(){var r = win.document.selection.createRange();var type=win.document.selection.type.toUpperCase();if(type == "CONTROL"){//TODO: multiple range selection(?)return new dijit.range.W3CRange(dijit.range.ie.decomposeControlRange(r));}else{return new dijit.range.W3CRange(dijit.range.ie.decomposeTextRange(r));}};this.getRangeAt = function(i){return this._ranges[i];};this._getCurrentSelection = function(){this.removeAllRanges();var r=_initCurrentRange();if(r){this.addRange(r, true);}};},decomposeControlRange: function(range){var firstnode = range.item(0), lastnode = range.item(range.length-1)var startContainer = firstnode.parentNode, endContainer = lastnode.parentNode;var startOffset = dijit.range.getIndex(firstnode, startContainer).o;var endOffset = dijit.range.getIndex(lastnode, endContainer).o+1;return [[startContainer, startOffset],[endContainer, endOffset]];},getEndPoint: function(range, end){var atmrange = range.duplicate();atmrange.collapse(!end);var cmpstr = 'EndTo' + (end?'End':'Start');var parentNode = atmrange.parentElement();var startnode, startOffset, lastNode;if(parentNode.childNodes.length>0){dojo.every(parentNode.childNodes, function(node,i){var calOffset;if(node.nodeType != 3){atmrange.moveToElementText(node);if(atmrange.compareEndPoints(cmpstr,range) > 0){startnode = node.previousSibling;if(lastNode && lastNode.nodeType == 3){//where share we put the start? in the text node or after?startnode = lastNode;calOffset = true;}else{startnode = parentNode;startOffset = i;return false;}}else{if(i==parentNode.childNodes.length-1){startnode = parentNode;startOffset = parentNode.childNodes.length;return false;}}}else{if(i==parentNode.childNodes.length-1){//at the end of this nodestartnode = node;calOffset = true;}}// try{if(calOffset && startnode){var prevnode = dijit.range.adjacentNoneTextNode(startnode)[0];if(prevnode){startnode = prevnode.nextSibling;}else{startnode = parentNode.firstChild; //firstChild must be a text node}var prevnodeobj = dijit.range.adjacentNoneTextNode(startnode);prevnode = prevnodeobj[0];var lenoffset = prevnodeobj[1];if(prevnode){atmrange.moveToElementText(prevnode);atmrange.collapse(false);}else{atmrange.moveToElementText(parentNode);}atmrange.setEndPoint(cmpstr, range);startOffset = atmrange.text.length-lenoffset;return false;}// }catch(e){ debugger }lastNode = node;return true;});}else{startnode = parentNode;startOffset = 0;}//if at the end of startnode and we are dealing with start container, then//move the startnode to nextSibling if it is a text node//TODO: do this for end container?if(!end && startnode.nodeType!=3 && startOffset == startnode.childNodes.length){if(startnode.nextSibling && startnode.nextSibling.nodeType==3){startnode = startnode.nextSibling;startOffset = 0;}}return [startnode, startOffset];},setEndPoint: function(range, container, offset){//text nodevar atmrange = range.duplicate();if(container.nodeType!=3){ //normal nodeatmrange.moveToElementText(container);atmrange.collapse(true);if(offset == container.childNodes.length){if(offset > 0){//a simple atmrange.collapse(false); won't work here://although moveToElementText(node) is supposed to encompass the content of the node,//but when collapse to end, it is in fact after the ending tag of node (collapse to start//is after the begining tag of node as expected)var node = container.lastChild;var len = 0;while(node && node.nodeType == 3){len += node.length;container = node; //pass throughnode = node.previousSibling;}if(node){atmrange.moveToElementText(node);}atmrange.collapse(false);offset = len; //pass through}else{ //no childNodesatmrange.moveToElementText(container);atmrange.collapse(true);}}else{if(offset > 0){var node = container.childNodes[offset-1];if(node.nodeType==3){container = node;offset = node.length;//pass through}else{atmrange.moveToElementText(node);atmrange.collapse(false);}}}}if(container.nodeType==3){var prevnodeobj = dijit.range.adjacentNoneTextNode(container);var prevnode = prevnodeobj[0], len = prevnodeobj[1];if(prevnode){atmrange.moveToElementText(prevnode);atmrange.collapse(false);//if contentEditable is not inherit, the above collapse won't make the end point//in the correctly position: it always has a -1 offset, so compensate itif(prevnode.contentEditable!='inherit'){len++;}}else{atmrange.moveToElementText(container.parentNode);atmrange.collapse(true);}offset += len;if(offset>0){if(atmrange.moveEnd('character',offset) != offset){alert('Error when moving!');}atmrange.collapse(false);}}return atmrange;},decomposeTextRange: function(range){var tmpary = dijit.range.ie.getEndPoint(range);var startContainter = tmpary[0], startOffset = tmpary[1];var endContainter = tmpary[0], endOffset = tmpary[1];if(range.htmlText.length){if(range.htmlText == range.text){ //in the same text nodeendOffset = startOffset+range.text.length;}else{tmpary = dijit.range.ie.getEndPoint(range,true);endContainter = tmpary[0], endOffset = tmpary[1];}}return [[startContainter, startOffset],[endContainter, endOffset], range.parentElement()];},setRange: function(range, startContainter,startOffset, endContainter, endOffset, check){var startrange = dijit.range.ie.setEndPoint(range, startContainter, startOffset);range.setEndPoint('StartToStart', startrange);if(!this.collapsed){var endrange = dijit.range.ie.setEndPoint(range, endContainter, endOffset);range.setEndPoint('EndToEnd', endrange);}return range;}}dojo.declare("dijit.range.W3CRange",null, {constructor: function(){if(arguments.length>0){this.setStart(arguments[0][0][0],arguments[0][0][1]);this.setEnd(arguments[0][1][0],arguments[0][1][1],arguments[0][2]);}else{this.commonAncestorContainer = null;this.startContainer = null;this.startOffset = 0;this.endContainer = null;this.endOffset = 0;this.collapsed = true;}},_simpleSetEndPoint: function(node, range, end){var r = (this._body||node.ownerDocument.body).createTextRange();if(node.nodeType!=1){r.moveToElementText(node.parentNode);}else{r.moveToElementText(node);}r.collapse(true);range.setEndPoint(end?'EndToEnd':'StartToStart',r);},_updateInternal: function(__internal_common){if(this.startContainer !== this.endContainer){if(!__internal_common){var r = (this._body||this.startContainer.ownerDocument.body).createTextRange();this._simpleSetEndPoint(this.startContainer,r);this._simpleSetEndPoint(this.endContainer,r,true);__internal_common = r.parentElement();}this.commonAncestorContainer = dijit.range.getCommonAncestor(this.startContainer, this.endContainer, __internal_common);}else{this.commonAncestorContainer = this.startContainer;}this.collapsed = (this.startContainer === this.endContainer) && (this.startOffset == this.endOffset);},setStart: function(node, offset, __internal_common){if(this.startContainer === node && this.startOffset == offset){return;}delete this._cachedBookmark;this.startContainer = node;this.startOffset = offset;if(!this.endContainer){this.setEnd(node, offset, __internal_common);}else{this._updateInternal(__internal_common);}},setEnd: function(node, offset, __internal_common){if(this.endContainer === node && this.endOffset == offset){return;}delete this._cachedBookmark;this.endContainer = node;this.endOffset = offset;if(!this.startContainer){this.setStart(node, offset, __internal_common);}else{this._updateInternal(__internal_common);}},setStartAfter: function(node, offset){this._setPoint('setStart', node, offset, 1);},setStartBefore: function(node, offset){this._setPoint('setStart', node, offset, 0);},setEndAfter: function(node, offset){this._setPoint('setEnd', node, offset, 1);},setEndBefore: function(node, offset){this._setPoint('setEnd', node, offset, 0);},_setPoint: function(what, node, offset, ext){var index = dijit.range.getIndex(node, node.parentNode).o;this[what](node.parentNode, index.pop()+ext);},_getIERange: function(){var r=(this._body||this.endContainer.ownerDocument.body).createTextRange();dijit.range.ie.setRange(r, this.startContainer, this.startOffset, this.endContainer, this.endOffset);return r;},getBookmark: function(body){this._getIERange();return this._cachedBookmark;},_select: function(){var r = this._getIERange();r.select();},deleteContents: function(){var r = this._getIERange();r.pasteHTML('');this.endContainer = this.startContainer;this.endOffset = this.startOffset;this.collapsed = true;},cloneRange: function(){var r = new dijit.range.W3CRange([[this.startContainer,this.startOffset],[this.endContainer,this.endOffset]]);r._body = this._body;return r;},detach: function(){this._body = null;this.commonAncestorContainer = null;this.startContainer = null;this.startOffset = 0;this.endContainer = null;this.endOffset = 0;this.collapsed = true;}});} //if(!dijit.range._w3c)}