dom_test.js 66 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881
  1. // Copyright 2009 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. /**
  15. * @fileoverview Shared code for dom_test.html and dom_quirks_test.html.
  16. */
  17. /** @suppress {extraProvide} */
  18. goog.provide('goog.dom.dom_test');
  19. goog.require('goog.array');
  20. goog.require('goog.dom');
  21. goog.require('goog.dom.BrowserFeature');
  22. goog.require('goog.dom.DomHelper');
  23. goog.require('goog.dom.InputType');
  24. goog.require('goog.dom.NodeType');
  25. goog.require('goog.dom.TagName');
  26. goog.require('goog.functions');
  27. goog.require('goog.html.SafeUrl');
  28. goog.require('goog.html.testing');
  29. goog.require('goog.object');
  30. goog.require('goog.string.Const');
  31. goog.require('goog.string.Unicode');
  32. goog.require('goog.testing.PropertyReplacer');
  33. goog.require('goog.testing.asserts');
  34. goog.require('goog.userAgent');
  35. goog.require('goog.userAgent.product');
  36. goog.require('goog.userAgent.product.isVersion');
  37. goog.setTestOnly('dom_test');
  38. var $ = goog.dom.getElement;
  39. var divForTestingScrolling;
  40. var myIframe;
  41. var myIframeDoc;
  42. var stubs;
  43. function setUpPage() {
  44. stubs = new goog.testing.PropertyReplacer();
  45. divForTestingScrolling = goog.dom.createElement(goog.dom.TagName.DIV);
  46. divForTestingScrolling.style.width = '5000px';
  47. divForTestingScrolling.style.height = '5000px';
  48. document.body.appendChild(divForTestingScrolling);
  49. // Setup for the iframe
  50. myIframe = $('myIframe');
  51. myIframeDoc = goog.dom.getFrameContentDocument(
  52. /** @type {HTMLIFrameElement} */ (myIframe));
  53. // Set up document for iframe: total height of elements in document is 65
  54. // If the elements are not create like below, IE will get a wrong height for
  55. // the document.
  56. myIframeDoc.open();
  57. // Make sure we progate the compat mode
  58. myIframeDoc.write(
  59. (goog.dom.isCss1CompatMode() ? '<!DOCTYPE html>' : '') +
  60. '<style>body{margin:0;padding:0}</style>' +
  61. '<div style="height:42px;font-size:1px;line-height:0;">' +
  62. 'hello world</div>' +
  63. '<div style="height:23px;font-size:1px;line-height:0;">' +
  64. 'hello world</div>');
  65. myIframeDoc.close();
  66. }
  67. function tearDownPage() {
  68. document.body.removeChild(divForTestingScrolling);
  69. }
  70. function tearDown() {
  71. window.scrollTo(0, 0);
  72. stubs.reset();
  73. }
  74. function testDom() {
  75. assert('Dom library exists', typeof goog.dom != 'undefined');
  76. }
  77. function testGetElement() {
  78. var el = $('testEl');
  79. assertEquals('Should be able to get id', el.id, 'testEl');
  80. assertEquals($, goog.dom.getElement);
  81. assertEquals(goog.dom.$, goog.dom.getElement);
  82. }
  83. function testGetElementDomHelper() {
  84. var domHelper = new goog.dom.DomHelper();
  85. var el = domHelper.getElement('testEl');
  86. assertEquals('Should be able to get id', el.id, 'testEl');
  87. }
  88. function testGetRequiredElement() {
  89. var el = goog.dom.getRequiredElement('testEl');
  90. assertTrue(goog.isDefAndNotNull(el));
  91. assertEquals('testEl', el.id);
  92. assertThrows(function() { goog.dom.getRequiredElement('does_not_exist'); });
  93. }
  94. function testGetRequiredElementDomHelper() {
  95. var domHelper = new goog.dom.DomHelper();
  96. var el = domHelper.getRequiredElement('testEl');
  97. assertTrue(goog.isDefAndNotNull(el));
  98. assertEquals('testEl', el.id);
  99. assertThrows(function() {
  100. goog.dom.getRequiredElementByClass('does_not_exist', container);
  101. });
  102. }
  103. function testGetRequiredElementByClassDomHelper() {
  104. var domHelper = new goog.dom.DomHelper();
  105. assertNotNull(domHelper.getRequiredElementByClass('test1'));
  106. assertNotNull(domHelper.getRequiredElementByClass('test2'));
  107. var container = domHelper.getElement('span-container');
  108. assertNotNull(domHelper.getElementByClass('test1', container));
  109. assertThrows(function() {
  110. domHelper.getRequiredElementByClass('does_not_exist', container);
  111. });
  112. }
  113. function testGetElementsByTagName() {
  114. var divs = goog.dom.getElementsByTagName(goog.dom.TagName.DIV);
  115. assertTrue(divs.length > 0);
  116. var el = goog.dom.getRequiredElement('testEl');
  117. var spans = goog.dom.getElementsByTagName(goog.dom.TagName.SPAN, el);
  118. assertTrue(spans.length > 0);
  119. }
  120. function testGetElementsByTagNameDomHelper() {
  121. var domHelper = new goog.dom.DomHelper();
  122. var divs = domHelper.getElementsByTagName(goog.dom.TagName.DIV);
  123. assertTrue(divs.length > 0);
  124. var el = domHelper.getRequiredElement('testEl');
  125. var spans = domHelper.getElementsByTagName(goog.dom.TagName.SPAN, el);
  126. assertTrue(spans.length > 0);
  127. }
  128. function testGetElementsByTagNameAndClass() {
  129. assertEquals(
  130. 'Should get 6 spans',
  131. goog.dom.getElementsByTagNameAndClass(goog.dom.TagName.SPAN).length, 6);
  132. assertEquals(
  133. 'Should get 6 spans',
  134. goog.dom.getElementsByTagNameAndClass(goog.dom.TagName.SPAN).length, 6);
  135. assertEquals(
  136. 'Should get 3 spans',
  137. goog.dom.getElementsByTagNameAndClass(goog.dom.TagName.SPAN, 'test1')
  138. .length,
  139. 3);
  140. assertEquals(
  141. 'Should get 1 span',
  142. goog.dom.getElementsByTagNameAndClass(goog.dom.TagName.SPAN, 'test2')
  143. .length,
  144. 1);
  145. assertEquals(
  146. 'Should get 1 span',
  147. goog.dom.getElementsByTagNameAndClass(goog.dom.TagName.SPAN, 'test2')
  148. .length,
  149. 1);
  150. assertEquals(
  151. 'Should get lots of elements',
  152. goog.dom.getElementsByTagNameAndClass().length,
  153. document.getElementsByTagName('*').length);
  154. assertEquals(
  155. 'Should get 1 span', goog.dom
  156. .getElementsByTagNameAndClass(
  157. goog.dom.TagName.SPAN, null, $('testEl'))
  158. .length,
  159. 1);
  160. // '*' as the tag name should be equivalent to all tags
  161. var container = goog.dom.getElement('span-container');
  162. assertEquals(
  163. 5,
  164. goog.dom.getElementsByTagNameAndClass('*', undefined, container).length);
  165. assertEquals(
  166. 3, goog.dom.getElementsByTagNameAndClass('*', 'test1', container).length);
  167. assertEquals(
  168. 1, goog.dom.getElementsByTagNameAndClass('*', 'test2', container).length);
  169. // Some version of WebKit have problems with mixed-case class names
  170. assertEquals(
  171. 1, goog.dom.getElementsByTagNameAndClass(undefined, 'mixedCaseClass')
  172. .length);
  173. // Make sure that out of bounds indices are OK
  174. assertUndefined(
  175. goog.dom.getElementsByTagNameAndClass(undefined, 'noSuchClass')[0]);
  176. assertEquals(
  177. goog.dom.getElementsByTagNameAndClass,
  178. goog.dom.getElementsByTagNameAndClass);
  179. }
  180. function testGetElementsByClass() {
  181. assertEquals(3, goog.dom.getElementsByClass('test1').length);
  182. assertEquals(1, goog.dom.getElementsByClass('test2').length);
  183. assertEquals(0, goog.dom.getElementsByClass('nonexistant').length);
  184. var container = goog.dom.getElement('span-container');
  185. assertEquals(3, goog.dom.getElementsByClass('test1', container).length);
  186. }
  187. function testGetElementByClass() {
  188. assertNotNull(goog.dom.getElementByClass('test1'));
  189. assertNotNull(goog.dom.getElementByClass('test2'));
  190. // assertNull(goog.dom.getElementByClass('nonexistant'));
  191. var container = goog.dom.getElement('span-container');
  192. assertNotNull(goog.dom.getElementByClass('test1', container));
  193. }
  194. function testGetElementByTagNameAndClass() {
  195. assertNotNull(goog.dom.getElementByTagNameAndClass('', 'test1'));
  196. assertNotNull(goog.dom.getElementByTagNameAndClass('*', 'test1'));
  197. assertNotNull(goog.dom.getElementByTagNameAndClass('span', 'test1'));
  198. assertNull(goog.dom.getElementByTagNameAndClass('div', 'test1'));
  199. assertNull(goog.dom.getElementByTagNameAndClass('*', 'nonexistant'));
  200. var container = goog.dom.getElement('span-container');
  201. assertNotNull(goog.dom.getElementByTagNameAndClass('*', 'test1', container));
  202. }
  203. function testSetProperties() {
  204. var attrs = {
  205. 'name': 'test3',
  206. 'title': 'A title',
  207. 'random': 'woop',
  208. 'other-random': null,
  209. 'href': goog.html.SafeUrl.sanitize('https://google.com')
  210. };
  211. var el = $('testEl');
  212. goog.dom.setProperties(el, attrs);
  213. assertEquals(el.name, 'test3');
  214. assertEquals(el.title, 'A title');
  215. assertEquals(el.random, 'woop');
  216. assertEquals(el.href, 'https://google.com');
  217. }
  218. function testSetPropertiesDirectAttributeMap() {
  219. var attrs = {'usemap': '#myMap'};
  220. var el = goog.dom.createDom(goog.dom.TagName.IMG);
  221. var res = goog.dom.setProperties(el, attrs);
  222. assertEquals('Should be equal', '#myMap', el.getAttribute('usemap'));
  223. }
  224. function testSetPropertiesDirectAttributeMapChecksForOwnProperties() {
  225. stubs.set(Object.prototype, 'customProp', 'sdflasdf.,m.,<>fsdflas213!@#');
  226. var attrs = {'usemap': '#myMap'};
  227. var el = goog.dom.createDom(goog.dom.TagName.IMG);
  228. var res = goog.dom.setProperties(el, attrs);
  229. assertEquals('Should be equal', '#myMap', el.getAttribute('usemap'));
  230. }
  231. function testSetPropertiesAria() {
  232. var attrs = {
  233. 'aria-hidden': 'true',
  234. 'aria-label': 'This is a label',
  235. 'role': 'presentation'
  236. };
  237. var el = goog.dom.createDom(goog.dom.TagName.DIV);
  238. goog.dom.setProperties(el, attrs);
  239. assertEquals('Should be equal', 'true', el.getAttribute('aria-hidden'));
  240. assertEquals(
  241. 'Should be equal', 'This is a label', el.getAttribute('aria-label'));
  242. assertEquals('Should be equal', 'presentation', el.getAttribute('role'));
  243. }
  244. function testSetPropertiesData() {
  245. var attrs = {
  246. 'data-tooltip': 'This is a tooltip',
  247. 'data-tooltip-delay': '100'
  248. };
  249. var el = goog.dom.createDom(goog.dom.TagName.DIV);
  250. goog.dom.setProperties(el, attrs);
  251. assertEquals(
  252. 'Should be equal', 'This is a tooltip', el.getAttribute('data-tooltip'));
  253. assertEquals('Should be equal', '100', el.getAttribute('data-tooltip-delay'));
  254. }
  255. function testSetTableProperties() {
  256. var attrs = {
  257. 'style': 'padding-left: 10px;',
  258. 'class': 'mytestclass',
  259. 'height': '101',
  260. 'cellpadding': '15'
  261. };
  262. var el = $('testTable1');
  263. var res = goog.dom.setProperties(el, attrs);
  264. assertEquals('Should be equal', el.style.paddingLeft, '10px');
  265. assertEquals('Should be equal', el.className, 'mytestclass');
  266. assertEquals('Should be equal', el.getAttribute('height'), '101');
  267. assertEquals('Should be equal', el.cellPadding, '15');
  268. }
  269. function testGetViewportSize() {
  270. // TODO: This is failing in the test runner now, fix later.
  271. // var dims = getViewportSize();
  272. // assertNotUndefined('Should be defined at least', dims.width);
  273. // assertNotUndefined('Should be defined at least', dims.height);
  274. }
  275. function testGetViewportSizeInIframe() {
  276. var iframe = /** @type {HTMLIFrameElement} */ (goog.dom.getElement('iframe'));
  277. var contentDoc = goog.dom.getFrameContentDocument(iframe);
  278. contentDoc.write('<body></body>');
  279. var outerSize = goog.dom.getViewportSize();
  280. var innerSize = (new goog.dom.DomHelper(contentDoc)).getViewportSize();
  281. assert('Viewport sizes must not match', innerSize.width != outerSize.width);
  282. }
  283. function testGetDocumentHeightInIframe() {
  284. var doc = goog.dom.getDomHelper(myIframeDoc).getDocument();
  285. var height = goog.dom.getDomHelper(myIframeDoc).getDocumentHeight();
  286. // Broken in webkit/edge quirks mode and in IE8+
  287. if ((goog.dom.isCss1CompatMode_(doc) ||
  288. !goog.userAgent.WEBKIT && !goog.userAgent.EDGE) &&
  289. !isIE8OrHigher()) {
  290. assertEquals('height should be 65', 42 + 23, height);
  291. }
  292. }
  293. function testCreateDom() {
  294. var el = goog.dom.createDom(
  295. goog.dom.TagName.DIV, {
  296. style: 'border: 1px solid black; width: 50%; background-color: #EEE;',
  297. onclick: 'alert(\'woo\')'
  298. },
  299. goog.dom.createDom(
  300. goog.dom.TagName.P, {style: 'font: normal 12px arial; color: red; '},
  301. 'Para 1'),
  302. goog.dom.createDom(
  303. goog.dom.TagName.P,
  304. {style: 'font: bold 18px garamond; color: blue; '}, 'Para 2'),
  305. goog.dom.createDom(
  306. goog.dom.TagName.P,
  307. {style: 'font: normal 24px monospace; color: green'}, 'Para 3 ',
  308. goog.dom.createDom(
  309. goog.dom.TagName.A, {
  310. name: 'link',
  311. href: goog.html.SafeUrl.sanitize('http://bbc.co.uk/')
  312. },
  313. 'has a link'),
  314. ', how cool is this?'));
  315. assertEquals(
  316. 'Tagname should be a DIV', String(goog.dom.TagName.DIV), el.tagName);
  317. assertEquals('Style width should be 50%', '50%', el.style.width);
  318. assertEquals(
  319. 'first child is a P tag', String(goog.dom.TagName.P),
  320. el.childNodes[0].tagName);
  321. assertEquals('second child .innerHTML', 'Para 2', el.childNodes[1].innerHTML);
  322. assertEquals(
  323. 'Link href as SafeUrl', 'http://bbc.co.uk/',
  324. el.childNodes[2].childNodes[1].href);
  325. }
  326. function testCreateDomNoChildren() {
  327. var el;
  328. // Test unspecified children.
  329. el = goog.dom.createDom(goog.dom.TagName.DIV);
  330. assertNull('firstChild should be null', el.firstChild);
  331. // Test null children.
  332. el = goog.dom.createDom(goog.dom.TagName.DIV, null, null);
  333. assertNull('firstChild should be null', el.firstChild);
  334. // Test empty array of children.
  335. el = goog.dom.createDom(goog.dom.TagName.DIV, null, []);
  336. assertNull('firstChild should be null', el.firstChild);
  337. }
  338. function testCreateDomAcceptsArray() {
  339. var items = [
  340. goog.dom.createDom(goog.dom.TagName.LI, {}, 'Item 1'),
  341. goog.dom.createDom(goog.dom.TagName.LI, {}, 'Item 2')
  342. ];
  343. var ul = goog.dom.createDom(goog.dom.TagName.UL, {}, items);
  344. assertEquals('List should have two children', 2, ul.childNodes.length);
  345. assertEquals(
  346. 'First child should be an LI tag', String(goog.dom.TagName.LI),
  347. ul.firstChild.tagName);
  348. assertEquals('Item 1', ul.childNodes[0].innerHTML);
  349. assertEquals('Item 2', ul.childNodes[1].innerHTML);
  350. }
  351. function testCreateDomStringArg() {
  352. var el;
  353. // Test string arg.
  354. el = goog.dom.createDom(goog.dom.TagName.DIV, null, 'Hello');
  355. assertEquals(
  356. 'firstChild should be a text node', goog.dom.NodeType.TEXT,
  357. el.firstChild.nodeType);
  358. assertEquals(
  359. 'firstChild should have node value "Hello"', 'Hello',
  360. el.firstChild.nodeValue);
  361. // Test text node arg.
  362. el = goog.dom.createDom(
  363. goog.dom.TagName.DIV, null, goog.dom.createTextNode('World'));
  364. assertEquals(
  365. 'firstChild should be a text node', goog.dom.NodeType.TEXT,
  366. el.firstChild.nodeType);
  367. assertEquals(
  368. 'firstChild should have node value "World"', 'World',
  369. el.firstChild.nodeValue);
  370. }
  371. function testCreateDomNodeListArg() {
  372. var el;
  373. var emptyElem = goog.dom.createDom(goog.dom.TagName.DIV);
  374. var simpleElem =
  375. goog.dom.createDom(goog.dom.TagName.DIV, null, 'Hello, world!');
  376. var complexElem = goog.dom.createDom(
  377. goog.dom.TagName.DIV, null, 'Hello, ',
  378. goog.dom.createDom(goog.dom.TagName.B, null, 'world'),
  379. goog.dom.createTextNode('!'));
  380. // Test empty node list.
  381. el = goog.dom.createDom(goog.dom.TagName.DIV, null, emptyElem.childNodes);
  382. assertNull('emptyElem.firstChild should be null', emptyElem.firstChild);
  383. assertNull('firstChild should be null', el.firstChild);
  384. // Test simple node list.
  385. el = goog.dom.createDom(goog.dom.TagName.DIV, null, simpleElem.childNodes);
  386. assertNull('simpleElem.firstChild should be null', simpleElem.firstChild);
  387. assertEquals(
  388. 'firstChild should be a text node with value "Hello, world!"',
  389. 'Hello, world!', el.firstChild.nodeValue);
  390. // Test complex node list.
  391. el = goog.dom.createDom(goog.dom.TagName.DIV, null, complexElem.childNodes);
  392. assertNull('complexElem.firstChild should be null', complexElem.firstChild);
  393. assertEquals('Element should have 3 child nodes', 3, el.childNodes.length);
  394. assertEquals(
  395. 'childNodes[0] should be a text node with value "Hello, "', 'Hello, ',
  396. el.childNodes[0].nodeValue);
  397. assertEquals(
  398. 'childNodes[1] should be an element node with tagName "B"',
  399. String(goog.dom.TagName.B), el.childNodes[1].tagName);
  400. assertEquals(
  401. 'childNodes[2] should be a text node with value "!"', '!',
  402. el.childNodes[2].nodeValue);
  403. }
  404. function testCreateDomWithTypeAttribute() {
  405. var el = goog.dom.createDom(
  406. goog.dom.TagName.BUTTON,
  407. {'type': goog.dom.InputType.RESET, 'id': 'cool-button'}, 'Cool button');
  408. assertNotNull('Button with type attribute was created successfully', el);
  409. assertEquals(
  410. 'Button has correct type attribute', goog.dom.InputType.RESET, el.type);
  411. assertEquals('Button has correct id', 'cool-button', el.id);
  412. }
  413. function testCreateDomWithClassList() {
  414. var el = goog.dom.createDom(goog.dom.TagName.DIV, ['foo', 'bar']);
  415. assertEquals('foo bar', el.className);
  416. }
  417. function testContains() {
  418. assertTrue(
  419. 'HTML should contain BODY',
  420. goog.dom.contains(document.documentElement, document.body));
  421. assertTrue(
  422. 'Document should contain BODY',
  423. goog.dom.contains(document, document.body));
  424. var d = goog.dom.createDom(goog.dom.TagName.P, null, 'A paragraph');
  425. var t = d.firstChild;
  426. assertTrue('Same element', goog.dom.contains(d, d));
  427. assertTrue('Same text', goog.dom.contains(t, t));
  428. assertTrue('Nested text', goog.dom.contains(d, t));
  429. assertFalse('Nested text, reversed', goog.dom.contains(t, d));
  430. assertFalse('Disconnected element', goog.dom.contains(document, d));
  431. goog.dom.appendChild(document.body, d);
  432. assertTrue('Connected element', goog.dom.contains(document, d));
  433. goog.dom.removeNode(d);
  434. }
  435. function testCreateDomWithClassName() {
  436. var el = goog.dom.createDom(goog.dom.TagName.DIV, 'cls');
  437. assertNull('firstChild should be null', el.firstChild);
  438. assertEquals(
  439. 'Tagname should be a DIV', String(goog.dom.TagName.DIV), el.tagName);
  440. assertEquals('ClassName should be cls', 'cls', el.className);
  441. el = goog.dom.createDom(goog.dom.TagName.DIV, '');
  442. assertEquals('ClassName should be empty', '', el.className);
  443. }
  444. function testCompareNodeOrder() {
  445. var b1 = $('b1');
  446. var b2 = $('b2');
  447. var p2 = $('p2');
  448. assertEquals(
  449. 'equal nodes should compare to 0', 0, goog.dom.compareNodeOrder(b1, b1));
  450. assertTrue(
  451. 'parent should come before child', goog.dom.compareNodeOrder(p2, b1) < 0);
  452. assertTrue(
  453. 'child should come after parent', goog.dom.compareNodeOrder(b1, p2) > 0);
  454. assertTrue(
  455. 'parent should come before text child',
  456. goog.dom.compareNodeOrder(b1, b1.firstChild) < 0);
  457. assertTrue(
  458. 'text child should come after parent',
  459. goog.dom.compareNodeOrder(b1.firstChild, b1) > 0);
  460. assertTrue(
  461. 'first sibling should come before second',
  462. goog.dom.compareNodeOrder(b1, b2) < 0);
  463. assertTrue(
  464. 'second sibling should come after first',
  465. goog.dom.compareNodeOrder(b2, b1) > 0);
  466. assertTrue(
  467. 'text node after cousin element returns correct value',
  468. goog.dom.compareNodeOrder(b1.nextSibling, b1) > 0);
  469. assertTrue(
  470. 'text node before cousin element returns correct value',
  471. goog.dom.compareNodeOrder(b1, b1.nextSibling) < 0);
  472. assertTrue(
  473. 'text node is before once removed cousin element',
  474. goog.dom.compareNodeOrder(b1.firstChild, b2) < 0);
  475. assertTrue(
  476. 'once removed cousin element is before text node',
  477. goog.dom.compareNodeOrder(b2, b1.firstChild) > 0);
  478. assertTrue(
  479. 'text node is after once removed cousin text node',
  480. goog.dom.compareNodeOrder(b1.nextSibling, b1.firstChild) > 0);
  481. assertTrue(
  482. 'once removed cousin text node is before text node',
  483. goog.dom.compareNodeOrder(b1.firstChild, b1.nextSibling) < 0);
  484. assertTrue(
  485. 'first text node is before second text node',
  486. goog.dom.compareNodeOrder(b1.previousSibling, b1.nextSibling) < 0);
  487. assertTrue(
  488. 'second text node is after first text node',
  489. goog.dom.compareNodeOrder(b1.nextSibling, b1.previousSibling) > 0);
  490. assertTrue(
  491. 'grandchild is after grandparent',
  492. goog.dom.compareNodeOrder(b1.firstChild, b1.parentNode) > 0);
  493. assertTrue(
  494. 'grandparent is after grandchild',
  495. goog.dom.compareNodeOrder(b1.parentNode, b1.firstChild) < 0);
  496. assertTrue(
  497. 'grandchild is after grandparent',
  498. goog.dom.compareNodeOrder(b1.firstChild, b1.parentNode) > 0);
  499. assertTrue(
  500. 'grandparent is after grandchild',
  501. goog.dom.compareNodeOrder(b1.parentNode, b1.firstChild) < 0);
  502. assertTrue(
  503. 'second cousins compare correctly',
  504. goog.dom.compareNodeOrder(b1.firstChild, b2.firstChild) < 0);
  505. assertTrue(
  506. 'second cousins compare correctly in reverse',
  507. goog.dom.compareNodeOrder(b2.firstChild, b1.firstChild) > 0);
  508. assertTrue(
  509. 'testEl2 is after testEl',
  510. goog.dom.compareNodeOrder($('testEl2'), $('testEl')) > 0);
  511. assertTrue(
  512. 'testEl is before testEl2',
  513. goog.dom.compareNodeOrder($('testEl'), $('testEl2')) < 0);
  514. var p = $('order-test');
  515. var text1 = document.createTextNode('1');
  516. p.appendChild(text1);
  517. var text2 = document.createTextNode('1');
  518. p.appendChild(text2);
  519. assertEquals(
  520. 'Equal text nodes should compare to 0', 0,
  521. goog.dom.compareNodeOrder(text1, text1));
  522. assertTrue(
  523. 'First text node is before second',
  524. goog.dom.compareNodeOrder(text1, text2) < 0);
  525. assertTrue(
  526. 'Second text node is after first',
  527. goog.dom.compareNodeOrder(text2, text1) > 0);
  528. assertTrue(
  529. 'Late text node is after b1',
  530. goog.dom.compareNodeOrder(text1, $('b1')) > 0);
  531. assertTrue(
  532. 'Document node is before non-document node',
  533. goog.dom.compareNodeOrder(document, b1) < 0);
  534. assertTrue(
  535. 'Non-document node is after document node',
  536. goog.dom.compareNodeOrder(b1, document) > 0);
  537. }
  538. function testFindCommonAncestor() {
  539. var b1 = $('b1');
  540. var b2 = $('b2');
  541. var p1 = $('p1');
  542. var p2 = $('p2');
  543. var testEl2 = $('testEl2');
  544. assertNull('findCommonAncestor() = null', goog.dom.findCommonAncestor());
  545. assertEquals(
  546. 'findCommonAncestor(b1) = b1', b1, goog.dom.findCommonAncestor(b1));
  547. assertEquals(
  548. 'findCommonAncestor(b1, b1) = b1', b1,
  549. goog.dom.findCommonAncestor(b1, b1));
  550. assertEquals(
  551. 'findCommonAncestor(b1, b2) = p2', p2,
  552. goog.dom.findCommonAncestor(b1, b2));
  553. assertEquals(
  554. 'findCommonAncestor(p1, b2) = body', document.body,
  555. goog.dom.findCommonAncestor(p1, b2));
  556. assertEquals(
  557. 'findCommonAncestor(testEl2, b1, b2, p1, p2) = body', document.body,
  558. goog.dom.findCommonAncestor(testEl2, b1, b2, p1, p2));
  559. var outOfDoc = goog.dom.createElement(goog.dom.TagName.DIV);
  560. assertNull(
  561. 'findCommonAncestor(outOfDoc, b1) = null',
  562. goog.dom.findCommonAncestor(outOfDoc, b1));
  563. }
  564. function testRemoveNode() {
  565. var b = goog.dom.createElement(goog.dom.TagName.B);
  566. var el = $('p1');
  567. el.appendChild(b);
  568. goog.dom.removeNode(b);
  569. assertTrue('b should have been removed', el.lastChild != b);
  570. }
  571. function testReplaceNode() {
  572. var n = $('toReplace');
  573. var previousSibling = n.previousSibling;
  574. var goodNode =
  575. goog.dom.createDom(goog.dom.TagName.DIV, {'id': 'goodReplaceNode'});
  576. goog.dom.replaceNode(goodNode, n);
  577. assertEquals(
  578. 'n should have been replaced', previousSibling.nextSibling, goodNode);
  579. assertNull('n should no longer be in the DOM tree', $('toReplace'));
  580. var badNode =
  581. goog.dom.createDom(goog.dom.TagName.DIV, {'id': 'badReplaceNode'});
  582. goog.dom.replaceNode(badNode, n);
  583. assertNull('badNode should not be in the DOM tree', $('badReplaceNode'));
  584. }
  585. function testAppendChildAt() {
  586. var parent = $('p2');
  587. var origNumChildren = parent.childNodes.length;
  588. var child1 = goog.dom.createElement(goog.dom.TagName.DIV);
  589. goog.dom.insertChildAt(parent, child1, origNumChildren);
  590. assertEquals(origNumChildren + 1, parent.childNodes.length);
  591. var child2 = goog.dom.createElement(goog.dom.TagName.DIV);
  592. goog.dom.insertChildAt(parent, child2, origNumChildren + 42);
  593. assertEquals(origNumChildren + 2, parent.childNodes.length);
  594. var child3 = goog.dom.createElement(goog.dom.TagName.DIV);
  595. goog.dom.insertChildAt(parent, child3, 0);
  596. assertEquals(origNumChildren + 3, parent.childNodes.length);
  597. var child4 = goog.dom.createElement(goog.dom.TagName.DIV);
  598. goog.dom.insertChildAt(parent, child3, 2);
  599. assertEquals(origNumChildren + 3, parent.childNodes.length);
  600. parent.removeChild(child1);
  601. parent.removeChild(child2);
  602. parent.removeChild(child3);
  603. var emptyParentNotInDocument = goog.dom.createElement(goog.dom.TagName.DIV);
  604. goog.dom.insertChildAt(emptyParentNotInDocument, child1, 0);
  605. assertEquals(1, emptyParentNotInDocument.childNodes.length);
  606. }
  607. function testFlattenElement() {
  608. var text = document.createTextNode('Text');
  609. var br = goog.dom.createElement(goog.dom.TagName.BR);
  610. var span = goog.dom.createDom(goog.dom.TagName.SPAN, null, text, br);
  611. assertEquals('span should have 2 children', 2, span.childNodes.length);
  612. var el = $('p1');
  613. el.appendChild(span);
  614. var ret = goog.dom.flattenElement(span);
  615. assertTrue('span should have been removed', el.lastChild != span);
  616. assertFalse(
  617. 'span should have no parent', !!span.parentNode &&
  618. span.parentNode.nodeType != goog.dom.NodeType.DOCUMENT_FRAGMENT);
  619. assertEquals('span should have no children', 0, span.childNodes.length);
  620. assertEquals('Last child of p should be br', br, el.lastChild);
  621. assertEquals(
  622. 'Previous sibling of br should be text', text, br.previousSibling);
  623. var outOfDoc = goog.dom.createDom(goog.dom.TagName.SPAN, null, '1 child');
  624. // Should do nothing.
  625. goog.dom.flattenElement(outOfDoc);
  626. assertEquals(
  627. 'outOfDoc should still have 1 child', 1, outOfDoc.childNodes.length);
  628. }
  629. function testIsNodeLike() {
  630. assertTrue('document should be node like', goog.dom.isNodeLike(document));
  631. assertTrue(
  632. 'document.body should be node like', goog.dom.isNodeLike(document.body));
  633. assertTrue(
  634. 'a text node should be node like',
  635. goog.dom.isNodeLike(document.createTextNode('')));
  636. assertFalse('null should not be node like', goog.dom.isNodeLike(null));
  637. assertFalse('a string should not be node like', goog.dom.isNodeLike('abcd'));
  638. assertTrue(
  639. 'custom object should be node like', goog.dom.isNodeLike({nodeType: 1}));
  640. }
  641. function testIsElement() {
  642. assertFalse('document is not an element', goog.dom.isElement(document));
  643. assertTrue('document.body is an element', goog.dom.isElement(document.body));
  644. assertFalse(
  645. 'a text node is not an element',
  646. goog.dom.isElement(document.createTextNode('')));
  647. assertTrue(
  648. 'an element created with createElement() is an element',
  649. goog.dom.isElement(goog.dom.createElement(goog.dom.TagName.A)));
  650. assertFalse('null is not an element', goog.dom.isElement(null));
  651. assertFalse('a string is not an element', goog.dom.isElement('abcd'));
  652. assertTrue('custom object is an element', goog.dom.isElement({nodeType: 1}));
  653. assertFalse(
  654. 'custom non-element object is a not an element',
  655. goog.dom.isElement({someProperty: 'somevalue'}));
  656. }
  657. function testIsWindow() {
  658. var global = goog.global;
  659. var frame = window.frames['frame'];
  660. var otherWindow = window.open('', 'blank');
  661. var object = {window: goog.global};
  662. var nullVar = null;
  663. var notDefined;
  664. try {
  665. // Use try/finally to ensure that we clean up the window we open, even if an
  666. // assertion fails or something else goes wrong.
  667. assertTrue(
  668. 'global object in HTML context should be a window',
  669. goog.dom.isWindow(goog.global));
  670. assertTrue('iframe window should be a window', goog.dom.isWindow(frame));
  671. if (otherWindow) {
  672. assertTrue(
  673. 'other window should be a window', goog.dom.isWindow(otherWindow));
  674. }
  675. assertFalse('object should not be a window', goog.dom.isWindow(object));
  676. assertFalse('null should not be a window', goog.dom.isWindow(nullVar));
  677. assertFalse(
  678. 'undefined should not be a window', goog.dom.isWindow(notDefined));
  679. } finally {
  680. if (otherWindow) {
  681. otherWindow.close();
  682. }
  683. }
  684. }
  685. function testGetOwnerDocument() {
  686. assertEquals(goog.dom.getOwnerDocument($('p1')), document);
  687. assertEquals(goog.dom.getOwnerDocument(document.body), document);
  688. assertEquals(goog.dom.getOwnerDocument(document.documentElement), document);
  689. }
  690. // Tests the breakages resulting in rollback cl/64715474
  691. function testGetOwnerDocumentNonNodeInput() {
  692. // We should fail on null.
  693. assertThrows(function() { goog.dom.getOwnerDocument(null); });
  694. assertEquals(document, goog.dom.getOwnerDocument(window));
  695. }
  696. function testDomHelper() {
  697. var x = new goog.dom.DomHelper(window.frames['frame'].document);
  698. assertTrue(
  699. 'Should have some HTML', x.getDocument().body.innerHTML.length > 0);
  700. }
  701. function testGetFirstElementChild() {
  702. var p2 = $('p2');
  703. var b1 = goog.dom.getFirstElementChild(p2);
  704. assertNotNull('First element child of p2 should not be null', b1);
  705. assertEquals('First element child is b1', 'b1', b1.id);
  706. var c = goog.dom.getFirstElementChild(b1);
  707. assertNull('First element child of b1 should be null', c);
  708. // Test with an undefined firstElementChild attribute.
  709. var b2 = $('b2');
  710. var mockP2 = {
  711. childNodes: [b1, b2],
  712. firstChild: b1,
  713. firstElementChild: undefined
  714. };
  715. b1 = goog.dom.getFirstElementChild(mockP2);
  716. assertNotNull('First element child of mockP2 should not be null', b1);
  717. assertEquals('First element child is b1', 'b1', b1.id);
  718. }
  719. function testGetLastElementChild() {
  720. var p2 = $('p2');
  721. var b2 = goog.dom.getLastElementChild(p2);
  722. assertNotNull('Last element child of p2 should not be null', b2);
  723. assertEquals('Last element child is b2', 'b2', b2.id);
  724. var c = goog.dom.getLastElementChild(b2);
  725. assertNull('Last element child of b2 should be null', c);
  726. // Test with an undefined lastElementChild attribute.
  727. var b1 = $('b1');
  728. var mockP2 = {
  729. childNodes: [b1, b2],
  730. lastChild: b2,
  731. lastElementChild: undefined
  732. };
  733. b2 = goog.dom.getLastElementChild(mockP2);
  734. assertNotNull('Last element child of mockP2 should not be null', b2);
  735. assertEquals('Last element child is b2', 'b2', b2.id);
  736. }
  737. function testGetNextElementSibling() {
  738. var b1 = $('b1');
  739. var b2 = goog.dom.getNextElementSibling(b1);
  740. assertNotNull('Next element sibling of b1 should not be null', b1);
  741. assertEquals('Next element sibling is b2', 'b2', b2.id);
  742. var c = goog.dom.getNextElementSibling(b2);
  743. assertNull('Next element sibling of b2 should be null', c);
  744. // Test with an undefined nextElementSibling attribute.
  745. var mockB1 = {nextSibling: b2, nextElementSibling: undefined};
  746. b2 = goog.dom.getNextElementSibling(mockB1);
  747. assertNotNull('Next element sibling of mockB1 should not be null', b1);
  748. assertEquals('Next element sibling is b2', 'b2', b2.id);
  749. }
  750. function testGetPreviousElementSibling() {
  751. var b2 = $('b2');
  752. var b1 = goog.dom.getPreviousElementSibling(b2);
  753. assertNotNull('Previous element sibling of b2 should not be null', b1);
  754. assertEquals('Previous element sibling is b1', 'b1', b1.id);
  755. var c = goog.dom.getPreviousElementSibling(b1);
  756. assertNull('Previous element sibling of b1 should be null', c);
  757. // Test with an undefined previousElementSibling attribute.
  758. var mockB2 = {previousSibling: b1, previousElementSibling: undefined};
  759. b1 = goog.dom.getPreviousElementSibling(mockB2);
  760. assertNotNull('Previous element sibling of mockB2 should not be null', b1);
  761. assertEquals('Previous element sibling is b1', 'b1', b1.id);
  762. }
  763. function testGetChildren() {
  764. var p2 = $('p2');
  765. var children = goog.dom.getChildren(p2);
  766. assertNotNull('Elements array should not be null', children);
  767. assertEquals(
  768. 'List of element children should be length two.', 2, children.length);
  769. var b1 = $('b1');
  770. var b2 = $('b2');
  771. assertObjectEquals('First element child should be b1.', b1, children[0]);
  772. assertObjectEquals('Second element child should be b2.', b2, children[1]);
  773. var noChildren = goog.dom.getChildren(b1);
  774. assertNotNull('Element children array should not be null', noChildren);
  775. assertEquals(
  776. 'List of element children should be length zero.', 0, noChildren.length);
  777. // Test with an undefined children attribute.
  778. var mockP2 = {childNodes: [b1, b2], children: undefined};
  779. children = goog.dom.getChildren(mockP2);
  780. assertNotNull('Elements array should not be null', children);
  781. assertEquals(
  782. 'List of element children should be length two.', 2, children.length);
  783. assertObjectEquals('First element child should be b1.', b1, children[0]);
  784. assertObjectEquals('Second element child should be b2.', b2, children[1]);
  785. }
  786. function testGetNextNode() {
  787. var tree = goog.dom.safeHtmlToNode(goog.html.testing.newSafeHtmlForTest(
  788. '<div>' +
  789. '<p>Some text</p>' +
  790. '<blockquote>Some <i>special</i> <b>text</b></blockquote>' +
  791. '<address><!-- comment -->Foo</address>' +
  792. '</div>'));
  793. assertNull(goog.dom.getNextNode(null));
  794. var node = tree;
  795. var next = function() { return node = goog.dom.getNextNode(node); };
  796. assertEquals(String(goog.dom.TagName.P), next().tagName);
  797. assertEquals('Some text', next().nodeValue);
  798. assertEquals(String(goog.dom.TagName.BLOCKQUOTE), next().tagName);
  799. assertEquals('Some ', next().nodeValue);
  800. assertEquals(String(goog.dom.TagName.I), next().tagName);
  801. assertEquals('special', next().nodeValue);
  802. assertEquals(' ', next().nodeValue);
  803. assertEquals(String(goog.dom.TagName.B), next().tagName);
  804. assertEquals('text', next().nodeValue);
  805. assertEquals(String(goog.dom.TagName.ADDRESS), next().tagName);
  806. assertEquals(goog.dom.NodeType.COMMENT, next().nodeType);
  807. assertEquals('Foo', next().nodeValue);
  808. assertNull(next());
  809. }
  810. function testGetPreviousNode() {
  811. var tree = goog.dom.safeHtmlToNode(goog.html.testing.newSafeHtmlForTest(
  812. '<div>' +
  813. '<p>Some text</p>' +
  814. '<blockquote>Some <i>special</i> <b>text</b></blockquote>' +
  815. '<address><!-- comment -->Foo</address>' +
  816. '</div>'));
  817. assertNull(goog.dom.getPreviousNode(null));
  818. var node = tree.lastChild.lastChild;
  819. var previous = function() { return node = goog.dom.getPreviousNode(node); };
  820. assertEquals(goog.dom.NodeType.COMMENT, previous().nodeType);
  821. assertEquals(String(goog.dom.TagName.ADDRESS), previous().tagName);
  822. assertEquals('text', previous().nodeValue);
  823. assertEquals(String(goog.dom.TagName.B), previous().tagName);
  824. assertEquals(' ', previous().nodeValue);
  825. assertEquals('special', previous().nodeValue);
  826. assertEquals(String(goog.dom.TagName.I), previous().tagName);
  827. assertEquals('Some ', previous().nodeValue);
  828. assertEquals(String(goog.dom.TagName.BLOCKQUOTE), previous().tagName);
  829. assertEquals('Some text', previous().nodeValue);
  830. assertEquals(String(goog.dom.TagName.P), previous().tagName);
  831. assertEquals(String(goog.dom.TagName.DIV), previous().tagName);
  832. if (!goog.userAgent.IE) {
  833. // Internet Explorer maintains a parentNode for Elements after they are
  834. // removed from the hierarchy. Everyone else agrees on a null parentNode.
  835. assertNull(previous());
  836. }
  837. }
  838. function testSetTextContent() {
  839. var p1 = $('p1');
  840. var s = 'hello world';
  841. goog.dom.setTextContent(p1, s);
  842. assertEquals(
  843. 'We should have one childNode after setTextContent', 1,
  844. p1.childNodes.length);
  845. assertEquals(s, p1.firstChild.data);
  846. assertEquals(s, p1.innerHTML);
  847. s = 'four elefants < five ants';
  848. var sHtml = 'four elefants &lt; five ants';
  849. goog.dom.setTextContent(p1, s);
  850. assertEquals(
  851. 'We should have one childNode after setTextContent', 1,
  852. p1.childNodes.length);
  853. assertEquals(s, p1.firstChild.data);
  854. assertEquals(sHtml, p1.innerHTML);
  855. // ensure that we remove existing children
  856. p1.innerHTML = 'a<b>b</b>c';
  857. s = 'hello world';
  858. goog.dom.setTextContent(p1, s);
  859. assertEquals(
  860. 'We should have one childNode after setTextContent', 1,
  861. p1.childNodes.length);
  862. assertEquals(s, p1.firstChild.data);
  863. // same but start with an element
  864. p1.innerHTML = '<b>a</b>b<i>c</i>';
  865. s = 'hello world';
  866. goog.dom.setTextContent(p1, s);
  867. assertEquals(
  868. 'We should have one childNode after setTextContent', 1,
  869. p1.childNodes.length);
  870. assertEquals(s, p1.firstChild.data);
  871. // Text/CharacterData
  872. goog.dom.setTextContent(p1, 'before');
  873. s = 'after';
  874. goog.dom.setTextContent(p1.firstChild, s);
  875. assertEquals(
  876. 'We should have one childNode after setTextContent', 1,
  877. p1.childNodes.length);
  878. assertEquals(s, p1.firstChild.data);
  879. // DocumentFragment
  880. var df = document.createDocumentFragment();
  881. s = 'hello world';
  882. goog.dom.setTextContent(df, s);
  883. assertEquals(
  884. 'We should have one childNode after setTextContent', 1,
  885. df.childNodes.length);
  886. assertEquals(s, df.firstChild.data);
  887. // clean up
  888. goog.dom.removeChildren(p1);
  889. }
  890. function testFindNode() {
  891. var expected = document.body;
  892. var result = goog.dom.findNode(document, function(n) {
  893. return n.nodeType == goog.dom.NodeType.ELEMENT &&
  894. n.tagName == goog.dom.TagName.BODY;
  895. });
  896. assertEquals(expected, result);
  897. expected = goog.dom.getElementsByTagName(goog.dom.TagName.P)[0];
  898. result = goog.dom.findNode(document, function(n) {
  899. return n.nodeType == goog.dom.NodeType.ELEMENT &&
  900. n.tagName == goog.dom.TagName.P;
  901. });
  902. assertEquals(expected, result);
  903. result = goog.dom.findNode(document, function(n) { return false; });
  904. assertUndefined(result);
  905. }
  906. function testFindNodes() {
  907. var expected = goog.dom.getElementsByTagName(goog.dom.TagName.P);
  908. var result = goog.dom.findNodes(document, function(n) {
  909. return n.nodeType == goog.dom.NodeType.ELEMENT &&
  910. n.tagName == goog.dom.TagName.P;
  911. });
  912. assertEquals(expected.length, result.length);
  913. assertEquals(expected[0], result[0]);
  914. assertEquals(expected[1], result[1]);
  915. result = goog.dom.findNodes(document, function(n) { return false; }).length;
  916. assertEquals(0, result);
  917. }
  918. function createTestDom(txt) {
  919. var dom = goog.dom.createDom(goog.dom.TagName.DIV);
  920. dom.innerHTML = txt;
  921. return dom;
  922. }
  923. function testIsFocusableTabIndex() {
  924. assertFalse(
  925. 'isFocusableTabIndex() must be false for no tab index',
  926. goog.dom.isFocusableTabIndex(goog.dom.getElement('noTabIndex')));
  927. assertFalse(
  928. 'isFocusableTabIndex() must be false for tab index -2',
  929. goog.dom.isFocusableTabIndex(goog.dom.getElement('tabIndexNegative2')));
  930. assertFalse(
  931. 'isFocusableTabIndex() must be false for tab index -1',
  932. goog.dom.isFocusableTabIndex(goog.dom.getElement('tabIndexNegative1')));
  933. // WebKit on Mac doesn't support focusable DIVs until version 526 and later.
  934. if (!goog.userAgent.WEBKIT || !goog.userAgent.MAC ||
  935. goog.userAgent.isVersionOrHigher('526')) {
  936. assertTrue(
  937. 'isFocusableTabIndex() must be true for tab index 0',
  938. goog.dom.isFocusableTabIndex(goog.dom.getElement('tabIndex0')));
  939. assertTrue(
  940. 'isFocusableTabIndex() must be true for tab index 1',
  941. goog.dom.isFocusableTabIndex(goog.dom.getElement('tabIndex1')));
  942. assertTrue(
  943. 'isFocusableTabIndex() must be true for tab index 2',
  944. goog.dom.isFocusableTabIndex(goog.dom.getElement('tabIndex2')));
  945. }
  946. }
  947. function testSetFocusableTabIndex() {
  948. // WebKit on Mac doesn't support focusable DIVs until version 526 and later.
  949. if (!goog.userAgent.WEBKIT || !goog.userAgent.MAC ||
  950. goog.userAgent.isVersionOrHigher('526')) {
  951. // Test enabling focusable tab index.
  952. goog.dom.setFocusableTabIndex(goog.dom.getElement('noTabIndex'), true);
  953. assertTrue(
  954. 'isFocusableTabIndex() must be true after enabling tab index',
  955. goog.dom.isFocusableTabIndex(goog.dom.getElement('noTabIndex')));
  956. // Test disabling focusable tab index that was added programmatically.
  957. goog.dom.setFocusableTabIndex(goog.dom.getElement('noTabIndex'), false);
  958. assertFalse(
  959. 'isFocusableTabIndex() must be false after disabling tab ' +
  960. 'index that was programmatically added',
  961. goog.dom.isFocusableTabIndex(goog.dom.getElement('noTabIndex')));
  962. // Test disabling focusable tab index that was specified in markup.
  963. goog.dom.setFocusableTabIndex(goog.dom.getElement('tabIndex0'), false);
  964. assertFalse(
  965. 'isFocusableTabIndex() must be false after disabling tab ' +
  966. 'index that was specified in markup',
  967. goog.dom.isFocusableTabIndex(goog.dom.getElement('tabIndex0')));
  968. // Test re-enabling focusable tab index.
  969. goog.dom.setFocusableTabIndex(goog.dom.getElement('tabIndex0'), true);
  970. assertTrue(
  971. 'isFocusableTabIndex() must be true after reenabling tabindex',
  972. goog.dom.isFocusableTabIndex(goog.dom.getElement('tabIndex0')));
  973. }
  974. }
  975. function testIsFocusable() {
  976. // Test all types of form elements with no tab index specified are focusable.
  977. assertTrue(
  978. 'isFocusable() must be true for anchor elements with ' +
  979. 'no tab index',
  980. goog.dom.isFocusable(goog.dom.getElement('noTabIndexAnchor')));
  981. assertTrue(
  982. 'isFocusable() must be true for input elements with ' +
  983. 'no tab index',
  984. goog.dom.isFocusable(goog.dom.getElement('noTabIndexInput')));
  985. assertTrue(
  986. 'isFocusable() must be true for textarea elements with ' +
  987. 'no tab index',
  988. goog.dom.isFocusable(goog.dom.getElement('noTabIndexTextArea')));
  989. assertTrue(
  990. 'isFocusable() must be true for select elements with ' +
  991. 'no tab index',
  992. goog.dom.isFocusable(goog.dom.getElement('noTabIndexSelect')));
  993. assertTrue(
  994. 'isFocusable() must be true for button elements with ' +
  995. 'no tab index',
  996. goog.dom.isFocusable(goog.dom.getElement('noTabIndexButton')));
  997. // Test form element with negative tab index is not focusable.
  998. assertFalse(
  999. 'isFocusable() must be false for form elements with ' +
  1000. 'negative tab index',
  1001. goog.dom.isFocusable(goog.dom.getElement('negTabIndexButton')));
  1002. // Test form element with zero tab index is focusable.
  1003. assertTrue(
  1004. 'isFocusable() must be true for form elements with ' +
  1005. 'zero tab index',
  1006. goog.dom.isFocusable(goog.dom.getElement('zeroTabIndexButton')));
  1007. // Test form element with positive tab index is focusable.
  1008. assertTrue(
  1009. 'isFocusable() must be true for form elements with ' +
  1010. 'positive tab index',
  1011. goog.dom.isFocusable(goog.dom.getElement('posTabIndexButton')));
  1012. // Test disabled form element with no tab index is not focusable.
  1013. assertFalse(
  1014. 'isFocusable() must be false for disabled form elements with ' +
  1015. 'no tab index',
  1016. goog.dom.isFocusable(goog.dom.getElement('disabledNoTabIndexButton')));
  1017. // Test disabled form element with negative tab index is not focusable.
  1018. assertFalse(
  1019. 'isFocusable() must be false for disabled form elements with ' +
  1020. 'negative tab index',
  1021. goog.dom.isFocusable(goog.dom.getElement('disabledNegTabIndexButton')));
  1022. // Test disabled form element with zero tab index is not focusable.
  1023. assertFalse(
  1024. 'isFocusable() must be false for disabled form elements with ' +
  1025. 'zero tab index',
  1026. goog.dom.isFocusable(goog.dom.getElement('disabledZeroTabIndexButton')));
  1027. // Test disabled form element with positive tab index is not focusable.
  1028. assertFalse(
  1029. 'isFocusable() must be false for disabled form elements with ' +
  1030. 'positive tab index',
  1031. goog.dom.isFocusable(goog.dom.getElement('disabledPosTabIndexButton')));
  1032. // Test non-form types should return same value as isFocusableTabIndex()
  1033. assertEquals(
  1034. 'isFocusable() and isFocusableTabIndex() must agree for ' +
  1035. ' no tab index',
  1036. goog.dom.isFocusableTabIndex(goog.dom.getElement('noTabIndex')),
  1037. goog.dom.isFocusable(goog.dom.getElement('noTabIndex')));
  1038. assertEquals(
  1039. 'isFocusable() and isFocusableTabIndex() must agree for ' +
  1040. ' tab index -2',
  1041. goog.dom.isFocusableTabIndex(goog.dom.getElement('tabIndexNegative2')),
  1042. goog.dom.isFocusable(goog.dom.getElement('tabIndexNegative2')));
  1043. assertEquals(
  1044. 'isFocusable() and isFocusableTabIndex() must agree for ' +
  1045. ' tab index -1',
  1046. goog.dom.isFocusableTabIndex(goog.dom.getElement('tabIndexNegative1')),
  1047. goog.dom.isFocusable(goog.dom.getElement('tabIndexNegative1')));
  1048. // Make sure IE doesn't throw for detached elements. IE can't measure detached
  1049. // elements, and calling getBoundingClientRect() will throw Unspecified Error.
  1050. goog.dom.isFocusable(goog.dom.createDom(goog.dom.TagName.BUTTON));
  1051. }
  1052. function testGetTextContent() {
  1053. function t(inp, out) {
  1054. assertEquals(
  1055. out.replace(/ /g, '_'),
  1056. goog.dom.getTextContent(createTestDom(inp)).replace(/ /g, '_'));
  1057. }
  1058. t('abcde', 'abcde');
  1059. t('a<b>bcd</b>efgh', 'abcdefgh');
  1060. t('a<script type="text/javascript' +
  1061. '">var a=1;<' +
  1062. '/script>h',
  1063. 'ah');
  1064. t('<html><head><style type="text/css">' +
  1065. 'p{margin:100%;padding:5px}\n.class{background-color:red;}</style>' +
  1066. '</head><body><h1>Hello</h1>\n<p>One two three</p>\n<table><tr><td>a' +
  1067. '<td>b</table><' +
  1068. 'script>var a = \'foo\';' +
  1069. '</scrip' +
  1070. 't></body></html>',
  1071. 'HelloOne two threeab');
  1072. t('abc<br>def', 'abc\ndef');
  1073. t('abc<br>\ndef', 'abc\ndef');
  1074. t('abc<br>\n\ndef', 'abc\ndef');
  1075. t('abc<br><br>\ndef', 'abc\n\ndef');
  1076. t(' <b>abcde </b> ', 'abcde ');
  1077. t(' <b>abcde </b> hi ', 'abcde hi ');
  1078. t(' \n<b>abcde </b> ', 'abcde ');
  1079. t(' \n<b>abcde </b> \n\n\n', 'abcde ');
  1080. t('<p>abcde</p>\nfg', 'abcdefg');
  1081. t('\n <div> <b>abcde </b> ', 'abcde ');
  1082. t(' \n&shy;<b>abcde &shy; </b> \n\n\n&shy;', 'abcde ');
  1083. t(' \n&shy;\n\n&shy;\na ', 'a ');
  1084. t(' \n<wbr></wbr><b>abcde <wbr></wbr> </b> \n\n\n<wbr></wbr>', 'abcde ');
  1085. t('a&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;b',
  1086. goog.dom.BrowserFeature.CAN_USE_INNER_TEXT ? 'a b' :
  1087. 'a\xA0\xA0\xA0\xA0\xA0b');
  1088. }
  1089. function testGetNodeTextLength() {
  1090. assertEquals(6, goog.dom.getNodeTextLength(createTestDom('abcdef')));
  1091. assertEquals(8, goog.dom.getNodeTextLength(createTestDom('a<b>bcd</b>efgh')));
  1092. assertEquals(
  1093. 2, goog.dom.getNodeTextLength(
  1094. createTestDom(
  1095. 'a<script type="text/javascript' +
  1096. '">var a = 1234;<' +
  1097. '/script>h')));
  1098. assertEquals(
  1099. 4, goog.dom.getNodeTextLength(
  1100. createTestDom('a<br>\n<!-- some comments -->\nfo')));
  1101. assertEquals(
  1102. 20,
  1103. goog.dom.getNodeTextLength(
  1104. createTestDom(
  1105. '<html><head><style type="text/css">' +
  1106. 'p{margin:100%;padding:5px}\n.class{background-color:red;}</style>' +
  1107. '</head><body><h1>Hello</h1><p>One two three</p><table><tr><td>a<td>b' +
  1108. '</table><' +
  1109. 'script>var a = \'foo\';</scrip' +
  1110. 't></body></html>')));
  1111. assertEquals(
  1112. 10, goog.dom.getNodeTextLength(createTestDom('a<b>bcd</b><br />efghi')));
  1113. }
  1114. function testGetNodeTextOffset() {
  1115. assertEquals(
  1116. 4, goog.dom.getNodeTextOffset($('offsetTest1'), $('offsetParent1')));
  1117. assertEquals(12, goog.dom.getNodeTextOffset($('offsetTest1')));
  1118. }
  1119. function testGetNodeAtOffset() {
  1120. var html = '<div id=a>123<b id=b>45</b><span id=c>67<b id=d>89<i id=e>01' +
  1121. '</i>23<i id=f>45</i>67</b>890<i id=g>123</i><b id=h>456</b>' +
  1122. '</span></div><div id=i>7890<i id=j>123</i></div>';
  1123. var node = goog.dom.createElement(goog.dom.TagName.DIV);
  1124. node.innerHTML = html;
  1125. var rv = {};
  1126. goog.dom.getNodeAtOffset(node, 2, rv);
  1127. assertEquals('123', rv.node.nodeValue);
  1128. assertEquals('a', rv.node.parentNode.id);
  1129. assertEquals(1, rv.remainder);
  1130. goog.dom.getNodeAtOffset(node, 3, rv);
  1131. assertEquals('123', rv.node.nodeValue);
  1132. assertEquals('a', rv.node.parentNode.id);
  1133. assertEquals(2, rv.remainder);
  1134. goog.dom.getNodeAtOffset(node, 5, rv);
  1135. assertEquals('45', rv.node.nodeValue);
  1136. assertEquals('b', rv.node.parentNode.id);
  1137. assertEquals(1, rv.remainder);
  1138. goog.dom.getNodeAtOffset(node, 6, rv);
  1139. assertEquals('67', rv.node.nodeValue);
  1140. assertEquals('c', rv.node.parentNode.id);
  1141. assertEquals(0, rv.remainder);
  1142. goog.dom.getNodeAtOffset(node, 23, rv);
  1143. assertEquals('123', rv.node.nodeValue);
  1144. assertEquals('g', rv.node.parentNode.id);
  1145. assertEquals(2, rv.remainder);
  1146. goog.dom.getNodeAtOffset(node, 30, rv);
  1147. assertEquals('7890', rv.node.nodeValue);
  1148. assertEquals('i', rv.node.parentNode.id);
  1149. assertEquals(3, rv.remainder);
  1150. }
  1151. // IE inserts line breaks and capitalizes nodenames.
  1152. function assertEqualsCaseAndLeadingWhitespaceInsensitive(value1, value2) {
  1153. value1 = value1.replace(/^\s+|\s+$/g, '').toLowerCase();
  1154. value2 = value2.replace(/^\s+|\s+$/g, '').toLowerCase();
  1155. assertEquals(value1, value2);
  1156. }
  1157. function testGetOuterHtml() {
  1158. var contents = '<b>foo</b>';
  1159. var node = goog.dom.createElement(goog.dom.TagName.DIV);
  1160. node.setAttribute('foo', 'bar');
  1161. node.innerHTML = contents;
  1162. assertEqualsCaseAndLeadingWhitespaceInsensitive(
  1163. goog.dom.getOuterHtml(node), '<div foo="bar">' + contents + '</div>');
  1164. var imgNode = goog.dom.createElement(goog.dom.TagName.IMG);
  1165. imgNode.setAttribute('foo', 'bar');
  1166. assertEqualsCaseAndLeadingWhitespaceInsensitive(
  1167. goog.dom.getOuterHtml(imgNode), '<img foo="bar">');
  1168. }
  1169. function testGetWindowFrame() {
  1170. var frameWindow = window.frames['frame'];
  1171. var frameDocument = frameWindow.document;
  1172. var frameDomHelper = new goog.dom.DomHelper(frameDocument);
  1173. // Cannot use assertEquals since IE fails on ===
  1174. assertTrue(frameWindow == frameDomHelper.getWindow());
  1175. }
  1176. function testGetWindow() {
  1177. var domHelper = new goog.dom.DomHelper();
  1178. // Cannot use assertEquals since IE fails on ===
  1179. assertTrue(window == domHelper.getWindow());
  1180. }
  1181. function testGetWindowStatic() {
  1182. // Cannot use assertEquals since IE fails on ===
  1183. assertTrue(window == goog.dom.getWindow());
  1184. }
  1185. function testIsNodeList() {
  1186. var elem = document.getElementById('p2');
  1187. var text = document.getElementById('b2').firstChild;
  1188. assertTrue(
  1189. 'NodeList should be a node list', goog.dom.isNodeList(elem.childNodes));
  1190. assertFalse('TextNode should not be a node list', goog.dom.isNodeList(text));
  1191. assertFalse(
  1192. 'Array of nodes should not be a node list',
  1193. goog.dom.isNodeList([elem.firstChild, elem.lastChild]));
  1194. }
  1195. function testGetFrameContentDocument() {
  1196. var iframe = goog.dom.getElementsByTagName(goog.dom.TagName.IFRAME)[0];
  1197. var name = iframe.name;
  1198. var iframeDoc = goog.dom.getFrameContentDocument(iframe);
  1199. assertEquals(window.frames[name].document, iframeDoc);
  1200. }
  1201. function testGetFrameContentWindow() {
  1202. var iframe = goog.dom.getElementsByTagName(goog.dom.TagName.IFRAME)[0];
  1203. var name = iframe.name;
  1204. var iframeWin = goog.dom.getFrameContentWindow(iframe);
  1205. assertEquals(window.frames[name], iframeWin);
  1206. }
  1207. function testGetFrameContentWindowNotInitialized() {
  1208. var iframe = goog.dom.createDom(goog.dom.TagName.IFRAME);
  1209. assertNull(goog.dom.getFrameContentWindow(iframe));
  1210. }
  1211. function testCanHaveChildren() {
  1212. var EMPTY_ELEMENTS = goog.object.createSet(
  1213. goog.dom.TagName.APPLET, goog.dom.TagName.AREA, goog.dom.TagName.BASE,
  1214. goog.dom.TagName.BR, goog.dom.TagName.COL, goog.dom.TagName.COMMAND,
  1215. goog.dom.TagName.EMBED, goog.dom.TagName.FRAME, goog.dom.TagName.HR,
  1216. goog.dom.TagName.IMG, goog.dom.TagName.INPUT, goog.dom.TagName.IFRAME,
  1217. goog.dom.TagName.ISINDEX, goog.dom.TagName.KEYGEN, goog.dom.TagName.LINK,
  1218. goog.dom.TagName.NOFRAMES, goog.dom.TagName.NOSCRIPT,
  1219. goog.dom.TagName.META, goog.dom.TagName.OBJECT, goog.dom.TagName.PARAM,
  1220. goog.dom.TagName.SCRIPT, goog.dom.TagName.SOURCE, goog.dom.TagName.STYLE,
  1221. goog.dom.TagName.TRACK, goog.dom.TagName.WBR);
  1222. // IE opens a dialog warning about using Java content if an EMBED is created.
  1223. var IE_ILLEGAL_ELEMENTS = goog.object.createSet(goog.dom.TagName.EMBED);
  1224. for (var tag in goog.dom.TagName) {
  1225. if (goog.userAgent.IE && tag in IE_ILLEGAL_ELEMENTS) {
  1226. continue;
  1227. }
  1228. var expected = !(tag in EMPTY_ELEMENTS);
  1229. var node = goog.dom.createElement(tag);
  1230. assertEquals(
  1231. tag + ' should ' + (expected ? '' : 'not ') + 'have children', expected,
  1232. goog.dom.canHaveChildren(node));
  1233. // Make sure we can _actually_ add a child if we identify the node as
  1234. // allowing children.
  1235. if (goog.dom.canHaveChildren(node)) {
  1236. node.appendChild(goog.dom.createDom(goog.dom.TagName.DIV, null, 'foo'));
  1237. }
  1238. }
  1239. }
  1240. function testGetAncestorNoElement() {
  1241. assertNull(goog.dom.getAncestor(
  1242. null /* element */, goog.functions.TRUE /* matcher */));
  1243. assertNull(goog.dom.getAncestor(
  1244. null /* element */, goog.functions.TRUE /* matcher */,
  1245. true /* opt_includeNode */));
  1246. }
  1247. function testGetAncestorNoMatch() {
  1248. var elem = goog.dom.getElement('nestedElement');
  1249. assertNull(goog.dom.getAncestor(elem, function() { return false; }));
  1250. }
  1251. function testGetAncestorMatchSelf() {
  1252. var elem = goog.dom.getElement('nestedElement');
  1253. var matched = goog.dom.getAncestor(elem, function() { return true; }, true);
  1254. assertEquals(elem, matched);
  1255. }
  1256. function testGetAncestorNoMatchSelf() {
  1257. var elem = goog.dom.getElement('nestedElement');
  1258. var matched = goog.dom.getAncestor(elem, function() { return true; });
  1259. assertEquals(elem.parentNode, matched);
  1260. }
  1261. function testGetAncestorWithMaxSearchStepsMatchSelf() {
  1262. var elem = goog.dom.getElement('nestedElement');
  1263. var matched =
  1264. goog.dom.getAncestor(elem, function() { return true; }, true, 2);
  1265. assertEquals(elem, matched);
  1266. }
  1267. function testGetAncestorWithMaxSearchStepsMatch() {
  1268. var elem = goog.dom.getElement('nestedElement');
  1269. var searchEl = elem.parentNode.parentNode;
  1270. var matched = goog.dom.getAncestor(
  1271. elem, function(el) { return el == searchEl; }, false, 1);
  1272. assertEquals(searchEl, matched);
  1273. }
  1274. function testGetAncestorWithMaxSearchStepsNoMatch() {
  1275. var elem = goog.dom.getElement('nestedElement');
  1276. var searchEl = elem.parentNode.parentNode;
  1277. var matched = goog.dom.getAncestor(
  1278. elem, function(el) { return el == searchEl; }, false, 0);
  1279. assertNull(matched);
  1280. }
  1281. function testGetAncestorByTagWithMaxSearchStepsNoMatch() {
  1282. var elem = goog.dom.getElement('nestedElement');
  1283. var searchEl = elem.parentNode.parentNode;
  1284. var matched = goog.dom.getAncestorByTagNameAndClass(
  1285. elem, goog.dom.TagName.DIV, /* class */ undefined, 0);
  1286. assertNull(matched);
  1287. }
  1288. function testGetAncestorByTagNameNoMatch() {
  1289. var elem = goog.dom.getElement('nestedElement');
  1290. assertNull(goog.dom.getAncestorByTagNameAndClass(elem, goog.dom.TagName.IMG));
  1291. }
  1292. function testGetAncestorByTagNameOnly() {
  1293. var elem = goog.dom.getElement('nestedElement');
  1294. var expected = goog.dom.getElement('testAncestorDiv');
  1295. assertEquals(
  1296. expected,
  1297. goog.dom.getAncestorByTagNameAndClass(elem, goog.dom.TagName.DIV));
  1298. assertEquals(expected, goog.dom.getAncestorByTagNameAndClass(elem, 'div'));
  1299. }
  1300. function testGetAncestorByClassWithMaxSearchStepsNoMatch() {
  1301. var elem = goog.dom.getElement('nestedElement');
  1302. var searchEl = elem.parentNode.parentNode;
  1303. var matched = goog.dom.getAncestorByClass(elem, 'testAncestor', 0);
  1304. assertNull(matched);
  1305. }
  1306. function testGetAncestorByClassNameNoMatch() {
  1307. var elem = goog.dom.getElement('nestedElement');
  1308. assertNull(goog.dom.getAncestorByClass(elem, 'bogusClassName'));
  1309. }
  1310. function testGetAncestorByClassName() {
  1311. var elem = goog.dom.getElement('nestedElement');
  1312. var expected = goog.dom.getElement('testAncestorP');
  1313. assertEquals(expected, goog.dom.getAncestorByClass(elem, 'testAncestor'));
  1314. }
  1315. function testGetAncestorByTagNameAndClass() {
  1316. var elem = goog.dom.getElement('nestedElement');
  1317. var expected = goog.dom.getElement('testAncestorDiv');
  1318. assertEquals(
  1319. expected, goog.dom.getAncestorByTagNameAndClass(
  1320. elem, goog.dom.TagName.DIV, 'testAncestor'));
  1321. assertNull(
  1322. 'Should return null if no search criteria are given',
  1323. goog.dom.getAncestorByTagNameAndClass(elem));
  1324. }
  1325. function testCreateTable() {
  1326. var table = goog.dom.createTable(2, 3, true);
  1327. assertEquals(
  1328. 2, goog.dom.getElementsByTagName(goog.dom.TagName.TR, table).length);
  1329. assertEquals(
  1330. 3, goog.dom.getElementsByTagName(goog.dom.TagName.TR, table)[0]
  1331. .childNodes.length);
  1332. assertEquals(
  1333. 6, goog.dom.getElementsByTagName(goog.dom.TagName.TD, table).length);
  1334. assertEquals(
  1335. goog.string.Unicode.NBSP,
  1336. goog.dom.getElementsByTagName(goog.dom.TagName.TD, table)[0]
  1337. .firstChild.nodeValue);
  1338. table = goog.dom.createTable(2, 3, false);
  1339. assertEquals(
  1340. 2, goog.dom.getElementsByTagName(goog.dom.TagName.TR, table).length);
  1341. assertEquals(
  1342. 3, goog.dom.getElementsByTagName(goog.dom.TagName.TR, table)[0]
  1343. .childNodes.length);
  1344. assertEquals(
  1345. 6, goog.dom.getElementsByTagName(goog.dom.TagName.TD, table).length);
  1346. assertEquals(
  1347. 0, goog.dom.getElementsByTagName(goog.dom.TagName.TD, table)[0]
  1348. .childNodes.length);
  1349. }
  1350. function testSafeHtmlToNode() {
  1351. var docFragment = goog.dom.safeHtmlToNode(
  1352. goog.html.testing.newSafeHtmlForTest('<a>1</a><b>2</b>'));
  1353. assertNull(docFragment.parentNode);
  1354. assertEquals(2, docFragment.childNodes.length);
  1355. var div = goog.dom.safeHtmlToNode(
  1356. goog.html.testing.newSafeHtmlForTest('<div>3</div>'));
  1357. assertEquals(String(goog.dom.TagName.DIV), div.tagName);
  1358. var script = goog.dom.safeHtmlToNode(
  1359. goog.html.testing.newSafeHtmlForTest('<script></script>'));
  1360. assertEquals(String(goog.dom.TagName.SCRIPT), script.tagName);
  1361. if (goog.userAgent.IE && !goog.userAgent.isDocumentModeOrHigher(9)) {
  1362. // Removing an Element from a DOM tree in IE sets its parentNode to a new
  1363. // DocumentFragment. Bizarre!
  1364. assertEquals(
  1365. goog.dom.NodeType.DOCUMENT_FRAGMENT,
  1366. goog.dom.removeNode(div).parentNode.nodeType);
  1367. } else {
  1368. assertNull(div.parentNode);
  1369. }
  1370. }
  1371. /**
  1372. * Assert that the given goog.string.Const, when converted to a Node,
  1373. * stringifies in one of the specified ways.
  1374. *
  1375. * @param{!Array<string>} potentialStringifications
  1376. * @param{...!goog.string.Const} var_args The constants to use.
  1377. */
  1378. function assertConstHtmlToNodeStringifiesToOneOf(
  1379. potentialStringifications, var_args) {
  1380. var node =
  1381. goog.dom.constHtmlToNode.apply(undefined, goog.array.slice(arguments, 1));
  1382. var stringified = goog.dom.getOuterHtml(node);
  1383. if (goog.array.find(potentialStringifications, function(element) {
  1384. return element == stringified;
  1385. }) === null) {
  1386. fail(
  1387. 'Unexpected stringification for a node built from "' +
  1388. goog.array.map(goog.array.slice(arguments, 1), goog.string.Const.unwrap)
  1389. .join('') +
  1390. '": "' + stringified + '"');
  1391. }
  1392. }
  1393. function testRegularConstHtmlToNodeStringifications() {
  1394. assertConstHtmlToNodeStringifiesToOneOf(
  1395. ['<b>foo</b>', '<B>foo</B>'], goog.string.Const.from('<b>foo</b>'));
  1396. assertConstHtmlToNodeStringifiesToOneOf(
  1397. ['<br>', '<BR>'], goog.string.Const.from('<br>'));
  1398. assertConstHtmlToNodeStringifiesToOneOf(
  1399. [
  1400. '<SVG></B>', '<svg></svg>', '<svg xmlns="http://www.w3.org/2000/svg" />'
  1401. ],
  1402. goog.string.Const.from('<svg></b>'));
  1403. assertConstHtmlToNodeStringifiesToOneOf(
  1404. ['<unknown></unknown>', '<unknown>', '<UNKNOWN />'],
  1405. goog.string.Const.from('<unknown />'));
  1406. assertConstHtmlToNodeStringifiesToOneOf(
  1407. ['&lt;"&amp;', '&lt;"'], goog.string.Const.from('<"&'));
  1408. }
  1409. function testConcatenatedConstHtmlToNodeStringifications() {
  1410. assertConstHtmlToNodeStringifiesToOneOf(
  1411. ['<b>foo</b>', '<B>foo</B>'], goog.string.Const.from('<b>foo<'),
  1412. goog.string.Const.from('/b>'));
  1413. assertConstHtmlToNodeStringifiesToOneOf(
  1414. ['<b>foo</b>', '<B>foo</B>'], goog.string.Const.from('<b>foo</b>'),
  1415. goog.string.Const.from(''));
  1416. assertConstHtmlToNodeStringifiesToOneOf(['']);
  1417. }
  1418. function testSpecialConstHtmlToNodeStringifications() {
  1419. // body one is IE8, \r\n is opera.
  1420. assertConstHtmlToNodeStringifiesToOneOf(
  1421. [
  1422. '<script></script>', '<SCRIPT></SCRIPT>', '<script></body></script>',
  1423. '\r\n' +
  1424. '<SCRIPT></SCRIPT>'
  1425. ],
  1426. goog.string.Const.from('<script>'));
  1427. assertConstHtmlToNodeStringifiesToOneOf(
  1428. ['&lt;% %&gt;', '<% %>'], goog.string.Const.from('<% %>'));
  1429. assertConstHtmlToNodeStringifiesToOneOf(
  1430. ['&lt;% <script> %></script>', '<% <script> %>'],
  1431. goog.string.Const.from('<% <script> %>'));
  1432. assertConstHtmlToNodeStringifiesToOneOf(
  1433. ['</ hi />', '<!-- hi /-->', ''], goog.string.Const.from('</ hi />'));
  1434. assertConstHtmlToNodeStringifiesToOneOf(
  1435. ['<!-- <script --> /&gt;', '</ <script>/&gt;', ' /&gt;'],
  1436. goog.string.Const.from('</ <script > />'));
  1437. }
  1438. function testAppend() {
  1439. var div = goog.dom.createElement(goog.dom.TagName.DIV);
  1440. var b = goog.dom.createElement(goog.dom.TagName.B);
  1441. var c = document.createTextNode('c');
  1442. goog.dom.append(div, 'a', b, c);
  1443. assertEqualsCaseAndLeadingWhitespaceInsensitive('a<b></b>c', div.innerHTML);
  1444. }
  1445. function testAppend2() {
  1446. var dom = new goog.dom.DomHelper(myIframeDoc);
  1447. var div = dom.createElement(goog.dom.TagName.DIV);
  1448. var b = dom.createElement(goog.dom.TagName.B);
  1449. var c = myIframeDoc.createTextNode('c');
  1450. goog.dom.append(div, 'a', b, c);
  1451. assertEqualsCaseAndLeadingWhitespaceInsensitive('a<b></b>c', div.innerHTML);
  1452. }
  1453. function testAppend3() {
  1454. var div = goog.dom.createElement(goog.dom.TagName.DIV);
  1455. var b = goog.dom.createElement(goog.dom.TagName.B);
  1456. var c = document.createTextNode('c');
  1457. goog.dom.append(div, ['a', b, c]);
  1458. assertEqualsCaseAndLeadingWhitespaceInsensitive('a<b></b>c', div.innerHTML);
  1459. }
  1460. function testAppend4() {
  1461. var div = goog.dom.createElement(goog.dom.TagName.DIV);
  1462. var div2 = goog.dom.createElement(goog.dom.TagName.DIV);
  1463. div2.innerHTML = 'a<b></b>c';
  1464. goog.dom.append(div, div2.childNodes);
  1465. assertEqualsCaseAndLeadingWhitespaceInsensitive('a<b></b>c', div.innerHTML);
  1466. assertFalse(div2.hasChildNodes());
  1467. }
  1468. function testGetDocumentScroll() {
  1469. // setUpPage added divForTestingScrolling to the DOM. It's not init'd here so
  1470. // it can be shared amonst other tests.
  1471. window.scrollTo(100, 100);
  1472. assertEquals(100, goog.dom.getDocumentScroll().x);
  1473. assertEquals(100, goog.dom.getDocumentScroll().y);
  1474. }
  1475. function testGetDocumentScrollOfFixedViewport() {
  1476. // iOS and perhaps other environments don't actually support scrolling.
  1477. // Instead, you view the document's fixed layout through a screen viewport.
  1478. // We need getDocumentScroll to handle this case though.
  1479. // In case of IE10 though, we do want to use scrollLeft/scrollTop
  1480. // because the rest of the positioning is done off the scrolled away origin.
  1481. var fakeDocumentScrollElement = {scrollLeft: 0, scrollTop: 0};
  1482. var fakeDocument = {
  1483. defaultView: {pageXOffset: 100, pageYOffset: 100},
  1484. documentElement: fakeDocumentScrollElement,
  1485. body: fakeDocumentScrollElement
  1486. };
  1487. var dh = goog.dom.getDomHelper(document);
  1488. dh.setDocument(fakeDocument);
  1489. if (goog.userAgent.IE && goog.userAgent.isVersionOrHigher(10)) {
  1490. assertEquals(0, dh.getDocumentScroll().x);
  1491. assertEquals(0, dh.getDocumentScroll().y);
  1492. } else {
  1493. assertEquals(100, dh.getDocumentScroll().x);
  1494. assertEquals(100, dh.getDocumentScroll().y);
  1495. }
  1496. }
  1497. function testGetDocumentScrollFromDocumentWithoutABody() {
  1498. // Some documents, like SVG docs, do not have a body element. The document
  1499. // element should be used when computing the document scroll for these
  1500. // documents.
  1501. var fakeDocument = {
  1502. defaultView: {pageXOffset: 0, pageYOffset: 0},
  1503. documentElement: {scrollLeft: 0, scrollTop: 0}
  1504. };
  1505. var dh = new goog.dom.DomHelper(fakeDocument);
  1506. assertEquals(fakeDocument.documentElement, dh.getDocumentScrollElement());
  1507. assertEquals(0, dh.getDocumentScroll().x);
  1508. assertEquals(0, dh.getDocumentScroll().y);
  1509. // OK if this does not throw.
  1510. }
  1511. function testDefaultToScrollingElement() {
  1512. var fakeDocument = {documentElement: {}, body: {}};
  1513. var dh = new goog.dom.DomHelper(fakeDocument);
  1514. // When scrollingElement isn't supported or is null (no element causes
  1515. // scrolling), then behavior is UA-dependent for maximum compatibility.
  1516. assertTrue(
  1517. dh.getDocumentScrollElement() == fakeDocument.body ||
  1518. dh.getDocumentScrollElement() == fakeDocument.documentElement);
  1519. fakeDocument.scrollingElement = null;
  1520. assertTrue(
  1521. dh.getDocumentScrollElement() == fakeDocument.body ||
  1522. dh.getDocumentScrollElement() == fakeDocument.documentElement);
  1523. // But when scrollingElement is set, we use it directly.
  1524. fakeDocument.scrollingElement = fakeDocument.documentElement;
  1525. assertEquals(fakeDocument.documentElement, dh.getDocumentScrollElement());
  1526. fakeDocument.scrollingElement = fakeDocument.body;
  1527. assertEquals(fakeDocument.body, dh.getDocumentScrollElement());
  1528. }
  1529. function testActiveElementIE() {
  1530. if (!goog.userAgent.IE) {
  1531. return;
  1532. }
  1533. var link = goog.dom.getElement('link');
  1534. link.focus();
  1535. assertEquals(link.tagName, goog.dom.getActiveElement(document).tagName);
  1536. assertEquals(link, goog.dom.getActiveElement(document));
  1537. }
  1538. function testParentElement() {
  1539. var testEl = $('testEl');
  1540. var bodyEl = goog.dom.getParentElement(testEl);
  1541. assertNotNull(bodyEl);
  1542. var htmlEl = goog.dom.getParentElement(bodyEl);
  1543. assertNotNull(htmlEl);
  1544. var documentNotAnElement = goog.dom.getParentElement(htmlEl);
  1545. assertNull(documentNotAnElement);
  1546. var tree = goog.dom.safeHtmlToNode(goog.html.testing.newSafeHtmlForTest(
  1547. '<div>' +
  1548. '<p>Some text</p>' +
  1549. '<blockquote>Some <i>special</i> <b>text</b></blockquote>' +
  1550. '<address><!-- comment -->Foo</address>' +
  1551. '</div>'));
  1552. assertNull(goog.dom.getParentElement(tree));
  1553. pEl = goog.dom.getNextNode(tree);
  1554. var fragmentRootEl = goog.dom.getParentElement(pEl);
  1555. assertEquals(tree, fragmentRootEl);
  1556. var detachedEl = goog.dom.createDom(goog.dom.TagName.DIV);
  1557. var detachedHasNoParent = goog.dom.getParentElement(detachedEl);
  1558. assertNull(detachedHasNoParent);
  1559. // svg is not supported in IE8 and below or in IE9 quirks mode
  1560. var supported = !goog.userAgent.IE ||
  1561. goog.userAgent.isDocumentModeOrHigher(10) ||
  1562. (goog.dom.isCss1CompatMode() && goog.userAgent.isDocumentModeOrHigher(9));
  1563. if (!supported) {
  1564. return;
  1565. }
  1566. var svg = $('testSvg');
  1567. assertNotNull(svg);
  1568. var rect = $('testRect');
  1569. assertNotNull(rect);
  1570. var g = $('testG');
  1571. assertNotNull(g);
  1572. if (goog.userAgent.IE && goog.userAgent.isVersionOrHigher('9')) {
  1573. // test to make sure IE9 is returning undefined for .parentElement
  1574. assertUndefined(g.parentElement);
  1575. assertUndefined(rect.parentElement);
  1576. assertUndefined(svg.parentElement);
  1577. }
  1578. var shouldBeG = goog.dom.getParentElement(rect);
  1579. assertEquals(g, shouldBeG);
  1580. var shouldBeSvg = goog.dom.getParentElement(g);
  1581. assertEquals(svg, shouldBeSvg);
  1582. var shouldBeBody = goog.dom.getParentElement(svg);
  1583. assertEquals(bodyEl, shouldBeBody);
  1584. }
  1585. /**
  1586. * @return {boolean} Returns true if the userAgent is IE8 or higher.
  1587. */
  1588. function isIE8OrHigher() {
  1589. return goog.userAgent.IE && goog.userAgent.product.isVersion('8');
  1590. }
  1591. /**
  1592. * Stub out goog.dom.getWindow with passed object.
  1593. * @param {!Object} win Fake window object.
  1594. */
  1595. function setWindow(win) {
  1596. stubs.set(goog.dom, 'getWindow', goog.functions.constant(win));
  1597. }
  1598. function testDevicePixelRatio() {
  1599. var devicePixelRatio = 1.5;
  1600. setWindow({
  1601. 'matchMedia': function(query) {
  1602. return {
  1603. 'matches': devicePixelRatio >= parseFloat(query.split(': ')[1], 10)
  1604. };
  1605. }
  1606. });
  1607. assertEquals(devicePixelRatio, goog.dom.getPixelRatio());
  1608. setWindow({'devicePixelRatio': 2.0});
  1609. assertEquals(2, goog.dom.getPixelRatio());
  1610. setWindow({});
  1611. assertEquals(1, goog.dom.getPixelRatio());
  1612. }