pluginHooks.js 72 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058
  1. import { arrayEach } from './helpers/array';
  2. import { objectEach } from './helpers/object';
  3. /**
  4. * @description
  5. * Handsontable events are the common interface that function in 2 ways: as __callbacks__ and as __hooks__.
  6. *
  7. * @example
  8. *
  9. * ```js
  10. * // Using events as callbacks:
  11. * ...
  12. * const hot1 = new Handsontable(document.getElementById('example1'), {
  13. * afterChange: function(changes, source) {
  14. * $.ajax({
  15. * url: "save.php',
  16. * data: change
  17. * });
  18. * }
  19. * });
  20. * ...
  21. * ```
  22. *
  23. * ```js
  24. * // Using events as plugin hooks:
  25. * ...
  26. * const hot1 = new Handsontable(document.getElementById('example1'), {
  27. * myPlugin: true
  28. * });
  29. *
  30. * const hot2 = new Handsontable(document.getElementById('example2'), {
  31. * myPlugin: false
  32. * });
  33. *
  34. * // global hook
  35. * Handsontable.hooks.add('afterChange', function() {
  36. * // Fired twice - for hot1 and hot2
  37. * if (this.getSettings().myPlugin) {
  38. * // function body - will only run for hot1
  39. * }
  40. * });
  41. *
  42. * // local hook (has same effect as a callback)
  43. * hot2.addHook('afterChange', function() {
  44. * // function body - will only run in #example2
  45. * });
  46. * ```
  47. * ...
  48. */
  49. // @TODO: Move plugin description hooks to plugin?
  50. const REGISTERED_HOOKS = [
  51. /**
  52. * Fired after resetting a cell's meta. This happens when the {@link Core#updateSettings} method is called.
  53. *
  54. * @event Hooks#afterCellMetaReset
  55. */
  56. 'afterCellMetaReset',
  57. /**
  58. * Fired after one or more cells has been changed. The changes are triggered in any situation when the
  59. * value is entered using an editor or changed using API (e.q setDataAtCell)
  60. *
  61. * __Note:__ For performance reasons, the `changes` array is null for `"loadData"` source.
  62. *
  63. * @event Hooks#afterChange
  64. * @param {Array} changes 2D array containing information about each of the edited cells `[[row, prop, oldVal, newVal], ...]`.
  65. * @param {String} [source] String that identifies source of hook call ([list of all available sources]{@link https://docs.handsontable.com/tutorial-using-callbacks.html#page-source-definition}).
  66. * @example
  67. * ```js
  68. * new Handsontable(element, {
  69. * afterChange: (changes) => {
  70. * changes.forEach(([row, prop, oldValue, newValue]) => {
  71. * // Some logic...
  72. * });
  73. * }
  74. * })
  75. * ```
  76. */
  77. 'afterChange',
  78. /**
  79. * Fired by {@link ObserveChanges} plugin after detecting changes in the data source. This hook is fired when
  80. * {@link Options#observeChanges} option is enabled.
  81. *
  82. * @event Hooks#afterChangesObserved
  83. */
  84. 'afterChangesObserved',
  85. /**
  86. * Fired by {@link ContextMenu} after setting up the Context Menu's default options. These options are a collection
  87. * which user can select by setting an array of keys or an array of objects in {@link Options#contextMenu} option.
  88. *
  89. * @event Hooks#afterContextMenuDefaultOptions
  90. * @param {Array} predefinedItems An array of objects containing information about the pre-defined Context Menu items.
  91. */
  92. 'afterContextMenuDefaultOptions',
  93. /**
  94. * Fired by {@link ContextMenu} plugin before setting up the Context Menu's items but after filtering these options by
  95. * user (`contextMenu` option). This hook can by helpful to determine if user use specified menu item or to set up
  96. * one of the menu item to by always visible.
  97. *
  98. * @event Hooks#beforeContextMenuSetItems
  99. * @param {Object[]} menuItems An array of objects containing information about to generated Context Menu items.
  100. */
  101. 'beforeContextMenuSetItems',
  102. /**
  103. * Fired by {@link DropdownMenu} plugin after setting up the Dropdown Menu's default options. These options are a
  104. * collection which user can select by setting an array of keys or an array of objects in {@link Options#dropdownMenu}
  105. * option.
  106. *
  107. * @pro
  108. * @event Hooks#afterDropdownMenuDefaultOptions
  109. * @param {Object[]} predefinedItems An array of objects containing information about the pre-defined Context Menu items.
  110. */
  111. 'afterDropdownMenuDefaultOptions',
  112. /**
  113. * Fired by {@link DropdownMenu} plugin before setting up the Dropdown Menu's items but after filtering these options
  114. * by user (`dropdownMenu` option). This hook can by helpful to determine if user use specified menu item or to set
  115. * up one of the menu item to by always visible.
  116. *
  117. * @pro
  118. * @event Hooks#beforeDropdownMenuSetItems
  119. * @param {Object[]} menuItems An array of objects containing information about to generated Dropdown Menu items.
  120. */
  121. 'beforeDropdownMenuSetItems',
  122. /**
  123. * Fired by {@link ContextMenu} plugin after hiding the Context Menu. This hook is fired when {@link Options#contextMenu}
  124. * option is enabled.
  125. *
  126. * @event Hooks#afterContextMenuHide
  127. * @param {Object} context The Context Menu plugin instance.
  128. */
  129. 'afterContextMenuHide',
  130. /**
  131. * Fired by {@link ContextMenu} plugin before opening the Context Menu. This hook is fired when {@link Options#contextMenu}
  132. * option is enabled.
  133. *
  134. * @event Hooks#beforeContextMenuShow
  135. * @param {Object} context The Context Menu instance.
  136. */
  137. 'beforeContextMenuShow',
  138. /**
  139. * Fired by {@link ContextMenu} plugin after opening the Context Menu. This hook is fired when {@link Options#contextMenu}
  140. * option is enabled.
  141. *
  142. * @event Hooks#afterContextMenuShow
  143. * @param {Object} context The Context Menu plugin instance.
  144. */
  145. 'afterContextMenuShow',
  146. /**
  147. * Fired by {@link CopyPaste} plugin after reaching the copy limit while copying data. This hook is fired when
  148. * {@link Options#copyPaste} option is enabled.
  149. *
  150. * @event Hooks#afterCopyLimit
  151. * @param {Number} selectedRows Count of selected copyable rows.
  152. * @param {Number} selectedColumns Count of selected copyable columns.
  153. * @param {Number} copyRowsLimit Current copy rows limit.
  154. * @param {Number} copyColumnsLimit Current copy columns limit.
  155. */
  156. 'afterCopyLimit',
  157. /**
  158. * Fired before created a new column.
  159. *
  160. * @event Hooks#beforeCreateCol
  161. * @param {Number} index Represents the visual index of first newly created column in the data source array.
  162. * @param {Number} amount Number of newly created columns in the data source array.
  163. * @param {String} [source] String that identifies source of hook call
  164. * ([list of all available sources]{@link http://docs.handsontable.com/tutorial-using-callbacks.html#page-source-definition}).
  165. */
  166. 'beforeCreateCol',
  167. /**
  168. * Fired after created a new column.
  169. *
  170. * @event Hooks#afterCreateCol
  171. * @param {Number} index Represents the visual index of first newly created column in the data source.
  172. * @param {Number} amount Number of newly created columns in the data source.
  173. * @param {String} [source] String that identifies source of hook call
  174. * ([list of all available sources]{@link http://docs.handsontable.com/tutorial-using-callbacks.html#page-source-definition}).
  175. */
  176. 'afterCreateCol',
  177. /**
  178. * Fired before created a new row.
  179. *
  180. * @event Hooks#beforeCreateRow
  181. * @param {Number} index Represents the visual index of first newly created row in the data source array.
  182. * @param {Number} amount Number of newly created rows in the data source array.
  183. * @param {String} [source] String that identifies source of hook call
  184. * ([list of all available sources]{@link http://docs.handsontable.com/tutorial-using-callbacks.html#page-source-definition}).
  185. */
  186. 'beforeCreateRow',
  187. /**
  188. * Fired after created a new row.
  189. *
  190. * @event Hooks#afterCreateRow
  191. * @param {Number} index Represents the visual index of first newly created row in the data source array.
  192. * @param {Number} amount Number of newly created rows in the data source array.
  193. * @param {String} [source] String that identifies source of hook call
  194. * ([list of all available sources]{@link http://docs.handsontable.com/tutorial-using-callbacks.html#page-source-definition}).
  195. */
  196. 'afterCreateRow',
  197. /**
  198. * Fired after the current cell is deselected.
  199. *
  200. * @event Hooks#afterDeselect
  201. */
  202. 'afterDeselect',
  203. /**
  204. * Fired after destroying the Handsontable instance.
  205. *
  206. * @event Hooks#afterDestroy
  207. */
  208. 'afterDestroy',
  209. /**
  210. * General hook which captures `keydown` events attached to the document body. These events are delegated to the
  211. * hooks system and consumed by Core and internal modules (e.g plugins, editors).
  212. *
  213. * @event Hooks#afterDocumentKeyDown
  214. * @param {Event} event A native `keydown` event object.
  215. */
  216. 'afterDocumentKeyDown',
  217. /**
  218. * Fired inside the Walkontable's selection `draw` method. Can be used to add additional class names to cells, depending on the current selection.
  219. *
  220. * @event Hooks#afterDrawSelection
  221. * @param {Number} currentRow Row index of the currently processed cell.
  222. * @param {Number} currentColumn Column index of the currently cell.
  223. * @param {Number[]} cornersOfSelection Array of the current selection in a form of `[startRow, startColumn, endRow, endColumn]`.
  224. * @param {Number|undefined} layerLevel Number indicating which layer of selection is currently processed.
  225. * @since 0.38.1
  226. * @returns {String|undefined} Can return a `String`, which will act as an additional `className` to be added to the currently processed cell.
  227. */
  228. 'afterDrawSelection',
  229. /**
  230. * Fired inside the Walkontable's `refreshSelections` method. Can be used to remove additional class names from all cells in the table.
  231. *
  232. * @event Hooks#beforeRemoveCellClassNames
  233. * @since 0.38.1
  234. * @returns {String[]|undefined} Can return an `Array` of `String`s. Each of these strings will act like class names to be removed from all the cells in the table.
  235. */
  236. 'beforeRemoveCellClassNames',
  237. /**
  238. * Fired after getting the cell settings.
  239. *
  240. * @event Hooks#afterGetCellMeta
  241. * @param {Number} row Visual row index.
  242. * @param {Number} column Visual column index.
  243. * @param {Object} cellProperties Object containing the cell properties.
  244. */
  245. 'afterGetCellMeta',
  246. /**
  247. * Fired after retrieving information about a column header and appending it to the table header.
  248. *
  249. * @event Hooks#afterGetColHeader
  250. * @param {Number} column Visual column index.
  251. * @param {HTMLTableCellElement} TH Header's TH element.
  252. */
  253. 'afterGetColHeader',
  254. /**
  255. * Fired after retrieving information about a row header and appending it to the table header.
  256. *
  257. * @event Hooks#afterGetRowHeader
  258. * @param {Number} row Visual row index.
  259. * @param {HTMLTableCellElement} TH Header's TH element.
  260. */
  261. 'afterGetRowHeader',
  262. /**
  263. * Fired after the Handsontable instance is initiated.
  264. *
  265. * @event Hooks#afterInit
  266. */
  267. 'afterInit',
  268. /**
  269. * Fired after new data is loaded (by `loadData` or `updateSettings` method) into the data source array.
  270. *
  271. * @event Hooks#afterLoadData
  272. * @param {Boolean} initialLoad flag that determines whether the data has been loaded during the initialization.
  273. */
  274. 'afterLoadData',
  275. /**
  276. * Fired after a scroll event, which is identified as a momentum scroll (e.g. on an iPad).
  277. *
  278. * @event Hooks#afterMomentumScroll
  279. */
  280. 'afterMomentumScroll',
  281. /**
  282. * Fired after a `mousedown` event is triggered on the cell corner (the drag handle).
  283. *
  284. * @event Hooks#afterOnCellCornerMouseDown
  285. * @param {Event} event `mousedown` event object.
  286. */
  287. 'afterOnCellCornerMouseDown',
  288. /**
  289. * Fired after a `dblclick` event is triggered on the cell corner (the drag handle).
  290. *
  291. * @event Hooks#afterOnCellCornerDblClick
  292. * @param {Event} event `dblclick` event object.
  293. */
  294. 'afterOnCellCornerDblClick',
  295. /**
  296. * Fired after clicking on a cell or row/column header. In case the row/column header was clicked, the coordinate
  297. * indexes are negative.
  298. *
  299. * For example clicking on the row header of cell (0, 0) results with `afterOnCellMouseDown` called
  300. * with coordinates `{row: 0, col: -1}`.
  301. *
  302. * @event Hooks#afterOnCellMouseDown
  303. * @param {Event} event `mousedown` event object.
  304. * @param {CellCoords} coords Coordinates object containing the visual row and visual column indexes of the clicked cell.
  305. * @param {HTMLTableCellElement} TD Cell's TD (or TH) element.
  306. */
  307. 'afterOnCellMouseDown',
  308. /**
  309. * Fired after clicking on a cell or row/column header. In case the row/column header was clicked, the coordinate
  310. * indexes are negative.
  311. *
  312. * For example clicking on the row header of cell (0, 0) results with `afterOnCellMouseUp` called
  313. * with coordinates `{row: 0, col: -1}`.
  314. *
  315. * @event Hooks#afterOnCellMouseUp
  316. * @param {Event} event `mouseup` event object.
  317. * @param {CellCoords} coords Coordinates object containing the visual row and visual column indexes of the clicked cell.
  318. * @param {HTMLTableCellElement} TD Cell's TD (or TH) element.
  319. */
  320. 'afterOnCellMouseUp',
  321. /**
  322. * Fired after clicking right mouse button on a cell or row/column header.
  323. *
  324. * For example clicking on the row header of cell (0, 0) results with `afterOnCellContextMenu` called
  325. * with coordinates `{row: 0, col: -1}`.
  326. *
  327. * @event Hooks#afterOnCellContextMenu
  328. * @since 4.1.0
  329. * @param {Event} event `contextmenu` event object.
  330. * @param {CellCoords} coords Coordinates object containing the visual row and visual column indexes of the clicked cell.
  331. * @param {HTMLTableCellElement} TD Cell's TD (or TH) element.
  332. */
  333. 'afterOnCellContextMenu',
  334. /**
  335. * Fired after hovering a cell or row/column header with the mouse cursor. In case the row/column header was
  336. * hovered, the index is negative.
  337. *
  338. * For example, hovering over the row header of cell (0, 0) results with `afterOnCellMouseOver` called
  339. * with coords `{row: 0, col: -1}`.
  340. *
  341. * @event Hooks#afterOnCellMouseOver
  342. * @param {Event} event `mouseover` event object.
  343. * @param {CellCoords} coords Hovered cell's visual coordinate object.
  344. * @param {HTMLTableCellElement} TD Cell's TD (or TH) element.
  345. */
  346. 'afterOnCellMouseOver',
  347. /**
  348. * Fired after leaving a cell or row/column header with the mouse cursor.
  349. *
  350. * @event Hooks#afterOnCellMouseOut
  351. * @param {Event} event `mouseout` event object.
  352. * @param {CellCoords} coords Leaved cell's visual coordinate object.
  353. * @param {HTMLTableCellElement} TD Cell's TD (or TH) element.
  354. */
  355. 'afterOnCellMouseOut',
  356. /**
  357. * Fired after one or more columns are removed.
  358. *
  359. * @event Hooks#afterRemoveCol
  360. * @param {Number} index Visual index of starter column.
  361. * @param {Number} amount An amount of removed columns.
  362. * @param {Number[]} physicalColumns An array of physical columns removed from the data source.
  363. * @param {String} [source] String that identifies source of hook call ([list of all available sources]{@link https://docs.handsontable.com/tutorial-using-callbacks.html#page-source-definition}).
  364. */
  365. 'afterRemoveCol',
  366. /**
  367. * Fired after one or more rows are removed.
  368. *
  369. * @event Hooks#afterRemoveRow
  370. * @param {Number} index Visual index of starter row.
  371. * @param {Number} amount An amount of removed rows.
  372. * @param {Number[]} physicalRows An array of physical rows removed from the data source.
  373. * @param {String} [source] String that identifies source of hook call ([list of all available sources]{@link https://docs.handsontable.com/tutorial-using-callbacks.html#page-source-definition}).
  374. */
  375. 'afterRemoveRow',
  376. /**
  377. * Fired after the Handsontable table is rendered.
  378. *
  379. * @event Hooks#afterRender
  380. * @param {Boolean} isForced Is `true` if rendering was triggered by a change of settings or data; or `false` if
  381. * rendering was triggered by scrolling or moving selection.
  382. */
  383. 'afterRender',
  384. /**
  385. * Fired before starting rendering the cell.
  386. *
  387. * @event Hooks#beforeRenderer
  388. * @param {HTMLTableCellElement} TD Currently rendered cell's TD element.
  389. * @param {Number} row Visual row index.
  390. * @param {Number} column Visual column index.
  391. * @param {String|Number} prop Column property name or a column index, if datasource is an array of arrays.
  392. * @param {*} value Value of the rendered cell.
  393. * @param {Object} cellProperties Object containing the cell's properties.
  394. */
  395. 'beforeRenderer',
  396. /**
  397. * Fired after finishing rendering the cell (after the renderer finishes).
  398. *
  399. * @event Hooks#afterRenderer
  400. * @param {HTMLTableCellElement} TD Currently rendered cell's TD element.
  401. * @param {Number} row Visual row index.
  402. * @param {Number} column Visual column index.
  403. * @param {String|Number} prop Column property name or a column index, if datasource is an array of arrays.
  404. * @param {*} value Value of the rendered cell.
  405. * @param {Object} cellProperties Object containing the cell's properties.
  406. */
  407. 'afterRenderer',
  408. /**
  409. * Fired after the horizontal scroll event.
  410. *
  411. * @event Hooks#afterScrollHorizontally
  412. */
  413. 'afterScrollHorizontally',
  414. /**
  415. * Fired after the vertical scroll event.
  416. *
  417. * @event Hooks#afterScrollVertically
  418. */
  419. 'afterScrollVertically',
  420. /**
  421. * Fired after one or more cells are selected (e.g. during mouse move).
  422. *
  423. * @event Hooks#afterSelection
  424. * @param {Number} row Selection start visual row index.
  425. * @param {Number} column Selection start visual column index.
  426. * @param {Number} row2 Selection end visual row index.
  427. * @param {Number} column2 Selection end visual column index.
  428. * @param {Object} preventScrolling Object with `value` property where its value change will be observed.
  429. * @param {Number} selectionLayerLevel The number which indicates what selection layer is currently modified.
  430. * @example
  431. * ```js
  432. * new Handsontable(element, {
  433. * afterSelection: (row, column, row2, column2, preventScrolling, selectionLayerLevel) => {
  434. * // setting if prevent scrolling after selection
  435. * preventScrolling.value = true;
  436. * }
  437. * })
  438. * ```
  439. */
  440. 'afterSelection',
  441. /**
  442. * Fired after one or more cells are selected.
  443. *
  444. * The `prop` and `prop2` arguments represent the source object property name instead of the column number.
  445. *
  446. * @event Hooks#afterSelectionByProp
  447. * @param {Number} row Selection start visual row index.
  448. * @param {String} prop Selection start data source object property name.
  449. * @param {Number} row2 Selection end visual row index.
  450. * @param {String} prop2 Selection end data source object property name.
  451. * @param {Object} preventScrolling Object with `value` property where its value change will be observed.
  452. * @param {Number} selectionLayerLevel The number which indicates what selection layer is currently modified.
  453. * @example
  454. * ```js
  455. * new Handsontable(element, {
  456. * afterSelectionByProp: (row, column, row2, column2, preventScrolling, selectionLayerLevel) => {
  457. * // setting if prevent scrolling after selection
  458. * preventScrolling.value = true;
  459. * }
  460. * })
  461. * ```
  462. */
  463. 'afterSelectionByProp',
  464. /**
  465. * Fired after one or more cells are selected (e.g. on mouse up).
  466. *
  467. * @event Hooks#afterSelectionEnd
  468. * @param {Number} row Selection start visual row index.
  469. * @param {Number} column Selection start visual column index.
  470. * @param {Number} row2 Selection end visual row index.
  471. * @param {Number} column2 Selection end visual column index.
  472. * @param {Number} selectionLayerLevel The number which indicates what selection layer is currently modified.
  473. */
  474. 'afterSelectionEnd',
  475. /**
  476. * Fired after one or more cells are selected (e.g. on mouse up).
  477. *
  478. * The `prop` and `prop2` arguments represent the source object property name instead of the column number.
  479. *
  480. * @event Hooks#afterSelectionEndByProp
  481. * @param {Number} row Selection start visual row index.
  482. * @param {String} prop Selection start data source object property index.
  483. * @param {Number} row2 Selection end visual row index.
  484. * @param {String} prop2 Selection end data source object property index.
  485. * @param {Number} selectionLayerLevel The number which indicates what selection layer is currently modified.
  486. */
  487. 'afterSelectionEndByProp',
  488. /**
  489. * Fired after cell meta is changed.
  490. *
  491. * @event Hooks#afterSetCellMeta
  492. * @param {Number} row Visual row index.
  493. * @param {Number} column Visual column index.
  494. * @param {String} key The updated meta key.
  495. * @param {*} value The updated meta value.
  496. */
  497. 'afterSetCellMeta',
  498. /**
  499. * Fired after cell meta is removed.
  500. *
  501. * @event Hooks#afterRemoveCellMeta
  502. * @param {Number} row Visual row index.
  503. * @param {Number} column Visual column index.
  504. * @param {String} key The removed meta key.
  505. * @param {*} value Value which was under removed key of cell meta.
  506. */
  507. 'afterRemoveCellMeta',
  508. /**
  509. * Fired after cell data was changed.
  510. *
  511. * @event Hooks#afterSetDataAtCell
  512. * @param {Array} changes An array of changes in format `[[row, column, oldValue, value], ...]`.
  513. * @param {String} [source] String that identifies source of hook call
  514. * ([list of all available sources]{@link http://docs.handsontable.com/tutorial-using-callbacks.html#page-source-definition}).
  515. */
  516. 'afterSetDataAtCell',
  517. /**
  518. * Fired after cell data was changed.
  519. *
  520. * @event Hooks#afterSetDataAtRowProp
  521. * @param {Array} changes An array of changes in format `[[row, prop, oldValue, value], ...]`.
  522. * @param {String} [source] String that identifies source of hook call
  523. * ([list of all available sources]{@link http://docs.handsontable.com/tutorial-using-callbacks.html#page-source-definition}).
  524. */
  525. 'afterSetDataAtRowProp',
  526. /**
  527. * Fired after calling the `updateSettings` method.
  528. *
  529. * @event Hooks#afterUpdateSettings
  530. * @param {Object} newSettings New settings object.
  531. */
  532. 'afterUpdateSettings',
  533. /**
  534. * @description
  535. * A plugin hook executed after validator function, only if validator function is defined.
  536. * Validation result is the first parameter. This can be used to determinate if validation passed successfully or not.
  537. *
  538. * __Returning false from the callback will mark the cell as invalid.__
  539. *
  540. * @event Hooks#afterValidate
  541. * @param {Boolean} isValid `true` if valid, `false` if not.
  542. * @param {*} value The value in question.
  543. * @param {Number} row Visual row index.
  544. * @param {String|Number} prop Property name / visual column index.
  545. * @param {String} [source] String that identifies source of hook call
  546. * ([list of all available sources]{@link http://docs.handsontable.com/tutorial-using-callbacks.html#page-source-definition}).
  547. */
  548. 'afterValidate',
  549. /**
  550. * Fired before successful change of language (when proper language code was set)
  551. *
  552. * @event Hooks#beforeLanguageChange
  553. * @since 0.35.0
  554. * @param {String} languageCode New language code.
  555. */
  556. 'beforeLanguageChange',
  557. /**
  558. * Fired after successful change of language (when proper language code was set).
  559. *
  560. * @event Hooks#afterLanguageChange
  561. * @since 0.35.0
  562. * @param {String} languageCode New language code.
  563. */
  564. 'afterLanguageChange',
  565. /**
  566. * Fired by {@link Autofill} plugin before populating the data in the autofill feature. This hook is fired when
  567. * {@link Options#fillHandle} option is enabled.
  568. *
  569. * @event Hooks#beforeAutofill
  570. * @param {CellCoords} start Object containing information about first filled cell: `{row: 2, col: 0}`.
  571. * @param {CellCoords} end Object containing information about last filled cell: `{row: 4, col: 1}`.
  572. * @param {Array[]} data 2D array containing information about fill pattern: `[["1", "Ted"], ["1", "John"]]`.
  573. */
  574. 'beforeAutofill',
  575. /**
  576. * Fired before aligning the cell contents.
  577. *
  578. * @event Hooks#beforeCellAlignment
  579. * @param {Object} stateBefore An object with class names defining the cell alignment.
  580. * @param {CellRange[]} range An array of CellRange coordinates where the alignment will be applied.
  581. * @param {String} type Type of the alignment - either `horizontal` or `vertical`.
  582. * @param {String} alignmentClass String defining the alignment class added to the cell.
  583. * Possible values:
  584. * * `htLeft`
  585. * * `htCenter`
  586. * * `htRight`
  587. * * `htJustify`
  588. * * `htTop`
  589. * * `htMiddle`
  590. * * `htBottom`
  591. */
  592. 'beforeCellAlignment',
  593. /**
  594. * Fired before one or more cells is changed. Its main purpose is to alter changes silently after input and before
  595. * table rendering.
  596. *
  597. * @event Hooks#beforeChange
  598. * @param {Array[]} changes 2D array containing information about each of the edited cells.
  599. * @param {String} [source] String that identifies source of hook call
  600. * ([list of all available sources]{@link http://docs.handsontable.com/tutorial-using-callbacks.html#page-source-definition}).
  601. * @example
  602. * ```js
  603. * // To disregard a single change, set changes[i] to null or remove it from array using changes.splice(i, 1).
  604. * new Handsontable(element, {
  605. * beforeChange: (changes, source) => {
  606. * // [[row, prop, oldVal, newVal], ...]
  607. * changes[0] = null;
  608. * }
  609. * });
  610. * // To alter a single change, overwrite the desired value to changes[i][3].
  611. * new Handsontable(element, {
  612. * beforeChange: (changes, source) => {
  613. * // [[row, prop, oldVal, newVal], ...]
  614. * changes[0][3] = 10;
  615. * }
  616. * });
  617. * // To cancel all edit, return false from the callback or set array length to 0 (changes.length = 0).
  618. * new Handsontable(element, {
  619. * beforeChange: (changes, source) => {
  620. * // [[row, prop, oldVal, newVal], ...]
  621. * return false;
  622. * }
  623. * });
  624. * ```
  625. */
  626. 'beforeChange',
  627. /**
  628. * Fired right before rendering the changes.
  629. *
  630. * @event Hooks#beforeChangeRender
  631. * @param {Array[]} changes Array in form of `[row, prop, oldValue, newValue]`.
  632. * @param {String} [source] String that identifies source of hook call
  633. * ([list of all available sources]{@link http://docs.handsontable.com/tutorial-using-callbacks.html#page-source-definition}).
  634. */
  635. 'beforeChangeRender',
  636. /**
  637. * Fired before drawing the borders.
  638. *
  639. * @event Hooks#beforeDrawBorders
  640. * @param {Array} corners Array specifying the current selection borders.
  641. * @param {String} borderClassName Specifies the border class name.
  642. */
  643. 'beforeDrawBorders',
  644. /**
  645. * Fired before getting cell settings.
  646. *
  647. * @event Hooks#beforeGetCellMeta
  648. * @param {Number} row Visual row index.
  649. * @param {Number} column Visual column index.
  650. * @param {Object} cellProperties Object containing the cell's properties.
  651. */
  652. 'beforeGetCellMeta',
  653. /**
  654. * Fired before cell meta is removed.
  655. *
  656. * @event Hooks#beforeRemoveCellMeta
  657. * @param {Number} row Visual row index.
  658. * @param {Number} column Visual column index.
  659. * @param {String} key The removed meta key.
  660. * @param {*} value Value which is under removed key of cell meta.
  661. */
  662. 'beforeRemoveCellMeta',
  663. /**
  664. * Fired before the Handsontable instance is initiated.
  665. *
  666. * @event Hooks#beforeInit
  667. */
  668. 'beforeInit',
  669. /**
  670. * Fired before the Walkontable instance is initiated.
  671. *
  672. * @event Hooks#beforeInitWalkontable
  673. * @param {Object} walkontableConfig Walkontable configuration object.
  674. */
  675. 'beforeInitWalkontable',
  676. /**
  677. * Fired before keydown event is handled. It can be used to overwrite default key bindings.
  678. *
  679. * __Note__: To prevent default behavior you need to call `event.stopImmediatePropagation()` in your `beforeKeyDown`
  680. * handler.
  681. *
  682. * @event Hooks#beforeKeyDown
  683. * @param {Event} event Original DOM event.
  684. */
  685. 'beforeKeyDown',
  686. /**
  687. * Fired after the user clicked a cell, but before all the calculations related with it.
  688. *
  689. * @event Hooks#beforeOnCellMouseDown
  690. * @param {Event} event The `mousedown` event object.
  691. * @param {CellCoords} coords Cell coords object containing the visual coordinates of the clicked cell.
  692. * @param {HTMLTableCellElement} TD TD element.
  693. * @param {Object} controller An object with keys `row`, `column` and `cells` which contains boolean values. This
  694. * object allows or disallows changing the selection for the particular axies.
  695. */
  696. 'beforeOnCellMouseDown',
  697. /**
  698. * Fired after the user clicked a cell.
  699. *
  700. * @event Hooks#beforeOnCellMouseUp
  701. * @param {Event} event The `mouseup` event object.
  702. * @param {CellCoords} coords Cell coords object containing the visual coordinates of the clicked cell.
  703. * @param {HTMLTableCellElement} TD TD element.
  704. * @param {Object} controller An object with keys `row`, `column` and `cells` which contains boolean values. This
  705. * object allows or disallows changing the selection for the particular axies.
  706. */
  707. 'beforeOnCellMouseUp',
  708. /**
  709. * Fired after the user clicked a cell, but before all the calculations related with it.
  710. *
  711. * @event Hooks#beforeOnCellContextMenu
  712. * @since 4.1.0
  713. * @param {Event} event The `contextmenu` event object.
  714. * @param {CellCoords} coords Cell coords object containing the visual coordinates of the clicked cell.
  715. * @param {HTMLTableCellElement} TD TD element.
  716. */
  717. 'beforeOnCellContextMenu',
  718. /**
  719. * Fired after the user moved cursor over a cell, but before all the calculations related with it.
  720. *
  721. * @event Hooks#beforeOnCellMouseOver
  722. * @param {Event} event The `mouseover` event object.
  723. * @param {CellCoords} coords CellCoords object containing the visual coordinates of the clicked cell.
  724. * @param {HTMLTableCellElement} TD TD element.
  725. * @param {Object} controller An object with keys `row`, `column` and `cells` which contains boolean values. This
  726. * object allows or disallows changing the selection for the particular axies.
  727. */
  728. 'beforeOnCellMouseOver',
  729. /**
  730. * Fired after the user moved cursor out from a cell, but before all the calculations related with it.
  731. *
  732. * @event Hooks#beforeOnCellMouseOut
  733. * @param {Event} event The `mouseout` event object.
  734. * @param {CellCoords} coords CellCoords object containing the visual coordinates of the leaved cell.
  735. * @param {HTMLTableCellElement} TD TD element.
  736. */
  737. 'beforeOnCellMouseOut',
  738. /**
  739. * Fired before one or more columns are about to be removed.
  740. *
  741. * @event Hooks#beforeRemoveCol
  742. * @param {Number} index Visual index of starter column.
  743. * @param {Number} amount Amount of columns to be removed.
  744. * @param {Number[]} physicalColumns An array of physical columns removed from the data source.
  745. * @param {String} [source] String that identifies source of hook call ([list of all available sources]{@link https://docs.handsontable.com/tutorial-using-callbacks.html#page-source-definition}).
  746. */
  747. 'beforeRemoveCol',
  748. /**
  749. * Fired when one or more rows are about to be removed.
  750. *
  751. * @event Hooks#beforeRemoveRow
  752. * @param {Number} index Visual index of starter column.
  753. * @param {Number} amount Amount of columns to be removed.
  754. * @param {Number[]} physicalRows An array of physical rows removed from the data source.
  755. * @param {String} [source] String that identifies source of hook call ([list of all available sources]{@link https://docs.handsontable.com/tutorial-using-callbacks.html#page-source-definition}).
  756. */
  757. 'beforeRemoveRow',
  758. /**
  759. * Fired before the Handsontable table is rendered.
  760. *
  761. * @event Hooks#beforeRender
  762. * @param {Boolean} isForced If `true` rendering was triggered by a change of settings or data; or `false` if
  763. * rendering was triggered by scrolling or moving selection.
  764. */
  765. 'beforeRender',
  766. /**
  767. * Fired before setting range is started but not finished yet.
  768. *
  769. * @event Hooks#beforeSetRangeStartOnly
  770. * @param {CellCoords} coords CellCoords instance.
  771. */
  772. 'beforeSetRangeStartOnly',
  773. /**
  774. * Fired before setting range is started.
  775. *
  776. * @event Hooks#beforeSetRangeStart
  777. * @param {CellCoords} coords CellCoords instance.
  778. */
  779. 'beforeSetRangeStart',
  780. /**
  781. * Fired before setting range is ended.
  782. *
  783. * @event Hooks#beforeSetRangeEnd
  784. * @param {CellCoords} coords CellCoords instance.
  785. */
  786. 'beforeSetRangeEnd',
  787. /**
  788. * Fired before the logic of handling a touch scroll, when user started scrolling on a touch-enabled device.
  789. *
  790. * @event Hooks#beforeTouchScroll
  791. */
  792. 'beforeTouchScroll',
  793. /**
  794. * Fired before cell validation, only if validator function is defined. This can be used to manipulate the value
  795. * of changed cell before it is applied to the validator function.
  796. *
  797. * __Note:__ this will not affect values of changes. This will change value *ONLY* for validation
  798. *
  799. * @event Hooks#beforeValidate
  800. * @param {*} value Value of the cell.
  801. * @param {Number} row Visual row index.
  802. * @param {String|Number} prop Property name / column index.
  803. * @param {String} [source] String that identifies source of hook call
  804. * ([list of all available sources]{@link http://docs.handsontable.com/tutorial-using-callbacks.html#page-source-definition}).
  805. */
  806. 'beforeValidate',
  807. /**
  808. * Fired before cell value is rendered into the DOM (through renderer function). This can be used to manipulate the
  809. * value which is passed to the renderer without modifying the renderer itself.
  810. *
  811. * @event Hooks#beforeValueRender
  812. * @param {*} value Cell value to render.
  813. * @param {Object} cellProperties An object containing the cell properties.
  814. */
  815. 'beforeValueRender',
  816. /**
  817. * Fired after Handsontable instance is constructed (using `new` operator).
  818. *
  819. * @event Hooks#construct
  820. */
  821. 'construct',
  822. /**
  823. * Fired after Handsontable instance is initiated but before table is rendered.
  824. *
  825. * @event Hooks#init
  826. */
  827. 'init',
  828. /**
  829. * Fired when a column index is about to be modified by a callback function.
  830. *
  831. * @event Hooks#modifyCol
  832. * @param {Number} column Visual column index.
  833. */
  834. 'modifyCol',
  835. /**
  836. * Fired when a column index is about to be de-modified by a callback function.
  837. *
  838. * @event Hooks#unmodifyCol
  839. * @param {Number} column Physical column index.
  840. */
  841. 'unmodifyCol',
  842. /**
  843. * Fired when a physical row index is about to be de-modified by a callback function.
  844. *
  845. * @event Hooks#unmodifyRow
  846. * @param {Number} row Physical row index.
  847. */
  848. 'unmodifyRow',
  849. /**
  850. * Fired when a column header index is about to be modified by a callback function.
  851. *
  852. * @event Hooks#modifyColHeader
  853. * @param {Number} column Visual column header index.
  854. */
  855. 'modifyColHeader',
  856. /**
  857. * Fired when a column width is about to be modified by a callback function.
  858. *
  859. * @event Hooks#modifyColWidth
  860. * @param {Number} width Current column width.
  861. * @param {Number} column Visual column index.
  862. */
  863. 'modifyColWidth',
  864. /**
  865. * Fired when a row index is about to be modified by a callback function.
  866. *
  867. * @event Hooks#modifyRow
  868. * @param {Number} row Visual row index.
  869. */
  870. 'modifyRow',
  871. /**
  872. * Fired when a row header index is about to be modified by a callback function.
  873. *
  874. * @event Hooks#modifyRowHeader
  875. * @param {Number} row Visual row header index.
  876. */
  877. 'modifyRowHeader',
  878. /**
  879. * Fired when a row height is about to be modified by a callback function.
  880. *
  881. * @event Hooks#modifyRowHeight
  882. * @param {Number} height Row height.
  883. * @param {Number} row Visual row index.
  884. */
  885. 'modifyRowHeight',
  886. /**
  887. * Fired when a data was retrieved or modified.
  888. *
  889. * @event Hooks#modifyData
  890. * @param {Number} row Row height.
  891. * @param {Number} column Column index.
  892. * @param {Object} valueHolder Object which contains original value which can be modified by overwriting `.value` property.
  893. * @param {String} ioMode String which indicates for what operation hook is fired (`get` or `set`).
  894. */
  895. 'modifyData',
  896. /**
  897. * Fired when a data was retrieved or modified.
  898. *
  899. * @event Hooks#modifyRowData
  900. * @param {Number} row Physical row index.
  901. */
  902. 'modifyRowData',
  903. /**
  904. * Used to modify the cell coordinates when using the `getCell` method.
  905. *
  906. * @event Hooks#modifyGetCellCoords
  907. * @since 0.36.0
  908. * @param {Number} row Visual row index.
  909. * @param {Number} column Visual column index.
  910. * @param {Boolean} topmost If set to `true`, it returns the TD element from the topmost overlay. For example,
  911. * if the wanted cell is in the range of fixed rows, it will return a TD element
  912. * from the `top` overlay.
  913. */
  914. 'modifyGetCellCoords',
  915. /**
  916. * Fired by {@link PersistentState} plugin, after loading value, saved under given key, from browser local storage. This hook is fired when
  917. * {@link Options#persistentState} option is enabled.
  918. *
  919. * @event Hooks#persistentStateLoad
  920. * @param {String} key Key.
  921. * @param {Object} valuePlaceholder Object containing the loaded value under `valuePlaceholder.value` (if no value have been saved, `value` key will be undefined).
  922. */
  923. 'persistentStateLoad',
  924. /**
  925. * Fired by {@link PersistentState} plugin after resetting data from local storage. If no key is given, all values associated with table will be cleared.
  926. * This hook is fired when {@link Options#persistentState} option is enabled.
  927. *
  928. * @event Hooks#persistentStateReset
  929. * @param {String} [key] Key.
  930. */
  931. 'persistentStateReset',
  932. /**
  933. * Fired by {@link PersistentState} plugin, after saving value under given key in browser local storage. This hook is fired when
  934. * {@link Options#persistentState} option is enabled.
  935. *
  936. * @event Hooks#persistentStateSave
  937. * @param {String} key Key.
  938. * @param {Mixed} value Value to save.
  939. */
  940. 'persistentStateSave',
  941. /**
  942. * Fired by {@link ColumnSorting} and {@link MultiColumnSorting} plugins before sorting the column. If you return `false` value inside callback for hook, then sorting
  943. * will be not applied by the Handsontable (useful for server-side sorting).
  944. *
  945. * This hook is fired when {@link Options#columnSorting} or {@link Options#multiColumnSorting} option is enabled.
  946. *
  947. * @event Hooks#beforeColumnSort
  948. * @param {Array} currentSortConfig Current sort configuration (for all sorted columns).
  949. * @param {Array} destinationSortConfigs Destination sort configuration (for all sorted columns).
  950. */
  951. 'beforeColumnSort',
  952. /**
  953. * Fired by {@link ColumnSorting} and {@link MultiColumnSorting} plugins after sorting the column. This hook is fired when {@link Options#columnSorting}
  954. * or {@link Options#multiColumnSorting} option is enabled.
  955. *
  956. * @event Hooks#afterColumnSort
  957. * @param {Array} currentSortConfig Current sort configuration (for all sorted columns).
  958. * @param {Array} destinationSortConfigs Destination sort configuration (for all sorted columns).
  959. */
  960. 'afterColumnSort',
  961. /**
  962. * Fired by {@link Autofill} plugin after setting range of autofill. This hook is fired when {@link Options#fillHandle}
  963. * option is enabled.
  964. *
  965. * @event Hooks#modifyAutofillRange
  966. * @param {Array} startArea Array of visual coordinates of the starting point for the drag-down operation (`[startRow, startColumn, endRow, endColumn]`).
  967. * @param {Array} entireArea Array of visual coordinates of the entire area of the drag-down operation (`[startRow, startColumn, endRow, endColumn]`).
  968. */
  969. 'modifyAutofillRange',
  970. /**
  971. * Fired to allow modifying the copyable range with a callback function.
  972. *
  973. * @event Hooks#modifyCopyableRange
  974. * @param {Array[]} copyableRanges Array of objects defining copyable cells.
  975. */
  976. 'modifyCopyableRange',
  977. /**
  978. * Fired by {@link CopyPaste} plugin before copying the values into clipboard and before clearing values of
  979. * the selected cells. This hook is fired when {@link Options#copyPaste} option is enabled.
  980. *
  981. * @event Hooks#beforeCut
  982. * @param {Array[]} data An array of arrays which contains data to cut.
  983. * @param {Object[]} coords An array of objects with ranges of the visual indexes (`startRow`, `startCol`, `endRow`, `endCol`)
  984. * which will be cut out.
  985. * @returns {*} If returns `false` then operation of the cutting out is canceled.
  986. * @example
  987. * ```js
  988. * // To disregard a single row, remove it from the array using data.splice(i, 1).
  989. * new Handsontable(element, {
  990. * beforeCut: function(data, coords) {
  991. * // data -> [[1, 2, 3], [4, 5, 6]]
  992. * data.splice(0, 1);
  993. * // data -> [[4, 5, 6]]
  994. * // coords -> [{startRow: 0, startCol: 0, endRow: 1, endCol: 2}]
  995. * }
  996. * });
  997. * // To cancel a cutting action, just return `false`.
  998. * new Handsontable(element, {
  999. * beforeCut: function(data, coords) {
  1000. * return false;
  1001. * }
  1002. * });
  1003. * ```
  1004. */
  1005. 'beforeCut',
  1006. /**
  1007. * Fired by {@link CopyPaste} plugin after data was cut out from the table. This hook is fired when
  1008. * {@link Options#copyPaste} option is enabled.
  1009. *
  1010. * @event Hooks#afterCut
  1011. * @param {Array[]} data An array of arrays which contains the cutted out data.
  1012. * @param {Object[]} coords An array of objects with ranges of the visual indexes (`startRow`, `startCol`, `endRow`, `endCol`)
  1013. * which was cut out.
  1014. */
  1015. 'afterCut',
  1016. /**
  1017. * Fired before values are copied into clipboard.
  1018. *
  1019. * @event Hooks#beforeCopy
  1020. * @param {Array[]} data An array of arrays which contains data to copied.
  1021. * @param {Object[]} coords An array of objects with ranges of the visual indexes (`startRow`, `startCol`, `endRow`, `endCol`)
  1022. * which will copied.
  1023. * @returns {*} If returns `false` then copying is canceled.
  1024. *
  1025. * @example
  1026. * ```js
  1027. * // To disregard a single row, remove it from array using data.splice(i, 1).
  1028. * ...
  1029. * new Handsontable(document.getElementById('example'), {
  1030. * beforeCopy: (data, coords) => {
  1031. * // data -> [[1, 2, 3], [4, 5, 6]]
  1032. * data.splice(0, 1);
  1033. * // data -> [[4, 5, 6]]
  1034. * // coords -> [{startRow: 0, startCol: 0, endRow: 1, endCol: 2}]
  1035. * }
  1036. * });
  1037. * ...
  1038. *
  1039. * // To cancel copying, return false from the callback.
  1040. * ...
  1041. * new Handsontable(document.getElementById('example'), {
  1042. * beforeCopy: (data, coords) => {
  1043. * return false;
  1044. * }
  1045. * });
  1046. * ...
  1047. * ```
  1048. */
  1049. 'beforeCopy',
  1050. /**
  1051. * Fired by {@link CopyPaste} plugin after data are pasted into table. This hook is fired when {@link Options#copyPaste}
  1052. * option is enabled.
  1053. *
  1054. * @event Hooks#afterCopy
  1055. * @param {Array[]} data An array of arrays which contains the copied data.
  1056. * @param {Object[]} coords An array of objects with ranges of the visual indexes (`startRow`, `startCol`, `endRow`, `endCol`)
  1057. * which was copied.
  1058. */
  1059. 'afterCopy',
  1060. /**
  1061. * Fired by {@link CopyPaste} plugin before values are pasted into table. This hook is fired when
  1062. * {@link Options#copyPaste} option is enabled.
  1063. *
  1064. * @event Hooks#beforePaste
  1065. * @param {Array[]} data An array of arrays which contains data to paste.
  1066. * @param {Object[]} coords An array of objects with ranges of the visual indexes (`startRow`, `startCol`, `endRow`, `endCol`)
  1067. * that correspond to the previously selected area.
  1068. * @returns {*} If returns `false` then pasting is canceled.
  1069. * @example
  1070. * ```js
  1071. * // To disregard a single row, remove it from array using data.splice(i, 1).
  1072. * new Handsontable(example, {
  1073. * beforePaste: (data, coords) => {
  1074. * // data -> [[1, 2, 3], [4, 5, 6]]
  1075. * data.splice(0, 1);
  1076. * // data -> [[4, 5, 6]]
  1077. * // coords -> [{startRow: 0, startCol: 0, endRow: 1, endCol: 2}]
  1078. * }
  1079. * });
  1080. * // To cancel pasting, return false from the callback.
  1081. * new Handsontable(example, {
  1082. * beforePaste: (data, coords) => {
  1083. * return false;
  1084. * }
  1085. * });
  1086. * ```
  1087. */
  1088. 'beforePaste',
  1089. /**
  1090. * Fired by {@link CopyPaste} plugin after values are pasted into table. This hook is fired when
  1091. * {@link Options#copyPaste} option is enabled.
  1092. *
  1093. * @event Hooks#afterPaste
  1094. * @param {Array[]} data An array of arrays which contains the pasted data.
  1095. * @param {Object[]} coords An array of objects with ranges of the visual indexes (`startRow`, `startCol`, `endRow`, `endCol`)
  1096. * that correspond to the previously selected area.
  1097. */
  1098. 'afterPaste',
  1099. /**
  1100. * Fired by {@link ManualColumnMove} plugin before change order of the visual indexes. This hook is fired when
  1101. * {@link Options#manualColumnMove} option is enabled.
  1102. *
  1103. * @event Hooks#beforeColumnMove
  1104. * @param {Number[]} columns Array of visual column indexes to be moved.
  1105. * @param {Number} target Visual column index being a target for moved columns.
  1106. */
  1107. 'beforeColumnMove',
  1108. /**
  1109. * Fired by {@link ManualColumnMove} plugin after changing order of the visual indexes. This hook is fired when
  1110. * {@link Options#manualColumnMove} option is enabled.
  1111. *
  1112. * @event Hooks#afterColumnMove
  1113. * @param {Number[]} columns Array of visual column indexes that were moved.
  1114. * @param {Number} target Visual column index being a target for moved columns.
  1115. */
  1116. 'afterColumnMove',
  1117. /**
  1118. * Fired by {@link ManualRowMove} plugin before change order of the visual indexes. This hook is fired when
  1119. * {@link Options#manualRowMove} option is enabled.
  1120. *
  1121. * @event Hooks#beforeRowMove
  1122. * @param {Number[]} rows An array of visual row indexes to be moved.
  1123. * @param {Number} target Visual row index being a target for moved rows.
  1124. */
  1125. 'beforeRowMove',
  1126. /**
  1127. * Fired by {@link ManualRowMove} plugin after change order of the visual indexes. This hook is fired when
  1128. * {@link Options#manualRowMove} option is enabled.
  1129. *
  1130. * @event Hooks#afterRowMove
  1131. * @param {Number[]} rows An array of visual row indexes that were moved.
  1132. * @param {Number} target Visual row index being a target for moved rows.
  1133. */
  1134. 'afterRowMove',
  1135. /**
  1136. * Fired by {@link ManualColumnResize} plugin before rendering the table with modified column sizes. This hook is
  1137. * fired when {@link Options#manualColumnResize} option is enabled.
  1138. *
  1139. * @event Hooks#beforeColumnResize
  1140. * @param {Number} currentColumn Visual index of the resized column.
  1141. * @param {Number} newSize Calculated new column width.
  1142. * @param {Boolean} isDoubleClick Flag that determines whether there was a double-click.
  1143. * @returns {Number} Returns a new column size or `undefined`, if column size should be calculated automatically.
  1144. */
  1145. 'beforeColumnResize',
  1146. /**
  1147. * Fired by {@link ManualColumnResize} plugin after rendering the table with modified column sizes. This hook is
  1148. * fired when {@link Options#manualColumnResize} option is enabled.
  1149. *
  1150. * @event Hooks#afterColumnResize
  1151. * @param {Number} currentColumn Visual index of the resized column.
  1152. * @param {Number} newSize Calculated new column width.
  1153. * @param {Boolean} isDoubleClick Flag that determines whether there was a double-click.
  1154. */
  1155. 'afterColumnResize',
  1156. /**
  1157. * Fired by {@link ManualRowResize} plugin before rendering the table with modified row sizes. This hook is
  1158. * fired when {@link Options#manualRowResize} option is enabled.
  1159. *
  1160. * @event Hooks#beforeRowResize
  1161. * @param {Number} currentRow Visual index of the resized row.
  1162. * @param {Number} newSize Calculated new row height.
  1163. * @param {Boolean} isDoubleClick Flag that determines whether there was a double-click.
  1164. * @returns {Number} Returns the new row size or `undefined` if row size should be calculated automatically.
  1165. */
  1166. 'beforeRowResize',
  1167. /**
  1168. * Fired by {@link ManualRowResize} plugin after rendering the table with modified row sizes. This hook is
  1169. * fired when {@link Options#manualRowResize} option is enabled.
  1170. *
  1171. * @event Hooks#afterRowResize
  1172. * @param {Number} currentRow Visual index of the resized row.
  1173. * @param {Number} newSize Calculated new row height.
  1174. * @param {Boolean} isDoubleClick Flag that determines whether there was a double-click.
  1175. */
  1176. 'afterRowResize',
  1177. /**
  1178. * Fired after getting the column header renderers.
  1179. *
  1180. * @event Hooks#afterGetColumnHeaderRenderers
  1181. * @param {Function[]} renderers An array of the column header renderers.
  1182. */
  1183. 'afterGetColumnHeaderRenderers',
  1184. /**
  1185. * Fired after getting the row header renderers.
  1186. *
  1187. * @event Hooks#afterGetRowHeaderRenderers
  1188. * @param {Function[]} renderers An array of the row header renderers.
  1189. */
  1190. 'afterGetRowHeaderRenderers',
  1191. /**
  1192. * Fired before applying stretched column width to column.
  1193. *
  1194. * @event Hooks#beforeStretchingColumnWidth
  1195. * @param {Number} stretchedWidth Calculated width.
  1196. * @param {Number} column Visual column index.
  1197. * @returns {Number} Returns new width which will be applied to the column element.
  1198. */
  1199. 'beforeStretchingColumnWidth',
  1200. /**
  1201. * Fired by {@link Filters} plugin before applying [filtering]{@link http://docs.handsontable.com/pro/demo-filtering.html}. This hook is fired when
  1202. * {@link Options#filters} option is enabled.
  1203. *
  1204. * @pro
  1205. * @event Hooks#beforeFilter
  1206. * @param {Object[]} conditionsStack An array of objects with added formulas.
  1207. * ```js
  1208. * // Example format of the conditionsStack argument:
  1209. * [
  1210. * {
  1211. * column: 2,
  1212. * conditions: [
  1213. * {name: 'begins_with', args: [['S']]}
  1214. * ],
  1215. * operation: 'conjunction'
  1216. * },
  1217. * {
  1218. * column: 4,
  1219. * conditions: [
  1220. * {name: 'not_empty', args: []}
  1221. * ],
  1222. * operation: 'conjunction'
  1223. * },
  1224. * ]
  1225. * ```
  1226. * @returns {Boolean} If hook returns `false` value then filtering won't be applied on the UI side (server-side filtering).
  1227. */
  1228. 'beforeFilter',
  1229. /**
  1230. * Fired by {@link Filters} plugin after applying [filtering]{@link http://docs.handsontable.com/pro/demo-filtering.html}. This hook is fired when
  1231. * {@link Options#filters} option is enabled.
  1232. *
  1233. * @pro
  1234. * @event Hooks#afterFilter
  1235. * @param {Object[]} conditionsStack An array of objects with added conditions.
  1236. * ```js
  1237. * // Example format of the conditionsStack argument:
  1238. * [
  1239. * {
  1240. * column: 2,
  1241. * conditions: [
  1242. * {name: 'begins_with', args: [['S']]}
  1243. * ],
  1244. * operation: 'conjunction'
  1245. * },
  1246. * {
  1247. * column: 4,
  1248. * conditions: [
  1249. * {name: 'not_empty', args: []}
  1250. * ],
  1251. * operation: 'conjunction'
  1252. * },
  1253. * ]
  1254. * ```
  1255. */
  1256. 'afterFilter',
  1257. /**
  1258. * Fired while retrieving the column header height.
  1259. *
  1260. * @event Hooks#modifyColumnHeaderHeight
  1261. */
  1262. 'modifyColumnHeaderHeight',
  1263. /**
  1264. * Fired by {@link UndoRedo} plugin before the undo action. Contains information about the action that is being undone.
  1265. * This hook is fired when {@link Options#undo} option is enabled.
  1266. *
  1267. * @event Hooks#beforeUndo
  1268. * @param {Object} action The action object. Contains information about the action being undone. The `actionType`
  1269. * property of the object specifies the type of the action in a String format. (e.g. `'remove_row'`).
  1270. */
  1271. 'beforeUndo',
  1272. /**
  1273. * Fired by {@link UndoRedo} plugin after the undo action. Contains information about the action that is being undone.
  1274. * This hook is fired when {@link Options#undo} option is enabled.
  1275. *
  1276. * @event Hooks#afterUndo
  1277. * @param {Object} action The action object. Contains information about the action being undone. The `actionType`
  1278. * property of the object specifies the type of the action in a String format. (e.g. `'remove_row'`).
  1279. */
  1280. 'afterUndo',
  1281. /**
  1282. * Fired by {@link UndoRedo} plugin before the redo action. Contains information about the action that is being redone.
  1283. * This hook is fired when {@link Options#undo} option is enabled.
  1284. *
  1285. * @event Hooks#beforeRedo
  1286. * @param {Object} action The action object. Contains information about the action being redone. The `actionType`
  1287. * property of the object specifies the type of the action in a String format (e.g. `'remove_row'`).
  1288. */
  1289. 'beforeRedo',
  1290. /**
  1291. * Fired by {@link UndoRedo} plugin after the redo action. Contains information about the action that is being redone.
  1292. * This hook is fired when {@link Options#undo} option is enabled.
  1293. *
  1294. * @event Hooks#afterRedo
  1295. * @param {Object} action The action object. Contains information about the action being redone. The `actionType`
  1296. * property of the object specifies the type of the action in a String format (e.g. `'remove_row'`).
  1297. */
  1298. 'afterRedo',
  1299. /**
  1300. * Fired while retrieving the row header width.
  1301. *
  1302. * @event Hooks#modifyRowHeaderWidth
  1303. * @param {Number} rowHeaderWidth Row header width.
  1304. */
  1305. 'modifyRowHeaderWidth',
  1306. /**
  1307. * Fired from the `populateFromArray` method during the `autofill` process. Fired for each "autofilled" cell individually.
  1308. *
  1309. * @event Hooks#beforeAutofillInsidePopulate
  1310. * @param {Object} index Object containing `row` and `col` properties, defining the number of rows/columns from the initial cell of the autofill.
  1311. * @param {String} direction Declares the direction of the autofill. Possible values: `up`, `down`, `left`, `right`.
  1312. * @param {Array[]} input Contains an array of rows with data being used in the autofill.
  1313. * @param {Array} deltas The deltas array passed to the `populateFromArray` method.
  1314. */
  1315. 'beforeAutofillInsidePopulate',
  1316. /**
  1317. * Fired when the start of the selection is being modified (e.g. moving the selection with the arrow keys).
  1318. *
  1319. * @event Hooks#modifyTransformStart
  1320. * @param {CellCoords} delta Cell coords object declaring the delta of the new selection relative to the previous one.
  1321. */
  1322. 'modifyTransformStart',
  1323. /**
  1324. * Fired when the end of the selection is being modified (e.g. moving the selection with the arrow keys).
  1325. *
  1326. * @event Hooks#modifyTransformEnd
  1327. * @param {CellCoords} delta Cell coords object declaring the delta of the new selection relative to the previous one.
  1328. */
  1329. 'modifyTransformEnd',
  1330. /**
  1331. * Fired after the start of the selection is being modified (e.g. moving the selection with the arrow keys).
  1332. *
  1333. * @event Hooks#afterModifyTransformStart
  1334. * @param {CellCoords} coords Coords of the freshly selected cell.
  1335. * @param {Number} rowTransformDir `-1` if trying to select a cell with a negative row index. `0` otherwise.
  1336. * @param {Number} colTransformDir `-1` if trying to select a cell with a negative column index. `0` otherwise.
  1337. */
  1338. 'afterModifyTransformStart',
  1339. /**
  1340. * Fired after the end of the selection is being modified (e.g. moving the selection with the arrow keys).
  1341. *
  1342. * @event Hooks#afterModifyTransformEnd
  1343. * @param {CellCoords} coords Visual coords of the freshly selected cell.
  1344. * @param {Number} rowTransformDir `-1` if trying to select a cell with a negative row index. `0` otherwise.
  1345. * @param {Number} colTransformDir `-1` if trying to select a cell with a negative column index. `0` otherwise.
  1346. */
  1347. 'afterModifyTransformEnd',
  1348. /**
  1349. * Fired inside the `viewportRowCalculatorOverride` method. Allows modifying the row calculator parameters.
  1350. *
  1351. * @event Hooks#afterViewportRowCalculatorOverride
  1352. * @param {Object} calc The row calculator.
  1353. */
  1354. 'afterViewportRowCalculatorOverride',
  1355. /**
  1356. * Fired inside the `viewportColumnCalculatorOverride` method. Allows modifying the row calculator parameters.
  1357. *
  1358. * @event Hooks#afterViewportColumnCalculatorOverride
  1359. * @param {Object} calc The row calculator.
  1360. */
  1361. 'afterViewportColumnCalculatorOverride',
  1362. /**
  1363. * Fired after initializing all the plugins.
  1364. *
  1365. * @event Hooks#afterPluginsInitialized
  1366. */
  1367. 'afterPluginsInitialized',
  1368. /**
  1369. * Used to skip the length cache calculation for a defined period of time.
  1370. *
  1371. * @event Hooks#skipLengthCache
  1372. * @param {Number} delay The delay in milliseconds.
  1373. */
  1374. 'skipLengthCache',
  1375. /**
  1376. * Fired by {@link TrimRows} plugin after trimming rows. This hook is fired when {@link Options#trimRows} option is enabled.
  1377. *
  1378. * @pro
  1379. * @event Hooks#afterTrimRow
  1380. * @param {Number[]} rows Physical indexes of trimmed rows.
  1381. */
  1382. 'afterTrimRow',
  1383. /**
  1384. * Fired by {@link TrimRows} plugin after untrimming rows. This hook is fired when {@link Options#trimRows} option is enabled.
  1385. *
  1386. * @pro
  1387. * @event Hooks#afterUntrimRow
  1388. * @param {Number[]} rows Physical indexes of untrimmed rows.
  1389. */
  1390. 'afterUntrimRow',
  1391. /**
  1392. * Fired by {@link DropdownMenu} plugin before opening the dropdown menu. This hook is fired when {@link Options#dropdownMenu}
  1393. * option is enabled.
  1394. *
  1395. * @pro
  1396. * @event Hooks#beforeDropdownMenuShow
  1397. * @param {DropdownMenu} dropdownMenu The DropdownMenu instance.
  1398. */
  1399. 'beforeDropdownMenuShow',
  1400. /**
  1401. * Fired by {@link DropdownMenu} plugin after opening the Dropdown Menu. This hook is fired when {@link Options#dropdownMenu}
  1402. * option is enabled.
  1403. *
  1404. * @pro
  1405. * @event Hooks#afterDropdownMenuShow
  1406. * @param {DropdownMenu} dropdownMenu The DropdownMenu instance.
  1407. */
  1408. 'afterDropdownMenuShow',
  1409. /**
  1410. * Fired by {@link DropdownMenu} plugin after hiding the Dropdown Menu. This hook is fired when {@link Options#dropdownMenu}
  1411. * option is enabled.
  1412. *
  1413. * @pro
  1414. * @event Hooks#afterDropdownMenuHide
  1415. * @param {DropdownMenu} instance The DropdownMenu instance.
  1416. */
  1417. 'afterDropdownMenuHide',
  1418. /**
  1419. * Fired by {@link HiddenRows} plugin to check whether the provided row index is hidden. This hook is fired when
  1420. * {@link Options#hiddenRows} option is enabled.
  1421. *
  1422. * @pro
  1423. * @event Hooks#hiddenRow
  1424. * @param {Number} row The visual row index in question.
  1425. */
  1426. 'hiddenRow',
  1427. /**
  1428. * Fired by {@link HiddenColumns} plugin to check whether the provided column index is hidden. This hook is fired when
  1429. * {@link Options#hiddenColumns} option is enabled.
  1430. *
  1431. * @pro
  1432. * @event Hooks#hiddenColumn
  1433. * @param {Number} column The visual column index in question.
  1434. */
  1435. 'hiddenColumn',
  1436. /**
  1437. * Fired by {@link NestedRows} plugin before adding a children to the NestedRows structure. This hook is fired when
  1438. * {@link Options#nestedRows} option is enabled.
  1439. *
  1440. * @pro
  1441. * @event Hooks#beforeAddChild
  1442. * @param {Object} parent The parent object.
  1443. * @param {Object|undefined} element The element added as a child. If `undefined`, a blank child was added.
  1444. * @param {Number|undefined} index The index within the parent where the new child was added. If `undefined`, the element was added as the last child.
  1445. */
  1446. 'beforeAddChild',
  1447. /**
  1448. * Fired by {@link NestedRows} plugin after adding a children to the NestedRows structure. This hook is fired when
  1449. * {@link Options#nestedRows} option is enabled.
  1450. *
  1451. * @pro
  1452. * @event Hooks#afterAddChild
  1453. * @param {Object} parent The parent object.
  1454. * @param {Object|undefined} element The element added as a child. If `undefined`, a blank child was added.
  1455. * @param {Number|undefined} index The index within the parent where the new child was added. If `undefined`, the element was added as the last child.
  1456. */
  1457. 'afterAddChild',
  1458. /**
  1459. * Fired by {@link NestedRows} plugin before detaching a child from its parent. This hook is fired when
  1460. * {@link Options#nestedRows} option is enabled.
  1461. *
  1462. * @pro
  1463. * @event Hooks#beforeDetachChild
  1464. * @param {Object} parent An object representing the parent from which the element is to be detached.
  1465. * @param {Object} element The detached element.
  1466. */
  1467. 'beforeDetachChild',
  1468. /**
  1469. * Fired by {@link NestedRows} plugin after detaching a child from its parent. This hook is fired when
  1470. * {@link Options#nestedRows} option is enabled.
  1471. *
  1472. * @pro
  1473. * @event Hooks#afterDetachChild
  1474. * @param {Object} parent An object representing the parent from which the element was detached.
  1475. * @param {Object} element The detached element.
  1476. */
  1477. 'afterDetachChild',
  1478. /**
  1479. * Fired after the editor is opened and rendered.
  1480. *
  1481. * @event Hooks#afterBeginEditing
  1482. * @param {Number} row Visual row index of the edited cell.
  1483. * @param {Number} column Visual column index of the edited cell.
  1484. */
  1485. 'afterBeginEditing',
  1486. /**
  1487. * Fired by {@link MergeCells} plugin before cell merging. This hook is fired when {@link Options#mergeCells}
  1488. * option is enabled.
  1489. *
  1490. * @event Hooks#beforeMergeCells
  1491. * @param {CellRange} cellRange Selection cell range.
  1492. * @param {Boolean} [auto=false] `true` if called automatically by the plugin.
  1493. */
  1494. 'beforeMergeCells',
  1495. /**
  1496. * Fired by {@link MergeCells} plugin after cell merging. This hook is fired when {@link Options#mergeCells}
  1497. * option is enabled.
  1498. *
  1499. * @event Hooks#afterMergeCells
  1500. * @param {CellRange} cellRange Selection cell range.
  1501. * @param {Object} mergeParent The parent collection of the provided cell range.
  1502. * @param {Boolean} [auto=false] `true` if called automatically by the plugin.
  1503. */
  1504. 'afterMergeCells',
  1505. /**
  1506. * Fired by {@link MergeCells} plugin before unmerging the cells. This hook is fired when {@link Options#mergeCells}
  1507. * option is enabled.
  1508. *
  1509. * @event Hooks#beforeUnmergeCells
  1510. * @param {CellRange} cellRange Selection cell range.
  1511. * @param {Boolean} [auto=false] `true` if called automatically by the plugin.
  1512. */
  1513. 'beforeUnmergeCells',
  1514. /**
  1515. * Fired by {@link MergeCells} plugin after unmerging the cells. This hook is fired when {@link Options#mergeCells}
  1516. * option is enabled.
  1517. *
  1518. * @event Hooks#afterUnmergeCells
  1519. * @param {CellRange} cellRange Selection cell range.
  1520. * @param {Boolean} [auto=false] `true` if called automatically by the plugin.
  1521. */
  1522. 'afterUnmergeCells',
  1523. /**
  1524. * Fired after the table was switched into listening mode. This allows Handsontable to capture keyboard events and
  1525. * respond in the right way.
  1526. *
  1527. * @event Hooks#afterListen
  1528. */
  1529. 'afterListen',
  1530. /**
  1531. * Fired after the table was switched off from the listening mode. This makes the Handsontable inert for any
  1532. * keyboard events.
  1533. *
  1534. * @event Hooks#afterUnlisten
  1535. */
  1536. 'afterUnlisten',
  1537. ];
  1538. class Hooks {
  1539. static getSingleton() {
  1540. return getGlobalSingleton();
  1541. }
  1542. /**
  1543. *
  1544. */
  1545. constructor() {
  1546. this.globalBucket = this.createEmptyBucket();
  1547. }
  1548. /**
  1549. * Returns a new object with empty handlers related to every registered hook name.
  1550. *
  1551. * @returns {Object} The empty bucket object.
  1552. *
  1553. * @example
  1554. * ```js
  1555. * Handsontable.hooks.createEmptyBucket();
  1556. * // Results:
  1557. * {
  1558. * ...
  1559. * afterCreateCol: [],
  1560. * afterCreateRow: [],
  1561. * beforeInit: [],
  1562. * ...
  1563. * }
  1564. * ```
  1565. */
  1566. createEmptyBucket() {
  1567. const bucket = Object.create(null);
  1568. // eslint-disable-next-line no-return-assign
  1569. arrayEach(REGISTERED_HOOKS, hook => (bucket[hook] = []));
  1570. return bucket;
  1571. }
  1572. /**
  1573. * Get hook bucket based on the context of the object or if argument is `undefined`, get the global hook bucket.
  1574. *
  1575. * @param {Object} [context=null] A Handsontable instance.
  1576. * @returns {Object} Returns a global or Handsontable instance bucket.
  1577. */
  1578. getBucket(context = null) {
  1579. if (context) {
  1580. if (!context.pluginHookBucket) {
  1581. context.pluginHookBucket = this.createEmptyBucket();
  1582. }
  1583. return context.pluginHookBucket;
  1584. }
  1585. return this.globalBucket;
  1586. }
  1587. /**
  1588. * Adds a listener (globally or locally) to a specified hook name.
  1589. * If the `context` parameter is provided, the hook will be added only to the instance it references.
  1590. * Otherwise, the callback will be used everytime the hook fires on any Handsontable instance.
  1591. * You can provide an array of callback functions as the `callback` argument, this way they will all be fired
  1592. * once the hook is triggered.
  1593. *
  1594. * @see Core#addHook
  1595. * @param {String} key Hook name.
  1596. * @param {Function|Array} callback Callback function or an array of functions.
  1597. * @param {Object} [context=null] The context for the hook callback to be added - a Handsontable instance or leave empty.
  1598. * @returns {Hooks} Instance of Hooks.
  1599. *
  1600. * @example
  1601. * ```js
  1602. * // single callback, added locally
  1603. * Handsontable.hooks.add('beforeInit', myCallback, hotInstance);
  1604. *
  1605. * // single callback, added globally
  1606. * Handsontable.hooks.add('beforeInit', myCallback);
  1607. *
  1608. * // multiple callbacks, added locally
  1609. * Handsontable.hooks.add('beforeInit', [myCallback, anotherCallback], hotInstance);
  1610. *
  1611. * // multiple callbacks, added globally
  1612. * Handsontable.hooks.add('beforeInit', [myCallback, anotherCallback]);
  1613. * ```
  1614. */
  1615. add(key, callback, context = null) {
  1616. if (Array.isArray(callback)) {
  1617. arrayEach(callback, c => this.add(key, c, context));
  1618. } else {
  1619. const bucket = this.getBucket(context);
  1620. if (typeof bucket[key] === 'undefined') {
  1621. this.register(key);
  1622. bucket[key] = [];
  1623. }
  1624. callback.skip = false;
  1625. if (bucket[key].indexOf(callback) === -1) {
  1626. // only add a hook if it has not already been added (adding the same hook twice is now silently ignored)
  1627. let foundInitialHook = false;
  1628. if (callback.initialHook) {
  1629. arrayEach(bucket[key], (cb, i) => {
  1630. if (cb.initialHook) {
  1631. bucket[key][i] = callback;
  1632. foundInitialHook = true;
  1633. return false;
  1634. }
  1635. });
  1636. }
  1637. if (!foundInitialHook) {
  1638. bucket[key].push(callback);
  1639. }
  1640. }
  1641. }
  1642. return this;
  1643. }
  1644. /**
  1645. * Adds a listener to a specified hook. After the hook runs this listener will be automatically removed from the bucket.
  1646. *
  1647. * @see Core#addHookOnce
  1648. * @param {String} key Hook/Event name.
  1649. * @param {Function|Array} callback Callback function.
  1650. * @param {Object} [context=null] A Handsontable instance.
  1651. *
  1652. * @example
  1653. * ```js
  1654. * Handsontable.hooks.once('beforeInit', myCallback, hotInstance);
  1655. * ```
  1656. */
  1657. once(key, callback, context = null) {
  1658. if (Array.isArray(callback)) {
  1659. arrayEach(callback, c => this.once(key, c, context));
  1660. } else {
  1661. callback.runOnce = true;
  1662. this.add(key, callback, context);
  1663. }
  1664. }
  1665. /**
  1666. * Removes a listener from a hook with a given name. If the `context` argument is provided, it removes a listener from a local hook assigned to the given Handsontable instance.
  1667. *
  1668. * @see Core#removeHook
  1669. * @param {String} key Hook/Event name.
  1670. * @param {Function} callback Callback function (needs the be the function that was previously added to the hook).
  1671. * @param {Object} [context=null] Handsontable instance.
  1672. * @return {Boolean} Returns `true` if hook was removed, `false` otherwise.
  1673. *
  1674. * @example
  1675. * ```js
  1676. * Handsontable.hooks.remove('beforeInit', myCallback);
  1677. * ```
  1678. */
  1679. remove(key, callback, context = null) {
  1680. const bucket = this.getBucket(context);
  1681. if (typeof bucket[key] !== 'undefined') {
  1682. if (bucket[key].indexOf(callback) >= 0) {
  1683. callback.skip = true;
  1684. return true;
  1685. }
  1686. }
  1687. return false;
  1688. }
  1689. /**
  1690. * Checks whether there are any registered listeners for the provided hook name.
  1691. * If the `context` parameter is provided, it only checks for listeners assigned to the given Handsontable instance.
  1692. *
  1693. * @param {String} key Hook name.
  1694. * @param {Object} [context=null] A Handsontable instance.
  1695. * @returns {Boolean} `true` for success, `false` otherwise.
  1696. */
  1697. has(key, context = null) {
  1698. const bucket = this.getBucket(context);
  1699. return !!(bucket[key] !== void 0 && bucket[key].length);
  1700. }
  1701. /**
  1702. * Runs all local and global callbacks assigned to the hook identified by the `key` parameter.
  1703. * It returns either a return value from the last called callback or the first parameter (`p1`) passed to the `run` function.
  1704. *
  1705. * @see Core#runHooks
  1706. * @param {Object} context Handsontable instance.
  1707. * @param {String} key Hook/Event name.
  1708. * @param {*} [p1] Parameter to be passed as an argument to the callback function.
  1709. * @param {*} [p2] Parameter to be passed as an argument to the callback function.
  1710. * @param {*} [p3] Parameter to be passed as an argument to the callback function.
  1711. * @param {*} [p4] Parameter to be passed as an argument to the callback function.
  1712. * @param {*} [p5] Parameter to be passed as an argument to the callback function.
  1713. * @param {*} [p6] Parameter to be passed as an argument to the callback function.
  1714. * @returns {*} Either a return value from the last called callback or `p1`.
  1715. *
  1716. * @example
  1717. * ```js
  1718. * Handsontable.hooks.run(hot, 'beforeInit');
  1719. * ```
  1720. */
  1721. run(context, key, p1, p2, p3, p4, p5, p6) {
  1722. {
  1723. const globalHandlers = this.globalBucket[key];
  1724. const length = globalHandlers ? globalHandlers.length : 0;
  1725. let index = 0;
  1726. if (length) {
  1727. // Do not optimise this loop with arrayEach or arrow function! If you do You'll decrease perf because of GC.
  1728. while (index < length) {
  1729. if (!globalHandlers[index] || globalHandlers[index].skip) {
  1730. index += 1;
  1731. /* eslint-disable no-continue */
  1732. continue;
  1733. }
  1734. // performance considerations - http://jsperf.com/call-vs-apply-for-a-plugin-architecture
  1735. const res = globalHandlers[index].call(context, p1, p2, p3, p4, p5, p6);
  1736. if (res !== void 0) {
  1737. // eslint-disable-next-line no-param-reassign
  1738. p1 = res;
  1739. }
  1740. if (globalHandlers[index] && globalHandlers[index].runOnce) {
  1741. this.remove(key, globalHandlers[index]);
  1742. }
  1743. index += 1;
  1744. }
  1745. }
  1746. }
  1747. {
  1748. const localHandlers = this.getBucket(context)[key];
  1749. const length = localHandlers ? localHandlers.length : 0;
  1750. let index = 0;
  1751. if (length) {
  1752. // Do not optimise this loop with arrayEach or arrow function! If you do You'll decrease perf because of GC.
  1753. while (index < length) {
  1754. if (!localHandlers[index] || localHandlers[index].skip) {
  1755. index += 1;
  1756. /* eslint-disable no-continue */
  1757. continue;
  1758. }
  1759. // performance considerations - http://jsperf.com/call-vs-apply-for-a-plugin-architecture
  1760. const res = localHandlers[index].call(context, p1, p2, p3, p4, p5, p6);
  1761. if (res !== void 0) {
  1762. // eslint-disable-next-line no-param-reassign
  1763. p1 = res;
  1764. }
  1765. if (localHandlers[index] && localHandlers[index].runOnce) {
  1766. this.remove(key, localHandlers[index], context);
  1767. }
  1768. index += 1;
  1769. }
  1770. }
  1771. }
  1772. return p1;
  1773. }
  1774. /**
  1775. * Destroy all listeners connected to the context. If no context is provided, the global listeners will be destroyed.
  1776. *
  1777. * @param {Object} [context=null] A Handsontable instance.
  1778. * @example
  1779. * ```js
  1780. * // destroy the global listeners
  1781. * Handsontable.hooks.destroy();
  1782. *
  1783. * // destroy the local listeners
  1784. * Handsontable.hooks.destroy(hotInstance);
  1785. * ```
  1786. */
  1787. destroy(context = null) {
  1788. // eslint-disable-next-line no-return-assign
  1789. objectEach(this.getBucket(context), (value, key, bucket) => (bucket[key].length = 0));
  1790. }
  1791. /**
  1792. * Registers a hook name (adds it to the list of the known hook names). Used by plugins.
  1793. * It is not necessary to call register, but if you use it, your plugin hook will be used returned by
  1794. * the `getRegistered` method. (which itself is used in the demo http://docs.handsontable.com/tutorial-callbacks.html).
  1795. *
  1796. * @param key {String} The hook name.
  1797. *
  1798. * @example
  1799. * ```js
  1800. * Handsontable.hooks.register('myHook');
  1801. * ```
  1802. */
  1803. register(key) {
  1804. if (!this.isRegistered(key)) {
  1805. REGISTERED_HOOKS.push(key);
  1806. }
  1807. }
  1808. /**
  1809. * Deregisters a hook name (removes it from the list of known hook names).
  1810. *
  1811. * @param key {String} Hook name.
  1812. *
  1813. * @example
  1814. * ```js
  1815. * Handsontable.hooks.deregister('myHook');
  1816. * ```
  1817. */
  1818. deregister(key) {
  1819. if (this.isRegistered(key)) {
  1820. REGISTERED_HOOKS.splice(REGISTERED_HOOKS.indexOf(key), 1);
  1821. }
  1822. }
  1823. /**
  1824. * Returns a boolean depending on if a hook by such name has been registered.
  1825. *
  1826. * @param key {String} Hook name.
  1827. * @returns {Boolean} `true` for success, `false` otherwise.
  1828. *
  1829. * @example
  1830. * ```js
  1831. * Handsontable.hooks.isRegistered('beforeInit');
  1832. *
  1833. * // Results:
  1834. * true
  1835. * ```
  1836. */
  1837. isRegistered(key) {
  1838. return REGISTERED_HOOKS.indexOf(key) >= 0;
  1839. }
  1840. /**
  1841. * Returns an array of registered hooks.
  1842. *
  1843. * @returns {Array} An array of registered hooks.
  1844. *
  1845. * @example
  1846. * ```js
  1847. * Handsontable.hooks.getRegistered();
  1848. *
  1849. * // Results:
  1850. * [
  1851. * ...
  1852. * 'beforeInit',
  1853. * 'beforeRender',
  1854. * 'beforeSetRangeEnd',
  1855. * 'beforeDrawBorders',
  1856. * 'beforeChange',
  1857. * ...
  1858. * ]
  1859. * ```
  1860. */
  1861. getRegistered() {
  1862. return REGISTERED_HOOKS;
  1863. }
  1864. }
  1865. const globalSingleton = new Hooks();
  1866. function getGlobalSingleton() {
  1867. return globalSingleton;
  1868. }
  1869. export default Hooks;