mergeCells.js 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637
  1. import Hooks from './../../pluginHooks';
  2. import { registerPlugin } from './../../plugins';
  3. import { stopImmediatePropagation } from './../../helpers/dom/event';
  4. import { CellCoords, CellRange, Table } from './../../3rdparty/walkontable/src';
  5. function CellInfoCollection() {
  6. var collection = [];
  7. collection.getInfo = function (row, col) {
  8. for (var i = 0, ilen = this.length; i < ilen; i++) {
  9. if (this[i].row <= row && this[i].row + this[i].rowspan - 1 >= row && this[i].col <= col && this[i].col + this[i].colspan - 1 >= col) {
  10. return this[i];
  11. }
  12. }
  13. };
  14. collection.setInfo = function (info) {
  15. for (var i = 0, ilen = this.length; i < ilen; i++) {
  16. if (this[i].row === info.row && this[i].col === info.col) {
  17. this[i] = info;
  18. return;
  19. }
  20. }
  21. this.push(info);
  22. };
  23. collection.removeInfo = function (row, col) {
  24. for (var i = 0, ilen = this.length; i < ilen; i++) {
  25. if (this[i].row === row && this[i].col === col) {
  26. this.splice(i, 1);
  27. break;
  28. }
  29. }
  30. };
  31. return collection;
  32. }
  33. /**
  34. * Plugin used to merge cells in Handsontable.
  35. *
  36. * @private
  37. * @plugin MergeCells
  38. * @class MergeCells
  39. */
  40. function MergeCells(mergeCellsSetting) {
  41. this.mergedCellInfoCollection = new CellInfoCollection();
  42. if (Array.isArray(mergeCellsSetting)) {
  43. for (var i = 0, ilen = mergeCellsSetting.length; i < ilen; i++) {
  44. this.mergedCellInfoCollection.setInfo(mergeCellsSetting[i]);
  45. }
  46. }
  47. }
  48. /**
  49. * @param cellRange (CellRange)
  50. */
  51. MergeCells.prototype.canMergeRange = function (cellRange) {
  52. // is more than one cell selected
  53. return !cellRange.isSingle();
  54. };
  55. MergeCells.prototype.mergeRange = function (cellRange) {
  56. if (!this.canMergeRange(cellRange)) {
  57. return;
  58. }
  59. // normalize top left corner
  60. var topLeft = cellRange.getTopLeftCorner();
  61. var bottomRight = cellRange.getBottomRightCorner();
  62. var mergeParent = {};
  63. mergeParent.row = topLeft.row;
  64. mergeParent.col = topLeft.col;
  65. // TD has rowspan == 1 by default. rowspan == 2 means spread over 2 cells
  66. mergeParent.rowspan = bottomRight.row - topLeft.row + 1;
  67. mergeParent.colspan = bottomRight.col - topLeft.col + 1;
  68. this.mergedCellInfoCollection.setInfo(mergeParent);
  69. };
  70. MergeCells.prototype.mergeOrUnmergeSelection = function (cellRange) {
  71. var info = this.mergedCellInfoCollection.getInfo(cellRange.from.row, cellRange.from.col);
  72. if (info) {
  73. // unmerge
  74. this.unmergeSelection(cellRange.from);
  75. } else {
  76. // merge
  77. this.mergeSelection(cellRange);
  78. }
  79. };
  80. MergeCells.prototype.mergeSelection = function (cellRange) {
  81. this.mergeRange(cellRange);
  82. };
  83. MergeCells.prototype.unmergeSelection = function (cellRange) {
  84. var info = this.mergedCellInfoCollection.getInfo(cellRange.row, cellRange.col);
  85. this.mergedCellInfoCollection.removeInfo(info.row, info.col);
  86. };
  87. MergeCells.prototype.applySpanProperties = function (TD, row, col) {
  88. var info = this.mergedCellInfoCollection.getInfo(row, col);
  89. if (info) {
  90. if (info.row === row && info.col === col) {
  91. TD.setAttribute('rowspan', info.rowspan);
  92. TD.setAttribute('colspan', info.colspan);
  93. } else {
  94. TD.removeAttribute('rowspan');
  95. TD.removeAttribute('colspan');
  96. TD.style.display = 'none';
  97. }
  98. } else {
  99. TD.removeAttribute('rowspan');
  100. TD.removeAttribute('colspan');
  101. }
  102. };
  103. MergeCells.prototype.modifyTransform = function (hook, currentSelectedRange, delta) {
  104. var sameRowspan = function sameRowspan(merged, coords) {
  105. if (coords.row >= merged.row && coords.row <= merged.row + merged.rowspan - 1) {
  106. return true;
  107. }
  108. return false;
  109. },
  110. sameColspan = function sameColspan(merged, coords) {
  111. if (coords.col >= merged.col && coords.col <= merged.col + merged.colspan - 1) {
  112. return true;
  113. }
  114. return false;
  115. },
  116. getNextPosition = function getNextPosition(newDelta) {
  117. return new CellCoords(currentSelectedRange.to.row + newDelta.row, currentSelectedRange.to.col + newDelta.col);
  118. };
  119. var newDelta = {
  120. row: delta.row,
  121. col: delta.col
  122. };
  123. if (hook == 'modifyTransformStart') {
  124. /* eslint-disable block-scoped-var */
  125. var nextPosition;
  126. if (!this.lastDesiredCoords) {
  127. this.lastDesiredCoords = new CellCoords(null, null);
  128. }
  129. var currentPosition = new CellCoords(currentSelectedRange.highlight.row, currentSelectedRange.highlight.col),
  130. // if current position's parent is a merged range, returns it
  131. mergedParent = this.mergedCellInfoCollection.getInfo(currentPosition.row, currentPosition.col),
  132. currentRangeContainsMerge; // if current range contains a merged range
  133. for (var i = 0, mergesLength = this.mergedCellInfoCollection.length; i < mergesLength; i++) {
  134. var range = this.mergedCellInfoCollection[i];
  135. range = new CellCoords(range.row + range.rowspan - 1, range.col + range.colspan - 1);
  136. if (currentSelectedRange.includes(range)) {
  137. currentRangeContainsMerge = true;
  138. break;
  139. }
  140. }
  141. if (mergedParent) {
  142. // only merge selected
  143. var mergeTopLeft = new CellCoords(mergedParent.row, mergedParent.col);
  144. var mergeBottomRight = new CellCoords(mergedParent.row + mergedParent.rowspan - 1, mergedParent.col + mergedParent.colspan - 1);
  145. var mergeRange = new CellRange(mergeTopLeft, mergeTopLeft, mergeBottomRight);
  146. if (!mergeRange.includes(this.lastDesiredCoords)) {
  147. this.lastDesiredCoords = new CellCoords(null, null); // reset outdated version of lastDesiredCoords
  148. }
  149. newDelta.row = this.lastDesiredCoords.row ? this.lastDesiredCoords.row - currentPosition.row : newDelta.row;
  150. newDelta.col = this.lastDesiredCoords.col ? this.lastDesiredCoords.col - currentPosition.col : newDelta.col;
  151. if (delta.row > 0) {
  152. // moving down
  153. newDelta.row = mergedParent.row + mergedParent.rowspan - 1 - currentPosition.row + delta.row;
  154. } else if (delta.row < 0) {
  155. // moving up
  156. newDelta.row = currentPosition.row - mergedParent.row + delta.row;
  157. }
  158. if (delta.col > 0) {
  159. // moving right
  160. newDelta.col = mergedParent.col + mergedParent.colspan - 1 - currentPosition.col + delta.col;
  161. } else if (delta.col < 0) {
  162. // moving left
  163. newDelta.col = currentPosition.col - mergedParent.col + delta.col;
  164. }
  165. }
  166. nextPosition = new CellCoords(currentSelectedRange.highlight.row + newDelta.row, currentSelectedRange.highlight.col + newDelta.col);
  167. var nextParentIsMerged = this.mergedCellInfoCollection.getInfo(nextPosition.row, nextPosition.col);
  168. if (nextParentIsMerged) {
  169. // skipping the invisible cells in the merge range
  170. this.lastDesiredCoords = nextPosition;
  171. newDelta = {
  172. row: nextParentIsMerged.row - currentPosition.row,
  173. col: nextParentIsMerged.col - currentPosition.col
  174. };
  175. }
  176. } else if (hook == 'modifyTransformEnd') {
  177. for (var _i = 0, _mergesLength = this.mergedCellInfoCollection.length; _i < _mergesLength; _i++) {
  178. var currentMerge = this.mergedCellInfoCollection[_i];
  179. var _mergeTopLeft = new CellCoords(currentMerge.row, currentMerge.col);
  180. var _mergeBottomRight = new CellCoords(currentMerge.row + currentMerge.rowspan - 1, currentMerge.col + currentMerge.colspan - 1);
  181. var mergedRange = new CellRange(_mergeTopLeft, _mergeTopLeft, _mergeBottomRight);
  182. var sharedBorders = currentSelectedRange.getBordersSharedWith(mergedRange);
  183. if (mergedRange.isEqual(currentSelectedRange)) {
  184. // only the merged range is selected
  185. currentSelectedRange.setDirection('NW-SE');
  186. } else if (sharedBorders.length > 0) {
  187. var mergeHighlighted = currentSelectedRange.highlight.isEqual(mergedRange.from);
  188. if (sharedBorders.indexOf('top') > -1) {
  189. // if range shares a border with the merged section, change range direction accordingly
  190. if (currentSelectedRange.to.isSouthEastOf(mergedRange.from) && mergeHighlighted) {
  191. currentSelectedRange.setDirection('NW-SE');
  192. } else if (currentSelectedRange.to.isSouthWestOf(mergedRange.from) && mergeHighlighted) {
  193. currentSelectedRange.setDirection('NE-SW');
  194. }
  195. } else if (sharedBorders.indexOf('bottom') > -1) {
  196. if (currentSelectedRange.to.isNorthEastOf(mergedRange.from) && mergeHighlighted) {
  197. currentSelectedRange.setDirection('SW-NE');
  198. } else if (currentSelectedRange.to.isNorthWestOf(mergedRange.from) && mergeHighlighted) {
  199. currentSelectedRange.setDirection('SE-NW');
  200. }
  201. }
  202. }
  203. nextPosition = getNextPosition(newDelta);
  204. var withinRowspan = sameRowspan(currentMerge, nextPosition),
  205. withinColspan = sameColspan(currentMerge, nextPosition);
  206. if (currentSelectedRange.includesRange(mergedRange) && (mergedRange.includes(nextPosition) || withinRowspan || withinColspan)) {
  207. // if next step overlaps a merged range, jump past it
  208. if (withinRowspan) {
  209. if (newDelta.row < 0) {
  210. newDelta.row -= currentMerge.rowspan - 1;
  211. } else if (newDelta.row > 0) {
  212. newDelta.row += currentMerge.rowspan - 1;
  213. }
  214. }
  215. if (withinColspan) {
  216. if (newDelta.col < 0) {
  217. newDelta.col -= currentMerge.colspan - 1;
  218. } else if (newDelta.col > 0) {
  219. newDelta.col += currentMerge.colspan - 1;
  220. }
  221. }
  222. }
  223. }
  224. }
  225. if (newDelta.row !== 0) {
  226. delta.row = newDelta.row;
  227. }
  228. if (newDelta.col !== 0) {
  229. delta.col = newDelta.col;
  230. }
  231. };
  232. MergeCells.prototype.shiftCollection = function (direction, index, count) {
  233. var shiftVector = [0, 0];
  234. switch (direction) {
  235. case 'right':
  236. shiftVector[0] += 1;
  237. break;
  238. case 'left':
  239. shiftVector[0] -= 1;
  240. break;
  241. case 'down':
  242. shiftVector[1] += 1;
  243. break;
  244. case 'up':
  245. shiftVector[1] -= 1;
  246. break;
  247. default:
  248. break;
  249. }
  250. for (var i = 0; i < this.mergedCellInfoCollection.length; i++) {
  251. var currentMerge = this.mergedCellInfoCollection[i];
  252. if (direction === 'right' || direction === 'left') {
  253. if (index <= currentMerge.col) {
  254. currentMerge.col += shiftVector[0];
  255. }
  256. } else if (index <= currentMerge.row) {
  257. currentMerge.row += shiftVector[1];
  258. }
  259. }
  260. };
  261. var beforeInit = function beforeInit() {
  262. var instance = this;
  263. var mergeCellsSetting = instance.getSettings().mergeCells;
  264. if (mergeCellsSetting) {
  265. if (!instance.mergeCells) {
  266. instance.mergeCells = new MergeCells(mergeCellsSetting);
  267. }
  268. }
  269. };
  270. var afterInit = function afterInit() {
  271. var instance = this;
  272. if (instance.mergeCells) {
  273. /**
  274. * Monkey patch Table.prototype.getCell to return TD for merged cell parent if asked for TD of a cell that is
  275. * invisible due to the merge. This is not the cleanest solution but there is a test case for it (merged cells scroll) so feel free to refactor it!
  276. */
  277. instance.view.wt.wtTable.getCell = function (coords) {
  278. if (instance.getSettings().mergeCells) {
  279. var mergeParent = instance.mergeCells.mergedCellInfoCollection.getInfo(coords.row, coords.col);
  280. if (mergeParent) {
  281. coords = mergeParent;
  282. }
  283. }
  284. return Table.prototype.getCell.call(this, coords);
  285. };
  286. }
  287. };
  288. var afterUpdateSettings = function afterUpdateSettings() {
  289. var instance = this;
  290. var mergeCellsSetting = instance.getSettings().mergeCells;
  291. if (mergeCellsSetting) {
  292. if (instance.mergeCells) {
  293. instance.mergeCells.mergedCellInfoCollection = new CellInfoCollection();
  294. if (Array.isArray(mergeCellsSetting)) {
  295. for (var i = 0, ilen = mergeCellsSetting.length; i < ilen; i++) {
  296. instance.mergeCells.mergedCellInfoCollection.setInfo(mergeCellsSetting[i]);
  297. }
  298. }
  299. } else {
  300. instance.mergeCells = new MergeCells(mergeCellsSetting);
  301. }
  302. } else if (instance.mergeCells) {
  303. // it doesn't actually turn off the plugin, just resets the settings. Need to refactor.
  304. instance.mergeCells.mergedCellInfoCollection = new CellInfoCollection();
  305. }
  306. };
  307. var onBeforeKeyDown = function onBeforeKeyDown(event) {
  308. if (!this.mergeCells) {
  309. return;
  310. }
  311. var ctrlDown = (event.ctrlKey || event.metaKey) && !event.altKey;
  312. if (ctrlDown) {
  313. if (event.keyCode === 77) {
  314. // CTRL + M
  315. this.mergeCells.mergeOrUnmergeSelection(this.getSelectedRange());
  316. this.render();
  317. stopImmediatePropagation(event);
  318. }
  319. }
  320. };
  321. var addMergeActionsToContextMenu = function addMergeActionsToContextMenu(defaultOptions) {
  322. if (!this.getSettings().mergeCells) {
  323. return;
  324. }
  325. defaultOptions.items.push({ name: '---------' });
  326. defaultOptions.items.push({
  327. key: 'mergeCells',
  328. name: function name() {
  329. var sel = this.getSelected();
  330. var info = this.mergeCells.mergedCellInfoCollection.getInfo(sel[0], sel[1]);
  331. if (info) {
  332. return 'Unmerge cells';
  333. }
  334. return 'Merge cells';
  335. },
  336. callback: function callback() {
  337. this.mergeCells.mergeOrUnmergeSelection(this.getSelectedRange());
  338. this.render();
  339. },
  340. disabled: function disabled() {
  341. return this.selection.selectedHeader.corner;
  342. }
  343. });
  344. };
  345. var afterRenderer = function afterRenderer(TD, row, col, prop, value, cellProperties) {
  346. if (this.mergeCells) {
  347. this.mergeCells.applySpanProperties(TD, row, col);
  348. }
  349. };
  350. var modifyTransformFactory = function modifyTransformFactory(hook) {
  351. return function (delta) {
  352. var mergeCellsSetting = this.getSettings().mergeCells;
  353. if (mergeCellsSetting) {
  354. var currentSelectedRange = this.getSelectedRange();
  355. this.mergeCells.modifyTransform(hook, currentSelectedRange, delta);
  356. if (hook === 'modifyTransformEnd') {
  357. // sanitize "from" (core.js will sanitize to)
  358. var totalRows = this.countRows();
  359. var totalCols = this.countCols();
  360. if (currentSelectedRange.from.row < 0) {
  361. currentSelectedRange.from.row = 0;
  362. } else if (currentSelectedRange.from.row > 0 && currentSelectedRange.from.row >= totalRows) {
  363. currentSelectedRange.from.row = currentSelectedRange.from - 1;
  364. }
  365. if (currentSelectedRange.from.col < 0) {
  366. currentSelectedRange.from.col = 0;
  367. } else if (currentSelectedRange.from.col > 0 && currentSelectedRange.from.col >= totalCols) {
  368. currentSelectedRange.from.col = totalCols - 1;
  369. }
  370. }
  371. }
  372. };
  373. };
  374. /**
  375. * While selecting cells with keyboard or mouse, make sure that rectangular area is expanded to the extent of the merged cell
  376. * @param coords
  377. */
  378. var beforeSetRangeEnd = function beforeSetRangeEnd(coords) {
  379. this.lastDesiredCoords = null; // unset lastDesiredCoords when selection is changed with mouse
  380. var mergeCellsSetting = this.getSettings().mergeCells;
  381. if (mergeCellsSetting) {
  382. var selRange = this.getSelectedRange();
  383. selRange.highlight = new CellCoords(selRange.highlight.row, selRange.highlight.col); // clone in case we will modify its reference
  384. selRange.to = coords;
  385. var rangeExpanded = false;
  386. do {
  387. rangeExpanded = false;
  388. for (var i = 0, ilen = this.mergeCells.mergedCellInfoCollection.length; i < ilen; i++) {
  389. var cellInfo = this.mergeCells.mergedCellInfoCollection[i];
  390. var mergedCellTopLeft = new CellCoords(cellInfo.row, cellInfo.col);
  391. var mergedCellBottomRight = new CellCoords(cellInfo.row + cellInfo.rowspan - 1, cellInfo.col + cellInfo.colspan - 1);
  392. var mergedCellRange = new CellRange(mergedCellTopLeft, mergedCellTopLeft, mergedCellBottomRight);
  393. if (selRange.expandByRange(mergedCellRange)) {
  394. coords.row = selRange.to.row;
  395. coords.col = selRange.to.col;
  396. rangeExpanded = true;
  397. }
  398. }
  399. } while (rangeExpanded);
  400. }
  401. };
  402. /**
  403. * Returns correct coordinates for merged start / end cells in selection for area borders
  404. * @param corners
  405. * @param className
  406. */
  407. var beforeDrawAreaBorders = function beforeDrawAreaBorders(corners, className) {
  408. if (className && className == 'area') {
  409. var mergeCellsSetting = this.getSettings().mergeCells;
  410. if (mergeCellsSetting) {
  411. var selRange = this.getSelectedRange();
  412. var startRange = new CellRange(selRange.from, selRange.from, selRange.from);
  413. var stopRange = new CellRange(selRange.to, selRange.to, selRange.to);
  414. for (var i = 0, ilen = this.mergeCells.mergedCellInfoCollection.length; i < ilen; i++) {
  415. var cellInfo = this.mergeCells.mergedCellInfoCollection[i];
  416. var mergedCellTopLeft = new CellCoords(cellInfo.row, cellInfo.col);
  417. var mergedCellBottomRight = new CellCoords(cellInfo.row + cellInfo.rowspan - 1, cellInfo.col + cellInfo.colspan - 1);
  418. var mergedCellRange = new CellRange(mergedCellTopLeft, mergedCellTopLeft, mergedCellBottomRight);
  419. if (startRange.expandByRange(mergedCellRange)) {
  420. corners[0] = startRange.from.row;
  421. corners[1] = startRange.from.col;
  422. }
  423. if (stopRange.expandByRange(mergedCellRange)) {
  424. corners[2] = stopRange.from.row;
  425. corners[3] = stopRange.from.col;
  426. }
  427. }
  428. }
  429. }
  430. };
  431. var afterGetCellMeta = function afterGetCellMeta(row, col, cellProperties) {
  432. var mergeCellsSetting = this.getSettings().mergeCells;
  433. if (mergeCellsSetting) {
  434. var mergeParent = this.mergeCells.mergedCellInfoCollection.getInfo(row, col);
  435. if (mergeParent && (mergeParent.row != row || mergeParent.col != col)) {
  436. cellProperties.copyable = false;
  437. }
  438. }
  439. };
  440. var afterViewportRowCalculatorOverride = function afterViewportRowCalculatorOverride(calc) {
  441. var mergeCellsSetting = this.getSettings().mergeCells;
  442. if (mergeCellsSetting) {
  443. var colCount = this.countCols();
  444. var mergeParent;
  445. for (var c = 0; c < colCount; c++) {
  446. mergeParent = this.mergeCells.mergedCellInfoCollection.getInfo(calc.startRow, c);
  447. if (mergeParent) {
  448. if (mergeParent.row < calc.startRow) {
  449. calc.startRow = mergeParent.row;
  450. return afterViewportRowCalculatorOverride.call(this, calc); // recursively search upwards
  451. }
  452. }
  453. mergeParent = this.mergeCells.mergedCellInfoCollection.getInfo(calc.endRow, c);
  454. if (mergeParent) {
  455. var mergeEnd = mergeParent.row + mergeParent.rowspan - 1;
  456. if (mergeEnd > calc.endRow) {
  457. calc.endRow = mergeEnd;
  458. return afterViewportRowCalculatorOverride.call(this, calc); // recursively search upwards
  459. }
  460. }
  461. }
  462. }
  463. };
  464. var afterViewportColumnCalculatorOverride = function afterViewportColumnCalculatorOverride(calc) {
  465. var mergeCellsSetting = this.getSettings().mergeCells;
  466. if (mergeCellsSetting) {
  467. var rowCount = this.countRows();
  468. var mergeParent;
  469. for (var r = 0; r < rowCount; r++) {
  470. mergeParent = this.mergeCells.mergedCellInfoCollection.getInfo(r, calc.startColumn);
  471. if (mergeParent) {
  472. if (mergeParent.col < calc.startColumn) {
  473. calc.startColumn = mergeParent.col;
  474. return afterViewportColumnCalculatorOverride.call(this, calc); // recursively search upwards
  475. }
  476. }
  477. mergeParent = this.mergeCells.mergedCellInfoCollection.getInfo(r, calc.endColumn);
  478. if (mergeParent) {
  479. var mergeEnd = mergeParent.col + mergeParent.colspan - 1;
  480. if (mergeEnd > calc.endColumn) {
  481. calc.endColumn = mergeEnd;
  482. return afterViewportColumnCalculatorOverride.call(this, calc); // recursively search upwards
  483. }
  484. }
  485. }
  486. }
  487. };
  488. var isMultipleSelection = function isMultipleSelection(isMultiple) {
  489. if (isMultiple && this.mergeCells) {
  490. var mergedCells = this.mergeCells.mergedCellInfoCollection,
  491. selectionRange = this.getSelectedRange();
  492. for (var group in mergedCells) {
  493. if (selectionRange.highlight.row == mergedCells[group].row && selectionRange.highlight.col == mergedCells[group].col && selectionRange.to.row == mergedCells[group].row + mergedCells[group].rowspan - 1 && selectionRange.to.col == mergedCells[group].col + mergedCells[group].colspan - 1) {
  494. return false;
  495. }
  496. }
  497. }
  498. return isMultiple;
  499. };
  500. function modifyAutofillRange(select, drag) {
  501. var mergeCellsSetting = this.getSettings().mergeCells;
  502. if (!mergeCellsSetting || this.selection.isMultiple()) {
  503. return;
  504. }
  505. var info = this.mergeCells.mergedCellInfoCollection.getInfo(select[0], select[1]);
  506. if (info) {
  507. select[0] = info.row;
  508. select[1] = info.col;
  509. select[2] = info.row + info.rowspan - 1;
  510. select[3] = info.col + info.colspan - 1;
  511. }
  512. }
  513. function onAfterCreateCol(col, count) {
  514. if (this.mergeCells) {
  515. this.mergeCells.shiftCollection('right', col, count);
  516. }
  517. }
  518. function onAfterRemoveCol(col, count) {
  519. if (this.mergeCells) {
  520. this.mergeCells.shiftCollection('left', col, count);
  521. }
  522. }
  523. function onAfterCreateRow(row, count) {
  524. if (this.mergeCells) {
  525. this.mergeCells.shiftCollection('down', row, count);
  526. }
  527. }
  528. function onAfterRemoveRow(row, count) {
  529. if (this.mergeCells) {
  530. this.mergeCells.shiftCollection('up', row, count);
  531. }
  532. }
  533. var hook = Hooks.getSingleton();
  534. hook.add('beforeInit', beforeInit);
  535. hook.add('afterInit', afterInit);
  536. hook.add('afterUpdateSettings', afterUpdateSettings);
  537. hook.add('beforeKeyDown', onBeforeKeyDown);
  538. hook.add('modifyTransformStart', modifyTransformFactory('modifyTransformStart'));
  539. hook.add('modifyTransformEnd', modifyTransformFactory('modifyTransformEnd'));
  540. hook.add('beforeSetRangeEnd', beforeSetRangeEnd);
  541. hook.add('beforeDrawBorders', beforeDrawAreaBorders);
  542. hook.add('afterIsMultipleSelection', isMultipleSelection);
  543. hook.add('afterRenderer', afterRenderer);
  544. hook.add('afterContextMenuDefaultOptions', addMergeActionsToContextMenu);
  545. hook.add('afterGetCellMeta', afterGetCellMeta);
  546. hook.add('afterViewportRowCalculatorOverride', afterViewportRowCalculatorOverride);
  547. hook.add('afterViewportColumnCalculatorOverride', afterViewportColumnCalculatorOverride);
  548. hook.add('modifyAutofillRange', modifyAutofillRange);
  549. hook.add('afterCreateCol', onAfterCreateCol);
  550. hook.add('afterRemoveCol', onAfterRemoveCol);
  551. hook.add('afterCreateRow', onAfterCreateRow);
  552. hook.add('afterRemoveRow', onAfterRemoveRow);
  553. export default MergeCells;