f8222e7c096d34809ce281cc06c3692641329866a759436f40d7db9b7244b426a1bb120d73b2fa05d04ed65f6dffcf277a02f70be1980c12177b890e7eacba 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743
  1. import BasePlugin from './../_base.js';
  2. import Hooks from './../../pluginHooks';
  3. import {arrayEach} from './../../helpers/array';
  4. import {addClass, removeClass, offset} from './../../helpers/dom/element';
  5. import {rangeEach} from './../../helpers/number';
  6. import EventManager from './../../eventManager';
  7. import {registerPlugin} from './../../plugins';
  8. import ColumnsMapper from './columnsMapper';
  9. import BacklightUI from './ui/backlight';
  10. import GuidelineUI from './ui/guideline';
  11. import {CellCoords} from './../../3rdparty/walkontable/src';
  12. import './manualColumnMove.css';
  13. Hooks.getSingleton().register('beforeColumnMove');
  14. Hooks.getSingleton().register('afterColumnMove');
  15. Hooks.getSingleton().register('unmodifyCol');
  16. const privatePool = new WeakMap();
  17. const CSS_PLUGIN = 'ht__manualColumnMove';
  18. const CSS_SHOW_UI = 'show-ui';
  19. const CSS_ON_MOVING = 'on-moving--columns';
  20. const CSS_AFTER_SELECTION = 'after-selection--columns';
  21. /**
  22. * @plugin ManualColumnMove
  23. *
  24. * @description
  25. * This plugin allows to change columns order.
  26. *
  27. * API:
  28. * - moveColumn - move single column to the new position.
  29. * - moveColumns - move many columns (as an array of indexes) to the new position.
  30. *
  31. * If you want apply visual changes, you have to call manually the render() method on the instance of Handsontable.
  32. *
  33. * UI components:
  34. * - backlight - highlight of selected columns.
  35. * - guideline - line which shows where rows has been moved.
  36. *
  37. * @class ManualColumnMove
  38. * @plugin ManualColumnMove
  39. */
  40. class ManualColumnMove extends BasePlugin {
  41. constructor(hotInstance) {
  42. super(hotInstance);
  43. /**
  44. * Set up WeakMap of plugin to sharing private parameters;
  45. */
  46. privatePool.set(this, {
  47. columnsToMove: [],
  48. countCols: 0,
  49. fixedColumns: 0,
  50. pressed: void 0,
  51. disallowMoving: void 0,
  52. target: {
  53. eventPageX: void 0,
  54. coords: void 0,
  55. TD: void 0,
  56. col: void 0
  57. }
  58. });
  59. /**
  60. * List of last removed row indexes.
  61. *
  62. * @type {Array}
  63. */
  64. this.removedColumns = [];
  65. /**
  66. * Object containing visual row indexes mapped to data source indexes.
  67. *
  68. * @type {RowsMapper}
  69. */
  70. this.columnsMapper = new ColumnsMapper(this);
  71. /**
  72. * Event Manager object.
  73. *
  74. * @type {Object}
  75. */
  76. this.eventManager = new EventManager(this);
  77. /**
  78. * Backlight UI object.
  79. *
  80. * @type {Object}
  81. */
  82. this.backlight = new BacklightUI(hotInstance);
  83. /**
  84. * Guideline UI object.
  85. *
  86. * @type {Object}
  87. */
  88. this.guideline = new GuidelineUI(hotInstance);
  89. }
  90. /**
  91. * Check if plugin is enabled.
  92. *
  93. * @returns {Boolean}
  94. */
  95. isEnabled() {
  96. return !!this.hot.getSettings().manualColumnMove;
  97. }
  98. /**
  99. * Enable the plugin.
  100. */
  101. enablePlugin() {
  102. if (this.enabled) {
  103. return;
  104. }
  105. this.addHook('beforeOnCellMouseDown', (event, coords, TD, blockCalculations) => this.onBeforeOnCellMouseDown(event, coords, TD, blockCalculations));
  106. this.addHook('beforeOnCellMouseOver', (event, coords, TD, blockCalculations) => this.onBeforeOnCellMouseOver(event, coords, TD, blockCalculations));
  107. this.addHook('afterScrollVertically', () => this.onAfterScrollVertically());
  108. this.addHook('modifyCol', (row, source) => this.onModifyCol(row, source));
  109. this.addHook('beforeRemoveCol', (index, amount) => this.onBeforeRemoveCol(index, amount));
  110. this.addHook('afterRemoveCol', (index, amount) => this.onAfterRemoveCol(index, amount));
  111. this.addHook('afterCreateCol', (index, amount) => this.onAfterCreateCol(index, amount));
  112. this.addHook('afterLoadData', (firstTime) => this.onAfterLoadData(firstTime));
  113. this.addHook('unmodifyCol', (column) => this.onUnmodifyCol(column));
  114. this.registerEvents();
  115. // TODO: move adding plugin classname to BasePlugin.
  116. addClass(this.hot.rootElement, CSS_PLUGIN);
  117. super.enablePlugin();
  118. }
  119. /**
  120. * Updates the plugin to use the latest options you have specified.
  121. */
  122. updatePlugin() {
  123. this.disablePlugin();
  124. this.enablePlugin();
  125. this.onAfterPluginsInitialized();
  126. super.updatePlugin();
  127. }
  128. /**
  129. * Disable plugin for this Handsontable instance.
  130. */
  131. disablePlugin() {
  132. let pluginSettings = this.hot.getSettings().manualColumnMove;
  133. if (Array.isArray(pluginSettings)) {
  134. this.columnsMapper.clearMap();
  135. }
  136. removeClass(this.hot.rootElement, CSS_PLUGIN);
  137. this.unregisterEvents();
  138. this.backlight.destroy();
  139. this.guideline.destroy();
  140. super.disablePlugin();
  141. }
  142. /**
  143. * Move a single column.
  144. *
  145. * @param {Number} column Visual column index to be moved.
  146. * @param {Number} target Visual column index being a target for the moved column.
  147. */
  148. moveColumn(column, target) {
  149. this.moveColumns([column], target);
  150. }
  151. /**
  152. * Move multiple columns.
  153. *
  154. * @param {Array} columns Array of visual column indexes to be moved.
  155. * @param {Number} target Visual column index being a target for the moved columns.
  156. */
  157. moveColumns(columns, target) {
  158. let priv = privatePool.get(this);
  159. let beforeColumnHook = this.hot.runHooks('beforeColumnMove', columns, target);
  160. priv.disallowMoving = !beforeColumnHook;
  161. if (beforeColumnHook !== false) {
  162. // first we need to rewrite an visual indexes to logical for save reference after move
  163. arrayEach(columns, (column, index, array) => {
  164. array[index] = this.columnsMapper.getValueByIndex(column);
  165. });
  166. // next, when we have got an logical indexes, we can move columns
  167. arrayEach(columns, (column, index) => {
  168. let actualPosition = this.columnsMapper.getIndexByValue(column);
  169. if (actualPosition !== target) {
  170. this.columnsMapper.moveColumn(actualPosition, target + index);
  171. }
  172. });
  173. // after moving we have to clear columnsMapper from null entries
  174. this.columnsMapper.clearNull();
  175. }
  176. this.hot.runHooks('afterColumnMove', columns, target);
  177. }
  178. /**
  179. * Correct the cell selection after the move action. Fired only when action was made with a mouse.
  180. * That means that changing the column order using the API won't correct the selection.
  181. *
  182. * @private
  183. * @param {Number} startColumn Visual column index for the start of the selection.
  184. * @param {Number} endColumn Visual column index for the end of the selection.
  185. */
  186. changeSelection(startColumn, endColumn) {
  187. let selection = this.hot.selection;
  188. let lastRowIndex = this.hot.countRows() - 1;
  189. selection.setRangeStartOnly(new CellCoords(0, startColumn));
  190. selection.setRangeEnd(new CellCoords(lastRowIndex, endColumn), false);
  191. }
  192. /**
  193. * Get the sum of the widths of columns in the provided range.
  194. *
  195. * @private
  196. * @param {Number} from Visual column index.
  197. * @param {Number} to Visual column index.
  198. * @returns {Number}
  199. */
  200. getColumnsWidth(from, to) {
  201. let width = 0;
  202. for (let i = from; i < to; i++) {
  203. let columnWidth = 0;
  204. if (i < 0) {
  205. columnWidth = this.hot.view.wt.wtTable.getColumnWidth(i) || 0;
  206. } else {
  207. columnWidth = this.hot.view.wt.wtTable.getStretchedColumnWidth(i) || 0;
  208. }
  209. width += columnWidth;
  210. }
  211. return width;
  212. }
  213. /**
  214. * Load initial settings when persistent state is saved or when plugin was initialized as an array.
  215. *
  216. * @private
  217. */
  218. initialSettings() {
  219. let pluginSettings = this.hot.getSettings().manualColumnMove;
  220. if (Array.isArray(pluginSettings)) {
  221. this.moveColumns(pluginSettings, 0);
  222. } else if (pluginSettings !== void 0) {
  223. this.persistentStateLoad();
  224. }
  225. }
  226. /**
  227. * Check if the provided column is in the fixedColumnsLeft section.
  228. *
  229. * @private
  230. * @param {Number} column Visual column index to check.
  231. * @returns {Boolean}
  232. */
  233. isFixedColumnsLeft(column) {
  234. return column < this.hot.getSettings().fixedColumnsLeft;
  235. }
  236. /**
  237. * Save the manual column positions to the persistent state.
  238. *
  239. * @private
  240. */
  241. persistentStateSave() {
  242. this.hot.runHooks('persistentStateSave', 'manualColumnMove', this.columnsMapper._arrayMap);
  243. }
  244. /**
  245. * Load the manual column positions from the persistent state.
  246. *
  247. * @private
  248. */
  249. persistentStateLoad() {
  250. let storedState = {};
  251. this.hot.runHooks('persistentStateLoad', 'manualColumnMove', storedState);
  252. if (storedState.value) {
  253. this.columnsMapper._arrayMap = storedState.value;
  254. }
  255. }
  256. /**
  257. * Prepare array of indexes based on actual selection.
  258. *
  259. * @private
  260. * @returns {Array}
  261. */
  262. prepareColumnsToMoving(start, end) {
  263. let selectedColumns = [];
  264. rangeEach(start, end, (i) => {
  265. selectedColumns.push(i);
  266. });
  267. return selectedColumns;
  268. }
  269. /**
  270. * Update the UI visual position.
  271. *
  272. * @private
  273. */
  274. refreshPositions() {
  275. let priv = privatePool.get(this);
  276. let firstVisible = this.hot.view.wt.wtTable.getFirstVisibleColumn();
  277. let lastVisible = this.hot.view.wt.wtTable.getLastVisibleColumn();
  278. let wtTable = this.hot.view.wt.wtTable;
  279. let scrollableElement = this.hot.view.wt.wtOverlays.scrollableElement;
  280. let scrollLeft = typeof scrollableElement.scrollX === 'number' ? scrollableElement.scrollX : scrollableElement.scrollLeft;
  281. let tdOffsetLeft = this.hot.view.THEAD.offsetLeft + this.getColumnsWidth(0, priv.coordsColumn);
  282. let mouseOffsetLeft = priv.target.eventPageX - (priv.rootElementOffset - (scrollableElement.scrollX === void 0 ? scrollLeft : 0));
  283. let hiderWidth = wtTable.hider.offsetWidth;
  284. let tbodyOffsetLeft = wtTable.TBODY.offsetLeft;
  285. let backlightElemMarginLeft = this.backlight.getOffset().left;
  286. let backlightElemWidth = this.backlight.getSize().width;
  287. let rowHeaderWidth = 0;
  288. if ((priv.rootElementOffset + wtTable.holder.offsetWidth + scrollLeft) < priv.target.eventPageX) {
  289. if (priv.coordsColumn < priv.countCols) {
  290. priv.coordsColumn++;
  291. }
  292. }
  293. if (priv.hasRowHeaders) {
  294. rowHeaderWidth = this.hot.view.wt.wtOverlays.leftOverlay.clone.wtTable.getColumnHeader(-1).offsetWidth;
  295. }
  296. if (this.isFixedColumnsLeft(priv.coordsColumn)) {
  297. tdOffsetLeft += scrollLeft;
  298. }
  299. tdOffsetLeft += rowHeaderWidth;
  300. if (priv.coordsColumn < 0) {
  301. // if hover on rowHeader
  302. if (priv.fixedColumns > 0) {
  303. priv.target.col = 0;
  304. } else {
  305. priv.target.col = firstVisible > 0 ? firstVisible - 1 : firstVisible;
  306. }
  307. } else if (((priv.target.TD.offsetWidth / 2) + tdOffsetLeft) <= mouseOffsetLeft) {
  308. let newCoordsCol = priv.coordsColumn >= priv.countCols ? priv.countCols - 1 : priv.coordsColumn;
  309. // if hover on right part of TD
  310. priv.target.col = newCoordsCol + 1;
  311. // unfortunately first column is bigger than rest
  312. tdOffsetLeft += priv.target.TD.offsetWidth;
  313. if (priv.target.col > lastVisible) {
  314. this.hot.scrollViewportTo(void 0, lastVisible + 1, void 0, true);
  315. }
  316. } else {
  317. // elsewhere on table
  318. priv.target.col = priv.coordsColumn;
  319. if (priv.target.col <= firstVisible && priv.target.col >= priv.fixedColumns) {
  320. this.hot.scrollViewportTo(void 0, firstVisible - 1);
  321. }
  322. }
  323. if (priv.target.col <= firstVisible && priv.target.col >= priv.fixedColumns) {
  324. this.hot.scrollViewportTo(void 0, firstVisible - 1);
  325. }
  326. let backlightLeft = mouseOffsetLeft;
  327. let guidelineLeft = tdOffsetLeft;
  328. if (mouseOffsetLeft + backlightElemWidth + backlightElemMarginLeft >= hiderWidth) {
  329. // prevent display backlight on the right side of the table
  330. backlightLeft = hiderWidth - backlightElemWidth - backlightElemMarginLeft;
  331. } else if (mouseOffsetLeft + backlightElemMarginLeft < tbodyOffsetLeft + rowHeaderWidth) {
  332. // prevent display backlight on the left side of the table
  333. backlightLeft = tbodyOffsetLeft + rowHeaderWidth + Math.abs(backlightElemMarginLeft);
  334. }
  335. if (tdOffsetLeft >= hiderWidth - 1) {
  336. // prevent display guideline outside the table
  337. guidelineLeft = hiderWidth - 1;
  338. } else if (guidelineLeft === 0) {
  339. // guideline has got `margin-left: -1px` as default
  340. guidelineLeft = 1;
  341. } else if (scrollableElement.scrollX !== void 0 && priv.coordsColumn < priv.fixedColumns) {
  342. guidelineLeft -= ((priv.rootElementOffset <= scrollableElement.scrollX) ? priv.rootElementOffset : 0);
  343. }
  344. this.backlight.setPosition(null, backlightLeft);
  345. this.guideline.setPosition(null, guidelineLeft);
  346. }
  347. /**
  348. * This method checks arrayMap from columnsMapper and updates the columnsMapper if it's necessary.
  349. *
  350. * @private
  351. */
  352. updateColumnsMapper() {
  353. let countCols = this.hot.countSourceCols();
  354. let columnsMapperLen = this.columnsMapper._arrayMap.length;
  355. if (columnsMapperLen === 0) {
  356. this.columnsMapper.createMap(countCols || this.hot.getSettings().startCols);
  357. } else if (columnsMapperLen < countCols) {
  358. let diff = countCols - columnsMapperLen;
  359. this.columnsMapper.insertItems(columnsMapperLen, diff);
  360. } else if (columnsMapperLen > countCols) {
  361. let maxIndex = countCols - 1;
  362. let columnsToRemove = [];
  363. arrayEach(this.columnsMapper._arrayMap, (value, index, array) => {
  364. if (value > maxIndex) {
  365. columnsToRemove.push(index);
  366. }
  367. });
  368. this.columnsMapper.removeItems(columnsToRemove);
  369. }
  370. }
  371. /**
  372. * Bind the events used by the plugin.
  373. *
  374. * @private
  375. */
  376. registerEvents() {
  377. this.eventManager.addEventListener(document.documentElement, 'mousemove', (event) => this.onMouseMove(event));
  378. this.eventManager.addEventListener(document.documentElement, 'mouseup', () => this.onMouseUp());
  379. }
  380. /**
  381. * Unbind the events used by the plugin.
  382. *
  383. * @private
  384. */
  385. unregisterEvents() {
  386. this.eventManager.clear();
  387. }
  388. /**
  389. * Change the behavior of selection / dragging.
  390. *
  391. * @private
  392. * @param {MouseEvent} event
  393. * @param {CellCoords} coords
  394. * @param {HTMLElement} TD
  395. * @param {Object} blockCalculations
  396. */
  397. onBeforeOnCellMouseDown(event, coords, TD, blockCalculations) {
  398. let wtTable = this.hot.view.wt.wtTable;
  399. let isHeaderSelection = this.hot.selection.selectedHeader.cols;
  400. let selection = this.hot.getSelectedRange();
  401. let priv = privatePool.get(this);
  402. let isSortingElement = event.realTarget.className.indexOf('columnSorting') > -1;
  403. if (!selection || !isHeaderSelection || priv.pressed || event.button !== 0 || isSortingElement) {
  404. priv.pressed = false;
  405. priv.columnsToMove.length = 0;
  406. removeClass(this.hot.rootElement, [CSS_ON_MOVING, CSS_SHOW_UI]);
  407. return;
  408. }
  409. let guidelineIsNotReady = this.guideline.isBuilt() && !this.guideline.isAppended();
  410. let backlightIsNotReady = this.backlight.isBuilt() && !this.backlight.isAppended();
  411. if (guidelineIsNotReady && backlightIsNotReady) {
  412. this.guideline.appendTo(wtTable.hider);
  413. this.backlight.appendTo(wtTable.hider);
  414. }
  415. let {from, to} = selection;
  416. let start = Math.min(from.col, to.col);
  417. let end = Math.max(from.col, to.col);
  418. if (coords.row < 0 && (coords.col >= start && coords.col <= end)) {
  419. blockCalculations.column = true;
  420. priv.pressed = true;
  421. priv.target.eventPageX = event.pageX;
  422. priv.coordsColumn = coords.col;
  423. priv.target.TD = TD;
  424. priv.target.col = coords.col;
  425. priv.columnsToMove = this.prepareColumnsToMoving(start, end);
  426. priv.hasRowHeaders = !!this.hot.getSettings().rowHeaders;
  427. priv.countCols = this.hot.countCols();
  428. priv.fixedColumns = this.hot.getSettings().fixedColumnsLeft;
  429. priv.rootElementOffset = offset(this.hot.rootElement).left;
  430. let countColumnsFrom = priv.hasRowHeaders ? -1 : 0;
  431. let topPos = wtTable.holder.scrollTop + wtTable.getColumnHeaderHeight(0) + 1;
  432. let fixedColumns = coords.col < priv.fixedColumns;
  433. let scrollableElement = this.hot.view.wt.wtOverlays.scrollableElement;
  434. let wrapperIsWindow = scrollableElement.scrollX ? scrollableElement.scrollX - priv.rootElementOffset : 0;
  435. let mouseOffset = event.layerX - (fixedColumns ? wrapperIsWindow : 0);
  436. let leftOffset = Math.abs(this.getColumnsWidth(start, coords.col) + mouseOffset);
  437. this.backlight.setPosition(topPos, this.getColumnsWidth(countColumnsFrom, start) + leftOffset);
  438. this.backlight.setSize(this.getColumnsWidth(start, end + 1), wtTable.hider.offsetHeight - topPos);
  439. this.backlight.setOffset(null, leftOffset * -1);
  440. addClass(this.hot.rootElement, CSS_ON_MOVING);
  441. } else {
  442. removeClass(this.hot.rootElement, CSS_AFTER_SELECTION);
  443. priv.pressed = false;
  444. priv.columnsToMove.length = 0;
  445. }
  446. }
  447. /**
  448. * 'mouseMove' event callback. Fired when pointer move on document.documentElement.
  449. *
  450. * @private
  451. * @param {MouseEvent} event `mousemove` event properties.
  452. */
  453. onMouseMove(event) {
  454. let priv = privatePool.get(this);
  455. if (!priv.pressed) {
  456. return;
  457. }
  458. // callback for browser which doesn't supports CSS pointer-event: none
  459. if (event.realTarget === this.backlight.element) {
  460. let width = this.backlight.getSize().width;
  461. this.backlight.setSize(0);
  462. setTimeout(function() {
  463. this.backlight.setPosition(width);
  464. });
  465. }
  466. priv.target.eventPageX = event.pageX;
  467. this.refreshPositions();
  468. }
  469. /**
  470. * 'beforeOnCellMouseOver' hook callback. Fired when pointer was over cell.
  471. *
  472. * @private
  473. * @param {MouseEvent} event `mouseover` event properties.
  474. * @param {CellCoords} coords Cell coordinates where was fired event.
  475. * @param {HTMLElement} TD Cell represented as HTMLElement.
  476. * @param {Object} blockCalculations Object which contains information about blockCalculation for row, column or cells.
  477. */
  478. onBeforeOnCellMouseOver(event, coords, TD, blockCalculations) {
  479. let selectedRange = this.hot.getSelectedRange();
  480. let priv = privatePool.get(this);
  481. if (!selectedRange || !priv.pressed) {
  482. return;
  483. }
  484. if (priv.columnsToMove.indexOf(coords.col) > -1) {
  485. removeClass(this.hot.rootElement, CSS_SHOW_UI);
  486. } else {
  487. addClass(this.hot.rootElement, CSS_SHOW_UI);
  488. }
  489. blockCalculations.row = true;
  490. blockCalculations.column = true;
  491. blockCalculations.cell = true;
  492. priv.coordsColumn = coords.col;
  493. priv.target.TD = TD;
  494. }
  495. /**
  496. * `onMouseUp` hook callback.
  497. *
  498. * @private
  499. */
  500. onMouseUp() {
  501. let priv = privatePool.get(this);
  502. priv.coordsColumn = void 0;
  503. priv.pressed = false;
  504. priv.backlightWidth = 0;
  505. removeClass(this.hot.rootElement, [CSS_ON_MOVING, CSS_SHOW_UI, CSS_AFTER_SELECTION]);
  506. if (this.hot.selection.selectedHeader.cols) {
  507. addClass(this.hot.rootElement, CSS_AFTER_SELECTION);
  508. }
  509. if (priv.columnsToMove.length < 1 || priv.target.col === void 0 || priv.columnsToMove.indexOf(priv.target.col) > -1) {
  510. return;
  511. }
  512. this.moveColumns(priv.columnsToMove, priv.target.col);
  513. this.persistentStateSave();
  514. this.hot.render();
  515. this.hot.view.wt.wtOverlays.adjustElementsSize(true);
  516. if (!priv.disallowMoving) {
  517. let selectionStart = this.columnsMapper.getIndexByValue(priv.columnsToMove[0]);
  518. let selectionEnd = this.columnsMapper.getIndexByValue(priv.columnsToMove[priv.columnsToMove.length - 1]);
  519. this.changeSelection(selectionStart, selectionEnd);
  520. }
  521. priv.columnsToMove.length = 0;
  522. }
  523. /**
  524. * `afterScrollHorizontally` hook callback. Fired the table was scrolled horizontally.
  525. *
  526. * @private
  527. */
  528. onAfterScrollVertically() {
  529. let wtTable = this.hot.view.wt.wtTable;
  530. let headerHeight = wtTable.getColumnHeaderHeight(0) + 1;
  531. let scrollTop = wtTable.holder.scrollTop;
  532. let posTop = headerHeight + scrollTop;
  533. this.backlight.setPosition(posTop);
  534. this.backlight.setSize(null, wtTable.hider.offsetHeight - posTop);
  535. }
  536. /**
  537. * `afterCreateCol` hook callback.
  538. *
  539. * @private
  540. * @param {Number} index Index of the created column.
  541. * @param {Number} amount Amount of created columns.
  542. */
  543. onAfterCreateCol(index, amount) {
  544. this.columnsMapper.shiftItems(index, amount);
  545. }
  546. /**
  547. * On before remove column listener.
  548. *
  549. * @private
  550. * @param {Number} index Column index.
  551. * @param {Number} amount Defines how many columns removed.
  552. */
  553. onBeforeRemoveCol(index, amount) {
  554. this.removedColumns.length = 0;
  555. if (index !== false) {
  556. // Collect physical row index.
  557. rangeEach(index, index + amount - 1, (removedIndex) => {
  558. this.removedColumns.push(this.hot.runHooks('modifyCol', removedIndex, this.pluginName));
  559. });
  560. }
  561. }
  562. /**
  563. * `afterRemoveCol` hook callback.
  564. *
  565. * @private
  566. * @param {Number} index Index of the removed column.
  567. * @param {Number} amount Amount of removed columns.
  568. */
  569. onAfterRemoveCol(index, amount) {
  570. this.columnsMapper.unshiftItems(this.removedColumns);
  571. }
  572. /**
  573. * `afterLoadData` hook callback.
  574. *
  575. * @private
  576. * @param {Boolean} firstTime True if that was loading data during the initialization.
  577. */
  578. onAfterLoadData(firstTime) {
  579. this.updateColumnsMapper();
  580. }
  581. /**
  582. * 'modifyRow' hook callback.
  583. *
  584. * @private
  585. * @param {Number} column Visual column index.
  586. * @returns {Number} Modified column index.
  587. */
  588. onModifyCol(column, source) {
  589. if (source !== this.pluginName) {
  590. // ugly fix for try to insert new, needed columns after pasting data
  591. let columnInMapper = this.columnsMapper.getValueByIndex(column);
  592. column = columnInMapper === null ? column : columnInMapper;
  593. }
  594. return column;
  595. }
  596. /**
  597. * 'unmodifyCol' hook callback.
  598. *
  599. * @private
  600. * @param {Number} column Visual column index.
  601. * @returns {Number} Logical column index.
  602. */
  603. onUnmodifyCol(column) {
  604. let indexInMapper = this.columnsMapper.getIndexByValue(column);
  605. return indexInMapper === null ? column : indexInMapper;
  606. }
  607. /**
  608. * `afterPluginsInitialized` hook callback.
  609. *
  610. * @private
  611. */
  612. onAfterPluginsInitialized() {
  613. this.updateColumnsMapper();
  614. this.initialSettings();
  615. this.backlight.build();
  616. this.guideline.build();
  617. }
  618. /**
  619. * Destroy plugin instance.
  620. */
  621. destroy() {
  622. this.backlight.destroy();
  623. this.guideline.destroy();
  624. super.destroy();
  625. }
  626. }
  627. registerPlugin('ManualColumnMove', ManualColumnMove);
  628. export default ManualColumnMove;