57e993f813a07ebf790651528dcacc0931fb1924bae3e984c36781ddbe3153378389a73a46b5f32e49fa0b1bd5e38d3dcff7844a1e38f11f0f5a3bc10d71c0 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252
  1. import BasePlugin from './../_base';
  2. import {registerPlugin} from './../../plugins';
  3. import {arrayEach} from './../../helpers/array';
  4. import freezeColumnItem from './contextMenuItem/freezeColumn';
  5. import unfreezeColumnItem from './contextMenuItem/unfreezeColumn';
  6. import './manualColumnFreeze.css';
  7. const privatePool = new WeakMap();
  8. /**
  9. * This plugin allows to manually "freeze" and "unfreeze" a column using an entry in the Context Menu.
  10. * You can turn it on by setting a `manualColumnFreeze` property to `true`.
  11. *
  12. * @plugin ManualColumnFreeze
  13. * @dependencies ManualColumnMove
  14. */
  15. class ManualColumnFreeze extends BasePlugin {
  16. constructor(hotInstance) {
  17. super(hotInstance);
  18. privatePool.set(this, {
  19. moveByFreeze: false,
  20. afterFirstUse: false,
  21. });
  22. /**
  23. * Original column positions
  24. *
  25. * @type {Array}
  26. */
  27. this.frozenColumnsBasePositions = [];
  28. /**
  29. * Reference to the `ManualColumnMove` plugin.
  30. */
  31. this.manualColumnMovePlugin = void 0;
  32. }
  33. /**
  34. * Check if the plugin is enabled in the Handsontable settings.
  35. *
  36. * @returns {Boolean}
  37. */
  38. isEnabled() {
  39. return !!this.hot.getSettings().manualColumnFreeze;
  40. }
  41. /**
  42. * Enable plugin for this Handsontable instance.
  43. */
  44. enablePlugin() {
  45. if (this.enabled) {
  46. return;
  47. }
  48. this.addHook('afterContextMenuDefaultOptions', (options) => this.addContextMenuEntry(options));
  49. this.addHook('afterInit', () => this.onAfterInit());
  50. this.addHook('beforeColumnMove', (rows, target) => this.onBeforeColumnMove(rows, target));
  51. super.enablePlugin();
  52. }
  53. /**
  54. * Disable plugin for this Handsontable instance.
  55. */
  56. disablePlugin() {
  57. let priv = privatePool.get(this);
  58. priv.afterFirstUse = false;
  59. priv.moveByFreeze = false;
  60. super.disablePlugin();
  61. }
  62. /**
  63. * Updates the plugin to use the latest options you have specified.
  64. */
  65. updatePlugin() {
  66. this.disablePlugin();
  67. this.enablePlugin();
  68. super.updatePlugin();
  69. }
  70. /**
  71. * Freeze the given column (add it to fixed columns).
  72. *
  73. * @param {Number} column Column index.
  74. */
  75. freezeColumn(column) {
  76. let priv = privatePool.get(this);
  77. let settings = this.hot.getSettings();
  78. if (!priv.afterFirstUse) {
  79. priv.afterFirstUse = true;
  80. }
  81. if (settings.fixedColumnsLeft === this.hot.countCols() || column <= settings.fixedColumnsLeft - 1) {
  82. return; // already fixed
  83. }
  84. priv.moveByFreeze = true;
  85. if (column !== this.getMovePlugin().columnsMapper.getValueByIndex(column)) {
  86. this.frozenColumnsBasePositions[settings.fixedColumnsLeft] = column;
  87. }
  88. this.getMovePlugin().moveColumn(column, settings.fixedColumnsLeft++);
  89. }
  90. /**
  91. * Unfreeze the given column (remove it from fixed columns and bring to it's previous position).
  92. *
  93. * @param {Number} column Column index.
  94. */
  95. unfreezeColumn(column) {
  96. let priv = privatePool.get(this);
  97. let settings = this.hot.getSettings();
  98. if (!priv.afterFirstUse) {
  99. priv.afterFirstUse = true;
  100. }
  101. if (settings.fixedColumnsLeft <= 0 || (column > settings.fixedColumnsLeft - 1)) {
  102. return; // not fixed
  103. }
  104. let returnCol = this.getBestColumnReturnPosition(column);
  105. priv.moveByFreeze = true;
  106. settings.fixedColumnsLeft--;
  107. this.getMovePlugin().moveColumn(column, returnCol + 1);
  108. }
  109. /**
  110. * Get the reference to the ManualColumnMove plugin.
  111. *
  112. * @private
  113. * @returns {Object}
  114. */
  115. getMovePlugin() {
  116. if (!this.manualColumnMovePlugin) {
  117. this.manualColumnMovePlugin = this.hot.getPlugin('manualColumnMove');
  118. }
  119. return this.manualColumnMovePlugin;
  120. }
  121. /**
  122. * Estimates the most fitting return position for unfrozen column.
  123. *
  124. * @private
  125. * @param {Number} column Column index.
  126. */
  127. getBestColumnReturnPosition(column) {
  128. let movePlugin = this.getMovePlugin();
  129. let settings = this.hot.getSettings();
  130. let i = settings.fixedColumnsLeft;
  131. let j = movePlugin.columnsMapper.getValueByIndex(i);
  132. let initialCol;
  133. if (this.frozenColumnsBasePositions[column] == null) {
  134. initialCol = movePlugin.columnsMapper.getValueByIndex(column);
  135. while (j < initialCol) {
  136. i++;
  137. j = movePlugin.columnsMapper.getValueByIndex(i);
  138. }
  139. } else {
  140. initialCol = this.frozenColumnsBasePositions[column];
  141. this.frozenColumnsBasePositions[column] = void 0;
  142. while (j <= initialCol) {
  143. i++;
  144. j = movePlugin.columnsMapper.getValueByIndex(i);
  145. }
  146. i = j;
  147. }
  148. return i - 1;
  149. }
  150. /**
  151. * Add the manualColumnFreeze context menu entries.
  152. *
  153. * @private
  154. * @param {Object} options Context menu options.
  155. */
  156. addContextMenuEntry(options) {
  157. options.items.push(
  158. {name: '---------'},
  159. freezeColumnItem(this),
  160. unfreezeColumnItem(this)
  161. );
  162. }
  163. /**
  164. * Enabling `manualColumnMove` plugin on `afterInit` hook.
  165. *
  166. * @private
  167. */
  168. onAfterInit() {
  169. if (!this.getMovePlugin().isEnabled()) {
  170. this.getMovePlugin().enablePlugin();
  171. }
  172. }
  173. /**
  174. * Prevent moving the rows from/to fixed area.
  175. *
  176. * @private
  177. * @param {Array} rows
  178. * @param {Number} target
  179. */
  180. onBeforeColumnMove(rows, target) {
  181. let priv = privatePool.get(this);
  182. if (priv.afterFirstUse && !priv.moveByFreeze) {
  183. let frozenLen = this.hot.getSettings().fixedColumnsLeft;
  184. let disallowMoving = target < frozenLen;
  185. if (!disallowMoving) {
  186. arrayEach(rows, (value, index, array) => {
  187. if (value < frozenLen) {
  188. disallowMoving = true;
  189. return false;
  190. }
  191. });
  192. }
  193. if (disallowMoving) {
  194. return false;
  195. }
  196. }
  197. if (priv.moveByFreeze) {
  198. priv.moveByFreeze = false;
  199. }
  200. }
  201. /**
  202. * Destroy plugin instance.
  203. */
  204. destroy() {
  205. super.destroy();
  206. }
  207. }
  208. registerPlugin('manualColumnFreeze', ManualColumnFreeze);
  209. export default ManualColumnFreeze;