/* Copyright (c) 2004-2011, The Dojo Foundation All Rights Reserved. Available via Academic Free License >= 2.1 OR the modified BSD license. see: http://dojotoolkit.org/license for details */ 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){ root = root||n1.ownerDocument.body; var getAncestors = function(n){ var as=[]; while(n){ as.unshift(n); if(n !== root){ n = n.parentNode; }else{ break; } } return as; }; var n1as = getAncestors(n1); var n2as = getAncestors(n2); 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 shall 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 == 1 && startOffset == startnode.childNodes.length){ var nextnode=startnode.nextSibling; if(nextnode && nextnode.nodeType == 3){ startnode = nextnode; startOffset = 0; } } return [startnode, startOffset]; }, setEndPoint: function(range, container, offset){ //text node var atmrange = range.duplicate(), node, len; if(container.nodeType!=3){ //normal node if(offset > 0){ node = container.childNodes[offset-1]; if(node){ if(node.nodeType == 3){ container = node; offset = node.length; //pass through }else{ if(node.nextSibling && node.nextSibling.nodeType == 3){ container=node.nextSibling; offset=0; //pass through }else{ atmrange.moveToElementText(node.nextSibling?node:container); var parent = node.parentNode; var tempNode = parent.insertBefore(node.ownerDocument.createTextNode(' '), node.nextSibling); atmrange.collapse(false); parent.removeChild(tempNode); } } } }else{ atmrange.moveToElementText(container); atmrange.collapse(true); } } 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.move('character',offset) != offset){ console.error('Error when moving!'); } } } return atmrange; }, decomposeTextRange: function(range){ var tmpary = dijit.range.ie.getEndPoint(range); var startContainer = tmpary[0], startOffset = tmpary[1]; var endContainer = 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); endContainer = tmpary[0], endOffset = tmpary[1]; // if(startContainer.tagName == "BODY"){ // startContainer = startContainer.firstChild; // } } } return [startContainer, startOffset, endContainer, endOffset]; }, setRange: function(range, startContainer, startOffset, endContainer, endOffset, collapsed){ var start=dijit.range.ie.setEndPoint(range, startContainer, startOffset); range.setEndPoint('StartToStart',start); if(!collapsed){ var end=dijit.range.ie.setEndPoint(range, endContainer, endOffset); } range.setEndPoint('EndToEnd',end || start); return range; } } dojo.declare("dijit.range.W3CRange",null, { constructor: function(){ if(arguments.length>0){ this.setStart(arguments[0][0],arguments[0][1]); this.setEnd(arguments[0][2],arguments[0][3]); }else{ this.commonAncestorContainer = null; this.startContainer = null; this.startOffset = 0; this.endContainer = null; this.endOffset = 0; this.collapsed = true; } }, _updateInternal: function(){ if(this.startContainer !== this.endContainer){ this.commonAncestorContainer = dijit.range.getCommonAncestor(this.startContainer, this.endContainer); }else{ this.commonAncestorContainer = this.startContainer; } this.collapsed = (this.startContainer === this.endContainer) && (this.startOffset == this.endOffset); }, setStart: function(node, offset){ 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); }else{ this._updateInternal(); } }, setEnd: function(node, offset){ 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); }else{ this._updateInternal(); } }, 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, this.collapsed); 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) }