import "core-js/modules/es.symbol"; import "core-js/modules/es.symbol.description"; import "core-js/modules/es.symbol.iterator"; import "core-js/modules/es.array.iterator"; import "core-js/modules/es.object.get-prototype-of"; import "core-js/modules/es.object.set-prototype-of"; import "core-js/modules/es.object.to-string"; import "core-js/modules/es.string.iterator"; import "core-js/modules/es.string.trim"; import "core-js/modules/web.dom-collections.iterator"; function _typeof(obj) { "@babel/helpers - typeof"; if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); } function _possibleConstructorReturn(self, call) { if (call && (_typeof(call) === "object" || typeof call === "function")) { return call; } return _assertThisInitialized(self); } function _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return self; } function _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); } function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function"); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true, configurable: true } }); if (superClass) _setPrototypeOf(subClass, superClass); } function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); } function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; } import { CellCoords } from './../3rdparty/walkontable/src'; import { stringify } from './../helpers/mixed'; import { mixin } from './../helpers/object'; import hooksRefRegisterer from './../mixins/hooksRefRegisterer'; export var EditorState = { VIRGIN: 'STATE_VIRGIN', // before editing EDITING: 'STATE_EDITING', WAITING: 'STATE_WAITING', // waiting for async validation FINISHED: 'STATE_FINISHED' }; /** * @util * @class BaseEditor */ var BaseEditor = /*#__PURE__*/ function () { function BaseEditor(instance) { _classCallCheck(this, BaseEditor); /** * A reference to the source instance of the Handsontable. * * @type {Handsontable} */ this.hot = instance; /** * A reference to the source instance of the Handsontable. * @deprecated * * @type {Handsontable} */ this.instance = instance; /** * Editor's state. * * @type {String} */ this.state = EditorState.VIRGIN; /** * Flag to store information about editor's opening status. * @private * * @type {Boolean} */ this._opened = false; /** * Defines the editor's editing mode. When false, then an editor works in fast editing mode. * @private * * @type {Boolean} */ this._fullEditMode = false; /** * Callback to call after closing editor. * * @type {Function} */ this._closeCallback = null; /** * Currently rendered cell's TD element. * * @type {HTMLTableCellElement} */ this.TD = null; /** * Visual row index. * * @type {Number} */ this.row = null; /** * Visual column index. * * @type {Number} */ this.col = null; /** * Column property name or a column index, if datasource is an array of arrays. * * @type {Number|String} */ this.prop = null; /** * Original cell's value. * * @type {*} */ this.originalValue = null; /** * Object containing the cell's properties. * * @type {Object} */ this.cellProperties = null; this.init(); } /** * Fires callback after closing editor. * * @private * @param {Boolean} result */ _createClass(BaseEditor, [{ key: "_fireCallbacks", value: function _fireCallbacks(result) { if (this._closeCallback) { this._closeCallback(result); this._closeCallback = null; } } /** * Initializes an editor's intance. */ }, { key: "init", value: function init() {} /** * Required method to get current value from editable element. */ }, { key: "getValue", value: function getValue() { throw Error('Editor getValue() method unimplemented'); } /** * Required method to set new value into editable element. */ }, { key: "setValue", value: function setValue() { throw Error('Editor setValue() method unimplemented'); } /** * Required method to open editor. */ }, { key: "open", value: function open() { throw Error('Editor open() method unimplemented'); } /** * Required method to close editor. */ }, { key: "close", value: function close() { throw Error('Editor close() method unimplemented'); } /** * Prepares editor's meta data. * * @param {Number} row * @param {Number} col * @param {Number|String} prop * @param {HTMLTableCellElement} td * @param {*} originalValue * @param {Object} cellProperties */ }, { key: "prepare", value: function prepare(row, col, prop, td, originalValue, cellProperties) { this.TD = td; this.row = row; this.col = col; this.prop = prop; this.originalValue = originalValue; this.cellProperties = cellProperties; this.state = EditorState.VIRGIN; } /** * Fallback method to provide extendable editors in ES5. */ }, { key: "extend", value: function extend() { return ( /*#__PURE__*/ function (_this$constructor) { _inherits(Editor, _this$constructor); function Editor() { _classCallCheck(this, Editor); return _possibleConstructorReturn(this, _getPrototypeOf(Editor).apply(this, arguments)); } return Editor; }(this.constructor) ); } /** * Saves value from editor into data storage. * * @param {*} value * @param {Boolean} ctrlDown If true, applies value to each cell in the last selected range. */ }, { key: "saveValue", value: function saveValue(value, ctrlDown) { var selection; var tmp; // if ctrl+enter and multiple cells selected, behave like Excel (finish editing and apply to all cells) if (ctrlDown) { selection = this.hot.getSelectedLast(); if (selection[0] > selection[2]) { tmp = selection[0]; selection[0] = selection[2]; selection[2] = tmp; } if (selection[1] > selection[3]) { tmp = selection[1]; selection[1] = selection[3]; selection[3] = tmp; } } else { selection = [this.row, this.col, null, null]; } this.hot.populateFromArray(selection[0], selection[1], value, selection[2], selection[3], 'edit'); } /** * Begins editing on a highlighted cell and hides fillHandle corner if was present. * * @param {*} newInitialValue * @param {*} event */ }, { key: "beginEditing", value: function beginEditing(newInitialValue, event) { if (this.state !== EditorState.VIRGIN) { return; } this.hot.view.scrollViewport(new CellCoords(this.row, this.col)); this.state = EditorState.EDITING; // Set the editor value only in the full edit mode. In other mode the focusable element has to be empty, // otherwise IME (editor for Asia users) doesn't work. if (this.isInFullEditMode()) { var stringifiedInitialValue = typeof newInitialValue === 'string' ? newInitialValue : stringify(this.originalValue); this.setValue(stringifiedInitialValue); } this.open(event); this._opened = true; this.focus(); // only rerender the selections (FillHandle should disappear when beginediting is triggered) this.hot.view.render(); this.hot.runHooks('afterBeginEditing', this.row, this.col); } /** * Finishes editing and start saving or restoring process for editing cell or last selected range. * * @param {Boolean} restoreOriginalValue If true, then closes editor without saving value from the editor into a cell. * @param {Boolean} ctrlDown If true, then saveValue will save editor's value to each cell in the last selected range. * @param {Function} callback */ }, { key: "finishEditing", value: function finishEditing(restoreOriginalValue, ctrlDown, callback) { var _this = this; var val; if (callback) { var previousCloseCallback = this._closeCallback; this._closeCallback = function (result) { if (previousCloseCallback) { previousCloseCallback(result); } callback(result); _this.hot.view.render(); }; } if (this.isWaiting()) { return; } if (this.state === EditorState.VIRGIN) { this.hot._registerTimeout(function () { _this._fireCallbacks(true); }); return; } if (this.state === EditorState.EDITING) { if (restoreOriginalValue) { this.cancelChanges(); this.hot.view.render(); return; } var value = this.getValue(); if (this.hot.getSettings().trimWhitespace) { // We trim only string values val = [[typeof value === 'string' ? String.prototype.trim.call(value || '') : value]]; } else { val = [[value]]; } this.state = EditorState.WAITING; this.saveValue(val, ctrlDown); if (this.hot.getCellValidator(this.cellProperties)) { this.hot.addHookOnce('postAfterValidate', function (result) { _this.state = EditorState.FINISHED; _this.discardEditor(result); }); } else { this.state = EditorState.FINISHED; this.discardEditor(true); } } } /** * Finishes editing without singout saving value. */ }, { key: "cancelChanges", value: function cancelChanges() { this.state = EditorState.FINISHED; this.discardEditor(); } /** * Verifies result of validation or closes editor if user's cancelled changes. * * @param {Boolean|undefined} result */ }, { key: "discardEditor", value: function discardEditor(result) { if (this.state !== EditorState.FINISHED) { return; } // validator was defined and failed if (result === false && this.cellProperties.allowInvalid !== true) { this.hot.selectCell(this.row, this.col); this.focus(); this.state = EditorState.EDITING; this._fireCallbacks(false); } else { this.close(); this._opened = false; this._fullEditMode = false; this.state = EditorState.VIRGIN; this._fireCallbacks(true); } } /** * Switch editor into full edit mode. In this state navigation keys don't close editor. This mode is activated * automatically after hit ENTER or F2 key on the cell or while editing cell press F2 key. */ }, { key: "enableFullEditMode", value: function enableFullEditMode() { this._fullEditMode = true; } /** * Checks if editor is in full edit mode. * * @returns {Boolean} */ }, { key: "isInFullEditMode", value: function isInFullEditMode() { return this._fullEditMode; } /** * Returns information whether the editor is open. */ }, { key: "isOpened", value: function isOpened() { return this._opened; } /** * Returns information whether the editor is waiting, eg.: for async validation. */ }, { key: "isWaiting", value: function isWaiting() { return this.state === EditorState.WAITING; } /** * Gets className of the edited cell if exist. * * @returns {string} */ }, { key: "getEditedCellsLayerClass", value: function getEditedCellsLayerClass() { var editorSection = this.checkEditorSection(); switch (editorSection) { case 'right': return 'ht_clone_right'; case 'left': return 'ht_clone_left'; case 'bottom': return 'ht_clone_bottom'; case 'bottom-right-corner': return 'ht_clone_bottom_right_corner'; case 'bottom-left-corner': return 'ht_clone_bottom_left_corner'; case 'top': return 'ht_clone_top'; case 'top-right-corner': return 'ht_clone_top_right_corner'; case 'top-left-corner': return 'ht_clone_top_left_corner'; default: return 'ht_clone_master'; } } /** * Gets HTMLTableCellElement of the edited cell if exist. * * @returns {HTMLTableCellElement|null} */ }, { key: "getEditedCell", value: function getEditedCell() { return this.hot.getCell(this.row, this.col, true); } /** * Returns name of the overlay, where editor is placed. * * @private */ }, { key: "checkEditorSection", value: function checkEditorSection() { var totalRows = this.hot.countRows(); var section = ''; if (this.row < this.hot.getSettings().fixedRowsTop) { if (this.col < this.hot.getSettings().fixedColumnsLeft) { section = 'top-left-corner'; } else { section = 'top'; } } else if (this.hot.getSettings().fixedRowsBottom && this.row >= totalRows - this.hot.getSettings().fixedRowsBottom) { if (this.col < this.hot.getSettings().fixedColumnsLeft) { section = 'bottom-left-corner'; } else { section = 'bottom'; } } else if (this.col < this.hot.getSettings().fixedColumnsLeft) { section = 'left'; } return section; } }]); return BaseEditor; }(); mixin(BaseEditor, hooksRefRegisterer); export default BaseEditor;