positioning_test.js 51 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387
  1. // Copyright 2008 The Closure Library Authors. All Rights Reserved.
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS-IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. /**
  15. * @fileoverview Unit tests for goog.position.
  16. *
  17. * @author eae@google.com (Emil A Eklund)
  18. */
  19. /** @suppress {extraProvide} */
  20. goog.provide('goog.positioningTest');
  21. goog.require('goog.dom');
  22. goog.require('goog.dom.DomHelper');
  23. goog.require('goog.dom.TagName');
  24. goog.require('goog.labs.userAgent.browser');
  25. goog.require('goog.math.Box');
  26. goog.require('goog.math.Coordinate');
  27. goog.require('goog.math.Size');
  28. goog.require('goog.positioning');
  29. goog.require('goog.positioning.Corner');
  30. goog.require('goog.positioning.Overflow');
  31. goog.require('goog.positioning.OverflowStatus');
  32. goog.require('goog.style');
  33. goog.require('goog.testing.ExpectedFailures');
  34. goog.require('goog.testing.jsunit');
  35. goog.require('goog.userAgent');
  36. goog.require('goog.userAgent.product');
  37. goog.setTestOnly('goog.positioningTest');
  38. // Allow positions to be off by one in gecko as it reports scrolling
  39. // offsets in steps of 2. Otherwise, allow for subpixel difference
  40. // as seen in IE10+
  41. var ALLOWED_OFFSET = goog.userAgent.GECKO ? 1 : 0.1;
  42. // Error bar for positions since some browsers are not super accurate
  43. // in reporting them.
  44. var EPSILON = 2;
  45. var expectedFailures = new goog.testing.ExpectedFailures();
  46. var corner = goog.positioning.Corner;
  47. var overflow = goog.positioning.Overflow;
  48. var testArea;
  49. function setUp() {
  50. window.scrollTo(0, 0);
  51. var viewportSize = goog.dom.getViewportSize();
  52. // Some tests need enough size viewport.
  53. if (viewportSize.width < 600 || viewportSize.height < 600) {
  54. window.moveTo(0, 0);
  55. window.resizeTo(640, 640);
  56. }
  57. testArea = goog.dom.getElement('test-area');
  58. }
  59. function tearDown() {
  60. expectedFailures.handleTearDown();
  61. testArea.setAttribute('style', '');
  62. goog.dom.removeChildren(testArea);
  63. }
  64. /**
  65. * This is used to round pixel values on FF3 Mac.
  66. */
  67. function assertRoundedEquals(a, b, c) {
  68. function round(x) {
  69. return goog.userAgent.GECKO && (goog.userAgent.MAC || goog.userAgent.X11) &&
  70. goog.userAgent.isVersionOrHigher('1.9') ?
  71. Math.round(x) :
  72. x;
  73. }
  74. if (arguments.length == 3) {
  75. assertRoughlyEquals(a, round(b), round(c), ALLOWED_OFFSET);
  76. } else {
  77. assertRoughlyEquals(round(a), round(b), ALLOWED_OFFSET);
  78. }
  79. }
  80. function testPositionAtAnchorLeftToRight() {
  81. var anchor = document.getElementById('anchor1');
  82. var popup = document.getElementById('popup1');
  83. // Anchor top left to top left.
  84. goog.positioning.positionAtAnchor(
  85. anchor, corner.TOP_LEFT, popup, corner.TOP_LEFT);
  86. var anchorRect = goog.style.getBounds(anchor);
  87. var popupRect = goog.style.getBounds(popup);
  88. assertRoundedEquals(
  89. 'Left edge of popup should line up with left edge ' +
  90. 'of anchor.',
  91. anchorRect.left, popupRect.left);
  92. assertRoundedEquals(
  93. 'Popup should have the same y position as the anchor.', anchorRect.top,
  94. popupRect.top);
  95. // Anchor top left to bottom left.
  96. goog.positioning.positionAtAnchor(
  97. anchor, corner.BOTTOM_LEFT, popup, corner.TOP_LEFT);
  98. anchorRect = goog.style.getBounds(anchor);
  99. popupRect = goog.style.getBounds(popup);
  100. assertRoundedEquals(
  101. 'Left edge of popup should line up with left edge ' +
  102. 'of anchor.',
  103. anchorRect.left, popupRect.left);
  104. assertRoundedEquals(
  105. 'Popup should be positioned just below the anchor.',
  106. anchorRect.top + anchorRect.height, popupRect.top);
  107. // Anchor top left to top right.
  108. goog.positioning.positionAtAnchor(
  109. anchor, corner.TOP_RIGHT, popup, corner.TOP_LEFT);
  110. anchorRect = goog.style.getBounds(anchor);
  111. popupRect = goog.style.getBounds(popup);
  112. assertRoundedEquals(
  113. 'Popup should be positioned just right of the anchor.',
  114. anchorRect.left + anchorRect.width, popupRect.left);
  115. assertRoundedEquals(
  116. 'Popup should have the same y position as the anchor.', anchorRect.top,
  117. popupRect.top);
  118. // Anchor top right to bottom right.
  119. goog.positioning.positionAtAnchor(
  120. anchor, corner.BOTTOM_RIGHT, popup, corner.TOP_RIGHT);
  121. anchorRect = goog.style.getBounds(anchor);
  122. popupRect = goog.style.getBounds(popup);
  123. assertRoundedEquals(
  124. 'Right edge of popup should line up with right edge ' +
  125. 'of anchor.',
  126. anchorRect.left + anchorRect.width, popupRect.left + popupRect.width);
  127. assertRoundedEquals(
  128. 'Popup should be positioned just below the anchor.',
  129. anchorRect.top + anchorRect.height, popupRect.top);
  130. // Anchor top start to bottom start.
  131. goog.positioning.positionAtAnchor(
  132. anchor, corner.BOTTOM_START, popup, corner.TOP_START);
  133. anchorRect = goog.style.getBounds(anchor);
  134. popupRect = goog.style.getBounds(popup);
  135. assertRoundedEquals(
  136. 'Left edge of popup should line up with left edge ' +
  137. 'of anchor.',
  138. anchorRect.left, popupRect.left);
  139. assertRoundedEquals(
  140. 'Popup should be positioned just below the anchor.',
  141. anchorRect.top + anchorRect.height, popupRect.top);
  142. // Anchor top center to top center.
  143. goog.positioning.positionAtAnchor(
  144. anchor, corner.TOP_CENTER, popup, corner.TOP_CENTER);
  145. anchorRect = goog.style.getBounds(anchor);
  146. popupRect = goog.style.getBounds(popup);
  147. // We use flooring math because we consider 10 and 10.5 to be "equal".
  148. // IE8 doesn't allow split pixels in positioning and as such this test would
  149. // fail on it, as Anchor L+W/2 is round while Popup L+W/2 is .5 away.
  150. assertRoundedEquals(
  151. 'The center of popup should line up with the center ' +
  152. 'of anchor.',
  153. Math.floor(anchorRect.left + anchorRect.width / 2),
  154. Math.floor(popupRect.left + popupRect.width / 2));
  155. assertRoundedEquals(
  156. 'Popup should have the same y position as the anchor.', anchorRect.top,
  157. popupRect.top);
  158. // Anchor top center to top left.
  159. goog.positioning.positionAtAnchor(
  160. anchor, corner.TOP_CENTER, popup, corner.TOP_LEFT);
  161. anchorRect = goog.style.getBounds(anchor);
  162. popupRect = goog.style.getBounds(popup);
  163. assertRoundedEquals(
  164. 'Left edge of popup should line up with the center ' +
  165. 'of anchor.',
  166. Math.floor(anchorRect.left + anchorRect.width / 2),
  167. Math.floor(popupRect.left));
  168. assertRoundedEquals(
  169. 'Popup should have the same y position as the anchor.', anchorRect.top,
  170. popupRect.top);
  171. // Anchor bottom center to top left.
  172. goog.positioning.positionAtAnchor(
  173. anchor, corner.BOTTOM_CENTER, popup, corner.TOP_LEFT);
  174. anchorRect = goog.style.getBounds(anchor);
  175. popupRect = goog.style.getBounds(popup);
  176. assertRoundedEquals(
  177. 'Left edge of popup should line up with the middle ' +
  178. 'of anchor.',
  179. Math.floor(anchorRect.left + anchorRect.width / 2),
  180. Math.floor(popupRect.left));
  181. assertRoundedEquals(
  182. 'Popup should be positioned just below the anchor.',
  183. anchorRect.top + anchorRect.height, popupRect.top);
  184. // Anchor bottom left to top center.
  185. goog.positioning.positionAtAnchor(
  186. anchor, corner.BOTTOM_LEFT, popup, corner.TOP_CENTER);
  187. anchorRect = goog.style.getBounds(anchor);
  188. popupRect = goog.style.getBounds(popup);
  189. assertRoundedEquals(
  190. 'Left edge of popup should line up with the middle ' +
  191. 'of anchor.',
  192. anchorRect.left, Math.floor(popupRect.left + popupRect.width / 2));
  193. assertRoundedEquals(
  194. 'Popup should be positioned just below the anchor.',
  195. anchorRect.top + anchorRect.height, popupRect.top);
  196. }
  197. function testPositionAtAnchorWithOffset() {
  198. var anchor = document.getElementById('anchor1');
  199. var popup = document.getElementById('popup1');
  200. // Anchor top left to top left with an offset moving the popup away from the
  201. // anchor.
  202. goog.positioning.positionAtAnchor(
  203. anchor, corner.TOP_LEFT, popup, corner.TOP_LEFT, newCoord(-15, -20));
  204. var anchorRect = goog.style.getBounds(anchor);
  205. var popupRect = goog.style.getBounds(popup);
  206. assertRoundedEquals(
  207. 'Left edge of popup should be fifteen pixels from ' +
  208. 'anchor.',
  209. anchorRect.left, popupRect.left + 15);
  210. assertRoundedEquals(
  211. 'Top edge of popup should be twenty pixels from anchor.', anchorRect.top,
  212. popupRect.top + 20);
  213. // Anchor top left to top left with an offset moving the popup towards the
  214. // anchor.
  215. goog.positioning.positionAtAnchor(
  216. anchor, corner.TOP_LEFT, popup, corner.TOP_LEFT, newCoord(3, 1));
  217. anchorRect = goog.style.getBounds(anchor);
  218. popupRect = goog.style.getBounds(popup);
  219. assertRoundedEquals(
  220. 'Left edge of popup should be three pixels right of ' +
  221. 'the anchor\'s left edge',
  222. anchorRect.left, popupRect.left - 3);
  223. assertRoundedEquals(
  224. 'Top edge of popup should be one pixel below of the ' +
  225. 'anchor\'s top edge',
  226. anchorRect.top, popupRect.top - 1);
  227. }
  228. function testPositionAtAnchorOverflowLeftEdgeRightToLeft() {
  229. var anchor = document.getElementById('anchor5');
  230. var popup = document.getElementById('popup5');
  231. var status = goog.positioning.positionAtAnchor(
  232. anchor, corner.TOP_LEFT, popup, corner.TOP_RIGHT, undefined, undefined,
  233. overflow.FAIL_X);
  234. assertFalse(
  235. 'Positioning operation should have failed.',
  236. (status & goog.positioning.OverflowStatus.FAILED) == 0);
  237. // Change overflow strategy to ADJUST.
  238. status = goog.positioning.positionAtAnchor(
  239. anchor, corner.TOP_LEFT, popup, corner.TOP_RIGHT, undefined, undefined,
  240. overflow.ADJUST_X);
  241. // Fails in Chrome because of infrastructure issues, temporarily disabled.
  242. // See b/4274723.
  243. expectedFailures.expectFailureFor(goog.userAgent.product.CHROME);
  244. try {
  245. assertTrue(
  246. 'Positioning operation should have been successful.',
  247. (status & goog.positioning.OverflowStatus.FAILED) == 0);
  248. assertTrue(
  249. 'Positioning operation should have been adjusted.',
  250. (status & goog.positioning.OverflowStatus.ADJUSTED_X) != 0);
  251. } catch (e) {
  252. expectedFailures.handleException(e);
  253. }
  254. var anchorRect = goog.style.getBounds(anchor);
  255. var popupRect = goog.style.getBounds(popup);
  256. var parentRect = goog.style.getBounds(anchor.parentNode);
  257. assertTrue(
  258. 'Position should have been adjusted so that the left edge of ' +
  259. 'the popup is left of the anchor but still within the bounding ' +
  260. 'box of the parent container.',
  261. anchorRect.left <= popupRect.left <= parentRect.left);
  262. }
  263. function testPositionAtAnchorWithMargin() {
  264. var anchor = document.getElementById('anchor1');
  265. var popup = document.getElementById('popup1');
  266. // Anchor top left to top left.
  267. goog.positioning.positionAtAnchor(
  268. anchor, corner.TOP_LEFT, popup, corner.TOP_LEFT, undefined,
  269. new goog.math.Box(1, 2, 3, 4));
  270. var anchorRect = goog.style.getBounds(anchor);
  271. var popupRect = goog.style.getBounds(popup);
  272. assertRoundedEquals(
  273. 'Left edge of popup should be four pixels from anchor.', anchorRect.left,
  274. popupRect.left - 4);
  275. assertRoundedEquals(
  276. 'Top edge of popup should be one pixels from anchor.', anchorRect.top,
  277. popupRect.top - 1);
  278. // Anchor top right to bottom right.
  279. goog.positioning.positionAtAnchor(
  280. anchor, corner.BOTTOM_RIGHT, popup, corner.TOP_RIGHT, undefined,
  281. new goog.math.Box(1, 2, 3, 4));
  282. anchorRect = goog.style.getBounds(anchor);
  283. popupRect = goog.style.getBounds(popup);
  284. var visibleAnchorRect = goog.positioning.getVisiblePart_(anchor);
  285. assertRoundedEquals(
  286. 'Right edge of popup should line up with right edge ' +
  287. 'of anchor.',
  288. visibleAnchorRect.left + visibleAnchorRect.width,
  289. popupRect.left + popupRect.width + 2);
  290. assertRoundedEquals(
  291. 'Popup should be positioned just below the anchor.',
  292. visibleAnchorRect.top + visibleAnchorRect.height, popupRect.top - 1);
  293. }
  294. function testPositionAtAnchorRightToLeft() {
  295. if (goog.userAgent.IE && goog.userAgent.isVersionOrHigher('6')) {
  296. // These tests fails with IE6.
  297. // TODO(user): Investigate the reason.
  298. return;
  299. }
  300. if (goog.userAgent.product.SAFARI) {
  301. // TODO(b/20733468): Disabled so we can get the rest of the Closure test
  302. // suite running in a continuous build. Will investigate later.
  303. return;
  304. }
  305. var anchor = document.getElementById('anchor2');
  306. var popup = document.getElementById('popup2');
  307. // Anchor top left to top left.
  308. goog.positioning.positionAtAnchor(
  309. anchor, corner.TOP_LEFT, popup, corner.TOP_LEFT);
  310. var anchorRect = goog.style.getBounds(anchor);
  311. var popupRect = goog.style.getBounds(popup);
  312. assertRoundedEquals(
  313. 'Left edge of popup should line up with left edge ' +
  314. 'of anchor.',
  315. anchorRect.left, popupRect.left);
  316. assertRoundedEquals(
  317. 'Popup should have the same y position as the anchor.', anchorRect.top,
  318. popupRect.top);
  319. // Anchor top start to bottom start.
  320. goog.positioning.positionAtAnchor(
  321. anchor, corner.BOTTOM_START, popup, corner.TOP_START);
  322. anchorRect = goog.style.getBounds(anchor);
  323. popupRect = goog.style.getBounds(popup);
  324. assertRoundedEquals(
  325. 'Right edge of popup should line up with right edge ' +
  326. 'of anchor.',
  327. anchorRect.left + anchorRect.width, popupRect.left + popupRect.width);
  328. assertRoundedEquals(
  329. 'Popup should be positioned just below the anchor.',
  330. anchorRect.top + anchorRect.height, popupRect.top);
  331. }
  332. function testPositionAtAnchorRightToLeftWithScroll() {
  333. if (goog.userAgent.IE && goog.userAgent.isVersionOrHigher('6')) {
  334. // These tests fails with IE6.
  335. // TODO(user): Investigate the reason.
  336. return;
  337. }
  338. if (goog.userAgent.product.SAFARI) {
  339. // TODO(b/20733468): Disabled so we can get the rest of the Closure test
  340. // suite running in a continuous build. Will investigate later.
  341. return;
  342. }
  343. var anchor = document.getElementById('anchor8');
  344. var popup = document.getElementById('popup8');
  345. // Anchor top left to top left.
  346. goog.positioning.positionAtAnchor(
  347. anchor, corner.TOP_LEFT, popup, corner.TOP_LEFT);
  348. var anchorRect = goog.style.getBounds(anchor);
  349. var popupRect = goog.style.getBounds(popup);
  350. // TODO(joeltine): Chrome 47 has issues with RTL scroll positioning. Remove
  351. // chrome check when
  352. // https://code.google.com/p/chromium/issues/detail?id=568706 is resolved.
  353. if (!goog.labs.userAgent.browser.isChrome()) {
  354. assertRoundedEquals(
  355. 'Left edge of popup should line up with left edge ' +
  356. 'of anchor.',
  357. anchorRect.left, popupRect.left);
  358. }
  359. assertRoundedEquals(
  360. 'Popup should have the same y position as the anchor.', anchorRect.top,
  361. popupRect.top);
  362. // Anchor top start to bottom start.
  363. goog.positioning.positionAtAnchor(
  364. anchor, corner.BOTTOM_START, popup, corner.TOP_START);
  365. anchorRect = goog.style.getBounds(anchor);
  366. popupRect = goog.style.getBounds(popup);
  367. var visibleAnchorRect = goog.positioning.getVisiblePart_(anchor);
  368. var visibleAnchorBox = visibleAnchorRect.toBox();
  369. // TODO(joeltine): Chrome 47 has issues with RTL scroll positioning. Remove
  370. // chrome check when
  371. // https://code.google.com/p/chromium/issues/detail?id=568706 is resolved.
  372. if (!goog.labs.userAgent.browser.isChrome()) {
  373. assertRoundedEquals(
  374. 'Right edge of popup should line up with right edge ' +
  375. 'of anchor.',
  376. anchorRect.left + anchorRect.width, popupRect.left + popupRect.width);
  377. }
  378. assertRoundedEquals(
  379. 'Popup should be positioned just below the anchor.',
  380. visibleAnchorBox.bottom, popupRect.top);
  381. }
  382. function testPositionAtAnchorBodyViewport() {
  383. var anchor = document.getElementById('anchor1');
  384. var popup = document.getElementById('popup3');
  385. // Anchor top left to top left.
  386. goog.positioning.positionAtAnchor(
  387. anchor, corner.TOP_LEFT, popup, corner.TOP_LEFT);
  388. var anchorRect = goog.style.getBounds(anchor);
  389. var popupRect = goog.style.getBounds(popup);
  390. assertEquals(
  391. 'Left edge of popup should line up with left edge of anchor.',
  392. anchorRect.left, popupRect.left);
  393. assertRoughlyEquals(
  394. 'Popup should have the same y position as the anchor.', anchorRect.top,
  395. popupRect.top, 1);
  396. // Anchor top start to bottom right.
  397. goog.positioning.positionAtAnchor(
  398. anchor, corner.BOTTOM_RIGHT, popup, corner.TOP_RIGHT);
  399. anchorRect = goog.style.getBounds(anchor);
  400. popupRect = goog.style.getBounds(popup);
  401. assertEquals(
  402. 'Right edge of popup should line up with right edge of anchor.',
  403. anchorRect.left + anchorRect.width, popupRect.left + popupRect.width);
  404. assertRoughlyEquals(
  405. 'Popup should be positioned just below the anchor.',
  406. anchorRect.top + anchorRect.height, popupRect.top, 1);
  407. // Anchor top right to top left.
  408. goog.positioning.positionAtAnchor(
  409. anchor, corner.TOP_LEFT, popup, corner.TOP_RIGHT);
  410. anchorRect = goog.style.getBounds(anchor);
  411. popupRect = goog.style.getBounds(popup);
  412. assertEquals(
  413. 'Right edge of popup should line up with left edge of anchor.',
  414. anchorRect.left, popupRect.left + popupRect.width);
  415. assertRoughlyEquals(
  416. 'Popup should have the same y position as the anchor.', anchorRect.top,
  417. popupRect.top, 1);
  418. }
  419. function testPositionAtAnchorSpecificViewport() {
  420. var anchor = document.getElementById('anchor1');
  421. var popup = document.getElementById('popup3');
  422. // Anchor top right to top left within outerbox.
  423. var status = goog.positioning.positionAtAnchor(
  424. anchor, corner.TOP_LEFT, popup, corner.TOP_RIGHT, undefined, undefined,
  425. overflow.FAIL_X);
  426. anchorRect = goog.style.getBounds(anchor);
  427. popupRect = goog.style.getBounds(popup);
  428. assertTrue(
  429. 'Positioning operation should have been successful.',
  430. (status & goog.positioning.OverflowStatus.FAILED) == 0);
  431. assertTrue(
  432. 'X position should not have been adjusted.',
  433. (status & goog.positioning.OverflowStatus.ADJUSTED_X) == 0);
  434. assertTrue(
  435. 'Y position should not have been adjusted.',
  436. (status & goog.positioning.OverflowStatus.ADJUSTED_Y) == 0);
  437. assertEquals(
  438. 'Right edge of popup should line up with left edge of anchor.',
  439. anchorRect.left, popupRect.left + popupRect.width);
  440. assertRoughlyEquals(
  441. 'Popup should have the same y position as the anchor.', anchorRect.top,
  442. popupRect.top, 1);
  443. // position again within box1.
  444. var box = document.getElementById('box1');
  445. var viewport = goog.style.getBounds(box);
  446. status = goog.positioning.positionAtAnchor(
  447. anchor, corner.TOP_LEFT, popup, corner.TOP_RIGHT, undefined, undefined,
  448. overflow.FAIL_X, undefined, viewport);
  449. assertFalse(
  450. 'Positioning operation should have failed.',
  451. (status & goog.positioning.OverflowStatus.FAILED) == 0);
  452. // Change overflow strategy to adjust.
  453. status = goog.positioning.positionAtAnchor(
  454. anchor, corner.TOP_LEFT, popup, corner.TOP_RIGHT, undefined, undefined,
  455. overflow.ADJUST_X, undefined, viewport);
  456. anchorRect = goog.style.getBounds(anchor);
  457. popupRect = goog.style.getBounds(popup);
  458. assertTrue(
  459. 'Positioning operation should have been successful.',
  460. (status & goog.positioning.OverflowStatus.FAILED) == 0);
  461. assertFalse(
  462. 'X position should have been adjusted.',
  463. (status & goog.positioning.OverflowStatus.ADJUSTED_X) == 0);
  464. assertTrue(
  465. 'Y position should not have been adjusted.',
  466. (status & goog.positioning.OverflowStatus.ADJUSTED_Y) == 0);
  467. assertRoughlyEquals(
  468. 'Left edge of popup should line up with left edge of viewport.',
  469. viewport.left, popupRect.left, EPSILON);
  470. assertRoughlyEquals(
  471. 'Popup should have the same y position as the anchor.', anchorRect.top,
  472. popupRect.top, 1);
  473. }
  474. function testPositionAtAnchorOutsideViewport() {
  475. var anchor = document.getElementById('anchor4');
  476. var popup = document.getElementById('popup1');
  477. var status = goog.positioning.positionAtAnchor(
  478. anchor, corner.TOP_LEFT, popup, corner.TOP_RIGHT);
  479. var anchorRect = goog.style.getBounds(anchor);
  480. var popupRect = goog.style.getBounds(popup);
  481. assertTrue(
  482. 'Positioning operation should have been successful.',
  483. (status & goog.positioning.OverflowStatus.FAILED) == 0);
  484. assertTrue(
  485. 'X position should not have been adjusted.',
  486. (status & goog.positioning.OverflowStatus.ADJUSTED_X) == 0);
  487. assertTrue(
  488. 'Y position should not have been adjusted.',
  489. (status & goog.positioning.OverflowStatus.ADJUSTED_Y) == 0);
  490. assertEquals(
  491. 'Right edge of popup should line up with left edge of anchor.',
  492. anchorRect.left, popupRect.left + popupRect.width);
  493. // Change overflow strategy to fail.
  494. status = goog.positioning.positionAtAnchor(
  495. anchor, corner.BOTTOM_RIGHT, popup, corner.TOP_RIGHT, undefined,
  496. undefined, overflow.FAIL_X);
  497. assertFalse(
  498. 'Positioning operation should have failed.',
  499. (status & goog.positioning.OverflowStatus.FAILED) == 0);
  500. // Change overflow strategy to adjust.
  501. status = goog.positioning.positionAtAnchor(
  502. anchor, corner.BOTTOM_RIGHT, popup, corner.TOP_RIGHT, undefined,
  503. undefined, overflow.ADJUST_X);
  504. anchorRect = goog.style.getBounds(anchor);
  505. popupRect = goog.style.getBounds(popup);
  506. assertTrue(
  507. 'Positioning operation should have been successful.',
  508. (status & goog.positioning.OverflowStatus.FAILED) == 0);
  509. assertFalse(
  510. 'X position should have been adjusted.',
  511. (status & goog.positioning.OverflowStatus.ADJUSTED_X) == 0);
  512. assertTrue(
  513. 'Y position should not have been adjusted.',
  514. (status & goog.positioning.OverflowStatus.ADJUSTED_Y) == 0);
  515. assertRoughlyEquals(
  516. 'Left edge of popup should line up with left edge of viewport.', 0,
  517. popupRect.left, EPSILON);
  518. assertEquals(
  519. 'Popup should be positioned just below the anchor.',
  520. anchorRect.top + anchorRect.height, popupRect.top);
  521. }
  522. function testAdjustForViewportFailIgnore() {
  523. var f = goog.positioning.adjustForViewport_;
  524. var viewport = new goog.math.Box(100, 200, 200, 100);
  525. var overflow = goog.positioning.Overflow.IGNORE;
  526. var pos = newCoord(150, 150);
  527. var size = newSize(50, 50);
  528. assertEquals(
  529. 'Viewport overflow should be ignored.',
  530. goog.positioning.OverflowStatus.NONE, f(pos, size, viewport, overflow));
  531. pos = newCoord(150, 150);
  532. size = newSize(100, 50);
  533. assertEquals(
  534. 'Viewport overflow should be ignored.',
  535. goog.positioning.OverflowStatus.NONE, f(pos, size, viewport, overflow));
  536. pos = newCoord(50, 50);
  537. size = newSize(50, 50);
  538. assertEquals(
  539. 'Viewport overflow should be ignored.',
  540. goog.positioning.OverflowStatus.NONE, f(pos, size, viewport, overflow));
  541. }
  542. function testAdjustForViewportFailXY() {
  543. var f = goog.positioning.adjustForViewport_;
  544. var viewport = new goog.math.Box(100, 200, 200, 100);
  545. var overflow =
  546. goog.positioning.Overflow.FAIL_X | goog.positioning.Overflow.FAIL_Y;
  547. var pos = newCoord(150, 150);
  548. var size = newSize(50, 50);
  549. assertEquals(
  550. 'Element should not overflow viewport.',
  551. goog.positioning.OverflowStatus.NONE, f(pos, size, viewport, overflow));
  552. pos = newCoord(150, 150);
  553. size = newSize(100, 50);
  554. assertEquals(
  555. 'Element should overflow the right edge of viewport.',
  556. goog.positioning.OverflowStatus.FAILED_RIGHT,
  557. f(pos, size, viewport, overflow));
  558. pos = newCoord(150, 150);
  559. size = newSize(50, 100);
  560. assertEquals(
  561. 'Element should overflow the bottom edge of viewport.',
  562. goog.positioning.OverflowStatus.FAILED_BOTTOM,
  563. f(pos, size, viewport, overflow));
  564. pos = newCoord(50, 150);
  565. size = newSize(50, 50);
  566. assertEquals(
  567. 'Element should overflow the left edge of viewport.',
  568. goog.positioning.OverflowStatus.FAILED_LEFT,
  569. f(pos, size, viewport, overflow));
  570. pos = newCoord(150, 50);
  571. size = newSize(50, 50);
  572. assertEquals(
  573. 'Element should overflow the top edge of viewport.',
  574. goog.positioning.OverflowStatus.FAILED_TOP,
  575. f(pos, size, viewport, overflow));
  576. pos = newCoord(50, 50);
  577. size = newSize(50, 50);
  578. assertEquals(
  579. 'Element should overflow the left & top edges of viewport.',
  580. goog.positioning.OverflowStatus.FAILED_LEFT |
  581. goog.positioning.OverflowStatus.FAILED_TOP,
  582. f(pos, size, viewport, overflow));
  583. }
  584. function testAdjustForViewportAdjustXFailY() {
  585. var f = goog.positioning.adjustForViewport_;
  586. var viewport = new goog.math.Box(100, 200, 200, 100);
  587. var overflow =
  588. goog.positioning.Overflow.ADJUST_X | goog.positioning.Overflow.FAIL_Y;
  589. var pos = newCoord(150, 150);
  590. var size = newSize(50, 50);
  591. assertEquals(
  592. 'Element should not overflow viewport.',
  593. goog.positioning.OverflowStatus.NONE, f(pos, size, viewport, overflow));
  594. assertEquals('X Position should not have been changed.', 150, pos.x);
  595. assertEquals('Y Position should not have been changed.', 150, pos.y);
  596. pos = newCoord(150, 150);
  597. size = newSize(100, 50);
  598. assertEquals(
  599. 'Element position should be adjusted not to overflow right ' +
  600. 'edge of viewport.',
  601. goog.positioning.OverflowStatus.ADJUSTED_X,
  602. f(pos, size, viewport, overflow));
  603. assertEquals('X Position should be adjusted to 100.', 100, pos.x);
  604. assertEquals('Y Position should not have been changed.', 150, pos.y);
  605. pos = newCoord(50, 150);
  606. size = newSize(100, 50);
  607. assertEquals(
  608. 'Element position should be adjusted not to overflow left ' +
  609. 'edge of viewport.',
  610. goog.positioning.OverflowStatus.ADJUSTED_X,
  611. f(pos, size, viewport, overflow));
  612. assertEquals('X Position should be adjusted to 100.', 100, pos.x);
  613. assertEquals('Y Position should not have been changed.', 150, pos.y);
  614. pos = newCoord(50, 50);
  615. size = newSize(100, 50);
  616. assertEquals(
  617. 'Element position should be adjusted not to overflow left ' +
  618. 'edge of viewport, should overflow bottom edge.',
  619. goog.positioning.OverflowStatus.ADJUSTED_X |
  620. goog.positioning.OverflowStatus.FAILED_TOP,
  621. f(pos, size, viewport, overflow));
  622. assertEquals('X Position should be adjusted to 100.', 100, pos.x);
  623. assertEquals('Y Position should not have been changed.', 50, pos.y);
  624. }
  625. function testAdjustForViewportResizeHeight() {
  626. var f = goog.positioning.adjustForViewport_;
  627. var viewport = new goog.math.Box(0, 200, 200, 0);
  628. var overflow = goog.positioning.Overflow.RESIZE_HEIGHT;
  629. var pos = newCoord(150, 150);
  630. var size = newSize(25, 100);
  631. assertEquals(
  632. 'Viewport height should be resized.',
  633. goog.positioning.OverflowStatus.HEIGHT_ADJUSTED,
  634. f(pos, size, viewport, overflow));
  635. assertEquals('Height should be resized to 50.', 50, size.height);
  636. assertTrue(
  637. 'Output box is within viewport',
  638. viewport.contains(
  639. new goog.math.Box(
  640. pos.y, pos.x + size.width, pos.y + size.height, pos.x)));
  641. var pos = newCoord(0, 0);
  642. var size = newSize(50, 250);
  643. assertEquals(
  644. 'Viewport height should be resized.',
  645. goog.positioning.OverflowStatus.HEIGHT_ADJUSTED,
  646. f(pos, size, viewport, overflow));
  647. assertEquals('Height should be resized to 200.', 200, size.height);
  648. assertTrue(
  649. 'Output box is within viewport',
  650. viewport.contains(
  651. new goog.math.Box(
  652. pos.y, pos.x + size.width, pos.y + size.height, pos.x)));
  653. var pos = newCoord(0, -50);
  654. var size = newSize(50, 240);
  655. assertEquals(
  656. 'Viewport height should be resized.',
  657. goog.positioning.OverflowStatus.HEIGHT_ADJUSTED,
  658. f(pos, size, viewport, overflow));
  659. assertEquals('Height should be resized to 190.', 190, size.height);
  660. assertTrue(
  661. 'Output box is within viewport',
  662. viewport.contains(
  663. new goog.math.Box(
  664. pos.y, pos.x + size.width, pos.y + size.height, pos.x)));
  665. var pos = newCoord(0, -50);
  666. var size = newSize(50, 300);
  667. assertEquals(
  668. 'Viewport height should be resized.',
  669. goog.positioning.OverflowStatus.HEIGHT_ADJUSTED,
  670. f(pos, size, viewport, overflow));
  671. assertEquals('Height should be resized to 200.', 200, size.height);
  672. assertTrue(
  673. 'Output box is within viewport',
  674. viewport.contains(
  675. new goog.math.Box(
  676. pos.y, pos.x + size.width, pos.y + size.height, pos.x)));
  677. pos = newCoord(150, 150);
  678. size = newSize(50, 50);
  679. assertEquals(
  680. 'No Viewport overflow.', goog.positioning.OverflowStatus.NONE,
  681. f(pos, size, viewport, overflow));
  682. assertTrue(
  683. 'Output box is within viewport',
  684. viewport.contains(
  685. new goog.math.Box(
  686. pos.y, pos.x + size.width, pos.y + size.height, pos.x)));
  687. var offsetViewport = new goog.math.Box(100, 200, 300, 0);
  688. var pos = newCoord(0, 50);
  689. var size = newSize(50, 240);
  690. assertEquals(
  691. 'Viewport height should be resized.',
  692. goog.positioning.OverflowStatus.HEIGHT_ADJUSTED,
  693. f(pos, size, offsetViewport, overflow));
  694. assertEquals('Height should be resized to 190.', 190, size.height);
  695. assertTrue(
  696. 'Output box is within viewport',
  697. offsetViewport.contains(
  698. new goog.math.Box(
  699. pos.y, pos.x + size.width, pos.y + size.height, pos.x)));
  700. }
  701. function testAdjustForViewportResizeWidth() {
  702. var f = goog.positioning.adjustForViewport_;
  703. var viewport = new goog.math.Box(0, 200, 200, 0);
  704. var overflow = goog.positioning.Overflow.RESIZE_WIDTH;
  705. var pos = newCoord(150, 150);
  706. var size = newSize(100, 25);
  707. assertEquals(
  708. 'Viewport width should be resized.',
  709. goog.positioning.OverflowStatus.WIDTH_ADJUSTED,
  710. f(pos, size, viewport, overflow));
  711. assertEquals('Width should be resized to 50.', 50, size.width);
  712. assertTrue(
  713. 'Output box is within viewport',
  714. viewport.contains(
  715. new goog.math.Box(
  716. pos.y, pos.x + size.width, pos.y + size.height, pos.x)));
  717. var pos = newCoord(0, 0);
  718. var size = newSize(250, 50);
  719. assertEquals(
  720. 'Viewport width should be resized.',
  721. goog.positioning.OverflowStatus.WIDTH_ADJUSTED,
  722. f(pos, size, viewport, overflow));
  723. assertEquals('Width should be resized to 200.', 200, size.width);
  724. assertTrue(
  725. 'Output box is within viewport',
  726. viewport.contains(
  727. new goog.math.Box(
  728. pos.y, pos.x + size.width, pos.y + size.height, pos.x)));
  729. var pos = newCoord(-50, 0);
  730. var size = newSize(240, 50);
  731. assertEquals(
  732. 'Viewport width should be resized.',
  733. goog.positioning.OverflowStatus.WIDTH_ADJUSTED,
  734. f(pos, size, viewport, overflow));
  735. assertEquals('Width should be resized to 190.', 190, size.width);
  736. assertTrue(
  737. 'Output box is within viewport',
  738. viewport.contains(
  739. new goog.math.Box(
  740. pos.y, pos.x + size.width, pos.y + size.height, pos.x)));
  741. var pos = newCoord(-50, 0);
  742. var size = newSize(300, 50);
  743. assertEquals(
  744. 'Viewport width should be resized.',
  745. goog.positioning.OverflowStatus.WIDTH_ADJUSTED,
  746. f(pos, size, viewport, overflow));
  747. assertEquals('Width should be resized to 200.', 200, size.width);
  748. assertTrue(
  749. 'Output box is within viewport',
  750. viewport.contains(
  751. new goog.math.Box(
  752. pos.y, pos.x + size.width, pos.y + size.height, pos.x)));
  753. pos = newCoord(150, 150);
  754. size = newSize(50, 50);
  755. assertEquals(
  756. 'No Viewport overflow.', goog.positioning.OverflowStatus.NONE,
  757. f(pos, size, viewport, overflow));
  758. assertTrue(
  759. 'Output box is within viewport',
  760. viewport.contains(
  761. new goog.math.Box(
  762. pos.y, pos.x + size.width, pos.y + size.height, pos.x)));
  763. var offsetViewport = new goog.math.Box(0, 300, 200, 100);
  764. var pos = newCoord(50, 0);
  765. var size = newSize(240, 50);
  766. assertEquals(
  767. 'Viewport width should be resized.',
  768. goog.positioning.OverflowStatus.WIDTH_ADJUSTED,
  769. f(pos, size, offsetViewport, overflow));
  770. assertEquals('Width should be resized to 190.', 190, size.width);
  771. assertTrue(
  772. 'Output box is within viewport',
  773. offsetViewport.contains(
  774. new goog.math.Box(
  775. pos.y, pos.x + size.width, pos.y + size.height, pos.x)));
  776. }
  777. function testPositionAtAnchorWithResizeHeight() {
  778. var anchor = document.getElementById('anchor9');
  779. var popup = document.getElementById('popup9');
  780. var box = document.getElementById('box9');
  781. var viewport = goog.style.getBounds(box);
  782. var status = goog.positioning.positionAtAnchor(
  783. anchor, corner.TOP_START, popup, corner.TOP_START,
  784. new goog.math.Coordinate(0, -20), null,
  785. goog.positioning.Overflow.RESIZE_HEIGHT, null, viewport.toBox());
  786. assertEquals(
  787. 'Status should be HEIGHT_ADJUSTED.',
  788. goog.positioning.OverflowStatus.HEIGHT_ADJUSTED, status);
  789. var TOLERANCE = 0.1;
  790. // Adjust the viewport to allow some tolerance for subpixel positioning,
  791. // this is required for this test to pass on IE10,11
  792. viewport.top -= TOLERANCE;
  793. viewport.left -= TOLERANCE;
  794. assertTrue(
  795. 'Popup ' + goog.style.getBounds(popup) + ' not is within viewport' +
  796. viewport,
  797. viewport.contains(goog.style.getBounds(popup)));
  798. }
  799. function testPositionAtCoordinateResizeHeight() {
  800. var f = goog.positioning.positionAtCoordinate;
  801. var viewport = new goog.math.Box(0, 50, 50, 0);
  802. var overflow = goog.positioning.Overflow.RESIZE_HEIGHT |
  803. goog.positioning.Overflow.ADJUST_Y;
  804. var popup = document.getElementById('popup1');
  805. var corner = goog.positioning.Corner.BOTTOM_LEFT;
  806. var pos = newCoord(100, 100);
  807. assertEquals(
  808. 'Viewport height should be resized.',
  809. goog.positioning.OverflowStatus.HEIGHT_ADJUSTED |
  810. goog.positioning.OverflowStatus.ADJUSTED_Y,
  811. f(pos, popup, corner, undefined, viewport, overflow));
  812. var bounds = goog.style.getSize(popup);
  813. assertEquals(
  814. 'Height should be resized to the size of the viewport.', 50,
  815. bounds.height);
  816. }
  817. function testGetPositionAtCoordinateResizeHeight() {
  818. var f = goog.positioning.getPositionAtCoordinate;
  819. var viewport = new goog.math.Box(0, 50, 50, 0);
  820. var overflow = goog.positioning.Overflow.RESIZE_HEIGHT |
  821. goog.positioning.Overflow.ADJUST_Y;
  822. var popup = document.getElementById('popup1');
  823. var corner = goog.positioning.Corner.BOTTOM_LEFT;
  824. var pos = newCoord(100, 100);
  825. var size = goog.style.getSize(popup);
  826. var result = f(pos, size, corner, undefined, viewport, overflow);
  827. assertEquals(
  828. 'Viewport height should be resized.',
  829. goog.positioning.OverflowStatus.HEIGHT_ADJUSTED |
  830. goog.positioning.OverflowStatus.ADJUSTED_Y,
  831. result.status);
  832. assertEquals(
  833. 'Height should be resized to the size of the viewport.', 50,
  834. result.rect.height);
  835. }
  836. function testGetEffectiveCornerLeftToRight() {
  837. var f = goog.positioning.getEffectiveCorner;
  838. var el = document.getElementById('ltr');
  839. assertEquals(
  840. 'TOP_LEFT should be unchanged for ltr.', corner.TOP_LEFT,
  841. f(el, corner.TOP_LEFT));
  842. assertEquals(
  843. 'TOP_RIGHT should be unchanged for ltr.', corner.TOP_RIGHT,
  844. f(el, corner.TOP_RIGHT));
  845. assertEquals(
  846. 'BOTTOM_LEFT should be unchanged for ltr.', corner.BOTTOM_LEFT,
  847. f(el, corner.BOTTOM_LEFT));
  848. assertEquals(
  849. 'BOTTOM_RIGHT should be unchanged for ltr.', corner.BOTTOM_RIGHT,
  850. f(el, corner.BOTTOM_RIGHT));
  851. assertEquals(
  852. 'TOP_START should be TOP_LEFT for ltr.', corner.TOP_LEFT,
  853. f(el, corner.TOP_START));
  854. assertEquals(
  855. 'TOP_END should be TOP_RIGHT for ltr.', corner.TOP_RIGHT,
  856. f(el, corner.TOP_END));
  857. assertEquals(
  858. 'BOTTOM_START should be BOTTOM_LEFT for ltr.', corner.BOTTOM_LEFT,
  859. f(el, corner.BOTTOM_START));
  860. assertEquals(
  861. 'BOTTOM_END should be BOTTOM_RIGHT for ltr.', corner.BOTTOM_RIGHT,
  862. f(el, corner.BOTTOM_END));
  863. }
  864. function testGetEffectiveCornerRightToLeft() {
  865. var f = goog.positioning.getEffectiveCorner;
  866. var el = document.getElementById('rtl');
  867. assertEquals(
  868. 'TOP_LEFT should be unchanged for rtl.', corner.TOP_LEFT,
  869. f(el, corner.TOP_LEFT));
  870. assertEquals(
  871. 'TOP_RIGHT should be unchanged for rtl.', corner.TOP_RIGHT,
  872. f(el, corner.TOP_RIGHT));
  873. assertEquals(
  874. 'BOTTOM_LEFT should be unchanged for rtl.', corner.BOTTOM_LEFT,
  875. f(el, corner.BOTTOM_LEFT));
  876. assertEquals(
  877. 'BOTTOM_RIGHT should be unchanged for rtl.', corner.BOTTOM_RIGHT,
  878. f(el, corner.BOTTOM_RIGHT));
  879. assertEquals(
  880. 'TOP_START should be TOP_RIGHT for rtl.', corner.TOP_RIGHT,
  881. f(el, corner.TOP_START));
  882. assertEquals(
  883. 'TOP_END should be TOP_LEFT for rtl.', corner.TOP_LEFT,
  884. f(el, corner.TOP_END));
  885. assertEquals(
  886. 'BOTTOM_START should be BOTTOM_RIGHT for rtl.', corner.BOTTOM_RIGHT,
  887. f(el, corner.BOTTOM_START));
  888. assertEquals(
  889. 'BOTTOM_END should be BOTTOM_LEFT for rtl.', corner.BOTTOM_LEFT,
  890. f(el, corner.BOTTOM_END));
  891. }
  892. function testFlipCornerHorizontal() {
  893. var f = goog.positioning.flipCornerHorizontal;
  894. assertEquals(
  895. 'TOP_LEFT should be flipped to TOP_RIGHT.', corner.TOP_RIGHT,
  896. f(corner.TOP_LEFT));
  897. assertEquals(
  898. 'TOP_RIGHT should be flipped to TOP_LEFT.', corner.TOP_LEFT,
  899. f(corner.TOP_RIGHT));
  900. assertEquals(
  901. 'BOTTOM_LEFT should be flipped to BOTTOM_RIGHT.', corner.BOTTOM_RIGHT,
  902. f(corner.BOTTOM_LEFT));
  903. assertEquals(
  904. 'BOTTOM_RIGHT should be flipped to BOTTOM_LEFT.', corner.BOTTOM_LEFT,
  905. f(corner.BOTTOM_RIGHT));
  906. assertEquals(
  907. 'TOP_START should be flipped to TOP_END.', corner.TOP_END,
  908. f(corner.TOP_START));
  909. assertEquals(
  910. 'TOP_END should be flipped to TOP_START.', corner.TOP_START,
  911. f(corner.TOP_END));
  912. assertEquals(
  913. 'BOTTOM_START should be flipped to BOTTOM_END.', corner.BOTTOM_END,
  914. f(corner.BOTTOM_START));
  915. assertEquals(
  916. 'BOTTOM_END should be flipped to BOTTOM_START.', corner.BOTTOM_START,
  917. f(corner.BOTTOM_END));
  918. }
  919. function testFlipCornerVertical() {
  920. var f = goog.positioning.flipCornerVertical;
  921. assertEquals(
  922. 'TOP_LEFT should be flipped to BOTTOM_LEFT.', corner.BOTTOM_LEFT,
  923. f(corner.TOP_LEFT));
  924. assertEquals(
  925. 'TOP_RIGHT should be flipped to BOTTOM_RIGHT.', corner.BOTTOM_RIGHT,
  926. f(corner.TOP_RIGHT));
  927. assertEquals(
  928. 'BOTTOM_LEFT should be flipped to TOP_LEFT.', corner.TOP_LEFT,
  929. f(corner.BOTTOM_LEFT));
  930. assertEquals(
  931. 'BOTTOM_RIGHT should be flipped to TOP_RIGHT.', corner.TOP_RIGHT,
  932. f(corner.BOTTOM_RIGHT));
  933. assertEquals(
  934. 'TOP_START should be flipped to BOTTOM_START.', corner.BOTTOM_START,
  935. f(corner.TOP_START));
  936. assertEquals(
  937. 'TOP_END should be flipped to BOTTOM_END.', corner.BOTTOM_END,
  938. f(corner.TOP_END));
  939. assertEquals(
  940. 'BOTTOM_START should be flipped to TOP_START.', corner.TOP_START,
  941. f(corner.BOTTOM_START));
  942. assertEquals(
  943. 'BOTTOM_END should be flipped to TOP_END.', corner.TOP_END,
  944. f(corner.BOTTOM_END));
  945. }
  946. function testFlipCorner() {
  947. var f = goog.positioning.flipCorner;
  948. assertEquals(
  949. 'TOP_LEFT should be flipped to BOTTOM_RIGHT.', corner.BOTTOM_RIGHT,
  950. f(corner.TOP_LEFT));
  951. assertEquals(
  952. 'TOP_RIGHT should be flipped to BOTTOM_LEFT.', corner.BOTTOM_LEFT,
  953. f(corner.TOP_RIGHT));
  954. assertEquals(
  955. 'BOTTOM_LEFT should be flipped to TOP_RIGHT.', corner.TOP_RIGHT,
  956. f(corner.BOTTOM_LEFT));
  957. assertEquals(
  958. 'BOTTOM_RIGHT should be flipped to TOP_LEFT.', corner.TOP_LEFT,
  959. f(corner.BOTTOM_RIGHT));
  960. assertEquals(
  961. 'TOP_START should be flipped to BOTTOM_END.', corner.BOTTOM_END,
  962. f(corner.TOP_START));
  963. assertEquals(
  964. 'TOP_END should be flipped to BOTTOM_START.', corner.BOTTOM_START,
  965. f(corner.TOP_END));
  966. assertEquals(
  967. 'BOTTOM_START should be flipped to TOP_END.', corner.TOP_END,
  968. f(corner.BOTTOM_START));
  969. assertEquals(
  970. 'BOTTOM_END should be flipped to TOP_START.', corner.TOP_START,
  971. f(corner.BOTTOM_END));
  972. }
  973. function testPositionAtAnchorFrameViewportStandard() {
  974. var iframe = document.getElementById('iframe-standard');
  975. var iframeDoc = goog.dom.getFrameContentDocument(iframe);
  976. assertTrue(new goog.dom.DomHelper(iframeDoc).isCss1CompatMode());
  977. new goog.dom.DomHelper(iframeDoc).getDocumentScrollElement().scrollTop = 100;
  978. var anchor = iframeDoc.getElementById('anchor1');
  979. var popup = document.getElementById('popup6');
  980. var status = goog.positioning.positionAtAnchor(
  981. anchor, corner.TOP_RIGHT, popup, corner.BOTTOM_RIGHT);
  982. var iframeRect = goog.style.getBounds(iframe);
  983. var popupRect = goog.style.getBounds(popup);
  984. assertEquals(
  985. 'Status should not have any ADJUSTED and FAILED.',
  986. goog.positioning.OverflowStatus.NONE, status);
  987. assertRoundedEquals(
  988. 'Popup should be positioned just above the iframe, ' +
  989. 'not above the anchor element inside the iframe',
  990. iframeRect.top, popupRect.top + popupRect.height);
  991. }
  992. function testPositionAtAnchorFrameViewportQuirk() {
  993. var iframe = document.getElementById('iframe-quirk');
  994. var iframeDoc = goog.dom.getFrameContentDocument(iframe);
  995. assertFalse(new goog.dom.DomHelper(iframeDoc).isCss1CompatMode());
  996. window.scrollTo(0, 100);
  997. new goog.dom.DomHelper(iframeDoc).getDocumentScrollElement().scrollTop = 100;
  998. var anchor = iframeDoc.getElementById('anchor1');
  999. var popup = document.getElementById('popup6');
  1000. var status = goog.positioning.positionAtAnchor(
  1001. anchor, corner.TOP_RIGHT, popup, corner.BOTTOM_RIGHT);
  1002. var iframeRect = goog.style.getBounds(iframe);
  1003. var popupRect = goog.style.getBounds(popup);
  1004. assertEquals(
  1005. 'Status should not have any ADJUSTED and FAILED.',
  1006. goog.positioning.OverflowStatus.NONE, status);
  1007. assertRoundedEquals(
  1008. 'Popup should be positioned just above the iframe, ' +
  1009. 'not above the anchor element inside the iframe',
  1010. iframeRect.top, popupRect.top + popupRect.height);
  1011. }
  1012. function testPositionAtAnchorFrameViewportWithPopupInScroller() {
  1013. var iframe = document.getElementById('iframe-standard');
  1014. var iframeDoc = goog.dom.getFrameContentDocument(iframe);
  1015. new goog.dom.DomHelper(iframeDoc).getDocumentScrollElement().scrollTop = 100;
  1016. var anchor = iframeDoc.getElementById('anchor1');
  1017. var popup = document.getElementById('popup7');
  1018. popup.offsetParent.scrollTop = 50;
  1019. var status = goog.positioning.positionAtAnchor(
  1020. anchor, corner.TOP_RIGHT, popup, corner.BOTTOM_RIGHT);
  1021. var iframeRect = goog.style.getBounds(iframe);
  1022. var popupRect = goog.style.getBounds(popup);
  1023. assertEquals(
  1024. 'Status should not have any ADJUSTED and FAILED.',
  1025. goog.positioning.OverflowStatus.NONE, status);
  1026. assertRoughlyEquals(
  1027. 'Popup should be positioned just above the iframe, ' +
  1028. 'not above the anchor element inside the iframe',
  1029. iframeRect.top, popupRect.top + popupRect.height, ALLOWED_OFFSET);
  1030. }
  1031. function testPositionAtAnchorNestedFrames() {
  1032. var outerIframe = document.getElementById('nested-outer');
  1033. var outerDoc = goog.dom.getFrameContentDocument(outerIframe);
  1034. var popup = outerDoc.getElementById('popup1');
  1035. var innerIframe = outerDoc.getElementById('inner-frame');
  1036. var innerDoc = goog.dom.getFrameContentDocument(innerIframe);
  1037. var anchor = innerDoc.getElementById('anchor1');
  1038. var status = goog.positioning.positionAtAnchor(
  1039. anchor, corner.TOP_LEFT, popup, corner.BOTTOM_LEFT);
  1040. assertEquals(
  1041. 'Status should not have any ADJUSTED and FAILED.',
  1042. goog.positioning.OverflowStatus.NONE, status);
  1043. var innerIframeRect = goog.style.getBounds(innerIframe);
  1044. var popupRect = goog.style.getBounds(popup);
  1045. assertRoundedEquals(
  1046. 'Top of frame should align with bottom of the popup', innerIframeRect.top,
  1047. popupRect.top + popupRect.height);
  1048. // The anchor is scrolled up by 10px.
  1049. // Popup position should be the same as above.
  1050. goog.dom.getWindow(innerDoc).scrollTo(0, 10);
  1051. status = goog.positioning.positionAtAnchor(
  1052. anchor, corner.TOP_LEFT, popup, corner.BOTTOM_LEFT);
  1053. assertEquals(
  1054. 'Status should not have any ADJUSTED and FAILED.',
  1055. goog.positioning.OverflowStatus.NONE, status);
  1056. innerIframeRect = goog.style.getBounds(innerIframe);
  1057. popupRect = goog.style.getBounds(popup);
  1058. assertRoundedEquals(
  1059. 'Top of frame should align with bottom of the popup', innerIframeRect.top,
  1060. popupRect.top + popupRect.height);
  1061. }
  1062. function testPositionAtAnchorOffscreen() {
  1063. var offset = 0;
  1064. var anchor = goog.dom.getElement('offscreen-anchor');
  1065. var popup = goog.dom.getElement('popup3');
  1066. goog.positioning.positionAtAnchor(
  1067. anchor, corner.TOP_LEFT, popup, corner.TOP_LEFT, null, null,
  1068. overflow.ADJUST_X | overflow.ADJUST_Y);
  1069. assertObjectEquals(newCoord(offset, offset), goog.style.getPageOffset(popup));
  1070. goog.positioning.positionAtAnchor(
  1071. anchor, corner.TOP_LEFT, popup, corner.TOP_LEFT, null, null,
  1072. overflow.ADJUST_X_EXCEPT_OFFSCREEN | overflow.ADJUST_Y);
  1073. assertObjectEquals(newCoord(-1000, offset), goog.style.getPageOffset(popup));
  1074. goog.positioning.positionAtAnchor(
  1075. anchor, corner.TOP_LEFT, popup, corner.TOP_LEFT, null, null,
  1076. overflow.ADJUST_X | overflow.ADJUST_Y_EXCEPT_OFFSCREEN);
  1077. assertObjectEquals(newCoord(offset, -1000), goog.style.getPageOffset(popup));
  1078. goog.positioning.positionAtAnchor(
  1079. anchor, corner.TOP_LEFT, popup, corner.TOP_LEFT, null, null,
  1080. overflow.ADJUST_X_EXCEPT_OFFSCREEN | overflow.ADJUST_Y_EXCEPT_OFFSCREEN);
  1081. assertObjectEquals(newCoord(-1000, -1000), goog.style.getPageOffset(popup));
  1082. }
  1083. function testPositionAtAnchorWithOverflowScrollOffsetParent() {
  1084. var testAreaOffset = goog.style.getPageOffset(testArea);
  1085. var scrollbarWidth = goog.style.getScrollbarWidth();
  1086. window.scrollTo(testAreaOffset.x, testAreaOffset.y);
  1087. var overflowDiv = goog.dom.createElement(goog.dom.TagName.DIV);
  1088. overflowDiv.style.overflow = 'scroll';
  1089. overflowDiv.style.position = 'relative';
  1090. goog.style.setSize(overflowDiv, 200 /* width */, 100 /* height */);
  1091. var anchor = goog.dom.createElement(goog.dom.TagName.DIV);
  1092. anchor.style.position = 'absolute';
  1093. goog.style.setSize(anchor, 50 /* width */, 50 /* height */);
  1094. goog.style.setPosition(anchor, 300 /* left */, 300 /* top */);
  1095. var popup = createPopupDiv(75 /* width */, 50 /* height */);
  1096. goog.dom.append(testArea, overflowDiv, anchor);
  1097. goog.dom.append(overflowDiv, popup);
  1098. // Popup should always be positioned within the overflowDiv
  1099. goog.style.setPosition(overflowDiv, 0 /* left */, 0 /* top */);
  1100. goog.positioning.positionAtAnchor(
  1101. anchor, corner.TOP_LEFT, popup, corner.TOP_RIGHT, null, null,
  1102. overflow.ADJUST_X | overflow.ADJUST_Y);
  1103. assertObjectRoughlyEquals(
  1104. new goog.math.Coordinate(
  1105. testAreaOffset.x + 200 - 75 - scrollbarWidth,
  1106. testAreaOffset.y + 100 - 50 - scrollbarWidth),
  1107. goog.style.getPageOffset(popup), 1);
  1108. goog.style.setPosition(overflowDiv, 400 /* left */, 0 /* top */);
  1109. goog.positioning.positionAtAnchor(
  1110. anchor, corner.TOP_RIGHT, popup, corner.TOP_LEFT, null, null,
  1111. overflow.ADJUST_X | overflow.ADJUST_Y);
  1112. assertObjectRoughlyEquals(
  1113. new goog.math.Coordinate(
  1114. testAreaOffset.x + 400, testAreaOffset.y + 100 - 50 - scrollbarWidth),
  1115. goog.style.getPageOffset(popup), 1);
  1116. goog.style.setPosition(overflowDiv, 0 /* left */, 400 /* top */);
  1117. goog.positioning.positionAtAnchor(
  1118. anchor, corner.BOTTOM_LEFT, popup, corner.BOTTOM_RIGHT, null, null,
  1119. overflow.ADJUST_X | overflow.ADJUST_Y);
  1120. assertObjectRoughlyEquals(
  1121. new goog.math.Coordinate(
  1122. testAreaOffset.x + 200 - 75 - scrollbarWidth, testAreaOffset.y + 400),
  1123. goog.style.getPageOffset(popup), 1);
  1124. goog.style.setPosition(overflowDiv, 400 /* left */, 400 /* top */);
  1125. goog.positioning.positionAtAnchor(
  1126. anchor, corner.BOTTOM_RIGHT, popup, corner.BOTTOM_LEFT, null, null,
  1127. overflow.ADJUST_X | overflow.ADJUST_Y);
  1128. assertObjectRoughlyEquals(
  1129. new goog.math.Coordinate(testAreaOffset.x + 400, testAreaOffset.y + 400),
  1130. goog.style.getPageOffset(popup), 1);
  1131. // No overflow.
  1132. goog.style.setPosition(overflowDiv, 300 - 50 /* left */, 300 /* top */);
  1133. goog.positioning.positionAtAnchor(
  1134. anchor, corner.TOP_LEFT, popup, corner.TOP_RIGHT, null, null,
  1135. overflow.ADJUST_X | overflow.ADJUST_Y);
  1136. assertObjectRoughlyEquals(
  1137. new goog.math.Coordinate(
  1138. testAreaOffset.x + 300 - 50, testAreaOffset.y + 300),
  1139. goog.style.getPageOffset(popup), 1);
  1140. }
  1141. function testPositionAtAnchorWithOverflowHiddenParent() {
  1142. var testAreaOffset = goog.style.getPageOffset(testArea);
  1143. window.scrollTo(testAreaOffset.x, testAreaOffset.y);
  1144. var overflowDiv = goog.dom.createElement(goog.dom.TagName.DIV);
  1145. overflowDiv.style.overflow = 'hidden';
  1146. overflowDiv.style.position = 'relative';
  1147. goog.style.setSize(overflowDiv, 200 /* width */, 100 /* height */);
  1148. var anchor = goog.dom.createElement(goog.dom.TagName.DIV);
  1149. anchor.style.position = 'absolute';
  1150. goog.style.setSize(anchor, 50 /* width */, 50 /* height */);
  1151. goog.style.setPosition(anchor, 300 /* left */, 300 /* top */);
  1152. var popup = createPopupDiv(75 /* width */, 50 /* height */);
  1153. goog.dom.append(testArea, overflowDiv, anchor);
  1154. goog.dom.append(overflowDiv, popup);
  1155. // Popup should always be positioned within the overflowDiv
  1156. goog.style.setPosition(overflowDiv, 0 /* left */, 0 /* top */);
  1157. goog.positioning.positionAtAnchor(
  1158. anchor, corner.TOP_LEFT, popup, corner.TOP_RIGHT, null, null,
  1159. overflow.ADJUST_X | overflow.ADJUST_Y);
  1160. assertObjectRoughlyEquals(
  1161. new goog.math.Coordinate(
  1162. testAreaOffset.x + 200 - 75, testAreaOffset.y + 100 - 50),
  1163. goog.style.getPageOffset(popup), 1);
  1164. goog.style.setPosition(overflowDiv, 400 /* left */, 0 /* top */);
  1165. goog.positioning.positionAtAnchor(
  1166. anchor, corner.TOP_RIGHT, popup, corner.TOP_LEFT, null, null,
  1167. overflow.ADJUST_X | overflow.ADJUST_Y);
  1168. assertObjectRoughlyEquals(
  1169. new goog.math.Coordinate(
  1170. testAreaOffset.x + 400, testAreaOffset.y + 100 - 50),
  1171. goog.style.getPageOffset(popup), 1);
  1172. goog.style.setPosition(overflowDiv, 0 /* left */, 400 /* top */);
  1173. goog.positioning.positionAtAnchor(
  1174. anchor, corner.BOTTOM_LEFT, popup, corner.BOTTOM_RIGHT, null, null,
  1175. overflow.ADJUST_X | overflow.ADJUST_Y);
  1176. assertObjectRoughlyEquals(
  1177. new goog.math.Coordinate(
  1178. testAreaOffset.x + 200 - 75, testAreaOffset.y + 400),
  1179. goog.style.getPageOffset(popup), 1);
  1180. goog.style.setPosition(overflowDiv, 400 /* left */, 400 /* top */);
  1181. goog.positioning.positionAtAnchor(
  1182. anchor, corner.BOTTOM_RIGHT, popup, corner.BOTTOM_LEFT, null, null,
  1183. overflow.ADJUST_X | overflow.ADJUST_Y);
  1184. assertObjectRoughlyEquals(
  1185. new goog.math.Coordinate(testAreaOffset.x + 400, testAreaOffset.y + 400),
  1186. goog.style.getPageOffset(popup), 1);
  1187. // No overflow.
  1188. goog.style.setPosition(overflowDiv, 300 - 50 /* left */, 300 /* top */);
  1189. goog.positioning.positionAtAnchor(
  1190. anchor, corner.TOP_LEFT, popup, corner.TOP_RIGHT, null, null,
  1191. overflow.ADJUST_X | overflow.ADJUST_Y);
  1192. assertObjectRoughlyEquals(
  1193. new goog.math.Coordinate(
  1194. testAreaOffset.x + 300 - 50, testAreaOffset.y + 300),
  1195. goog.style.getPageOffset(popup), 1);
  1196. }
  1197. function createPopupDiv(width, height) {
  1198. var popupDiv = goog.dom.createElement(goog.dom.TagName.DIV);
  1199. popupDiv.style.position = 'absolute';
  1200. goog.style.setSize(popupDiv, width, height);
  1201. goog.style.setPosition(popupDiv, 0 /* left */, 250 /* top */);
  1202. return popupDiv;
  1203. }
  1204. function newCoord(x, y) {
  1205. return new goog.math.Coordinate(x, y);
  1206. }
  1207. function newSize(w, h) {
  1208. return new goog.math.Size(w, h);
  1209. }
  1210. function newBox(coord, size) {}