firststrong_test.js 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440
  1. // Copyright 2012 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.editor.plugins.FirstStrongTest');
  15. goog.setTestOnly('goog.editor.plugins.FirstStrongTest');
  16. goog.require('goog.dom.Range');
  17. goog.require('goog.editor.Command');
  18. goog.require('goog.editor.Field');
  19. goog.require('goog.editor.plugins.FirstStrong');
  20. goog.require('goog.editor.range');
  21. goog.require('goog.events.KeyCodes');
  22. goog.require('goog.testing.MockClock');
  23. goog.require('goog.testing.editor.TestHelper');
  24. goog.require('goog.testing.events');
  25. goog.require('goog.testing.jsunit');
  26. goog.require('goog.userAgent');
  27. // The key code for the Hebrew א, a strongly RTL letter.
  28. var ALEPH_KEYCODE = 1488;
  29. var field;
  30. var fieldElement;
  31. var dom;
  32. var helper;
  33. var triggeredCommand = null;
  34. var clock;
  35. function setUp() {
  36. field = new goog.editor.Field('field');
  37. field.registerPlugin(new goog.editor.plugins.FirstStrong());
  38. field.makeEditable();
  39. fieldElement = field.getElement();
  40. helper = new goog.testing.editor.TestHelper(fieldElement);
  41. dom = field.getEditableDomHelper();
  42. // Mock out execCommand to see if a direction change has been triggered.
  43. field.execCommand = function(command) {
  44. if (command == goog.editor.Command.DIR_LTR ||
  45. command == goog.editor.Command.DIR_RTL)
  46. triggeredCommand = command;
  47. };
  48. }
  49. function tearDown() {
  50. goog.dispose(field);
  51. goog.dispose(helper);
  52. triggeredCommand = null;
  53. goog.dispose(clock); // Make sure clock is disposed.
  54. }
  55. function testFirstCharacter_RTL() {
  56. field.setHtml(false, '<div id="text">&nbsp;</div>');
  57. field.focusAndPlaceCursorAtStart();
  58. goog.testing.events.fireNonAsciiKeySequence(
  59. fieldElement, goog.events.KeyCodes.T, ALEPH_KEYCODE);
  60. assertRTL();
  61. }
  62. function testFirstCharacter_LTR() {
  63. field.setHtml(false, '<div dir="rtl" id="text">&nbsp;</div>');
  64. field.focusAndPlaceCursorAtStart();
  65. goog.testing.events.fireKeySequence(fieldElement, goog.events.KeyCodes.A);
  66. assertLTR();
  67. }
  68. function testFirstStrongCharacter_RTL() {
  69. field.setHtml(false, '<div id="text">123.7 3121, <b><++{}></b> - $45</div>');
  70. field.focusAndPlaceCursorAtStart();
  71. goog.testing.events.fireNonAsciiKeySequence(
  72. fieldElement, goog.events.KeyCodes.T, ALEPH_KEYCODE);
  73. assertRTL();
  74. }
  75. function testFirstStrongCharacter_LTR() {
  76. field.setHtml(
  77. false, '<div dir="rtl" id="text">123.7 3121, <b><++{}></b> - $45</div>');
  78. field.focusAndPlaceCursorAtStart();
  79. goog.testing.events.fireKeySequence(fieldElement, goog.events.KeyCodes.A);
  80. assertLTR();
  81. }
  82. function testNotStrongCharacter_RTL() {
  83. field.setHtml(false, '<div id="text">123.7 3121, - $45</div>');
  84. field.focusAndPlaceCursorAtStart();
  85. goog.testing.events.fireKeySequence(fieldElement, goog.events.KeyCodes.NINE);
  86. assertNoCommand();
  87. }
  88. function testNotStrongCharacter_LTR() {
  89. field.setHtml(false, '<div dir="rtl" id="text">123.7 3121 $45</div>');
  90. field.focusAndPlaceCursorAtStart();
  91. goog.testing.events.fireKeySequence(fieldElement, goog.events.KeyCodes.NINE);
  92. assertNoCommand();
  93. }
  94. function testNotFirstStrongCharacter_RTL() {
  95. field.setHtml(false, '<div id="text">123.7 3121, <b>English</b> - $45</div>');
  96. field.focusAndPlaceCursorAtStart();
  97. goog.testing.events.fireNonAsciiKeySequence(
  98. fieldElement, goog.events.KeyCodes.T, ALEPH_KEYCODE);
  99. assertNoCommand();
  100. }
  101. function testNotFirstStrongCharacter_LTR() {
  102. field.setHtml(
  103. false, '<div dir="rtl" id="text">123.7 3121, <b>עברית</b> - $45</div>');
  104. field.focusAndPlaceCursorAtStart();
  105. goog.testing.events.fireKeySequence(fieldElement, goog.events.KeyCodes.A);
  106. assertNoCommand();
  107. }
  108. function testFirstStrongCharacterWithInnerDiv_RTL() {
  109. field.setHtml(
  110. false, '<div id="text">123.7 3121, <b id="b"><++{}></b>' +
  111. '<div id="inner">English</div>' +
  112. '</div>');
  113. field.focusAndPlaceCursorAtStart();
  114. goog.testing.events.fireNonAsciiKeySequence(
  115. fieldElement, goog.events.KeyCodes.T, ALEPH_KEYCODE);
  116. assertRTL();
  117. }
  118. function testFirstStrongCharacterWithInnerDiv_LTR() {
  119. field.setHtml(
  120. false, '<div dir="rtl" id="text">123.7 3121, <b id="b"><++{}></b>' +
  121. '<div id="inner">English</div>' +
  122. '</div>');
  123. field.focusAndPlaceCursorAtStart();
  124. goog.testing.events.fireKeySequence(fieldElement, goog.events.KeyCodes.A);
  125. assertLTR();
  126. }
  127. /**
  128. * Regression test for {@link http://b/7549696}
  129. */
  130. function testFirstStrongCharacterInNewLine_RTL() {
  131. field.setHtml(false, '<div><b id="cur">English<br>1</b></div>');
  132. goog.dom.Range.createCaret(dom.$('cur'), 2).select();
  133. goog.testing.events.fireNonAsciiKeySequence(
  134. fieldElement, goog.events.KeyCodes.T, ALEPH_KEYCODE);
  135. // Only GECKO treats <br> as a new paragraph.
  136. if (goog.userAgent.GECKO) {
  137. assertRTL();
  138. } else {
  139. assertNoCommand();
  140. }
  141. }
  142. function testFirstStrongCharacterInParagraph_RTL() {
  143. field.setHtml(
  144. false, '<div id="text1">1&gt; English</div>' +
  145. '<div id="text2">2&gt;</div>' +
  146. '<div id="text3">3&gt;</div>');
  147. goog.dom.Range.createCaret(dom.$('text2'), 0).select();
  148. goog.testing.events.fireNonAsciiKeySequence(
  149. fieldElement, goog.events.KeyCodes.T, ALEPH_KEYCODE);
  150. assertRTL();
  151. }
  152. function testFirstStrongCharacterInParagraph_LTR() {
  153. field.setHtml(
  154. false, '<div dir="rtl" id="text1">1&gt; עברית</div>' +
  155. '<div dir="rtl" id="text2">2&gt;</div>' +
  156. '<div dir="rtl" id="text3">3&gt;</div>');
  157. goog.dom.Range.createCaret(dom.$('text2'), 0).select();
  158. goog.testing.events.fireKeySequence(fieldElement, goog.events.KeyCodes.A);
  159. assertLTR();
  160. }
  161. function testFirstStrongCharacterInList_RTL() {
  162. field.setHtml(
  163. false, '<div id="text1">1&gt; English</div>' +
  164. '<ul id="list">' +
  165. '<li>10&gt;</li>' +
  166. '<li id="li2"></li>' +
  167. '<li>30</li>' +
  168. '</ul>' +
  169. '<div id="text3">3&gt;</div>');
  170. goog.editor.range.placeCursorNextTo(dom.$('li2'), true);
  171. goog.testing.events.fireNonAsciiKeySequence(
  172. fieldElement, goog.events.KeyCodes.T, ALEPH_KEYCODE);
  173. assertRTL();
  174. }
  175. function testFirstStrongCharacterInList_LTR() {
  176. field.setHtml(
  177. false, '<div dir="rtl" id="text1">1&gt; English</div>' +
  178. '<ul dir="rtl" id="list">' +
  179. '<li>10&gt;</li>' +
  180. '<li id="li2"></li>' +
  181. '<li>30</li>' +
  182. '</ul>' +
  183. '<div dir="rtl" id="text3">3&gt;</div>');
  184. goog.editor.range.placeCursorNextTo(dom.$('li2'), true);
  185. goog.testing.events.fireKeySequence(fieldElement, goog.events.KeyCodes.A);
  186. assertLTR();
  187. }
  188. function testNotFirstStrongCharacterInList_RTL() {
  189. field.setHtml(
  190. false, '<div id="text1">1</div>' +
  191. '<ul id="list">' +
  192. '<li>10&gt;</li>' +
  193. '<li id="li2"></li>' +
  194. '<li>30<b>3<i>Hidden English</i>32</b></li>' +
  195. '</ul>' +
  196. '<div id="text3">3&gt;</div>');
  197. goog.editor.range.placeCursorNextTo(dom.$('li2'), true);
  198. goog.testing.events.fireNonAsciiKeySequence(
  199. fieldElement, goog.events.KeyCodes.T, ALEPH_KEYCODE);
  200. assertNoCommand();
  201. }
  202. function testNotFirstStrongCharacterInList_LTR() {
  203. field.setHtml(
  204. false, '<div dir="rtl" id="text1">1&gt; English</div>' +
  205. '<ul dir="rtl" id="list">' +
  206. '<li>10&gt;</li>' +
  207. '<li id="li2"></li>' +
  208. '<li>30<b>3<i>עברית סמויה</i>32</b></li>' +
  209. '</ul>' +
  210. '<div dir="rtl" id="text3">3&gt;</div>');
  211. goog.editor.range.placeCursorNextTo(dom.$('li2'), true);
  212. goog.testing.events.fireKeySequence(fieldElement, goog.events.KeyCodes.A);
  213. assertNoCommand();
  214. }
  215. function testFirstStrongCharacterWithBR_RTL() {
  216. field.setHtml(
  217. false, '<div id="container">' +
  218. '<div id="text1">ABC</div>' +
  219. '<div id="text2">' +
  220. '1<br>' +
  221. '2<b id="inner">3</b><i>4<u>5<br>' +
  222. '6</u>7</i>8</b>9<br>' +
  223. '10' +
  224. '</div>' +
  225. '<div id="text3">11</div>' +
  226. '</div>');
  227. goog.editor.range.placeCursorNextTo(dom.$('inner'), true);
  228. goog.testing.events.fireNonAsciiKeySequence(
  229. fieldElement, goog.events.KeyCodes.T, ALEPH_KEYCODE);
  230. assertRTL();
  231. }
  232. function testFirstStrongCharacterWithBR_LTR() {
  233. field.setHtml(
  234. false, '<div dir="rtl" id="container">' +
  235. '<div dir="rtl" id="text1">אבג</div>' +
  236. '<div dir="rtl" id="text2">' +
  237. '1<br>' +
  238. '2<b id="inner">3</b><i>4<u>5<br>' +
  239. '6</u>7</i>8</b>9<br>' +
  240. '10' +
  241. '</div>' +
  242. '<div dir="rtl" id="text3">11</div>' +
  243. '</div>');
  244. goog.editor.range.placeCursorNextTo(dom.$('inner'), true);
  245. goog.testing.events.fireKeySequence(fieldElement, goog.events.KeyCodes.A);
  246. assertLTR();
  247. }
  248. function testNotFirstStrongCharacterInBR_RTL() {
  249. field.setHtml(
  250. false, '<div id="container">' +
  251. '<div id="text1">ABC</div>' +
  252. '<div id="text2">' +
  253. '1<br>' +
  254. '2<b id="inner">3</b><i><em>4G</em><u>5<br>' +
  255. '6</u>7</i>8</b>9<br>' +
  256. '10' +
  257. '</div>' +
  258. '<div id="text3">11</div>' +
  259. '</div>');
  260. goog.editor.range.placeCursorNextTo(dom.$('inner'), true);
  261. goog.testing.events.fireNonAsciiKeySequence(
  262. fieldElement, goog.events.KeyCodes.T, ALEPH_KEYCODE);
  263. assertNoCommand();
  264. }
  265. function testNotFirstStrongCharacterInBR_LTR() {
  266. field.setHtml(
  267. false, '<div dir="rtl" id="container">' +
  268. '<div dir="rtl" id="text1">ABC</div>' +
  269. '<div dir="rtl" id="text2">' +
  270. '1<br>' +
  271. '2<b id="inner">3</b><i><em>4G</em><u>5<br>' +
  272. '6</u>7</i>8</b>9<br>' +
  273. '10' +
  274. '</div>' +
  275. '<div dir="rtl" id="text3">11</div>' +
  276. '</div>');
  277. goog.editor.range.placeCursorNextTo(dom.$('inner'), true);
  278. goog.testing.events.fireKeySequence(fieldElement, goog.events.KeyCodes.A);
  279. assertNoCommand();
  280. }
  281. /**
  282. * Regression test for {@link http://b/7530985}
  283. */
  284. function testFirstStrongCharacterWithPreviousBlockSibling_RTL() {
  285. field.setHtml(false, '<div>Te<div>xt</div>1<b id="cur">2</b>3</div>');
  286. goog.editor.range.placeCursorNextTo(dom.$('cur'), true);
  287. goog.testing.events.fireNonAsciiKeySequence(
  288. fieldElement, goog.events.KeyCodes.T, ALEPH_KEYCODE);
  289. assertRTL();
  290. }
  291. function testFirstStrongCharacterWithPreviousBlockSibling_LTR() {
  292. field.setHtml(
  293. false, '<div dir="rtl">טק<div>סט</div>1<b id="cur">2</b>3</div>');
  294. goog.editor.range.placeCursorNextTo(dom.$('cur'), true);
  295. goog.testing.events.fireKeySequence(fieldElement, goog.events.KeyCodes.A);
  296. assertLTR();
  297. }
  298. function testFirstStrongCharacterWithFollowingBlockSibling_RTL() {
  299. field.setHtml(false, '<div>1<b id="cur">2</b>3<div>Te</div>xt</div>');
  300. goog.editor.range.placeCursorNextTo(dom.$('cur'), true);
  301. goog.testing.events.fireNonAsciiKeySequence(
  302. fieldElement, goog.events.KeyCodes.T, ALEPH_KEYCODE);
  303. assertRTL();
  304. }
  305. function testFirstStrongCharacterWithFollowingBlockSibling_RTL() {
  306. field.setHtml(false, '<div dir="rtl">1<b id="cur">2</b>3<div>א</div>ב</div>');
  307. goog.editor.range.placeCursorNextTo(dom.$('cur'), true);
  308. goog.testing.events.fireKeySequence(fieldElement, goog.events.KeyCodes.A);
  309. assertLTR();
  310. }
  311. function testFirstStrongCharacterFromIME_RTL() {
  312. field.setHtml(false, '<div id="text">123.7 3121, </div>');
  313. field.focusAndPlaceCursorAtStart();
  314. var attributes = {};
  315. attributes[goog.editor.plugins.FirstStrong.INPUT_ATTRIBUTE] = 'אבג';
  316. goog.testing.events.fireNonAsciiKeySequence(fieldElement, 0, 0, attributes);
  317. if (goog.userAgent.IE) {
  318. // goog.testing.events.fireNonAsciiKeySequence doesn't send KEYPRESS event
  319. // so no command is expected.
  320. assertNoCommand();
  321. } else {
  322. assertRTL();
  323. }
  324. }
  325. function testFirstCharacterFromIME_LTR() {
  326. field.setHtml(false, '<div dir="rtl" id="text"> 1234 </div>');
  327. field.focusAndPlaceCursorAtStart();
  328. var attributes = {};
  329. attributes[goog.editor.plugins.FirstStrong.INPUT_ATTRIBUTE] = 'ABC';
  330. goog.testing.events.fireNonAsciiKeySequence(fieldElement, 0, 0, attributes);
  331. if (goog.userAgent.IE) {
  332. // goog.testing.events.fireNonAsciiKeySequence doesn't send KEYPRESS event
  333. // so no command is expected.
  334. assertNoCommand();
  335. } else {
  336. assertLTR();
  337. }
  338. }
  339. /**
  340. * Regression test for {@link http://b/19297723}
  341. */
  342. function testLTRShortlyAfterRTLAndEnter() {
  343. clock = new goog.testing.MockClock();
  344. field.focusAndPlaceCursorAtStart();
  345. goog.testing.events.fireNonAsciiKeySequence(
  346. fieldElement, goog.events.KeyCodes.T, ALEPH_KEYCODE);
  347. assertRTL();
  348. clock.tick(1000); // Make sure no pending selection change event.
  349. goog.testing.events.fireKeySequence(fieldElement, goog.events.KeyCodes.ENTER);
  350. assertRTL();
  351. goog.testing.events.fireKeySequence(fieldElement, goog.events.KeyCodes.A);
  352. assertLTR();
  353. // Verify no RTL for first keypress on already-striong paragraph after
  354. // delayed selection change event.
  355. clock.tick(1000); // Let delayed selection change event fire.
  356. goog.testing.events.fireNonAsciiKeySequence(
  357. fieldElement, goog.events.KeyCodes.T, ALEPH_KEYCODE);
  358. assertLTR();
  359. }
  360. function testRTLShortlyAfterLTRAndEnter() {
  361. clock = new goog.testing.MockClock();
  362. field.focusAndPlaceCursorAtStart();
  363. goog.testing.events.fireKeySequence(fieldElement, goog.events.KeyCodes.A);
  364. assertLTR();
  365. clock.tick(1000); // Make sure no pending selection change event.
  366. goog.testing.events.fireKeySequence(fieldElement, goog.events.KeyCodes.ENTER);
  367. assertLTR();
  368. goog.testing.events.fireNonAsciiKeySequence(
  369. fieldElement, goog.events.KeyCodes.T, ALEPH_KEYCODE);
  370. assertRTL();
  371. // Verify no LTR for first keypress on already-strong paragraph after
  372. // delayed selection change event.
  373. clock.tick(1000); // Let delayed selection change event fire.
  374. goog.testing.events.fireKeySequence(fieldElement, goog.events.KeyCodes.A);
  375. assertRTL();
  376. }
  377. function assertRTL() {
  378. assertEquals(goog.editor.Command.DIR_RTL, triggeredCommand);
  379. }
  380. function assertLTR() {
  381. assertEquals(goog.editor.Command.DIR_LTR, triggeredCommand);
  382. }
  383. function assertNoCommand() {
  384. assertNull(triggeredCommand);
  385. }