renderer_test.js 43 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759
  1. // Copyright 2010 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.ui.ac.RendererTest');
  15. goog.setTestOnly('goog.ui.ac.RendererTest');
  16. goog.require('goog.a11y.aria');
  17. goog.require('goog.a11y.aria.State');
  18. goog.require('goog.dom');
  19. goog.require('goog.dom.TagName');
  20. goog.require('goog.dom.classlist');
  21. goog.require('goog.events');
  22. goog.require('goog.fx.dom.FadeInAndShow');
  23. goog.require('goog.fx.dom.FadeOutAndHide');
  24. goog.require('goog.string');
  25. goog.require('goog.style');
  26. goog.require('goog.testing.PropertyReplacer');
  27. goog.require('goog.testing.jsunit');
  28. goog.require('goog.ui.ac.AutoComplete');
  29. goog.require('goog.ui.ac.Renderer');
  30. var renderer;
  31. var rendRows = [];
  32. var someElement;
  33. var target;
  34. var viewport;
  35. var viewportTarget;
  36. var widthProvder;
  37. var propertyReplacer;
  38. function setUpPage() {
  39. someElement = goog.dom.getElement('someElement');
  40. target = goog.dom.getElement('target');
  41. viewport = goog.dom.getElement('viewport');
  42. viewportTarget = goog.dom.getElement('viewportTarget');
  43. widthProvder = goog.dom.getElement('widthProvider');
  44. propertyReplacer = new goog.testing.PropertyReplacer();
  45. }
  46. // One-time set up of rows formatted for the renderer.
  47. var rows = [
  48. 'Amanda Annie Anderson', 'Frankie Manning', 'Louis D Armstrong',
  49. // NOTE(user): sorry about this test input, but it has caused problems
  50. // in the past, so I want to make sure to test against it.
  51. 'Foo Bar................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................', '<div><div>test</div></div>',
  52. '<div><div>test1</div><div>test2</div></div>',
  53. '<div>random test string<div>test1</div><div><div>test2</div><div>test3</div></div></div>'
  54. ];
  55. for (var i = 0; i < rows.length; i++) {
  56. rendRows.push({id: i, data: rows[i]});
  57. }
  58. function setUp() {
  59. renderer = new goog.ui.ac.Renderer();
  60. renderer.rowDivs_ = [];
  61. renderer.target_ = target;
  62. }
  63. function tearDown() {
  64. renderer.dispose();
  65. propertyReplacer.reset();
  66. }
  67. function testBasicMatchingWithHtmlRow() {
  68. // '<div><div>test</div></div>'
  69. var row = rendRows[4];
  70. var token = 'te';
  71. enableHtmlRendering(renderer);
  72. var node = renderer.renderRowHtml(row, token);
  73. var boldTagElArray = goog.dom.getElementsByTagName(goog.dom.TagName.B, node);
  74. assertNumBoldTags(boldTagElArray, 1);
  75. }
  76. function testShouldMatchOnlyOncePerDefaultWithComplexHtmlStrings() {
  77. // '<div><div>test1</div><div>test2</div></div>'
  78. var row = rendRows[5];
  79. var token = 'te';
  80. enableHtmlRendering(renderer);
  81. var node = renderer.renderRowHtml(row, token);
  82. var boldTagElArray = goog.dom.getElementsByTagName(goog.dom.TagName.B, node);
  83. // It should match and render highlighting for the first 'test1' and
  84. // stop here. This is the default behavior of the renderer.
  85. assertNumBoldTags(boldTagElArray, 1);
  86. }
  87. function testShouldMatchMultipleTimesWithComplexHtmlStrings() {
  88. renderer.setHighlightAllTokens(true);
  89. // '<div><div>test1</div><div>test2</div></div>'
  90. var row = rendRows[5];
  91. var token = 'te';
  92. enableHtmlRendering(renderer);
  93. var node = renderer.renderRowHtml(row, token);
  94. var boldTagElArray = goog.dom.getElementsByTagName(goog.dom.TagName.B, node);
  95. // It should match and render highlighting for both 'test1' and 'test2'.
  96. assertNumBoldTags(boldTagElArray, 2);
  97. // Try again with a more complex HTML string.
  98. // '<div>random test
  99. // string<div>test1</div><div><div>test2</div><div>test3</div></div></div>'
  100. row = rendRows[6];
  101. node = renderer.renderRowHtml(row, token);
  102. boldTagElArray = goog.dom.getElementsByTagName(goog.dom.TagName.B, node);
  103. // It should match 'test', 'test1', 'test2' and 'test3' wherever
  104. // they are in the DOM tree.
  105. assertNumBoldTags(boldTagElArray, 4);
  106. }
  107. function testBasicStringTokenHighlightingUsingUniversalMatching() {
  108. var row = rendRows[0]; // 'Amanda Annie Anderson'
  109. renderer.setMatchWordBoundary(false);
  110. // Should highlight first match only.
  111. var token = 'A';
  112. var node = renderer.renderRowHtml(row, token);
  113. var boldTagElArray = goog.dom.getElementsByTagName(goog.dom.TagName.B, node);
  114. assertNumBoldTags(boldTagElArray, 1);
  115. assertPreviousNodeText(boldTagElArray[0], '');
  116. assertHighlightedText(boldTagElArray[0], 'A');
  117. assertLastNodeText(node, 'manda Annie Anderson');
  118. // Match should be case insensitive, and should match tokens in the
  119. // middle of words if useWordMatching is turned off ("an" in Amanda).
  120. var token = 'an';
  121. var node = renderer.renderRowHtml(row, token);
  122. var boldTagElArray = goog.dom.getElementsByTagName(goog.dom.TagName.B, node);
  123. assertNumBoldTags(boldTagElArray, 1);
  124. assertPreviousNodeText(boldTagElArray[0], 'Am');
  125. assertHighlightedText(boldTagElArray[0], 'an');
  126. assertLastNodeText(node, 'da Annie Anderson');
  127. // Should only match on non-empty strings.
  128. token = '';
  129. node = renderer.renderRowHtml(row, token);
  130. boldTagElArray = goog.dom.getElementsByTagName(goog.dom.TagName.B, node);
  131. assertNumBoldTags(boldTagElArray, 0);
  132. assertLastNodeText(node, 'Amanda Annie Anderson');
  133. // Should not match leading whitespace.
  134. token = ' an';
  135. node = renderer.renderRowHtml(row, token);
  136. boldTagElArray = goog.dom.getElementsByTagName(goog.dom.TagName.B, node);
  137. assertNumBoldTags(boldTagElArray, 0);
  138. assertLastNodeText(node, 'Amanda Annie Anderson');
  139. }
  140. function testBasicStringTokenHighlighting() {
  141. var row = rendRows[0]; // 'Amanda Annie Anderson'
  142. // Should highlight first match only.
  143. var token = 'A';
  144. var node = renderer.renderRowHtml(row, token);
  145. var boldTagElArray = goog.dom.getElementsByTagName(goog.dom.TagName.B, node);
  146. assertNumBoldTags(boldTagElArray, 1);
  147. assertPreviousNodeText(boldTagElArray[0], '');
  148. assertHighlightedText(boldTagElArray[0], 'A');
  149. assertLastNodeText(node, 'manda Annie Anderson');
  150. // Should only match on non-empty strings.
  151. token = '';
  152. node = renderer.renderRowHtml(row, token);
  153. boldTagElArray = goog.dom.getElementsByTagName(goog.dom.TagName.B, node);
  154. assertNumBoldTags(boldTagElArray, 0);
  155. assertLastNodeText(node, 'Amanda Annie Anderson');
  156. // Match should be case insensitive, and should not match tokens in the
  157. // middle of words ("an" in Amanda).
  158. token = 'an';
  159. node = renderer.renderRowHtml(row, token);
  160. boldTagElArray = goog.dom.getElementsByTagName(goog.dom.TagName.B, node);
  161. assertNumBoldTags(boldTagElArray, 1);
  162. assertPreviousNodeText(boldTagElArray[0], 'Amanda ');
  163. assertHighlightedText(boldTagElArray[0], 'An');
  164. assertLastNodeText(node, 'nie Anderson');
  165. // Should not match whitespace.
  166. token = ' ';
  167. node = renderer.renderRowHtml(row, token);
  168. boldTagElArray = goog.dom.getElementsByTagName(goog.dom.TagName.B, node);
  169. assertNumBoldTags(boldTagElArray, 0);
  170. assertLastNodeText(node, 'Amanda Annie Anderson');
  171. // Should not match leading whitespace since all matches are at the start of
  172. // word boundaries.
  173. token = ' an';
  174. node = renderer.renderRowHtml(row, token);
  175. boldTagElArray = goog.dom.getElementsByTagName(goog.dom.TagName.B, node);
  176. assertNumBoldTags(boldTagElArray, 0);
  177. assertLastNodeText(node, 'Amanda Annie Anderson');
  178. // Should match trailing whitespace.
  179. token = 'annie ';
  180. node = renderer.renderRowHtml(row, token);
  181. boldTagElArray = goog.dom.getElementsByTagName(goog.dom.TagName.B, node);
  182. assertNumBoldTags(boldTagElArray, 1);
  183. assertPreviousNodeText(boldTagElArray[0], 'Amanda ');
  184. assertHighlightedText(boldTagElArray[0], 'Annie ');
  185. assertLastNodeText(node, 'Anderson');
  186. // Should match across whitespace.
  187. row = rendRows[2]; // 'Louis D Armstrong'
  188. token = 'd a';
  189. node = renderer.renderRowHtml(row, token);
  190. boldTagElArray = goog.dom.getElementsByTagName(goog.dom.TagName.B, node);
  191. assertNumBoldTags(boldTagElArray, 1);
  192. assertPreviousNodeText(boldTagElArray[0], 'Louis ');
  193. assertHighlightedText(boldTagElArray[0], 'D A');
  194. assertLastNodeText(node, 'rmstrong');
  195. // Should match the last token.
  196. token = 'aRmStRoNg';
  197. node = renderer.renderRowHtml(row, token);
  198. boldTagElArray = goog.dom.getElementsByTagName(goog.dom.TagName.B, node);
  199. assertNumBoldTags(boldTagElArray, 1);
  200. assertPreviousNodeText(boldTagElArray[0], 'Louis D ');
  201. assertHighlightedText(boldTagElArray[0], 'Armstrong');
  202. assertLastNodeText(node, '');
  203. }
  204. // The name of this function is fortuitous, in that it gets tested
  205. // last on FF. The lazy regexp on FF is particularly slow, and causes
  206. // the test to take a long time, and sometimes time out when run on forge
  207. // because it triggers the test runner to go back to the event loop...
  208. function testPathologicalInput() {
  209. // Should not hang on bizarrely long strings
  210. var row = rendRows[3]; // pathological row
  211. var token = 'foo';
  212. var node = renderer.renderRowHtml(row, token);
  213. var boldTagElArray = goog.dom.getElementsByTagName(goog.dom.TagName.B, node);
  214. assertNumBoldTags(boldTagElArray, 1);
  215. assertHighlightedText(boldTagElArray[0], 'Foo');
  216. assert(
  217. goog.string.startsWith(
  218. boldTagElArray[0].nextSibling.nodeValue, ' Bar...'));
  219. }
  220. function testBasicArrayTokenHighlighting() {
  221. var row = rendRows[1]; // 'Frankie Manning'
  222. // Only the first match in the array should be highlighted.
  223. var token = ['f', 'm'];
  224. var node = renderer.renderRowHtml(row, token);
  225. var boldTagElArray = goog.dom.getElementsByTagName(goog.dom.TagName.B, node);
  226. assertNumBoldTags(boldTagElArray, 1);
  227. assertPreviousNodeText(boldTagElArray[0], '');
  228. assertHighlightedText(boldTagElArray[0], 'F');
  229. assertLastNodeText(node, 'rankie Manning');
  230. // Only the first match in the array should be highlighted.
  231. token = ['m', 'f'];
  232. node = renderer.renderRowHtml(row, token);
  233. boldTagElArray = goog.dom.getElementsByTagName(goog.dom.TagName.B, node);
  234. assertNumBoldTags(boldTagElArray, 1);
  235. assertPreviousNodeText(boldTagElArray[0], 'Frankie ');
  236. assertHighlightedText(boldTagElArray[0], 'M');
  237. assertLastNodeText(node, 'anning');
  238. // Skip tokens that do not match.
  239. token = ['asdf', 'f'];
  240. node = renderer.renderRowHtml(row, token);
  241. boldTagElArray = goog.dom.getElementsByTagName(goog.dom.TagName.B, node);
  242. assertNumBoldTags(boldTagElArray, 1);
  243. assertPreviousNodeText(boldTagElArray[0], '');
  244. assertHighlightedText(boldTagElArray[0], 'F');
  245. assertLastNodeText(node, 'rankie Manning');
  246. // Highlight nothing if no tokens match.
  247. token = ['Foo', 'bar', 'baz'];
  248. node = renderer.renderRowHtml(row, token);
  249. boldTagElArray = goog.dom.getElementsByTagName(goog.dom.TagName.B, node);
  250. assertNumBoldTags(boldTagElArray, 0);
  251. assertLastNodeText(node, 'Frankie Manning');
  252. // Empty array should not match.
  253. token = [];
  254. node = renderer.renderRowHtml(row, token);
  255. boldTagElArray = goog.dom.getElementsByTagName(goog.dom.TagName.B, node);
  256. assertNumBoldTags(boldTagElArray, 0);
  257. assertLastNodeText(node, 'Frankie Manning');
  258. // Empty string in array should not match.
  259. token = [''];
  260. node = renderer.renderRowHtml(row, token);
  261. boldTagElArray = goog.dom.getElementsByTagName(goog.dom.TagName.B, node);
  262. assertNumBoldTags(boldTagElArray, 0);
  263. assertLastNodeText(node, 'Frankie Manning');
  264. // Whitespace in array should not match.
  265. token = [' '];
  266. node = renderer.renderRowHtml(row, token);
  267. boldTagElArray = goog.dom.getElementsByTagName(goog.dom.TagName.B, node);
  268. assertNumBoldTags(boldTagElArray, 0);
  269. assertLastNodeText(node, 'Frankie Manning');
  270. // Whitespace entries in array should not match.
  271. token = [' ', 'man'];
  272. node = renderer.renderRowHtml(row, token);
  273. boldTagElArray = goog.dom.getElementsByTagName(goog.dom.TagName.B, node);
  274. assertNumBoldTags(boldTagElArray, 1);
  275. assertPreviousNodeText(boldTagElArray[0], 'Frankie ');
  276. assertHighlightedText(boldTagElArray[0], 'Man');
  277. assertLastNodeText(node, 'ning');
  278. // Whitespace in array entry should match as a whole token.
  279. row = rendRows[2]; // 'Louis D Armstrong'
  280. token = ['d arm', 'lou'];
  281. node = renderer.renderRowHtml(row, token);
  282. boldTagElArray = goog.dom.getElementsByTagName(goog.dom.TagName.B, node);
  283. assertNumBoldTags(boldTagElArray, 1);
  284. assertPreviousNodeText(boldTagElArray[0], 'Louis ');
  285. assertHighlightedText(boldTagElArray[0], 'D Arm');
  286. assertLastNodeText(node, 'strong');
  287. }
  288. function testHighlightAllTokensSingleTokenHighlighting() {
  289. renderer.setHighlightAllTokens(true);
  290. var row = rendRows[0]; // 'Amanda Annie Anderson'
  291. // All matches at the start of the word should be highlighted when
  292. // highlightAllTokens is set.
  293. var token = 'a';
  294. var node = renderer.renderRowHtml(row, token);
  295. var boldTagElArray = goog.dom.getElementsByTagName(goog.dom.TagName.B, node);
  296. assertNumBoldTags(boldTagElArray, 3);
  297. assertPreviousNodeText(boldTagElArray[0], '');
  298. assertHighlightedText(boldTagElArray[0], 'A');
  299. assertPreviousNodeText(boldTagElArray[1], 'manda ');
  300. assertHighlightedText(boldTagElArray[1], 'A');
  301. assertPreviousNodeText(boldTagElArray[2], 'nnie ');
  302. assertHighlightedText(boldTagElArray[2], 'A');
  303. assertLastNodeText(node, 'nderson');
  304. // Should not match on empty string.
  305. token = '';
  306. node = renderer.renderRowHtml(row, token);
  307. boldTagElArray = goog.dom.getElementsByTagName(goog.dom.TagName.B, node);
  308. assertNumBoldTags(boldTagElArray, 0);
  309. assertLastNodeText(node, 'Amanda Annie Anderson');
  310. // Match should be case insensitive.
  311. token = 'AN';
  312. node = renderer.renderRowHtml(row, token);
  313. boldTagElArray = goog.dom.getElementsByTagName(goog.dom.TagName.B, node);
  314. assertNumBoldTags(boldTagElArray, 2);
  315. assertPreviousNodeText(boldTagElArray[0], 'Amanda ');
  316. assertHighlightedText(boldTagElArray[0], 'An');
  317. assertPreviousNodeText(boldTagElArray[1], 'nie ');
  318. assertHighlightedText(boldTagElArray[1], 'An');
  319. assertLastNodeText(node, 'derson');
  320. // Should not match on whitespace.
  321. token = ' ';
  322. node = renderer.renderRowHtml(row, token);
  323. boldTagElArray = goog.dom.getElementsByTagName(goog.dom.TagName.B, node);
  324. assertNumBoldTags(boldTagElArray, 0);
  325. assertLastNodeText(node, 'Amanda Annie Anderson');
  326. // When highlighting all tokens, should match despite leading whitespace.
  327. token = ' am';
  328. node = renderer.renderRowHtml(row, token);
  329. boldTagElArray = goog.dom.getElementsByTagName(goog.dom.TagName.B, node);
  330. assertNumBoldTags(boldTagElArray, 1);
  331. assertPreviousNodeText(boldTagElArray[0], '');
  332. assertHighlightedText(boldTagElArray[0], 'Am');
  333. assertLastNodeText(node, 'anda Annie Anderson');
  334. // Should match with trailing whitepsace.
  335. token = 'ann ';
  336. node = renderer.renderRowHtml(row, token);
  337. boldTagElArray = goog.dom.getElementsByTagName(goog.dom.TagName.B, node);
  338. assertNumBoldTags(boldTagElArray, 1);
  339. assertPreviousNodeText(boldTagElArray[0], 'Amanda ');
  340. assertHighlightedText(boldTagElArray[0], 'Ann');
  341. assertLastNodeText(node, 'ie Anderson');
  342. }
  343. function testHighlightAllTokensMultipleStringTokenHighlighting() {
  344. renderer.setHighlightAllTokens(true);
  345. var row = rendRows[1]; // 'Frankie Manning'
  346. // Each individual space-separated token should match.
  347. var token = 'm F';
  348. var node = renderer.renderRowHtml(row, token);
  349. var boldTagElArray = goog.dom.getElementsByTagName(goog.dom.TagName.B, node);
  350. assertNumBoldTags(boldTagElArray, 2);
  351. assertPreviousNodeText(boldTagElArray[0], '');
  352. assertHighlightedText(boldTagElArray[0], 'F');
  353. assertPreviousNodeText(boldTagElArray[1], 'rankie ');
  354. assertHighlightedText(boldTagElArray[1], 'M');
  355. assertLastNodeText(node, 'anning');
  356. }
  357. function testHighlightAllTokensArrayTokenHighlighting() {
  358. renderer.setHighlightAllTokens(true);
  359. var row = rendRows[0]; // 'Amanda Annie Anderson'
  360. // All tokens in the array should match.
  361. var token = ['AM', 'AN'];
  362. var node = renderer.renderRowHtml(row, token);
  363. var boldTagElArray = goog.dom.getElementsByTagName(goog.dom.TagName.B, node);
  364. assertNumBoldTags(boldTagElArray, 3);
  365. assertPreviousNodeText(boldTagElArray[0], '');
  366. assertHighlightedText(boldTagElArray[0], 'Am');
  367. assertPreviousNodeText(boldTagElArray[1], 'anda ');
  368. assertHighlightedText(boldTagElArray[1], 'An');
  369. assertPreviousNodeText(boldTagElArray[2], 'nie ');
  370. assertHighlightedText(boldTagElArray[2], 'An');
  371. assertLastNodeText(node, 'derson');
  372. // Empty array should not match.
  373. token = [];
  374. node = renderer.renderRowHtml(row, token);
  375. boldTagElArray = goog.dom.getElementsByTagName(goog.dom.TagName.B, node);
  376. assertNumBoldTags(boldTagElArray, 0);
  377. assertLastNodeText(node, 'Amanda Annie Anderson');
  378. // Empty string in array should not match.
  379. token = [''];
  380. node = renderer.renderRowHtml(row, token);
  381. boldTagElArray = goog.dom.getElementsByTagName(goog.dom.TagName.B, node);
  382. assertNumBoldTags(boldTagElArray, 0);
  383. assertLastNodeText(node, 'Amanda Annie Anderson');
  384. // Whitespace in array should not match.
  385. token = [' '];
  386. node = renderer.renderRowHtml(row, token);
  387. boldTagElArray = goog.dom.getElementsByTagName(goog.dom.TagName.B, node);
  388. assertNumBoldTags(boldTagElArray, 0);
  389. assertLastNodeText(node, 'Amanda Annie Anderson');
  390. // Empty string entries in array should not match.
  391. token = ['', 'Ann'];
  392. node = renderer.renderRowHtml(row, token);
  393. boldTagElArray = goog.dom.getElementsByTagName(goog.dom.TagName.B, node);
  394. assertNumBoldTags(boldTagElArray, 1);
  395. assertPreviousNodeText(boldTagElArray[0], 'Amanda ');
  396. assertHighlightedText(boldTagElArray[0], 'Ann');
  397. assertLastNodeText(node, 'ie Anderson');
  398. // Whitespace entries in array should not match.
  399. token = [' ', 'And'];
  400. node = renderer.renderRowHtml(row, token);
  401. boldTagElArray = goog.dom.getElementsByTagName(goog.dom.TagName.B, node);
  402. assertNumBoldTags(boldTagElArray, 1);
  403. assertPreviousNodeText(boldTagElArray[0], 'Amanda Annie ');
  404. assertHighlightedText(boldTagElArray[0], 'And');
  405. assertLastNodeText(node, 'erson');
  406. // Whitespace in array entry should match as a whole token.
  407. token = ['annie a', 'Am'];
  408. node = renderer.renderRowHtml(row, token);
  409. var boldTagElArray = goog.dom.getElementsByTagName(goog.dom.TagName.B, node);
  410. assertNumBoldTags(boldTagElArray, 2);
  411. assertPreviousNodeText(boldTagElArray[0], '');
  412. assertHighlightedText(boldTagElArray[0], 'Am');
  413. assertPreviousNodeText(boldTagElArray[1], 'anda ');
  414. assertHighlightedText(boldTagElArray[1], 'Annie A');
  415. assertLastNodeText(node, 'nderson');
  416. }
  417. function testMenuFadeDuration() {
  418. renderer.maybeCreateElement_();
  419. var hideCalled = false;
  420. var hideAnimCalled = false;
  421. var showCalled = false;
  422. var showAnimCalled = false;
  423. propertyReplacer.set(goog.style, 'setElementShown', function(el, state) {
  424. if (state) {
  425. showCalled = true;
  426. } else {
  427. hideCalled = true;
  428. }
  429. });
  430. propertyReplacer.set(goog.fx.dom.FadeInAndShow.prototype, 'play', function() {
  431. showAnimCalled = true;
  432. });
  433. propertyReplacer.set(
  434. goog.fx.dom.FadeOutAndHide.prototype, 'play',
  435. function() { hideAnimCalled = true; });
  436. // Default behavior does show/hide but not animations.
  437. renderer.show();
  438. assertTrue(showCalled);
  439. assertFalse(showAnimCalled);
  440. renderer.dismiss();
  441. assertTrue(hideCalled);
  442. assertFalse(hideAnimCalled);
  443. // But animations can be turned on.
  444. showCalled = false;
  445. hideCalled = false;
  446. renderer.setMenuFadeDuration(100);
  447. renderer.show();
  448. assertFalse(showCalled);
  449. assertTrue(showAnimCalled);
  450. renderer.dismiss();
  451. assertFalse(hideCalled);
  452. assertTrue(hideAnimCalled);
  453. }
  454. function testAriaTags() {
  455. renderer.maybeCreateElement_();
  456. assertNotNull(target);
  457. assertEvaluatesToFalse(
  458. 'The role should be empty.', goog.a11y.aria.getRole(target));
  459. assertEquals(
  460. '', goog.a11y.aria.getState(target, goog.a11y.aria.State.HASPOPUP));
  461. assertEquals(
  462. '', goog.a11y.aria.getState(
  463. renderer.getElement(), goog.a11y.aria.State.EXPANDED));
  464. assertEquals('', goog.a11y.aria.getState(target, goog.a11y.aria.State.OWNS));
  465. renderer.show();
  466. assertEquals(
  467. 'true', goog.a11y.aria.getState(target, goog.a11y.aria.State.HASPOPUP));
  468. assertEquals(
  469. 'true', goog.a11y.aria.getState(target, goog.a11y.aria.State.EXPANDED));
  470. assertEquals(
  471. 'true', goog.a11y.aria.getState(
  472. renderer.getElement(), goog.a11y.aria.State.EXPANDED));
  473. assertEquals(
  474. renderer.getElement().id,
  475. goog.a11y.aria.getState(target, goog.a11y.aria.State.OWNS));
  476. renderer.dismiss();
  477. assertEquals(
  478. 'false', goog.a11y.aria.getState(target, goog.a11y.aria.State.HASPOPUP));
  479. assertEquals(
  480. 'false', goog.a11y.aria.getState(target, goog.a11y.aria.State.EXPANDED));
  481. assertEquals(
  482. 'false', goog.a11y.aria.getState(
  483. renderer.getElement(), goog.a11y.aria.State.EXPANDED));
  484. assertEquals('', goog.a11y.aria.getState(target, goog.a11y.aria.State.OWNS));
  485. }
  486. function testHiliteRowWithDefaultRenderer() {
  487. renderer.renderRows(rendRows, '');
  488. renderer.hiliteRow(2);
  489. assertEquals(2, renderer.hilitedRow_);
  490. assertTrue(
  491. goog.dom.classlist.contains(
  492. renderer.rowDivs_[2], renderer.activeClassName));
  493. }
  494. function testHiliteRowWithCustomRenderer() {
  495. goog.dispose(renderer);
  496. // Use a custom renderer that doesn't put the result divs as direct children
  497. // of this.element_.
  498. var customRenderer = {
  499. render: function(renderer, element, rows, token) {
  500. // Put all of the results into a results holder div that is a child of
  501. // this.element_.
  502. var resultsHolder = goog.dom.createDom(goog.dom.TagName.DIV);
  503. goog.dom.appendChild(element, resultsHolder);
  504. for (var i = 0, row; row = rows[i]; ++i) {
  505. var node = renderer.renderRowHtml(row, token);
  506. goog.dom.appendChild(resultsHolder, node);
  507. }
  508. }
  509. };
  510. renderer = new goog.ui.ac.Renderer(null, customRenderer);
  511. // Make sure we can still highlight the row at position 2 even though
  512. // this.element_.childNodes contains only a single child.
  513. renderer.renderRows(rendRows, '');
  514. renderer.hiliteRow(2);
  515. assertEquals(2, renderer.hilitedRow_);
  516. assertTrue(
  517. goog.dom.classlist.contains(
  518. renderer.rowDivs_[2], renderer.activeClassName));
  519. }
  520. function testReposition() {
  521. renderer.renderRows(rendRows, '', target);
  522. var el = renderer.getElement();
  523. el.style.position = 'absolute';
  524. el.style.width = '100px';
  525. renderer.setAutoPosition(true);
  526. renderer.redraw();
  527. var rendererOffset = goog.style.getPageOffset(renderer.getElement());
  528. var rendererSize = goog.style.getSize(renderer.getElement());
  529. var targetOffset = goog.style.getPageOffset(target);
  530. var targetSize = goog.style.getSize(target);
  531. assertEquals(0 + targetOffset.x, rendererOffset.x);
  532. assertRoughlyEquals(targetOffset.y + targetSize.height, rendererOffset.y, 1);
  533. }
  534. function testSetWidthProvider() {
  535. renderer.setWidthProvider(widthProvder);
  536. renderer.renderRows(rendRows, '');
  537. var el = renderer.getElement();
  538. el.style.width = '1px';
  539. renderer.redraw();
  540. var rendererSize = goog.style.getSize(el);
  541. var widthProviderSize = goog.style.getSize(widthProvder);
  542. assertEquals(rendererSize.width, widthProviderSize.width);
  543. }
  544. function testSetWidthProviderWithBorderWidth() {
  545. var borderWidth = 5;
  546. renderer.setWidthProvider(widthProvder, borderWidth);
  547. renderer.renderRows(rendRows, '');
  548. var el = renderer.getElement();
  549. el.style.width = '1px';
  550. renderer.redraw();
  551. var rendererSize = goog.style.getSize(el);
  552. var widthProviderSize = goog.style.getSize(widthProvder);
  553. assertEquals(rendererSize.width, widthProviderSize.width - borderWidth);
  554. }
  555. function testRepositionWithRightAlign() {
  556. renderer.renderRows(rendRows, '', target);
  557. var el = renderer.getElement();
  558. el.style.position = 'absolute';
  559. el.style.width = '150px';
  560. renderer.setAutoPosition(true);
  561. renderer.setRightAlign(true);
  562. renderer.redraw();
  563. var rendererOffset = goog.style.getPageOffset(renderer.getElement());
  564. var rendererSize = goog.style.getSize(renderer.getElement());
  565. var targetOffset = goog.style.getPageOffset(target);
  566. var targetSize = goog.style.getSize(target);
  567. assertRoughlyEquals(
  568. targetOffset.x + targetSize.width, rendererOffset.x + rendererSize.width,
  569. 1);
  570. assertRoughlyEquals(targetOffset.y + targetSize.height, rendererOffset.y, 1);
  571. }
  572. function testRepositionResizeHeight() {
  573. renderer = new goog.ui.ac.Renderer(viewport);
  574. // Render the first 4 rows from test set.
  575. renderer.renderRows(rendRows.slice(0, 4), '', viewportTarget);
  576. renderer.setAutoPosition(true);
  577. renderer.setShowScrollbarsIfTooLarge(true);
  578. // Stick a huge row in the dropdown element, to make sure it won't
  579. // fit in the viewport.
  580. var hugeRow =
  581. goog.dom.createDom(goog.dom.TagName.DIV, {style: 'height:1000px'});
  582. goog.dom.appendChild(renderer.getElement(), hugeRow);
  583. renderer.reposition();
  584. var rendererOffset = goog.style.getPageOffset(renderer.getElement());
  585. var rendererSize = goog.style.getSize(renderer.getElement());
  586. var viewportOffset = goog.style.getPageOffset(viewport);
  587. var viewportSize = goog.style.getSize(viewport);
  588. assertRoughlyEquals(
  589. viewportOffset.y + viewportSize.height,
  590. rendererSize.height + rendererOffset.y, 1);
  591. // Remove the huge row, and make sure that the dropdown element gets shrunk.
  592. renderer.getElement().removeChild(hugeRow);
  593. renderer.reposition();
  594. rendererOffset = goog.style.getPageOffset(renderer.getElement());
  595. rendererSize = goog.style.getSize(renderer.getElement());
  596. viewportOffset = goog.style.getPageOffset(viewport);
  597. viewportSize = goog.style.getSize(viewport);
  598. assertTrue(
  599. (rendererSize.height + rendererOffset.y) <
  600. (viewportOffset.y + viewportSize.height));
  601. }
  602. function testHiliteEvent() {
  603. renderer.renderRows(rendRows, '');
  604. var hiliteEventFired = false;
  605. goog.events.listenOnce(
  606. renderer, goog.ui.ac.AutoComplete.EventType.ROW_HILITE, function(e) {
  607. hiliteEventFired = true;
  608. assertEquals(e.row, rendRows[1].data);
  609. });
  610. renderer.hiliteRow(1);
  611. assertTrue(hiliteEventFired);
  612. hiliteEventFired = false;
  613. goog.events.listenOnce(
  614. renderer, goog.ui.ac.AutoComplete.EventType.ROW_HILITE, function(e) {
  615. hiliteEventFired = true;
  616. assertNull(e.row);
  617. });
  618. renderer.hiliteRow(rendRows.length); // i.e. out of bounds.
  619. assertTrue(hiliteEventFired);
  620. }
  621. // ------- Helper functions -------
  622. // The default rowRenderer will escape any HTML in the row content.
  623. // Activating HTML rendering will allow HTML strings to be rendered to DOM
  624. // instead of being escaped.
  625. function enableHtmlRendering(renderer) {
  626. renderer.customRenderer_ = {
  627. renderRow: function(row, token, node) {
  628. node.innerHTML = row.data.toString();
  629. }
  630. };
  631. }
  632. function assertNumBoldTags(boldTagElArray, expectedNum) {
  633. assertEquals(
  634. 'Incorrect number of bold tags', expectedNum, boldTagElArray.length);
  635. }
  636. function assertPreviousNodeText(boldTag, expectedText) {
  637. var prevNode = boldTag.previousSibling;
  638. assertEquals(
  639. 'Expected text before the token does not match', expectedText,
  640. prevNode.nodeValue);
  641. }
  642. function assertHighlightedText(boldTag, expectedHighlightedText) {
  643. assertEquals(
  644. 'Incorrect text bolded', expectedHighlightedText, boldTag.innerHTML);
  645. }
  646. function assertLastNodeText(node, expectedText) {
  647. var lastNode = node.lastChild;
  648. assertEquals(
  649. 'Incorrect text in the last node', expectedText, lastNode.nodeValue);
  650. }