common.js 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776
  1. export function sleep(delay = 100) {
  2. return Promise.resolve({
  3. then(resolve) {
  4. setTimeout(resolve, delay);
  5. }
  6. });
  7. }
  8. export function promisfy(fn) {
  9. return new Promise((resolve, reject) => fn(resolve, reject));
  10. }
  11. /**
  12. * Calls a method in current Handsontable instance, returns its output
  13. * @param method
  14. * @return {Function}
  15. */
  16. export function handsontableMethodFactory(method) {
  17. return function(...args) {
  18. let instance;
  19. try {
  20. instance = spec().$container.handsontable('getInstance');
  21. } catch (err) {
  22. /* eslint-disable */
  23. console.error(err);
  24. /* eslint-enable */
  25. }
  26. if (instance) {
  27. if (method === 'destroy') {
  28. spec().$container.removeData();
  29. }
  30. } else {
  31. if (method === 'destroy') {
  32. return; // we can forgive this... maybe it was destroyed in the test
  33. }
  34. throw new Error('Something wrong with the test spec: Handsontable instance not found');
  35. }
  36. return instance[method](...args);
  37. };
  38. }
  39. export const addHook = handsontableMethodFactory('addHook');
  40. export const alter = handsontableMethodFactory('alter');
  41. export const colToProp = handsontableMethodFactory('colToProp');
  42. export const countCols = handsontableMethodFactory('countCols');
  43. export const countEmptyCols = handsontableMethodFactory('countEmptyCols');
  44. export const countEmptyRows = handsontableMethodFactory('countEmptyRows');
  45. export const countRows = handsontableMethodFactory('countRows');
  46. export const countSourceCols = handsontableMethodFactory('countSourceCols');
  47. export const countSourceRows = handsontableMethodFactory('countSourceRows');
  48. export const deselectCell = handsontableMethodFactory('deselectCell');
  49. export const destroy = handsontableMethodFactory('destroy');
  50. export const destroyEditor = handsontableMethodFactory('destroyEditor');
  51. export const emptySelectedCells = handsontableMethodFactory('emptySelectedCells');
  52. export const getActiveEditor = handsontableMethodFactory('getActiveEditor');
  53. export const getCell = handsontableMethodFactory('getCell');
  54. export const getCellEditor = handsontableMethodFactory('getCellEditor');
  55. export const getCellMeta = handsontableMethodFactory('getCellMeta');
  56. export const getCellMetaAtRow = handsontableMethodFactory('getCellMetaAtRow');
  57. export const getCellRenderer = handsontableMethodFactory('getCellRenderer');
  58. export const getCellsMeta = handsontableMethodFactory('getCellsMeta');
  59. export const getCellValidator = handsontableMethodFactory('getCellValidator');
  60. export const getColHeader = handsontableMethodFactory('getColHeader');
  61. export const getCopyableData = handsontableMethodFactory('getCopyableData');
  62. export const getCopyableText = handsontableMethodFactory('getCopyableText');
  63. export const getData = handsontableMethodFactory('getData');
  64. export const getDataAtCell = handsontableMethodFactory('getDataAtCell');
  65. export const getDataAtCol = handsontableMethodFactory('getDataAtCol');
  66. export const getDataAtRow = handsontableMethodFactory('getDataAtRow');
  67. export const getDataAtRowProp = handsontableMethodFactory('getDataAtRowProp');
  68. export const getDataType = handsontableMethodFactory('getDataType');
  69. export const getInstance = handsontableMethodFactory('getInstance');
  70. export const getPlugin = handsontableMethodFactory('getPlugin');
  71. export const getRowHeader = handsontableMethodFactory('getRowHeader');
  72. export const getSelected = handsontableMethodFactory('getSelected');
  73. export const getSelectedLast = handsontableMethodFactory('getSelectedLast');
  74. export const getSelectedRange = handsontableMethodFactory('getSelectedRange');
  75. export const getSelectedRangeLast = handsontableMethodFactory('getSelectedRangeLast');
  76. export const getSourceData = handsontableMethodFactory('getSourceData');
  77. export const getSourceDataArray = handsontableMethodFactory('getSourceDataArray');
  78. export const getSourceDataAtCell = handsontableMethodFactory('getSourceDataAtCell');
  79. export const getSourceDataAtCol = handsontableMethodFactory('getSourceDataAtCol');
  80. export const getSourceDataAtRow = handsontableMethodFactory('getSourceDataAtRow');
  81. export const getValue = handsontableMethodFactory('getValue');
  82. export const loadData = handsontableMethodFactory('loadData');
  83. export const populateFromArray = handsontableMethodFactory('populateFromArray');
  84. export const propToCol = handsontableMethodFactory('propToCol');
  85. export const removeCellMeta = handsontableMethodFactory('removeCellMeta');
  86. export const render = handsontableMethodFactory('render');
  87. export const selectAll = handsontableMethodFactory('selectAll');
  88. export const selectCell = handsontableMethodFactory('selectCell');
  89. export const selectCells = handsontableMethodFactory('selectCells');
  90. export const selectColumns = handsontableMethodFactory('selectColumns');
  91. export const selectRows = handsontableMethodFactory('selectRows');
  92. export const setCellMeta = handsontableMethodFactory('setCellMeta');
  93. export const setDataAtCell = handsontableMethodFactory('setDataAtCell');
  94. export const setDataAtRowProp = handsontableMethodFactory('setDataAtRowProp');
  95. export const spliceCellsMeta = handsontableMethodFactory('spliceCellsMeta');
  96. export const spliceCol = handsontableMethodFactory('spliceCol');
  97. export const spliceRow = handsontableMethodFactory('spliceRow');
  98. export const updateSettings = handsontableMethodFactory('updateSettings');
  99. export const undo = handsontableMethodFactory('undo');
  100. const specContext = {};
  101. beforeEach(function() {
  102. specContext.spec = this;
  103. });
  104. afterEach(() => {
  105. specContext.spec = null;
  106. });
  107. export function spec() {
  108. return specContext.spec;
  109. }
  110. export function hot() {
  111. return spec().$container.data('handsontable');
  112. }
  113. export function handsontable(options) {
  114. const currentSpec = spec();
  115. currentSpec.$container.handsontable(options);
  116. currentSpec.$container[0].focus(); // otherwise TextEditor tests do not pass in IE8
  117. return currentSpec.$container.data('handsontable');
  118. }
  119. /**
  120. * As for v. 0.11 the only scrolling method is native scroll, which creates copies of main htCore table inside of the container.
  121. * Therefore, simple $(".htCore") will return more than one object. Most of the time, you're interested in the original
  122. * htCore, not the copies made by native scroll.
  123. *
  124. * This method returns the original htCore object
  125. *
  126. * @returns {jqObject} reference to the original htCore
  127. */
  128. export function getHtCore() {
  129. return spec().$container.find('.htCore').first();
  130. }
  131. export function getMaster() {
  132. return spec().$container.find('.ht_master');
  133. }
  134. export function getTopClone() {
  135. return spec().$container.find('.ht_clone_top');
  136. }
  137. export function getTopLeftClone() {
  138. return spec().$container.find('.ht_clone_top_left_corner');
  139. }
  140. // for compatybility
  141. // const getCornerClone = getTopLeftClone;
  142. export function getLeftClone() {
  143. return spec().$container.find('.ht_clone_left');
  144. }
  145. export function getBottomClone() {
  146. return spec().$container.find('.ht_clone_bottom');
  147. }
  148. export function getBottomLeftClone() {
  149. return spec().$container.find('.ht_clone_bottom_left_corner');
  150. }
  151. // Rename me to countTD
  152. export function countCells() {
  153. return getHtCore().find('tbody td').length;
  154. }
  155. export function isEditorVisible(editableElement) {
  156. if (editableElement && !(editableElement.hasClass('handsontableInput') || editableElement.hasClass('handsontableEditor'))) {
  157. throw new Error('Editable element of the editor was not found.');
  158. }
  159. const keyProxyHolder = (editableElement || keyProxy()).parent();
  160. if (keyProxyHolder.size() === 0) {
  161. return false;
  162. }
  163. const css = cssProp => keyProxyHolder.css(cssProp);
  164. return css('z-index') !== '-1' && css('top') !== '-9999px' && css('left') !== '-9999px';
  165. }
  166. export function isFillHandleVisible() {
  167. return !!spec().$container.find('.wtBorder.corner:visible').length;
  168. }
  169. export function getCorrespondingOverlay(cell, container) {
  170. const overlay = $(cell).parents('.handsontable');
  171. if (overlay[0] === container[0]) {
  172. return $('.ht_master');
  173. }
  174. return $(overlay[0]);
  175. }
  176. /**
  177. * Shows context menu
  178. */
  179. export function contextMenu(cell) {
  180. const hotInstance = spec().$container.data('handsontable');
  181. let clickedCell = cell;
  182. let selected = hotInstance.getSelectedLast();
  183. if (!selected) {
  184. hotInstance.selectCell(0, 0);
  185. selected = hotInstance.getSelectedLast();
  186. }
  187. if (!clickedCell) {
  188. clickedCell = getCell(selected[0], selected[1]);
  189. }
  190. const cellOffset = $(clickedCell).offset();
  191. $(clickedCell).simulate('mousedown', { button: 2 });
  192. $(clickedCell).simulate('contextmenu', {
  193. clientX: cellOffset.left - Handsontable.dom.getWindowScrollLeft(),
  194. clientY: cellOffset.top - Handsontable.dom.getWindowScrollTop(),
  195. });
  196. // Chrome doesn't call `mouseup`.
  197. // $(cell).simulate('mouseup', { button: 2 });
  198. }
  199. export function closeContextMenu() {
  200. $(document).simulate('mousedown');
  201. // $(document).trigger('mousedown');
  202. }
  203. /**
  204. * Shows dropdown menu
  205. */
  206. export function dropdownMenu(columnIndex) {
  207. const hotInstance = spec().$container.data('handsontable');
  208. const th = hotInstance.view.wt.wtTable.getColumnHeader(columnIndex || 0);
  209. const button = th.querySelector('.changeType');
  210. if (button) {
  211. $(button).simulate('mousedown');
  212. $(button).simulate('click');
  213. }
  214. }
  215. export function closeDropdownMenu() {
  216. $(document).simulate('mousedown');
  217. }
  218. export function dropdownMenuRootElement() {
  219. const plugin = hot().getPlugin('dropdownMenu');
  220. let root;
  221. if (plugin && plugin.menu) {
  222. root = plugin.menu.container;
  223. }
  224. return root;
  225. }
  226. /**
  227. * Returns a function that triggers a mouse event
  228. * @param {String} type Event type
  229. * @return {Function}
  230. */
  231. export function handsontableMouseTriggerFactory(type, button) {
  232. return function(element) {
  233. let handsontableElement = element;
  234. if (!(handsontableElement instanceof jQuery)) {
  235. handsontableElement = $(handsontableElement);
  236. }
  237. const ev = $.Event(type);
  238. ev.which = button || 1; // left click by default
  239. handsontableElement.simulate(type, ev);
  240. };
  241. }
  242. export const mouseDown = handsontableMouseTriggerFactory('mousedown');
  243. export const mouseMove = handsontableMouseTriggerFactory('mousemove');
  244. export const mouseOver = handsontableMouseTriggerFactory('mouseover');
  245. export const mouseUp = handsontableMouseTriggerFactory('mouseup');
  246. export function mouseDoubleClick(element) {
  247. mouseDown(element);
  248. mouseUp(element);
  249. mouseDown(element);
  250. mouseUp(element);
  251. }
  252. export const mouseRightDown = handsontableMouseTriggerFactory('mousedown', 3);
  253. export const mouseRightUp = handsontableMouseTriggerFactory('mouseup', 3);
  254. /**
  255. * Returns a function that triggers a key event
  256. * @param {String} type Event type
  257. * @return {Function}
  258. */
  259. export function handsontableKeyTriggerFactory(type) {
  260. return function(key, extend) {
  261. const ev = {}; // $.Event(type);
  262. let keyToTrigger = key;
  263. if (typeof keyToTrigger === 'string') {
  264. if (keyToTrigger.indexOf('shift+') > -1) {
  265. keyToTrigger = keyToTrigger.substring(6);
  266. ev.shiftKey = true;
  267. }
  268. if (keyToTrigger.indexOf('ctrl+') > -1) {
  269. keyToTrigger = keyToTrigger.substring(5);
  270. ev.ctrlKey = true;
  271. ev.metaKey = true;
  272. }
  273. switch (keyToTrigger) {
  274. case 'tab':
  275. ev.keyCode = 9;
  276. break;
  277. case 'enter':
  278. ev.keyCode = 13;
  279. break;
  280. case 'esc':
  281. ev.keyCode = 27;
  282. break;
  283. case 'f2':
  284. ev.keyCode = 113;
  285. break;
  286. case 'arrow_left':
  287. ev.keyCode = 37;
  288. break;
  289. case 'arrow_up':
  290. ev.keyCode = 38;
  291. break;
  292. case 'arrow_right':
  293. ev.keyCode = 39;
  294. break;
  295. case 'arrow_down':
  296. ev.keyCode = 40;
  297. break;
  298. case 'ctrl':
  299. if (window.navigator.platform.includes('Mac')) {
  300. ev.keyCode = 91;
  301. } else {
  302. ev.keyCode = 17;
  303. }
  304. break;
  305. case 'shift':
  306. ev.keyCode = 16;
  307. break;
  308. case 'backspace':
  309. ev.keyCode = 8;
  310. break;
  311. case 'delete':
  312. ev.keyCode = 46;
  313. break;
  314. case 'space':
  315. ev.keyCode = 32;
  316. break;
  317. case 'x':
  318. ev.keyCode = 88;
  319. break;
  320. case 'c':
  321. ev.keyCode = 67;
  322. break;
  323. case 'v':
  324. ev.keyCode = 86;
  325. break;
  326. case 'a':
  327. ev.keyCode = 65;
  328. break;
  329. default:
  330. throw new Error(`Unrecognised key name: ${keyToTrigger}`);
  331. }
  332. } else if (typeof keyToTrigger === 'number') {
  333. ev.keyCode = keyToTrigger;
  334. }
  335. // ev.originalEvent = {}; //needed as long Handsontable searches for event.originalEvent
  336. $.extend(ev, extend);
  337. $(document.activeElement).simulate(type, ev);
  338. };
  339. }
  340. export const keyDown = handsontableKeyTriggerFactory('keydown');
  341. export const keyUp = handsontableKeyTriggerFactory('keyup');
  342. /**
  343. * Presses keyDown, then keyUp
  344. */
  345. export function keyDownUp(key, extend) {
  346. if (typeof key === 'string' && key.indexOf('shift+') > -1) {
  347. keyDown('shift');
  348. }
  349. keyDown(key, extend);
  350. keyUp(key, extend);
  351. if (typeof key === 'string' && key.indexOf('shift+') > -1) {
  352. keyUp('shift');
  353. }
  354. }
  355. /**
  356. * Returns current value of the keyboard proxy textarea
  357. * @return {String}
  358. */
  359. export function keyProxy() {
  360. return spec().$container.find('textarea.handsontableInput');
  361. }
  362. export function serveImmediatePropagation(event) {
  363. if ((event !== null || event !== void 0)
  364. && (event.isImmediatePropagationEnabled === null || event.isImmediatePropagationEnabled === void 0)) {
  365. event.stopImmediatePropagation = function() {
  366. this.isImmediatePropagationEnabled = false;
  367. this.cancelBubble = true;
  368. };
  369. event.isImmediatePropagationEnabled = true;
  370. event.isImmediatePropagationStopped = function() {
  371. return !this.isImmediatePropagationEnabled;
  372. };
  373. }
  374. return event;
  375. }
  376. export function autocompleteEditor() {
  377. return spec().$container.find('.handsontableInput');
  378. }
  379. /**
  380. * Sets text cursor inside keyboard proxy
  381. */
  382. export function setCaretPosition(pos) {
  383. const el = keyProxy()[0];
  384. if (el.setSelectionRange) {
  385. el.focus();
  386. el.setSelectionRange(pos, pos);
  387. } else if (el.createTextRange) {
  388. const range = el.createTextRange();
  389. range.collapse(true);
  390. range.moveEnd('character', pos);
  391. range.moveStart('character', pos);
  392. range.select();
  393. }
  394. }
  395. /**
  396. * Returns autocomplete instance
  397. */
  398. export function autocomplete() {
  399. return spec().$container.find('.autocompleteEditor');
  400. }
  401. /**
  402. * Triggers paste string on current selection
  403. */
  404. export function triggerPaste(str) {
  405. spec().$container.data('handsontable').getPlugin('CopyPaste').paste(str);
  406. }
  407. /**
  408. * Returns column width for HOT container
  409. * @param $elem
  410. * @param col
  411. * @returns {Number}
  412. */
  413. export function colWidth($elem, col) {
  414. const TR = $elem[0].querySelector('TBODY TR');
  415. let cell;
  416. if (TR) {
  417. cell = TR.querySelectorAll('TD')[col];
  418. } else {
  419. cell = $elem[0].querySelector('THEAD TR').querySelectorAll('TH')[col];
  420. }
  421. if (!cell) {
  422. throw new Error(`Cannot find table column of index '${col}'`);
  423. }
  424. return cell.offsetWidth;
  425. }
  426. /**
  427. * Returns row height for HOT container
  428. * @param $elem
  429. * @param row
  430. * @returns {Number}
  431. */
  432. export function rowHeight($elem, row) {
  433. let TD;
  434. if (row >= 0) {
  435. TD = $elem[0].querySelector(`tbody tr:nth-child(${row + 1}) td`);
  436. } else {
  437. TD = $elem[0].querySelector(`thead tr:nth-child(${Math.abs(row)})`);
  438. }
  439. if (!TD) {
  440. throw new Error(`Cannot find table row of index '${row}'`);
  441. }
  442. return Handsontable.dom.outerHeight(TD);
  443. }
  444. /**
  445. * Returns value that has been rendered in table cell
  446. * @param {Number} trIndex
  447. * @param {Number} tdIndex
  448. * @returns {String}
  449. */
  450. export function getRenderedValue(trIndex, tdIndex) {
  451. return spec().$container.find('tbody tr').eq(trIndex).find('td').eq(tdIndex).html();
  452. }
  453. /**
  454. * Returns nodes that have been rendered in table cell
  455. * @param {Number} trIndex
  456. * @param {Number} tdIndex
  457. * @returns {String}
  458. */
  459. export function getRenderedContent(trIndex, tdIndex) {
  460. return spec().$container.find('tbody tr').eq(trIndex).find('td').eq(tdIndex).children();
  461. }
  462. /**
  463. * Create numerical data values for the table
  464. * @param rowCount
  465. * @param colCount
  466. * @returns {Array}
  467. */
  468. export function createNumericData(rowCount, colCount) {
  469. const rowsMax = typeof rowCount === 'number' ? rowCount : 100;
  470. const columnsMax = typeof colCount === 'number' ? colCount : 4;
  471. const rows = [];
  472. let i;
  473. let j;
  474. for (i = 0; i < rowsMax; i++) {
  475. const row = [];
  476. for (j = 0; j < columnsMax; j++) {
  477. row.push((i + 1));
  478. }
  479. rows.push(row);
  480. }
  481. return rows;
  482. }
  483. /**
  484. * Model factory, which creates object with private properties, accessible by setters and getters.
  485. * Created for the purpose of testing HOT with Backbone-like Models
  486. * @param opts
  487. * @returns {{}}
  488. * @constructor
  489. */
  490. export function Model(opts) {
  491. const obj = {};
  492. const _data = $.extend({
  493. id: undefined,
  494. name: undefined,
  495. address: undefined
  496. }, opts);
  497. obj.attr = function(name, value) {
  498. if (typeof value === 'undefined') {
  499. return this.get(name);
  500. }
  501. return this.set(name, value);
  502. };
  503. obj.get = function(name) {
  504. return _data[name];
  505. };
  506. obj.set = function(name, value) {
  507. _data[name] = value;
  508. return this;
  509. };
  510. return obj;
  511. }
  512. /**
  513. * Factory which produces an accessor for objects of type "Model" (see above).
  514. * This function should be used to create accessor for a given property name and pass it as `data` option in column
  515. * configuration.
  516. *
  517. * @param name - name of the property for which an accessor function will be created
  518. * @returns {Function}
  519. */
  520. export function createAccessorForProperty(name) {
  521. return function(obj, value) {
  522. return obj.attr(name, value);
  523. };
  524. }
  525. export function resizeColumn(displayedColumnIndex, width) {
  526. const $container = spec().$container;
  527. const $th = $container.find(`thead tr:eq(0) th:eq(${displayedColumnIndex})`);
  528. $th.simulate('mouseover');
  529. const $resizer = $container.find('.manualColumnResizer');
  530. const resizerPosition = $resizer.position();
  531. $resizer.simulate('mousedown', {
  532. clientX: resizerPosition.left,
  533. });
  534. const delta = width - $th.width() - 2;
  535. const newPosition = resizerPosition.left + delta;
  536. $resizer.simulate('mousemove', {
  537. clientX: newPosition
  538. });
  539. $resizer.simulate('mouseup');
  540. }
  541. export function resizeRow(displayedRowIndex, height) {
  542. const $container = spec().$container;
  543. const $th = $container.find(`tbody tr:eq(${displayedRowIndex}) th:eq(0)`);
  544. $th.simulate('mouseover');
  545. const $resizer = $container.find('.manualRowResizer');
  546. const resizerPosition = $resizer.position();
  547. $resizer.simulate('mousedown', {
  548. clientY: resizerPosition.top
  549. });
  550. let delta = height - $th.height() - 2;
  551. if (delta < 0) {
  552. delta = 0;
  553. }
  554. $resizer.simulate('mousemove', {
  555. clientY: resizerPosition.top + delta
  556. });
  557. $resizer.simulate('mouseup');
  558. }
  559. export function moveSecondDisplayedRowBeforeFirstRow(container, secondDisplayedRowIndex) {
  560. const $mainContainer = container.parents('.handsontable').not('[class*=clone]').not('[class*=master]').first();
  561. const $rowHeaders = container.find('tbody tr th');
  562. const $firstRowHeader = $rowHeaders.eq(secondDisplayedRowIndex - 1);
  563. const $secondRowHeader = $rowHeaders.eq(secondDisplayedRowIndex);
  564. $secondRowHeader.simulate('mouseover');
  565. const $manualRowMover = $mainContainer.find('.manualRowMover');
  566. if ($manualRowMover.length) {
  567. $manualRowMover.simulate('mousedown', {
  568. clientY: $manualRowMover[0].getBoundingClientRect().top
  569. });
  570. $manualRowMover.simulate('mousemove', {
  571. clientY: $manualRowMover[0].getBoundingClientRect().top - 20
  572. });
  573. $firstRowHeader.simulate('mouseover');
  574. $secondRowHeader.simulate('mouseup');
  575. }
  576. }
  577. export function moveFirstDisplayedRowAfterSecondRow(container, firstDisplayedRowIndex) {
  578. const $mainContainer = container.parents('.handsontable').not('[class*=clone]').not('[class*=master]').first();
  579. const $rowHeaders = container.find('tbody tr th');
  580. const $firstRowHeader = $rowHeaders.eq(firstDisplayedRowIndex);
  581. const $secondRowHeader = $rowHeaders.eq(firstDisplayedRowIndex + 1);
  582. $secondRowHeader.simulate('mouseover');
  583. const $manualRowMover = $mainContainer.find('.manualRowMover');
  584. if ($manualRowMover.length) {
  585. $manualRowMover.simulate('mousedown', {
  586. clientY: $manualRowMover[0].getBoundingClientRect().top
  587. });
  588. $manualRowMover.simulate('mousemove', {
  589. clientY: $manualRowMover[0].getBoundingClientRect().top + 20
  590. });
  591. $firstRowHeader.simulate('mouseover');
  592. $secondRowHeader.simulate('mouseup');
  593. }
  594. }
  595. export function swapDisplayedColumns(container, from, to) {
  596. const $mainContainer = container.parents('.handsontable').not('[class*=clone]').not('[class*=master]').first();
  597. const $colHeaders = container.find('thead tr:eq(0) th');
  598. const $to = $colHeaders.eq(to);
  599. const $from = $colHeaders.eq(from);
  600. // Enter the second column header
  601. $from.simulate('mouseover');
  602. const $manualColumnMover = $mainContainer.find('.manualColumnMover');
  603. // Grab the second column
  604. $manualColumnMover.simulate('mousedown', {
  605. pageX: $manualColumnMover[0].getBoundingClientRect().left,
  606. });
  607. // Drag the second column over the first column
  608. $manualColumnMover.simulate('mousemove', {
  609. pageX: $manualColumnMover[0].getBoundingClientRect().left - 20,
  610. });
  611. $to.simulate('mouseover');
  612. // Drop the second column
  613. $from.simulate('mouseup');
  614. }
  615. export function triggerTouchEvent(type, target, pageX, pageY) {
  616. const e = document.createEvent('TouchEvent');
  617. const targetCoords = target.getBoundingClientRect();
  618. const targetPageX = pageX || parseInt(targetCoords.left + 3, 10);
  619. const targetPageY = pageY || parseInt(targetCoords.top + 3, 10);
  620. let touches;
  621. let targetTouches;
  622. let changedTouches;
  623. const touch = document.createTouch(window, target, 0, targetPageX, targetPageY, targetPageX, targetPageY);
  624. if (type === 'touchend') {
  625. touches = document.createTouchList();
  626. targetTouches = document.createTouchList();
  627. changedTouches = document.createTouchList(touch);
  628. } else {
  629. touches = document.createTouchList(touch);
  630. targetTouches = document.createTouchList(touch);
  631. changedTouches = document.createTouchList(touch);
  632. }
  633. e.initTouchEvent(type, true, true, window, null, 0, 0, 0, 0, false, false, false, false, touches, targetTouches, changedTouches, 1, 0);
  634. target.dispatchEvent(e);
  635. }
  636. export function createSpreadsheetData(...args) {
  637. return Handsontable.helper.createSpreadsheetData(...args);
  638. }