textrange_test.js 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324
  1. // Copyright 2008 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.TextRangeTest');
  15. goog.setTestOnly('goog.dom.TextRangeTest');
  16. goog.require('goog.dom');
  17. goog.require('goog.dom.ControlRange');
  18. goog.require('goog.dom.Range');
  19. goog.require('goog.dom.TextRange');
  20. goog.require('goog.math.Coordinate');
  21. goog.require('goog.style');
  22. goog.require('goog.testing.ExpectedFailures');
  23. goog.require('goog.testing.jsunit');
  24. goog.require('goog.userAgent');
  25. goog.require('goog.userAgent.product');
  26. var logo;
  27. var logo2;
  28. var logo3;
  29. var logo3Rtl;
  30. var table;
  31. var table2;
  32. var table2div;
  33. var test3;
  34. var test3Rtl;
  35. var expectedFailures;
  36. function setUpPage() {
  37. logo = goog.dom.getElement('logo');
  38. logo2 = goog.dom.getElement('logo2');
  39. logo3 = goog.dom.getElement('logo3');
  40. logo3Rtl = goog.dom.getElement('logo3Rtl');
  41. table = goog.dom.getElement('table');
  42. table2 = goog.dom.getElement('table2');
  43. table2div = goog.dom.getElement('table2div');
  44. test3 = goog.dom.getElement('test3');
  45. test3Rtl = goog.dom.getElement('test3Rtl');
  46. expectedFailures = new goog.testing.ExpectedFailures();
  47. }
  48. function tearDown() {
  49. expectedFailures.handleTearDown();
  50. }
  51. function testCreateFromNodeContents() {
  52. assertNotNull(
  53. 'Text range object can be created for element node',
  54. goog.dom.TextRange.createFromNodeContents(logo));
  55. assertNotNull(
  56. 'Text range object can be created for text node',
  57. goog.dom.TextRange.createFromNodeContents(logo2.previousSibling));
  58. }
  59. function testMoveToNodes() {
  60. var range = goog.dom.TextRange.createFromNodeContents(table2);
  61. range.moveToNodes(table2div, 0, table2div, 1, false);
  62. assertEquals(
  63. 'Range should start in table2div', table2div, range.getStartNode());
  64. assertEquals('Range should end in table2div', table2div, range.getEndNode());
  65. assertEquals('Range start offset should be 0', 0, range.getStartOffset());
  66. assertEquals('Range end offset should be 0', 1, range.getEndOffset());
  67. assertFalse('Range should not be reversed', range.isReversed());
  68. range.moveToNodes(table2div, 0, table2div, 1, true);
  69. assertTrue('Range should be reversed', range.isReversed());
  70. assertEquals('Range text should be "foo"', 'foo', range.getText());
  71. }
  72. function testContainsTextRange() {
  73. var range = goog.dom.TextRange.createFromNodeContents(table2);
  74. var range2 = goog.dom.TextRange.createFromNodeContents(table2div);
  75. assertTrue('TextRange contains other TextRange', range.containsRange(range2));
  76. assertFalse(
  77. 'TextRange does not contain other TextRange',
  78. range2.containsRange(range));
  79. range = goog.dom.Range.createFromNodes(
  80. table2div.firstChild, 1, table2div.lastChild, 1);
  81. range2 = goog.dom.TextRange.createFromNodes(
  82. table2div.firstChild, 0, table2div.lastChild, 0);
  83. assertTrue(
  84. 'TextRange partially contains other TextRange',
  85. range2.containsRange(range, true));
  86. assertFalse(
  87. 'TextRange does not fully contain other TextRange',
  88. range2.containsRange(range, false));
  89. }
  90. function testContainsControlRange() {
  91. if (goog.userAgent.IE) {
  92. var range = goog.dom.ControlRange.createFromElements(table2);
  93. var range2 = goog.dom.TextRange.createFromNodeContents(table2div);
  94. assertFalse(
  95. 'TextRange does not contain ControlRange', range2.containsRange(range));
  96. range = goog.dom.ControlRange.createFromElements(logo2);
  97. assertTrue('TextRange contains ControlRange', range2.containsRange(range));
  98. range = goog.dom.TextRange.createFromNodeContents(table2);
  99. range2 = goog.dom.ControlRange.createFromElements(logo, logo2);
  100. assertTrue(
  101. 'TextRange partially contains ControlRange',
  102. range2.containsRange(range, true));
  103. assertFalse(
  104. 'TextRange does not fully contain ControlRange',
  105. range2.containsRange(range, false));
  106. }
  107. }
  108. function getTest3ElementTopLeft() {
  109. var topLeft = goog.style.getPageOffset(test3.firstChild);
  110. if (goog.userAgent.EDGE_OR_IE) {
  111. // On IE the selection is as tall as its tallest element.
  112. var logoPosition = goog.style.getPageOffset(logo3);
  113. topLeft.y = logoPosition.y;
  114. if (!goog.userAgent.isVersionOrHigher('8')) {
  115. topLeft.x += 2;
  116. topLeft.y += 2;
  117. }
  118. }
  119. return topLeft;
  120. }
  121. function testGetStartPosition() {
  122. expectedFailures.expectFailureFor(
  123. goog.userAgent.GECKO && !goog.userAgent.isVersionOrHigher('2'));
  124. // The start node is in the top left.
  125. var range = goog.dom.TextRange.createFromNodeContents(test3);
  126. try {
  127. var result = assertNotThrows(goog.bind(range.getStartPosition, range));
  128. assertObjectRoughlyEquals(getTest3ElementTopLeft(), result, 1);
  129. } catch (e) {
  130. expectedFailures.handleException(e);
  131. }
  132. }
  133. function testGetStartPositionNotInDocument() {
  134. expectedFailures.expectFailureFor(
  135. goog.userAgent.GECKO && !goog.userAgent.isVersionOrHigher('2'));
  136. expectedFailures.expectFailureFor(
  137. goog.userAgent.IE && !goog.userAgent.isVersionOrHigher('8'));
  138. var range = goog.dom.TextRange.createFromNodeContents(test3);
  139. goog.dom.removeNode(test3);
  140. try {
  141. var result = assertNotThrows(goog.bind(range.getStartPosition, range));
  142. assertNull(result);
  143. } catch (e) {
  144. expectedFailures.handleException(e);
  145. } finally {
  146. goog.dom.appendChild(document.body, test3);
  147. }
  148. }
  149. function testGetStartPositionReversed() {
  150. expectedFailures.expectFailureFor(
  151. goog.userAgent.GECKO && !goog.userAgent.isVersionOrHigher('2'));
  152. // Simulate the user selecting backwards from right-to-left.
  153. // The start node is now in the bottom right.
  154. var firstNode = test3.firstChild.firstChild;
  155. var lastNode = test3.lastChild.lastChild;
  156. var range = goog.dom.TextRange.createFromNodes(
  157. lastNode, lastNode.nodeValue.length, firstNode, 0);
  158. try {
  159. var result = assertNotThrows(goog.bind(range.getStartPosition, range));
  160. assertObjectRoughlyEquals(getTest3ElementTopLeft(), result, 1);
  161. } catch (e) {
  162. expectedFailures.handleException(e);
  163. }
  164. }
  165. function testGetStartPositionRightToLeft() {
  166. if (goog.userAgent.product.SAFARI) {
  167. // TODO(b/20733468): Disabled so we can get the rest of the Closure test
  168. // suite running in a continuous build. Will investigate later.
  169. return;
  170. }
  171. expectedFailures.expectFailureFor(
  172. goog.userAgent.GECKO && !goog.userAgent.isVersionOrHigher('2'));
  173. // Even in RTL content the start node is still in the top left.
  174. var range = goog.dom.TextRange.createFromNodeContents(test3Rtl);
  175. var topLeft = goog.style.getPageOffset(test3Rtl.firstChild);
  176. if (goog.userAgent.EDGE_OR_IE) {
  177. // On IE the selection is as tall as its tallest element.
  178. var logoPosition = goog.style.getPageOffset(logo3Rtl);
  179. topLeft.y = logoPosition.y;
  180. if (!goog.userAgent.isVersionOrHigher('8')) {
  181. topLeft.x += 2;
  182. topLeft.y += 2;
  183. }
  184. }
  185. try {
  186. var result = assertNotThrows(goog.bind(range.getStartPosition, range));
  187. assertObjectRoughlyEquals(topLeft, result, 0.1);
  188. } catch (e) {
  189. expectedFailures.handleException(e);
  190. }
  191. }
  192. function getTest3ElementBottomRight() {
  193. var pageOffset = goog.style.getPageOffset(test3.lastChild);
  194. var bottomRight = new goog.math.Coordinate(
  195. pageOffset.x + test3.lastChild.offsetWidth,
  196. pageOffset.y + test3.lastChild.offsetHeight);
  197. if (goog.userAgent.IE && !goog.userAgent.isVersionOrHigher('8')) {
  198. bottomRight.x += 6;
  199. bottomRight.y += 2;
  200. }
  201. return bottomRight;
  202. }
  203. function testGetEndPosition() {
  204. expectedFailures.expectFailureFor(
  205. goog.userAgent.GECKO && !goog.userAgent.isVersionOrHigher('2'));
  206. // The end node is in the bottom right.
  207. var range = goog.dom.TextRange.createFromNodeContents(test3);
  208. var expected = getTest3ElementBottomRight();
  209. try {
  210. var result = assertNotThrows(goog.bind(range.getEndPosition, range));
  211. assertObjectRoughlyEquals(expected, result, 1);
  212. } catch (e) {
  213. expectedFailures.handleException(e);
  214. }
  215. }
  216. function testGetEndPositionNotInDocument() {
  217. expectedFailures.expectFailureFor(
  218. goog.userAgent.GECKO && !goog.userAgent.isVersionOrHigher('2'));
  219. expectedFailures.expectFailureFor(
  220. goog.userAgent.IE && !goog.userAgent.isVersionOrHigher('8'));
  221. var range = goog.dom.TextRange.createFromNodeContents(test3);
  222. goog.dom.removeNode(test3);
  223. try {
  224. var result = assertNotThrows(goog.bind(range.getEndPosition, range));
  225. assertNull(result);
  226. } catch (e) {
  227. expectedFailures.handleException(e);
  228. } finally {
  229. goog.dom.appendChild(document.body, test3);
  230. }
  231. }
  232. function testGetEndPositionReversed() {
  233. expectedFailures.expectFailureFor(
  234. goog.userAgent.GECKO && !goog.userAgent.isVersionOrHigher('2'));
  235. // Simulate the user selecting backwards from right-to-left.
  236. // The end node is still in the lower right.
  237. var range = goog.dom.TextRange.createFromNodeContents(test3, true);
  238. var expected = getTest3ElementBottomRight();
  239. try {
  240. var result = assertNotThrows(goog.bind(range.getEndPosition, range));
  241. // For some reason, ie7 is further off than other browsers.
  242. var estimate =
  243. (goog.userAgent.IE && !goog.userAgent.isVersionOrHigher('8')) ? 4 : 1;
  244. assertObjectRoughlyEquals(expected, result, estimate);
  245. } catch (e) {
  246. expectedFailures.handleException(e);
  247. }
  248. }
  249. function testGetEndPositionRightToLeft() {
  250. expectedFailures.expectFailureFor(
  251. goog.userAgent.GECKO && !goog.userAgent.isVersionOrHigher('2'));
  252. expectedFailures.expectFailureFor(
  253. goog.userAgent.IE && !goog.userAgent.isVersionOrHigher('8'));
  254. // Even in RTL content the end node is still in the bottom right.
  255. var range = goog.dom.TextRange.createFromNodeContents(test3Rtl);
  256. var pageOffset = goog.style.getPageOffset(test3Rtl.lastChild);
  257. var bottomRight = new goog.math.Coordinate(
  258. pageOffset.x + test3Rtl.lastChild.offsetWidth,
  259. pageOffset.y + test3Rtl.lastChild.offsetHeight);
  260. if (goog.userAgent.IE && !goog.userAgent.isVersionOrHigher('8')) {
  261. bottomRight.x += 2;
  262. bottomRight.y += 2;
  263. }
  264. try {
  265. var result = assertNotThrows(goog.bind(range.getEndPosition, range));
  266. assertObjectRoughlyEquals(bottomRight, result, 1);
  267. } catch (e) {
  268. expectedFailures.handleException(e);
  269. }
  270. }
  271. function testCloneRangeDeep() {
  272. var range = goog.dom.TextRange.createFromNodeContents(logo);
  273. assertFalse(range.isCollapsed());
  274. var cloned = range.clone();
  275. cloned.collapse();
  276. assertTrue(cloned.isCollapsed());
  277. assertFalse(range.isCollapsed());
  278. }