dragger_test.js 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499
  1. // Copyright 2008 The Closure Library Authors. All Rights Reserved.
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS-IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. goog.provide('goog.fx.DraggerTest');
  15. goog.setTestOnly('goog.fx.DraggerTest');
  16. goog.require('goog.dom');
  17. goog.require('goog.dom.TagName');
  18. goog.require('goog.events');
  19. goog.require('goog.events.BrowserEvent');
  20. goog.require('goog.events.Event');
  21. goog.require('goog.events.EventType');
  22. goog.require('goog.fx.Dragger');
  23. goog.require('goog.math.Rect');
  24. goog.require('goog.style.bidi');
  25. goog.require('goog.testing.StrictMock');
  26. goog.require('goog.testing.events');
  27. goog.require('goog.testing.jsunit');
  28. goog.require('goog.userAgent');
  29. var HAS_SET_CAPTURE = goog.fx.Dragger.HAS_SET_CAPTURE_;
  30. var target;
  31. var targetRtl;
  32. function setUp() {
  33. var sandbox = goog.dom.getElement('sandbox');
  34. target = goog.dom.createDom(goog.dom.TagName.DIV, {
  35. 'id': 'target',
  36. 'style': 'display:none;position:absolute;top:15px;left:10px'
  37. });
  38. sandbox.appendChild(target);
  39. sandbox.appendChild(goog.dom.createDom(goog.dom.TagName.DIV, {id: 'handle'}));
  40. var sandboxRtl = goog.dom.getElement('sandbox_rtl');
  41. targetRtl = goog.dom.createDom(goog.dom.TagName.DIV, {
  42. 'id': 'target_rtl',
  43. 'style': 'position:absolute; top:15px; right:10px; width:10px; ' +
  44. 'height: 10px; background: green;'
  45. });
  46. sandboxRtl.appendChild(targetRtl);
  47. sandboxRtl.appendChild(goog.dom.createDom(goog.dom.TagName.DIV, {
  48. 'id': 'background_rtl',
  49. 'style': 'width: 10000px;height:50px;position:absolute;color:blue;'
  50. }));
  51. sandboxRtl.appendChild(
  52. goog.dom.createDom(goog.dom.TagName.DIV, {id: 'handle_rtl'}));
  53. }
  54. function tearDown() {
  55. goog.dom.removeChildren(goog.dom.getElement('sandbox'));
  56. goog.dom.removeChildren(goog.dom.getElement('sandbox_rtl'));
  57. goog.events.removeAll(document);
  58. }
  59. function testStartDrag() {
  60. runStartDragTest('handle', target);
  61. }
  62. function testStartDrag_rtl() {
  63. runStartDragTest('handle_rtl', targetRtl);
  64. }
  65. function runStartDragTest(handleId, targetElement) {
  66. var dragger =
  67. new goog.fx.Dragger(targetElement, goog.dom.getElement(handleId));
  68. if (handleId == 'handle_rtl') {
  69. dragger.enableRightPositioningForRtl(true);
  70. }
  71. var e = new goog.testing.StrictMock(goog.events.BrowserEvent);
  72. e.type = goog.events.EventType.MOUSEDOWN;
  73. e.clientX = 1;
  74. e.clientY = 2;
  75. e.isMouseActionButton().$returns(true);
  76. e.preventDefault();
  77. e.isMouseActionButton().$returns(true);
  78. e.preventDefault();
  79. e.$replay();
  80. goog.events.listen(dragger, goog.fx.Dragger.EventType.START, function() {
  81. targetElement.style.display = 'block';
  82. });
  83. dragger.startDrag(e);
  84. assertTrue(
  85. 'Start drag with no hysteresis must actually start the drag.',
  86. dragger.isDragging());
  87. if (handleId == 'handle_rtl') {
  88. assertEquals(10, goog.style.bidi.getOffsetStart(targetElement));
  89. }
  90. assertEquals(
  91. 'Dragger startX must match event\'s clientX.', 1, dragger.startX);
  92. assertEquals(
  93. 'Dragger clientX must match event\'s clientX', 1, dragger.clientX);
  94. assertEquals(
  95. 'Dragger startY must match event\'s clientY.', 2, dragger.startY);
  96. assertEquals(
  97. 'Dragger clientY must match event\'s clientY', 2, dragger.clientY);
  98. assertEquals(
  99. 'Dragger deltaX must match target\'s offsetLeft', 10, dragger.deltaX);
  100. assertEquals(
  101. 'Dragger deltaY must match target\'s offsetTop', 15, dragger.deltaY);
  102. dragger = new goog.fx.Dragger(targetElement, goog.dom.getElement(handleId));
  103. dragger.setHysteresis(1);
  104. dragger.startDrag(e);
  105. assertFalse(
  106. 'Start drag with a valid non-zero hysteresis should not start ' +
  107. 'the drag.',
  108. dragger.isDragging());
  109. e.$verify();
  110. }
  111. /**
  112. * @bug 1381317 Cancelling start drag didn't end the attempt to drag.
  113. */
  114. function testStartDrag_Cancel() {
  115. var dragger = new goog.fx.Dragger(target);
  116. var e = new goog.testing.StrictMock(goog.events.BrowserEvent);
  117. e.type = goog.events.EventType.MOUSEDOWN;
  118. e.clientX = 1;
  119. e.clientY = 2;
  120. e.isMouseActionButton().$returns(true);
  121. e.$replay();
  122. goog.events.listen(dragger, goog.fx.Dragger.EventType.START, function(e) {
  123. // Cancel drag.
  124. e.preventDefault();
  125. });
  126. dragger.startDrag(e);
  127. assertFalse('Start drag must have been cancelled.', dragger.isDragging());
  128. assertFalse(
  129. 'Dragger must not have registered mousemove handlers.',
  130. goog.events.hasListener(
  131. dragger.document_, goog.events.EventType.MOUSEMOVE,
  132. !HAS_SET_CAPTURE));
  133. assertFalse(
  134. 'Dragger must not have registered mouseup handlers.',
  135. goog.events.hasListener(
  136. dragger.document_, goog.events.EventType.MOUSEUP, !HAS_SET_CAPTURE));
  137. e.$verify();
  138. }
  139. /**
  140. * Tests that start drag happens on left mousedown.
  141. */
  142. function testStartDrag_LeftMouseDownOnly() {
  143. var dragger = new goog.fx.Dragger(target);
  144. var e = new goog.testing.StrictMock(goog.events.BrowserEvent);
  145. e.type = goog.events.EventType.MOUSEDOWN;
  146. e.clientX = 1;
  147. e.clientY = 2;
  148. e.isMouseActionButton().$returns(false);
  149. e.$replay();
  150. goog.events.listen(dragger, goog.fx.Dragger.EventType.START, function(e) {
  151. fail('No drag START event should have been dispatched');
  152. });
  153. dragger.startDrag(e);
  154. assertFalse('Start drag must have been cancelled.', dragger.isDragging());
  155. assertFalse(
  156. 'Dragger must not have registered mousemove handlers.',
  157. goog.events.hasListener(
  158. dragger.document_, goog.events.EventType.MOUSEMOVE, true));
  159. assertFalse(
  160. 'Dragger must not have registered mouseup handlers.',
  161. goog.events.hasListener(
  162. dragger.document_, goog.events.EventType.MOUSEUP, true));
  163. e.$verify();
  164. }
  165. /**
  166. * Tests that start drag happens on other event type than MOUSEDOWN.
  167. */
  168. function testStartDrag_MouseMove() {
  169. var dragger = new goog.fx.Dragger(target);
  170. var e = new goog.testing.StrictMock(goog.events.BrowserEvent);
  171. e.type = goog.events.EventType.MOUSEMOVE;
  172. e.clientX = 1;
  173. e.clientY = 2;
  174. // preventDefault is not called.
  175. e.$replay();
  176. var startDragFired = false;
  177. goog.events.listen(dragger, goog.fx.Dragger.EventType.START, function(e) {
  178. startDragFired = true;
  179. });
  180. dragger.startDrag(e);
  181. assertTrue('Dragging should be in progress.', dragger.isDragging());
  182. assertTrue('Start drag event should have fired.', startDragFired);
  183. assertTrue(
  184. 'Dragger must have registered mousemove handlers.',
  185. goog.events.hasListener(
  186. dragger.document_, goog.events.EventType.MOUSEMOVE,
  187. !HAS_SET_CAPTURE));
  188. assertTrue(
  189. 'Dragger must have registered mouseup handlers.',
  190. goog.events.hasListener(
  191. dragger.document_, goog.events.EventType.MOUSEUP, !HAS_SET_CAPTURE));
  192. e.$verify();
  193. }
  194. /**
  195. * Tests that preventDefault is not called for TOUCHSTART event.
  196. */
  197. function testStartDrag_TouchStart() {
  198. var dragger = new goog.fx.Dragger(target);
  199. var e = new goog.testing.StrictMock(goog.events.BrowserEvent);
  200. e.type = goog.events.EventType.TOUCHSTART;
  201. // preventDefault is not called.
  202. e.$replay();
  203. var startDragFired = false;
  204. goog.events.listen(dragger, goog.fx.Dragger.EventType.START, function(e) {
  205. startDragFired = true;
  206. });
  207. dragger.startDrag(e);
  208. assertTrue('Dragging should be in progress.', dragger.isDragging());
  209. assertTrue('Start drag event should have fired.', startDragFired);
  210. assertTrue(
  211. 'Dragger must have registered touchstart listener.',
  212. goog.events.hasListener(
  213. dragger.handle, goog.events.EventType.TOUCHSTART, false /*opt_cap*/));
  214. e.$verify();
  215. }
  216. /**
  217. * Tests that preventDefault is not called for TOUCHSTART event when hysteresis
  218. * is set to be greater than zero.
  219. */
  220. function testStartDrag_TouchStart_NonZeroHysteresis() {
  221. var dragger = new goog.fx.Dragger(target);
  222. dragger.setHysteresis(5);
  223. var e = new goog.testing.StrictMock(goog.events.BrowserEvent);
  224. e.type = goog.events.EventType.TOUCHSTART;
  225. // preventDefault is not called.
  226. e.$replay();
  227. var startDragFired = false;
  228. goog.events.listen(dragger, goog.fx.Dragger.EventType.START, function(e) {
  229. startDragFired = true;
  230. });
  231. dragger.startDrag(e);
  232. assertFalse(
  233. 'Start drag must not start drag because of hysterisis.',
  234. dragger.isDragging());
  235. assertTrue(
  236. 'Dragger must have registered touchstart listener.',
  237. goog.events.hasListener(
  238. dragger.handle, goog.events.EventType.TOUCHSTART, false /*opt_cap*/));
  239. e.$verify();
  240. }
  241. /**
  242. * @bug 1381317 Cancelling start drag didn't end the attempt to drag.
  243. */
  244. function testHandleMove_Cancel() {
  245. var dragger = new goog.fx.Dragger(target);
  246. dragger.setHysteresis(5);
  247. goog.events.listen(dragger, goog.fx.Dragger.EventType.START, function(e) {
  248. // Cancel drag.
  249. e.preventDefault();
  250. });
  251. var e = new goog.testing.StrictMock(goog.events.BrowserEvent);
  252. e.clientX = 1;
  253. e.clientY = 2;
  254. e.isMouseActionButton().$returns(true).$anyTimes();
  255. // preventDefault is not called.
  256. e.$replay();
  257. dragger.startDrag(e);
  258. assertFalse(
  259. 'Start drag must not start drag because of hysterisis.',
  260. dragger.isDragging());
  261. assertTrue(
  262. 'Dragger must have registered mousemove handlers.',
  263. goog.events.hasListener(
  264. dragger.document_, goog.events.EventType.MOUSEMOVE,
  265. !HAS_SET_CAPTURE));
  266. assertTrue(
  267. 'Dragger must have registered mouseup handlers.',
  268. goog.events.hasListener(
  269. dragger.document_, goog.events.EventType.MOUSEUP, !HAS_SET_CAPTURE));
  270. e.clientX = 10;
  271. e.clientY = 10;
  272. dragger.handleMove_(e);
  273. assertFalse('Drag must be cancelled.', dragger.isDragging());
  274. assertFalse(
  275. 'Dragger must unregistered mousemove handlers.',
  276. goog.events.hasListener(
  277. dragger.document_, goog.events.EventType.MOUSEMOVE, true));
  278. assertFalse(
  279. 'Dragger must unregistered mouseup handlers.',
  280. goog.events.hasListener(
  281. dragger.document_, goog.events.EventType.MOUSEUP, true));
  282. e.$verify();
  283. }
  284. /**
  285. * @bug 1714667 IE<9 built in drag and drop handling stops dragging.
  286. */
  287. function testIeDragStartCancelling() {
  288. // Testing only IE<9.
  289. if (!goog.userAgent.IE || goog.userAgent.isVersionOrHigher(9)) {
  290. return;
  291. }
  292. // Built in 'dragstart' cancelling not enabled.
  293. var dragger = new goog.fx.Dragger(target);
  294. var e = new goog.events.Event(goog.events.EventType.MOUSEDOWN);
  295. e.clientX = 1;
  296. e.clientY = 2;
  297. e.button = 1; // IE only constant for left button.
  298. var be = new goog.events.BrowserEvent(e);
  299. dragger.startDrag(be);
  300. assertTrue('The drag should have started.', dragger.isDragging());
  301. e = new goog.events.Event(goog.events.EventType.DRAGSTART);
  302. e.target = dragger.document_.documentElement;
  303. assertTrue(
  304. 'The event should not be canceled.',
  305. goog.testing.events.fireBrowserEvent(e));
  306. dragger.dispose();
  307. // Built in 'dragstart' cancelling enabled.
  308. dragger = new goog.fx.Dragger(target);
  309. dragger.setCancelIeDragStart(true);
  310. e = new goog.events.Event(goog.events.EventType.MOUSEDOWN);
  311. e.clientX = 1;
  312. e.clientY = 2;
  313. e.button = 1; // IE only constant for left button.
  314. be = new goog.events.BrowserEvent(e);
  315. dragger.startDrag(be);
  316. assertTrue('The drag should have started.', dragger.isDragging());
  317. e = new goog.events.Event(goog.events.EventType.DRAGSTART);
  318. e.target = dragger.document_.documentElement;
  319. assertFalse(
  320. 'The event should be canceled.', goog.testing.events.fireBrowserEvent(e));
  321. dragger.dispose();
  322. }
  323. function testPreventMouseDown() {
  324. var dragger = new goog.fx.Dragger(target);
  325. dragger.setPreventMouseDown(false);
  326. var e = new goog.testing.StrictMock(goog.events.BrowserEvent);
  327. e.type = goog.events.EventType.MOUSEDOWN;
  328. e.clientX = 1;
  329. e.clientY = 2;
  330. e.isMouseActionButton().$returns(true);
  331. // preventDefault is not called.
  332. e.$replay();
  333. dragger.startDrag(e);
  334. assertTrue('Dragging should be in progess.', dragger.isDragging());
  335. e.$verify();
  336. }
  337. function testLimits() {
  338. var dragger = new goog.fx.Dragger(target);
  339. assertEquals(100, dragger.limitX(100));
  340. assertEquals(100, dragger.limitY(100));
  341. dragger.setLimits(new goog.math.Rect(10, 20, 30, 40));
  342. assertEquals(10, dragger.limitX(0));
  343. assertEquals(40, dragger.limitX(100));
  344. assertEquals(20, dragger.limitY(0));
  345. assertEquals(60, dragger.limitY(100));
  346. }
  347. function testWindowBlur() {
  348. if (!goog.fx.Dragger.HAS_SET_CAPTURE_) {
  349. var dragger = new goog.fx.Dragger(target);
  350. var dragEnded = false;
  351. goog.events.listen(dragger, goog.fx.Dragger.EventType.END, function(e) {
  352. dragEnded = true;
  353. });
  354. var e = new goog.testing.StrictMock(goog.events.BrowserEvent);
  355. e.type = goog.events.EventType.MOUSEDOWN;
  356. e.clientX = 1;
  357. e.clientY = 2;
  358. e.isMouseActionButton().$returns(true);
  359. e.preventDefault();
  360. e.$replay();
  361. dragger.startDrag(e);
  362. e.$verify();
  363. assertTrue(dragger.isDragging());
  364. e = new goog.events.BrowserEvent();
  365. e.type = goog.events.EventType.BLUR;
  366. e.target = window;
  367. e.currentTarget = window;
  368. goog.testing.events.fireBrowserEvent(e);
  369. assertTrue(dragEnded);
  370. }
  371. }
  372. function testBlur() {
  373. if (!goog.fx.Dragger.HAS_SET_CAPTURE_) {
  374. var dragger = new goog.fx.Dragger(target);
  375. var dragEnded = false;
  376. goog.events.listen(dragger, goog.fx.Dragger.EventType.END, function(e) {
  377. dragEnded = true;
  378. });
  379. var e = new goog.testing.StrictMock(goog.events.BrowserEvent);
  380. e.type = goog.events.EventType.MOUSEDOWN;
  381. e.clientX = 1;
  382. e.clientY = 2;
  383. e.isMouseActionButton().$returns(true);
  384. e.preventDefault();
  385. e.$replay();
  386. dragger.startDrag(e);
  387. e.$verify();
  388. assertTrue(dragger.isDragging());
  389. e = new goog.events.BrowserEvent();
  390. e.type = goog.events.EventType.BLUR;
  391. e.target = document.body;
  392. e.currentTarget = document.body;
  393. // Blur events do not bubble but the test event system does not emulate that
  394. // part so we add a capturing listener on the target and stops the
  395. // propagation at the target, preventing any event from bubbling.
  396. goog.events.listen(document.body, goog.events.EventType.BLUR, function(e) {
  397. e.propagationStopped_ = true;
  398. }, true);
  399. goog.testing.events.fireBrowserEvent(e);
  400. assertFalse(dragEnded);
  401. }
  402. }
  403. function testCloneNode() {
  404. var element = goog.dom.createDom(goog.dom.TagName.DIV);
  405. element.innerHTML = '<input type="hidden" value="v0">' +
  406. '<textarea>v1</textarea>' +
  407. '<textarea>v2</textarea>';
  408. element.childNodes[0].value = '\'new\'\n"value"';
  409. element.childNodes[1].value = '<' +
  410. '/textarea>&lt;3';
  411. element.childNodes[2].value = '<script>\n\talert("oops!");<' +
  412. '/script>';
  413. var clone = goog.fx.Dragger.cloneNode(element);
  414. assertEquals(element.childNodes[0].value, clone.childNodes[0].value);
  415. assertEquals(element.childNodes[1].value, clone.childNodes[1].value);
  416. assertEquals(element.childNodes[2].value, clone.childNodes[2].value);
  417. clone = goog.fx.Dragger.cloneNode(element.childNodes[2]);
  418. assertEquals(element.childNodes[2].value, clone.value);
  419. }