123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629 |
- 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 row
- if (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)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; 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
- // space
- if (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 space
- if (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.length
- node = node[prop];
- }
- return [node, len];
- }
- dijit.range._w3c = Boolean(window['getSelection']);
- dijit.range.create = function() {
- if (dijit.range._w3c) {
- return document.createRange();
- } else {// IE
- return new dijit.range.W3CRange;
- }
- }
- dijit.range.getSelection = function(win, /* Boolean? */ignoreUpdate) {
- if (dijit.range._w3c) {
- return win.getSelection();
- } else {// IE
- var 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 cache
- id = (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
- // 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();
- 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)
- var node = container.lastChild;
- var 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) {
- 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 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) {
- 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)
- }
|