UNPKG

@true-directive/base

Version:

The set of base classes for the TrueDirective Grid

451 lines (450 loc) 20.3 kB
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; return c > 3 && r && Object.defineProperty(target, key, r), r; }; var __metadata = (this && this.__metadata) || function (k, v) { if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v); }; /** * Copyright (c) 2018-2019 Aleksey Melnikov, True Directive Company. * @link https://truedirective.com/ * @license MIT */ import { AxInject } from '../classes/ax-inject.class'; import { Keys } from '../common/keys.class'; import { Utils } from '../common/utils.class'; import { ColumnType, EditorShowMode, SelectionMode } from '../classes/enums'; import { UIActionType } from '../classes/ui-action.class'; import { ValueChangedEvent, CheckedChangedEvent } from '../classes/events'; import { Selection } from '../classes/selection.class'; import { DataSource } from '../classes/data-source.class'; import { GridSettings } from '../classes/grid-settings.class'; import { ColumnCollection } from '../classes/column-collection.class'; import { GridCheckHandler } from './grid-check.handler'; import { LayoutsHandler } from './layouts.handler'; var GridUIHandler = /** @class */ (function () { function GridUIHandler() { /** * Previous position of the focused cell */ this._prevFocused = null; /** * Position of the cell containing an editor */ this._editor = null; /** * Значение редактора. Storing value here because cell may be not rendered. */ this.editorValue = null; /** * Cell value before editing */ this.editorValueChanged = false; /** * If the editor has been shown. This flag is necessary for understanding * if the dropdown list has been shown avoid more showing * (during the scrolling the editor may be initialized several times). */ this.editorWasShown = false; /** * Editor's height. We need to remember it because cell containing editor can * affect the height of the row. Without storing this value the row's height will * be lost. */ this.editorHeight = null; } Object.defineProperty(GridUIHandler.prototype, "cc", { get: function () { return this.columnCollection; }, enumerable: true, configurable: true }); Object.defineProperty(GridUIHandler.prototype, "columns", { get: function () { return this.cc.columns; }, enumerable: true, configurable: true }); Object.defineProperty(GridUIHandler.prototype, "focusedCell", { /** * Focused cell position */ get: function () { return this.selection.focusedCell; }, set: function (cp) { this.selection.focusedCell = cp === null ? null : cp.clone(); }, enumerable: true, configurable: true }); GridUIHandler.prototype.cellPosition = function (row, rowIndex, fieldName) { return this.selection.cellPosition(row, rowIndex, fieldName, this.settings.keyField); }; Object.defineProperty(GridUIHandler.prototype, "editor", { get: function () { return this._editor; }, enumerable: true, configurable: true }); /** * Проверка возможности редактирования заданной ячейки * @param cp Позиция ячейки * @return Можно ли редактировать */ // В источник данных? - зависит от настроек. Давайте в колонку /* protected canEditColumnCell(cp: CellPosition): boolean { if (cp) { const col: Column = this.columnByFieldName(cp.fieldName); return col.isCheckbox ? false : this.settings.canEditColumnCell(col); } return false; } */ /** * Проверка видимости строки после изменения значения одного из полей * @param r Измененная строка * @param fieldName Наименование поля * @return Необходим ли перезапрос данных */ GridUIHandler.prototype.checkDataUpdateNeed = function (r, fieldName) { if (this.dataSource.checkDataUpdateNeed(r, fieldName)) { this.events.queryChangedEvent(this.dataSource.getQuery()); return true; } return false; }; /** * Handling of the pressed key before editor Initialization. * This may happen with quick user typing. */ GridUIHandler.prototype.processKeyBeforeEdit = function (keyEvent) { var keyChar = Keys.keyChar(keyEvent); if (this._editor !== null && keyChar.length === 1) { // Initialization of the editor is started. // Apply key. if (!this.editorValueChanged) { this.editorValue = keyChar; this.editorValueChanged = true; } else { this.editorValue += keyChar; } keyEvent.stopPropagation(); keyEvent.preventDefault(); } }; /** * Editor Initialization. * @param cp Cell position * @param returnFocus Set this parameter true if it is necessary to return the focus into the grid. * @param keyEvent The key that runs cell into the edit mode. * @param cancelCurrent Set this parameter true to reject the changes of the previous editing. */ GridUIHandler.prototype.setEditor = function (cp, returnFocus, keyEvent, cancelCurrent) { if (returnFocus === void 0) { returnFocus = false; } if (keyEvent === void 0) { keyEvent = null; } if (cancelCurrent === void 0) { cancelCurrent = false; } if (this._editor === null && cp === null) { return; } // There is no editor or previous editor is equal to the currrent one. if (this._editor === null || !this._editor.equals(cp)) { var v0 = this.editorValue; // Previous value var ed0 = this._editor; this._editor = cp === null ? null : cp.clone(); this.editorHeight = null; // Current value var v = null; if (cp !== null) { v = cp.row[cp.fieldName]; var col = this.cc.columnByFieldName(cp.fieldName); if (col.type === ColumnType.STRING) { v = v === null ? '' : Utils.htmlToPlaintext(v); } } this.editorWasShown = false; this.editorValueChanged = false; this.editorValue = v; this.processKeyBeforeEdit(keyEvent); if (ed0 !== null && this._editor === null) { // Save value of the current editor. if (this.settings.editorAutoCommit && !cancelCurrent) { this.commitEditor(ed0.row, ed0.fieldName, v0); } this.events.stopEditingEvent(returnFocus); } else { // Send notification about the new editor. if (this._editor !== null) { this.events.startEditingEvent(this._editor); } } } }; // Пользователь начинает выделять ячейки - MouseDown GridUIHandler.prototype.startAction = function (cp, ctrl, byTouch, button) { if (ctrl === void 0) { ctrl = false; } if (byTouch === void 0) { byTouch = false; } if (button === void 0) { button = 0; } if (this.focusedCell != null && this.focusedCell.equals(cp) && this.settings.editorShowMode === EditorShowMode.ON_CLICK_FOCUSED && byTouch) { // Только для touch делаем это при начале выделения. this.startEditing(cp); return null; } if (!cp || cp.fieldName === '') { // Не попали в ячейку return null; } if (button === 2 && this.selection.isSelected(this.layoutsHandler.layoutColumns, cp, this.settings)) { // Контекстное меню лучше вызовем this.selection.focusedCell = cp; // событие по изменению фокуса должно вызваться return null; } // Сохраняем текущий фокус this._prevFocused = this.focusedCell === null ? null : this.focusedCell.clone(); this.startSelect(cp, ctrl && this.settings.multiSelect); return UIActionType.SELECT; }; /** * Start selecting cells * @param cp Cell position * @param add */ GridUIHandler.prototype.startSelect = function (cp, add) { if (add === void 0) { add = false; } this.selection.startSelect(cp, add); }; // Пользователь продолжает выделять ячейки (MouseMove) GridUIHandler.prototype.proceedToSelect = function (cp) { if (this.settings.editorShowMode === EditorShowMode.ON_MOUSE_DOWN) { // Включен редактор, не расширяем из него выделение if (this.editor && this.editor.equals(this.focusedCell)) { return false; } } // Продолжить выделение можно только в некоторых режимах при // отсутствии настройки перетаскивания строки if (this.settings.rowDrag) { return false; } if (this.settings.selectionMode !== SelectionMode.RANGE && this.settings.selectionMode !== SelectionMode.ROW_AND_RANGE) { return false; } // Можно.. if (this.selection.proceedToSelect(cp)) { return true; } return false; }; /** * The user has finished selecting the cells (MouseUp) * @param cp Cell RowPosition * @param byTouch Selection took place in touch events * @param button Левая или правая кнопка мыши */ GridUIHandler.prototype.endSelect = function (cp, byTouch, button) { if (byTouch === void 0) { byTouch = false; } if (button === void 0) { button = 0; } // Check duplicates this.selection.endSelect(this.settings.selectionMode); // Commit the changes, start editing if necessary if (this.selection.focusedCell !== null) { if (this.settings.editorShowMode === EditorShowMode.ON_FOCUS && this.selection.isSingleCellSelected() && button === 0) { this.startEditing(cp); return; } if (this.settings.editorShowMode === EditorShowMode.ON_CLICK_FOCUSED && this.focusedCell.equals(this._prevFocused) && this.focusedCell.equals(cp) && button === 0 && !byTouch) { this.startEditing(cp); return; } } }; /** * Обработка события mousedown. Возможно, необходимо включить редактор * @param cp Позиция * @return Если true, то событие обработано, дальнейшая обработка не требуется */ GridUIHandler.prototype.mouseDown = function (cp, touch, button) { if (touch === void 0) { touch = false; } if (button === void 0) { button = 0; } // Если планируется переключение чекбокса, то выходим из процедуры if (this.settings.checkByCellClick && this.check.canToggleCheck(cp)) { // Не начинаем выделение return true; } // Включение редактора при EditorShowMode.ON_MOUSE_DOWN if (this.settings.editorShowMode === EditorShowMode.ON_MOUSE_DOWN && this.editor === null) { this.selection.focusedCell = null; this.selection.startSelect(cp, false); return true; } return false; }; // Пользователь переключает галку в группе или строке GridUIHandler.prototype.toggleCheck = function (row, fieldName, v) { if (v === void 0) { v = undefined; } var col = this.cc.columnByFieldName(fieldName); if (col && col.type !== ColumnType.CHECKBOX) { this.commitEditor(row, fieldName, !row[fieldName]); return; } if (v !== undefined) { if (row[fieldName] !== v) { row[fieldName] = v; this.check.updateCheckColumns(fieldName); // Сигнализируем о том, что нужно проверить изменения this.events.valueChangedEvent(new ValueChangedEvent(row, fieldName)); this.events.checkedChangedEvent(new CheckedChangedEvent('row', row, fieldName, v)); } } else { row[fieldName] = !row[fieldName]; this.check.updateCheckColumns(fieldName); // Сигнализируем о том, что нужно проверить изменения this.events.valueChangedEvent(new ValueChangedEvent(row, fieldName)); this.events.checkedChangedEvent(new CheckedChangedEvent('row', row, fieldName, row[fieldName])); } }; /** * Пользователь переключает галку в заголовке столбца * @param col Колонка с чекбоксом */ GridUIHandler.prototype.toggleCheckColumn = function (col) { var newValue = true; if (col.isChecked || col.isChecked === null) { newValue = false; } this.check.setColumnCheck(col, newValue); }; /** * Click event handling. Toggle cell checkbox. * @param cp Cell position * @return Has event been handled */ GridUIHandler.prototype.click = function (cp) { if (this.settings.checkByCellClick && this.check.canToggleCheck(cp)) { this.toggleCheck(cp.row, cp.fieldName); return true; } return false; }; /** * Отработка события DblClick. Включение редкатора по EditorShowMode.ON_DBL_CLICK * @param e Параметры события * @param r Строка, по которой был даблклик */ GridUIHandler.prototype.dblClick = function (e, r) { if (this.selection.isSingleCellSelected()) { if (this.settings.editorShowMode === EditorShowMode.ON_DBL_CLICK) { this.startEditing(this.focusedCell); } } }; // Начало редактирования GridUIHandler.prototype.startEditing = function (cp, keyEvent) { if (keyEvent === void 0) { keyEvent = null; } if (this.dataSource.canEditCell(cp)) { this.setEditor(cp.clone(), false, keyEvent); return true; } return false; }; // Окончание редактирования GridUIHandler.prototype.stopEditing = function (cp, returnFocus, cancelChanges) { if (returnFocus === void 0) { returnFocus = false; } if (cancelChanges === void 0) { cancelChanges = false; } if (cp !== null && cp.equals(this.editor)) { this.setEditor(null, returnFocus, '', cancelChanges); } }; /** * Подтверждение нового значения ячейки после редактирования * @param row Строка * @param fieldName Наименвание поля * @param value Новое значение * @return Изменено ли в итоге значение */ GridUIHandler.prototype.commitEditor = function (row, fieldName, value) { // Останавливаем редактор this.stopEditing(this.editor, true); // Значение не изменилось if (this.dataSource.value(row, fieldName) === value) { return false; } // Индекс строки здесь не важен if (this.dataSource.canEditCell(this.cellPosition(row, -1, fieldName))) { var rowData = this.dataSource.updateValue(row, fieldName, value); this.checkDataUpdateNeed(rowData, fieldName); this.events.valueChangedEvent(new ValueChangedEvent(rowData, fieldName)); return true; } return false; }; // Обработка нажатия клавиши GridUIHandler.prototype.processKey = function (pageCapacity, // Емкость предыдущей и следующей страниц keyEvent) { // При нажатии ENTER или символьной клавиши - включаем редактор if ((keyEvent.keyCode === Keys.ENTER || Keys.keyChar(keyEvent).length === 1) && this.dataSource.canEditCell(this.focusedCell) && this.settings.editorByKey) { if (this.startEditing(this.focusedCell, keyEvent)) { // Обработали return true; } } // Дальше, всё, что мы еще можем обработать - это работа с выделенными областями var res = this.selection.move(this.layoutsHandler.layouts, this.settings, this.dataSource.resultRows, pageCapacity, keyEvent); if (res !== null) { return true; } // Всё-таки, клавиша не пригодилась return false; }; __decorate([ AxInject('layouts'), __metadata("design:type", LayoutsHandler) ], GridUIHandler.prototype, "layoutsHandler", void 0); __decorate([ AxInject('events'), __metadata("design:type", Object) ], GridUIHandler.prototype, "events", void 0); __decorate([ AxInject('settings'), __metadata("design:type", GridSettings) ], GridUIHandler.prototype, "settings", void 0); __decorate([ AxInject('selection'), __metadata("design:type", Selection) ], GridUIHandler.prototype, "selection", void 0); __decorate([ AxInject('dataSource'), __metadata("design:type", DataSource) ], GridUIHandler.prototype, "dataSource", void 0); __decorate([ AxInject('check'), __metadata("design:type", GridCheckHandler) ], GridUIHandler.prototype, "check", void 0); __decorate([ AxInject('columns'), __metadata("design:type", ColumnCollection) ], GridUIHandler.prototype, "columnCollection", void 0); return GridUIHandler; }()); export { GridUIHandler };