TouchCapableSpec.js 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571
  1. /* The following functions are taken and slightly modified from mock-phantom-touch-events.
  2. *
  3. * The original mock-phantom-touch-events can be found at https://github.com/gardr/mock-phantom-touch-events
  4. *
  5. * mock-phantom-touch-events is licensed under:
  6. *
  7. * The MIT License (MIT)
  8. * Copyright (c) 2013 FINN.no AS
  9. * Permission is hereby granted, free of charge, to any person obtaining a copy of
  10. * this software and associated documentation files (the "Software"), to deal in
  11. * the Software without restriction, including without limitation the rights to
  12. * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
  13. * the Software, and to permit persons to whom the Software is furnished to do so,
  14. * subject to the following conditions:
  15. * The above copyright notice and this permission notice shall be included in all
  16. * copies or substantial portions of the Software.
  17. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  18. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
  19. * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
  20. * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
  21. * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
  22. * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  23. *
  24. */
  25. /*
  26. list can be either [[x, y], [x, y]] or [x, y]
  27. */
  28. function createTouchList(target, list) {
  29. if (Array.isArray(list) && list[0] && !Array.isArray(list[0])) {
  30. list = [list];
  31. }
  32. list = list.map(function (entry, index) {
  33. var x = entry[0], y = entry[1], id = entry[2] ? entry[2] : index + 1;
  34. return createTouch(x, y, target, id);
  35. });
  36. return document.createTouchList.apply(document, list);
  37. }
  38. function createTouch(x, y, target, id) {
  39. return document.createTouch(window, target,
  40. id || 1, //identifier
  41. x, //pageX / clientX
  42. y, //pageY / clientY
  43. x, //screenX
  44. y //screenY
  45. );
  46. }
  47. function initTouchEvent(touchEvent, type, touches) {
  48. var touch1 = touches[0];
  49. return touchEvent.initTouchEvent(
  50. touches, //touches
  51. touches, //targetTouches
  52. touches, //changedTouches
  53. type, //type
  54. window, //view
  55. touch1.screenX, //screenX
  56. touch1.screenY, //screenY
  57. touch1.clientX, //clientX
  58. touch1.clientY, //clientY
  59. false, //ctrlKey
  60. false, //altKey
  61. false, //shiftKey
  62. false //metaKey
  63. );
  64. }
  65. function createTouchEvent(elem, type, touches) {
  66. var touchEvent = document.createEvent('TouchEvent');
  67. if (Array.isArray(touches)) {
  68. touches = createTouchList(elem, touches);
  69. }
  70. initTouchEvent(touchEvent, type, touches);
  71. return touchEvent;
  72. }
  73. function calcTouchEventCoords(element) {
  74. var elementBB = element.getBoundingClientRect();
  75. return {
  76. x: elementBB.left,
  77. y: elementBB.top
  78. };
  79. }
  80. describe("Touch Capable Tests", function() {
  81. var touchStart;
  82. var touchMove;
  83. var touchEnd;
  84. var $testSlider;
  85. var sliderInst;
  86. var inputId;
  87. var sliderId;
  88. var sliderOptions;
  89. beforeEach(function() {
  90. inputId = 'testSlider1';
  91. sliderId = 'mySlider';
  92. sliderOptions = {
  93. id: sliderId,
  94. step: 1,
  95. value: 5,
  96. ticks: [0, 3, 5, 7, 10]
  97. };
  98. // Enable touch
  99. window.ontouchstart = true;
  100. });
  101. afterEach(function() {
  102. window.ontouchstart = null;
  103. if ($testSlider) {
  104. $testSlider.slider('destroy');
  105. $testSlider = null;
  106. }
  107. });
  108. describe("single slider", function() {
  109. beforeEach(function() {
  110. // Initialize the slider
  111. $testSlider = $('#' + inputId).slider(sliderOptions);
  112. // Get slider instance
  113. sliderInst = $testSlider.data('slider');
  114. });
  115. // index= [0 1 2 3 4]
  116. // ticks= [0 3 5 7 10]
  117. it("should slide the handle to the left from 5 to 3", function(done) {
  118. var sliderElem = $testSlider.slider('getElement');
  119. $testSlider.on('slideStop', function() {
  120. var value = $testSlider.slider('getValue');
  121. expect(value).toBe(3);
  122. done();
  123. });
  124. var tick = sliderInst.ticks[2]; // 5
  125. var sliderCoords = calcTouchEventCoords(sliderElem);
  126. var coords = [sliderCoords.x + tick.offsetLeft, sliderCoords.y];
  127. touchStart = createTouchEvent(sliderElem, 'touchstart', coords);
  128. tick = sliderInst.ticks[1]; // 3
  129. coords = [sliderCoords.x + tick.offsetLeft, sliderCoords.y];
  130. touchMove = createTouchEvent(sliderElem, 'touchmove', coords);
  131. touchEnd = createTouchEvent(sliderElem, 'touchend', coords);
  132. sliderElem.dispatchEvent(touchStart);
  133. sliderElem.dispatchEvent(touchMove);
  134. sliderElem.dispatchEvent(touchEnd);
  135. });
  136. it("should slide the handle to the right from 5 to 7", function(done) {
  137. var sliderElem = $testSlider.slider('getElement');
  138. $testSlider.on('slideStop', function() {
  139. var value = $testSlider.slider('getValue');
  140. expect(value).toBe(7);
  141. done();
  142. });
  143. var tick = sliderInst.ticks[2]; // 5
  144. var sliderCoords = calcTouchEventCoords(sliderElem);
  145. var coords = [sliderCoords.x + tick.offsetLeft, sliderCoords.y];
  146. touchStart = createTouchEvent(sliderElem, 'touchstart', coords);
  147. tick = sliderInst.ticks[3]; // 7
  148. coords = [sliderCoords.x + tick.offsetLeft, sliderCoords.y];
  149. touchMove = createTouchEvent(sliderElem, 'touchmove', coords);
  150. touchEnd = createTouchEvent(sliderElem, 'touchend', coords);
  151. sliderElem.dispatchEvent(touchStart);
  152. sliderElem.dispatchEvent(touchMove);
  153. sliderElem.dispatchEvent(touchEnd);
  154. });
  155. });
  156. describe("single, vertical slider", function() {
  157. beforeEach(function() {
  158. // Initialize the slider
  159. sliderOptions.orientation = 'vertical';
  160. $testSlider = $('#' + inputId).slider(sliderOptions);
  161. // Get slider instance
  162. sliderInst = $testSlider.data('slider');
  163. });
  164. // index= [0 1 2 3 4]
  165. // ticks= [0 3 5 7 10]
  166. it("should slide the handle to the top from 5 to 3", function(done) {
  167. var sliderElem = $testSlider.slider('getElement');
  168. $testSlider.on('slideStop', function() {
  169. var value = $testSlider.slider('getValue');
  170. expect(value).toBe(3);
  171. done();
  172. });
  173. var tick = sliderInst.ticks[2]; // 5
  174. var sliderCoords = calcTouchEventCoords(sliderElem);
  175. var coords = [sliderCoords.x, sliderCoords.y + tick.offsetTop];
  176. touchStart = createTouchEvent(sliderElem, 'touchstart', coords);
  177. tick = sliderInst.ticks[1]; // 3
  178. coords = [sliderCoords.x, sliderCoords.y + tick.offsetTop];
  179. touchMove = createTouchEvent(sliderElem, 'touchmove', coords);
  180. touchEnd = createTouchEvent(sliderElem, 'touchend', coords);
  181. sliderElem.dispatchEvent(touchStart);
  182. sliderElem.dispatchEvent(touchMove);
  183. sliderElem.dispatchEvent(touchEnd);
  184. });
  185. it("should slide the handle to the bottom from 5 to 7", function(done) {
  186. var sliderElem = $testSlider.slider('getElement');
  187. $testSlider.on('slideStop', function() {
  188. var value = $testSlider.slider('getValue');
  189. expect(value).toBe(7);
  190. done();
  191. });
  192. var tick = sliderInst.ticks[2]; // 5
  193. var sliderCoords = calcTouchEventCoords(sliderElem);
  194. var coords = [sliderCoords.x, sliderCoords.y + tick.offsetTop];
  195. touchStart = createTouchEvent(sliderElem, 'touchstart', coords);
  196. tick = sliderInst.ticks[3]; // 7
  197. coords = [sliderCoords.x, sliderCoords.y + tick.offsetTop];
  198. touchMove = createTouchEvent(sliderElem, 'touchmove', coords);
  199. touchEnd = createTouchEvent(sliderElem, 'touchend', coords);
  200. sliderElem.dispatchEvent(touchStart);
  201. sliderElem.dispatchEvent(touchMove);
  202. sliderElem.dispatchEvent(touchEnd);
  203. });
  204. });
  205. describe("range slider", function() {
  206. beforeEach(function() {
  207. sliderOptions.range = true;
  208. sliderOptions.value = [3, 7];
  209. // Initialize the slider
  210. $testSlider = $('#' + inputId).slider(sliderOptions);
  211. // Get slider instance
  212. sliderInst = $testSlider.data('slider');
  213. });
  214. // index= [0 1 2 3 4]
  215. // ticks= [0 3 5 7 10]
  216. it("should slide the first handle to the left from 3 to 0", function(done) {
  217. var sliderElem = $testSlider.slider('getElement');
  218. $testSlider.on('slideStop', function() {
  219. var value = $testSlider.slider('getValue');
  220. expect(value).toEqual([0, 7]);
  221. done();
  222. });
  223. var tick = sliderInst.ticks[1]; // 3
  224. var sliderCoords = calcTouchEventCoords(sliderElem);
  225. var coords = [sliderCoords.x + tick.offsetLeft, sliderCoords.y];
  226. touchStart = createTouchEvent(sliderElem, 'touchstart', coords);
  227. tick = sliderInst.ticks[0]; // 0
  228. coords = [sliderCoords.x + tick.offsetLeft, sliderCoords.y];
  229. touchMove = createTouchEvent(sliderElem, 'touchmove', coords);
  230. touchEnd = createTouchEvent(sliderElem, 'touchend', coords);
  231. sliderElem.dispatchEvent(touchStart);
  232. sliderElem.dispatchEvent(touchMove);
  233. sliderElem.dispatchEvent(touchEnd);
  234. });
  235. it("should slide the second handle to the right from 7 to 10", function(done) {
  236. var sliderElem = $testSlider.slider('getElement');
  237. $testSlider.on('slideStop', function() {
  238. var value = $testSlider.slider('getValue');
  239. expect(value).toEqual([3, 10]);
  240. done();
  241. });
  242. var tick = sliderInst.ticks[3]; // 7
  243. var sliderCoords = calcTouchEventCoords(sliderElem);
  244. var coords = [sliderCoords.x + tick.offsetLeft, sliderCoords.y];
  245. touchStart = createTouchEvent(sliderElem, 'touchstart', coords);
  246. tick = sliderInst.ticks[4]; // 10
  247. coords = [sliderCoords.x + tick.offsetLeft, sliderCoords.y];
  248. touchMove = createTouchEvent(sliderElem, 'touchmove', coords);
  249. touchEnd = createTouchEvent(sliderElem, 'touchend', coords);
  250. sliderElem.dispatchEvent(touchStart);
  251. sliderElem.dispatchEvent(touchMove);
  252. sliderElem.dispatchEvent(touchEnd);
  253. });
  254. });
  255. describe("range, vertical slider", function() {
  256. beforeEach(function() {
  257. sliderOptions.range = true;
  258. sliderOptions.value = [3, 7];
  259. sliderOptions.orientation = 'vertical';
  260. // Initialize the slider
  261. $testSlider = $('#' + inputId).slider(sliderOptions);
  262. // Get slider instance
  263. sliderInst = $testSlider.data('slider');
  264. });
  265. // index= [0 1 2 3 4]
  266. // ticks= [0 3 5 7 10]
  267. it("should slide the first handle to the top from 3 to 0", function(done) {
  268. var sliderElem = $testSlider.slider('getElement');
  269. $testSlider.on('slideStop', function() {
  270. var value = $testSlider.slider('getValue');
  271. expect(value).toEqual([0, 7]);
  272. done();
  273. });
  274. var tick = sliderInst.ticks[1]; // 3
  275. var sliderCoords = calcTouchEventCoords(sliderElem);
  276. var coords = [sliderCoords.x, sliderCoords.y + tick.offsetTop];
  277. touchStart = createTouchEvent(sliderElem, 'touchstart', coords);
  278. tick = sliderInst.ticks[0]; // 0
  279. coords = [sliderCoords.x, sliderCoords.y + tick.offsetTop];
  280. touchMove = createTouchEvent(sliderElem, 'touchmove', coords);
  281. touchEnd = createTouchEvent(sliderElem, 'touchend', coords);
  282. sliderElem.dispatchEvent(touchStart);
  283. sliderElem.dispatchEvent(touchMove);
  284. sliderElem.dispatchEvent(touchEnd);
  285. });
  286. it("should slide the second handle to the bottom from 7 to 10", function(done) {
  287. var sliderElem = $testSlider.slider('getElement');
  288. $testSlider.on('slideStop', function() {
  289. var value = $testSlider.slider('getValue');
  290. expect(value).toEqual([3, 10]);
  291. done();
  292. });
  293. var tick = sliderInst.ticks[3]; // 7
  294. var sliderCoords = calcTouchEventCoords(sliderElem);
  295. var coords = [sliderCoords.x, sliderCoords.y + tick.offsetTop];
  296. touchStart = createTouchEvent(sliderElem, 'touchstart', coords);
  297. tick = sliderInst.ticks[4]; // 10
  298. coords = [sliderCoords.x, sliderCoords.y + tick.offsetTop];
  299. touchMove = createTouchEvent(sliderElem, 'touchmove', coords);
  300. touchEnd = createTouchEvent(sliderElem, 'touchend', coords);
  301. sliderElem.dispatchEvent(touchStart);
  302. sliderElem.dispatchEvent(touchMove);
  303. sliderElem.dispatchEvent(touchEnd);
  304. });
  305. });
  306. describe("Tooltip tests", function() {
  307. var $tooltip;
  308. describe("single slider", function() {
  309. beforeEach(function() {
  310. // Initialize the slider
  311. $testSlider = $('#' + inputId).slider(sliderOptions);
  312. // Get slider instance
  313. sliderInst = $testSlider.data('slider');
  314. });
  315. // index= [0 1 2 3 4]
  316. // ticks= [0 3 5 7 10]
  317. it("should show the tooltip when touching the slider at value 5", function(done) {
  318. var sliderElem = $testSlider.slider('getElement');
  319. $tooltip = $(sliderElem).find('.tooltip.tooltip-main');
  320. /* Note: You can't use $testSlider.on('slideStart', function() {}) because jQuery
  321. * maintains its own list of event handlers and you may get unexpected results
  322. * when you add event handlers using $.on() versus DOM.addEventListener()
  323. * as they are called in a different order.
  324. *
  325. * The browser will call the event handlers registered with addEventListener()
  326. * in the order in which they are registered. For example, you'll get the following
  327. * execution order when listening for "touchstart" events.
  328. *
  329. * 1) _touchstart()
  330. * 2) _showTooltip()
  331. * 3) your event handler here
  332. */
  333. sliderElem.addEventListener('touchstart', function() {
  334. expect($tooltip.hasClass('in')).toBe(true);
  335. }, false);
  336. $testSlider.on('slideStop', function() {
  337. expect($tooltip.hasClass('in')).toBe(false);
  338. done();
  339. });
  340. var tick = sliderInst.ticks[2]; // 5
  341. var sliderCoords = calcTouchEventCoords(sliderElem);
  342. var coords = [sliderCoords.x + tick.offsetLeft, sliderCoords.y];
  343. touchStart = createTouchEvent(sliderElem, 'touchstart', coords);
  344. touchEnd = createTouchEvent(sliderElem, 'touchend', coords);
  345. sliderElem.dispatchEvent(touchStart);
  346. sliderElem.dispatchEvent(touchEnd);
  347. });
  348. });
  349. describe("range slider", function() {
  350. var touchStart2;
  351. beforeEach(function() {
  352. sliderOptions.range = true;
  353. sliderOptions.value = [3, 7];
  354. // Initialize the slider
  355. $testSlider = $('#' + inputId).slider(sliderOptions);
  356. // Get slider instance
  357. sliderInst = $testSlider.data('slider');
  358. });
  359. // index= [0 1 2 3 4]
  360. // ticks= [0 3 5 7 10]
  361. it("should show the tooltip when touching the slider at value 3 and 7", function(done) {
  362. var sliderElem = $testSlider.slider('getElement');
  363. $tooltip = $(sliderElem).find('.tooltip.tooltip-main');
  364. sliderElem.addEventListener('touchstart', function() {
  365. expect($tooltip.hasClass('in')).toBe(true);
  366. }, false);
  367. $testSlider.on('slideStop', function() {
  368. expect($tooltip.hasClass('in')).toBe(false);
  369. done();
  370. });
  371. var tick = sliderInst.ticks[1]; // 3
  372. var sliderCoords = calcTouchEventCoords(sliderElem);
  373. var coords = [sliderCoords.x + tick.offsetLeft, sliderCoords.y];
  374. touchStart = createTouchEvent(sliderElem, 'touchstart', coords);
  375. // For second handle
  376. tick = sliderInst.ticks[3]; // 7
  377. coords = [sliderCoords.x + tick.offsetLeft, sliderCoords.y];
  378. touchStart2 = createTouchEvent(sliderElem, 'touchstart', coords);
  379. touchEnd = createTouchEvent(sliderElem, 'touchend', coords);
  380. sliderElem.dispatchEvent(touchStart);
  381. sliderElem.dispatchEvent(touchStart2);
  382. sliderElem.dispatchEvent(touchEnd);
  383. });
  384. });
  385. });
  386. describe("Scrolling tests", function() {
  387. describe("horizontal sliding tests", function() {
  388. var horzScrollDiv;
  389. beforeEach(function() {
  390. // Initialize the slider
  391. $testSlider = $('#' + inputId).slider(sliderOptions);
  392. // Get slider instance
  393. sliderInst = $testSlider.data('slider');
  394. horzScrollDiv = document.getElementById('horz-scroll-div');
  395. });
  396. // index= [0 1 2 3 4]
  397. // ticks= [0 3 5 7 10]
  398. it("should not scroll the div horizontally while sliding the slider", function(done) {
  399. var sliderElem = $testSlider.slider('getElement');
  400. $testSlider.on('slideStop', function() {
  401. expect(horzScrollDiv.scrollLeft).toBe(0);
  402. done();
  403. });
  404. var tick = sliderInst.ticks[2]; // 5
  405. var sliderCoords = calcTouchEventCoords(sliderElem);
  406. var coords = [sliderCoords.x + tick.offsetLeft, sliderCoords.y];
  407. touchStart = createTouchEvent(sliderElem, 'touchstart', coords);
  408. tick = sliderInst.ticks[3]; // 7
  409. coords = [sliderCoords.x + tick.offsetLeft, sliderCoords.y];
  410. touchMove = createTouchEvent(sliderElem, 'touchmove', coords);
  411. touchEnd = createTouchEvent(sliderElem, 'touchend', coords);
  412. sliderElem.dispatchEvent(touchStart);
  413. sliderElem.dispatchEvent(touchMove);
  414. sliderElem.dispatchEvent(touchEnd);
  415. });
  416. });
  417. describe("vertical sliding tests", function() {
  418. var vertScrollDiv;
  419. beforeEach(function() {
  420. sliderOptions.orientation = 'vertical';
  421. // Initialize the slider
  422. $testSlider = $('#' + inputId).slider(sliderOptions);
  423. // Get slider instance
  424. sliderInst = $testSlider.data('slider');
  425. vertScrollDiv = document.getElementById('vert-scroll-div');
  426. });
  427. // index= [0 1 2 3 4]
  428. // ticks= [0 3 5 7 10]
  429. it("should not scroll the div vertically while sliding the slider", function(done) {
  430. var sliderElem = $testSlider.slider('getElement');
  431. $testSlider.on('slideStop', function() {
  432. expect(vertScrollDiv.scrollTop).toBe(0);
  433. done();
  434. });
  435. var tick = sliderInst.ticks[2]; // 5
  436. var sliderCoords = calcTouchEventCoords(sliderElem);
  437. var coords = [sliderCoords.x + tick.offsetLeft, sliderCoords.y];
  438. touchStart = createTouchEvent(sliderElem, 'touchstart', coords);
  439. tick = sliderInst.ticks[3]; // 7
  440. coords = [sliderCoords.x + tick.offsetLeft, sliderCoords.y];
  441. touchMove = createTouchEvent(sliderElem, 'touchmove', coords);
  442. touchEnd = createTouchEvent(sliderElem, 'touchend', coords);
  443. sliderElem.dispatchEvent(touchStart);
  444. sliderElem.dispatchEvent(touchMove);
  445. sliderElem.dispatchEvent(touchEnd);
  446. });
  447. });
  448. });
  449. });