9161ea7e0d128f9a95c284f4a828bbf3d9de538b5b3478d4f1e213bd322a6a1a0918650a2f6eb5582f9b87e3de19afc2049edbbf767064d0cc9b2ae6138454 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270
  1. import {CellCoords} from './../3rdparty/walkontable/src';
  2. import {stringify} from './../helpers/mixed';
  3. export const EditorState = {
  4. VIRGIN: 'STATE_VIRGIN', // before editing
  5. EDITING: 'STATE_EDITING',
  6. WAITING: 'STATE_WAITING', // waiting for async validation
  7. FINISHED: 'STATE_FINISHED'
  8. };
  9. function BaseEditor(instance) {
  10. this.instance = instance;
  11. this.state = EditorState.VIRGIN;
  12. this._opened = false;
  13. this._fullEditMode = false;
  14. this._closeCallback = null;
  15. this.init();
  16. }
  17. BaseEditor.prototype._fireCallbacks = function(result) {
  18. if (this._closeCallback) {
  19. this._closeCallback(result);
  20. this._closeCallback = null;
  21. }
  22. };
  23. BaseEditor.prototype.init = function() {};
  24. BaseEditor.prototype.getValue = function() {
  25. throw Error('Editor getValue() method unimplemented');
  26. };
  27. BaseEditor.prototype.setValue = function(newValue) {
  28. throw Error('Editor setValue() method unimplemented');
  29. };
  30. BaseEditor.prototype.open = function() {
  31. throw Error('Editor open() method unimplemented');
  32. };
  33. BaseEditor.prototype.close = function() {
  34. throw Error('Editor close() method unimplemented');
  35. };
  36. BaseEditor.prototype.prepare = function(row, col, prop, td, originalValue, cellProperties) {
  37. this.TD = td;
  38. this.row = row;
  39. this.col = col;
  40. this.prop = prop;
  41. this.originalValue = originalValue;
  42. this.cellProperties = cellProperties;
  43. let invalidActiveElement = !document.activeElement || (document.activeElement && document.activeElement.nodeName === void 0);
  44. if (this.instance.view.isMouseDown() && document.activeElement && document.activeElement !== document.body && !invalidActiveElement) {
  45. document.activeElement.blur();
  46. } else if (invalidActiveElement) { // IE
  47. document.body.focus();
  48. }
  49. this.state = EditorState.VIRGIN;
  50. };
  51. BaseEditor.prototype.extend = function() {
  52. var baseClass = this.constructor;
  53. function Editor() {
  54. baseClass.apply(this, arguments);
  55. }
  56. function inherit(Child, Parent) {
  57. function Bridge() {}
  58. Bridge.prototype = Parent.prototype;
  59. Child.prototype = new Bridge();
  60. Child.prototype.constructor = Child;
  61. return Child;
  62. }
  63. return inherit(Editor, baseClass);
  64. };
  65. BaseEditor.prototype.saveValue = function(value, ctrlDown) {
  66. let selection;
  67. let tmp;
  68. // if ctrl+enter and multiple cells selected, behave like Excel (finish editing and apply to all cells)
  69. if (ctrlDown) {
  70. selection = this.instance.getSelected();
  71. if (selection[0] > selection[2]) {
  72. tmp = selection[0];
  73. selection[0] = selection[2];
  74. selection[2] = tmp;
  75. }
  76. if (selection[1] > selection[3]) {
  77. tmp = selection[1];
  78. selection[1] = selection[3];
  79. selection[3] = tmp;
  80. }
  81. } else {
  82. selection = [this.row, this.col, null, null];
  83. }
  84. this.instance.populateFromArray(selection[0], selection[1], value, selection[2], selection[3], 'edit');
  85. };
  86. BaseEditor.prototype.beginEditing = function(initialValue, event) {
  87. if (this.state != EditorState.VIRGIN) {
  88. return;
  89. }
  90. this.instance.view.scrollViewport(new CellCoords(this.row, this.col));
  91. this.instance.view.render();
  92. this.state = EditorState.EDITING;
  93. initialValue = typeof initialValue == 'string' ? initialValue : this.originalValue;
  94. this.setValue(stringify(initialValue));
  95. this.open(event);
  96. this._opened = true;
  97. this.focus();
  98. // only rerender the selections (FillHandle should disappear when beginediting is triggered)
  99. this.instance.view.render();
  100. this.instance.runHooks('afterBeginEditing', this.row, this.col);
  101. };
  102. BaseEditor.prototype.finishEditing = function(restoreOriginalValue, ctrlDown, callback) {
  103. var _this = this,
  104. val;
  105. if (callback) {
  106. var previousCloseCallback = this._closeCallback;
  107. this._closeCallback = function(result) {
  108. if (previousCloseCallback) {
  109. previousCloseCallback(result);
  110. }
  111. callback(result);
  112. _this.instance.view.render();
  113. };
  114. }
  115. if (this.isWaiting()) {
  116. return;
  117. }
  118. if (this.state == EditorState.VIRGIN) {
  119. this.instance._registerTimeout(setTimeout(() => {
  120. _this._fireCallbacks(true);
  121. }, 0));
  122. return;
  123. }
  124. if (this.state == EditorState.EDITING) {
  125. if (restoreOriginalValue) {
  126. this.cancelChanges();
  127. this.instance.view.render();
  128. return;
  129. }
  130. let value = this.getValue();
  131. if (this.instance.getSettings().trimWhitespace) {
  132. // We trim only string values
  133. val = [
  134. [typeof value === 'string' ? String.prototype.trim.call(value || '') : value]
  135. ];
  136. } else {
  137. val = [
  138. [value]
  139. ];
  140. }
  141. this.state = EditorState.WAITING;
  142. this.saveValue(val, ctrlDown);
  143. if (this.instance.getCellValidator(this.cellProperties)) {
  144. this.instance.addHookOnce('postAfterValidate', (result) => {
  145. _this.state = EditorState.FINISHED;
  146. _this.discardEditor(result);
  147. });
  148. } else {
  149. this.state = EditorState.FINISHED;
  150. this.discardEditor(true);
  151. }
  152. }
  153. };
  154. BaseEditor.prototype.cancelChanges = function() {
  155. this.state = EditorState.FINISHED;
  156. this.discardEditor();
  157. };
  158. BaseEditor.prototype.discardEditor = function(result) {
  159. if (this.state !== EditorState.FINISHED) {
  160. return;
  161. }
  162. // validator was defined and failed
  163. if (result === false && this.cellProperties.allowInvalid !== true) {
  164. this.instance.selectCell(this.row, this.col);
  165. this.focus();
  166. this.state = EditorState.EDITING;
  167. this._fireCallbacks(false);
  168. } else {
  169. this.close();
  170. this._opened = false;
  171. this._fullEditMode = false;
  172. this.state = EditorState.VIRGIN;
  173. this._fireCallbacks(true);
  174. }
  175. };
  176. /**
  177. * Switch editor into full edit mode. In this state navigation keys don't close editor. This mode is activated
  178. * automatically after hit ENTER or F2 key on the cell or while editing cell press F2 key.
  179. */
  180. BaseEditor.prototype.enableFullEditMode = function() {
  181. this._fullEditMode = true;
  182. };
  183. /**
  184. * Checks if editor is in full edit mode.
  185. *
  186. * @returns {Boolean}
  187. */
  188. BaseEditor.prototype.isInFullEditMode = function() {
  189. return this._fullEditMode;
  190. };
  191. BaseEditor.prototype.isOpened = function() {
  192. return this._opened;
  193. };
  194. BaseEditor.prototype.isWaiting = function() {
  195. return this.state === EditorState.WAITING;
  196. };
  197. BaseEditor.prototype.checkEditorSection = function() {
  198. var totalRows = this.instance.countRows();
  199. var section = '';
  200. if (this.row < this.instance.getSettings().fixedRowsTop) {
  201. if (this.col < this.instance.getSettings().fixedColumnsLeft) {
  202. section = 'top-left-corner';
  203. } else {
  204. section = 'top';
  205. }
  206. } else if (this.instance.getSettings().fixedRowsBottom && this.row >= totalRows - this.instance.getSettings().fixedRowsBottom) {
  207. if (this.col < this.instance.getSettings().fixedColumnsLeft) {
  208. section = 'bottom-left-corner';
  209. } else {
  210. section = 'bottom';
  211. }
  212. } else if (this.col < this.instance.getSettings().fixedColumnsLeft) {
  213. section = 'left';
  214. }
  215. return section;
  216. };
  217. export default BaseEditor;