handsontable
Version:
Handsontable is a JavaScript Data Grid available for React, Angular and Vue.
283 lines (268 loc) • 9.01 kB
JavaScript
"use strict";
exports.__esModule = true;
var _textEditor = require("../textEditor");
var _element = require("../../helpers/dom/element");
var _event = require("../../helpers/dom/event");
var _object = require("../../helpers/object");
var _shortcutContexts = require("../../shortcutContexts");
const SHORTCUTS_GROUP = 'handsontableEditor';
const EDITOR_TYPE = exports.EDITOR_TYPE = 'handsontable';
/**
* @private
* @class HandsontableEditor
*/
class HandsontableEditor extends _textEditor.TextEditor {
static get EDITOR_TYPE() {
return EDITOR_TYPE;
}
/**
* Opens the editor and adjust its size.
*/
open() {
super.open();
const containerStyle = this.htContainer.style;
if (this.htEditor) {
this.htEditor.destroy();
containerStyle.width = '';
containerStyle.height = '';
containerStyle.overflow = '';
}
if (containerStyle.display === 'none') {
containerStyle.display = '';
}
// Constructs and initializes a new Handsontable instance
this.htEditor = new this.hot.constructor(this.htContainer, this.htOptions);
this.htEditor.init();
this.htEditor.rootElement.style.display = '';
if (this.cellProperties.strict) {
this.htEditor.selectCell(0, 0);
} else {
this.htEditor.deselectCell();
}
(0, _element.setCaretPosition)(this.TEXTAREA, 0, this.TEXTAREA.value.length);
this.htEditor.updateSettings({
width: this.getWidth(),
height: this.getHeight()
});
this.refreshDimensions();
}
/**
* Closes the editor.
*/
close() {
if (this.htEditor) {
this.htEditor.rootElement.style.display = 'none';
}
this.removeHooksByKey('beforeKeyDown');
super.close();
}
/**
* Prepares editor's meta data and configuration of the internal Handsontable's instance.
*
* @param {number} row The visual row index.
* @param {number} col The visual column index.
* @param {number|string} prop The column property (passed when datasource is an array of objects).
* @param {HTMLTableCellElement} td The rendered cell element.
* @param {*} value The rendered value.
* @param {object} cellProperties The cell meta object (see {@link Core#getCellMeta}).
*/
prepare(row, col, prop, td, value, cellProperties) {
super.prepare(row, col, prop, td, value, cellProperties);
const parent = this;
const options = {
startRows: 0,
startCols: 0,
minRows: 0,
minCols: 0,
className: 'listbox',
copyPaste: false,
autoColumnSize: false,
autoRowSize: false,
readOnly: true,
fillHandle: false,
autoWrapCol: false,
autoWrapRow: false,
ariaTags: false,
themeName: this.hot.getCurrentThemeName(),
afterOnCellMouseDown(_, coords) {
const sourceValue = this.getSourceData(coords.row, coords.col);
// if the value is undefined then it means we don't want to set the value
if (sourceValue !== undefined) {
parent.setValue(sourceValue);
}
parent.hot.destroyEditor();
},
preventWheel: true,
layoutDirection: this.hot.isRtl() ? 'rtl' : 'ltr'
};
if (this.cellProperties.handsontable) {
(0, _object.extend)(options, cellProperties.handsontable);
}
this.htOptions = options;
}
/**
* Begins editing on a highlighted cell and hides fillHandle corner if was present.
*
* @param {*} newInitialValue The editor initial value.
* @param {*} event The keyboard event object.
*/
beginEditing(newInitialValue, event) {
const onBeginEditing = this.hot.getSettings().onBeginEditing;
if (onBeginEditing && onBeginEditing() === false) {
return;
}
super.beginEditing(newInitialValue, event);
}
/**
* Creates an editor's elements and adds necessary CSS classnames.
*/
createElements() {
super.createElements();
const DIV = this.hot.rootDocument.createElement('DIV');
DIV.className = 'handsontableEditor';
this.TEXTAREA_PARENT.appendChild(DIV);
this.htContainer = DIV;
this.assignHooks();
}
/**
* 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 The callback function, fired after editor closing.
*/
finishEditing(restoreOriginalValue, ctrlDown, callback) {
if (this.htEditor && this.htEditor.isListening()) {
// if focus is still in the HOT editor
this.hot.listen(); // return the focus to the parent HOT instance
}
if (this.htEditor && this.htEditor.getSelectedLast()) {
const value = this.htEditor.getValue();
if (value !== undefined) {
// if the value is undefined then it means we don't want to set the value
this.setValue(value);
}
}
super.finishEditing(restoreOriginalValue, ctrlDown, callback);
}
/**
* Calculates and return the internal Handsontable's height.
*
* @private
* @returns {number}
*/
getHeight() {
return this.htEditor.view.getTableHeight() + 1;
}
/**
* Calculates and return the internal Handsontable's width.
*
* @private
* @returns {number}
*/
getWidth() {
return this.htEditor.view.getTableWidth();
}
/**
* Assigns afterDestroy callback to prevent memory leaks.
*
* @private
*/
assignHooks() {
this.hot.addHook('afterDestroy', () => {
var _this$htEditor;
(_this$htEditor = this.htEditor) === null || _this$htEditor === void 0 || _this$htEditor.destroy();
});
this.hot.addHook('afterSetTheme', (themeName, firstRun) => {
if (!firstRun) {
var _this$htEditor2;
(_this$htEditor2 = this.htEditor) === null || _this$htEditor2 === void 0 || _this$htEditor2.useTheme(themeName);
}
});
}
/**
* Register shortcuts responsible for handling editor.
*
* @private
*/
registerShortcuts() {
const shortcutManager = this.hot.getShortcutManager();
const editorContext = shortcutManager.getContext('editor');
super.registerShortcuts();
const contextConfig = {
group: SHORTCUTS_GROUP,
relativeToGroup: _shortcutContexts.EDITOR_EDIT_GROUP,
position: 'before'
};
const action = (rowToSelect, event) => {
const innerHOT = this.htEditor;
if (rowToSelect !== undefined) {
if (rowToSelect < 0 || innerHOT.flipped && rowToSelect > innerHOT.countRows() - 1) {
innerHOT.deselectCell();
} else {
innerHOT.selectCell(rowToSelect, 0);
}
if (innerHOT.getData().length) {
event.preventDefault();
(0, _event.stopImmediatePropagation)(event);
this.hot.listen();
this.TEXTAREA.focus();
return false;
}
}
};
editorContext.addShortcuts([{
keys: [['ArrowUp']],
callback: event => {
const innerHOT = this.htEditor;
let rowToSelect;
let selectedRow;
if (!innerHOT.getSelectedLast() && innerHOT.flipped) {
rowToSelect = innerHOT.countRows() - 1;
} else if (innerHOT.getSelectedLast()) {
if (innerHOT.flipped) {
selectedRow = innerHOT.getSelectedLast()[0];
rowToSelect = Math.max(0, selectedRow - 1);
} else {
selectedRow = innerHOT.getSelectedLast()[0];
rowToSelect = selectedRow - 1;
}
}
return action(rowToSelect, event);
},
preventDefault: false // Doesn't block default behaviour (navigation) for a `textArea` HTMLElement.
}, {
keys: [['ArrowDown']],
callback: event => {
const innerHOT = this.htEditor;
let rowToSelect;
let selectedRow;
if (!innerHOT.getSelectedLast() && !innerHOT.flipped) {
rowToSelect = 0;
} else if (innerHOT.getSelectedLast()) {
if (innerHOT.flipped) {
rowToSelect = innerHOT.getSelectedLast()[0] + 1;
} else if (!innerHOT.flipped) {
const lastRow = innerHOT.countRows() - 1;
selectedRow = innerHOT.getSelectedLast()[0];
rowToSelect = Math.min(lastRow, selectedRow + 1);
}
}
return action(rowToSelect, event);
},
preventDefault: false // Doesn't block default behaviour (navigation) for a `textArea` HTMLElement.
}], contextConfig);
}
/**
* Unregister shortcuts responsible for handling editor.
*
* @private
*/
unregisterShortcuts() {
super.unregisterShortcuts();
const shortcutManager = this.hot.getShortcutManager();
const editorContext = shortcutManager.getContext('editor');
editorContext.removeShortcutsByGroup(SHORTCUTS_GROUP);
}
}
exports.HandsontableEditor = HandsontableEditor;