browserrange_test.js 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644
  1. // Copyright 2007 The Closure Library Authors. All Rights Reserved.
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS-IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. goog.provide('goog.dom.browserrangeTest');
  15. goog.setTestOnly('goog.dom.browserrangeTest');
  16. goog.require('goog.dom');
  17. goog.require('goog.dom.NodeType');
  18. goog.require('goog.dom.Range');
  19. goog.require('goog.dom.RangeEndpoint');
  20. goog.require('goog.dom.TagName');
  21. goog.require('goog.dom.browserrange');
  22. goog.require('goog.html.testing');
  23. goog.require('goog.testing.dom');
  24. goog.require('goog.testing.jsunit');
  25. var test1;
  26. var test2;
  27. var cetest;
  28. var empty;
  29. var dynamic;
  30. var onlybrdiv;
  31. function setUpPage() {
  32. test1 = goog.dom.getElement('test1');
  33. test2 = goog.dom.getElement('test2');
  34. cetest = goog.dom.getElement('cetest');
  35. empty = goog.dom.getElement('empty');
  36. dynamic = goog.dom.getElement('dynamic');
  37. onlybrdiv = goog.dom.getElement('onlybr');
  38. }
  39. function testCreate() {
  40. assertNotNull(
  41. 'Browser range object can be created for node',
  42. goog.dom.browserrange.createRangeFromNodeContents(test1));
  43. }
  44. function testRangeEndPoints() {
  45. var container = cetest.firstChild;
  46. var range =
  47. goog.dom.browserrange.createRangeFromNodes(container, 2, container, 2);
  48. range.select();
  49. var selRange = goog.dom.Range.createFromWindow();
  50. var startNode = selRange.getStartNode();
  51. var endNode = selRange.getEndNode();
  52. var startOffset = selRange.getStartOffset();
  53. var endOffset = selRange.getEndOffset();
  54. if (startNode.nodeType == goog.dom.NodeType.TEXT) {
  55. // Special case for Webkit (up to Chrome 57) and IE8.
  56. assertEquals(
  57. 'Start node should have text: abc', 'abc', startNode.nodeValue);
  58. assertEquals('End node should have text: abc', 'abc', endNode.nodeValue);
  59. assertEquals('Start offset should be 3', 3, startOffset);
  60. assertEquals('End offset should be 3', 3, endOffset);
  61. } else {
  62. assertEquals('Start node should be the first div', container, startNode);
  63. assertEquals('End node should be the first div', container, endNode);
  64. assertEquals('Start offset should be 2', 2, startOffset);
  65. assertEquals('End offset should be 2', 2, endOffset);
  66. }
  67. }
  68. function testCreateFromNodeContents() {
  69. var range = goog.dom.Range.createFromNodeContents(onlybrdiv);
  70. goog.testing.dom.assertRangeEquals(onlybrdiv, 0, onlybrdiv, 1, range);
  71. }
  72. /**
  73. * @param {string} str
  74. * @return {string}
  75. */
  76. function normalizeHtml(str) {
  77. return str.toLowerCase().replace(/[\n\r\f"]/g, '');
  78. }
  79. // TODO(robbyw): We really need tests for (and code fixes for)
  80. // createRangeFromNodes in the following cases:
  81. // * BR boundary (before + after)
  82. function testCreateFromNodes() {
  83. var start = test1.firstChild;
  84. var range =
  85. goog.dom.browserrange.createRangeFromNodes(start, 2, test2.firstChild, 2);
  86. assertNotNull(
  87. 'Browser range object can be created for W3C node range', range);
  88. assertEquals(
  89. 'Start node should be selected at start endpoint', start,
  90. range.getStartNode());
  91. assertEquals('Selection should start at offset 2', 2, range.getStartOffset());
  92. assertEquals(
  93. 'Text node should be selected at end endpoint', test2.firstChild,
  94. range.getEndNode());
  95. assertEquals('Selection should end at offset 2', 2, range.getEndOffset());
  96. assertTrue(
  97. 'Text content should be "xt\\s*ab"', /xt\s*ab/.test(range.getText()));
  98. assertFalse('Nodes range is not collapsed', range.isCollapsed());
  99. assertEquals(
  100. 'Should contain correct html fragment', 'xt</div><div id=test2>ab',
  101. normalizeHtml(range.getHtmlFragment()));
  102. assertEquals(
  103. 'Should contain correct valid html',
  104. '<div id=test1>xt</div><div id=test2>ab</div>',
  105. normalizeHtml(range.getValidHtml()));
  106. }
  107. function testTextNode() {
  108. var range =
  109. goog.dom.browserrange.createRangeFromNodeContents(test1.firstChild);
  110. assertEquals(
  111. 'Text node should be selected at start endpoint', 'Text',
  112. range.getStartNode().nodeValue);
  113. assertEquals('Selection should start at offset 0', 0, range.getStartOffset());
  114. assertEquals(
  115. 'Text node should be selected at end endpoint', 'Text',
  116. range.getEndNode().nodeValue);
  117. assertEquals(
  118. 'Selection should end at offset 4', 'Text'.length, range.getEndOffset());
  119. assertEquals(
  120. 'Container should be text node', goog.dom.NodeType.TEXT,
  121. range.getContainer().nodeType);
  122. assertEquals('Text content should be "Text"', 'Text', range.getText());
  123. assertFalse('Text range is not collapsed', range.isCollapsed());
  124. assertEquals(
  125. 'Should contain correct html fragment', 'Text', range.getHtmlFragment());
  126. assertEquals(
  127. 'Should contain correct valid html', 'Text', range.getValidHtml());
  128. }
  129. function testTextNodes() {
  130. goog.dom.removeChildren(dynamic);
  131. dynamic.appendChild(goog.dom.createTextNode('Part1'));
  132. dynamic.appendChild(goog.dom.createTextNode('Part2'));
  133. var range = goog.dom.browserrange.createRangeFromNodes(
  134. dynamic.firstChild, 0, dynamic.lastChild, 5);
  135. assertEquals(
  136. 'Text node 1 should be selected at start endpoint', 'Part1',
  137. range.getStartNode().nodeValue);
  138. assertEquals('Selection should start at offset 0', 0, range.getStartOffset());
  139. assertEquals(
  140. 'Text node 2 should be selected at end endpoint', 'Part2',
  141. range.getEndNode().nodeValue);
  142. assertEquals(
  143. 'Selection should end at offset 5', 'Part2'.length, range.getEndOffset());
  144. assertEquals(
  145. 'Container should be DIV', String(goog.dom.TagName.DIV),
  146. range.getContainer().tagName);
  147. assertEquals(
  148. 'Text content should be "Part1Part2"', 'Part1Part2', range.getText());
  149. assertFalse('Text range is not collapsed', range.isCollapsed());
  150. assertEquals(
  151. 'Should contain correct html fragment', 'Part1Part2',
  152. range.getHtmlFragment());
  153. assertEquals(
  154. 'Should contain correct valid html', 'part1part2',
  155. normalizeHtml(range.getValidHtml()));
  156. }
  157. function testDiv() {
  158. var range = goog.dom.browserrange.createRangeFromNodeContents(test2);
  159. assertEquals(
  160. 'Text node "abc" should be selected at start endpoint', 'abc',
  161. range.getStartNode().nodeValue);
  162. assertEquals('Selection should start at offset 0', 0, range.getStartOffset());
  163. assertEquals(
  164. 'Text node "def" should be selected at end endpoint', 'def',
  165. range.getEndNode().nodeValue);
  166. assertEquals(
  167. 'Selection should end at offset 3', 'def'.length, range.getEndOffset());
  168. assertEquals('Container should be DIV', 'DIV', range.getContainer().tagName);
  169. assertTrue(
  170. 'Div text content should be "abc\\s*def"',
  171. /abc\s*def/.test(range.getText()));
  172. assertEquals(
  173. 'Should contain correct html fragment', 'abc<br id=br>def',
  174. normalizeHtml(range.getHtmlFragment()));
  175. assertEquals(
  176. 'Should contain correct valid html',
  177. '<div id=test2>abc<br id=br>def</div>',
  178. normalizeHtml(range.getValidHtml()));
  179. assertFalse('Div range is not collapsed', range.isCollapsed());
  180. }
  181. function testEmptyNodeHtmlInsert() {
  182. var range = goog.dom.browserrange.createRangeFromNodeContents(empty);
  183. var html = '<b>hello</b>';
  184. range.insertNode(goog.dom.safeHtmlToNode(
  185. goog.html.testing.newSafeHtmlForTest(html)));
  186. assertEquals(
  187. 'Html is not inserted correctly', html, normalizeHtml(empty.innerHTML));
  188. goog.dom.removeChildren(empty);
  189. }
  190. function testEmptyNode() {
  191. var range = goog.dom.browserrange.createRangeFromNodeContents(empty);
  192. assertEquals(
  193. 'DIV be selected at start endpoint', 'DIV', range.getStartNode().tagName);
  194. assertEquals('Selection should start at offset 0', 0, range.getStartOffset());
  195. assertEquals(
  196. 'DIV should be selected at end endpoint', 'DIV',
  197. range.getEndNode().tagName);
  198. assertEquals('Selection should end at offset 0', 0, range.getEndOffset());
  199. assertEquals('Container should be DIV', 'DIV', range.getContainer().tagName);
  200. assertEquals('Empty text content should be ""', '', range.getText());
  201. assertTrue('Empty range is collapsed', range.isCollapsed());
  202. assertEquals(
  203. 'Should contain correct valid html', '<div id=empty></div>',
  204. normalizeHtml(range.getValidHtml()));
  205. assertEquals('Should contain no html fragment', '', range.getHtmlFragment());
  206. }
  207. function testRemoveContents() {
  208. var outer = goog.dom.getElement('removeTest');
  209. var range =
  210. goog.dom.browserrange.createRangeFromNodeContents(outer.firstChild);
  211. range.removeContents();
  212. assertEquals('Removed range content should be ""', '', range.getText());
  213. assertTrue('Removed range is now collapsed', range.isCollapsed());
  214. assertEquals('Outer div has 1 child now', 1, outer.childNodes.length);
  215. assertEquals('Inner div is empty', 0, outer.firstChild.childNodes.length);
  216. }
  217. function testRemoveContentsEmptyNode() {
  218. var outer = goog.dom.getElement('removeTestEmptyNode');
  219. var range = goog.dom.browserrange.createRangeFromNodeContents(outer);
  220. range.removeContents();
  221. assertEquals('Removed range content should be ""', '', range.getText());
  222. assertTrue('Removed range is now collapsed', range.isCollapsed());
  223. assertEquals(
  224. 'Outer div should have 0 children now', 0, outer.childNodes.length);
  225. }
  226. function testRemoveContentsSingleNode() {
  227. var outer = goog.dom.getElement('removeTestSingleNode');
  228. var range =
  229. goog.dom.browserrange.createRangeFromNodeContents(outer.firstChild);
  230. range.removeContents();
  231. assertEquals('Removed range content should be ""', '', range.getText());
  232. assertTrue('Removed range is now collapsed', range.isCollapsed());
  233. assertEquals('', goog.dom.getTextContent(outer));
  234. }
  235. function testRemoveContentsMidNode() {
  236. var outer = goog.dom.getElement('removeTestMidNode');
  237. var textNode = outer.firstChild.firstChild;
  238. var range =
  239. goog.dom.browserrange.createRangeFromNodes(textNode, 1, textNode, 4);
  240. assertEquals(
  241. 'Previous range content should be "123"', '123', range.getText());
  242. range.removeContents();
  243. assertEquals(
  244. 'Removed range content should be "0456789"', '0456789',
  245. goog.dom.getTextContent(outer));
  246. }
  247. function testRemoveContentsMidMultipleNodes() {
  248. var outer = goog.dom.getElement('removeTestMidMultipleNodes');
  249. var firstTextNode = outer.firstChild.firstChild;
  250. var lastTextNode = outer.lastChild.firstChild;
  251. var range = goog.dom.browserrange.createRangeFromNodes(
  252. firstTextNode, 1, lastTextNode, 4);
  253. assertEquals(
  254. 'Previous range content', '1234567890123',
  255. range.getText().replace(/\s/g, ''));
  256. range.removeContents();
  257. assertEquals(
  258. 'Removed range content should be "0456789"', '0456789',
  259. goog.dom.getTextContent(outer).replace(/\s/g, ''));
  260. }
  261. function testRemoveDivCaretRange() {
  262. var outer = goog.dom.getElement('sandbox');
  263. outer.innerHTML = '<div>Test1</div><div></div>';
  264. var range = goog.dom.browserrange.createRangeFromNodes(
  265. outer.lastChild, 0, outer.lastChild, 0);
  266. range.removeContents();
  267. range.insertNode(
  268. goog.dom.createDom(goog.dom.TagName.SPAN, undefined, 'Hello'), true);
  269. assertEquals(
  270. 'Resulting contents', 'Test1Hello',
  271. goog.dom.getTextContent(outer).replace(/\s/g, ''));
  272. }
  273. function testCollapse() {
  274. var range = goog.dom.browserrange.createRangeFromNodeContents(test2);
  275. assertFalse('Div range is not collapsed', range.isCollapsed());
  276. range.collapse();
  277. assertTrue(
  278. 'Div range is collapsed after call to empty()', range.isCollapsed());
  279. range = goog.dom.browserrange.createRangeFromNodeContents(empty);
  280. assertTrue('Empty range is collapsed', range.isCollapsed());
  281. range.collapse();
  282. assertTrue('Empty range is still collapsed', range.isCollapsed());
  283. }
  284. function testIdWithSpecialCharacters() {
  285. goog.dom.removeChildren(dynamic);
  286. dynamic.appendChild(goog.dom.createTextNode('1'));
  287. dynamic.appendChild(goog.dom.createDom(goog.dom.TagName.DIV, {id: '<>'}));
  288. dynamic.appendChild(goog.dom.createTextNode('2'));
  289. var range = goog.dom.browserrange.createRangeFromNodes(
  290. dynamic.firstChild, 0, dynamic.lastChild, 1);
  291. // Difference in special character handling is ok.
  292. assertContains(
  293. 'Should have correct html fragment',
  294. normalizeHtml(range.getHtmlFragment()),
  295. [
  296. '1<div id=<>></div>2', // IE
  297. '1<div id=&lt;>></div>2', // WebKit
  298. '1<div id=&lt;&gt;></div>2' // Others
  299. ]);
  300. }
  301. function testEndOfChildren() {
  302. dynamic.innerHTML = '<span id="a">123<br>456</span><span id="b">text</span>';
  303. var range = goog.dom.browserrange.createRangeFromNodes(
  304. goog.dom.getElement('a'), 3, goog.dom.getElement('b'), 1);
  305. assertEquals('Should have correct text.', 'text', range.getText());
  306. }
  307. function testEndOfDiv() {
  308. dynamic.innerHTML = '<div id="a">abc</div><div id="b">def</div>';
  309. var a = goog.dom.getElement('a');
  310. var range = goog.dom.browserrange.createRangeFromNodes(a, 1, a, 1);
  311. var expectedStartNode = a;
  312. var expectedStartOffset = 1;
  313. var expectedEndNode = a;
  314. var expectedEndOffset = 1;
  315. assertEquals('startNode is wrong', expectedStartNode, range.getStartNode());
  316. assertEquals(
  317. 'startOffset is wrong', expectedStartOffset, range.getStartOffset());
  318. assertEquals('endNode is wrong', expectedEndNode, range.getEndNode());
  319. assertEquals('endOffset is wrong', expectedEndOffset, range.getEndOffset());
  320. }
  321. function testRangeEndingWithBR() {
  322. dynamic.innerHTML = '<span id="a">123<br>456</span>';
  323. var spanElem = goog.dom.getElement('a');
  324. var range =
  325. goog.dom.browserrange.createRangeFromNodes(spanElem, 0, spanElem, 2);
  326. var htmlText = range.getValidHtml().toLowerCase();
  327. assertContains('Should include BR in HTML.', 'br', htmlText);
  328. assertEquals('Should have correct text.', '123', range.getText());
  329. range.select();
  330. var selRange = goog.dom.Range.createFromWindow();
  331. var startNode = selRange.getStartNode();
  332. if (startNode.nodeType == goog.dom.NodeType.TEXT) {
  333. // Special case for Webkit (up to Chrome 57) and IE8.
  334. assertEquals('Startnode should have text:123', '123', startNode.nodeValue);
  335. } else {
  336. assertEquals('Start node should be span', spanElem, startNode);
  337. }
  338. assertEquals('Startoffset should be 0', 0, selRange.getStartOffset());
  339. var endNode = selRange.getEndNode();
  340. assertEquals('Endnode should be span', spanElem, endNode);
  341. assertEquals('Endoffset should be 2', 2, selRange.getEndOffset());
  342. }
  343. function testRangeEndingWithBR2() {
  344. dynamic.innerHTML = '<span id="a">123<br></span>';
  345. var spanElem = goog.dom.getElement('a');
  346. var range =
  347. goog.dom.browserrange.createRangeFromNodes(spanElem, 0, spanElem, 2);
  348. var htmlText = range.getValidHtml().toLowerCase();
  349. assertContains('Should include BR in HTML.', 'br', htmlText);
  350. assertEquals('Should have correct text.', '123', range.getText());
  351. range.select();
  352. var selRange = goog.dom.Range.createFromWindow();
  353. var startNode = selRange.getStartNode();
  354. var endNode = selRange.getEndNode();
  355. if (startNode.nodeType == goog.dom.NodeType.TEXT) {
  356. // Special case for Webkit (up to Chrome 57) and IE8.
  357. assertEquals('Start node should have text:123', '123', startNode.nodeValue);
  358. } else {
  359. assertEquals('Start node should be span', spanElem, startNode);
  360. }
  361. assertEquals('Startoffset should be 0', 0, selRange.getStartOffset());
  362. if (endNode.nodeType == goog.dom.NodeType.TEXT) {
  363. // Special case for Webkit (up to Chrome 57) and IE8.
  364. assertEquals('Endnode should have text', '123', endNode.nodeValue);
  365. assertEquals('Endoffset should be 3', 3, selRange.getEndOffset());
  366. } else {
  367. assertEquals('Endnode should be span', spanElem, endNode);
  368. assertEquals('Endoffset should be 2', 2, selRange.getEndOffset());
  369. }
  370. }
  371. function testRangeEndingBeforeBR() {
  372. dynamic.innerHTML = '<span id="a">123<br>456</span>';
  373. var spanElem = goog.dom.getElement('a');
  374. var range =
  375. goog.dom.browserrange.createRangeFromNodes(spanElem, 0, spanElem, 1);
  376. var htmlText = range.getValidHtml().toLowerCase();
  377. assertNotContains('Should not include BR in HTML.', 'br', htmlText);
  378. assertEquals('Should have correct text.', '123', range.getText());
  379. range.select();
  380. var selRange = goog.dom.Range.createFromWindow();
  381. var startNode = selRange.getStartNode();
  382. if (startNode.nodeType == goog.dom.NodeType.TEXT) {
  383. // Special case for Webkit (up to Chrome 57) and IE8.
  384. assertEquals('Startnode should have text:123', '123', startNode.nodeValue);
  385. } else {
  386. assertEquals('Start node should be span', spanElem, startNode);
  387. }
  388. assertEquals('Startoffset should be 0', 0, selRange.getStartOffset());
  389. var endNode = selRange.getEndNode();
  390. if (endNode.nodeType == goog.dom.NodeType.TEXT) {
  391. // Special case for Webkit (up to Chrome 57) and IE8.
  392. assertEquals('Endnode should have text:123', '123', endNode.nodeValue);
  393. assertEquals('Endoffset should be 3', 3, selRange.getEndOffset());
  394. } else {
  395. assertEquals('Endnode should be span', spanElem, endNode);
  396. assertEquals('Endoffset should be 1', 1, selRange.getEndOffset());
  397. }
  398. }
  399. function testRangeStartingWithBR() {
  400. dynamic.innerHTML = '<span id="a">123<br>456</span>';
  401. var spanElem = goog.dom.getElement('a');
  402. var range =
  403. goog.dom.browserrange.createRangeFromNodes(spanElem, 1, spanElem, 3);
  404. var htmlText = range.getValidHtml().toLowerCase();
  405. assertContains('Should include BR in HTML.', 'br', htmlText);
  406. // Firefox returns '456' as the range text while IE returns '\r\n456'.
  407. // Therefore skipping the text check.
  408. range.select();
  409. var selRange = goog.dom.Range.createFromWindow();
  410. var startNode = selRange.getStartNode();
  411. var endNode = selRange.getEndNode();
  412. if (startNode.nodeType == goog.dom.NodeType.TEXT) {
  413. // Special case for Webkit (up to Chrome 57) and IE8.
  414. assertEquals('Start node should be text:123', '123', startNode.nodeValue);
  415. assertEquals('Startoffset should be 1', 1, selRange.getStartOffset());
  416. } else {
  417. assertEquals('Start node should be span', spanElem, startNode);
  418. assertEquals('Startoffset should be 1', 1, selRange.getStartOffset());
  419. }
  420. if (endNode.nodeType == goog.dom.NodeType.TEXT) {
  421. assertEquals('Endnode should have text:456', '456', endNode.nodeValue);
  422. assertEquals('Endoffset should be 3', 3, selRange.getEndOffset());
  423. } else {
  424. assertEquals('Endnode should be span', spanElem, endNode);
  425. assertEquals('Endoffset should be 3', 3, selRange.getEndOffset());
  426. }
  427. }
  428. function testRangeStartingAfterBR() {
  429. dynamic.innerHTML = '<span id="a">123<br>4567</span>';
  430. var spanElem = goog.dom.getElement('a');
  431. var range =
  432. goog.dom.browserrange.createRangeFromNodes(spanElem, 2, spanElem, 3);
  433. var htmlText = range.getValidHtml().toLowerCase();
  434. assertNotContains('Should not include BR in HTML.', 'br', htmlText);
  435. assertEquals('Should have correct text.', '4567', range.getText());
  436. range.select();
  437. var selRange = goog.dom.Range.createFromWindow();
  438. var startNode = selRange.getStartNode();
  439. if (startNode.nodeType == goog.dom.NodeType.TEXT) {
  440. // Special case for Webkit (up to Chrome 57) and IE8.
  441. assertEquals(
  442. 'Startnode should have text:4567', '4567', startNode.nodeValue);
  443. assertEquals('Startoffset should be 0', 0, selRange.getStartOffset());
  444. } else {
  445. assertEquals('Start node should be span', spanElem, startNode);
  446. assertEquals('Startoffset should be 2', 2, selRange.getStartOffset());
  447. }
  448. var endNode = selRange.getEndNode();
  449. if (startNode.nodeType == goog.dom.NodeType.TEXT) {
  450. // Special case for Webkit (up to Chrome 57) and IE8.
  451. assertEquals('Endnode should have text:4567', '4567', endNode.nodeValue);
  452. assertEquals('Endoffset should be 4', 4, selRange.getEndOffset());
  453. } else {
  454. assertEquals('Endnode should be span', spanElem, endNode);
  455. assertEquals('Endoffset should be 3', 3, selRange.getEndOffset());
  456. }
  457. }
  458. function testCollapsedRangeBeforeBR() {
  459. dynamic.innerHTML = '<span id="a">123<br>456</span>';
  460. var range = goog.dom.browserrange.createRangeFromNodes(
  461. goog.dom.getElement('a'), 1, goog.dom.getElement('a'), 1);
  462. // Firefox returns <span id="a"></span> as the range HTML while IE returns
  463. // empty string. Therefore skipping the HTML check.
  464. assertEquals('Should have no text.', '', range.getText());
  465. }
  466. function testCollapsedRangeAfterBR() {
  467. dynamic.innerHTML = '<span id="a">123<br>456</span>';
  468. var range = goog.dom.browserrange.createRangeFromNodes(
  469. goog.dom.getElement('a'), 2, goog.dom.getElement('a'), 2);
  470. // Firefox returns <span id="a"></span> as the range HTML while IE returns
  471. // empty string. Therefore skipping the HTML check.
  472. assertEquals('Should have no text.', '', range.getText());
  473. }
  474. function testCompareBrowserRangeEndpoints() {
  475. var outer = goog.dom.getElement('outer');
  476. var inner = goog.dom.getElement('inner');
  477. var range_outer = goog.dom.browserrange.createRangeFromNodeContents(outer);
  478. var range_inner = goog.dom.browserrange.createRangeFromNodeContents(inner);
  479. assertEquals(
  480. 'The start of the inner selection should be after the outer.', 1,
  481. range_inner.compareBrowserRangeEndpoints(
  482. range_outer.getBrowserRange(), goog.dom.RangeEndpoint.START,
  483. goog.dom.RangeEndpoint.START));
  484. assertEquals(
  485. "The start of the inner selection should be before the outer's end.", -1,
  486. range_inner.compareBrowserRangeEndpoints(
  487. range_outer.getBrowserRange(), goog.dom.RangeEndpoint.START,
  488. goog.dom.RangeEndpoint.END));
  489. assertEquals(
  490. "The end of the inner selection should be after the outer's start.", 1,
  491. range_inner.compareBrowserRangeEndpoints(
  492. range_outer.getBrowserRange(), goog.dom.RangeEndpoint.END,
  493. goog.dom.RangeEndpoint.START));
  494. assertEquals(
  495. "The end of the inner selection should be before the outer's end.", -1,
  496. range_inner.compareBrowserRangeEndpoints(
  497. range_outer.getBrowserRange(), goog.dom.RangeEndpoint.END,
  498. goog.dom.RangeEndpoint.END));
  499. }
  500. /**
  501. * Regression test for a bug in IeRange.insertNode_ where if the node to be
  502. * inserted was not an element (e.g. a text node), it would clone the node
  503. * in the inserting process but return the original node instead of the newly
  504. * created and inserted node.
  505. */
  506. function testInsertNodeNonElement() {
  507. goog.dom.setTextContent(dynamic, 'beforeafter');
  508. var range = goog.dom.browserrange.createRangeFromNodes(
  509. dynamic.firstChild, 6, dynamic.firstChild, 6);
  510. var newNode = goog.dom.createTextNode('INSERTED');
  511. var inserted = range.insertNode(newNode, false);
  512. assertEquals(
  513. 'Text should be inserted between "before" and "after"',
  514. 'beforeINSERTEDafter', goog.dom.getRawTextContent(dynamic));
  515. assertEquals(
  516. 'Node returned by insertNode() should be a child of the div' +
  517. ' containing the text',
  518. dynamic, inserted.parentNode);
  519. }
  520. function testSelectOverwritesOldSelection() {
  521. goog.dom.browserrange.createRangeFromNodes(test1, 0, test1, 1).select();
  522. goog.dom.browserrange.createRangeFromNodes(test2, 0, test2, 1).select();
  523. assertEquals(
  524. 'The old selection must be replaced with the new one', 'abc',
  525. goog.dom.Range.createFromWindow().getText());
  526. }
  527. // Following testcase is special for IE. The comparison of ranges created in
  528. // testcases with a range over empty span using native inRange fails. So the
  529. // fallback mechanism is needed.
  530. function testGetContainerInTextNodesAroundEmptySpan() {
  531. dynamic.innerHTML = 'abc<span></span>def';
  532. var abc = dynamic.firstChild;
  533. var def = dynamic.lastChild;
  534. var range;
  535. range = goog.dom.browserrange.createRangeFromNodes(abc, 1, abc, 1);
  536. assertEquals(
  537. 'textNode abc should be the range container', abc, range.getContainer());
  538. assertEquals(
  539. 'textNode abc should be the range start node', abc, range.getStartNode());
  540. assertEquals(
  541. 'textNode abc should be the range end node', abc, range.getEndNode());
  542. range = goog.dom.browserrange.createRangeFromNodes(def, 1, def, 1);
  543. assertEquals(
  544. 'textNode def should be the range container', def, range.getContainer());
  545. assertEquals(
  546. 'textNode def should be the range start node', def, range.getStartNode());
  547. assertEquals(
  548. 'textNode def should be the range end node', def, range.getEndNode());
  549. }