editorManager.js 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425
  1. 'use strict';
  2. exports.__esModule = true;
  3. var _src = require('./3rdparty/walkontable/src');
  4. var _unicode = require('./helpers/unicode');
  5. var _event = require('./helpers/dom/event');
  6. var _editors = require('./editors');
  7. var _eventManager = require('./eventManager');
  8. var _eventManager2 = _interopRequireDefault(_eventManager);
  9. var _baseEditor = require('./editors/_baseEditor');
  10. function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
  11. function EditorManager(instance, priv, selection) {
  12. var _this = this,
  13. destroyed = false,
  14. eventManager,
  15. activeEditor;
  16. eventManager = new _eventManager2.default(instance);
  17. function moveSelectionAfterEnter(shiftKey) {
  18. selection.setSelectedHeaders(false, false, false);
  19. var enterMoves = typeof priv.settings.enterMoves === 'function' ? priv.settings.enterMoves(event) : priv.settings.enterMoves;
  20. if (shiftKey) {
  21. // move selection up
  22. selection.transformStart(-enterMoves.row, -enterMoves.col);
  23. } else {
  24. // move selection down (add a new row if needed)
  25. selection.transformStart(enterMoves.row, enterMoves.col, true);
  26. }
  27. }
  28. function moveSelectionUp(shiftKey) {
  29. if (shiftKey) {
  30. if (selection.selectedHeader.cols) {
  31. selection.setSelectedHeaders(selection.selectedHeader.rows, false, false);
  32. }
  33. selection.transformEnd(-1, 0);
  34. } else {
  35. selection.setSelectedHeaders(false, false, false);
  36. selection.transformStart(-1, 0);
  37. }
  38. }
  39. function moveSelectionDown(shiftKey) {
  40. if (shiftKey) {
  41. // expanding selection down with shift
  42. selection.transformEnd(1, 0);
  43. } else {
  44. selection.setSelectedHeaders(false, false, false);
  45. selection.transformStart(1, 0);
  46. }
  47. }
  48. function moveSelectionRight(shiftKey) {
  49. if (shiftKey) {
  50. selection.transformEnd(0, 1);
  51. } else {
  52. selection.setSelectedHeaders(false, false, false);
  53. selection.transformStart(0, 1);
  54. }
  55. }
  56. function moveSelectionLeft(shiftKey) {
  57. if (shiftKey) {
  58. if (selection.selectedHeader.rows) {
  59. selection.setSelectedHeaders(false, selection.selectedHeader.cols, false);
  60. }
  61. selection.transformEnd(0, -1);
  62. } else {
  63. selection.setSelectedHeaders(false, false, false);
  64. selection.transformStart(0, -1);
  65. }
  66. }
  67. function onKeyDown(event) {
  68. var ctrlDown, rangeModifier;
  69. if (!instance.isListening()) {
  70. return;
  71. }
  72. instance.runHooks('beforeKeyDown', event);
  73. if (destroyed) {
  74. return;
  75. }
  76. if ((0, _event.isImmediatePropagationStopped)(event)) {
  77. return;
  78. }
  79. priv.lastKeyCode = event.keyCode;
  80. if (!selection.isSelected()) {
  81. return;
  82. }
  83. // catch CTRL but not right ALT (which in some systems triggers ALT+CTRL)
  84. ctrlDown = (event.ctrlKey || event.metaKey) && !event.altKey;
  85. if (activeEditor && !activeEditor.isWaiting()) {
  86. if (!(0, _unicode.isMetaKey)(event.keyCode) && !(0, _unicode.isCtrlKey)(event.keyCode) && !ctrlDown && !_this.isEditorOpened()) {
  87. _this.openEditor('', event);
  88. return;
  89. }
  90. }
  91. rangeModifier = event.shiftKey ? selection.setRangeEnd : selection.setRangeStart;
  92. switch (event.keyCode) {
  93. case _unicode.KEY_CODES.A:
  94. if (!_this.isEditorOpened() && ctrlDown) {
  95. selection.selectAll();
  96. event.preventDefault();
  97. (0, _event.stopPropagation)(event);
  98. }
  99. break;
  100. case _unicode.KEY_CODES.ARROW_UP:
  101. if (_this.isEditorOpened() && !activeEditor.isWaiting()) {
  102. _this.closeEditorAndSaveChanges(ctrlDown);
  103. }
  104. moveSelectionUp(event.shiftKey);
  105. event.preventDefault();
  106. (0, _event.stopPropagation)(event);
  107. break;
  108. case _unicode.KEY_CODES.ARROW_DOWN:
  109. if (_this.isEditorOpened() && !activeEditor.isWaiting()) {
  110. _this.closeEditorAndSaveChanges(ctrlDown);
  111. }
  112. moveSelectionDown(event.shiftKey);
  113. event.preventDefault();
  114. (0, _event.stopPropagation)(event);
  115. break;
  116. case _unicode.KEY_CODES.ARROW_RIGHT:
  117. if (_this.isEditorOpened() && !activeEditor.isWaiting()) {
  118. _this.closeEditorAndSaveChanges(ctrlDown);
  119. }
  120. moveSelectionRight(event.shiftKey);
  121. event.preventDefault();
  122. (0, _event.stopPropagation)(event);
  123. break;
  124. case _unicode.KEY_CODES.ARROW_LEFT:
  125. if (_this.isEditorOpened() && !activeEditor.isWaiting()) {
  126. _this.closeEditorAndSaveChanges(ctrlDown);
  127. }
  128. moveSelectionLeft(event.shiftKey);
  129. event.preventDefault();
  130. (0, _event.stopPropagation)(event);
  131. break;
  132. case _unicode.KEY_CODES.TAB:
  133. selection.setSelectedHeaders(false, false, false);
  134. var tabMoves = typeof priv.settings.tabMoves === 'function' ? priv.settings.tabMoves(event) : priv.settings.tabMoves;
  135. if (event.shiftKey) {
  136. // move selection left
  137. selection.transformStart(-tabMoves.row, -tabMoves.col);
  138. } else {
  139. // move selection right (add a new column if needed)
  140. selection.transformStart(tabMoves.row, tabMoves.col, true);
  141. }
  142. event.preventDefault();
  143. (0, _event.stopPropagation)(event);
  144. break;
  145. case _unicode.KEY_CODES.BACKSPACE:
  146. case _unicode.KEY_CODES.DELETE:
  147. selection.empty(event);
  148. _this.prepareEditor();
  149. event.preventDefault();
  150. break;
  151. case _unicode.KEY_CODES.F2:
  152. /* F2 */
  153. _this.openEditor(null, event);
  154. if (activeEditor) {
  155. activeEditor.enableFullEditMode();
  156. }
  157. event.preventDefault(); // prevent Opera from opening 'Go to Page dialog'
  158. break;
  159. case _unicode.KEY_CODES.ENTER:
  160. /* return/enter */
  161. if (_this.isEditorOpened()) {
  162. if (activeEditor && activeEditor.state !== _baseEditor.EditorState.WAITING) {
  163. _this.closeEditorAndSaveChanges(ctrlDown);
  164. }
  165. moveSelectionAfterEnter(event.shiftKey);
  166. } else if (instance.getSettings().enterBeginsEditing) {
  167. _this.openEditor(null, event);
  168. if (activeEditor) {
  169. activeEditor.enableFullEditMode();
  170. }
  171. } else {
  172. moveSelectionAfterEnter(event.shiftKey);
  173. }
  174. event.preventDefault(); // don't add newline to field
  175. (0, _event.stopImmediatePropagation)(event); // required by HandsontableEditor
  176. break;
  177. case _unicode.KEY_CODES.ESCAPE:
  178. if (_this.isEditorOpened()) {
  179. _this.closeEditorAndRestoreOriginalValue(ctrlDown);
  180. }
  181. event.preventDefault();
  182. break;
  183. case _unicode.KEY_CODES.HOME:
  184. selection.setSelectedHeaders(false, false, false);
  185. if (event.ctrlKey || event.metaKey) {
  186. rangeModifier(new _src.CellCoords(0, priv.selRange.from.col));
  187. } else {
  188. rangeModifier(new _src.CellCoords(priv.selRange.from.row, 0));
  189. }
  190. event.preventDefault(); // don't scroll the window
  191. (0, _event.stopPropagation)(event);
  192. break;
  193. case _unicode.KEY_CODES.END:
  194. selection.setSelectedHeaders(false, false, false);
  195. if (event.ctrlKey || event.metaKey) {
  196. rangeModifier(new _src.CellCoords(instance.countRows() - 1, priv.selRange.from.col));
  197. } else {
  198. rangeModifier(new _src.CellCoords(priv.selRange.from.row, instance.countCols() - 1));
  199. }
  200. event.preventDefault(); // don't scroll the window
  201. (0, _event.stopPropagation)(event);
  202. break;
  203. case _unicode.KEY_CODES.PAGE_UP:
  204. selection.setSelectedHeaders(false, false, false);
  205. selection.transformStart(-instance.countVisibleRows(), 0);
  206. event.preventDefault(); // don't page up the window
  207. (0, _event.stopPropagation)(event);
  208. break;
  209. case _unicode.KEY_CODES.PAGE_DOWN:
  210. selection.setSelectedHeaders(false, false, false);
  211. selection.transformStart(instance.countVisibleRows(), 0);
  212. event.preventDefault(); // don't page down the window
  213. (0, _event.stopPropagation)(event);
  214. break;
  215. default:
  216. break;
  217. }
  218. }
  219. function init() {
  220. instance.addHook('afterDocumentKeyDown', onKeyDown);
  221. eventManager.addEventListener(document.documentElement, 'keydown', function (event) {
  222. if (!destroyed) {
  223. instance.runHooks('afterDocumentKeyDown', event);
  224. }
  225. });
  226. function onDblClick(event, coords, elem) {
  227. // may be TD or TH
  228. if (elem.nodeName == 'TD') {
  229. _this.openEditor();
  230. if (activeEditor) {
  231. activeEditor.enableFullEditMode();
  232. }
  233. }
  234. }
  235. instance.view.wt.update('onCellDblClick', onDblClick);
  236. instance.addHook('afterDestroy', function () {
  237. destroyed = true;
  238. });
  239. }
  240. /**
  241. * Destroy current editor, if exists.
  242. *
  243. * @function destroyEditor
  244. * @memberof! Handsontable.EditorManager#
  245. * @param {Boolean} revertOriginal
  246. */
  247. this.destroyEditor = function (revertOriginal) {
  248. this.closeEditor(revertOriginal);
  249. };
  250. /**
  251. * Get active editor.
  252. *
  253. * @function getActiveEditor
  254. * @memberof! Handsontable.EditorManager#
  255. * @returns {*}
  256. */
  257. this.getActiveEditor = function () {
  258. return activeEditor;
  259. };
  260. /**
  261. * Prepare text input to be displayed at given grid cell.
  262. *
  263. * @function prepareEditor
  264. * @memberof! Handsontable.EditorManager#
  265. */
  266. this.prepareEditor = function () {
  267. var row, col, prop, td, originalValue, cellProperties, editorClass;
  268. if (activeEditor && activeEditor.isWaiting()) {
  269. this.closeEditor(false, false, function (dataSaved) {
  270. if (dataSaved) {
  271. _this.prepareEditor();
  272. }
  273. });
  274. return;
  275. }
  276. row = priv.selRange.highlight.row;
  277. col = priv.selRange.highlight.col;
  278. prop = instance.colToProp(col);
  279. td = instance.getCell(row, col);
  280. originalValue = instance.getSourceDataAtCell(instance.runHooks('modifyRow', row), col);
  281. cellProperties = instance.getCellMeta(row, col);
  282. editorClass = instance.getCellEditor(cellProperties);
  283. if (editorClass) {
  284. activeEditor = (0, _editors.getEditorInstance)(editorClass, instance);
  285. activeEditor.prepare(row, col, prop, td, originalValue, cellProperties);
  286. } else {
  287. activeEditor = void 0;
  288. }
  289. };
  290. /**
  291. * Check is editor is opened/showed.
  292. *
  293. * @function isEditorOpened
  294. * @memberof! Handsontable.EditorManager#
  295. * @returns {Boolean}
  296. */
  297. this.isEditorOpened = function () {
  298. return activeEditor && activeEditor.isOpened();
  299. };
  300. /**
  301. * Open editor with initial value.
  302. *
  303. * @function openEditor
  304. * @memberof! Handsontable.EditorManager#
  305. * @param {String} initialValue
  306. * @param {DOMEvent} event
  307. */
  308. this.openEditor = function (initialValue, event) {
  309. if (activeEditor && !activeEditor.cellProperties.readOnly) {
  310. activeEditor.beginEditing(initialValue, event);
  311. } else if (activeEditor && activeEditor.cellProperties.readOnly) {
  312. // move the selection after opening the editor with ENTER key
  313. if (event && event.keyCode === _unicode.KEY_CODES.ENTER) {
  314. moveSelectionAfterEnter();
  315. }
  316. }
  317. };
  318. /**
  319. * Close editor, finish editing cell.
  320. *
  321. * @function closeEditor
  322. * @memberof! Handsontable.EditorManager#
  323. * @param {Boolean} restoreOriginalValue
  324. * @param {Boolean} [ctrlDown]
  325. * @param {Function} [callback]
  326. */
  327. this.closeEditor = function (restoreOriginalValue, ctrlDown, callback) {
  328. if (activeEditor) {
  329. activeEditor.finishEditing(restoreOriginalValue, ctrlDown, callback);
  330. } else if (callback) {
  331. callback(false);
  332. }
  333. };
  334. /**
  335. * Close editor and save changes.
  336. *
  337. * @function closeEditorAndSaveChanges
  338. * @memberof! Handsontable.EditorManager#
  339. * @param {Boolean} ctrlDown
  340. */
  341. this.closeEditorAndSaveChanges = function (ctrlDown) {
  342. return this.closeEditor(false, ctrlDown);
  343. };
  344. /**
  345. * Close editor and restore original value.
  346. *
  347. * @function closeEditorAndRestoreOriginalValue
  348. * @memberof! Handsontable.EditorManager#
  349. * @param {Boolean} ctrlDown
  350. */
  351. this.closeEditorAndRestoreOriginalValue = function (ctrlDown) {
  352. return this.closeEditor(true, ctrlDown);
  353. };
  354. init();
  355. }
  356. exports.default = EditorManager;