range.js 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780
  1. var _START_TO_START = 0,
  2. _START_TO_END = 1,
  3. _END_TO_END = 2,
  4. _END_TO_START = 3,
  5. _BOOKMARK_ID = 0;
  6. function _updateCollapsed(range) {
  7. range.collapsed = (range.startContainer === range.endContainer && range.startOffset === range.endOffset);
  8. return range;
  9. }
  10. /**
  11. cloneContents: _copyAndDelete(this, true, false)
  12. extractContents: _copyAndDelete(this, true, true)
  13. deleteContents: _copyAndDelete(this, false, true)
  14. */
  15. function _copyAndDelete(range, isCopy, isDelete) {
  16. var doc = range.doc, nodeList = [];
  17. //split a textNode
  18. function splitTextNode(node, startOffset, endOffset) {
  19. var length = node.nodeValue.length, centerNode;
  20. if (isCopy) {
  21. var cloneNode = node.cloneNode(true);
  22. if (startOffset > 0) {
  23. centerNode = cloneNode.splitText(startOffset);
  24. } else {
  25. centerNode = cloneNode;
  26. }
  27. if (endOffset < length) {
  28. centerNode.splitText(endOffset - startOffset);
  29. }
  30. }
  31. if (isDelete) {
  32. var center = node;
  33. if (startOffset > 0) {
  34. center = node.splitText(startOffset);
  35. range.setStart(node, startOffset);
  36. }
  37. if (endOffset < length) {
  38. var right = center.splitText(endOffset - startOffset);
  39. range.setEnd(right, 0);
  40. }
  41. nodeList.push(center);
  42. }
  43. return centerNode;
  44. }
  45. function removeNodes() {
  46. if (isDelete) {
  47. range.up().collapse(true);
  48. }
  49. for (var i = 0, len = nodeList.length; i < len; i++) {
  50. var node = nodeList[i];
  51. if (node.parentNode) {
  52. node.parentNode.removeChild(node);
  53. }
  54. }
  55. }
  56. var copyRange = range.cloneRange().down();
  57. var start = -1, incStart = -1, incEnd = -1, end = -1,
  58. ancestor = range.commonAncestor(), frag = doc.createDocumentFragment();
  59. // startContainer is textNode and startContainer == endContainer
  60. if (ancestor.nodeType == 3) {
  61. var textNode = splitTextNode(ancestor, range.startOffset, range.endOffset);
  62. if (isCopy) {
  63. frag.appendChild(textNode);
  64. }
  65. removeNodes();
  66. return isCopy ? frag : range;
  67. }
  68. // other case
  69. function extractNodes(parent, frag) {
  70. var node = parent.firstChild, nextNode;
  71. while (node) {
  72. var testRange = new KRange(doc).selectNode(node);
  73. start = testRange.compareBoundaryPoints(_START_TO_END, range);
  74. if (start >= 0 && incStart <= 0) {
  75. incStart = testRange.compareBoundaryPoints(_START_TO_START, range);
  76. }
  77. if (incStart >= 0 && incEnd <= 0) {
  78. incEnd = testRange.compareBoundaryPoints(_END_TO_END, range);
  79. }
  80. if (incEnd >= 0 && end <= 0) {
  81. end = testRange.compareBoundaryPoints(_END_TO_START, range);
  82. }
  83. if (end >= 0) {
  84. return false;
  85. }
  86. nextNode = node.nextSibling;
  87. if (start > 0) {
  88. if (node.nodeType == 1) {
  89. if (incStart >= 0 && incEnd <= 0) {
  90. if (isCopy) {
  91. frag.appendChild(node.cloneNode(true));
  92. }
  93. if (isDelete) {
  94. nodeList.push(node);
  95. }
  96. } else {
  97. var childFlag;
  98. if (isCopy) {
  99. childFlag = node.cloneNode(false);
  100. frag.appendChild(childFlag);
  101. }
  102. if (extractNodes(node, childFlag) === false) {
  103. return false;
  104. }
  105. }
  106. } else if (node.nodeType == 3) {
  107. var textNode;
  108. if (node == copyRange.startContainer) {
  109. textNode = splitTextNode(node, copyRange.startOffset, node.nodeValue.length);
  110. } else if (node == copyRange.endContainer) {
  111. textNode = splitTextNode(node, 0, copyRange.endOffset);
  112. } else {
  113. textNode = splitTextNode(node, 0, node.nodeValue.length);
  114. }
  115. if (isCopy) {
  116. // TODO: IE9有时候报错
  117. try {
  118. frag.appendChild(textNode);
  119. } catch(e) {}
  120. }
  121. }
  122. }
  123. node = nextNode;
  124. }
  125. }
  126. extractNodes(ancestor, frag);
  127. if (isDelete) {
  128. range.up().collapse(true);
  129. }
  130. for (var i = 0, len = nodeList.length; i < len; i++) {
  131. var node = nodeList[i];
  132. if (node.parentNode) {
  133. node.parentNode.removeChild(node);
  134. }
  135. }
  136. return isCopy ? frag : range;
  137. }
  138. //在marquee、select元素里不能使用moveToElementText,IE专用
  139. function _moveToElementText(range, el) {
  140. var node = el;
  141. while (node) {
  142. var knode = K(node);
  143. if (knode.name == 'marquee' || knode.name == 'select') {
  144. return;
  145. }
  146. node = node.parentNode;
  147. }
  148. // IE有时候报错,屏蔽错误
  149. try {
  150. range.moveToElementText(el);
  151. } catch(e) {}
  152. }
  153. //根据原生Range,取得开始节点和结束节点的位置。IE专用
  154. function _getStartEnd(rng, isStart) {
  155. var doc = rng.parentElement().ownerDocument,
  156. pointRange = rng.duplicate();
  157. pointRange.collapse(isStart);
  158. var parent = pointRange.parentElement(),
  159. nodes = parent.childNodes;
  160. if (nodes.length === 0) {
  161. return {node: parent.parentNode, offset: K(parent).index()};
  162. }
  163. var startNode = doc, startPos = 0, cmp = -1;
  164. var testRange = rng.duplicate();
  165. _moveToElementText(testRange, parent);
  166. for (var i = 0, len = nodes.length; i < len; i++) {
  167. var node = nodes[i];
  168. cmp = testRange.compareEndPoints('StartToStart', pointRange);
  169. if (cmp === 0) {
  170. return {node: node.parentNode, offset: i};
  171. }
  172. if (node.nodeType == 1) {
  173. var nodeRange = rng.duplicate(), dummy, knode = K(node), newNode = node;
  174. // <table></table><img>ab[cd]ef
  175. if (knode.isControl()) {
  176. dummy = doc.createElement('span');
  177. knode.after(dummy);
  178. newNode = dummy;
  179. // 0123456[7]89<table><tr><td>123</td></tr></table>
  180. startPos += knode.text().replace(/\r\n|\n|\r/g, '').length;
  181. }
  182. _moveToElementText(nodeRange, newNode);
  183. testRange.setEndPoint('StartToEnd', nodeRange);
  184. if (cmp > 0) {
  185. startPos += nodeRange.text.replace(/\r\n|\n|\r/g, '').length;
  186. } else {
  187. startPos = 0;
  188. }
  189. if (dummy) {
  190. K(dummy).remove();
  191. }
  192. } else if (node.nodeType == 3) {
  193. testRange.moveStart('character', node.nodeValue.length);
  194. startPos += node.nodeValue.length;
  195. }
  196. if (cmp < 0) {
  197. startNode = node;
  198. }
  199. }
  200. //<p>abc<img>|</p>
  201. if (cmp < 0 && startNode.nodeType == 1) {
  202. return {node: parent, offset: K(parent.lastChild).index() + 1};
  203. }
  204. //<p><table></table><img>ab|c</p>
  205. if (cmp > 0) {
  206. while (startNode.nextSibling && startNode.nodeType == 1) {
  207. startNode = startNode.nextSibling;
  208. }
  209. }
  210. testRange = rng.duplicate();
  211. _moveToElementText(testRange, parent);
  212. testRange.setEndPoint('StartToEnd', pointRange);
  213. startPos -= testRange.text.replace(/\r\n|\n|\r/g, '').length;
  214. // [textNode1][textNode2]ab|cd
  215. if (cmp > 0 && startNode.nodeType == 3) {
  216. var prevNode = startNode.previousSibling;
  217. while (prevNode && prevNode.nodeType == 3) {
  218. startPos -= prevNode.nodeValue.length;
  219. prevNode = prevNode.previousSibling;
  220. }
  221. }
  222. return {node: startNode, offset: startPos};
  223. }
  224. //根据Node和offset,取得表示该位置的原生Range。IE专用
  225. function _getEndRange(node, offset) {
  226. var doc = node.ownerDocument || node,
  227. range = doc.body.createTextRange();
  228. if (doc == node) {
  229. range.collapse(true);
  230. return range;
  231. }
  232. if (node.nodeType == 1 && node.childNodes.length > 0) {
  233. var children = node.childNodes, isStart, child;
  234. if (offset === 0) {
  235. child = children[0];
  236. isStart = true;
  237. } else {
  238. child = children[offset - 1];
  239. isStart = false;
  240. }
  241. if (!child) {
  242. return range;
  243. }
  244. if (K(child).name === 'head') {
  245. if (offset === 1) {
  246. isStart = true;
  247. }
  248. if (offset === 2) {
  249. isStart = false;
  250. }
  251. range.collapse(isStart);
  252. return range;
  253. }
  254. if (child.nodeType == 1) {
  255. var kchild = K(child), span;
  256. if (kchild.isControl()) {
  257. span = doc.createElement('span');
  258. if (isStart) {
  259. kchild.before(span);
  260. } else {
  261. kchild.after(span);
  262. }
  263. child = span;
  264. }
  265. _moveToElementText(range, child);
  266. range.collapse(isStart);
  267. if (span) {
  268. K(span).remove();
  269. }
  270. return range;
  271. }
  272. node = child;
  273. offset = isStart ? 0 : child.nodeValue.length;
  274. }
  275. var dummy = doc.createElement('span');
  276. K(node).before(dummy);
  277. _moveToElementText(range, dummy);
  278. range.moveStart('character', offset);
  279. K(dummy).remove();
  280. return range;
  281. }
  282. // convert native Range to KRange
  283. function _toRange(rng) {
  284. var doc, range;
  285. // <table><tr><td></td>|<td></td></tr></table>
  286. // to <table><tr><td></td><td>|</td></tr></table>
  287. function tr2td(start) {
  288. if (K(start.node).name == 'tr') {
  289. start.node = start.node.cells[start.offset];
  290. start.offset = 0;
  291. }
  292. }
  293. // IE
  294. if (_IERANGE) {
  295. if (rng.item) {
  296. doc = _getDoc(rng.item(0));
  297. range = new KRange(doc);
  298. range.selectNode(rng.item(0));
  299. return range;
  300. }
  301. doc = rng.parentElement().ownerDocument;
  302. var start = _getStartEnd(rng, true),
  303. end = _getStartEnd(rng, false);
  304. tr2td(start);
  305. tr2td(end);
  306. range = new KRange(doc);
  307. range.setStart(start.node, start.offset);
  308. range.setEnd(end.node, end.offset);
  309. return range;
  310. }
  311. // other browser
  312. var startContainer = rng.startContainer;
  313. doc = startContainer.ownerDocument || startContainer;
  314. range = new KRange(doc);
  315. range.setStart(startContainer, rng.startOffset);
  316. range.setEnd(rng.endContainer, rng.endOffset);
  317. return range;
  318. }
  319. // create KRange class
  320. function KRange(doc) {
  321. this.init(doc);
  322. }
  323. _extend(KRange, {
  324. init : function(doc) {
  325. var self = this;
  326. self.startContainer = doc;
  327. self.startOffset = 0;
  328. self.endContainer = doc;
  329. self.endOffset = 0;
  330. self.collapsed = true;
  331. self.doc = doc;
  332. },
  333. commonAncestor : function() {
  334. function getParents(node) {
  335. var parents = [];
  336. while (node) {
  337. parents.push(node);
  338. node = node.parentNode;
  339. }
  340. return parents;
  341. }
  342. var parentsA = getParents(this.startContainer),
  343. parentsB = getParents(this.endContainer),
  344. i = 0, lenA = parentsA.length, lenB = parentsB.length, parentA, parentB;
  345. while (++i) {
  346. parentA = parentsA[lenA - i];
  347. parentB = parentsB[lenB - i];
  348. if (!parentA || !parentB || parentA !== parentB) {
  349. break;
  350. }
  351. }
  352. return parentsA[lenA - i + 1];
  353. },
  354. setStart : function(node, offset) {
  355. var self = this, doc = self.doc;
  356. self.startContainer = node;
  357. self.startOffset = offset;
  358. if (self.endContainer === doc) {
  359. self.endContainer = node;
  360. self.endOffset = offset;
  361. }
  362. return _updateCollapsed(this);
  363. },
  364. setEnd : function(node, offset) {
  365. var self = this, doc = self.doc;
  366. self.endContainer = node;
  367. self.endOffset = offset;
  368. if (self.startContainer === doc) {
  369. self.startContainer = node;
  370. self.startOffset = offset;
  371. }
  372. return _updateCollapsed(this);
  373. },
  374. setStartBefore : function(node) {
  375. return this.setStart(node.parentNode || this.doc, K(node).index());
  376. },
  377. setStartAfter : function(node) {
  378. return this.setStart(node.parentNode || this.doc, K(node).index() + 1);
  379. },
  380. setEndBefore : function(node) {
  381. return this.setEnd(node.parentNode || this.doc, K(node).index());
  382. },
  383. setEndAfter : function(node) {
  384. return this.setEnd(node.parentNode || this.doc, K(node).index() + 1);
  385. },
  386. selectNode : function(node) {
  387. return this.setStartBefore(node).setEndAfter(node);
  388. },
  389. selectNodeContents : function(node) {
  390. var knode = K(node);
  391. if (knode.type == 3 || knode.isSingle()) {
  392. return this.selectNode(node);
  393. }
  394. var children = knode.children();
  395. if (children.length > 0) {
  396. return this.setStartBefore(children[0]).setEndAfter(children[children.length - 1]);
  397. }
  398. return this.setStart(node, 0).setEnd(node, 0);
  399. },
  400. collapse : function(toStart) {
  401. if (toStart) {
  402. return this.setEnd(this.startContainer, this.startOffset);
  403. }
  404. return this.setStart(this.endContainer, this.endOffset);
  405. },
  406. compareBoundaryPoints : function(how, range) {
  407. var rangeA = this.get(), rangeB = range.get();
  408. if (_IERANGE) {
  409. var arr = {};
  410. arr[_START_TO_START] = 'StartToStart';
  411. arr[_START_TO_END] = 'EndToStart';
  412. arr[_END_TO_END] = 'EndToEnd';
  413. arr[_END_TO_START] = 'StartToEnd';
  414. var cmp = rangeA.compareEndPoints(arr[how], rangeB);
  415. if (cmp !== 0) {
  416. return cmp;
  417. }
  418. var nodeA, nodeB, nodeC, posA, posB;
  419. if (how === _START_TO_START || how === _END_TO_START) {
  420. nodeA = this.startContainer;
  421. posA = this.startOffset;
  422. }
  423. if (how === _START_TO_END || how === _END_TO_END) {
  424. nodeA = this.endContainer;
  425. posA = this.endOffset;
  426. }
  427. if (how === _START_TO_START || how === _START_TO_END) {
  428. nodeB = range.startContainer;
  429. posB = range.startOffset;
  430. }
  431. if (how === _END_TO_END || how === _END_TO_START) {
  432. nodeB = range.endContainer;
  433. posB = range.endOffset;
  434. }
  435. // nodeA和nodeA相同时
  436. if (nodeA === nodeB) {
  437. var diff = posA - posB;
  438. return diff > 0 ? 1 : (diff < 0 ? -1 : 0);
  439. }
  440. // nodeA是nodeB的祖先时
  441. nodeC = nodeB;
  442. while (nodeC && nodeC.parentNode !== nodeA) {
  443. nodeC = nodeC.parentNode;
  444. }
  445. if (nodeC) {
  446. return K(nodeC).index() >= posA ? -1 : 1;
  447. }
  448. // nodeB是nodeA的祖先时
  449. nodeC = nodeA;
  450. while (nodeC && nodeC.parentNode !== nodeB) {
  451. nodeC = nodeC.parentNode;
  452. }
  453. if (nodeC) {
  454. return K(nodeC).index() >= posB ? 1 : -1;
  455. }
  456. // nodeB的下一个节点是nodeA的祖先
  457. nodeC = K(nodeB).next();
  458. if (nodeC && nodeC.contains(nodeA)) {
  459. return 1;
  460. }
  461. // nodeA的下一个节点是nodeB的祖先
  462. nodeC = K(nodeA).next();
  463. if (nodeC && nodeC.contains(nodeB)) {
  464. return -1;
  465. }
  466. //其它情况,暂时不需要
  467. } else {
  468. return rangeA.compareBoundaryPoints(how, rangeB);
  469. }
  470. },
  471. cloneRange : function() {
  472. return new KRange(this.doc).setStart(this.startContainer, this.startOffset).setEnd(this.endContainer, this.endOffset);
  473. },
  474. toString : function() {
  475. //TODO
  476. var rng = this.get(), str = _IERANGE ? rng.text : rng.toString();
  477. return str.replace(/\r\n|\n|\r/g, '');
  478. },
  479. cloneContents : function() {
  480. return _copyAndDelete(this, true, false);
  481. },
  482. deleteContents : function() {
  483. return _copyAndDelete(this, false, true);
  484. },
  485. extractContents : function() {
  486. return _copyAndDelete(this, true, true);
  487. },
  488. insertNode : function(node) {
  489. var self = this,
  490. sc = self.startContainer, so = self.startOffset,
  491. ec = self.endContainer, eo = self.endOffset,
  492. firstChild, lastChild, c, nodeCount = 1;
  493. //node为文档碎片时
  494. if (node.nodeName.toLowerCase() === '#document-fragment') {
  495. firstChild = node.firstChild;
  496. lastChild = node.lastChild;
  497. nodeCount = node.childNodes.length;
  498. }
  499. //startContainer为element时
  500. if (sc.nodeType == 1) {
  501. c = sc.childNodes[so];
  502. if (c) {
  503. sc.insertBefore(node, c);
  504. //调整结束节点位置
  505. if (sc === ec) {
  506. eo += nodeCount;
  507. }
  508. } else {
  509. sc.appendChild(node);
  510. }
  511. //startContainer为text时
  512. } else if (sc.nodeType == 3) {
  513. if (so === 0) {
  514. sc.parentNode.insertBefore(node, sc);
  515. //调整结束节点位置
  516. if (sc.parentNode === ec) {
  517. eo += nodeCount;
  518. }
  519. } else if (so >= sc.nodeValue.length) {
  520. if (sc.nextSibling) {
  521. sc.parentNode.insertBefore(node, sc.nextSibling);
  522. } else {
  523. sc.parentNode.appendChild(node);
  524. }
  525. } else {
  526. if (so > 0) {
  527. c = sc.splitText(so);
  528. } else {
  529. c = sc;
  530. }
  531. sc.parentNode.insertBefore(node, c);
  532. //调整结束节点位置
  533. if (sc === ec) {
  534. ec = c;
  535. eo -= so;
  536. }
  537. }
  538. }
  539. if (firstChild) {
  540. self.setStartBefore(firstChild).setEndAfter(lastChild);
  541. } else {
  542. self.selectNode(node);
  543. }
  544. if (self.compareBoundaryPoints(_END_TO_END, self.cloneRange().setEnd(ec, eo)) >= 1) {
  545. return self;
  546. }
  547. return self.setEnd(ec, eo);
  548. },
  549. surroundContents : function(node) {
  550. node.appendChild(this.extractContents());
  551. return this.insertNode(node).selectNode(node);
  552. },
  553. // 判断range是不是control range
  554. isControl : function() {
  555. var self = this,
  556. sc = self.startContainer, so = self.startOffset,
  557. ec = self.endContainer, eo = self.endOffset, rng;
  558. return sc.nodeType == 1 && sc === ec && so + 1 === eo && K(sc.childNodes[so]).isControl();
  559. },
  560. // get original range
  561. get : function(hasControlRange) {
  562. var self = this, doc = self.doc, node, rng;
  563. // not IE
  564. if (!_IERANGE) {
  565. rng = doc.createRange();
  566. try {
  567. rng.setStart(self.startContainer, self.startOffset);
  568. rng.setEnd(self.endContainer, self.endOffset);
  569. } catch (e) {}
  570. return rng;
  571. }
  572. // IE control range
  573. if (hasControlRange && self.isControl()) {
  574. rng = doc.body.createControlRange();
  575. rng.addElement(self.startContainer.childNodes[self.startOffset]);
  576. return rng;
  577. }
  578. // IE text range
  579. var range = self.cloneRange().down();
  580. rng = doc.body.createTextRange();
  581. rng.setEndPoint('StartToStart', _getEndRange(range.startContainer, range.startOffset));
  582. rng.setEndPoint('EndToStart', _getEndRange(range.endContainer, range.endOffset));
  583. return rng;
  584. },
  585. html : function() {
  586. return K(this.cloneContents()).outer();
  587. },
  588. // 降低range的位置
  589. // <p><strong><span>123</span>|abc</strong>def</p>
  590. // postion(strong, 1) -> positon("abc", 0)
  591. // or
  592. // <p><strong>abc|<span>123</span></strong>def</p>
  593. // postion(strong, 1) -> positon("abc", 3)
  594. down : function() {
  595. var self = this;
  596. function downPos(node, pos, isStart) {
  597. if (node.nodeType != 1) {
  598. return;
  599. }
  600. var children = K(node).children();
  601. if (children.length === 0) {
  602. return;
  603. }
  604. var left, right, child, offset;
  605. if (pos > 0) {
  606. left = children.eq(pos - 1);
  607. }
  608. if (pos < children.length) {
  609. right = children.eq(pos);
  610. }
  611. if (left && left.type == 3) {
  612. child = left[0];
  613. offset = child.nodeValue.length;
  614. }
  615. if (right && right.type == 3) {
  616. child = right[0];
  617. offset = 0;
  618. }
  619. if (!child) {
  620. return;
  621. }
  622. if (isStart) {
  623. self.setStart(child, offset);
  624. } else {
  625. self.setEnd(child, offset);
  626. }
  627. }
  628. downPos(self.startContainer, self.startOffset, true);
  629. downPos(self.endContainer, self.endOffset, false);
  630. return self;
  631. },
  632. // 提高range的位置
  633. // <p><strong><span>123</span>|abc</strong>def</p>
  634. // positon("abc", 0) -> postion(strong, 1)
  635. // or
  636. // <p><strong>abc|<span>123</span></strong>def</p>
  637. // positon("abc", 3) -> postion(strong, 1)
  638. up : function() {
  639. var self = this;
  640. function upPos(node, pos, isStart) {
  641. if (node.nodeType != 3) {
  642. return;
  643. }
  644. if (pos === 0) {
  645. if (isStart) {
  646. self.setStartBefore(node);
  647. } else {
  648. self.setEndBefore(node);
  649. }
  650. } else if (pos == node.nodeValue.length) {
  651. if (isStart) {
  652. self.setStartAfter(node);
  653. } else {
  654. self.setEndAfter(node);
  655. }
  656. }
  657. }
  658. upPos(self.startContainer, self.startOffset, true);
  659. upPos(self.endContainer, self.endOffset, false);
  660. return self;
  661. },
  662. // 扩大边界
  663. // <p><strong><span>[123</span>abc]</strong>def</p> to <p>[<strong><span>123</span>abc</strong>]def</p>
  664. enlarge : function(toBlock) {
  665. var self = this;
  666. self.up();
  667. function enlargePos(node, pos, isStart) {
  668. var knode = K(node), parent;
  669. if (knode.type == 3 || _NOSPLIT_TAG_MAP[knode.name] || !toBlock && knode.isBlock()) {
  670. return;
  671. }
  672. if (pos === 0) {
  673. while (!knode.prev()) {
  674. parent = knode.parent();
  675. if (!parent || _NOSPLIT_TAG_MAP[parent.name] || !toBlock && parent.isBlock()) {
  676. break;
  677. }
  678. knode = parent;
  679. }
  680. if (isStart) {
  681. self.setStartBefore(knode[0]);
  682. } else {
  683. self.setEndBefore(knode[0]);
  684. }
  685. } else if (pos == knode.children().length) {
  686. while (!knode.next()) {
  687. parent = knode.parent();
  688. if (!parent || _NOSPLIT_TAG_MAP[parent.name] || !toBlock && parent.isBlock()) {
  689. break;
  690. }
  691. knode = parent;
  692. }
  693. if (isStart) {
  694. self.setStartAfter(knode[0]);
  695. } else {
  696. self.setEndAfter(knode[0]);
  697. }
  698. }
  699. }
  700. enlargePos(self.startContainer, self.startOffset, true);
  701. enlargePos(self.endContainer, self.endOffset, false);
  702. return self;
  703. },
  704. // 缩小边界
  705. // <body>[<p><strong>123</strong></p>]</body> to <body><p><strong>[123]</strong></p></body>
  706. shrink : function() {
  707. var self = this, child, collapsed = self.collapsed;
  708. while (self.startContainer.nodeType == 1 && (child = self.startContainer.childNodes[self.startOffset]) && child.nodeType == 1 && !K(child).isSingle()) {
  709. self.setStart(child, 0);
  710. }
  711. if (collapsed) {
  712. return self.collapse(collapsed);
  713. }
  714. while (self.endContainer.nodeType == 1 && self.endOffset > 0 && (child = self.endContainer.childNodes[self.endOffset - 1]) && child.nodeType == 1 && !K(child).isSingle()) {
  715. self.setEnd(child, child.childNodes.length);
  716. }
  717. return self;
  718. },
  719. // 创建bookmark,通过插入临时节点标记位置
  720. createBookmark : function(serialize) {
  721. var self = this, doc = self.doc, endNode,
  722. startNode = K('<span style="display:none;"></span>', doc)[0];
  723. startNode.id = '__kindeditor_bookmark_start_' + (_BOOKMARK_ID++) + '__';
  724. if (!self.collapsed) {
  725. endNode = startNode.cloneNode(true);
  726. endNode.id = '__kindeditor_bookmark_end_' + (_BOOKMARK_ID++) + '__';
  727. }
  728. if (endNode) {
  729. self.cloneRange().collapse(false).insertNode(endNode).setEndBefore(endNode);
  730. }
  731. self.insertNode(startNode).setStartAfter(startNode);
  732. return {
  733. start : serialize ? '#' + startNode.id : startNode,
  734. end : endNode ? (serialize ? '#' + endNode.id : endNode) : null
  735. };
  736. },
  737. // 根据bookmark重新设置range
  738. moveToBookmark : function(bookmark) {
  739. var self = this, doc = self.doc,
  740. start = K(bookmark.start, doc), end = bookmark.end ? K(bookmark.end, doc) : null;
  741. if (!start || start.length < 1) {
  742. return self;
  743. }
  744. self.setStartBefore(start[0]);
  745. start.remove();
  746. if (end && end.length > 0) {
  747. self.setEndBefore(end[0]);
  748. end.remove();
  749. } else {
  750. self.collapse(true);
  751. }
  752. return self;
  753. },
  754. dump : function() {
  755. console.log('--------------------');
  756. console.log(this.startContainer.nodeType == 3 ? this.startContainer.nodeValue : this.startContainer, this.startOffset);
  757. console.log(this.endContainer.nodeType == 3 ? this.endContainer.nodeValue : this.endContainer, this.endOffset);
  758. }
  759. });
  760. function _range(mixed) {
  761. if (!mixed.nodeName) {
  762. return mixed.constructor === KRange ? mixed : _toRange(mixed);
  763. }
  764. return new KRange(mixed);
  765. }
  766. K.RangeClass = KRange;
  767. K.range = _range;
  768. K.START_TO_START = _START_TO_START;
  769. K.START_TO_END = _START_TO_END;
  770. K.END_TO_END = _END_TO_END;
  771. K.END_TO_START = _END_TO_START;