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; var pnode, n; while(node != stop){ var i = 0; pnode = node.parentNode; 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 row if(ret.length>0 && onode.nodeType==3){ 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)debugger dojo.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;i0){ 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 node startnode = 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 node var atmrange = range.duplicate(), node, len; if(container.nodeType!=3){ //normal node atmrange.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) node = container.lastChild; len = 0; while(node && node.nodeType == 3){ len += node.length; container = node; //pass through node = node.previousSibling; } if(node){ atmrange.moveToElementText(node); } atmrange.collapse(false); offset = len; //pass through }else{ //no childNodes atmrange.moveToElementText(container); atmrange.collapse(true); } }else{ if(offset > 0){ 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 it if(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 node endOffset = 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){ offset=parseInt(offset); 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){ offset=parseInt(offset); 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) }