4c4fa1c3de97da841efee63c0385f9a5f65b654fb88abfae62a903bc2ebf24242ea33bf96965f8a75db100a5343ccd8b6438d005130e45aed8c1cdf7cf223a 30 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105
  1. describe('Core_selection', () => {
  2. var id = 'testContainer';
  3. beforeEach(function() {
  4. this.$container = $(`<div id="${id}"></div>`).appendTo('body');
  5. });
  6. afterEach(function() {
  7. if (this.$container) {
  8. destroy();
  9. this.$container.remove();
  10. }
  11. });
  12. it('should call onSelection callback', () => {
  13. var output = null;
  14. handsontable({
  15. afterSelection(r, c) {
  16. output = [r, c];
  17. }
  18. });
  19. selectCell(1, 2);
  20. expect(output[0]).toEqual(1);
  21. expect(output[1]).toEqual(2);
  22. });
  23. it('should trigger selection event', () => {
  24. var output = null;
  25. handsontable();
  26. Handsontable.hooks.add('afterSelection', (r, c) => {
  27. output = [r, c];
  28. });
  29. selectCell(1, 2);
  30. expect(output[0]).toEqual(1);
  31. expect(output[1]).toEqual(2);
  32. });
  33. it('this.rootElement should point to handsontable rootElement (onSelection)', function() {
  34. var output = null;
  35. handsontable({
  36. afterSelection() {
  37. output = this.rootElement;
  38. }
  39. });
  40. selectCell(0, 0);
  41. expect(output).toEqual(this.$container[0]);
  42. });
  43. it('this.rootElement should point to handsontable rootElement (onSelectionByProp)', function() {
  44. var output = null;
  45. handsontable({
  46. afterSelectionByProp() {
  47. output = this.rootElement;
  48. }
  49. });
  50. selectCell(0, 0);
  51. expect(output).toEqual(this.$container[0]);
  52. });
  53. it('should focus external textarea when clicked during editing', () => {
  54. var textarea = $('<input type="text">').prependTo($('body'));
  55. handsontable();
  56. selectCell(0, 0);
  57. keyDown('enter');
  58. // $("html").triggerHandler('mouseup');
  59. $('html').simulate('mouseup');
  60. textarea.focus();
  61. expect(document.activeElement).toBe(textarea[0]);
  62. textarea.remove();
  63. });
  64. it('should deselect currently selected cell', () => {
  65. handsontable();
  66. selectCell(0, 0);
  67. $('html').simulate('mousedown');
  68. expect(getSelected()).toBeUndefined();
  69. });
  70. it('should not deselect the currently selected cell after clicking on a scrollbar', () => {
  71. var hot = handsontable({
  72. outsideClickDeselects: false,
  73. minRows: 20,
  74. minCols: 2,
  75. width: 400,
  76. height: 100
  77. });
  78. selectCell(0, 0);
  79. var holderBoundingBox = hot.view.wt.wtTable.holder.getBoundingClientRect(),
  80. verticalScrollbarCoords = {
  81. x: holderBoundingBox.left + holderBoundingBox.width - 3,
  82. y: holderBoundingBox.top + (holderBoundingBox.height / 2)
  83. },
  84. horizontalScrollbarCoords = {
  85. x: holderBoundingBox.left + (holderBoundingBox.width / 2),
  86. y: holderBoundingBox.top + holderBoundingBox.height - 3
  87. };
  88. $(hot.view.wt.wtTable.holder).simulate('mousedown', {
  89. clientX: verticalScrollbarCoords.x,
  90. clientY: verticalScrollbarCoords.y
  91. });
  92. expect(getSelected()).toEqual([0, 0, 0, 0]);
  93. $(hot.view.wt.wtTable.holder).simulate('mousedown', {
  94. clientX: horizontalScrollbarCoords.x,
  95. clientY: horizontalScrollbarCoords.y
  96. });
  97. expect(getSelected()).toEqual([0, 0, 0, 0]);
  98. });
  99. it('should not deselect currently selected cell', () => {
  100. handsontable({
  101. outsideClickDeselects: false
  102. });
  103. selectCell(0, 0);
  104. $('html').simulate('mousedown');
  105. expect(getSelected()).toEqual([0, 0, 0, 0]);
  106. });
  107. it('should allow to focus on external input and hold current selection informations', () => {
  108. var textarea = $('<input id="test_textarea" type="text">').prependTo($('body'));
  109. handsontable({
  110. outsideClickDeselects: false
  111. });
  112. selectCell(0, 0);
  113. textarea.simulate('mousedown');
  114. textarea.focus();
  115. expect(document.activeElement.id).toEqual('test_textarea');
  116. expect(getSelected()).toEqual([0, 0, 0, 0]);
  117. textarea.remove();
  118. });
  119. it('should allow to type in external input while holding current selection information', () => {
  120. var textarea = $('<textarea id="test_textarea"></textarea>').prependTo($('body'));
  121. var keyPressed;
  122. handsontable({
  123. outsideClickDeselects: false
  124. });
  125. selectCell(0, 0);
  126. textarea.focus();
  127. textarea.simulate('mousedown');
  128. textarea.simulate('mouseup');
  129. textarea.on('keydown', (event) => {
  130. keyPressed = event.keyCode;
  131. });
  132. var LETTER_A_KEY = 97;
  133. $(document.activeElement).simulate('keydown', {
  134. keyCode: LETTER_A_KEY
  135. });
  136. // textarea should receive the event and be an active element
  137. expect(keyPressed).toEqual(LETTER_A_KEY);
  138. expect(document.activeElement).toBe(document.getElementById('test_textarea'));
  139. // should preserve selection, close editor and save changes
  140. expect(getSelected()).toEqual([0, 0, 0, 0]);
  141. expect(getDataAtCell(0, 0)).toBeNull();
  142. textarea.remove();
  143. });
  144. it('should allow to type in external input after opening cell editor', () => {
  145. var textarea = $('<textarea id="test_textarea"></textarea>').prependTo($('body'));
  146. var keyPressed;
  147. handsontable({
  148. outsideClickDeselects: false
  149. });
  150. selectCell(0, 0);
  151. keyDown('enter');
  152. document.activeElement.value = 'Foo';
  153. textarea.focus();
  154. textarea.simulate('mousedown');
  155. textarea.simulate('mouseup');
  156. textarea.on('keydown', (event) => {
  157. keyPressed = event.keyCode;
  158. });
  159. var LETTER_A_KEY = 97;
  160. $(document.activeElement).simulate('keydown', {
  161. keyCode: LETTER_A_KEY
  162. });
  163. // textarea should receive the event and be an active element
  164. expect(keyPressed).toEqual(LETTER_A_KEY);
  165. expect(document.activeElement).toBe(document.getElementById('test_textarea'));
  166. // should preserve selection, close editor and save changes
  167. expect(getSelected()).toEqual([0, 0, 0, 0]);
  168. expect(getDataAtCell(0, 0)).toEqual('Foo');
  169. textarea.remove();
  170. });
  171. it('should deselect on outside click if outsideClickDeselects is a function that returns true', () => {
  172. var textarea = $('<textarea id="test_textarea"></textarea>').prependTo($('body'));
  173. var keyPressed;
  174. handsontable({
  175. outsideClickDeselects: () => true,
  176. });
  177. selectCell(0, 0);
  178. keyDown('enter');
  179. document.activeElement.value = 'Foo';
  180. textarea.focus();
  181. textarea.simulate('mousedown');
  182. textarea.simulate('mouseup');
  183. textarea.on('keydown', (event) => {
  184. keyPressed = event.keyCode;
  185. });
  186. var LETTER_A_KEY = 97;
  187. $(document.activeElement).simulate('keydown', {
  188. keyCode: LETTER_A_KEY
  189. });
  190. // textarea should receive the event and be an active element
  191. expect(keyPressed).toEqual(LETTER_A_KEY);
  192. expect(document.activeElement).toBe(document.getElementById('test_textarea'));
  193. // should NOT preserve selection
  194. expect(getSelected()).toEqual(undefined);
  195. expect(getDataAtCell(0, 0)).toEqual('Foo');
  196. textarea.remove();
  197. });
  198. it('should not deselect on outside click if outsideClickDeselects is a function that returns false', () => {
  199. var textarea = $('<textarea id="test_textarea"></textarea>').prependTo($('body'));
  200. var keyPressed;
  201. handsontable({
  202. outsideClickDeselects: () => false,
  203. });
  204. selectCell(0, 0);
  205. keyDown('enter');
  206. document.activeElement.value = 'Foo';
  207. textarea.focus();
  208. textarea.simulate('mousedown');
  209. textarea.simulate('mouseup');
  210. textarea.on('keydown', (event) => {
  211. keyPressed = event.keyCode;
  212. });
  213. var LETTER_A_KEY = 97;
  214. $(document.activeElement).simulate('keydown', {
  215. keyCode: LETTER_A_KEY
  216. });
  217. // textarea should receive the event and be an active element
  218. expect(keyPressed).toEqual(LETTER_A_KEY);
  219. expect(document.activeElement).toBe(document.getElementById('test_textarea'));
  220. // should preserve selection, close editor and save changes
  221. expect(getSelected()).toEqual([0, 0, 0, 0]);
  222. expect(getDataAtCell(0, 0)).toEqual('Foo');
  223. textarea.remove();
  224. });
  225. it('should fix start range if provided is out of bounds (to the left)', () => {
  226. handsontable({
  227. startRows: 5,
  228. startCols: 5
  229. });
  230. selectCell(0, 0);
  231. keyDownUp('arrow_left');
  232. expect(getSelected()).toEqual([0, 0, 0, 0]);
  233. });
  234. it('should fix start range if provided is out of bounds (to the top)', () => {
  235. handsontable({
  236. startRows: 5,
  237. startCols: 5
  238. });
  239. selectCell(0, 0);
  240. keyDownUp('arrow_up');
  241. expect(getSelected()).toEqual([0, 0, 0, 0]);
  242. });
  243. it('should fix start range if provided is out of bounds (to the right)', () => {
  244. handsontable({
  245. startRows: 5,
  246. startCols: 5
  247. });
  248. selectCell(0, 4);
  249. keyDownUp('arrow_right');
  250. expect(getSelected()).toEqual([0, 4, 0, 4]);
  251. });
  252. it('should fix start range if provided is out of bounds (to the bottom)', () => {
  253. handsontable({
  254. startRows: 5,
  255. startCols: 5
  256. });
  257. selectCell(4, 0);
  258. keyDownUp('arrow_down');
  259. expect(getSelected()).toEqual([4, 0, 4, 0]);
  260. });
  261. it('should fix end range if provided is out of bounds (to the left)', () => {
  262. handsontable({
  263. startRows: 5,
  264. startCols: 5
  265. });
  266. selectCell(0, 1);
  267. keyDownUp('shift+arrow_left');
  268. keyDownUp('shift+arrow_left');
  269. expect(getSelected()).toEqual([0, 1, 0, 0]);
  270. });
  271. it('should fix end range if provided is out of bounds (to the top)', () => {
  272. handsontable({
  273. startRows: 5,
  274. startCols: 5
  275. });
  276. selectCell(1, 0);
  277. keyDownUp('shift+arrow_up');
  278. keyDownUp('shift+arrow_up');
  279. expect(getSelected()).toEqual([1, 0, 0, 0]);
  280. });
  281. it('should fix end range if provided is out of bounds (to the right)', () => {
  282. handsontable({
  283. startRows: 5,
  284. startCols: 5
  285. });
  286. selectCell(0, 3);
  287. keyDownUp('shift+arrow_right');
  288. keyDownUp('shift+arrow_right');
  289. expect(getSelected()).toEqual([0, 3, 0, 4]);
  290. });
  291. it('should fix end range if provided is out of bounds (to the bottom)', () => {
  292. handsontable({
  293. startRows: 5,
  294. startCols: 5
  295. });
  296. selectCell(3, 0);
  297. keyDownUp('shift+arrow_down');
  298. keyDownUp('shift+arrow_down');
  299. keyDownUp('shift+arrow_down');
  300. expect(getSelected()).toEqual([3, 0, 4, 0]);
  301. });
  302. it('should select multiple cells', () => {
  303. handsontable({
  304. startRows: 5,
  305. startCols: 5
  306. });
  307. selectCell(3, 0, 4, 1);
  308. expect(getSelected()).toEqual([3, 0, 4, 1]);
  309. });
  310. it('should call onSelectionEnd as many times as onSelection when `selectCell` is called', () => {
  311. var tick = 0,
  312. tickEnd = 0;
  313. handsontable({
  314. startRows: 5,
  315. startCols: 5,
  316. afterSelection() {
  317. tick++;
  318. },
  319. afterSelectionEnd() {
  320. tickEnd++;
  321. }
  322. });
  323. selectCell(3, 0);
  324. selectCell(1, 1);
  325. expect(tick).toEqual(2);
  326. expect(tickEnd).toEqual(2);
  327. });
  328. it('should call onSelectionEnd when user finishes selection by releasing SHIFT key (3 times)', () => {
  329. var tick = 0;
  330. handsontable({
  331. startRows: 5,
  332. startCols: 5,
  333. afterSelectionEnd() {
  334. tick++;
  335. }
  336. });
  337. selectCell(3, 0); // makes tick++
  338. keyDownUp('shift+arrow_down'); // makes tick++
  339. keyDownUp('shift+arrow_down'); // makes tick++
  340. keyDownUp('shift+arrow_down'); // makes tick++
  341. expect(getSelected()).toEqual([3, 0, 4, 0]);
  342. expect(tick).toEqual(4);
  343. });
  344. it('should call onSelectionEnd when user finishes selection by releasing SHIFT key (1 time)', () => {
  345. var tick = 0;
  346. handsontable({
  347. startRows: 5,
  348. startCols: 5,
  349. afterSelectionEnd() {
  350. tick++;
  351. }
  352. });
  353. selectCell(3, 0); // makes tick++
  354. keyDown('shift+arrow_down');
  355. keyDown('shift+arrow_down');
  356. keyDownUp('shift+arrow_down'); // makes tick++
  357. expect(getSelected()).toEqual([3, 0, 4, 0]);
  358. expect(tick).toEqual(2);
  359. });
  360. it('should select columns by click on header with SHIFT key', function() {
  361. handsontable({
  362. startRows: 5,
  363. startCols: 5,
  364. colHeaders: true
  365. });
  366. this.$container.find('.ht_clone_top tr:eq(0) th:eq(1)').simulate('mousedown');
  367. this.$container.find('.ht_clone_top tr:eq(0) th:eq(1)').simulate('mouseup');
  368. this.$container.find('.ht_clone_top tr:eq(0) th:eq(4)').simulate('mousedown', {shiftKey: true});
  369. this.$container.find('.ht_clone_top tr:eq(0) th:eq(4)').simulate('mouseup');
  370. expect(getSelected()).toEqual([0, 1, 4, 4]);
  371. });
  372. it('should select rows by click on header with SHIFT key', function() {
  373. handsontable({
  374. startRows: 5,
  375. startCols: 5,
  376. rowHeaders: true
  377. });
  378. this.$container.find('.ht_clone_left tr:eq(1) th:eq(0)').simulate('mousedown');
  379. this.$container.find('.ht_clone_left tr:eq(1) th:eq(0)').simulate('mouseup');
  380. this.$container.find('.ht_clone_left tr:eq(4) th:eq(0)').simulate('mousedown', {shiftKey: true});
  381. this.$container.find('.ht_clone_left tr:eq(4) th:eq(0)').simulate('mouseup');
  382. expect(getSelected()).toEqual([1, 0, 4, 4]);
  383. });
  384. it('should select columns by click on header with SHIFT key', function() {
  385. handsontable({
  386. startRows: 5,
  387. startCols: 5,
  388. colHeaders: true
  389. });
  390. this.$container.find('.ht_clone_top tr:eq(0) th:eq(1)').simulate('mousedown');
  391. this.$container.find('.ht_clone_top tr:eq(0) th:eq(1)').simulate('mouseup');
  392. this.$container.find('.ht_clone_top tr:eq(0) th:eq(4)').simulate('mousedown', {shiftKey: true});
  393. this.$container.find('.ht_clone_top tr:eq(0) th:eq(4)').simulate('mouseup');
  394. expect(getSelected()).toEqual([0, 1, 4, 4]);
  395. });
  396. it('should change selection after click on row header with SHIFT key', function() {
  397. handsontable({
  398. startRows: 5,
  399. startCols: 5,
  400. rowHeaders: true
  401. });
  402. selectCell(1, 1, 3, 3);
  403. this.$container.find('.ht_clone_left tr:eq(4) th:eq(0)').simulate('mousedown', {shiftKey: true});
  404. this.$container.find('.ht_clone_left tr:eq(4) th:eq(0)').simulate('mouseup');
  405. expect(getSelected()).toEqual([1, 0, 4, 4]);
  406. });
  407. it('should change selection after click on column header with SHIFT key', function() {
  408. handsontable({
  409. startRows: 5,
  410. startCols: 5,
  411. colHeaders: true
  412. });
  413. selectCell(1, 1, 3, 3);
  414. this.$container.find('.ht_clone_top tr:eq(0) th:eq(4)').simulate('mousedown', {shiftKey: true});
  415. this.$container.find('.ht_clone_top tr:eq(0) th:eq(4)').simulate('mouseup');
  416. expect(getSelected()).toEqual([0, 1, 4, 4]);
  417. });
  418. it('should call onSelection while user selects cells with mouse; onSelectionEnd when user finishes selection', function() {
  419. var tick = 0,
  420. tickEnd = 0;
  421. handsontable({
  422. startRows: 5,
  423. startCols: 5,
  424. afterSelection() {
  425. tick++;
  426. },
  427. afterSelectionEnd() {
  428. tickEnd++;
  429. }
  430. });
  431. this.$container.find('tr:eq(0) td:eq(0)').simulate('mousedown');
  432. this.$container.find('tr:eq(0) td:eq(1)').simulate('mouseover');
  433. this.$container.find('tr:eq(1) td:eq(3)').simulate('mouseover');
  434. this.$container.find('tr:eq(1) td:eq(3)').simulate('mouseup');
  435. expect(getSelected()).toEqual([0, 0, 1, 3]);
  436. expect(tick).toEqual(3);
  437. expect(tickEnd).toEqual(1);
  438. });
  439. it('should properly select columns, when the user moves the cursor over column headers across two overlays', function() {
  440. handsontable({
  441. startRows: 5,
  442. startCols: 5,
  443. colHeaders: true,
  444. fixedColumnsLeft: 2
  445. });
  446. this.$container.find('.ht_clone_left tr:eq(0) th:eq(1)').simulate('mousedown');
  447. this.$container.find('.ht_clone_left tr:eq(0) th:eq(1)').simulate('mouseover');
  448. this.$container.find('.ht_clone_top tr:eq(0) th:eq(2)').simulate('mouseover');
  449. this.$container.find('.ht_clone_left tr:eq(0) th:eq(1)').simulate('mouseover');
  450. this.$container.find('.ht_clone_left tr:eq(0) th:eq(1)').simulate('mouseup');
  451. expect(getSelected()).toEqual([0, 1, 4, 1]);
  452. });
  453. it('should move focus to selected cell', () => {
  454. var $input = $('<input>').appendTo(document.body);
  455. handsontable({
  456. startRows: 5,
  457. startCols: 5
  458. });
  459. $input[0].focus();
  460. selectCell(0, 0);
  461. keyDownUp('enter');
  462. expect(isEditorVisible()).toEqual(true);
  463. $input.remove();
  464. });
  465. // This test should cover the #893 case, but it always passes. It seems like the keydown event (with CTRL key pressed) isn't delivered.
  466. it('should not move focus from outside elements on CTRL keydown event, when no cell is selected', () => {
  467. var $input = $('<input type="text"/>');
  468. $('body').append($input);
  469. handsontable();
  470. selectCell(0, 0);
  471. expect(document.activeElement.nodeName).toBeInArray(['BODY', 'HTML']);
  472. $input.focus();
  473. expect(document.activeElement.nodeName).toBe('INPUT');
  474. // var keyDownEvent = $.Event('keydown', {ctrlKey: true, metaKey: true});
  475. // $input.trigger(keyDownEvent);
  476. $input.simulate('keydown', {ctrlKey: true, metaKey: true});
  477. expect(document.activeElement.nodeName).toBe('INPUT');
  478. $input.remove();
  479. });
  480. it('should select the entire column after column header is clicked', function() {
  481. var hot = handsontable({
  482. width: 200,
  483. height: 100,
  484. startRows: 50,
  485. startCols: 5,
  486. colHeaders: true
  487. });
  488. this.$container.find('thead th:eq(0)').simulate('mousedown');
  489. expect(getSelected()).toEqual([0, 0, 49, 0]);
  490. expect(hot.selection.selectedHeader.rows).toBe(false);
  491. expect(hot.selection.selectedHeader.cols).toBe(true);
  492. expect(hot.selection.selectedHeader.corner).toBe(false);
  493. });
  494. it('should add classname after select column', function() {
  495. var hot = handsontable({
  496. width: 200,
  497. height: 100,
  498. startRows: 50,
  499. startCols: 5,
  500. colHeaders: true
  501. });
  502. this.$container.find('thead th:eq(0)').simulate('mousedown');
  503. expect(this.$container.hasClass('ht__selection--columns')).toBeTruthy();
  504. });
  505. it('should select the entire column after column header is clicked (in fixed rows/cols corner)', function() {
  506. var hot = handsontable({
  507. width: 200,
  508. height: 100,
  509. startRows: 50,
  510. startCols: 5,
  511. colHeaders: true,
  512. rowHeaders: true,
  513. fixedRowsTop: 2,
  514. fixedColumnsLeft: 2
  515. });
  516. this.$container.find('.ht_master thead th:eq(1)').simulate('mousedown');
  517. expect(getSelected()).toEqual([0, 0, 49, 0]);
  518. expect(hot.selection.selectedHeader.rows).toBe(false);
  519. expect(hot.selection.selectedHeader.cols).toBe(true);
  520. expect(hot.selection.selectedHeader.corner).toBe(false);
  521. });
  522. it('should select the entire fixed column after column header is clicked, after scroll horizontally', function() {
  523. var hot = handsontable({
  524. width: 200,
  525. height: 100,
  526. startRows: 50,
  527. startCols: 50,
  528. colHeaders: true,
  529. rowHeaders: true,
  530. fixedColumnsLeft: 2
  531. });
  532. hot.render();
  533. hot.view.wt.scrollHorizontal(20);
  534. this.$container.find('.ht_master thead th:eq(2)').simulate('mousedown');
  535. this.$container.find('.ht_master thead th:eq(2)').simulate('mouseup');
  536. expect(getSelected()).toEqual([0, 1, 49, 1]);
  537. expect(hot.selection.selectedHeader.rows).toBe(false);
  538. expect(hot.selection.selectedHeader.cols).toBe(true);
  539. expect(hot.selection.selectedHeader.corner).toBe(false);
  540. });
  541. it('should set the selection end to the first visible row, when dragging the selection from a cell to a column header', (done) => {
  542. var hot = handsontable({
  543. width: 200,
  544. height: 200,
  545. startRows: 20,
  546. startCols: 20,
  547. colHeaders: true,
  548. rowHeaders: true
  549. });
  550. hot.view.wt.scrollVertical(10);
  551. hot.view.wt.scrollHorizontal(10);
  552. hot.render();
  553. setTimeout(() => {
  554. $(getCell(12, 11)).simulate('mousedown');
  555. spec().$container.find('.ht_clone_top thead th:eq(2)').simulate('mouseover');
  556. }, 30);
  557. setTimeout(() => {
  558. expect(getSelected()).toEqual([12, 11, 10, 11]);
  559. done();
  560. }, 60);
  561. });
  562. it('should set the selection end to the first visible column, when dragging the selection from a cell to a row header', (done) => {
  563. var hot = handsontable({
  564. width: 200,
  565. height: 200,
  566. startRows: 20,
  567. startCols: 20,
  568. colHeaders: true,
  569. rowHeaders: true
  570. });
  571. hot.view.wt.scrollVertical(10);
  572. hot.view.wt.scrollHorizontal(10);
  573. hot.render();
  574. setTimeout(() => {
  575. $(getCell(12, 11)).simulate('mousedown');
  576. spec().$container.find('.ht_clone_left tbody th:eq(12)').simulate('mouseover');
  577. }, 30);
  578. setTimeout(() => {
  579. expect(getSelected()).toEqual([12, 11, 12, 10]);
  580. done();
  581. }, 60);
  582. });
  583. it('should allow to scroll the table when a whole column is selected and table is longer than it\'s container', function(done) {
  584. var errCount = 0;
  585. $(window).on('error.selectionTest', () => {
  586. errCount++;
  587. });
  588. var onAfterScrollVertically = jasmine.createSpy('onAfterScrollVertically');
  589. var hot = handsontable({
  590. height: 100,
  591. width: 300,
  592. startRows: 100,
  593. startCols: 5,
  594. colHeaders: true,
  595. rowHeaders: true,
  596. afterScrollVertically: onAfterScrollVertically
  597. });
  598. var mainHolder = hot.view.wt.wtTable.holder;
  599. mainHolder.scrollTop = 0;
  600. this.$container.find('thead tr:eq(0) th:eq(2)').simulate('mousedown');
  601. this.$container.find('thead tr:eq(0) th:eq(2)').simulate('mouseup');
  602. mainHolder.scrollTop = 120;
  603. setTimeout(() => {
  604. expect(errCount).toEqual(0); // expect no errors to be thrown
  605. $(window).off('error.selectionTest');
  606. done();
  607. }, 100);
  608. });
  609. it('should scroll to the end of the selection, when selecting cells using the keyboard', () => {
  610. var hot = handsontable({
  611. height: 300,
  612. width: 300,
  613. startRows: 50,
  614. startCols: 50,
  615. colHeaders: true,
  616. rowHeaders: true,
  617. fixedRowsTop: 2,
  618. fixedColumnsLeft: 2
  619. });
  620. var mainHolder = hot.view.wt.wtTable.holder;
  621. mainHolder.scrollTop = 100;
  622. selectCell(1, 3);
  623. keyDownUp('arrow_down');
  624. expect(mainHolder.scrollTop).toEqual(0);
  625. mainHolder.scrollTop = 100;
  626. selectCell(1, 3);
  627. keyDownUp('shift+arrow_down');
  628. expect(mainHolder.scrollTop).toEqual(0);
  629. mainHolder.scrollLeft = 100;
  630. selectCell(3, 1);
  631. keyDownUp('arrow_right');
  632. expect(mainHolder.scrollLeft).toEqual(0);
  633. mainHolder.scrollLeft = 100;
  634. selectCell(3, 1);
  635. keyDownUp('shift+arrow_right');
  636. expect(mainHolder.scrollLeft).toEqual(0);
  637. var lastVisibleColumn = hot.view.wt.wtTable.getLastVisibleColumn();
  638. selectCell(3, lastVisibleColumn);
  639. keyDownUp('arrow_right');
  640. expect(hot.view.wt.wtTable.getLastVisibleColumn()).toEqual(lastVisibleColumn + 1);
  641. keyDownUp('arrow_right');
  642. expect(hot.view.wt.wtTable.getLastVisibleColumn()).toEqual(lastVisibleColumn + 2);
  643. keyDownUp('shift+arrow_right');
  644. expect(hot.view.wt.wtTable.getLastVisibleColumn()).toEqual(lastVisibleColumn + 3);
  645. var lastVisibleRow = hot.view.wt.wtTable.getLastVisibleRow();
  646. selectCell(lastVisibleRow, 3);
  647. keyDownUp('arrow_down');
  648. expect(hot.view.wt.wtTable.getLastVisibleRow()).toEqual(lastVisibleRow + 1);
  649. keyDownUp('arrow_down');
  650. expect(hot.view.wt.wtTable.getLastVisibleRow()).toEqual(lastVisibleRow + 2);
  651. keyDownUp('shift+arrow_down');
  652. expect(hot.view.wt.wtTable.getLastVisibleRow()).toEqual(lastVisibleRow + 3);
  653. });
  654. it('should select the entire row after row header is clicked', function() {
  655. var hot = handsontable({
  656. startRows: 5,
  657. startCols: 5,
  658. colHeaders: true,
  659. rowHeaders: true
  660. });
  661. this.$container.find('tr:eq(2) th:eq(0)').simulate('mousedown');
  662. expect(getSelected()).toEqual([1, 0, 1, 4]);
  663. expect(hot.selection.selectedHeader.rows).toBe(true);
  664. expect(hot.selection.selectedHeader.cols).toBe(false);
  665. expect(hot.selection.selectedHeader.corner).toBe(false);
  666. });
  667. it('should add classname after select row', function() {
  668. var hot = handsontable({
  669. width: 200,
  670. height: 100,
  671. startRows: 50,
  672. startCols: 5,
  673. rowHeaders: true
  674. });
  675. this.$container.find('tbody tr:eq(0) th:eq(0)').simulate('mousedown');
  676. expect(this.$container.hasClass('ht__selection--rows')).toBeTruthy();
  677. });
  678. it('should select the entire row of a partially fixed table after row header is clicked', function() {
  679. handsontable({
  680. startRows: 5,
  681. startCols: 5,
  682. colHeaders: true,
  683. rowHeaders: true,
  684. fixedRowsTop: 2,
  685. fixedColumnsLeft: 2
  686. });
  687. this.$container.find('tr:eq(2) th:eq(0)').simulate('mousedown');
  688. expect(getSelected()).toEqual([1, 0, 1, 4]);
  689. this.$container.find('tr:eq(3) th:eq(0)').simulate('mousedown');
  690. expect(getSelected()).toEqual([2, 0, 2, 4]);
  691. });
  692. it('should select a cell in a newly added row after automatic row adding, triggered by editing a cell in the last row with minSpareRows > 0, ' +
  693. 'unless editing happened within the fixed bottom rows', (done) => {
  694. var hot = handsontable({
  695. startRows: 5,
  696. startCols: 2,
  697. minSpareRows: 1
  698. });
  699. setTimeout(() => {
  700. selectCell(4, 0);
  701. keyDownUp('enter');
  702. }, 10);
  703. setTimeout(() => {
  704. keyDownUp('enter');
  705. }, 100);
  706. setTimeout(() => {
  707. expect(countRows()).toEqual(6);
  708. expect(getSelected()).toEqual([5, 0, 5, 0]);
  709. }, 200);
  710. setTimeout(() => {
  711. done();
  712. }, 250);
  713. });
  714. it('should change selected coords by modifying coords object via `modifyTransformStart` hook', () => {
  715. var hot = handsontable({
  716. startRows: 5,
  717. startCols: 5
  718. });
  719. selectCell(0, 0);
  720. hot.addHook('modifyTransformStart', (coords) => {
  721. coords.col += 1;
  722. coords.row += 1;
  723. });
  724. keyDown('arrow_down');
  725. expect(getSelected()).toEqual([2, 1, 2, 1]);
  726. });
  727. it('should change selected coords by modifying coords object via `modifyTransformEnd` hook', () => {
  728. var hot = handsontable({
  729. startRows: 5,
  730. startCols: 5
  731. });
  732. selectCell(0, 0);
  733. hot.addHook('modifyTransformEnd', (coords) => {
  734. coords.col += 2;
  735. coords.row += 1;
  736. });
  737. keyDown('shift+arrow_down');
  738. expect(getSelected()).toEqual([0, 0, 2, 2]);
  739. });
  740. it('should indicate is coords is out of bounds via `afterModifyTransformStart` hook', () => {
  741. var spy = jasmine.createSpy();
  742. var hot = handsontable({
  743. startRows: 5,
  744. startCols: 5
  745. });
  746. hot.addHook('afterModifyTransformStart', spy);
  747. selectCell(2, 0);
  748. keyDownUp('arrow_left');
  749. expect(spy.calls.mostRecent().args[1]).toBe(0);
  750. expect(spy.calls.mostRecent().args[2]).toBe(-1);
  751. spy.calls.reset();
  752. selectCell(2, 4);
  753. keyDownUp('arrow_right');
  754. expect(spy.calls.mostRecent().args[1]).toBe(0);
  755. expect(spy.calls.mostRecent().args[2]).toBe(1);
  756. spy.calls.reset();
  757. selectCell(4, 2);
  758. keyDownUp('arrow_down');
  759. expect(spy.calls.mostRecent().args[1]).toBe(1);
  760. expect(spy.calls.mostRecent().args[2]).toBe(0);
  761. spy.calls.reset();
  762. selectCell(0, 2);
  763. keyDownUp('arrow_up');
  764. expect(spy.calls.mostRecent().args[1]).toBe(-1);
  765. expect(spy.calls.mostRecent().args[2]).toBe(0);
  766. });
  767. it('should indicate is coords is out of bounds via `afterModifyTransformEnd` hook', () => {
  768. var spy = jasmine.createSpy();
  769. var hot = handsontable({
  770. startRows: 5,
  771. startCols: 5
  772. });
  773. hot.addHook('afterModifyTransformEnd', spy);
  774. selectCell(2, 0);
  775. keyDownUp('shift+arrow_left');
  776. expect(spy.calls.mostRecent().args[1]).toBe(0);
  777. expect(spy.calls.mostRecent().args[2]).toBe(-1);
  778. spy.calls.reset();
  779. selectCell(2, 4);
  780. keyDownUp('shift+arrow_right');
  781. expect(spy.calls.mostRecent().args[1]).toBe(0);
  782. expect(spy.calls.mostRecent().args[2]).toBe(1);
  783. spy.calls.reset();
  784. selectCell(4, 2);
  785. keyDownUp('shift+arrow_down');
  786. expect(spy.calls.mostRecent().args[1]).toBe(1);
  787. expect(spy.calls.mostRecent().args[2]).toBe(0);
  788. spy.calls.reset();
  789. selectCell(0, 2);
  790. keyDownUp('shift+arrow_up');
  791. expect(spy.calls.mostRecent().args[1]).toBe(-1);
  792. expect(spy.calls.mostRecent().args[2]).toBe(0);
  793. });
  794. it('should change selection after left mouse button on one of selected cell', () => {
  795. var hot = handsontable({
  796. startRows: 5,
  797. startCols: 5
  798. });
  799. var cells = $('.ht_master.handsontable td');
  800. cells.eq(6).simulate('mousedown');
  801. cells.eq(18).simulate('mouseover');
  802. cells.eq(18).simulate('mouseup');
  803. expect(hot.getSelected()).toEqual([1, 1, 3, 3]);
  804. cells.eq(16).simulate('mousedown');
  805. cells.eq(16).simulate('mouseup');
  806. expect(hot.getSelected()).toEqual([3, 1, 3, 1]);
  807. });
  808. it('should select the first row after corner header is clicked', function() {
  809. var hot = handsontable({
  810. startRows: 5,
  811. startCols: 5,
  812. colHeaders: true,
  813. rowHeaders: true
  814. });
  815. this.$container.find('thead').find('th').eq(0).simulate('mousedown');
  816. expect(getSelected()).toEqual([0, 0, 0, 0]);
  817. expect(hot.selection.selectedHeader.rows).toBe(false);
  818. expect(hot.selection.selectedHeader.cols).toBe(false);
  819. expect(hot.selection.selectedHeader.corner).toBe(true);
  820. });
  821. it('should redraw selection when option `colHeaders` is set and user scrolled', function (done) {
  822. var hot = handsontable({
  823. startRows: 20,
  824. startCols: 20,
  825. colHeaders: true,
  826. rowHeaders: true,
  827. width: 400,
  828. height: 200
  829. });
  830. var cellVerticalPosition;
  831. var borderOffsetInPixels = 1;
  832. var topBorder;
  833. selectCell(5, 5);
  834. hot.view.wt.wtOverlays.topOverlay.scrollTo(2);
  835. setTimeout(function () {
  836. cellVerticalPosition = hot.getCell(5, 5).offsetTop;
  837. topBorder = $('.wtBorder.current')[0];
  838. expect(topBorder.offsetTop).toEqual(cellVerticalPosition - borderOffsetInPixels);
  839. hot.view.wt.wtOverlays.topOverlay.scrollTo(0);
  840. }, 100);
  841. setTimeout(function () {
  842. cellVerticalPosition = hot.getCell(5, 5).offsetTop;
  843. topBorder = $('.wtBorder.current')[0];
  844. expect(topBorder.offsetTop).toEqual(cellVerticalPosition - borderOffsetInPixels);
  845. done();
  846. }, 200);
  847. });
  848. it('should redraw selection on `leftOverlay` when options `colHeaders` and `fixedColumnsLeft` are set, and user scrolled', function (done) {
  849. var hot = handsontable({
  850. fixedColumnsLeft: 2,
  851. startRows: 20,
  852. startCols: 20,
  853. colHeaders: true,
  854. rowHeaders: true,
  855. width: 400,
  856. height: 200
  857. });
  858. var cellVerticalPosition;
  859. var borderOffsetInPixels = 1;
  860. var topBorder;
  861. selectCell(1, 0);
  862. hot.view.wt.wtOverlays.topOverlay.scrollTo(5);
  863. setTimeout(function () {
  864. cellVerticalPosition = hot.getCell(1, 0).offsetTop;
  865. topBorder = $('.wtBorder.current')[0];
  866. expect(topBorder.offsetTop).toEqual(cellVerticalPosition - borderOffsetInPixels);
  867. hot.view.wt.wtOverlays.topOverlay.scrollTo(0);
  868. }, 100);
  869. setTimeout(function () {
  870. cellVerticalPosition = hot.getCell(1, 0).offsetTop;
  871. topBorder = $('.wtBorder.current')[0];
  872. expect(topBorder.offsetTop).toEqual(cellVerticalPosition - borderOffsetInPixels);
  873. done();
  874. }, 200);
  875. });
  876. });