@true-directive/base
Version:
The set of base classes for the TrueDirective Grid
451 lines (450 loc) • 20.3 kB
JavaScript
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 };